Add option to passively listen for PCIE hotplug events
Subsystems (2)
PATCH 1/1 Add option to passively listen for PCIE hotplug events
Various pieces of hardware (such as the Acer Aspire One and Asus EEE) use PCIE hotplug to change the state of devices in response to events such as the removal of SD cards or disabling the wireless radio. However, they do not provide firmware support for this. As a consequence pciehp will refuse to load and various things break.
The existing workaround has been to use the pciehp_force option. This is undesirable as there is little guarantee that manipulating the power file in the slot directory will actually result in anything happening, leading to potential user confusion and hardware damage. This patch adds a new option, pciehp_passive. In this configuration pciehp will listen for events and notify the PCI core appropriately. However, it will not provide any user controllable sysfs attributes and so the risk of confusion or damage is averted. Any system slots that do have firmware support will continue to provide full functionality.
---
drivers/pci/hotplug/pciehp_core.c +18 -4
@@ -41,6 +41,7 @@ int pciehp_debug;int pciehp_poll_mode;int pciehp_poll_time;int pciehp_force; +int pciehp_passive;struct workqueue_struct *pciehp_wq;#define DRIVER_VERSION "0.4"
@@ -55,10 +56,12 @@ module_param(pciehp_debug, bool, 0644);module_param (pciehp_poll_mode, bool,0644 );module_param (pciehp_poll_time, int,0644 );module_param (pciehp_force, bool,0644 ); +module_param (pciehp_passive, bool,0644 );MODULE_PARM_DESC (pciehp_debug,"Debugging mode enabled or not" );MODULE_PARM_DESC (pciehp_poll_mode,"Using polling mechanism for hot-plug events or not" );MODULE_PARM_DESC (pciehp_poll_time,"Polling mechanism frequency, in seconds" );MODULE_PARM_DESC (pciehp_force,"Force pciehp, even if _OSC and OSHP are missing" ); +MODULE_PARM_DESC (pciehp_passive,"Listen for pciehp events, even if _OSC and OSHP are missing" );#define PCIE_MODULE_NAME "pciehp"
@@ -85,6 +88,13 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { .get_cur_bus_speed = get_cur_bus_speed, }; +static struct hotplug_slot_ops pciehp_passive_hotplug_slot_ops = { + .owner =THIS_MODULE , + .get_adapter_status = get_adapter_status, + .get_max_bus_speed = get_max_bus_speed, + .get_cur_bus_speed = get_cur_bus_speed, +}; +/* * Check the status of the Electro Mechanical Interlock (EMI) */
@@ -212,7 +222,11 @@ static int init_slots(struct controller *ctrl) hotplug_slot->info = info; hotplug_slot->private = slot; hotplug_slot->release = &release_slot; - hotplug_slot->ops = &pciehp_hotplug_slot_ops; +if (pciehp_passive && +pciehp_get_hp_hw_control_from_firmware (ctrl->pci_dev)) + hotplug_slot->ops = &pciehp_passive_hotplug_slot_ops; +else + hotplug_slot->ops = &pciehp_hotplug_slot_ops; slot->hotplug_slot = hotplug_slot;snprintf (name,SLOT_NAME_SIZE ,"%u" , slot->number);
@@ -407,7 +421,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_u8 value;struct pci_dev *pdev = dev->port; -if (pciehp_force) +if (pciehp_force || pciehp_passive)dev_info (&dev->device,"Bypassing BIOS check for pciehp use on %s\n" ,pci_name (pdev));
@@ -435,7 +449,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ t_slot =pciehp_find_slot (ctrl, ctrl->slot_device_offset); t_slot->hpc_ops->get_adapter_status (t_slot, &value);/* Check if slot is occupied */ -if (value && pciehp_force) { +if (value && (pciehp_force || pciehp_passive)) { rc =pciehp_enable_slot (t_slot);if (rc)/* -ENODEV: shouldn't happen, but deal with it */ value =0 ;
@@ -474,7 +488,7 @@ static int pciehp_suspend (struct pcie_device *dev, pm_message_t state)static int pciehp_resume (struct pcie_device *dev) {dev_info (&dev->device,"%s ENTRY\n" , __func__); -if (pciehp_force) { +if (pciehp_force || pciehp_passive) {struct controller *ctrl =get_service_data (dev);struct slot *t_slot;u8 status;
Signature · 1 line
Matthew Garrett | [email protected]
Quoted 16 lines · Matthew Garrett
Various pieces of hardware (such as the Acer Aspire One and Asus EEE) use PCIE hotplug to change the state of devices in response to events such as the removal of SD cards or disabling the wireless radio. However, they do not provide firmware support for this. As a consequence pciehp will refuse to load and various things break.
The existing workaround has been to use the
pciehp_forceoption. This is undesirable as there is little guarantee that manipulating the power file in the slot directory will actually result in anything happening, leading to potential user confusion and hardware damage. This patch adds a new option,pciehp_passive. In this configuration pciehp will listen for events and notify the PCI core appropriately. However, it will not provide any user controllable sysfs attributes and so the risk of confusion or damage is averted. Any system slots that do have firmware support will continue to provide full functionality.
Quoted 1 line
Signed-off-by Matthew Garrett <[email protected]>
Can you add something to Documentation/ for this new option? Either kernel-parameters.txt or something in PCI/ seems appropriate.
Just cutting/pasting the above would be good enough for me.
thanks,
grant
Quoted 89 lines
---
drivers/pci/hotplug/pciehp_core.c +18
-4@@ -41,6 +41,7 @@ int pciehp_debug;int pciehp_poll_mode;int pciehp_poll_time;int pciehp_force; +int pciehp_passive;struct workqueue_struct *pciehp_wq;#define DRIVER_VERSION "0.4"@@ -55,10 +56,12 @@ module_param(pciehp_debug, bool, 0644);module_param (pciehp_poll_mode, bool,0644 );module_param (pciehp_poll_time, int,0644 );module_param (pciehp_force, bool,0644 ); +module_param (pciehp_passive, bool,0644 );MODULE_PARM_DESC (pciehp_debug,"Debugging mode enabled or not" );MODULE_PARM_DESC (pciehp_poll_mode,"Using polling mechanism for hot-plug events or not" );MODULE_PARM_DESC (pciehp_poll_time,"Polling mechanism frequency, in seconds" );MODULE_PARM_DESC (pciehp_force,"Force pciehp, even if _OSC and OSHP are missing" ); +MODULE_PARM_DESC (pciehp_passive,"Listen for pciehp events, even if _OSC and OSHP are missing" );#define PCIE_MODULE_NAME "pciehp"@@ -85,6 +88,13 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { .get_cur_bus_speed = get_cur_bus_speed, }; +static struct hotplug_slot_ops pciehp_passive_hotplug_slot_ops = { + .owner =THIS_MODULE , + .get_adapter_status = get_adapter_status, + .get_max_bus_speed = get_max_bus_speed, + .get_cur_bus_speed = get_cur_bus_speed, +}; +/* * Check the status of the Electro Mechanical Interlock (EMI) */ @@ -212,7 +222,11 @@ static int init_slots(struct controller *ctrl) hotplug_slot->info = info; hotplug_slot->private = slot; hotplug_slot->release = &release_slot; - hotplug_slot->ops = &pciehp_hotplug_slot_ops; +if (pciehp_passive && +pciehp_get_hp_hw_control_from_firmware (ctrl->pci_dev)) + hotplug_slot->ops = &pciehp_passive_hotplug_slot_ops; +else + hotplug_slot->ops = &pciehp_hotplug_slot_ops; slot->hotplug_slot = hotplug_slot;snprintf (name,SLOT_NAME_SIZE ,"%u" , slot->number);@@ -407,7 +421,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_u8 value;struct pci_dev *pdev = dev->port; -if (pciehp_force) +if (pciehp_force || pciehp_passive)dev_info (&dev->device,"Bypassing BIOS check for pciehp use on %s\n" ,pci_name (pdev));@@ -435,7 +449,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ t_slot =pciehp_find_slot (ctrl, ctrl->slot_device_offset); t_slot->hpc_ops->get_adapter_status (t_slot, &value);/* Check if slot is occupied */ -if (value && pciehp_force) { +if (value && (pciehp_force || pciehp_passive)) { rc =pciehp_enable_slot (t_slot);if (rc)/* -ENODEV: shouldn't happen, but deal with it */ value =0 ;@@ -474,7 +488,7 @@ static int pciehp_suspend (struct pcie_device *dev, pm_message_t state)static int pciehp_resume (struct pcie_device *dev) {dev_info (&dev->device,"%s ENTRY\n" , __func__); -if (pciehp_force) { +if (pciehp_force || pciehp_passive) {struct controller *ctrl =get_service_data (dev);struct slot *t_slot;u8 status;Signature · 6 lines
-- Matthew Garrett | [email protected] -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 1/1 Add option to passively listen for PCIE hotplug events
Various pieces of hardware (such as the Acer Aspire One and Asus EEE) use PCIE hotplug to change the state of devices in response to events such as the removal of SD cards or disabling the wireless radio. However, they do not provide firmware support for this. As a consequence pciehp will refuse to load and various things break.
The existing workaround has been to use the pciehp_force option. This is undesirable as there is little guarantee that manipulating the power file in the slot directory will actually result in anything happening, leading to potential user confusion and hardware damage. This patch adds a new option, pciehp_passive. In this configuration pciehp will listen for events and notify the PCI core appropriately. However, it will not provide any user controllable sysfs attributes and so the risk of confusion or damage is averted. Any system slots that do have firmware support will continue to provide full functionality.
---
Includes a minor code change suggested by Matthew Wilcox to avoid calling pciehp_get_hp_hw_control_from_firmware() twice and documentation updates as suggested Grant Grundler.
Documentation/kernel-parameters.txt +14 -0
@@ -1711,6 +1711,20 @@ and is between 256 and 4096 characters. It is defined in the file force Enable ASPM even on devices that claim not to support it. WARNING: Forcing ASPM on may cause system lockups. + pciehp.pciehp_force= [PCIE] Forcibly enable PCIE hotplug support on a + slot even if the firmware provides no support for + it. + + pciehp.pciehp_passive= [PCIE] Forcibly enable listening for PCIE + hotplug events on a slot even if the firmware + provides no support for it. Unlike pciehp.force, + does not provide user interface for triggering + hotplug events. + + pciehp.pciehp_poll_mode= [PCIE] Poll for PCIE hotplug events + + pciehp.pciehp_poll_time= [PCIE] Seconds to wait between polls + pcmv= [HW,PCMCIA] BadgePAD 4 pd. [PARIDE]
drivers/pci/hotplug/pciehp.h +4 -0
@@ -224,6 +224,10 @@ static inline int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev) {u32 flags = (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL ); +if (pciehp_force) { +dev_info (&dev->dev,"Bypassing BIOS check for pciehp\n" ); +return 0 ; + }return acpi_get_hp_hw_control_from_firmware (dev, flags); }
drivers/pci/hotplug/pciehp_core.c +17 -7
@@ -41,6 +41,7 @@ int pciehp_debug;int pciehp_poll_mode;int pciehp_poll_time;int pciehp_force; +int pciehp_passive;struct workqueue_struct *pciehp_wq;#define DRIVER_VERSION "0.4"
@@ -55,10 +56,12 @@ module_param(pciehp_debug, bool, 0644);module_param (pciehp_poll_mode, bool,0644 );module_param (pciehp_poll_time, int,0644 );module_param (pciehp_force, bool,0644 ); +module_param (pciehp_passive, bool,0644 );MODULE_PARM_DESC (pciehp_debug,"Debugging mode enabled or not" );MODULE_PARM_DESC (pciehp_poll_mode,"Using polling mechanism for hot-plug events or not" );MODULE_PARM_DESC (pciehp_poll_time,"Polling mechanism frequency, in seconds" );MODULE_PARM_DESC (pciehp_force,"Force pciehp, even if _OSC and OSHP are missing" ); +MODULE_PARM_DESC (pciehp_passive,"Listen for pciehp events, even if _OSC and OSHP are missing" );#define PCIE_MODULE_NAME "pciehp"
@@ -85,6 +88,13 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { .get_cur_bus_speed = get_cur_bus_speed, }; +static struct hotplug_slot_ops pciehp_passive_hotplug_slot_ops = { + .owner =THIS_MODULE , + .get_adapter_status = get_adapter_status, + .get_max_bus_speed = get_max_bus_speed, + .get_cur_bus_speed = get_cur_bus_speed, +}; +/* * Check the status of the Electro Mechanical Interlock (EMI) */
@@ -212,7 +222,11 @@ static int init_slots(struct controller *ctrl) hotplug_slot->info = info; hotplug_slot->private = slot; hotplug_slot->release = &release_slot; - hotplug_slot->ops = &pciehp_hotplug_slot_ops; +if (pciehp_passive && +pciehp_get_hp_hw_control_from_firmware (ctrl->pci_dev)) + hotplug_slot->ops = &pciehp_passive_hotplug_slot_ops; +else + hotplug_slot->ops = &pciehp_hotplug_slot_ops; slot->hotplug_slot = hotplug_slot;snprintf (name,SLOT_NAME_SIZE ,"%u" , slot->number);
@@ -407,11 +421,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_u8 value;struct pci_dev *pdev = dev->port; -if (pciehp_force) -dev_info (&dev->device, -"Bypassing BIOS check for pciehp use on %s\n" , -pci_name (pdev)); -else if (pciehp_get_hp_hw_control_from_firmware (pdev)) +if (!pciehp_passive &&pciehp_get_hp_hw_control_from_firmware (pdev)) goto err_out_none; ctrl =pcie_init (dev);
@@ -474,7 +484,7 @@ static int pciehp_suspend (struct pcie_device *dev, pm_message_t state)static int pciehp_resume (struct pcie_device *dev) {dev_info (&dev->device,"%s ENTRY\n" , __func__); -if (pciehp_force) { +if (pciehp_force || pciehp_passive) {struct controller *ctrl =get_service_data (dev);struct slot *t_slot;u8 status;
Signature · 1 line
Matthew Garrett | [email protected]
Hi.
Quoted 16 lines · Matthew Garrett
Various pieces of hardware (such as the Acer Aspire One and Asus EEE) use PCIE hotplug to change the state of devices in response to events such as the removal of SD cards or disabling the wireless radio. However, they do not provide firmware support for this. As a consequence pciehp will refuse to load and various things break.
The existing workaround has been to use the
pciehp_forceoption. This is undesirable as there is little guarantee that manipulating the power file in the slot directory will actually result in anything happening, leading to potential user confusion and hardware damage. This patch adds a new option,pciehp_passive. In this configuration pciehp will listen for events and notify the PCI core appropriately. However, it will not provide any user controllable sysfs attributes and so the risk of confusion or damage is averted. Any system slots that do have firmware support will continue to provide full functionality.
Quoted 2 lines
Signed-off-by Matthew Garrett <[email protected]>
On my system (a hp laptop) I have to use pciehp_force=1 to have the service driver hpdriver loaded and an IRQ (MSI-Edge) assigned.
Does this patch mean that in the future I'd have to use the new pciehp_passive=1 switch instead?
Sorry if I wasn't clear, I'm not an English native speaker.
Regards,
Fabio
Quoted 5 lines · Fabio Comolli
On my system (a hp laptop) I have to use pciehp_force=1 to have the service driver hpdriver loaded and an IRQ (MSI-Edge) assigned.
Does this patch mean that in the future I'd have to use the new pciehp_passive=1 switch instead?
You wouldn't /have/ to - force should still work. However, the passive option may be a better plan.
Signature · 1 line
Matthew Garrett | [email protected]
Quoted 36 lines · On Mon, 3 Nov 2008 13:26:06 +0000 Matthew Garrett wrote:
Various pieces of hardware (such as the Acer Aspire One and Asus EEE) use PCIE hotplug to change the state of devices in response to events such as the removal of SD cards or disabling the wireless radio. However, they do not provide firmware support for this. As a consequence pciehp will refuse to load and various things break.
The existing workaround has been to use the
pciehp_forceoption. This is undesirable as there is little guarantee that manipulating the power file in the slot directory will actually result in anything happening, leading to potential user confusion and hardware damage. This patch adds a new option,pciehp_passive. In this configuration pciehp will listen for events and notify the PCI core appropriately. However, it will not provide any user controllable sysfs attributes and so the risk of confusion or damage is averted. Any system slots that do have firmware support will continue to provide full functionality.Signed-off-by Matthew Garrett <[email protected]>---
Includes a minor code change suggested by Matthew Wilcox to avoid calling
pciehp_get_hp_hw_control_from_firmware()twice and documentation updates as suggested Grant Grundler.Documentation/kernel-parameters.txt +4
-0@@ -1711,6 +1711,20 @@ and is between 256 and 4096 characters. It is defined in the file force Enable ASPM even on devices that claim not to support it. WARNING: Forcing ASPM on may cause system lockups. + pciehp.pciehp_force= [PCIE] Forcibly enable PCIE hotplug support on a + slot even if the firmware provides no support for + it. +
Documentation/kernel-parameters.txt and is between 256 and 4096 characters. It is defined in the file · line 1727
Quoted 10 lines
Documentation/kernel-parameters.txt +10
-0+ pciehp.pciehp_passive= [PCIE] Forcibly enable listening for PCIE + hotplug events on a slot even if the firmware + provides no support for it. Unlike pciehp.force, + does not provide user interface for triggering + hotplug events. + + pciehp.pciehp_poll_mode= [PCIE] Poll for PCIE hotplug events + + pciehp.pciehp_poll_time= [PCIE] Seconds to wait between polls +
Hi,
Is it too late to comment on these parameters?
Please don't make users repeat the "pciehp.pciehp" name. This can be changed easily in the source code by keeping the variable names as is but using module_param_named() instead of module_param(). One good example is drivers/video/uvesafb.c.
Quoted 19 lines
Documentation/kernel-parameters.txt +0
-0pcmv= [HW,PCMCIA] BadgePAD 4 pd. [PARIDE]drivers/pci/hotplug/pciehp_core.c +1
-0@@ -41,6 +41,7 @@ int pciehp_debug;int pciehp_poll_mode;int pciehp_poll_time;int pciehp_force; +int pciehp_passive;struct workqueue_struct *pciehp_wq;#define DRIVER_VERSION "0.4"@@ -55,10 +56,12 @@ module_param(pciehp_debug, bool, 0644);module_param (pciehp_poll_mode, bool,0644 );module_param (pciehp_poll_time, int,0644 );
drivers/pci/hotplug/pciehp_core.c module_param(pciehp_debug, bool, 0644); · line 67
Quoted 10 lines
drivers/pci/hotplug/pciehp_core.c +2
-0module_param (pciehp_force, bool,0644 ); +module_param (pciehp_passive, bool,0644 );MODULE_PARM_DESC (pciehp_debug,"Debugging mode enabled or not" );MODULE_PARM_DESC (pciehp_poll_mode,"Using polling mechanism for hot-plug events or not" );MODULE_PARM_DESC (pciehp_poll_time,"Polling mechanism frequency, in seconds" );MODULE_PARM_DESC (pciehp_force,"Force pciehp, even if _OSC and OSHP are missing" ); +MODULE_PARM_DESC (pciehp_passive,"Listen for pciehp events, even if _OSC and OSHP are missing" );#define PCIE_MODULE_NAME "pciehp"
---
~Randy
Quoted 5 lines · Randy Dunlap
Is it too late to comment on these parameters?
Please don't make users repeat the "pciehp.pciehp" name. This can be changed easily in the source code by keeping the variable names as is but usingmodule_param_named()instead ofmodule_param(). One good example isdrivers/video/uvesafb.c.
It maintains consistency with the existing parameter names, but after looking at the problem more closely I'm no longer planning to push this anyway.
Signature · 1 line
Matthew Garrett | [email protected]
Quoted 6 lines · On Wed, 29 Oct 2008 20:09:03 +0000 Matthew Garrett <[email protected]> wrote:
Various pieces of hardware (such as the Acer Aspire One and Asus EEE) use PCIE hotplug to change the state of devices in response to events such as the removal of SD cards or disabling the wireless radio. However, they do not provide firmware support for this. As a consequence pciehp will refuse to load and various things break.
Quoted 10 lines
The existing workaround has been to use the
pciehp_forceoption. This is undesirable as there is little guarantee that manipulating the power file in the slot directory will actually result in anything happening, leading to potential user confusion and hardware damage. This patch adds a new option,pciehp_passive. In this configuration pciehp will listen for events and notify the PCI core appropriately. However, it will not provide any user controllable sysfs attributes and so the risk of confusion or damage is averted. Any system slots that do have firmware support will continue to provide full functionality.
Gad. I don't think I understood any of that. But that's OK - it's par for the course.
However, what worries me a bit is how our users are to understand whether they need to use this option, how to use it, etc. Does it require too much knowledge of PCIE internals to be very useful? Is there any way in which we can make it more user-friendly?
Quoted 16 lines
---
drivers/pci/hotplug/pciehp_core.c +1
-0@@ -41,6 +41,7 @@ int pciehp_debug;int pciehp_poll_mode;int pciehp_poll_time;int pciehp_force; +int pciehp_passive;struct workqueue_struct *pciehp_wq;#define DRIVER_VERSION "0.4"
drivers/pci/hotplug/pciehp_core.c module_param(pciehp_debug, bool, 0644); · line 64
Quoted 9 lines
drivers/pci/hotplug/pciehp_core.c +2
-0@@ -55,10 +56,12 @@ module_param(pciehp_debug, bool, 0644);module_param (pciehp_poll_mode, bool,0644 );module_param (pciehp_poll_time, int,0644 );module_param (pciehp_force, bool,0644 ); +module_param (pciehp_passive, bool,0644 );MODULE_PARM_DESC (pciehp_debug,"Debugging mode enabled or not" );MODULE_PARM_DESC (pciehp_poll_mode,"Using polling mechanism for hot-plug events or not" );MODULE_PARM_DESC (pciehp_poll_time,"Polling mechanism frequency, in seconds" );MODULE_PARM_DESC (pciehp_force,"Force pciehp, even if _OSC and OSHP are missing" ); +MODULE_PARM_DESC (pciehp_passive,"Listen for pciehp events, even if _OSC and OSHP are missing" );
I don't think that helped much ;)
Quoted 49 lines
drivers/pci/hotplug/pciehp_core.c +14
-3#define PCIE_MODULE_NAME "pciehp"@@ -85,6 +88,13 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { .get_cur_bus_speed = get_cur_bus_speed, }; +static struct hotplug_slot_ops pciehp_passive_hotplug_slot_ops = { + .owner =THIS_MODULE , + .get_adapter_status = get_adapter_status, + .get_max_bus_speed = get_max_bus_speed, + .get_cur_bus_speed = get_cur_bus_speed, +}; +/* * Check the status of the Electro Mechanical Interlock (EMI) */ @@ -212,7 +222,11 @@ static int init_slots(struct controller *ctrl) hotplug_slot->info = info; hotplug_slot->private = slot; hotplug_slot->release = &release_slot; - hotplug_slot->ops = &pciehp_hotplug_slot_ops; +if (pciehp_passive && +pciehp_get_hp_hw_control_from_firmware (ctrl->pci_dev)) + hotplug_slot->ops = &pciehp_passive_hotplug_slot_ops; +else + hotplug_slot->ops = &pciehp_hotplug_slot_ops; slot->hotplug_slot = hotplug_slot;snprintf (name,SLOT_NAME_SIZE ,"%u" , slot->number);@@ -407,7 +421,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_u8 value;struct pci_dev *pdev = dev->port; -if (pciehp_force) +if (pciehp_force || pciehp_passive)dev_info (&dev->device,"Bypassing BIOS check for pciehp use on %s\n" ,pci_name (pdev));@@ -435,7 +449,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ t_slot =pciehp_find_slot (ctrl, ctrl->slot_device_offset); t_slot->hpc_ops->get_adapter_status (t_slot, &value);/* Check if slot is occupied */ -if (value && pciehp_force) { +if (value && (pciehp_force || pciehp_passive)) { rc =pciehp_enable_slot (t_slot);if (rc)/* -ENODEV: shouldn't happen, but deal with it */ value =0 ;
drivers/pci/hotplug/pciehp_core.c static int pciehp_suspend (struct pcie_device *dev, pm_message_t state) · line 494
Quoted 8 lines
drivers/pci/hotplug/pciehp_core.c +1
-1@@ -474,7 +488,7 @@ static int pciehp_suspend (struct pcie_device *dev, pm_message_t state)static int pciehp_resume (struct pcie_device *dev) {dev_info (&dev->device,"%s ENTRY\n" , __func__); -if (pciehp_force) { +if (pciehp_force || pciehp_passive) {struct controller *ctrl =get_service_data (dev);struct slot *t_slot;u8 status;
Was this change so obvious that no code comments were needed? Perhaps...
Quoted 4 lines · Andrew Morton
However, what worries me a bit is how our users are to understand whether they need to use this option, how to use it, etc. Does it require too much knowledge of PCIE internals to be very useful? Is there any way in which we can make it more user-friendly?
I'd lean towards this being the default behaviour in the long run, but right now there's not a great deal of understanding of what the failure cases may be. We're planning to give it a go in Fedora and see what the feedback from that is.
Signature · 1 line
Matthew Garrett | [email protected]
Quoted 4 lines · Matthew Garrett
Various pieces of hardware (such as the Acer Aspire One and Asus EEE) use PCIE hotplug to change the state of devices in response to events such as the removal of SD cards or disabling the wireless radio. However, they do not provide firmware support for this. As a consequence pciehp will refuse to load and various things break.
The existing workaround has been to use the
pciehp_forceoption. This is undesirable as there is little guarantee that manipulating the power file in the slot directory will actually result in anything happening, leading to potential user confusion and hardware damage. This patch adds a new option,pciehp_passive. In this configuration pciehp will listen for events and notify the PCI core appropriately. However, it will not provide any user controllable sysfs attributes and so the risk of confusion or damage is averted. Any system slots that do have firmware support will continue to provide full functionality.
I have several comments/questions below.
- Even with pciehp_passive option, pciehp driver controls hotplug related registers at the initialization time, enabling software notification mechanism for hotplug events, trying to turn power on the slot and so on. Is this your intended behaviour?
- Maybe I don't understand what "pciehp will listen for events..." in your patch description means. But if you expect the pciehp's interrupts for hotplug events, it would not work properly when hotplug control is not granted through _OSC or OSHP.
- Using pciehp_passive or pciehp_force option causes system reset on my system because of Master-Abort. I think it is an already existing problem with pciehp_force option. The cause of this problem is the code below.
drivers/pci/hotplug/pciehp_core.c static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ · line 455
Quoted 6 lines
drivers/pci/hotplug/pciehp_core.c +1
-1t_slot->hpc_ops->get_adapter_status (t_slot, &value);/* Check if slot is occupied */ -if (value && pciehp_force) { +if (value && (pciehp_force || pciehp_passive)) { rc =pciehp_enable_slot (t_slot);if (rc)/* -ENODEV: shouldn't happen, but deal with it */ value =0 ;
The pciehp_enable_slot() here returns error on my system because it detects the slot is already powered on state when it tries to turn power on the slot. As a result 'value' is set with 0. After that, pciehp turn power off the slot by the following code even though the adapter card on the slot is currently working, and it caused Master-Abort.
if ((POWER_CTRL(ctrl)) && !value) {
rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot
if not occupied*/
if (rc)
goto err_out_free_ctrl_slot;
}I guess the reason why you didn't encounter this problem is that your laptop doesn't have power controller on hotplug controller. I'll try to make a patch to fix this problem soon.
Thanks,
Kenji Kaneshige
Quoted 84 lines
Signed-off-by Matthew Garrett <[email protected]>---
drivers/pci/hotplug/pciehp_core.c +18
-4@@ -41,6 +41,7 @@ int pciehp_debug;int pciehp_poll_mode;int pciehp_poll_time;int pciehp_force; +int pciehp_passive;struct workqueue_struct *pciehp_wq;#define DRIVER_VERSION "0.4"@@ -55,10 +56,12 @@ module_param(pciehp_debug, bool, 0644);module_param (pciehp_poll_mode, bool,0644 );module_param (pciehp_poll_time, int,0644 );module_param (pciehp_force, bool,0644 ); +module_param (pciehp_passive, bool,0644 );MODULE_PARM_DESC (pciehp_debug,"Debugging mode enabled or not" );MODULE_PARM_DESC (pciehp_poll_mode,"Using polling mechanism for hot-plug events or not" );MODULE_PARM_DESC (pciehp_poll_time,"Polling mechanism frequency, in seconds" );MODULE_PARM_DESC (pciehp_force,"Force pciehp, even if _OSC and OSHP are missing" ); +MODULE_PARM_DESC (pciehp_passive,"Listen for pciehp events, even if _OSC and OSHP are missing" );#define PCIE_MODULE_NAME "pciehp"@@ -85,6 +88,13 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { .get_cur_bus_speed = get_cur_bus_speed, }; +static struct hotplug_slot_ops pciehp_passive_hotplug_slot_ops = { + .owner =THIS_MODULE , + .get_adapter_status = get_adapter_status, + .get_max_bus_speed = get_max_bus_speed, + .get_cur_bus_speed = get_cur_bus_speed, +}; +/* * Check the status of the Electro Mechanical Interlock (EMI) */ @@ -212,7 +222,11 @@ static int init_slots(struct controller *ctrl) hotplug_slot->info = info; hotplug_slot->private = slot; hotplug_slot->release = &release_slot; - hotplug_slot->ops = &pciehp_hotplug_slot_ops; +if (pciehp_passive && +pciehp_get_hp_hw_control_from_firmware (ctrl->pci_dev)) + hotplug_slot->ops = &pciehp_passive_hotplug_slot_ops; +else + hotplug_slot->ops = &pciehp_hotplug_slot_ops; slot->hotplug_slot = hotplug_slot;snprintf (name,SLOT_NAME_SIZE ,"%u" , slot->number);@@ -407,7 +421,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_u8 value;struct pci_dev *pdev = dev->port; -if (pciehp_force) +if (pciehp_force || pciehp_passive)dev_info (&dev->device,"Bypassing BIOS check for pciehp use on %s\n" ,pci_name (pdev));@@ -435,7 +449,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ t_slot =pciehp_find_slot (ctrl, ctrl->slot_device_offset); t_slot->hpc_ops->get_adapter_status (t_slot, &value);/* Check if slot is occupied */ -if (value && pciehp_force) { +if (value && (pciehp_force || pciehp_passive)) { rc =pciehp_enable_slot (t_slot);if (rc)/* -ENODEV: shouldn't happen, but deal with it */ value =0 ;@@ -474,7 +488,7 @@ static int pciehp_suspend (struct pcie_device *dev, pm_message_t state)static int pciehp_resume (struct pcie_device *dev) {dev_info (&dev->device,"%s ENTRY\n" , __func__); -if (pciehp_force) { +if (pciehp_force || pciehp_passive) {struct controller *ctrl =get_service_data (dev);struct slot *t_slot;u8 status;
Quoted 4 lines · Kenji Kaneshige
- Even with
pciehp_passiveoption, pciehp driver controls hotplug related registers at the initialization time, enabling software notification mechanism for hotplug events, trying to turn power on the slot and so on. Is this your intended behaviour?
Yes, although the most recent version of the patch doesn't do the forcible power on if no card is detected.
Quoted 4 lines
- Maybe I don't understand what "pciehp will listen for events..." in your patch description means. But if you expect the pciehp's interrupts for hotplug events, it would not work properly when hotplug control is not granted through
_OSCor OSHP.
What do you mean by "not work properly"? The hardware we've tested with fires events even without an OSHP method being present. That's the case we're trying to deal with.
Quoted 7 lines
Quoted 7 lines
t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */drivers/pci/hotplug/pciehp_core.c +1
-1-if (value && pciehp_force) { +if (value && (pciehp_force || pciehp_passive)) {rc = pciehp_enable_slot(t_slot); if (rc) /* -ENODEV: shouldn't happen, but deal with it */ value = 0;
This code no longer runs in the pciehp_passive case. However, by the looks of it it still does in the resume case - that probably wants fixing.
Signature · 1 line
Matthew Garrett | [email protected]
Quoted 9 lines · Matthew Garrett
Quoted 4 lines · Kenji Kaneshige
- Even with
pciehp_passiveoption, pciehp driver controls hotplug related registers at the initialization time, enabling software notification mechanism for hotplug events, trying to turn power on the slot and so on. Is this your intended behaviour?Yes, although the most recent version of the patch doesn't do the forcible power on if no card is detected.
Oh, sorry.
I didn't noticed it was already changed in your v2 patch.
Quoted 7 lines
Quoted 4 lines
- Maybe I don't understand what "pciehp will listen for events..." in your patch description means. But if you expect the pciehp's interrupts for hotplug events, it would not work properly when hotplug control is not granted through
_OSCor OSHP.What do you mean by "not work properly"? The hardware we've tested with fires events even without an OSHP method being present. That's the case we're trying to deal with.
Because the explanation of PCI Express Native Hot Plug control bit in _OSC return value in PCI firmware spec says
"... If firmware allows the operating system control of this feature, then in the context of the _OSC method, it must ensure that all hot plug events are routed to device interrupts as described in the PCI Express Base Specification. ..."
My understanding is that it is not ensured that all hot plug events are routed to device interrupts, if hotplug control is not granted.
Thanks,
Kenji Kaneshige
Quoted 10 lines
Quoted 7 lines
Quoted 7 lines
t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */drivers/pci/hotplug/pciehp_core.c +1
-1-if (value && pciehp_force) { +if (value && (pciehp_force || pciehp_passive)) {rc = pciehp_enable_slot(t_slot); if (rc) /* -ENODEV: shouldn't happen, but deal with it */ value = 0;This code no longer runs in the
pciehp_passivecase. However, by the looks of it it still does in the resume case - that probably wants fixing.
Quoted 9 lines · Kenji Kaneshige
Quoted 4 lines · Matthew Garrett
What do you mean by "not work properly"? The hardware we've tested with fires events even without an OSHP method being present. That's the case we're trying to deal with.
Because the explanation of PCI Express Native Hot Plug control bit in
_OSCreturn value in PCI firmware spec says
Quoted 7 lines
"... If firmware allows the operating system control of this feature, then in the context of the
_OSCmethod, it must ensure that all hot plug events are routed to device interrupts as described in the PCI Express Base Specification. ..."My understanding is that it is not ensured that all hot plug events are routed to device interrupts, if hotplug control is not granted.
My understanding is that in the worst case the hardware/firmware won't give us any events - that's basically equivalent to not having the driver loaded at all. On hardware that gives us the events anyway, we get some extra functionality.
Thanks for the feedback!
Signature · 1 line
Matthew Garrett | [email protected]
Quoted 12 lines · Matthew Garrett
Quoted 11 lines · Kenji Kaneshige
Quoted 2 lines · Matthew Garrett
What do you mean by "not work properly"? The hardware we've tested with fires events even without an OSHP method being present. That's the case we're trying to deal with.
Because the explanation of PCI Express Native Hot Plug control bit in
_OSCreturn value in PCI firmware spec says"... If firmware allows the operating system control of this feature, then in the context of the
_OSCmethod, it must ensure that all hot plug events are routed to device interrupts as described in the PCI Express Base Specification. ..."
Quoted 6 lines
Quoted 2 lines
My understanding is that it is not ensured that all hot plug events are routed to device interrupts, if hotplug control is not granted.
My understanding is that in the worst case the hardware/firmware won't give us any events - that's basically equivalent to not having the driver loaded at all. On hardware that gives us the events anyway, we get some extra functionality.
Thanks for the feedback!
Ok, I understood that my worries are already within the scope of the assumption.
Thanks,
Kenji Kaneshige
Quoted 12 lines · Matthew Garrett
Quoted 7 lines · Kenji Kaneshige
Quoted 7 lines
t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */drivers/pci/hotplug/pciehp_core.c +1
-1-if (value && pciehp_force) { +if (value && (pciehp_force || pciehp_passive)) {rc = pciehp_enable_slot(t_slot); if (rc) /* -ENODEV: shouldn't happen, but deal with it */ value = 0;This code no longer runs in the
pciehp_passivecase. However, by the looks of it it still does in the resume case - that probably wants fixing.
Thinking about this - you said that the problem occurs because pciehp_force=1 causes it to try to enable an already enabled slot, and then tries to power down the slot as a result? It sounds like this code should actually be checking whether the return value is ENODEV or EINVAL, and in the latter case not powering the slot down. That sounds like a separate bugfix that I'll send later on.
Signature · 1 line
Matthew Garrett | [email protected]
Quoted 11 lines · Matthew Garrett
Quoted 9 lines · Matthew Garrett
Quoted 7 lines · Kenji Kaneshige
Quoted 7 lines
t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */drivers/pci/hotplug/pciehp_core.c +1
-1-if (value && pciehp_force) { +if (value && (pciehp_force || pciehp_passive)) {rc = pciehp_enable_slot(t_slot); if (rc) /* -ENODEV: shouldn't happen, but deal with it */ value = 0;This code no longer runs in the
pciehp_passivecase. However, by the looks of it it still does in the resume case - that probably wants fixing.
Quoted 2 lines
Thinking about this - you said that the problem occurs because pciehp_force=1 causes it to try to enable an already enabled slot, and then tries to power down the slot as a result? It sounds like this code should actually be checking whether the return value is ENODEV or EINVAL, and in the latter case not powering the slot down. That sounds like a separate bugfix that I'll send later on.
I think the root cause of this problem is the following line.
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
value = 0;
I can't understand why the 'value' is set to 0 when pciehp_enable_slot() returns error. The 'value' here is representing whether the slot is occupied or not. Even if pciehp_enable_slot() returns error, it doesn't mean slot is not occupied. So I think it is clearly wrong thing that changing 'value' to 0 from 1 here.
How about just ignore the return value from pciehp_enable_slot()? The code would be as follows.
t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
t_slot->hpc_ops->get_adapter_status(t_slot, &value);
if (value) {
if (pciehp_force)
pciehp_enable_slot(t_slot);
} else {
/* Power off the slot if not occupied, just in case */
if (POWER_CTRL(ctrl))
if (t_slot->hpc_ops->power_off_slot(t_slot))
goto err_out_free_ctrl_slots;
}Thanks,
Kenji Kaneshige
Quoted 8 lines · Kenji Kaneshige
I can't understand why the 'value' is set to 0 when
pciehp_enable_slot()returns error. The 'value' here is representing whether the slot is occupied or not. Even ifpciehp_enable_slot()returns error, it doesn't mean slot is not occupied. So I think it is clearly wrong thing that changing 'value' to 0 from 1 here.How about just ignore the return value from
pciehp_enable_slot()? The code would be as follows.
Yeah, I agree with that.
Signature · 1 line
Matthew Garrett | [email protected]