From 6048718d719f460abba8eaff1c0122247b2c3d91 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 4 May 2010 09:58:55 -0700 Subject: [PATCH] Staging: hv: transmit scatter gather support The transmit management of pages was confusing for handling fragmented SKB's. (But since NETIF_F_SG was never set, the code was never hit). The parameter AdditionalRequestPageBufferCount is always one, (and leads to ugly code), so just inline and add comments. Signed-off-by: Stephen Hemminger Acked-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/RndisFilter.c | 1 - drivers/staging/hv/netvsc_drv.c | 53 +++++++++++++------------------- 2 files changed, 22 insertions(+), 32 deletions(-) diff --git a/drivers/staging/hv/RndisFilter.c b/drivers/staging/hv/RndisFilter.c index 861139677e33..de4bc80341c3 100644 --- a/drivers/staging/hv/RndisFilter.c +++ b/drivers/staging/hv/RndisFilter.c @@ -624,7 +624,6 @@ int RndisFilterInit(struct netvsc_driver *Driver) sizeof(struct rndis_filter_packet)); Driver->RequestExtSize = sizeof(struct rndis_filter_packet); - Driver->AdditionalRequestPageBufferCount = 1; /* For rndis header */ /* Driver->Context = rndisDriver; */ diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c index b02455cfe237..4124979835a6 100644 --- a/drivers/staging/hv/netvsc_drv.c +++ b/drivers/staging/hv/netvsc_drv.c @@ -144,27 +144,21 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) (struct netvsc_driver_context *)driver_ctx; struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj; struct hv_netvsc_packet *packet; - int i; int ret; - int num_frags; + unsigned int i, num_pages; int retries = 0; DPRINT_ENTER(NETVSC_DRV); - /* Support only 1 chain of frags */ - ASSERT(skb_shinfo(skb)->frag_list == NULL); - ASSERT(skb->dev == net); - DPRINT_DBG(NETVSC_DRV, "xmit packet - len %d data_len %d", skb->len, skb->data_len); - /* Add 1 for skb->data and any additional ones requested */ - num_frags = skb_shinfo(skb)->nr_frags + 1 + - net_drv_obj->AdditionalRequestPageBufferCount; + /* Add 1 for skb->data and additional one for RNDIS */ + num_pages = skb_shinfo(skb)->nr_frags + 1 + 1; /* Allocate a netvsc packet based on # of frags. */ packet = kzalloc(sizeof(struct hv_netvsc_packet) + - (num_frags * sizeof(struct hv_page_buffer)) + + (num_pages * sizeof(struct hv_page_buffer)) + net_drv_obj->RequestExtSize, GFP_ATOMIC); if (!packet) { DPRINT_ERR(NETVSC_DRV, "unable to allocate hv_netvsc_packet"); @@ -173,36 +167,30 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) packet->Extension = (void *)(unsigned long)packet + sizeof(struct hv_netvsc_packet) + - (num_frags * sizeof(struct hv_page_buffer)); + (num_pages * sizeof(struct hv_page_buffer)); /* Setup the rndis header */ - packet->PageBufferCount = num_frags; + packet->PageBufferCount = num_pages; /* TODO: Flush all write buffers/ memory fence ??? */ /* wmb(); */ /* Initialize it from the skb */ - ASSERT(skb->data); packet->TotalDataBufferLength = skb->len; - /* - * Start filling in the page buffers starting at - * AdditionalRequestPageBufferCount offset - */ - packet->PageBuffers[net_drv_obj->AdditionalRequestPageBufferCount].Pfn = virt_to_phys(skb->data) >> PAGE_SHIFT; - packet->PageBuffers[net_drv_obj->AdditionalRequestPageBufferCount].Offset = (unsigned long)skb->data & (PAGE_SIZE - 1); - packet->PageBuffers[net_drv_obj->AdditionalRequestPageBufferCount].Length = skb->len - skb->data_len; - - ASSERT((skb->len - skb->data_len) <= PAGE_SIZE); - - for (i = net_drv_obj->AdditionalRequestPageBufferCount + 1; - i < num_frags; i++) { - packet->PageBuffers[i].Pfn = - page_to_pfn(skb_shinfo(skb)->frags[i-(net_drv_obj->AdditionalRequestPageBufferCount+1)].page); - packet->PageBuffers[i].Offset = - skb_shinfo(skb)->frags[i-(net_drv_obj->AdditionalRequestPageBufferCount+1)].page_offset; - packet->PageBuffers[i].Length = - skb_shinfo(skb)->frags[i-(net_drv_obj->AdditionalRequestPageBufferCount+1)].size; + /* Start filling in the page buffers starting after RNDIS buffer. */ + packet->PageBuffers[1].Pfn = virt_to_phys(skb->data) >> PAGE_SHIFT; + packet->PageBuffers[1].Offset + = (unsigned long)skb->data & (PAGE_SIZE - 1); + packet->PageBuffers[1].Length = skb_headlen(skb); + + /* Additional fragments are after SKB data */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *f = &skb_shinfo(skb)->frags[i]; + + packet->PageBuffers[i+2].Pfn = page_to_pfn(f->page); + packet->PageBuffers[i+2].Offset = f->page_offset; + packet->PageBuffers[i+2].Length = f->size; } /* Set the completion routine */ @@ -423,6 +411,9 @@ static int netvsc_probe(struct device *device) net->netdev_ops = &device_ops; + /* TODO: Add GSO and Checksum offload */ + net->features = NETIF_F_SG; + SET_NETDEV_DEV(net, device); ret = register_netdev(net); -- 2.20.1