summaryrefslogtreecommitdiff
path: root/drivers/net/sfc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/sfc')
-rw-r--r--drivers/net/sfc/Makefile7
-rw-r--r--drivers/net/sfc/efx.c353
-rw-r--r--drivers/net/sfc/efx.h46
-rw-r--r--drivers/net/sfc/ethtool.c181
-rw-r--r--drivers/net/sfc/falcon.c136
-rw-r--r--drivers/net/sfc/falcon_boards.c203
-rw-r--r--drivers/net/sfc/falcon_gmac.c230
-rw-r--r--drivers/net/sfc/falcon_xmac.c2
-rw-r--r--drivers/net/sfc/filter.c454
-rw-r--r--drivers/net/sfc/filter.h189
-rw-r--r--drivers/net/sfc/mac.h2
-rw-r--r--drivers/net/sfc/mcdi.c4
-rw-r--r--drivers/net/sfc/mcdi.h2
-rw-r--r--drivers/net/sfc/mcdi_phy.c3
-rw-r--r--drivers/net/sfc/mdio_10g.c30
-rw-r--r--drivers/net/sfc/net_driver.h117
-rw-r--r--drivers/net/sfc/nic.c199
-rw-r--r--drivers/net/sfc/phy.h18
-rw-r--r--drivers/net/sfc/regs.h14
-rw-r--r--drivers/net/sfc/rx.c73
-rw-r--r--drivers/net/sfc/selftest.c17
-rw-r--r--drivers/net/sfc/siena.c6
-rw-r--r--drivers/net/sfc/tenxpress.c424
-rw-r--r--drivers/net/sfc/tx.c78
-rw-r--r--drivers/net/sfc/txc43128_phy.c560
-rw-r--r--drivers/net/sfc/workarounds.h9
26 files changed, 2105 insertions, 1252 deletions
diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile
index 1047b19c60a5..ab31c7124db1 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 ba674c5ca29e..05df20e47976 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 060dc952a0fd..10a1bf40da96 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 fd19d6ab97a2..edb9d16b8b47 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 4f9d33f3cca1..267019bb2b15 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, &reg, FR_AB_GM_CFG1);
- udelay(1000);
-
- EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_SW_RST, 0);
- efx_writeo(efx, &reg, FR_AB_GM_CFG1);
- udelay(1000);
- return;
- } else {
- EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_CORE_RST, 1);
- efx_writeo(efx, &reg, FR_AB_XM_GLB_CFG);
-
- for (count = 0; count < 10000; count++) {
- efx_reado(efx, &reg, 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, &reg, FR_AB_XM_GLB_CFG);
+
+ for (count = 0; count < 10000; count++) {
+ efx_reado(efx, &reg, 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 3d950c2cf205..cfc6a5b5a477 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, &reg, FR_AB_GPIO_CTL);
- EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO2_OEN, true);
- efx_writeo(efx, &reg, 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, &reg, 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 7dadfcbd6ce7..000000000000
--- 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, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, FR_AB_GMF_CFG3);
- udelay(10);
-
- /* FIFO configuration register 4 */
- EFX_POPULATE_OWORD_1(reg, FRF_AB_GMF_HSTFLTRFRM_PAUSE, 1);
- efx_writeo(efx, &reg, FR_AB_GMF_CFG4);
- udelay(10);
-
- /* FIFO configuration register 5 */
- efx_reado(efx, &reg, 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, &reg, 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, &reg, 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, &reg, 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 bae656dd2c4e..b31f595ebb5b 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 000000000000..52cb6082b910
--- /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 000000000000..a53319ded79c
--- /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 f1aa5f374890..6886cdf87c12 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 3912b8fed912..12cf910c2ce7 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 f1f89ad4075a..c792f1d65e48 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 0121e71702bf..c992742446b1 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 eeaf0bd64bd3..98d946020429 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 64e7caa4bbb5..0a7e26d73b52 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 f595d920c7c4..41c36b9a4244 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, &reg,
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, &reg,
- FR_AZ_RX_DESC_UPD_DWORD_P0, rx_queue->queue);
+ efx_writed_page(efx, &reg, 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 5bc26137257b..1dab609757fb 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 18a3be428348..96430ed81c36 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 799c461ce7b8..6d0959b5158e 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 85f015f005d5..0ebfb99f1299 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 3fab030f8ab5..45236f58a258 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 6791be90c2fe..1bc6c48c96ee 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 c6942da2c99a..11726989fe2d 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 000000000000..351794a79215
--- /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 782e45a613d6..e0d63083c3a8 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 */