mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 17:13:52 +02:00
Merge branch '200GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue
Tony Nguyen says: ==================== idpf: replace Tx flow scheduling buffer ring with buffer pool Joshua Hay says: This series fixes a stability issue in the flow scheduling Tx send/clean path that results in a Tx timeout. The existing guardrails in the Tx path were not sufficient to prevent the driver from reusing completion tags that were still in flight (held by the HW). This collision would cause the driver to erroneously clean the wrong packet thus leaving the descriptor ring in a bad state. The main point of this fix is to replace the flow scheduling buffer ring with a large pool/array of buffers. The completion tag then simply is the index into this array. The driver tracks the free tags and pulls the next free one from a refillq. The cleaning routines simply use the completion tag from the completion descriptor to index into the array to quickly find the buffers to clean. All of the code to support this is added first to ensure traffic still passes with each patch. The final patch then removes all of the obsolete stashing code. * '200GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue: idpf: remove obsolete stashing code idpf: stop Tx if there are insufficient buffer resources idpf: replace flow scheduling buffer ring with buffer pool idpf: simplify and fix splitq Tx packet rollback error path idpf: improve when to set RE bit logic idpf: add support for Tx refillqs in flow scheduling mode ==================== Link: https://patch.msgid.link/20250821180100.401955-1-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
c61ac2ec10
|
|
@ -179,6 +179,58 @@ static int idpf_tx_singleq_csum(struct sk_buff *skb,
|
|||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* idpf_tx_singleq_dma_map_error - handle TX DMA map errors
|
||||
* @txq: queue to send buffer on
|
||||
* @skb: send buffer
|
||||
* @first: original first buffer info buffer for packet
|
||||
* @idx: starting point on ring to unwind
|
||||
*/
|
||||
static void idpf_tx_singleq_dma_map_error(struct idpf_tx_queue *txq,
|
||||
struct sk_buff *skb,
|
||||
struct idpf_tx_buf *first, u16 idx)
|
||||
{
|
||||
struct libeth_sq_napi_stats ss = { };
|
||||
struct libeth_cq_pp cp = {
|
||||
.dev = txq->dev,
|
||||
.ss = &ss,
|
||||
};
|
||||
|
||||
u64_stats_update_begin(&txq->stats_sync);
|
||||
u64_stats_inc(&txq->q_stats.dma_map_errs);
|
||||
u64_stats_update_end(&txq->stats_sync);
|
||||
|
||||
/* clear dma mappings for failed tx_buf map */
|
||||
for (;;) {
|
||||
struct idpf_tx_buf *tx_buf;
|
||||
|
||||
tx_buf = &txq->tx_buf[idx];
|
||||
libeth_tx_complete(tx_buf, &cp);
|
||||
if (tx_buf == first)
|
||||
break;
|
||||
if (idx == 0)
|
||||
idx = txq->desc_count;
|
||||
idx--;
|
||||
}
|
||||
|
||||
if (skb_is_gso(skb)) {
|
||||
union idpf_tx_flex_desc *tx_desc;
|
||||
|
||||
/* If we failed a DMA mapping for a TSO packet, we will have
|
||||
* used one additional descriptor for a context
|
||||
* descriptor. Reset that here.
|
||||
*/
|
||||
tx_desc = &txq->flex_tx[idx];
|
||||
memset(tx_desc, 0, sizeof(*tx_desc));
|
||||
if (idx == 0)
|
||||
idx = txq->desc_count;
|
||||
idx--;
|
||||
}
|
||||
|
||||
/* Update tail in case netdev_xmit_more was previously true */
|
||||
idpf_tx_buf_hw_update(txq, idx, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* idpf_tx_singleq_map - Build the Tx base descriptor
|
||||
* @tx_q: queue to send buffer on
|
||||
|
|
@ -219,8 +271,9 @@ static void idpf_tx_singleq_map(struct idpf_tx_queue *tx_q,
|
|||
for (frag = &skb_shinfo(skb)->frags[0];; frag++) {
|
||||
unsigned int max_data = IDPF_TX_MAX_DESC_DATA_ALIGNED;
|
||||
|
||||
if (dma_mapping_error(tx_q->dev, dma))
|
||||
return idpf_tx_dma_map_error(tx_q, skb, first, i);
|
||||
if (unlikely(dma_mapping_error(tx_q->dev, dma)))
|
||||
return idpf_tx_singleq_dma_map_error(tx_q, skb,
|
||||
first, i);
|
||||
|
||||
/* record length, and DMA address */
|
||||
dma_unmap_len_set(tx_buf, len, size);
|
||||
|
|
@ -362,11 +415,11 @@ netdev_tx_t idpf_tx_singleq_frame(struct sk_buff *skb,
|
|||
{
|
||||
struct idpf_tx_offload_params offload = { };
|
||||
struct idpf_tx_buf *first;
|
||||
u32 count, buf_count = 1;
|
||||
int csum, tso, needed;
|
||||
unsigned int count;
|
||||
__be16 protocol;
|
||||
|
||||
count = idpf_tx_desc_count_required(tx_q, skb);
|
||||
count = idpf_tx_res_count_required(tx_q, skb, &buf_count);
|
||||
if (unlikely(!count))
|
||||
return idpf_tx_drop_skb(tx_q, skb);
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -108,8 +108,8 @@ do { \
|
|||
*/
|
||||
#define IDPF_TX_SPLITQ_RE_MIN_GAP 64
|
||||
|
||||
#define IDPF_RX_BI_GEN_M BIT(16)
|
||||
#define IDPF_RX_BI_BUFID_M GENMASK(15, 0)
|
||||
#define IDPF_RFL_BI_GEN_M BIT(16)
|
||||
#define IDPF_RFL_BI_BUFID_M GENMASK(15, 0)
|
||||
|
||||
#define IDPF_RXD_EOF_SPLITQ VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_EOF_M
|
||||
#define IDPF_RXD_EOF_SINGLEQ VIRTCHNL2_RX_BASE_DESC_STATUS_EOF_M
|
||||
|
|
@ -118,10 +118,6 @@ do { \
|
|||
((((txq)->next_to_clean > (txq)->next_to_use) ? 0 : (txq)->desc_count) + \
|
||||
(txq)->next_to_clean - (txq)->next_to_use - 1)
|
||||
|
||||
#define IDPF_TX_BUF_RSV_UNUSED(txq) ((txq)->stash->buf_stack.top)
|
||||
#define IDPF_TX_BUF_RSV_LOW(txq) (IDPF_TX_BUF_RSV_UNUSED(txq) < \
|
||||
(txq)->desc_count >> 2)
|
||||
|
||||
#define IDPF_TX_COMPLQ_OVERFLOW_THRESH(txcq) ((txcq)->desc_count >> 1)
|
||||
/* Determine the absolute number of completions pending, i.e. the number of
|
||||
* completions that are expected to arrive on the TX completion queue.
|
||||
|
|
@ -131,11 +127,7 @@ do { \
|
|||
0 : U32_MAX) + \
|
||||
(txq)->num_completions_pending - (txq)->complq->num_completions)
|
||||
|
||||
#define IDPF_TX_SPLITQ_COMPL_TAG_WIDTH 16
|
||||
/* Adjust the generation for the completion tag and wrap if necessary */
|
||||
#define IDPF_TX_ADJ_COMPL_TAG_GEN(txq) \
|
||||
((++(txq)->compl_tag_cur_gen) >= (txq)->compl_tag_gen_max ? \
|
||||
0 : (txq)->compl_tag_cur_gen)
|
||||
#define IDPF_TXBUF_NULL U32_MAX
|
||||
|
||||
#define IDPF_TXD_LAST_DESC_CMD (IDPF_TX_DESC_CMD_EOP | IDPF_TX_DESC_CMD_RS)
|
||||
|
||||
|
|
@ -152,18 +144,6 @@ union idpf_tx_flex_desc {
|
|||
|
||||
#define idpf_tx_buf libeth_sqe
|
||||
|
||||
/**
|
||||
* struct idpf_buf_lifo - LIFO for managing OOO completions
|
||||
* @top: Used to know how many buffers are left
|
||||
* @size: Total size of LIFO
|
||||
* @bufs: Backing array
|
||||
*/
|
||||
struct idpf_buf_lifo {
|
||||
u16 top;
|
||||
u16 size;
|
||||
struct idpf_tx_stash **bufs;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct idpf_tx_offload_params - Offload parameters for a given packet
|
||||
* @tx_flags: Feature flags enabled for this packet
|
||||
|
|
@ -196,6 +176,9 @@ struct idpf_tx_offload_params {
|
|||
* @compl_tag: Associated tag for completion
|
||||
* @td_tag: Descriptor tunneling tag
|
||||
* @offload: Offload parameters
|
||||
* @prev_ntu: stored TxQ next_to_use in case of rollback
|
||||
* @prev_refill_ntc: stored refillq next_to_clean in case of packet rollback
|
||||
* @prev_refill_gen: stored refillq generation bit in case of packet rollback
|
||||
*/
|
||||
struct idpf_tx_splitq_params {
|
||||
enum idpf_tx_desc_dtype_value dtype;
|
||||
|
|
@ -206,6 +189,10 @@ struct idpf_tx_splitq_params {
|
|||
};
|
||||
|
||||
struct idpf_tx_offload_params offload;
|
||||
|
||||
u16 prev_ntu;
|
||||
u16 prev_refill_ntc;
|
||||
bool prev_refill_gen;
|
||||
};
|
||||
|
||||
enum idpf_tx_ctx_desc_eipt_offload {
|
||||
|
|
@ -467,17 +454,6 @@ struct idpf_tx_queue_stats {
|
|||
#define IDPF_ITR_IDX_SPACING(spacing, dflt) (spacing ? spacing : dflt)
|
||||
#define IDPF_DIM_DEFAULT_PROFILE_IX 1
|
||||
|
||||
/**
|
||||
* struct idpf_txq_stash - Tx buffer stash for Flow-based scheduling mode
|
||||
* @buf_stack: Stack of empty buffers to store buffer info for out of order
|
||||
* buffer completions. See struct idpf_buf_lifo
|
||||
* @sched_buf_hash: Hash table to store buffers
|
||||
*/
|
||||
struct idpf_txq_stash {
|
||||
struct idpf_buf_lifo buf_stack;
|
||||
DECLARE_HASHTABLE(sched_buf_hash, 12);
|
||||
} ____cacheline_aligned;
|
||||
|
||||
/**
|
||||
* struct idpf_rx_queue - software structure representing a receive queue
|
||||
* @rx: universal receive descriptor array
|
||||
|
|
@ -610,6 +586,8 @@ libeth_cacheline_set_assert(struct idpf_rx_queue, 64,
|
|||
* @netdev: &net_device corresponding to this queue
|
||||
* @next_to_use: Next descriptor to use
|
||||
* @next_to_clean: Next descriptor to clean
|
||||
* @last_re: last descriptor index that RE bit was set
|
||||
* @tx_max_bufs: Max buffers that can be transmitted with scatter-gather
|
||||
* @cleaned_bytes: Splitq only, TXQ only: When a TX completion is received on
|
||||
* the TX completion queue, it can be for any TXQ associated
|
||||
* with that completion queue. This means we can clean up to
|
||||
|
|
@ -620,11 +598,7 @@ libeth_cacheline_set_assert(struct idpf_rx_queue, 64,
|
|||
* only once at the end of the cleaning routine.
|
||||
* @clean_budget: singleq only, queue cleaning budget
|
||||
* @cleaned_pkts: Number of packets cleaned for the above said case
|
||||
* @tx_max_bufs: Max buffers that can be transmitted with scatter-gather
|
||||
* @stash: Tx buffer stash for Flow-based scheduling mode
|
||||
* @compl_tag_bufid_m: Completion tag buffer id mask
|
||||
* @compl_tag_cur_gen: Used to keep track of current completion tag generation
|
||||
* @compl_tag_gen_max: To determine when compl_tag_cur_gen should be reset
|
||||
* @refillq: Pointer to refill queue
|
||||
* @cached_tstamp_caps: Tx timestamp capabilities negotiated with the CP
|
||||
* @tstamp_task: Work that handles Tx timestamp read
|
||||
* @stats_sync: See struct u64_stats_sync
|
||||
|
|
@ -633,6 +607,7 @@ libeth_cacheline_set_assert(struct idpf_rx_queue, 64,
|
|||
* @size: Length of descriptor ring in bytes
|
||||
* @dma: Physical address of ring
|
||||
* @q_vector: Backreference to associated vector
|
||||
* @buf_pool_size: Total number of idpf_tx_buf
|
||||
*/
|
||||
struct idpf_tx_queue {
|
||||
__cacheline_group_begin_aligned(read_mostly);
|
||||
|
|
@ -654,7 +629,6 @@ struct idpf_tx_queue {
|
|||
u16 desc_count;
|
||||
|
||||
u16 tx_min_pkt_len;
|
||||
u16 compl_tag_gen_s;
|
||||
|
||||
struct net_device *netdev;
|
||||
__cacheline_group_end_aligned(read_mostly);
|
||||
|
|
@ -662,6 +636,8 @@ struct idpf_tx_queue {
|
|||
__cacheline_group_begin_aligned(read_write);
|
||||
u16 next_to_use;
|
||||
u16 next_to_clean;
|
||||
u16 last_re;
|
||||
u16 tx_max_bufs;
|
||||
|
||||
union {
|
||||
u32 cleaned_bytes;
|
||||
|
|
@ -669,12 +645,7 @@ struct idpf_tx_queue {
|
|||
};
|
||||
u16 cleaned_pkts;
|
||||
|
||||
u16 tx_max_bufs;
|
||||
struct idpf_txq_stash *stash;
|
||||
|
||||
u16 compl_tag_bufid_m;
|
||||
u16 compl_tag_cur_gen;
|
||||
u16 compl_tag_gen_max;
|
||||
struct idpf_sw_queue *refillq;
|
||||
|
||||
struct idpf_ptp_vport_tx_tstamp_caps *cached_tstamp_caps;
|
||||
struct work_struct *tstamp_task;
|
||||
|
|
@ -689,11 +660,12 @@ struct idpf_tx_queue {
|
|||
dma_addr_t dma;
|
||||
|
||||
struct idpf_q_vector *q_vector;
|
||||
u32 buf_pool_size;
|
||||
__cacheline_group_end_aligned(cold);
|
||||
};
|
||||
libeth_cacheline_set_assert(struct idpf_tx_queue, 64,
|
||||
112 + sizeof(struct u64_stats_sync),
|
||||
24);
|
||||
104 + sizeof(struct u64_stats_sync),
|
||||
32);
|
||||
|
||||
/**
|
||||
* struct idpf_buf_queue - software structure representing a buffer queue
|
||||
|
|
@ -903,7 +875,6 @@ struct idpf_rxq_group {
|
|||
* @vport: Vport back pointer
|
||||
* @num_txq: Number of TX queues associated
|
||||
* @txqs: Array of TX queue pointers
|
||||
* @stashes: array of OOO stashes for the queues
|
||||
* @complq: Associated completion queue pointer, split queue only
|
||||
* @num_completions_pending: Total number of completions pending for the
|
||||
* completion queue, acculumated for all TX queues
|
||||
|
|
@ -918,7 +889,6 @@ struct idpf_txq_group {
|
|||
|
||||
u16 num_txq;
|
||||
struct idpf_tx_queue *txqs[IDPF_LARGE_MAX_Q];
|
||||
struct idpf_txq_stash *stashes;
|
||||
|
||||
struct idpf_compl_queue *complq;
|
||||
|
||||
|
|
@ -1011,6 +981,17 @@ static inline void idpf_vport_intr_set_wb_on_itr(struct idpf_q_vector *q_vector)
|
|||
reg->dyn_ctl);
|
||||
}
|
||||
|
||||
/**
|
||||
* idpf_tx_splitq_get_free_bufs - get number of free buf_ids in refillq
|
||||
* @refillq: pointer to refillq containing buf_ids
|
||||
*/
|
||||
static inline u32 idpf_tx_splitq_get_free_bufs(struct idpf_sw_queue *refillq)
|
||||
{
|
||||
return (refillq->next_to_use > refillq->next_to_clean ?
|
||||
0 : refillq->desc_count) +
|
||||
refillq->next_to_use - refillq->next_to_clean - 1;
|
||||
}
|
||||
|
||||
int idpf_vport_singleq_napi_poll(struct napi_struct *napi, int budget);
|
||||
void idpf_vport_init_num_qs(struct idpf_vport *vport,
|
||||
struct virtchnl2_create_vport *vport_msg);
|
||||
|
|
@ -1038,10 +1019,8 @@ void idpf_tx_buf_hw_update(struct idpf_tx_queue *tx_q, u32 val,
|
|||
bool xmit_more);
|
||||
unsigned int idpf_size_to_txd_count(unsigned int size);
|
||||
netdev_tx_t idpf_tx_drop_skb(struct idpf_tx_queue *tx_q, struct sk_buff *skb);
|
||||
void idpf_tx_dma_map_error(struct idpf_tx_queue *txq, struct sk_buff *skb,
|
||||
struct idpf_tx_buf *first, u16 ring_idx);
|
||||
unsigned int idpf_tx_desc_count_required(struct idpf_tx_queue *txq,
|
||||
struct sk_buff *skb);
|
||||
unsigned int idpf_tx_res_count_required(struct idpf_tx_queue *txq,
|
||||
struct sk_buff *skb, u32 *buf_count);
|
||||
void idpf_tx_timeout(struct net_device *netdev, unsigned int txqueue);
|
||||
netdev_tx_t idpf_tx_singleq_frame(struct sk_buff *skb,
|
||||
struct idpf_tx_queue *tx_q);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user