summaryrefslogtreecommitdiff
path: root/drivers/net/hyperv
diff options
context:
space:
mode:
authorHaiyang Zhang <haiyangz@microsoft.com>2012-10-02 09:30:23 +0400
committerDavid S. Miller <davem@davemloft.net>2012-10-02 22:39:31 +0400
commit63f6921d300c6fbdca3d0e73dcc24b4e5e4dced2 (patch)
tree5cd2560e12959f51574e0235bc1d9bdb81b30b98 /drivers/net/hyperv
parent6562640bd3b368a7ffb1caa61c82abe6e9d54b3b (diff)
downloadlinux-63f6921d300c6fbdca3d0e73dcc24b4e5e4dced2.tar.xz
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/hyperv')
-rw-r--r--drivers/net/hyperv/hyperv_net.h2
-rw-r--r--drivers/net/hyperv/netvsc.c18
-rw-r--r--drivers/net/hyperv/netvsc_drv.c2
-rw-r--r--drivers/net/hyperv/rndis_filter.c19
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;
/* Represent the xfer page packet which contains 1 or more netvsc packet */
struct xferpage_packet {
struct list_head list_ent;
+ u32 status;
/* # of netvsc packets this xfer packet contains */
u32 count;
@@ -47,6 +48,7 @@ struct xferpage_packet {
struct hv_netvsc_packet {
/* Bookkeeping stuff */
struct list_head list_ent;
+ u32 status;
struct hv_device *device;
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,
}
static void netvsc_send_recv_completion(struct hv_device *device,
- u64 transaction_id)
+ u64 transaction_id, u32 status)
{
struct nvsp_message recvcompMessage;
int retries = 0;
@@ -571,9 +571,7 @@ static void netvsc_send_recv_completion(struct hv_device *device,
recvcompMessage.hdr.msg_type =
NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE;
- /* FIXME: Pass in the status */
- recvcompMessage.msg.v1_msg.send_rndis_pkt_complete.status =
- NVSP_STAT_SUCCESS;
+ recvcompMessage.msg.v1_msg.send_rndis_pkt_complete.status = status;
retry_send_cmplt:
/* Send the completion */
@@ -613,6 +611,7 @@ static void netvsc_receive_completion(void *context)
bool fsend_receive_comp = false;
unsigned long flags;
struct net_device *ndev;
+ u32 status = NVSP_STAT_NONE;
/*
* Even though it seems logical to do a GetOutboundNetDevice() here to
@@ -627,6 +626,9 @@ static void netvsc_receive_completion(void *context)
/* Overloading use of the lock. */
spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
+ if (packet->status != NVSP_STAT_SUCCESS)
+ packet->xfer_page_pkt->status = NVSP_STAT_FAIL;
+
packet->xfer_page_pkt->count--;
/*
@@ -636,6 +638,7 @@ static void netvsc_receive_completion(void *context)
if (packet->xfer_page_pkt->count == 0) {
fsend_receive_comp = true;
transaction_id = packet->completion.recv.recv_completion_tid;
+ status = packet->xfer_page_pkt->status;
list_add_tail(&packet->xfer_page_pkt->list_ent,
&net_device->recv_pkt_list);
@@ -647,7 +650,7 @@ static void netvsc_receive_completion(void *context)
/* Send a receive completion for the xfer page packet */
if (fsend_receive_comp)
- netvsc_send_recv_completion(device, transaction_id);
+ netvsc_send_recv_completion(device, transaction_id, status);
}
@@ -736,7 +739,8 @@ static void netvsc_receive(struct hv_device *device,
flags);
netvsc_send_recv_completion(device,
- vmxferpage_packet->d.trans_id);
+ vmxferpage_packet->d.trans_id,
+ NVSP_STAT_FAIL);
return;
}
@@ -744,6 +748,7 @@ static void netvsc_receive(struct hv_device *device,
/* Remove the 1st packet to represent the xfer page packet itself */
xferpage_packet = (struct xferpage_packet *)listHead.next;
list_del(&xferpage_packet->list_ent);
+ xferpage_packet->status = NVSP_STAT_SUCCESS;
/* This is how much we can satisfy */
xferpage_packet->count = count - 1;
@@ -760,6 +765,7 @@ static void netvsc_receive(struct hv_device *device,
list_del(&netvsc_packet->list_ent);
/* Initialize the netvsc packet */
+ netvsc_packet->status = NVSP_STAT_SUCCESS;
netvsc_packet->xfer_page_pkt = xferpage_packet;
netvsc_packet->completion.recv.recv_completion =
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,
if (!net) {
netdev_err(net, "got receive callback but net device"
" not initialized yet\n");
+ packet->status = NVSP_STAT_FAIL;
return 0;
}
@@ -272,6 +273,7 @@ int netvsc_recv_callback(struct hv_device *device_obj,
skb = netdev_alloc_skb_ip_align(net, packet->total_data_buflen);
if (unlikely(!skb)) {
++net->stats.rx_dropped;
+ packet->status = NVSP_STAT_FAIL;
return 0;
}
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,
struct rndis_device *rndis_dev;
struct rndis_message *rndis_msg;
struct net_device *ndev;
+ int ret = 0;
- if (!net_dev)
- return -EINVAL;
+ if (!net_dev) {
+ ret = -EINVAL;
+ goto exit;
+ }
ndev = net_dev->ndev;
@@ -421,14 +424,16 @@ int rndis_filter_receive(struct hv_device *dev,
if (!net_dev->extension) {
netdev_err(ndev, "got rndis message but no rndis device - "
"dropping this message!\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto exit;
}
rndis_dev = (struct rndis_device *)net_dev->extension;
if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
netdev_err(ndev, "got rndis message but rndis device "
"uninitialized...dropping this message!\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto exit;
}
rndis_msg = pkt->data;
@@ -460,7 +465,11 @@ int rndis_filter_receive(struct hv_device *dev,
break;
}
- return 0;
+exit:
+ if (ret != 0)
+ pkt->status = NVSP_STAT_FAIL;
+
+ return ret;
}
static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,