drivers/net/ethernet/huawei/hinic3/hinic3_rx.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/huawei/hinic3/hinic3_rx.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/huawei/hinic3/hinic3_rx.c
Extension
.c
Size
15197 bytes
Lines
593
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 (rx_info->page) {
			page_pool_put_full_page(rqres->page_pool,
						rx_info->page, false);
			rx_info->page = NULL;
		}
	}
}

static void hinic3_add_rx_frag(struct hinic3_rxq *rxq,
			       struct hinic3_rx_info *rx_info,
			       struct sk_buff *skb, u32 size)
{
	struct page *page;
	u8 *va;

	page = rx_info->page;
	va = (u8 *)page_address(page) + rx_info->page_offset;
	net_prefetch(va);

	page_pool_dma_sync_for_cpu(rxq->page_pool, page, rx_info->page_offset,
				   rxq->buf_len);

	if (size <= HINIC3_RX_HDR_SIZE && !skb_is_nonlinear(skb)) {
		memcpy(__skb_put(skb, size), va,
		       ALIGN(size, sizeof(long)));
		page_pool_put_full_page(rxq->page_pool, page, false);

		return;
	}

	skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
			rx_info->page_offset, size, rxq->buf_len);
	skb_mark_for_recycle(skb);
}

static void packaging_skb(struct hinic3_rxq *rxq, struct sk_buff *skb,
			  u32 sge_num, u32 pkt_len)
{
	struct hinic3_rx_info *rx_info;
	u32 temp_pkt_len = pkt_len;
	u32 temp_sge_num = sge_num;
	u32 sw_ci;
	u32 size;

	sw_ci = rxq->cons_idx & rxq->q_mask;
	while (temp_sge_num) {
		rx_info = &rxq->rx_info[sw_ci];
		sw_ci = (sw_ci + 1) & rxq->q_mask;
		if (unlikely(temp_pkt_len > rxq->buf_len)) {
			size = rxq->buf_len;
			temp_pkt_len -= rxq->buf_len;
		} else {
			size = temp_pkt_len;
		}

		hinic3_add_rx_frag(rxq, rx_info, skb, size);

		/* clear contents of buffer_info */
		rx_info->page = NULL;
		temp_sge_num--;
	}
}

static u32 hinic3_get_sge_num(struct hinic3_rxq *rxq, u32 pkt_len)
{
	u32 sge_num;

	sge_num = pkt_len >> rxq->buf_len_shift;
	sge_num += (pkt_len & (rxq->buf_len - 1)) ? 1 : 0;

	return sge_num;
}

static struct sk_buff *hinic3_fetch_rx_buffer(struct hinic3_rxq *rxq,
					      u32 pkt_len)
{
	struct sk_buff *skb;
	u32 sge_num;

	skb = napi_alloc_skb(&rxq->irq_cfg->napi, HINIC3_RX_HDR_SIZE);
	if (unlikely(!skb))
		return NULL;

	sge_num = hinic3_get_sge_num(rxq, pkt_len);

	net_prefetchw(skb->data);
	packaging_skb(rxq, skb, sge_num, pkt_len);

	rxq->cons_idx += sge_num;
	rxq->delta += sge_num;

Annotation

Implementation Notes