diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/hotplug/pciehp.h | 3 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_ctrl.c | 80 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 10 |
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) { |