xsk: support ZC Tx multi-buffer in batch API

Modify xskq_cons_read_desc_batch() in a way that each processed
descriptor will be checked if it is an EOP one or not and act
accordingly to that.

Change the behavior of mentioned function to break the processing when
stumbling upon invalid descriptor instead of skipping it. Furthermore,
let us give only full packets down to ZC driver.
With these two assumptions ZC drivers will not have to take care of an
intermediate state of incomplete frames, which will simplify its
implementations a lot.

Last but not least, stop processing when count of frags would exceed
max supported segments on underlying device.

Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
Link: https://lore.kernel.org/r/20230719132421.584801-15-maciej.fijalkowski@intel.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Maciej Fijalkowski 2023-07-19 15:24:11 +02:00 committed by Alexei Starovoitov
parent 1c9ba9c146
commit d558196604

View File

@ -48,6 +48,11 @@ struct xsk_queue {
size_t ring_vmalloc_size;
};
struct parsed_desc {
u32 mb;
u32 valid;
};
/* The structure of the shared state of the rings are a simple
* circular buffer, as outlined in
* Documentation/core-api/circular-buffers.rst. For the Rx and
@ -218,30 +223,52 @@ static inline void xskq_cons_release_n(struct xsk_queue *q, u32 cnt)
q->cached_cons += cnt;
}
static inline u32 xskq_cons_read_desc_batch(struct xsk_queue *q, struct xsk_buff_pool *pool,
u32 max)
static inline void parse_desc(struct xsk_queue *q, struct xsk_buff_pool *pool,
struct xdp_desc *desc, struct parsed_desc *parsed)
{
parsed->valid = xskq_cons_is_valid_desc(q, desc, pool);
parsed->mb = xp_mb_desc(desc);
}
static inline
u32 xskq_cons_read_desc_batch(struct xsk_queue *q, struct xsk_buff_pool *pool,
u32 max)
{
u32 cached_cons = q->cached_cons, nb_entries = 0;
struct xdp_desc *descs = pool->tx_descs;
u32 total_descs = 0, nr_frags = 0;
/* track first entry, if stumble upon *any* invalid descriptor, rewind
* current packet that consists of frags and stop the processing
*/
while (cached_cons != q->cached_prod && nb_entries < max) {
struct xdp_rxtx_ring *ring = (struct xdp_rxtx_ring *)q->ring;
u32 idx = cached_cons & q->ring_mask;
struct parsed_desc parsed;
descs[nb_entries] = ring->desc[idx];
if (unlikely(!xskq_cons_is_valid_desc(q, &descs[nb_entries], pool))) {
/* Skip the entry */
cached_cons++;
continue;
}
nb_entries++;
cached_cons++;
parse_desc(q, pool, &descs[nb_entries], &parsed);
if (unlikely(!parsed.valid))
break;
if (likely(!parsed.mb)) {
total_descs += (nr_frags + 1);
nr_frags = 0;
} else {
nr_frags++;
if (nr_frags == pool->netdev->xdp_zc_max_segs) {
nr_frags = 0;
break;
}
}
nb_entries++;
}
cached_cons -= nr_frags;
/* Release valid plus any invalid entries */
xskq_cons_release_n(q, cached_cons - q->cached_cons);
return nb_entries;
return total_descs;
}
/* Functions for consumers */