drivers/net/hyperv/netvsc_drv.c

Source file repositories/reference/linux-study-clean/drivers/net/hyperv/netvsc_drv.c

File Facts

System
Linux kernel
Corpus path
drivers/net/hyperv/netvsc_drv.c
Extension
.c
Size
76374 bytes
Lines
2901
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern 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

const struct net_device_ops *vf_ops = vf_netdev->netdev_ops;

		if (vf_ops->ndo_select_queue)
			txq = vf_ops->ndo_select_queue(vf_netdev, skb, sb_dev);
		else
			txq = netdev_pick_tx(vf_netdev, skb, NULL);

		/* Record the queue selected by VF so that it can be
		 * used for common case where VF has more queues than
		 * the synthetic device.
		 */
		qdisc_skb_cb(skb)->slave_dev_queue_mapping = txq;
	} else {
		txq = netvsc_pick_tx(ndev, skb);
	}
	rcu_read_unlock();

	while (txq >= ndev->real_num_tx_queues)
		txq -= ndev->real_num_tx_queues;

	return txq;
}

static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb,
			   struct hv_netvsc_packet *packet,
			   struct hv_page_buffer *pb)
{
	int frags = skb_shinfo(skb)->nr_frags;
	int i;

	/* The packet is laid out thus:
	 * 1. hdr: RNDIS header and PPI
	 * 2. skb linear data
	 * 3. skb fragment data
	 */

	pb[0].offset = offset_in_hvpage(hdr);
	pb[0].len = len;
	pb[0].pfn = virt_to_hvpfn(hdr);
	packet->rmsg_size = len;

	pb[1].offset = offset_in_hvpage(skb->data);
	pb[1].len = skb_headlen(skb);
	pb[1].pfn = virt_to_hvpfn(skb->data);

	for (i = 0; i < frags; i++) {
		skb_frag_t *frag = skb_shinfo(skb)->frags + i;
		struct hv_page_buffer *cur_pb = &pb[i + 2];
		u64 pfn = page_to_hvpfn(skb_frag_page(frag));
		u32 offset = skb_frag_off(frag);

		cur_pb->offset = offset_in_hvpage(offset);
		cur_pb->len = skb_frag_size(frag);
		cur_pb->pfn = pfn + (offset >> HV_HYP_PAGE_SHIFT);
	}
	return frags + 2;
}

static int count_skb_frag_slots(struct sk_buff *skb)
{
	int i, frags = skb_shinfo(skb)->nr_frags;
	int pages = 0;

	for (i = 0; i < frags; i++) {
		skb_frag_t *frag = skb_shinfo(skb)->frags + i;
		unsigned long size = skb_frag_size(frag);
		unsigned long offset = skb_frag_off(frag);

		/* Skip unused frames from start of page */
		offset &= ~HV_HYP_PAGE_MASK;
		pages += HVPFN_UP(offset + size);
	}
	return pages;
}

static int netvsc_get_slots(struct sk_buff *skb)
{
	char *data = skb->data;
	unsigned int offset = offset_in_hvpage(data);
	unsigned int len = skb_headlen(skb);
	int slots;
	int frag_slots;

	slots = DIV_ROUND_UP(offset + len, HV_HYP_PAGE_SIZE);
	frag_slots = count_skb_frag_slots(skb);
	return slots + frag_slots;
}

static u32 net_checksum_info(struct sk_buff *skb)
{

Annotation

Implementation Notes