drivers:pnp Add support for descendants claiming memory address space
Subsystems (9)
PATCH 1/3 drivers:pnp Add support for descendants claiming memory address space
This patch adds some wrapper functions in the pnp layer. The intent is to allow memory address space claims by devices which are descendants (a child or grandchild of) a device which is already part of the pnp layer. This allows a device to make a resource claim that doesn't conflict with its "aunts" and "uncles."
This is useful in a Hyper-V VM because some paravirtual "devices" need memory-mapped I/O space, and their aunts and uncles can be PCI devices. Furthermore, the hypervisor expresses the possible memory address combinations for the devices in the VM through the ACPI namespace. The paravirtual devices need to suballocate from the ACPI nodes, and they need to avoid conflicting with choices that the Linux PCI code makes about the PCI devices in the VM.
It might seem like this should be done in the platform layer rather than the pnp layer, but the platform layer assumes that the configuration of the devices in the machine are static, or at least expressed by firmware in a static fashion. The nature of a Hyper-V VM is that new devices can be added while the machine is running, and the potential configurations for them are expressed as part of the paravirtual communications channel. This much more naturally aligns with the pnp layer.
--- drivers/pnp/Makefile | 2 +- drivers/pnp/base.h | 2 + drivers/pnp/core.c | 1 + drivers/pnp/descendant.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pnp.h | 23 ++++++++++ 5 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 drivers/pnp/descendant.c
drivers/pnp/Makefile +1 -1
@@ -4,7 +4,7 @@ obj-y := pnp.o -pnp-y := core.o card.o driver.o resource.o manager.o support.o interface.o quirks.o +pnp-y := core.o card.o driver.o resource.o manager.o support.o interface.o quirks.o descendant.o obj-$(CONFIG_PNPACPI) += pnpacpi/ obj-$(CONFIG_PNPBIOS) += pnpbios/
drivers/pnp/base.h +2 -0
@@ -175,6 +175,8 @@ struct pnp_resource *pnp_add_bus_resource(struct pnp_dev *dev,resource_size_t start, resource_size_t end); +int __init pnpdescendant_init (void ); +extern int pnp_debug;#if defined(CONFIG_PNP_DEBUG_MESSAGES )
drivers/pnp/core.c +1 -0
@@ -212,6 +212,7 @@ void __pnp_remove_device(struct pnp_dev *dev)static int __init pnp_init (void ) { +pnpdescendant_init ();return bus_register (&pnp_bus_type); }
drivers/pnp/descendant.c new file +117 -0
117 lines not on this page · raw message
include/linux/pnp.h +23 -0
@@ -477,6 +477,15 @@ int compare_pnp_id(struct pnp_id *pos, const char *id);int pnp_register_driver (struct pnp_driver *drv);void pnp_unregister_driver (struct pnp_driver *drv); +/* descendant support */ +struct pnp_dev *alloc_pnp_descendant (const char *pnpid); +void free_pnp_descendant (struct pnp_dev *dev); +int pnp_add_descendant (struct pnp_dev *dev); +void pnp_remove_descendant (struct pnp_dev *dev); +int pnp_descendant_memory_option (struct pnp_dev *dev,resource_size_t min, +resource_size_t max,resource_size_t alignment, +resource_size_t size,unsigned char flags); +#else /* device management */
@@ -508,6 +517,20 @@ static inline int compare_pnp_id(struct pnp_id *pos, const char *id) { return -Estatic inline int pnp_register_driver (struct pnp_driver *drv) {return -ENODEV ; }static inline void pnp_unregister_driver (struct pnp_driver *drv) { } +/* descendant support */ +static inline struct pnp_dev *alloc_pnp_descendant (const char *pnpid) +{return NULL ; } +static inline void free_pnp_descendant (struct pnp_dev *dev) { } +static inline int pnp_add_descendant (struct pnp_dev *dev) {return -ENODEV ; } +static inline void pnp_remove_descendant (struct pnp_dev *dev) { } +static inline int pnp_descendant_memory_option (struct pnp_dev *dev, +resource_size_t min, +resource_size_t max, +resource_size_t alignment, +resource_size_t size, +unsigned char flags) +{return -ENODEV ; } +#endif /* CONFIG_PNP */ #endif /* _LINUX_PNP_H */
Signature · 1 line
1.9.1
PATCH 2/3 drivers:hv Convert VMBus and its descendants to PnP
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.
--- 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(-)
drivers/hid/hid-hyperv.c +3 -3
@@ -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);
drivers/hv/channel_mgmt.c +3 -2
@@ -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;
drivers/hv/hyperv_vmbus.h +1 -0
@@ -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);
drivers/hv/vmbus_drv.c +54 -15
117 lines not on this page · raw message
drivers/input/serio/hyperv-keyboard.c +12 -12
@@ -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);
drivers/net/hyperv/netvsc.c +3 -2
@@ -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);
drivers/net/hyperv/netvsc_drv.c +2 -2
@@ -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 ; }
drivers/net/hyperv/rndis_filter.c +2 -2
@@ -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; }
drivers/scsi/storvsc_drv.c +1 -1
@@ -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;
drivers/video/fbdev/hyperv_fb.c +1 -1
@@ -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 ;
include/linux/hyperv.h +11 -4
@@ -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 */
Signature · 1 line
1.9.1
Re: [PATCH 2/3] drivers:hv Convert VMBus and its descendants to PnP
Quoted 14 lines · Jake Oshins
drivers/hv/vmbus_drv.c +12
-0+ 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);
drivers/hv/vmbus_drv.c struct hv_device *vmbus_device_create(const uuid_le *type, · line 902
Quoted 10 lines
drivers/hv/vmbus_drv.c +3
-2+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; }
This error handling is horribly ugly and has a bug. Please, read my essay on how to do error handling properly.
https://plus.google.com/106378716002406849458/posts/dnanfhQ4mHQ
1) Don't do "One Err" style error handling.
2) Don't twist the success path and the error paths together.
3) Don't use the "added" variable.
4) Don't initialize "ret" at the start of the function.
5) Don't forget to undo pnp_descendant_memory_option()
It should look something like:
return 0;
err_remove_desc:
pnp_remove_descendant(child_device_obj->pnp_dev); err_remove_option: if (bytes) remove_whatever(); err_free_desc: free_pnp_descendant(child_device_obj->pnp_dev); return ret;
regards,
dan carpenter
RE: [PATCH 2/3] drivers:hv Convert VMBus and its descendants to PnP
Quoted 60 lines
-----Original Message-----
From: Dan Carpenter [mailto:[email protected]]
Sent: Wednesday, February 18, 2015 2:24 AM
To: Jake Oshins
Cc: [email protected]; [email protected]; KY Srinivasan; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: Re: [PATCH 2/3] drivers:hv Convert VMBus and its descendants to PnPQuoted 14 lines · Jake Oshins
drivers/hv/vmbus_drv.c +12
-0+ 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);drivers/hv/vmbus_drv.c struct hv_device *vmbus_device_create(const uuid_le *type, · line 902
Quoted 10 lines
drivers/hv/vmbus_drv.c +3
-2+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; }This error handling is horribly ugly and has a bug. Please, read my essay on how to do error handling properly.
https://plus.google.com/106378716002406849458/posts/dnanfhQ4mHQ
1) Don't do "One Err" style error handling.
2) Don't twist the success path and the error paths together.
3) Don't use the "added" variable.
4) Don't initialize "ret" at the start of the function.
5) Don't forget to undopnp_descendant_memory_option()It should look something like:
return 0;
err_remove_desc:pnp_remove_descendant(child_device_obj->pnp_dev); err_remove_option: if (bytes) remove_whatever(); err_free_desc: free_pnp_descendant(child_device_obj->pnp_dev); return ret;
Quoted 2 lines
regards,
dan carpenter
Will do. Thanks for the review.
-- Jake Oshins
PATCH 3/3 drivers:hv Remove old MMIO management code
In reply to Jake OshinsThis patch removes the code that is no longer necessary after the first two patches in this series have been applied. It exposed a static range of memory-mapped I/O space gleaned from the ACPI namespace, in a way that worked for a single paravirtual device, the video frame buffer.
--- drivers/hv/vmbus_drv.c | 25 ------------------------- drivers/video/fbdev/hyperv_fb.c | 27 ++++++++++++++------------- include/linux/hyperv.h | 2 -- 3 files changed, 14 insertions(+), 40 deletions(-)
drivers/hv/vmbus_drv.c +0 -25
@@ -44,12 +44,6 @@ 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 )
@@ -555,7 +549,6 @@ static void vmbus_device_release(struct device *device)kfree (hv_dev); } -/* The one and only one */ static struct bus_type hv_bus = { .name ="vmbus" ,
@@ -931,11 +924,6 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)case ACPI_RESOURCE_TYPE_IRQ : irq = res->data.irq.interrupts[0 ];break ; - -case ACPI_RESOURCE_TYPE_ADDRESS64 : - hyperv_mmio.start = res->data.address64.address.minimum; - hyperv_mmio.end = res->data.address64.address.maximum; -break ; }return AE_OK ;
@@ -953,20 +941,7 @@ static int vmbus_acpi_add(struct acpi_device *device)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:
drivers/video/fbdev/hyperv_fb.c +14 -13
@@ -675,26 +675,22 @@ static void hvfb_get_option(struct fb_info *info)/* Get framebuffer memory from Hyper-V video pci space */ -static int hvfb_getmem (struct fb_info *info) +static int hvfb_getmem (struct hv_device *hdev,struct fb_info *info) {struct hvfb_par *par = info->par;struct pci_dev *pdev =NULL ;void __iomem *fb_virt; +struct resource *res;int gen2vm =efi_enabled (EFI_BOOT );int ret; - par->mem.name =KBUILD_MODNAME ; - par->mem.flags =IORESOURCE_MEM |IORESOURCE_BUSY ;if (gen2vm) { - ret =allocate_resource (&hyperv_mmio, &par->mem, - screen_fb_size, -0 ,-1 , - screen_fb_size, -NULL ,NULL ); -if (ret !=0 ) { -pr_err ("Unable to allocate framebuffer memory\n" ); + res =pnp_get_resource (hdev->pnp_dev,IORESOURCE_MEM ,0 ); +if (!res) { +pr_err ("Unable to fetch FB claim\n" );return -ENODEV ; } + par->mem = *res; }else { pdev =pci_get_device (PCI_VENDOR_ID_MICROSOFT ,PCI_DEVICE_ID_HYPERV_VIDEO ,NULL );
@@ -707,6 +703,8 @@ static int hvfb_getmem(struct fb_info *info) pci_resource_len(pdev, 0) < screen_fb_size) goto err1; + par->mem.name =KBUILD_MODNAME ; + par->mem.flags =IORESOURCE_MEM |IORESOURCE_BUSY ; par->mem.end =pci_resource_end (pdev,0 ); par->mem.start = par->mem.end - screen_fb_size +1 ; ret =request_resource (&pdev->resource[0 ], &par->mem);
@@ -747,7 +745,8 @@ static int hvfb_getmem(struct fb_info *info) err3:iounmap (fb_virt); err2: -release_resource (&par->mem); +if (!gen2vm) +release_resource (&par->mem); err1:if (!gen2vm)pci_dev_put (pdev);
@@ -759,9 +758,11 @@ err1:static void hvfb_putmem (struct fb_info *info) {struct hvfb_par *par = info->par; +int gen2vm =efi_enabled (EFI_BOOT );iounmap (info->screen_base); -release_resource (&par->mem); +if (!gen2vm) +release_resource (&par->mem); }
@@ -792,7 +793,7 @@ static int hvfb_probe(struct hv_device *hdev, goto error1; } - ret =hvfb_getmem (info); + ret =hvfb_getmem (hdev, info);if (ret) {pr_err ("No memory for framebuffer\n" ); goto error2;
include/linux/hyperv.h +0 -2
@@ -1221,8 +1221,6 @@ int hv_vss_init(struct hv_util_service *);void hv_vss_deinit (void );void hv_vss_onchannelcallback (void *); -extern struct resource hyperv_mmio; -/* * Negotiated version with the Host. */
Signature · 1 line
1.9.1
Quoted 24 lines · Jake Oshins
This patch adds some wrapper functions in the pnp layer. The intent is to allow memory address space claims by devices which are descendants (a child or grandchild of) a device which is already part of the pnp layer. This allows a device to make a resource claim that doesn't conflict with its "aunts" and "uncles."
This is useful in a Hyper-V VM because some paravirtual "devices" need memory-mapped I/O space, and their aunts and uncles can be PCI devices. Furthermore, the hypervisor expresses the possible memory address combinations for the devices in the VM through the ACPI namespace. The paravirtual devices need to suballocate from the ACPI nodes, and they need to avoid conflicting with choices that the Linux PCI code makes about the PCI devices in the VM.
It might seem like this should be done in the platform layer rather than the pnp layer, but the platform layer assumes that the configuration of the devices in the machine are static, or at least expressed by firmware in a static fashion. The nature of a Hyper-V VM is that new devices can be added while the machine is running, and the potential configurations for them are expressed as part of the paravirtual communications channel. This much more naturally aligns with the pnp layer.
Signed-off-by Jake Oshins <[email protected]>
Quoted 8 lines
--- drivers/pnp/Makefile | 2 +- drivers/pnp/base.h | 2 + drivers/pnp/core.c | 1 + drivers/pnp/descendant.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pnp.h | 23 ++++++++++ 5 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 drivers/pnp/descendant.c
At first glance, this looks ok. Does it change the sysfs layout of hyperv devices?
also, I'd like KY to sign-off on it, verifying that he at least tested the series and it works for him.
thanks,
greg k-h
Quoted 47 lines
-----Original Message-----
From: Greg KH [mailto:[email protected]]
Sent: Sunday, March 1, 2015 7:34 PM
To: Jake Oshins
Cc: [email protected]; KY Srinivasan; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: Re: [PATCH 1/3] drivers:pnp Add support for descendants claiming memory address spaceQuoted 23 lines · Jake Oshins
This patch adds some wrapper functions in the pnp layer. The intent is to allow memory address space claims by devices which are descendants (a child or grandchild of) a device which is already part of the pnp layer. This allows a device to make a resource claim that doesn't conflict with its "aunts" and "uncles."
This is useful in a Hyper-V VM because some paravirtual "devices" need memory-mapped I/O space, and their aunts and uncles can be PCI devices. Furthermore, the hypervisor expresses the possible memory address combinations for the devices in the VM through the ACPI namespace. The paravirtual devices need to suballocate from the ACPI nodes, and they need to avoid conflicting with choices that the Linux PCI code makes about the PCI devices in the VM.
It might seem like this should be done in the platform layer rather than the pnp layer, but the platform layer assumes that the configuration of the devices in the machine are static, or at least expressed by firmware in a static fashion. The nature of a Hyper-V VM is that new devices can be added while the machine is running, and the potential configurations for them are expressed as part of the paravirtual communications channel. This much more naturally aligns with the pnp layer.
Quoted 6 lines
Signed-off-by Jake Oshins <[email protected]>--- drivers/pnp/Makefile | 2 +- drivers/pnp/base.h | 2 + drivers/pnp/core.c | 1 + drivers/pnp/descendant.c | 117+++++++++++++++++++++++++++++++++++++++++++++++
Quoted 3 lines
include/linux/pnp.h | 23 ++++++++++ 5 files changed, 144 insertions(+), 1 deletion(-) create mode 100644
drivers/pnp/descendant.c
Quoted 5 lines
At first glance, this looks ok. Does it change the sysfs layout of hyperv devices?
also, I'd like KY to sign-off on it, verifying that he at least tested the series and it works for him.
Greg,
Dan had some comments that Jake will address and resend. Also, we are waiting for Rafael to review this patch.
Regards,
K. Y
Quoted 4 lines
thanks,
greg k-h
Quoted 5 lines · Jake Oshins
This patch adds some wrapper functions in the pnp layer. The intent is to allow memory address space claims by devices which are descendants (a child or grandchild of) a device which is already part of the pnp layer. This allows a device to make a resource claim that doesn't conflict with its "aunts" and "uncles."
How is this going to happen?
Quoted 8 lines
This is useful in a Hyper-V VM because some paravirtual "devices" need memory-mapped I/O space, and their aunts and uncles can be PCI devices. Furthermore, the hypervisor expresses the possible memory address combinations for the devices in the VM through the ACPI namespace. The paravirtual devices need to suballocate from the ACPI nodes, and they need to avoid conflicting with choices that the Linux PCI code makes about the PCI devices in the VM.
Quoted 4 lines
It might seem like this should be done in the platform layer rather than the pnp layer, but the platform layer assumes that the configuration of the devices in the machine are static, or at least expressed by firmware in a static fashion.
I'm not sure if I'm following you here.
Where exactly do we make that assumption?
Yes, some code to support platform device hotplug may be missing, but I'd very much prefer to add it instead of reviving the dead man walking which is the PNP subsystem today.
Quoted 5 lines
The nature of a Hyper-V
VM is that new devices can be added while the machine is running, and the potential configurations for them are expressed as part of the paravirtual communications channel. This much more naturally aligns with the pnp layer.
That's debatable.
That aside, it would help a lot if you described your design in plain English and added some useful kerneldoc comments to the new functions.
Kind regards,
Rafael
Quoted 10 lines
-----Original Message-----
From: Rafael J. Wysocki [mailto:[email protected]]
Sent: Thursday, March 5, 2015 3:04 PM
To: Jake Oshins
Cc: [email protected]; KY Srinivasan; linux- [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; Rafael J. Wysocki; Linux ACPI
Subject: Re: [PATCH 1/3] drivers:pnp Add support for descendants claiming memory address space
Quoted 8 lines
Quoted 5 lines · Jake Oshins
This patch adds some wrapper functions in the pnp layer. The intent is to allow memory address space claims by devices which are descendants (a child or grandchild of) a device which is already part of the pnp layer. This allows a device to make a resource claim that doesn't conflict with its "aunts" and "uncles."
How is this going to happen?
First, thanks for the review.
As for your question, I'm not sure whether you're asking how the code that I supplied makes it happen or how we might happen to be in a situation where you want to make a resource claim that doesn't conflict with aunts and uncles. I'll address the second interpretation first.
Imagine you have a PC from the mid '90s, or any time period when PCI coexisted with other bus technologies like ISA and EISA. You have a region of memory address space that's reserved for I/O devices. PCI devices sit below that. So do bridges to other bus technologies. When picking a memory region for one of the PCI devices, you need to ensure that it doesn't overlap both other PCI devices and devices which are beneath the EISA/ISA/other bridge. The PCI devices are the aunts and uncles. The EISA/ISA devices are nephews and nieces. The bridge to the EISA/ISA bus claims nothing and just passes through cycles that aren't claimed by PCI devices.
A Hyper-V VM is much like that mid '90s PC. "Generation 1 VMs" in Hyper-V are like it because they are, in fact, an emulation of a specific PC from 1997. "Generation 2 VMs" in Hyper-V are like it because they have a single region reported by the virtual UEFI firmware to be used by everything below that, with nothing else described by the firmware, except a "bridge" to a virtual bus called VMBus, which itself has no address space description, much like the EISA/ISA bus had no address space description. Devices can be added or removed from the VM while it is running, and they have no description in ACPI.
As for how the code I supplied makes this happen, it adds a more generic wrapper to the pnp layer, augmenting the four wrappers which already exist; ISAPNP/PNPBIOS, PCI, PCMCIA and ACPI. Each of these four wrappers has code specific to the bus type. I just added a small wrapper that doesn't have that.
Quoted 14 lines
Quoted 9 lines
This is useful in a Hyper-V VM because some paravirtual "devices" need memory-mapped I/O space, and their aunts and uncles can be PCI devices. Furthermore, the hypervisor expresses the possible memory address combinations for the devices in the VM through the ACPI namespace. The paravirtual devices need to suballocate from the ACPI nodes, and they need to avoid conflicting with choices that the Linux PCI code makes about the PCI devices in the VM.
Quoted 4 lines
It might seem like this should be done in the platform layer rather than the pnp layer, but the platform layer assumes that the configuration of the devices in the machine are static, or at least expressed by firmware in a static fashion.
Quoted 8 lines
I'm not sure if I'm following you here.
Where exactly do we make that assumption?
Yes, some code to support platform device hotplug may be missing, but I'd very much prefer to add it instead of reviving the dead man walking which is the PNP subsystem today.
I'm completely open to adding this to the platform layer instead of the pnp layer. But it seems like you'd have to accommodate a usage model that doesn't yet exist in the platform layer. (You confirmed for me yourself in another e-mail that the platform layer doesn't have a provision for asking for things like "any 100MB of memory address space under my root bus, and I won't bloat this message by pasting that in unless you'd like me to send it along.)
If I were to try to use the platform layer without heavily modifying it, I'd have to write code that, from the client, driver, tried to probe for regions of free address space. Imagine an algorithm that attempted to find a free 16K by just calling allocate_resources() for every 16K region, starting from the top (or bottom) of address space until one of those claims succeeded. You could cut down the search space considerably by walking up the device tree in your driver, looking for a parent ACPI bus or module device node with a _CRS. In fact, you'd have to, or else you might end up claiming space that is outside the physical address width of the processor, or in use by something which didn't call allocate_resource(), etc. You'd have to duplicate much of the code that already exists in d
rivers/pnp/manager.c.
In fact, the hv_vmbus and hyperv_fb drivers currently in the tree do more or less just this. They hunt through the ACPI structures looking for the _CRS object in an ACPI module device above hv_vmbus (and the code is broken today in the cases where there isn't a module device, but a root PCI bus) and then they just make claims in that region, hoping for success.
The problem comes in if there are PCI devices in the same region. There's no easy way to figure out whether the claim conflicts with the PCI devices, since the PCI device's claims are made through the pnp layer.
I'm curious, by the way, about what you really mean when you say that the PNP subsystem is a dead man walking. Do you intend to pull it out? If so, I think that you'll have the same sorts of problems in those drivers that I'm describing here. You could, of course, put the logic for assigning resources across all the devices on the bus into the platform layer, but that will just end up merging it the pnp layer, no?
If you want to take the path of adding to the platform layer what's missing there, the specific requirements would be something like these:
1) It must be possible to describe "options" for the device, not specific regions for the device. These options are generally expressed in terms of base, limit, length and alignment.
2) It must be possible to look up the assignments that were chosen from among the options, after a phase where all the options have been collected and the various possible configurations have been boiled down to specific set of assignments.
Quoted 6 lines
Quoted 5 lines
The nature of a Hyper-V
VM is that new devices can be added while the machine is running, and the potential configurations for them are expressed as part of the paravirtual communications channel. This much more naturally aligns with the pnp layer.
Quoted 8 lines
That's debatable.
That aside, it would help a lot if you described your design in plain English
and added some useful kerneldoc comments to the new functions.Kind regards,
Rafael
If comments are the fundamental issue here, I'm more than happen to add them. I'll wait to propose specific changes there until this discussion resolves.
Thank you so much for your time,
Jake Oshins
Quoted 17 lines · Jake Oshins
Quoted 17 lines
-----Original Message-----
From: Rafael J. Wysocki [mailto:[email protected]]
Sent: Thursday, March 5, 2015 3:04 PM
To: Jake Oshins
Cc: [email protected]; KY Srinivasan; linux- [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; Rafael J. Wysocki; Linux ACPI
Subject: Re: [PATCH 1/3] drivers:pnp Add support for descendants claiming memory address spaceQuoted 5 lines · Jake Oshins
This patch adds some wrapper functions in the pnp layer. The intent is to allow memory address space claims by devices which are descendants (a child or grandchild of) a device which is already part of the pnp layer. This allows a device to make a resource claim that doesn't conflict with its "aunts" and "uncles."
Quoted 8 lines
Quoted 1 line
How is this going to happen?
First, thanks for the review.
As for your question, I'm not sure whether you're asking how the code that I supplied makes it happen or how we might happen to be in a situation where you want to make a resource claim that doesn't conflict with aunts and uncles. I'll address the second interpretation first.
Actually, both.
Quoted 9 lines
Imagine you have a PC from the mid '90s, or any time period when PCI coexisted with other bus technologies like ISA and EISA. You have a region of memory address space that's reserved for I/O devices. PCI devices sit below that.
So do bridges to other bus technologies. When picking a memory region for
one of the PCI devices, you need to ensure that it doesn't overlap both other PCI devices and devices which are beneath the EISA/ISA/other bridge. The PCI devices are the aunts and uncles. The EISA/ISA devices are nephews and nieces. The bridge to the EISA/ISA bus claims nothing and just passes through cycles that aren't claimed by PCI devices.
OK, adding PCI to the CC.
Quoted 9 lines
A Hyper-V VM is much like that mid '90s PC. "Generation 1 VMs" in Hyper-V are like it because they are, in fact, an emulation of a specific PC from 1997. "Generation 2 VMs" in Hyper-V are like it because they have a single region reported by the virtual UEFI firmware to be used by everything below that, with nothing else described by the firmware, except a "bridge" to a virtual bus called VMBus, which itself has no address space description, much like the EISA/ISA bus had no address space description. Devices can be added or removed from the VM while it is running, and they have no description in ACPI.
Quoted 4 lines
As for how the code I supplied makes this happen, it adds a more generic wrapper to the pnp layer, augmenting the four wrappers which already exist; ISAPNP/PNPBIOS, PCI, PCMCIA and ACPI. Each of these four wrappers has code specific to the bus type. I just added a small wrapper that doesn't have that.
It seems to me then that what you really want is a null protocol for PNP which simply doesn't do anything. I don't see any justification for the "descendant_protocol" name. It's just a null one.
In that case you should slightly modify the PNP bus type to be able to use a null protocol without defining the stub ->get, ->put and ->disable methods that just do nothing and return 0.
Then, you can define the null protocol without any methods in drivers/pnp/core.c and use it in your code without adding the "descendant" concept.
Of course, that comes with a price which is that every device using the null protocol will have that protocol's abstract device as its parent. I suppose that this is not a problem?
But first of all, I don't see why you need the whole PNP bus type mechanics in that case. It looks like what you really need is the check_mem_region() call in pnp_check_mem() and I'm not sure how the whole PNP stuff helps here. But I may be overlooking something.
While at it I'm not sure what's wrong with calling pnp_register_mem_resource() directy from the Hyper-V code instead of adding a wrapper around it in the first patch.
In the second patch you may consider changing the device member of struct hv_device into a struct device pointer instead of replacing it with a struct pnp_dev pointer. That would reduce the number of pointer dereferences you need to carry out all over.
Quoted 17 lines
Quoted 17 lines
Quoted 8 lines
This is useful in a Hyper-V VM because some paravirtual "devices" need memory-mapped I/O space, and their aunts and uncles can be PCI devices. Furthermore, the hypervisor expresses the possible memory address combinations for the devices in the VM through the ACPI namespace. The paravirtual devices need to suballocate from the ACPI nodes, and they need to avoid conflicting with choices that the Linux PCI code makes about the PCI devices in the VM.
Quoted 4 lines
It might seem like this should be done in the platform layer rather than the pnp layer, but the platform layer assumes that the configuration of the devices in the machine are static, or at least expressed by firmware in a static fashion.
I'm not sure if I'm following you here.
Where exactly do we make that assumption?
Quoted 7 lines
Quoted 4 lines
Yes, some code to support platform device hotplug may be missing, but I'd very much prefer to add it instead of reviving the dead man walking which is the PNP subsystem today.
I'm completely open to adding this to the platform layer instead of the pnp layer.
Well, I'm not sure at this point, more information needed. :-)
Quoted 6 lines
But it seems like you'd have to accommodate a usage model that doesn't yet exist in the platform layer. (You confirmed for me yourself in another e-mail that the platform layer doesn't have a provision for asking for things like "any 100MB of memory address space under my root bus, and I won't bloat this message by pasting that in unless you'd like me to send it along.)
Quoted 11 lines
If I were to try to use the platform layer without heavily modifying it, I'd have to write code that, from the client, driver, tried to probe for regions of free address space. Imagine an algorithm that attempted to find a free 16K by just calling
allocate_resources()for every 16K region, starting from the top (or bottom) of address space until one of those claims succeeded. You could cut down the search space considerably by walking up the device tree in your driver, looking for a parent ACPI bus or module device node with a_CRS. In fact, you'd have to, or else you might end up claiming space that is outside the physical address width of the processor, or in use by something which didn't callallocate_resource(), etc. You'd have to duplicate much of the code that already exists indrivers/pnp/manager.c.
Well, honestly, I'm not sure about that. I'd first like to understand how much of that code you really need.
Quoted 5 lines
In fact, the
hv_vmbusandhyperv_fbdrivers currently in the tree do more or less just this. They hunt through the ACPI structures looking for the_CRSobject in an ACPI module device abovehv_vmbus(and the code is broken today in the cases where there isn't a module device, but a root PCI bus) and then they just make claims in that region, hoping for success.
I see.
Quoted 3 lines
The problem comes in if there are PCI devices in the same region. There's no easy way to figure out whether the claim conflicts with the PCI devices, since the PCI device's claims are made through the pnp layer.
Well, please look at __pci_request_region() then and tell me where it uses the PNP layer.
Quoted 2 lines
I'm curious, by the way, about what you really mean when you say that the PNP subsystem is a dead man walking. Do you intend to pull it out?
No. It just is old and in the deep maintenance mode meaning that no new PNP drivers are expected to be submitted going forward.
Quoted 2 lines
If so, I think that you'll have the same sorts of problems in those drivers that I'm describing here.
I'm not sure about that. All boils down to being able to reserve resource ranges and avoiding resource conflicts. We can do that without the PNP subsystem just fine.
Quoted 3 lines
You could, of course, put the logic for assigning resources across all the devices on the bus into the platform layer, but that will just end up merging it the pnp layer, no?
I don't think so.
Quoted 11 lines
If you want to take the path of adding to the platform layer what's missing there, the specific requirements would be something like these:
1) It must be possible to describe "options" for the device, not specific regions for the device. These options are generally expressed in terms of base, limit, length and alignment.
2) It must be possible to look up the assignments that were chosen from among the options, after a phase where all the options have been collected and the various possible configurations have been boiled down to specific set of assignments.
That's correct.
Quoted 12 lines
Quoted 12 lines
Quoted 5 lines
The nature of a Hyper-V
VM is that new devices can be added while the machine is running, and the potential configurations for them are expressed as part of the paravirtual communications channel. This much more naturally aligns with the pnp layer.That's debatable.
That aside, it would help a lot if you described your design in plain English
and added some useful kerneldoc comments to the new functions.
Quoted 5 lines
Quoted 2 lines
Kind regards,
RafaelIf comments are the fundamental issue here, I'm more than happen to add them. I'll wait to propose specific changes there until this discussion resolves.
They aren't fundamental, but will be necessary for final patches to get accepted.
Kind regards,
Rafael
Quoted 10 lines
-----Original Message-----
From: Rafael J. Wysocki [mailto:[email protected]]
Sent: Tuesday, March 10, 2015 5:34 PM
To: Jake Oshins; [email protected]
Cc: Rafael J. Wysocki; [email protected]; KY Srinivasan; linux- [email protected]; [email protected]; [email protected]; Linux ACPI; Linux PCI; Bjorn Helgaas
Subject: Re: [PATCH 1/3] drivers:pnp Add support for descendants claiming memory address space
<snip>
Quoted 16 lines
It seems to me then that what you really want is a null protocol for PNP which simply doesn't do anything. I don't see any justification for the "
descendant_protocol" name. It's just a null one.In that case you should slightly modify the PNP bus type to be able to use a null protocol without defining the stub ->get, ->put and ->disable methods that just do nothing and return 0.
Then, you can define the null protocol without any methods in
drivers/pnp/core.cand use it in your code without adding the "descendant" concept.Of course, that comes with a price which is that every device using the null protocol will have that protocol's abstract device as its parent. I suppose that this is not a problem?
<snip>
Quoted 11 lines
Quoted 2 lines
The problem comes in if there are PCI devices in the same region. There's
no
Quoted 1 line
easy way to figure out whether the claim conflicts with the PCI devices,
since
Quoted 1 line
the PCI device's claims are made through the pnp layer.
Well, please look at
__pci_request_region()then and tell me where it uses the
PNP layer.
I've been thinking a lot (and poking around in the code, trying things) in response to what you wrote, and in particular in response to the two parts quoted above. Having a null protocol where each of the devices has the same abstract parent doesn't serve my needs, because it won't guarantee that the ranges claimed fall within the _CRS of the grandparent or great-grandparent node. And, in fact, I don't think that my proposed patch is actually accomplishing that deterministically either, at the moment.
Your response, at length, convinced me to look at things differently and I realized that I wasn't getting as much from this approach as I thought I was. I'd like to withdraw this patch series. I can come up with an alternative solution that exists only within the Hyper-V-related drivers.
Thanks again for your time and patience,
Jake Oshins