Merge branch 'pci/pcie-rmw'
- Add locking for read/modify/write PCIe Capability Register accessors for Link Control and Root Control (Ilpo Järvinen) - Use PCIe RMW accessors for Link Control updates in PCI core, pciehp, amdgpu, radeon, mlx5, ath10k, ath11k, ath12k (Ilpo Järvinen) - Convert PCIBIOS error values in mlx5 to generic errnos (Ilpo Järvinen) - Simplify pcie_capability_clear_and_set_word() control flow (Bjorn Helgaas) * pci/pcie-rmw: PCI: Simplify pcie_capability_clear_and_set_word() control flow net/mlx5: Convert PCI error values to generic errnos PCI: Document the Capability accessor RMW improvements wifi: ath10k: Use RMW accessors for changing LNKCTL wifi: ath12k: Use RMW accessors for changing LNKCTL wifi: ath11k: Use RMW accessors for changing LNKCTL net/mlx5: Use RMW accessors for changing LNKCTL drm/radeon: Use RMW accessors for changing LNKCTL drm/amdgpu: Use RMW accessors for changing LNKCTL PCI/ASPM: Use RMW accessors for changing LNKCTL PCI: pciehp: Use RMW accessors for changing LNKCTL PCI: Make link retraining use RMW accessors for changing LNKCTL PCI: Add locking to RMW PCI Express Capability Register accessors
This commit is contained in:
commit
8b524514e4
|
@ -213,8 +213,12 @@ PCI Config Registers
|
|||
--------------------
|
||||
|
||||
Each service driver runs its PCI config operations on its own
|
||||
capability structure except the PCI Express capability structure, in
|
||||
which Root Control register and Device Control register are shared
|
||||
between PME and AER. This patch assumes that all service drivers
|
||||
will be well behaved and not overwrite other service driver's
|
||||
configuration settings.
|
||||
capability structure except the PCI Express capability structure,
|
||||
that is shared between many drivers including the service drivers.
|
||||
RMW Capability accessors (pcie_capability_clear_and_set_word(),
|
||||
pcie_capability_set_word(), and pcie_capability_clear_word()) protect
|
||||
a selected set of PCI Express Capability Registers (Link Control
|
||||
Register and Root Control Register). Any change to those registers
|
||||
should be performed using RMW accessors to avoid problems due to
|
||||
concurrent updates. For the up-to-date list of protected registers,
|
||||
see pcie_capability_clear_and_set_word().
|
||||
|
|
|
@ -1574,17 +1574,8 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev)
|
|||
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(adev->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(adev->pdev, PCI_EXP_LNKCTL,
|
||||
tmp16);
|
||||
pcie_capability_set_word(root, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD);
|
||||
pcie_capability_set_word(adev->pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD);
|
||||
|
||||
tmp = RREG32_PCIE(ixPCIE_LC_STATUS1);
|
||||
max_lw = (tmp & PCIE_LC_STATUS1__LC_DETECTED_LINK_WIDTH_MASK) >>
|
||||
|
@ -1637,21 +1628,14 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev)
|
|||
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(adev->pdev,
|
||||
PCI_EXP_LNKCTL,
|
||||
&tmp16);
|
||||
tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
|
||||
tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD);
|
||||
pcie_capability_write_word(adev->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(adev->pdev, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_HAWD,
|
||||
gpu_cfg &
|
||||
PCI_EXP_LNKCTL_HAWD);
|
||||
|
||||
/* linkctl2 */
|
||||
pcie_capability_read_word(root, PCI_EXP_LNKCTL2,
|
||||
|
|
|
@ -2276,17 +2276,8 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev)
|
|||
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(adev->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(adev->pdev, PCI_EXP_LNKCTL,
|
||||
tmp16);
|
||||
pcie_capability_set_word(root, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_HAWD);
|
||||
pcie_capability_set_word(adev->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;
|
||||
|
@ -2331,21 +2322,14 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev)
|
|||
|
||||
mdelay(100);
|
||||
|
||||
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(adev->pdev,
|
||||
PCI_EXP_LNKCTL,
|
||||
&tmp16);
|
||||
tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
|
||||
tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD);
|
||||
pcie_capability_write_word(adev->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(adev->pdev, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_HAWD,
|
||||
gpu_cfg &
|
||||
PCI_EXP_LNKCTL_HAWD);
|
||||
|
||||
pcie_capability_read_word(root, PCI_EXP_LNKCTL2,
|
||||
&tmp16);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -311,7 +311,7 @@ static int mlx5_check_dev_ids(struct mlx5_core_dev *dev, u16 dev_id)
|
|||
list_for_each_entry(sdev, &bridge_bus->devices, bus_list) {
|
||||
err = pci_read_config_word(sdev, PCI_DEVICE_ID, &sdev_id);
|
||||
if (err)
|
||||
return err;
|
||||
return pcibios_err_to_errno(err);
|
||||
if (sdev_id != dev_id) {
|
||||
mlx5_core_warn(dev, "unrecognized dev_id (0x%x)\n", sdev_id);
|
||||
return -EPERM;
|
||||
|
@ -371,7 +371,7 @@ static int mlx5_pci_link_toggle(struct mlx5_core_dev *dev)
|
|||
|
||||
err = pci_read_config_word(dev->pdev, PCI_DEVICE_ID, &dev_id);
|
||||
if (err)
|
||||
return err;
|
||||
return pcibios_err_to_errno(err);
|
||||
err = mlx5_check_dev_ids(dev, dev_id);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -384,18 +384,13 @@ static int mlx5_pci_link_toggle(struct mlx5_core_dev *dev)
|
|||
pci_cfg_access_lock(sdev);
|
||||
}
|
||||
/* PCI link toggle */
|
||||
err = pci_read_config_word(bridge, cap + PCI_EXP_LNKCTL, ®16);
|
||||
err = pcie_capability_set_word(bridge, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_LD);
|
||||
if (err)
|
||||
return err;
|
||||
reg16 |= PCI_EXP_LNKCTL_LD;
|
||||
err = pci_write_config_word(bridge, cap + PCI_EXP_LNKCTL, reg16);
|
||||
if (err)
|
||||
return err;
|
||||
return pcibios_err_to_errno(err);
|
||||
msleep(500);
|
||||
reg16 &= ~PCI_EXP_LNKCTL_LD;
|
||||
err = pci_write_config_word(bridge, cap + PCI_EXP_LNKCTL, reg16);
|
||||
err = pcie_capability_clear_word(bridge, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_LD);
|
||||
if (err)
|
||||
return err;
|
||||
return pcibios_err_to_errno(err);
|
||||
|
||||
/* Check link */
|
||||
if (!bridge->link_active_reporting) {
|
||||
|
@ -408,7 +403,7 @@ static int mlx5_pci_link_toggle(struct mlx5_core_dev *dev)
|
|||
do {
|
||||
err = pci_read_config_word(bridge, cap + PCI_EXP_LNKSTA, ®16);
|
||||
if (err)
|
||||
return err;
|
||||
return pcibios_err_to_errno(err);
|
||||
if (reg16 & PCI_EXP_LNKSTA_DLLLA)
|
||||
break;
|
||||
msleep(20);
|
||||
|
@ -426,7 +421,7 @@ static int mlx5_pci_link_toggle(struct mlx5_core_dev *dev)
|
|||
do {
|
||||
err = pci_read_config_word(dev->pdev, PCI_DEVICE_ID, ®16);
|
||||
if (err)
|
||||
return err;
|
||||
return pcibios_err_to_errno(err);
|
||||
if (reg16 == dev_id)
|
||||
break;
|
||||
msleep(20);
|
||||
|
|
|
@ -1963,8 +1963,9 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
|
|||
ath10k_pci_irq_enable(ar);
|
||||
ath10k_pci_rx_post(ar);
|
||||
|
||||
pcie_capability_write_word(ar_pci->pdev, PCI_EXP_LNKCTL,
|
||||
ar_pci->link_ctl);
|
||||
pcie_capability_clear_and_set_word(ar_pci->pdev, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_ASPMC,
|
||||
ar_pci->link_ctl & PCI_EXP_LNKCTL_ASPMC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2821,8 +2822,8 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar,
|
|||
|
||||
pcie_capability_read_word(ar_pci->pdev, PCI_EXP_LNKCTL,
|
||||
&ar_pci->link_ctl);
|
||||
pcie_capability_write_word(ar_pci->pdev, PCI_EXP_LNKCTL,
|
||||
ar_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
|
||||
pcie_capability_clear_word(ar_pci->pdev, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_ASPMC);
|
||||
|
||||
/*
|
||||
* Bring the target up cleanly.
|
||||
|
|
|
@ -581,8 +581,8 @@ static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci)
|
|||
u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1));
|
||||
|
||||
/* disable L0s and L1 */
|
||||
pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
|
||||
ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
|
||||
pcie_capability_clear_word(ab_pci->pdev, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_ASPMC);
|
||||
|
||||
set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags);
|
||||
}
|
||||
|
@ -590,8 +590,10 @@ static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci)
|
|||
static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci)
|
||||
{
|
||||
if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags))
|
||||
pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
|
||||
ab_pci->link_ctl);
|
||||
pcie_capability_clear_and_set_word(ab_pci->pdev, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_ASPMC,
|
||||
ab_pci->link_ctl &
|
||||
PCI_EXP_LNKCTL_ASPMC);
|
||||
}
|
||||
|
||||
static int ath11k_pci_power_up(struct ath11k_base *ab)
|
||||
|
|
|
@ -794,8 +794,8 @@ static void ath12k_pci_aspm_disable(struct ath12k_pci *ab_pci)
|
|||
u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1));
|
||||
|
||||
/* disable L0s and L1 */
|
||||
pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
|
||||
ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
|
||||
pcie_capability_clear_word(ab_pci->pdev, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_ASPMC);
|
||||
|
||||
set_bit(ATH12K_PCI_ASPM_RESTORE, &ab_pci->flags);
|
||||
}
|
||||
|
@ -803,8 +803,10 @@ static void ath12k_pci_aspm_disable(struct ath12k_pci *ab_pci)
|
|||
static void ath12k_pci_aspm_restore(struct ath12k_pci *ab_pci)
|
||||
{
|
||||
if (test_and_clear_bit(ATH12K_PCI_ASPM_RESTORE, &ab_pci->flags))
|
||||
pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
|
||||
ab_pci->link_ctl);
|
||||
pcie_capability_clear_and_set_word(ab_pci->pdev, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_ASPMC,
|
||||
ab_pci->link_ctl &
|
||||
PCI_EXP_LNKCTL_ASPMC);
|
||||
}
|
||||
|
||||
static void ath12k_pci_kill_tasklets(struct ath12k_base *ab)
|
||||
|
|
|
@ -497,22 +497,35 @@ int pcie_capability_write_dword(struct pci_dev *dev, int pos, u32 val)
|
|||
}
|
||||
EXPORT_SYMBOL(pcie_capability_write_dword);
|
||||
|
||||
int pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos,
|
||||
u16 clear, u16 set)
|
||||
int pcie_capability_clear_and_set_word_unlocked(struct pci_dev *dev, int pos,
|
||||
u16 clear, u16 set)
|
||||
{
|
||||
int ret;
|
||||
u16 val;
|
||||
|
||||
ret = pcie_capability_read_word(dev, pos, &val);
|
||||
if (!ret) {
|
||||
val &= ~clear;
|
||||
val |= set;
|
||||
ret = pcie_capability_write_word(dev, pos, val);
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val &= ~clear;
|
||||
val |= set;
|
||||
return pcie_capability_write_word(dev, pos, val);
|
||||
}
|
||||
EXPORT_SYMBOL(pcie_capability_clear_and_set_word_unlocked);
|
||||
|
||||
int pcie_capability_clear_and_set_word_locked(struct pci_dev *dev, int pos,
|
||||
u16 clear, u16 set)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&dev->pcie_cap_lock, flags);
|
||||
ret = pcie_capability_clear_and_set_word_unlocked(dev, pos, clear, set);
|
||||
spin_unlock_irqrestore(&dev->pcie_cap_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(pcie_capability_clear_and_set_word);
|
||||
EXPORT_SYMBOL(pcie_capability_clear_and_set_word_locked);
|
||||
|
||||
int pcie_capability_clear_and_set_dword(struct pci_dev *dev, int pos,
|
||||
u32 clear, u32 set)
|
||||
|
@ -521,13 +534,12 @@ int pcie_capability_clear_and_set_dword(struct pci_dev *dev, int pos,
|
|||
u32 val;
|
||||
|
||||
ret = pcie_capability_read_dword(dev, pos, &val);
|
||||
if (!ret) {
|
||||
val &= ~clear;
|
||||
val |= set;
|
||||
ret = pcie_capability_write_dword(dev, pos, val);
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
val &= ~clear;
|
||||
val |= set;
|
||||
return pcie_capability_write_dword(dev, pos, val);
|
||||
}
|
||||
EXPORT_SYMBOL(pcie_capability_clear_and_set_dword);
|
||||
|
||||
|
|
|
@ -332,17 +332,11 @@ int pciehp_check_link_status(struct controller *ctrl)
|
|||
static int __pciehp_link_set(struct controller *ctrl, bool enable)
|
||||
{
|
||||
struct pci_dev *pdev = ctrl_dev(ctrl);
|
||||
u16 lnk_ctrl;
|
||||
|
||||
pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &lnk_ctrl);
|
||||
pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_LD,
|
||||
enable ? 0 : PCI_EXP_LNKCTL_LD);
|
||||
|
||||
if (enable)
|
||||
lnk_ctrl &= ~PCI_EXP_LNKCTL_LD;
|
||||
else
|
||||
lnk_ctrl |= PCI_EXP_LNKCTL_LD;
|
||||
|
||||
pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, lnk_ctrl);
|
||||
ctrl_dbg(ctrl, "%s: lnk_ctrl = %x\n", __func__, lnk_ctrl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -4927,7 +4927,6 @@ static int pcie_wait_for_link_status(struct pci_dev *pdev,
|
|||
int pcie_retrain_link(struct pci_dev *pdev, bool use_lt)
|
||||
{
|
||||
int rc;
|
||||
u16 lnkctl;
|
||||
|
||||
/*
|
||||
* Ensure the updated LNKCTL parameters are used during link
|
||||
|
@ -4939,17 +4938,14 @@ int pcie_retrain_link(struct pci_dev *pdev, bool use_lt)
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &lnkctl);
|
||||
lnkctl |= PCI_EXP_LNKCTL_RL;
|
||||
pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, lnkctl);
|
||||
pcie_capability_set_word(pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_RL);
|
||||
if (pdev->clear_retrain_link) {
|
||||
/*
|
||||
* Due to an erratum in some devices the Retrain Link bit
|
||||
* needs to be cleared again manually to allow the link
|
||||
* training to succeed.
|
||||
*/
|
||||
lnkctl &= ~PCI_EXP_LNKCTL_RL;
|
||||
pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, lnkctl);
|
||||
pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_RL);
|
||||
}
|
||||
|
||||
return pcie_wait_for_link_status(pdev, use_lt, !use_lt);
|
||||
|
|
|
@ -199,7 +199,7 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist)
|
|||
static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
|
||||
{
|
||||
int same_clock = 1;
|
||||
u16 reg16, parent_reg, child_reg[8];
|
||||
u16 reg16, ccc, parent_old_ccc, child_old_ccc[8];
|
||||
struct pci_dev *child, *parent = link->pdev;
|
||||
struct pci_bus *linkbus = parent->subordinate;
|
||||
/*
|
||||
|
@ -221,6 +221,7 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
|
|||
|
||||
/* Port might be already in common clock mode */
|
||||
pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16);
|
||||
parent_old_ccc = reg16 & PCI_EXP_LNKCTL_CCC;
|
||||
if (same_clock && (reg16 & PCI_EXP_LNKCTL_CCC)) {
|
||||
bool consistent = true;
|
||||
|
||||
|
@ -237,34 +238,29 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
|
|||
pci_info(parent, "ASPM: current common clock configuration is inconsistent, reconfiguring\n");
|
||||
}
|
||||
|
||||
ccc = same_clock ? PCI_EXP_LNKCTL_CCC : 0;
|
||||
/* Configure downstream component, all functions */
|
||||
list_for_each_entry(child, &linkbus->devices, bus_list) {
|
||||
pcie_capability_read_word(child, PCI_EXP_LNKCTL, ®16);
|
||||
child_reg[PCI_FUNC(child->devfn)] = reg16;
|
||||
if (same_clock)
|
||||
reg16 |= PCI_EXP_LNKCTL_CCC;
|
||||
else
|
||||
reg16 &= ~PCI_EXP_LNKCTL_CCC;
|
||||
pcie_capability_write_word(child, PCI_EXP_LNKCTL, reg16);
|
||||
child_old_ccc[PCI_FUNC(child->devfn)] = reg16 & PCI_EXP_LNKCTL_CCC;
|
||||
pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_CCC, ccc);
|
||||
}
|
||||
|
||||
/* Configure upstream component */
|
||||
pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16);
|
||||
parent_reg = reg16;
|
||||
if (same_clock)
|
||||
reg16 |= PCI_EXP_LNKCTL_CCC;
|
||||
else
|
||||
reg16 &= ~PCI_EXP_LNKCTL_CCC;
|
||||
pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
|
||||
pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_CCC, ccc);
|
||||
|
||||
if (pcie_retrain_link(link->pdev, true)) {
|
||||
|
||||
/* Training failed. Restore common clock configurations */
|
||||
pci_err(parent, "ASPM: Could not configure common clock\n");
|
||||
list_for_each_entry(child, &linkbus->devices, bus_list)
|
||||
pcie_capability_write_word(child, PCI_EXP_LNKCTL,
|
||||
child_reg[PCI_FUNC(child->devfn)]);
|
||||
pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_reg);
|
||||
pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_CCC,
|
||||
child_old_ccc[PCI_FUNC(child->devfn)]);
|
||||
pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_CCC, parent_old_ccc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2324,6 +2324,7 @@ struct pci_dev *pci_alloc_dev(struct pci_bus *bus)
|
|||
.end = -1,
|
||||
};
|
||||
|
||||
spin_lock_init(&dev->pcie_cap_lock);
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
raw_spin_lock_init(&dev->msi_lock);
|
||||
#endif
|
||||
|
|
|
@ -467,6 +467,7 @@ struct pci_dev {
|
|||
pci_dev_flags_t dev_flags;
|
||||
atomic_t enable_cnt; /* pci_enable_device has been called */
|
||||
|
||||
spinlock_t pcie_cap_lock; /* Protects RMW ops in capability accessors */
|
||||
u32 saved_config_space[16]; /* Config space saved at suspend time */
|
||||
struct hlist_head saved_cap_space;
|
||||
int rom_attr_enabled; /* Display of ROM attribute enabled? */
|
||||
|
@ -1217,11 +1218,40 @@ int pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val);
|
|||
int pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val);
|
||||
int pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val);
|
||||
int pcie_capability_write_dword(struct pci_dev *dev, int pos, u32 val);
|
||||
int pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos,
|
||||
u16 clear, u16 set);
|
||||
int pcie_capability_clear_and_set_word_unlocked(struct pci_dev *dev, int pos,
|
||||
u16 clear, u16 set);
|
||||
int pcie_capability_clear_and_set_word_locked(struct pci_dev *dev, int pos,
|
||||
u16 clear, u16 set);
|
||||
int pcie_capability_clear_and_set_dword(struct pci_dev *dev, int pos,
|
||||
u32 clear, u32 set);
|
||||
|
||||
/**
|
||||
* pcie_capability_clear_and_set_word - RMW accessor for PCI Express Capability Registers
|
||||
* @dev: PCI device structure of the PCI Express device
|
||||
* @pos: PCI Express Capability Register
|
||||
* @clear: Clear bitmask
|
||||
* @set: Set bitmask
|
||||
*
|
||||
* Perform a Read-Modify-Write (RMW) operation using @clear and @set
|
||||
* bitmasks on PCI Express Capability Register at @pos. Certain PCI Express
|
||||
* Capability Registers are accessed concurrently in RMW fashion, hence
|
||||
* require locking which is handled transparently to the caller.
|
||||
*/
|
||||
static inline int pcie_capability_clear_and_set_word(struct pci_dev *dev,
|
||||
int pos,
|
||||
u16 clear, u16 set)
|
||||
{
|
||||
switch (pos) {
|
||||
case PCI_EXP_LNKCTL:
|
||||
case PCI_EXP_RTCTL:
|
||||
return pcie_capability_clear_and_set_word_locked(dev, pos,
|
||||
clear, set);
|
||||
default:
|
||||
return pcie_capability_clear_and_set_word_unlocked(dev, pos,
|
||||
clear, set);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int pcie_capability_set_word(struct pci_dev *dev, int pos,
|
||||
u16 set)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue