diff options
Diffstat (limited to 'drivers/staging/hv/netvsc_drv.c')
-rw-r--r-- | drivers/staging/hv/netvsc_drv.c | 190 |
1 files changed, 55 insertions, 135 deletions
diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c index aaa8188..7b9c229 100644 --- a/drivers/staging/hv/netvsc_drv.c +++ b/drivers/staging/hv/netvsc_drv.c @@ -18,6 +18,8 @@ * Haiyang Zhang <haiyangz@microsoft.com> * Hank Janssen <hjanssen@microsoft.com> */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/init.h> #include <linux/module.h> #include <linux/highmem.h> @@ -36,11 +38,9 @@ #include <net/route.h> #include <net/sock.h> #include <net/pkt_sched.h> -#include "hv_api.h" -#include "logging.h" -#include "version_info.h" -#include "vmbus.h" -#include "netvsc_api.h" + +#include "hyperv.h" +#include "hyperv_net.h" struct net_device_context { /* point back to our device context */ @@ -58,9 +58,6 @@ static int ring_size = 128; module_param(ring_size, int, S_IRUGO); MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)"); -/* The one and only one */ -static struct netvsc_driver g_netvsc_drv; - /* no-op so the netdev core doesn't return -EINVAL when modifying the the * multicast address list in SIOCADDMULTI. hv is setup to get all multicast * when it calls RndisFilterOnOpen() */ @@ -78,14 +75,14 @@ static int netvsc_open(struct net_device *net) /* Open up the device */ ret = rndis_filter_open(device_obj); if (ret != 0) { - DPRINT_ERR(NETVSC_DRV, - "unable to open device (ret %d).", ret); + netdev_err(net, "unable to open device (ret %d).\n", + ret); return ret; } netif_start_queue(net); } else { - DPRINT_ERR(NETVSC_DRV, "unable to open device...link is down."); + netdev_err(net, "unable to open device...link is down.\n"); } return ret; @@ -101,7 +98,7 @@ static int netvsc_close(struct net_device *net) ret = rndis_filter_close(device_obj); if (ret != 0) - DPRINT_ERR(NETVSC_DRV, "unable to close device (ret %d).", ret); + netdev_err(net, "unable to close device (ret %d).\n", ret); return ret; } @@ -130,16 +127,10 @@ static void netvsc_xmit_completion(void *context) 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_driver *drv = - drv_to_hv_drv(net_device_ctx->device_ctx->device.driver); - struct netvsc_driver *net_drv_obj = drv->priv; struct hv_netvsc_packet *packet; int ret; unsigned int i, num_pages; - DPRINT_DBG(NETVSC_DRV, "xmit packet - len %d data_len %d", - skb->len, skb->data_len); - /* Add 1 for skb->data and additional one for RNDIS */ num_pages = skb_shinfo(skb)->nr_frags + 1 + 1; if (num_pages > net_device_ctx->avail) @@ -148,10 +139,10 @@ 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_pages * sizeof(struct hv_page_buffer)) + - net_drv_obj->req_ext_size, GFP_ATOMIC); + sizeof(struct rndis_filter_packet), GFP_ATOMIC); if (!packet) { /* out of memory, silently drop packet */ - DPRINT_ERR(NETVSC_DRV, "unable to allocate hv_netvsc_packet"); + netdev_err(net, "unable to allocate hv_netvsc_packet\n"); dev_kfree_skb(skb); net->stats.tx_dropped++; @@ -191,16 +182,12 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) packet->completion.send.send_completion_ctx = packet; packet->completion.send.send_completion_tid = (unsigned long)skb; - ret = net_drv_obj->send(net_device_ctx->device_ctx, + ret = rndis_filter_send(net_device_ctx->device_ctx, packet); if (ret == 0) { net->stats.tx_bytes += skb->len; net->stats.tx_packets++; - DPRINT_DBG(NETVSC_DRV, "# of xmits %lu total size %lu", - net->stats.tx_packets, - net->stats.tx_bytes); - net_device_ctx->avail -= num_pages; if (net_device_ctx->avail < PACKET_PAGES_LOWATER) netif_stop_queue(net); @@ -216,15 +203,15 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) /* * netvsc_linkstatus_callback - Link up/down notification */ -static void netvsc_linkstatus_callback(struct hv_device *device_obj, +void netvsc_linkstatus_callback(struct hv_device *device_obj, unsigned int status) { struct net_device *net = dev_get_drvdata(&device_obj->device); struct net_device_context *ndev_ctx; if (!net) { - DPRINT_ERR(NETVSC_DRV, "got link status but net device " - "not initialized yet"); + netdev_err(net, "got link status but net device " + "not initialized yet\n"); return; } @@ -244,7 +231,7 @@ static void netvsc_linkstatus_callback(struct hv_device *device_obj, * netvsc_recv_callback - Callback when we receive a packet from the * "wire" on the specified device. */ -static int netvsc_recv_callback(struct hv_device *device_obj, +int netvsc_recv_callback(struct hv_device *device_obj, struct hv_netvsc_packet *packet) { struct net_device *net = dev_get_drvdata(&device_obj->device); @@ -254,8 +241,8 @@ static int netvsc_recv_callback(struct hv_device *device_obj, unsigned long flags; if (!net) { - DPRINT_ERR(NETVSC_DRV, "got receive callback but net device " - "not initialized yet"); + netdev_err(net, "got receive callback but net device" + " not initialized yet\n"); return 0; } @@ -301,9 +288,6 @@ static int netvsc_recv_callback(struct hv_device *device_obj, */ netif_rx(skb); - DPRINT_DBG(NETVSC_DRV, "# of recvs %lu total size %lu", - net->stats.rx_packets, net->stats.rx_bytes); - return 0; } @@ -349,20 +333,13 @@ static void netvsc_send_garp(struct work_struct *w) } -static int netvsc_probe(struct device *device) +static int netvsc_probe(struct hv_device *dev) { - struct hv_driver *drv = - drv_to_hv_drv(device->driver); - struct netvsc_driver *net_drv_obj = drv->priv; - struct hv_device *device_obj = device_to_hv_device(device); struct net_device *net = NULL; struct net_device_context *net_device_ctx; struct netvsc_device_info device_info; int ret; - if (!net_drv_obj->base.dev_add) - return -1; - net = alloc_etherdev(sizeof(struct net_device_context)); if (!net) return -1; @@ -371,19 +348,19 @@ static int netvsc_probe(struct device *device) netif_carrier_off(net); net_device_ctx = netdev_priv(net); - net_device_ctx->device_ctx = device_obj; + net_device_ctx->device_ctx = dev; net_device_ctx->avail = ring_size; - dev_set_drvdata(device, net); + dev_set_drvdata(&dev->device, net); INIT_WORK(&net_device_ctx->work, netvsc_send_garp); /* Notify the netvsc driver of the new device */ - ret = net_drv_obj->base.dev_add(device_obj, &device_info); + device_info.ring_size = ring_size; + ret = rndis_filte_device_add(dev, &device_info); if (ret != 0) { free_netdev(net); - dev_set_drvdata(device, NULL); + dev_set_drvdata(&dev->device, NULL); - DPRINT_ERR(NETVSC_DRV, "unable to add netvsc device (ret %d)", - ret); + netdev_err(net, "unable to add netvsc device (ret %d)\n", ret); return ret; } @@ -408,35 +385,28 @@ static int netvsc_probe(struct device *device) net->features = NETIF_F_SG; SET_ETHTOOL_OPS(net, ðtool_ops); - SET_NETDEV_DEV(net, device); + SET_NETDEV_DEV(net, &dev->device); ret = register_netdev(net); if (ret != 0) { /* Remove the device and release the resource */ - net_drv_obj->base.dev_rm(device_obj); + rndis_filter_device_remove(dev); free_netdev(net); } return ret; } -static int netvsc_remove(struct device *device) +static int netvsc_remove(struct hv_device *dev) { - struct hv_driver *drv = - drv_to_hv_drv(device->driver); - struct netvsc_driver *net_drv_obj = drv->priv; - struct hv_device *device_obj = device_to_hv_device(device); - struct net_device *net = dev_get_drvdata(&device_obj->device); + struct net_device *net = dev_get_drvdata(&dev->device); int ret; if (net == NULL) { - DPRINT_INFO(NETVSC, "no net device to remove"); + dev_err(&dev->device, "No net device to remove\n"); return 0; } - if (!net_drv_obj->base.dev_rm) - return -1; - /* Stop outbound asap */ netif_stop_queue(net); /* netif_carrier_off(net); */ @@ -447,84 +417,27 @@ static int netvsc_remove(struct device *device) * Call to the vsc driver to let it know that the device is being * removed */ - ret = net_drv_obj->base.dev_rm(device_obj); + ret = rndis_filter_device_remove(dev); if (ret != 0) { /* TODO: */ - DPRINT_ERR(NETVSC, "unable to remove vsc device (ret %d)", ret); + netdev_err(net, "unable to remove vsc device (ret %d)\n", ret); } free_netdev(net); return ret; } -static int netvsc_drv_exit_cb(struct device *dev, void *data) -{ - struct device **curr = (struct device **)data; - - *curr = dev; - /* stop iterating */ - return 1; -} +/* The one and only one */ +static struct hv_driver netvsc_drv = { + .probe = netvsc_probe, + .remove = netvsc_remove, +}; -static void netvsc_drv_exit(void) +static void __exit netvsc_drv_exit(void) { - struct netvsc_driver *netvsc_drv_obj = &g_netvsc_drv; - struct hv_driver *drv = &g_netvsc_drv.base; - struct device *current_dev; - int ret; - - while (1) { - current_dev = NULL; - - /* Get the device */ - ret = driver_for_each_device(&drv->driver, NULL, - ¤t_dev, netvsc_drv_exit_cb); - if (ret) - DPRINT_WARN(NETVSC_DRV, - "driver_for_each_device returned %d", ret); - - if (current_dev == NULL) - break; - - /* Initiate removal from the top-down */ - DPRINT_INFO(NETVSC_DRV, "unregistering device (%p)...", - current_dev); - - device_unregister(current_dev); - } - - if (netvsc_drv_obj->base.cleanup) - netvsc_drv_obj->base.cleanup(&netvsc_drv_obj->base); - - vmbus_child_driver_unregister(&drv->driver); - - return; + vmbus_child_driver_unregister(&netvsc_drv.driver); } -static int netvsc_drv_init(int (*drv_init)(struct hv_driver *drv)) -{ - struct netvsc_driver *net_drv_obj = &g_netvsc_drv; - struct hv_driver *drv = &g_netvsc_drv.base; - int ret; - - net_drv_obj->ring_buf_size = ring_size * PAGE_SIZE; - net_drv_obj->recv_cb = netvsc_recv_callback; - net_drv_obj->link_status_change = netvsc_linkstatus_callback; - drv->priv = net_drv_obj; - - /* Callback to client driver to complete the initialization */ - drv_init(&net_drv_obj->base); - - drv->driver.name = net_drv_obj->base.name; - - drv->driver.probe = netvsc_probe; - drv->driver.remove = netvsc_remove; - - /* The driver belongs to vmbus */ - ret = vmbus_child_driver_register(&drv->driver); - - return ret; -} static const struct dmi_system_id __initconst hv_netvsc_dmi_table[] __maybe_unused = { @@ -540,19 +453,26 @@ hv_netvsc_dmi_table[] __maybe_unused = { }; MODULE_DEVICE_TABLE(dmi, hv_netvsc_dmi_table); -static int __init netvsc_init(void) +static int __init netvsc_drv_init(void) { - DPRINT_INFO(NETVSC_DRV, "Netvsc initializing...."); + struct hv_driver *drv = &netvsc_drv; + int ret; + + pr_info("initializing...."); if (!dmi_check_system(hv_netvsc_dmi_table)) return -ENODEV; - return netvsc_drv_init(netvsc_initialize); -} -static void __exit netvsc_exit(void) -{ - netvsc_drv_exit(); + /* Callback to client driver to complete the initialization */ + netvsc_initialize(drv); + + drv->driver.name = drv->name; + + /* The driver belongs to vmbus */ + ret = vmbus_child_driver_register(&drv->driver); + + return ret; } static const struct pci_device_id __initconst @@ -566,5 +486,5 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(HV_DRV_VERSION); MODULE_DESCRIPTION("Microsoft Hyper-V network driver"); -module_init(netvsc_init); -module_exit(netvsc_exit); +module_init(netvsc_drv_init); +module_exit(netvsc_drv_exit); |