sfc: assign TXQs without gaps
authorEdward Cree <ecree@solarflare.com>
Thu, 2 Jul 2020 16:29:58 +0000 (17:29 +0100)
committerDavid S. Miller <davem@davemloft.net>
Thu, 2 Jul 2020 21:47:40 +0000 (14:47 -0700)
Since we only allocate VIs for the number of TXQs we actually need, we
 cannot naively use "channel * TXQ_TYPES + txq" for the TXQ number, as
 this has gaps (when efx->tx_queues_per_channel < EFX_TXQ_TYPES) and
 thus overruns the driver's VI allocations, causing the firmware to
 reject the MC_CMD_INIT_TXQ based on INSTANCE.
Thus, we distinguish INSTANCE (stored in tx_queue->queue) from LABEL
 (tx_queue->label); the former is allocated starting from 0 in
 efx_set_channels(), while the latter is simply the txq type (index in
 channel->tx_queue array).
To simplify things, rather than changing tx_queues_per_channel after
 setting up TXQs, make Siena always probe its HIGHPRI queues at start
 of day, rather than deferring it until tc mqprio enables them.

Signed-off-by: Edward Cree <ecree@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/efx_channels.c
drivers/net/ethernet/sfc/ethtool_common.c
drivers/net/ethernet/sfc/farch.c
drivers/net/ethernet/sfc/mcdi_functions.c
drivers/net/ethernet/sfc/net_driver.h
drivers/net/ethernet/sfc/nic_common.h
drivers/net/ethernet/sfc/selftest.c
drivers/net/ethernet/sfc/siena.c
drivers/net/ethernet/sfc/tx.c

index be15640..311a2d2 100644 (file)
@@ -2244,7 +2244,7 @@ static u32 efx_ef10_tso_versions(struct efx_nic *efx)
 
 static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue)
 {
-       bool csum_offload = tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD;
+       bool csum_offload = tx_queue->label & EFX_TXQ_TYPE_OFFLOAD;
        struct efx_channel *channel = tx_queue->channel;
        struct efx_nic *efx = tx_queue->efx;
        struct efx_ef10_nic_data *nic_data;
index 30358f3..dd4f30e 100644 (file)
@@ -524,7 +524,8 @@ efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel)
        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->queue = -1;
+               tx_queue->label = j;
                tx_queue->channel = channel;
        }
 
