Merge tag 'md/4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shli/md
[cascardo/linux.git] / drivers / hv / vmbus_drv.c
index 328e4c3..64713ff 100644 (file)
@@ -45,7 +45,6 @@
 
 static struct acpi_device  *hv_acpi_dev;
 
-static struct tasklet_struct msg_dpc;
 static struct completion probe_event;
 
 
@@ -477,6 +476,24 @@ static ssize_t channel_vp_mapping_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(channel_vp_mapping);
 
+static ssize_t vendor_show(struct device *dev,
+                          struct device_attribute *dev_attr,
+                          char *buf)
+{
+       struct hv_device *hv_dev = device_to_hv_device(dev);
+       return sprintf(buf, "0x%x\n", hv_dev->vendor_id);
+}
+static DEVICE_ATTR_RO(vendor);
+
+static ssize_t device_show(struct device *dev,
+                          struct device_attribute *dev_attr,
+                          char *buf)
+{
+       struct hv_device *hv_dev = device_to_hv_device(dev);
+       return sprintf(buf, "0x%x\n", hv_dev->device_id);
+}
+static DEVICE_ATTR_RO(device);
+
 /* Set up per device attributes in /sys/bus/vmbus/devices/<bus device> */
 static struct attribute *vmbus_attrs[] = {
        &dev_attr_id.attr,
@@ -502,6 +519,8 @@ static struct attribute *vmbus_attrs[] = {
        &dev_attr_in_read_bytes_avail.attr,
        &dev_attr_in_write_bytes_avail.attr,
        &dev_attr_channel_vp_mapping.attr,
+       &dev_attr_vendor.attr,
+       &dev_attr_device.attr,
        NULL,
 };
 ATTRIBUTE_GROUPS(vmbus);
@@ -562,6 +581,10 @@ 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);
 
+       /* The hv_sock driver handles all hv_sock offers. */
+       if (is_hvsock_channel(hv_dev->channel))
+               return drv->hvsock;
+
        if (hv_vmbus_get_id(drv->id_table, &hv_dev->dev_type))
                return 1;
 
@@ -685,28 +708,10 @@ static void hv_process_timer_expiration(struct hv_message *msg, int cpu)
        if (dev->event_handler)
                dev->event_handler(dev);
 
-       msg->header.message_type = HVMSG_NONE;
-
-       /*
-        * Make sure the write to MessageType (ie set to
-        * HVMSG_NONE) happens before we read the
-        * MessagePending and EOMing. Otherwise, the EOMing
-        * will not deliver any more messages since there is
-        * no empty slot
-        */
-       mb();
-
-       if (msg->header.message_flags.msg_pending) {
-               /*
-                * This will cause message queue rescan to
-                * possibly deliver another msg from the
-                * hypervisor
-                */
-               wrmsrl(HV_X64_MSR_EOM, 0);
-       }
+       vmbus_signal_eom(msg);
 }
 
