This patch adds paravirtual "devices" discovered by hv_vmbus to the
pnp layer, and adds any memory-mapped I/O space claims expressed
by those paravirtual devices to the "options" for that device in pnp.
This allows the pnp layer to choose the memory-mapped I/O space that
those paravirtual devices use.

Signed-off-by: Jake Oshins <ja...@microsoft.com>
---
 drivers/hid/hid-hyperv.c              |  6 +--
 drivers/hv/channel_mgmt.c             |  5 ++-
 drivers/hv/hyperv_vmbus.h             |  1 +
 drivers/hv/vmbus_drv.c                | 69 +++++++++++++++++++++++++++--------
 drivers/input/serio/hyperv-keyboard.c | 24 ++++++------
 drivers/net/hyperv/netvsc.c           |  5 ++-
 drivers/net/hyperv/netvsc_drv.c       |  4 +-
 drivers/net/hyperv/rndis_filter.c     |  4 +-
 drivers/scsi/storvsc_drv.c            |  2 +-
 drivers/video/fbdev/hyperv_fb.c       |  2 +-
 include/linux/hyperv.h                | 15 ++++++--
 11 files changed, 93 insertions(+), 44 deletions(-)

diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index 6039f07..0cf9105 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -309,7 +309,7 @@ static void mousevsc_on_receive(struct hv_device *device,
                hid_input_report(input_dev->hid_device, HID_INPUT_REPORT,
                                 input_dev->input_buf, len, 1);
 
-               pm_wakeup_event(&input_dev->device->device, 0);
+               pm_wakeup_event(&input_dev->device->pnp_dev->dev, 0);
 
                break;
        default:
@@ -552,7 +552,7 @@ static int mousevsc_probe(struct hv_device *device,
                goto probe_err2;
        }
 
-       device_init_wakeup(&device->device, true);
+       device_init_wakeup(&device->pnp_dev->dev, true);
 
        input_dev->connected = true;
        input_dev->init_complete = true;
@@ -576,7 +576,7 @@ static int mousevsc_remove(struct hv_device *dev)
 {
        struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
 
-       device_init_wakeup(&dev->device, false);
+       device_init_wakeup(&dev->pnp_dev->dev, false);
        vmbus_close(dev->channel);
        hid_hw_stop(input_dev->hid_device);
        hid_destroy_device(input_dev->hid_device);
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 3736f71..fcb1be8 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -218,8 +218,8 @@ static void vmbus_process_rescind_offer(struct work_struct 
*work)
        struct vmbus_channel_relid_released msg;
        struct device *dev;
 
-       if (channel->device_obj) {
-               dev = get_device(&channel->device_obj->device);
+       if (channel->device_obj && channel->device_obj->pnp_dev) {
+               dev = get_device(&channel->device_obj->pnp_dev->dev);
                if (dev) {
                        vmbus_device_unregister(channel->device_obj);
                        put_device(dev);
@@ -359,6 +359,7 @@ static void vmbus_process_offer(struct work_struct *work)
        newchannel->device_obj = vmbus_device_create(
                &newchannel->offermsg.offer.if_type,
                &newchannel->offermsg.offer.if_instance,
+               newchannel->offermsg.offer.mmio_megabytes,
                newchannel);
        if (!newchannel->device_obj)
                goto err_free_chan;
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 44b1c94..73b9bc0 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -676,6 +676,7 @@ extern struct vmbus_connection vmbus_connection;
 
 struct hv_device *vmbus_device_create(const uuid_le *type,
                                      const uuid_le *instance,
+                                     u16 mmio_mb,
                                      struct vmbus_channel *channel);
 
 int vmbus_device_register(struct hv_device *child_device_obj);
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index f518b8d7..5d85ef3 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -549,10 +549,13 @@ static void vmbus_device_release(struct device *device)
 {
        struct hv_device *hv_dev = device_to_hv_device(device);
 
-       kfree(hv_dev);
+       if (hv_dev->pnp_dev)
+               free_pnp_descendant(hv_dev->pnp_dev);
 
+       kfree(hv_dev);
 }
 
+
 /* The one and only one */
 static struct bus_type  hv_bus = {
        .name =         "vmbus",
@@ -814,6 +817,7 @@ EXPORT_SYMBOL_GPL(vmbus_driver_unregister);
  */
 struct hv_device *vmbus_device_create(const uuid_le *type,
                                      const uuid_le *instance,
+                                     u16 mmio_mb,
                                      struct vmbus_channel *channel)
 {
        struct hv_device *child_device_obj;
@@ -825,6 +829,7 @@ struct hv_device *vmbus_device_create(const uuid_le *type,
        }
 
        child_device_obj->channel = channel;
+       child_device_obj->mmio_mb = mmio_mb;
        memcpy(&child_device_obj->dev_type, type, sizeof(uuid_le));
        memcpy(&child_device_obj->dev_instance, instance,
               sizeof(uuid_le));
@@ -839,27 +844,59 @@ struct hv_device *vmbus_device_create(const uuid_le *type,
 int vmbus_device_register(struct hv_device *child_device_obj)
 {
        int ret = 0;
-
+       char device_id[40];
+       bool added = FALSE;
+       resource_size_t bytes = child_device_obj->mmio_mb * 0x100000;
        static atomic_t device_num = ATOMIC_INIT(0);
 
-       dev_set_name(&child_device_obj->device, "vmbus_0_%d",
+
+       sprintf(device_id, "{%pUl}", child_device_obj->dev_instance.b);
+       child_device_obj->pnp_dev = alloc_pnp_descendant(device_id);
+       if (!child_device_obj->pnp_dev)
+               return -ENOMEM;
+
+       dev_set_name(&child_device_obj->pnp_dev->dev, "vmbus_0_%d",
                     atomic_inc_return(&device_num));
 
-       child_device_obj->device.bus = &hv_bus;
-       child_device_obj->device.parent = &hv_acpi_dev->dev;
-       child_device_obj->device.release = vmbus_device_release;
+       child_device_obj->pnp_dev->data = child_device_obj;
+       child_device_obj->pnp_dev->dev.bus = &hv_bus;
+       child_device_obj->pnp_dev->dev.parent = &hv_acpi_dev->dev;
+       child_device_obj->pnp_dev->dev.release = vmbus_device_release;
 
-       /*
-        * Register with the LDM. This will kick off the driver/device
-        * binding...which will eventually call vmbus_match() and vmbus_probe()
-        */
-       ret = device_register(&child_device_obj->device);
+       if (bytes) {
+               /*
+                * Add a memory option that is aligned on the length.  All VMBus
+                * channels can tolerate their memory regions going above
+                * the 32-bit line.
+                */
+               ret = pnp_descendant_memory_option(child_device_obj->pnp_dev,
+                                                  (u64)0x100000000,
+                                                  (u64)(-1),
+                                                  bytes,
+                                                  bytes,
+                                                  IORESOURCE_MEM_WRITEABLE);
+               if (ret)
+                       goto register_exit;
+       }
 
+       ret = pnp_add_descendant(child_device_obj->pnp_dev);
        if (ret)
+               goto register_exit;
+
+       added = TRUE;
+
+       ret = pnp_activate_dev(child_device_obj->pnp_dev);
+
+register_exit:
+
+       if (ret) {
+               if (added)
+                       pnp_remove_descendant(child_device_obj->pnp_dev);
+               free_pnp_descendant(child_device_obj->pnp_dev);
                pr_err("Unable to register child device\n");
-       else
+       } else
                pr_debug("child device %s registered\n",
-                       dev_name(&child_device_obj->device));
+                        dev_name(&child_device_obj->pnp_dev->dev));
 
        return ret;
 }
@@ -870,14 +907,16 @@ int vmbus_device_register(struct hv_device 
*child_device_obj)
  */
 void vmbus_device_unregister(struct hv_device *device_obj)
 {
+       pnp_disable_dev(device_obj->pnp_dev);
+
        pr_debug("child device %s unregistered\n",
-               dev_name(&device_obj->device));
+                dev_name(&device_obj->pnp_dev->dev));
 
        /*
         * Kick off the process of unregistering the device.
         * This will call vmbus_remove() and eventually vmbus_device_release()
         */
-       device_unregister(&device_obj->device);
+       pnp_remove_descendant(device_obj->pnp_dev);
 }
 
 
diff --git a/drivers/input/serio/hyperv-keyboard.c 
b/drivers/input/serio/hyperv-keyboard.c
index e74e5d6..0115e23 100644
--- a/drivers/input/serio/hyperv-keyboard.c
+++ b/drivers/input/serio/hyperv-keyboard.c
@@ -124,7 +124,7 @@ static void hv_kbd_on_receive(struct hv_device *hv_dev,
                 * goes away).
                 */
                if (msg_length < sizeof(struct synth_kbd_protocol_response)) {
-                       dev_err(&hv_dev->device,
+                       dev_err(&hv_dev->pnp_dev->dev,
                                "Illegal protocol response packet (len: %d)\n",
                                msg_length);
                        break;
@@ -143,7 +143,7 @@ static void hv_kbd_on_receive(struct hv_device *hv_dev,
                 * goes away).
                 */
                if (msg_length < sizeof(struct  synth_kbd_keystroke)) {
-                       dev_err(&hv_dev->device,
+                       dev_err(&hv_dev->pnp_dev->dev,
                                "Illegal keyboard event packet (len: %d)\n",
                                msg_length);
                        break;
@@ -177,12 +177,12 @@ static void hv_kbd_on_receive(struct hv_device *hv_dev,
                 * state because the Enter-UP can trigger a wakeup at once.
                 */
                if (!(info & IS_BREAK))
-                       pm_wakeup_event(&hv_dev->device, 0);
+                       pm_wakeup_event(&hv_dev->pnp_dev->dev, 0);
 
                break;
 
        default:
-               dev_err(&hv_dev->device,
+               dev_err(&hv_dev->pnp_dev->dev,
                        "unhandled message type %d\n", msg_type);
        }
 }
@@ -225,7 +225,7 @@ static void hv_kbd_handle_received_packet(struct hv_device 
*hv_dev,
                         * Drop the packet and hope
                         * the problem magically goes away.
                         */
-                       dev_err(&hv_dev->device,
+                       dev_err(&hv_dev->pnp_dev->dev,
                                "Illegal packet (type: %d, tid: %llx, size: 
%d)\n",
                                desc->type, req_id, msg_sz);
                        break;
@@ -236,7 +236,7 @@ static void hv_kbd_handle_received_packet(struct hv_device 
*hv_dev,
                break;
 
        default:
-               dev_err(&hv_dev->device,
+               dev_err(&hv_dev->pnp_dev->dev,
                        "unhandled packet type %d, tid %llx len %d\n",
                        desc->type, req_id, bytes_recvd);
                break;
@@ -309,7 +309,7 @@ static int hv_kbd_connect_to_vsp(struct hv_device *hv_dev)
        response = &kbd_dev->protocol_resp;
        proto_status = __le32_to_cpu(response->proto_status);
        if (!(proto_status & PROTOCOL_ACCEPTED)) {
-               dev_err(&hv_dev->device,
+               dev_err(&hv_dev->pnp_dev->dev,
                        "synth_kbd protocol request failed (version %d)\n",
                        SYNTH_KBD_VERSION);
                return -ENODEV;
@@ -360,12 +360,12 @@ static int hv_kbd_probe(struct hv_device *hv_dev,
        init_completion(&kbd_dev->wait_event);
        hv_set_drvdata(hv_dev, kbd_dev);
 
-       hv_serio->dev.parent  = &hv_dev->device;
+       hv_serio->dev.parent  = &hv_dev->pnp_dev->dev;
        hv_serio->id.type = SERIO_8042_XL;
        hv_serio->port_data = kbd_dev;
-       strlcpy(hv_serio->name, dev_name(&hv_dev->device),
+       strlcpy(hv_serio->name, dev_name(&hv_dev->pnp_dev->dev),
                sizeof(hv_serio->name));
-       strlcpy(hv_serio->phys, dev_name(&hv_dev->device),
+       strlcpy(hv_serio->phys, dev_name(&hv_dev->pnp_dev->dev),
                sizeof(hv_serio->phys));
 
        hv_serio->start = hv_kbd_start;
@@ -386,7 +386,7 @@ static int hv_kbd_probe(struct hv_device *hv_dev,
 
        serio_register_port(kbd_dev->hv_serio);
 
-       device_init_wakeup(&hv_dev->device, true);
+       device_init_wakeup(&hv_dev->pnp_dev->dev, true);
 
        return 0;
 
@@ -402,7 +402,7 @@ static int hv_kbd_remove(struct hv_device *hv_dev)
 {
        struct hv_kbd_dev *kbd_dev = hv_get_drvdata(hv_dev);
 
-       device_init_wakeup(&hv_dev->device, false);
+       device_init_wakeup(&hv_dev->pnp_dev->dev, false);
        serio_unregister_port(kbd_dev->hv_serio);
        vmbus_close(hv_dev->channel);
        kfree(kbd_dev);
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 208eb05..00ecfba 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -379,7 +379,8 @@ static int netvsc_init_buf(struct hv_device *device)
        net_device->send_section_cnt =
                net_device->send_buf_size/net_device->send_section_size;
 
-       dev_info(&device->device, "Send section size: %d, Section count:%d\n",
+       dev_info(&device->pnp_dev->dev,
+                "Send section size: %d, Section count:%d\n",
                 net_device->send_section_size, net_device->send_section_cnt);
 
        /* Setup state for managing the send buffer. */
@@ -557,7 +558,7 @@ int netvsc_device_remove(struct hv_device *device)
         * At this point, no one should be accessing net_device
         * except in here
         */
-       dev_notice(&device->device, "net device safe to remove\n");
+       dev_notice(&device->pnp_dev->dev, "net device safe to remove\n");
 
        /* Now, we can close the channel safely */
        vmbus_close(device->channel);
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 15d82ed..37f867b 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -853,7 +853,7 @@ static int netvsc_probe(struct hv_device *dev,
                        NETIF_F_IP_CSUM | NETIF_F_TSO;
 
        net->ethtool_ops = &ethtool_ops;
-       SET_NETDEV_DEV(net, &dev->device);
+       SET_NETDEV_DEV(net, &dev->pnp_dev->dev);
 
        /* Notify the netvsc driver of the new device */
        device_info.ring_size = ring_size;
@@ -892,7 +892,7 @@ static int netvsc_remove(struct hv_device *dev)
        net = net_device->ndev;
 
        if (net == NULL) {
-               dev_err(&dev->device, "No net device to remove\n");
+               dev_err(&dev->pnp_dev->dev, "No net device to remove\n");
                return 0;
        }
 
diff --git a/drivers/net/hyperv/rndis_filter.c 
b/drivers/net/hyperv/rndis_filter.c
index 7816d98..ae9f626 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -1079,7 +1079,7 @@ int rndis_filter_device_add(struct hv_device *dev,
 
        device_info->link_state = rndis_device->link_state;
 
-       dev_info(&dev->device, "Device MAC %pM link state %s\n",
+       dev_info(&dev->pnp_dev->dev, "Device MAC %pM link state %s\n",
                 rndis_device->hw_mac_adr,
                 device_info->link_state ? "down" : "up");
 
@@ -1103,7 +1103,7 @@ int rndis_filter_device_add(struct hv_device *dev,
                                         NETVSC_PACKET_SIZE);
        if (!net_device->sub_cb_buf) {
                net_device->num_chn = 1;
-               dev_info(&dev->device, "No memory for subchannels.\n");
+               dev_info(&dev->pnp_dev->dev, "No memory for subchannels.\n");
                goto out;
        }
 
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index efc6e44..1f15a26b 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -1781,7 +1781,7 @@ static int storvsc_probe(struct hv_device *device,
        host->max_cmd_len = STORVSC_MAX_CMD_LEN;
 
        /* Register the HBA and start the scsi bus scan */
-       ret = scsi_add_host(host, &device->device);
+       ret = scsi_add_host(host, &device->pnp_dev->dev);
        if (ret != 0)
                goto err_out2;
 
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index 4254336..69ea59b 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -772,7 +772,7 @@ static int hvfb_probe(struct hv_device *hdev,
        struct hvfb_par *par;
        int ret;
 
-       info = framebuffer_alloc(sizeof(struct hvfb_par), &hdev->device);
+       info = framebuffer_alloc(sizeof(struct hvfb_par), &hdev->pnp_dev->dev);
        if (!info) {
                pr_err("No memory for framebuffer info\n");
                return -ENOMEM;
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 5a2ba67..796cc32 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -35,6 +35,7 @@
 #include <linux/completion.h>
 #include <linux/device.h>
 #include <linux/mod_devicetable.h>
+#include <linux/pnp.h>
 
 
 #define MAX_PAGE_BUFFER_COUNT                          32
@@ -928,7 +929,11 @@ struct hv_device {
        /* the device instance id of this device */
        uuid_le dev_instance;
 
-       struct device device;
+       /* the amount of memory address space that should be
+          reserved for this channel, in megabytes */
+       u16 mmio_mb;
+
+       struct pnp_dev *pnp_dev;
 
        struct vmbus_channel *channel;
 };
@@ -936,7 +941,9 @@ struct hv_device {
 
 static inline struct hv_device *device_to_hv_device(struct device *d)
 {
-       return container_of(d, struct hv_device, device);
+       struct pnp_dev *pnp_dev = container_of(d, struct pnp_dev, dev);
+
+       return (struct hv_device *)(pnp_dev->data);
 }
 
 static inline struct hv_driver *drv_to_hv_drv(struct device_driver *d)
@@ -946,12 +953,12 @@ static inline struct hv_driver *drv_to_hv_drv(struct 
device_driver *d)
 
 static inline void hv_set_drvdata(struct hv_device *dev, void *data)
 {
-       dev_set_drvdata(&dev->device, data);
+       dev_set_drvdata(&dev->pnp_dev->dev, data);
 }
 
 static inline void *hv_get_drvdata(struct hv_device *dev)
 {
-       return dev_get_drvdata(&dev->device);
+       return dev_get_drvdata(&dev->pnp_dev->dev);
 }
 
 /* Vmbus interface */
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to