From patchwork Thu Mar 6 11:13:06 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KY Srinivasan X-Patchwork-Id: 327374 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 175AB2C00AF for ; Thu, 6 Mar 2014 21:27:04 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753129AbaCFK0S (ORCPT ); Thu, 6 Mar 2014 05:26:18 -0500 Received: from p3plsmtps2ded03.prod.phx3.secureserver.net ([208.109.80.60]:34982 "EHLO p3plsmtps2ded03.prod.phx3.secureserver.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753031AbaCFK0N (ORCPT ); Thu, 6 Mar 2014 05:26:13 -0500 Received: from linuxonhyperv.com ([72.167.245.219]) by p3plsmtps2ded03.prod.phx3.secureserver.net with : DED : id aALp1n04k4kklxU01ALpuU; Thu, 06 Mar 2014 03:20:49 -0700 x-originating-ip: 72.167.245.219 Received: by linuxonhyperv.com (Postfix, from userid 507) id 7A54019041F; Thu, 6 Mar 2014 03:13:12 -0800 (PST) From: "K. Y. Srinivasan" To: davem@davemloft.net, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, devel@linuxdriverproject.org, olaf@aepfle.de, apw@canonical.com, jasowang@redhat.com Cc: "K. Y. Srinivasan" Subject: [PATCH 2/6] Drivers: net: hyperv: Cleanup the send path Date: Thu, 6 Mar 2014 03:13:06 -0800 Message-Id: <1394104390-23477-2-git-send-email-kys@microsoft.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1394104390-23477-1-git-send-email-kys@microsoft.com> References: <1394104358-23438-1-git-send-email-kys@microsoft.com> <1394104390-23477-1-git-send-email-kys@microsoft.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org In preparation for enabling offloads, cleanup the send path. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang --- drivers/net/hyperv/hyperv_net.h | 7 +--- drivers/net/hyperv/netvsc_drv.c | 87 +++++++++++++++++++++++++++++------- drivers/net/hyperv/rndis_filter.c | 66 ---------------------------- 3 files changed, 71 insertions(+), 89 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 39fc230..694bf7c 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -73,7 +73,7 @@ struct hv_netvsc_packet { } completion; /* This points to the memory after page_buf */ - void *extension; + struct rndis_message *rndis_msg; u32 total_data_buflen; /* Points to the send/receive buffer where the ethernet frame is */ @@ -126,11 +126,6 @@ void rndis_filter_device_remove(struct hv_device *dev); int rndis_filter_receive(struct hv_device *dev, struct hv_netvsc_packet *pkt); - - -int rndis_filter_send(struct hv_device *dev, - struct hv_netvsc_packet *pkt); - int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter); int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac); diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index afa9c53..e812529 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -128,6 +128,28 @@ static int netvsc_close(struct net_device *net) return ret; } + +static void *init_ppi_data(struct rndis_message *msg, u32 ppi_size, + int pkt_type) +{ + struct rndis_packet *rndis_pkt; + struct rndis_per_packet_info *ppi; + + rndis_pkt = &msg->msg.pkt; + rndis_pkt->data_offset += ppi_size; + + ppi = (struct rndis_per_packet_info *)((ulong)rndis_pkt + + rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_len); + + ppi->size = ppi_size; + ppi->type = pkt_type; + ppi->ppi_offset = sizeof(struct rndis_per_packet_info); + + rndis_pkt->per_pkt_info_len += ppi_size; + + return ppi; +} + static void netvsc_xmit_completion(void *context) { struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context; @@ -173,7 +195,7 @@ static u32 fill_pg_buf(struct page *page, u32 offset, u32 len, return j + 1; } -static void init_page_array(void *hdr, u32 len, struct sk_buff *skb, +static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb, struct hv_page_buffer *pb) { u32 slots_used = 0; @@ -204,6 +226,7 @@ static void init_page_array(void *hdr, u32 len, struct sk_buff *skb, frag->page_offset, skb_frag_size(frag), &pb[slots_used]); } + return slots_used; } static int count_skb_frag_slots(struct sk_buff *skb) @@ -241,15 +264,20 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) struct net_device_context *net_device_ctx = netdev_priv(net); struct hv_netvsc_packet *packet; int ret; - unsigned int num_data_pages; + unsigned int num_data_pgs; + struct rndis_message *rndis_msg; + struct rndis_packet *rndis_pkt; + u32 rndis_msg_size; + bool isvlan; + struct rndis_per_packet_info *ppi; /* * We will atmost need two pages to describe the rndis * header. We can only transmit MAX_PAGE_BUFFER_COUNT number * of pages in a single packet. */ - num_data_pages = netvsc_get_slots(skb) + 2; - if (num_data_pages > MAX_PAGE_BUFFER_COUNT) { + num_data_pgs = netvsc_get_slots(skb) + 2; + if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) { netdev_err(net, "Packet too big: %u\n", skb->len); dev_kfree_skb(skb); net->stats.tx_dropped++; @@ -258,7 +286,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) /* Allocate a netvsc packet based on # of frags. */ packet = kzalloc(sizeof(struct hv_netvsc_packet) + - (num_data_pages * sizeof(struct hv_page_buffer)) + + (num_data_pgs * sizeof(struct hv_page_buffer)) + sizeof(struct rndis_message) + NDIS_VLAN_PPI_SIZE, GFP_ATOMIC); if (!packet) { @@ -272,26 +300,51 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) packet->vlan_tci = skb->vlan_tci; - packet->extension = (void *)(unsigned long)packet + - sizeof(struct hv_netvsc_packet) + - (num_data_pages * sizeof(struct hv_page_buffer)); - - /* If the rndis msg goes beyond 1 page, we will add 1 later */ - packet->page_buf_cnt = num_data_pages - 1; - - /* Initialize it from the skb */ + packet->is_data_pkt = true; packet->total_data_buflen = skb->len; - /* Start filling in the page buffers starting after RNDIS buffer. */ - init_page_array(NULL, 0, skb, &packet->page_buf[1]); + packet->rndis_msg = (struct rndis_message *)((unsigned long)packet + + sizeof(struct hv_netvsc_packet) + + (num_data_pgs * sizeof(struct hv_page_buffer))); /* Set the completion routine */ packet->completion.send.send_completion = netvsc_xmit_completion; packet->completion.send.send_completion_ctx = packet; packet->completion.send.send_completion_tid = (unsigned long)skb; - ret = rndis_filter_send(net_device_ctx->device_ctx, - packet); + isvlan = packet->vlan_tci & VLAN_TAG_PRESENT; + + /* Add the rndis header */ + rndis_msg = packet->rndis_msg; + rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET; + rndis_msg->msg_len = packet->total_data_buflen; + rndis_pkt = &rndis_msg->msg.pkt; + rndis_pkt->data_offset = sizeof(struct rndis_packet); + rndis_pkt->data_len = packet->total_data_buflen; + rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet); + + rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet); + + if (isvlan) { + struct ndis_pkt_8021q_info *vlan; + + rndis_msg_size += NDIS_VLAN_PPI_SIZE; + ppi = init_ppi_data(rndis_msg, NDIS_VLAN_PPI_SIZE, + IEEE_8021Q_INFO); + vlan = (struct ndis_pkt_8021q_info *)((ulong)ppi + + ppi->ppi_offset); + vlan->vlanid = packet->vlan_tci & VLAN_VID_MASK; + vlan->pri = (packet->vlan_tci & VLAN_PRIO_MASK) >> + VLAN_PRIO_SHIFT; + } + + /* Start filling in the page buffers with the rndis hdr */ + rndis_msg->msg_len += rndis_msg_size; + packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size, + skb, &packet->page_buf[0]); + + ret = netvsc_send(net_device_ctx->device_ctx, packet); + if (ret == 0) { net->stats.tx_bytes += skb->len; net->stats.tx_packets++; diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 6a9f602..dcbf144e 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -910,69 +910,3 @@ int rndis_filter_close(struct hv_device *dev) return rndis_filter_close_device(nvdev->extension); } - -int rndis_filter_send(struct hv_device *dev, - struct hv_netvsc_packet *pkt) -{ - struct rndis_message *rndis_msg; - struct rndis_packet *rndis_pkt; - u32 rndis_msg_size; - bool isvlan = pkt->vlan_tci & VLAN_TAG_PRESENT; - - /* Add the rndis header */ - rndis_msg = (struct rndis_message *)pkt->extension; - - rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet); - if (isvlan) - rndis_msg_size += NDIS_VLAN_PPI_SIZE; - - rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET; - rndis_msg->msg_len = pkt->total_data_buflen + - rndis_msg_size; - - rndis_pkt = &rndis_msg->msg.pkt; - rndis_pkt->data_offset = sizeof(struct rndis_packet); - if (isvlan) - rndis_pkt->data_offset += NDIS_VLAN_PPI_SIZE; - rndis_pkt->data_len = pkt->total_data_buflen; - - if (isvlan) { - struct rndis_per_packet_info *ppi; - struct ndis_pkt_8021q_info *vlan; - - rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet); - rndis_pkt->per_pkt_info_len = NDIS_VLAN_PPI_SIZE; - - ppi = (struct rndis_per_packet_info *)((ulong)rndis_pkt + - rndis_pkt->per_pkt_info_offset); - ppi->size = NDIS_VLAN_PPI_SIZE; - ppi->type = IEEE_8021Q_INFO; - ppi->ppi_offset = sizeof(struct rndis_per_packet_info); - - vlan = (struct ndis_pkt_8021q_info *)((ulong)ppi + - ppi->ppi_offset); - vlan->vlanid = pkt->vlan_tci & VLAN_VID_MASK; - vlan->pri = (pkt->vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; - } - - pkt->is_data_pkt = true; - pkt->page_buf[0].pfn = virt_to_phys(rndis_msg) >> PAGE_SHIFT; - pkt->page_buf[0].offset = - (unsigned long)rndis_msg & (PAGE_SIZE-1); - pkt->page_buf[0].len = rndis_msg_size; - - /* Add one page_buf if the rndis msg goes beyond page boundary */ - if (pkt->page_buf[0].offset + rndis_msg_size > PAGE_SIZE) { - int i; - for (i = pkt->page_buf_cnt; i > 1; i--) - pkt->page_buf[i] = pkt->page_buf[i-1]; - pkt->page_buf_cnt++; - pkt->page_buf[0].len = PAGE_SIZE - pkt->page_buf[0].offset; - pkt->page_buf[1].pfn = virt_to_phys((void *)((ulong) - rndis_msg + pkt->page_buf[0].len)) >> PAGE_SHIFT; - pkt->page_buf[1].offset = 0; - pkt->page_buf[1].len = rndis_msg_size - pkt->page_buf[0].len; - } - - return netvsc_send(dev, pkt); -}