mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
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:
parent
323a09e56c
commit
230753e46a
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user