PCI pciehp: fix power fault interrupt storm problem
Enabling power fault detected event notification in current pciehp might cause power fault interrupt storm on some machines. On those machines. On those machines, power fault detected bit in the slot status register was set again immediately when it is cleared in the interrupt service routine, and next power fault detected interrupt was notified again. Therefore, disable power fault detected event notification for now. This patch also removes unnecessary handling for power fault cleared event because this event is not supported by PCIe spec. Tested-by: Jens Axboe <jens.axboe@oracle.com> Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
This commit is contained in:
parent
13598378f2
commit
5651c48cfa
2 changed files with 17 additions and 36 deletions
|
@ -142,23 +142,9 @@ u8 pciehp_handle_power_fault(struct slot *p_slot)
|
||||||
|
|
||||||
/* power fault */
|
/* power fault */
|
||||||
ctrl_dbg(ctrl, "Power fault interrupt received\n");
|
ctrl_dbg(ctrl, "Power fault interrupt received\n");
|
||||||
|
ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot));
|
||||||
if (!pciehp_query_power_fault(p_slot)) {
|
|
||||||
/*
|
|
||||||
* power fault Cleared
|
|
||||||
*/
|
|
||||||
ctrl_info(ctrl, "Power fault cleared on Slot(%s)\n",
|
|
||||||
slot_name(p_slot));
|
|
||||||
event_type = INT_POWER_FAULT_CLEAR;
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* power fault
|
|
||||||
*/
|
|
||||||
ctrl_info(ctrl, "Power fault on Slot(%s)\n", slot_name(p_slot));
|
|
||||||
event_type = INT_POWER_FAULT;
|
event_type = INT_POWER_FAULT;
|
||||||
ctrl_info(ctrl, "Power fault bit %x set\n", 0);
|
ctrl_info(ctrl, "Power fault bit %x set\n", 0);
|
||||||
}
|
|
||||||
|
|
||||||
queue_interrupt_event(p_slot, event_type);
|
queue_interrupt_event(p_slot, event_type);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -224,13 +210,12 @@ static int board_added(struct slot *p_slot)
|
||||||
retval = pciehp_check_link_status(ctrl);
|
retval = pciehp_check_link_status(ctrl);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
ctrl_err(ctrl, "Failed to check link status\n");
|
ctrl_err(ctrl, "Failed to check link status\n");
|
||||||
set_slot_off(ctrl, p_slot);
|
goto err_exit;
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for a power fault */
|
/* Check for a power fault */
|
||||||
if (pciehp_query_power_fault(p_slot)) {
|
if (ctrl->power_fault_detected || pciehp_query_power_fault(p_slot)) {
|
||||||
ctrl_dbg(ctrl, "Power fault detected\n");
|
ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot));
|
||||||
retval = -EIO;
|
retval = -EIO;
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
}
|
}
|
||||||
|
|
|
@ -511,15 +511,10 @@ int pciehp_power_on_slot(struct slot * slot)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ctrl->power_fault_detected = 0;
|
||||||
|
|
||||||
slot_cmd = POWER_ON;
|
slot_cmd = POWER_ON;
|
||||||
cmd_mask = PCI_EXP_SLTCTL_PCC;
|
cmd_mask = PCI_EXP_SLTCTL_PCC;
|
||||||
if (!pciehp_poll_mode) {
|
|
||||||
/* Enable power fault detection turned off at power off time */
|
|
||||||
slot_cmd |= PCI_EXP_SLTCTL_PFDE;
|
|
||||||
cmd_mask |= PCI_EXP_SLTCTL_PFDE;
|
|
||||||
}
|
|
||||||
|
|
||||||
retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
|
retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
ctrl_err(ctrl, "Write %x command failed!\n", slot_cmd);
|
ctrl_err(ctrl, "Write %x command failed!\n", slot_cmd);
|
||||||
|
@ -528,7 +523,6 @@ int pciehp_power_on_slot(struct slot * slot)
|
||||||
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
|
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
|
||||||
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd);
|
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd);
|
||||||
|
|
||||||
ctrl->power_fault_detected = 0;
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,12 +535,6 @@ int pciehp_power_off_slot(struct slot * slot)
|
||||||
|
|
||||||
slot_cmd = POWER_OFF;
|
slot_cmd = POWER_OFF;
|
||||||
cmd_mask = PCI_EXP_SLTCTL_PCC;
|
cmd_mask = PCI_EXP_SLTCTL_PCC;
|
||||||
if (!pciehp_poll_mode) {
|
|
||||||
/* Disable power fault detection */
|
|
||||||
slot_cmd &= ~PCI_EXP_SLTCTL_PFDE;
|
|
||||||
cmd_mask |= PCI_EXP_SLTCTL_PFDE;
|
|
||||||
}
|
|
||||||
|
|
||||||
retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
|
retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
ctrl_err(ctrl, "Write command failed!\n");
|
ctrl_err(ctrl, "Write command failed!\n");
|
||||||
|
@ -790,11 +778,19 @@ int pcie_enable_notification(struct controller *ctrl)
|
||||||
{
|
{
|
||||||
u16 cmd, mask;
|
u16 cmd, mask;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TBD: Power fault detected software notification support.
|
||||||
|
*
|
||||||
|
* Power fault detected software notification is not enabled
|
||||||
|
* now, because it caused power fault detected interrupt storm
|
||||||
|
* on some machines. On those machines, power fault detected
|
||||||
|
* bit in the slot status register was set again immediately
|
||||||
|
* when it is cleared in the interrupt service routine, and
|
||||||
|
* next power fault detected interrupt was notified again.
|
||||||
|
*/
|
||||||
cmd = PCI_EXP_SLTCTL_PDCE;
|
cmd = PCI_EXP_SLTCTL_PDCE;
|
||||||
if (ATTN_BUTTN(ctrl))
|
if (ATTN_BUTTN(ctrl))
|
||||||
cmd |= PCI_EXP_SLTCTL_ABPE;
|
cmd |= PCI_EXP_SLTCTL_ABPE;
|
||||||
if (POWER_CTRL(ctrl))
|
|
||||||
cmd |= PCI_EXP_SLTCTL_PFDE;
|
|
||||||
if (MRL_SENS(ctrl))
|
if (MRL_SENS(ctrl))
|
||||||
cmd |= PCI_EXP_SLTCTL_MRLSCE;
|
cmd |= PCI_EXP_SLTCTL_MRLSCE;
|
||||||
if (!pciehp_poll_mode)
|
if (!pciehp_poll_mode)
|
||||||
|
|
Loading…
Add table
Reference in a new issue