|
@@ -542,7 +542,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
|
|
struct pci_bus *subordinate = pdev->subordinate;
|
|
struct pci_bus *subordinate = pdev->subordinate;
|
|
struct pci_dev *dev;
|
|
struct pci_dev *dev;
|
|
struct slot *slot = ctrl->slot;
|
|
struct slot *slot = ctrl->slot;
|
|
- u16 detected, intr_loc;
|
|
|
|
|
|
+ u16 status, events;
|
|
u8 present;
|
|
u8 present;
|
|
bool link;
|
|
bool link;
|
|
|
|
|
|
@@ -555,31 +555,35 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
|
|
* serviced, we need to re-inspect Slot Status register after
|
|
* serviced, we need to re-inspect Slot Status register after
|
|
* clearing what is presumed to be the last pending interrupt.
|
|
* clearing what is presumed to be the last pending interrupt.
|
|
*/
|
|
*/
|
|
- intr_loc = 0;
|
|
|
|
|
|
+ events = 0;
|
|
do {
|
|
do {
|
|
- pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &detected);
|
|
|
|
- if (detected == (u16) ~0) {
|
|
|
|
|
|
+ pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &status);
|
|
|
|
+ if (status == (u16) ~0) {
|
|
ctrl_info(ctrl, "%s: no response from device\n",
|
|
ctrl_info(ctrl, "%s: no response from device\n",
|
|
__func__);
|
|
__func__);
|
|
return IRQ_HANDLED;
|
|
return IRQ_HANDLED;
|
|
}
|
|
}
|
|
|
|
|
|
- detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
|
|
|
|
- PCI_EXP_SLTSTA_PDC |
|
|
|
|
- PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC);
|
|
|
|
- detected &= ~intr_loc;
|
|
|
|
- intr_loc |= detected;
|
|
|
|
- if (!intr_loc)
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Slot Status contains plain status bits as well as event
|
|
|
|
+ * notification bits; right now we only want the event bits.
|
|
|
|
+ */
|
|
|
|
+ status &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
|
|
|
|
+ PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_CC |
|
|
|
|
+ PCI_EXP_SLTSTA_DLLSC);
|
|
|
|
+ status &= ~events;
|
|
|
|
+ events |= status;
|
|
|
|
+ if (!events)
|
|
return IRQ_NONE;
|
|
return IRQ_NONE;
|
|
- if (detected)
|
|
|
|
|
|
+ if (status)
|
|
pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
|
|
pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
|
|
- intr_loc);
|
|
|
|
- } while (detected);
|
|
|
|
|
|
+ events);
|
|
|
|
+ } while (status);
|
|
|
|
|
|
- ctrl_dbg(ctrl, "pending interrupts %#06x from Slot Status\n", intr_loc);
|
|
|
|
|
|
+ ctrl_dbg(ctrl, "pending interrupts %#06x from Slot Status\n", events);
|
|
|
|
|
|
/* Check Command Complete Interrupt Pending */
|
|
/* Check Command Complete Interrupt Pending */
|
|
- if (intr_loc & PCI_EXP_SLTSTA_CC) {
|
|
|
|
|
|
+ if (events & PCI_EXP_SLTSTA_CC) {
|
|
ctrl->cmd_busy = 0;
|
|
ctrl->cmd_busy = 0;
|
|
smp_mb();
|
|
smp_mb();
|
|
wake_up(&ctrl->queue);
|
|
wake_up(&ctrl->queue);
|
|
@@ -589,24 +593,24 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
|
|
list_for_each_entry(dev, &subordinate->devices, bus_list) {
|
|
list_for_each_entry(dev, &subordinate->devices, bus_list) {
|
|
if (dev->ignore_hotplug) {
|
|
if (dev->ignore_hotplug) {
|
|
ctrl_dbg(ctrl, "ignoring hotplug event %#06x (%s requested no hotplug)\n",
|
|
ctrl_dbg(ctrl, "ignoring hotplug event %#06x (%s requested no hotplug)\n",
|
|
- intr_loc, pci_name(dev));
|
|
|
|
|
|
+ events, pci_name(dev));
|
|
return IRQ_HANDLED;
|
|
return IRQ_HANDLED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- if (!(intr_loc & ~PCI_EXP_SLTSTA_CC))
|
|
|
|
|
|
+ if (!(events & ~PCI_EXP_SLTSTA_CC))
|
|
return IRQ_HANDLED;
|
|
return IRQ_HANDLED;
|
|
|
|
|
|
/* Check Attention Button Pressed */
|
|
/* Check Attention Button Pressed */
|
|
- if (intr_loc & PCI_EXP_SLTSTA_ABP) {
|
|
|
|
|
|
+ if (events & PCI_EXP_SLTSTA_ABP) {
|
|
ctrl_info(ctrl, "Button pressed on Slot(%s)\n",
|
|
ctrl_info(ctrl, "Button pressed on Slot(%s)\n",
|
|
slot_name(slot));
|
|
slot_name(slot));
|
|
pciehp_queue_interrupt_event(slot, INT_BUTTON_PRESS);
|
|
pciehp_queue_interrupt_event(slot, INT_BUTTON_PRESS);
|
|
}
|
|
}
|
|
|
|
|
|
/* Check Presence Detect Changed */
|
|
/* Check Presence Detect Changed */
|
|
- if (intr_loc & PCI_EXP_SLTSTA_PDC) {
|
|
|
|
|
|
+ if (events & PCI_EXP_SLTSTA_PDC) {
|
|
pciehp_get_adapter_status(slot, &present);
|
|
pciehp_get_adapter_status(slot, &present);
|
|
ctrl_info(ctrl, "Card %spresent on Slot(%s)\n",
|
|
ctrl_info(ctrl, "Card %spresent on Slot(%s)\n",
|
|
present ? "" : "not ", slot_name(slot));
|
|
present ? "" : "not ", slot_name(slot));
|
|
@@ -615,13 +619,13 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
|
|
}
|
|
}
|
|
|
|
|
|
/* Check Power Fault Detected */
|
|
/* Check Power Fault Detected */
|
|
- if ((intr_loc & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) {
|
|
|
|
|
|
+ if ((events & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) {
|
|
ctrl->power_fault_detected = 1;
|
|
ctrl->power_fault_detected = 1;
|
|
ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(slot));
|
|
ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(slot));
|
|
pciehp_queue_interrupt_event(slot, INT_POWER_FAULT);
|
|
pciehp_queue_interrupt_event(slot, INT_POWER_FAULT);
|
|
}
|
|
}
|
|
|
|
|
|
- if (intr_loc & PCI_EXP_SLTSTA_DLLSC) {
|
|
|
|
|
|
+ if (events & PCI_EXP_SLTSTA_DLLSC) {
|
|
link = pciehp_check_link_active(ctrl);
|
|
link = pciehp_check_link_active(ctrl);
|
|
ctrl_info(ctrl, "slot(%s): Link %s event\n",
|
|
ctrl_info(ctrl, "slot(%s): Link %s event\n",
|
|
slot_name(slot), link ? "Up" : "Down");
|
|
slot_name(slot), link ? "Up" : "Down");
|