From 04ed3e741d0f133e02bed7fa5c98edba128f90e7 Mon Sep 17 00:00:00 2001 From: Michał Mirosław Date: Mon, 24 Jan 2011 15:32:47 -0800 Subject: net: change netdev->features to u32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Quoting Ben Hutchings: we presumably won't be defining features that can only be enabled on 64-bit architectures. Occurences found by `grep -r` on net/, drivers/net, include/ [ Move features and vlan_features next to each other in struct netdev, as per Eric Dumazet's suggestion -DaveM ] Signed-off-by: Michał Mirosław Signed-off-by: David S. Miller --- drivers/net/sfc/ethtool.c | 4 ++-- drivers/net/sfc/net_driver.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 0e8bb19ed60d..713969accdbd 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -502,7 +502,7 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable) { struct efx_nic *efx __attribute__ ((unused)) = netdev_priv(net_dev); - unsigned long features; + u32 features; features = NETIF_F_TSO; if (efx->type->offload_features & NETIF_F_V6_CSUM) @@ -519,7 +519,7 @@ static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable) static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable) { struct efx_nic *efx = netdev_priv(net_dev); - unsigned long features = efx->type->offload_features & NETIF_F_ALL_CSUM; + u32 features = efx->type->offload_features & NETIF_F_ALL_CSUM; if (enable) net_dev->features |= features; diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 28df8665256a..c65270241d2d 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -906,7 +906,7 @@ struct efx_nic_type { unsigned int phys_addr_channels; unsigned int tx_dc_base; unsigned int rx_dc_base; - unsigned long offload_features; + u32 offload_features; u32 reset_world_flags; }; -- cgit From 60031fcc17057e21566ed34ba23e93fffda1aa27 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 12 Jan 2011 18:39:40 +0000 Subject: sfc: Move TX queue core queue mapping into tx.c efx_hard_start_xmit() needs to implement a mapping which is the inverse of tx_queue::core_txq. Move the initialisation of tx_queue::core_txq next to efx_hard_start_xmit() to make the connection more obvious. Signed-off-by: Ben Hutchings --- drivers/net/sfc/efx.c | 6 ++---- drivers/net/sfc/efx.h | 1 + drivers/net/sfc/tx.c | 7 +++++++ 3 files changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 002bac743843..c559bc372fc1 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1910,10 +1910,8 @@ static int efx_register_netdev(struct efx_nic *efx) efx_for_each_channel(channel, efx) { struct efx_tx_queue *tx_queue; - efx_for_each_channel_tx_queue(tx_queue, channel) { - tx_queue->core_txq = netdev_get_tx_queue( - efx->net_dev, tx_queue->queue / EFX_TXQ_TYPES); - } + efx_for_each_channel_tx_queue(tx_queue, channel) + efx_init_tx_queue_core_txq(tx_queue); } /* Always start with carrier off; PHY events will detect the link */ diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index d43a7e5212b1..116207045068 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -29,6 +29,7 @@ extern int efx_probe_tx_queue(struct efx_tx_queue *tx_queue); extern void efx_remove_tx_queue(struct efx_tx_queue *tx_queue); extern void efx_init_tx_queue(struct efx_tx_queue *tx_queue); +extern void efx_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue); extern void efx_fini_tx_queue(struct efx_tx_queue *tx_queue); extern void efx_release_tx_buffers(struct efx_tx_queue *tx_queue); extern netdev_tx_t diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index 2f5e9da657bf..7e463fb19fb9 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -347,6 +347,13 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, return efx_enqueue_skb(tx_queue, skb); } +void efx_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue) +{ + /* Must be inverse of queue lookup in efx_hard_start_xmit() */ + tx_queue->core_txq = netdev_get_tx_queue( + tx_queue->efx->net_dev, tx_queue->queue / EFX_TXQ_TYPES); +} + void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) { unsigned fill_level; -- cgit From 525da9072c28df815bff64bf00f3b11ab88face8 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 7 Feb 2011 23:04:38 +0000 Subject: sfc: Distinguish queue lookup from test for queue existence efx_channel_get_{rx,tx}_queue() currently return NULL if the channel isn't used for traffic in that direction. In most cases this is a bug, but some callers rely on it as an existence test. Add existence test functions efx_channel_has_{rx_queue,tx_queues}() and use them as appropriate. Change efx_channel_get_{rx,tx}_queue() to assert that the requested queue exists. Remove now-redundant initialisation from efx_set_channels(). Signed-off-by: Ben Hutchings --- drivers/net/sfc/efx.c | 17 ++--------------- drivers/net/sfc/ethtool.c | 6 +++--- drivers/net/sfc/net_driver.h | 39 ++++++++++++++++++++++++++++----------- 3 files changed, 33 insertions(+), 29 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index c559bc372fc1..6189d3066018 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1271,21 +1271,8 @@ static void efx_remove_interrupts(struct efx_nic *efx) static void efx_set_channels(struct efx_nic *efx) { - struct efx_channel *channel; - struct efx_tx_queue *tx_queue; - efx->tx_channel_offset = separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0; - - /* Channel pointers were set in efx_init_struct() but we now - * need to clear them for TX queues in any RX-only channels. */ - efx_for_each_channel(channel, efx) { - if (channel->channel - efx->tx_channel_offset >= - efx->n_tx_channels) { - efx_for_each_channel_tx_queue(tx_queue, channel) - tx_queue->channel = NULL; - } - } } static int efx_probe_nic(struct efx_nic *efx) @@ -1531,9 +1518,9 @@ void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs, efx->irq_rx_adaptive = rx_adaptive; efx->irq_rx_moderation = rx_ticks; efx_for_each_channel(channel, efx) { - if (efx_channel_get_rx_queue(channel)) + if (efx_channel_has_rx_queue(channel)) channel->irq_moderation = rx_ticks; - else if (efx_channel_get_tx_queue(channel, 0)) + else if (efx_channel_has_tx_queues(channel)) channel->irq_moderation = tx_ticks; } } diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 713969accdbd..272cfe724e1b 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -631,7 +631,7 @@ static int efx_ethtool_get_coalesce(struct net_device *net_dev, /* Find lowest IRQ moderation across all used TX queues */ coalesce->tx_coalesce_usecs_irq = ~((u32) 0); efx_for_each_channel(channel, efx) { - if (!efx_channel_get_tx_queue(channel, 0)) + if (!efx_channel_has_tx_queues(channel)) continue; if (channel->irq_moderation < coalesce->tx_coalesce_usecs_irq) { if (channel->channel < efx->n_rx_channels) @@ -676,8 +676,8 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev, /* If the channel is shared only allow RX parameters to be set */ efx_for_each_channel(channel, efx) { - if (efx_channel_get_rx_queue(channel) && - efx_channel_get_tx_queue(channel, 0) && + if (efx_channel_has_rx_queue(channel) && + efx_channel_has_tx_queues(channel) && tx_usecs) { netif_err(efx, drv, efx->net_dev, "Channel is shared. " "Only RX coalescing may be set\n"); diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index c65270241d2d..77b7ce451519 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -938,19 +938,28 @@ efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type) return &efx->channel[efx->tx_channel_offset + index]->tx_queue[type]; } +static inline bool efx_channel_has_tx_queues(struct efx_channel *channel) +{ + return channel->channel - channel->efx->tx_channel_offset < + channel->efx->n_tx_channels; +} + static inline struct efx_tx_queue * efx_channel_get_tx_queue(struct efx_channel *channel, unsigned type) { - struct efx_tx_queue *tx_queue = channel->tx_queue; - EFX_BUG_ON_PARANOID(type >= EFX_TXQ_TYPES); - return tx_queue->channel ? tx_queue + type : NULL; + EFX_BUG_ON_PARANOID(!efx_channel_has_tx_queues(channel) || + type >= EFX_TXQ_TYPES); + return &channel->tx_queue[type]; } /* Iterate over all TX queues belonging to a channel */ #define efx_for_each_channel_tx_queue(_tx_queue, _channel) \ - for (_tx_queue = efx_channel_get_tx_queue(channel, 0); \ - _tx_queue && _tx_queue < (_channel)->tx_queue + EFX_TXQ_TYPES; \ - _tx_queue++) + if (!efx_channel_has_tx_queues(_channel)) \ + ; \ + else \ + for (_tx_queue = (_channel)->tx_queue; \ + _tx_queue < (_channel)->tx_queue + EFX_TXQ_TYPES; \ + _tx_queue++) static inline struct efx_rx_queue * efx_get_rx_queue(struct efx_nic *efx, unsigned index) @@ -959,18 +968,26 @@ efx_get_rx_queue(struct efx_nic *efx, unsigned index) return &efx->channel[index]->rx_queue; } +static inline bool efx_channel_has_rx_queue(struct efx_channel *channel) +{ + return channel->channel < channel->efx->n_rx_channels; +} + static inline struct efx_rx_queue * efx_channel_get_rx_queue(struct efx_channel *channel) { - return channel->channel < channel->efx->n_rx_channels ? - &channel->rx_queue : NULL; + EFX_BUG_ON_PARANOID(!efx_channel_has_rx_queue(channel)); + return &channel->rx_queue; } /* Iterate over all RX queues belonging to a channel */ #define efx_for_each_channel_rx_queue(_rx_queue, _channel) \ - for (_rx_queue = efx_channel_get_rx_queue(channel); \ - _rx_queue; \ - _rx_queue = NULL) + if (!efx_channel_has_rx_queue(_channel)) \ + ; \ + else \ + for (_rx_queue = &(_channel)->rx_queue; \ + _rx_queue; \ + _rx_queue = NULL) static inline struct efx_channel * efx_rx_queue_channel(struct efx_rx_queue *rx_queue) -- cgit From 94b274bf5fba6c75b922c8a23ad4b5639a168780 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 10 Jan 2011 21:18:20 +0000 Subject: sfc: Add TX queues for high-priority traffic Implement the ndo_setup_tc() operation with 2 traffic classes. Current Solarstorm controllers do not implement TX queue priority, but they do allow queues to be 'paced' with an enforced delay between packets. Paced and unpaced queues are scheduled in round-robin within two separate hardware bins (paced queues with a large delay may be placed into a third bin temporarily, but we won't use that). If there are queues in both bins, the TX scheduler will alternate between them. If we make high-priority queues unpaced and best-effort queues paced, and high-priority queues are mostly empty, a single high-priority queue can then instantly take 50% of the packet rate regardless of how many of the best-effort queues have descriptors outstanding. We do not actually want an enforced delay between packets on best- effort queues, so we set the pace value to a reserved value that actually results in a delay of 0. Signed-off-by: Ben Hutchings --- drivers/net/sfc/efx.c | 8 ++-- drivers/net/sfc/efx.h | 1 + drivers/net/sfc/net_driver.h | 29 ++++++++++++--- drivers/net/sfc/nic.c | 51 +++++++++++++++++++------- drivers/net/sfc/regs.h | 6 +++ drivers/net/sfc/selftest.c | 2 +- drivers/net/sfc/tx.c | 87 +++++++++++++++++++++++++++++++++++++++++--- 7 files changed, 156 insertions(+), 28 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 6189d3066018..d4e04256730b 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -673,7 +673,7 @@ static void efx_fini_channels(struct efx_nic *efx) efx_for_each_channel_rx_queue(rx_queue, channel) efx_fini_rx_queue(rx_queue); - efx_for_each_channel_tx_queue(tx_queue, channel) + efx_for_each_possible_channel_tx_queue(tx_queue, channel) efx_fini_tx_queue(tx_queue); efx_fini_eventq(channel); } @@ -689,7 +689,7 @@ static void efx_remove_channel(struct efx_channel *channel) efx_for_each_channel_rx_queue(rx_queue, channel) efx_remove_rx_queue(rx_queue); - efx_for_each_channel_tx_queue(tx_queue, channel) + efx_for_each_possible_channel_tx_queue(tx_queue, channel) efx_remove_tx_queue(tx_queue); efx_remove_eventq(channel); } @@ -1836,6 +1836,7 @@ static const struct net_device_ops efx_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = efx_netpoll, #endif + .ndo_setup_tc = efx_setup_tc, }; static void efx_update_name(struct efx_nic *efx) @@ -2386,7 +2387,8 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, int i, rc; /* Allocate and initialise a struct net_device and struct efx_nic */ - net_dev = alloc_etherdev_mq(sizeof(*efx), EFX_MAX_CORE_TX_QUEUES); + net_dev = alloc_etherdev_mqs(sizeof(*efx), EFX_MAX_CORE_TX_QUEUES, + EFX_MAX_RX_QUEUES); if (!net_dev) return -ENOMEM; net_dev->features |= (type->offload_features | NETIF_F_SG | diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index 116207045068..0cb198a64a63 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -37,6 +37,7 @@ efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev); extern netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb); extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index); +extern int efx_setup_tc(struct net_device *net_dev, u8 num_tc); /* RX */ extern int efx_probe_rx_queue(struct efx_rx_queue *rx_queue); diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 77b7ce451519..96e22ad34970 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -63,10 +63,12 @@ /* Checksum generation is a per-queue option in hardware, so each * queue visible to the networking core is backed by two hardware TX * queues. */ -#define EFX_MAX_CORE_TX_QUEUES EFX_MAX_CHANNELS -#define EFX_TXQ_TYPE_OFFLOAD 1 -#define EFX_TXQ_TYPES 2 -#define EFX_MAX_TX_QUEUES (EFX_TXQ_TYPES * EFX_MAX_CORE_TX_QUEUES) +#define EFX_MAX_TX_TC 2 +#define EFX_MAX_CORE_TX_QUEUES (EFX_MAX_TX_TC * EFX_MAX_CHANNELS) +#define EFX_TXQ_TYPE_OFFLOAD 1 /* flag */ +#define EFX_TXQ_TYPE_HIGHPRI 2 /* flag */ +#define EFX_TXQ_TYPES 4 +#define EFX_MAX_TX_QUEUES (EFX_TXQ_TYPES * EFX_MAX_CHANNELS) /** * struct efx_special_buffer - An Efx special buffer @@ -140,6 +142,7 @@ struct efx_tx_buffer { * @buffer: The software buffer ring * @txd: The hardware descriptor ring * @ptr_mask: The size of the ring minus 1. + * @initialised: Has hardware queue been initialised? * @flushed: Used when handling queue flushing * @read_count: Current read pointer. * This is the number of buffers that have been removed from both rings. @@ -182,6 +185,7 @@ struct efx_tx_queue { struct efx_tx_buffer *buffer; struct efx_special_buffer txd; unsigned int ptr_mask; + bool initialised; enum efx_flush_state flushed; /* Members used mainly on the completion path */ @@ -377,7 +381,7 @@ struct efx_channel { bool rx_pkt_csummed; struct efx_rx_queue rx_queue; - struct efx_tx_queue tx_queue[2]; + struct efx_tx_queue tx_queue[EFX_TXQ_TYPES]; }; enum efx_led_mode { @@ -952,15 +956,28 @@ efx_channel_get_tx_queue(struct efx_channel *channel, unsigned type) return &channel->tx_queue[type]; } +static inline bool efx_tx_queue_used(struct efx_tx_queue *tx_queue) +{ + return !(tx_queue->efx->net_dev->num_tc < 2 && + tx_queue->queue & EFX_TXQ_TYPE_HIGHPRI); +} + /* Iterate over all TX queues belonging to a channel */ #define efx_for_each_channel_tx_queue(_tx_queue, _channel) \ if (!efx_channel_has_tx_queues(_channel)) \ ; \ else \ for (_tx_queue = (_channel)->tx_queue; \ - _tx_queue < (_channel)->tx_queue + EFX_TXQ_TYPES; \ + _tx_queue < (_channel)->tx_queue + EFX_TXQ_TYPES && \ + efx_tx_queue_used(_tx_queue); \ _tx_queue++) +/* Iterate over all possible TX queues belonging to a channel */ +#define efx_for_each_possible_channel_tx_queue(_tx_queue, _channel) \ + for (_tx_queue = (_channel)->tx_queue; \ + _tx_queue < (_channel)->tx_queue + EFX_TXQ_TYPES; \ + _tx_queue++) + static inline struct efx_rx_queue * efx_get_rx_queue(struct efx_nic *efx, unsigned index) { diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index da386599ab68..1d0b8b6f25c4 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -445,8 +445,8 @@ int efx_nic_probe_tx(struct efx_tx_queue *tx_queue) void efx_nic_init_tx(struct efx_tx_queue *tx_queue) { - efx_oword_t tx_desc_ptr; struct efx_nic *efx = tx_queue->efx; + efx_oword_t reg; tx_queue->flushed = FLUSH_NONE; @@ -454,7 +454,7 @@ void efx_nic_init_tx(struct efx_tx_queue *tx_queue) efx_init_special_buffer(efx, &tx_queue->txd); /* Push TX descriptor ring to card */ - EFX_POPULATE_OWORD_10(tx_desc_ptr, + EFX_POPULATE_OWORD_10(reg, FRF_AZ_TX_DESCQ_EN, 1, FRF_AZ_TX_ISCSI_DDIG_EN, 0, FRF_AZ_TX_ISCSI_HDIG_EN, 0, @@ -470,17 +470,15 @@ void efx_nic_init_tx(struct efx_tx_queue *tx_queue) if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { int csum = tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD; - EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_IP_CHKSM_DIS, !csum); - EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_TCP_CHKSM_DIS, + EFX_SET_OWORD_FIELD(reg, FRF_BZ_TX_IP_CHKSM_DIS, !csum); + EFX_SET_OWORD_FIELD(reg, FRF_BZ_TX_TCP_CHKSM_DIS, !csum); } - efx_writeo_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base, + efx_writeo_table(efx, ®, efx->type->txd_ptr_tbl_base, tx_queue->queue); if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) { - efx_oword_t reg; - /* Only 128 bits in this register */ BUILD_BUG_ON(EFX_MAX_TX_QUEUES > 128); @@ -491,6 +489,16 @@ void efx_nic_init_tx(struct efx_tx_queue *tx_queue) set_bit_le(tx_queue->queue, (void *)®); efx_writeo(efx, ®, FR_AA_TX_CHKSM_CFG); } + + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { + EFX_POPULATE_OWORD_1(reg, + FRF_BZ_TX_PACE, + (tx_queue->queue & EFX_TXQ_TYPE_HIGHPRI) ? + FFE_BZ_TX_PACE_OFF : + FFE_BZ_TX_PACE_RESERVED); + efx_writeo_table(efx, ®, FR_BZ_TX_PACE_TBL, + tx_queue->queue); + } } static void efx_flush_tx_queue(struct efx_tx_queue *tx_queue) @@ -1238,8 +1246,10 @@ int efx_nic_flush_queues(struct efx_nic *efx) /* Flush all tx queues in parallel */ efx_for_each_channel(channel, efx) { - efx_for_each_channel_tx_queue(tx_queue, channel) - efx_flush_tx_queue(tx_queue); + efx_for_each_possible_channel_tx_queue(tx_queue, channel) { + if (tx_queue->initialised) + efx_flush_tx_queue(tx_queue); + } } /* The hardware supports four concurrent rx flushes, each of which may @@ -1262,8 +1272,9 @@ int efx_nic_flush_queues(struct efx_nic *efx) ++rx_pending; } } - efx_for_each_channel_tx_queue(tx_queue, channel) { - if (tx_queue->flushed != FLUSH_DONE) + efx_for_each_possible_channel_tx_queue(tx_queue, channel) { + if (tx_queue->initialised && + tx_queue->flushed != FLUSH_DONE) ++tx_pending; } } @@ -1278,8 +1289,9 @@ int efx_nic_flush_queues(struct efx_nic *efx) /* Mark the queues as all flushed. We're going to return failure * leading to a reset, or fake up success anyway */ efx_for_each_channel(channel, efx) { - efx_for_each_channel_tx_queue(tx_queue, channel) { - if (tx_queue->flushed != FLUSH_DONE) + efx_for_each_possible_channel_tx_queue(tx_queue, channel) { + if (tx_queue->initialised && + tx_queue->flushed != FLUSH_DONE) netif_err(efx, hw, efx->net_dev, "tx queue %d flush command timed out\n", tx_queue->queue); @@ -1682,6 +1694,19 @@ void efx_nic_init_common(struct efx_nic *efx) if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1); efx_writeo(efx, &temp, FR_AZ_TX_RESERVED); + + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { + EFX_POPULATE_OWORD_4(temp, + /* Default values */ + FRF_BZ_TX_PACE_SB_NOT_AF, 0x15, + FRF_BZ_TX_PACE_SB_AF, 0xb, + FRF_BZ_TX_PACE_FB_BASE, 0, + /* Allow large pace values in the + * fast bin. */ + FRF_BZ_TX_PACE_BIN_TH, + FFE_BZ_TX_PACE_RESERVED); + efx_writeo(efx, &temp, FR_BZ_TX_PACE); + } } /* Register dump */ diff --git a/drivers/net/sfc/regs.h b/drivers/net/sfc/regs.h index 96430ed81c36..8227de62014f 100644 --- a/drivers/net/sfc/regs.h +++ b/drivers/net/sfc/regs.h @@ -2907,6 +2907,12 @@ #define FRF_CZ_TMFT_SRC_MAC_HI_LBN 44 #define FRF_CZ_TMFT_SRC_MAC_HI_WIDTH 16 +/* TX_PACE_TBL */ +/* Values >20 are documented as reserved, but will result in a queue going + * into the fast bin with a pace value of zero. */ +#define FFE_BZ_TX_PACE_OFF 0 +#define FFE_BZ_TX_PACE_RESERVED 21 + /* DRIVER_EV */ /* Sub-fields of an RX flush completion event */ #define FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL_LBN 12 diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 0ebfb99f1299..f936892aa423 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -644,7 +644,7 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, goto out; } - /* Test both types of TX queue */ + /* Test all enabled types of TX queue */ efx_for_each_channel_tx_queue(tx_queue, channel) { state->offload_csum = (tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD); diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index 7e463fb19fb9..1a51653bb92b 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -336,22 +336,89 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, { struct efx_nic *efx = netdev_priv(net_dev); struct efx_tx_queue *tx_queue; + unsigned index, type; if (unlikely(efx->port_inhibited)) return NETDEV_TX_BUSY; - tx_queue = efx_get_tx_queue(efx, skb_get_queue_mapping(skb), - skb->ip_summed == CHECKSUM_PARTIAL ? - EFX_TXQ_TYPE_OFFLOAD : 0); + index = skb_get_queue_mapping(skb); + type = skb->ip_summed == CHECKSUM_PARTIAL ? EFX_TXQ_TYPE_OFFLOAD : 0; + if (index >= efx->n_tx_channels) { + index -= efx->n_tx_channels; + type |= EFX_TXQ_TYPE_HIGHPRI; + } + tx_queue = efx_get_tx_queue(efx, index, type); return efx_enqueue_skb(tx_queue, skb); } void efx_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue) { + struct efx_nic *efx = tx_queue->efx; + /* Must be inverse of queue lookup in efx_hard_start_xmit() */ - tx_queue->core_txq = netdev_get_tx_queue( - tx_queue->efx->net_dev, tx_queue->queue / EFX_TXQ_TYPES); + tx_queue->core_txq = + netdev_get_tx_queue(efx->net_dev, + tx_queue->queue / EFX_TXQ_TYPES + + ((tx_queue->queue & EFX_TXQ_TYPE_HIGHPRI) ? + efx->n_tx_channels : 0)); +} + +int efx_setup_tc(struct net_device *net_dev, u8 num_tc) +{ + struct efx_nic *efx = netdev_priv(net_dev); + struct efx_channel *channel; + struct efx_tx_queue *tx_queue; + unsigned tc; + int rc; + + if (efx_nic_rev(efx) < EFX_REV_FALCON_B0 || num_tc > EFX_MAX_TX_TC) + return -EINVAL; + + if (num_tc == net_dev->num_tc) + return 0; + + for (tc = 0; tc < num_tc; tc++) { + net_dev->tc_to_txq[tc].offset = tc * efx->n_tx_channels; + net_dev->tc_to_txq[tc].count = efx->n_tx_channels; + } + + if (num_tc > net_dev->num_tc) { + /* Initialise high-priority queues as necessary */ + efx_for_each_channel(channel, efx) { + efx_for_each_possible_channel_tx_queue(tx_queue, + channel) { + if (!(tx_queue->queue & EFX_TXQ_TYPE_HIGHPRI)) + continue; + if (!tx_queue->buffer) { + rc = efx_probe_tx_queue(tx_queue); + if (rc) + return rc; + } + if (!tx_queue->initialised) + efx_init_tx_queue(tx_queue); + efx_init_tx_queue_core_txq(tx_queue); + } + } + } else { + /* Reduce number of classes before number of queues */ + net_dev->num_tc = num_tc; + } + + rc = netif_set_real_num_tx_queues(net_dev, + max_t(int, num_tc, 1) * + efx->n_tx_channels); + if (rc) + return rc; + + /* Do not destroy high-priority queues when they become + * unused. We would have to flush them first, and it is + * fairly difficult to flush a subset of TX queues. Leave + * it to efx_fini_channels(). + */ + + net_dev->num_tc = num_tc; + return 0; } void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) @@ -437,6 +504,8 @@ void efx_init_tx_queue(struct efx_tx_queue *tx_queue) /* Set up TX descriptor ring */ efx_nic_init_tx(tx_queue); + + tx_queue->initialised = true; } void efx_release_tx_buffers(struct efx_tx_queue *tx_queue) @@ -459,9 +528,14 @@ void efx_release_tx_buffers(struct efx_tx_queue *tx_queue) void efx_fini_tx_queue(struct efx_tx_queue *tx_queue) { + if (!tx_queue->initialised) + return; + netif_dbg(tx_queue->efx, drv, tx_queue->efx->net_dev, "shutting down TX queue %d\n", tx_queue->queue); + tx_queue->initialised = false; + /* Flush TX queue, remove descriptor ring */ efx_nic_fini_tx(tx_queue); @@ -473,6 +547,9 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue) void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) { + if (!tx_queue->buffer) + return; + netif_dbg(tx_queue->efx, drv, tx_queue->efx->net_dev, "destroying TX queue %d\n", tx_queue->queue); efx_nic_remove_tx(tx_queue); -- cgit From d4726051043dd270f9a161414a8d5ced76e91dff Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 4 Jan 2011 15:22:36 +0000 Subject: sfc: Limit filter search depth further for performance hints (i.e. RFS) Signed-off-by: Ben Hutchings --- drivers/net/sfc/filter.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/filter.c b/drivers/net/sfc/filter.c index d4722c41c4ce..47a1b7984788 100644 --- a/drivers/net/sfc/filter.c +++ b/drivers/net/sfc/filter.c @@ -27,6 +27,10 @@ */ #define FILTER_CTL_SRCH_MAX 200 +/* Don't try very hard to find space for performance hints, as this is + * counter-productive. */ +#define FILTER_CTL_SRCH_HINT_MAX 5 + enum efx_filter_table_id { EFX_FILTER_TABLE_RX_IP = 0, EFX_FILTER_TABLE_RX_MAC, @@ -325,15 +329,16 @@ static int efx_filter_search(struct efx_filter_table *table, struct efx_filter_spec *spec, u32 key, bool for_insert, int *depth_required) { - unsigned hash, incr, filter_idx, depth; + unsigned hash, incr, filter_idx, depth, depth_max; struct efx_filter_spec *cmp; hash = efx_filter_hash(key); incr = efx_filter_increment(key); + depth_max = (spec->priority <= EFX_FILTER_PRI_HINT ? + FILTER_CTL_SRCH_HINT_MAX : FILTER_CTL_SRCH_MAX); for (depth = 1, filter_idx = hash & (table->size - 1); - depth <= FILTER_CTL_SRCH_MAX && - test_bit(filter_idx, table->used_bitmap); + depth <= depth_max && test_bit(filter_idx, table->used_bitmap); ++depth) { cmp = &table->spec[filter_idx]; if (efx_filter_equal(spec, cmp)) @@ -342,7 +347,7 @@ static int efx_filter_search(struct efx_filter_table *table, } if (!for_insert) return -ENOENT; - if (depth > FILTER_CTL_SRCH_MAX) + if (depth > depth_max) return -EBUSY; found: *depth_required = depth; -- cgit From 64d8ad6d745bbb596bfce3c5d0157267feba7e26 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 5 Jan 2011 00:50:41 +0000 Subject: sfc: Implement hardware acceleration of RFS Use the existing filter management functions to insert TCP/IPv4 and UDP/IPv4 4-tuple filters for Receive Flow Steering. For each channel, track how many RFS filters are being added during processing of received packets and scan the corresponding number of table entries for filters that may be reclaimed. Do this in batches to reduce lock overhead. Signed-off-by: Ben Hutchings --- drivers/net/sfc/efx.c | 49 +++++++++++++++++++- drivers/net/sfc/efx.h | 15 +++++++ drivers/net/sfc/filter.c | 104 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/sfc/net_driver.h | 3 ++ 4 files changed, 169 insertions(+), 2 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index d4e04256730b..35b7bc52a2d1 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "net_driver.h" #include "efx.h" #include "nic.h" @@ -307,6 +308,8 @@ static int efx_poll(struct napi_struct *napi, int budget) channel->irq_mod_score = 0; } + efx_filter_rfs_expire(channel); + /* There is no race here; although napi_disable() will * only wait for napi_complete(), this isn't a problem * since efx_channel_processed() will have no effect if @@ -1175,10 +1178,32 @@ static int efx_wanted_channels(void) return count; } +static int +efx_init_rx_cpu_rmap(struct efx_nic *efx, struct msix_entry *xentries) +{ +#ifdef CONFIG_RFS_ACCEL + int i, rc; + + efx->net_dev->rx_cpu_rmap = alloc_irq_cpu_rmap(efx->n_rx_channels); + if (!efx->net_dev->rx_cpu_rmap) + return -ENOMEM; + for (i = 0; i < efx->n_rx_channels; i++) { + rc = irq_cpu_rmap_add(efx->net_dev->rx_cpu_rmap, + xentries[i].vector); + if (rc) { + free_irq_cpu_rmap(efx->net_dev->rx_cpu_rmap); + efx->net_dev->rx_cpu_rmap = NULL; + return rc; + } + } +#endif + return 0; +} + /* Probe the number and type of interrupts we are able to obtain, and * the resulting numbers of channels and RX queues. */ -static void efx_probe_interrupts(struct efx_nic *efx) +static int efx_probe_interrupts(struct efx_nic *efx) { int max_channels = min_t(int, efx->type->phys_addr_channels, EFX_MAX_CHANNELS); @@ -1220,6 +1245,11 @@ static void efx_probe_interrupts(struct efx_nic *efx) efx->n_tx_channels = efx->n_channels; efx->n_rx_channels = efx->n_channels; } + rc = efx_init_rx_cpu_rmap(efx, xentries); + if (rc) { + pci_disable_msix(efx->pci_dev); + return rc; + } for (i = 0; i < n_channels; i++) efx_get_channel(efx, i)->irq = xentries[i].vector; @@ -1253,6 +1283,8 @@ static void efx_probe_interrupts(struct efx_nic *efx) efx->n_tx_channels = 1; efx->legacy_irq = efx->pci_dev->irq; } + + return 0; } static void efx_remove_interrupts(struct efx_nic *efx) @@ -1289,7 +1321,9 @@ static int efx_probe_nic(struct efx_nic *efx) /* Determine the number of channels and queues by trying to hook * in MSI-X interrupts. */ - efx_probe_interrupts(efx); + rc = efx_probe_interrupts(efx); + if (rc) + goto fail; if (efx->n_channels > 1) get_random_bytes(&efx->rx_hash_key, sizeof(efx->rx_hash_key)); @@ -1304,6 +1338,10 @@ static int efx_probe_nic(struct efx_nic *efx) efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec, true); return 0; + +fail: + efx->type->remove(efx); + return rc; } static void efx_remove_nic(struct efx_nic *efx) @@ -1837,6 +1875,9 @@ static const struct net_device_ops efx_netdev_ops = { .ndo_poll_controller = efx_netpoll, #endif .ndo_setup_tc = efx_setup_tc, +#ifdef CONFIG_RFS_ACCEL + .ndo_rx_flow_steer = efx_filter_rfs, +#endif }; static void efx_update_name(struct efx_nic *efx) @@ -2274,6 +2315,10 @@ static void efx_fini_struct(struct efx_nic *efx) */ static void efx_pci_remove_main(struct efx_nic *efx) { +#ifdef CONFIG_RFS_ACCEL + free_irq_cpu_rmap(efx->net_dev->rx_cpu_rmap); + efx->net_dev->rx_cpu_rmap = NULL; +#endif efx_nic_fini_interrupt(efx); efx_fini_channels(efx); efx_fini_port(efx); diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index 0cb198a64a63..cbce62b9c996 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -76,6 +76,21 @@ extern int efx_filter_remove_filter(struct efx_nic *efx, struct efx_filter_spec *spec); extern void efx_filter_clear_rx(struct efx_nic *efx, enum efx_filter_priority priority); +#ifdef CONFIG_RFS_ACCEL +extern int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, + u16 rxq_index, u32 flow_id); +extern bool __efx_filter_rfs_expire(struct efx_nic *efx, unsigned quota); +static inline void efx_filter_rfs_expire(struct efx_channel *channel) +{ + if (channel->rfs_filters_added >= 60 && + __efx_filter_rfs_expire(channel->efx, 100)) + channel->rfs_filters_added -= 60; +} +#define efx_filter_rfs_enabled() 1 +#else +static inline void efx_filter_rfs_expire(struct efx_channel *channel) {} +#define efx_filter_rfs_enabled() 0 +#endif /* Channels */ extern void efx_process_channel_now(struct efx_channel *channel); diff --git a/drivers/net/sfc/filter.c b/drivers/net/sfc/filter.c index 47a1b7984788..95a980fd63d5 100644 --- a/drivers/net/sfc/filter.c +++ b/drivers/net/sfc/filter.c @@ -8,6 +8,7 @@ */ #include +#include #include "efx.h" #include "filter.h" #include "io.h" @@ -51,6 +52,10 @@ struct efx_filter_table { struct efx_filter_state { spinlock_t lock; struct efx_filter_table table[EFX_FILTER_TABLE_COUNT]; +#ifdef CONFIG_RFS_ACCEL + u32 *rps_flow_id; + unsigned rps_expire_index; +#endif }; /* The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit @@ -567,6 +572,13 @@ int efx_probe_filters(struct efx_nic *efx) spin_lock_init(&state->lock); if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { +#ifdef CONFIG_RFS_ACCEL + state->rps_flow_id = kcalloc(FR_BZ_RX_FILTER_TBL0_ROWS, + sizeof(*state->rps_flow_id), + GFP_KERNEL); + if (!state->rps_flow_id) + goto fail; +#endif table = &state->table[EFX_FILTER_TABLE_RX_IP]; table->id = EFX_FILTER_TABLE_RX_IP; table->offset = FR_BZ_RX_FILTER_TBL0; @@ -612,5 +624,97 @@ void efx_remove_filters(struct efx_nic *efx) kfree(state->table[table_id].used_bitmap); vfree(state->table[table_id].spec); } +#ifdef CONFIG_RFS_ACCEL + kfree(state->rps_flow_id); +#endif kfree(state); } + +#ifdef CONFIG_RFS_ACCEL + +int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, + u16 rxq_index, u32 flow_id) +{ + struct efx_nic *efx = netdev_priv(net_dev); + struct efx_channel *channel; + struct efx_filter_state *state = efx->filter_state; + struct efx_filter_spec spec; + const struct iphdr *ip; + const __be16 *ports; + int nhoff; + int rc; + + nhoff = skb_network_offset(skb); + + if (skb->protocol != htons(ETH_P_IP)) + return -EPROTONOSUPPORT; + + /* RFS must validate the IP header length before calling us */ + EFX_BUG_ON_PARANOID(!pskb_may_pull(skb, nhoff + sizeof(*ip))); + ip = (const struct iphdr *)(skb->data + nhoff); + if (ip->frag_off & htons(IP_MF | IP_OFFSET)) + return -EPROTONOSUPPORT; + EFX_BUG_ON_PARANOID(!pskb_may_pull(skb, nhoff + 4 * ip->ihl + 4)); + ports = (const __be16 *)(skb->data + nhoff + 4 * ip->ihl); + + efx_filter_init_rx(&spec, EFX_FILTER_PRI_HINT, 0, rxq_index); + rc = efx_filter_set_ipv4_full(&spec, ip->protocol, + ip->daddr, ports[1], ip->saddr, ports[0]); + if (rc) + return rc; + + rc = efx_filter_insert_filter(efx, &spec, true); + if (rc < 0) + return rc; + + /* Remember this so we can check whether to expire the filter later */ + state->rps_flow_id[rc] = flow_id; + channel = efx_get_channel(efx, skb_get_rx_queue(skb)); + ++channel->rfs_filters_added; + + netif_info(efx, rx_status, efx->net_dev, + "steering %s %pI4:%u:%pI4:%u to queue %u [flow %u filter %d]\n", + (ip->protocol == IPPROTO_TCP) ? "TCP" : "UDP", + &ip->saddr, ntohs(ports[0]), &ip->daddr, ntohs(ports[1]), + rxq_index, flow_id, rc); + + return rc; +} + +bool __efx_filter_rfs_expire(struct efx_nic *efx, unsigned quota) +{ + struct efx_filter_state *state = efx->filter_state; + struct efx_filter_table *table = &state->table[EFX_FILTER_TABLE_RX_IP]; + unsigned mask = table->size - 1; + unsigned index; + unsigned stop; + + if (!spin_trylock_bh(&state->lock)) + return false; + + index = state->rps_expire_index; + stop = (index + quota) & mask; + + while (index != stop) { + if (test_bit(index, table->used_bitmap) && + table->spec[index].priority == EFX_FILTER_PRI_HINT && + rps_may_expire_flow(efx->net_dev, + table->spec[index].dmaq_id, + state->rps_flow_id[index], index)) { + netif_info(efx, rx_status, efx->net_dev, + "expiring filter %d [flow %u]\n", + index, state->rps_flow_id[index]); + efx_filter_table_clear_entry(efx, table, index); + } + index = (index + 1) & mask; + } + + state->rps_expire_index = stop; + if (table->used == 0) + efx_filter_table_reset_search_depth(table); + + spin_unlock_bh(&state->lock); + return true; +} + +#endif /* CONFIG_RFS_ACCEL */ diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 96e22ad34970..15b9068e5b87 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -362,6 +362,9 @@ struct efx_channel { unsigned int irq_count; unsigned int irq_mod_score; +#ifdef CONFIG_RFS_ACCEL + unsigned int rfs_filters_added; +#endif int rx_alloc_level; int rx_alloc_push_pages; -- cgit From 8ba5366adacef220b6ce16dca777600433a22a42 Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Thu, 24 Feb 2011 23:36:01 +0000 Subject: sfc: Reduce size of efx_rx_buffer by unionising skb and page [bwh: Forward-ported to net-next-2.6.] Signed-off-by: Ben Hutchings --- drivers/net/sfc/net_driver.h | 8 +++- drivers/net/sfc/rx.c | 96 +++++++++++++++++++++----------------------- 2 files changed, 51 insertions(+), 53 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 15b9068e5b87..59ff32ac7ec6 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -216,13 +216,17 @@ struct efx_tx_queue { * If both this and skb are %NULL, the buffer slot is currently free. * @data: Pointer to ethernet header * @len: Buffer length, in bytes. + * @is_page: Indicates if @page is valid. If false, @skb is valid. */ struct efx_rx_buffer { dma_addr_t dma_addr; - struct sk_buff *skb; - struct page *page; + union { + struct sk_buff *skb; + struct page *page; + } u; char *data; unsigned int len; + bool is_page; }; /** diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index 3925fd621177..bcbd2ec2d92a 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -129,6 +129,7 @@ static int efx_init_rx_buffers_skb(struct efx_rx_queue *rx_queue) struct efx_nic *efx = rx_queue->efx; struct net_device *net_dev = efx->net_dev; struct efx_rx_buffer *rx_buf; + struct sk_buff *skb; int skb_len = efx->rx_buffer_len; unsigned index, count; @@ -136,24 +137,24 @@ static int efx_init_rx_buffers_skb(struct efx_rx_queue *rx_queue) index = rx_queue->added_count & rx_queue->ptr_mask; rx_buf = efx_rx_buffer(rx_queue, index); - rx_buf->skb = netdev_alloc_skb(net_dev, skb_len); - if (unlikely(!rx_buf->skb)) + rx_buf->u.skb = skb = netdev_alloc_skb(net_dev, skb_len); + if (unlikely(!skb)) return -ENOMEM; - rx_buf->page = NULL; /* Adjust the SKB for padding and checksum */ - skb_reserve(rx_buf->skb, NET_IP_ALIGN); + skb_reserve(skb, NET_IP_ALIGN); + rx_buf->data = (char *)skb->data; rx_buf->len = skb_len - NET_IP_ALIGN; - rx_buf->data = (char *)rx_buf->skb->data; - rx_buf->skb->ip_summed = CHECKSUM_UNNECESSARY; + rx_buf->is_page = false; + skb->ip_summed = CHECKSUM_UNNECESSARY; rx_buf->dma_addr = pci_map_single(efx->pci_dev, rx_buf->data, rx_buf->len, PCI_DMA_FROMDEVICE); if (unlikely(pci_dma_mapping_error(efx->pci_dev, rx_buf->dma_addr))) { - dev_kfree_skb_any(rx_buf->skb); - rx_buf->skb = NULL; + dev_kfree_skb_any(skb); + rx_buf->u.skb = NULL; return -EIO; } @@ -211,10 +212,10 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue) index = rx_queue->added_count & rx_queue->ptr_mask; rx_buf = efx_rx_buffer(rx_queue, index); rx_buf->dma_addr = dma_addr + EFX_PAGE_IP_ALIGN; - rx_buf->skb = NULL; - rx_buf->page = page; + rx_buf->u.page = page; rx_buf->data = page_addr + EFX_PAGE_IP_ALIGN; rx_buf->len = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN; + rx_buf->is_page = true; ++rx_queue->added_count; ++rx_queue->alloc_page_count; ++state->refcnt; @@ -235,19 +236,17 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue) static void efx_unmap_rx_buffer(struct efx_nic *efx, struct efx_rx_buffer *rx_buf) { - if (rx_buf->page) { + if (rx_buf->is_page && rx_buf->u.page) { struct efx_rx_page_state *state; - EFX_BUG_ON_PARANOID(rx_buf->skb); - - state = page_address(rx_buf->page); + state = page_address(rx_buf->u.page); if (--state->refcnt == 0) { pci_unmap_page(efx->pci_dev, state->dma_addr, efx_rx_buf_size(efx), PCI_DMA_FROMDEVICE); } - } else if (likely(rx_buf->skb)) { + } else if (!rx_buf->is_page && rx_buf->u.skb) { pci_unmap_single(efx->pci_dev, rx_buf->dma_addr, rx_buf->len, PCI_DMA_FROMDEVICE); } @@ -256,12 +255,12 @@ static void efx_unmap_rx_buffer(struct efx_nic *efx, static void efx_free_rx_buffer(struct efx_nic *efx, struct efx_rx_buffer *rx_buf) { - if (rx_buf->page) { - __free_pages(rx_buf->page, efx->rx_buffer_order); - rx_buf->page = NULL; - } else if (likely(rx_buf->skb)) { - dev_kfree_skb_any(rx_buf->skb); - rx_buf->skb = NULL; + if (rx_buf->is_page && rx_buf->u.page) { + __free_pages(rx_buf->u.page, efx->rx_buffer_order); + rx_buf->u.page = NULL; + } else if (!rx_buf->is_page && rx_buf->u.skb) { + dev_kfree_skb_any(rx_buf->u.skb); + rx_buf->u.skb = NULL; } } @@ -277,7 +276,7 @@ static void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue, static void efx_resurrect_rx_buffer(struct efx_rx_queue *rx_queue, struct efx_rx_buffer *rx_buf) { - struct efx_rx_page_state *state = page_address(rx_buf->page); + struct efx_rx_page_state *state = page_address(rx_buf->u.page); struct efx_rx_buffer *new_buf; unsigned fill_level, index; @@ -292,16 +291,16 @@ static void efx_resurrect_rx_buffer(struct efx_rx_queue *rx_queue, } ++state->refcnt; - get_page(rx_buf->page); + get_page(rx_buf->u.page); index = rx_queue->added_count & rx_queue->ptr_mask; new_buf = efx_rx_buffer(rx_queue, index); new_buf->dma_addr = rx_buf->dma_addr ^ (PAGE_SIZE >> 1); - new_buf->skb = NULL; - new_buf->page = rx_buf->page; + new_buf->u.page = rx_buf->u.page; new_buf->data = (void *) ((__force unsigned long)rx_buf->data ^ (PAGE_SIZE >> 1)); new_buf->len = rx_buf->len; + new_buf->is_page = true; ++rx_queue->added_count; } @@ -315,16 +314,15 @@ static void efx_recycle_rx_buffer(struct efx_channel *channel, struct efx_rx_buffer *new_buf; unsigned index; - if (rx_buf->page != NULL && efx->rx_buffer_len <= EFX_RX_HALF_PAGE && - page_count(rx_buf->page) == 1) + if (rx_buf->is_page && efx->rx_buffer_len <= EFX_RX_HALF_PAGE && + page_count(rx_buf->u.page) == 1) efx_resurrect_rx_buffer(rx_queue, rx_buf); index = rx_queue->added_count & rx_queue->ptr_mask; new_buf = efx_rx_buffer(rx_queue, index); memcpy(new_buf, rx_buf, sizeof(*new_buf)); - rx_buf->page = NULL; - rx_buf->skb = NULL; + rx_buf->u.page = NULL; ++rx_queue->added_count; } @@ -428,7 +426,7 @@ static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue, * data at the end of the skb will be trashed. So * we have no choice but to leak the fragment. */ - *leak_packet = (rx_buf->skb != NULL); + *leak_packet = !rx_buf->is_page; efx_schedule_reset(efx, RESET_TYPE_RX_RECOVERY); } else { if (net_ratelimit()) @@ -454,13 +452,12 @@ static void efx_rx_packet_gro(struct efx_channel *channel, gro_result_t gro_result; /* Pass the skb/page into the GRO engine */ - if (rx_buf->page) { + if (rx_buf->is_page) { struct efx_nic *efx = channel->efx; - struct page *page = rx_buf->page; + struct page *page = rx_buf->u.page; struct sk_buff *skb; - EFX_BUG_ON_PARANOID(rx_buf->skb); - rx_buf->page = NULL; + rx_buf->u.page = NULL; skb = napi_get_frags(napi); if (!skb) { @@ -487,11 +484,10 @@ static void efx_rx_packet_gro(struct efx_channel *channel, gro_result = napi_gro_frags(napi); } else { - struct sk_buff *skb = rx_buf->skb; + struct sk_buff *skb = rx_buf->u.skb; - EFX_BUG_ON_PARANOID(!skb); EFX_BUG_ON_PARANOID(!checksummed); - rx_buf->skb = NULL; + rx_buf->u.skb = NULL; gro_result = napi_gro_receive(napi, skb); } @@ -514,8 +510,6 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, rx_buf = efx_rx_buffer(rx_queue, index); EFX_BUG_ON_PARANOID(!rx_buf->data); - EFX_BUG_ON_PARANOID(rx_buf->skb && rx_buf->page); - EFX_BUG_ON_PARANOID(!(rx_buf->skb || rx_buf->page)); /* This allows the refill path to post another buffer. * EFX_RXD_HEAD_ROOM ensures that the slot we are using @@ -587,32 +581,32 @@ void __efx_rx_packet(struct efx_channel *channel, return; } - if (rx_buf->skb) { - prefetch(skb_shinfo(rx_buf->skb)); + if (!rx_buf->is_page) { + skb = rx_buf->u.skb; + + prefetch(skb_shinfo(skb)); - skb_reserve(rx_buf->skb, efx->type->rx_buffer_hash_size); - skb_put(rx_buf->skb, rx_buf->len); + skb_reserve(skb, efx->type->rx_buffer_hash_size); + skb_put(skb, rx_buf->len); if (efx->net_dev->features & NETIF_F_RXHASH) - rx_buf->skb->rxhash = efx_rx_buf_hash(rx_buf); + skb->rxhash = efx_rx_buf_hash(rx_buf); /* Move past the ethernet header. rx_buf->data still points * at the ethernet header */ - rx_buf->skb->protocol = eth_type_trans(rx_buf->skb, - efx->net_dev); + skb->protocol = eth_type_trans(skb, efx->net_dev); - skb_record_rx_queue(rx_buf->skb, channel->channel); + skb_record_rx_queue(skb, channel->channel); } - if (likely(checksummed || rx_buf->page)) { + if (likely(checksummed || rx_buf->is_page)) { efx_rx_packet_gro(channel, rx_buf, checksummed); return; } /* We now own the SKB */ - skb = rx_buf->skb; - rx_buf->skb = NULL; - EFX_BUG_ON_PARANOID(!skb); + skb = rx_buf->u.skb; + rx_buf->u.skb = NULL; /* Set the SKB flags */ skb_checksum_none_assert(skb); -- cgit From a526f140b22131376b0e49577210e6af73e2b89f Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Thu, 24 Feb 2011 23:45:16 +0000 Subject: sfc: Reduce size of efx_rx_buffer further by removing data member Instead calculate the KVA of receive data. It's not like it's a hard sum. [bwh: Fixed to work with GRO.] Signed-off-by: Ben Hutchings --- drivers/net/sfc/net_driver.h | 2 -- drivers/net/sfc/rx.c | 50 +++++++++++++++++++++++++------------------- 2 files changed, 28 insertions(+), 24 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 59ff32ac7ec6..5b001c1c73d4 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -214,7 +214,6 @@ struct efx_tx_queue { * If both this and page are %NULL, the buffer slot is currently free. * @page: The associated page buffer, if any. * If both this and skb are %NULL, the buffer slot is currently free. - * @data: Pointer to ethernet header * @len: Buffer length, in bytes. * @is_page: Indicates if @page is valid. If false, @skb is valid. */ @@ -224,7 +223,6 @@ struct efx_rx_buffer { struct sk_buff *skb; struct page *page; } u; - char *data; unsigned int len; bool is_page; }; diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index bcbd2ec2d92a..81bec873e9d3 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -89,24 +89,37 @@ static unsigned int rx_refill_limit = 95; */ #define EFX_RXD_HEAD_ROOM 2 -static inline unsigned int efx_rx_buf_offset(struct efx_rx_buffer *buf) +/* Offset of ethernet header within page */ +static inline unsigned int efx_rx_buf_offset(struct efx_nic *efx, + struct efx_rx_buffer *buf) { /* Offset is always within one page, so we don't need to consider * the page order. */ - return (__force unsigned long) buf->data & (PAGE_SIZE - 1); + return (((__force unsigned long) buf->dma_addr & (PAGE_SIZE - 1)) + + efx->type->rx_buffer_hash_size); } static inline unsigned int efx_rx_buf_size(struct efx_nic *efx) { return PAGE_SIZE << efx->rx_buffer_order; } -static inline u32 efx_rx_buf_hash(struct efx_rx_buffer *buf) +static u8 *efx_rx_buf_eh(struct efx_nic *efx, struct efx_rx_buffer *buf) { + if (buf->is_page) + return page_address(buf->u.page) + efx_rx_buf_offset(efx, buf); + else + return ((u8 *)buf->u.skb->data + + efx->type->rx_buffer_hash_size); +} + +static inline u32 efx_rx_buf_hash(const u8 *eh) +{ + /* The ethernet header is always directly after any hash. */ #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) || NET_IP_ALIGN % 4 == 0 - return __le32_to_cpup((const __le32 *)(buf->data - 4)); + return __le32_to_cpup((const __le32 *)(eh - 4)); #else - const u8 *data = (const u8 *)(buf->data - 4); + const u8 *data = eh - 4; return ((u32)data[0] | (u32)data[1] << 8 | (u32)data[2] << 16 | @@ -143,13 +156,12 @@ static int efx_init_rx_buffers_skb(struct efx_rx_queue *rx_queue) /* Adjust the SKB for padding and checksum */ skb_reserve(skb, NET_IP_ALIGN); - rx_buf->data = (char *)skb->data; rx_buf->len = skb_len - NET_IP_ALIGN; rx_buf->is_page = false; skb->ip_summed = CHECKSUM_UNNECESSARY; rx_buf->dma_addr = pci_map_single(efx->pci_dev, - rx_buf->data, rx_buf->len, + skb->data, rx_buf->len, PCI_DMA_FROMDEVICE); if (unlikely(pci_dma_mapping_error(efx->pci_dev, rx_buf->dma_addr))) { @@ -213,7 +225,6 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue) rx_buf = efx_rx_buffer(rx_queue, index); rx_buf->dma_addr = dma_addr + EFX_PAGE_IP_ALIGN; rx_buf->u.page = page; - rx_buf->data = page_addr + EFX_PAGE_IP_ALIGN; rx_buf->len = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN; rx_buf->is_page = true; ++rx_queue->added_count; @@ -297,8 +308,6 @@ static void efx_resurrect_rx_buffer(struct efx_rx_queue *rx_queue, new_buf = efx_rx_buffer(rx_queue, index); new_buf->dma_addr = rx_buf->dma_addr ^ (PAGE_SIZE >> 1); new_buf->u.page = rx_buf->u.page; - new_buf->data = (void *) - ((__force unsigned long)rx_buf->data ^ (PAGE_SIZE >> 1)); new_buf->len = rx_buf->len; new_buf->is_page = true; ++rx_queue->added_count; @@ -446,7 +455,7 @@ static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue, */ static void efx_rx_packet_gro(struct efx_channel *channel, struct efx_rx_buffer *rx_buf, - bool checksummed) + const u8 *eh, bool checksummed) { struct napi_struct *napi = &channel->napi_str; gro_result_t gro_result; @@ -466,11 +475,11 @@ static void efx_rx_packet_gro(struct efx_channel *channel, } if (efx->net_dev->features & NETIF_F_RXHASH) - skb->rxhash = efx_rx_buf_hash(rx_buf); + skb->rxhash = efx_rx_buf_hash(eh); skb_shinfo(skb)->frags[0].page = page; skb_shinfo(skb)->frags[0].page_offset = - efx_rx_buf_offset(rx_buf); + efx_rx_buf_offset(efx, rx_buf); skb_shinfo(skb)->frags[0].size = rx_buf->len; skb_shinfo(skb)->nr_frags = 1; @@ -509,7 +518,6 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, bool leak_packet = false; rx_buf = efx_rx_buffer(rx_queue, index); - EFX_BUG_ON_PARANOID(!rx_buf->data); /* This allows the refill path to post another buffer. * EFX_RXD_HEAD_ROOM ensures that the slot we are using @@ -548,12 +556,12 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, /* Prefetch nice and early so data will (hopefully) be in cache by * the time we look at it. */ - prefetch(rx_buf->data); + prefetch(efx_rx_buf_eh(efx, rx_buf)); /* Pipeline receives so that we give time for packet headers to be * prefetched into cache. */ - rx_buf->len = len; + rx_buf->len = len - efx->type->rx_buffer_hash_size; out: if (channel->rx_pkt) __efx_rx_packet(channel, @@ -568,15 +576,13 @@ void __efx_rx_packet(struct efx_channel *channel, { struct efx_nic *efx = channel->efx; struct sk_buff *skb; - - rx_buf->data += efx->type->rx_buffer_hash_size; - rx_buf->len -= efx->type->rx_buffer_hash_size; + u8 *eh = efx_rx_buf_eh(efx, rx_buf); /* If we're in loopback test, then pass the packet directly to the * loopback layer, and free the rx_buf here */ if (unlikely(efx->loopback_selftest)) { - efx_loopback_rx_packet(efx, rx_buf->data, rx_buf->len); + efx_loopback_rx_packet(efx, eh, rx_buf->len); efx_free_rx_buffer(efx, rx_buf); return; } @@ -590,7 +596,7 @@ void __efx_rx_packet(struct efx_channel *channel, skb_put(skb, rx_buf->len); if (efx->net_dev->features & NETIF_F_RXHASH) - skb->rxhash = efx_rx_buf_hash(rx_buf); + skb->rxhash = efx_rx_buf_hash(eh); /* Move past the ethernet header. rx_buf->data still points * at the ethernet header */ @@ -600,7 +606,7 @@ void __efx_rx_packet(struct efx_channel *channel, } if (likely(checksummed || rx_buf->is_page)) { - efx_rx_packet_gro(channel, rx_buf, checksummed); + efx_rx_packet_gro(channel, rx_buf, eh, checksummed); return; } -- cgit From e5f0fd278084d79d6be0920043519749374b0507 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 24 Feb 2011 23:57:47 +0000 Subject: sfc: Read MC firmware version when requested through ethtool We currently make no use of siena_nic_data::fw_{version,build} except to format the firmware version for ethtool_get_drvinfo(). Since we only read the version at start of day, this information is incorrect after an MC firmware update. Remove the cached version information and read it via MCDI whenever it is requested. Signed-off-by: Ben Hutchings --- drivers/net/sfc/ethtool.c | 4 ++-- drivers/net/sfc/mcdi.c | 21 ++++++--------------- drivers/net/sfc/mcdi.h | 2 +- drivers/net/sfc/nic.h | 6 ------ drivers/net/sfc/siena.c | 17 ----------------- 5 files changed, 9 insertions(+), 41 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 272cfe724e1b..3e974b11db0e 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -237,8 +237,8 @@ static void efx_ethtool_get_drvinfo(struct net_device *net_dev, strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version)); if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) - siena_print_fwver(efx, info->fw_version, - sizeof(info->fw_version)); + efx_mcdi_print_fwver(efx, info->fw_version, + sizeof(info->fw_version)); strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info)); } diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c index b716e827b291..88e786b11ed1 100644 --- a/drivers/net/sfc/mcdi.c +++ b/drivers/net/sfc/mcdi.c @@ -602,7 +602,7 @@ void efx_mcdi_process_event(struct efx_channel *channel, ************************************************************************** */ -int efx_mcdi_fwver(struct efx_nic *efx, u64 *version, u32 *build) +void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len) { u8 outbuf[ALIGN(MC_CMD_GET_VERSION_V1_OUT_LEN, 4)]; size_t outlength; @@ -616,29 +616,20 @@ int efx_mcdi_fwver(struct efx_nic *efx, u64 *version, u32 *build) if (rc) goto fail; - if (outlength == MC_CMD_GET_VERSION_V0_OUT_LEN) { - *version = 0; - *build = MCDI_DWORD(outbuf, GET_VERSION_OUT_FIRMWARE); - return 0; - } - if (outlength < MC_CMD_GET_VERSION_V1_OUT_LEN) { rc = -EIO; goto fail; } ver_words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_OUT_VERSION); - *version = (((u64)le16_to_cpu(ver_words[0]) << 48) | - ((u64)le16_to_cpu(ver_words[1]) << 32) | - ((u64)le16_to_cpu(ver_words[2]) << 16) | - le16_to_cpu(ver_words[3])); - *build = MCDI_DWORD(outbuf, GET_VERSION_OUT_FIRMWARE); - - return 0; + snprintf(buf, len, "%u.%u.%u.%u", + le16_to_cpu(ver_words[0]), le16_to_cpu(ver_words[1]), + le16_to_cpu(ver_words[2]), le16_to_cpu(ver_words[3])); + return; fail: netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); - return rc; + buf[0] = 0; } int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating, diff --git a/drivers/net/sfc/mcdi.h b/drivers/net/sfc/mcdi.h index c792f1d65e48..9bac250143d9 100644 --- a/drivers/net/sfc/mcdi.h +++ b/drivers/net/sfc/mcdi.h @@ -93,7 +93,7 @@ extern void efx_mcdi_process_event(struct efx_channel *channel, #define MCDI_EVENT_FIELD(_ev, _field) \ EFX_QWORD_FIELD(_ev, MCDI_EVENT_ ## _field) -extern int efx_mcdi_fwver(struct efx_nic *efx, u64 *version, u32 *build); +extern void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len); extern int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating, bool *was_attached_out); extern int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address, diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index eb0586925b51..17407eac0030 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h @@ -142,20 +142,14 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx) /** * struct siena_nic_data - Siena NIC state - * @fw_version: Management controller firmware version - * @fw_build: Firmware build number * @mcdi: Management-Controller-to-Driver Interface * @wol_filter_id: Wake-on-LAN packet filter id */ struct siena_nic_data { - u64 fw_version; - u32 fw_build; struct efx_mcdi_iface mcdi; int wol_filter_id; }; -extern void siena_print_fwver(struct efx_nic *efx, char *buf, size_t len); - extern struct efx_nic_type falcon_a1_nic_type; extern struct efx_nic_type falcon_b0_nic_type; extern struct efx_nic_type siena_a0_nic_type; diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index bf8456176443..07b59a8c9a4c 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -227,13 +227,6 @@ static int siena_probe_nic(struct efx_nic *efx) if (rc) goto fail1; - rc = efx_mcdi_fwver(efx, &nic_data->fw_version, &nic_data->fw_build); - if (rc) { - netif_err(efx, probe, efx->net_dev, - "Failed to read MCPU firmware version - rc %d\n", rc); - goto fail1; /* MCPU absent? */ - } - /* Let the BMC know that the driver is now in charge of link and * filter settings. We must do this before we reset the NIC */ rc = efx_mcdi_drv_attach(efx, true, &already_attached); @@ -514,16 +507,6 @@ static void siena_stop_nic_stats(struct efx_nic *efx) efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, 0, 0, 0); } -void siena_print_fwver(struct efx_nic *efx, char *buf, size_t len) -{ - struct siena_nic_data *nic_data = efx->nic_data; - snprintf(buf, len, "%u.%u.%u.%u", - (unsigned int)(nic_data->fw_version >> 48), - (unsigned int)(nic_data->fw_version >> 32 & 0xffff), - (unsigned int)(nic_data->fw_version >> 16 & 0xffff), - (unsigned int)(nic_data->fw_version & 0xffff)); -} - /************************************************************************** * * Wake on LAN -- cgit From a461103ba2e22cbb70771588b36f40df39a50f46 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 24 Feb 2011 23:59:15 +0000 Subject: sfc: Do not read STAT1.FAULT in efx_mdio_check_mmd() This field does not exist in all MMDs we want to check, and all callers allow it to be set (fault_fatal = 0). Remove the loopback condition, as STAT2.DEVPRST should be valid regardless of any fault. Signed-off-by: Ben Hutchings --- drivers/net/sfc/mdio_10g.c | 32 +++++--------------------------- drivers/net/sfc/mdio_10g.h | 3 +-- drivers/net/sfc/tenxpress.c | 2 +- drivers/net/sfc/txc43128_phy.c | 2 +- 4 files changed, 8 insertions(+), 31 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 56b0266b441f..6e82e5ba583a 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c @@ -51,13 +51,10 @@ int efx_mdio_reset_mmd(struct efx_nic *port, int mmd, return spins ? spins : -ETIMEDOUT; } -static int efx_mdio_check_mmd(struct efx_nic *efx, int mmd, int fault_fatal) +static int efx_mdio_check_mmd(struct efx_nic *efx, int mmd) { int status; - if (LOOPBACK_INTERNAL(efx)) - return 0; - if (mmd != MDIO_MMD_AN) { /* Read MMD STATUS2 to check it is responding. */ status = efx_mdio_read(efx, mmd, MDIO_STAT2); @@ -68,20 +65,6 @@ static int efx_mdio_check_mmd(struct efx_nic *efx, int mmd, int fault_fatal) } } - /* Read MMD STATUS 1 to check for fault. */ - status = efx_mdio_read(efx, mmd, MDIO_STAT1); - if (status & MDIO_STAT1_FAULT) { - if (fault_fatal) { - netif_err(efx, hw, efx->net_dev, - "PHY MMD %d reporting fatal" - " fault: status %x\n", mmd, status); - return -EIO; - } else { - netif_dbg(efx, hw, efx->net_dev, - "PHY MMD %d reporting status" - " %x (expected)\n", mmd, status); - } - } return 0; } @@ -130,8 +113,7 @@ int efx_mdio_wait_reset_mmds(struct efx_nic *efx, unsigned int mmd_mask) return rc; } -int efx_mdio_check_mmds(struct efx_nic *efx, - unsigned int mmd_mask, unsigned int fatal_mask) +int efx_mdio_check_mmds(struct efx_nic *efx, unsigned int mmd_mask) { int mmd = 0, probe_mmd, devs1, devs2; u32 devices; @@ -161,13 +143,9 @@ int efx_mdio_check_mmds(struct efx_nic *efx, /* Check all required MMDs are responding and happy. */ while (mmd_mask) { - if (mmd_mask & 1) { - int fault_fatal = fatal_mask & 1; - if (efx_mdio_check_mmd(efx, mmd, fault_fatal)) - return -EIO; - } + if ((mmd_mask & 1) && efx_mdio_check_mmd(efx, mmd)) + return -EIO; mmd_mask = mmd_mask >> 1; - fatal_mask = fatal_mask >> 1; mmd++; } @@ -337,7 +315,7 @@ int efx_mdio_test_alive(struct efx_nic *efx) "no MDIO PHY present with ID %d\n", efx->mdio.prtad); rc = -EINVAL; } else { - rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0); + rc = efx_mdio_check_mmds(efx, efx->mdio.mmds); } mutex_unlock(&efx->mac_lock); diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h index 75791d3d4963..44c5dee52107 100644 --- a/drivers/net/sfc/mdio_10g.h +++ b/drivers/net/sfc/mdio_10g.h @@ -68,8 +68,7 @@ extern int efx_mdio_reset_mmd(struct efx_nic *efx, int mmd, int spins, int spintime); /* As efx_mdio_check_mmd but for multiple MMDs */ -int efx_mdio_check_mmds(struct efx_nic *efx, - unsigned int mmd_mask, unsigned int fatal_mask); +int efx_mdio_check_mmds(struct efx_nic *efx, unsigned int mmd_mask); /* Check the link status of specified mmds in bit mask */ extern bool efx_mdio_links_ok(struct efx_nic *efx, unsigned int mmd_mask); diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index f102912eba91..581911f70441 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -196,7 +196,7 @@ static int tenxpress_phy_init(struct efx_nic *efx) if (rc < 0) return rc; - rc = efx_mdio_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0); + rc = efx_mdio_check_mmds(efx, TENXPRESS_REQUIRED_DEVS); if (rc < 0) return rc; } diff --git a/drivers/net/sfc/txc43128_phy.c b/drivers/net/sfc/txc43128_phy.c index 351794a79215..4e2b48a8f5c4 100644 --- a/drivers/net/sfc/txc43128_phy.c +++ b/drivers/net/sfc/txc43128_phy.c @@ -193,7 +193,7 @@ static int txc_reset_phy(struct efx_nic *efx) goto fail; /* Check that all the MMDs we expect are present and responding. */ - rc = efx_mdio_check_mmds(efx, TXC_REQUIRED_DEVS, 0); + rc = efx_mdio_check_mmds(efx, TXC_REQUIRED_DEVS); if (rc < 0) goto fail; -- cgit From 0a6f40c66ba388e6349a11bea146955716c4d492 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 25 Feb 2011 00:01:34 +0000 Subject: sfc: Update copyright dates Signed-off-by: Ben Hutchings --- drivers/net/sfc/efx.c | 2 +- drivers/net/sfc/efx.h | 2 +- drivers/net/sfc/ethtool.c | 2 +- drivers/net/sfc/falcon.c | 2 +- drivers/net/sfc/falcon_boards.c | 2 +- drivers/net/sfc/falcon_xmac.c | 2 +- drivers/net/sfc/io.h | 2 +- drivers/net/sfc/mcdi.c | 2 +- drivers/net/sfc/mcdi.h | 2 +- drivers/net/sfc/mcdi_mac.c | 2 +- drivers/net/sfc/mcdi_pcol.h | 2 +- drivers/net/sfc/mcdi_phy.c | 2 +- drivers/net/sfc/mdio_10g.c | 2 +- drivers/net/sfc/mdio_10g.h | 2 +- drivers/net/sfc/mtd.c | 2 +- drivers/net/sfc/net_driver.h | 2 +- drivers/net/sfc/nic.c | 2 +- drivers/net/sfc/nic.h | 2 +- drivers/net/sfc/phy.h | 2 +- drivers/net/sfc/qt202x_phy.c | 2 +- drivers/net/sfc/regs.h | 2 +- drivers/net/sfc/rx.c | 2 +- drivers/net/sfc/selftest.c | 2 +- drivers/net/sfc/selftest.h | 2 +- drivers/net/sfc/siena.c | 2 +- drivers/net/sfc/spi.h | 2 +- drivers/net/sfc/tenxpress.c | 2 +- drivers/net/sfc/tx.c | 2 +- drivers/net/sfc/txc43128_phy.c | 2 +- drivers/net/sfc/workarounds.h | 2 +- 30 files changed, 30 insertions(+), 30 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 35b7bc52a2d1..d563049859a8 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2005-2009 Solarflare Communications Inc. + * Copyright 2005-2011 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index cbce62b9c996..3d83a1f74fef 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2009 Solarflare Communications Inc. + * Copyright 2006-2010 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 3e974b11db0e..52fa661aede9 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2009 Solarflare Communications Inc. + * Copyright 2006-2010 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 61ddd2c6e750..87481a6df42c 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2009 Solarflare Communications Inc. + * Copyright 2006-2010 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c index 2dd16f0b3ced..b9cc846811d6 100644 --- a/drivers/net/sfc/falcon_boards.c +++ b/drivers/net/sfc/falcon_boards.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007-2009 Solarflare Communications Inc. + * Copyright 2007-2010 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index b49e84394641..2c9ee5db3bf7 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2009 Solarflare Communications Inc. + * Copyright 2006-2010 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/io.h b/drivers/net/sfc/io.h index 6da4ae20a039..dc45110b2456 100644 --- a/drivers/net/sfc/io.h +++ b/drivers/net/sfc/io.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2009 Solarflare Communications Inc. + * Copyright 2006-2010 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c index 88e786b11ed1..8bba8955f310 100644 --- a/drivers/net/sfc/mcdi.c +++ b/drivers/net/sfc/mcdi.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2008-2009 Solarflare Communications Inc. + * Copyright 2008-2011 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/mcdi.h b/drivers/net/sfc/mcdi.h index 9bac250143d9..aced2a7856fc 100644 --- a/drivers/net/sfc/mcdi.h +++ b/drivers/net/sfc/mcdi.h @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2008-2009 Solarflare Communications Inc. + * Copyright 2008-2010 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/mcdi_mac.c b/drivers/net/sfc/mcdi_mac.c index f88f4bf986ff..33f7294edb47 100644 --- a/drivers/net/sfc/mcdi_mac.c +++ b/drivers/net/sfc/mcdi_mac.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2009 Solarflare Communications Inc. + * Copyright 2009-2010 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/mcdi_pcol.h b/drivers/net/sfc/mcdi_pcol.h index 90359e644006..b86a15f221ad 100644 --- a/drivers/net/sfc/mcdi_pcol.h +++ b/drivers/net/sfc/mcdi_pcol.h @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2009 Solarflare Communications Inc. + * Copyright 2009-2011 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c index 0e97eed663c6..ec3f740f5465 100644 --- a/drivers/net/sfc/mcdi_phy.c +++ b/drivers/net/sfc/mcdi_phy.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2009 Solarflare Communications Inc. + * Copyright 2009-2010 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 6e82e5ba583a..19e68c26d103 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2006-2009 Solarflare Communications Inc. + * Copyright 2006-2011 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h index 44c5dee52107..df0703940c83 100644 --- a/drivers/net/sfc/mdio_10g.h +++ b/drivers/net/sfc/mdio_10g.h @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2006-2009 Solarflare Communications Inc. + * Copyright 2006-2011 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c index d38627448c22..e646bfce2d84 100644 --- a/drivers/net/sfc/mtd.c +++ b/drivers/net/sfc/mtd.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2009 Solarflare Communications Inc. + * Copyright 2006-2010 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 5b001c1c73d4..9ea6cc2d205e 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2005-2009 Solarflare Communications Inc. + * Copyright 2005-2011 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index 1d0b8b6f25c4..fb25b87a1835 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2009 Solarflare Communications Inc. + * Copyright 2006-2011 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index 17407eac0030..1daaee6c7f07 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2009 Solarflare Communications Inc. + * Copyright 2006-2011 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h index 1dab609757fb..b3b79472421e 100644 --- a/drivers/net/sfc/phy.h +++ b/drivers/net/sfc/phy.h @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007-2009 Solarflare Communications Inc. + * Copyright 2007-2010 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index ea3ae0089315..55f90924247e 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2006-2009 Solarflare Communications Inc. + * Copyright 2006-2010 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/regs.h b/drivers/net/sfc/regs.h index 8227de62014f..cc2c86b76a7b 100644 --- a/drivers/net/sfc/regs.h +++ b/drivers/net/sfc/regs.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2009 Solarflare Communications Inc. + * Copyright 2006-2010 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index 81bec873e9d3..c0fdb59030fb 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2005-2009 Solarflare Communications Inc. + * Copyright 2005-2011 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index f936892aa423..a0f49b348d62 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2009 Solarflare Communications Inc. + * Copyright 2006-2010 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/selftest.h b/drivers/net/sfc/selftest.h index aed495a4dad7..dba5456e70f3 100644 --- a/drivers/net/sfc/selftest.h +++ b/drivers/net/sfc/selftest.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2010 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index 07b59a8c9a4c..8bd537e1de7f 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2009 Solarflare Communications Inc. + * Copyright 2006-2010 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/spi.h b/drivers/net/sfc/spi.h index 879b7f6bde3d..71f2e3ebe1c7 100644 --- a/drivers/net/sfc/spi.h +++ b/drivers/net/sfc/spi.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005 Fen Systems Ltd. - * Copyright 2006 Solarflare Communications Inc. + * Copyright 2006-2010 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 581911f70441..efdceb35aaae 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007-2009 Solarflare Communications Inc. + * Copyright 2007-2011 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index 1a51653bb92b..139801908217 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2005-2009 Solarflare Communications Inc. + * Copyright 2005-2010 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/txc43128_phy.c b/drivers/net/sfc/txc43128_phy.c index 4e2b48a8f5c4..d9886addcc99 100644 --- a/drivers/net/sfc/txc43128_phy.c +++ b/drivers/net/sfc/txc43128_phy.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2006-2010 Solarflare Communications Inc. + * Copyright 2006-2011 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h index e0d63083c3a8..e4dd3a7f304b 100644 --- a/drivers/net/sfc/workarounds.h +++ b/drivers/net/sfc/workarounds.h @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2006-2009 Solarflare Communications Inc. + * Copyright 2006-2010 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published -- cgit From 119226c563be011c6396c6a2d268d1ca7e467bd3 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 18 Feb 2011 19:14:13 +0000 Subject: sfc: Expose TX push and TSO counters through ethtool statistics Signed-off-by: Ben Hutchings --- drivers/net/sfc/ethtool.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 52fa661aede9..158d5b5630b6 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -28,7 +28,8 @@ struct efx_ethtool_stat { enum { EFX_ETHTOOL_STAT_SOURCE_mac_stats, EFX_ETHTOOL_STAT_SOURCE_nic, - EFX_ETHTOOL_STAT_SOURCE_channel + EFX_ETHTOOL_STAT_SOURCE_channel, + EFX_ETHTOOL_STAT_SOURCE_tx_queue } source; unsigned offset; u64(*get_stat) (void *field); /* Reader function */ @@ -86,6 +87,10 @@ static u64 efx_get_atomic_stat(void *field) EFX_ETHTOOL_STAT(field, channel, n_##field, \ unsigned int, efx_get_uint_stat) +#define EFX_ETHTOOL_UINT_TXQ_STAT(field) \ + EFX_ETHTOOL_STAT(tx_##field, tx_queue, field, \ + unsigned int, efx_get_uint_stat) + static struct efx_ethtool_stat efx_ethtool_stats[] = { EFX_ETHTOOL_U64_MAC_STAT(tx_bytes), EFX_ETHTOOL_U64_MAC_STAT(tx_good_bytes), @@ -116,6 +121,10 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = { EFX_ETHTOOL_ULONG_MAC_STAT(tx_non_tcpudp), EFX_ETHTOOL_ULONG_MAC_STAT(tx_mac_src_error), EFX_ETHTOOL_ULONG_MAC_STAT(tx_ip_src_error), + EFX_ETHTOOL_UINT_TXQ_STAT(tso_bursts), + EFX_ETHTOOL_UINT_TXQ_STAT(tso_long_headers), + EFX_ETHTOOL_UINT_TXQ_STAT(tso_packets), + EFX_ETHTOOL_UINT_TXQ_STAT(pushes), EFX_ETHTOOL_U64_MAC_STAT(rx_bytes), EFX_ETHTOOL_U64_MAC_STAT(rx_good_bytes), EFX_ETHTOOL_U64_MAC_STAT(rx_bad_bytes), @@ -470,6 +479,7 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, struct efx_mac_stats *mac_stats = &efx->mac_stats; struct efx_ethtool_stat *stat; struct efx_channel *channel; + struct efx_tx_queue *tx_queue; struct rtnl_link_stats64 temp; int i; @@ -495,6 +505,15 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, data[i] += stat->get_stat((void *)channel + stat->offset); break; + case EFX_ETHTOOL_STAT_SOURCE_tx_queue: + data[i] = 0; + efx_for_each_channel(channel, efx) { + efx_for_each_channel_tx_queue(tx_queue, channel) + data[i] += + stat->get_stat((void *)tx_queue + + stat->offset); + } + break; } } } -- cgit From 5fb6b06d4eda2167eab662ad5e30058cecd67b8b Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 24 Feb 2011 19:30:41 +0000 Subject: sfc: Remove configurable FIFO thresholds for pause frame generation In Falcon we can configure the fill levels of the RX data FIFO which trigger the generation of pause frames (if enabled), and we have module parameters for this. Siena does not allow the levels to be configured (or, if it does, this is done by the MC firmware and is not configurable by drivers). So far as I can tell, the module parameters are not used by our internal scripts and have not been documented (with the exception of the short parameter descriptions). Therefore, remove them and always initialise Falcon with the default values. Signed-off-by: Ben Hutchings --- drivers/net/sfc/falcon.c | 20 +++++--------------- drivers/net/sfc/nic.c | 20 -------------------- drivers/net/sfc/nic.h | 1 - drivers/net/sfc/siena.c | 5 ----- 4 files changed, 5 insertions(+), 41 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 87481a6df42c..734fcfb52e85 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -1478,36 +1478,26 @@ static void falcon_init_rx_cfg(struct efx_nic *efx) /* RX control FIFO thresholds (32 entries) */ const unsigned ctrl_xon_thr = 20; const unsigned ctrl_xoff_thr = 25; - /* RX data FIFO thresholds (256-byte units; size varies) */ - int data_xon_thr = efx_nic_rx_xon_thresh >> 8; - int data_xoff_thr = efx_nic_rx_xoff_thresh >> 8; efx_oword_t reg; efx_reado(efx, ®, FR_AZ_RX_CFG); if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) { /* Data FIFO size is 5.5K */ - if (data_xon_thr < 0) - data_xon_thr = 512 >> 8; - if (data_xoff_thr < 0) - data_xoff_thr = 2048 >> 8; EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_DESC_PUSH_EN, 0); EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_USR_BUF_SIZE, huge_buf_size); - EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_MAC_TH, data_xon_thr); - EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_MAC_TH, data_xoff_thr); + EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_MAC_TH, 512 >> 8); + EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_MAC_TH, 2048 >> 8); EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_TX_TH, ctrl_xon_thr); EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_TX_TH, ctrl_xoff_thr); } else { /* Data FIFO size is 80K; register fields moved */ - if (data_xon_thr < 0) - data_xon_thr = 27648 >> 8; /* ~3*max MTU */ - if (data_xoff_thr < 0) - data_xoff_thr = 54272 >> 8; /* ~80Kb - 3*max MTU */ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_DESC_PUSH_EN, 0); EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_USR_BUF_SIZE, huge_buf_size); - EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_MAC_TH, data_xon_thr); - EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_MAC_TH, data_xoff_thr); + /* Send XON and XOFF at ~3 * max MTU away from empty/full */ + EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_MAC_TH, 27648 >> 8); + EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_MAC_TH, 54272 >> 8); EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_TX_TH, ctrl_xon_thr); EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_TX_TH, ctrl_xoff_thr); EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1); diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index fb25b87a1835..e8396614daf3 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -41,26 +41,6 @@ #define RX_DC_ENTRIES 64 #define RX_DC_ENTRIES_ORDER 3 -/* RX FIFO XOFF watermark - * - * When the amount of the RX FIFO increases used increases past this - * watermark send XOFF. Only used if RX flow control is enabled (ethtool -A) - * This also has an effect on RX/TX arbitration - */ -int efx_nic_rx_xoff_thresh = -1; -module_param_named(rx_xoff_thresh_bytes, efx_nic_rx_xoff_thresh, int, 0644); -MODULE_PARM_DESC(rx_xoff_thresh_bytes, "RX fifo XOFF threshold"); - -/* RX FIFO XON watermark - * - * When the amount of the RX FIFO used decreases below this - * watermark send XON. Only used if TX flow control is enabled (ethtool -A) - * This also has an effect on RX/TX arbitration - */ -int efx_nic_rx_xon_thresh = -1; -module_param_named(rx_xon_thresh_bytes, efx_nic_rx_xon_thresh, int, 0644); -MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold"); - /* If EFX_MAX_INT_ERRORS internal errors occur within * EFX_INT_ERROR_EXPIRE seconds, we consider the NIC broken and * disable it. diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index 1daaee6c7f07..d9de1b647d41 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h @@ -188,7 +188,6 @@ extern void efx_nic_eventq_read_ack(struct efx_channel *channel); /* MAC/PHY */ extern void falcon_drain_tx_fifo(struct efx_nic *efx); extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx); -extern int efx_nic_rx_xoff_thresh, efx_nic_rx_xon_thresh; /* Interrupts and test events */ extern int efx_nic_init_interrupt(struct efx_nic *efx); diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index 8bd537e1de7f..e4dd8986b1fe 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -341,11 +341,6 @@ static int siena_init_nic(struct efx_nic *efx) FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8); efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG3); - if (efx_nic_rx_xoff_thresh >= 0 || efx_nic_rx_xon_thresh >= 0) - /* No MCDI operation has been defined to set thresholds */ - netif_err(efx, hw, efx->net_dev, - "ignoring RX flow control thresholds\n"); - /* Enable event logging */ rc = efx_mcdi_log_ctrl(efx, true, false, 0); if (rc) -- cgit From 6d84b986b26bac1d4d678ff10c10a633bf53f834 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 25 Feb 2011 00:04:42 +0000 Subject: sfc: Bump version to 3.1 All features originally planned for version 3.1 (and some that weren't) have been implemented. Signed-off-by: Ben Hutchings --- drivers/net/sfc/net_driver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 9ea6cc2d205e..215d5c51bfa0 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -41,7 +41,7 @@ * **************************************************************************/ -#define EFX_DRIVER_VERSION "3.0" +#define EFX_DRIVER_VERSION "3.1" #ifdef EFX_ENABLE_DEBUG #define EFX_BUG_ON_PARANOID(x) BUG_ON(x) -- cgit From 65f0b417dee94f779ce9b77102b7d73c93723b39 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 22 Feb 2011 17:26:10 +0000 Subject: sfc: Use write-combining to reduce TX latency Based on work by Neil Turton and Kieran Mansley . The BIU has now been verified to handle 3- and 4-dword writes within a single 128-bit register correctly. This means we can enable write- combining and only insert write barriers between writes to distinct registers. This has been observed to save about 0.5 us when pushing a TX descriptor to an empty TX queue. Signed-off-by: Ben Hutchings --- drivers/net/sfc/efx.c | 4 ++-- drivers/net/sfc/io.h | 13 +++++++++---- drivers/net/sfc/mcdi.c | 9 +++++---- 3 files changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index d563049859a8..b8bd936374f2 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1104,8 +1104,8 @@ static int efx_init_io(struct efx_nic *efx) rc = -EIO; goto fail3; } - efx->membase = ioremap_nocache(efx->membase_phys, - efx->type->mem_map_size); + efx->membase = ioremap_wc(efx->membase_phys, + efx->type->mem_map_size); if (!efx->membase) { netif_err(efx, probe, efx->net_dev, "could not map memory BAR at %llx+%x\n", diff --git a/drivers/net/sfc/io.h b/drivers/net/sfc/io.h index dc45110b2456..d9d8c2ef1074 100644 --- a/drivers/net/sfc/io.h +++ b/drivers/net/sfc/io.h @@ -48,9 +48,9 @@ * replacing the low 96 bits with zero does not affect functionality. * - If the host writes to the last dword address of such a register * (i.e. the high 32 bits) the underlying register will always be - * written. If the collector does not hold values for the low 96 - * bits of the register, they will be written as zero. Writing to - * the last qword does not have this effect and must not be done. + * written. If the collector and the current write together do not + * provide values for all 128 bits of the register, the low 96 bits + * will be written as zero. * - If the host writes to the address of any other part of such a * register while the collector already holds values for some other * register, the write is discarded and the collector maintains its @@ -103,6 +103,7 @@ static inline void efx_writeo(struct efx_nic *efx, efx_oword_t *value, _efx_writed(efx, value->u32[2], reg + 8); _efx_writed(efx, value->u32[3], reg + 12); #endif + wmb(); mmiowb(); spin_unlock_irqrestore(&efx->biu_lock, flags); } @@ -125,6 +126,7 @@ static inline void efx_sram_writeq(struct efx_nic *efx, void __iomem *membase, __raw_writel((__force u32)value->u32[0], membase + addr); __raw_writel((__force u32)value->u32[1], membase + addr + 4); #endif + wmb(); mmiowb(); spin_unlock_irqrestore(&efx->biu_lock, flags); } @@ -139,6 +141,7 @@ static inline void efx_writed(struct efx_nic *efx, efx_dword_t *value, /* No lock required */ _efx_writed(efx, value->u32[0], reg); + wmb(); } /* Read a 128-bit CSR, locking as appropriate. */ @@ -237,12 +240,14 @@ static inline void _efx_writeo_page(struct efx_nic *efx, efx_oword_t *value, #ifdef EFX_USE_QWORD_IO _efx_writeq(efx, value->u64[0], reg + 0); + _efx_writeq(efx, value->u64[1], reg + 8); #else _efx_writed(efx, value->u32[0], reg + 0); _efx_writed(efx, value->u32[1], reg + 4); -#endif _efx_writed(efx, value->u32[2], reg + 8); _efx_writed(efx, value->u32[3], reg + 12); +#endif + wmb(); } #define efx_writeo_page(efx, value, reg, page) \ _efx_writeo_page(efx, value, \ diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c index 8bba8955f310..5e118f0d2479 100644 --- a/drivers/net/sfc/mcdi.c +++ b/drivers/net/sfc/mcdi.c @@ -94,14 +94,15 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd, efx_writed(efx, &hdr, pdu); - for (i = 0; i < inlen; i += 4) + for (i = 0; i < inlen; i += 4) { _efx_writed(efx, *((__le32 *)(inbuf + i)), pdu + 4 + i); - - /* Ensure the payload is written out before the header */ - wmb(); + /* use wmb() within loop to inhibit write combining */ + wmb(); + } /* ring the doorbell with a distinctive value */ _efx_writed(efx, (__force __le32) 0x45789abc, doorbell); + wmb(); } static void efx_mcdi_copyout(struct efx_nic *efx, u8 *outbuf, size_t outlen) -- cgit