summaryrefslogtreecommitdiffstats
path: root/drivers/staging/hv/netvsc_drv.c
diff options
context:
space:
mode:
authorStephen Hemminger2010-05-04 18:58:55 +0200
committerGreg Kroah-Hartman2010-05-11 20:36:09 +0200
commit6048718d719f460abba8eaff1c0122247b2c3d91 (patch)
treebca18394ccf66190d2221c422ed0419135a6ea28 /drivers/staging/hv/netvsc_drv.c
parentStaging: hv: use existing Ethernet header size (diff)
downloadkernel-qcow2-linux-6048718d719f460abba8eaff1c0122247b2c3d91.tar.gz
kernel-qcow2-linux-6048718d719f460abba8eaff1c0122247b2c3d91.tar.xz
kernel-qcow2-linux-6048718d719f460abba8eaff1c0122247b2c3d91.zip
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 <shemminger@vyatta.com> Acked-by: Hank Janssen <hjanssen@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/hv/netvsc_drv.c')
-rw-r--r--drivers/staging/hv/netvsc_drv.c53
1 files changed, 22 insertions, 31 deletions
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);