summaryrefslogtreecommitdiffstats
path: root/drivers/staging/hv/netvsc_drv.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-10-26 15:39:02 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2011-10-26 15:39:02 +0200
commitaa77677e0a288e08073620db5d2a31df83ca4788 (patch)
tree0d14b995a21c43f365d66b9ad101a334109fc4e4 /drivers/staging/hv/netvsc_drv.c
parentefb8d21b2c6db3497655cc6a033ae8a9883e4063 (diff)
parent43a3beb6da994549ec28a9f31727b997a025f958 (diff)
downloadop-kernel-dev-aa77677e0a288e08073620db5d2a31df83ca4788.zip
op-kernel-dev-aa77677e0a288e08073620db5d2a31df83ca4788.tar.gz
Merge branch 'staging-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
* 'staging-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (1519 commits) staging: et131x: Remove redundant check and return statement staging: et131x: Mainly whitespace changes to appease checkpatch staging: et131x: Remove last of the forward declarations staging: et131x: Remove even more forward declarations staging: et131x: Remove yet more forward declarations staging: et131x: Remove more forward declarations staging: et131x: Remove forward declaration of et131x_adapter_setup staging: et131x: Remove some forward declarations staging: et131x: Remove unused rx_ring.recv_packet_pool staging: et131x: Remove call to find pci pm capability staging: et131x: Remove redundant et131x_reset_recv() call staging: et131x: Remove unused rx_ring.recv_buffer_pool Staging: bcm: Fix three initialization errors in InterfaceDld.c Staging: bcm: Fix coding style issues in InterfaceDld.c staging:iio:dac: Add AD5360 driver staging:iio:trigger:bfin-timer: Fix compile error Staging: vt6655: add some range checks before memcpy() Staging: vt6655: whitespace fixes to iotcl.c Staging: vt6656: add some range checks before memcpy() Staging: vt6656: whitespace cleanups in ioctl.c ... Fix up conflicts in: - drivers/{Kconfig,Makefile}, drivers/staging/{Kconfig,Makefile}: vg driver movement - drivers/staging/brcm80211/brcmfmac/{dhd_linux.c,mac80211_if.c}: driver removal vs now stale changes - drivers/staging/rtl8192e/r8192E_core.c: driver removal vs now stale changes - drivers/staging/et131x/et131*: driver consolidation into one file, tried to do fixups
Diffstat (limited to 'drivers/staging/hv/netvsc_drv.c')
-rw-r--r--drivers/staging/hv/netvsc_drv.c148
1 files changed, 64 insertions, 84 deletions
diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c
index 4c7739f..93b0e91 100644
--- a/drivers/staging/hv/netvsc_drv.c
+++ b/drivers/staging/hv/netvsc_drv.c
@@ -33,14 +33,11 @@
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/slab.h>
-#include <linux/dmi.h>
-#include <linux/pci.h>
#include <net/arp.h>
#include <net/route.h>
#include <net/sock.h>
#include <net/pkt_sched.h>
-#include "hyperv.h"
#include "hyperv_net.h"
struct net_device_context {
@@ -72,20 +69,15 @@ static int netvsc_open(struct net_device *net)
struct hv_device *device_obj = net_device_ctx->device_ctx;
int ret = 0;
- if (netif_carrier_ok(net)) {
- /* Open up the device */
- ret = rndis_filter_open(device_obj);
- if (ret != 0) {
- netdev_err(net, "unable to open device (ret %d).\n",
- ret);
- return ret;
- }
-
- netif_start_queue(net);
- } else {
- netdev_err(net, "unable to open device...link is down.\n");
+ /* Open up the device */
+ ret = rndis_filter_open(device_obj);
+ if (ret != 0) {
+ netdev_err(net, "unable to open device (ret %d).\n", ret);
+ return ret;
}
+ netif_start_queue(net);
+
return ret;
}
@@ -143,12 +135,12 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
(num_pages * sizeof(struct hv_page_buffer)) +
sizeof(struct rndis_filter_packet), GFP_ATOMIC);
if (!packet) {
- /* out of memory, silently drop packet */
+ /* out of memory, drop packet */
netdev_err(net, "unable to allocate hv_netvsc_packet\n");
dev_kfree_skb(skb);
net->stats.tx_dropped++;
- return NETDEV_TX_OK;
+ return NETDEV_TX_BUSY;
}
packet->extension = (void *)(unsigned long)packet +
@@ -193,10 +185,11 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
} else {
/* we are shutting down or bus overloaded, just drop packet */
net->stats.tx_dropped++;
- netvsc_xmit_completion(packet);
+ kfree(packet);
+ dev_kfree_skb_any(skb);
}
- return NETDEV_TX_OK;
+ return ret ? NETDEV_TX_BUSY : NETDEV_TX_OK;
}
/*
@@ -205,8 +198,12 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
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 *net;
struct net_device_context *ndev_ctx;
+ struct netvsc_device *net_device;
+
+ net_device = hv_get_drvdata(device_obj);
+ net = net_device->ndev;
if (!net) {
netdev_err(net, "got link status but net device "
@@ -217,8 +214,8 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,
if (status == 1) {
netif_carrier_on(net);
netif_wake_queue(net);
- netif_notify_peers(net);
ndev_ctx = netdev_priv(net);
+ schedule_delayed_work(&ndev_ctx->dwork, 0);
schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20));
} else {
netif_carrier_off(net);
@@ -238,6 +235,10 @@ int netvsc_recv_callback(struct hv_device *device_obj,
void *data;
int i;
unsigned long flags;
+ struct netvsc_device *net_device;
+
+ net_device = hv_get_drvdata(device_obj);
+ net = net_device->ndev;
if (!net) {
netdev_err(net, "got receive callback but net device"
@@ -324,14 +325,17 @@ static void netvsc_send_garp(struct work_struct *w)
{
struct net_device_context *ndev_ctx;
struct net_device *net;
+ struct netvsc_device *net_device;
ndev_ctx = container_of(w, struct net_device_context, dwork.work);
- net = dev_get_drvdata(&ndev_ctx->device_ctx->device);
+ net_device = hv_get_drvdata(ndev_ctx->device_ctx);
+ net = net_device->ndev;
netif_notify_peers(net);
}
-static int netvsc_probe(struct hv_device *dev)
+static int netvsc_probe(struct hv_device *dev,
+ const struct hv_vmbus_device_id *dev_id)
{
struct net_device *net = NULL;
struct net_device_context *net_device_ctx;
@@ -340,7 +344,7 @@ static int netvsc_probe(struct hv_device *dev)
net = alloc_etherdev(sizeof(struct net_device_context));
if (!net)
- return -1;
+ return -ENOMEM;
/* Set initial state */
netif_carrier_off(net);
@@ -348,24 +352,9 @@ static int netvsc_probe(struct hv_device *dev)
net_device_ctx = netdev_priv(net);
net_device_ctx->device_ctx = dev;
atomic_set(&net_device_ctx->avail, ring_size);
- dev_set_drvdata(&dev->device, net);
+ hv_set_drvdata(dev, net);
INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_send_garp);
- /* Notify the netvsc driver of the new device */
- device_info.ring_size = ring_size;
- ret = rndis_filter_device_add(dev, &device_info);
- if (ret != 0) {
- free_netdev(net);
- dev_set_drvdata(&dev->device, NULL);
-
- netdev_err(net, "unable to add netvsc device (ret %d)\n", ret);
- return ret;
- }
-
- netif_carrier_on(net);
-
- memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN);
-
net->netdev_ops = &device_ops;
/* TODO: Add GSO and Checksum offload */
@@ -377,18 +366,37 @@ static int netvsc_probe(struct hv_device *dev)
ret = register_netdev(net);
if (ret != 0) {
- /* Remove the device and release the resource */
- rndis_filter_device_remove(dev);
+ pr_err("Unable to register netdev.\n");
+ free_netdev(net);
+ goto out;
+ }
+
+ /* Notify the netvsc driver of the new device */
+ device_info.ring_size = ring_size;
+ ret = rndis_filter_device_add(dev, &device_info);
+ if (ret != 0) {
+ netdev_err(net, "unable to add netvsc device (ret %d)\n", ret);
+ unregister_netdev(net);
free_netdev(net);
+ hv_set_drvdata(dev, NULL);
+ return ret;
}
+ memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN);
+
+ netif_carrier_on(net);
+out:
return ret;
}
static int netvsc_remove(struct hv_device *dev)
{
- struct net_device *net = dev_get_drvdata(&dev->device);
+ struct net_device *net;
struct net_device_context *ndev_ctx;
+ struct netvsc_device *net_device;
+
+ net_device = hv_get_drvdata(dev);
+ net = net_device->ndev;
if (net == NULL) {
dev_err(&dev->device, "No net device to remove\n");
@@ -413,61 +421,33 @@ static int netvsc_remove(struct hv_device *dev)
return 0;
}
+static const struct hv_vmbus_device_id id_table[] = {
+ /* Network guid */
+ { VMBUS_DEVICE(0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
+ 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E) },
+ { },
+};
+
+MODULE_DEVICE_TABLE(vmbus, id_table);
+
/* The one and only one */
static struct hv_driver netvsc_drv = {
+ .name = "netvsc",
+ .id_table = id_table,
.probe = netvsc_probe,
.remove = netvsc_remove,
};
static void __exit netvsc_drv_exit(void)
{
- vmbus_child_driver_unregister(&netvsc_drv.driver);
+ vmbus_driver_unregister(&netvsc_drv);
}
-
-static const struct dmi_system_id __initconst
-hv_netvsc_dmi_table[] __maybe_unused = {
- {
- .ident = "Hyper-V",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
- DMI_MATCH(DMI_BOARD_NAME, "Virtual Machine"),
- },
- },
- { },
-};
-MODULE_DEVICE_TABLE(dmi, hv_netvsc_dmi_table);
-
static int __init netvsc_drv_init(void)
{
- struct hv_driver *drv = &netvsc_drv;
- int ret;
-
- pr_info("initializing....");
-
- if (!dmi_check_system(hv_netvsc_dmi_table))
- return -ENODEV;
-
-
- /* 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;
+ return vmbus_driver_register(&netvsc_drv);
}
-static const struct pci_device_id __initconst
-hv_netvsc_pci_table[] __maybe_unused = {
- { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */
- { 0 }
-};
-MODULE_DEVICE_TABLE(pci, hv_netvsc_pci_table);
-
MODULE_LICENSE("GPL");
MODULE_VERSION(HV_DRV_VERSION);
MODULE_DESCRIPTION("Microsoft Hyper-V network driver");
OpenPOWER on IntegriCloud