blob: bec135bc704c4b8ec9bcb7005e7113f6ce5f48fb [file] [log] [blame]
Hank Janssenfceaf242009-07-13 15:34:54 -07001/*
2 *
3 * Copyright (c) 2009, Microsoft Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16 * Place - Suite 330, Boston, MA 02111-1307 USA.
17 *
18 * Authors:
19 * Hank Janssen <hjanssen@microsoft.com>
20 *
21 */
22
Hank Janssenfceaf242009-07-13 15:34:54 -070023#include <linux/init.h>
24#include <linux/module.h>
25#include <linux/highmem.h>
26#include <linux/device.h>
Hank Janssenfceaf242009-07-13 15:34:54 -070027#include <linux/io.h>
Hank Janssenfceaf242009-07-13 15:34:54 -070028#include <linux/delay.h>
29#include <linux/netdevice.h>
30#include <linux/inetdevice.h>
31#include <linux/etherdevice.h>
32#include <linux/skbuff.h>
33#include <linux/in.h>
34#include <net/arp.h>
35#include <net/route.h>
36#include <net/sock.h>
37#include <net/pkt_sched.h>
38
Greg Kroah-Hartman4983b392009-08-19 16:14:47 -070039#include "osd.h"
Greg Kroah-Hartman645954c2009-08-28 16:22:59 -070040#include "logging.h"
Greg Kroah-Hartman870cde82009-08-19 16:21:28 -070041#include "vmbus.h"
Hank Janssenfceaf242009-07-13 15:34:54 -070042
Greg Kroah-Hartmancc2118122009-08-28 16:23:17 -070043#include "NetVscApi.h"
Hank Janssenfceaf242009-07-13 15:34:54 -070044
45MODULE_LICENSE("GPL");
46
Bill Pemberton454f18a2009-07-27 16:47:24 -040047
48/* Static decl */
49
Hank Janssenfceaf242009-07-13 15:34:54 -070050static int netvsc_probe(struct device *device);
51static int netvsc_remove(struct device *device);
52static int netvsc_open(struct net_device *net);
53static void netvsc_xmit_completion(void *context);
54static int netvsc_start_xmit (struct sk_buff *skb, struct net_device *net);
Nicolas Palix4193d4f2009-07-29 14:10:10 +020055static int netvsc_recv_callback(struct hv_device *device_obj, struct hv_netvsc_packet *Packet);
Hank Janssenfceaf242009-07-13 15:34:54 -070056static int netvsc_close(struct net_device *net);
57static struct net_device_stats *netvsc_get_stats(struct net_device *net);
Nicolas Palix3d3b5512009-07-28 17:32:53 +020058static void netvsc_linkstatus_callback(struct hv_device *device_obj, unsigned int status);
Hank Janssenfceaf242009-07-13 15:34:54 -070059
Bill Pemberton454f18a2009-07-27 16:47:24 -040060
61/* Data types */
62
Hank Janssenfceaf242009-07-13 15:34:54 -070063struct net_device_context {
Bill Pemberton454f18a2009-07-27 16:47:24 -040064 struct device_context *device_ctx; /* point back to our device context */
Hank Janssenfceaf242009-07-13 15:34:54 -070065 struct net_device_stats stats;
66};
67
68struct netvsc_driver_context {
Bill Pemberton454f18a2009-07-27 16:47:24 -040069 /* !! These must be the first 2 fields !! */
Greg Kroah-Hartman7e23a6e2009-08-27 15:58:15 -070070 /* Which is a bug FIXME! */
Hank Janssenfceaf242009-07-13 15:34:54 -070071 struct driver_context drv_ctx;
Greg Kroah-Hartman7e23a6e2009-08-27 15:58:15 -070072 struct netvsc_driver drv_obj;
Hank Janssenfceaf242009-07-13 15:34:54 -070073};
74
Bill Pemberton454f18a2009-07-27 16:47:24 -040075
76/* Globals */
77
Hank Janssenfceaf242009-07-13 15:34:54 -070078
79static int netvsc_ringbuffer_size = NETVSC_DEVICE_RING_BUFFER_SIZE;
80
Bill Pemberton454f18a2009-07-27 16:47:24 -040081/* The one and only one */
Hank Janssenfceaf242009-07-13 15:34:54 -070082static struct netvsc_driver_context g_netvsc_drv;
83
Bill Pemberton454f18a2009-07-27 16:47:24 -040084
85/* Routines */
86
Hank Janssenfceaf242009-07-13 15:34:54 -070087
88/*++
89
90Name: netvsc_drv_init()
91
92Desc: NetVsc driver initialization
93
94--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -070095static int netvsc_drv_init(PFN_DRIVERINITIALIZE pfn_drv_init)
Hank Janssenfceaf242009-07-13 15:34:54 -070096{
97 int ret=0;
Greg Kroah-Hartman7e23a6e2009-08-27 15:58:15 -070098 struct netvsc_driver *net_drv_obj=&g_netvsc_drv.drv_obj;
Hank Janssenfceaf242009-07-13 15:34:54 -070099 struct driver_context *drv_ctx=&g_netvsc_drv.drv_ctx;
100
101 DPRINT_ENTER(NETVSC_DRV);
102
103 vmbus_get_interface(&net_drv_obj->Base.VmbusChannelInterface);
104
105 net_drv_obj->RingBufferSize = netvsc_ringbuffer_size;
106 net_drv_obj->OnReceiveCallback = netvsc_recv_callback;
107 net_drv_obj->OnLinkStatusChanged = netvsc_linkstatus_callback;
108
Bill Pemberton454f18a2009-07-27 16:47:24 -0400109 /* Callback to client driver to complete the initialization */
Hank Janssenfceaf242009-07-13 15:34:54 -0700110 pfn_drv_init(&net_drv_obj->Base);
111
112 drv_ctx->driver.name = net_drv_obj->Base.name;
Greg Kroah-Hartmancaf26a32009-08-19 16:17:03 -0700113 memcpy(&drv_ctx->class_id, &net_drv_obj->Base.deviceType, sizeof(struct hv_guid));
Hank Janssenfceaf242009-07-13 15:34:54 -0700114
Hank Janssenfceaf242009-07-13 15:34:54 -0700115 drv_ctx->probe = netvsc_probe;
116 drv_ctx->remove = netvsc_remove;
Hank Janssenfceaf242009-07-13 15:34:54 -0700117
Bill Pemberton454f18a2009-07-27 16:47:24 -0400118 /* The driver belongs to vmbus */
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400119 ret = vmbus_child_driver_register(drv_ctx);
Hank Janssenfceaf242009-07-13 15:34:54 -0700120
121 DPRINT_EXIT(NETVSC_DRV);
122
123 return ret;
124}
125
126/*++
127
128Name: netvsc_get_stats()
129
130Desc: Get the network stats
131
132--*/
133static struct net_device_stats *netvsc_get_stats(struct net_device *net)
134{
135 struct net_device_context *net_device_ctx = netdev_priv(net);
136
137 return &net_device_ctx->stats;
138}
139
140/*++
141
142Name: netvsc_set_multicast_list()
143
144Desc: Set the multicast list
145
146Remark: No-op here
147--*/
Greg Kroah-Hartman4e9bfef2009-07-15 12:45:20 -0700148static void netvsc_set_multicast_list(struct net_device *net)
Hank Janssenfceaf242009-07-13 15:34:54 -0700149{
150}
151
152
Greg Kroah-Hartmanc86f3e22009-07-14 10:59:56 -0700153static const struct net_device_ops device_ops = {
154 .ndo_open = netvsc_open,
155 .ndo_stop = netvsc_close,
156 .ndo_start_xmit = netvsc_start_xmit,
157 .ndo_get_stats = netvsc_get_stats,
158 .ndo_set_multicast_list = netvsc_set_multicast_list,
159};
160
Hank Janssenfceaf242009-07-13 15:34:54 -0700161/*++
162
163Name: netvsc_probe()
164
165Desc: Add the specified new device to this driver
166
167--*/
168static int netvsc_probe(struct device *device)
169{
170 int ret=0;
171
172 struct driver_context *driver_ctx = driver_to_driver_context(device->driver);
173 struct netvsc_driver_context *net_drv_ctx = (struct netvsc_driver_context*)driver_ctx;
Greg Kroah-Hartman7e23a6e2009-08-27 15:58:15 -0700174 struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj;
Hank Janssenfceaf242009-07-13 15:34:54 -0700175
176 struct device_context *device_ctx = device_to_device_context(device);
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200177 struct hv_device *device_obj = &device_ctx->device_obj;
Hank Janssenfceaf242009-07-13 15:34:54 -0700178
179 struct net_device *net = NULL;
180 struct net_device_context *net_device_ctx;
Greg Kroah-Hartman7e23a6e2009-08-27 15:58:15 -0700181 struct netvsc_device_info device_info;
Hank Janssenfceaf242009-07-13 15:34:54 -0700182
183 DPRINT_ENTER(NETVSC_DRV);
184
185 if (!net_drv_obj->Base.OnDeviceAdd)
186 {
187 return -1;
188 }
189
190 net = alloc_netdev(sizeof(struct net_device_context), "seth%d", ether_setup);
Bill Pemberton454f18a2009-07-27 16:47:24 -0400191 /* net = alloc_etherdev(sizeof(struct net_device_context)); */
Hank Janssenfceaf242009-07-13 15:34:54 -0700192 if (!net)
193 {
194 return -1;
195 }
196
Bill Pemberton454f18a2009-07-27 16:47:24 -0400197 /* Set initial state */
Hank Janssenfceaf242009-07-13 15:34:54 -0700198 netif_carrier_off(net);
199 netif_stop_queue(net);
200
201 net_device_ctx = netdev_priv(net);
202 net_device_ctx->device_ctx = device_ctx;
Greg Kroah-Hartman621d7fb2009-07-24 11:00:39 -0700203 dev_set_drvdata(device, net);
Hank Janssenfceaf242009-07-13 15:34:54 -0700204
Bill Pemberton454f18a2009-07-27 16:47:24 -0400205 /* Notify the netvsc driver of the new device */
Hank Janssenfceaf242009-07-13 15:34:54 -0700206 ret = net_drv_obj->Base.OnDeviceAdd(device_obj, (void*)&device_info);
207 if (ret != 0)
208 {
209 free_netdev(net);
Greg Kroah-Hartman621d7fb2009-07-24 11:00:39 -0700210 dev_set_drvdata(device, NULL);
Hank Janssenfceaf242009-07-13 15:34:54 -0700211
212 DPRINT_ERR(NETVSC_DRV, "unable to add netvsc device (ret %d)", ret);
213 return ret;
214 }
215
Bill Pemberton454f18a2009-07-27 16:47:24 -0400216 /* If carrier is still off ie we did not get a link status callback, update it if necessary */
217 /* FIXME: We should use a atomic or test/set instead to avoid getting out of sync with the device's link status */
Hank Janssenfceaf242009-07-13 15:34:54 -0700218 if (!netif_carrier_ok(net))
219 {
220 if (!device_info.LinkState)
221 {
222 netif_carrier_on(net);
223 }
224 }
225
226 memcpy(net->dev_addr, device_info.MacAddr, ETH_ALEN);
227
Greg Kroah-Hartmanc86f3e22009-07-14 10:59:56 -0700228 net->netdev_ops = &device_ops;
Hank Janssenfceaf242009-07-13 15:34:54 -0700229
Hank Janssenfceaf242009-07-13 15:34:54 -0700230 SET_NETDEV_DEV(net, device);
231
232 ret = register_netdev(net);
233 if (ret != 0)
234 {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400235 /* Remove the device and release the resource */
Hank Janssenfceaf242009-07-13 15:34:54 -0700236 net_drv_obj->Base.OnDeviceRemove(device_obj);
237 free_netdev(net);
238 }
239
240 DPRINT_EXIT(NETVSC_DRV);
241
242 return ret;
243}
244
245static int netvsc_remove(struct device *device)
246{
247 int ret=0;
248 struct driver_context *driver_ctx = driver_to_driver_context(device->driver);
249 struct netvsc_driver_context *net_drv_ctx = (struct netvsc_driver_context*)driver_ctx;
Greg Kroah-Hartman7e23a6e2009-08-27 15:58:15 -0700250 struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj;
Hank Janssenfceaf242009-07-13 15:34:54 -0700251
252 struct device_context *device_ctx = device_to_device_context(device);
Greg Kroah-Hartman621d7fb2009-07-24 11:00:39 -0700253 struct net_device *net = dev_get_drvdata(&device_ctx->device);
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200254 struct hv_device *device_obj = &device_ctx->device_obj;
Hank Janssenfceaf242009-07-13 15:34:54 -0700255
256 DPRINT_ENTER(NETVSC_DRV);
257
258 if (net == NULL)
259 {
260 DPRINT_INFO(NETVSC, "no net device to remove");
261 DPRINT_EXIT(NETVSC_DRV);
262 return 0;
263 }
264
265 if (!net_drv_obj->Base.OnDeviceRemove)
266 {
267 DPRINT_EXIT(NETVSC_DRV);
268 return -1;
269 }
270
Bill Pemberton454f18a2009-07-27 16:47:24 -0400271 /* Stop outbound asap */
Hank Janssenfceaf242009-07-13 15:34:54 -0700272 netif_stop_queue(net);
Bill Pemberton454f18a2009-07-27 16:47:24 -0400273 /* netif_carrier_off(net); */
Hank Janssenfceaf242009-07-13 15:34:54 -0700274
275 unregister_netdev(net);
276
Bill Pemberton454f18a2009-07-27 16:47:24 -0400277 /* Call to the vsc driver to let it know that the device is being removed */
Hank Janssenfceaf242009-07-13 15:34:54 -0700278 ret = net_drv_obj->Base.OnDeviceRemove(device_obj);
279 if (ret != 0)
280 {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400281 /* TODO: */
Hank Janssenfceaf242009-07-13 15:34:54 -0700282 DPRINT_ERR(NETVSC, "unable to remove vsc device (ret %d)", ret);
283 }
284
285 free_netdev(net);
286
287 DPRINT_EXIT(NETVSC_DRV);
288
289 return ret;
290}
291
292/*++
293
294Name: netvsc_open()
295
296Desc: Open the specified interface device
297
298--*/
299static int netvsc_open(struct net_device *net)
300{
301 int ret=0;
302 struct net_device_context *net_device_ctx = netdev_priv(net);
303 struct driver_context *driver_ctx = driver_to_driver_context(net_device_ctx->device_ctx->device.driver);
304 struct netvsc_driver_context *net_drv_ctx = (struct netvsc_driver_context*)driver_ctx;
Greg Kroah-Hartman7e23a6e2009-08-27 15:58:15 -0700305 struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj;
Hank Janssenfceaf242009-07-13 15:34:54 -0700306
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200307 struct hv_device *device_obj = &net_device_ctx->device_ctx->device_obj;
Hank Janssenfceaf242009-07-13 15:34:54 -0700308
309 DPRINT_ENTER(NETVSC_DRV);
310
311 if (netif_carrier_ok(net))
312 {
313 memset(&net_device_ctx->stats, 0 , sizeof(struct net_device_stats));
314
Bill Pemberton454f18a2009-07-27 16:47:24 -0400315 /* Open up the device */
Hank Janssenfceaf242009-07-13 15:34:54 -0700316 ret = net_drv_obj->OnOpen(device_obj);
317 if (ret != 0)
318 {
319 DPRINT_ERR(NETVSC_DRV, "unable to open device (ret %d).", ret);
320 return ret;
321 }
322
323 netif_start_queue(net);
324 }
325 else
326 {
327 DPRINT_ERR(NETVSC_DRV, "unable to open device...link is down.");
328 }
329
330 DPRINT_EXIT(NETVSC_DRV);
331 return ret;
332}
333
334/*++
335
336Name: netvsc_close()
337
338Desc: Close the specified interface device
339
340--*/
341static int netvsc_close(struct net_device *net)
342{
343 int ret=0;
344 struct net_device_context *net_device_ctx = netdev_priv(net);
345 struct driver_context *driver_ctx = driver_to_driver_context(net_device_ctx->device_ctx->device.driver);
346 struct netvsc_driver_context *net_drv_ctx = (struct netvsc_driver_context*)driver_ctx;
Greg Kroah-Hartman7e23a6e2009-08-27 15:58:15 -0700347 struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj;
Hank Janssenfceaf242009-07-13 15:34:54 -0700348
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200349 struct hv_device *device_obj = &net_device_ctx->device_ctx->device_obj;
Hank Janssenfceaf242009-07-13 15:34:54 -0700350
351 DPRINT_ENTER(NETVSC_DRV);
352
353 netif_stop_queue(net);
354
355 ret = net_drv_obj->OnClose(device_obj);
356 if (ret != 0)
357 {
358 DPRINT_ERR(NETVSC_DRV, "unable to close device (ret %d).", ret);
359 }
360
361 DPRINT_EXIT(NETVSC_DRV);
362
363 return ret;
364}
365
366
367/*++
368
369Name: netvsc_xmit_completion()
370
371Desc: Send completion processing
372
373--*/
374static void netvsc_xmit_completion(void *context)
375{
Nicolas Palix4193d4f2009-07-29 14:10:10 +0200376 struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context;
Greg Kroah-Hartmanc4b0bc92009-07-14 15:12:46 -0700377 struct sk_buff *skb = (struct sk_buff *)(unsigned long)packet->Completion.Send.SendCompletionTid;
Hank Janssenfceaf242009-07-13 15:34:54 -0700378 struct net_device* net;
379
380 DPRINT_ENTER(NETVSC_DRV);
381
382 kfree(packet);
383
384 if (skb)
385 {
386 net = skb->dev;
387
388 dev_kfree_skb_any(skb);
389
390 if (netif_queue_stopped(net))
391 {
392 DPRINT_INFO(NETVSC_DRV, "net device (%p) waking up...", net);
393
394 netif_wake_queue(net);
395 }
396 }
397
398 DPRINT_EXIT(NETVSC_DRV);
399}
400
401/*++
402
403Name: netvsc_start_xmit()
404
405Desc: Start a send
406
407--*/
408static int netvsc_start_xmit (struct sk_buff *skb, struct net_device *net)
409{
410 int ret=0;
411 struct net_device_context *net_device_ctx = netdev_priv(net);
412 struct driver_context *driver_ctx = driver_to_driver_context(net_device_ctx->device_ctx->device.driver);
413 struct netvsc_driver_context *net_drv_ctx = (struct netvsc_driver_context*)driver_ctx;
Greg Kroah-Hartman7e23a6e2009-08-27 15:58:15 -0700414 struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj;
Hank Janssenfceaf242009-07-13 15:34:54 -0700415
416 int i=0;
Nicolas Palix4193d4f2009-07-29 14:10:10 +0200417 struct hv_netvsc_packet *packet;
Hank Janssenfceaf242009-07-13 15:34:54 -0700418 int num_frags;
419 int retries=0;
420
421 DPRINT_ENTER(NETVSC_DRV);
422
Bill Pemberton454f18a2009-07-27 16:47:24 -0400423 /* Support only 1 chain of frags */
Hank Janssenfceaf242009-07-13 15:34:54 -0700424 ASSERT(skb_shinfo(skb)->frag_list == NULL);
425 ASSERT(skb->dev == net);
426
427 DPRINT_DBG(NETVSC_DRV, "xmit packet - len %d data_len %d", skb->len, skb->data_len);
428
Bill Pemberton454f18a2009-07-27 16:47:24 -0400429 /* Add 1 for skb->data and any additional ones requested */
Hank Janssenfceaf242009-07-13 15:34:54 -0700430 num_frags = skb_shinfo(skb)->nr_frags + 1 + net_drv_obj->AdditionalRequestPageBufferCount;
431
Bill Pemberton454f18a2009-07-27 16:47:24 -0400432 /* Allocate a netvsc packet based on # of frags. */
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700433 packet = kzalloc(sizeof(struct hv_netvsc_packet) + (num_frags * sizeof(struct hv_page_buffer)) + net_drv_obj->RequestExtSize, GFP_ATOMIC);
Hank Janssenfceaf242009-07-13 15:34:54 -0700434 if (!packet)
435 {
Nicolas Palix4193d4f2009-07-29 14:10:10 +0200436 DPRINT_ERR(NETVSC_DRV, "unable to allocate hv_netvsc_packet");
Hank Janssenfceaf242009-07-13 15:34:54 -0700437 return -1;
438 }
439
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700440 packet->Extension = (void*)(unsigned long)packet + sizeof(struct hv_netvsc_packet) + (num_frags * sizeof(struct hv_page_buffer)) ;
Hank Janssenfceaf242009-07-13 15:34:54 -0700441
Bill Pemberton454f18a2009-07-27 16:47:24 -0400442 /* Setup the rndis header */
Hank Janssenfceaf242009-07-13 15:34:54 -0700443 packet->PageBufferCount = num_frags;
444
Bill Pemberton454f18a2009-07-27 16:47:24 -0400445 /* TODO: Flush all write buffers/ memory fence ??? */
446 /* wmb(); */
Hank Janssenfceaf242009-07-13 15:34:54 -0700447
Bill Pemberton454f18a2009-07-27 16:47:24 -0400448 /* Initialize it from the skb */
Hank Janssenfceaf242009-07-13 15:34:54 -0700449 ASSERT(skb->data);
450 packet->TotalDataBufferLength = skb->len;
451
Bill Pemberton454f18a2009-07-27 16:47:24 -0400452 /* Start filling in the page buffers starting at AdditionalRequestPageBufferCount offset */
Hank Janssenfceaf242009-07-13 15:34:54 -0700453 packet->PageBuffers[net_drv_obj->AdditionalRequestPageBufferCount].Pfn = virt_to_phys(skb->data) >> PAGE_SHIFT;
454 packet->PageBuffers[net_drv_obj->AdditionalRequestPageBufferCount].Offset = (unsigned long)skb->data & (PAGE_SIZE -1);
455 packet->PageBuffers[net_drv_obj->AdditionalRequestPageBufferCount].Length = skb->len - skb->data_len;
456
457 ASSERT((skb->len - skb->data_len) <= PAGE_SIZE);
458
459 for (i=net_drv_obj->AdditionalRequestPageBufferCount+1; i<num_frags; i++)
460 {
461 packet->PageBuffers[i].Pfn = page_to_pfn(skb_shinfo(skb)->frags[i-(net_drv_obj->AdditionalRequestPageBufferCount+1)].page);
462 packet->PageBuffers[i].Offset = skb_shinfo(skb)->frags[i-(net_drv_obj->AdditionalRequestPageBufferCount+1)].page_offset;
463 packet->PageBuffers[i].Length = skb_shinfo(skb)->frags[i-(net_drv_obj->AdditionalRequestPageBufferCount+1)].size;
464 }
465
Bill Pemberton454f18a2009-07-27 16:47:24 -0400466 /* Set the completion routine */
Hank Janssenfceaf242009-07-13 15:34:54 -0700467 packet->Completion.Send.OnSendCompletion = netvsc_xmit_completion;
468 packet->Completion.Send.SendCompletionContext = packet;
Greg Kroah-Hartmanc4b0bc92009-07-14 15:12:46 -0700469 packet->Completion.Send.SendCompletionTid = (unsigned long)skb;
Hank Janssenfceaf242009-07-13 15:34:54 -0700470
471retry_send:
472 ret = net_drv_obj->OnSend(&net_device_ctx->device_ctx->device_obj, packet);
473
474 if (ret == 0)
475 {
Hank Janssenfceaf242009-07-13 15:34:54 -0700476 ret = NETDEV_TX_OK;
477 net_device_ctx->stats.tx_bytes += skb->len;
478 net_device_ctx->stats.tx_packets++;
479 }
480 else
481 {
482 retries++;
483 if (retries < 4)
484 {
485 DPRINT_ERR(NETVSC_DRV, "unable to send...retrying %d...", retries);
486 udelay(100);
487 goto retry_send;
488 }
489
Bill Pemberton454f18a2009-07-27 16:47:24 -0400490 /* no more room or we are shutting down */
Hank Janssenfceaf242009-07-13 15:34:54 -0700491 DPRINT_ERR(NETVSC_DRV, "unable to send (%d)...marking net device (%p) busy", ret, net);
492 DPRINT_INFO(NETVSC_DRV, "net device (%p) stopping", net);
493
494 ret = NETDEV_TX_BUSY;
495 net_device_ctx->stats.tx_dropped++;
496
497 netif_stop_queue(net);
498
Bill Pemberton454f18a2009-07-27 16:47:24 -0400499 /* Null it since the caller will free it instead of the completion routine */
Hank Janssenfceaf242009-07-13 15:34:54 -0700500 packet->Completion.Send.SendCompletionTid = 0;
501
Bill Pemberton454f18a2009-07-27 16:47:24 -0400502 /* Release the resources since we will not get any send completion */
Hank Janssenfceaf242009-07-13 15:34:54 -0700503 netvsc_xmit_completion((void*)packet);
504 }
505
506 DPRINT_DBG(NETVSC_DRV, "# of xmits %lu total size %lu", net_device_ctx->stats.tx_packets, net_device_ctx->stats.tx_bytes);
507
508 DPRINT_EXIT(NETVSC_DRV);
509 return ret;
510}
511
512
513/*++
514
515Name: netvsc_linkstatus_callback()
516
517Desc: Link up/down notification
518
519--*/
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200520static void netvsc_linkstatus_callback(struct hv_device *device_obj, unsigned int status)
Hank Janssenfceaf242009-07-13 15:34:54 -0700521{
522 struct device_context* device_ctx = to_device_context(device_obj);
Greg Kroah-Hartman621d7fb2009-07-24 11:00:39 -0700523 struct net_device* net = dev_get_drvdata(&device_ctx->device);
Hank Janssenfceaf242009-07-13 15:34:54 -0700524
525 DPRINT_ENTER(NETVSC_DRV);
526
527 if (!net)
528 {
529 DPRINT_ERR(NETVSC_DRV, "got link status but net device not initialized yet");
530 return;
531 }
532
533 if (status == 1)
534 {
535 netif_carrier_on(net);
536 netif_wake_queue(net);
537 }
538 else
539 {
540 netif_carrier_off(net);
541 netif_stop_queue(net);
542 }
543 DPRINT_EXIT(NETVSC_DRV);
544}
545
546
547/*++
548
549Name: netvsc_recv_callback()
550
551Desc: Callback when we receive a packet from the "wire" on the specify device
552
553--*/
Nicolas Palix4193d4f2009-07-29 14:10:10 +0200554static int netvsc_recv_callback(struct hv_device *device_obj, struct hv_netvsc_packet *packet)
Hank Janssenfceaf242009-07-13 15:34:54 -0700555{
556 int ret=0;
557 struct device_context *device_ctx = to_device_context(device_obj);
Greg Kroah-Hartman621d7fb2009-07-24 11:00:39 -0700558 struct net_device *net = dev_get_drvdata(&device_ctx->device);
Hank Janssenfceaf242009-07-13 15:34:54 -0700559 struct net_device_context *net_device_ctx;
560
561 struct sk_buff *skb;
562 void *data;
563 int i=0;
564 unsigned long flags;
565
566 DPRINT_ENTER(NETVSC_DRV);
567
568 if (!net)
569 {
570 DPRINT_ERR(NETVSC_DRV, "got receive callback but net device not initialized yet");
571 return 0;
572 }
573
574 net_device_ctx = netdev_priv(net);
575
Bill Pemberton454f18a2009-07-27 16:47:24 -0400576 /* Allocate a skb - TODO preallocate this */
577 /* skb = alloc_skb(packet->TotalDataBufferLength, GFP_ATOMIC); */
578 skb = dev_alloc_skb(packet->TotalDataBufferLength + 2); /* Pad 2-bytes to align IP header to 16 bytes */
Hank Janssenfceaf242009-07-13 15:34:54 -0700579 ASSERT(skb);
580 skb_reserve(skb, 2);
581 skb->dev = net;
582
Bill Pemberton454f18a2009-07-27 16:47:24 -0400583 /* for kmap_atomic */
Hank Janssenfceaf242009-07-13 15:34:54 -0700584 local_irq_save(flags);
585
Nicolas Palix4193d4f2009-07-29 14:10:10 +0200586 /* Copy to skb. This copy is needed here since the memory pointed by hv_netvsc_packet */
Bill Pemberton454f18a2009-07-27 16:47:24 -0400587 /* cannot be deallocated */
Hank Janssenfceaf242009-07-13 15:34:54 -0700588 for (i=0; i<packet->PageBufferCount; i++)
589 {
590 data = kmap_atomic(pfn_to_page(packet->PageBuffers[i].Pfn), KM_IRQ1);
591 data = (void*)(unsigned long)data + packet->PageBuffers[i].Offset;
592
593 memcpy(skb_put(skb, packet->PageBuffers[i].Length), data, packet->PageBuffers[i].Length);
594
595 kunmap_atomic((void*)((unsigned long)data - packet->PageBuffers[i].Offset), KM_IRQ1);
596 }
597
598 local_irq_restore(flags);
599
600 skb->protocol = eth_type_trans(skb, net);
601
602 skb->ip_summed = CHECKSUM_NONE;
603
Bill Pemberton454f18a2009-07-27 16:47:24 -0400604 /* Pass the skb back up. Network stack will deallocate the skb when it is done */
Hank Janssenfceaf242009-07-13 15:34:54 -0700605 ret = netif_rx(skb);
606
607 switch (ret)
608 {
609 case NET_RX_DROP:
610 net_device_ctx->stats.rx_dropped++;
611 break;
612 default:
613 net_device_ctx->stats.rx_packets++;
614 net_device_ctx->stats.rx_bytes += skb->len;
615 break;
616
617 }
618 DPRINT_DBG(NETVSC_DRV, "# of recvs %lu total size %lu", net_device_ctx->stats.rx_packets, net_device_ctx->stats.rx_bytes);
619
620 DPRINT_EXIT(NETVSC_DRV);
621
622 return 0;
623}
624
625static int netvsc_drv_exit_cb(struct device *dev, void *data)
626{
627 struct device **curr = (struct device **)data;
628 *curr = dev;
Bill Pemberton454f18a2009-07-27 16:47:24 -0400629 return 1; /* stop iterating */
Hank Janssenfceaf242009-07-13 15:34:54 -0700630}
631
632/*++
633
634Name: netvsc_drv_exit()
635
636Desc:
637
638--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700639static void netvsc_drv_exit(void)
Hank Janssenfceaf242009-07-13 15:34:54 -0700640{
Greg Kroah-Hartman7e23a6e2009-08-27 15:58:15 -0700641 struct netvsc_driver *netvsc_drv_obj=&g_netvsc_drv.drv_obj;
Hank Janssenfceaf242009-07-13 15:34:54 -0700642 struct driver_context *drv_ctx=&g_netvsc_drv.drv_ctx;
Hank Janssenfceaf242009-07-13 15:34:54 -0700643 struct device *current_dev=NULL;
Bill Pemberton2295ba22009-07-28 13:46:22 -0400644 int ret;
Hank Janssenfceaf242009-07-13 15:34:54 -0700645
646 DPRINT_ENTER(NETVSC_DRV);
647
648 while (1)
649 {
650 current_dev = NULL;
651
Bill Pemberton454f18a2009-07-27 16:47:24 -0400652 /* Get the device */
Bill Pemberton2295ba22009-07-28 13:46:22 -0400653 ret = driver_for_each_device(&drv_ctx->driver, NULL,
654 (void *) &current_dev,
655 netvsc_drv_exit_cb);
656
657 if (ret)
658 DPRINT_WARN(NETVSC_DRV,
659 "driver_for_each_device returned %d", ret);
660
Hank Janssenfceaf242009-07-13 15:34:54 -0700661
662 if (current_dev == NULL)
663 break;
664
Bill Pemberton454f18a2009-07-27 16:47:24 -0400665 /* Initiate removal from the top-down */
Hank Janssenfceaf242009-07-13 15:34:54 -0700666 DPRINT_INFO(NETVSC_DRV, "unregistering device (%p)...", current_dev);
667
668 device_unregister(current_dev);
669 }
670
671 if (netvsc_drv_obj->Base.OnCleanup)
672 netvsc_drv_obj->Base.OnCleanup(&netvsc_drv_obj->Base);
673
674 vmbus_child_driver_unregister(drv_ctx);
675
676 DPRINT_EXIT(NETVSC_DRV);
677
678 return;
679}
680
681static int __init netvsc_init(void)
682{
683 int ret;
684
685 DPRINT_ENTER(NETVSC_DRV);
686 DPRINT_INFO(NETVSC_DRV, "Netvsc initializing....");
687
688 ret = netvsc_drv_init(NetVscInitialize);
689
690 DPRINT_EXIT(NETVSC_DRV);
691
692 return ret;
693}
694
695static void __exit netvsc_exit(void)
696{
697 DPRINT_ENTER(NETVSC_DRV);
698
699 netvsc_drv_exit();
700
701 DPRINT_EXIT(NETVSC_DRV);
702}
703
704module_param(netvsc_ringbuffer_size, int, S_IRUGO);
705
706module_init(netvsc_init);
707module_exit(netvsc_exit);