Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlaf Hering <ohering@suse.de>2011-10-12 21:56:23 +0200
committerOlaf Hering <ohering@suse.de>2011-10-12 21:56:23 +0200
commit1e8fb5b9762a6a3cd976cf2fd85f690d5d475ac3 (patch)
treed1c35666fc6a18487f873493d551af72bfd5101b
parent98cdb5f11faf292435ba2b28a427b0d84e72f4cb (diff)
- Various updates for hv drivers, which fix also the hv_mouse driver
- staging: hv: storvsc: ignore SET_WINDOWN scsi command (bnc#722646). - staging/hv: advertise hv_storvsc instead of storvsc as sysfs driver name (bnc#716708). - staging/hv: fill scsi/proc_name for the sake of mkinitrd (bnc#716708). - Staging: hv: util: Invoke cn_netlink_send() in a work context. - Refresh patches.suse/staging-hv-pata_piix-ignore-disks.patch. - Refresh patches.xen/xen3-patch-2.6.32. - Delete patches.suse/staging-hv-vmbus-modalias-show.patch. suse-commit: c836841c92e5dddedad6b9283c93b1146d7d149b
-rw-r--r--drivers/ata/ata_piix.c18
-rw-r--r--drivers/staging/hv/Kconfig2
-rw-r--r--drivers/staging/hv/TODO11
-rw-r--r--drivers/staging/hv/channel_mgmt.c139
-rw-r--r--drivers/staging/hv/connection.c18
-rw-r--r--drivers/staging/hv/hv_kvp.c45
-rw-r--r--drivers/staging/hv/hv_kvp.h2
-rw-r--r--drivers/staging/hv/hv_mouse.c94
-rw-r--r--drivers/staging/hv/hv_util.c130
-rw-r--r--drivers/staging/hv/hyperv.h40
-rw-r--r--drivers/staging/hv/hyperv_net.h2
-rw-r--r--drivers/staging/hv/hyperv_vmbus.h6
-rw-r--r--drivers/staging/hv/netvsc.c167
-rw-r--r--drivers/staging/hv/netvsc_drv.c92
-rw-r--r--drivers/staging/hv/rndis_filter.c97
-rw-r--r--drivers/staging/hv/storvsc_drv.c164
-rw-r--r--drivers/staging/hv/vmbus_drv.c241
17 files changed, 591 insertions, 677 deletions
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 8b012dd4f3c3..d68f0b2f478e 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -98,10 +98,6 @@
#define DRV_NAME "ata_piix"
#define DRV_VERSION "2.13"
-#if defined(CONFIG_HYPERV_STORAGE) || defined(CONFIG_HYPERV_STORAGE_MODULE)
-#define PIIX_IGNORE_ATA_ON_HYPERV 1
-#endif
-
enum {
PIIX_IOCFG = 0x54, /* IDE I/O configuration register */
ICH5_PMR = 0x90, /* port mapping register */
@@ -625,7 +621,7 @@ MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-#if defined(PIIX_IGNORE_ATA_ON_HYPERV)
+#if defined(CONFIG_HYPERV_STORAGE) || defined(CONFIG_HYPERV_STORAGE_MODULE)
static int piix_msft_hyperv(void)
{
static const struct dmi_system_id hv_dmi_ident[] = {
@@ -641,6 +637,11 @@ static int piix_msft_hyperv(void)
};
return !!dmi_check_system(hv_dmi_ident);
}
+#else
+static inline int piix_msft_hyperv(void)
+{
+ return 0;
+}
#endif
struct ich_laptop {
@@ -726,13 +727,9 @@ static int piix_pata_prereset(struct ata_link *link, unsigned long deadline)
return ata_sff_prereset(link, deadline);
}
-/**
- *
- */
static unsigned int piix_pata_read_id(struct ata_device *adev, struct ata_taskfile *tf, u16 *id)
{
unsigned int err_mask = ata_do_dev_read_id(adev, tf, id);
-#if defined(PIIX_IGNORE_ATA_ON_HYPERV)
/*
* Ignore disks in a hyper-v guest.
* There is no unplug protocol like it is done with xen_emul_unplug= option.
@@ -745,7 +742,6 @@ static unsigned int piix_pata_read_id(struct ata_device *adev, struct ata_taskfi
ata_dev_printk(adev, KERN_WARNING, "ATA device ignored in Hyper-V guest\n");
id[ATA_ID_CONFIG] |= (1 << 15);
}
-#endif
return err_mask;
}
@@ -1724,13 +1720,11 @@ static int __init piix_init(void)
{
int rc;
-#if defined(PIIX_IGNORE_ATA_ON_HYPERV)
/* disabled until hv_storvsc drives also cdrom devices */
if (0 && piix_msft_hyperv()) {
printk(KERN_DEBUG "%s: hv_storvsc will bind to storage\n", __func__);
return -ENODEV;
}
-#endif
DPRINTK("pci_register_driver\n");
rc = pci_register_driver(&piix_pci_driver);
if (rc)
diff --git a/drivers/staging/hv/Kconfig b/drivers/staging/hv/Kconfig
index 5902ddf42413..0fb85fae113f 100644
--- a/drivers/staging/hv/Kconfig
+++ b/drivers/staging/hv/Kconfig
@@ -1,6 +1,6 @@
config HYPERV
tristate "Microsoft Hyper-V client drivers"
- depends on X86 && ACPI && PCI && !XEN && m
+ depends on X86 && ACPI && PCI && !XEN
default n
help
Select this option to run Linux as a Hyper-V client operating
diff --git a/drivers/staging/hv/TODO b/drivers/staging/hv/TODO
index 582fd4ab3f1e..ed4d63619df2 100644
--- a/drivers/staging/hv/TODO
+++ b/drivers/staging/hv/TODO
@@ -1,14 +1,7 @@
TODO:
- - fix remaining checkpatch warnings and errors
- - audit the vmbus to verify it is working properly with the
- driver model
- - see if the vmbus can be merged with the other virtual busses
- in the kernel
- audit the network driver
- - checking for carrier inside open is wrong, network device API
- confusion??
- - audit the block driver
- audit the scsi driver
Please send patches for this code to Greg Kroah-Hartman <gregkh@suse.de>,
-Hank Janssen <hjanssen@microsoft.com>, and Haiyang Zhang <haiyangz@microsoft.com>.
+Hank Janssen <hjanssen@microsoft.com>, Haiyang Zhang <haiyangz@microsoft.com>,
+K. Y. Srinivasan <kys@microsoft.com>
diff --git a/drivers/staging/hv/channel_mgmt.c b/drivers/staging/hv/channel_mgmt.c
index 11beb41c373e..9f007522a9d5 100644
--- a/drivers/staging/hv/channel_mgmt.c
+++ b/drivers/staging/hv/channel_mgmt.c
@@ -158,118 +158,6 @@ void prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
}
EXPORT_SYMBOL(prep_negotiate_resp);
-/**
- * chn_cb_negotiate() - Default handler for non IDE/SCSI/NETWORK
- * Hyper-V requests
- * @context: Pointer to argument structure.
- *
- * Set up the default handler for non device driver specific requests
- * from Hyper-V. This stub responds to the default negotiate messages
- * that come in for every non IDE/SCSI/Network request.
- * This behavior is normally overwritten in the hv_utils driver. That
- * driver handles requests like graceful shutdown, heartbeats etc.
- *
- * Mainly used by Hyper-V drivers.
- */
-void chn_cb_negotiate(void *context)
-{
- struct vmbus_channel *channel = context;
- u8 *buf;
- u32 buflen, recvlen;
- u64 requestid;
-
- struct icmsg_hdr *icmsghdrp;
- struct icmsg_negotiate *negop = NULL;
-
- if (channel->util_index >= 0) {
- /*
- * This is a properly initialized util channel.
- * Route this callback appropriately and setup state
- * so that we don't need to reroute again.
- */
- if (hv_cb_utils[channel->util_index].callback != NULL) {
- /*
- * The util driver has established a handler for
- * this service; do the magic.
- */
- channel->onchannel_callback =
- hv_cb_utils[channel->util_index].callback;
- (hv_cb_utils[channel->util_index].callback)(channel);
- return;
- }
- }
-
- buflen = PAGE_SIZE;
- buf = kmalloc(buflen, GFP_ATOMIC);
-
- vmbus_recvpacket(channel, buf, buflen, &recvlen, &requestid);
-
- if (recvlen > 0) {
- icmsghdrp = (struct icmsg_hdr *)&buf[
- sizeof(struct vmbuspipe_hdr)];
-
- prep_negotiate_resp(icmsghdrp, negop, buf);
-
- icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
- | ICMSGHDRFLAG_RESPONSE;
-
- vmbus_sendpacket(channel, buf,
- recvlen, requestid,
- VM_PKT_DATA_INBAND, 0);
- }
-
- kfree(buf);
-}
-EXPORT_SYMBOL(chn_cb_negotiate);
-
-/*
- * Function table used for message responses for non IDE/SCSI/Network type
- * messages. (Such as KVP/Shutdown etc)
- */
-struct hyperv_service_callback hv_cb_utils[MAX_MSG_TYPES] = {
- /* 0E0B6031-5213-4934-818B-38D90CED39DB */
- /* Shutdown */
- {
- .msg_type = HV_SHUTDOWN_MSG,
- .data.b = {
- 0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
- 0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
- },
- .log_msg = "Shutdown channel functionality initialized"
- },
-
- /* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
- /* TimeSync */
- {
- .msg_type = HV_TIMESYNC_MSG,
- .data.b = {
- 0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
- 0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
- },
- .log_msg = "Timesync channel functionality initialized"
- },
- /* {57164f39-9115-4e78-ab55-382f3bd5422d} */
- /* Heartbeat */
- {
- .msg_type = HV_HEARTBEAT_MSG,
- .data.b = {
- 0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
- 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d
- },
- .log_msg = "Heartbeat channel functionality initialized"
- },
- /* {A9A0F4E7-5A45-4d96-B827-8A841E8C03E6} */
- /* KVP */
- {
- .data.b = {
- 0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d,
- 0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3, 0xe6
- },
- .log_msg = "KVP channel functionality initialized"
- },
-};
-EXPORT_SYMBOL(hv_cb_utils);
-
/*
* alloc_channel - Allocate and initialize a vmbus channel object
*/
@@ -333,7 +221,7 @@ static void vmbus_process_rescind_offer(struct work_struct *work)
struct vmbus_channel,
work);
- vmbus_child_device_unregister(channel->device_obj);
+ vmbus_device_unregister(channel->device_obj);
}
/*
@@ -348,7 +236,6 @@ static void vmbus_process_offer(struct work_struct *work)
struct vmbus_channel *channel;
bool fnew = true;
int ret;
- int cnt;
unsigned long flags;
/* The next possible work is rescind handling */
@@ -383,7 +270,7 @@ static void vmbus_process_offer(struct work_struct *work)
* We need to set the DeviceObject field before calling
* vmbus_child_dev_add()
*/
- newchannel->device_obj = vmbus_child_device_create(
+ newchannel->device_obj = vmbus_device_create(
&newchannel->offermsg.offer.if_type,
&newchannel->offermsg.offer.if_instance,
newchannel);
@@ -393,7 +280,7 @@ static void vmbus_process_offer(struct work_struct *work)
* binding which eventually invokes the device driver's AddDevice()
* method.
*/
- ret = vmbus_child_device_register(newchannel->device_obj);
+ ret = vmbus_device_register(newchannel->device_obj);
if (ret != 0) {
pr_err("unable to add child device object (relid %d)\n",
newchannel->offermsg.child_relid);
@@ -410,32 +297,12 @@ static void vmbus_process_offer(struct work_struct *work)
* can cleanup properly
*/
newchannel->state = CHANNEL_OPEN_STATE;
- newchannel->util_index = -1; /* Invalid index */
-
- /* Open IC channels */
- for (cnt = 0; cnt < MAX_MSG_TYPES; cnt++) {
- if (!uuid_le_cmp(newchannel->offermsg.offer.if_type,
- hv_cb_utils[cnt].data) &&
- vmbus_open(newchannel, 2 * PAGE_SIZE,
- 2 * PAGE_SIZE, NULL, 0,
- chn_cb_negotiate,
- newchannel) == 0) {
- hv_cb_utils[cnt].channel = newchannel;
- newchannel->util_index = cnt;
-
- pr_info("%s\n", hv_cb_utils[cnt].log_msg);
-
- }
- }
}
}
/*
* vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
*
- * We ignore all offers except network and storage offers. For each network and
- * storage offers, we create a channel object and queue a work item to the
- * channel object to process the offer synchronously
*/
static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
{
diff --git a/drivers/staging/hv/connection.c b/drivers/staging/hv/connection.c
index 9e99c044b23f..649b91bcd8c1 100644
--- a/drivers/staging/hv/connection.c
+++ b/drivers/staging/hv/connection.c
@@ -219,11 +219,25 @@ static void process_chn_event(u32 relid)
*/
channel = relid2channel(relid);
+ if (!channel) {
+ pr_err("channel not found for relid - %u\n", relid);
+ return;
+ }
+
+ /*
+ * A channel once created is persistent even when there
+ * is no driver handling the device. An unloading driver
+ * sets the onchannel_callback to NULL under the
+ * protection of the channel inbound_lock. Thus, checking
+ * and invoking the driver specific callback takes care of
+ * orderly unloading of the driver.
+ */
+
spin_lock_irqsave(&channel->inbound_lock, flags);
- if (channel && (channel->onchannel_callback != NULL))
+ if (channel->onchannel_callback != NULL)
channel->onchannel_callback(channel->channel_callback_context);
else
- pr_err("channel not found for relid - %u\n", relid);
+ pr_err("no channel callback for relid - %u\n", relid);
spin_unlock_irqrestore(&channel->inbound_lock, flags);
}
diff --git a/drivers/staging/hv/hv_kvp.c b/drivers/staging/hv/hv_kvp.c
index 13b0ecf7d5d6..1e9515cc6094 100644
--- a/drivers/staging/hv/hv_kvp.c
+++ b/drivers/staging/hv/hv_kvp.c
@@ -44,21 +44,24 @@
static struct {
bool active; /* transaction status - active or not */
int recv_len; /* number of bytes received. */
+ int index; /* current index */
struct vmbus_channel *recv_channel; /* chn we got the request */
u64 recv_req_id; /* request ID. */
} kvp_transaction;
-static int kvp_send_key(int index);
+static void kvp_send_key(struct work_struct *dummy);
+
+#define TIMEOUT_FIRED 1
static void kvp_respond_to_host(char *key, char *value, int error);
static void kvp_work_func(struct work_struct *dummy);
static void kvp_register(void);
static DECLARE_DELAYED_WORK(kvp_work, kvp_work_func);
+static DECLARE_WORK(kvp_sendkey_work, kvp_send_key);
static struct cb_id kvp_id = { CN_KVP_IDX, CN_KVP_VAL };
static const char kvp_name[] = "kvp_kernel_module";
-static int timeout_fired;
static u8 *recv_buffer;
/*
* Register the kernel component with the user-level daemon.
@@ -90,8 +93,7 @@ kvp_work_func(struct work_struct *dummy)
* If the timer fires, the user-mode component has not responded;
* process the pending transaction.
*/
- kvp_respond_to_host("Unknown key", "Guest timed out", timeout_fired);
- timeout_fired = 1;
+ kvp_respond_to_host("Unknown key", "Guest timed out", TIMEOUT_FIRED);
}
/*
@@ -121,10 +123,11 @@ kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
}
}
-static int
-kvp_send_key(int index)
+static void
+kvp_send_key(struct work_struct *dummy)
{
struct cn_msg *msg;
+ int index = kvp_transaction.index;
msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg) , GFP_ATOMIC);
@@ -136,9 +139,8 @@ kvp_send_key(int index)
msg->len = sizeof(struct hv_ku_msg);
cn_netlink_send(msg, 0, GFP_ATOMIC);
kfree(msg);
- return 0;
}
- return 1;
+ return;
}
/*
@@ -177,6 +179,15 @@ kvp_respond_to_host(char *key, char *value, int error)
channel = kvp_transaction.recv_channel;
req_id = kvp_transaction.recv_req_id;
+ kvp_transaction.active = false;
+
+ if (channel->onchannel_callback == NULL)
+ /*
+ * We have raced with util driver being unloaded;
+ * silently return.
+ */
+ return;
+
icmsghdrp = (struct icmsg_hdr *)
&recv_buffer[sizeof(struct vmbuspipe_hdr)];
kvp_msg = (struct hv_kvp_msg *)
@@ -217,7 +228,6 @@ response_done:
vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
VM_PKT_DATA_INBAND, 0);
- kvp_transaction.active = false;
}
/*
@@ -243,10 +253,6 @@ void hv_kvp_onchannelcallback(void *context)
struct icmsg_negotiate *negop = NULL;
- if (kvp_transaction.active)
- return;
-
-
vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE, &recvlen, &requestid);
if (recvlen > 0) {
@@ -282,6 +288,7 @@ void hv_kvp_onchannelcallback(void *context)
kvp_transaction.recv_channel = channel;
kvp_transaction.recv_req_id = requestid;
kvp_transaction.active = true;
+ kvp_transaction.index = kvp_data->index;
/*
* Get the information from the
@@ -292,8 +299,8 @@ void hv_kvp_onchannelcallback(void *context)
* Set a timeout to deal with
* user-mode not responding.
*/
- kvp_send_key(kvp_data->index);
- schedule_delayed_work(&kvp_work, 100);
+ schedule_work(&kvp_sendkey_work);
+ schedule_delayed_work(&kvp_work, 5*HZ);
return;
@@ -312,16 +319,14 @@ callback_done:
}
int
-hv_kvp_init(void)
+hv_kvp_init(struct hv_util_service *srv)
{
int err;
err = cn_add_callback(&kvp_id, kvp_name, kvp_cn_callback);
if (err)
return err;
- recv_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!recv_buffer)
- return -ENOMEM;
+ recv_buffer = srv->recv_buffer;
return 0;
}
@@ -330,5 +335,5 @@ void hv_kvp_deinit(void)
{
cn_del_callback(&kvp_id);
cancel_delayed_work_sync(&kvp_work);
- kfree(recv_buffer);
+ cancel_work_sync(&kvp_sendkey_work);
}
diff --git a/drivers/staging/hv/hv_kvp.h b/drivers/staging/hv/hv_kvp.h
index 8c402f357d37..9b765d7df838 100644
--- a/drivers/staging/hv/hv_kvp.h
+++ b/drivers/staging/hv/hv_kvp.h
@@ -175,7 +175,7 @@ struct hv_kvp_msg {
struct hv_kvp_msg_enumerate kvp_data;
};
-int hv_kvp_init(void);
+int hv_kvp_init(struct hv_util_service *);
void hv_kvp_deinit(void);
void hv_kvp_onchannelcallback(void *);
diff --git a/drivers/staging/hv/hv_mouse.c b/drivers/staging/hv/hv_mouse.c
index dbb04ee4e968..74faa2678485 100644
--- a/drivers/staging/hv/hv_mouse.c
+++ b/drivers/staging/hv/hv_mouse.c
@@ -30,10 +30,11 @@
* Data types
*/
struct hv_input_dev_info {
+ unsigned int size;
unsigned short vendor;
unsigned short product;
unsigned short version;
- char name[128];
+ unsigned short reserved[11];
};
/* The maximum size of a synthetic input message. */
@@ -171,15 +172,11 @@ struct mousevsc_dev {
unsigned char *report_desc;
u32 report_desc_size;
struct hv_input_dev_info hid_dev_info;
-};
-
-struct input_device_context {
- struct hv_device *device_ctx;
- struct hid_device *hid_device;
- struct hv_input_dev_info device_info;
int connected;
+ struct hid_device *hid_device;
};
+
static struct mousevsc_dev *alloc_input_device(struct hv_device *device)
{
struct mousevsc_dev *input_dev;
@@ -196,14 +193,14 @@ static struct mousevsc_dev *alloc_input_device(struct hv_device *device)
atomic_cmpxchg(&input_dev->ref_count, 0, 2);
input_dev->device = device;
- device->ext = input_dev;
+ hv_set_drvdata(device, input_dev);
return input_dev;
}
static void free_input_device(struct mousevsc_dev *device)
{
- WARN_ON(atomic_read(&device->ref_count) == 0);
+ WARN_ON(atomic_read(&device->ref_count) != 0);
kfree(device);
}
@@ -214,7 +211,7 @@ static struct mousevsc_dev *get_input_device(struct hv_device *device)
{
struct mousevsc_dev *input_dev;
- input_dev = (struct mousevsc_dev *)device->ext;
+ input_dev = hv_get_drvdata(device);
/*
* FIXME
@@ -240,7 +237,7 @@ static struct mousevsc_dev *must_get_input_device(struct hv_device *device)
{
struct mousevsc_dev *input_dev;
- input_dev = (struct mousevsc_dev *)device->ext;
+ input_dev = hv_get_drvdata(device);
if (input_dev && atomic_read(&input_dev->ref_count))
atomic_inc(&input_dev->ref_count);
@@ -254,7 +251,7 @@ static void put_input_device(struct hv_device *device)
{
struct mousevsc_dev *input_dev;
- input_dev = (struct mousevsc_dev *)device->ext;
+ input_dev = hv_get_drvdata(device);
atomic_dec(&input_dev->ref_count);
}
@@ -266,7 +263,7 @@ static struct mousevsc_dev *release_input_device(struct hv_device *device)
{
struct mousevsc_dev *input_dev;
- input_dev = (struct mousevsc_dev *)device->ext;
+ input_dev = hv_get_drvdata(device);
/* Busy wait until the ref drop to 2, then set it to 1 */
while (atomic_cmpxchg(&input_dev->ref_count, 2, 1) != 2)
@@ -282,13 +279,13 @@ static struct mousevsc_dev *final_release_input_device(struct hv_device *device)
{
struct mousevsc_dev *input_dev;
- input_dev = (struct mousevsc_dev *)device->ext;
+ input_dev = hv_get_drvdata(device);
/* Busy wait until the ref drop to 1, then set it to 0 */
while (atomic_cmpxchg(&input_dev->ref_count, 1, 0) != 1)
udelay(100);
- device->ext = NULL;
+ hv_set_drvdata(device, NULL);
return input_dev;
}
@@ -330,9 +327,9 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
/* Save the hid desc */
desc = &device_info->hid_descriptor;
- WARN_ON(desc->bLength > 0);
+ WARN_ON(desc->bLength == 0);
- input_device->hid_desc = kzalloc(desc->bLength, GFP_KERNEL);
+ input_device->hid_desc = kzalloc(desc->bLength, GFP_ATOMIC);
if (!input_device->hid_desc) {
pr_err("unable to allocate hid descriptor - size %d",
@@ -344,8 +341,10 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
/* Save the report desc */
input_device->report_desc_size = desc->desc[0].wDescriptorLength;
+ if (input_device->report_desc_size == 0)
+ goto cleanup;
input_device->report_desc = kzalloc(input_device->report_desc_size,
- GFP_KERNEL);
+ GFP_ATOMIC);
if (!input_device->report_desc) {
pr_err("unable to allocate report descriptor - size %d",
@@ -401,7 +400,6 @@ static void mousevsc_on_receive_input_report(struct mousevsc_dev *input_device,
struct synthhid_input_report *input_report)
{
struct hv_driver *input_drv;
- struct input_device_context *input_dev_ctx;
if (!input_device->init_complete) {
pr_info("Initialization incomplete...ignoring input_report msg");
@@ -410,9 +408,8 @@ static void mousevsc_on_receive_input_report(struct mousevsc_dev *input_device,
input_drv = drv_to_hv_drv(input_device->device->device.driver);
- input_dev_ctx = dev_get_drvdata(&input_device->device->device);
- hid_input_report(input_dev_ctx->hid_device,
+ hid_input_report(input_device->hid_device,
HID_INPUT_REPORT, input_report->buffer, input_report->header.size, 1);
}
@@ -452,7 +449,7 @@ static void mousevsc_on_receive(struct hv_device *device,
break;
case SynthHidInitialDeviceInfo:
- WARN_ON(pipe_msg->size >= sizeof(struct hv_input_dev_info));
+ WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info));
/*
* Parse out the device info into device attr,
@@ -546,7 +543,7 @@ static void mousevsc_on_channel_callback(void *context)
} else if (ret == -ENOBUFS) {
/* Handle large packet */
bufferlen = bytes_recvd;
- buffer = kzalloc(bytes_recvd, GFP_KERNEL);
+ buffer = kzalloc(bytes_recvd, GFP_ATOMIC);
if (buffer == NULL) {
buffer = packet;
@@ -593,7 +590,7 @@ static int mousevsc_connect_to_vsp(struct hv_device *device)
request->size = sizeof(struct synthhid_protocol_request);
request->request.header.type = SynthHidProtocolRequest;
- request->request.header.size = sizeof(unsigned long);
+ request->request.header.size = sizeof(unsigned int);
request->request.version_requested.version = SYNTHHID_INPUT_VERSION;
pr_info("synthhid protocol request...");
@@ -661,9 +658,8 @@ static void mousevsc_hid_close(struct hid_device *hid)
static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len)
{
- struct input_device_context *input_device_ctx =
- dev_get_drvdata(&dev->device);
struct hid_device *hid_dev;
+ struct mousevsc_dev *input_device = hv_get_drvdata(dev);
/* hid_debug = -1; */
hid_dev = kmalloc(sizeof(struct hid_device), GFP_KERNEL);
@@ -680,13 +676,13 @@ static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len)
hid_dev->ll_driver->close = mousevsc_hid_close;
hid_dev->bus = BUS_VIRTUAL;
- hid_dev->vendor = input_device_ctx->device_info.vendor;
- hid_dev->product = input_device_ctx->device_info.product;
- hid_dev->version = input_device_ctx->device_info.version;
+ hid_dev->vendor = input_device->hid_dev_info.vendor;
+ hid_dev->product = input_device->hid_dev_info.product;
+ hid_dev->version = input_device->hid_dev_info.version;
hid_dev->dev = dev->device;
sprintf(hid_dev->name, "%s",
- input_device_ctx->device_info.name);
+ "Microsoft Vmbus HID-compliant Mouse");
/*
* HJ Do we want to call it with a 0
@@ -694,7 +690,7 @@ static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len)
if (!hidinput_connect(hid_dev, 0)) {
hid_dev->claimed |= HID_CLAIMED_INPUT;
- input_device_ctx->connected = 1;
+ input_device->connected = 1;
DPRINT_INFO(INPUTVSC_DRV,
"HID device claimed by input\n");
@@ -706,7 +702,7 @@ static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len)
"input or hiddev\n");
}
- input_device_ctx->hid_device = hid_dev;
+ input_device->hid_device = hid_dev;
}
kfree(hid_dev);
@@ -718,8 +714,6 @@ static int mousevsc_on_device_add(struct hv_device *device,
int ret = 0;
struct mousevsc_dev *input_dev;
struct hv_driver *input_drv;
- struct hv_input_dev_info dev_info;
- struct input_device_context *input_device_ctx;
input_dev = alloc_input_device(device);
@@ -760,15 +754,7 @@ static int mousevsc_on_device_add(struct hv_device *device,
input_drv = drv_to_hv_drv(input_dev->device->device.driver);
- dev_info.vendor = input_dev->hid_dev_info.vendor;
- dev_info.product = input_dev->hid_dev_info.product;
- dev_info.version = input_dev->hid_dev_info.version;
- strcpy(dev_info.name, "Microsoft Vmbus HID-compliant Mouse");
- /* Send the device info back up */
- input_device_ctx = dev_get_drvdata(&device->device);
- memcpy(&input_device_ctx->device_info, &dev_info,
- sizeof(struct hv_input_dev_info));
/* Send the report desc back up */
/* workaround SA-167 */
@@ -790,7 +776,7 @@ static int mousevsc_on_device_remove(struct hv_device *device)
int ret = 0;
pr_info("disabling input device (%p)...",
- device->ext);
+ hv_get_drvdata(device));
input_dev = release_input_device(device);
@@ -808,7 +794,7 @@ static int mousevsc_on_device_remove(struct hv_device *device)
udelay(100);
}
- pr_info("removing input device (%p)...", device->ext);
+ pr_info("removing input device (%p)...", hv_get_drvdata(device));
input_dev = final_release_input_device(device);
@@ -823,16 +809,11 @@ static int mousevsc_on_device_remove(struct hv_device *device)
}
-static int mousevsc_probe(struct hv_device *dev)
+static int mousevsc_probe(struct hv_device *dev,
+ const struct hv_vmbus_device_id *dev_id)
{
int ret = 0;
- struct input_device_context *input_dev_ctx;
-
- input_dev_ctx = kmalloc(sizeof(struct input_device_context),
- GFP_KERNEL);
-
- dev_set_drvdata(&dev->device, input_dev_ctx);
/* Call to the vsc driver to add the device */
ret = mousevsc_on_device_add(dev, NULL);
@@ -848,13 +829,12 @@ static int mousevsc_probe(struct hv_device *dev)
static int mousevsc_remove(struct hv_device *dev)
{
- struct input_device_context *input_dev_ctx;
+ struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
int ret;
- input_dev_ctx = dev_get_drvdata(&dev->device);
- if (input_dev_ctx->connected) {
- hidinput_disconnect(input_dev_ctx->hid_device);
- input_dev_ctx->connected = 0;
+ if (input_dev->connected) {
+ hidinput_disconnect(input_dev->hid_device);
+ input_dev->connected = 0;
}
/*
@@ -867,8 +847,6 @@ static int mousevsc_remove(struct hv_device *dev)
"unable to remove vsc device (ret %d)", ret);
}
- kfree(input_dev_ctx);
-
return ret;
}
diff --git a/drivers/staging/hv/hv_util.c b/drivers/staging/hv/hv_util.c
index e29a2a23eda5..faa66074cc21 100644
--- a/drivers/staging/hv/hv_util.c
+++ b/drivers/staging/hv/hv_util.c
@@ -30,9 +30,27 @@
#include "hyperv.h"
#include "hv_kvp.h"
-static u8 *shut_txf_buf;
-static u8 *time_txf_buf;
-static u8 *hbeat_txf_buf;
+
+static void shutdown_onchannelcallback(void *context);
+static struct hv_util_service util_shutdown = {
+ .util_cb = shutdown_onchannelcallback,
+};
+
+static void timesync_onchannelcallback(void *context);
+static struct hv_util_service util_timesynch = {
+ .util_cb = timesync_onchannelcallback,
+};
+
+static void heartbeat_onchannelcallback(void *context);
+static struct hv_util_service util_heartbeat = {
+ .util_cb = heartbeat_onchannelcallback,
+};
+
+static struct hv_util_service util_kvp = {
+ .util_cb = hv_kvp_onchannelcallback,
+ .util_init = hv_kvp_init,
+ .util_deinit = hv_kvp_deinit,
+};
static void shutdown_onchannelcallback(void *context)
{
@@ -40,6 +58,7 @@ static void shutdown_onchannelcallback(void *context)
u32 recvlen;
u64 requestid;
u8 execute_shutdown = false;
+ u8 *shut_txf_buf = util_shutdown.recv_buffer;
struct shutdown_msg_data *shutdown_msg;
@@ -169,6 +188,7 @@ static void timesync_onchannelcallback(void *context)
u64 requestid;
struct icmsg_hdr *icmsghdrp;
struct ictimesync_data *timedatap;
+ u8 *time_txf_buf = util_timesynch.recv_buffer;
vmbus_recvpacket(channel, time_txf_buf,
PAGE_SIZE, &recvlen, &requestid);
@@ -207,6 +227,7 @@ static void heartbeat_onchannelcallback(void *context)
u64 requestid;
struct icmsg_hdr *icmsghdrp;
struct heartbeat_msg_data *heartbeat_msg;
+ u8 *hbeat_txf_buf = util_heartbeat.recv_buffer;
vmbus_recvpacket(channel, hbeat_txf_buf,
PAGE_SIZE, &recvlen, &requestid);
@@ -235,33 +256,69 @@ static void heartbeat_onchannelcallback(void *context)
}
}
-/*
- * The devices managed by the util driver don't need any additional
- * setup.
- */
-static int util_probe(struct hv_device *dev)
+static int util_probe(struct hv_device *dev,
+ const struct hv_vmbus_device_id *dev_id)
{
+ struct hv_util_service *srv =
+ (struct hv_util_service *)dev_id->driver_data;
+ int ret;
+
+ srv->recv_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!srv->recv_buffer)
+ return -ENOMEM;
+ if (srv->util_init) {
+ ret = srv->util_init(srv);
+ if (ret) {
+ ret = -ENODEV;
+ goto error1;
+ }
+ }
+
+ ret = vmbus_open(dev->channel, 2 * PAGE_SIZE, 2 * PAGE_SIZE, NULL, 0,
+ srv->util_cb, dev->channel);
+ if (ret)
+ goto error;
+
+ hv_set_drvdata(dev, srv);
return 0;
+
+error:
+ if (srv->util_deinit)
+ srv->util_deinit();
+error1:
+ kfree(srv->recv_buffer);
+ return ret;
}
static int util_remove(struct hv_device *dev)
{
+ struct hv_util_service *srv = hv_get_drvdata(dev);
+
+ vmbus_close(dev->channel);
+ if (srv->util_deinit)
+ srv->util_deinit();
+ kfree(srv->recv_buffer);
+
return 0;
}
static const struct hv_vmbus_device_id id_table[] = {
/* Shutdown guid */
{ VMBUS_DEVICE(0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
- 0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB) },
+ 0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB)
+ .driver_data = (unsigned long)&util_shutdown },
/* Time synch guid */
{ VMBUS_DEVICE(0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
- 0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf) },
+ 0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf)
+ .driver_data = (unsigned long)&util_timesynch },
/* Heartbeat guid */
{ VMBUS_DEVICE(0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
- 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d) },
+ 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d)
+ .driver_data = (unsigned long)&util_heartbeat },
/* KVP guid */
{ VMBUS_DEVICE(0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d,
- 0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3, 0xe6) },
+ 0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3, 0xe6)
+ .driver_data = (unsigned long)&util_kvp },
{ },
};
@@ -279,30 +336,6 @@ static int __init init_hyperv_utils(void)
{
pr_info("Registering HyperV Utility Driver\n");
- if (hv_kvp_init())
- return -ENODEV;
-
-
- shut_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- time_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- hbeat_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
-
- if (!shut_txf_buf || !time_txf_buf || !hbeat_txf_buf) {
- pr_info("Unable to allocate memory for receive buffer\n");
- kfree(shut_txf_buf);
- kfree(time_txf_buf);
- kfree(hbeat_txf_buf);
- return -ENOMEM;
- }
-
- hv_cb_utils[HV_SHUTDOWN_MSG].callback = &shutdown_onchannelcallback;
-
- hv_cb_utils[HV_TIMESYNC_MSG].callback = &timesync_onchannelcallback;
-
- hv_cb_utils[HV_HEARTBEAT_MSG].callback = &heartbeat_onchannelcallback;
-
- hv_cb_utils[HV_KVP_MSG].callback = &hv_kvp_onchannelcallback;
-
return vmbus_driver_register(&util_drv);
}
@@ -310,31 +343,6 @@ static void exit_hyperv_utils(void)
{
pr_info("De-Registered HyperV Utility Driver\n");
- if (hv_cb_utils[HV_SHUTDOWN_MSG].channel != NULL)
- hv_cb_utils[HV_SHUTDOWN_MSG].channel->onchannel_callback =
- &chn_cb_negotiate;
- hv_cb_utils[HV_SHUTDOWN_MSG].callback = NULL;
-
- if (hv_cb_utils[HV_TIMESYNC_MSG].channel != NULL)
- hv_cb_utils[HV_TIMESYNC_MSG].channel->onchannel_callback =
- &chn_cb_negotiate;
- hv_cb_utils[HV_TIMESYNC_MSG].callback = NULL;
-
- if (hv_cb_utils[HV_HEARTBEAT_MSG].channel != NULL)
- hv_cb_utils[HV_HEARTBEAT_MSG].channel->onchannel_callback =
- &chn_cb_negotiate;
- hv_cb_utils[HV_HEARTBEAT_MSG].callback = NULL;
-
- if (hv_cb_utils[HV_KVP_MSG].channel != NULL)
- hv_cb_utils[HV_KVP_MSG].channel->onchannel_callback =
- &chn_cb_negotiate;
- hv_cb_utils[HV_KVP_MSG].callback = NULL;
-
- hv_kvp_deinit();
-
- kfree(shut_txf_buf);
- kfree(time_txf_buf);
- kfree(hbeat_txf_buf);
vmbus_driver_unregister(&util_drv);
}
diff --git a/drivers/staging/hv/hyperv.h b/drivers/staging/hv/hyperv.h
index c24981198b1b..edaa9e2f58ec 100644
--- a/drivers/staging/hv/hyperv.h
+++ b/drivers/staging/hv/hyperv.h
@@ -581,11 +581,6 @@ struct vmbus_channel {
struct work_struct work;
enum vmbus_channel_state state;
- /*
- * For util channels, stash the
- * the service index for easy access.
- */
- s8 util_index;
struct vmbus_channel_offer_channel offermsg;
/*
@@ -810,7 +805,7 @@ struct hv_driver {
struct device_driver driver;
- int (*probe)(struct hv_device *);
+ int (*probe)(struct hv_device *, const struct hv_vmbus_device_id *);
int (*remove)(struct hv_device *);
void (*shutdown)(struct hv_device *);
@@ -827,9 +822,6 @@ struct hv_device {
struct device device;
struct vmbus_channel *channel;
-
- /* Device extension; */
- void *ext;
};
@@ -843,6 +835,15 @@ static inline struct hv_driver *drv_to_hv_drv(struct device_driver *d)
return container_of(d, struct hv_driver, driver);
}
+static inline void hv_set_drvdata(struct hv_device *dev, void *data)
+{
+ dev_set_drvdata(&dev->device, data);
+}
+
+static inline void *hv_get_drvdata(struct hv_device *dev)
+{
+ return dev_get_drvdata(&dev->device);
+}
/* Vmbus interface */
#define vmbus_driver_register(driver) \
@@ -883,6 +884,19 @@ void vmbus_driver_unregister(struct hv_driver *hv_driver);
#define HV_ERROR_NOT_SUPPORTED 0x80070032
#define HV_ERROR_MACHINE_LOCKED 0x800704F7
+/*
+ * While we want to handle util services as regular devices,
+ * there is only one instance of each of these services; so
+ * we statically allocate the service specific state.
+ */
+
+struct hv_util_service {
+ u8 *recv_buffer;
+ void (*util_cb)(void *);
+ int (*util_init)(struct hv_util_service *);
+ void (*util_deinit)(void);
+};
+
struct vmbuspipe_hdr {
u32 flags;
u32 msgsize;
@@ -941,12 +955,6 @@ struct ictimesync_data {
u8 flags;
} __packed;
-/* Index for each IC struct in array hv_cb_utils[] */
-#define HV_SHUTDOWN_MSG 0
-#define HV_TIMESYNC_MSG 1
-#define HV_HEARTBEAT_MSG 2
-#define HV_KVP_MSG 3
-
struct hyperv_service_callback {
u8 msg_type;
char *log_msg;
@@ -957,7 +965,5 @@ struct hyperv_service_callback {
extern void prep_negotiate_resp(struct icmsg_hdr *,
struct icmsg_negotiate *, u8 *);
-extern void chn_cb_negotiate(void *);
-extern struct hyperv_service_callback hv_cb_utils[];
#endif /* _HYPERV_H */
diff --git a/drivers/staging/hv/hyperv_net.h b/drivers/staging/hv/hyperv_net.h
index af8a37fb502f..366dd2b32b13 100644
--- a/drivers/staging/hv/hyperv_net.h
+++ b/drivers/staging/hv/hyperv_net.h
@@ -392,6 +392,8 @@ struct netvsc_device {
struct nvsp_message revoke_packet;
/* unsigned char HwMacAddr[HW_MACADDR_LEN]; */
+ struct net_device *ndev;
+
/* Holds rndis device info */
void *extension;
};
diff --git a/drivers/staging/hv/hyperv_vmbus.h b/drivers/staging/hv/hyperv_vmbus.h
index 16ca90d9ac24..3d2d836c3cc8 100644
--- a/drivers/staging/hv/hyperv_vmbus.h
+++ b/drivers/staging/hv/hyperv_vmbus.h
@@ -601,12 +601,12 @@ extern struct vmbus_connection vmbus_connection;
/* General vmbus interface */
-struct hv_device *vmbus_child_device_create(uuid_le *type,
+struct hv_device *vmbus_device_create(uuid_le *type,
uuid_le *instance,
struct vmbus_channel *channel);
-int vmbus_child_device_register(struct hv_device *child_device_obj);
-void vmbus_child_device_unregister(struct hv_device *device_obj);
+int vmbus_device_register(struct hv_device *child_device_obj);
+void vmbus_device_unregister(struct hv_device *device_obj);
/* static void */
/* VmbusChildDeviceDestroy( */
diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c
index 30d313952852..b902579c7fe6 100644
--- a/drivers/staging/hv/netvsc.c
+++ b/drivers/staging/hv/netvsc.c
@@ -27,14 +27,15 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/netdevice.h>
-#include "hyperv.h"
#include "hyperv_net.h"
static struct netvsc_device *alloc_net_device(struct hv_device *device)
{
struct netvsc_device *net_device;
+ struct net_device *ndev = hv_get_drvdata(device);
net_device = kzalloc(sizeof(struct netvsc_device), GFP_KERNEL);
if (!net_device)
@@ -43,8 +44,9 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
net_device->destroy = false;
net_device->dev = device;
- device->ext = net_device;
+ net_device->ndev = ndev;
+ hv_set_drvdata(device, net_device);
return net_device;
}
@@ -52,7 +54,7 @@ static struct netvsc_device *get_outbound_net_device(struct hv_device *device)
{
struct netvsc_device *net_device;
- net_device = device->ext;
+ net_device = hv_get_drvdata(device);
if (net_device && net_device->destroy)
net_device = NULL;
@@ -63,7 +65,7 @@ static struct netvsc_device *get_inbound_net_device(struct hv_device *device)
{
struct netvsc_device *net_device;
- net_device = device->ext;
+ net_device = hv_get_drvdata(device);
if (!net_device)
goto get_in_err;
@@ -81,6 +83,7 @@ static int netvsc_destroy_recv_buf(struct netvsc_device *net_device)
{
struct nvsp_message *revoke_packet;
int ret = 0;
+ struct net_device *ndev = net_device->ndev;
/*
* If we got a section count, it means we received a
@@ -108,8 +111,8 @@ static int netvsc_destroy_recv_buf(struct netvsc_device *net_device)
* have a leak rather than continue and a bugchk
*/
if (ret != 0) {
- dev_err(&net_device->dev->device, "unable to send "
- "revoke receive buffer to netvsp");
+ netdev_err(ndev, "unable to send "
+ "revoke receive buffer to netvsp\n");
return ret;
}
}
@@ -123,8 +126,8 @@ static int netvsc_destroy_recv_buf(struct netvsc_device *net_device)
* rather than continue and a bugchk
*/
if (ret != 0) {
- dev_err(&net_device->dev->device,
- "unable to teardown receive buffer's gpadl");
+ netdev_err(ndev,
+ "unable to teardown receive buffer's gpadl\n");
return ret;
}
net_device->recv_buf_gpadl_handle = 0;
@@ -152,20 +155,19 @@ static int netvsc_init_recv_buf(struct hv_device *device)
int t;
struct netvsc_device *net_device;
struct nvsp_message *init_packet;
+ struct net_device *ndev;
net_device = get_outbound_net_device(device);
- if (!net_device) {
- dev_err(&device->device, "unable to get net device..."
- "device being destroyed?");
+ if (!net_device)
return -ENODEV;
- }
+ ndev = net_device->ndev;
net_device->recv_buf =
(void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO,
get_order(net_device->recv_buf_size));
if (!net_device->recv_buf) {
- dev_err(&device->device, "unable to allocate receive "
- "buffer of size %d", net_device->recv_buf_size);
+ netdev_err(ndev, "unable to allocate receive "
+ "buffer of size %d\n", net_device->recv_buf_size);
ret = -ENOMEM;
goto cleanup;
}
@@ -179,8 +181,8 @@ static int netvsc_init_recv_buf(struct hv_device *device)
net_device->recv_buf_size,
&net_device->recv_buf_gpadl_handle);
if (ret != 0) {
- dev_err(&device->device,
- "unable to establish receive buffer's gpadl");
+ netdev_err(ndev,
+ "unable to establish receive buffer's gpadl\n");
goto cleanup;
}
@@ -203,8 +205,8 @@ static int netvsc_init_recv_buf(struct hv_device *device)
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0) {
- dev_err(&device->device,
- "unable to send receive buffer's gpadl to netvsp");
+ netdev_err(ndev,
+ "unable to send receive buffer's gpadl to netvsp\n");
goto cleanup;
}
@@ -215,8 +217,8 @@ static int netvsc_init_recv_buf(struct hv_device *device)
/* Check the response */
if (init_packet->msg.v1_msg.
send_recv_buf_complete.status != NVSP_STAT_SUCCESS) {
- dev_err(&device->device, "Unable to complete receive buffer "
- "initialzation with NetVsp - status %d",
+ netdev_err(ndev, "Unable to complete receive buffer "
+ "initialization with NetVsp - status %d\n",
init_packet->msg.v1_msg.
send_recv_buf_complete.status);
ret = -EINVAL;
@@ -267,13 +269,12 @@ static int netvsc_connect_vsp(struct hv_device *device)
struct netvsc_device *net_device;
struct nvsp_message *init_packet;
int ndis_version;
+ struct net_device *ndev;
net_device = get_outbound_net_device(device);
- if (!net_device) {
- dev_err(&device->device, "unable to get net device..."
- "device being destroyed?");
+ if (!net_device)
return -ENODEV;
- }
+ ndev = net_device->ndev;
init_packet = &net_device->channel_init_pkt;
@@ -354,15 +355,15 @@ int netvsc_device_remove(struct hv_device *device)
struct hv_netvsc_packet *netvsc_packet, *pos;
unsigned long flags;
- net_device = (struct netvsc_device *)device->ext;
+ net_device = hv_get_drvdata(device);
spin_lock_irqsave(&device->channel->inbound_lock, flags);
net_device->destroy = true;
spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
/* Wait for all send completions */
while (atomic_read(&net_device->num_outstanding_sends)) {
- dev_err(&device->device,
- "waiting for %d requests to complete...",
+ dev_info(&device->device,
+ "waiting for %d requests to complete...\n",
atomic_read(&net_device->num_outstanding_sends));
udelay(100);
}
@@ -378,11 +379,14 @@ int netvsc_device_remove(struct hv_device *device)
*/
spin_lock_irqsave(&device->channel->inbound_lock, flags);
- device->ext = NULL;
+ hv_set_drvdata(device, NULL);
spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
- /* At this point, no one should be accessing netDevice except in here */
- dev_notice(&device->device, "net device safe to remove");
+ /*
+ * At this point, no one should be accessing net_device
+ * except in here
+ */
+ dev_notice(&device->device, "net device safe to remove\n");
/* Now, we can close the channel safely */
vmbus_close(device->channel);
@@ -404,13 +408,12 @@ static void netvsc_send_completion(struct hv_device *device,
struct netvsc_device *net_device;
struct nvsp_message *nvsp_packet;
struct hv_netvsc_packet *nvsc_packet;
+ struct net_device *ndev;
net_device = get_inbound_net_device(device);
- if (!net_device) {
- dev_err(&device->device, "unable to get net device..."
- "device being destroyed?");
+ if (!net_device)
return;
- }
+ ndev = net_device->ndev;
nvsp_packet = (struct nvsp_message *)((unsigned long)packet +
(packet->offset8 << 3));
@@ -436,8 +439,8 @@ static void netvsc_send_completion(struct hv_device *device,
atomic_dec(&net_device->num_outstanding_sends);
} else {
- dev_err(&device->device, "Unknown send completion packet type- "
- "%d received!!", nvsp_packet->hdr.msg_type);
+ netdev_err(ndev, "Unknown send completion packet type- "
+ "%d received!!\n", nvsp_packet->hdr.msg_type);
}
}
@@ -447,15 +450,13 @@ int netvsc_send(struct hv_device *device,
{
struct netvsc_device *net_device;
int ret = 0;
-
struct nvsp_message sendMessage;
+ struct net_device *ndev;
net_device = get_outbound_net_device(device);
- if (!net_device) {
- dev_err(&device->device, "net device (%p) shutting down..."
- "ignoring outbound packets", net_device);
+ if (!net_device)
return -ENODEV;
- }
+ ndev = net_device->ndev;
sendMessage.hdr.msg_type = NVSP_MSG1_TYPE_SEND_RNDIS_PKT;
if (packet->is_data_pkt) {
@@ -488,10 +489,11 @@ int netvsc_send(struct hv_device *device,
}
if (ret != 0)
- dev_err(&device->device, "Unable to send packet %p ret %d",
+ netdev_err(ndev, "Unable to send packet %p ret %d\n",
packet, ret);
+ else
+ atomic_inc(&net_device->num_outstanding_sends);
- atomic_inc(&net_device->num_outstanding_sends);
return ret;
}
@@ -501,6 +503,10 @@ static void netvsc_send_recv_completion(struct hv_device *device,
struct nvsp_message recvcompMessage;
int retries = 0;
int ret;
+ struct net_device *ndev;
+ struct netvsc_device *net_device = hv_get_drvdata(device);
+
+ ndev = net_device->ndev;
recvcompMessage.hdr.msg_type =
NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE;
@@ -520,20 +526,20 @@ retry_send_cmplt:
} else if (ret == -EAGAIN) {
/* no more room...wait a bit and attempt to retry 3 times */
retries++;
- dev_err(&device->device, "unable to send receive completion pkt"
- " (tid %llx)...retrying %d", transaction_id, retries);
+ netdev_err(ndev, "unable to send receive completion pkt"
+ " (tid %llx)...retrying %d\n", transaction_id, retries);
if (retries < 4) {
udelay(100);
goto retry_send_cmplt;
} else {
- dev_err(&device->device, "unable to send receive "
- "completion pkt (tid %llx)...give up retrying",
+ netdev_err(ndev, "unable to send receive "
+ "completion pkt (tid %llx)...give up retrying\n",
transaction_id);
}
} else {
- dev_err(&device->device, "unable to send receive "
- "completion pkt - %llx", transaction_id);
+ netdev_err(ndev, "unable to send receive "
+ "completion pkt - %llx\n", transaction_id);
}
}
@@ -546,6 +552,7 @@ static void netvsc_receive_completion(void *context)
u64 transaction_id = 0;
bool fsend_receive_comp = false;
unsigned long flags;
+ struct net_device *ndev;
/*
* Even though it seems logical to do a GetOutboundNetDevice() here to
@@ -553,11 +560,9 @@ static void netvsc_receive_completion(void *context)
* since we may have disable outbound traffic already.
*/
net_device = get_inbound_net_device(device);
- if (!net_device) {
- dev_err(&device->device, "unable to get net device..."
- "device being destroyed?");
+ if (!net_device)
return;
- }
+ ndev = net_device->ndev;
/* Overloading use of the lock. */
spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
@@ -600,22 +605,21 @@ static void netvsc_receive(struct hv_device *device,
int i, j;
int count = 0, bytes_remain = 0;
unsigned long flags;
+ struct net_device *ndev;
LIST_HEAD(listHead);
net_device = get_inbound_net_device(device);
- if (!net_device) {
- dev_err(&device->device, "unable to get net device..."
- "device being destroyed?");
+ if (!net_device)
return;
- }
+ ndev = net_device->ndev;
/*
* All inbound packets other than send completion should be xfer page
* packet
*/
if (packet->type != VM_PKT_DATA_USING_XFER_PAGES) {
- dev_err(&device->device, "Unknown packet type received - %d",
+ netdev_err(ndev, "Unknown packet type received - %d\n",
packet->type);
return;
}
@@ -626,16 +630,16 @@ static void netvsc_receive(struct hv_device *device,
/* Make sure this is a valid nvsp packet */
if (nvsp_packet->hdr.msg_type !=
NVSP_MSG1_TYPE_SEND_RNDIS_PKT) {
- dev_err(&device->device, "Unknown nvsp packet type received-"
- " %d", nvsp_packet->hdr.msg_type);
+ netdev_err(ndev, "Unknown nvsp packet type received-"
+ " %d\n", nvsp_packet->hdr.msg_type);
return;
}
vmxferpage_packet = (struct vmtransfer_page_packet_header *)packet;
if (vmxferpage_packet->xfer_pageset_id != NETVSC_RECEIVE_BUFFER_ID) {
- dev_err(&device->device, "Invalid xfer page set id - "
- "expecting %x got %x", NETVSC_RECEIVE_BUFFER_ID,
+ netdev_err(ndev, "Invalid xfer page set id - "
+ "expecting %x got %x\n", NETVSC_RECEIVE_BUFFER_ID,
vmxferpage_packet->xfer_pageset_id);
return;
}
@@ -660,8 +664,8 @@ static void netvsc_receive(struct hv_device *device,
* some of the xfer page packet ranges...
*/
if (count < 2) {
- dev_err(&device->device, "Got only %d netvsc pkt...needed "
- "%d pkts. Dropping this xfer page packet completely!",
+ netdev_err(ndev, "Got only %d netvsc pkt...needed "
+ "%d pkts. Dropping this xfer page packet completely!\n",
count, vmxferpage_packet->range_cnt + 1);
/* Return it to the freelist */
@@ -687,8 +691,8 @@ static void netvsc_receive(struct hv_device *device,
xferpage_packet->count = count - 1;
if (xferpage_packet->count != vmxferpage_packet->range_cnt) {
- dev_err(&device->device, "Needed %d netvsc pkts to satisy "
- "this xfer page...got %d",
+ netdev_err(ndev, "Needed %d netvsc pkts to satisfy "
+ "this xfer page...got %d\n",
vmxferpage_packet->range_cnt, xferpage_packet->count);
}
@@ -776,6 +780,7 @@ static void netvsc_channel_cb(void *context)
struct vmpacket_descriptor *desc;
unsigned char *buffer;
int bufferlen = NETVSC_PACKET_SIZE;
+ struct net_device *ndev;
packet = kzalloc(NETVSC_PACKET_SIZE * sizeof(unsigned char),
GFP_ATOMIC);
@@ -784,11 +789,9 @@ static void netvsc_channel_cb(void *context)
buffer = packet;
net_device = get_inbound_net_device(device);
- if (!net_device) {
- dev_err(&device->device, "net device (%p) shutting down..."
- "ignoring inbound packets", net_device);
+ if (!net_device)
goto out;
- }
+ ndev = net_device->ndev;
do {
ret = vmbus_recvpacket_raw(device->channel, buffer, bufferlen,
@@ -806,7 +809,7 @@ static void netvsc_channel_cb(void *context)
break;
default:
- dev_err(&device->device,
+ netdev_err(ndev,
"unhandled packet type %d, "
"tid %llx len %d\n",
desc->type, request_id,
@@ -835,9 +838,9 @@ static void netvsc_channel_cb(void *context)
buffer = kmalloc(bytes_recvd, GFP_ATOMIC);
if (buffer == NULL) {
/* Try again next time around */
- dev_err(&device->device,
+ netdev_err(ndev,
"unable to allocate buffer of size "
- "(%d)!!", bytes_recvd);
+ "(%d)!!\n", bytes_recvd);
break;
}
@@ -862,6 +865,7 @@ int netvsc_device_add(struct hv_device *device, void *additional_info)
((struct netvsc_device_info *)additional_info)->ring_size;
struct netvsc_device *net_device;
struct hv_netvsc_packet *packet, *pos;
+ struct net_device *ndev;
net_device = alloc_net_device(device);
if (!net_device) {
@@ -869,6 +873,15 @@ int netvsc_device_add(struct hv_device *device, void *additional_info)
goto cleanup;
}
+ /*
+ * Coming into this function, struct net_device * is
+ * registered as the driver private data.
+ * In alloc_net_device(), we register struct netvsc_device *
+ * as the driver private data and stash away struct net_device *
+ * in struct netvsc_device *.
+ */
+ ndev = net_device->ndev;
+
/* Initialize the NetVSC channel extension */
net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE;
spin_lock_init(&net_device->recv_pkt_list_lock);
@@ -893,18 +906,18 @@ int netvsc_device_add(struct hv_device *device, void *additional_info)
netvsc_channel_cb, device);
if (ret != 0) {
- dev_err(&device->device, "unable to open channel: %d", ret);
+ netdev_err(ndev, "unable to open channel: %d\n", ret);
goto cleanup;
}
/* Channel is opened */
- pr_info("hv_netvsc channel opened successfully");
+ pr_info("hv_netvsc channel opened successfully\n");
/* Connect with the NetVsp */
ret = netvsc_connect_vsp(device);
if (ret != 0) {
- dev_err(&device->device,
- "unable to connect to NetVSP - %d", ret);
+ netdev_err(ndev,
+ "unable to connect to NetVSP - %d\n", ret);
goto close;
}
diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c
index 90a3198c9978..c4461c471753 100644
--- a/drivers/staging/hv/netvsc_drv.c
+++ b/drivers/staging/hv/netvsc_drv.c
@@ -38,7 +38,6 @@
#include <net/sock.h>
#include <net/pkt_sched.h>
-#include "hyperv.h"
#include "hyperv_net.h"
struct net_device_context {
@@ -70,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;
}
@@ -141,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 +
@@ -191,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;
}
/*
@@ -203,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 "
@@ -215,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);
@@ -236,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"
@@ -291,7 +294,7 @@ int netvsc_recv_callback(struct hv_device *device_obj,
static void netvsc_get_drvinfo(struct net_device *net,
struct ethtool_drvinfo *info)
{
- strcpy(info->driver, "hv_netvsc");
+ strcpy(info->driver, KBUILD_MODNAME);
strcpy(info->version, HV_DRV_VERSION);
strcpy(info->fw_version, "N/A");
}
@@ -322,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;
@@ -346,22 +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);
- 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 */
@@ -373,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");
@@ -420,7 +432,7 @@ MODULE_DEVICE_TABLE(vmbus, id_table);
/* The one and only one */
static struct hv_driver netvsc_drv = {
- .name = "netvsc",
+ .name = KBUILD_MODNAME,
.id_table = id_table,
.probe = netvsc_probe,
.remove = netvsc_remove,
diff --git a/drivers/staging/hv/rndis_filter.c b/drivers/staging/hv/rndis_filter.c
index 6db48b92fe98..bafccb360041 100644
--- a/drivers/staging/hv/rndis_filter.c
+++ b/drivers/staging/hv/rndis_filter.c
@@ -27,7 +27,6 @@
#include <linux/if_ether.h>
#include <linux/netdevice.h>
-#include "hyperv.h"
#include "hyperv_net.h"
@@ -42,7 +41,7 @@ struct rndis_device {
struct netvsc_device *net_dev;
enum rndis_device_state state;
- u32 link_stat;
+ bool link_state;
atomic_t new_req_id;
spinlock_t request_lock;
@@ -142,7 +141,11 @@ static void put_rndis_request(struct rndis_device *dev,
static void dump_rndis_message(struct hv_device *hv_dev,
struct rndis_message *rndis_msg)
{
- struct net_device *netdev = dev_get_drvdata(&hv_dev->device);
+ struct net_device *netdev;
+ struct netvsc_device *net_device;
+
+ net_device = hv_get_drvdata(hv_dev);
+ netdev = net_device->ndev;
switch (rndis_msg->ndis_msg_type) {
case REMOTE_NDIS_PACKET_MSG:
@@ -250,6 +253,9 @@ static void rndis_filter_receive_response(struct rndis_device *dev,
struct rndis_request *request = NULL;
bool found = false;
unsigned long flags;
+ struct net_device *ndev;
+
+ ndev = dev->net_dev->ndev;
spin_lock_irqsave(&dev->request_lock, flags);
list_for_each_entry(request, &dev->req_list, list_ent) {
@@ -270,7 +276,7 @@ static void rndis_filter_receive_response(struct rndis_device *dev,
memcpy(&request->response_msg, resp,
resp->msg_len);
} else {
- dev_err(&dev->net_dev->dev->device,
+ netdev_err(ndev,
"rndis response buffer overflow "
"detected (size %u max %zu)\n",
resp->msg_len,
@@ -290,7 +296,7 @@ static void rndis_filter_receive_response(struct rndis_device *dev,
complete(&request->wait_event);
} else {
- dev_err(&dev->net_dev->dev->device,
+ netdev_err(ndev,
"no rndis request found for this response "
"(id 0x%x res type 0x%x)\n",
resp->msg.init_complete.req_id,
@@ -323,6 +329,7 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
{
struct rndis_packet *rndis_pkt;
u32 data_offset;
+ int i;
rndis_pkt = &msg->msg.pkt;
@@ -338,6 +345,15 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
pkt->page_buf[0].offset += data_offset;
pkt->page_buf[0].len -= data_offset;
+ /* Drop the 0th page, if rndis data go beyond page boundary */
+ if (pkt->page_buf[0].offset >= PAGE_SIZE) {
+ pkt->page_buf[1].offset = pkt->page_buf[0].offset - PAGE_SIZE;
+ pkt->page_buf[1].len -= pkt->page_buf[1].offset;
+ pkt->page_buf_cnt--;
+ for (i = 0; i < pkt->page_buf_cnt; i++)
+ pkt->page_buf[i] = pkt->page_buf[i+1];
+ }
+
pkt->is_data_pkt = true;
netvsc_recv_callback(dev->net_dev->dev, pkt);
@@ -346,24 +362,27 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
int rndis_filter_receive(struct hv_device *dev,
struct hv_netvsc_packet *pkt)
{
- struct netvsc_device *net_dev = dev->ext;
+ struct netvsc_device *net_dev = hv_get_drvdata(dev);
struct rndis_device *rndis_dev;
struct rndis_message rndis_msg;
struct rndis_message *rndis_hdr;
+ struct net_device *ndev;
if (!net_dev)
return -EINVAL;
+ ndev = net_dev->ndev;
+
/* Make sure the rndis device state is initialized */
if (!net_dev->extension) {
- dev_err(&dev->device, "got rndis message but no rndis device - "
+ netdev_err(ndev, "got rndis message but no rndis device - "
"dropping this message!\n");
return -ENODEV;
}
rndis_dev = (struct rndis_device *)net_dev->extension;
if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
- dev_err(&dev->device, "got rndis message but rndis device "
+ netdev_err(ndev, "got rndis message but rndis device "
"uninitialized...dropping this message!\n");
return -ENODEV;
}
@@ -377,7 +396,7 @@ int rndis_filter_receive(struct hv_device *dev,
/* Make sure we got a valid rndis message */
if ((rndis_hdr->ndis_msg_type != REMOTE_NDIS_PACKET_MSG) &&
(rndis_hdr->msg_len > sizeof(struct rndis_message))) {
- dev_err(&dev->device, "incoming rndis message buffer overflow "
+ netdev_err(ndev, "incoming rndis message buffer overflow "
"detected (got %u, max %zu)..marking it an error!\n",
rndis_hdr->msg_len,
sizeof(struct rndis_message));
@@ -410,7 +429,7 @@ int rndis_filter_receive(struct hv_device *dev,
rndis_filter_receive_indicate_status(rndis_dev, &rndis_msg);
break;
default:
- dev_err(&dev->device,
+ netdev_err(ndev,
"unhandled rndis message (type %u len %u)\n",
rndis_msg.ndis_msg_type,
rndis_msg.msg_len);
@@ -492,10 +511,15 @@ static int rndis_filter_query_device_mac(struct rndis_device *dev)
static int rndis_filter_query_device_link_status(struct rndis_device *dev)
{
u32 size = sizeof(u32);
+ u32 link_status;
+ int ret;
- return rndis_filter_query_device(dev,
+ ret = rndis_filter_query_device(dev,
RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
- &dev->link_stat, &size);
+ &link_status, &size);
+ dev->link_state = (link_status != 0) ? true : false;
+
+ return ret;
}
static int rndis_filter_set_packet_filter(struct rndis_device *dev,
@@ -506,6 +530,9 @@ static int rndis_filter_set_packet_filter(struct rndis_device *dev,
struct rndis_set_complete *set_complete;
u32 status;
int ret, t;
+ struct net_device *ndev;
+
+ ndev = dev->net_dev->ndev;
request = get_rndis_request(dev, REMOTE_NDIS_SET_MSG,
RNDIS_MESSAGE_SIZE(struct rndis_set_request) +
@@ -531,7 +558,7 @@ static int rndis_filter_set_packet_filter(struct rndis_device *dev,
t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
if (t == 0) {
- dev_err(&dev->net_dev->dev->device,
+ netdev_err(ndev,
"timeout before we got a set response...\n");
/*
* We can't deallocate the request since we may still receive a
@@ -667,12 +694,12 @@ int rndis_filter_device_add(struct hv_device *dev,
void *additional_info)
{
int ret;
- struct netvsc_device *netDevice;
- struct rndis_device *rndisDevice;
- struct netvsc_device_info *deviceInfo = additional_info;
+ struct netvsc_device *net_device;
+ struct rndis_device *rndis_device;
+ struct netvsc_device_info *device_info = additional_info;
- rndisDevice = get_rndis_device();
- if (!rndisDevice)
+ rndis_device = get_rndis_device();
+ if (!rndis_device)
return -ENODEV;
/*
@@ -682,19 +709,19 @@ int rndis_filter_device_add(struct hv_device *dev,
*/
ret = netvsc_device_add(dev, additional_info);
if (ret != 0) {
- kfree(rndisDevice);
+ kfree(rndis_device);
return ret;
}
/* Initialize the rndis device */
- netDevice = dev->ext;
+ net_device = hv_get_drvdata(dev);
- netDevice->extension = rndisDevice;
- rndisDevice->net_dev = netDevice;
+ net_device->extension = rndis_device;
+ rndis_device->net_dev = net_device;
/* Send the rndis initialization message */
- ret = rndis_filter_init_device(rndisDevice);
+ ret = rndis_filter_init_device(rndis_device);
if (ret != 0) {
/*
* TODO: If rndis init failed, we will need to shut down the
@@ -703,29 +730,29 @@ int rndis_filter_device_add(struct hv_device *dev,
}
/* Get the mac address */
- ret = rndis_filter_query_device_mac(rndisDevice);
+ ret = rndis_filter_query_device_mac(rndis_device);
if (ret != 0) {
/*
* TODO: shutdown rndis device and the channel
*/
}
- memcpy(deviceInfo->mac_adr, rndisDevice->hw_mac_adr, ETH_ALEN);
+ memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN);
- rndis_filter_query_device_link_status(rndisDevice);
+ rndis_filter_query_device_link_status(rndis_device);
- deviceInfo->link_state = rndisDevice->link_stat;
+ device_info->link_state = rndis_device->link_state;
- dev_info(&dev->device, "Device MAC %pM link state %s",
- rndisDevice->hw_mac_adr,
- ((deviceInfo->link_state) ? ("down\n") : ("up\n")));
+ dev_info(&dev->device, "Device MAC %pM link state %s\n",
+ rndis_device->hw_mac_adr,
+ device_info->link_state ? "down" : "up");
return ret;
}
void rndis_filter_device_remove(struct hv_device *dev)
{
- struct netvsc_device *net_dev = dev->ext;
+ struct netvsc_device *net_dev = hv_get_drvdata(dev);
struct rndis_device *rndis_dev = net_dev->extension;
/* Halt and release the rndis device */
@@ -740,17 +767,17 @@ void rndis_filter_device_remove(struct hv_device *dev)
int rndis_filter_open(struct hv_device *dev)
{
- struct netvsc_device *netDevice = dev->ext;
+ struct netvsc_device *net_device = hv_get_drvdata(dev);
- if (!netDevice)
+ if (!net_device)
return -EINVAL;
- return rndis_filter_open_device(netDevice->extension);
+ return rndis_filter_open_device(net_device->extension);
}
int rndis_filter_close(struct hv_device *dev)
{
- struct netvsc_device *netDevice = dev->ext;
+ struct netvsc_device *netDevice = hv_get_drvdata(dev);
if (!netDevice)
return -EINVAL;
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 3686d1048e31..c6d810aadf7d 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -232,6 +232,7 @@ struct vstor_packet {
#define STORVSC_MAX_LUNS_PER_TARGET 64
#define STORVSC_MAX_TARGETS 1
#define STORVSC_MAX_CHANNELS 1
+#define STORVSC_MAX_CMD_LEN 16
struct hv_storvsc_request;
@@ -244,7 +245,6 @@ enum storvsc_request_type {
struct hv_storvsc_request {
- struct hv_storvsc_request *request;
struct hv_device *device;
/* Synchronize the request/response if needed */
@@ -259,14 +259,6 @@ struct hv_storvsc_request {
};
-struct storvsc_device_info {
- u32 ring_buffer_size;
- unsigned int port_number;
- unsigned char path_id;
- unsigned char target_id;
-};
-
-
/* A storvsc device is a device object that contains a vmbus channel */
struct storvsc_device {
struct hv_device *device;
@@ -274,6 +266,7 @@ struct storvsc_device {
bool destroy;
bool drain_notify;
atomic_t num_outstanding_req;
+ struct Scsi_Host *host;
wait_queue_head_t waiting_to_drain;
@@ -314,7 +307,7 @@ static inline struct storvsc_device *get_out_stor_device(
{
struct storvsc_device *stor_device;
- stor_device = (struct storvsc_device *)device->ext;
+ stor_device = hv_get_drvdata(device);
if (stor_device && stor_device->destroy)
stor_device = NULL;
@@ -331,29 +324,12 @@ static inline void storvsc_wait_to_drain(struct storvsc_device *dev)
dev->drain_notify = false;
}
-static inline struct storvsc_device *alloc_stor_device(struct hv_device *device)
-{
- struct storvsc_device *stor_device;
-
- stor_device = kzalloc(sizeof(struct storvsc_device), GFP_KERNEL);
- if (!stor_device)
- return NULL;
-
- stor_device->destroy = false;
- init_waitqueue_head(&stor_device->waiting_to_drain);
- stor_device->device = device;
- device->ext = stor_device;
-
- return stor_device;
-}
-
-
static inline struct storvsc_device *get_in_stor_device(
struct hv_device *device)
{
struct storvsc_device *stor_device;
- stor_device = (struct storvsc_device *)device->ext;
+ stor_device = hv_get_drvdata(device);
if (!stor_device)
goto get_in_err;
@@ -505,8 +481,7 @@ static void storvsc_on_io_completion(struct hv_device *device,
struct storvsc_device *stor_device;
struct vstor_packet *stor_pkt;
- stor_device = (struct storvsc_device *)device->ext;
-
+ stor_device = hv_get_drvdata(device);
stor_pkt = &request->vstor_packet;
/*
@@ -650,47 +625,12 @@ static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size)
return ret;
}
-static int storvsc_dev_add(struct hv_device *device,
- void *additional_info)
-{
- struct storvsc_device *stor_device;
- struct storvsc_device_info *device_info;
- int ret = 0;
-
- device_info = (struct storvsc_device_info *)additional_info;
- stor_device = alloc_stor_device(device);
- if (!stor_device)
- return -ENOMEM;
-
- /* Save the channel properties to our storvsc channel */
-
- /*
- * If we support more than 1 scsi channel, we need to set the
- * port number here to the scsi channel but how do we get the
- * scsi channel prior to the bus scan.
- *
- * The host does not support this.
- */
-
- stor_device->port_number = device_info->port_number;
- /* Send it back up */
- ret = storvsc_connect_to_vsp(device, device_info->ring_buffer_size);
- if (ret) {
- kfree(stor_device);
- return ret;
- }
- device_info->path_id = stor_device->path_id;
- device_info->target_id = stor_device->target_id;
-
- return ret;
-}
-
static int storvsc_dev_remove(struct hv_device *device)
{
struct storvsc_device *stor_device;
unsigned long flags;
- stor_device = (struct storvsc_device *)device->ext;
+ stor_device = hv_get_drvdata(device);
spin_lock_irqsave(&device->channel->inbound_lock, flags);
stor_device->destroy = true;
@@ -712,7 +652,7 @@ static int storvsc_dev_remove(struct hv_device *device)
* allow incoming packets.
*/
spin_lock_irqsave(&device->channel->inbound_lock, flags);
- device->ext = NULL;
+ hv_set_drvdata(device, NULL);
spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
/* Close the channel */
@@ -1022,7 +962,8 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
static int storvsc_remove(struct hv_device *dev)
{
- struct Scsi_Host *host = dev_get_drvdata(&dev->device);
+ struct storvsc_device *stor_device = hv_get_drvdata(dev);
+ struct Scsi_Host *host = stor_device->host;
struct hv_host_device *host_dev =
(struct hv_host_device *)host->hostdata;
@@ -1164,7 +1105,7 @@ static void storvsc_command_completion(struct hv_storvsc_request *request)
if (scmnd->result) {
if (scsi_normalize_sense(scmnd->sense_buffer,
SCSI_SENSE_BUFFERSIZE, &sense_hdr))
- scsi_print_sense_hdr("storvsc", &sense_hdr);
+ scsi_print_sense_hdr(KBUILD_MODNAME, &sense_hdr);
}
scsi_set_resid(scmnd,
@@ -1181,6 +1122,22 @@ static void storvsc_command_completion(struct hv_storvsc_request *request)
kmem_cache_free(host_dev->request_pool, cmd_request);
}
+static bool storvsc_check_scsi_cmd(struct scsi_cmnd *scmnd)
+{
+ bool allowed = true;
+ u8 scsi_op = scmnd->cmnd[0];
+
+ switch (scsi_op) {
+ /* smartd sends this command, which will offline the device */
+ case SET_WINDOW:
+ scmnd->result = DID_ERROR << 16;
+ allowed = false;
+ break;
+ default:
+ break;
+ }
+ return allowed;
+}
/*
* storvsc_queuecommand - Initiate command processing
@@ -1200,6 +1157,10 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
unsigned int sg_count = 0;
struct vmscsi_request *vm_srb;
+ if (storvsc_check_scsi_cmd(scmnd) == false) {
+ done(scmnd);
+ return 0;
+ }
/* If retrying, no need to prep the cmd */
if (scmnd->host_scribble) {
@@ -1333,7 +1294,8 @@ static DEF_SCSI_QCMD(storvsc_queuecommand)
/* Scsi driver */
static struct scsi_host_template scsi_driver = {
.module = THIS_MODULE,
- .name = "storvsc_host_t",
+ .name = KBUILD_MODNAME,
+ .proc_name = KBUILD_MODNAME,
.bios_param = storvsc_get_chs,
.queuecommand = storvsc_queuecommand,
.eh_host_reset_handler = storvsc_host_reset_handler,
@@ -1358,17 +1320,20 @@ static struct scsi_host_template scsi_driver = {
.dma_boundary = PAGE_SIZE-1,
};
-/*
- * The storvsc_probe function assumes that the IDE guid
- * is the second entry.
- */
+enum {
+ SCSI_GUID,
+ IDE_GUID,
+};
+
static const struct hv_vmbus_device_id id_table[] = {
/* SCSI guid */
{ VMBUS_DEVICE(0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
- 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f) },
+ 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f)
+ .driver_data = SCSI_GUID },
/* IDE guid */
{ VMBUS_DEVICE(0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
- 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5) },
+ 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5)
+ .driver_data = IDE_GUID },
{ },
};
@@ -1379,28 +1344,22 @@ MODULE_DEVICE_TABLE(vmbus, id_table);
* storvsc_probe - Add a new device for this driver
*/
-static int storvsc_probe(struct hv_device *device)
+static int storvsc_probe(struct hv_device *device,
+ const struct hv_vmbus_device_id *dev_id)
{
int ret;
struct Scsi_Host *host;
struct hv_host_device *host_dev;
- struct storvsc_device_info device_info;
- bool dev_is_ide;
+ bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false);
int path = 0;
int target = 0;
-
- if (!memcmp(&device->dev_type.b, id_table[1].guid, sizeof(uuid_le)))
- dev_is_ide = true;
- else
- dev_is_ide = false;
+ struct storvsc_device *stor_device;
host = scsi_host_alloc(&scsi_driver,
sizeof(struct hv_host_device));
if (!host)
return -ENOMEM;
- dev_set_drvdata(&device->device, host);
-
host_dev = (struct hv_host_device *)host->hostdata;
memset(host_dev, 0, sizeof(struct hv_host_device));
@@ -1417,22 +1376,33 @@ static int storvsc_probe(struct hv_device *device)
return -ENOMEM;
}
- device_info.port_number = host->host_no;
- device_info.ring_buffer_size = storvsc_ringbuffer_size;
- /* Call to the vsc driver to add the device */
- ret = storvsc_dev_add(device, (void *)&device_info);
+ stor_device = kzalloc(sizeof(struct storvsc_device), GFP_KERNEL);
+ if (!stor_device) {
+ kmem_cache_destroy(host_dev->request_pool);
+ scsi_host_put(host);
+ return -ENOMEM;
+ }
+
+ stor_device->destroy = false;
+ init_waitqueue_head(&stor_device->waiting_to_drain);
+ stor_device->device = device;
+ stor_device->host = host;
+ hv_set_drvdata(device, stor_device);
- if (ret != 0) {
+ stor_device->port_number = host->host_no;
+ ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size);
+ if (ret) {
kmem_cache_destroy(host_dev->request_pool);
scsi_host_put(host);
- return -ENODEV;
+ kfree(stor_device);
+ return ret;
}
if (dev_is_ide)
storvsc_get_ide_info(device, &target, &path);
- host_dev->path = device_info.path_id;
- host_dev->target = device_info.target_id;
+ host_dev->path = stor_device->path_id;
+ host_dev->target = stor_device->target_id;
/* max # of devices per target */
host->max_lun = STORVSC_MAX_LUNS_PER_TARGET;
@@ -1440,6 +1410,8 @@ static int storvsc_probe(struct hv_device *device)
host->max_id = STORVSC_MAX_TARGETS;
/* max # of channels */
host->max_channel = STORVSC_MAX_CHANNELS - 1;
+ /* max cmd length */
+ host->max_cmd_len = STORVSC_MAX_CMD_LEN;
/* Register the HBA and start the scsi bus scan */
ret = scsi_add_host(host, &device->device);
@@ -1467,7 +1439,7 @@ err_out:
/* The one and only one */
static struct hv_driver storvsc_drv = {
- .name = "storvsc",
+ .name = KBUILD_MODNAME,
.id_table = id_table,
.probe = storvsc_probe,
.remove = storvsc_remove,
@@ -1504,5 +1476,7 @@ static void __exit storvsc_drv_exit(void)
MODULE_LICENSE("GPL");
MODULE_VERSION(HV_DRV_VERSION);
MODULE_DESCRIPTION("Microsoft Hyper-V virtual storage driver");
+/* bind to old driver to simplify upgrade path */
+MODULE_ALIAS("hv_blkvsc");
module_init(storvsc_drv_init);
module_exit(storvsc_drv_exit);
diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c
index 8fb56668fd66..d2562afcce4c 100644
--- a/drivers/staging/hv/vmbus_drv.c
+++ b/drivers/staging/hv/vmbus_drv.c
@@ -112,101 +112,105 @@ static ssize_t vmbus_show_device_attr(struct device *dev,
char *buf)
{
struct hv_device *hv_dev = device_to_hv_device(dev);
- struct hv_device_info device_info;
+ struct hv_device_info *device_info;
char alias_name[VMBUS_ALIAS_LEN + 1];
+ int ret = 0;
- memset(&device_info, 0, sizeof(struct hv_device_info));
+ device_info = kzalloc(sizeof(struct hv_device_info), GFP_KERNEL);
+ if (!device_info)
+ return ret;
- get_channel_info(hv_dev, &device_info);
+ get_channel_info(hv_dev, device_info);
if (!strcmp(dev_attr->attr.name, "class_id")) {
- return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
+ ret = sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
"%02x%02x%02x%02x%02x%02x%02x%02x}\n",
- device_info.chn_type.b[3],
- device_info.chn_type.b[2],
- device_info.chn_type.b[1],
- device_info.chn_type.b[0],
- device_info.chn_type.b[5],
- device_info.chn_type.b[4],
- device_info.chn_type.b[7],
- device_info.chn_type.b[6],
- device_info.chn_type.b[8],
- device_info.chn_type.b[9],
- device_info.chn_type.b[10],
- device_info.chn_type.b[11],
- device_info.chn_type.b[12],
- device_info.chn_type.b[13],
- device_info.chn_type.b[14],
- device_info.chn_type.b[15]);
+ device_info->chn_type.b[3],
+ device_info->chn_type.b[2],
+ device_info->chn_type.b[1],
+ device_info->chn_type.b[0],
+ device_info->chn_type.b[5],
+ device_info->chn_type.b[4],
+ device_info->chn_type.b[7],
+ device_info->chn_type.b[6],
+ device_info->chn_type.b[8],
+ device_info->chn_type.b[9],
+ device_info->chn_type.b[10],
+ device_info->chn_type.b[11],
+ device_info->chn_type.b[12],
+ device_info->chn_type.b[13],
+ device_info->chn_type.b[14],
+ device_info->chn_type.b[15]);
} else if (!strcmp(dev_attr->attr.name, "device_id")) {
- return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
+ ret = sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
"%02x%02x%02x%02x%02x%02x%02x%02x}\n",
- device_info.chn_instance.b[3],
- device_info.chn_instance.b[2],
- device_info.chn_instance.b[1],
- device_info.chn_instance.b[0],
- device_info.chn_instance.b[5],
- device_info.chn_instance.b[4],
- device_info.chn_instance.b[7],
- device_info.chn_instance.b[6],
- device_info.chn_instance.b[8],
- device_info.chn_instance.b[9],
- device_info.chn_instance.b[10],
- device_info.chn_instance.b[11],
- device_info.chn_instance.b[12],
- device_info.chn_instance.b[13],
- device_info.chn_instance.b[14],
- device_info.chn_instance.b[15]);
+ device_info->chn_instance.b[3],
+ device_info->chn_instance.b[2],
+ device_info->chn_instance.b[1],
+ device_info->chn_instance.b[0],
+ device_info->chn_instance.b[5],
+ device_info->chn_instance.b[4],
+ device_info->chn_instance.b[7],
+ device_info->chn_instance.b[6],
+ device_info->chn_instance.b[8],
+ device_info->chn_instance.b[9],
+ device_info->chn_instance.b[10],
+ device_info->chn_instance.b[11],
+ device_info->chn_instance.b[12],
+ device_info->chn_instance.b[13],
+ device_info->chn_instance.b[14],
+ device_info->chn_instance.b[15]);
} else if (!strcmp(dev_attr->attr.name, "modalias")) {
print_alias_name(hv_dev, alias_name);
- return sprintf(buf, "vmbus:%s\n", alias_name);
+ ret = sprintf(buf, "vmbus:%s\n", alias_name);
} else if (!strcmp(dev_attr->attr.name, "state")) {
- return sprintf(buf, "%d\n", device_info.chn_state);
+ ret = sprintf(buf, "%d\n", device_info->chn_state);
} else if (!strcmp(dev_attr->attr.name, "id")) {
- return sprintf(buf, "%d\n", device_info.chn_id);
+ ret = sprintf(buf, "%d\n", device_info->chn_id);
} else if (!strcmp(dev_attr->attr.name, "out_intr_mask")) {
- return sprintf(buf, "%d\n", device_info.outbound.int_mask);
+ ret = sprintf(buf, "%d\n", device_info->outbound.int_mask);
} else if (!strcmp(dev_attr->attr.name, "out_read_index")) {
- return sprintf(buf, "%d\n", device_info.outbound.read_idx);
+ ret = sprintf(buf, "%d\n", device_info->outbound.read_idx);
} else if (!strcmp(dev_attr->attr.name, "out_write_index")) {
- return sprintf(buf, "%d\n", device_info.outbound.write_idx);
+ ret = sprintf(buf, "%d\n", device_info->outbound.write_idx);
} else if (!strcmp(dev_attr->attr.name, "out_read_bytes_avail")) {
- return sprintf(buf, "%d\n",
- device_info.outbound.bytes_avail_toread);
+ ret = sprintf(buf, "%d\n",
+ device_info->outbound.bytes_avail_toread);
} else if (!strcmp(dev_attr->attr.name, "out_write_bytes_avail")) {
- return sprintf(buf, "%d\n",
- device_info.outbound.bytes_avail_towrite);
+ ret = sprintf(buf, "%d\n",
+ device_info->outbound.bytes_avail_towrite);
} else if (!strcmp(dev_attr->attr.name, "in_intr_mask")) {
- return sprintf(buf, "%d\n", device_info.inbound.int_mask);
+ ret = sprintf(buf, "%d\n", device_info->inbound.int_mask);
} else if (!strcmp(dev_attr->attr.name, "in_read_index")) {
- return sprintf(buf, "%d\n", device_info.inbound.read_idx);
+ ret = sprintf(buf, "%d\n", device_info->inbound.read_idx);
} else if (!strcmp(dev_attr->attr.name, "in_write_index")) {
- return sprintf(buf, "%d\n", device_info.inbound.write_idx);
+ ret = sprintf(buf, "%d\n", device_info->inbound.write_idx);
} else if (!strcmp(dev_attr->attr.name, "in_read_bytes_avail")) {
- return sprintf(buf, "%d\n",
- device_info.inbound.bytes_avail_toread);
+ ret = sprintf(buf, "%d\n",
+ device_info->inbound.bytes_avail_toread);
} else if (!strcmp(dev_attr->attr.name, "in_write_bytes_avail")) {
- return sprintf(buf, "%d\n",
- device_info.inbound.bytes_avail_towrite);
+ ret = sprintf(buf, "%d\n",
+ device_info->inbound.bytes_avail_towrite);
} else if (!strcmp(dev_attr->attr.name, "monitor_id")) {
- return sprintf(buf, "%d\n", device_info.monitor_id);
+ ret = sprintf(buf, "%d\n", device_info->monitor_id);
} else if (!strcmp(dev_attr->attr.name, "server_monitor_pending")) {
- return sprintf(buf, "%d\n", device_info.server_monitor_pending);
+ ret = sprintf(buf, "%d\n", device_info->server_monitor_pending);
} else if (!strcmp(dev_attr->attr.name, "server_monitor_latency")) {
- return sprintf(buf, "%d\n", device_info.server_monitor_latency);
+ ret = sprintf(buf, "%d\n", device_info->server_monitor_latency);
} else if (!strcmp(dev_attr->attr.name, "server_monitor_conn_id")) {
- return sprintf(buf, "%d\n",
- device_info.server_monitor_conn_id);
+ ret = sprintf(buf, "%d\n",
+ device_info->server_monitor_conn_id);
} else if (!strcmp(dev_attr->attr.name, "client_monitor_pending")) {
- return sprintf(buf, "%d\n", device_info.client_monitor_pending);
+ ret = sprintf(buf, "%d\n", device_info->client_monitor_pending);
} else if (!strcmp(dev_attr->attr.name, "client_monitor_latency")) {
- return sprintf(buf, "%d\n", device_info.client_monitor_latency);
+ ret = sprintf(buf, "%d\n", device_info->client_monitor_latency);
} else if (!strcmp(dev_attr->attr.name, "client_monitor_conn_id")) {
- return sprintf(buf, "%d\n",
- device_info.client_monitor_conn_id);
- } else {
- return 0;
+ ret = sprintf(buf, "%d\n",
+ device_info->client_monitor_conn_id);
}
+
+ kfree(device_info);
+ return ret;
}
/* Set up per device attributes in /sys/bus/vmbus/devices/<bus device> */
@@ -272,6 +276,22 @@ static inline bool is_null_guid(const __u8 *guid)
return true;
}
+/*
+ * Return a matching hv_vmbus_device_id pointer.
+ * If there is no match, return NULL.
+ */
+static const struct hv_vmbus_device_id *hv_vmbus_get_id(
+ const struct hv_vmbus_device_id *id,
+ __u8 *guid)
+{
+ for (; !is_null_guid(id->guid); id++)
+ if (!memcmp(&id->guid, guid, sizeof(uuid_le)))
+ return id;
+
+ return NULL;
+}
+
+
/*
* vmbus_match - Attempt to match the specified device to the specified driver
@@ -280,12 +300,9 @@ static int vmbus_match(struct device *device, struct device_driver *driver)
{
struct hv_driver *drv = drv_to_hv_drv(driver);
struct hv_device *hv_dev = device_to_hv_device(device);
- const struct hv_vmbus_device_id *id_array = drv->id_table;
- for (; !is_null_guid(id_array->guid); id_array++)
- if (!memcmp(&id_array->guid, &hv_dev->dev_type.b,
- sizeof(uuid_le)))
- return 1;
+ if (hv_vmbus_get_id(drv->id_table, hv_dev->dev_type.b))
+ return 1;
return 0;
}
@@ -299,9 +316,11 @@ static int vmbus_probe(struct device *child_device)
struct hv_driver *drv =
drv_to_hv_drv(child_device->driver);
struct hv_device *dev = device_to_hv_device(child_device);
+ const struct hv_vmbus_device_id *dev_id;
+ dev_id = hv_vmbus_get_id(drv->id_table, dev->dev_type.b);
if (drv->probe) {
- ret = drv->probe(dev);
+ ret = drv->probe(dev, dev_id);
if (ret != 0)
pr_err("probe failed for device %s (%d)\n",
dev_name(child_device), ret);
@@ -319,22 +338,14 @@ static int vmbus_probe(struct device *child_device)
*/
static int vmbus_remove(struct device *child_device)
{
- int ret;
- struct hv_driver *drv;
-
+ struct hv_driver *drv = drv_to_hv_drv(child_device->driver);
struct hv_device *dev = device_to_hv_device(child_device);
- if (child_device->driver) {
- drv = drv_to_hv_drv(child_device->driver);
-
- if (drv->remove) {
- ret = drv->remove(dev);
- } else {
- pr_err("remove not set for driver %s\n",
- dev_name(child_device));
- ret = -ENODEV;
- }
- }
+ if (drv->remove)
+ drv->remove(dev);
+ else
+ pr_err("remove not set for driver %s\n",
+ dev_name(child_device));
return 0;
}
@@ -453,14 +464,11 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
union hv_synic_event_flags *event;
bool handled = false;
- page_addr = hv_context.synic_message_page[cpu];
- msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
-
- /* Check if there are actual msgs to be process */
- if (msg->header.message_type != HVMSG_NONE) {
- handled = true;
- tasklet_schedule(&msg_dpc);
- }
+ /*
+ * Check for events before checking for messages. This is the order
+ * in which events and messages are checked in Windows guests on
+ * Hyper-V, and the Windows team suggested we do the same.
+ */
page_addr = hv_context.synic_event_page[cpu];
event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT;
@@ -471,6 +479,15 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
tasklet_schedule(&event_dpc);
}
+ page_addr = hv_context.synic_message_page[cpu];
+ msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
+
+ /* Check if there are actual msgs to be processed */
+ if (msg->header.message_type != HVMSG_NONE) {
+ handled = true;
+ tasklet_schedule(&msg_dpc);
+ }
+
if (handled)
return IRQ_HANDLED;
else
@@ -503,7 +520,7 @@ static int vmbus_bus_init(int irq)
ret = bus_register(&hv_bus);
if (ret)
- return ret;
+ goto err_cleanup;
ret = request_irq(irq, vmbus_isr, IRQF_SAMPLE_RANDOM,
driver_name, hv_acpi_dev);
@@ -511,10 +528,7 @@ static int vmbus_bus_init(int irq)
if (ret != 0) {
pr_err("Unable to request IRQ %d\n",
irq);
-
- bus_unregister(&hv_bus);
-
- return ret;
+ goto err_unregister;
}
vector = IRQ0_VECTOR + irq;
@@ -525,16 +539,23 @@ static int vmbus_bus_init(int irq)
*/
on_each_cpu(hv_synic_init, (void *)&vector, 1);
ret = vmbus_connect();
- if (ret) {
- free_irq(irq, hv_acpi_dev);
- bus_unregister(&hv_bus);
- return ret;
- }
-
+ if (ret)
+ goto err_irq;
vmbus_request_offers();
return 0;
+
+err_irq:
+ free_irq(irq, hv_acpi_dev);
+
+err_unregister:
+ bus_unregister(&hv_bus);
+
+err_cleanup:
+ hv_cleanup();
+
+ return ret;
}
/**
@@ -584,10 +605,10 @@ void vmbus_driver_unregister(struct hv_driver *hv_driver)
EXPORT_SYMBOL_GPL(vmbus_driver_unregister);
/*
- * vmbus_child_device_create - Creates and registers a new child device
+ * vmbus_device_create - Creates and registers a new child device
* on the vmbus.
*/
-struct hv_device *vmbus_child_device_create(uuid_le *type,
+struct hv_device *vmbus_device_create(uuid_le *type,
uuid_le *instance,
struct vmbus_channel *channel)
{
@@ -609,9 +630,9 @@ struct hv_device *vmbus_child_device_create(uuid_le *type,
}
/*
- * vmbus_child_device_register - Register the child device
+ * vmbus_device_register - Register the child device
*/
-int vmbus_child_device_register(struct hv_device *child_device_obj)
+int vmbus_device_register(struct hv_device *child_device_obj)
{
int ret = 0;
@@ -640,10 +661,10 @@ int vmbus_child_device_register(struct hv_device *child_device_obj)
}
/*
- * vmbus_child_device_unregister - Remove the specified child device
+ * vmbus_device_unregister - Remove the specified child device
* from the vmbus.
*/
-void vmbus_child_device_unregister(struct hv_device *device_obj)
+void vmbus_device_unregister(struct hv_device *device_obj)
{
/*
* Kick off the process of unregistering the device.