diff options
author | Stephen Hemminger <shemminger@vyatta.com> | 2010-05-04 12:58:55 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-05-11 14:36:09 -0400 |
commit | 6048718d719f460abba8eaff1c0122247b2c3d91 (patch) | |
tree | bca18394ccf66190d2221c422ed0419135a6ea28 | |
parent | 9f8bd8bacf90c78e331ad63c38b0ea167e2ce639 (diff) |
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>
-rw-r--r-- | drivers/staging/hv/RndisFilter.c | 1 | ||||
-rw-r--r-- | 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 861139677e3..de4bc80341c 100644 --- a/drivers/staging/hv/RndisFilter.c +++ b/drivers/staging/hv/RndisFilter.c | |||
@@ -624,7 +624,6 @@ int RndisFilterInit(struct netvsc_driver *Driver) | |||
624 | sizeof(struct rndis_filter_packet)); | 624 | sizeof(struct rndis_filter_packet)); |
625 | 625 | ||
626 | Driver->RequestExtSize = sizeof(struct rndis_filter_packet); | 626 | Driver->RequestExtSize = sizeof(struct rndis_filter_packet); |
627 | Driver->AdditionalRequestPageBufferCount = 1; /* For rndis header */ | ||
628 | 627 | ||
629 | /* Driver->Context = rndisDriver; */ | 628 | /* Driver->Context = rndisDriver; */ |
630 | 629 | ||
diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c index b02455cfe23..4124979835a 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) | |||
144 | (struct netvsc_driver_context *)driver_ctx; | 144 | (struct netvsc_driver_context *)driver_ctx; |
145 | struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj; | 145 | struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj; |
146 | struct hv_netvsc_packet *packet; | 146 | struct hv_netvsc_packet *packet; |
147 | int i; | ||
148 | int ret; | 147 | int ret; |
149 | int num_frags; | 148 | unsigned int i, num_pages; |
150 | int retries = 0; | 149 | int retries = 0; |
151 | 150 | ||
152 | DPRINT_ENTER(NETVSC_DRV); | 151 | DPRINT_ENTER(NETVSC_DRV); |
153 | 152 | ||
154 | /* Support only 1 chain of frags */ | ||
155 | ASSERT(skb_shinfo(skb)->frag_list == NULL); | ||
156 | ASSERT(skb->dev == net); | ||
157 | |||
158 | DPRINT_DBG(NETVSC_DRV, "xmit packet - len %d data_len %d", | 153 | DPRINT_DBG(NETVSC_DRV, "xmit packet - len %d data_len %d", |
159 | skb->len, skb->data_len); | 154 | skb->len, skb->data_len); |
160 | 155 | ||
161 | /* Add 1 for skb->data and any additional ones requested */ | 156 | /* Add 1 for skb->data and additional one for RNDIS */ |
162 | num_frags = skb_shinfo(skb)->nr_frags + 1 + | 157 | num_pages = skb_shinfo(skb)->nr_frags + 1 + 1; |
163 | net_drv_obj->AdditionalRequestPageBufferCount; | ||
164 | 158 | ||
165 | /* Allocate a netvsc packet based on # of frags. */ | 159 | /* Allocate a netvsc packet based on # of frags. */ |
166 | packet = kzalloc(sizeof(struct hv_netvsc_packet) + | 160 | packet = kzalloc(sizeof(struct hv_netvsc_packet) + |
167 | (num_frags * sizeof(struct hv_page_buffer)) + | 161 | (num_pages * sizeof(struct hv_page_buffer)) + |
168 | net_drv_obj->RequestExtSize, GFP_ATOMIC); | 162 | net_drv_obj->RequestExtSize, GFP_ATOMIC); |
169 | if (!packet) { | 163 | if (!packet) { |
170 | DPRINT_ERR(NETVSC_DRV, "unable to allocate hv_netvsc_packet"); | 164 | 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) | |||
173 | 167 | ||
174 | packet->Extension = (void *)(unsigned long)packet + | 168 | packet->Extension = (void *)(unsigned long)packet + |
175 | sizeof(struct hv_netvsc_packet) + | 169 | sizeof(struct hv_netvsc_packet) + |
176 | (num_frags * sizeof(struct hv_page_buffer)); | 170 | (num_pages * sizeof(struct hv_page_buffer)); |
177 | 171 | ||
178 | /* Setup the rndis header */ | 172 | /* Setup the rndis header */ |
179 | packet->PageBufferCount = num_frags; | 173 | packet->PageBufferCount = num_pages; |
180 | 174 | ||
181 | /* TODO: Flush all write buffers/ memory fence ??? */ | 175 | /* TODO: Flush all write buffers/ memory fence ??? */ |
182 | /* wmb(); */ | 176 | /* wmb(); */ |
183 | 177 | ||
184 | /* Initialize it from the skb */ | 178 | /* Initialize it from the skb */ |
185 | ASSERT(skb->data); | ||
186 | packet->TotalDataBufferLength = skb->len; | 179 | packet->TotalDataBufferLength = skb->len; |
187 | 180 | ||
188 | /* | 181 | /* Start filling in the page buffers starting after RNDIS buffer. */ |
189 | * Start filling in the page buffers starting at | 182 | packet->PageBuffers[1].Pfn = virt_to_phys(skb->data) >> PAGE_SHIFT; |
190 | * AdditionalRequestPageBufferCount offset | 183 | packet->PageBuffers[1].Offset |
191 | */ | 184 | = (unsigned long)skb->data & (PAGE_SIZE - 1); |
192 | packet->PageBuffers[net_drv_obj->AdditionalRequestPageBufferCount].Pfn = virt_to_phys(skb->data) >> PAGE_SHIFT; | 185 | packet->PageBuffers[1].Length = skb_headlen(skb); |
193 | packet->PageBuffers[net_drv_obj->AdditionalRequestPageBufferCount].Offset = (unsigned long)skb->data & (PAGE_SIZE - 1); | 186 | |
194 | packet->PageBuffers[net_drv_obj->AdditionalRequestPageBufferCount].Length = skb->len - skb->data_len; | 187 | /* Additional fragments are after SKB data */ |
195 | 188 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | |
196 | ASSERT((skb->len - skb->data_len) <= PAGE_SIZE); | 189 | skb_frag_t *f = &skb_shinfo(skb)->frags[i]; |
197 | 190 | ||
198 | for (i = net_drv_obj->AdditionalRequestPageBufferCount + 1; | 191 | packet->PageBuffers[i+2].Pfn = page_to_pfn(f->page); |
199 | i < num_frags; i++) { | 192 | packet->PageBuffers[i+2].Offset = f->page_offset; |
200 | packet->PageBuffers[i].Pfn = | 193 | packet->PageBuffers[i+2].Length = f->size; |
201 | page_to_pfn(skb_shinfo(skb)->frags[i-(net_drv_obj->AdditionalRequestPageBufferCount+1)].page); | ||
202 | packet->PageBuffers[i].Offset = | ||
203 | skb_shinfo(skb)->frags[i-(net_drv_obj->AdditionalRequestPageBufferCount+1)].page_offset; | ||
204 | packet->PageBuffers[i].Length = | ||
205 | skb_shinfo(skb)->frags[i-(net_drv_obj->AdditionalRequestPageBufferCount+1)].size; | ||
206 | } | 194 | } |
207 | 195 | ||
208 | /* Set the completion routine */ | 196 | /* Set the completion routine */ |
@@ -423,6 +411,9 @@ static int netvsc_probe(struct device *device) | |||
423 | 411 | ||
424 | net->netdev_ops = &device_ops; | 412 | net->netdev_ops = &device_ops; |
425 | 413 | ||
414 | /* TODO: Add GSO and Checksum offload */ | ||
415 | net->features = NETIF_F_SG; | ||
416 | |||
426 | SET_NETDEV_DEV(net, device); | 417 | SET_NETDEV_DEV(net, device); |
427 | 418 | ||
428 | ret = register_netdev(net); | 419 | ret = register_netdev(net); |