drivers/net/ethernet/cavium/thunder/nicvf_queues.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/cavium/thunder/nicvf_queues.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/cavium/thunder/nicvf_queues.c
Extension
.c
Size
52459 bytes
Lines
1972
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (rbdr->is_xdp) {
			if (ref_count == pgcache->ref_count)
				pgcache->ref_count--;
			else
				page = NULL;
		} else if (ref_count != 1) {
			page = NULL;
		}
	}

	if (!page) {
		page = alloc_pages(gfp | __GFP_COMP | __GFP_NOWARN, 0);
		if (!page)
			return NULL;

		this_cpu_inc(nic->pnicvf->drv_stats->page_alloc);

		/* Check for space */
		if (rbdr->pgalloc >= rbdr->pgcnt) {
			/* Page can still be used */
			nic->rb_page = page;
			return NULL;
		}

		/* Save the page in page cache */
		pgcache->page = page;
		pgcache->dma_addr = 0;
		pgcache->ref_count = 0;
		rbdr->pgalloc++;
	}

	/* Take additional page references for recycling */
	if (rbdr->is_xdp) {
		/* Since there is single RBDR (i.e single core doing
		 * page recycling) per 8 Rx queues, in XDP mode adjusting
		 * page references atomically is the biggest bottleneck, so
		 * take bunch of references at a time.
		 *
		 * So here, below reference counts defer by '1'.
		 */
		if (!pgcache->ref_count) {
			pgcache->ref_count = XDP_PAGE_REFCNT_REFILL;
			page_ref_add(page, XDP_PAGE_REFCNT_REFILL);
		}
	} else {
		/* In non-XDP case, single 64K page is divided across multiple
		 * receive buffers, so cost of recycling is less anyway.
		 * So we can do with just one extra reference.
		 */
		page_ref_add(page, 1);
	}

	rbdr->pgidx++;
	rbdr->pgidx &= (rbdr->pgcnt - 1);

	/* Prefetch refcount of next page in page cache */
	next = &rbdr->pgcache[rbdr->pgidx];
	page = next->page;
	if (page)
		prefetch(&page->_refcount);

	return pgcache;
}

/* Allocate buffer for packet reception */
static inline int nicvf_alloc_rcv_buffer(struct nicvf *nic, struct rbdr *rbdr,
					 gfp_t gfp, u32 buf_len, u64 *rbuf)
{
	struct pgcache *pgcache = NULL;

	/* Check if request can be accomodated in previous allocated page.
	 * But in XDP mode only one buffer per page is permitted.
	 */
	if (!rbdr->is_xdp && nic->rb_page &&
	    ((nic->rb_page_offset + buf_len) <= PAGE_SIZE)) {
		nic->rb_pageref++;
		goto ret;
	}

	nicvf_get_page(nic);
	nic->rb_page = NULL;

	/* Get new page, either recycled or new one */
	pgcache = nicvf_alloc_page(nic, rbdr, gfp);
	if (!pgcache && !nic->rb_page) {
		this_cpu_inc(nic->pnicvf->drv_stats->rcv_buffer_alloc_failures);
		return -ENOMEM;
	}

	nic->rb_page_offset = 0;

Annotation

Implementation Notes