Skip to content

Commit 929b426

Browse files
roxanan1996PlaidCat
authored andcommitted
idpf: add support for Tx refillqs in flow scheduling mode
jira KERNEL-168 commit-author Joshua Hay <joshua.a.hay@intel.com> commit cb83b55 upstream-diff | 1. adjusted context around idpf_rx_splitq_clean function due to missing - 74d1412 ("idpf: use libeth Rx buffer management for payload buffer") - 6ad5ff6 ("libeth: convert to netmem") 2. adjusted context around struct idpf_tx_queue members and docstring and did not include the libeth_cacheline_set_assert changes due to missing: - 5a816aa ("idpf: strictly assert cachelines of queue and queue vector structures") 3. fix compilation issue (std=89) in idpf_tx_desc_alloc due to for loop var declaration In certain production environments, it is possible for completion tags to collide, meaning N packets with the same completion tag are in flight at the same time. In this environment, any given Tx queue is effectively used to send both slower traffic and higher throughput traffic simultaneously. This is the result of a customer's specific configuration in the device pipeline, the details of which Intel cannot provide. This configuration results in a small number of out-of-order completions, i.e., a small number of packets in flight. The existing guardrails in the driver only protect against a large number of packets in flight. The slower flow completions are delayed which causes the out-of-order completions. The fast flow will continue sending traffic and generating tags. Because tags are generated on the fly, the fast flow eventually uses the same tag for a packet that is still in flight from the slower flow. The driver has no idea which packet it should clean when it processes the completion with that tag, but it will look for the packet on the buffer ring before the hash table. If the slower flow packet completion is processed first, it will end up cleaning the fast flow packet on the ring prematurely. This leaves the descriptor ring in a bad state resulting in a crash or Tx timeout. In summary, generating a tag when a packet is sent can lead to the same tag being associated with multiple packets. This can lead to resource leaks, crashes, and/or Tx timeouts. Before we can replace the tag generation, we need a new mechanism for the send path to know what tag to use next. The driver will allocate and initialize a refillq for each TxQ with all of the possible free tag values. During send, the driver grabs the next free tag from the refillq from next_to_clean. While cleaning the packet, the clean routine posts the tag back to the refillq's next_to_use to indicate that it is now free to use. This mechanism works exactly the same way as the existing Rx refill queues, which post the cleaned buffer IDs back to the buffer queue to be reposted to HW. Since we're using the refillqs for both Rx and Tx now, genericize some of the existing refillq support. Note: the refillqs will not be used yet. This is only demonstrating how they will be used to pass free tags back to the send path. Signed-off-by: Joshua Hay <joshua.a.hay@intel.com> Reviewed-by: Madhu Chittim <madhu.chittim@intel.com> Tested-by: Samuel Salin <Samuel.salin@intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com> (cherry picked from commit cb83b55) Signed-off-by: Roxana Nicolescu <rnicolescu@ciq.com>
1 parent d24d6a4 commit 929b426

2 files changed

Lines changed: 91 additions & 9 deletions

File tree

drivers/net/ethernet/intel/idpf/idpf_txrx.c

Lines changed: 87 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ static void idpf_tx_desc_rel(struct idpf_tx_queue *txq)
137137
if (!txq->desc_ring)
138138
return;
139139

