Commit 7189576e authored by Ilpo Järvinen's avatar Ilpo Järvinen Committed by Bjorn Helgaas
Browse files

drm/radeon: Use RMW accessors for changing LNKCTL



Don't assume that only the driver would be accessing LNKCTL. ASPM policy
changes can trigger write to LNKCTL outside of driver's control.  And in
the case of upstream bridge, the driver does not even own the device it's
changing the registers for.

Use RMW capability accessors which do proper locking to avoid losing
concurrent updates to the register value.

Suggested-by: default avatarLukas Wunner <lukas@wunner.de>
Fixes: 8a7cd276 ("drm/radeon/cik: add support for pcie gen1/2/3 switching")
Fixes: b9d305df ("drm/radeon: implement pcie gen2/3 support for SI")
Link: https://lore.kernel.org/r/20230717120503.15276-7-ilpo.jarvinen@linux.intel.com


Signed-off-by: default avatarIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Acked-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent ce7d8811
Loading
Loading
Loading
Loading
+10 −26
Original line number Diff line number Diff line
@@ -9534,17 +9534,8 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev)
			u16 bridge_cfg2, gpu_cfg2;
			u32 max_lw, current_lw, tmp;

			pcie_capability_read_word(root, PCI_EXP_LNKCTL,
						  &bridge_cfg);
			pcie_capability_read_word(rdev->pdev, PCI_EXP_LNKCTL,
						  &gpu_cfg);

			tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD;
			pcie_capability_write_word(root, PCI_EXP_LNKCTL, tmp16);

			tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD;
			pcie_capability_write_word(rdev->pdev, PCI_EXP_LNKCTL,
						   tmp16);
			pcie_capability_set_word(root, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD);
			pcie_capability_set_word(rdev->pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD);

			tmp = RREG32_PCIE_PORT(PCIE_LC_STATUS1);
			max_lw = (tmp & LC_DETECTED_LINK_WIDTH_MASK) >> LC_DETECTED_LINK_WIDTH_SHIFT;
@@ -9591,21 +9582,14 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev)
				msleep(100);

				/* linkctl */
				pcie_capability_read_word(root, PCI_EXP_LNKCTL,
							  &tmp16);
				tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
				tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD);
				pcie_capability_write_word(root, PCI_EXP_LNKCTL,
							   tmp16);

				pcie_capability_read_word(rdev->pdev,
							  PCI_EXP_LNKCTL,
							  &tmp16);
				tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
				tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD);
				pcie_capability_write_word(rdev->pdev,
							   PCI_EXP_LNKCTL,
							   tmp16);
				pcie_capability_clear_and_set_word(root, PCI_EXP_LNKCTL,
								   PCI_EXP_LNKCTL_HAWD,
								   bridge_cfg &
								   PCI_EXP_LNKCTL_HAWD);
				pcie_capability_clear_and_set_word(rdev->pdev, PCI_EXP_LNKCTL,
								   PCI_EXP_LNKCTL_HAWD,
								   gpu_cfg &
								   PCI_EXP_LNKCTL_HAWD);

				/* linkctl2 */
				pcie_capability_read_word(root, PCI_EXP_LNKCTL2,
+10 −27
Original line number Diff line number Diff line
@@ -7131,17 +7131,8 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev)
			u16 bridge_cfg2, gpu_cfg2;
			u32 max_lw, current_lw, tmp;

			pcie_capability_read_word(root, PCI_EXP_LNKCTL,
						  &bridge_cfg);
			pcie_capability_read_word(rdev->pdev, PCI_EXP_LNKCTL,
						  &gpu_cfg);

			tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD;
			pcie_capability_write_word(root, PCI_EXP_LNKCTL, tmp16);

			tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD;
			pcie_capability_write_word(rdev->pdev, PCI_EXP_LNKCTL,
						   tmp16);
			pcie_capability_set_word(root, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD);
			pcie_capability_set_word(rdev->pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD);

			tmp = RREG32_PCIE(PCIE_LC_STATUS1);
			max_lw = (tmp & LC_DETECTED_LINK_WIDTH_MASK) >> LC_DETECTED_LINK_WIDTH_SHIFT;
@@ -7188,22 +7179,14 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev)
				msleep(100);

				/* linkctl */
				pcie_capability_read_word(root, PCI_EXP_LNKCTL,
							  &tmp16);
				tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
				tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD);
				pcie_capability_write_word(root,
							   PCI_EXP_LNKCTL,
							   tmp16);

				pcie_capability_read_word(rdev->pdev,
							  PCI_EXP_LNKCTL,
							  &tmp16);
				tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
				tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD);
				pcie_capability_write_word(rdev->pdev,
							   PCI_EXP_LNKCTL,
							   tmp16);
				pcie_capability_clear_and_set_word(root, PCI_EXP_LNKCTL,
								   PCI_EXP_LNKCTL_HAWD,
								   bridge_cfg &
								   PCI_EXP_LNKCTL_HAWD);
				pcie_capability_clear_and_set_word(rdev->pdev, PCI_EXP_LNKCTL,
								   PCI_EXP_LNKCTL_HAWD,
								   gpu_cfg &
								   PCI_EXP_LNKCTL_HAWD);

				/* linkctl2 */
				pcie_capability_read_word(root, PCI_EXP_LNKCTL2,