sfc: assign TXQs without gaps
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>
This commit is contained in:
parent
69a704962e
commit
a81dcd85a7
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"));
|
||||
}
|
||||
|
@ -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, ®, FR_BZ_TX_PACE_TBL, tx_queue->queue);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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]);
|
||||
|
@ -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, ®, FR_AZ_CS_DEBUG);
|
||||
efx->port_num = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1;
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user