Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3271e4f1 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'hv_netvsc-next'



K. Y. Srinivasan says:

====================
hv_netvsc: Eliminate memory allocation in the send path

The network protocol used to communicate with the host is the remote ndis (rndis)
protocol. We need to decorate each outgoing packet with a rndis header and
additional rndis state (rndis per-packet state). To manage this state, we
currently allocate memory in the transmit path. Eliminate this allocation by
requesting additional head room in the skb.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 4e833c59 b08cc791
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -128,6 +128,7 @@ struct ndis_tcp_ip_checksum_info;
struct hv_netvsc_packet {
	/* Bookkeeping stuff */
	u32 status;
	bool part_of_skb;

	struct hv_device *device;
	bool is_data_pkt;
@@ -150,7 +151,7 @@ struct hv_netvsc_packet {
	/* Points to the send/receive buffer where the ethernet frame is */
	void *data;
	u32 page_buf_cnt;
	struct hv_page_buffer page_buf[0];
	struct hv_page_buffer *page_buf;
};

struct netvsc_device_info {
+7 −2
Original line number Diff line number Diff line
@@ -866,8 +866,13 @@ int netvsc_send(struct hv_device *device,
		netvsc_copy_to_send_buf(net_device,
					section_index, msd_len,
					packet);
		if (!packet->part_of_skb) {
			skb = (struct sk_buff *)
		       (unsigned long)packet->send_completion_tid;
				(unsigned long)
				packet->send_completion_tid;

			packet->send_completion_tid = 0;
		}

		packet->page_buf_cnt = 0;
		packet->send_buf_index = section_index;
+50 −20
Original line number Diff line number Diff line
@@ -234,11 +234,11 @@ static void netvsc_xmit_completion(void *context)
	struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context;
	struct sk_buff *skb = (struct sk_buff *)
		(unsigned long)packet->send_completion_tid;
	u32 index = packet->send_buf_index;

	if (!packet->part_of_skb)
		kfree(packet);

	if (skb && (index == NETVSC_INVALID_INDEX))
	if (skb)
		dev_kfree_skb_any(skb);
}

@@ -384,6 +384,9 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
	u32 net_trans_info;
	u32 hash;
	u32 skb_length = skb->len;
	u32 head_room = skb_headroom(skb);
	u32 pkt_sz;
	struct hv_page_buffer page_buf[MAX_PAGE_BUFFER_COUNT];


	/* We will atmost need two pages to describe the rndis
@@ -398,24 +401,32 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
		return NETDEV_TX_OK;
	}

	/* Allocate a netvsc packet based on # of frags. */
	packet = kzalloc(sizeof(struct hv_netvsc_packet) +
			 (num_data_pgs * sizeof(struct hv_page_buffer)) +
	pkt_sz = sizeof(struct hv_netvsc_packet) +
			sizeof(struct rndis_message) +
			NDIS_VLAN_PPI_SIZE + NDIS_CSUM_PPI_SIZE +
			 NDIS_LSO_PPI_SIZE + NDIS_HASH_PPI_SIZE, GFP_ATOMIC);
			NDIS_LSO_PPI_SIZE + NDIS_HASH_PPI_SIZE;

	if (head_room < pkt_sz) {
		packet = kmalloc(pkt_sz, GFP_ATOMIC);
		if (!packet) {
			/* out of memory, drop packet */
		netdev_err(net, "unable to allocate hv_netvsc_packet\n");

			netdev_err(net, "unable to alloc hv_netvsc_packet\n");
			dev_kfree_skb(skb);
			net->stats.tx_dropped++;
			return NETDEV_TX_OK;
		}
		packet->part_of_skb = false;
	} else {
		/* Use the headroom for building up the packet */
		packet = (struct hv_netvsc_packet *)skb->head;
		packet->part_of_skb = true;
	}

	packet->status = 0;
	packet->xmit_more = skb->xmit_more;

	packet->vlan_tci = skb->vlan_tci;
	packet->page_buf = page_buf;

	packet->q_idx = skb_get_queue_mapping(skb);

@@ -423,8 +434,13 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
	packet->total_data_buflen = skb->len;

	packet->rndis_msg = (struct rndis_message *)((unsigned long)packet +
				sizeof(struct hv_netvsc_packet) +
				(num_data_pgs * sizeof(struct hv_page_buffer)));
				sizeof(struct hv_netvsc_packet));

	memset(packet->rndis_msg, 0, sizeof(struct rndis_message) +
					NDIS_VLAN_PPI_SIZE +
					NDIS_CSUM_PPI_SIZE +
					NDIS_LSO_PPI_SIZE +
					NDIS_HASH_PPI_SIZE);

	/* Set the completion routine */
	packet->send_completion = netvsc_xmit_completion;
@@ -556,7 +572,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
	rndis_msg->msg_len += rndis_msg_size;
	packet->total_data_buflen = rndis_msg->msg_len;
	packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size,
					skb, &packet->page_buf[0]);
					skb, &page_buf[0]);

	ret = netvsc_send(net_device_ctx->device_ctx, packet);

@@ -565,6 +581,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
		net->stats.tx_bytes += skb_length;
		net->stats.tx_packets++;
	} else {
		if (!packet->part_of_skb)
			kfree(packet);
		if (ret != -EAGAIN) {
			dev_kfree_skb_any(skb);
@@ -847,12 +864,18 @@ static int netvsc_probe(struct hv_device *dev,
	struct netvsc_device_info device_info;
	struct netvsc_device *nvdev;
	int ret;
	u32 max_needed_headroom;

	net = alloc_etherdev_mq(sizeof(struct net_device_context),
				num_online_cpus());
	if (!net)
		return -ENOMEM;

	max_needed_headroom = sizeof(struct hv_netvsc_packet) +
				sizeof(struct rndis_message) +
				NDIS_VLAN_PPI_SIZE + NDIS_CSUM_PPI_SIZE +
				NDIS_LSO_PPI_SIZE + NDIS_HASH_PPI_SIZE;

	netif_carrier_off(net);

	net_device_ctx = netdev_priv(net);
@@ -871,6 +894,13 @@ static int netvsc_probe(struct hv_device *dev,
	net->ethtool_ops = &ethtool_ops;
	SET_NETDEV_DEV(net, &dev->device);

	/*
	 * Request additional head room in the skb.
	 * We will use this space to build the rndis
	 * heaser and other state we need to maintain.
	 */
	net->needed_headroom = max_needed_headroom;

	/* Notify the netvsc driver of the new device */
	device_info.ring_size = ring_size;
	ret = rndis_filter_device_add(dev, &device_info);
+2 −0
Original line number Diff line number Diff line
@@ -210,6 +210,7 @@ static int rndis_filter_send_request(struct rndis_device *dev,
{
	int ret;
	struct hv_netvsc_packet *packet;
	struct hv_page_buffer page_buf[2];

	/* Setup the packet to send it */
	packet = &req->pkt;
@@ -217,6 +218,7 @@ static int rndis_filter_send_request(struct rndis_device *dev,
	packet->is_data_pkt = false;
	packet->total_data_buflen = req->request_msg.msg_len;
	packet->page_buf_cnt = 1;
	packet->page_buf = page_buf;

	packet->page_buf[0].pfn = virt_to_phys(&req->request_msg) >>
					PAGE_SHIFT;