diff options
Diffstat (limited to 'drivers/net/hyperv')
-rw-r--r-- | drivers/net/hyperv/hyperv_net.h | 4 | ||||
-rw-r--r-- | drivers/net/hyperv/netvsc.c | 22 | ||||
-rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 4 | ||||
-rw-r--r-- | drivers/net/hyperv/rndis_filter.c | 60 |
4 files changed, 63 insertions, 27 deletions
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 95ceb3593043..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; @@ -465,8 +467,6 @@ struct nvsp_message { #define NETVSC_RECEIVE_BUFFER_ID 0xcafe -#define NETVSC_RECEIVE_SG_COUNT 1 - /* Preallocated receive packets */ #define NETVSC_RECEIVE_PACKETLIST_COUNT 256 diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 4a1a5f58fa73..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; @@ -904,9 +910,7 @@ int netvsc_device_add(struct hv_device *device, void *additional_info) INIT_LIST_HEAD(&net_device->recv_pkt_list); for (i = 0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) { - packet = kzalloc(sizeof(struct hv_netvsc_packet) + - (NETVSC_RECEIVE_SG_COUNT * - sizeof(struct hv_page_buffer)), GFP_KERNEL); + packet = kzalloc(sizeof(struct hv_netvsc_packet), GFP_KERNEL); if (!packet) break; diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 8c5a1c43c81d..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; } @@ -400,7 +402,7 @@ static void netvsc_send_garp(struct work_struct *w) ndev_ctx = container_of(w, struct net_device_context, dwork.work); net_device = hv_get_drvdata(ndev_ctx->device_ctx); net = net_device->ndev; - netif_notify_peers(net); + netdev_notify_peers(net); } diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 1e88a1095934..928148cc3220 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -32,23 +32,31 @@ #include "hyperv_net.h" +#define RNDIS_EXT_LEN 100 struct rndis_request { struct list_head list_ent; struct completion wait_event; + struct rndis_message response_msg; /* - * FIXME: We assumed a fixed size response here. If we do ever need to - * handle a bigger response, we can either define a max response - * message or add a response buffer variable above this field + * The buffer for extended info after the RNDIS response message. It's + * referenced based on the data offset in the RNDIS message. Its size + * is enough for current needs, and should be sufficient for the near + * future. */ - struct rndis_message response_msg; + u8 response_ext[RNDIS_EXT_LEN]; /* Simplify allocation by having a netvsc packet inline */ struct hv_netvsc_packet pkt; - struct hv_page_buffer buf; - /* FIXME: We assumed a fixed size request here. */ + /* Set 2 pages for rndis requests crossing page boundary */ + struct hv_page_buffer buf[2]; + struct rndis_message request_msg; - u8 ext[100]; + /* + * The buffer for the extended info after the RNDIS request message. + * It is referenced and sized in a similar way as response_ext. + */ + u8 request_ext[RNDIS_EXT_LEN]; }; static void rndis_filter_send_completion(void *ctx); @@ -221,6 +229,18 @@ static int rndis_filter_send_request(struct rndis_device *dev, packet->page_buf[0].offset = (unsigned long)&req->request_msg & (PAGE_SIZE - 1); + /* Add one page_buf when request_msg crossing page boundary */ + if (packet->page_buf[0].offset + packet->page_buf[0].len > PAGE_SIZE) { + packet->page_buf_cnt++; + packet->page_buf[0].len = PAGE_SIZE - + packet->page_buf[0].offset; + packet->page_buf[1].pfn = virt_to_phys((void *)&req->request_msg + + packet->page_buf[0].len) >> PAGE_SHIFT; + packet->page_buf[1].offset = 0; + packet->page_buf[1].len = req->request_msg.msg_len - + packet->page_buf[0].len; + } + packet->completion.send.send_completion_ctx = req;/* packet; */ packet->completion.send.send_completion = rndis_filter_send_request_completion; @@ -255,7 +275,8 @@ static void rndis_filter_receive_response(struct rndis_device *dev, spin_unlock_irqrestore(&dev->request_lock, flags); if (found) { - if (resp->msg_len <= sizeof(struct rndis_message)) { + if (resp->msg_len <= + sizeof(struct rndis_message) + RNDIS_EXT_LEN) { memcpy(&request->response_msg, resp, resp->msg_len); } else { @@ -392,9 +413,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; @@ -402,14 +426,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; @@ -441,7 +467,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, @@ -641,6 +671,7 @@ int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter) if (t == 0) { netdev_err(ndev, "timeout before we got a set response...\n"); + ret = -ETIMEDOUT; /* * We can't deallocate the request since we may still receive a * send completion for it. @@ -678,8 +709,7 @@ static int rndis_filter_init_device(struct rndis_device *dev) init = &request->request_msg.msg.init_req; init->major_ver = RNDIS_MAJOR_VERSION; init->minor_ver = RNDIS_MINOR_VERSION; - /* FIXME: Use 1536 - rounded ethernet frame size */ - init->max_xfer_size = 2048; + init->max_xfer_size = 0x4000; dev->state = RNDIS_DEV_INITIALIZING; |