Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'pci/dpc' into next

* pci/dpc:
PCI/DPC: Wait for Root Port busy to clear
PCI/DPC: Decode extended reasons

+32 -3
+31 -3
drivers/pci/pcie/pcie-dpc.c
··· 19 19 struct pcie_device *dev; 20 20 struct work_struct work; 21 21 int cap_pos; 22 + bool rp; 22 23 }; 24 + 25 + static int dpc_wait_rp_inactive(struct dpc_dev *dpc) 26 + { 27 + unsigned long timeout = jiffies + HZ; 28 + struct pci_dev *pdev = dpc->dev->port; 29 + u16 status; 30 + 31 + pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS, &status); 32 + while (status & PCI_EXP_DPC_RP_BUSY && 33 + !time_after(jiffies, timeout)) { 34 + msleep(10); 35 + pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS, &status); 36 + } 37 + if (status & PCI_EXP_DPC_RP_BUSY) { 38 + dev_warn(&pdev->dev, "DPC root port still busy\n"); 39 + return -EBUSY; 40 + } 41 + return 0; 42 + } 23 43 24 44 static void dpc_wait_link_inactive(struct pci_dev *pdev) 25 45 { ··· 53 33 pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status); 54 34 } 55 35 if (lnk_status & PCI_EXP_LNKSTA_DLLLA) 56 - dev_warn(&pdev->dev, "Link state not disabled for DPC event"); 36 + dev_warn(&pdev->dev, "Link state not disabled for DPC event\n"); 57 37 } 58 38 59 39 static void interrupt_event_handler(struct work_struct *work) ··· 72 52 pci_unlock_rescan_remove(); 73 53 74 54 dpc_wait_link_inactive(pdev); 55 + if (dpc->rp && dpc_wait_rp_inactive(dpc)) 56 + return; 75 57 pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS, 76 58 PCI_EXP_DPC_STATUS_TRIGGER | PCI_EXP_DPC_STATUS_INTERRUPT); 77 59 } ··· 95 73 96 74 if (status & PCI_EXP_DPC_STATUS_TRIGGER) { 97 75 u16 reason = (status >> 1) & 0x3; 76 + u16 ext_reason = (status >> 5) & 0x3; 98 77 99 - dev_warn(&dpc->dev->device, "DPC %s triggered, remove downstream devices\n", 78 + dev_warn(&dpc->dev->device, "DPC %s detected, remove downstream devices\n", 100 79 (reason == 0) ? "unmasked uncorrectable error" : 101 80 (reason == 1) ? "ERR_NONFATAL" : 102 - (reason == 2) ? "ERR_FATAL" : "extended error"); 81 + (reason == 2) ? "ERR_FATAL" : 82 + (ext_reason == 0) ? "RP PIO error" : 83 + (ext_reason == 1) ? "software trigger" : 84 + "reserved error"); 103 85 schedule_work(&dpc->work); 104 86 } 105 87 return IRQ_HANDLED; ··· 136 110 137 111 pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CAP, &cap); 138 112 pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, &ctl); 113 + 114 + dpc->rp = (cap & PCI_EXP_DPC_CAP_RP_EXT); 139 115 140 116 ctl |= PCI_EXP_DPC_CTL_EN_NONFATAL | PCI_EXP_DPC_CTL_INT_EN; 141 117 pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, ctl);
+1
include/uapi/linux/pci_regs.h
··· 974 974 #define PCI_EXP_DPC_STATUS 8 /* DPC Status */ 975 975 #define PCI_EXP_DPC_STATUS_TRIGGER 0x01 /* Trigger Status */ 976 976 #define PCI_EXP_DPC_STATUS_INTERRUPT 0x08 /* Interrupt Status */ 977 + #define PCI_EXP_DPC_RP_BUSY 0x10 /* Root Port Busy */ 977 978 978 979 #define PCI_EXP_DPC_SOURCE_ID 10 /* DPC Source Identifier */ 979 980