staticconstchar * const rp_pio_error_string[] = { "Configuration Request received UR Completion", /* Bit Position 0 */ "Configuration Request received CA Completion", /* Bit Position 1 */ "Configuration Request Completion Timeout", /* Bit Position 2 */
NULL,
NULL,
NULL,
NULL,
NULL, "I/O Request received UR Completion", /* Bit Position 8 */ "I/O Request received CA Completion", /* Bit Position 9 */ "I/O Request Completion Timeout", /* Bit Position 10 */
NULL,
NULL,
NULL,
NULL,
NULL, "Memory Request received UR Completion", /* Bit Position 16 */ "Memory Request received CA Completion", /* Bit Position 17 */ "Memory Request Completion Timeout", /* Bit Position 18 */
};
if (test_bit(PCI_DPC_RECOVERING, &pdev->priv_flags)) returnfalse;
returntrue;
}
/** * pci_dpc_recovered - whether DPC triggered and has recovered successfully * @pdev: PCI device * * Return true if DPC was triggered for @pdev and has recovered successfully. * Wait for recovery if it hasn't completed yet. Called from the PCIe hotplug * driver to recognize and ignore Link Down/Up events caused by DPC.
*/ bool pci_dpc_recovered(struct pci_dev *pdev)
{ struct pci_host_bridge *host;
if (!pdev->dpc_cap) returnfalse;
/* * Synchronization between hotplug and DPC is not supported * if DPC is owned by firmware and EDR is not enabled.
*/
host = pci_find_host_bridge(pdev->bus); if (!host->native_dpc && !IS_ENABLED(CONFIG_PCIE_EDR)) returnfalse;
/* * Need a timeout in case DPC never completes due to failure of * dpc_wait_rp_inactive(). The spec doesn't mandate a time limit, * but reports indicate that DPC completes within 4 seconds.
*/
wait_event_timeout(dpc_completed_waitqueue, dpc_completed(pdev),
msecs_to_jiffies(4000));
/* * DPC disables the Link automatically in hardware, so it has * already been reset by the time we get here.
*/
cap = pdev->dpc_cap;
/* * Wait until the Link is inactive, then clear DPC Trigger Status * to allow the Port to leave DPC.
*/ if (!pcie_wait_for_link(pdev, false))
pci_info(pdev, "Data Link Layer Link Active not cleared in 1000 msec\n");
if (pdev->dpc_rp_extensions && dpc_wait_rp_inactive(pdev)) {
clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
ret = PCI_ERS_RESULT_DISCONNECT; goto out;
}
pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS,
PCI_EXP_DPC_STATUS_TRIGGER);
if (pci_bridge_wait_for_secondary_bus(pdev, "DPC")) {
clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
ret = PCI_ERS_RESULT_DISCONNECT;
} else {
set_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
ret = PCI_ERS_RESULT_RECOVERED;
}
out:
clear_bit(PCI_DPC_RECOVERING, &pdev->priv_flags);
wake_up_all(&dpc_completed_waitqueue); return ret;
}
pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS, &status);
pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_MASK, &mask);
pci_err(pdev, "rp_pio_status: %#010x, rp_pio_mask: %#010x\n",
status, mask);
pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_SEVERITY, &sev);
pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_SYSERROR, &syserr);
pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_EXCEPTION, &exc);
pci_err(pdev, "RP PIO severity=%#010x, syserror=%#010x, exception=%#010x\n",
sev, syserr, exc);
/* Get First Error Pointer */
pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &dpc_status);
first_error = FIELD_GET(PCI_EXP_DPC_RP_PIO_FEP, dpc_status);
for (i = 0; i < ARRAY_SIZE(rp_pio_error_string); i++) { if ((status & ~mask) & (1 << i))
pci_err(pdev, "[%2d] %s%s\n", i, rp_pio_error_string[i],
first_error == i ? " (First)" : "");
}
if (pdev->dpc_rp_log_size < PCIE_STD_NUM_TLP_HEADERLOG) goto clear_status;
pcie_read_tlp_log(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG,
cap + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG,
dpc_tlp_log_len(pdev),
pdev->subordinate->flit_mode,
&tlp_log);
pcie_print_tlp_log(pdev, &tlp_log, KERN_ERR, dev_fmt(""));
if (pdev->dpc_rp_log_size < PCIE_STD_NUM_TLP_HEADERLOG + 1) goto clear_status;
pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_IMPSPEC_LOG, &log);
pci_err(pdev, "RP PIO ImpSpec Log %#010x\n", log);
clear_status:
pci_write_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS, status);
}
/* * In practice, Surprise Down errors have been observed to also set * error bits in the Status Register as well as the Fatal Error * Detected bit in the Device Status Register.
*/
pci_write_config_word(pdev, PCI_STATUS, 0xffff);
staticvoid dpc_handle_surprise_removal(struct pci_dev *pdev)
{ if (!pcie_wait_for_link(pdev, false)) {
pci_info(pdev, "Data Link Layer Link Active not cleared in 1000 msec\n"); goto out;
}
if (pdev->dpc_rp_extensions && dpc_wait_rp_inactive(pdev)) goto out;
/* * According to PCIe r6.0 sec 6.7.6, errors are an expected side effect * of async removal and should be ignored by software.
*/ if (dpc_is_surprise_removal(pdev)) {
dpc_handle_surprise_removal(pdev); return IRQ_HANDLED;
}
dpc_process_error(pdev);
/* We configure DPC so it only triggers on ERR_FATAL */
pcie_do_recovery(pdev, pci_channel_io_frozen, dpc_reset_link);
/* * Clear DPC Interrupt Status so we don't get an interrupt for an * old event when setting DPC Interrupt Enable.
*/
pci_write_config_word(pdev, dpc + PCI_EXP_DPC_STATUS,
PCI_EXP_DPC_STATUS_INTERRUPT);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.