@@ -853,8 +854,9 @@ rollback:
 
 int efx_set_channels(struct efx_nic *efx)
 {
-       struct efx_channel *channel;
        struct efx_tx_queue *tx_queue;
+       struct efx_channel *channel;
+       unsigned int next_queue = 0;
        int xdp_queue_number;
        int rc;
 
@@ -884,14 +886,30 @@ int efx_set_channels(struct efx_nic *efx)
                else
                        channel->rx_queue.core_index = -1;
 
-               efx_for_each_channel_tx_queue(tx_queue, channel) {
-                       tx_queue->queue -= (efx->tx_channel_offset *
-                                           EFX_TXQ_TYPES);
-
-                       if (efx_channel_is_xdp_tx(channel) &&
-                           xdp_queue_number < efx->xdp_tx_queue_count) {
-                               efx->xdp_tx_queues[xdp_queue_number] = tx_queue;
-                               xdp_queue_number++;
+               if (channel->channel >= efx->tx_channel_offset) {
+                       if (efx_channel_is_xdp_tx(channel)) {
+                               efx_for_each_channel_tx_queue(tx_queue, channel) {
+                                       tx_queue->queue = next_queue++;
+                                       netif_dbg(efx, drv, efx->net_dev, "Channel %u TXQ %u is XDP %u, HW %u\n",
+                                                 channel->channel, tx_queue->label,
+                                                 xdp_queue_number, tx_queue->queue);
+                                       /* We may have a few left-over XDP TX
+                                        * queues owing to xdp_tx_queue_count
+                                        * not dividing evenly by EFX_TXQ_TYPES.
+                                        * We still allocate and probe those
+                                        * TXQs, but never use them.
+                                        */
+                                       if (xdp_queue_number < efx->xdp_tx_queue_count)
+                                               efx->xdp_tx_queues[xdp_queue_number] = tx_queue;
+                                       xdp_queue_number++;
+                               }
+                       } else {
+                               efx_for_each_channel_tx_queue(tx_queue, channel) {
+                                       tx_queue->queue = next_queue++;
+                                       netif_dbg(efx, drv, efx->net_dev, "Channel %u TXQ %u is HW %u\n",
+                                                 channel->channel, tx_queue->label,
+                                                 tx_queue->queue);
+                               }
                        }
                }
        }
index 738d9be..37a4409 100644 (file)
@@ -287,8 +287,7 @@ static void efx_fill_test(unsigned int test_index, u8 *strings, u64 *data,
 }
 
 #define EFX_CHANNEL_NAME(_channel) "chan%d", _channel->channel
-#define EFX_TX_QUEUE_NAME(_tx_queue) "txq%d", _tx_queue->queue
-#define EFX_RX_QUEUE_NAME(_rx_queue) "rxq%d", _rx_queue->queue
+#define EFX_TX_QUEUE_NAME(_tx_queue) "txq%d", _tx_queue->label
 #define EFX_LOOPBACK_NAME(_mode, _counter)                     \
        "loopback.%s." _counter, STRING_TABLE_LOOKUP(_mode, efx_loopback_mode)
 
@@ -316,11 +315,11 @@ static int efx_fill_loopback_test(struct efx_nic *efx,
 
        efx_for_each_channel_tx_queue(tx_queue, channel) {
                efx_fill_test(test_index++, strings, data,
-                             &lb_tests->tx_sent[tx_queue->queue],
+                             &lb_tests->tx_sent[tx_queue->label],
                              EFX_TX_QUEUE_NAME(tx_queue),
                              EFX_LOOPBACK_NAME(mode, "tx_sent"));
                efx_fill_test(test_index++, strings, data,
-                             &lb_tests->tx_done[tx_queue->queue],
+                             &lb_tests->tx_done[tx_queue->label],
                              EFX_TX_QUEUE_NAME(tx_queue),
                              EFX_LOOPBACK_NAME(mode, "tx_done"));
        }
index dbbb898..d07eeaa 100644 (file)
@@ -379,7 +379,7 @@ int efx_farch_tx_probe(struct efx_tx_queue *tx_queue)
 
 void efx_farch_tx_init(struct efx_tx_queue *tx_queue)
 {
-       int csum = tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD;
+       int csum = tx_queue->label & EFX_TXQ_TYPE_OFFLOAD;
        struct efx_nic *efx = tx_queue->efx;
        efx_oword_t reg;
 
@@ -395,7 +395,7 @@ void efx_farch_tx_init(struct efx_tx_queue *tx_queue)
                              FRF_AZ_TX_DESCQ_EVQ_ID,
                              tx_queue->channel->channel,
                              FRF_AZ_TX_DESCQ_OWNER_ID, 0,
-                             FRF_AZ_TX_DESCQ_LABEL, tx_queue->queue,
+                             FRF_AZ_TX_DESCQ_LABEL, tx_queue->label,
                              FRF_AZ_TX_DESCQ_SIZE,
                              __ffs(tx_queue->txd.entries),
                              FRF_AZ_TX_DESCQ_TYPE, 0,
@@ -409,7 +409,7 @@ void efx_farch_tx_init(struct efx_tx_queue *tx_queue)
 
        EFX_POPULATE_OWORD_1(reg,
                             FRF_BZ_TX_PACE,
-                            (tx_queue->queue & EFX_TXQ_TYPE_HIGHPRI) ?
+                            (tx_queue->label & EFX_TXQ_TYPE_HIGHPRI) ?
                             FFE_BZ_TX_PACE_OFF :
                             FFE_BZ_TX_PACE_RESERVED);
        efx_writeo_table(efx, &reg, FR_BZ_TX_PACE_TBL, tx_queue->queue);
index 962d839..b3a8aa8 100644 (file)
@@ -164,7 +164,7 @@ int efx_mcdi_tx_init(struct efx_tx_queue *tx_queue, bool tso_v2)
 {
        MCDI_DECLARE_BUF(inbuf, MC_CMD_INIT_TXQ_IN_LEN(EFX_MAX_DMAQ_SIZE * 8 /
                                                       EFX_BUF_SIZE));
-       bool csum_offload = tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD;
+       bool csum_offload = tx_queue->label & EFX_TXQ_TYPE_OFFLOAD;
        size_t entries = tx_queue->txd.buf.len / EFX_BUF_SIZE;
        struct efx_channel *channel = tx_queue->channel;
        struct efx_nic *efx = tx_queue->efx;
@@ -176,7 +176,7 @@ int efx_mcdi_tx_init(struct efx_tx_queue *tx_queue, bool tso_v2)
 
        MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_SIZE, tx_queue->ptr_mask + 1);
        MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_TARGET_EVQ, channel->channel);
-       MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_LABEL, tx_queue->queue);
+       MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_LABEL, tx_queue->label);
        MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_INSTANCE, tx_queue->queue);
        MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_OWNER_ID, 0);
        MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_PORT_ID, efx->vport_id);
