Contributors: 3
Author Tokens Token Proportion Commits Commit Proportion
Alexander Lobakin 518 98.48% 2 50.00%
Anirudh Venkataramanan 4 0.76% 1 25.00%
Greg Rose 4 0.76% 1 25.00%
Total 526 4


// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2024 Intel Corporation */

#include <net/libeth/rx.h>

/* Rx buffer management */

/**
 * libeth_rx_hw_len - get the actual buffer size to be passed to HW
 * @pp: &page_pool_params of the netdev to calculate the size for
 * @max_len: maximum buffer size for a single descriptor
 *
 * Return: HW-writeable length per one buffer to pass it to the HW accounting:
 * MTU the @dev has, HW required alignment, minimum and maximum allowed values,
 * and system's page size.
 */
static u32 libeth_rx_hw_len(const struct page_pool_params *pp, u32 max_len)
{
	u32 len;

	len = READ_ONCE(pp->netdev->mtu) + LIBETH_RX_LL_LEN;
	len = ALIGN(len, LIBETH_RX_BUF_STRIDE);
	len = min3(len, ALIGN_DOWN(max_len ? : U32_MAX, LIBETH_RX_BUF_STRIDE),
		   pp->max_len);

	return len;
}

/**
 * libeth_rx_fq_create - create a PP with the default libeth settings
 * @fq: buffer queue struct to fill
 * @napi: &napi_struct covering this PP (no usage outside its poll loops)
 *
 * Return: %0 on success, -%errno on failure.
 */
int libeth_rx_fq_create(struct libeth_fq *fq, struct napi_struct *napi)
{
	struct page_pool_params pp = {
		.flags		= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
		.order		= LIBETH_RX_PAGE_ORDER,
		.pool_size	= fq->count,
		.nid		= fq->nid,
		.dev		= napi->dev->dev.parent,
		.netdev		= napi->dev,
		.napi		= napi,
		.dma_dir	= DMA_FROM_DEVICE,
		.offset		= LIBETH_SKB_HEADROOM,
	};
	struct libeth_fqe *fqes;
	struct page_pool *pool;

	/* HW-writeable / syncable length per one page */
	pp.max_len = LIBETH_RX_PAGE_LEN(pp.offset);

	/* HW-writeable length per buffer */
	fq->buf_len = libeth_rx_hw_len(&pp, fq->buf_len);
	/* Buffer size to allocate */
	fq->truesize = roundup_pow_of_two(SKB_HEAD_ALIGN(pp.offset +
							 fq->buf_len));

	pool = page_pool_create(&pp);
	if (IS_ERR(pool))
		return PTR_ERR(pool);

	fqes = kvcalloc_node(fq->count, sizeof(*fqes), GFP_KERNEL, fq->nid);
	if (!fqes)
		goto err_buf;

	fq->fqes = fqes;
	fq->pp = pool;

	return 0;

err_buf:
	page_pool_destroy(pool);

	return -ENOMEM;
}
EXPORT_SYMBOL_NS_GPL(libeth_rx_fq_create, LIBETH);

/**
 * libeth_rx_fq_destroy - destroy a &page_pool created by libeth
 * @fq: buffer queue to process
 */
void libeth_rx_fq_destroy(struct libeth_fq *fq)
{
	kvfree(fq->fqes);
	page_pool_destroy(fq->pp);
}
EXPORT_SYMBOL_NS_GPL(libeth_rx_fq_destroy, LIBETH);

/**
 * libeth_rx_recycle_slow - recycle a libeth page from the NAPI context
 * @page: page to recycle
 *
 * To be used on exceptions or rare cases not requiring fast inline recycling.
 */
void libeth_rx_recycle_slow(struct page *page)
{
	page_pool_recycle_direct(page->pp, page);
}
EXPORT_SYMBOL_NS_GPL(libeth_rx_recycle_slow, LIBETH);

/* Converting abstract packet type numbers into a software structure with
 * the packet parameters to do O(1) lookup on Rx.
 */

static const u16 libeth_rx_pt_xdp_oip[] = {
	[LIBETH_RX_PT_OUTER_L2]		= XDP_RSS_TYPE_NONE,
	[LIBETH_RX_PT_OUTER_IPV4]	= XDP_RSS_L3_IPV4,
	[LIBETH_RX_PT_OUTER_IPV6]	= XDP_RSS_L3_IPV6,
};

static const u16 libeth_rx_pt_xdp_iprot[] = {
	[LIBETH_RX_PT_INNER_NONE]	= XDP_RSS_TYPE_NONE,
	[LIBETH_RX_PT_INNER_UDP]	= XDP_RSS_L4_UDP,
	[LIBETH_RX_PT_INNER_TCP]	= XDP_RSS_L4_TCP,
	[LIBETH_RX_PT_INNER_SCTP]	= XDP_RSS_L4_SCTP,
	[LIBETH_RX_PT_INNER_ICMP]	= XDP_RSS_L4_ICMP,
	[LIBETH_RX_PT_INNER_TIMESYNC]	= XDP_RSS_TYPE_NONE,
};

static const u16 libeth_rx_pt_xdp_pl[] = {
	[LIBETH_RX_PT_PAYLOAD_NONE]	= XDP_RSS_TYPE_NONE,
	[LIBETH_RX_PT_PAYLOAD_L2]	= XDP_RSS_TYPE_NONE,
	[LIBETH_RX_PT_PAYLOAD_L3]	= XDP_RSS_TYPE_NONE,
	[LIBETH_RX_PT_PAYLOAD_L4]	= XDP_RSS_L4,
};

/**
 * libeth_rx_pt_gen_hash_type - generate an XDP RSS hash type for a PT
 * @pt: PT structure to evaluate
 *
 * Generates ```hash_type``` field with XDP RSS type values from the parsed
 * packet parameters if they're obtained dynamically at runtime.
 */
void libeth_rx_pt_gen_hash_type(struct libeth_rx_pt *pt)
{
	pt->hash_type = 0;
	pt->hash_type |= libeth_rx_pt_xdp_oip[pt->outer_ip];
	pt->hash_type |= libeth_rx_pt_xdp_iprot[pt->inner_prot];
	pt->hash_type |= libeth_rx_pt_xdp_pl[pt->payload_layer];
}
EXPORT_SYMBOL_NS_GPL(libeth_rx_pt_gen_hash_type, LIBETH);

/* Module */

MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("Common Ethernet library");
MODULE_LICENSE("GPL");