On Tue, Sep 15, 2026 at 12:09 PM Mario Limonciello <[email protected]> wrote: > > Commit eb53125a7ad9 ("drm/amd: Add dedicated helper for > amdgpu_device_find_parent()") made amdgpu_device_gpu_bandwidth() query > the first device outside the dGPU. That is the host side of the > physical link, not the GPU side. > > As a result, the ASIC and platform capability masks can both be based > on the host port. drm_amdgpu_info_device then exposes the host > capabilities to userspace, such as Gen5 x16 for a Gen4 x8 GPU. > > Cache both ends of the physical link during device initialization. > Use link_dev for the GPU capability and link_partner for the platform > capability and _PR3 detection. > > Reported-by: "Marek Olšák" <[email protected]> > Closes: > https://lore.kernel.org/amd-gfx/caaxe2a4vhsazzo1qjbjug+ngnbd04zzmyn6xsujxjkjhh6h...@mail.gmail.com/ > Suggested-by: Lijo Lazar <[email protected]> > Fixes: eb53125a7ad9 ("drm/amd: Add dedicated helper for > amdgpu_device_find_parent()") > Cc: [email protected] > Signed-off-by: Mario Limonciello <[email protected]>
Reviewed-by: Alex Deucher <[email protected]> > --- > drivers/gpu/drm/amd/amdgpu/amdgpu.h | 3 ++ > drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 48 ++++++++-------------- > 2 files changed, 20 insertions(+), 31 deletions(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h > b/drivers/gpu/drm/amd/amdgpu/amdgpu.h > index 79b69d74eb2e5..3bad7b8f621cc 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h > @@ -626,6 +626,9 @@ enum amdgpu_enforce_isolation_mode { > struct amdgpu_device { > struct device *dev; > struct pci_dev *pdev; > + /* The two ends of the physical PCIe link outside the device. */ > + struct pci_dev *link_dev; > + struct pci_dev *link_partner; > struct drm_device ddev; > > #ifdef CONFIG_DRM_AMD_ACP > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c > b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c > index 44091ac12fa9c..0d277516fd55e 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c > @@ -1959,18 +1959,17 @@ static void amdgpu_uid_fini(struct amdgpu_device > *adev) > adev->uid_info = NULL; > } > > -static struct pci_dev *amdgpu_device_find_parent(struct amdgpu_device *adev) > +static void amdgpu_device_init_pcie_links(struct amdgpu_device *adev) > { > - struct pci_dev *parent = adev->pdev; > + adev->link_dev = adev->pdev; > + adev->link_partner = pci_upstream_bridge(adev->link_dev); > > - /* skip upstream/downstream switches internal to dGPU */ > - while ((parent = pci_upstream_bridge(parent))) { > - if (parent->vendor == PCI_VENDOR_ID_ATI) > - continue; > - break; > + /* Skip upstream/downstream switches internal to the dGPU. */ > + while (adev->link_partner && > + adev->link_partner->vendor == PCI_VENDOR_ID_ATI) { > + adev->link_dev = adev->link_partner; > + adev->link_partner = pci_upstream_bridge(adev->link_dev); > } > - > - return parent; > } > > /** > @@ -1986,7 +1985,6 @@ static struct pci_dev *amdgpu_device_find_parent(struct > amdgpu_device *adev) > static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) > { > struct amdgpu_ip_block *ip_block; > - struct pci_dev *parent; > bool total, skip_bios, early_full_gpu_access = false; > uint32_t bios_flags; > int i, r; > @@ -2082,10 +2080,9 @@ static int amdgpu_device_ip_early_init(struct > amdgpu_device *adev) > !dev_is_removable(&adev->pdev->dev)) > adev->flags |= AMD_IS_PX; > > - if (!(adev->flags & AMD_IS_APU)) { > - parent = amdgpu_device_find_parent(adev); > - adev->has_pr3 = parent ? pci_pr3_present(parent) : false; > - } > + if (!(adev->flags & AMD_IS_APU)) > + adev->has_pr3 = adev->link_partner && > + pci_pr3_present(adev->link_partner); > > adev->pm.pp_feature = amdgpu_pp_feature_mask; > if (amdgpu_sriov_vf(adev) || sched_policy == KFD_SCHED_POLICY_NO_HWS) > @@ -3783,6 +3780,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, > > adev->shutdown = false; > adev->flags = flags; > + amdgpu_device_init_pcie_links(adev); > > if (amdgpu_force_asic_type >= 0 && amdgpu_force_asic_type < CHIP_LAST) > adev->asic_type = amdgpu_force_asic_type; > @@ -5880,11 +5878,9 @@ static void amdgpu_device_partner_bandwidth(struct > amdgpu_device *adev, > *width = PCIE_LNK_WIDTH_UNKNOWN; > > if (amdgpu_device_pcie_dynamic_switching_supported(adev)) { > - struct pci_dev *parent = amdgpu_device_find_parent(adev); > - > - if (parent) { > - *speed = pcie_get_speed_cap(parent); > - *width = pcie_get_width_cap(parent); > + if (adev->link_partner) { > + *speed = pcie_get_speed_cap(adev->link_partner); > + *width = pcie_get_width_cap(adev->link_partner); > } > } else { > /* use the current speeds rather than max if switching is not > supported */ > @@ -5906,21 +5902,11 @@ static void amdgpu_device_gpu_bandwidth(struct > amdgpu_device *adev, > enum pci_bus_speed *speed, > enum pcie_link_width *width) > { > - struct pci_dev *parent = adev->pdev; > - > if (!speed || !width) > return; > > - /* use the device itself */ > - *speed = pcie_get_speed_cap(adev->pdev); > - *width = pcie_get_width_cap(adev->pdev); > - > - /* use the link outside the device */ > - parent = amdgpu_device_find_parent(adev); > - if (parent) { > - *speed = pcie_get_speed_cap(parent); > - *width = pcie_get_width_cap(parent); > - } > + *speed = pcie_get_speed_cap(adev->link_dev); > + *width = pcie_get_width_cap(adev->link_dev); > } > > /** > -- > 2.43.0 >
