PCI: pciehp: Always enable occupied slot on probe
Per PCIe r4.0, sec 6.7.3.4, a "port may optionally send an MSI when there are hot-plug events that occur while interrupt generation is disabled, and interrupt generation is subsequently enabled." On probe, we currently clear all event bits in the Slot Status register with the notable exception of the Presence Detect Changed bit. Thereby we seek to receive an interrupt for an already occupied slot once event notification is enabled. But because the interrupt is optional, users may have to specify the pciehp_force parameter on the command line, which is inconvenient. Moreover, now that pciehp's event handling has become resilient to missed events, a Presence Detect Changed interrupt for a slot which is powered on is interpreted as removal of the card. If the slot has already been brought up by the BIOS, receiving such an interrupt on probe causes the slot to be powered off and immediately back on, which is likewise undesirable. Avoid both issues by making the behavior of pciehp_force the default and clearing the Presence Detect Changed bit on probe. Note that the stated purpose of pciehp_force per the MODULE_PARM_DESC ("Force pciehp, even if OSHP is missing") seems nonsensical because the OSHP control method is only relevant for SHCP slots according to the PCI Firmware specification r3.0, sec 4.8. Signed-off-by: Lukas Wunner <lukas@wunner.de> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Cc: Mika Westerberg <mika.westerberg@linux.intel.com>
This commit is contained in:
parent
d331710ea7
commit
cdf6b73621
|
@ -30,7 +30,6 @@
|
||||||
bool pciehp_debug;
|
bool pciehp_debug;
|
||||||
bool pciehp_poll_mode;
|
bool pciehp_poll_mode;
|
||||||
int pciehp_poll_time;
|
int pciehp_poll_time;
|
||||||
static bool pciehp_force;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* not really modular, but the easiest way to keep compat with existing
|
* not really modular, but the easiest way to keep compat with existing
|
||||||
|
@ -39,11 +38,9 @@ static bool pciehp_force;
|
||||||
module_param(pciehp_debug, bool, 0644);
|
module_param(pciehp_debug, bool, 0644);
|
||||||
module_param(pciehp_poll_mode, bool, 0644);
|
module_param(pciehp_poll_mode, bool, 0644);
|
||||||
module_param(pciehp_poll_time, int, 0644);
|
module_param(pciehp_poll_time, int, 0644);
|
||||||
module_param(pciehp_force, bool, 0644);
|
|
||||||
MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not");
|
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_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_poll_time, "Polling mechanism frequency, in seconds");
|
||||||
MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if OSHP is missing");
|
|
||||||
|
|
||||||
#define PCIE_MODULE_NAME "pciehp"
|
#define PCIE_MODULE_NAME "pciehp"
|
||||||
|
|
||||||
|
@ -243,11 +240,10 @@ static int pciehp_probe(struct pcie_device *dev)
|
||||||
mutex_lock(&slot->lock);
|
mutex_lock(&slot->lock);
|
||||||
pciehp_get_adapter_status(slot, &occupied);
|
pciehp_get_adapter_status(slot, &occupied);
|
||||||
pciehp_get_power_status(slot, &poweron);
|
pciehp_get_power_status(slot, &poweron);
|
||||||
if (pciehp_force &&
|
if ((occupied && (slot->state == OFF_STATE ||
|
||||||
((occupied && (slot->state == OFF_STATE ||
|
slot->state == BLINKINGON_STATE)) ||
|
||||||
slot->state == BLINKINGON_STATE)) ||
|
(!occupied && (slot->state == ON_STATE ||
|
||||||
(!occupied && (slot->state == ON_STATE ||
|
slot->state == BLINKINGOFF_STATE)))
|
||||||
slot->state == BLINKINGOFF_STATE))))
|
|
||||||
pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
|
pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
|
||||||
/* If empty slot's power status is on, turn power off */
|
/* If empty slot's power status is on, turn power off */
|
||||||
if (!occupied && poweron && POWER_CTRL(ctrl))
|
if (!occupied && poweron && POWER_CTRL(ctrl))
|
||||||
|
|
|
@ -844,16 +844,11 @@ struct controller *pcie_init(struct pcie_device *dev)
|
||||||
if (link_cap & PCI_EXP_LNKCAP_DLLLARC)
|
if (link_cap & PCI_EXP_LNKCAP_DLLLARC)
|
||||||
ctrl->link_active_reporting = 1;
|
ctrl->link_active_reporting = 1;
|
||||||
|
|
||||||
/*
|
/* Clear all remaining event bits in Slot Status register. */
|
||||||
* Clear all remaining event bits in Slot Status register except
|
|
||||||
* Presence Detect Changed. We want to make sure possible
|
|
||||||
* hotplug event is triggered when the interrupt is unmasked so
|
|
||||||
* that we don't lose that event.
|
|
||||||
*/
|
|
||||||
pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
|
pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
|
||||||
PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
|
PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
|
||||||
PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_CC |
|
PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_CC |
|
||||||
PCI_EXP_SLTSTA_DLLSC);
|
PCI_EXP_SLTSTA_DLLSC | PCI_EXP_SLTSTA_PDC);
|
||||||
|
|
||||||
ctrl_info(ctrl, "Slot #%d AttnBtn%c PwrCtrl%c MRL%c AttnInd%c PwrInd%c HotPlug%c Surprise%c Interlock%c NoCompl%c LLActRep%c%s\n",
|
ctrl_info(ctrl, "Slot #%d AttnBtn%c PwrCtrl%c MRL%c AttnInd%c PwrInd%c HotPlug%c Surprise%c Interlock%c NoCompl%c LLActRep%c%s\n",
|
||||||
(slot_cap & PCI_EXP_SLTCAP_PSN) >> 19,
|
(slot_cap & PCI_EXP_SLTCAP_PSN) >> 19,
|
||||||
|
|
Loading…
Reference in New Issue