Merge branch 'pci/aspm' into next
* pci/aspm: PCI/ASPM: Unexport internal ASPM interfaces PCI/ASPM: Enable Latency Tolerance Reporting when supported PCI/ASPM: Calculate LTR_L1.2_THRESHOLD from device characteristics
This commit is contained in:
commit
3ea8bc3326
|
@ -342,6 +342,26 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
|
|||
|
||||
void pci_enable_acs(struct pci_dev *dev);
|
||||
|
||||
#ifdef CONFIG_PCIEASPM
|
||||
void pcie_aspm_init_link_state(struct pci_dev *pdev);
|
||||
void pcie_aspm_exit_link_state(struct pci_dev *pdev);
|
||||
void pcie_aspm_pm_state_change(struct pci_dev *pdev);
|
||||
void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
|
||||
#else
|
||||
static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) { }
|
||||
static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev) { }
|
||||
static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev) { }
|
||||
static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCIEASPM_DEBUG
|
||||
void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev);
|
||||
void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev);
|
||||
#else
|
||||
static inline void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev) { }
|
||||
static inline void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) { }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCIE_PTM
|
||||
void pci_ptm_init(struct pci_dev *dev);
|
||||
#else
|
||||
|
|
|
@ -43,18 +43,6 @@
|
|||
#define ASPM_STATE_ALL (ASPM_STATE_L0S | ASPM_STATE_L1 | \
|
||||
ASPM_STATE_L1SS)
|
||||
|
||||
/*
|
||||
* When L1 substates are enabled, the LTR L1.2 threshold is a timing parameter
|
||||
* that decides whether L1.1 or L1.2 is entered (Refer PCIe spec for details).
|
||||
* Not sure is there is a way to "calculate" this on the fly, but maybe we
|
||||
* could turn it into a parameter in future. This value has been taken from
|
||||
* the following files from Intel's coreboot (which is the only code I found
|
||||
* to have used this):
|
||||
* https://www.coreboot.org/pipermail/coreboot-gerrit/2015-March/021134.html
|
||||
* https://review.coreboot.org/#/c/8832/
|
||||
*/
|
||||
#define LTR_L1_2_THRESHOLD_BITS ((1 << 21) | (1 << 23) | (1 << 30))
|
||||
|
||||
struct aspm_latency {
|
||||
u32 l0s; /* L0s latency (nsec) */
|
||||
u32 l1; /* L1 latency (nsec) */
|
||||
|
@ -333,6 +321,32 @@ static u32 calc_l1ss_pwron(struct pci_dev *pdev, u32 scale, u32 val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void encode_l12_threshold(u32 threshold_us, u32 *scale, u32 *value)
|
||||
{
|
||||
u64 threshold_ns = threshold_us * 1000;
|
||||
|
||||
/* See PCIe r3.1, sec 7.33.3 and sec 6.18 */
|
||||
if (threshold_ns < 32) {
|
||||
*scale = 0;
|
||||
*value = threshold_ns;
|
||||
} else if (threshold_ns < 1024) {
|
||||
*scale = 1;
|
||||
*value = threshold_ns >> 5;
|
||||
} else if (threshold_ns < 32768) {
|
||||
*scale = 2;
|
||||
*value = threshold_ns >> 10;
|
||||
} else if (threshold_ns < 1048576) {
|
||||
*scale = 3;
|
||||
*value = threshold_ns >> 15;
|
||||
} else if (threshold_ns < 33554432) {
|
||||
*scale = 4;
|
||||
*value = threshold_ns >> 20;
|
||||
} else {
|
||||
*scale = 5;
|
||||
*value = threshold_ns >> 25;
|
||||
}
|
||||
}
|
||||
|
||||
struct aspm_register_info {
|
||||
u32 support:2;
|
||||
u32 enabled:2;
|
||||
|
@ -443,6 +457,7 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link,
|
|||
struct aspm_register_info *dwreg)
|
||||
{
|
||||
u32 val1, val2, scale1, scale2;
|
||||
u32 t_common_mode, t_power_on, l1_2_threshold, scale, value;
|
||||
|
||||
link->l1ss.up_cap_ptr = upreg->l1ss_cap_ptr;
|
||||
link->l1ss.dw_cap_ptr = dwreg->l1ss_cap_ptr;
|
||||
|
@ -454,16 +469,7 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link,
|
|||
/* Choose the greater of the two Port Common_Mode_Restore_Times */
|
||||
val1 = (upreg->l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
|
||||
val2 = (dwreg->l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
|
||||
if (val1 > val2)
|
||||
link->l1ss.ctl1 |= val1 << 8;
|
||||
else
|
||||
link->l1ss.ctl1 |= val2 << 8;
|
||||
|
||||
/*
|
||||
* We currently use LTR L1.2 threshold to be fixed constant picked from
|
||||
* Intel's coreboot.
|
||||
*/
|
||||
link->l1ss.ctl1 |= LTR_L1_2_THRESHOLD_BITS;
|
||||
t_common_mode = max(val1, val2);
|
||||
|
||||
/* Choose the greater of the two Port T_POWER_ON times */
|
||||
val1 = (upreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
|
||||
|
@ -472,10 +478,27 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link,
|
|||
scale2 = (dwreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
|
||||
|
||||
if (calc_l1ss_pwron(link->pdev, scale1, val1) >
|
||||
calc_l1ss_pwron(link->downstream, scale2, val2))
|
||||
calc_l1ss_pwron(link->downstream, scale2, val2)) {
|
||||
link->l1ss.ctl2 |= scale1 | (val1 << 3);
|
||||
else
|
||||
t_power_on = calc_l1ss_pwron(link->pdev, scale1, val1);
|
||||
} else {
|
||||
link->l1ss.ctl2 |= scale2 | (val2 << 3);
|
||||
t_power_on = calc_l1ss_pwron(link->downstream, scale2, val2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set LTR_L1.2_THRESHOLD to the time required to transition the
|
||||
* Link from L0 to L1.2 and back to L0 so we enter L1.2 only if
|
||||
* downstream devices report (via LTR) that they can tolerate at
|
||||
* least that much latency.
|
||||
*
|
||||
* Based on PCIe r3.1, sec 5.5.3.3.1, Figures 5-16 and 5-17, and
|
||||
* Table 5-11. T(POWER_OFF) is at most 2us and T(L1.2) is at
|
||||
* least 4us.
|
||||
*/
|
||||
l1_2_threshold = 2 + 4 + t_common_mode + t_power_on;
|
||||
encode_l12_threshold(l1_2_threshold, &scale, &value);
|
||||
link->l1ss.ctl1 |= t_common_mode << 8 | scale << 29 | value << 16;
|
||||
}
|
||||
|
||||
static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
|
||||
|
|
|
@ -1875,6 +1875,38 @@ static void pci_configure_relaxed_ordering(struct pci_dev *dev)
|
|||
}
|
||||
}
|
||||
|
||||
static void pci_configure_ltr(struct pci_dev *dev)
|
||||
{
|
||||
#ifdef CONFIG_PCIEASPM
|
||||
u32 cap;
|
||||
struct pci_dev *bridge;
|
||||
|
||||
if (!pci_is_pcie(dev))
|
||||
return;
|
||||
|
||||
pcie_capability_read_dword(dev, PCI_EXP_DEVCAP2, &cap);
|
||||
if (!(cap & PCI_EXP_DEVCAP2_LTR))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Software must not enable LTR in an Endpoint unless the Root
|
||||
* Complex and all intermediate Switches indicate support for LTR.
|
||||
* PCIe r3.1, sec 6.18.
|
||||
*/
|
||||
if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)
|
||||
dev->ltr_path = 1;
|
||||
else {
|
||||
bridge = pci_upstream_bridge(dev);
|
||||
if (bridge && bridge->ltr_path)
|
||||
dev->ltr_path = 1;
|
||||
}
|
||||
|
||||
if (dev->ltr_path)
|
||||
pcie_capability_set_word(dev, PCI_EXP_DEVCTL2,
|
||||
PCI_EXP_DEVCTL2_LTR_EN);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void pci_configure_device(struct pci_dev *dev)
|
||||
{
|
||||
struct hotplug_params hpp;
|
||||
|
@ -1883,6 +1915,7 @@ static void pci_configure_device(struct pci_dev *dev)
|
|||
pci_configure_mps(dev);
|
||||
pci_configure_extended_tags(dev, NULL);
|
||||
pci_configure_relaxed_ordering(dev);
|
||||
pci_configure_ltr(dev);
|
||||
|
||||
memset(&hpp, 0, sizeof(hpp));
|
||||
ret = pci_get_hp_params(dev, &hpp);
|
||||
|
|
|
@ -24,43 +24,12 @@
|
|||
#define PCIE_LINK_STATE_CLKPM 4
|
||||
|
||||
#ifdef CONFIG_PCIEASPM
|
||||
void pcie_aspm_init_link_state(struct pci_dev *pdev);
|
||||
void pcie_aspm_exit_link_state(struct pci_dev *pdev);
|
||||
void pcie_aspm_pm_state_change(struct pci_dev *pdev);
|
||||
void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
|
||||
void pci_disable_link_state(struct pci_dev *pdev, int state);
|
||||
void pci_disable_link_state_locked(struct pci_dev *pdev, int state);
|
||||
void pcie_no_aspm(void);
|
||||
#else
|
||||
static inline void pcie_aspm_init_link_state(struct pci_dev *pdev)
|
||||
{
|
||||
}
|
||||
static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev)
|
||||
{
|
||||
}
|
||||
static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev)
|
||||
{
|
||||
}
|
||||
static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
|
||||
{
|
||||
}
|
||||
static inline void pci_disable_link_state(struct pci_dev *pdev, int state)
|
||||
{
|
||||
}
|
||||
static inline void pcie_no_aspm(void)
|
||||
{
|
||||
}
|
||||
static inline void pci_disable_link_state(struct pci_dev *pdev, int state) { }
|
||||
static inline void pcie_no_aspm(void) { }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCIEASPM_DEBUG /* this depends on CONFIG_PCIEASPM */
|
||||
void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev);
|
||||
void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev);
|
||||
#else
|
||||
static inline void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev)
|
||||
{
|
||||
}
|
||||
static inline void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#endif /* LINUX_ASPM_H */
|
||||
|
|
|
@ -350,6 +350,8 @@ struct pci_dev {
|
|||
|
||||
#ifdef CONFIG_PCIEASPM
|
||||
struct pcie_link_state *link_state; /* ASPM link state */
|
||||
unsigned int ltr_path:1; /* Latency Tolerance Reporting
|
||||
supported from root to here */
|
||||
#endif
|
||||
|
||||
pci_channel_state_t error_state; /* current connectivity state */
|
||||
|
|
Loading…
Reference in New Issue