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 <jakeo@xxxxxxxxxxxxx> --- 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 = ðtool_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 _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel