diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-23 11:47:02 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-23 11:47:02 -0700 |
commit | 5f05647dd81c11a6a165ccc8f0c1370b16f3bcb0 (patch) | |
tree | 7851ef1c93aa1aba7ef327ca4b75fd35e6d10f29 /drivers/net/sfc | |
parent | 02f36038c568111ad4fc433f6fa760ff5e38fab4 (diff) | |
parent | ec37a48d1d16c30b655ac5280209edf52a6775d4 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1699 commits)
bnx2/bnx2x: Unsupported Ethtool operations should return -EINVAL.
vlan: Calling vlan_hwaccel_do_receive() is always valid.
tproxy: use the interface primary IP address as a default value for --on-ip
tproxy: added IPv6 support to the socket match
cxgb3: function namespace cleanup
tproxy: added IPv6 support to the TPROXY target
tproxy: added IPv6 socket lookup function to nf_tproxy_core
be2net: Changes to use only priority codes allowed by f/w
tproxy: allow non-local binds of IPv6 sockets if IP_TRANSPARENT is enabled
tproxy: added tproxy sockopt interface in the IPV6 layer
tproxy: added udp6_lib_lookup function
tproxy: added const specifiers to udp lookup functions
tproxy: split off ipv6 defragmentation to a separate module
l2tp: small cleanup
nf_nat: restrict ICMP translation for embedded header
can: mcp251x: fix generation of error frames
can: mcp251x: fix endless loop in interrupt handler if CANINTF_MERRF is set
can-raw: add msg_flags to distinguish local traffic
9p: client code cleanup
rds: make local functions/variables static
...
Fix up conflicts in net/core/dev.c, drivers/net/pcmcia/smc91c92_cs.c and
drivers/net/wireless/ath/ath9k/debug.c as per David
Diffstat (limited to 'drivers/net/sfc')
-rw-r--r-- | drivers/net/sfc/Makefile | 7 | ||||
-rw-r--r-- | drivers/net/sfc/efx.c | 353 | ||||
-rw-r--r-- | drivers/net/sfc/efx.h | 46 | ||||
-rw-r--r-- | drivers/net/sfc/ethtool.c | 181 | ||||
-rw-r--r-- | drivers/net/sfc/falcon.c | 136 | ||||
-rw-r--r-- | drivers/net/sfc/falcon_boards.c | 203 | ||||
-rw-r--r-- | drivers/net/sfc/falcon_gmac.c | 230 | ||||
-rw-r--r-- | drivers/net/sfc/falcon_xmac.c | 2 | ||||
-rw-r--r-- | drivers/net/sfc/filter.c | 454 | ||||
-rw-r--r-- | drivers/net/sfc/filter.h | 189 | ||||
-rw-r--r-- | drivers/net/sfc/mac.h | 2 | ||||
-rw-r--r-- | drivers/net/sfc/mcdi.c | 4 | ||||
-rw-r--r-- | drivers/net/sfc/mcdi.h | 2 | ||||
-rw-r--r-- | drivers/net/sfc/mcdi_phy.c | 3 | ||||
-rw-r--r-- | drivers/net/sfc/mdio_10g.c | 30 | ||||
-rw-r--r-- | drivers/net/sfc/net_driver.h | 117 | ||||
-rw-r--r-- | drivers/net/sfc/nic.c | 199 | ||||
-rw-r--r-- | drivers/net/sfc/phy.h | 18 | ||||
-rw-r--r-- | drivers/net/sfc/regs.h | 14 | ||||
-rw-r--r-- | drivers/net/sfc/rx.c | 73 | ||||
-rw-r--r-- | drivers/net/sfc/selftest.c | 17 | ||||
-rw-r--r-- | drivers/net/sfc/siena.c | 6 | ||||
-rw-r--r-- | drivers/net/sfc/tenxpress.c | 424 | ||||
-rw-r--r-- | drivers/net/sfc/tx.c | 78 | ||||
-rw-r--r-- | drivers/net/sfc/txc43128_phy.c | 560 | ||||
-rw-r--r-- | drivers/net/sfc/workarounds.h | 9 |
26 files changed, 2105 insertions, 1252 deletions
diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile index 1047b19c60a..ab31c7124db 100644 --- a/drivers/net/sfc/Makefile +++ b/drivers/net/sfc/Makefile @@ -1,7 +1,8 @@ -sfc-y += efx.o nic.o falcon.o siena.o tx.o rx.o \ - falcon_gmac.o falcon_xmac.o mcdi_mac.o \ +sfc-y += efx.o nic.o falcon.o siena.o tx.o rx.o filter.o \ + falcon_xmac.o mcdi_mac.o \ selftest.o ethtool.o qt202x_phy.o mdio_10g.o \ - tenxpress.o falcon_boards.o mcdi.o mcdi_phy.o + tenxpress.o txc43128_phy.o falcon_boards.o \ + mcdi.o mcdi_phy.o sfc-$(CONFIG_SFC_MTD) += mtd.o obj-$(CONFIG_SFC) += sfc.o diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index ba674c5ca29..05df20e4797 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -68,14 +68,6 @@ const char *efx_loopback_mode_names[] = { [LOOPBACK_PHYXS_WS] = "PHYXS_WS", }; -/* Interrupt mode names (see INT_MODE())) */ -const unsigned int efx_interrupt_mode_max = EFX_INT_MODE_MAX; -const char *efx_interrupt_mode_names[] = { - [EFX_INT_MODE_MSIX] = "MSI-X", - [EFX_INT_MODE_MSI] = "MSI", - [EFX_INT_MODE_LEGACY] = "legacy", -}; - const unsigned int efx_reset_type_max = RESET_TYPE_MAX; const char *efx_reset_type_names[] = { [RESET_TYPE_INVISIBLE] = "INVISIBLE", @@ -114,7 +106,7 @@ static struct workqueue_struct *reset_workqueue; * This is only used in MSI-X interrupt mode */ static unsigned int separate_tx_channels; -module_param(separate_tx_channels, uint, 0644); +module_param(separate_tx_channels, uint, 0444); MODULE_PARM_DESC(separate_tx_channels, "Use separate channels for TX and RX"); @@ -124,10 +116,11 @@ MODULE_PARM_DESC(separate_tx_channels, static int napi_weight = 64; /* This is the time (in jiffies) between invocations of the hardware - * monitor, which checks for known hardware bugs and resets the - * hardware and driver as necessary. + * monitor. On Falcon-based NICs, this will: + * - Check the on-board hardware monitor; + * - Poll the link state and reconfigure the hardware as necessary. */ -unsigned int efx_monitor_interval = 1 * HZ; +static unsigned int efx_monitor_interval = 1 * HZ; /* This controls whether or not the driver will initialise devices * with invalid MAC addresses stored in the EEPROM or flash. If true, @@ -201,10 +194,13 @@ MODULE_PARM_DESC(debug, "Bitmapped debugging message enable value"); * Utility functions and prototypes * *************************************************************************/ -static void efx_remove_channel(struct efx_channel *channel); + +static void efx_remove_channels(struct efx_nic *efx); static void efx_remove_port(struct efx_nic *efx); static void efx_fini_napi(struct efx_nic *efx); -static void efx_fini_channels(struct efx_nic *efx); +static void efx_fini_struct(struct efx_nic *efx); +static void efx_start_all(struct efx_nic *efx); +static void efx_stop_all(struct efx_nic *efx); #define EFX_ASSERT_RESET_SERIALISED(efx) \ do { \ @@ -248,7 +244,7 @@ static int efx_process_channel(struct efx_channel *channel, int budget) efx_rx_strategy(channel); - efx_fast_push_rx_descriptors(&efx->rx_queue[channel->channel]); + efx_fast_push_rx_descriptors(efx_channel_get_rx_queue(channel)); return spent; } @@ -334,6 +330,7 @@ void efx_process_channel_now(struct efx_channel *channel) { struct efx_nic *efx = channel->efx; + BUG_ON(channel->channel >= efx->n_channels); BUG_ON(!channel->enabled); /* Disable interrupts and wait for ISRs to complete */ @@ -347,7 +344,7 @@ void efx_process_channel_now(struct efx_channel *channel) napi_disable(&channel->napi_str); /* Poll the channel */ - efx_process_channel(channel, EFX_EVQ_SIZE); + efx_process_channel(channel, channel->eventq_mask + 1); /* Ack the eventq. This may cause an interrupt to be generated * when they are reenabled */ @@ -364,9 +361,18 @@ void efx_process_channel_now(struct efx_channel *channel) */ static int efx_probe_eventq(struct efx_channel *channel) { + struct efx_nic *efx = channel->efx; + unsigned long entries; + netif_dbg(channel->efx, probe, channel->efx->net_dev, "chan %d create event queue\n", channel->channel); + /* Build an event queue with room for one event per tx and rx buffer, + * plus some extra for link state events and MCDI completions. */ + entries = roundup_pow_of_two(efx->rxq_entries + efx->txq_entries + 128); + EFX_BUG_ON_PARANOID(entries > EFX_MAX_EVQ_SIZE); + channel->eventq_mask = max(entries, EFX_MIN_EVQ_SIZE) - 1; + return efx_nic_probe_eventq(channel); } @@ -403,6 +409,63 @@ static void efx_remove_eventq(struct efx_channel *channel) * *************************************************************************/ +/* Allocate and initialise a channel structure, optionally copying + * parameters (but not resources) from an old channel structure. */ +static struct efx_channel * +efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel) +{ + struct efx_channel *channel; + struct efx_rx_queue *rx_queue; + struct efx_tx_queue *tx_queue; + int j; + + if (old_channel) { + channel = kmalloc(sizeof(*channel), GFP_KERNEL); + if (!channel) + return NULL; + + *channel = *old_channel; + + memset(&channel->eventq, 0, sizeof(channel->eventq)); + + rx_queue = &channel->rx_queue; + rx_queue->buffer = NULL; + memset(&rx_queue->rxd, 0, sizeof(rx_queue->rxd)); + + for (j = 0; j < EFX_TXQ_TYPES; j++) { + tx_queue = &channel->tx_queue[j]; + if (tx_queue->channel) + tx_queue->channel = channel; + tx_queue->buffer = NULL; + memset(&tx_queue->txd, 0, sizeof(tx_queue->txd)); + } + } else { + channel = kzalloc(sizeof(*channel), GFP_KERNEL); + if (!channel) + return NULL; + + channel->efx = efx; + channel->channel = i; + + for (j = 0; j < EFX_TXQ_TYPES; j++) { + tx_queue = &channel->tx_queue[j]; + tx_queue->efx = efx; + tx_queue->queue = i * EFX_TXQ_TYPES + j; + tx_queue->channel = channel; + } + } + + spin_lock_init(&channel->tx_stop_lock); + atomic_set(&channel->tx_stop_count, 1); + + rx_queue = &channel->rx_queue; + rx_queue->efx = efx; + setup_timer(&rx_queue->slow_fill, efx_rx_slow_fill, + (unsigned long)rx_queue); + + return channel; +} + static int efx_probe_channel(struct efx_channel *channel) { struct efx_tx_queue *tx_queue; @@ -459,11 +522,38 @@ static void efx_set_channel_names(struct efx_nic *efx) number -= efx->n_rx_channels; } } - snprintf(channel->name, sizeof(channel->name), + snprintf(efx->channel_name[channel->channel], + sizeof(efx->channel_name[0]), "%s%s-%d", efx->name, type, number); } } +static int efx_probe_channels(struct efx_nic *efx) +{ + struct efx_channel *channel; + int rc; + + /* Restart special buffer allocation */ + efx->next_buffer_table = 0; + + efx_for_each_channel(channel, efx) { + rc = efx_probe_channel(channel); + if (rc) { + netif_err(efx, probe, efx->net_dev, + "failed to create channel %d\n", + channel->channel); + goto fail; + } + } + efx_set_channel_names(efx); + + return 0; + +fail: + efx_remove_channels(efx); + return rc; +} + /* Channels are shutdown and reinitialised whilst the NIC is running * to propagate configuration changes (mtu, checksum offload), or * to clear hardware error conditions @@ -601,6 +691,75 @@ static void efx_remove_channel(struct efx_channel *channel) efx_remove_eventq(channel); } +static void efx_remove_channels(struct efx_nic *efx) +{ + struct efx_channel *channel; + + efx_for_each_channel(channel, efx) + efx_remove_channel(channel); +} + +int +efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries) +{ + struct efx_channel *other_channel[EFX_MAX_CHANNELS], *channel; + u32 old_rxq_entries, old_txq_entries; + unsigned i; + int rc; + + efx_stop_all(efx); + efx_fini_channels(efx); + + /* Clone channels */ + memset(other_channel, 0, sizeof(other_channel)); + for (i = 0; i < efx->n_channels; i++) { + channel = efx_alloc_channel(efx, i, efx->channel[i]); + if (!channel) { + rc = -ENOMEM; + goto out; + } + other_channel[i] = channel; + } + + /* Swap entry counts and channel pointers */ + old_rxq_entries = efx->rxq_entries; + old_txq_entries = efx->txq_entries; + efx->rxq_entries = rxq_entries; + efx->txq_entries = txq_entries; + for (i = 0; i < efx->n_channels; i++) { + channel = efx->channel[i]; + efx->channel[i] = other_channel[i]; + other_channel[i] = channel; + } + + rc = efx_probe_channels(efx); + if (rc) + goto rollback; + + /* Destroy old channels */ + for (i = 0; i < efx->n_channels; i++) + efx_remove_channel(other_channel[i]); +out: + /* Free unused channel structures */ + for (i = 0; i < efx->n_channels; i++) + kfree(other_channel[i]); + + efx_init_channels(efx); + efx_start_all(efx); + return rc; + +rollback: + /* Swap back */ + efx->rxq_entries = old_rxq_entries; + efx->txq_entries = old_txq_entries; + for (i = 0; i < efx->n_channels; i++) { + channel = efx->channel[i]; + efx->channel[i] = other_channel[i]; + other_channel[i] = channel; + } + goto out; +} + void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue) { mod_timer(&rx_queue->slow_fill, jiffies + msecs_to_jiffies(100)); @@ -761,7 +920,7 @@ static int efx_probe_port(struct efx_nic *efx) /* Connect up MAC/PHY operations table */ rc = efx->type->probe_port(efx); if (rc) - goto err; + return rc; /* Sanity check MAC address */ if (is_valid_ether_addr(efx->mac_address)) { @@ -782,7 +941,7 @@ static int efx_probe_port(struct efx_nic *efx) return 0; err: - efx_remove_port(efx); + efx->type->remove_port(efx); return rc; } @@ -1050,7 +1209,8 @@ static void efx_probe_interrupts(struct efx_nic *efx) efx->n_rx_channels = efx->n_channels; } for (i = 0; i < n_channels; i++) - efx->channel[i].irq = xentries[i].vector; + efx_get_channel(efx, i)->irq = + xentries[i].vector; } else { /* Fall back to single channel MSI */ efx->interrupt_mode = EFX_INT_MODE_MSI; @@ -1066,7 +1226,7 @@ static void efx_probe_interrupts(struct efx_nic *efx) efx->n_tx_channels = 1; rc = pci_enable_msi(efx->pci_dev); if (rc == 0) { - efx->channel[0].irq = efx->pci_dev->irq; + efx_get_channel(efx, 0)->irq = efx->pci_dev->irq; } else { netif_err(efx, drv, efx->net_dev, "could not enable MSI\n"); @@ -1097,26 +1257,32 @@ static void efx_remove_interrupts(struct efx_nic *efx) efx->legacy_irq = 0; } +struct efx_tx_queue * +efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type) +{ + unsigned tx_channel_offset = + separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0; + EFX_BUG_ON_PARANOID(index >= efx->n_tx_channels || + type >= EFX_TXQ_TYPES); + return &efx->channel[tx_channel_offset + index]->tx_queue[type]; +} + static void efx_set_channels(struct efx_nic *efx) { struct efx_channel *channel; struct efx_tx_queue *tx_queue; - struct efx_rx_queue *rx_queue; unsigned 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 - tx_channel_offset < efx->n_tx_channels) { - channel->tx_queue = &efx->tx_queue[ - (channel->channel - tx_channel_offset) * - EFX_TXQ_TYPES]; + if (channel->channel - tx_channel_offset >= + efx->n_tx_channels) { efx_for_each_channel_tx_queue(tx_queue, channel) - tx_queue->channel = channel; + tx_queue->channel = NULL; } } - - efx_for_each_rx_queue(rx_queue, efx) - rx_queue->channel = &efx->channel[rx_queue->queue]; } static int efx_probe_nic(struct efx_nic *efx) @@ -1141,7 +1307,8 @@ static int efx_probe_nic(struct efx_nic *efx) efx->rx_indir_table[i] = i % efx->n_rx_channels; efx_set_channels(efx); - efx->net_dev->real_num_tx_queues = efx->n_tx_channels; + netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels); + netif_set_real_num_rx_queues(efx->net_dev, efx->n_rx_channels); /* Initialise the interrupt moderation settings */ efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec, true); @@ -1165,40 +1332,37 @@ static void efx_remove_nic(struct efx_nic *efx) static int efx_probe_all(struct efx_nic *efx) { - struct efx_channel *channel; int rc; - /* Create NIC */ rc = efx_probe_nic(efx); if (rc) { netif_err(efx, probe, efx->net_dev, "failed to create NIC\n"); goto fail1; } - /* Create port */ rc = efx_probe_port(efx); if (rc) { netif_err(efx, probe, efx->net_dev, "failed to create port\n"); goto fail2; } - /* Create channels */ - efx_for_each_channel(channel, efx) { - rc = efx_probe_channel(channel); - if (rc) { - netif_err(efx, probe, efx->net_dev, - "failed to create channel %d\n", - channel->channel); - goto fail3; - } + efx->rxq_entries = efx->txq_entries = EFX_DEFAULT_DMAQ_SIZE; + rc = efx_probe_channels(efx); + if (rc) + goto fail3; + + rc = efx_probe_filters(efx); + if (rc) { + netif_err(efx, probe, efx->net_dev, + "failed to create filter tables\n"); + goto fail4; } - efx_set_channel_names(efx); return 0; + fail4: + efx_remove_channels(efx); fail3: - efx_for_each_channel(channel, efx) - efx_remove_channel(channel); efx_remove_port(efx); fail2: efx_remove_nic(efx); @@ -1328,10 +1492,8 @@ static void efx_stop_all(struct efx_nic *efx) static void efx_remove_all(struct efx_nic *efx) { - struct efx_channel *channel; - - efx_for_each_channel(channel, efx) - efx_remove_channel(channel); + efx_remove_filters(efx); + efx_remove_channels(efx); efx_remove_port(efx); efx_remove_nic(efx); } @@ -1355,20 +1517,20 @@ static unsigned irq_mod_ticks(int usecs, int resolution) void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs, bool rx_adaptive) { - struct efx_tx_queue *tx_queue; - struct efx_rx_queue *rx_queue; + struct efx_channel *channel; unsigned tx_ticks = irq_mod_ticks(tx_usecs, EFX_IRQ_MOD_RESOLUTION); unsigned rx_ticks = irq_mod_ticks(rx_usecs, EFX_IRQ_MOD_RESOLUTION); EFX_ASSERT_RESET_SERIALISED(efx); - efx_for_each_tx_queue(tx_queue, efx) - tx_queue->channel->irq_moderation = tx_ticks; - efx->irq_rx_adaptive = rx_adaptive; efx->irq_rx_moderation = rx_ticks; - efx_for_each_rx_queue(rx_queue, efx) - rx_queue->channel->irq_moderation = rx_ticks; + efx_for_each_channel(channel, efx) { + if (efx_channel_get_rx_queue(channel)) + channel->irq_moderation = rx_ticks; + else if (efx_channel_get_tx_queue(channel, 0)) + channel->irq_moderation = tx_ticks; + } } /************************************************************************** @@ -1377,8 +1539,7 @@ void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs, * **************************************************************************/ -/* Run periodically off the general workqueue. Serialised against - * efx_reconfigure_port via the mac_lock */ +/* Run periodically off the general workqueue */ static void efx_monitor(struct work_struct *data) { struct efx_nic *efx = container_of(data, struct efx_nic, @@ -1391,16 +1552,13 @@ static void efx_monitor(struct work_struct *data) /* If the mac_lock is already held then it is likely a port * reconfiguration is already in place, which will likely do - * most of the work of check_hw() anyway. */ - if (!mutex_trylock(&efx->mac_lock)) - goto out_requeue; - if (!efx->port_enabled) - goto out_unlock; - efx->type->monitor(efx); + * most of the work of monitor() anyway. */ + if (mutex_trylock(&efx->mac_lock)) { + if (efx->port_enabled) + efx->type->monitor(efx); + mutex_unlock(&efx->mac_lock); + } -out_unlock: - mutex_unlock(&efx->mac_lock); -out_requeue: queue_delayed_work(efx->workqueue, &efx->monitor_work, efx_monitor_interval); } @@ -1546,11 +1704,11 @@ static struct rtnl_link_stats64 *efx_net_stats(struct net_device *net_dev, struc stats->tx_packets = mac_stats->tx_packets; stats->rx_bytes = mac_stats->rx_bytes; stats->tx_bytes = mac_stats->tx_bytes; + stats->rx_dropped = efx->n_rx_nodesc_drop_cnt; stats->multicast = mac_stats->rx_multicast; stats->collisions = mac_stats->tx_collision; stats->rx_length_errors = (mac_stats->rx_gtjumbo + mac_stats->rx_length_error); - stats->rx_over_errors = efx->n_rx_nodesc_drop_cnt; stats->rx_crc_errors = mac_stats->rx_bad; stats->rx_frame_errors = mac_stats->rx_align_error; stats->rx_fifo_errors = mac_stats->rx_overflow; @@ -1767,6 +1925,7 @@ fail_registered: static void efx_unregister_netdev(struct efx_nic *efx) { + struct efx_channel *channel; struct efx_tx_queue *tx_queue; if (!efx->net_dev) @@ -1777,8 +1936,10 @@ static void efx_unregister_netdev(struct efx_nic *efx) /* Free up any skbs still remaining. This has to happen before * we try to unregister the netdev as running their destructors * may be needed to get the device ref. count to 0. */ - efx_for_each_tx_queue(tx_queue, efx) - efx_release_tx_buffers(tx_queue); + efx_for_each_channel(channel, efx) { + efx_for_each_channel_tx_queue(tx_queue, channel) + efx_release_tx_buffers(tx_queue); + } if (efx_dev_registered(efx)) { strlcpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name)); @@ -1841,6 +2002,7 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) efx->mac_op->reconfigure(efx); efx_init_channels(efx); + efx_restore_filters(efx); mutex_unlock(&efx->spi_lock); mutex_unlock(&efx->mac_lock); @@ -2010,10 +2172,8 @@ int efx_port_dummy_op_int(struct efx_nic *efx) return 0; } void efx_port_dummy_op_void(struct efx_nic *efx) {} -void efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) -{ -} -bool efx_port_dummy_op_poll(struct efx_nic *efx) + +static bool efx_port_dummy_op_poll(struct efx_nic *efx) { return false; } @@ -2037,9 +2197,6 @@ static struct efx_phy_operations efx_dummy_phy_operations = { static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, struct pci_dev *pci_dev, struct net_device *net_dev) { - struct efx_channel *channel; - struct efx_tx_queue *tx_queue; - struct efx_rx_queue *rx_queue; int i; /* Initialise common structures */ @@ -2068,36 +2225,13 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, INIT_WORK(&efx->mac_work, efx_mac_work); for (i = 0; i < EFX_MAX_CHANNELS; i++) { - channel = &efx->channel[i]; - channel->efx = efx; - channel->channel = i; - channel->work_pending = false; - spin_lock_init(&channel->tx_stop_lock); - atomic_set(&channel->tx_stop_count, 1); - } - for (i = 0; i < EFX_MAX_TX_QUEUES; i++) { - tx_queue = &efx->tx_queue[i]; - tx_queue->efx = efx; - tx_queue->queue = i; - tx_queue->buffer = NULL; - tx_queue->channel = &efx->channel[0]; /* for safety */ - tx_queue->tso_headers_free = NULL; - } - for (i = 0; i < EFX_MAX_RX_QUEUES; i++) { - rx_queue = &efx->rx_queue[i]; - rx_queue->efx = efx; - rx_queue->queue = i; - rx_queue->channel = &efx->channel[0]; /* for safety */ - rx_queue->buffer = NULL; - setup_timer(&rx_queue->slow_fill, efx_rx_slow_fill, - (unsigned long)rx_queue); + efx->channel[i] = efx_alloc_channel(efx, i, NULL); + if (!efx->channel[i]) + goto fail; } efx->type = type; - /* As close as we can get to guaranteeing that we don't overflow */ - BUILD_BUG_ON(EFX_EVQ_SIZE < EFX_TXQ_SIZE + EFX_RXQ_SIZE); - EFX_BUG_ON_PARANOID(efx->type->phys_addr_channels > EFX_MAX_CHANNELS); /* Higher numbered interrupt modes are less capable! */ @@ -2109,13 +2243,22 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, pci_name(pci_dev)); efx->workqueue = create_singlethread_workqueue(efx->workqueue_name); if (!efx->workqueue) - return -ENOMEM; + goto fail; return 0; + +fail: + efx_fini_struct(efx); + return -ENOMEM; } static void efx_fini_struct(struct efx_nic *efx) { + int i; + + for (i = 0; i < EFX_MAX_CHANNELS; i++) + kfree(efx->channel[i]); + if (efx->workqueue) { destroy_workqueue(efx->workqueue); efx->workqueue = NULL; diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index 060dc952a0f..10a1bf40da9 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -12,6 +12,7 @@ #define EFX_EFX_H #include "net_driver.h" +#include "filter.h" /* PCI IDs */ #define EFX_VENDID_SFC 0x1924 @@ -37,8 +38,6 @@ 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 void efx_stop_queue(struct efx_channel *channel); extern void efx_wake_queue(struct efx_channel *channel); -#define EFX_TXQ_SIZE 1024 -#define EFX_TXQ_MASK (EFX_TXQ_SIZE - 1) /* RX */ extern int efx_probe_rx_queue(struct efx_rx_queue *rx_queue); @@ -53,23 +52,42 @@ extern void __efx_rx_packet(struct efx_channel *channel, extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, unsigned int len, bool checksummed, bool discard); extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue); -#define EFX_RXQ_SIZE 1024 -#define EFX_RXQ_MASK (EFX_RXQ_SIZE - 1) + +#define EFX_MAX_DMAQ_SIZE 4096UL +#define EFX_DEFAULT_DMAQ_SIZE 1024UL +#define EFX_MIN_DMAQ_SIZE 512UL + +#define EFX_MAX_EVQ_SIZE 16384UL +#define EFX_MIN_EVQ_SIZE 512UL + +/* The smallest [rt]xq_entries that the driver supports. Callers of + * efx_wake_queue() assume that they can subsequently send at least one + * skb. Falcon/A1 may require up to three descriptors per skb_frag. */ +#define EFX_MIN_RING_SIZE (roundup_pow_of_two(2 * 3 * MAX_SKB_FRAGS)) + +/* Filters */ +extern int efx_probe_filters(struct efx_nic *efx); +extern void efx_restore_filters(struct efx_nic *efx); +extern void efx_remove_filters(struct efx_nic *efx); +extern int efx_filter_insert_filter(struct efx_nic *efx, + struct efx_filter_spec *spec, + bool replace); +extern int efx_filter_remove_filter(struct efx_nic *efx, + struct efx_filter_spec *spec); +extern void efx_filter_table_clear(struct efx_nic *efx, + enum efx_filter_table_id table_id, + enum efx_filter_priority priority); /* Channels */ extern void efx_process_channel_now(struct efx_channel *channel); -#define EFX_EVQ_SIZE 4096 -#define EFX_EVQ_MASK (EFX_EVQ_SIZE - 1) +extern int +efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries); /* Ports */ extern int efx_reconfigure_port(struct efx_nic *efx); extern int __efx_reconfigure_port(struct efx_nic *efx); /* Ethtool support */ -extern int efx_ethtool_get_settings(struct net_device *net_dev, - struct ethtool_cmd *ecmd); -extern int efx_ethtool_set_settings(struct net_device *net_dev, - struct ethtool_cmd *ecmd); extern const struct ethtool_ops efx_ethtool_ops; /* Reset handling */ @@ -81,15 +99,11 @@ extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok); extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); extern void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs, bool rx_adaptive); -extern int efx_request_power(struct efx_nic *efx, int mw, const char *name); -extern void efx_hex_dump(const u8 *, unsigned int, const char *); /* Dummy PHY ops for PHY drivers */ extern int efx_port_dummy_op_int(struct efx_nic *efx); extern void efx_port_dummy_op_void(struct efx_nic *efx); -extern void -efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); -extern bool efx_port_dummy_op_poll(struct efx_nic *efx); + /* MTD */ #ifdef CONFIG_SFC_MTD @@ -102,8 +116,6 @@ static inline void efx_mtd_rename(struct efx_nic *efx) {} static inline void efx_mtd_remove(struct efx_nic *efx) {} #endif -extern unsigned int efx_monitor_interval; - static inline void efx_schedule_channel(struct efx_channel *channel) { netif_vdbg(channel->efx, intr, channel->efx->net_dev, diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index fd19d6ab97a..edb9d16b8b4 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -15,6 +15,7 @@ #include "workarounds.h" #include "selftest.h" #include "efx.h" +#include "filter.h" #include "nic.h" #include "spi.h" #include "mdio_10g.h" @@ -186,8 +187,8 @@ static int efx_ethtool_phys_id(struct net_device *net_dev, u32 count) } /* This must be called with rtnl_lock held. */ -int efx_ethtool_get_settings(struct net_device *net_dev, - struct ethtool_cmd *ecmd) +static int efx_ethtool_get_settings(struct net_device *net_dev, + struct ethtool_cmd *ecmd) { struct efx_nic *efx = netdev_priv(net_dev); struct efx_link_state *link_state = &efx->link_state; @@ -210,8 +211,8 @@ int efx_ethtool_get_settings(struct net_device *net_dev, } /* This must be called with rtnl_lock held. */ -int efx_ethtool_set_settings(struct net_device *net_dev, - struct ethtool_cmd *ecmd) +static int efx_ethtool_set_settings(struct net_device *net_dev, + struct ethtool_cmd *ecmd) { struct efx_nic *efx = netdev_priv(net_dev); int rc; @@ -328,9 +329,10 @@ static int efx_fill_loopback_test(struct efx_nic *efx, unsigned int test_index, struct ethtool_string *strings, u64 *data) { + struct efx_channel *channel = efx_get_channel(efx, 0); struct efx_tx_queue *tx_queue; - efx_for_each_channel_tx_queue(tx_queue, &efx->channel[0]) { + efx_for_each_channel_tx_queue(tx_queue, channel) { efx_fill_test(test_index++, strings, data, &lb_tests->tx_sent[tx_queue->queue], EFX_TX_QUEUE_NAME(tx_queue), @@ -550,9 +552,22 @@ static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev) static int efx_ethtool_set_flags(struct net_device *net_dev, u32 data) { struct efx_nic *efx = netdev_priv(net_dev); - u32 supported = efx->type->offload_features & ETH_FLAG_RXHASH; + u32 supported = (efx->type->offload_features & + (ETH_FLAG_RXHASH | ETH_FLAG_NTUPLE)); + int rc; + + rc = ethtool_op_set_flags(net_dev, data, supported); + if (rc) + return rc; - return ethtool_op_set_flags(net_dev, data, supported); + if (!(data & ETH_FLAG_NTUPLE)) { + efx_filter_table_clear(efx, EFX_FILTER_TABLE_RX_IP, + EFX_FILTER_PRI_MANUAL); + efx_filter_table_clear(efx, EFX_FILTER_TABLE_RX_MAC, + EFX_FILTER_PRI_MANUAL); + } + + return 0; } static void efx_ethtool_self_test(struct net_device *net_dev, @@ -673,15 +688,15 @@ static int efx_ethtool_get_coalesce(struct net_device *net_dev, struct ethtool_coalesce *coalesce) { struct efx_nic *efx = netdev_priv(net_dev); - struct efx_tx_queue *tx_queue; struct efx_channel *channel; memset(coalesce, 0, sizeof(*coalesce)); /* Find lowest IRQ moderation across all used TX queues */ coalesce->tx_coalesce_usecs_irq = ~((u32) 0); - efx_for_each_tx_queue(tx_queue, efx) { - channel = tx_queue->channel; + efx_for_each_channel(channel, efx) { + if (!efx_channel_get_tx_queue(channel, 0)) + continue; if (channel->irq_moderation < coalesce->tx_coalesce_usecs_irq) { if (channel->channel < efx->n_rx_channels) coalesce->tx_coalesce_usecs_irq = @@ -708,7 +723,6 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev, { struct efx_nic *efx = netdev_priv(net_dev); struct efx_channel *channel; - struct efx_tx_queue *tx_queue; unsigned tx_usecs, rx_usecs, adaptive; if (coalesce->use_adaptive_tx_coalesce) @@ -725,8 +739,9 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev, adaptive = coalesce->use_adaptive_rx_coalesce; /* If the channel is shared only allow RX parameters to be set */ - efx_for_each_tx_queue(tx_queue, efx) { - if ((tx_queue->channel->channel < efx->n_rx_channels) && + efx_for_each_channel(channel, efx) { + if (efx_channel_get_rx_queue(channel) && + efx_channel_get_tx_queue(channel, 0) && tx_usecs) { netif_err(efx, drv, efx->net_dev, "Channel is shared. " "Only RX coalescing may be set\n"); @@ -741,6 +756,42 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev, return 0; } +static void efx_ethtool_get_ringparam(struct net_device *net_dev, + struct ethtool_ringparam *ring) +{ + struct efx_nic *efx = netdev_priv(net_dev); + + ring->rx_max_pending = EFX_MAX_DMAQ_SIZE; + ring->tx_max_pending = EFX_MAX_DMAQ_SIZE; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = efx->rxq_entries; + ring->tx_pending = efx->txq_entries; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; +} + +static int efx_ethtool_set_ringparam(struct net_device *net_dev, + struct ethtool_ringparam *ring) +{ + struct efx_nic *efx = netdev_priv(net_dev); + + if (ring->rx_mini_pending || ring->rx_jumbo_pending || + ring->rx_pending > EFX_MAX_DMAQ_SIZE || + ring->tx_pending > EFX_MAX_DMAQ_SIZE) + return -EINVAL; + + if (ring->rx_pending < EFX_MIN_RING_SIZE || + ring->tx_pending < EFX_MIN_RING_SIZE) { + netif_err(efx, drv, efx->net_dev, + "TX and RX queues cannot be smaller than %ld\n", + EFX_MIN_RING_SIZE); + return -EINVAL; + } + + return efx_realloc_channels(efx, ring->rx_pending, ring->tx_pending); +} + static int efx_ethtool_set_pauseparam(struct net_device *net_dev, struct ethtool_pauseparam *pause) { @@ -840,7 +891,7 @@ static int efx_ethtool_set_wol(struct net_device *net_dev, return efx->type->set_wol(efx, wol->wolopts); } -extern int efx_ethtool_reset(struct net_device *net_dev, u32 *flags) +static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags) { struct efx_nic *efx = netdev_priv(net_dev); enum reset_type method; @@ -918,6 +969,105 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev, } } +static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev, + struct ethtool_rx_ntuple *ntuple) +{ + struct efx_nic *efx = netdev_priv(net_dev); + struct ethtool_tcpip4_spec *ip_entry = &ntuple->fs.h_u.tcp_ip4_spec; + struct ethtool_tcpip4_spec *ip_mask = &ntuple->fs.m_u.tcp_ip4_spec; + struct ethhdr *mac_entry = &ntuple->fs.h_u.ether_spec; + struct ethhdr *mac_mask = &ntuple->fs.m_u.ether_spec; + struct efx_filter_spec filter; + + /* Range-check action */ + if (ntuple->fs.action < ETHTOOL_RXNTUPLE_ACTION_CLEAR || + ntuple->fs.action >= (s32)efx->n_rx_channels) + return -EINVAL; + + if (~ntuple->fs.data_mask) + return -EINVAL; + + switch (ntuple->fs.flow_type) { + case TCP_V4_FLOW: + case UDP_V4_FLOW: + /* Must match all of destination, */ + if (ip_mask->ip4dst | ip_mask->pdst) + return -EINVAL; + /* all or none of source, */ + if ((ip_mask->ip4src | ip_mask->psrc) && + ((__force u32)~ip_mask->ip4src | + (__force u16)~ip_mask->psrc)) + return -EINVAL; + /* and nothing else */ + if ((u8)~ip_mask->tos | (u16)~ntuple->fs.vlan_tag_mask) + return -EINVAL; + break; + case ETHER_FLOW: + /* Must match all of destination, */ + if (!is_zero_ether_addr(mac_mask->h_dest)) + return -EINVAL; + /* all or none of VID, */ + if (ntuple->fs.vlan_tag_mask != 0xf000 && + ntuple->fs.vlan_tag_mask != 0xffff) + return -EINVAL; + /* and nothing else */ + if (!is_broadcast_ether_addr(mac_mask->h_source) || + mac_mask->h_proto != htons(0xffff)) + return -EINVAL; + break; + default: + return -EINVAL; + } + + filter.priority = EFX_FILTER_PRI_MANUAL; + filter.flags = 0; + + switch (ntuple->fs.flow_type) { + case TCP_V4_FLOW: + if (!ip_mask->ip4src) + efx_filter_set_rx_tcp_full(&filter, + htonl(ip_entry->ip4src), + htons(ip_entry->psrc), + htonl(ip_entry->ip4dst), + htons(ip_entry->pdst)); + else + efx_filter_set_rx_tcp_wild(&filter, + htonl(ip_entry->ip4dst), + htons(ip_entry->pdst)); + break; + case UDP_V4_FLOW: + if (!ip_mask->ip4src) + efx_filter_set_rx_udp_full(&filter, + htonl(ip_entry->ip4src), + htons(ip_entry->psrc), + htonl(ip_entry->ip4dst), + htons(ip_entry->pdst)); + else + efx_filter_set_rx_udp_wild(&filter, + htonl(ip_entry->ip4dst), + htons(ip_entry->pdst)); + break; + case ETHER_FLOW: + if (ntuple->fs.vlan_tag_mask == 0xf000) + efx_filter_set_rx_mac_full(&filter, + ntuple->fs.vlan_tag & 0xfff, + mac_entry->h_dest); + else + efx_filter_set_rx_mac_wild(&filter, mac_entry->h_dest); + break; + } + + if (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_CLEAR) { + return efx_filter_remove_filter(efx, &filter); + } else { + if (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP) + filter.dmaq_id = 0xfff; + else + filter.dmaq_id = ntuple->fs.action; + return efx_filter_insert_filter(efx, &filter, true); + } +} + static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, struct ethtool_rxfh_indir *indir) { @@ -971,6 +1121,8 @@ const struct ethtool_ops efx_ethtool_ops = { .set_eeprom = efx_ethtool_set_eeprom, .get_coalesce = efx_ethtool_get_coalesce, .set_coalesce = efx_ethtool_set_coalesce, + .get_ringparam = efx_ethtool_get_ringparam, + .set_ringparam = efx_ethtool_set_ringparam, .get_pauseparam = efx_ethtool_get_pauseparam, .set_pauseparam = efx_ethtool_set_pauseparam, .get_rx_csum = efx_ethtool_get_rx_csum, @@ -994,6 +1146,7 @@ const struct ethtool_ops efx_ethtool_ops = { .set_wol = efx_ethtool_set_wol, .reset = efx_ethtool_reset, .get_rxnfc = efx_ethtool_get_rxnfc, + .set_rx_ntuple = efx_ethtool_set_rx_ntuple, .get_rxfh_indir = efx_ethtool_get_rxfh_indir, .set_rxfh_indir = efx_ethtool_set_rxfh_indir, }; diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 4f9d33f3cca..267019bb2b1 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -159,7 +159,6 @@ irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) { struct efx_nic *efx = dev_id; efx_oword_t *int_ker = efx->irq_status.addr; - struct efx_channel *channel; int syserr; int queues; @@ -194,15 +193,10 @@ irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) wmb(); /* Ensure the vector is cleared before interrupt ack */ falcon_irq_ack_a1(efx); - /* Schedule processing of any interrupting queues */ - channel = &efx->channel[0]; - while (queues) { - if (queues & 0x01) - efx_schedule_channel(channel); - channel++; - queues >>= 1; - } - + if (queues & 1) + efx_schedule_channel(efx_get_channel(efx, 0)); + if (queues & 2) + efx_schedule_channel(efx_get_channel(efx, 1)); return IRQ_HANDLED; } /************************************************************************** @@ -452,30 +446,19 @@ static void falcon_reset_macs(struct efx_nic *efx) /* It's not safe to use GLB_CTL_REG to reset the * macs, so instead use the internal MAC resets */ - if (!EFX_IS10G(efx)) { - EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_SW_RST, 1); - efx_writeo(efx, ®, FR_AB_GM_CFG1); - udelay(1000); - - EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_SW_RST, 0); - efx_writeo(efx, ®, FR_AB_GM_CFG1); - udelay(1000); - return; - } else { - EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_CORE_RST, 1); - efx_writeo(efx, ®, FR_AB_XM_GLB_CFG); - - for (count = 0; count < 10000; count++) { - efx_reado(efx, ®, FR_AB_XM_GLB_CFG); - if (EFX_OWORD_FIELD(reg, FRF_AB_XM_CORE_RST) == - 0) - return; - udelay(10); - } - - netif_err(efx, hw, efx->net_dev, - "timed out waiting for XMAC core reset\n"); + EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_CORE_RST, 1); + efx_writeo(efx, ®, FR_AB_XM_GLB_CFG); + + for (count = 0; count < 10000; count++) { + efx_reado(efx, ®, FR_AB_XM_GLB_CFG); + if (EFX_OWORD_FIELD(reg, FRF_AB_XM_CORE_RST) == + 0) + return; + udelay(10); } + + netif_err(efx, hw, efx->net_dev, + "timed out waiting for XMAC core reset\n"); } /* Mac stats will fail whist the TX fifo is draining */ @@ -514,7 +497,6 @@ static void falcon_reset_macs(struct efx_nic *efx) * are re-enabled by the caller */ efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL); - /* This can run even when the GMAC is selected */ falcon_setup_xaui(efx); } @@ -652,8 +634,6 @@ static void falcon_stats_timer_func(unsigned long context) spin_unlock(&efx->stats_lock); } -static void falcon_switch_mac(struct efx_nic *efx); - static bool falcon_loopback_link_poll(struct efx_nic *efx) { struct efx_link_state old_state = efx->link_state; @@ -664,11 +644,7 @@ static bool falcon_loopback_link_poll(struct efx_nic *efx) efx->link_state.fd = true; efx->link_state.fc = efx->wanted_fc; efx->link_state.up = true; - - if (efx->loopback_mode == LOOPBACK_GMAC) - efx->link_state.speed = 1000; - else - efx->link_state.speed = 10000; + efx->link_state.speed = 10000; return !efx_link_state_equal(&efx->link_state, &old_state); } @@ -691,7 +667,7 @@ static int falcon_reconfigure_port(struct efx_nic *efx) falcon_stop_nic_stats(efx); falcon_deconfigure_mac_wrapper(efx); - falcon_switch_mac(efx); + falcon_reset_macs(efx); efx->phy_op->reconfigure(efx); rc = efx->mac_op->reconfigure(efx); @@ -841,73 +817,23 @@ out: return rc; } -static void falcon_clock_mac(struct efx_nic *efx) -{ - unsigned strap_val; - efx_oword_t nic_stat; - - /* Configure the NIC generated MAC clock correctly */ - efx_reado(efx, &nic_stat, FR_AB_NIC_STAT); - strap_val = EFX_IS10G(efx) ? 5 : 3; - if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { - EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP_EN, 1); - EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP, strap_val); - efx_writeo(efx, &nic_stat, FR_AB_NIC_STAT); - } else { - /* Falcon A1 does not support 1G/10G speed switching - * and must not be used with a PHY that does. */ - BUG_ON(EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_PINS) != - strap_val); - } -} - -static void falcon_switch_mac(struct efx_nic *efx) -{ - struct efx_mac_operations *old_mac_op = efx->mac_op; - struct falcon_nic_data *nic_data = efx->nic_data; - unsigned int stats_done_offset; - - WARN_ON(!mutex_is_locked(&efx->mac_lock)); - WARN_ON(nic_data->stats_disable_count == 0); - - efx->mac_op = (EFX_IS10G(efx) ? - &falcon_xmac_operations : &falcon_gmac_operations); - - if (EFX_IS10G(efx)) - stats_done_offset = XgDmaDone_offset; - else - stats_done_offset = GDmaDone_offset; - nic_data->stats_dma_done = efx->stats_buffer.addr + stats_done_offset; - - if (old_mac_op == efx->mac_op) - return; - - falcon_clock_mac(efx); - - netif_dbg(efx, hw, efx->net_dev, "selected %cMAC\n", - EFX_IS10G(efx) ? 'X' : 'G'); - /* Not all macs support a mac-level link state */ - efx->xmac_poll_required = false; - falcon_reset_macs(efx); -} - /* This call is responsible for hooking in the MAC and PHY operations */ static int falcon_probe_port(struct efx_nic *efx) { + struct falcon_nic_data *nic_data = efx->nic_data; int rc; switch (efx->phy_type) { case PHY_TYPE_SFX7101: efx->phy_op = &falcon_sfx7101_phy_ops; break; - case PHY_TYPE_SFT9001A: - case PHY_TYPE_SFT9001B: - efx->phy_op = &falcon_sft9001_phy_ops; - break; case PHY_TYPE_QT2022C2: case PHY_TYPE_QT2025C: efx->phy_op = &falcon_qt202x_phy_ops; break; + case PHY_TYPE_TXC43128: + efx->phy_op = &falcon_txc_phy_ops; + break; default: netif_err(efx, probe, efx->net_dev, "Unknown PHY type %d\n", efx->phy_type); @@ -943,6 +869,7 @@ static int falcon_probe_port(struct efx_nic *efx) (u64)efx->stats_buffer.dma_addr, efx->stats_buffer.addr, (u64)virt_to_phys(efx->stats_buffer.addr)); + nic_data->stats_dma_done = efx->stats_buffer.addr + XgDmaDone_offset; return 0; } @@ -1207,7 +1134,7 @@ static void falcon_monitor(struct efx_nic *efx) falcon_stop_nic_stats(efx); falcon_deconfigure_mac_wrapper(efx); - falcon_switch_mac(efx); + falcon_reset_macs(efx); rc = efx->mac_op->reconfigure(efx); BUG_ON(rc); @@ -1216,8 +1143,7 @@ static void falcon_monitor(struct efx_nic *efx) efx_link_status_changed(efx); } - if (EFX_IS10G(efx)) - falcon_poll_xmac(efx); + falcon_poll_xmac(efx); } /* Zeroes out the SRAM contents. This routine must be called in @@ -1610,16 +1536,6 @@ static int falcon_init_nic(struct efx_nic *efx) EFX_SET_OWORD_FIELD(temp, FRF_AB_ONCHIP_SRAM, 1); efx_writeo(efx, &temp, FR_AB_NIC_STAT); - /* Set the source of the GMAC clock */ - if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) { - efx_reado(efx, &temp, FR_AB_GPIO_CTL); - EFX_SET_OWORD_FIELD(temp, FRF_AB_USE_NIC_CLK, true); - efx_writeo(efx, &temp, FR_AB_GPIO_CTL); - } - - /* Select the correct MAC */ - falcon_clock_mac(efx); - rc = falcon_reset_sram(efx); if (rc) return rc; @@ -1880,7 +1796,7 @@ struct efx_nic_type falcon_b0_nic_type = { * channels */ .tx_dc_base = 0x130000, .rx_dc_base = 0x100000, - .offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH, + .offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH | NETIF_F_NTUPLE, .reset_world_flags = ETH_RESET_IRQ, }; diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c index 3d950c2cf20..cfc6a5b5a47 100644 --- a/drivers/net/sfc/falcon_boards.c +++ b/drivers/net/sfc/falcon_boards.c @@ -26,7 +26,7 @@ /* Board types */ #define FALCON_BOARD_SFE4001 0x01 #define FALCON_BOARD_SFE4002 0x02 -#define FALCON_BOARD_SFN4111T 0x51 +#define FALCON_BOARD_SFE4003 0x03 #define FALCON_BOARD_SFN4112F 0x52 /* Board temperature is about 15°C above ambient when air flow is @@ -142,17 +142,17 @@ static inline int efx_check_lm87(struct efx_nic *efx, unsigned mask) #endif /* CONFIG_SENSORS_LM87 */ /***************************************************************************** - * Support for the SFE4001 and SFN4111T NICs. + * Support for the SFE4001 NIC. * * The SFE4001 does not power-up fully at reset due to its high power * consumption. We control its power via a PCA9539 I/O expander. - * Both boards have a MAX6647 temperature monitor which we expose to + * It also has a MAX6647 temperature monitor which we expose to * the lm90 driver. * * This also provides minimal support for reflashing the PHY, which is * initiated by resetting it with the FLASH_CFG_1 pin pulled down. * On SFE4001 rev A2 and later this is connected to the 3V3X output of - * the IO-expander; on the SFN4111T it is connected to Falcon's GPIO3. + * the IO-expander. * We represent reflash mode as PHY_MODE_SPECIAL and make it mutually * exclusive with the network device being open. */ @@ -304,34 +304,6 @@ fail_on: return rc; } -static int sfn4111t_reset(struct efx_nic *efx) -{ - struct falcon_board *board = falcon_board(efx); - efx_oword_t reg; - - /* GPIO 3 and the GPIO register are shared with I2C, so block that */ - i2c_lock_adapter(&board->i2c_adap); - - /* Pull RST_N (GPIO 2) low then let it up again, setting the - * FLASH_CFG_1 strap (GPIO 3) appropriately. Only change the - * output enables; the output levels should always be 0 (low) - * and we rely on external pull-ups. */ - efx_reado(efx, ®, FR_AB_GPIO_CTL); - EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO2_OEN, true); - efx_writeo(efx, ®, FR_AB_GPIO_CTL); - msleep(1000); - EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO2_OEN, false); - EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO3_OEN, - !!(efx->phy_mode & PHY_MODE_SPECIAL)); - efx_writeo(efx, ®, FR_AB_GPIO_CTL); - msleep(1); - - i2c_unlock_adapter(&board->i2c_adap); - - ssleep(1); - return 0; -} - static ssize_t show_phy_flash_cfg(struct device *dev, struct device_attribute *attr, char *buf) { @@ -363,10 +335,7 @@ static ssize_t set_phy_flash_cfg(struct device *dev, efx->phy_mode = new_mode; if (new_mode & PHY_MODE_SPECIAL) falcon_stop_nic_stats(efx); - if (falcon_board(efx)->type->id == FALCON_BOARD_SFE4001) - err = sfe4001_poweron(efx); - else - err = sfn4111t_reset(efx); + err = sfe4001_poweron(efx); if (!err) err = efx_reconfigure_port(efx); if (!(new_mode & PHY_MODE_SPECIAL)) @@ -479,83 +448,6 @@ fail_hwmon: return rc; } -static int sfn4111t_check_hw(struct efx_nic *efx) -{ - s32 status; - - /* If XAUI link is up then do not monitor */ - if (EFX_WORKAROUND_7884(efx) && !efx->xmac_poll_required) - return 0; - - /* Test LHIGH, RHIGH, FAULT, EOT and IOT alarms */ - status = i2c_smbus_read_byte_data(falcon_board(efx)->hwmon_client, - MAX664X_REG_RSL); - if (status < 0) - return -EIO; - if (status & 0x57) - return -ERANGE; - return 0; -} - -static void sfn4111t_fini(struct efx_nic *efx) -{ - netif_info(efx, drv, efx->net_dev, "%s\n", __func__); - - device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); - i2c_unregister_device(falcon_board(efx)->hwmon_client); -} - -static struct i2c_board_info sfn4111t_a0_hwmon_info = { - I2C_BOARD_INFO("max6647", 0x4e), -}; - -static struct i2c_board_info sfn4111t_r5_hwmon_info = { - I2C_BOARD_INFO("max6646", 0x4d), -}; - -static void sfn4111t_init_phy(struct efx_nic *efx) -{ - if (!(efx->phy_mode & PHY_MODE_SPECIAL)) { - if (sft9001_wait_boot(efx) != -EINVAL) - return; - - efx->phy_mode = PHY_MODE_SPECIAL; - falcon_stop_nic_stats(efx); - } - - sfn4111t_reset(efx); - sft9001_wait_boot(efx); -} - -static int sfn4111t_init(struct efx_nic *efx) -{ - struct falcon_board *board = falcon_board(efx); - int rc; - - board->hwmon_client = - i2c_new_device(&board->i2c_adap, - (board->minor < 5) ? - &sfn4111t_a0_hwmon_info : - &sfn4111t_r5_hwmon_info); - if (!board->hwmon_client) - return -EIO; - - rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); - if (rc) - goto fail_hwmon; - - if (efx->phy_mode & PHY_MODE_SPECIAL) - /* PHY may not generate a 156.25 MHz clock and MAC - * stats fetch will fail. */ - falcon_stop_nic_stats(efx); - - return 0; - -fail_hwmon: - i2c_unregister_device(board->hwmon_client); - return rc; -} - /***************************************************************************** * Support for the SFE4002 * @@ -691,6 +583,75 @@ static int sfn4112f_init(struct efx_nic *efx) return efx_init_lm87(efx, &sfn4112f_hwmon_info, sfn4112f_lm87_regs); } +/***************************************************************************** + * Support for the SFE4003 + * + */ +static u8 sfe4003_lm87_channel = 0x03; /* use AIN not FAN inputs */ + +static const u8 sfe4003_lm87_regs[] = { + LM87_IN_LIMITS(0, 0x67, 0x7f), /* 2.5V: 1.5V +/- 10% */ + LM87_IN_LIMITS(1, 0x4c, 0x5e), /* Vccp1: 1.2V +/- 10% */ + LM87_IN_LIMITS(2, 0xac, 0xd4), /* 3.3V: 3.3V +/- 10% */ + LM87_IN_LIMITS(4, 0xac, 0xe0), /* 12V: 10.8-14V */ + LM87_IN_LIMITS(5, 0x3f, 0x4f), /* Vccp2: 1.0V +/- 10% */ + LM87_TEMP_INT_LIMITS(0, 70 + FALCON_BOARD_TEMP_BIAS), + 0 +}; + +static struct i2c_board_info sfe4003_hwmon_info = { + I2C_BOARD_INFO("lm87", 0x2e), + .platform_data = &sfe4003_lm87_channel, +}; + +/* Board-specific LED info. */ +#define SFE4003_RED_LED_GPIO 11 +#define SFE4003_LED_ON 1 +#define SFE4003_LED_OFF 0 + +static void sfe4003_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) +{ + struct falcon_board *board = falcon_board(efx); + + /* The LEDs were not wired to GPIOs before A3 */ + if (board->minor < 3 && board->major == 0) + return; + + falcon_txc_set_gpio_val( + efx, SFE4003_RED_LED_GPIO, + (mode == EFX_LED_ON) ? SFE4003_LED_ON : SFE4003_LED_OFF); +} + +static void sfe4003_init_phy(struct efx_nic *efx) +{ + struct falcon_board *board = falcon_board(efx); + + /* The LEDs were not wired to GPIOs before A3 */ + if (board->minor < 3 && board->major == 0) + return; + + falcon_txc_set_gpio_dir(efx, SFE4003_RED_LED_GPIO, TXC_GPIO_DIR_OUTPUT); + falcon_txc_set_gpio_val(efx, SFE4003_RED_LED_GPIO, SFE4003_LED_OFF); +} + +static int sfe4003_check_hw(struct efx_nic *efx) +{ + struct falcon_board *board = falcon_board(efx); + + /* A0/A1/A2 board rev. 4003s report a temperature fault the whole time + * (bad sensor) so we mask it out. */ + unsigned alarm_mask = + (board->major == 0 && board->minor <= 2) ? + ~LM87_ALARM_TEMP_EXT1 : ~0; + + return efx_check_lm87(efx, alarm_mask); +} + +static int sfe4003_init(struct efx_nic *efx) +{ + return efx_init_lm87(efx, &sfe4003_hwmon_info, sfe4003_lm87_regs); +} + static const struct falcon_board_type board_types[] = { { .id = FALCON_BOARD_SFE4001, @@ -713,14 +674,14 @@ static const struct falcon_board_type board_types[] = { .monitor = sfe4002_check_hw, }, { - .id = FALCON_BOARD_SFN4111T, - .ref_model = "SFN4111T", - .gen_type = "100/1000/10GBASE-T adapter", - .init = sfn4111t_init, - .init_phy = sfn4111t_init_phy, - .fini = sfn4111t_fini, - .set_id_led = tenxpress_set_id_led, - .monitor = sfn4111t_check_hw, + .id = FALCON_BOARD_SFE4003, + .ref_model = "SFE4003", + .gen_type = "10GBASE-CX4 adapter", + .init = sfe4003_init, + .init_phy = sfe4003_init_phy, + .fini = efx_fini_lm87, + .set_id_led = sfe4003_set_id_led, + .monitor = sfe4003_check_hw, }, { .id = FALCON_BOARD_SFN4112F, diff --git a/drivers/net/sfc/falcon_gmac.c b/drivers/net/sfc/falcon_gmac.c deleted file mode 100644 index 7dadfcbd6ce..00000000000 --- a/drivers/net/sfc/falcon_gmac.c +++ /dev/null @@ -1,230 +0,0 @@ -/**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2009 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 - * by the Free Software Foundation, incorporated herein by reference. - */ - -#include <linux/delay.h> -#include "net_driver.h" -#include "efx.h" -#include "nic.h" -#include "mac.h" -#include "regs.h" -#include "io.h" - -/************************************************************************** - * - * MAC operations - * - *************************************************************************/ - -static int falcon_reconfigure_gmac(struct efx_nic *efx) -{ - struct efx_link_state *link_state = &efx->link_state; - bool loopback, tx_fc, rx_fc, bytemode; - int if_mode; - unsigned int max_frame_len; - efx_oword_t reg; - - /* Configuration register 1 */ - tx_fc = (link_state->fc & EFX_FC_TX) || !link_state->fd; - rx_fc = !!(link_state->fc & EFX_FC_RX); - loopback = (efx->loopback_mode == LOOPBACK_GMAC); - bytemode = (link_state->speed == 1000); - - EFX_POPULATE_OWORD_5(reg, - FRF_AB_GM_LOOP, loopback, - FRF_AB_GM_TX_EN, 1, - FRF_AB_GM_TX_FC_EN, tx_fc, - FRF_AB_GM_RX_EN, 1, - FRF_AB_GM_RX_FC_EN, rx_fc); - efx_writeo(efx, ®, FR_AB_GM_CFG1); - udelay(10); - - /* Configuration register 2 */ - if_mode = (bytemode) ? 2 : 1; - EFX_POPULATE_OWORD_5(reg, - FRF_AB_GM_IF_MODE, if_mode, - FRF_AB_GM_PAD_CRC_EN, 1, - FRF_AB_GM_LEN_CHK, 1, - FRF_AB_GM_FD, link_state->fd, - FRF_AB_GM_PAMBL_LEN, 0x7/*datasheet recommended */); - - efx_writeo(efx, ®, FR_AB_GM_CFG2); - udelay(10); - - /* Max frame len register */ - max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu); - EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_MAX_FLEN, max_frame_len); - efx_writeo(efx, ®, FR_AB_GM_MAX_FLEN); - udelay(10); - - /* FIFO configuration register 0 */ - EFX_POPULATE_OWORD_5(reg, - FRF_AB_GMF_FTFENREQ, 1, - FRF_AB_GMF_STFENREQ, 1, - FRF_AB_GMF_FRFENREQ, 1, - FRF_AB_GMF_SRFENREQ, 1, - FRF_AB_GMF_WTMENREQ, 1); - efx_writeo(efx, ®, FR_AB_GMF_CFG0); - udelay(10); - - /* FIFO configuration register 1 */ - EFX_POPULATE_OWORD_2(reg, - FRF_AB_GMF_CFGFRTH, 0x12, - FRF_AB_GMF_CFGXOFFRTX, 0xffff); - efx_writeo(efx, ®, FR_AB_GMF_CFG1); - udelay(10); - - /* FIFO configuration register 2 */ - EFX_POPULATE_OWORD_2(reg, - FRF_AB_GMF_CFGHWM, 0x3f, - FRF_AB_GMF_CFGLWM, 0xa); - efx_writeo(efx, ®, FR_AB_GMF_CFG2); - udelay(10); - - /* FIFO configuration register 3 */ - EFX_POPULATE_OWORD_2(reg, - FRF_AB_GMF_CFGHWMFT, 0x1c, - FRF_AB_GMF_CFGFTTH, 0x08); - efx_writeo(efx, ®, FR_AB_GMF_CFG3); - udelay(10); - - /* FIFO configuration register 4 */ - EFX_POPULATE_OWORD_1(reg, FRF_AB_GMF_HSTFLTRFRM_PAUSE, 1); - efx_writeo(efx, ®, FR_AB_GMF_CFG4); - udelay(10); - - /* FIFO configuration register 5 */ - efx_reado(efx, ®, FR_AB_GMF_CFG5); - EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_CFGBYTMODE, bytemode); - EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_CFGHDPLX, !link_state->fd); - EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_HSTDRPLT64, !link_state->fd); - EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_HSTFLTRFRMDC_PAUSE, 0); - efx_writeo(efx, ®, FR_AB_GMF_CFG5); - udelay(10); - - /* MAC address */ - EFX_POPULATE_OWORD_4(reg, - FRF_AB_GM_ADR_B0, efx->net_dev->dev_addr[5], - FRF_AB_GM_ADR_B1, efx->net_dev->dev_addr[4], - FRF_AB_GM_ADR_B2, efx->net_dev->dev_addr[3], - FRF_AB_GM_ADR_B3, efx->net_dev->dev_addr[2]); - efx_writeo(efx, ®, FR_AB_GM_ADR1); - udelay(10); - EFX_POPULATE_OWORD_2(reg, - FRF_AB_GM_ADR_B4, efx->net_dev->dev_addr[1], - FRF_AB_GM_ADR_B5, efx->net_dev->dev_addr[0]); - efx_writeo(efx, ®, FR_AB_GM_ADR2); - udelay(10); - - falcon_reconfigure_mac_wrapper(efx); - - return 0; -} - -static void falcon_update_stats_gmac(struct efx_nic *efx) -{ - struct efx_mac_stats *mac_stats = &efx->mac_stats; - unsigned long old_rx_pause, old_tx_pause; - unsigned long new_rx_pause, new_tx_pause; - - /* Pause frames are erroneously counted as errors (SFC bug 3269) */ - old_rx_pause = mac_stats->rx_pause; - old_tx_pause = mac_stats->tx_pause; - - /* Update MAC stats from DMAed values */ - FALCON_STAT(efx, GRxGoodOct, rx_good_bytes); - FALCON_STAT(efx, GRxBadOct, rx_bad_bytes); - FALCON_STAT(efx, GRxMissPkt, rx_missed); - FALCON_STAT(efx, GRxFalseCRS, rx_false_carrier); - FALCON_STAT(efx, GRxPausePkt, rx_pause); - FALCON_STAT(efx, GRxBadPkt, rx_bad); - FALCON_STAT(efx, GRxUcastPkt, rx_unicast); - FALCON_STAT(efx, GRxMcastPkt, rx_multicast); - FALCON_STAT(efx, GRxBcastPkt, rx_broadcast); - FALCON_STAT(efx, GRxGoodLt64Pkt, rx_good_lt64); - FALCON_STAT(efx, GRxBadLt64Pkt, rx_bad_lt64); - FALCON_STAT(efx, GRx64Pkt, rx_64); - FALCON_STAT(efx, GRx65to127Pkt, rx_65_to_127); - FALCON_STAT(efx, GRx128to255Pkt, rx_128_to_255); - FALCON_STAT(efx, GRx256to511Pkt, rx_256_to_511); - FALCON_STAT(efx, GRx512to1023Pkt, rx_512_to_1023); - FALCON_STAT(efx, GRx1024to15xxPkt, rx_1024_to_15xx); - FALCON_STAT(efx, GRx15xxtoJumboPkt, rx_15xx_to_jumbo); - FALCON_STAT(efx, GRxGtJumboPkt, rx_gtjumbo); - FALCON_STAT(efx, GRxFcsErr64to15xxPkt, rx_bad_64_to_15xx); - FALCON_STAT(efx, GRxFcsErr15xxtoJumboPkt, rx_bad_15xx_to_jumbo); - FALCON_STAT(efx, GRxFcsErrGtJumboPkt, rx_bad_gtjumbo); - FALCON_STAT(efx, GTxGoodBadOct, tx_bytes); - FALCON_STAT(efx, GTxGoodOct, tx_good_bytes); - FALCON_STAT(efx, GTxSglColPkt, tx_single_collision); - FALCON_STAT(efx, GTxMultColPkt, tx_multiple_collision); - FALCON_STAT(efx, GTxExColPkt, tx_excessive_collision); - FALCON_STAT(efx, GTxDefPkt, tx_deferred); - FALCON_STAT(efx, GTxLateCol, tx_late_collision); - FALCON_STAT(efx, GTxExDefPkt, tx_excessive_deferred); - FALCON_STAT(efx, GTxPausePkt, tx_pause); - FALCON_STAT(efx, GTxBadPkt, tx_bad); - FALCON_STAT(efx, GTxUcastPkt, tx_unicast); - FALCON_STAT(efx, GTxMcastPkt, tx_multicast); - FALCON_STAT(efx, GTxBcastPkt, tx_broadcast); - FALCON_STAT(efx, GTxLt64Pkt, tx_lt64); - FALCON_STAT(efx, GTx64Pkt, tx_64); - FALCON_STAT(efx, GTx65to127Pkt, tx_65_to_127); - FALCON_STAT(efx, GTx128to255Pkt, tx_128_to_255); - FALCON_STAT(efx, GTx256to511Pkt, tx_256_to_511); - FALCON_STAT(efx, GTx512to1023Pkt, tx_512_to_1023); - FALCON_STAT(efx, GTx1024to15xxPkt, tx_1024_to_15xx); - FALCON_STAT(efx, GTx15xxtoJumboPkt, tx_15xx_to_jumbo); - FALCON_STAT(efx, GTxGtJumboPkt, tx_gtjumbo); - FALCON_STAT(efx, GTxNonTcpUdpPkt, tx_non_tcpudp); - FALCON_STAT(efx, GTxMacSrcErrPkt, tx_mac_src_error); - FALCON_STAT(efx, GTxIpSrcErrPkt, tx_ip_src_error); - - /* Pause frames are erroneously counted as errors (SFC bug 3269) */ - new_rx_pause = mac_stats->rx_pause; - new_tx_pause = mac_stats->tx_pause; - mac_stats->rx_bad -= (new_rx_pause - old_rx_pause); - mac_stats->tx_bad -= (new_tx_pause - old_tx_pause); - - /* Derive stats that the MAC doesn't provide directly */ - mac_stats->tx_bad_bytes = - mac_stats->tx_bytes - mac_stats->tx_good_bytes; - mac_stats->tx_packets = - mac_stats->tx_lt64 + mac_stats->tx_64 + - mac_stats->tx_65_to_127 + mac_stats->tx_128_to_255 + - mac_stats->tx_256_to_511 + mac_stats->tx_512_to_1023 + - mac_stats->tx_1024_to_15xx + mac_stats->tx_15xx_to_jumbo + - mac_stats->tx_gtjumbo; - mac_stats->tx_collision = - mac_stats->tx_single_collision + - mac_stats->tx_multiple_collision + - mac_stats->tx_excessive_collision + - mac_stats->tx_late_collision; - mac_stats->rx_bytes = - mac_stats->rx_good_bytes + mac_stats->rx_bad_bytes; - mac_stats->rx_packets = - mac_stats->rx_good_lt64 + mac_stats->rx_bad_lt64 + - mac_stats->rx_64 + mac_stats->rx_65_to_127 + - mac_stats->rx_128_to_255 + mac_stats->rx_256_to_511 + - mac_stats->rx_512_to_1023 + mac_stats->rx_1024_to_15xx + - mac_stats->rx_15xx_to_jumbo + mac_stats->rx_gtjumbo; - mac_stats->rx_good = mac_stats->rx_packets - mac_stats->rx_bad; - mac_stats->rx_lt64 = mac_stats->rx_good_lt64 + mac_stats->rx_bad_lt64; -} - -static bool falcon_gmac_check_fault(struct efx_nic *efx) -{ - return false; -} - -struct efx_mac_operations falcon_gmac_operations = { - .reconfigure = falcon_reconfigure_gmac, - .update_stats = falcon_update_stats_gmac, - .check_fault = falcon_gmac_check_fault, -}; diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index bae656dd2c4..b31f595ebb5 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -143,7 +143,7 @@ static bool falcon_xmac_link_ok(struct efx_nic *efx) efx_mdio_phyxgxs_lane_sync(efx)); } -void falcon_reconfigure_xmac_core(struct efx_nic *efx) +static void falcon_reconfigure_xmac_core(struct efx_nic *efx) { unsigned int max_frame_len; efx_oword_t reg; diff --git a/drivers/net/sfc/filter.c b/drivers/net/sfc/filter.c new file mode 100644 index 00000000000..52cb6082b91 --- /dev/null +++ b/drivers/net/sfc/filter.c @@ -0,0 +1,454 @@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * 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 + * by the Free Software Foundation, incorporated herein by reference. + */ + +#include "efx.h" +#include "filter.h" +#include "io.h" +#include "nic.h" +#include "regs.h" + +/* "Fudge factors" - difference between programmed value and actual depth. + * Due to pipelined implementation we need to program H/W with a value that + * is larger than the hop limit we want. + */ +#define FILTER_CTL_SRCH_FUDGE_WILD 3 +#define FILTER_CTL_SRCH_FUDGE_FULL 1 + +/* Hard maximum hop limit. Hardware will time-out beyond 200-something. + * We also need to avoid infinite loops in efx_filter_search() when the + * table is full. + */ +#define FILTER_CTL_SRCH_MAX 200 + +struct efx_filter_table { + u32 offset; /* address of table relative to BAR */ + unsigned size; /* number of entries */ + unsigned step; /* step between entries */ + unsigned used; /* number currently used */ + unsigned long *used_bitmap; + struct efx_filter_spec *spec; +}; + +struct efx_filter_state { + spinlock_t lock; + struct efx_filter_table table[EFX_FILTER_TABLE_COUNT]; + unsigned search_depth[EFX_FILTER_TYPE_COUNT]; +}; + +/* The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit + * key derived from the n-tuple. The initial LFSR state is 0xffff. */ +static u16 efx_filter_hash(u32 key) +{ + u16 tmp; + + /* First 16 rounds */ + tmp = 0x1fff ^ key >> 16; + tmp = tmp ^ tmp >> 3 ^ tmp >> 6; + tmp = tmp ^ tmp >> 9; + /* Last 16 rounds */ + tmp = tmp ^ tmp << 13 ^ key; + tmp = tmp ^ tmp >> 3 ^ tmp >> 6; + return tmp ^ tmp >> 9; +} + +/* To allow for hash collisions, filter search continues at these + * increments from the first possible entry selected by the hash. */ +static u16 efx_filter_increment(u32 key) +{ + return key * 2 - 1; +} + +static enum efx_filter_table_id +efx_filter_type_table_id(enum efx_filter_type type) +{ + BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_RX_TCP_FULL >> 2)); + BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_RX_TCP_WILD >> 2)); + BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_RX_UDP_FULL >> 2)); + BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_RX_UDP_WILD >> 2)); + BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_RX_MAC_FULL >> 2)); + BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_RX_MAC_WILD >> 2)); + return type >> 2; +} + +static void +efx_filter_table_reset_search_depth(struct efx_filter_state *state, + enum efx_filter_table_id table_id) +{ + memset(state->search_depth + (table_id << 2), 0, + sizeof(state->search_depth[0]) << 2); +} + +static void efx_filter_push_rx_limits(struct efx_nic *efx) +{ + struct efx_filter_state *state = efx->filter_state; + efx_oword_t filter_ctl; + + efx_reado(efx, &filter_ctl, FR_BZ_RX_FILTER_CTL); + + EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_FULL_SRCH_LIMIT, + state->search_depth[EFX_FILTER_RX_TCP_FULL] + + FILTER_CTL_SRCH_FUDGE_FULL); + EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_TCP_WILD_SRCH_LIMIT, + state->search_depth[EFX_FILTER_RX_TCP_WILD] + + FILTER_CTL_SRCH_FUDGE_WILD); + EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_FULL_SRCH_LIMIT, + state->search_depth[EFX_FILTER_RX_UDP_FULL] + + FILTER_CTL_SRCH_FUDGE_FULL); + EFX_SET_OWORD_FIELD(filter_ctl, FRF_BZ_UDP_WILD_SRCH_LIMIT, + state->search_depth[EFX_FILTER_RX_UDP_WILD] + + FILTER_CTL_SRCH_FUDGE_WILD); + + if (state->table[EFX_FILTER_TABLE_RX_MAC].size) { + EFX_SET_OWORD_FIELD( + filter_ctl, FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT, + state->search_depth[EFX_FILTER_RX_MAC_FULL] + + FILTER_CTL_SRCH_FUDGE_FULL); + EFX_SET_OWORD_FIELD( + filter_ctl, FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT, + state->search_depth[EFX_FILTER_RX_MAC_WILD] + + FILTER_CTL_SRCH_FUDGE_WILD); + } + + efx_writeo(efx, &filter_ctl, FR_BZ_RX_FILTER_CTL); +} + +/* Build a filter entry and return its n-tuple key. */ +static u32 efx_filter_build(efx_oword_t *filter, struct efx_filter_spec *spec) +{ + u32 data3; + + switch (efx_filter_type_table_id(spec->type)) { + case EFX_FILTER_TABLE_RX_IP: { + bool is_udp = (spec->type == EFX_FILTER_RX_UDP_FULL || + spec->type == EFX_FILTER_RX_UDP_WILD); + EFX_POPULATE_OWORD_7( + *filter, + FRF_BZ_RSS_EN, + !!(spec->flags & EFX_FILTER_FLAG_RX_RSS), + FRF_BZ_SCATTER_EN, + !!(spec->flags & EFX_FILTER_FLAG_RX_SCATTER), + FRF_BZ_TCP_UDP, is_udp, + FRF_BZ_RXQ_ID, spec->dmaq_id, + EFX_DWORD_2, spec->data[2], + EFX_DWORD_1, spec->data[1], + EFX_DWORD_0, spec->data[0]); + data3 = is_udp; + break; + } + + case EFX_FILTER_TABLE_RX_MAC: { + bool is_wild = spec->type == EFX_FILTER_RX_MAC_WILD; + EFX_POPULATE_OWORD_8( + *filter, + FRF_CZ_RMFT_RSS_EN, + !!(spec->flags & EFX_FILTER_FLAG_RX_RSS), + FRF_CZ_RMFT_SCATTER_EN, + !!(spec->flags & EFX_FILTER_FLAG_RX_SCATTER), + FRF_CZ_RMFT_IP_OVERRIDE, + !!(spec->flags & EFX_FILTER_FLAG_RX_OVERRIDE_IP), + FRF_CZ_RMFT_RXQ_ID, spec->dmaq_id, + FRF_CZ_RMFT_WILDCARD_MATCH, is_wild, + FRF_CZ_RMFT_DEST_MAC_HI, spec->data[2], + FRF_CZ_RMFT_DEST_MAC_LO, spec->data[1], + FRF_CZ_RMFT_VLAN_ID, spec->data[0]); + data3 = is_wild; + break; + } + + default: + BUG(); + } + + return spec->data[0] ^ spec->data[1] ^ spec->data[2] ^ data3; +} + +static bool efx_filter_equal(const struct efx_filter_spec *left, + const struct efx_filter_spec *right) +{ + if (left->type != right->type || + memcmp(left->data, right->data, sizeof(left->data))) + return false; + + return true; +} + +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; + struct efx_filter_spec *cmp; + + hash = efx_filter_hash(key); + incr = efx_filter_increment(key); + + for (depth = 1, filter_idx = hash & (table->size - 1); + depth <= FILTER_CTL_SRCH_MAX && + test_bit(filter_idx, table->used_bitmap); + ++depth) { + cmp = &table->spec[filter_idx]; + if (efx_filter_equal(spec, cmp)) + goto found; + filter_idx = (filter_idx + incr) & (table->size - 1); + } + if (!for_insert) + return -ENOENT; + if (depth > FILTER_CTL_SRCH_MAX) + return -EBUSY; +found: + *depth_required = depth; + return filter_idx; +} + +/** + * efx_filter_insert_filter - add or replace a filter + * @efx: NIC in which to insert the filter + * @spec: Specification for the filter + * @replace: Flag for whether the specified filter may replace a filter + * with an identical match expression and equal or lower priority + * + * On success, return the filter index within its table. + * On failure, return a negative error code. + */ +int efx_filter_insert_filter(struct efx_nic *efx, struct efx_filter_spec *spec, + bool replace) +{ + struct efx_filter_state *state = efx->filter_state; + enum efx_filter_table_id table_id = + efx_filter_type_table_id(spec->type); + struct efx_filter_table *table = &state->table[table_id]; + struct efx_filter_spec *saved_spec; + efx_oword_t filter; + int filter_idx, depth; + u32 key; + int rc; + + if (table->size == 0) + return -EINVAL; + + key = efx_filter_build(&filter, spec); + + netif_vdbg(efx, hw, efx->net_dev, + "%s: type %d search_depth=%d", __func__, spec->type, + state->search_depth[spec->type]); + + spin_lock_bh(&state->lock); + + rc = efx_filter_search(table, spec, key, true, &depth); + if (rc < 0) + goto out; + filter_idx = rc; + BUG_ON(filter_idx >= table->size); + saved_spec = &table->spec[filter_idx]; + + if (test_bit(filter_idx, table->used_bitmap)) { + /* Should we replace the existing filter? */ + if (!replace) { + rc = -EEXIST; + goto out; + } + if (spec->priority < saved_spec->priority) { + rc = -EPERM; + goto out; + } + } else { + __set_bit(filter_idx, table->used_bitmap); + ++table->used; + } + *saved_spec = *spec; + + if (state->search_depth[spec->type] < depth) { + state->search_depth[spec->type] = depth; + efx_filter_push_rx_limits(efx); + } + + efx_writeo(efx, &filter, table->offset + table->step * filter_idx); + + netif_vdbg(efx, hw, efx->net_dev, + "%s: filter type %d index %d rxq %u set", + __func__, spec->type, filter_idx, spec->dmaq_id); + +out: + spin_unlock_bh(&state->lock); + return rc; +} + +static void efx_filter_table_clear_entry(struct efx_nic *efx, + struct efx_filter_table *table, + int filter_idx) +{ + static efx_oword_t filter; + + if (test_bit(filter_idx, table->used_bitmap)) { + __clear_bit(filter_idx, table->used_bitmap); + --table->used; + memset(&table->spec[filter_idx], 0, sizeof(table->spec[0])); + + efx_writeo(efx, &filter, + table->offset + table->step * filter_idx); + } +} + +/** + * efx_filter_remove_filter - remove a filter by specification + * @efx: NIC from which to remove the filter + * @spec: Specification for the filter + * + * On success, return zero. + * On failure, return a negative error code. + */ +int efx_filter_remove_filter(struct efx_nic *efx, struct efx_filter_spec *spec) +{ + struct efx_filter_state *state = efx->filter_state; + enum efx_filter_table_id table_id = + efx_filter_type_table_id(spec->type); + struct efx_filter_table *table = &state->table[table_id]; + struct efx_filter_spec *saved_spec; + efx_oword_t filter; + int filter_idx, depth; + u32 key; + int rc; + + key = efx_filter_build(&filter, spec); + + spin_lock_bh(&state->lock); + + rc = efx_filter_search(table, spec, key, false, &depth); + if (rc < 0) + goto out; + filter_idx = rc; + saved_spec = &table->spec[filter_idx]; + + if (spec->priority < saved_spec->priority) { + rc = -EPERM; + goto out; + } + + efx_filter_table_clear_entry(efx, table, filter_idx); + if (table->used == 0) + efx_filter_table_reset_search_depth(state, table_id); + rc = 0; + +out: + spin_unlock_bh(&state->lock); + return rc; +} + +/** + * efx_filter_table_clear - remove filters from a table by priority + * @efx: NIC from which to remove the filters + * @table_id: Table from which to remove the filters + * @priority: Maximum priority to remove + */ +void efx_filter_table_clear(struct efx_nic *efx, + enum efx_filter_table_id table_id, + enum efx_filter_priority priority) +{ + struct efx_filter_state *state = efx->filter_state; + struct efx_filter_table *table = &state->table[table_id]; + int filter_idx; + + spin_lock_bh(&state->lock); + + for (filter_idx = 0; filter_idx < table->size; ++filter_idx) + if (table->spec[filter_idx].priority <= priority) + efx_filter_table_clear_entry(efx, table, filter_idx); + if (table->used == 0) + efx_filter_table_reset_search_depth(state, table_id); + + spin_unlock_bh(&state->lock); +} + +/* Restore filter stater after reset */ +void efx_restore_filters(struct efx_nic *efx) +{ + struct efx_filter_state *state = efx->filter_state; + enum efx_filter_table_id table_id; + struct efx_filter_table *table; + efx_oword_t filter; + int filter_idx; + + spin_lock_bh(&state->lock); + + for (table_id = 0; table_id < EFX_FILTER_TABLE_COUNT; table_id++) { + table = &state->table[table_id]; + for (filter_idx = 0; filter_idx < table->size; filter_idx++) { + if (!test_bit(filter_idx, table->used_bitmap)) + continue; + efx_filter_build(&filter, &table->spec[filter_idx]); + efx_writeo(efx, &filter, + table->offset + table->step * filter_idx); + } + } + + efx_filter_push_rx_limits(efx); + + spin_unlock_bh(&state->lock); +} + +int efx_probe_filters(struct efx_nic *efx) +{ + struct efx_filter_state *state; + struct efx_filter_table *table; + unsigned table_id; + + state = kzalloc(sizeof(*efx->filter_state), GFP_KERNEL); + if (!state) + return -ENOMEM; + efx->filter_state = state; + + spin_lock_init(&state->lock); + + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { + table = &state->table[EFX_FILTER_TABLE_RX_IP]; + table->offset = FR_BZ_RX_FILTER_TBL0; + table->size = FR_BZ_RX_FILTER_TBL0_ROWS; + table->step = FR_BZ_RX_FILTER_TBL0_STEP; + } + + if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) { + table = &state->table[EFX_FILTER_TABLE_RX_MAC]; + table->offset = FR_CZ_RX_MAC_FILTER_TBL0; + table->size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS; + table->step = FR_CZ_RX_MAC_FILTER_TBL0_STEP; + } + + for (table_id = 0; table_id < EFX_FILTER_TABLE_COUNT; table_id++) { + table = &state->table[table_id]; + if (table->size == 0) + continue; + table->used_bitmap = kcalloc(BITS_TO_LONGS(table->size), + sizeof(unsigned long), + GFP_KERNEL); + if (!table->used_bitmap) + goto fail; + table->spec = vmalloc(table->size * sizeof(*table->spec)); + if (!table->spec) + goto fail; + memset(table->spec, 0, table->size * sizeof(*table->spec)); + } + + return 0; + +fail: + efx_remove_filters(efx); + return -ENOMEM; +} + +void efx_remove_filters(struct efx_nic *efx) +{ + struct efx_filter_state *state = efx->filter_state; + enum efx_filter_table_id table_id; + + for (table_id = 0; table_id < EFX_FILTER_TABLE_COUNT; table_id++) { + kfree(state->table[table_id].used_bitmap); + vfree(state->table[table_id].spec); + } + kfree(state); +} diff --git a/drivers/net/sfc/filter.h b/drivers/net/sfc/filter.h new file mode 100644 index 00000000000..a53319ded79 --- /dev/null +++ b/drivers/net/sfc/filter.h @@ -0,0 +1,189 @@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * 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 + * by the Free Software Foundation, incorporated herein by reference. + */ + +#ifndef EFX_FILTER_H +#define EFX_FILTER_H + +#include <linux/types.h> + +enum efx_filter_table_id { + EFX_FILTER_TABLE_RX_IP = 0, + EFX_FILTER_TABLE_RX_MAC, + EFX_FILTER_TABLE_COUNT, +}; + +/** + * enum efx_filter_type - type of hardware filter + * @EFX_FILTER_RX_TCP_FULL: RX, matching TCP/IPv4 4-tuple + * @EFX_FILTER_RX_TCP_WILD: RX, matching TCP/IPv4 destination (host, port) + * @EFX_FILTER_RX_UDP_FULL: RX, matching UDP/IPv4 4-tuple + * @EFX_FILTER_RX_UDP_WILD: RX, matching UDP/IPv4 destination (host, port) + * @EFX_FILTER_RX_MAC_FULL: RX, matching Ethernet destination MAC address, VID + * @EFX_FILTER_RX_MAC_WILD: RX, matching Ethernet destination MAC address + * + * Falcon NICs only support the RX TCP/IPv4 and UDP/IPv4 filter types. + */ +enum efx_filter_type { + EFX_FILTER_RX_TCP_FULL = 0, + EFX_FILTER_RX_TCP_WILD, + EFX_FILTER_RX_UDP_FULL, + EFX_FILTER_RX_UDP_WILD, + EFX_FILTER_RX_MAC_FULL = 4, + EFX_FILTER_RX_MAC_WILD, + EFX_FILTER_TYPE_COUNT, +}; + +/** + * enum efx_filter_priority - priority of a hardware filter specification + * @EFX_FILTER_PRI_HINT: Performance hint + * @EFX_FILTER_PRI_MANUAL: Manually configured filter + * @EFX_FILTER_PRI_REQUIRED: Required for correct behaviour + */ +enum efx_filter_priority { + EFX_FILTER_PRI_HINT = 0, + EFX_FILTER_PRI_MANUAL, + EFX_FILTER_PRI_REQUIRED, +}; + +/** + * enum efx_filter_flags - flags for hardware filter specifications + * @EFX_FILTER_FLAG_RX_RSS: Use RSS to spread across multiple queues. + * By default, matching packets will be delivered only to the + * specified queue. If this flag is set, they will be delivered + * to a range of queues offset from the specified queue number + * according to the indirection table. + * @EFX_FILTER_FLAG_RX_SCATTER: Enable DMA scatter on the receiving + * queue. + * @EFX_FILTER_FLAG_RX_OVERRIDE_IP: Enables a MAC filter to override + * any IP filter that matches the same packet. By default, IP + * filters take precedence. + * + * Currently, no flags are defined for TX filters. + */ +enum efx_filter_flags { + EFX_FILTER_FLAG_RX_RSS = 0x01, + EFX_FILTER_FLAG_RX_SCATTER = 0x02, + EFX_FILTER_FLAG_RX_OVERRIDE_IP = 0x04, +}; + +/** + * struct efx_filter_spec - specification for a hardware filter + * @type: Type of match to be performed, from &enum efx_filter_type + * @priority: Priority of the filter, from &enum efx_filter_priority + * @flags: Miscellaneous flags, from &enum efx_filter_flags + * @dmaq_id: Source/target queue index + * @data: Match data (type-dependent) + * + * Use the efx_filter_set_*() functions to initialise the @type and + * @data fields. + */ +struct efx_filter_spec { + u8 type:4; + u8 priority:4; + u8 flags; + u16 dmaq_id; + u32 data[3]; +}; + +/** + * efx_filter_set_rx_tcp_full - specify RX filter with TCP/IPv4 full match + * @spec: Specification to initialise + * @shost: Source host address (host byte order) + * @sport: Source port (host byte order) + * @dhost: Destination host address (host byte order) + * @dport: Destination port (host byte order) + */ +static inline void +efx_filter_set_rx_tcp_full(struct efx_filter_spec *spec, + u32 shost, u16 sport, u32 dhost, u16 dport) +{ + spec->type = EFX_FILTER_RX_TCP_FULL; + spec->data[0] = sport | shost << 16; + spec->data[1] = dport << 16 | shost >> 16; + spec->data[2] = dhost; +} + +/** + * efx_filter_set_rx_tcp_wild - specify RX filter with TCP/IPv4 wildcard match + * @spec: Specification to initialise + * @dhost: Destination host address (host byte order) + * @dport: Destination port (host byte order) + */ +static inline void +efx_filter_set_rx_tcp_wild(struct efx_filter_spec *spec, u32 dhost, u16 dport) +{ + spec->type = EFX_FILTER_RX_TCP_WILD; + spec->data[0] = 0; + spec->data[1] = dport << 16; + spec->data[2] = dhost; +} + +/** + * efx_filter_set_rx_udp_full - specify RX filter with UDP/IPv4 full match + * @spec: Specification to initialise + * @shost: Source host address (host byte order) + * @sport: Source port (host byte order) + * @dhost: Destination host address (host byte order) + * @dport: Destination port (host byte order) + */ +static inline void +efx_filter_set_rx_udp_full(struct efx_filter_spec *spec, + u32 shost, u16 sport, u32 dhost, u16 dport) +{ + spec->type = EFX_FILTER_RX_UDP_FULL; + spec->data[0] = sport | shost << 16; + spec->data[1] = dport << 16 | shost >> 16; + spec->data[2] = dhost; +} + +/** + * efx_filter_set_rx_udp_wild - specify RX filter with UDP/IPv4 wildcard match + * @spec: Specification to initialise + * @dhost: Destination host address (host byte order) + * @dport: Destination port (host byte order) + */ +static inline void +efx_filter_set_rx_udp_wild(struct efx_filter_spec *spec, u32 dhost, u16 dport) +{ + spec->type = EFX_FILTER_RX_UDP_WILD; + spec->data[0] = dport; + spec->data[1] = 0; + spec->data[2] = dhost; +} + +/** + * efx_filter_set_rx_mac_full - specify RX filter with MAC full match + * @spec: Specification to initialise + * @vid: VLAN ID + * @addr: Destination MAC address + */ +static inline void efx_filter_set_rx_mac_full(struct efx_filter_spec *spec, + u16 vid, const u8 *addr) +{ + spec->type = EFX_FILTER_RX_MAC_FULL; + spec->data[0] = vid; + spec->data[1] = addr[2] << 24 | addr[3] << 16 | addr[4] << 8 | addr[5]; + spec->data[2] = addr[0] << 8 | addr[1]; +} + +/** + * efx_filter_set_rx_mac_full - specify RX filter with MAC wildcard match + * @spec: Specification to initialise + * @addr: Destination MAC address + */ +static inline void efx_filter_set_rx_mac_wild(struct efx_filter_spec *spec, + const u8 *addr) +{ + spec->type = EFX_FILTER_RX_MAC_WILD; + spec->data[0] = 0; + spec->data[1] = addr[2] << 24 | addr[3] << 16 | addr[4] << 8 | addr[5]; + spec->data[2] = addr[0] << 8 | addr[1]; +} + +#endif /* EFX_FILTER_H */ diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h index f1aa5f37489..6886cdf87c1 100644 --- a/drivers/net/sfc/mac.h +++ b/drivers/net/sfc/mac.h @@ -13,10 +13,8 @@ #include "net_driver.h" -extern struct efx_mac_operations falcon_gmac_operations; extern struct efx_mac_operations falcon_xmac_operations; extern struct efx_mac_operations efx_mcdi_mac_operations; -extern void falcon_reconfigure_xmac_core(struct efx_nic *efx); extern int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr, u32 dma_len, int enable, int clear); diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c index 3912b8fed91..12cf910c2ce 100644 --- a/drivers/net/sfc/mcdi.c +++ b/drivers/net/sfc/mcdi.c @@ -1093,8 +1093,8 @@ int efx_mcdi_reset_mc(struct efx_nic *efx) return rc; } -int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type, - const u8 *mac, int *id_out) +static int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type, + const u8 *mac, int *id_out) { u8 inbuf[MC_CMD_WOL_FILTER_SET_IN_LEN]; u8 outbuf[MC_CMD_WOL_FILTER_SET_OUT_LEN]; diff --git a/drivers/net/sfc/mcdi.h b/drivers/net/sfc/mcdi.h index f1f89ad4075..c792f1d65e4 100644 --- a/drivers/net/sfc/mcdi.h +++ b/drivers/net/sfc/mcdi.h @@ -121,8 +121,6 @@ extern int efx_mcdi_handle_assertion(struct efx_nic *efx); extern void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); extern int efx_mcdi_reset_port(struct efx_nic *efx); extern int efx_mcdi_reset_mc(struct efx_nic *efx); -extern int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type, - const u8 *mac, int *id_out); extern int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac, int *id_out); extern int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out); diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c index 0121e71702b..c992742446b 100644 --- a/drivers/net/sfc/mcdi_phy.c +++ b/drivers/net/sfc/mcdi_phy.c @@ -713,7 +713,8 @@ static int efx_mcdi_phy_run_tests(struct efx_nic *efx, int *results, return 0; } -const char *efx_mcdi_phy_test_name(struct efx_nic *efx, unsigned int index) +static const char *efx_mcdi_phy_test_name(struct efx_nic *efx, + unsigned int index) { struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index eeaf0bd64bd..98d94602042 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c @@ -286,46 +286,24 @@ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) */ void efx_mdio_an_reconfigure(struct efx_nic *efx) { - bool xnp = (efx->link_advertising & ADVERTISED_10000baseT_Full - || EFX_WORKAROUND_13204(efx)); int reg; WARN_ON(!(efx->mdio.mmds & MDIO_DEVS_AN)); /* Set up the base page */ - reg = ADVERTISE_CSMA; - if (efx->link_advertising & ADVERTISED_10baseT_Half) - reg |= ADVERTISE_10HALF; - if (efx->link_advertising & ADVERTISED_10baseT_Full) - reg |= ADVERTISE_10FULL; - if (efx->link_advertising & ADVERTISED_100baseT_Half) - reg |= ADVERTISE_100HALF; - if (efx->link_advertising & ADVERTISED_100baseT_Full) - reg |= ADVERTISE_100FULL; - if (xnp) - reg |= ADVERTISE_RESV; - else if (efx->link_advertising & (ADVERTISED_1000baseT_Half | - ADVERTISED_1000baseT_Full)) - reg |= ADVERTISE_NPAGE; + reg = ADVERTISE_CSMA | ADVERTISE_RESV; if (efx->link_advertising & ADVERTISED_Pause) reg |= ADVERTISE_PAUSE_CAP; if (efx->link_advertising & ADVERTISED_Asym_Pause) reg |= ADVERTISE_PAUSE_ASYM; efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); - /* Set up the (extended) next page if necessary */ - if (efx->phy_op->set_npage_adv) - efx->phy_op->set_npage_adv(efx, efx->link_advertising); + /* Set up the (extended) next page */ + efx->phy_op->set_npage_adv(efx, efx->link_advertising); /* Enable and restart AN */ reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1); - reg |= MDIO_AN_CTRL1_ENABLE; - if (!(EFX_WORKAROUND_15195(efx) && LOOPBACK_EXTERNAL(efx))) - reg |= MDIO_AN_CTRL1_RESTART; - if (xnp) - reg |= MDIO_AN_CTRL1_XNP; - else - reg &= ~MDIO_AN_CTRL1_XNP; + reg |= MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART | MDIO_AN_CTRL1_XNP; efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg); } diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 64e7caa4bbb..0a7e26d73b5 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -29,6 +29,7 @@ #include <linux/device.h> #include <linux/highmem.h> #include <linux/workqueue.h> +#include <linux/vmalloc.h> #include <linux/i2c.h> #include "enum.h" @@ -137,6 +138,7 @@ struct efx_tx_buffer { * @channel: The associated channel * @buffer: The software buffer ring * @txd: The hardware descriptor ring + * @ptr_mask: The size of the ring minus 1. * @flushed: Used when handling queue flushing * @read_count: Current read pointer. * This is the number of buffers that have been removed from both rings. @@ -170,6 +172,7 @@ struct efx_tx_queue { struct efx_nic *nic; struct efx_tx_buffer *buffer; struct efx_special_buffer txd; + unsigned int ptr_mask; enum efx_flush_state flushed; /* Members used mainly on the completion path */ @@ -225,10 +228,9 @@ struct efx_rx_page_state { /** * struct efx_rx_queue - An Efx RX queue * @efx: The associated Efx NIC - * @queue: DMA queue number - * @channel: The associated channel * @buffer: The software buffer ring * @rxd: The hardware descriptor ring + * @ptr_mask: The size of the ring minus 1. * @added_count: Number of buffers added to the receive queue. * @notified_count: Number of buffers given to NIC (<= @added_count). * @removed_count: Number of buffers removed from the receive queue. @@ -240,9 +242,6 @@ struct efx_rx_page_state { * @min_fill: RX descriptor minimum non-zero fill level. * This records the minimum fill level observed when a ring * refill was triggered. - * @min_overfill: RX descriptor minimum overflow fill level. - * This records the minimum fill level at which RX queue - * overflow was observed. It should never be set. * @alloc_page_count: RX allocation strategy counter. * @alloc_skb_count: RX allocation strategy counter. * @slow_fill: Timer used to defer efx_nic_generate_fill_event(). @@ -250,10 +249,9 @@ struct efx_rx_page_state { */ struct efx_rx_queue { struct efx_nic *efx; - int queue; - struct efx_channel *channel; struct efx_rx_buffer *buffer; struct efx_special_buffer rxd; + unsigned int ptr_mask; int added_count; int notified_count; @@ -302,7 +300,6 @@ enum efx_rx_alloc_method { * * @efx: Associated Efx NIC * @channel: Channel instance number - * @name: Name for channel and IRQ * @enabled: Channel enabled indicator * @irq: IRQ number (MSI and MSI-X only) * @irq_moderation: IRQ moderation value (in hardware ticks) @@ -311,6 +308,7 @@ enum efx_rx_alloc_method { * @reset_work: Scheduled reset work thread * @work_pending: Is work pending via NAPI? * @eventq: Event queue buffer + * @eventq_mask: Event queue pointer mask * @eventq_read_ptr: Event queue read pointer * @last_eventq_read_ptr: Last event queue read pointer value. * @magic_count: Event queue test event count @@ -327,14 +325,14 @@ enum efx_rx_alloc_method { * @n_rx_frm_trunc: Count of RX_FRM_TRUNC errors * @n_rx_overlength: Count of RX_OVERLENGTH errors * @n_skbuff_leaks: Count of skbuffs leaked due to RX overrun - * @tx_queue: Pointer to first TX queue, or %NULL if not used for TX + * @rx_queue: RX queue for this channel * @tx_stop_count: Core TX queue stop count * @tx_stop_lock: Core TX queue stop lock + * @tx_queue: TX queues for this channel */ struct efx_channel { struct efx_nic *efx; int channel; - char name[IFNAMSIZ + 6]; bool enabled; int irq; unsigned int irq_moderation; @@ -342,6 +340,7 @@ struct efx_channel { struct napi_struct napi_str; bool work_pending; struct efx_special_buffer eventq; + unsigned int eventq_mask; unsigned int eventq_read_ptr; unsigned int last_eventq_read_ptr; unsigned int magic_count; @@ -366,9 +365,12 @@ struct efx_channel { struct efx_rx_buffer *rx_pkt; bool rx_pkt_csummed; - struct efx_tx_queue *tx_queue; + struct efx_rx_queue rx_queue; + atomic_t tx_stop_count; spinlock_t tx_stop_lock; + + struct efx_tx_queue tx_queue[2]; }; enum efx_led_mode { @@ -385,11 +387,6 @@ extern const unsigned int efx_loopback_mode_max; #define LOOPBACK_MODE(efx) \ STRING_TABLE_LOOKUP((efx)->loopback_mode, efx_loopback_mode) -extern const char *efx_interrupt_mode_names[]; -extern const unsigned int efx_interrupt_mode_max; -#define INT_MODE(efx) \ - STRING_TABLE_LOOKUP(efx->interrupt_mode, efx_interrupt_mode) - extern const char *efx_reset_type_names[]; extern const unsigned int efx_reset_type_max; #define RESET_TYPE(type) \ @@ -404,8 +401,6 @@ enum efx_int_mode { }; #define EFX_INT_MODE_USE_MSI(x) (((x)->interrupt_mode) <= EFX_INT_MODE_MSI) -#define EFX_IS10G(efx) ((efx)->link_state.speed == 10000) - enum nic_state { STATE_INIT = 0, STATE_RUNNING = 1, @@ -618,6 +613,8 @@ union efx_multicast_hash { efx_oword_t oword[EFX_MCAST_HASH_ENTRIES / sizeof(efx_oword_t) / 8]; }; +struct efx_filter_state; + /** * struct efx_nic - an Efx NIC * @name: Device name (net device name or bus id before net device registered) @@ -641,6 +638,9 @@ union efx_multicast_hash { * @tx_queue: TX DMA queues * @rx_queue: RX DMA queues * @channel: Channels + * @channel_name: Names for channels and their IRQs + * @rxq_entries: Size of receive queues requested by user. + * @txq_entries: Size of transmit queues requested by user. * @next_buffer_table: First available buffer table id * @n_channels: Number of channels in use * @n_rx_channels: Number of channels used for RX (= number of RX queues) @@ -724,10 +724,11 @@ struct efx_nic { enum nic_state state; enum reset_type reset_pending; - struct efx_tx_queue tx_queue[EFX_MAX_TX_QUEUES]; - struct efx_rx_queue rx_queue[EFX_MAX_RX_QUEUES]; - struct efx_channel channel[EFX_MAX_CHANNELS]; + struct efx_channel *channel[EFX_MAX_CHANNELS]; + char channel_name[EFX_MAX_CHANNELS][IFNAMSIZ + 6]; + unsigned rxq_entries; + unsigned txq_entries; unsigned next_buffer_table; unsigned n_channels; unsigned n_rx_channels; @@ -794,6 +795,8 @@ struct efx_nic { u64 loopback_modes; void *loopback_selftest; + + struct efx_filter_state *filter_state; }; static inline int efx_dev_registered(struct efx_nic *efx) @@ -909,39 +912,67 @@ struct efx_nic_type { * *************************************************************************/ +static inline struct efx_channel * +efx_get_channel(struct efx_nic *efx, unsigned index) +{ + EFX_BUG_ON_PARANOID(index >= efx->n_channels); + return efx->channel[index]; +} + /* Iterate over all used channels */ #define efx_for_each_channel(_channel, _efx) \ - for (_channel = &((_efx)->channel[0]); \ - _channel < &((_efx)->channel[(efx)->n_channels]); \ - _channel++) - -/* Iterate over all used TX queues */ -#define efx_for_each_tx_queue(_tx_queue, _efx) \ - for (_tx_queue = &((_efx)->tx_queue[0]); \ - _tx_queue < &((_efx)->tx_queue[EFX_TXQ_TYPES * \ - (_efx)->n_tx_channels]); \ - _tx_queue++) + for (_channel = (_efx)->channel[0]; \ + _channel; \ + _channel = (_channel->channel + 1 < (_efx)->n_channels) ? \ + (_efx)->channel[_channel->channel + 1] : NULL) + +extern struct efx_tx_queue * +efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type); + +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; +} /* Iterate over all TX queues belonging to a channel */ #define efx_for_each_channel_tx_queue(_tx_queue, _channel) \ - for (_tx_queue = (_channel)->tx_queue; \ + for (_tx_queue = efx_channel_get_tx_queue(channel, 0); \ _tx_queue && _tx_queue < (_channel)->tx_queue + EFX_TXQ_TYPES; \ _tx_queue++) -/* Iterate over all used RX queues */ -#define efx_for_each_rx_queue(_rx_queue, _efx) \ - for (_rx_queue = &((_efx)->rx_queue[0]); \ - _rx_queue < &((_efx)->rx_queue[(_efx)->n_rx_channels]); \ - _rx_queue++) +static inline struct efx_rx_queue * +efx_get_rx_queue(struct efx_nic *efx, unsigned index) +{ + EFX_BUG_ON_PARANOID(index >= efx->n_rx_channels); + return &efx->channel[index]->rx_queue; +} + +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; +} /* Iterate over all RX queues belonging to a channel */ #define efx_for_each_channel_rx_queue(_rx_queue, _channel) \ - for (_rx_queue = &((_channel)->efx->rx_queue[(_channel)->channel]); \ + for (_rx_queue = efx_channel_get_rx_queue(channel); \ _rx_queue; \ - _rx_queue = NULL) \ - if (_rx_queue->channel != (_channel)) \ - continue; \ - else + _rx_queue = NULL) + +static inline struct efx_channel * +efx_rx_queue_channel(struct efx_rx_queue *rx_queue) +{ + return container_of(rx_queue, struct efx_channel, rx_queue); +} + +static inline int efx_rx_queue_index(struct efx_rx_queue *rx_queue) +{ + return efx_rx_queue_channel(rx_queue)->channel; +} /* Returns a pointer to the specified receive buffer in the RX * descriptor queue. @@ -949,7 +980,7 @@ struct efx_nic_type { static inline struct efx_rx_buffer *efx_rx_buffer(struct efx_rx_queue *rx_queue, unsigned int index) { - return (&rx_queue->buffer[index]); + return &rx_queue->buffer[index]; } /* Set bit in a little-endian bitfield */ diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index f595d920c7c..41c36b9a424 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -104,7 +104,7 @@ static inline void efx_write_buf_tbl(struct efx_nic *efx, efx_qword_t *value, static inline efx_qword_t *efx_event(struct efx_channel *channel, unsigned int index) { - return (((efx_qword_t *) (channel->eventq.addr)) + index); + return ((efx_qword_t *) (channel->eventq.addr)) + index; } /* See if an event is present @@ -119,8 +119,8 @@ static inline efx_qword_t *efx_event(struct efx_channel *channel, */ static inline int efx_event_present(efx_qword_t *event) { - return (!(EFX_DWORD_IS_ALL_ONES(event->dword[0]) | - EFX_DWORD_IS_ALL_ONES(event->dword[1]))); + return !(EFX_DWORD_IS_ALL_ONES(event->dword[0]) | + EFX_DWORD_IS_ALL_ONES(event->dword[1])); } static bool efx_masked_compare_oword(const efx_oword_t *a, const efx_oword_t *b, @@ -263,8 +263,8 @@ static int efx_alloc_special_buffer(struct efx_nic *efx, { len = ALIGN(len, EFX_BUF_SIZE); - buffer->addr = pci_alloc_consistent(efx->pci_dev, len, - &buffer->dma_addr); + buffer->addr = dma_alloc_coherent(&efx->pci_dev->dev, len, + &buffer->dma_addr, GFP_KERNEL); if (!buffer->addr) return -ENOMEM; buffer->len = len; @@ -301,8 +301,8 @@ efx_free_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer) (u64)buffer->dma_addr, buffer->len, buffer->addr, (u64)virt_to_phys(buffer->addr)); - pci_free_consistent(efx->pci_dev, buffer->len, buffer->addr, - buffer->dma_addr); + dma_free_coherent(&efx->pci_dev->dev, buffer->len, buffer->addr, + buffer->dma_addr); buffer->addr = NULL; buffer->entries = 0; } @@ -347,7 +347,7 @@ void efx_nic_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer) static inline efx_qword_t * efx_tx_desc(struct efx_tx_queue *tx_queue, unsigned int index) { - return (((efx_qword_t *) (tx_queue->txd.addr)) + index); + return ((efx_qword_t *) (tx_queue->txd.addr)) + index; } /* This writes to the TX_DESC_WPTR; write pointer for TX descriptor ring */ @@ -356,7 +356,7 @@ static inline void efx_notify_tx_desc(struct efx_tx_queue *tx_queue) unsigned write_ptr; efx_dword_t reg; - write_ptr = tx_queue->write_count & EFX_TXQ_MASK; + write_ptr = tx_queue->write_count & tx_queue->ptr_mask; EFX_POPULATE_DWORD_1(reg, FRF_AZ_TX_DESC_WPTR_DWORD, write_ptr); efx_writed_page(tx_queue->efx, ®, FR_AZ_TX_DESC_UPD_DWORD_P0, tx_queue->queue); @@ -377,7 +377,7 @@ void efx_nic_push_buffers(struct efx_tx_queue *tx_queue) BUG_ON(tx_queue->write_count == tx_queue->insert_count); do { - write_ptr = tx_queue->write_count & EFX_TXQ_MASK; + write_ptr = tx_queue->write_count & tx_queue->ptr_mask; buffer = &tx_queue->buffer[write_ptr]; txd = efx_tx_desc(tx_queue, write_ptr); ++tx_queue->write_count; @@ -398,10 +398,11 @@ void efx_nic_push_buffers(struct efx_tx_queue *tx_queue) int efx_nic_probe_tx(struct efx_tx_queue *tx_queue) { struct efx_nic *efx = tx_queue->efx; - BUILD_BUG_ON(EFX_TXQ_SIZE < 512 || EFX_TXQ_SIZE > 4096 || - EFX_TXQ_SIZE & EFX_TXQ_MASK); + unsigned entries; + + entries = tx_queue->ptr_mask + 1; return efx_alloc_special_buffer(efx, &tx_queue->txd, - EFX_TXQ_SIZE * sizeof(efx_qword_t)); + entries * sizeof(efx_qword_t)); } void efx_nic_init_tx(struct efx_tx_queue *tx_queue) @@ -501,7 +502,7 @@ void efx_nic_remove_tx(struct efx_tx_queue *tx_queue) static inline efx_qword_t * efx_rx_desc(struct efx_rx_queue *rx_queue, unsigned int index) { - return (((efx_qword_t *) (rx_queue->rxd.addr)) + index); + return ((efx_qword_t *) (rx_queue->rxd.addr)) + index; } /* This creates an entry in the RX descriptor queue */ @@ -526,30 +527,32 @@ efx_build_rx_desc(struct efx_rx_queue *rx_queue, unsigned index) */ void efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue) { + struct efx_nic *efx = rx_queue->efx; efx_dword_t reg; unsigned write_ptr; while (rx_queue->notified_count != rx_queue->added_count) { - efx_build_rx_desc(rx_queue, - rx_queue->notified_count & - EFX_RXQ_MASK); + efx_build_rx_desc( + rx_queue, + rx_queue->notified_count & rx_queue->ptr_mask); ++rx_queue->notified_count; } wmb(); - write_ptr = rx_queue->added_count & EFX_RXQ_MASK; + write_ptr = rx_queue->added_count & rx_queue->ptr_mask; EFX_POPULATE_DWORD_1(reg, FRF_AZ_RX_DESC_WPTR_DWORD, write_ptr); - efx_writed_page(rx_queue->efx, ®, - FR_AZ_RX_DESC_UPD_DWORD_P0, rx_queue->queue); + efx_writed_page(efx, ®, FR_AZ_RX_DESC_UPD_DWORD_P0, + efx_rx_queue_index(rx_queue)); } int efx_nic_probe_rx(struct efx_rx_queue *rx_queue) { struct efx_nic *efx = rx_queue->efx; - BUILD_BUG_ON(EFX_RXQ_SIZE < 512 || EFX_RXQ_SIZE > 4096 || - EFX_RXQ_SIZE & EFX_RXQ_MASK); + unsigned entries; + + entries = rx_queue->ptr_mask + 1; return efx_alloc_special_buffer(efx, &rx_queue->rxd, - EFX_RXQ_SIZE * sizeof(efx_qword_t)); + entries * sizeof(efx_qword_t)); } void efx_nic_init_rx(struct efx_rx_queue *rx_queue) @@ -561,7 +564,7 @@ void efx_nic_init_rx(struct efx_rx_queue *rx_queue) netif_dbg(efx, hw, efx->net_dev, "RX queue %d ring in special buffers %d-%d\n", - rx_queue->queue, rx_queue->rxd.index, + efx_rx_queue_index(rx_queue), rx_queue->rxd.index, rx_queue->rxd.index + rx_queue->rxd.entries - 1); rx_queue->flushed = FLUSH_NONE; @@ -575,9 +578,10 @@ void efx_nic_init_rx(struct efx_rx_queue *rx_queue) FRF_AZ_RX_ISCSI_HDIG_EN, iscsi_digest_en, FRF_AZ_RX_DESCQ_BUF_BASE_ID, rx_queue->rxd.index, FRF_AZ_RX_DESCQ_EVQ_ID, - rx_queue->channel->channel, + efx_rx_queue_channel(rx_queue)->channel, FRF_AZ_RX_DESCQ_OWNER_ID, 0, - FRF_AZ_RX_DESCQ_LABEL, rx_queue->queue, + FRF_AZ_RX_DESCQ_LABEL, + efx_rx_queue_index(rx_queue), FRF_AZ_RX_DESCQ_SIZE, __ffs(rx_queue->rxd.entries), FRF_AZ_RX_DESCQ_TYPE, 0 /* kernel queue */ , @@ -585,7 +589,7 @@ void efx_nic_init_rx(struct efx_rx_queue *rx_queue) FRF_AZ_RX_DESCQ_JUMBO, !is_b0, FRF_AZ_RX_DESCQ_EN, 1); efx_writeo_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base, - rx_queue->queue); + efx_rx_queue_index(rx_queue)); } static void efx_flush_rx_queue(struct efx_rx_queue *rx_queue) @@ -598,7 +602,8 @@ static void efx_flush_rx_queue(struct efx_rx_queue *rx_queue) /* Post a flush command */ EFX_POPULATE_OWORD_2(rx_flush_descq, FRF_AZ_RX_FLUSH_DESCQ_CMD, 1, - FRF_AZ_RX_FLUSH_DESCQ, rx_queue->queue); + FRF_AZ_RX_FLUSH_DESCQ, + efx_rx_queue_index(rx_queue)); efx_writeo(efx, &rx_flush_descq, FR_AZ_RX_FLUSH_DESCQ); } @@ -613,7 +618,7 @@ void efx_nic_fini_rx(struct efx_rx_queue *rx_queue) /* Remove RX descriptor ring from card */ EFX_ZERO_OWORD(rx_desc_ptr); efx_writeo_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base, - rx_queue->queue); + efx_rx_queue_index(rx_queue)); /* Unpin RX descriptor ring */ efx_fini_special_buffer(efx, &rx_queue->rxd); @@ -648,7 +653,7 @@ void efx_nic_eventq_read_ack(struct efx_channel *channel) } /* Use HW to insert a SW defined event */ -void efx_generate_event(struct efx_channel *channel, efx_qword_t *event) +static void efx_generate_event(struct efx_channel *channel, efx_qword_t *event) { efx_oword_t drv_ev_reg; @@ -680,15 +685,17 @@ efx_handle_tx_event(struct efx_channel *channel, efx_qword_t *event) /* Transmit completion */ tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_DESC_PTR); tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL); - tx_queue = &efx->tx_queue[tx_ev_q_label]; + tx_queue = efx_channel_get_tx_queue( + channel, tx_ev_q_label % EFX_TXQ_TYPES); tx_packets = ((tx_ev_desc_ptr - tx_queue->read_count) & - EFX_TXQ_MASK); + tx_queue->ptr_mask); channel->irq_mod_score += tx_packets; efx_xmit_done(tx_queue, tx_ev_desc_ptr); } else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_WQ_FF_FULL)) { /* Rewrite the FIFO write pointer */ tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL); - tx_queue = &efx->tx_queue[tx_ev_q_label]; + tx_queue = efx_channel_get_tx_queue( + channel, tx_ev_q_label % EFX_TXQ_TYPES); if (efx_dev_registered(efx)) netif_tx_lock(efx->net_dev); @@ -714,6 +721,7 @@ static void efx_handle_rx_not_ok(struct efx_rx_queue *rx_queue, bool *rx_ev_pkt_ok, bool *discard) { + struct efx_channel *channel = efx_rx_queue_channel(rx_queue); struct efx_nic *efx = rx_queue->efx; bool rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err; bool rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err; @@ -746,14 +754,14 @@ static void efx_handle_rx_not_ok(struct efx_rx_queue *rx_queue, /* Count errors that are not in MAC stats. Ignore expected * checksum errors during self-test. */ if (rx_ev_frm_trunc) - ++rx_queue->channel->n_rx_frm_trunc; + ++channel->n_rx_frm_trunc; else if (rx_ev_tobe_disc) - ++rx_queue->channel->n_rx_tobe_disc; + ++channel->n_rx_tobe_disc; else if (!efx->loopback_selftest) { if (rx_ev_ip_hdr_chksum_err) - ++rx_queue->channel->n_rx_ip_hdr_chksum_err; + ++channel->n_rx_ip_hdr_chksum_err; else if (rx_ev_tcp_udp_chksum_err) - ++rx_queue->channel->n_rx_tcp_udp_chksum_err; + ++channel->n_rx_tcp_udp_chksum_err; } /* The frame must be discarded if any of these are true. */ @@ -769,7 +777,7 @@ static void efx_handle_rx_not_ok(struct efx_rx_queue *rx_queue, netif_dbg(efx, rx_err, efx->net_dev, " RX queue %d unexpected RX event " EFX_QWORD_FMT "%s%s%s%s%s%s%s%s\n", - rx_queue->queue, EFX_QWORD_VAL(*event), + efx_rx_queue_index(rx_queue), EFX_QWORD_VAL(*event), rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "", rx_ev_ip_hdr_chksum_err ? " [IP_HDR_CHKSUM_ERR]" : "", @@ -791,8 +799,8 @@ efx_handle_rx_bad_index(struct efx_rx_queue *rx_queue, unsigned index) struct efx_nic *efx = rx_queue->efx; unsigned expected, dropped; - expected = rx_queue->removed_count & EFX_RXQ_MASK; - dropped = (index - expected) & EFX_RXQ_MASK; + expected = rx_queue->removed_count & rx_queue->ptr_mask; + dropped = (index - expected) & rx_queue->ptr_mask; netif_info(efx, rx_err, efx->net_dev, "dropped %d events (index=%d expected=%d)\n", dropped, index, expected); @@ -827,10 +835,10 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event) WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_Q_LABEL) != channel->channel); - rx_queue = &efx->rx_queue[channel->channel]; + rx_queue = efx_channel_get_rx_queue(channel); rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_DESC_PTR); - expected_ptr = rx_queue->removed_count & EFX_RXQ_MASK; + expected_ptr = rx_queue->removed_count & rx_queue->ptr_mask; if (unlikely(rx_ev_desc_ptr != expected_ptr)) efx_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr); @@ -879,7 +887,7 @@ efx_handle_generated_event(struct efx_channel *channel, efx_qword_t *event) /* The queue must be empty, so we won't receive any rx * events, so efx_process_channel() won't refill the * queue. Refill it here */ - efx_fast_push_rx_descriptors(&efx->rx_queue[channel->channel]); + efx_fast_push_rx_descriptors(efx_channel_get_rx_queue(channel)); else netif_dbg(efx, hw, efx->net_dev, "channel %d received " "generated event "EFX_QWORD_FMT"\n", @@ -997,6 +1005,7 @@ efx_handle_driver_event(struct efx_channel *channel, efx_qword_t *event) int efx_nic_process_eventq(struct efx_channel *channel, int budget) { + struct efx_nic *efx = channel->efx; unsigned int read_ptr; efx_qword_t event, *p_event; int ev_code; @@ -1021,7 +1030,7 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget) EFX_SET_QWORD(*p_event); /* Increment read pointer */ - read_ptr = (read_ptr + 1) & EFX_EVQ_MASK; + read_ptr = (read_ptr + 1) & channel->eventq_mask; ev_code = EFX_QWORD_FIELD(event, FSF_AZ_EV_CODE); @@ -1033,7 +1042,7 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget) break; case FSE_AZ_EV_CODE_TX_EV: tx_packets += efx_handle_tx_event(channel, &event); - if (tx_packets >= EFX_TXQ_SIZE) { + if (tx_packets > efx->txq_entries) { spent = budget; goto out; } @@ -1068,10 +1077,11 @@ out: int efx_nic_probe_eventq(struct efx_channel *channel) { struct efx_nic *efx = channel->efx; - BUILD_BUG_ON(EFX_EVQ_SIZE < 512 || EFX_EVQ_SIZE > 32768 || - EFX_EVQ_SIZE & EFX_EVQ_MASK); + unsigned entries; + + entries = channel->eventq_mask + 1; return efx_alloc_special_buffer(efx, &channel->eventq, - EFX_EVQ_SIZE * sizeof(efx_qword_t)); + entries * sizeof(efx_qword_t)); } void efx_nic_init_eventq(struct efx_channel *channel) @@ -1163,11 +1173,11 @@ void efx_nic_generate_fill_event(struct efx_channel *channel) static void efx_poll_flush_events(struct efx_nic *efx) { - struct efx_channel *channel = &efx->channel[0]; + struct efx_channel *channel = efx_get_channel(efx, 0); struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; unsigned int read_ptr = channel->eventq_read_ptr; - unsigned int end_ptr = (read_ptr - 1) & EFX_EVQ_MASK; + unsigned int end_ptr = (read_ptr - 1) & channel->eventq_mask; do { efx_qword_t *event = efx_event(channel, read_ptr); @@ -1185,7 +1195,9 @@ static void efx_poll_flush_events(struct efx_nic *efx) ev_queue = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBDATA); if (ev_queue < EFX_TXQ_TYPES * efx->n_tx_channels) { - tx_queue = efx->tx_queue + ev_queue; + tx_queue = efx_get_tx_queue( + efx, ev_queue / EFX_TXQ_TYPES, + ev_queue % EFX_TXQ_TYPES); tx_queue->flushed = FLUSH_DONE; } } else if (ev_code == FSE_AZ_EV_CODE_DRIVER_EV && @@ -1195,7 +1207,7 @@ static void efx_poll_flush_events(struct efx_nic *efx) ev_failed = EFX_QWORD_FIELD( *event, FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL); if (ev_queue < efx->n_rx_channels) { - rx_queue = efx->rx_queue + ev_queue; + rx_queue = efx_get_rx_queue(efx, ev_queue); rx_queue->flushed = ev_failed ? FLUSH_FAILED : FLUSH_DONE; } @@ -1205,7 +1217,7 @@ static void efx_poll_flush_events(struct efx_nic *efx) * it's ok to throw away every non-flush event */ EFX_SET_QWORD(*event); - read_ptr = (read_ptr + 1) & EFX_EVQ_MASK; + read_ptr = (read_ptr + 1) & channel->eventq_mask; } while (read_ptr != end_ptr); channel->eventq_read_ptr = read_ptr; @@ -1216,6 +1228,7 @@ static void efx_poll_flush_events(struct efx_nic *efx) * serialise them */ int efx_nic_flush_queues(struct efx_nic *efx) { + struct efx_channel *channel; struct efx_rx_queue *rx_queue; struct efx_tx_queue *tx_queue; int i, tx_pending, rx_pending; @@ -1224,29 +1237,35 @@ int efx_nic_flush_queues(struct efx_nic *efx) efx->type->prepare_flush(efx); /* Flush all tx queues in parallel */ - efx_for_each_tx_queue(tx_queue, efx) - efx_flush_tx_queue(tx_queue); + efx_for_each_channel(channel, efx) { + efx_for_each_channel_tx_queue(tx_queue, channel) + efx_flush_tx_queue(tx_queue); + } /* The hardware supports four concurrent rx flushes, each of which may * need to be retried if there is an outstanding descriptor fetch */ for (i = 0; i < EFX_FLUSH_POLL_COUNT; ++i) { rx_pending = tx_pending = 0; - efx_for_each_rx_queue(rx_queue, efx) { - if (rx_queue->flushed == FLUSH_PENDING) - ++rx_pending; - } - efx_for_each_rx_queue(rx_queue, efx) { - if (rx_pending == EFX_RX_FLUSH_COUNT) - break; - if (rx_queue->flushed == FLUSH_FAILED || - rx_queue->flushed == FLUSH_NONE) { - efx_flush_rx_queue(rx_queue); - ++rx_pending; + efx_for_each_channel(channel, efx) { + efx_for_each_channel_rx_queue(rx_queue, channel) { + if (rx_queue->flushed == FLUSH_PENDING) + ++rx_pending; } } - efx_for_each_tx_queue(tx_queue, efx) { - if (tx_queue->flushed != FLUSH_DONE) - ++tx_pending; + efx_for_each_channel(channel, efx) { + efx_for_each_channel_rx_queue(rx_queue, channel) { + if (rx_pending == EFX_RX_FLUSH_COUNT) + break; + if (rx_queue->flushed == FLUSH_FAILED || + rx_queue->flushed == FLUSH_NONE) { + efx_flush_rx_queue(rx_queue); + ++rx_pending; + } + } + efx_for_each_channel_tx_queue(tx_queue, channel) { + if (tx_queue->flushed != FLUSH_DONE) + ++tx_pending; + } } if (rx_pending == 0 && tx_pending == 0) @@ -1258,19 +1277,21 @@ 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_tx_queue(tx_queue, efx) { - if (tx_queue->flushed != FLUSH_DONE) - netif_err(efx, hw, efx->net_dev, - "tx queue %d flush command timed out\n", - tx_queue->queue); - tx_queue->flushed = FLUSH_DONE; - } - efx_for_each_rx_queue(rx_queue, efx) { - if (rx_queue->flushed != FLUSH_DONE) - netif_err(efx, hw, efx->net_dev, - "rx queue %d flush command timed out\n", - rx_queue->queue); - rx_queue->flushed = FLUSH_DONE; + efx_for_each_channel(channel, efx) { + efx_for_each_channel_tx_queue(tx_queue, channel) { + if (tx_queue->flushed != FLUSH_DONE) + netif_err(efx, hw, efx->net_dev, + "tx queue %d flush command timed out\n", + tx_queue->queue); + tx_queue->flushed = FLUSH_DONE; + } + efx_for_each_channel_rx_queue(rx_queue, channel) { + if (rx_queue->flushed != FLUSH_DONE) + netif_err(efx, hw, efx->net_dev, + "rx queue %d flush command timed out\n", + efx_rx_queue_index(rx_queue)); + rx_queue->flushed = FLUSH_DONE; + } } return -ETIMEDOUT; @@ -1457,7 +1478,7 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id) */ static irqreturn_t efx_msi_interrupt(int irq, void *dev_id) { - struct efx_channel *channel = dev_id; + struct efx_channel *channel = *(struct efx_channel **)dev_id; struct efx_nic *efx = channel->efx; efx_oword_t *int_ker = efx->irq_status.addr; int syserr; @@ -1532,7 +1553,8 @@ int efx_nic_init_interrupt(struct efx_nic *efx) efx_for_each_channel(channel, efx) { rc = request_irq(channel->irq, efx_msi_interrupt, IRQF_PROBE_SHARED, /* Not shared */ - channel->name, channel); + efx->channel_name[channel->channel], + &efx->channel[channel->channel]); if (rc) { netif_err(efx, drv, efx->net_dev, "failed to hook IRQ %d\n", channel->irq); @@ -1544,7 +1566,7 @@ int efx_nic_init_interrupt(struct efx_nic *efx) fail2: efx_for_each_channel(channel, efx) - free_irq(channel->irq, channel); + free_irq(channel->irq, &efx->channel[channel->channel]); fail1: return rc; } @@ -1557,7 +1579,7 @@ void efx_nic_fini_interrupt(struct efx_nic *efx) /* Disable MSI/MSI-X interrupts */ efx_for_each_channel(channel, efx) { if (channel->irq) - free_irq(channel->irq, channel); + free_irq(channel->irq, &efx->channel[channel->channel]); } /* ACK legacy interrupt */ @@ -1827,8 +1849,7 @@ static const struct efx_nic_reg_table efx_nic_reg_tables[] = { REGISTER_TABLE_BB_CZ(TX_DESC_PTR_TBL), REGISTER_TABLE_AA(EVQ_PTR_TBL_KER), REGISTER_TABLE_BB_CZ(EVQ_PTR_TBL), - /* The register buffer is allocated with slab, so we can't - * reasonably read all of the buffer table (up to 8MB!). + /* We can't reasonably read all of the buffer table (up to 8MB!). * However this driver will only use a few entries. Reading * 1K entries allows for some expansion of queue count and * size before we need to change the version. */ @@ -1836,7 +1857,6 @@ static const struct efx_nic_reg_table efx_nic_reg_tables[] = { A, A, 8, 1024), REGISTER_TABLE_DIMENSIONS(BUF_FULL_TBL, FR_BZ_BUF_FULL_TBL, B, Z, 8, 1024), - /* RX_FILTER_TBL{0,1} is huge and not used by this driver */ REGISTER_TABLE_CZ(RX_MAC_FILTER_TBL0), REGISTER_TABLE_BB_CZ(TIMER_TBL), REGISTER_TABLE_BB_CZ(TX_PACE_TBL), @@ -1846,6 +1866,7 @@ static const struct efx_nic_reg_table efx_nic_reg_tables[] = { REGISTER_TABLE_CZ(MC_TREG_SMEM), /* MSIX_PBA_TABLE is not mapped */ /* SRM_DBG is not mapped (and is redundant with BUF_FLL_TBL) */ + REGISTER_TABLE_BZ(RX_FILTER_TBL0), }; size_t efx_nic_get_regs_len(struct efx_nic *efx) diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h index 5bc26137257..1dab609757f 100644 --- a/drivers/net/sfc/phy.h +++ b/drivers/net/sfc/phy.h @@ -11,17 +11,12 @@ #define EFX_PHY_H /**************************************************************************** - * 10Xpress (SFX7101 and SFT9001) PHYs + * 10Xpress (SFX7101) PHY */ extern struct efx_phy_operations falcon_sfx7101_phy_ops; -extern struct efx_phy_operations falcon_sft9001_phy_ops; extern void tenxpress_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); -/* Wait for the PHY to boot. Return 0 on success, -EINVAL if the PHY failed - * to boot due to corrupt flash, or some other negative error code. */ -extern int sft9001_wait_boot(struct efx_nic *efx); - /**************************************************************************** * AMCC/Quake QT202x PHYs */ @@ -42,6 +37,17 @@ extern struct efx_phy_operations falcon_qt202x_phy_ops; extern void falcon_qt202x_set_led(struct efx_nic *p, int led, int state); /**************************************************************************** +* Transwitch CX4 retimer +*/ +extern struct efx_phy_operations falcon_txc_phy_ops; + +#define TXC_GPIO_DIR_INPUT 0 +#define TXC_GPIO_DIR_OUTPUT 1 + +extern void falcon_txc_set_gpio_dir(struct efx_nic *efx, int pin, int dir); +extern void falcon_txc_set_gpio_val(struct efx_nic *efx, int pin, int val); + +/**************************************************************************** * Siena managed PHYs */ extern struct efx_phy_operations efx_mcdi_phy_ops; diff --git a/drivers/net/sfc/regs.h b/drivers/net/sfc/regs.h index 18a3be42834..96430ed81c3 100644 --- a/drivers/net/sfc/regs.h +++ b/drivers/net/sfc/regs.h @@ -2893,6 +2893,20 @@ #define FRF_AB_XX_FORCE_SIG_WIDTH 8 #define FFE_AB_XX_FORCE_SIG_ALL_LANES 0xff +/* RX_MAC_FILTER_TBL0 */ +/* RMFT_DEST_MAC is wider than 32 bits */ +#define FRF_CZ_RMFT_DEST_MAC_LO_LBN 12 +#define FRF_CZ_RMFT_DEST_MAC_LO_WIDTH 32 +#define FRF_CZ_RMFT_DEST_MAC_HI_LBN 44 +#define FRF_CZ_RMFT_DEST_MAC_HI_WIDTH 16 + +/* TX_MAC_FILTER_TBL0 */ +/* TMFT_SRC_MAC is wider than 32 bits */ +#define FRF_CZ_TMFT_SRC_MAC_LO_LBN 12 +#define FRF_CZ_TMFT_SRC_MAC_LO_WIDTH 32 +#define FRF_CZ_TMFT_SRC_MAC_HI_LBN 44 +#define FRF_CZ_TMFT_SRC_MAC_HI_WIDTH 16 + /* 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/rx.c b/drivers/net/sfc/rx.c index 799c461ce7b..6d0959b5158 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -133,7 +133,7 @@ static int efx_init_rx_buffers_skb(struct efx_rx_queue *rx_queue) unsigned index, count; for (count = 0; count < EFX_RX_BATCH; ++count) { - index = rx_queue->added_count & EFX_RXQ_MASK; + 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); @@ -208,7 +208,7 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue) dma_addr += sizeof(struct efx_rx_page_state); split: - index = rx_queue->added_count & EFX_RXQ_MASK; + 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; @@ -285,7 +285,7 @@ static void efx_resurrect_rx_buffer(struct efx_rx_queue *rx_queue, * we'd like to insert an additional descriptor whilst leaving * EFX_RXD_HEAD_ROOM for the non-recycle path */ fill_level = (rx_queue->added_count - rx_queue->removed_count + 2); - if (unlikely(fill_level >= EFX_RXQ_SIZE - EFX_RXD_HEAD_ROOM)) { + if (unlikely(fill_level > rx_queue->max_fill)) { /* We could place "state" on a list, and drain the list in * efx_fast_push_rx_descriptors(). For now, this will do. */ return; @@ -294,7 +294,7 @@ static void efx_resurrect_rx_buffer(struct efx_rx_queue *rx_queue, ++state->refcnt; get_page(rx_buf->page); - index = rx_queue->added_count & EFX_RXQ_MASK; + 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; @@ -311,7 +311,7 @@ static void efx_recycle_rx_buffer(struct efx_channel *channel, struct efx_rx_buffer *rx_buf) { struct efx_nic *efx = channel->efx; - struct efx_rx_queue *rx_queue = &efx->rx_queue[channel->channel]; + struct efx_rx_queue *rx_queue = efx_channel_get_rx_queue(channel); struct efx_rx_buffer *new_buf; unsigned index; @@ -319,7 +319,7 @@ static void efx_recycle_rx_buffer(struct efx_channel *channel, page_count(rx_buf->page) == 1) efx_resurrect_rx_buffer(rx_queue, rx_buf); - index = rx_queue->added_count & EFX_RXQ_MASK; + 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)); @@ -341,13 +341,13 @@ static void efx_recycle_rx_buffer(struct efx_channel *channel, */ void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue) { - struct efx_channel *channel = rx_queue->channel; + struct efx_channel *channel = efx_rx_queue_channel(rx_queue); unsigned fill_level; int space, rc = 0; /* Calculate current fill level, and exit if we don't need to fill */ fill_level = (rx_queue->added_count - rx_queue->removed_count); - EFX_BUG_ON_PARANOID(fill_level > EFX_RXQ_SIZE); + EFX_BUG_ON_PARANOID(fill_level > rx_queue->efx->rxq_entries); if (fill_level >= rx_queue->fast_fill_trigger) goto out; @@ -364,7 +364,8 @@ void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue) netif_vdbg(rx_queue->efx, rx_status, rx_queue->efx->net_dev, "RX queue %d fast-filling descriptor ring from" " level %d to level %d using %s allocation\n", - rx_queue->queue, fill_level, rx_queue->fast_fill_limit, + efx_rx_queue_index(rx_queue), fill_level, + rx_queue->fast_fill_limit, channel->rx_alloc_push_pages ? "page" : "skb"); do { @@ -382,7 +383,7 @@ void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue) netif_vdbg(rx_queue->efx, rx_status, rx_queue->efx->net_dev, "RX queue %d fast-filled descriptor ring " - "to level %d\n", rx_queue->queue, + "to level %d\n", efx_rx_queue_index(rx_queue), rx_queue->added_count - rx_queue->removed_count); out: @@ -393,7 +394,7 @@ void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue) void efx_rx_slow_fill(unsigned long context) { struct efx_rx_queue *rx_queue = (struct efx_rx_queue *)context; - struct efx_channel *channel = rx_queue->channel; + struct efx_channel *channel = efx_rx_queue_channel(rx_queue); /* Post an event to cause NAPI to run and refill the queue */ efx_nic_generate_fill_event(channel); @@ -421,7 +422,7 @@ static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue, netif_err(efx, rx_err, efx->net_dev, " RX queue %d seriously overlength " "RX event (0x%x > 0x%x+0x%x). Leaking\n", - rx_queue->queue, len, max_len, + efx_rx_queue_index(rx_queue), len, max_len, efx->type->rx_buffer_padding); /* If this buffer was skb-allocated, then the meta * data at the end of the skb will be trashed. So @@ -434,10 +435,10 @@ static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue, netif_err(efx, rx_err, efx->net_dev, " RX queue %d overlength RX event " "(0x%x > 0x%x)\n", - rx_queue->queue, len, max_len); + efx_rx_queue_index(rx_queue), len, max_len); } - rx_queue->channel->n_rx_overlength++; + efx_rx_queue_channel(rx_queue)->n_rx_overlength++; } /* Pass a received packet up through the generic LRO stack @@ -507,7 +508,7 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, unsigned int len, bool checksummed, bool discard) { struct efx_nic *efx = rx_queue->efx; - struct efx_channel *channel = rx_queue->channel; + struct efx_channel *channel = efx_rx_queue_channel(rx_queue); struct efx_rx_buffer *rx_buf; bool leak_packet = false; @@ -528,7 +529,7 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, netif_vdbg(efx, rx_status, efx->net_dev, "RX queue %d received id %x at %llx+%x %s%s\n", - rx_queue->queue, index, + efx_rx_queue_index(rx_queue), index, (unsigned long long)rx_buf->dma_addr, len, (checksummed ? " [SUMMED]" : ""), (discard ? " [DISCARD]" : "")); @@ -560,12 +561,11 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, */ rx_buf->len = len; out: - if (rx_queue->channel->rx_pkt) - __efx_rx_packet(rx_queue->channel, - rx_queue->channel->rx_pkt, - rx_queue->channel->rx_pkt_csummed); - rx_queue->channel->rx_pkt = rx_buf; - rx_queue->channel->rx_pkt_csummed = checksummed; + if (channel->rx_pkt) + __efx_rx_packet(channel, + channel->rx_pkt, channel->rx_pkt_csummed); + channel->rx_pkt = rx_buf; + channel->rx_pkt_csummed = checksummed; } /* Handle a received packet. Second half: Touches packet payload. */ @@ -615,7 +615,7 @@ void __efx_rx_packet(struct efx_channel *channel, EFX_BUG_ON_PARANOID(!skb); /* Set the SKB flags */ - skb->ip_summed = CHECKSUM_NONE; + skb_checksum_none_assert(skb); /* Pass the packet up */ netif_receive_skb(skb); @@ -650,15 +650,22 @@ void efx_rx_strategy(struct efx_channel *channel) int efx_probe_rx_queue(struct efx_rx_queue *rx_queue) { struct efx_nic *efx = rx_queue->efx; - unsigned int rxq_size; + unsigned int entries; int rc; + /* Create the smallest power-of-two aligned ring */ + entries = max(roundup_pow_of_two(efx->rxq_entries), EFX_MIN_DMAQ_SIZE); + EFX_BUG_ON_PARANOID(entries > EFX_MAX_DMAQ_SIZE); + rx_queue->ptr_mask = entries - 1; + netif_dbg(efx, probe, efx->net_dev, - "creating RX queue %d\n", rx_queue->queue); + "creating RX queue %d size %#x mask %#x\n", + efx_rx_queue_index(rx_queue), efx->rxq_entries, + rx_queue->ptr_mask); /* Allocate RX buffers */ - rxq_size = EFX_RXQ_SIZE * sizeof(*rx_queue->buffer); - rx_queue->buffer = kzalloc(rxq_size, GFP_KERNEL); + rx_queue->buffer = kzalloc(entries * sizeof(*rx_queue->buffer), + GFP_KERNEL); if (!rx_queue->buffer) return -ENOMEM; @@ -672,20 +679,20 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue) void efx_init_rx_queue(struct efx_rx_queue *rx_queue) { + struct efx_nic *efx = rx_queue->efx; unsigned int max_fill, trigger, limit; netif_dbg(rx_queue->efx, drv, rx_queue->efx->net_dev, - "initialising RX queue %d\n", rx_queue->queue); + "initialising RX queue %d\n", efx_rx_queue_index(rx_queue)); /* Initialise ptr fields */ rx_queue->added_count = 0; rx_queue->notified_count = 0; rx_queue->removed_count = 0; rx_queue->min_fill = -1U; - rx_queue->min_overfill = -1U; /* Initialise limit fields */ - max_fill = EFX_RXQ_SIZE - EFX_RXD_HEAD_ROOM; + max_fill = efx->rxq_entries - EFX_RXD_HEAD_ROOM; trigger = max_fill * min(rx_refill_threshold, 100U) / 100U; limit = max_fill * min(rx_refill_limit, 100U) / 100U; @@ -703,14 +710,14 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue) struct efx_rx_buffer *rx_buf; netif_dbg(rx_queue->efx, drv, rx_queue->efx->net_dev, - "shutting down RX queue %d\n", rx_queue->queue); + "shutting down RX queue %d\n", efx_rx_queue_index(rx_queue)); del_timer_sync(&rx_queue->slow_fill); efx_nic_fini_rx(rx_queue); /* Release RX buffers NB start at index 0 not current HW ptr */ if (rx_queue->buffer) { - for (i = 0; i <= EFX_RXQ_MASK; i++) { + for (i = 0; i <= rx_queue->ptr_mask; i++) { rx_buf = efx_rx_buffer(rx_queue, i); efx_fini_rx_buffer(rx_queue, rx_buf); } @@ -720,7 +727,7 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue) void efx_remove_rx_queue(struct efx_rx_queue *rx_queue) { netif_dbg(rx_queue->efx, drv, rx_queue->efx->net_dev, - "destroying RX queue %d\n", rx_queue->queue); + "destroying RX queue %d\n", efx_rx_queue_index(rx_queue)); efx_nic_remove_rx(rx_queue); diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 85f015f005d..0ebfb99f129 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -48,6 +48,16 @@ static const unsigned char payload_source[ETH_ALEN] = { static const char payload_msg[] = "Hello world! This is an Efx loopback test in progress!"; +/* Interrupt mode names */ +static const unsigned int efx_interrupt_mode_max = EFX_INT_MODE_MAX; +static const char *efx_interrupt_mode_names[] = { + [EFX_INT_MODE_MSIX] = "MSI-X", + [EFX_INT_MODE_MSI] = "MSI", + [EFX_INT_MODE_LEGACY] = "legacy", +}; +#define INT_MODE(efx) \ + STRING_TABLE_LOOKUP(efx->interrupt_mode, efx_interrupt_mode) + /** * efx_loopback_state - persistent state during a loopback selftest * @flush: Drop all packets in efx_loopback_rx_packet @@ -506,7 +516,7 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, for (i = 0; i < 3; i++) { /* Determine how many packets to send */ - state->packet_count = EFX_TXQ_SIZE / 3; + state->packet_count = efx->txq_entries / 3; state->packet_count = min(1 << (i << 2), state->packet_count); state->skbs = kzalloc(sizeof(state->skbs[0]) * state->packet_count, GFP_KERNEL); @@ -567,7 +577,7 @@ static int efx_wait_for_link(struct efx_nic *efx) efx->type->monitor(efx); mutex_unlock(&efx->mac_lock); } else { - struct efx_channel *channel = &efx->channel[0]; + struct efx_channel *channel = efx_get_channel(efx, 0); if (channel->work_pending) efx_process_channel_now(channel); } @@ -594,6 +604,7 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, { enum efx_loopback_mode mode; struct efx_loopback_state *state; + struct efx_channel *channel = efx_get_channel(efx, 0); struct efx_tx_queue *tx_queue; int rc = 0; @@ -634,7 +645,7 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, } /* Test both types of TX queue */ - efx_for_each_channel_tx_queue(tx_queue, &efx->channel[0]) { + efx_for_each_channel_tx_queue(tx_queue, channel) { state->offload_csum = (tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD); rc = efx_test_loopback(tx_queue, diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index 3fab030f8ab..45236f58a25 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -129,7 +129,7 @@ static int siena_probe_port(struct efx_nic *efx) return 0; } -void siena_remove_port(struct efx_nic *efx) +static void siena_remove_port(struct efx_nic *efx) { efx->phy_op->remove(efx); efx_nic_free_buffer(efx, &efx->stats_buffer); @@ -450,7 +450,7 @@ static int siena_try_update_nic_stats(struct efx_nic *efx) mac_stats->rx_bad_bytes); MAC_STAT(rx_packets, RX_PKTS); MAC_STAT(rx_good, RX_GOOD_PKTS); - mac_stats->rx_bad = mac_stats->rx_packets - mac_stats->rx_good; + MAC_STAT(rx_bad, RX_BAD_FCS_PKTS); MAC_STAT(rx_pause, RX_PAUSE_PKTS); MAC_STAT(rx_control, RX_CONTROL_PKTS); MAC_STAT(rx_unicast, RX_UNICAST_PKTS); @@ -651,6 +651,6 @@ struct efx_nic_type siena_a0_nic_type = { .tx_dc_base = 0x88000, .rx_dc_base = 0x68000, .offload_features = (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_RXHASH), + NETIF_F_RXHASH | NETIF_F_NTUPLE), .reset_world_flags = ETH_RESET_MGMT << ETH_RESET_SHARED_SHIFT, }; diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 6791be90c2f..1bc6c48c96e 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -19,10 +19,7 @@ #include "workarounds.h" #include "selftest.h" -/* We expect these MMDs to be in the package. SFT9001 also has a - * clause 22 extension MMD, but since it doesn't have all the generic - * MMD registers it is pointless to include it here. - */ +/* We expect these MMDs to be in the package. */ #define TENXPRESS_REQUIRED_DEVS (MDIO_DEVS_PMAPMD | \ MDIO_DEVS_PCS | \ MDIO_DEVS_PHYXS | \ @@ -33,12 +30,6 @@ (1 << LOOPBACK_PMAPMD) | \ (1 << LOOPBACK_PHYXS_WS)) -#define SFT9001_LOOPBACKS ((1 << LOOPBACK_GPHY) | \ - (1 << LOOPBACK_PHYXS) | \ - (1 << LOOPBACK_PCS) | \ - (1 << LOOPBACK_PMAPMD) | \ - (1 << LOOPBACK_PHYXS_WS)) - /* We complain if we fail to see the link partner as 10G capable this many * times in a row (must be > 1 as sampling the autoneg. registers is racy) */ @@ -50,9 +41,8 @@ #define PMA_PMD_EXT_GMII_EN_WIDTH 1 #define PMA_PMD_EXT_CLK_OUT_LBN 2 #define PMA_PMD_EXT_CLK_OUT_WIDTH 1 -#define PMA_PMD_LNPGA_POWERDOWN_LBN 8 /* SFX7101 only */ +#define PMA_PMD_LNPGA_POWERDOWN_LBN 8 #define PMA_PMD_LNPGA_POWERDOWN_WIDTH 1 -#define PMA_PMD_EXT_CLK312_LBN 8 /* SFT9001 only */ #define PMA_PMD_EXT_CLK312_WIDTH 1 #define PMA_PMD_EXT_LPOWER_LBN 12 #define PMA_PMD_EXT_LPOWER_WIDTH 1 @@ -84,7 +74,6 @@ #define PMA_PMD_LED_FLASH (3) #define PMA_PMD_LED_MASK 3 /* All LEDs under hardware control */ -#define SFT9001_PMA_PMD_LED_DEFAULT 0 /* Green and Amber under hardware control, Red off */ #define SFX7101_PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN) @@ -98,31 +87,7 @@ #define PMA_PMD_SPEED_LBN 4 #define PMA_PMD_SPEED_WIDTH 4 -/* Cable diagnostics - SFT9001 only */ -#define PMA_PMD_CDIAG_CTRL_REG 49213 -#define CDIAG_CTRL_IMMED_LBN 15 -#define CDIAG_CTRL_BRK_LINK_LBN 12 -#define CDIAG_CTRL_IN_PROG_LBN 11 -#define CDIAG_CTRL_LEN_UNIT_LBN 10 -#define CDIAG_CTRL_LEN_METRES 1 -#define PMA_PMD_CDIAG_RES_REG 49174 -#define CDIAG_RES_A_LBN 12 -#define CDIAG_RES_B_LBN 8 -#define CDIAG_RES_C_LBN 4 -#define CDIAG_RES_D_LBN 0 -#define CDIAG_RES_WIDTH 4 -#define CDIAG_RES_OPEN 2 -#define CDIAG_RES_OK 1 -#define CDIAG_RES_INVALID 0 -/* Set of 4 registers for pairs A-D */ -#define PMA_PMD_CDIAG_LEN_REG 49175 - -/* Serdes control registers - SFT9001 only */ -#define PMA_PMD_CSERDES_CTRL_REG 64258 -/* Set the 156.25 MHz output to 312.5 MHz to drive Falcon's XMAC */ -#define PMA_PMD_CSERDES_DEFAULT 0x000f - -/* Misc register defines - SFX7101 only */ +/* Misc register defines */ #define PCS_CLOCK_CTRL_REG 55297 #define PLL312_RST_N_LBN 2 @@ -185,121 +150,17 @@ struct tenxpress_phy_data { int bad_lp_tries; }; -static ssize_t show_phy_short_reach(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); - int reg; - - reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR); - return sprintf(buf, "%d\n", !!(reg & MDIO_PMA_10GBT_TXPWR_SHORT)); -} - -static ssize_t set_phy_short_reach(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); - int rc; - - rtnl_lock(); - if (efx->state != STATE_RUNNING) { - rc = -EBUSY; - } else { - efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR, - MDIO_PMA_10GBT_TXPWR_SHORT, - count != 0 && *buf != '0'); - rc = efx_reconfigure_port(efx); - } - rtnl_unlock(); - - return rc < 0 ? rc : (ssize_t)count; -} - -static DEVICE_ATTR(phy_short_reach, 0644, show_phy_short_reach, - set_phy_short_reach); - -int sft9001_wait_boot(struct efx_nic *efx) -{ - unsigned long timeout = jiffies + HZ + 1; - int boot_stat; - - for (;;) { - boot_stat = efx_mdio_read(efx, MDIO_MMD_PCS, - PCS_BOOT_STATUS_REG); - if (boot_stat >= 0) { - netif_dbg(efx, hw, efx->net_dev, - "PHY boot status = %#x\n", boot_stat); - switch (boot_stat & - ((1 << PCS_BOOT_FATAL_ERROR_LBN) | - (3 << PCS_BOOT_PROGRESS_LBN) | - (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN) | - (1 << PCS_BOOT_CODE_STARTED_LBN))) { - case ((1 << PCS_BOOT_FATAL_ERROR_LBN) | - (PCS_BOOT_PROGRESS_CHECKSUM << - PCS_BOOT_PROGRESS_LBN)): - case ((1 << PCS_BOOT_FATAL_ERROR_LBN) | - (PCS_BOOT_PROGRESS_INIT << - PCS_BOOT_PROGRESS_LBN) | - (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN)): - return -EINVAL; - case ((PCS_BOOT_PROGRESS_WAIT_MDIO << - PCS_BOOT_PROGRESS_LBN) | - (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN)): - return (efx->phy_mode & PHY_MODE_SPECIAL) ? - 0 : -EIO; - case ((PCS_BOOT_PROGRESS_JUMP << - PCS_BOOT_PROGRESS_LBN) | - (1 << PCS_BOOT_CODE_STARTED_LBN)): - case ((PCS_BOOT_PROGRESS_JUMP << - PCS_BOOT_PROGRESS_LBN) | - (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN) | - (1 << PCS_BOOT_CODE_STARTED_LBN)): - return (efx->phy_mode & PHY_MODE_SPECIAL) ? - -EIO : 0; - default: - if (boot_stat & (1 << PCS_BOOT_FATAL_ERROR_LBN)) - return -EIO; - break; - } - } - - if (time_after_eq(jiffies, timeout)) - return -ETIMEDOUT; - - msleep(50); - } -} - static int tenxpress_init(struct efx_nic *efx) { - int reg; - - if (efx->phy_type == PHY_TYPE_SFX7101) { - /* Enable 312.5 MHz clock */ - efx_mdio_write(efx, MDIO_MMD_PCS, PCS_TEST_SELECT_REG, - 1 << CLK312_EN_LBN); - } else { - /* Enable 312.5 MHz clock and GMII */ - reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG); - reg |= ((1 << PMA_PMD_EXT_GMII_EN_LBN) | - (1 << PMA_PMD_EXT_CLK_OUT_LBN) | - (1 << PMA_PMD_EXT_CLK312_LBN) | - (1 << PMA_PMD_EXT_ROBUST_LBN)); - - efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg); - efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, - GPHY_XCONTROL_REG, 1 << GPHY_ISOLATE_LBN, - false); - } + /* Enable 312.5 MHz clock */ + efx_mdio_write(efx, MDIO_MMD_PCS, PCS_TEST_SELECT_REG, + 1 << CLK312_EN_LBN); /* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */ - if (efx->phy_type == PHY_TYPE_SFX7101) { - efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG, - 1 << PMA_PMA_LED_ACTIVITY_LBN, true); - efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, - SFX7101_PMA_PMD_LED_DEFAULT); - } + efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG, + 1 << PMA_PMA_LED_ACTIVITY_LBN, true); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, + SFX7101_PMA_PMD_LED_DEFAULT); return 0; } @@ -307,7 +168,6 @@ static int tenxpress_init(struct efx_nic *efx) static int tenxpress_phy_probe(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data; - int rc; /* Allocate phy private storage */ phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); @@ -316,42 +176,15 @@ static int tenxpress_phy_probe(struct efx_nic *efx) efx->phy_data = phy_data; phy_data->phy_mode = efx->phy_mode; - /* Create any special files */ - if (efx->phy_type == PHY_TYPE_SFT9001B) { - rc = device_create_file(&efx->pci_dev->dev, - &dev_attr_phy_short_reach); - if (rc) - goto fail; - } - - if (efx->phy_type == PHY_TYPE_SFX7101) { - efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS; - efx->mdio.mode_support = MDIO_SUPPORTS_C45; - - efx->loopback_modes = SFX7101_LOOPBACKS | FALCON_XMAC_LOOPBACKS; + efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS; + efx->mdio.mode_support = MDIO_SUPPORTS_C45; - efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg | - ADVERTISED_10000baseT_Full); - } else { - efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS; - efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; + efx->loopback_modes = SFX7101_LOOPBACKS | FALCON_XMAC_LOOPBACKS; - efx->loopback_modes = (SFT9001_LOOPBACKS | - FALCON_XMAC_LOOPBACKS | - FALCON_GMAC_LOOPBACKS); - - efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg | - ADVERTISED_10000baseT_Full | - ADVERTISED_1000baseT_Full | - ADVERTISED_100baseT_Full); - } + efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg | + ADVERTISED_10000baseT_Full); return 0; - -fail: - kfree(efx->phy_data); - efx->phy_data = NULL; - return rc; } static int tenxpress_phy_init(struct efx_nic *efx) @@ -361,16 +194,6 @@ static int tenxpress_phy_init(struct efx_nic *efx) falcon_board(efx)->type->init_phy(efx); if (!(efx->phy_mode & PHY_MODE_SPECIAL)) { - if (efx->phy_type == PHY_TYPE_SFT9001A) { - int reg; - reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, - PMA_PMD_XCONTROL_REG); - reg |= (1 << PMA_PMD_EXT_SSR_LBN); - efx_mdio_write(efx, MDIO_MMD_PMAPMD, - PMA_PMD_XCONTROL_REG, reg); - mdelay(200); - } - rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS); if (rc < 0) return rc; @@ -403,7 +226,7 @@ static int tenxpress_special_reset(struct efx_nic *efx) { int rc, reg; - /* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so + /* The XGMAC clock is driven from the SFX7101 312MHz clock, so * a special software reset can glitch the XGMAC sufficiently for stats * requests to fail. */ falcon_stop_nic_stats(efx); @@ -484,53 +307,18 @@ static bool sfx7101_link_ok(struct efx_nic *efx) MDIO_DEVS_PHYXS); } -static bool sft9001_link_ok(struct efx_nic *efx, struct ethtool_cmd *ecmd) -{ - u32 reg; - - if (efx_phy_mode_disabled(efx->phy_mode)) - return false; - else if (efx->loopback_mode == LOOPBACK_GPHY) - return true; - else if (efx->loopback_mode) - return efx_mdio_links_ok(efx, - MDIO_DEVS_PMAPMD | - MDIO_DEVS_PHYXS); - - /* We must use the same definition of link state as LASI, - * otherwise we can miss a link state transition - */ - if (ecmd->speed == 10000) { - reg = efx_mdio_read(efx, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT1); - return reg & MDIO_PCS_10GBRT_STAT1_BLKLK; - } else { - reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_STATUS_REG); - return reg & (1 << C22EXT_STATUS_LINK_LBN); - } -} - static void tenxpress_ext_loopback(struct efx_nic *efx) { efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, PHYXS_TEST1, 1 << LOOPBACK_NEAR_LBN, efx->loopback_mode == LOOPBACK_PHYXS); - if (efx->phy_type != PHY_TYPE_SFX7101) - efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, GPHY_XCONTROL_REG, - 1 << GPHY_LOOPBACK_NEAR_LBN, - efx->loopback_mode == LOOPBACK_GPHY); } static void tenxpress_low_power(struct efx_nic *efx) { - if (efx->phy_type == PHY_TYPE_SFX7101) - efx_mdio_set_mmds_lpower( - efx, !!(efx->phy_mode & PHY_MODE_LOW_POWER), - TENXPRESS_REQUIRED_DEVS); - else - efx_mdio_set_flag( - efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, - 1 << PMA_PMD_EXT_LPOWER_LBN, - !!(efx->phy_mode & PHY_MODE_LOW_POWER)); + efx_mdio_set_mmds_lpower( + efx, !!(efx->phy_mode & PHY_MODE_LOW_POWER), + TENXPRESS_REQUIRED_DEVS); } static int tenxpress_phy_reconfigure(struct efx_nic *efx) @@ -550,12 +338,7 @@ static int tenxpress_phy_reconfigure(struct efx_nic *efx) if (loop_reset || phy_mode_change) { tenxpress_special_reset(efx); - - /* Reset XAUI if we were in 10G, and are staying - * in 10G. If we're moving into and out of 10G - * then xaui will be reset anyway */ - if (EFX_IS10G(efx)) - falcon_reset_xaui(efx); + falcon_reset_xaui(efx); } tenxpress_low_power(efx); @@ -578,29 +361,12 @@ static bool tenxpress_phy_poll(struct efx_nic *efx) { struct efx_link_state old_state = efx->link_state; - if (efx->phy_type == PHY_TYPE_SFX7101) { - efx->link_state.up = sfx7101_link_ok(efx); - efx->link_state.speed = 10000; - efx->link_state.fd = true; - efx->link_state.fc = efx_mdio_get_pause(efx); - - sfx7101_check_bad_lp(efx, efx->link_state.up); - } else { - struct ethtool_cmd ecmd; - - /* Check the LASI alarm first */ - if (efx->loopback_mode == LOOPBACK_NONE && - !(efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT) & - MDIO_PMA_LASI_LSALARM)) - return false; + efx->link_state.up = sfx7101_link_ok(efx); + efx->link_state.speed = 10000; + efx->link_state.fd = true; + efx->link_state.fc = efx_mdio_get_pause(efx); - tenxpress_get_settings(efx, &ecmd); - - efx->link_state.up = sft9001_link_ok(efx, &ecmd); - efx->link_state.speed = ecmd.speed; - efx->link_state.fd = (ecmd.duplex == DUPLEX_FULL); - efx->link_state.fc = efx_mdio_get_pause(efx); - } + sfx7101_check_bad_lp(efx, efx->link_state.up); return !efx_link_state_equal(&efx->link_state, &old_state); } @@ -621,10 +387,6 @@ static void sfx7101_phy_fini(struct efx_nic *efx) static void tenxpress_phy_remove(struct efx_nic *efx) { - if (efx->phy_type == PHY_TYPE_SFT9001B) - device_remove_file(&efx->pci_dev->dev, - &dev_attr_phy_short_reach); - kfree(efx->phy_data); efx->phy_data = NULL; } @@ -647,10 +409,7 @@ void tenxpress_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) (PMA_PMD_LED_ON << PMA_PMD_LED_LINK_LBN); break; default: - if (efx->phy_type == PHY_TYPE_SFX7101) - reg = SFX7101_PMA_PMD_LED_DEFAULT; - else - reg = SFT9001_PMA_PMD_LED_DEFAULT; + reg = SFX7101_PMA_PMD_LED_DEFAULT; break; } @@ -685,102 +444,12 @@ sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags) return rc; } -static const char *const sft9001_test_names[] = { - "bist", - "cable.pairA.status", - "cable.pairB.status", - "cable.pairC.status", - "cable.pairD.status", - "cable.pairA.length", - "cable.pairB.length", - "cable.pairC.length", - "cable.pairD.length", -}; - -static const char *sft9001_test_name(struct efx_nic *efx, unsigned int index) -{ - if (index < ARRAY_SIZE(sft9001_test_names)) - return sft9001_test_names[index]; - return NULL; -} - -static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags) -{ - int rc = 0, rc2, i, ctrl_reg, res_reg; - - /* Initialise cable diagnostic results to unknown failure */ - for (i = 1; i < 9; ++i) - results[i] = -1; - - /* Run cable diagnostics; wait up to 5 seconds for them to complete. - * A cable fault is not a self-test failure, but a timeout is. */ - ctrl_reg = ((1 << CDIAG_CTRL_IMMED_LBN) | - (CDIAG_CTRL_LEN_METRES << CDIAG_CTRL_LEN_UNIT_LBN)); - if (flags & ETH_TEST_FL_OFFLINE) { - /* Break the link in order to run full diagnostics. We - * must reset the PHY to resume normal service. */ - ctrl_reg |= (1 << CDIAG_CTRL_BRK_LINK_LBN); - } - efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG, - ctrl_reg); - i = 0; - while (efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG) & - (1 << CDIAG_CTRL_IN_PROG_LBN)) { - if (++i == 50) { - rc = -ETIMEDOUT; - goto out; - } - msleep(100); - } - res_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_RES_REG); - for (i = 0; i < 4; i++) { - int pair_res = - (res_reg >> (CDIAG_RES_A_LBN - i * CDIAG_RES_WIDTH)) - & ((1 << CDIAG_RES_WIDTH) - 1); - int len_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, - PMA_PMD_CDIAG_LEN_REG + i); - if (pair_res == CDIAG_RES_OK) - results[1 + i] = 1; - else if (pair_res == CDIAG_RES_INVALID) - results[1 + i] = -1; - else - results[1 + i] = -pair_res; - if (pair_res != CDIAG_RES_INVALID && - pair_res != CDIAG_RES_OPEN && - len_reg != 0xffff) - results[5 + i] = len_reg; - } - -out: - if (flags & ETH_TEST_FL_OFFLINE) { - /* Reset, running the BIST and then resuming normal service. */ - rc2 = tenxpress_special_reset(efx); - results[0] = rc2 ? -1 : 1; - if (!rc) - rc = rc2; - - efx_mdio_an_reconfigure(efx); - } - - return rc; -} - static void tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { u32 adv = 0, lpa = 0; int reg; - if (efx->phy_type != PHY_TYPE_SFX7101) { - reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_CTRL); - if (reg & (1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN)) - adv |= ADVERTISED_1000baseT_Full; - reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_STATUS); - if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_HD_LBN)) - lpa |= ADVERTISED_1000baseT_Half; - if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_FD_LBN)) - lpa |= ADVERTISED_1000baseT_Full; - } reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL); if (reg & MDIO_AN_10GBT_CTRL_ADV10G) adv |= ADVERTISED_10000baseT_Full; @@ -790,23 +459,9 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa); - if (efx->phy_type != PHY_TYPE_SFX7101) { - ecmd->supported |= (SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Full); - if (ecmd->speed != SPEED_10000) { - ecmd->eth_tp_mdix = - (efx_mdio_read(efx, MDIO_MMD_PMAPMD, - PMA_PMD_XSTATUS_REG) & - (1 << PMA_PMD_XSTAT_MDIX_LBN)) - ? ETH_TP_MDI_X : ETH_TP_MDI; - } - } - /* In loopback, the PHY automatically brings up the correct interface, * but doesn't advertise the correct speed. So override it */ - if (efx->loopback_mode == LOOPBACK_GPHY) - ecmd->speed = SPEED_1000; - else if (LOOPBACK_EXTERNAL(efx)) + if (LOOPBACK_EXTERNAL(efx)) ecmd->speed = SPEED_10000; } @@ -825,16 +480,6 @@ static void sfx7101_set_npage_adv(struct efx_nic *efx, u32 advertising) advertising & ADVERTISED_10000baseT_Full); } -static void sft9001_set_npage_adv(struct efx_nic *efx, u32 advertising) -{ - efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_CTRL, - 1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN, - advertising & ADVERTISED_1000baseT_Full); - efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, - MDIO_AN_10GBT_CTRL_ADV10G, - advertising & ADVERTISED_10000baseT_Full); -} - struct efx_phy_operations falcon_sfx7101_phy_ops = { .probe = tenxpress_phy_probe, .init = tenxpress_phy_init, @@ -849,18 +494,3 @@ struct efx_phy_operations falcon_sfx7101_phy_ops = { .test_name = sfx7101_test_name, .run_tests = sfx7101_run_tests, }; - -struct efx_phy_operations falcon_sft9001_phy_ops = { - .probe = tenxpress_phy_probe, - .init = tenxpress_phy_init, - .reconfigure = tenxpress_phy_reconfigure, - .poll = tenxpress_phy_poll, - .fini = efx_port_dummy_op_void, - .remove = tenxpress_phy_remove, - .get_settings = tenxpress_get_settings, - .set_settings = tenxpress_set_settings, - .set_npage_adv = sft9001_set_npage_adv, - .test_alive = efx_mdio_test_alive, - .test_name = sft9001_test_name, - .run_tests = sft9001_run_tests, -}; diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index c6942da2c99..11726989fe2 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -28,7 +28,7 @@ * The tx_queue descriptor ring fill-level must fall below this value * before we restart the netif queue */ -#define EFX_TXQ_THRESHOLD (EFX_TXQ_MASK / 2u) +#define EFX_TXQ_THRESHOLD(_efx) ((_efx)->txq_entries / 2u) /* We need to be able to nest calls to netif_tx_stop_queue(), partly * because of the 2 hardware queues associated with each core queue, @@ -37,8 +37,9 @@ void efx_stop_queue(struct efx_channel *channel) { struct efx_nic *efx = channel->efx; + struct efx_tx_queue *tx_queue = efx_channel_get_tx_queue(channel, 0); - if (!channel->tx_queue) + if (!tx_queue) return; spin_lock_bh(&channel->tx_stop_lock); @@ -46,9 +47,8 @@ void efx_stop_queue(struct efx_channel *channel) atomic_inc(&channel->tx_stop_count); netif_tx_stop_queue( - netdev_get_tx_queue( - efx->net_dev, - channel->tx_queue->queue / EFX_TXQ_TYPES)); + netdev_get_tx_queue(efx->net_dev, + tx_queue->queue / EFX_TXQ_TYPES)); spin_unlock_bh(&channel->tx_stop_lock); } @@ -57,8 +57,9 @@ void efx_stop_queue(struct efx_channel *channel) void efx_wake_queue(struct efx_channel *channel) { struct efx_nic *efx = channel->efx; + struct efx_tx_queue *tx_queue = efx_channel_get_tx_queue(channel, 0); - if (!channel->tx_queue) + if (!tx_queue) return; local_bh_disable(); @@ -66,9 +67,8 @@ void efx_wake_queue(struct efx_channel *channel) &channel->tx_stop_lock)) { netif_vdbg(efx, tx_queued, efx->net_dev, "waking TX queue\n"); netif_tx_wake_queue( - netdev_get_tx_queue( - efx->net_dev, - channel->tx_queue->queue / EFX_TXQ_TYPES)); + netdev_get_tx_queue(efx->net_dev, + tx_queue->queue / EFX_TXQ_TYPES)); spin_unlock(&channel->tx_stop_lock); } local_bh_enable(); @@ -207,7 +207,7 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) } fill_level = tx_queue->insert_count - tx_queue->old_read_count; - q_space = EFX_TXQ_MASK - 1 - fill_level; + q_space = efx->txq_entries - 1 - fill_level; /* Map for DMA. Use pci_map_single rather than pci_map_page * since this is more efficient on machines with sparse @@ -244,14 +244,14 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) &tx_queue->read_count; fill_level = (tx_queue->insert_count - tx_queue->old_read_count); - q_space = EFX_TXQ_MASK - 1 - fill_level; + q_space = efx->txq_entries - 1 - fill_level; if (unlikely(q_space-- <= 0)) goto stop; smp_mb(); --tx_queue->stopped; } - insert_ptr = tx_queue->insert_count & EFX_TXQ_MASK; + insert_ptr = tx_queue->insert_count & tx_queue->ptr_mask; buffer = &tx_queue->buffer[insert_ptr]; efx_tsoh_free(tx_queue, buffer); EFX_BUG_ON_PARANOID(buffer->tsoh); @@ -320,7 +320,7 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) /* Work backwards until we hit the original insert pointer value */ while (tx_queue->insert_count != tx_queue->write_count) { --tx_queue->insert_count; - insert_ptr = tx_queue->insert_count & EFX_TXQ_MASK; + insert_ptr = tx_queue->insert_count & tx_queue->ptr_mask; buffer = &tx_queue->buffer[insert_ptr]; efx_dequeue_buffer(tx_queue, buffer); buffer->len = 0; @@ -350,8 +350,8 @@ static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue, struct efx_nic *efx = tx_queue->efx; unsigned int stop_index, read_ptr; - stop_index = (index + 1) & EFX_TXQ_MASK; - read_ptr = tx_queue->read_count & EFX_TXQ_MASK; + stop_index = (index + 1) & tx_queue->ptr_mask; + read_ptr = tx_queue->read_count & tx_queue->ptr_mask; while (read_ptr != stop_index) { struct efx_tx_buffer *buffer = &tx_queue->buffer[read_ptr]; @@ -368,7 +368,7 @@ static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue, buffer->len = 0; ++tx_queue->read_count; - read_ptr = tx_queue->read_count & EFX_TXQ_MASK; + read_ptr = tx_queue->read_count & tx_queue->ptr_mask; } } @@ -390,9 +390,9 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, if (unlikely(efx->port_inhibited)) return NETDEV_TX_BUSY; - tx_queue = &efx->tx_queue[EFX_TXQ_TYPES * skb_get_queue_mapping(skb)]; - if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) - tx_queue += EFX_TXQ_TYPE_OFFLOAD; + tx_queue = efx_get_tx_queue(efx, skb_get_queue_mapping(skb), + skb->ip_summed == CHECKSUM_PARTIAL ? + EFX_TXQ_TYPE_OFFLOAD : 0); return efx_enqueue_skb(tx_queue, skb); } @@ -402,7 +402,7 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) unsigned fill_level; struct efx_nic *efx = tx_queue->efx; - EFX_BUG_ON_PARANOID(index > EFX_TXQ_MASK); + EFX_BUG_ON_PARANOID(index > tx_queue->ptr_mask); efx_dequeue_buffers(tx_queue, index); @@ -412,7 +412,7 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) smp_mb(); if (unlikely(tx_queue->stopped) && likely(efx->port_enabled)) { fill_level = tx_queue->insert_count - tx_queue->read_count; - if (fill_level < EFX_TXQ_THRESHOLD) { + if (fill_level < EFX_TXQ_THRESHOLD(efx)) { EFX_BUG_ON_PARANOID(!efx_dev_registered(efx)); /* Do this under netif_tx_lock(), to avoid racing @@ -430,18 +430,24 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) int efx_probe_tx_queue(struct efx_tx_queue *tx_queue) { struct efx_nic *efx = tx_queue->efx; - unsigned int txq_size; + unsigned int entries; int i, rc; - netif_dbg(efx, probe, efx->net_dev, "creating TX queue %d\n", - tx_queue->queue); + /* Create the smallest power-of-two aligned ring */ + entries = max(roundup_pow_of_two(efx->txq_entries), EFX_MIN_DMAQ_SIZE); + EFX_BUG_ON_PARANOID(entries > EFX_MAX_DMAQ_SIZE); + tx_queue->ptr_mask = entries - 1; + + netif_dbg(efx, probe, efx->net_dev, + "creating TX queue %d size %#x mask %#x\n", + tx_queue->queue, efx->txq_entries, tx_queue->ptr_mask); /* Allocate software ring */ - txq_size = EFX_TXQ_SIZE * sizeof(*tx_queue->buffer); - tx_queue->buffer = kzalloc(txq_size, GFP_KERNEL); + tx_queue->buffer = kzalloc(entries * sizeof(*tx_queue->buffer), + GFP_KERNEL); if (!tx_queue->buffer) return -ENOMEM; - for (i = 0; i <= EFX_TXQ_MASK; ++i) + for (i = 0; i <= tx_queue->ptr_mask; ++i) tx_queue->buffer[i].continuation = true; /* Allocate hardware ring */ @@ -481,7 +487,7 @@ void efx_release_tx_buffers(struct efx_tx_queue *tx_queue) /* Free any buffers left in the ring */ while (tx_queue->read_count != tx_queue->write_count) { - buffer = &tx_queue->buffer[tx_queue->read_count & EFX_TXQ_MASK]; + buffer = &tx_queue->buffer[tx_queue->read_count & tx_queue->ptr_mask]; efx_dequeue_buffer(tx_queue, buffer); buffer->continuation = true; buffer->len = 0; @@ -741,7 +747,7 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue, fill_level = tx_queue->insert_count - tx_queue->old_read_count; /* -1 as there is no way to represent all descriptors used */ - q_space = EFX_TXQ_MASK - 1 - fill_level; + q_space = efx->txq_entries - 1 - fill_level; while (1) { if (unlikely(q_space-- <= 0)) { @@ -757,7 +763,7 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue, *(volatile unsigned *)&tx_queue->read_count; fill_level = (tx_queue->insert_count - tx_queue->old_read_count); - q_space = EFX_TXQ_MASK - 1 - fill_level; + q_space = efx->txq_entries - 1 - fill_level; if (unlikely(q_space-- <= 0)) { *final_buffer = NULL; return 1; @@ -766,13 +772,13 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue, --tx_queue->stopped; } - insert_ptr = tx_queue->insert_count & EFX_TXQ_MASK; + insert_ptr = tx_queue->insert_count & tx_queue->ptr_mask; buffer = &tx_queue->buffer[insert_ptr]; ++tx_queue->insert_count; EFX_BUG_ON_PARANOID(tx_queue->insert_count - - tx_queue->read_count > - EFX_TXQ_MASK); + tx_queue->read_count >= + efx->txq_entries); efx_tsoh_free(tx_queue, buffer); EFX_BUG_ON_PARANOID(buffer->len); @@ -813,7 +819,7 @@ static void efx_tso_put_header(struct efx_tx_queue *tx_queue, { struct efx_tx_buffer *buffer; - buffer = &tx_queue->buffer[tx_queue->insert_count & EFX_TXQ_MASK]; + buffer = &tx_queue->buffer[tx_queue->insert_count & tx_queue->ptr_mask]; efx_tsoh_free(tx_queue, buffer); EFX_BUG_ON_PARANOID(buffer->len); EFX_BUG_ON_PARANOID(buffer->unmap_len); @@ -838,7 +844,7 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue) while (tx_queue->insert_count != tx_queue->write_count) { --tx_queue->insert_count; buffer = &tx_queue->buffer[tx_queue->insert_count & - EFX_TXQ_MASK]; + tx_queue->ptr_mask]; efx_tsoh_free(tx_queue, buffer); EFX_BUG_ON_PARANOID(buffer->skb); if (buffer->unmap_len) { @@ -1168,7 +1174,7 @@ static void efx_fini_tso(struct efx_tx_queue *tx_queue) unsigned i; if (tx_queue->buffer) { - for (i = 0; i <= EFX_TXQ_MASK; ++i) + for (i = 0; i <= tx_queue->ptr_mask; ++i) efx_tsoh_free(tx_queue, &tx_queue->buffer[i]); } diff --git a/drivers/net/sfc/txc43128_phy.c b/drivers/net/sfc/txc43128_phy.c new file mode 100644 index 00000000000..351794a7921 --- /dev/null +++ b/drivers/net/sfc/txc43128_phy.c @@ -0,0 +1,560 @@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * 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 + * by the Free Software Foundation, incorporated herein by reference. + */ + +/* + * Driver for Transwitch/Mysticom CX4 retimer + * see www.transwitch.com, part is TXC-43128 + */ + +#include <linux/delay.h> +#include <linux/slab.h> +#include "efx.h" +#include "mdio_10g.h" +#include "phy.h" +#include "nic.h" + +/* We expect these MMDs to be in the package */ +#define TXC_REQUIRED_DEVS (MDIO_DEVS_PCS | \ + MDIO_DEVS_PMAPMD | \ + MDIO_DEVS_PHYXS) + +#define TXC_LOOPBACKS ((1 << LOOPBACK_PCS) | \ + (1 << LOOPBACK_PMAPMD) | \ + (1 << LOOPBACK_PHYXS_WS)) + +/************************************************************************** + * + * Compile-time config + * + ************************************************************************** + */ +#define TXCNAME "TXC43128" +/* Total length of time we'll wait for the PHY to come out of reset (ms) */ +#define TXC_MAX_RESET_TIME 500 +/* Interval between checks (ms) */ +#define TXC_RESET_WAIT 10 +/* How long to run BIST (us) */ +#define TXC_BIST_DURATION 50 + +/************************************************************************** + * + * Register definitions + * + ************************************************************************** + */ + +/* Command register */ +#define TXC_GLRGS_GLCMD 0xc004 +/* Useful bits in command register */ +/* Lane power-down */ +#define TXC_GLCMD_L01PD_LBN 5 +#define TXC_GLCMD_L23PD_LBN 6 +/* Limited SW reset: preserves configuration but + * initiates a logic reset. Self-clearing */ +#define TXC_GLCMD_LMTSWRST_LBN 14 + +/* Signal Quality Control */ +#define TXC_GLRGS_GSGQLCTL 0xc01a +/* Enable bit */ +#define TXC_GSGQLCT_SGQLEN_LBN 15 +/* Lane selection */ +#define TXC_GSGQLCT_LNSL_LBN 13 +#define TXC_GSGQLCT_LNSL_WIDTH 2 + +/* Analog TX control */ +#define TXC_ALRGS_ATXCTL 0xc040 +/* Lane power-down */ +#define TXC_ATXCTL_TXPD3_LBN 15 +#define TXC_ATXCTL_TXPD2_LBN 14 +#define TXC_ATXCTL_TXPD1_LBN 13 +#define TXC_ATXCTL_TXPD0_LBN 12 + +/* Amplitude on lanes 0, 1 */ +#define TXC_ALRGS_ATXAMP0 0xc041 +/* Amplitude on lanes 2, 3 */ +#define TXC_ALRGS_ATXAMP1 0xc042 +/* Bit position of value for lane 0 (or 2) */ +#define TXC_ATXAMP_LANE02_LBN 3 +/* Bit position of value for lane 1 (or 3) */ +#define TXC_ATXAMP_LANE13_LBN 11 + +#define TXC_ATXAMP_1280_mV 0 +#define TXC_ATXAMP_1200_mV 8 +#define TXC_ATXAMP_1120_mV 12 +#define TXC_ATXAMP_1060_mV 14 +#define TXC_ATXAMP_0820_mV 25 +#define TXC_ATXAMP_0720_mV 26 +#define TXC_ATXAMP_0580_mV 27 +#define TXC_ATXAMP_0440_mV 28 + +#define TXC_ATXAMP_0820_BOTH \ + ((TXC_ATXAMP_0820_mV << TXC_ATXAMP_LANE02_LBN) \ + | (TXC_ATXAMP_0820_mV << TXC_ATXAMP_LANE13_LBN)) + +#define TXC_ATXAMP_DEFAULT 0x6060 /* From databook */ + +/* Preemphasis on lanes 0, 1 */ +#define TXC_ALRGS_ATXPRE0 0xc043 +/* Preemphasis on lanes 2, 3 */ +#define TXC_ALRGS_ATXPRE1 0xc044 + +#define TXC_ATXPRE_NONE 0 +#define TXC_ATXPRE_DEFAULT 0x1010 /* From databook */ + +#define TXC_ALRGS_ARXCTL 0xc045 +/* Lane power-down */ +#define TXC_ARXCTL_RXPD3_LBN 15 +#define TXC_ARXCTL_RXPD2_LBN 14 +#define TXC_ARXCTL_RXPD1_LBN 13 +#define TXC_ARXCTL_RXPD0_LBN 12 + +/* Main control */ +#define TXC_MRGS_CTL 0xc340 +/* Bits in main control */ +#define TXC_MCTL_RESET_LBN 15 /* Self clear */ +#define TXC_MCTL_TXLED_LBN 14 /* 1 to show align status */ +#define TXC_MCTL_RXLED_LBN 13 /* 1 to show align status */ + +/* GPIO output */ +#define TXC_GPIO_OUTPUT 0xc346 +#define TXC_GPIO_DIR 0xc348 + +/* Vendor-specific BIST registers */ +#define TXC_BIST_CTL 0xc280 +#define TXC_BIST_TXFRMCNT 0xc281 +#define TXC_BIST_RX0FRMCNT 0xc282 +#define TXC_BIST_RX1FRMCNT 0xc283 +#define TXC_BIST_RX2FRMCNT 0xc284 +#define TXC_BIST_RX3FRMCNT 0xc285 +#define TXC_BIST_RX0ERRCNT 0xc286 +#define TXC_BIST_RX1ERRCNT 0xc287 +#define TXC_BIST_RX2ERRCNT 0xc288 +#define TXC_BIST_RX3ERRCNT 0xc289 + +/* BIST type (controls bit patter in test) */ +#define TXC_BIST_CTRL_TYPE_LBN 10 +#define TXC_BIST_CTRL_TYPE_TSD 0 /* TranSwitch Deterministic */ +#define TXC_BIST_CTRL_TYPE_CRP 1 /* CRPAT standard */ +#define TXC_BIST_CTRL_TYPE_CJP 2 /* CJPAT standard */ +#define TXC_BIST_CTRL_TYPE_TSR 3 /* TranSwitch pseudo-random */ +/* Set this to 1 for 10 bit and 0 for 8 bit */ +#define TXC_BIST_CTRL_B10EN_LBN 12 +/* Enable BIST (write 0 to disable) */ +#define TXC_BIST_CTRL_ENAB_LBN 13 +/* Stop BIST (self-clears when stop complete) */ +#define TXC_BIST_CTRL_STOP_LBN 14 +/* Start BIST (cleared by writing 1 to STOP) */ +#define TXC_BIST_CTRL_STRT_LBN 15 + +/* Mt. Diablo test configuration */ +#define TXC_MTDIABLO_CTRL 0xc34f +#define TXC_MTDIABLO_CTRL_PMA_LOOP_LBN 10 + +struct txc43128_data { + unsigned long bug10934_timer; + enum efx_phy_mode phy_mode; + enum efx_loopback_mode loopback_mode; +}; + +/* The PHY sometimes needs a reset to bring the link back up. So long as + * it reports link down, we reset it every 5 seconds. + */ +#define BUG10934_RESET_INTERVAL (5 * HZ) + +/* Perform a reset that doesn't clear configuration changes */ +static void txc_reset_logic(struct efx_nic *efx); + +/* Set the output value of a gpio */ +void falcon_txc_set_gpio_val(struct efx_nic *efx, int pin, int on) +{ + efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, TXC_GPIO_OUTPUT, 1 << pin, on); +} + +/* Set up the GPIO direction register */ +void falcon_txc_set_gpio_dir(struct efx_nic *efx, int pin, int dir) +{ + efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, TXC_GPIO_DIR, 1 << pin, dir); +} + +/* Reset the PMA/PMD MMD. The documentation is explicit that this does a + * global reset (it's less clear what reset of other MMDs does).*/ +static int txc_reset_phy(struct efx_nic *efx) +{ + int rc = efx_mdio_reset_mmd(efx, MDIO_MMD_PMAPMD, + TXC_MAX_RESET_TIME / TXC_RESET_WAIT, + TXC_RESET_WAIT); + if (rc < 0) + goto fail; + + /* Check that all the MMDs we expect are present and responding. */ + rc = efx_mdio_check_mmds(efx, TXC_REQUIRED_DEVS, 0); + if (rc < 0) + goto fail; + + return 0; + +fail: + netif_err(efx, hw, efx->net_dev, TXCNAME ": reset timed out!\n"); + return rc; +} + +/* Run a single BIST on one MMD */ +static int txc_bist_one(struct efx_nic *efx, int mmd, int test) +{ + int ctrl, bctl; + int lane; + int rc = 0; + + /* Set PMA to test into loopback using Mt Diablo reg as per app note */ + ctrl = efx_mdio_read(efx, MDIO_MMD_PCS, TXC_MTDIABLO_CTRL); + ctrl |= (1 << TXC_MTDIABLO_CTRL_PMA_LOOP_LBN); + efx_mdio_write(efx, MDIO_MMD_PCS, TXC_MTDIABLO_CTRL, ctrl); + + /* The BIST app. note lists these as 3 distinct steps. */ + /* Set the BIST type */ + bctl = (test << TXC_BIST_CTRL_TYPE_LBN); + efx_mdio_write(efx, mmd, TXC_BIST_CTL, bctl); + + /* Set the BSTEN bit in the BIST Control register to enable */ + bctl |= (1 << TXC_BIST_CTRL_ENAB_LBN); + efx_mdio_write(efx, mmd, TXC_BIST_CTL, bctl); + + /* Set the BSTRT bit in the BIST Control register */ + efx_mdio_write(efx, mmd, TXC_BIST_CTL, + bctl | (1 << TXC_BIST_CTRL_STRT_LBN)); + + /* Wait. */ + udelay(TXC_BIST_DURATION); + + /* Set the BSTOP bit in the BIST Control register */ + bctl |= (1 << TXC_BIST_CTRL_STOP_LBN); + efx_mdio_write(efx, mmd, TXC_BIST_CTL, bctl); + + /* The STOP bit should go off when things have stopped */ + while (bctl & (1 << TXC_BIST_CTRL_STOP_LBN)) + bctl = efx_mdio_read(efx, mmd, TXC_BIST_CTL); + + /* Check all the error counts are 0 and all the frame counts are + non-zero */ + for (lane = 0; lane < 4; lane++) { + int count = efx_mdio_read(efx, mmd, TXC_BIST_RX0ERRCNT + lane); + if (count != 0) { + netif_err(efx, hw, efx->net_dev, TXCNAME": BIST error. " + "Lane %d had %d errs\n", lane, count); + rc = -EIO; + } + count = efx_mdio_read(efx, mmd, TXC_BIST_RX0FRMCNT + lane); + if (count == 0) { + netif_err(efx, hw, efx->net_dev, TXCNAME": BIST error. " + "Lane %d got 0 frames\n", lane); + rc = -EIO; + } + } + + if (rc == 0) + netif_info(efx, hw, efx->net_dev, TXCNAME": BIST pass\n"); + + /* Disable BIST */ + efx_mdio_write(efx, mmd, TXC_BIST_CTL, 0); + + /* Turn off loopback */ + ctrl &= ~(1 << TXC_MTDIABLO_CTRL_PMA_LOOP_LBN); + efx_mdio_write(efx, MDIO_MMD_PCS, TXC_MTDIABLO_CTRL, ctrl); + + return rc; +} + +static int txc_bist(struct efx_nic *efx) +{ + return txc_bist_one(efx, MDIO_MMD_PCS, TXC_BIST_CTRL_TYPE_TSD); +} + +/* Push the non-configurable defaults into the PHY. This must be + * done after every full reset */ +static void txc_apply_defaults(struct efx_nic *efx) +{ + int mctrl; + + /* Turn amplitude down and preemphasis off on the host side + * (PHY<->MAC) as this is believed less likely to upset Falcon + * and no adverse effects have been noted. It probably also + * saves a picowatt or two */ + + /* Turn off preemphasis */ + efx_mdio_write(efx, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE0, TXC_ATXPRE_NONE); + efx_mdio_write(efx, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE1, TXC_ATXPRE_NONE); + + /* Turn down the amplitude */ + efx_mdio_write(efx, MDIO_MMD_PHYXS, + TXC_ALRGS_ATXAMP0, TXC_ATXAMP_0820_BOTH); + efx_mdio_write(efx, MDIO_MMD_PHYXS, + TXC_ALRGS_ATXAMP1, TXC_ATXAMP_0820_BOTH); + + /* Set the line side amplitude and preemphasis to the databook + * defaults as an erratum causes them to be 0 on at least some + * PHY rev.s */ + efx_mdio_write(efx, MDIO_MMD_PMAPMD, + TXC_ALRGS_ATXPRE0, TXC_ATXPRE_DEFAULT); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, + TXC_ALRGS_ATXPRE1, TXC_ATXPRE_DEFAULT); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, + TXC_ALRGS_ATXAMP0, TXC_ATXAMP_DEFAULT); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, + TXC_ALRGS_ATXAMP1, TXC_ATXAMP_DEFAULT); + + /* Set up the LEDs */ + mctrl = efx_mdio_read(efx, MDIO_MMD_PHYXS, TXC_MRGS_CTL); + + /* Set the Green and Red LEDs to their default modes */ + mctrl &= ~((1 << TXC_MCTL_TXLED_LBN) | (1 << TXC_MCTL_RXLED_LBN)); + efx_mdio_write(efx, MDIO_MMD_PHYXS, TXC_MRGS_CTL, mctrl); + + /* Databook recommends doing this after configuration changes */ + txc_reset_logic(efx); + + falcon_board(efx)->type->init_phy(efx); +} + +static int txc43128_phy_probe(struct efx_nic *efx) +{ + struct txc43128_data *phy_data; + + /* Allocate phy private storage */ + phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); + if (!phy_data) + return -ENOMEM; + efx->phy_data = phy_data; + phy_data->phy_mode = efx->phy_mode; + + efx->mdio.mmds = TXC_REQUIRED_DEVS; + efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; + + efx->loopback_modes = TXC_LOOPBACKS | FALCON_XMAC_LOOPBACKS; + + return 0; +} + +/* Initialisation entry point for this PHY driver */ +static int txc43128_phy_init(struct efx_nic *efx) +{ + int rc; + + rc = txc_reset_phy(efx); + if (rc < 0) + return rc; + + rc = txc_bist(efx); + if (rc < 0) + return rc; + + txc_apply_defaults(efx); + + return 0; +} + +/* Set the lane power down state in the global registers */ +static void txc_glrgs_lane_power(struct efx_nic *efx, int mmd) +{ + int pd = (1 << TXC_GLCMD_L01PD_LBN) | (1 << TXC_GLCMD_L23PD_LBN); + int ctl = efx_mdio_read(efx, mmd, TXC_GLRGS_GLCMD); + + if (!(efx->phy_mode & PHY_MODE_LOW_POWER)) + ctl &= ~pd; + else + ctl |= pd; + + efx_mdio_write(efx, mmd, TXC_GLRGS_GLCMD, ctl); +} + +/* Set the lane power down state in the analog control registers */ +static void txc_analog_lane_power(struct efx_nic *efx, int mmd) +{ + int txpd = (1 << TXC_ATXCTL_TXPD3_LBN) | (1 << TXC_ATXCTL_TXPD2_LBN) + | (1 << TXC_ATXCTL_TXPD1_LBN) | (1 << TXC_ATXCTL_TXPD0_LBN); + int rxpd = (1 << TXC_ARXCTL_RXPD3_LBN) | (1 << TXC_ARXCTL_RXPD2_LBN) + | (1 << TXC_ARXCTL_RXPD1_LBN) | (1 << TXC_ARXCTL_RXPD0_LBN); + int txctl = efx_mdio_read(efx, mmd, TXC_ALRGS_ATXCTL); + int rxctl = efx_mdio_read(efx, mmd, TXC_ALRGS_ARXCTL); + + if (!(efx->phy_mode & PHY_MODE_LOW_POWER)) { + txctl &= ~txpd; + rxctl &= ~rxpd; + } else { + txctl |= txpd; + rxctl |= rxpd; + } + + efx_mdio_write(efx, mmd, TXC_ALRGS_ATXCTL, txctl); + efx_mdio_write(efx, mmd, TXC_ALRGS_ARXCTL, rxctl); +} + +static void txc_set_power(struct efx_nic *efx) +{ + /* According to the data book, all the MMDs can do low power */ + efx_mdio_set_mmds_lpower(efx, + !!(efx->phy_mode & PHY_MODE_LOW_POWER), + TXC_REQUIRED_DEVS); + + /* Global register bank is in PCS, PHY XS. These control the host + * side and line side settings respectively. */ + txc_glrgs_lane_power(efx, MDIO_MMD_PCS); + txc_glrgs_lane_power(efx, MDIO_MMD_PHYXS); + + /* Analog register bank in PMA/PMD, PHY XS */ + txc_analog_lane_power(efx, MDIO_MMD_PMAPMD); + txc_analog_lane_power(efx, MDIO_MMD_PHYXS); +} + +static void txc_reset_logic_mmd(struct efx_nic *efx, int mmd) +{ + int val = efx_mdio_read(efx, mmd, TXC_GLRGS_GLCMD); + int tries = 50; + + val |= (1 << TXC_GLCMD_LMTSWRST_LBN); + efx_mdio_write(efx, mmd, TXC_GLRGS_GLCMD, val); + while (tries--) { + val = efx_mdio_read(efx, mmd, TXC_GLRGS_GLCMD); + if (!(val & (1 << TXC_GLCMD_LMTSWRST_LBN))) + break; + udelay(1); + } + if (!tries) + netif_info(efx, hw, efx->net_dev, + TXCNAME " Logic reset timed out!\n"); +} + +/* Perform a logic reset. This preserves the configuration registers + * and is needed for some configuration changes to take effect */ +static void txc_reset_logic(struct efx_nic *efx) +{ + /* The data sheet claims we can do the logic reset on either the + * PCS or the PHYXS and the result is a reset of both host- and + * line-side logic. */ + txc_reset_logic_mmd(efx, MDIO_MMD_PCS); +} + +static bool txc43128_phy_read_link(struct efx_nic *efx) +{ + return efx_mdio_links_ok(efx, TXC_REQUIRED_DEVS); +} + +static int txc43128_phy_reconfigure(struct efx_nic *efx) +{ + struct txc43128_data *phy_data = efx->phy_data; + enum efx_phy_mode mode_change = efx->phy_mode ^ phy_data->phy_mode; + bool loop_change = LOOPBACK_CHANGED(phy_data, efx, TXC_LOOPBACKS); + + if (efx->phy_mode & mode_change & PHY_MODE_TX_DISABLED) { + txc_reset_phy(efx); + txc_apply_defaults(efx); + falcon_reset_xaui(efx); + mode_change &= ~PHY_MODE_TX_DISABLED; + } + + efx_mdio_transmit_disable(efx); + efx_mdio_phy_reconfigure(efx); + if (mode_change & PHY_MODE_LOW_POWER) + txc_set_power(efx); + + /* The data sheet claims this is required after every reconfiguration + * (note at end of 7.1), but we mustn't do it when nothing changes as + * it glitches the link, and reconfigure gets called on link change, + * so we get an IRQ storm on link up. */ + if (loop_change || mode_change) + txc_reset_logic(efx); + + phy_data->phy_mode = efx->phy_mode; + phy_data->loopback_mode = efx->loopback_mode; + + return 0; +} + +static void txc43128_phy_fini(struct efx_nic *efx) +{ + /* Disable link events */ + efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, 0); +} + +static void txc43128_phy_remove(struct efx_nic *efx) +{ + kfree(efx->phy_data); + efx->phy_data = NULL; +} + +/* Periodic callback: this exists mainly to poll link status as we + * don't use LASI interrupts */ +static bool txc43128_phy_poll(struct efx_nic *efx) +{ + struct txc43128_data *data = efx->phy_data; + bool was_up = efx->link_state.up; + + efx->link_state.up = txc43128_phy_read_link(efx); + efx->link_state.speed = 10000; + efx->link_state.fd = true; + efx->link_state.fc = efx->wanted_fc; + + if (efx->link_state.up || (efx->loopback_mode != LOOPBACK_NONE)) { + data->bug10934_timer = jiffies; + } else { + if (time_after_eq(jiffies, (data->bug10934_timer + + BUG10934_RESET_INTERVAL))) { + data->bug10934_timer = jiffies; + txc_reset_logic(efx); + } + } + + return efx->link_state.up != was_up; +} + +static const char *txc43128_test_names[] = { + "bist" +}; + +static const char *txc43128_test_name(struct efx_nic *efx, unsigned int index) +{ + if (index < ARRAY_SIZE(txc43128_test_names)) + return txc43128_test_names[index]; + return NULL; +} + +static int txc43128_run_tests(struct efx_nic *efx, int *results, unsigned flags) +{ + int rc; + + if (!(flags & ETH_TEST_FL_OFFLINE)) + return 0; + + rc = txc_reset_phy(efx); + if (rc < 0) + return rc; + + rc = txc_bist(efx); + txc_apply_defaults(efx); + results[0] = rc ? -1 : 1; + return rc; +} + +static void txc43128_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) +{ + mdio45_ethtool_gset(&efx->mdio, ecmd); +} + +struct efx_phy_operations falcon_txc_phy_ops = { + .probe = txc43128_phy_probe, + .init = txc43128_phy_init, + .reconfigure = txc43128_phy_reconfigure, + .poll = txc43128_phy_poll, + .fini = txc43128_phy_fini, + .remove = txc43128_phy_remove, + .get_settings = txc43128_get_settings, + .set_settings = efx_mdio_set_settings, + .test_alive = efx_mdio_test_alive, + .run_tests = txc43128_run_tests, + .test_name = txc43128_test_name, +}; diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h index 782e45a613d..e0d63083c3a 100644 --- a/drivers/net/sfc/workarounds.h +++ b/drivers/net/sfc/workarounds.h @@ -19,9 +19,7 @@ #define EFX_WORKAROUND_FALCON_A(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) #define EFX_WORKAROUND_FALCON_AB(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_B0) #define EFX_WORKAROUND_SIENA(efx) (efx_nic_rev(efx) == EFX_REV_SIENA_A0) -#define EFX_WORKAROUND_10G(efx) EFX_IS10G(efx) -#define EFX_WORKAROUND_SFT9001(efx) ((efx)->phy_type == PHY_TYPE_SFT9001A || \ - (efx)->phy_type == PHY_TYPE_SFT9001B) +#define EFX_WORKAROUND_10G(efx) 1 /* XAUI resets if link not detected */ #define EFX_WORKAROUND_5147 EFX_WORKAROUND_ALWAYS @@ -58,9 +56,4 @@ /* Leak overlength packets rather than free */ #define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A -/* Need to send XNP pages for 100BaseT */ -#define EFX_WORKAROUND_13204 EFX_WORKAROUND_SFT9001 -/* Don't restart AN in near-side loopback */ -#define EFX_WORKAROUND_15195 EFX_WORKAROUND_SFT9001 - #endif /* EFX_WORKAROUNDS_H */ |