Skip to content

Commit 377a0dc

Browse files
committed
NVIDIA: SAUCE: PCI: quirks: mirror PI7C9X3G606GPC Port 4 BAR0
Some Pericom/Diodes PI7C9X3G606GPC switches require downstream Port 4 BAR0 to mirror BAR0 of the immediate upstream port. Firmware may apply this during boot, but Linux PCI resource assignment can move the upstream BAR0 and leave Port 4 without the required mirror. Diodes confirmed that Tile0/P4 is OS-visible as device 04, function 0 on the bus below the upstream port. Add a final and resume quirk for that downstream function. The quirk verifies that the immediate upstream bridge is the same switch, then writes Port 4 BAR0 from the upstream BAR0 after resource assignment and after resume. Port 4 BAR0 may read back as zero even after a successful write, so the write must be validated by platform-specific means. Signed-off-by: Nirmoy Das <nirmoyd@nvidia.com>
1 parent 42cad5f commit 377a0dc

2 files changed

Lines changed: 59 additions & 0 deletions

File tree

drivers/pci/quirks.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6261,6 +6261,64 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0x2303,
62616261
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0x2303,
62626262
pci_fixup_pericom_acs_store_forward);
62636263

6264+
/*
6265+
* Some Pericom/Diodes PI7C9X3G606GPC switches require downstream Port 4
6266+
* BAR 0 to mirror BAR 0 of the immediate upstream port. Firmware may
6267+
* program this during boot, but Linux resource assignment can move the
6268+
* upstream BAR.
6269+
*
6270+
* Diodes confirmed Tile0/P4 appears to Linux as device 4, function 0 on
6271+
* the bus below the upstream port. Match that downstream function and
6272+
* re-apply the mirror after resource assignment and resume.
6273+
*/
6274+
static void pci_fixup_pericom_pi7c9x3g606gpc_bar0_mirror(struct pci_dev *pdev)
6275+
{
6276+
struct pci_dev *upstream;
6277+
u32 bar, upstream_bar;
6278+
6279+
if (pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM)
6280+
return;
6281+
6282+
if (PCI_SLOT(pdev->devfn) != 4 || PCI_FUNC(pdev->devfn))
6283+
return;
6284+
6285+
upstream = pci_upstream_bridge(pdev);
6286+
if (!upstream || upstream->vendor != PCI_VENDOR_ID_PERICOM ||
6287+
upstream->device != PCI_DEVICE_ID_PERICOM_PI7C9X3G606GPC ||
6288+
pci_pcie_type(upstream) != PCI_EXP_TYPE_UPSTREAM)
6289+
return;
6290+
6291+
pci_read_config_dword(upstream, PCI_BASE_ADDRESS_0, &upstream_bar);
6292+
if (upstream_bar & PCI_BASE_ADDRESS_SPACE_IO)
6293+
return;
6294+
6295+
if ((upstream_bar & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
6296+
PCI_BASE_ADDRESS_MEM_TYPE_64) {
6297+
pci_warn(pdev, "skipping PI7C9X3G606GPC BAR0 mirror workaround for 64-bit upstream BAR 0\n");
6298+
return;
6299+
}
6300+
6301+
if (!(upstream_bar & PCI_BASE_ADDRESS_MEM_MASK)) {
6302+
pci_warn(pdev, "skipping PI7C9X3G606GPC BAR0 mirror workaround because upstream BAR 0 is unassigned\n");
6303+
return;
6304+
}
6305+
6306+
pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &bar);
6307+
if (bar == upstream_bar)
6308+
return;
6309+
6310+
/* Port 4 BAR 0 may read back as zero even after a successful write. */
6311+
pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, upstream_bar);
6312+
pci_info(pdev, "wrote upstream BAR 0 %#x to Port 4 BAR 0 for PI7C9X3G606GPC BAR0 mirror workaround\n",
6313+
upstream_bar);
6314+
}
6315+
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_PERICOM,
6316+
PCI_DEVICE_ID_PERICOM_PI7C9X3G606GPC,
6317+
pci_fixup_pericom_pi7c9x3g606gpc_bar0_mirror);
6318+
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM,
6319+
PCI_DEVICE_ID_PERICOM_PI7C9X3G606GPC,
6320+
pci_fixup_pericom_pi7c9x3g606gpc_bar0_mirror);
6321+
62646322
static void nvidia_ion_ahci_fixup(struct pci_dev *pdev)
62656323
{
62666324
pdev->dev_flags |= PCI_DEV_FLAGS_HAS_MSI_MASKING;

include/linux/pci_ids.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1850,6 +1850,7 @@
18501850
#define PCI_DEVICE_ID_NVIDIA_SGS_RIVA128 0x0018
18511851

18521852
#define PCI_VENDOR_ID_PERICOM 0x12D8
1853+
#define PCI_DEVICE_ID_PERICOM_PI7C9X3G606GPC 0xc008
18531854
#define PCI_DEVICE_ID_PERICOM_PI7C9X7951 0x7951
18541855
#define PCI_DEVICE_ID_PERICOM_PI7C9X7952 0x7952
18551856
#define PCI_DEVICE_ID_PERICOM_PI7C9X7954 0x7954

0 commit comments

Comments
 (0)