-static void vmbus_on_msg_dpc(unsigned long data)
+void vmbus_on_msg_dpc(unsigned long data)
 {
        int cpu = smp_processor_id();
        void *page_addr = hv_context.synic_message_page[cpu];
@@ -716,52 +721,32 @@ static void vmbus_on_msg_dpc(unsigned long data)
        struct vmbus_channel_message_table_entry *entry;
        struct onmessage_work_context *ctx;
 
-       while (1) {
-               if (msg->header.message_type == HVMSG_NONE)
-                       /* no msg */
-                       break;
+       if (msg->header.message_type == HVMSG_NONE)
+               /* no msg */
+               return;
 
-               hdr = (struct vmbus_channel_message_header *)msg->u.payload;
+       hdr = (struct vmbus_channel_message_header *)msg->u.payload;
 
-               if (hdr->msgtype >= CHANNELMSG_COUNT) {
-                       WARN_ONCE(1, "unknown msgtype=%d\n", hdr->msgtype);
-                       goto msg_handled;
-               }
+       if (hdr->msgtype >= CHANNELMSG_COUNT) {
+               WARN_ONCE(1, "unknown msgtype=%d\n", hdr->msgtype);
+               goto msg_handled;
+       }
 
-               entry = &channel_message_table[hdr->msgtype];
-               if (entry->handler_type == VMHT_BLOCKING) {
-                       ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
-                       if (ctx == NULL)
-                               continue;
+       entry = &channel_message_table[hdr->msgtype];
+       if (entry->handler_type == VMHT_BLOCKING) {
+               ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
+               if (ctx == NULL)
+                       return;
 
-                       INIT_WORK(&ctx->work, vmbus_onmessage_work);
-                       memcpy(&ctx->msg, msg, sizeof(*msg));
+               INIT_WORK(&ctx->work, vmbus_onmessage_work);
+               memcpy(&ctx->msg, msg, sizeof(*msg));
 
-                       queue_work(vmbus_connection.work_queue, &ctx->work);
-               } else
-                       entry->message_handler(hdr);
+               queue_work(vmbus_connection.work_queue, &ctx->work);
+       } else
+               entry->message_handler(hdr);
 
 msg_handled:
-               msg->header.message_type = HVMSG_NONE;
-
-               /*
-                * Make sure the write to MessageType (ie set to
-                * HVMSG_NONE) happens before we read the
-                * MessagePending and EOMing. Otherwise, the EOMing
-                * will not deliver any more messages since there is
-                * no empty slot
-                */
-               mb();
-
-               if (msg->header.message_flags.msg_pending) {
-                       /*
-                        * This will cause message queue rescan to
-                        * possibly deliver another msg from the
-                        * hypervisor
-                        */
-                       wrmsrl(HV_X64_MSR_EOM, 0);
-               }
-       }
+       vmbus_signal_eom(msg);
 }
 
 static void vmbus_isr(void)
@@ -814,7 +799,7 @@ static void vmbus_isr(void)
                if (msg->header.message_type == HVMSG_TIMER_EXPIRED)
                        hv_process_timer_expiration(msg, cpu);
                else
-                       tasklet_schedule(&msg_dpc);
+                       tasklet_schedule(hv_context.msg_dpc[cpu]);
        }
 }
 
@@ -838,8 +823,6 @@ static int vmbus_bus_init(void)
                return ret;
        }
 
-       tasklet_init(&msg_dpc, vmbus_on_msg_dpc, 0);
-
        ret = bus_register(&hv_bus);
        if (ret)
                goto err_cleanup;
@@ -957,6 +940,7 @@ struct hv_device *vmbus_device_create(const uuid_le *type,
        memcpy(&child_device_obj->dev_type, type, sizeof(uuid_le));
        memcpy(&child_device_obj->dev_instance, instance,
               sizeof(uuid_le));
+       child_device_obj->vendor_id = 0x1414; /* MSFT vendor ID */
 
 
        return child_device_obj;
@@ -1268,7 +1252,7 @@ static void hv_kexec_handler(void)
        int cpu;
 
        hv_synic_clockevents_cleanup();
-       vmbus_initiate_unload();
+       vmbus_initiate_unload(false);
        for_each_online_cpu(cpu)
                smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1);
        hv_cleanup();
@@ -1276,7 +1260,7 @@ static void hv_kexec_handler(void)
 
 static void hv_crash_handler(struct pt_regs *regs)
 {
-       vmbus_initiate_unload();
+       vmbus_initiate_unload(true);
        /*
         * In crash handler we can't schedule synic cleanup for all CPUs,
         * doing the cleanup for current CPU only. This should be sufficient
@@ -1334,7 +1318,8 @@ static void __exit vmbus_exit(void)
        hv_synic_clockevents_cleanup();
        vmbus_disconnect();
        hv_remove_vmbus_irq();
-       tasklet_kill(&msg_dpc);
+       for_each_online_cpu(cpu)
+               tasklet_kill(hv_context.msg_dpc[cpu]);
        vmbus_free_channels();
        if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) {
                unregister_die_notifier(&hyperv_die_block);