Merge tag 'char-misc-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregk...
[sfrench/cifs-2.6.git] / drivers / hv / vmbus_drv.c
index 077bb1bdac34ef4ed87c65c7bf0d204fd42001b4..8e53a3c2607e00c07e066b28f11c056aef4a6abd 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/device.h>
-#include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/sysctl.h>
 #include <linux/slab.h>
@@ -44,6 +43,12 @@ static struct tasklet_struct msg_dpc;
 static struct completion probe_event;
 static int irq;
 
+struct resource hyperv_mmio = {
+       .name  = "hyperv mmio",
+       .flags = IORESOURCE_MEM,
+};
+EXPORT_SYMBOL_GPL(hyperv_mmio);
+
 static int vmbus_exists(void)
 {
        if (hv_acpi_dev == NULL)
@@ -558,9 +563,6 @@ static struct bus_type  hv_bus = {
        .dev_groups =           vmbus_groups,
 };
 
-static const char *driver_name = "hyperv";
-
-
 struct onmessage_work_context {
        struct work_struct work;
        struct hv_message msg;
@@ -619,7 +621,7 @@ static void vmbus_on_msg_dpc(unsigned long data)
        }
 }
 
-static irqreturn_t vmbus_isr(int irq, void *dev_id)
+static void vmbus_isr(void)
 {
        int cpu = smp_processor_id();
        void *page_addr;
@@ -629,7 +631,7 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
 
        page_addr = hv_context.synic_event_page[cpu];
        if (page_addr == NULL)
-               return IRQ_NONE;
+               return;
 
        event = (union hv_synic_event_flags *)page_addr +
                                         VMBUS_MESSAGE_SINT;
@@ -665,28 +667,8 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
        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;
+       if (msg->header.message_type != HVMSG_NONE)
                tasklet_schedule(&msg_dpc);
-       }
-
-       if (handled)
-               return IRQ_HANDLED;
-       else
-               return IRQ_NONE;
-}
-
-/*
- * vmbus interrupt flow handler:
- * vmbus interrupts can concurrently occur on multiple CPUs and
- * can be handled concurrently.
- */
-
-static void vmbus_flow_handler(unsigned int irq, struct irq_desc *desc)
-{
-       kstat_incr_irqs_this_cpu(irq, desc);
-
-       desc->action->handler(irq, desc->action->dev_id);
 }
 
 /*
@@ -715,25 +697,7 @@ static int vmbus_bus_init(int irq)
        if (ret)
                goto err_cleanup;
 
-       ret = request_irq(irq, vmbus_isr, 0, driver_name, hv_acpi_dev);
-
-       if (ret != 0) {
-               pr_err("Unable to request IRQ %d\n",
-                          irq);
-               goto err_unregister;
-       }
-
-       /*
-        * Vmbus interrupts can be handled concurrently on
-        * different CPUs. Establish an appropriate interrupt flow
-        * handler that can support this model.
-        */
-       irq_set_handler(irq, vmbus_flow_handler);
-
-       /*
-        * Register our interrupt handler.
-        */
-       hv_register_vmbus_handler(irq, vmbus_isr);
+       hv_setup_vmbus_irq(vmbus_isr);
 
        ret = hv_synic_alloc();
        if (ret)
@@ -753,9 +717,8 @@ static int vmbus_bus_init(int irq)
 
 err_alloc:
        hv_synic_free();
-       free_irq(irq, hv_acpi_dev);
+       hv_remove_vmbus_irq();
 
-err_unregister:
        bus_unregister(&hv_bus);
 
 err_cleanup:
@@ -886,18 +849,21 @@ void vmbus_device_unregister(struct hv_device *device_obj)
 
 
 /*
- * VMBUS is an acpi enumerated device. Get the the IRQ information
- * from DSDT.
+ * VMBUS is an acpi enumerated device. Get the the information we
+ * need from DSDT.
  */
 
-static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *irq)
+static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
 {
+       switch (res->type) {
+       case ACPI_RESOURCE_TYPE_IRQ:
+               irq = res->data.irq.interrupts[0];
+               break;
 
-       if (res->type == ACPI_RESOURCE_TYPE_IRQ) {
-               struct acpi_resource_irq *irqp;
-               irqp = &res->data.irq;
-
-               *((unsigned int *)irq) = irqp->interrupts[0];
+       case ACPI_RESOURCE_TYPE_ADDRESS64:
+               hyperv_mmio.start = res->data.address64.minimum;
+               hyperv_mmio.end = res->data.address64.maximum;
+               break;
        }
 
        return AE_OK;
@@ -906,18 +872,34 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *irq)
 static int vmbus_acpi_add(struct acpi_device *device)
 {
        acpi_status result;
+       int ret_val = -ENODEV;
 
        hv_acpi_dev = device;
 
        result = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
-                                       vmbus_walk_resources, &irq);
+                                       vmbus_walk_resources, NULL);
 
-       if (ACPI_FAILURE(result)) {
-               complete(&probe_event);
-               return -ENODEV;
+       if (ACPI_FAILURE(result))
+               goto acpi_walk_err;
+       /*
+        * The parent of the vmbus acpi device (Gen2 firmware) is the VMOD that
+        * has the mmio ranges. Get that.
+        */
+       if (device->parent) {
+               result = acpi_walk_resources(device->parent->handle,
+                                       METHOD_NAME__CRS,
+                                       vmbus_walk_resources, NULL);
+
+               if (ACPI_FAILURE(result))
+                       goto acpi_walk_err;
+               if (hyperv_mmio.start && hyperv_mmio.end)
+                       request_resource(&iomem_resource, &hyperv_mmio);
        }
+       ret_val = 0;
+
+acpi_walk_err:
        complete(&probe_event);
-       return 0;
+       return ret_val;
 }
 
 static const struct acpi_device_id vmbus_acpi_device_ids[] = {
@@ -947,7 +929,6 @@ static int __init hv_acpi_init(void)
        /*
         * Get irq resources first.
         */
-
        ret = acpi_bus_register_driver(&vmbus_acpi_driver);
 
        if (ret)
@@ -978,8 +959,7 @@ cleanup:
 
 static void __exit vmbus_exit(void)
 {
-
-       free_irq(irq, hv_acpi_dev);
+       hv_remove_vmbus_irq();
        vmbus_free_channels();
        bus_unregister(&hv_bus);
        hv_cleanup();