aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/hyperv
diff options
context:
space:
mode:
authorHaiyang Zhang <haiyangz@microsoft.com>2014-04-21 17:54:43 -0400
committerDavid S. Miller <davem@davemloft.net>2014-04-23 14:48:39 -0400
commit4baab26129e0540746744232022110dbe9e011e7 (patch)
tree191b15d289faf1ba4cdaf6005156cbe87a920901 /drivers/net/hyperv
parentfd0d192be6e814495aec91f357b5801afc3b6262 (diff)
hyperv: Remove recv_pkt_list and lock
Removed recv_pkt_list and lock, and updated related code, so that the locking overhead is reduced especially when multiple channels are in use. The recv_pkt_list isn't actually necessary because the packets are processed sequentially in each channel. It has been replaced by a local variable, and the related lock for this list is also removed. The is_data_pkt field is not used in receive path, so its assignment is cleaned up. Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com> Reviewed-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.h33
-rw-r--r--drivers/net/hyperv/netvsc.c174
-rw-r--r--drivers/net/hyperv/netvsc_drv.c2
-rw-r--r--drivers/net/hyperv/rndis_filter.c2
4 files changed, 13 insertions, 198 deletions
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 57eb3f906d64..a1af0f7711e2 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -119,27 +119,14 @@ struct ndis_recv_scale_param { /* NDIS_RECEIVE_SCALE_PARAMETERS */
119}; 119};
120 120
121/* Fwd declaration */ 121/* Fwd declaration */
122struct hv_netvsc_packet;
123struct ndis_tcp_ip_checksum_info; 122struct ndis_tcp_ip_checksum_info;
124 123
125/* Represent the xfer page packet which contains 1 or more netvsc packet */
126struct xferpage_packet {
127 struct list_head list_ent;
128 u32 status;
129
130 /* # of netvsc packets this xfer packet contains */
131 u32 count;
132
133 struct vmbus_channel *channel;
134};
135
136/* 124/*
137 * Represent netvsc packet which contains 1 RNDIS and 1 ethernet frame 125 * Represent netvsc packet which contains 1 RNDIS and 1 ethernet frame
138 * within the RNDIS 126 * within the RNDIS
139 */ 127 */
140struct hv_netvsc_packet { 128struct hv_netvsc_packet {
141 /* Bookkeeping stuff */ 129 /* Bookkeeping stuff */
142 struct list_head list_ent;
143 u32 status; 130 u32 status;
144 131
145 struct hv_device *device; 132 struct hv_device *device;
@@ -149,19 +136,8 @@ struct hv_netvsc_packet {
149 u16 q_idx; 136 u16 q_idx;
150 struct vmbus_channel *channel; 137 struct vmbus_channel *channel;
151 138
152 /*
153 * Valid only for receives when we break a xfer page packet
154 * into multiple netvsc packets
155 */
156 struct xferpage_packet *xfer_page_pkt;
157
158 union { 139 union {
159 struct { 140 struct {
160 u64 recv_completion_tid;
161 void *recv_completion_ctx;
162 void (*recv_completion)(void *context);
163 } recv;
164 struct {
165 u64 send_completion_tid; 141 u64 send_completion_tid;
166 void *send_completion_ctx; 142 void *send_completion_ctx;
167 void (*send_completion)(void *context); 143 void (*send_completion)(void *context);
@@ -613,9 +589,6 @@ struct nvsp_message {
613 589
614#define NETVSC_RECEIVE_BUFFER_ID 0xcafe 590#define NETVSC_RECEIVE_BUFFER_ID 0xcafe
615 591
616/* Preallocated receive packets */
617#define NETVSC_RECEIVE_PACKETLIST_COUNT 256
618
619#define NETVSC_PACKET_SIZE 2048 592#define NETVSC_PACKET_SIZE 2048
620 593
621#define VRSS_SEND_TAB_SIZE 16 594#define VRSS_SEND_TAB_SIZE 16
@@ -630,12 +603,6 @@ struct netvsc_device {
630 wait_queue_head_t wait_drain; 603 wait_queue_head_t wait_drain;
631 bool start_remove; 604 bool start_remove;
632 bool destroy; 605 bool destroy;
633 /*
634 * List of free preallocated hv_netvsc_packet to represent receive
635 * packet
636 */
637 struct list_head recv_pkt_list;
638 spinlock_t recv_pkt_list_lock;
639 606
640 /* Receive buffer allocated by us but manages by NetVSP */ 607 /* Receive buffer allocated by us but manages by NetVSP */
641 void *recv_buf; 608 void *recv_buf;
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index e7e77f12bc38..b10334773b32 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -387,7 +387,6 @@ static void netvsc_disconnect_vsp(struct netvsc_device *net_device)
387int netvsc_device_remove(struct hv_device *device) 387int netvsc_device_remove(struct hv_device *device)
388{ 388{
389 struct netvsc_device *net_device; 389 struct netvsc_device *net_device;
390 struct hv_netvsc_packet *netvsc_packet, *pos;
391 unsigned long flags; 390 unsigned long flags;
392 391
393 net_device = hv_get_drvdata(device); 392 net_device = hv_get_drvdata(device);
@@ -416,12 +415,6 @@ int netvsc_device_remove(struct hv_device *device)
416 vmbus_close(device->channel); 415 vmbus_close(device->channel);
417 416
418 /* Release all resources */ 417 /* Release all resources */
419 list_for_each_entry_safe(netvsc_packet, pos,
420 &net_device->recv_pkt_list, list_ent) {
421 list_del(&netvsc_packet->list_ent);
422 kfree(netvsc_packet);
423 }
424
425 if (net_device->sub_cb_buf) 418 if (net_device->sub_cb_buf)
426 vfree(net_device->sub_cb_buf); 419 vfree(net_device->sub_cb_buf);
427 420
@@ -641,62 +634,6 @@ retry_send_cmplt:
641 } 634 }
642} 635}
643 636
644/* Send a receive completion packet to RNDIS device (ie NetVsp) */
645static void netvsc_receive_completion(void *context)
646{
647 struct hv_netvsc_packet *packet = context;
648 struct hv_device *device = packet->device;
649 struct vmbus_channel *channel;
650 struct netvsc_device *net_device;
651 u64 transaction_id = 0;
652 bool fsend_receive_comp = false;
653 unsigned long flags;
654 struct net_device *ndev;
655 u32 status = NVSP_STAT_NONE;
656
657 /*
658 * Even though it seems logical to do a GetOutboundNetDevice() here to
659 * send out receive completion, we are using GetInboundNetDevice()
660 * since we may have disable outbound traffic already.
661 */
662 net_device = get_inbound_net_device(device);
663 if (!net_device)
664 return;
665 ndev = net_device->ndev;
666
667 /* Overloading use of the lock. */
668 spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
669
670 if (packet->status != NVSP_STAT_SUCCESS)
671 packet->xfer_page_pkt->status = NVSP_STAT_FAIL;
672
673 packet->xfer_page_pkt->count--;
674
675 /*
676 * Last one in the line that represent 1 xfer page packet.
677 * Return the xfer page packet itself to the freelist
678 */
679 if (packet->xfer_page_pkt->count == 0) {
680 fsend_receive_comp = true;
681 channel = packet->xfer_page_pkt->channel;
682 transaction_id = packet->completion.recv.recv_completion_tid;
683 status = packet->xfer_page_pkt->status;
684 list_add_tail(&packet->xfer_page_pkt->list_ent,
685 &net_device->recv_pkt_list);
686
687 }
688
689 /* Put the packet back */
690 list_add_tail(&packet->list_ent, &net_device->recv_pkt_list);
691 spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags);
692
693 /* Send a receive completion for the xfer page packet */
694 if (fsend_receive_comp)
695 netvsc_send_recv_completion(device, channel, net_device,
696 transaction_id, status);
697
698}
699
700static void netvsc_receive(struct netvsc_device *net_device, 637static void netvsc_receive(struct netvsc_device *net_device,
701 struct vmbus_channel *channel, 638 struct vmbus_channel *channel,
702 struct hv_device *device, 639 struct hv_device *device,
@@ -704,16 +641,13 @@ static void netvsc_receive(struct netvsc_device *net_device,
704{ 641{
705 struct vmtransfer_page_packet_header *vmxferpage_packet; 642 struct vmtransfer_page_packet_header *vmxferpage_packet;
706 struct nvsp_message *nvsp_packet; 643 struct nvsp_message *nvsp_packet;
707 struct hv_netvsc_packet *netvsc_packet = NULL; 644 struct hv_netvsc_packet nv_pkt;
708 /* struct netvsc_driver *netvscDriver; */ 645 struct hv_netvsc_packet *netvsc_packet = &nv_pkt;
709 struct xferpage_packet *xferpage_packet = NULL; 646 u32 status = NVSP_STAT_SUCCESS;
710 int i; 647 int i;
711 int count = 0; 648 int count = 0;
712 unsigned long flags;
713 struct net_device *ndev; 649 struct net_device *ndev;
714 650
715 LIST_HEAD(listHead);
716
717 ndev = net_device->ndev; 651 ndev = net_device->ndev;
718 652
719 /* 653 /*
@@ -746,78 +680,14 @@ static void netvsc_receive(struct netvsc_device *net_device,
746 return; 680 return;
747 } 681 }
748 682
749 /* 683 count = vmxferpage_packet->range_cnt;
750 * Grab free packets (range count + 1) to represent this xfer 684 netvsc_packet->device = device;
751 * page packet. +1 to represent the xfer page packet itself. 685 netvsc_packet->channel = channel;
752 * We grab it here so that we know exactly how many we can
753 * fulfil
754 */
755 spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
756 while (!list_empty(&net_device->recv_pkt_list)) {
757 list_move_tail(net_device->recv_pkt_list.next, &listHead);
758 if (++count == vmxferpage_packet->range_cnt + 1)
759 break;
760 }
761 spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags);
762
763 /*
764 * We need at least 2 netvsc pkts (1 to represent the xfer
765 * page and at least 1 for the range) i.e. we can handled
766 * some of the xfer page packet ranges...
767 */
768 if (count < 2) {
769 netdev_err(ndev, "Got only %d netvsc pkt...needed "
770 "%d pkts. Dropping this xfer page packet completely!\n",
771 count, vmxferpage_packet->range_cnt + 1);
772
773 /* Return it to the freelist */
774 spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
775 for (i = count; i != 0; i--) {
776 list_move_tail(listHead.next,
777 &net_device->recv_pkt_list);
778 }
779 spin_unlock_irqrestore(&net_device->recv_pkt_list_lock,
780 flags);
781
782 netvsc_send_recv_completion(device, channel, net_device,
783 vmxferpage_packet->d.trans_id,
784 NVSP_STAT_FAIL);
785
786 return;
787 }
788
789 /* Remove the 1st packet to represent the xfer page packet itself */
790 xferpage_packet = (struct xferpage_packet *)listHead.next;
791 list_del(&xferpage_packet->list_ent);
792 xferpage_packet->status = NVSP_STAT_SUCCESS;
793 xferpage_packet->channel = channel;
794
795 /* This is how much we can satisfy */
796 xferpage_packet->count = count - 1;
797
798 if (xferpage_packet->count != vmxferpage_packet->range_cnt) {
799 netdev_err(ndev, "Needed %d netvsc pkts to satisfy "
800 "this xfer page...got %d\n",
801 vmxferpage_packet->range_cnt, xferpage_packet->count);
802 }
803 686
804 /* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */ 687 /* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */
805 for (i = 0; i < (count - 1); i++) { 688 for (i = 0; i < count; i++) {
806 netvsc_packet = (struct hv_netvsc_packet *)listHead.next;
807 list_del(&netvsc_packet->list_ent);
808
809 /* Initialize the netvsc packet */ 689 /* Initialize the netvsc packet */
810 netvsc_packet->status = NVSP_STAT_SUCCESS; 690 netvsc_packet->status = NVSP_STAT_SUCCESS;
811 netvsc_packet->xfer_page_pkt = xferpage_packet;
812 netvsc_packet->completion.recv.recv_completion =
813 netvsc_receive_completion;
814 netvsc_packet->completion.recv.recv_completion_ctx =
815 netvsc_packet;
816 netvsc_packet->device = device;
817 /* Save this so that we can send it back */
818 netvsc_packet->completion.recv.recv_completion_tid =
819 vmxferpage_packet->d.trans_id;
820
821 netvsc_packet->data = (void *)((unsigned long)net_device-> 691 netvsc_packet->data = (void *)((unsigned long)net_device->
822 recv_buf + vmxferpage_packet->ranges[i].byte_offset); 692 recv_buf + vmxferpage_packet->ranges[i].byte_offset);
823 netvsc_packet->total_data_buflen = 693 netvsc_packet->total_data_buflen =
@@ -826,10 +696,12 @@ static void netvsc_receive(struct netvsc_device *net_device,
826 /* Pass it to the upper layer */ 696 /* Pass it to the upper layer */
827 rndis_filter_receive(device, netvsc_packet); 697 rndis_filter_receive(device, netvsc_packet);
828 698
829 netvsc_receive_completion(netvsc_packet-> 699 if (netvsc_packet->status != NVSP_STAT_SUCCESS)
830 completion.recv.recv_completion_ctx); 700 status = NVSP_STAT_FAIL;
831 } 701 }
832 702
703 netvsc_send_recv_completion(device, channel, net_device,
704 vmxferpage_packet->d.trans_id, status);
833} 705}
834 706
835 707
@@ -956,11 +828,9 @@ void netvsc_channel_cb(void *context)
956int netvsc_device_add(struct hv_device *device, void *additional_info) 828int netvsc_device_add(struct hv_device *device, void *additional_info)
957{ 829{
958 int ret = 0; 830 int ret = 0;
959 int i;
960 int ring_size = 831 int ring_size =
961 ((struct netvsc_device_info *)additional_info)->ring_size; 832 ((struct netvsc_device_info *)additional_info)->ring_size;
962 struct netvsc_device *net_device; 833 struct netvsc_device *net_device;
963 struct hv_netvsc_packet *packet, *pos;
964 struct net_device *ndev; 834 struct net_device *ndev;
965 835
966 net_device = alloc_net_device(device); 836 net_device = alloc_net_device(device);
@@ -981,18 +851,6 @@ int netvsc_device_add(struct hv_device *device, void *additional_info)
981 ndev = net_device->ndev; 851 ndev = net_device->ndev;
982 852
983 /* Initialize the NetVSC channel extension */ 853 /* Initialize the NetVSC channel extension */
984 spin_lock_init(&net_device->recv_pkt_list_lock);
985
986 INIT_LIST_HEAD(&net_device->recv_pkt_list);
987
988 for (i = 0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) {
989 packet = kzalloc(sizeof(struct hv_netvsc_packet), GFP_KERNEL);
990 if (!packet)
991 break;
992
993 list_add_tail(&packet->list_ent,
994 &net_device->recv_pkt_list);
995 }
996 init_completion(&net_device->channel_init_wait); 854 init_completion(&net_device->channel_init_wait);
997 855
998 set_per_channel_state(device->channel, net_device->cb_buffer); 856 set_per_channel_state(device->channel, net_device->cb_buffer);
@@ -1028,16 +886,8 @@ close:
1028 886
1029cleanup: 887cleanup:
1030 888
1031 if (net_device) { 889 if (net_device)
1032 list_for_each_entry_safe(packet, pos,
1033 &net_device->recv_pkt_list,
1034 list_ent) {
1035 list_del(&packet->list_ent);
1036 kfree(packet);
1037 }
1038
1039 kfree(net_device); 890 kfree(net_device);
1040 }
1041 891
1042 return ret; 892 return ret;
1043} 893}
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 093cf3fc46b8..8f6d53a2ed95 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -638,7 +638,7 @@ int netvsc_recv_callback(struct hv_device *device_obj,
638 __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), 638 __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
639 packet->vlan_tci); 639 packet->vlan_tci);
640 640
641 skb_record_rx_queue(skb, packet->xfer_page_pkt->channel-> 641 skb_record_rx_queue(skb, packet->channel->
642 offermsg.offer.sub_channel_index % 642 offermsg.offer.sub_channel_index %
643 net->real_num_rx_queues); 643 net->real_num_rx_queues);
644 644
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index d92cfbe43410..48f5a0fbd674 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -401,8 +401,6 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
401 pkt->total_data_buflen = rndis_pkt->data_len; 401 pkt->total_data_buflen = rndis_pkt->data_len;
402 pkt->data = (void *)((unsigned long)pkt->data + data_offset); 402 pkt->data = (void *)((unsigned long)pkt->data + data_offset);
403 403
404 pkt->is_data_pkt = true;
405
406 vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO); 404 vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO);
407 if (vlan) { 405 if (vlan) {
408 pkt->vlan_tci = VLAN_TAG_PRESENT | vlan->vlanid | 406 pkt->vlan_tci = VLAN_TAG_PRESENT | vlan->vlanid |