[PATCH 2/3] drivers:hv Convert VMBus and its descendants to PnP

From: Jake Oshins
Date: Tue Feb 17 2015 - 13:27:53 EST


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 = &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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/