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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel




[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux