Skip to content

Commit c6c411a

Browse files
committed
Merge branch 'pci/dpc'
- After a DPC event, print all logged TLP Prefixes instead of printing the first prefix several times (Ilpo Järvinen) - Ignore the expected Surprise Down error that may cause a DPC event when hot-removing a device (Smita Koralahalli) - Add an RP PIO log size quirk for Intel Raptor Lake Root Ports, which still don't advertise the correct log size, which prevented logging of RP PIO Log registers when DPC is triggered (Paul Menzel) * pci/dpc: PCI/DPC: Quirk PIO log size for Intel Raptor Lake Root Ports PCI/DPC: Ignore Surprise Down error on hot removal PCI/DPC: Print all TLP Prefixes, not just the first
2 parents 47c94b2 + 627c6db commit c6c411a

File tree

2 files changed

+63
-1
lines changed

2 files changed

+63
-1
lines changed

drivers/pci/pcie/dpc.c

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ static void dpc_process_rp_pio_error(struct pci_dev *pdev)
228228

229229
for (i = 0; i < pdev->dpc_rp_log_size - 5; i++) {
230230
pci_read_config_dword(pdev,
231-
cap + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG, &prefix);
231+
cap + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG + i * 4, &prefix);
232232
pci_err(pdev, "TLP Prefix Header: dw%d, %#010x\n", i, prefix);
233233
}
234234
clear_status:
@@ -297,10 +297,70 @@ void dpc_process_error(struct pci_dev *pdev)
297297
}
298298
}
299299

300+
static void pci_clear_surpdn_errors(struct pci_dev *pdev)
301+
{
302+
if (pdev->dpc_rp_extensions)
303+
pci_write_config_dword(pdev, pdev->dpc_cap +
304+
PCI_EXP_DPC_RP_PIO_STATUS, ~0);
305+
306+
/*
307+
* In practice, Surprise Down errors have been observed to also set
308+
* error bits in the Status Register as well as the Fatal Error
309+
* Detected bit in the Device Status Register.
310+
*/
311+
pci_write_config_word(pdev, PCI_STATUS, 0xffff);
312+
313+
pcie_capability_write_word(pdev, PCI_EXP_DEVSTA, PCI_EXP_DEVSTA_FED);
314+
}
315+
316+
static void dpc_handle_surprise_removal(struct pci_dev *pdev)
317+
{
318+
if (!pcie_wait_for_link(pdev, false)) {
319+
pci_info(pdev, "Data Link Layer Link Active not cleared in 1000 msec\n");
320+
goto out;
321+
}
322+
323+
if (pdev->dpc_rp_extensions && dpc_wait_rp_inactive(pdev))
324+
goto out;
325+
326+
pci_aer_raw_clear_status(pdev);
327+
pci_clear_surpdn_errors(pdev);
328+
329+
pci_write_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_STATUS,
330+
PCI_EXP_DPC_STATUS_TRIGGER);
331+
332+
out:
333+
clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
334+
wake_up_all(&dpc_completed_waitqueue);
335+
}
336+
337+
static bool dpc_is_surprise_removal(struct pci_dev *pdev)
338+
{
339+
u16 status;
340+
341+
if (!pdev->is_hotplug_bridge)
342+
return false;
343+
344+
if (pci_read_config_word(pdev, pdev->aer_cap + PCI_ERR_UNCOR_STATUS,
345+
&status))
346+
return false;
347+
348+
return status & PCI_ERR_UNC_SURPDN;
349+
}
350+
300351
static irqreturn_t dpc_handler(int irq, void *context)
301352
{
302353
struct pci_dev *pdev = context;
303354

355+
/*
356+
* According to PCIe r6.0 sec 6.7.6, errors are an expected side effect
357+
* of async removal and should be ignored by software.
358+
*/
359+
if (dpc_is_surprise_removal(pdev)) {
360+
dpc_handle_surprise_removal(pdev);
361+
return IRQ_HANDLED;
362+
}
363+
304364
dpc_process_error(pdev);
305365

306366
/* We configure DPC so it only triggers on ERR_FATAL */

drivers/pci/quirks.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6225,6 +6225,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2b, dpc_log_size);
62256225
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2d, dpc_log_size);
62266226
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2f, dpc_log_size);
62276227
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a31, dpc_log_size);
6228+
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0xa73f, dpc_log_size);
6229+
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0xa76e, dpc_log_size);
62286230
#endif
62296231

62306232
/*

0 commit comments

Comments
 (0)