mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2025-01-07 22:34:18 +08:00
PCI/ASPM: Update save_state when configuration changes
Many PCIe device drivers save the configuration state of their device during probe and restore it when their .slot_reset() hook is called during PCIe error recovery. If the ASPM configuration is changed after the driver's probe is called and before an error event occurs, .slot_reset() restores the ASPM configuration to what it was at the time of probe, not to what it was just before the occurrence of the error event. This leads to a mismatch in ASPM configuration between the device and its upstream device. Update the saved configuration of the device when the ASPM configuration changes. Link: https://lore.kernel.org/r/20240222174436.3565146-1-vidyas@nvidia.com Signed-off-by: Vidya Sagar <vidyas@nvidia.com> [bhelgaas: commit log, rebase to pci/aspm, rename to pci_update_aspm_saved_state() since it updates only LNKCTL, update only ASPMC and CLKREQ_EN in LNKCTL] Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com> Reviewed-by: David E. Box <david.e.box@linux.intel.com>
This commit is contained in:
parent
64dbb2d707
commit
6d42666752
@ -301,16 +301,42 @@ static int policy_to_clkpm_state(struct pcie_link_state *link)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pci_update_aspm_saved_state(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_cap_saved_state *save_state;
|
||||
u16 *cap, lnkctl, aspm_ctl;
|
||||
|
||||
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
|
||||
if (!save_state)
|
||||
return;
|
||||
|
||||
pcie_capability_read_word(dev, PCI_EXP_LNKCTL, &lnkctl);
|
||||
|
||||
/*
|
||||
* Update ASPM and CLKREQ bits of LNKCTL in save_state. We only
|
||||
* write PCI_EXP_LNKCTL_CCC during enumeration, so it shouldn't
|
||||
* change after being captured in save_state.
|
||||
*/
|
||||
aspm_ctl = lnkctl & (PCI_EXP_LNKCTL_ASPMC | PCI_EXP_LNKCTL_CLKREQ_EN);
|
||||
lnkctl &= ~(PCI_EXP_LNKCTL_ASPMC | PCI_EXP_LNKCTL_CLKREQ_EN);
|
||||
|
||||
/* Depends on pci_save_pcie_state(): cap[1] is LNKCTL */
|
||||
cap = (u16 *)&save_state->cap.data[0];
|
||||
cap[1] = lnkctl | aspm_ctl;
|
||||
}
|
||||
|
||||
static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable)
|
||||
{
|
||||
struct pci_dev *child;
|
||||
struct pci_bus *linkbus = link->pdev->subordinate;
|
||||
u32 val = enable ? PCI_EXP_LNKCTL_CLKREQ_EN : 0;
|
||||
|
||||
list_for_each_entry(child, &linkbus->devices, bus_list)
|
||||
list_for_each_entry(child, &linkbus->devices, bus_list) {
|
||||
pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_CLKREQ_EN,
|
||||
val);
|
||||
pci_update_aspm_saved_state(child);
|
||||
}
|
||||
link->clkpm_enabled = !!enable;
|
||||
}
|
||||
|
||||
@ -929,6 +955,12 @@ static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state)
|
||||
pcie_config_aspm_dev(parent, upstream);
|
||||
|
||||
link->aspm_enabled = state;
|
||||
|
||||
/* Update latest ASPM configuration in saved context */
|
||||
pci_save_aspm_l1ss_state(link->downstream);
|
||||
pci_update_aspm_saved_state(link->downstream);
|
||||
pci_save_aspm_l1ss_state(parent);
|
||||
pci_update_aspm_saved_state(parent);
|
||||
}
|
||||
|
||||
static void pcie_config_aspm_path(struct pcie_link_state *link)
|
||||
|
Loading…
Reference in New Issue
Block a user