140+
if (txq->refillq)
141+
kfree(txq->refillq->ring);
142+
140143
dmam_free_coherent(txq->dev, txq->size, txq->desc_ring, txq->dma);
141144
txq->desc_ring = NULL;
142145
txq->next_to_use = 0;
@@ -242,7 +245,9 @@ static int idpf_tx_desc_alloc(const struct idpf_vport *vport,
242245
struct idpf_tx_queue *tx_q)
243246
{
244247
struct device *dev = tx_q->dev;
248+
struct idpf_sw_queue *refillq;
245249
int err;
250+
unsigned int i = 0;
246251

247252
err = idpf_tx_buf_alloc_all(tx_q);
248253
if (err)
@@ -265,6 +270,29 @@ static int idpf_tx_desc_alloc(const struct idpf_vport *vport,
265270
tx_q->next_to_clean = 0;
266271
idpf_queue_set(GEN_CHK, tx_q);
267272

273+
if (!idpf_queue_has(FLOW_SCH_EN, tx_q))
274+
return 0;
275+
276+
refillq = tx_q->refillq;
277+
refillq->desc_count = tx_q->desc_count;
278+
refillq->ring = kcalloc(refillq->desc_count, sizeof(u32),
279+
GFP_KERNEL);
280+
if (!refillq->ring) {
281+
err = -ENOMEM;
282+
goto err_alloc;
283+
}
284+
285+
for (i = 0; i < refillq->desc_count; i++)
286+
refillq->ring[i] =
287+
FIELD_PREP(IDPF_RFL_BI_BUFID_M, i) |
288+
FIELD_PREP(IDPF_RFL_BI_GEN_M,
289+
idpf_queue_has(GEN_CHK, refillq));
290+
291+
/* Go ahead and flip the GEN bit since this counts as filling
292+
* up the ring, i.e. we already ring wrapped.
293+
*/
294+
idpf_queue_change(GEN_CHK, refillq);
295+
268296
return 0;
269297

270298
err_alloc:
@@ -586,18 +614,18 @@ static int idpf_rx_hdr_buf_alloc_all(struct idpf_buf_queue *bufq)
586614
}
587615

588616
/**
589-
* idpf_rx_post_buf_refill - Post buffer id to refill queue
617+
* idpf_post_buf_refill - Post buffer id to refill queue
590618
* @refillq: refill queue to post to
591619
* @buf_id: buffer id to post
592620
*/
593-
static void idpf_rx_post_buf_refill(struct idpf_sw_queue *refillq, u16 buf_id)
621+
static void idpf_post_buf_refill(struct idpf_sw_queue *refillq, u16 buf_id)
594622
{
595623
u32 nta = refillq->next_to_use;
596624

597625
/* store the buffer ID and the SW maintained GEN bit to the refillq */
598626
refillq->ring[nta] =
599-
FIELD_PREP(IDPF_RX_BI_BUFID_M, buf_id) |
600-
FIELD_PREP(IDPF_RX_BI_GEN_M,
627+
FIELD_PREP(IDPF_RFL_BI_BUFID_M, buf_id) |
628+
FIELD_PREP(IDPF_RFL_BI_GEN_M,
601629
idpf_queue_has(GEN_CHK, refillq));
602630

603631
if (unlikely(++nta == refillq->desc_count)) {
@@ -977,6 +1005,11 @@ static void idpf_txq_group_rel(struct idpf_vport *vport)
9771005
struct idpf_txq_group *txq_grp = &vport->txq_grps[i];
9781006

9791007
for (j = 0; j < txq_grp->num_txq; j++) {
1008+
if (flow_sch_en) {
1009+
kfree(txq_grp->txqs[j]->refillq);
1010+
txq_grp->txqs[j]->refillq = NULL;
1011+
}
1012+
9801013
kfree(txq_grp->txqs[j]);
9811014
txq_grp->txqs[j] = NULL;
9821015
}
@@ -1394,6 +1427,13 @@ static int idpf_txq_group_alloc(struct idpf_vport *vport, u16 num_txq)
13941427
}
13951428

13961429
idpf_queue_set(FLOW_SCH_EN, q);
1430+
1431+
q->refillq = kzalloc(sizeof(*q->refillq), GFP_KERNEL);
1432+
if (!q->refillq)
1433+
goto err_alloc;
1434+
1435+
idpf_queue_set(GEN_CHK, q->refillq);
1436+
idpf_queue_set(RFL_GEN_CHK, q->refillq);
13971437
}
13981438

13991439
if (!split)
@@ -1950,6 +1990,8 @@ static void idpf_tx_handle_rs_completion(struct idpf_tx_queue *txq,
19501990

19511991
compl_tag = le16_to_cpu(desc->q_head_compl_tag.compl_tag);
19521992

1993+
idpf_post_buf_refill(txq->refillq, compl_tag);
1994+
19531995
/* If we didn't clean anything on the ring, this packet must be
19541996
* in the hash table. Go clean it there.
19551997
*/
@@ -2309,6 +2351,37 @@ static unsigned int idpf_tx_splitq_bump_ntu(struct idpf_tx_queue *txq, u16 ntu)
23092351
return ntu;
23102352
}
23112353

2354+
/**
2355+
* idpf_tx_get_free_buf_id - get a free buffer ID from the refill queue
2356+
* @refillq: refill queue to get buffer ID from
2357+
* @buf_id: return buffer ID
2358+
*
2359+
* Return: true if a buffer ID was found, false if not
2360+
*/
2361+
static bool idpf_tx_get_free_buf_id(struct idpf_sw_queue *refillq,
2362+
u16 *buf_id)
2363+
{
2364+
u32 ntc = refillq->next_to_clean;
2365+
u32 refill_desc;
2366+
2367+
refill_desc = refillq->ring[ntc];
2368+
2369+
if (unlikely(idpf_queue_has(RFL_GEN_CHK, refillq) !=
2370+
!!(refill_desc & IDPF_RFL_BI_GEN_M)))
2371+
return false;
2372+
2373+
*buf_id = FIELD_GET(IDPF_RFL_BI_BUFID_M, refill_desc);
2374+
2375+
if (unlikely(++ntc == refillq->desc_count)) {
2376+
idpf_queue_change(RFL_GEN_CHK, refillq);
2377+
ntc = 0;
2378+
}
2379+
2380+
refillq->next_to_clean = ntc;
2381+
2382+
return true;
2383+
}
2384+
23122385
/**
23132386
* idpf_tx_splitq_map - Build the Tx flex descriptor
23142387
* @tx_q: queue to send buffer on
@@ -2784,6 +2857,13 @@ static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb,
27842857
}
27852858

27862859
if (idpf_queue_has(FLOW_SCH_EN, tx_q)) {
2860+
if (unlikely(!idpf_tx_get_free_buf_id(tx_q->refillq,
2861+
&tx_params.compl_tag))) {
2862+
u64_stats_update_begin(&tx_q->stats_sync);
2863+
u64_stats_inc(&tx_q->q_stats.q_busy);
2864+
u64_stats_update_end(&tx_q->stats_sync);
2865+
}
2866+
27872867
tx_params.dtype = IDPF_TX_DESC_DTYPE_FLEX_FLOW_SCHE;
27882868
tx_params.eop_cmd = IDPF_TXD_FLEX_FLOW_CMD_EOP;
27892869
/* Set the RE bit to catch any packets that may have not been
@@ -3360,7 +3440,7 @@ static int idpf_rx_splitq_clean(struct idpf_rx_queue *rxq, int budget)
33603440
if (!skb)
33613441
break;
33623442

3363-
idpf_rx_post_buf_refill(refillq, buf_id);
3443+
idpf_post_buf_refill(refillq, buf_id);
33643444

33653445
IDPF_RX_BUMP_NTC(rxq, ntc);
33663446
/* skip if it is non EOP desc */
@@ -3458,10 +3538,10 @@ static void idpf_rx_clean_refillq(struct idpf_buf_queue *bufq,
34583538
bool failure;
34593539

34603540
if (idpf_queue_has(RFL_GEN_CHK, refillq) !=
3461-
!!(refill_desc & IDPF_RX_BI_GEN_M))
3541+
!!(refill_desc & IDPF_RFL_BI_GEN_M))
34623542
break;
34633543

3464-
buf_id = FIELD_GET(IDPF_RX_BI_BUFID_M, refill_desc);
3544+
buf_id = FIELD_GET(IDPF_RFL_BI_BUFID_M, refill_desc);
34653545
failure = idpf_rx_update_bufq_desc(bufq, buf_id, buf_desc);
34663546
if (failure)
34673547
break;

drivers/net/ethernet/intel/idpf/idpf_txrx.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ do { \
113113
*/
114114
#define IDPF_TX_SPLITQ_RE_MIN_GAP 64
115115

116-
#define IDPF_RX_BI_GEN_M BIT(16)
117-
#define IDPF_RX_BI_BUFID_M GENMASK(15, 0)
116+
#define IDPF_RFL_BI_GEN_M BIT(16)
117+
#define IDPF_RFL_BI_BUFID_M GENMASK(15, 0)
118118

119119
#define IDPF_RXD_EOF_SPLITQ VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_EOF_M
120120
#define IDPF_RXD_EOF_SINGLEQ VIRTCHNL2_RX_BASE_DESC_STATUS_EOF_M
@@ -685,6 +685,7 @@ struct idpf_rx_queue {
685685
* @cleaned_pkts: Number of packets cleaned for the above said case
686686
* @tx_max_bufs: Max buffers that can be transmitted with scatter-gather
687687
* @tx_min_pkt_len: Min supported packet length
688+
* @refillq: Pointer to refill queue
688689
* @compl_tag_bufid_m: Completion tag buffer id mask
689690
* @compl_tag_gen_s: Completion tag generation bit
690691
* The format of the completion tag will change based on the TXQ
@@ -746,6 +747,7 @@ struct idpf_tx_queue {
746747

747748
u16 tx_max_bufs;
748749
u16 tx_min_pkt_len;
750+
struct idpf_sw_queue *refillq;
749751

750752
u16 compl_tag_bufid_m;
751753
u16 compl_tag_gen_s;

0 commit comments

Comments
 (0)