Merge branch 'pci/ptm'
- Save/restore Precision Time Measurement Capability for suspend/resume (David E. Box) - Disable PTM during suspend to save power (David E. Box) * pci/ptm: PCI: Disable PTM during suspend to save power PCI/PTM: Save/restore Precision Time Measurement Capability for suspend/resume
This commit is contained in:
commit
72b3a644bb
@ -1561,6 +1561,7 @@ int pci_save_state(struct pci_dev *dev)
|
||||
pci_save_aspm_l1ss_state(dev);
|
||||
pci_save_dpc_state(dev);
|
||||
pci_save_aer_state(dev);
|
||||
pci_save_ptm_state(dev);
|
||||
return pci_save_vc_state(dev);
|
||||
}
|
||||
EXPORT_SYMBOL(pci_save_state);
|
||||
@ -1673,6 +1674,7 @@ void pci_restore_state(struct pci_dev *dev)
|
||||
pci_restore_vc_state(dev);
|
||||
pci_restore_rebar_state(dev);
|
||||
pci_restore_dpc_state(dev);
|
||||
pci_restore_ptm_state(dev);
|
||||
|
||||
pci_aer_clear_status(dev);
|
||||
pci_restore_aer_state(dev);
|
||||
@ -2602,12 +2604,24 @@ int pci_prepare_to_sleep(struct pci_dev *dev)
|
||||
if (target_state == PCI_POWER_ERROR)
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* There are systems (for example, Intel mobile chips since Coffee
|
||||
* Lake) where the power drawn while suspended can be significantly
|
||||
* reduced by disabling PTM on PCIe root ports as this allows the
|
||||
* port to enter a lower-power PM state and the SoC to reach a
|
||||
* lower-power idle state as a whole.
|
||||
*/
|
||||
if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)
|
||||
pci_disable_ptm(dev);
|
||||
|
||||
pci_enable_wake(dev, target_state, wakeup);
|
||||
|
||||
error = pci_set_power_state(dev, target_state);
|
||||
|
||||
if (error)
|
||||
if (error) {
|
||||
pci_enable_wake(dev, target_state, false);
|
||||
pci_restore_ptm_state(dev);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
@ -2645,12 +2659,23 @@ int pci_finish_runtime_suspend(struct pci_dev *dev)
|
||||
|
||||
dev->runtime_d3cold = target_state == PCI_D3cold;
|
||||
|
||||
/*
|
||||
* There are systems (for example, Intel mobile chips since Coffee
|
||||
* Lake) where the power drawn while suspended can be significantly
|
||||
* reduced by disabling PTM on PCIe root ports as this allows the
|
||||
* port to enter a lower-power PM state and the SoC to reach a
|
||||
* lower-power idle state as a whole.
|
||||
*/
|
||||
if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)
|
||||
pci_disable_ptm(dev);
|
||||
|
||||
__pci_enable_wake(dev, target_state, pci_dev_run_wake(dev));
|
||||
|
||||
error = pci_set_power_state(dev, target_state);
|
||||
|
||||
if (error) {
|
||||
pci_enable_wake(dev, target_state, false);
|
||||
pci_restore_ptm_state(dev);
|
||||
dev->runtime_d3cold = false;
|
||||
}
|
||||
|
||||
|
@ -524,6 +524,16 @@ static inline int pci_iov_bus_range(struct pci_bus *bus)
|
||||
|
||||
#endif /* CONFIG_PCI_IOV */
|
||||
|
||||
#ifdef CONFIG_PCIE_PTM
|
||||
void pci_save_ptm_state(struct pci_dev *dev);
|
||||
void pci_restore_ptm_state(struct pci_dev *dev);
|
||||
void pci_disable_ptm(struct pci_dev *dev);
|
||||
#else
|
||||
static inline void pci_save_ptm_state(struct pci_dev *dev) { }
|
||||
static inline void pci_restore_ptm_state(struct pci_dev *dev) { }
|
||||
static inline void pci_disable_ptm(struct pci_dev *dev) { }
|
||||
#endif
|
||||
|
||||
unsigned long pci_cardbus_resource_alignment(struct resource *);
|
||||
|
||||
static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
|
||||
|
@ -29,6 +29,64 @@ static void pci_ptm_info(struct pci_dev *dev)
|
||||
dev->ptm_root ? " (root)" : "", clock_desc);
|
||||
}
|
||||
|
||||
void pci_disable_ptm(struct pci_dev *dev)
|
||||
{
|
||||
int ptm;
|
||||
u16 ctrl;
|
||||
|
||||
if (!pci_is_pcie(dev))
|
||||
return;
|
||||
|
||||
ptm = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
|
||||
if (!ptm)
|
||||
return;
|
||||
|
||||
pci_read_config_word(dev, ptm + PCI_PTM_CTRL, &ctrl);
|
||||
ctrl &= ~(PCI_PTM_CTRL_ENABLE | PCI_PTM_CTRL_ROOT);
|
||||
pci_write_config_word(dev, ptm + PCI_PTM_CTRL, ctrl);
|
||||
}
|
||||
|
||||
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 +123,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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user