aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/hotplug/pciehp.h3
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c80
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c10
3 files changed, 40 insertions, 53 deletions
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 9c75acd291fb..47cd9af5caf3 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -169,8 +169,7 @@ int pciehp_sysfs_disable_slot(struct slot *slot);
void pciehp_request(struct controller *ctrl, int action);
void pciehp_handle_button_press(struct slot *slot);
void pciehp_handle_disable_request(struct slot *slot);
-void pciehp_handle_link_change(struct slot *slot);
-void pciehp_handle_presence_change(struct slot *slot);
+void pciehp_handle_presence_or_link_change(struct slot *slot, u32 events);
int pciehp_configure_device(struct slot *p_slot);
void pciehp_unconfigure_device(struct slot *p_slot);
void pciehp_queue_pushbutton_work(struct work_struct *work);
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 4a12e70aacd0..811019902ada 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -217,66 +217,60 @@ void pciehp_handle_disable_request(struct slot *slot)
ctrl->request_result = pciehp_disable_slot(slot);
}
-void pciehp_handle_link_change(struct slot *p_slot)
+void pciehp_handle_presence_or_link_change(struct slot *slot, u32 events)
{
- struct controller *ctrl = p_slot->ctrl;
+ struct controller *ctrl = slot->ctrl;
bool link_active;
+ u8 present;
- mutex_lock(&p_slot->lock);
- link_active = pciehp_check_link_active(ctrl);
-
- switch (p_slot->state) {
- case BLINKINGON_STATE:
+ /*
+ * If the slot is on and presence or link has changed, turn it off.
+ * Even if it's occupied again, we cannot assume the card is the same.
+ */
+ mutex_lock(&slot->lock);
+ switch (slot->state) {
case BLINKINGOFF_STATE:
- cancel_delayed_work(&p_slot->work);
- /* Fall through */
+ cancel_delayed_work(&slot->work);
case ON_STATE:
- case OFF_STATE:
- if (link_active) {
- p_slot->state = POWERON_STATE;
- mutex_unlock(&p_slot->lock);
- ctrl_info(ctrl, "Slot(%s): Link Up\n", slot_name(p_slot));
- pciehp_enable_slot(p_slot);
- } else {
- p_slot->state = POWEROFF_STATE;
- mutex_unlock(&p_slot->lock);
- ctrl_info(ctrl, "Slot(%s): Link Down\n", slot_name(p_slot));
- pciehp_disable_slot(p_slot);
- }
- return;
+ slot->state = POWEROFF_STATE;
+ mutex_unlock(&slot->lock);
+ if (events & PCI_EXP_SLTSTA_DLLSC)
+ ctrl_info(ctrl, "Slot(%s): Link Down\n",
+ slot_name(slot));
+ if (events & PCI_EXP_SLTSTA_PDC)
+ ctrl_info(ctrl, "Slot(%s): Card not present\n",
+ slot_name(slot));
+ pciehp_disable_slot(slot);
break;
default:
- ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n",
- slot_name(p_slot), p_slot->state);
- break;
+ mutex_unlock(&slot->lock);
}
- mutex_unlock(&p_slot->lock);
-}
-
-void pciehp_handle_presence_change(struct slot *slot)
-{
- struct controller *ctrl = slot->ctrl;
- u8 present;
+ /* Turn the slot on if it's occupied or link is up */
mutex_lock(&slot->lock);
+ pciehp_get_adapter_status(slot, &present);
+ link_active = pciehp_check_link_active(ctrl);
+ if (!present && !link_active) {
+ mutex_unlock(&slot->lock);
+ return;
+ }
+
switch (slot->state) {
case BLINKINGON_STATE:
- case BLINKINGOFF_STATE:
cancel_delayed_work(&slot->work);
- }
-
- pciehp_get_adapter_status(slot, &present);
- ctrl_info(ctrl, "Slot(%s): Card %spresent\n", slot_name(slot),
- present ? "" : "not ");
-
- if (present) {
+ case OFF_STATE:
slot->state = POWERON_STATE;
mutex_unlock(&slot->lock);
+ if (present)
+ ctrl_info(ctrl, "Slot(%s): Card present\n",
+ slot_name(slot));
+ if (link_active)
+ ctrl_info(ctrl, "Slot(%s): Link Up\n",
+ slot_name(slot));
ctrl->request_result = pciehp_enable_slot(slot);
- } else {
- slot->state = POWEROFF_STATE;
+ break;
+ default:
mutex_unlock(&slot->lock);
- pciehp_disable_slot(slot);
}
}
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 6b8350a3875c..d588b3c1ffcc 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -602,17 +602,11 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id)
/*
* Disable requests have higher priority than Presence Detect Changed
* or Data Link Layer State Changed events.
- *
- * Check Link Status Changed at higher precedence than Presence
- * Detect Changed. The PDS value may be set to "card present" from
- * out-of-band detection, which may be in conflict with a Link Down.
*/
if (events & DISABLE_SLOT)
pciehp_handle_disable_request(slot);
- else if (events & PCI_EXP_SLTSTA_DLLSC)
- pciehp_handle_link_change(slot);
- else if (events & PCI_EXP_SLTSTA_PDC)
- pciehp_handle_presence_change(slot);
+ else if (events & (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC))
+ pciehp_handle_presence_or_link_change(slot, events);
/* Check Power Fault Detected */
if ((events & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) {