aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/hyperv
diff options
context:
space:
mode:
authorKY Srinivasan <kys@microsoft.com>2015-03-30 00:08:42 -0400
committerDavid S. Miller <davem@davemloft.net>2015-03-31 14:12:36 -0400
commitb08cc79155fc26d0d112b1470d1ece5034651a4b (patch)
treef1d9c3316edd991b7c08ae73099d0bd53e0c4b54 /drivers/net/hyperv
parentcbacec76bcd03ff21b37ac331e652b5a8f3ea644 (diff)
hv_netvsc: Eliminate memory allocation in the packet 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: K. Y. Srinivasan <kys@microsoft.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/hyperv')
-rw-r--r--drivers/net/hyperv/hyperv_net.h3
-rw-r--r--drivers/net/hyperv/netvsc.c10
-rw-r--r--drivers/net/hyperv/netvsc_drv.c67
-rw-r--r--drivers/net/hyperv/rndis_filter.c2
4 files changed, 60 insertions, 22 deletions
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 384f057d6570..309adee6e791 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -128,6 +128,7 @@ struct ndis_tcp_ip_checksum_info;
128struct hv_netvsc_packet { 128struct hv_netvsc_packet {
129 /* Bookkeeping stuff */ 129 /* Bookkeeping stuff */
130 u32 status; 130 u32 status;
131 bool part_of_skb;
131 132
132 struct hv_device *device; 133 struct hv_device *device;
133 bool is_data_pkt; 134 bool is_data_pkt;
@@ -150,7 +151,7 @@ struct hv_netvsc_packet {
150 /* Points to the send/receive buffer where the ethernet frame is */ 151 /* Points to the send/receive buffer where the ethernet frame is */
151 void *data; 152 void *data;
152 u32 page_buf_cnt; 153 u32 page_buf_cnt;
153 struct hv_page_buffer page_buf[0]; 154 struct hv_page_buffer *page_buf;
154}; 155};
155 156
156struct netvsc_device_info { 157struct netvsc_device_info {
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index ecbd81385e96..f69923695b5b 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -866,11 +866,15 @@ int netvsc_send(struct hv_device *device,
866 netvsc_copy_to_send_buf(net_device, 866 netvsc_copy_to_send_buf(net_device,
867 section_index, msd_len, 867 section_index, msd_len,
868 packet); 868 packet);
869 skb = (struct sk_buff *) 869 if (!packet->part_of_skb) {
870 (unsigned long)packet->send_completion_tid; 870 skb = (struct sk_buff *)
871 (unsigned long)
872 packet->send_completion_tid;
873
874 packet->send_completion_tid = 0;
875 }
871 876
872 packet->page_buf_cnt = 0; 877 packet->page_buf_cnt = 0;
873 packet->send_completion_tid = 0;
874 packet->send_buf_index = section_index; 878 packet->send_buf_index = section_index;
875 packet->total_data_buflen += msd_len; 879 packet->total_data_buflen += msd_len;
876 880
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 75beb89aac9c..f9db6bc513e9 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -235,7 +235,8 @@ static void netvsc_xmit_completion(void *context)
235 struct sk_buff *skb = (struct sk_buff *) 235 struct sk_buff *skb = (struct sk_buff *)
236 (unsigned long)packet->send_completion_tid; 236 (unsigned long)packet->send_completion_tid;
237 237
238 kfree(packet); 238 if (!packet->part_of_skb)
239 kfree(packet);
239 240
240 if (skb) 241 if (skb)
241 dev_kfree_skb_any(skb); 242 dev_kfree_skb_any(skb);
@@ -383,6 +384,9 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
383 u32 net_trans_info; 384 u32 net_trans_info;
384 u32 hash; 385 u32 hash;
385 u32 skb_length = skb->len; 386 u32 skb_length = skb->len;
387 u32 head_room = skb_headroom(skb);
388 u32 pkt_sz;
389 struct hv_page_buffer page_buf[MAX_PAGE_BUFFER_COUNT];
386 390
387 391
388 /* We will atmost need two pages to describe the rndis 392 /* We will atmost need two pages to describe the rndis
@@ -397,24 +401,32 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
397 return NETDEV_TX_OK; 401 return NETDEV_TX_OK;
398 } 402 }
399 403
400 /* Allocate a netvsc packet based on # of frags. */ 404 pkt_sz = sizeof(struct hv_netvsc_packet) +
401 packet = kzalloc(sizeof(struct hv_netvsc_packet) + 405 sizeof(struct rndis_message) +
402 (num_data_pgs * sizeof(struct hv_page_buffer)) + 406 NDIS_VLAN_PPI_SIZE + NDIS_CSUM_PPI_SIZE +
403 sizeof(struct rndis_message) + 407 NDIS_LSO_PPI_SIZE + NDIS_HASH_PPI_SIZE;
404 NDIS_VLAN_PPI_SIZE + NDIS_CSUM_PPI_SIZE + 408
405 NDIS_LSO_PPI_SIZE + NDIS_HASH_PPI_SIZE, GFP_ATOMIC); 409 if (head_room < pkt_sz) {
406 if (!packet) { 410 packet = kmalloc(pkt_sz, GFP_ATOMIC);
407 /* out of memory, drop packet */ 411 if (!packet) {
408 netdev_err(net, "unable to allocate hv_netvsc_packet\n"); 412 /* out of memory, drop packet */
409 413 netdev_err(net, "unable to alloc hv_netvsc_packet\n");
410 dev_kfree_skb(skb); 414 dev_kfree_skb(skb);
411 net->stats.tx_dropped++; 415 net->stats.tx_dropped++;
412 return NETDEV_TX_OK; 416 return NETDEV_TX_OK;
417 }
418 packet->part_of_skb = false;
419 } else {
420 /* Use the headroom for building up the packet */
421 packet = (struct hv_netvsc_packet *)skb->head;
422 packet->part_of_skb = true;
413 } 423 }
414 424
425 packet->status = 0;
415 packet->xmit_more = skb->xmit_more; 426 packet->xmit_more = skb->xmit_more;
416 427
417 packet->vlan_tci = skb->vlan_tci; 428 packet->vlan_tci = skb->vlan_tci;
429 packet->page_buf = page_buf;
418 430
419 packet->q_idx = skb_get_queue_mapping(skb); 431 packet->q_idx = skb_get_queue_mapping(skb);
420 432
@@ -422,8 +434,13 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
422 packet->total_data_buflen = skb->len; 434 packet->total_data_buflen = skb->len;
423 435
424 packet->rndis_msg = (struct rndis_message *)((unsigned long)packet + 436 packet->rndis_msg = (struct rndis_message *)((unsigned long)packet +
425 sizeof(struct hv_netvsc_packet) + 437 sizeof(struct hv_netvsc_packet));
426 (num_data_pgs * sizeof(struct hv_page_buffer))); 438
439 memset(packet->rndis_msg, 0, sizeof(struct rndis_message) +
440 NDIS_VLAN_PPI_SIZE +
441 NDIS_CSUM_PPI_SIZE +
442 NDIS_LSO_PPI_SIZE +
443 NDIS_HASH_PPI_SIZE);
427 444
428 /* Set the completion routine */ 445 /* Set the completion routine */
429 packet->send_completion = netvsc_xmit_completion; 446 packet->send_completion = netvsc_xmit_completion;
@@ -555,7 +572,7 @@ do_send:
555 rndis_msg->msg_len += rndis_msg_size; 572 rndis_msg->msg_len += rndis_msg_size;
556 packet->total_data_buflen = rndis_msg->msg_len; 573 packet->total_data_buflen = rndis_msg->msg_len;
557 packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size, 574 packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size,
558 skb, &packet->page_buf[0]); 575 skb, &page_buf[0]);
559 576
560 ret = netvsc_send(net_device_ctx->device_ctx, packet); 577 ret = netvsc_send(net_device_ctx->device_ctx, packet);
561 578
@@ -564,7 +581,8 @@ drop:
564 net->stats.tx_bytes += skb_length; 581 net->stats.tx_bytes += skb_length;
565 net->stats.tx_packets++; 582 net->stats.tx_packets++;
566 } else { 583 } else {
567 kfree(packet); 584 if (!packet->part_of_skb)
585 kfree(packet);
568 if (ret != -EAGAIN) { 586 if (ret != -EAGAIN) {
569 dev_kfree_skb_any(skb); 587 dev_kfree_skb_any(skb);
570 net->stats.tx_dropped++; 588 net->stats.tx_dropped++;
@@ -846,12 +864,18 @@ static int netvsc_probe(struct hv_device *dev,
846 struct netvsc_device_info device_info; 864 struct netvsc_device_info device_info;
847 struct netvsc_device *nvdev; 865 struct netvsc_device *nvdev;
848 int ret; 866 int ret;
867 u32 max_needed_headroom;
849 868
850 net = alloc_etherdev_mq(sizeof(struct net_device_context), 869 net = alloc_etherdev_mq(sizeof(struct net_device_context),
851 num_online_cpus()); 870 num_online_cpus());
852 if (!net) 871 if (!net)
853 return -ENOMEM; 872 return -ENOMEM;
854 873
874 max_needed_headroom = sizeof(struct hv_netvsc_packet) +
875 sizeof(struct rndis_message) +
876 NDIS_VLAN_PPI_SIZE + NDIS_CSUM_PPI_SIZE +
877 NDIS_LSO_PPI_SIZE + NDIS_HASH_PPI_SIZE;
878
855 netif_carrier_off(net); 879 netif_carrier_off(net);
856 880
857 net_device_ctx = netdev_priv(net); 881 net_device_ctx = netdev_priv(net);
@@ -870,6 +894,13 @@ static int netvsc_probe(struct hv_device *dev,
870 net->ethtool_ops = &ethtool_ops; 894 net->ethtool_ops = &ethtool_ops;
871 SET_NETDEV_DEV(net, &dev->device); 895 SET_NETDEV_DEV(net, &dev->device);
872 896
897 /*
898 * Request additional head room in the skb.
899 * We will use this space to build the rndis
900 * heaser and other state we need to maintain.
901 */
902 net->needed_headroom = max_needed_headroom;
903
873 /* Notify the netvsc driver of the new device */ 904 /* Notify the netvsc driver of the new device */
874 device_info.ring_size = ring_size; 905 device_info.ring_size = ring_size;
875 ret = rndis_filter_device_add(dev, &device_info); 906 ret = rndis_filter_device_add(dev, &device_info);
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index fdfab1feccfc..a1604376aee1 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -210,6 +210,7 @@ static int rndis_filter_send_request(struct rndis_device *dev,
210{ 210{
211 int ret; 211 int ret;
212 struct hv_netvsc_packet *packet; 212 struct hv_netvsc_packet *packet;
213 struct hv_page_buffer page_buf[2];
213 214
214 /* Setup the packet to send it */ 215 /* Setup the packet to send it */
215 packet = &req->pkt; 216 packet = &req->pkt;
@@ -217,6 +218,7 @@ static int rndis_filter_send_request(struct rndis_device *dev,
217 packet->is_data_pkt = false; 218 packet->is_data_pkt = false;
218 packet->total_data_buflen = req->request_msg.msg_len; 219 packet->total_data_buflen = req->request_msg.msg_len;
219 packet->page_buf_cnt = 1; 220 packet->page_buf_cnt = 1;
221 packet->page_buf = page_buf;
220 222
221 packet->page_buf[0].pfn = virt_to_phys(&req->request_msg) >> 223 packet->page_buf[0].pfn = virt_to_phys(&req->request_msg) >>
222 PAGE_SHIFT; 224 PAGE_SHIFT;