diff options
author | Haiyang Zhang <haiyangz@microsoft.com> | 2012-10-02 01:30:23 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-10-02 14:39:31 -0400 |
commit | 63f6921d300c6fbdca3d0e73dcc24b4e5e4dced2 (patch) | |
tree | 5cd2560e12959f51574e0235bc1d9bdb81b30b98 /drivers/net | |
parent | 6562640bd3b368a7ffb1caa61c82abe6e9d54b3b (diff) |
hyperv: Report actual status in receive completion packet
The existing code always reports NVSP_STAT_SUCCESS. This patch adds the
mechanism to report failure when it happens.
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')
-rw-r--r-- | drivers/net/hyperv/hyperv_net.h | 2 | ||||
-rw-r--r-- | drivers/net/hyperv/netvsc.c | 18 | ||||
-rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 2 | ||||
-rw-r--r-- | drivers/net/hyperv/rndis_filter.c | 19 |
4 files changed, 30 insertions, 11 deletions
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index d58f28c46386..5fd6f4674326 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h | |||
@@ -35,6 +35,7 @@ struct hv_netvsc_packet; | |||
35 | /* Represent the xfer page packet which contains 1 or more netvsc packet */ | 35 | /* Represent the xfer page packet which contains 1 or more netvsc packet */ |
36 | struct xferpage_packet { | 36 | struct xferpage_packet { |
37 | struct list_head list_ent; | 37 | struct list_head list_ent; |
38 | u32 status; | ||
38 | 39 | ||
39 | /* # of netvsc packets this xfer packet contains */ | 40 | /* # of netvsc packets this xfer packet contains */ |
40 | u32 count; | 41 | u32 count; |
@@ -47,6 +48,7 @@ struct xferpage_packet { | |||
47 | struct hv_netvsc_packet { | 48 | struct hv_netvsc_packet { |
48 | /* Bookkeeping stuff */ | 49 | /* Bookkeeping stuff */ |
49 | struct list_head list_ent; | 50 | struct list_head list_ent; |
51 | u32 status; | ||
50 | 52 | ||
51 | struct hv_device *device; | 53 | struct hv_device *device; |
52 | bool is_data_pkt; | 54 | bool is_data_pkt; |
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index d9c4c0399c88..1cd77483da50 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c | |||
@@ -558,7 +558,7 @@ int netvsc_send(struct hv_device *device, | |||
558 | } | 558 | } |
559 | 559 | ||
560 | static void netvsc_send_recv_completion(struct hv_device *device, | 560 | static void netvsc_send_recv_completion(struct hv_device *device, |
561 | u64 transaction_id) | 561 | u64 transaction_id, u32 status) |
562 | { | 562 | { |
563 | struct nvsp_message recvcompMessage; | 563 | struct nvsp_message recvcompMessage; |
564 | int retries = 0; | 564 | int retries = 0; |
@@ -571,9 +571,7 @@ static void netvsc_send_recv_completion(struct hv_device *device, | |||
571 | recvcompMessage.hdr.msg_type = | 571 | recvcompMessage.hdr.msg_type = |
572 | NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE; | 572 | NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE; |
573 | 573 | ||
574 | /* FIXME: Pass in the status */ | 574 | recvcompMessage.msg.v1_msg.send_rndis_pkt_complete.status = status; |
575 | recvcompMessage.msg.v1_msg.send_rndis_pkt_complete.status = | ||
576 | NVSP_STAT_SUCCESS; | ||
577 | 575 | ||
578 | retry_send_cmplt: | 576 | retry_send_cmplt: |
579 | /* Send the completion */ | 577 | /* Send the completion */ |
@@ -613,6 +611,7 @@ static void netvsc_receive_completion(void *context) | |||
613 | bool fsend_receive_comp = false; | 611 | bool fsend_receive_comp = false; |
614 | unsigned long flags; | 612 | unsigned long flags; |
615 | struct net_device *ndev; | 613 | struct net_device *ndev; |
614 | u32 status = NVSP_STAT_NONE; | ||
616 | 615 | ||
617 | /* | 616 | /* |
618 | * Even though it seems logical to do a GetOutboundNetDevice() here to | 617 | * Even though it seems logical to do a GetOutboundNetDevice() here to |
@@ -627,6 +626,9 @@ static void netvsc_receive_completion(void *context) | |||
627 | /* Overloading use of the lock. */ | 626 | /* Overloading use of the lock. */ |
628 | spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags); | 627 | spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags); |
629 | 628 | ||
629 | if (packet->status != NVSP_STAT_SUCCESS) | ||
630 | packet->xfer_page_pkt->status = NVSP_STAT_FAIL; | ||
631 | |||
630 | packet->xfer_page_pkt->count--; | 632 | packet->xfer_page_pkt->count--; |
631 | 633 | ||
632 | /* | 634 | /* |
@@ -636,6 +638,7 @@ static void netvsc_receive_completion(void *context) | |||
636 | if (packet->xfer_page_pkt->count == 0) { | 638 | if (packet->xfer_page_pkt->count == 0) { |
637 | fsend_receive_comp = true; | 639 | fsend_receive_comp = true; |
638 | transaction_id = packet->completion.recv.recv_completion_tid; | 640 | transaction_id = packet->completion.recv.recv_completion_tid; |
641 | status = packet->xfer_page_pkt->status; | ||
639 | list_add_tail(&packet->xfer_page_pkt->list_ent, | 642 | list_add_tail(&packet->xfer_page_pkt->list_ent, |
640 | &net_device->recv_pkt_list); | 643 | &net_device->recv_pkt_list); |
641 | 644 | ||
@@ -647,7 +650,7 @@ static void netvsc_receive_completion(void *context) | |||
647 | 650 | ||
648 | /* Send a receive completion for the xfer page packet */ | 651 | /* Send a receive completion for the xfer page packet */ |
649 | if (fsend_receive_comp) | 652 | if (fsend_receive_comp) |
650 | netvsc_send_recv_completion(device, transaction_id); | 653 | netvsc_send_recv_completion(device, transaction_id, status); |
651 | 654 | ||
652 | } | 655 | } |
653 | 656 | ||
@@ -736,7 +739,8 @@ static void netvsc_receive(struct hv_device *device, | |||
736 | flags); | 739 | flags); |
737 | 740 | ||
738 | netvsc_send_recv_completion(device, | 741 | netvsc_send_recv_completion(device, |
739 | vmxferpage_packet->d.trans_id); | 742 | vmxferpage_packet->d.trans_id, |
743 | NVSP_STAT_FAIL); | ||
740 | 744 | ||
741 | return; | 745 | return; |
742 | } | 746 | } |
@@ -744,6 +748,7 @@ static void netvsc_receive(struct hv_device *device, | |||
744 | /* Remove the 1st packet to represent the xfer page packet itself */ | 748 | /* Remove the 1st packet to represent the xfer page packet itself */ |
745 | xferpage_packet = (struct xferpage_packet *)listHead.next; | 749 | xferpage_packet = (struct xferpage_packet *)listHead.next; |
746 | list_del(&xferpage_packet->list_ent); | 750 | list_del(&xferpage_packet->list_ent); |
751 | xferpage_packet->status = NVSP_STAT_SUCCESS; | ||
747 | 752 | ||
748 | /* This is how much we can satisfy */ | 753 | /* This is how much we can satisfy */ |
749 | xferpage_packet->count = count - 1; | 754 | xferpage_packet->count = count - 1; |
@@ -760,6 +765,7 @@ static void netvsc_receive(struct hv_device *device, | |||
760 | list_del(&netvsc_packet->list_ent); | 765 | list_del(&netvsc_packet->list_ent); |
761 | 766 | ||
762 | /* Initialize the netvsc packet */ | 767 | /* Initialize the netvsc packet */ |
768 | netvsc_packet->status = NVSP_STAT_SUCCESS; | ||
763 | netvsc_packet->xfer_page_pkt = xferpage_packet; | 769 | netvsc_packet->xfer_page_pkt = xferpage_packet; |
764 | netvsc_packet->completion.recv.recv_completion = | 770 | netvsc_packet->completion.recv.recv_completion = |
765 | netvsc_receive_completion; | 771 | netvsc_receive_completion; |
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index e91111a656f7..f825a629a699 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c | |||
@@ -265,6 +265,7 @@ int netvsc_recv_callback(struct hv_device *device_obj, | |||
265 | if (!net) { | 265 | if (!net) { |
266 | netdev_err(net, "got receive callback but net device" | 266 | netdev_err(net, "got receive callback but net device" |
267 | " not initialized yet\n"); | 267 | " not initialized yet\n"); |
268 | packet->status = NVSP_STAT_FAIL; | ||
268 | return 0; | 269 | return 0; |
269 | } | 270 | } |
270 | 271 | ||
@@ -272,6 +273,7 @@ int netvsc_recv_callback(struct hv_device *device_obj, | |||
272 | skb = netdev_alloc_skb_ip_align(net, packet->total_data_buflen); | 273 | skb = netdev_alloc_skb_ip_align(net, packet->total_data_buflen); |
273 | if (unlikely(!skb)) { | 274 | if (unlikely(!skb)) { |
274 | ++net->stats.rx_dropped; | 275 | ++net->stats.rx_dropped; |
276 | packet->status = NVSP_STAT_FAIL; | ||
275 | return 0; | 277 | return 0; |
276 | } | 278 | } |
277 | 279 | ||
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index f25f41e1fdb7..e7e12cfbbf37 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c | |||
@@ -411,9 +411,12 @@ int rndis_filter_receive(struct hv_device *dev, | |||
411 | struct rndis_device *rndis_dev; | 411 | struct rndis_device *rndis_dev; |
412 | struct rndis_message *rndis_msg; | 412 | struct rndis_message *rndis_msg; |
413 | struct net_device *ndev; | 413 | struct net_device *ndev; |
414 | int ret = 0; | ||
414 | 415 | ||
415 | if (!net_dev) | 416 | if (!net_dev) { |
416 | return -EINVAL; | 417 | ret = -EINVAL; |
418 | goto exit; | ||
419 | } | ||
417 | 420 | ||
418 | ndev = net_dev->ndev; | 421 | ndev = net_dev->ndev; |
419 | 422 | ||
@@ -421,14 +424,16 @@ int rndis_filter_receive(struct hv_device *dev, | |||
421 | if (!net_dev->extension) { | 424 | if (!net_dev->extension) { |
422 | netdev_err(ndev, "got rndis message but no rndis device - " | 425 | netdev_err(ndev, "got rndis message but no rndis device - " |
423 | "dropping this message!\n"); | 426 | "dropping this message!\n"); |
424 | return -ENODEV; | 427 | ret = -ENODEV; |
428 | goto exit; | ||
425 | } | 429 | } |
426 | 430 | ||
427 | rndis_dev = (struct rndis_device *)net_dev->extension; | 431 | rndis_dev = (struct rndis_device *)net_dev->extension; |
428 | if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) { | 432 | if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) { |
429 | netdev_err(ndev, "got rndis message but rndis device " | 433 | netdev_err(ndev, "got rndis message but rndis device " |
430 | "uninitialized...dropping this message!\n"); | 434 | "uninitialized...dropping this message!\n"); |
431 | return -ENODEV; | 435 | ret = -ENODEV; |
436 | goto exit; | ||
432 | } | 437 | } |
433 | 438 | ||
434 | rndis_msg = pkt->data; | 439 | rndis_msg = pkt->data; |
@@ -460,7 +465,11 @@ int rndis_filter_receive(struct hv_device *dev, | |||
460 | break; | 465 | break; |
461 | } | 466 | } |
462 | 467 | ||
463 | return 0; | 468 | exit: |
469 | if (ret != 0) | ||
470 | pkt->status = NVSP_STAT_FAIL; | ||
471 | |||
472 | return ret; | ||
464 | } | 473 | } |
465 | 474 | ||
466 | static int rndis_filter_query_device(struct rndis_device *dev, u32 oid, | 475 | static int rndis_filter_query_device(struct rndis_device *dev, u32 oid, |