wcxb: Disable presence detect reporting on upstream port during PCIe hard reset.
When the card goes through a reset the PCIe link will be brought down. Some slots will report this change upstream to the root port which will believe that the card has been hotplugged out of the system. This fixes cases on some systems where, during a firmware update, the card gets removed from the system's logical PCI tree with messages like the following in the kernel log: pciehp 0000:00:1c.0:pcie04: Card not present on Slot(259) pciehp 0000:00:1c.0:pcie04: Card present on Slot(259) Internal-Issue-ID: DAHDI-1091 Signed-off-by: Shaun Ruffell <sruffell@digium.com>
This commit is contained in:
@@ -45,10 +45,13 @@
|
||||
|
||||
/* The definition for Surprise Down was added in Linux 3.6 in (a0dee2e PCI: misc
|
||||
* pci_reg additions). It may be backported though so we won't check for the
|
||||
* version. */
|
||||
* version. Same with PCI_EXP_SLTCTL_PDCE. */
|
||||
#ifndef PCI_ERR_UNC_SURPDN
|
||||
#define PCI_ERR_UNC_SURPDN 0x20
|
||||
#endif
|
||||
#ifndef PCI_EXP_SLTCTL_PDCE
|
||||
#define PCI_EXP_SLTCTL_PDCE 0x8
|
||||
#endif
|
||||
|
||||
/* FPGA Status definitions */
|
||||
#define OCT_CPU_RESET (1 << 0)
|
||||
@@ -602,27 +605,41 @@ static void _wcxb_pcie_hard_reset(struct wcxb *xb)
|
||||
{
|
||||
struct pci_dev *const parent = xb->pdev->bus->self;
|
||||
u32 aer_mask;
|
||||
int pos;
|
||||
u16 sltctl;
|
||||
int pos_err;
|
||||
int pos_exp;
|
||||
|
||||
if (!wcxb_is_pcie(xb))
|
||||
return;
|
||||
|
||||
pos = pci_find_ext_capability(parent, PCI_EXT_CAP_ID_ERR);
|
||||
if (pos) {
|
||||
pci_read_config_dword(parent, pos + PCI_ERR_UNCOR_MASK,
|
||||
pos_err = pci_find_ext_capability(parent, PCI_EXT_CAP_ID_ERR);
|
||||
if (pos_err) {
|
||||
pci_read_config_dword(parent, pos_err + PCI_ERR_UNCOR_MASK,
|
||||
&aer_mask);
|
||||
pci_write_config_dword(parent, pos + PCI_ERR_UNCOR_MASK,
|
||||
pci_write_config_dword(parent, pos_err + PCI_ERR_UNCOR_MASK,
|
||||
aer_mask | PCI_ERR_UNC_SURPDN);
|
||||
}
|
||||
|
||||
/* Also disable any presence change reporting. */
|
||||
pos_exp = pci_find_capability(parent, PCI_CAP_ID_EXP);
|
||||
if (pos_exp) {
|
||||
pci_read_config_word(parent, pos_exp + PCI_EXP_SLTCTL,
|
||||
&sltctl);
|
||||
pci_write_config_word(parent, pos_exp + PCI_EXP_SLTCTL,
|
||||
sltctl & ~PCI_EXP_SLTCTL_PDCE);
|
||||
}
|
||||
|
||||
_wcxb_hard_reset(xb);
|
||||
|
||||
if (pos) {
|
||||
pci_write_config_dword(parent, pos + PCI_ERR_UNCOR_MASK,
|
||||
if (pos_exp)
|
||||
pci_write_config_word(parent, pos_exp + PCI_EXP_SLTCTL, sltctl);
|
||||
|
||||
if (pos_err) {
|
||||
pci_write_config_dword(parent, pos_err + PCI_ERR_UNCOR_MASK,
|
||||
aer_mask);
|
||||
|
||||
/* Clear the error as well from the status register. */
|
||||
pci_write_config_dword(parent, pos + PCI_ERR_UNCOR_STATUS,
|
||||
pci_write_config_dword(parent, pos_err + PCI_ERR_UNCOR_STATUS,
|
||||
PCI_ERR_UNC_SURPDN);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user