drm/amdgpu: Guard reads in pcie state readout

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 <lijo.lazar@amd.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Lijo Lazar 2026-06-17 14:42:02 +05:30 committed by Alex Deucher
parent 323a09e56c
commit 230753e46a

View File

@ -591,6 +591,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)
{
@ -598,7 +621,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)
@ -630,25 +653,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);
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);
}
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;