index 4ded155..0bf11eb 100644 (file)
@@ -189,6 +189,8 @@ struct efx_tx_buffer {
  *
  * @efx: The associated Efx NIC
  * @queue: DMA queue number
+ * @label: Label for TX completion events.
+ *     Is our index within @channel->tx_queue array.
  * @tso_version: Version of TSO in use for this queue.
  * @channel: The associated channel
  * @core_txq: The networking core TX queue structure
@@ -250,7 +252,8 @@ struct efx_tx_buffer {
 struct efx_tx_queue {
        /* Members which don't change on the fast path */
        struct efx_nic *efx ____cacheline_aligned_in_smp;
-       unsigned queue;
+       unsigned int queue;
+       unsigned int label;
        unsigned int tso_version;
        struct efx_channel *channel;
        struct netdev_queue *core_txq;
index fd474d9..813f288 100644 (file)
@@ -90,7 +90,7 @@ static inline bool efx_nic_tx_is_empty(struct efx_tx_queue *tx_queue)
 /* XXX is this a thing on EF100? */
 static inline struct efx_tx_queue *efx_tx_queue_partner(struct efx_tx_queue *tx_queue)
 {
-       if (tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD)
+       if (tx_queue->label & EFX_TXQ_TYPE_OFFLOAD)
                return tx_queue - EFX_TXQ_TYPE_OFFLOAD;
        else
                return tx_queue + EFX_TXQ_TYPE_OFFLOAD;
index 1ae3690..e71d6d3 100644 (file)
@@ -445,7 +445,7 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue)
                if (rc != NETDEV_TX_OK) {
                        netif_err(efx, drv, efx->net_dev,
                                  "TX queue %d could not transmit packet %d of "
-                                 "%d in %s loopback test\n", tx_queue->queue,
+                                 "%d in %s loopback test\n", tx_queue->label,
                                  i + 1, state->packet_count,
                                  LOOPBACK_MODE(efx));
 
@@ -497,7 +497,7 @@ static int efx_end_loopback(struct efx_tx_queue *tx_queue,
                netif_err(efx, drv, efx->net_dev,
                          "TX queue %d saw only %d out of an expected %d "
                          "TX completion events in %s loopback test\n",
-                         tx_queue->queue, tx_done, state->packet_count,
+                         tx_queue->label, tx_done, state->packet_count,
                          LOOPBACK_MODE(efx));
                rc = -ETIMEDOUT;
                /* Allow to fall through so we see the RX errors as well */
@@ -508,15 +508,15 @@ static int efx_end_loopback(struct efx_tx_queue *tx_queue,
                netif_dbg(efx, drv, efx->net_dev,
                          "TX queue %d saw only %d out of an expected %d "
                          "received packets in %s loopback test\n",
-                         tx_queue->queue, rx_good, state->packet_count,
+                         tx_queue->label, rx_good, state->packet_count,
                          LOOPBACK_MODE(efx));
                rc = -ETIMEDOUT;
                /* Fall through */
        }
 
        /* Update loopback test structure */
-       lb_tests->tx_sent[tx_queue->queue] += state->packet_count;
-       lb_tests->tx_done[tx_queue->queue] += tx_done;
+       lb_tests->tx_sent[tx_queue->label] += state->packet_count;
+       lb_tests->tx_done[tx_queue->label] += tx_done;
        lb_tests->rx_good += rx_good;
        lb_tests->rx_bad += rx_bad;
 
@@ -542,8 +542,8 @@ efx_test_loopback(struct efx_tx_queue *tx_queue,
                state->flush = false;
 
                netif_dbg(efx, drv, efx->net_dev,
-                         "TX queue %d testing %s loopback with %d packets\n",
-                         tx_queue->queue, LOOPBACK_MODE(efx),
+                         "TX queue %d (hw %d) testing %s loopback with %d packets\n",
+                         tx_queue->label, tx_queue->queue, LOOPBACK_MODE(efx),
                          state->packet_count);
 
                efx_iterate_state(efx);
@@ -570,7 +570,7 @@ efx_test_loopback(struct efx_tx_queue *tx_queue,
 
        netif_dbg(efx, drv, efx->net_dev,
                  "TX queue %d passed %s loopback test with a burst length "
-                 "of %d packets\n", tx_queue->queue, LOOPBACK_MODE(efx),
+                 "of %d packets\n", tx_queue->label, LOOPBACK_MODE(efx),
                  state->packet_count);
 
        return 0;
@@ -660,7 +660,7 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests,
 
                /* Test all enabled types of TX queue */
                efx_for_each_channel_tx_queue(tx_queue, channel) {
-                       state->offload_csum = (tx_queue->queue &
+                       state->offload_csum = (tx_queue->label &
                                               EFX_TXQ_TYPE_OFFLOAD);
                        rc = efx_test_loopback(tx_queue,
                                               &tests->loopback[mode]);
index 4c5881a..219fb3a 100644 (file)
@@ -279,7 +279,7 @@ static int siena_probe_nic(struct efx_nic *efx)
        efx->max_channels = EFX_MAX_CHANNELS;
        efx->max_vis = EFX_MAX_CHANNELS;
        efx->max_tx_channels = EFX_MAX_CHANNELS;
-       efx->tx_queues_per_channel = 2;
+       efx->tx_queues_per_channel = 4;
 
        efx_reado(efx, &reg, FR_AZ_CS_DEBUG);
        efx->port_num = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1;
index 76ff394..1bcf50a 100644 (file)
@@ -551,8 +551,8 @@ void efx_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue)
        /* Must be inverse of queue lookup in efx_hard_start_xmit() */
        tx_queue->core_txq =
                netdev_get_tx_queue(efx->net_dev,
-                                   tx_queue->queue / EFX_TXQ_TYPES +
-                                   ((tx_queue->queue & EFX_TXQ_TYPE_HIGHPRI) ?
+                                   tx_queue->channel->channel +
+                                   ((tx_queue->label & EFX_TXQ_TYPE_HIGHPRI) ?
                                     efx->n_tx_channels : 0));
 }
 
@@ -561,10 +561,7 @@ int efx_setup_tc(struct net_device *net_dev, enum tc_setup_type type,
 {
        struct efx_nic *efx = netdev_priv(net_dev);
        struct tc_mqprio_qopt *mqprio = type_data;
-       struct efx_channel *channel;
-       struct efx_tx_queue *tx_queue;
        unsigned tc, num_tc;
-       int rc;
 
        if (type != TC_SETUP_QDISC_MQPRIO)
                return -EOPNOTSUPP;
@@ -588,40 +585,9 @@ int efx_setup_tc(struct net_device *net_dev, enum tc_setup_type type,
                net_dev->tc_to_txq[tc].count = efx->n_tx_channels;
        }
 
-       if (num_tc > net_dev->num_tc) {
-               efx->tx_queues_per_channel = 4;
-               /* Initialise high-priority queues as necessary */
-               efx_for_each_channel(channel, efx) {
-                       efx_for_each_channel_tx_queue(tx_queue, channel) {
-                               if (!(tx_queue->queue & EFX_TXQ_TYPE_HIGHPRI))
-                                       continue;
-                               if (!tx_queue->buffer) {
-                                       rc = efx_probe_tx_queue(tx_queue);
-                                       if (rc)
-                                               return rc;
-                               }
-                               if (!tx_queue->initialised)
-                                       efx_init_tx_queue(tx_queue);
-                               efx_init_tx_queue_core_txq(tx_queue);
-                       }
-               }
-       } else {
-               /* Reduce number of classes before number of queues */
-               net_dev->num_tc = num_tc;
-       }
-
-       rc = netif_set_real_num_tx_queues(net_dev,
-                                         max_t(int, num_tc, 1) *
-                                         efx->n_tx_channels);
-       if (rc)
-               return rc;
-
-       /* Do not destroy high-priority queues when they become
-        * unused.  We would have to flush them first, and it is
-        * fairly difficult to flush a subset of TX queues.  Leave
-        * it to efx_fini_channels().
-        */
-
        net_dev->num_tc = num_tc;
-       return 0;
+
+       return netif_set_real_num_tx_queues(net_dev,
+                                           max_t(int, num_tc, 1) *
+                                           efx->n_tx_channels);
 }