summaryrefslogtreecommitdiff
path: root/drivers/pci/pcie
diff options
context:
space:
mode:
authorDavid E. Box <david.e.box@linux.intel.com>2020-12-07 14:39:50 -0800
committerBjorn Helgaas <bhelgaas@google.com>2020-12-10 14:43:54 -0600
commit39850ed51062f89cd46214a16aaafba5ca49fd6c (patch)
treeb8cb10061b1aecb2eb14001219f1bf8277565354 /drivers/pci/pcie
parentf8394f232b1eab649ce2df5c5f15b0e528c92091 (diff)
PCI/PTM: Save/restore Precision Time Measurement Capability for suspend/resume
The PCI subsystem does not currently save and restore the configuration space for the Precision Time Measurement (PTM) Extended Capability leading to the possibility of the feature returning disabled on S3 resume. This has been observed on Intel Coffee Lake desktops. Add save/restore of the PTM control register. This saves the PTM Enable, Root Select, and Effective Granularity bits. Suggested-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Link: https://lore.kernel.org/r/20201207223951.19667-1-david.e.box@linux.intel.com Signed-off-by: David E. Box <david.e.box@linux.intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci/pcie')
-rw-r--r--drivers/pci/pcie/ptm.c43
1 files changed, 43 insertions, 0 deletions
diff --git a/drivers/pci/pcie/ptm.c b/drivers/pci/pcie/ptm.c
index 357a454cafa0..6b24a1c9327a 100644
--- a/drivers/pci/pcie/ptm.c
+++ b/drivers/pci/pcie/ptm.c
@@ -29,6 +29,47 @@ static void pci_ptm_info(struct pci_dev *dev)
dev->ptm_root ? " (root)" : "", clock_desc);
}
+void pci_save_ptm_state(struct pci_dev *dev)
+{
+ int ptm;
+ struct pci_cap_saved_state *save_state;
+ u16 *cap;
+
+ if (!pci_is_pcie(dev))
+ return;
+
+ ptm = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
+ if (!ptm)
+ return;
+
+ save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_PTM);
+ if (!save_state) {
+ pci_err(dev, "no suspend buffer for PTM\n");
+ return;
+ }
+
+ cap = (u16 *)&save_state->cap.data[0];
+ pci_read_config_word(dev, ptm + PCI_PTM_CTRL, cap);
+}
+
+void pci_restore_ptm_state(struct pci_dev *dev)
+{
+ struct pci_cap_saved_state *save_state;
+ int ptm;
+ u16 *cap;
+
+ if (!pci_is_pcie(dev))
+ return;
+
+ save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_PTM);
+ ptm = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
+ if (!save_state || !ptm)
+ return;
+
+ cap = (u16 *)&save_state->cap.data[0];
+ pci_write_config_word(dev, ptm + PCI_PTM_CTRL, *cap);
+}
+
void pci_ptm_init(struct pci_dev *dev)
{
int pos;
@@ -65,6 +106,8 @@ void pci_ptm_init(struct pci_dev *dev)
if (!pos)
return;
+ pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_PTM, sizeof(u16));
+
pci_read_config_dword(dev, pos + PCI_PTM_CAP, &cap);
local_clock = (cap & PCI_PTM_GRANULARITY_MASK) >> 8;