Internal US/DS switch may not be exposed in passthrough. Guard the
upstream port reads to avoid a NULL dereference.

Signed-off-by: Lijo Lazar <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c | 59 +++++++++++++++-------
 1 file changed, 42 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c 
b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c
index 72ea37dbfea8..5f1389901504 100644
--- a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c
+++ b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c
@@ -589,6 +589,29 @@ static struct aqua_reg_list pcie_reg_addrs[] = {
        { smreg_0x1A380088, 6, DW_ADDR_INCR },
 };
 
+/*
+ * Return the GPU's internal US switch port, or NULL if it is not visible
+ * (e.g. passthrough) or the EP is parented under an unrelated bridge.
+ */
+static struct pci_dev *aqua_vanjaram_get_us_pdev(struct amdgpu_device *adev)
+{
+       struct pci_dev *ds_pdev, *us_pdev;
+
+       ds_pdev = pci_upstream_bridge(adev->pdev);
+       if (!ds_pdev || ds_pdev->vendor != PCI_VENDOR_ID_ATI ||
+           pci_pcie_type(ds_pdev) != PCI_EXP_TYPE_DOWNSTREAM)
+               return NULL;
+
+       us_pdev = pci_upstream_bridge(ds_pdev);
+       if (!us_pdev ||
+           (us_pdev->vendor != PCI_VENDOR_ID_ATI &&
+            us_pdev->vendor != PCI_VENDOR_ID_AMD) ||
+           pci_pcie_type(us_pdev) != PCI_EXP_TYPE_UPSTREAM)
+               return NULL;
+
+       return us_pdev;
+}
+
 static ssize_t aqua_vanjaram_read_pcie_state(struct amdgpu_device *adev,
                                             void *buf, size_t max_size)
 {
@@ -596,7 +619,7 @@ static ssize_t aqua_vanjaram_read_pcie_state(struct 
amdgpu_device *adev,
        uint32_t start_addr, incrx, num_regs, szbuf;
        struct amdgpu_regs_pcie_v1_0 *pcie_regs;
        struct amdgpu_smn_reg_data *reg_data;
-       struct pci_dev *us_pdev, *ds_pdev;
+       struct pci_dev *us_pdev;
        int aer_cap, r, n;
 
        if (!buf || !max_size)
@@ -628,25 +651,27 @@ static ssize_t aqua_vanjaram_read_pcie_state(struct 
amdgpu_device *adev,
                }
        }
 
-       ds_pdev = pci_upstream_bridge(adev->pdev);
-       us_pdev = pci_upstream_bridge(ds_pdev);
+       us_pdev = aqua_vanjaram_get_us_pdev(adev);
+       if (us_pdev) {
+               pcie_capability_read_word(us_pdev, PCI_EXP_DEVSTA,
+                                         &pcie_regs->device_status);
+               pcie_capability_read_word(us_pdev, PCI_EXP_LNKSTA,
+                                         &pcie_regs->link_status);
+
+               aer_cap = pci_find_ext_capability(us_pdev, PCI_EXT_CAP_ID_ERR);
+               if (aer_cap) {
+                       pci_read_config_dword(us_pdev,
+                                             aer_cap + PCI_ERR_COR_STATUS,
+                                             &pcie_regs->pcie_corr_err_status);
+                       pci_read_config_dword(us_pdev,
+                                             aer_cap + PCI_ERR_UNCOR_STATUS,
+                                             
&pcie_regs->pcie_uncorr_err_status);
+               }
 
-       pcie_capability_read_word(us_pdev, PCI_EXP_DEVSTA,
-                                 &pcie_regs->device_status);
-       pcie_capability_read_word(us_pdev, PCI_EXP_LNKSTA,
-                                 &pcie_regs->link_status);
-
-       aer_cap = pci_find_ext_capability(us_pdev, PCI_EXT_CAP_ID_ERR);
-       if (aer_cap) {
-               pci_read_config_dword(us_pdev, aer_cap + PCI_ERR_COR_STATUS,
-                                     &pcie_regs->pcie_corr_err_status);
-               pci_read_config_dword(us_pdev, aer_cap + PCI_ERR_UNCOR_STATUS,
-                                     &pcie_regs->pcie_uncorr_err_status);
+               pci_read_config_dword(us_pdev, PCI_PRIMARY_BUS,
+                                     &pcie_regs->sub_bus_number_latency);
        }
 
-       pci_read_config_dword(us_pdev, PCI_PRIMARY_BUS,
-                             &pcie_regs->sub_bus_number_latency);
-
        pcie_reg_state->common_header.structure_size = szbuf;
        pcie_reg_state->common_header.format_revision = 1;
        pcie_reg_state->common_header.content_revision = 0;
-- 
2.49.0

Reply via email to