aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/pciehp_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/hotplug/pciehp_core.c')
-rw-r--r--drivers/pci/hotplug/pciehp_core.c63
1 files changed, 32 insertions, 31 deletions
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index 01fcf1fa0f66..ec48c9433ae5 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -200,12 +200,40 @@ static int reset_slot(struct hotplug_slot *hotplug_slot, int probe)
return pciehp_reset_slot(slot, probe);
}
+/**
+ * pciehp_check_presence() - synthesize event if presence has changed
+ *
+ * On probe and resume, an explicit presence check is necessary to bring up an
+ * occupied slot or bring down an unoccupied slot. This can't be triggered by
+ * events in the Slot Status register, they may be stale and are therefore
+ * cleared. Secondly, sending an interrupt for "events that occur while
+ * interrupt generation is disabled [when] interrupt generation is subsequently
+ * enabled" is optional per PCIe r4.0, sec 6.7.3.4.
+ */
+static void pciehp_check_presence(struct controller *ctrl)
+{
+ struct slot *slot = ctrl->slot;
+ u8 occupied;
+
+ down_read(&ctrl->reset_lock);
+ mutex_lock(&slot->lock);
+
+ pciehp_get_adapter_status(slot, &occupied);
+ if ((occupied && (slot->state == OFF_STATE ||
+ slot->state == BLINKINGON_STATE)) ||
+ (!occupied && (slot->state == ON_STATE ||
+ slot->state == BLINKINGOFF_STATE)))
+ pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
+
+ mutex_unlock(&slot->lock);
+ up_read(&ctrl->reset_lock);
+}
+
static int pciehp_probe(struct pcie_device *dev)
{
int rc;
struct controller *ctrl;
struct slot *slot;
- u8 occupied, poweron;
/* If this is not a "hotplug" service, we have no business here. */
if (dev->service != PCIE_PORT_SERVICE_HP)
@@ -250,21 +278,7 @@ static int pciehp_probe(struct pcie_device *dev)
goto err_out_shutdown_notification;
}
- /* Check if slot is occupied */
- down_read(&ctrl->reset_lock);
- mutex_lock(&slot->lock);
- pciehp_get_adapter_status(slot, &occupied);
- pciehp_get_power_status(slot, &poweron);
- if ((occupied && (slot->state == OFF_STATE ||
- slot->state == BLINKINGON_STATE)) ||
- (!occupied && (slot->state == ON_STATE ||
- slot->state == BLINKINGOFF_STATE)))
- pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
- /* If empty slot's power status is on, turn power off */
- if (!occupied && poweron && POWER_CTRL(ctrl))
- pciehp_power_off_slot(slot);
- mutex_unlock(&slot->lock);
- up_read(&ctrl->reset_lock);
+ pciehp_check_presence(ctrl);
return 0;
@@ -311,22 +325,9 @@ static int pciehp_resume_noirq(struct pcie_device *dev)
static int pciehp_resume(struct pcie_device *dev)
{
- struct controller *ctrl;
- struct slot *slot;
- u8 status;
-
- ctrl = get_service_data(dev);
- slot = ctrl->slot;
+ struct controller *ctrl = get_service_data(dev);
- /* Check if slot is occupied */
- pciehp_get_adapter_status(slot, &status);
- mutex_lock(&slot->lock);
- if ((status && (slot->state == OFF_STATE ||
- slot->state == BLINKINGON_STATE)) ||
- (!status && (slot->state == ON_STATE ||
- slot->state == BLINKINGOFF_STATE)))
- pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
- mutex_unlock(&slot->lock);
+ pciehp_check_presence(ctrl);
return 0;
}