1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
27d715a6cSShaohua Li /*
3df62ab5eSBjorn Helgaas * Enable PCIe link L0s/L1 state and Clock Power Management
47d715a6cSShaohua Li *
57d715a6cSShaohua Li * Copyright (C) 2007 Intel
67d715a6cSShaohua Li * Copyright (C) Zhang Yanmin (yanmin.zhang@intel.com)
77d715a6cSShaohua Li * Copyright (C) Shaohua Li (shaohua.li@intel.com)
87d715a6cSShaohua Li */
97d715a6cSShaohua Li
107d715a6cSShaohua Li #include <linux/kernel.h>
117afeb84dSBjorn Helgaas #include <linux/math.h>
127d715a6cSShaohua Li #include <linux/module.h>
137d715a6cSShaohua Li #include <linux/moduleparam.h>
147d715a6cSShaohua Li #include <linux/pci.h>
157d715a6cSShaohua Li #include <linux/pci_regs.h>
167d715a6cSShaohua Li #include <linux/errno.h>
177d715a6cSShaohua Li #include <linux/pm.h>
187d715a6cSShaohua Li #include <linux/init.h>
197d715a6cSShaohua Li #include <linux/slab.h>
202a42d9dbSThomas Renninger #include <linux/jiffies.h>
21987a4c78SAndrew Patterson #include <linux/delay.h>
227d715a6cSShaohua Li #include "../pci.h"
237d715a6cSShaohua Li
247d715a6cSShaohua Li #ifdef MODULE_PARAM_PREFIX
257d715a6cSShaohua Li #undef MODULE_PARAM_PREFIX
267d715a6cSShaohua Li #endif
277d715a6cSShaohua Li #define MODULE_PARAM_PREFIX "pcie_aspm."
287d715a6cSShaohua Li
29ac18018aSKenji Kaneshige /* Note: those are not register definitions */
30ac18018aSKenji Kaneshige #define ASPM_STATE_L0S_UP (1) /* Upstream direction L0s state */
31ac18018aSKenji Kaneshige #define ASPM_STATE_L0S_DW (2) /* Downstream direction L0s state */
32ac18018aSKenji Kaneshige #define ASPM_STATE_L1 (4) /* L1 state */
33b2103ccbSRajat Jain #define ASPM_STATE_L1_1 (8) /* ASPM L1.1 state */
34b2103ccbSRajat Jain #define ASPM_STATE_L1_2 (0x10) /* ASPM L1.2 state */
35b2103ccbSRajat Jain #define ASPM_STATE_L1_1_PCIPM (0x20) /* PCI PM L1.1 state */
36b2103ccbSRajat Jain #define ASPM_STATE_L1_2_PCIPM (0x40) /* PCI PM L1.2 state */
37b2103ccbSRajat Jain #define ASPM_STATE_L1_SS_PCIPM (ASPM_STATE_L1_1_PCIPM | ASPM_STATE_L1_2_PCIPM)
38b2103ccbSRajat Jain #define ASPM_STATE_L1_2_MASK (ASPM_STATE_L1_2 | ASPM_STATE_L1_2_PCIPM)
39b2103ccbSRajat Jain #define ASPM_STATE_L1SS (ASPM_STATE_L1_1 | ASPM_STATE_L1_1_PCIPM |\
40b2103ccbSRajat Jain ASPM_STATE_L1_2_MASK)
41ac18018aSKenji Kaneshige #define ASPM_STATE_L0S (ASPM_STATE_L0S_UP | ASPM_STATE_L0S_DW)
42b2103ccbSRajat Jain #define ASPM_STATE_ALL (ASPM_STATE_L0S | ASPM_STATE_L1 | \
43b2103ccbSRajat Jain ASPM_STATE_L1SS)
44ac18018aSKenji Kaneshige
457d715a6cSShaohua Li struct pcie_link_state {
465cde89d8SKenji Kaneshige struct pci_dev *pdev; /* Upstream component of the Link */
47b5a0a9b5SRajat Jain struct pci_dev *downstream; /* Downstream component, function 0 */
485c92ffb1SKenji Kaneshige struct pcie_link_state *root; /* pointer to the root port link */
495cde89d8SKenji Kaneshige struct pcie_link_state *parent; /* pointer to the parent Link state */
505cde89d8SKenji Kaneshige struct list_head sibling; /* node in link_list */
517d715a6cSShaohua Li
527d715a6cSShaohua Li /* ASPM state */
53b2103ccbSRajat Jain u32 aspm_support:7; /* Supported ASPM state */
54b2103ccbSRajat Jain u32 aspm_enabled:7; /* Enabled ASPM state */
55b2103ccbSRajat Jain u32 aspm_capable:7; /* Capable ASPM state with latency */
56b2103ccbSRajat Jain u32 aspm_default:7; /* Default ASPM state by BIOS */
57b2103ccbSRajat Jain u32 aspm_disable:7; /* Disabled ASPM state */
5880bfdbe3SKenji Kaneshige
594d246e45SKenji Kaneshige /* Clock PM state */
604d246e45SKenji Kaneshige u32 clkpm_capable:1; /* Clock PM capable? */
614d246e45SKenji Kaneshige u32 clkpm_enabled:1; /* Current Clock PM state */
624d246e45SKenji Kaneshige u32 clkpm_default:1; /* Default Clock PM state by BIOS */
6335efea32SHeiner Kallweit u32 clkpm_disable:1; /* Clock PM disabled */
647d715a6cSShaohua Li };
657d715a6cSShaohua Li
663c076351SMatthew Garrett static int aspm_disabled, aspm_force;
678b8bae90SRafael J. Wysocki static bool aspm_support_enabled = true;
687d715a6cSShaohua Li static DEFINE_MUTEX(aspm_lock);
697d715a6cSShaohua Li static LIST_HEAD(link_list);
707d715a6cSShaohua Li
717d715a6cSShaohua Li #define POLICY_DEFAULT 0 /* BIOS default setting */
727d715a6cSShaohua Li #define POLICY_PERFORMANCE 1 /* high performance */
737d715a6cSShaohua Li #define POLICY_POWERSAVE 2 /* high power saving */
74b2103ccbSRajat Jain #define POLICY_POWER_SUPERSAVE 3 /* possibly even more power saving */
75ad71c962SMatthew Garrett
76ad71c962SMatthew Garrett #ifdef CONFIG_PCIEASPM_PERFORMANCE
77ad71c962SMatthew Garrett static int aspm_policy = POLICY_PERFORMANCE;
78ad71c962SMatthew Garrett #elif defined CONFIG_PCIEASPM_POWERSAVE
79ad71c962SMatthew Garrett static int aspm_policy = POLICY_POWERSAVE;
80b2103ccbSRajat Jain #elif defined CONFIG_PCIEASPM_POWER_SUPERSAVE
81b2103ccbSRajat Jain static int aspm_policy = POLICY_POWER_SUPERSAVE;
82ad71c962SMatthew Garrett #else
837d715a6cSShaohua Li static int aspm_policy;
84ad71c962SMatthew Garrett #endif
85ad71c962SMatthew Garrett
867d715a6cSShaohua Li static const char *policy_str[] = {
877d715a6cSShaohua Li [POLICY_DEFAULT] = "default",
887d715a6cSShaohua Li [POLICY_PERFORMANCE] = "performance",
89b2103ccbSRajat Jain [POLICY_POWERSAVE] = "powersave",
90b2103ccbSRajat Jain [POLICY_POWER_SUPERSAVE] = "powersupersave"
917d715a6cSShaohua Li };
927d715a6cSShaohua Li
9343262f00SBolarinwa O. Saheed /*
9443262f00SBolarinwa O. Saheed * The L1 PM substate capability is only implemented in function 0 in a
9543262f00SBolarinwa O. Saheed * multi function device.
9643262f00SBolarinwa O. Saheed */
pci_function_0(struct pci_bus * linkbus)9743262f00SBolarinwa O. Saheed static struct pci_dev *pci_function_0(struct pci_bus *linkbus)
9843262f00SBolarinwa O. Saheed {
9943262f00SBolarinwa O. Saheed struct pci_dev *child;
10043262f00SBolarinwa O. Saheed
10143262f00SBolarinwa O. Saheed list_for_each_entry(child, &linkbus->devices, bus_list)
10243262f00SBolarinwa O. Saheed if (PCI_FUNC(child->devfn) == 0)
10343262f00SBolarinwa O. Saheed return child;
10443262f00SBolarinwa O. Saheed return NULL;
10543262f00SBolarinwa O. Saheed }
10643262f00SBolarinwa O. Saheed
policy_to_aspm_state(struct pcie_link_state * link)1075aa63583SKenji Kaneshige static int policy_to_aspm_state(struct pcie_link_state *link)
1087d715a6cSShaohua Li {
1097d715a6cSShaohua Li switch (aspm_policy) {
1107d715a6cSShaohua Li case POLICY_PERFORMANCE:
1117d715a6cSShaohua Li /* Disable ASPM and Clock PM */
1127d715a6cSShaohua Li return 0;
1137d715a6cSShaohua Li case POLICY_POWERSAVE:
1147d715a6cSShaohua Li /* Enable ASPM L0s/L1 */
115b2103ccbSRajat Jain return (ASPM_STATE_L0S | ASPM_STATE_L1);
116b2103ccbSRajat Jain case POLICY_POWER_SUPERSAVE:
117b2103ccbSRajat Jain /* Enable Everything */
118ac18018aSKenji Kaneshige return ASPM_STATE_ALL;
1197d715a6cSShaohua Li case POLICY_DEFAULT:
1205aa63583SKenji Kaneshige return link->aspm_default;
1217d715a6cSShaohua Li }
1227d715a6cSShaohua Li return 0;
1237d715a6cSShaohua Li }
1247d715a6cSShaohua Li
policy_to_clkpm_state(struct pcie_link_state * link)1255aa63583SKenji Kaneshige static int policy_to_clkpm_state(struct pcie_link_state *link)
1267d715a6cSShaohua Li {
1277d715a6cSShaohua Li switch (aspm_policy) {
1287d715a6cSShaohua Li case POLICY_PERFORMANCE:
1297d715a6cSShaohua Li /* Disable ASPM and Clock PM */
1307d715a6cSShaohua Li return 0;
1317d715a6cSShaohua Li case POLICY_POWERSAVE:
132b2103ccbSRajat Jain case POLICY_POWER_SUPERSAVE:
133b2103ccbSRajat Jain /* Enable Clock PM */
1347d715a6cSShaohua Li return 1;
1357d715a6cSShaohua Li case POLICY_DEFAULT:
1365aa63583SKenji Kaneshige return link->clkpm_default;
1377d715a6cSShaohua Li }
1387d715a6cSShaohua Li return 0;
1397d715a6cSShaohua Li }
1407d715a6cSShaohua Li
pcie_set_clkpm_nocheck(struct pcie_link_state * link,int enable)141430842e2SKenji Kaneshige static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable)
1427d715a6cSShaohua Li {
1435aa63583SKenji Kaneshige struct pci_dev *child;
1445aa63583SKenji Kaneshige struct pci_bus *linkbus = link->pdev->subordinate;
1450c0cbb6cSBjorn Helgaas u32 val = enable ? PCI_EXP_LNKCTL_CLKREQ_EN : 0;
1467d715a6cSShaohua Li
1470c0cbb6cSBjorn Helgaas list_for_each_entry(child, &linkbus->devices, bus_list)
1480c0cbb6cSBjorn Helgaas pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL,
1490c0cbb6cSBjorn Helgaas PCI_EXP_LNKCTL_CLKREQ_EN,
1500c0cbb6cSBjorn Helgaas val);
1515aa63583SKenji Kaneshige link->clkpm_enabled = !!enable;
1527d715a6cSShaohua Li }
1537d715a6cSShaohua Li
pcie_set_clkpm(struct pcie_link_state * link,int enable)154430842e2SKenji Kaneshige static void pcie_set_clkpm(struct pcie_link_state *link, int enable)
155430842e2SKenji Kaneshige {
15635efea32SHeiner Kallweit /*
15735efea32SHeiner Kallweit * Don't enable Clock PM if the link is not Clock PM capable
15835efea32SHeiner Kallweit * or Clock PM is disabled
15935efea32SHeiner Kallweit */
16035efea32SHeiner Kallweit if (!link->clkpm_capable || link->clkpm_disable)
1612f671e2dSMatthew Garrett enable = 0;
162430842e2SKenji Kaneshige /* Need nothing if the specified equals to current state */
163430842e2SKenji Kaneshige if (link->clkpm_enabled == enable)
164430842e2SKenji Kaneshige return;
165430842e2SKenji Kaneshige pcie_set_clkpm_nocheck(link, enable);
166430842e2SKenji Kaneshige }
167430842e2SKenji Kaneshige
pcie_clkpm_cap_init(struct pcie_link_state * link,int blacklist)1688d349aceSKenji Kaneshige static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist)
1697d715a6cSShaohua Li {
170f12eb72aSJiang Liu int capable = 1, enabled = 1;
1717d715a6cSShaohua Li u32 reg32;
1727d715a6cSShaohua Li u16 reg16;
1735aa63583SKenji Kaneshige struct pci_dev *child;
1745aa63583SKenji Kaneshige struct pci_bus *linkbus = link->pdev->subordinate;
1757d715a6cSShaohua Li
1767d715a6cSShaohua Li /* All functions should have the same cap and state, take the worst */
1775aa63583SKenji Kaneshige list_for_each_entry(child, &linkbus->devices, bus_list) {
178f12eb72aSJiang Liu pcie_capability_read_dword(child, PCI_EXP_LNKCAP, ®32);
1797d715a6cSShaohua Li if (!(reg32 & PCI_EXP_LNKCAP_CLKPM)) {
1807d715a6cSShaohua Li capable = 0;
1817d715a6cSShaohua Li enabled = 0;
1827d715a6cSShaohua Li break;
1837d715a6cSShaohua Li }
184f12eb72aSJiang Liu pcie_capability_read_word(child, PCI_EXP_LNKCTL, ®16);
1857d715a6cSShaohua Li if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN))
1867d715a6cSShaohua Li enabled = 0;
1877d715a6cSShaohua Li }
1885aa63583SKenji Kaneshige link->clkpm_enabled = enabled;
1895aa63583SKenji Kaneshige link->clkpm_default = enabled;
19035efea32SHeiner Kallweit link->clkpm_capable = capable;
19135efea32SHeiner Kallweit link->clkpm_disable = blacklist ? 1 : 0;
19246bbdfa4SShaohua Li }
19346bbdfa4SShaohua Li
1947d715a6cSShaohua Li /*
1957d715a6cSShaohua Li * pcie_aspm_configure_common_clock: check if the 2 ends of a link
1967d715a6cSShaohua Li * could use common clock. If they are, configure them to use the
1977d715a6cSShaohua Li * common clock. That will reduce the ASPM state exit latency.
1987d715a6cSShaohua Li */
pcie_aspm_configure_common_clock(struct pcie_link_state * link)1995aa63583SKenji Kaneshige static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
2007d715a6cSShaohua Li {
201f12eb72aSJiang Liu int same_clock = 1;
202e09060b3SIlpo Järvinen u16 reg16, ccc, parent_old_ccc, child_old_ccc[8];
2035aa63583SKenji Kaneshige struct pci_dev *child, *parent = link->pdev;
2045aa63583SKenji Kaneshige struct pci_bus *linkbus = parent->subordinate;
2057d715a6cSShaohua Li /*
2065aa63583SKenji Kaneshige * All functions of a slot should have the same Slot Clock
2077d715a6cSShaohua Li * Configuration, so just check one function
2085aa63583SKenji Kaneshige */
2095aa63583SKenji Kaneshige child = list_entry(linkbus->devices.next, struct pci_dev, bus_list);
2108b06477dSKenji Kaneshige BUG_ON(!pci_is_pcie(child));
2117d715a6cSShaohua Li
2127d715a6cSShaohua Li /* Check downstream component if bit Slot Clock Configuration is 1 */
213f12eb72aSJiang Liu pcie_capability_read_word(child, PCI_EXP_LNKSTA, ®16);
2147d715a6cSShaohua Li if (!(reg16 & PCI_EXP_LNKSTA_SLC))
2157d715a6cSShaohua Li same_clock = 0;
2167d715a6cSShaohua Li
2177d715a6cSShaohua Li /* Check upstream component if bit Slot Clock Configuration is 1 */
218f12eb72aSJiang Liu pcie_capability_read_word(parent, PCI_EXP_LNKSTA, ®16);
2197d715a6cSShaohua Li if (!(reg16 & PCI_EXP_LNKSTA_SLC))
2207d715a6cSShaohua Li same_clock = 0;
2217d715a6cSShaohua Li
22204875177SSinan Kaya /* Port might be already in common clock mode */
22304875177SSinan Kaya pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16);
224e09060b3SIlpo Järvinen parent_old_ccc = reg16 & PCI_EXP_LNKCTL_CCC;
22504875177SSinan Kaya if (same_clock && (reg16 & PCI_EXP_LNKCTL_CCC)) {
22604875177SSinan Kaya bool consistent = true;
22704875177SSinan Kaya
22804875177SSinan Kaya list_for_each_entry(child, &linkbus->devices, bus_list) {
22904875177SSinan Kaya pcie_capability_read_word(child, PCI_EXP_LNKCTL,
23004875177SSinan Kaya ®16);
23104875177SSinan Kaya if (!(reg16 & PCI_EXP_LNKCTL_CCC)) {
23204875177SSinan Kaya consistent = false;
23304875177SSinan Kaya break;
23404875177SSinan Kaya }
23504875177SSinan Kaya }
23604875177SSinan Kaya if (consistent)
23704875177SSinan Kaya return;
2383b364c65SChris Packham pci_info(parent, "ASPM: current common clock configuration is inconsistent, reconfiguring\n");
23904875177SSinan Kaya }
24004875177SSinan Kaya
241e09060b3SIlpo Järvinen ccc = same_clock ? PCI_EXP_LNKCTL_CCC : 0;
2427d715a6cSShaohua Li /* Configure downstream component, all functions */
2435aa63583SKenji Kaneshige list_for_each_entry(child, &linkbus->devices, bus_list) {
244f12eb72aSJiang Liu pcie_capability_read_word(child, PCI_EXP_LNKCTL, ®16);
245e09060b3SIlpo Järvinen child_old_ccc[PCI_FUNC(child->devfn)] = reg16 & PCI_EXP_LNKCTL_CCC;
246e09060b3SIlpo Järvinen pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL,
247e09060b3SIlpo Järvinen PCI_EXP_LNKCTL_CCC, ccc);
2487d715a6cSShaohua Li }
2497d715a6cSShaohua Li
2507d715a6cSShaohua Li /* Configure upstream component */
251e09060b3SIlpo Järvinen pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL,
252e09060b3SIlpo Järvinen PCI_EXP_LNKCTL_CCC, ccc);
2537d715a6cSShaohua Li
2541abb4739SBjorn Helgaas if (pcie_retrain_link(link->pdev, true)) {
2555aa63583SKenji Kaneshige
2565aa63583SKenji Kaneshige /* Training failed. Restore common clock configurations */
2577506dc79SFrederick Lawler pci_err(parent, "ASPM: Could not configure common clock\n");
258f12eb72aSJiang Liu list_for_each_entry(child, &linkbus->devices, bus_list)
259e09060b3SIlpo Järvinen pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL,
260e09060b3SIlpo Järvinen PCI_EXP_LNKCTL_CCC,
261e09060b3SIlpo Järvinen child_old_ccc[PCI_FUNC(child->devfn)]);
262e09060b3SIlpo Järvinen pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL,
263e09060b3SIlpo Järvinen PCI_EXP_LNKCTL_CCC, parent_old_ccc);
2647d715a6cSShaohua Li }
265f5297a01SBjorn Helgaas }
2667d715a6cSShaohua Li
2675e0eaa7dSKenji Kaneshige /* Convert L0s latency encoding to ns */
calc_l0s_latency(u32 lnkcap)2685f7875d6SSaheed O. Bolarinwa static u32 calc_l0s_latency(u32 lnkcap)
2697d715a6cSShaohua Li {
2705f7875d6SSaheed O. Bolarinwa u32 encoding = (lnkcap & PCI_EXP_LNKCAP_L0SEL) >> 12;
2715f7875d6SSaheed O. Bolarinwa
2725e0eaa7dSKenji Kaneshige if (encoding == 0x7)
2735e0eaa7dSKenji Kaneshige return (5 * 1000); /* > 4us */
2745e0eaa7dSKenji Kaneshige return (64 << encoding);
2757d715a6cSShaohua Li }
2767d715a6cSShaohua Li
2775e0eaa7dSKenji Kaneshige /* Convert L0s acceptable latency encoding to ns */
calc_l0s_acceptable(u32 encoding)2785e0eaa7dSKenji Kaneshige static u32 calc_l0s_acceptable(u32 encoding)
2797d715a6cSShaohua Li {
2805e0eaa7dSKenji Kaneshige if (encoding == 0x7)
2815e0eaa7dSKenji Kaneshige return -1U;
2825e0eaa7dSKenji Kaneshige return (64 << encoding);
2835e0eaa7dSKenji Kaneshige }
2847d715a6cSShaohua Li
2855e0eaa7dSKenji Kaneshige /* Convert L1 latency encoding to ns */
calc_l1_latency(u32 lnkcap)2865f7875d6SSaheed O. Bolarinwa static u32 calc_l1_latency(u32 lnkcap)
2875e0eaa7dSKenji Kaneshige {
2885f7875d6SSaheed O. Bolarinwa u32 encoding = (lnkcap & PCI_EXP_LNKCAP_L1EL) >> 15;
2895f7875d6SSaheed O. Bolarinwa
2905e0eaa7dSKenji Kaneshige if (encoding == 0x7)
2915e0eaa7dSKenji Kaneshige return (65 * 1000); /* > 64us */
2925e0eaa7dSKenji Kaneshige return (1000 << encoding);
2935e0eaa7dSKenji Kaneshige }
2945e0eaa7dSKenji Kaneshige
2955e0eaa7dSKenji Kaneshige /* Convert L1 acceptable latency encoding to ns */
calc_l1_acceptable(u32 encoding)2965e0eaa7dSKenji Kaneshige static u32 calc_l1_acceptable(u32 encoding)
2975e0eaa7dSKenji Kaneshige {
2985e0eaa7dSKenji Kaneshige if (encoding == 0x7)
2995e0eaa7dSKenji Kaneshige return -1U;
3005e0eaa7dSKenji Kaneshige return (1000 << encoding);
3017d715a6cSShaohua Li }
3027d715a6cSShaohua Li
303f1f0366dSRajat Jain /* Convert L1SS T_pwr encoding to usec */
calc_l12_pwron(struct pci_dev * pdev,u32 scale,u32 val)30405a55d9cSAjay Agarwal static u32 calc_l12_pwron(struct pci_dev *pdev, u32 scale, u32 val)
305f1f0366dSRajat Jain {
306f1f0366dSRajat Jain switch (scale) {
307f1f0366dSRajat Jain case 0:
308f1f0366dSRajat Jain return val * 2;
309f1f0366dSRajat Jain case 1:
310f1f0366dSRajat Jain return val * 10;
311f1f0366dSRajat Jain case 2:
312f1f0366dSRajat Jain return val * 100;
313f1f0366dSRajat Jain }
3147506dc79SFrederick Lawler pci_err(pdev, "%s: Invalid T_PwrOn scale: %u\n", __func__, scale);
315f1f0366dSRajat Jain return 0;
316f1f0366dSRajat Jain }
317f1f0366dSRajat Jain
3187afeb84dSBjorn Helgaas /*
3197afeb84dSBjorn Helgaas * Encode an LTR_L1.2_THRESHOLD value for the L1 PM Substates Control 1
3207afeb84dSBjorn Helgaas * register. Ports enter L1.2 when the most recent LTR value is greater
3217afeb84dSBjorn Helgaas * than or equal to LTR_L1.2_THRESHOLD, so we round up to make sure we
3227afeb84dSBjorn Helgaas * don't enter L1.2 too aggressively.
3237afeb84dSBjorn Helgaas *
3247afeb84dSBjorn Helgaas * See PCIe r6.0, sec 5.5.1, 6.18, 7.8.3.3.
3257afeb84dSBjorn Helgaas */
encode_l12_threshold(u32 threshold_us,u32 * scale,u32 * value)32680d7d7a9SBjorn Helgaas static void encode_l12_threshold(u32 threshold_us, u32 *scale, u32 *value)
32780d7d7a9SBjorn Helgaas {
3287afeb84dSBjorn Helgaas u64 threshold_ns = (u64) threshold_us * 1000;
32980d7d7a9SBjorn Helgaas
3307afeb84dSBjorn Helgaas /*
3317afeb84dSBjorn Helgaas * LTR_L1.2_THRESHOLD_Value ("value") is a 10-bit field with max
3327afeb84dSBjorn Helgaas * value of 0x3ff.
3337afeb84dSBjorn Helgaas */
3347afeb84dSBjorn Helgaas if (threshold_ns <= 0x3ff * 1) {
3357afeb84dSBjorn Helgaas *scale = 0; /* Value times 1ns */
33680d7d7a9SBjorn Helgaas *value = threshold_ns;
3377afeb84dSBjorn Helgaas } else if (threshold_ns <= 0x3ff * 32) {
3387afeb84dSBjorn Helgaas *scale = 1; /* Value times 32ns */
3397afeb84dSBjorn Helgaas *value = roundup(threshold_ns, 32) / 32;
3407afeb84dSBjorn Helgaas } else if (threshold_ns <= 0x3ff * 1024) {
3417afeb84dSBjorn Helgaas *scale = 2; /* Value times 1024ns */
3427afeb84dSBjorn Helgaas *value = roundup(threshold_ns, 1024) / 1024;
3437afeb84dSBjorn Helgaas } else if (threshold_ns <= 0x3ff * 32768) {
3447afeb84dSBjorn Helgaas *scale = 3; /* Value times 32768ns */
3457afeb84dSBjorn Helgaas *value = roundup(threshold_ns, 32768) / 32768;
3467afeb84dSBjorn Helgaas } else if (threshold_ns <= 0x3ff * 1048576) {
3477afeb84dSBjorn Helgaas *scale = 4; /* Value times 1048576ns */
3487afeb84dSBjorn Helgaas *value = roundup(threshold_ns, 1048576) / 1048576;
3497afeb84dSBjorn Helgaas } else if (threshold_ns <= 0x3ff * (u64) 33554432) {
3507afeb84dSBjorn Helgaas *scale = 5; /* Value times 33554432ns */
3517afeb84dSBjorn Helgaas *value = roundup(threshold_ns, 33554432) / 33554432;
35280d7d7a9SBjorn Helgaas } else {
35380d7d7a9SBjorn Helgaas *scale = 5;
3547afeb84dSBjorn Helgaas *value = 0x3ff; /* Max representable value */
35580d7d7a9SBjorn Helgaas }
35680d7d7a9SBjorn Helgaas }
35780d7d7a9SBjorn Helgaas
pcie_aspm_check_latency(struct pci_dev * endpoint)35807d92760SKenji Kaneshige static void pcie_aspm_check_latency(struct pci_dev *endpoint)
35907d92760SKenji Kaneshige {
3606e332df7SSaheed O. Bolarinwa u32 latency, encoding, lnkcap_up, lnkcap_dw;
361fa285bafSSaheed O. Bolarinwa u32 l1_switch_latency = 0, latency_up_l0s;
362fa285bafSSaheed O. Bolarinwa u32 latency_up_l1, latency_dw_l0s, latency_dw_l1;
363fa285bafSSaheed O. Bolarinwa u32 acceptable_l0s, acceptable_l1;
36407d92760SKenji Kaneshige struct pcie_link_state *link;
36507d92760SKenji Kaneshige
36607d92760SKenji Kaneshige /* Device not in D0 doesn't need latency check */
36707d92760SKenji Kaneshige if ((endpoint->current_state != PCI_D0) &&
36807d92760SKenji Kaneshige (endpoint->current_state != PCI_UNKNOWN))
36907d92760SKenji Kaneshige return;
37007d92760SKenji Kaneshige
37107d92760SKenji Kaneshige link = endpoint->bus->self->link_state;
3726e332df7SSaheed O. Bolarinwa
3736e332df7SSaheed O. Bolarinwa /* Calculate endpoint L0s acceptable latency */
3746e332df7SSaheed O. Bolarinwa encoding = (endpoint->devcap & PCI_EXP_DEVCAP_L0S) >> 6;
375fa285bafSSaheed O. Bolarinwa acceptable_l0s = calc_l0s_acceptable(encoding);
3766e332df7SSaheed O. Bolarinwa
3776e332df7SSaheed O. Bolarinwa /* Calculate endpoint L1 acceptable latency */
3786e332df7SSaheed O. Bolarinwa encoding = (endpoint->devcap & PCI_EXP_DEVCAP_L1) >> 9;
379fa285bafSSaheed O. Bolarinwa acceptable_l1 = calc_l1_acceptable(encoding);
38007d92760SKenji Kaneshige
38107d92760SKenji Kaneshige while (link) {
382222578daSSaheed O. Bolarinwa struct pci_dev *dev = pci_function_0(link->pdev->subordinate);
383222578daSSaheed O. Bolarinwa
384222578daSSaheed O. Bolarinwa /* Read direction exit latencies */
385222578daSSaheed O. Bolarinwa pcie_capability_read_dword(link->pdev, PCI_EXP_LNKCAP,
386222578daSSaheed O. Bolarinwa &lnkcap_up);
387222578daSSaheed O. Bolarinwa pcie_capability_read_dword(dev, PCI_EXP_LNKCAP,
388222578daSSaheed O. Bolarinwa &lnkcap_dw);
389fa285bafSSaheed O. Bolarinwa latency_up_l0s = calc_l0s_latency(lnkcap_up);
390fa285bafSSaheed O. Bolarinwa latency_up_l1 = calc_l1_latency(lnkcap_up);
391fa285bafSSaheed O. Bolarinwa latency_dw_l0s = calc_l0s_latency(lnkcap_dw);
392fa285bafSSaheed O. Bolarinwa latency_dw_l1 = calc_l1_latency(lnkcap_dw);
393222578daSSaheed O. Bolarinwa
394ac18018aSKenji Kaneshige /* Check upstream direction L0s latency */
395ac18018aSKenji Kaneshige if ((link->aspm_capable & ASPM_STATE_L0S_UP) &&
396fa285bafSSaheed O. Bolarinwa (latency_up_l0s > acceptable_l0s))
397ac18018aSKenji Kaneshige link->aspm_capable &= ~ASPM_STATE_L0S_UP;
398ac18018aSKenji Kaneshige
399ac18018aSKenji Kaneshige /* Check downstream direction L0s latency */
400ac18018aSKenji Kaneshige if ((link->aspm_capable & ASPM_STATE_L0S_DW) &&
401fa285bafSSaheed O. Bolarinwa (latency_dw_l0s > acceptable_l0s))
402ac18018aSKenji Kaneshige link->aspm_capable &= ~ASPM_STATE_L0S_DW;
40307d92760SKenji Kaneshige /*
40407d92760SKenji Kaneshige * Check L1 latency.
40507d92760SKenji Kaneshige * Every switch on the path to root complex need 1
40607d92760SKenji Kaneshige * more microsecond for L1. Spec doesn't mention L0s.
407a142f4d3SRajat Jain *
408a142f4d3SRajat Jain * The exit latencies for L1 substates are not advertised
409a142f4d3SRajat Jain * by a device. Since the spec also doesn't mention a way
410a142f4d3SRajat Jain * to determine max latencies introduced by enabling L1
411a142f4d3SRajat Jain * substates on the components, it is not clear how to do
412a142f4d3SRajat Jain * a L1 substate exit latency check. We assume that the
413a142f4d3SRajat Jain * L1 exit latencies advertised by a device include L1
414a142f4d3SRajat Jain * substate latencies (and hence do not do any check).
41507d92760SKenji Kaneshige */
416fa285bafSSaheed O. Bolarinwa latency = max_t(u32, latency_up_l1, latency_dw_l1);
417ac18018aSKenji Kaneshige if ((link->aspm_capable & ASPM_STATE_L1) &&
418fa285bafSSaheed O. Bolarinwa (latency + l1_switch_latency > acceptable_l1))
419ac18018aSKenji Kaneshige link->aspm_capable &= ~ASPM_STATE_L1;
42007d92760SKenji Kaneshige l1_switch_latency += 1000;
42107d92760SKenji Kaneshige
42207d92760SKenji Kaneshige link = link->parent;
42307d92760SKenji Kaneshige }
42407d92760SKenji Kaneshige }
42507d92760SKenji Kaneshige
pci_clear_and_set_dword(struct pci_dev * pdev,int pos,u32 clear,u32 set)4260f1619cfSBjorn Helgaas static void pci_clear_and_set_dword(struct pci_dev *pdev, int pos,
4270f1619cfSBjorn Helgaas u32 clear, u32 set)
4280f1619cfSBjorn Helgaas {
4290f1619cfSBjorn Helgaas u32 val;
4300f1619cfSBjorn Helgaas
4310f1619cfSBjorn Helgaas pci_read_config_dword(pdev, pos, &val);
4320f1619cfSBjorn Helgaas val &= ~clear;
4330f1619cfSBjorn Helgaas val |= set;
4340f1619cfSBjorn Helgaas pci_write_config_dword(pdev, pos, val);
4350f1619cfSBjorn Helgaas }
4360f1619cfSBjorn Helgaas
437f1f0366dSRajat Jain /* Calculate L1.2 PM substate timing parameters */
aspm_calc_l12_info(struct pcie_link_state * link,u32 parent_l1ss_cap,u32 child_l1ss_cap)43805a55d9cSAjay Agarwal static void aspm_calc_l12_info(struct pcie_link_state *link,
4391e8955fdSBjorn Helgaas u32 parent_l1ss_cap, u32 child_l1ss_cap)
440f1f0366dSRajat Jain {
441190cd42cSBjorn Helgaas struct pci_dev *child = link->downstream, *parent = link->pdev;
442f1f0366dSRajat Jain u32 val1, val2, scale1, scale2;
44380d7d7a9SBjorn Helgaas u32 t_common_mode, t_power_on, l1_2_threshold, scale, value;
444df8f1058SSaheed O. Bolarinwa u32 ctl1 = 0, ctl2 = 0;
445df8f1058SSaheed O. Bolarinwa u32 pctl1, pctl2, cctl1, cctl2;
446ff209eccSBjorn Helgaas u32 pl1_2_enables, cl1_2_enables;
447f1f0366dSRajat Jain
448a48f3d5bSBjorn Helgaas /* Choose the greater of the two Port Common_Mode_Restore_Times */
4491e8955fdSBjorn Helgaas val1 = (parent_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
4501e8955fdSBjorn Helgaas val2 = (child_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
45180d7d7a9SBjorn Helgaas t_common_mode = max(val1, val2);
452f1f0366dSRajat Jain
453a48f3d5bSBjorn Helgaas /* Choose the greater of the two Port T_POWER_ON times */
4541e8955fdSBjorn Helgaas val1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
4551e8955fdSBjorn Helgaas scale1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
4561e8955fdSBjorn Helgaas val2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
4571e8955fdSBjorn Helgaas scale2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
458f1f0366dSRajat Jain
45905a55d9cSAjay Agarwal if (calc_l12_pwron(parent, scale1, val1) >
46005a55d9cSAjay Agarwal calc_l12_pwron(child, scale2, val2)) {
461df8f1058SSaheed O. Bolarinwa ctl2 |= scale1 | (val1 << 3);
46205a55d9cSAjay Agarwal t_power_on = calc_l12_pwron(parent, scale1, val1);
46380d7d7a9SBjorn Helgaas } else {
464df8f1058SSaheed O. Bolarinwa ctl2 |= scale2 | (val2 << 3);
46505a55d9cSAjay Agarwal t_power_on = calc_l12_pwron(child, scale2, val2);
46680d7d7a9SBjorn Helgaas }
46780d7d7a9SBjorn Helgaas
46880d7d7a9SBjorn Helgaas /*
46980d7d7a9SBjorn Helgaas * Set LTR_L1.2_THRESHOLD to the time required to transition the
47080d7d7a9SBjorn Helgaas * Link from L0 to L1.2 and back to L0 so we enter L1.2 only if
47180d7d7a9SBjorn Helgaas * downstream devices report (via LTR) that they can tolerate at
47280d7d7a9SBjorn Helgaas * least that much latency.
47380d7d7a9SBjorn Helgaas *
47480d7d7a9SBjorn Helgaas * Based on PCIe r3.1, sec 5.5.3.3.1, Figures 5-16 and 5-17, and
47580d7d7a9SBjorn Helgaas * Table 5-11. T(POWER_OFF) is at most 2us and T(L1.2) is at
47680d7d7a9SBjorn Helgaas * least 4us.
47780d7d7a9SBjorn Helgaas */
47880d7d7a9SBjorn Helgaas l1_2_threshold = 2 + 4 + t_common_mode + t_power_on;
47980d7d7a9SBjorn Helgaas encode_l12_threshold(l1_2_threshold, &scale, &value);
480df8f1058SSaheed O. Bolarinwa ctl1 |= t_common_mode << 8 | scale << 29 | value << 16;
481df8f1058SSaheed O. Bolarinwa
4824353594eSRajat Jain /* Some broken devices only support dword access to L1 SS */
483df8f1058SSaheed O. Bolarinwa pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, &pctl1);
484df8f1058SSaheed O. Bolarinwa pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, &pctl2);
485df8f1058SSaheed O. Bolarinwa pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL1, &cctl1);
486df8f1058SSaheed O. Bolarinwa pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL2, &cctl2);
487df8f1058SSaheed O. Bolarinwa
488df8f1058SSaheed O. Bolarinwa if (ctl1 == pctl1 && ctl1 == cctl1 &&
489df8f1058SSaheed O. Bolarinwa ctl2 == pctl2 && ctl2 == cctl2)
490df8f1058SSaheed O. Bolarinwa return;
491df8f1058SSaheed O. Bolarinwa
492ff209eccSBjorn Helgaas /* Disable L1.2 while updating. See PCIe r5.0, sec 5.5.4, 7.8.3.3 */
493ff209eccSBjorn Helgaas pl1_2_enables = pctl1 & PCI_L1SS_CTL1_L1_2_MASK;
494ff209eccSBjorn Helgaas cl1_2_enables = cctl1 & PCI_L1SS_CTL1_L1_2_MASK;
495df8f1058SSaheed O. Bolarinwa
496ff209eccSBjorn Helgaas if (pl1_2_enables || cl1_2_enables) {
497ff209eccSBjorn Helgaas pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
498ff209eccSBjorn Helgaas PCI_L1SS_CTL1_L1_2_MASK, 0);
499ff209eccSBjorn Helgaas pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
500ff209eccSBjorn Helgaas PCI_L1SS_CTL1_L1_2_MASK, 0);
501ff209eccSBjorn Helgaas }
502ff209eccSBjorn Helgaas
503ff209eccSBjorn Helgaas /* Program T_POWER_ON times in both ports */
504ff209eccSBjorn Helgaas pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, ctl2);
505ff209eccSBjorn Helgaas pci_write_config_dword(child, child->l1ss + PCI_L1SS_CTL2, ctl2);
506ff209eccSBjorn Helgaas
507ff209eccSBjorn Helgaas /* Program Common_Mode_Restore_Time in upstream device */
508ff209eccSBjorn Helgaas pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
509ff209eccSBjorn Helgaas PCI_L1SS_CTL1_CM_RESTORE_TIME, ctl1);
510ff209eccSBjorn Helgaas
511ff209eccSBjorn Helgaas /* Program LTR_L1.2_THRESHOLD time in both ports */
512ff209eccSBjorn Helgaas pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
5135e85eba6SVidya Sagar PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
514ff209eccSBjorn Helgaas PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1);
515ff209eccSBjorn Helgaas pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
5165e85eba6SVidya Sagar PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
517ff209eccSBjorn Helgaas PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1);
518ff209eccSBjorn Helgaas
519ff209eccSBjorn Helgaas if (pl1_2_enables || cl1_2_enables) {
520ff209eccSBjorn Helgaas pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, 0,
521ff209eccSBjorn Helgaas pl1_2_enables);
522ff209eccSBjorn Helgaas pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, 0,
523ff209eccSBjorn Helgaas cl1_2_enables);
524ff209eccSBjorn Helgaas }
525f1f0366dSRajat Jain }
526f1f0366dSRajat Jain
aspm_l1ss_init(struct pcie_link_state * link)5279e2a0317SBjorn Helgaas static void aspm_l1ss_init(struct pcie_link_state *link)
5289e2a0317SBjorn Helgaas {
5299e2a0317SBjorn Helgaas struct pci_dev *child = link->downstream, *parent = link->pdev;
5309e2a0317SBjorn Helgaas u32 parent_l1ss_cap, child_l1ss_cap;
5319e2a0317SBjorn Helgaas u32 parent_l1ss_ctl1 = 0, child_l1ss_ctl1 = 0;
5329e2a0317SBjorn Helgaas
533cfc00286SBjorn Helgaas if (!parent->l1ss || !child->l1ss)
534cfc00286SBjorn Helgaas return;
535cfc00286SBjorn Helgaas
5369e2a0317SBjorn Helgaas /* Setup L1 substate */
5379e2a0317SBjorn Helgaas pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CAP,
5389e2a0317SBjorn Helgaas &parent_l1ss_cap);
5399e2a0317SBjorn Helgaas pci_read_config_dword(child, child->l1ss + PCI_L1SS_CAP,
5409e2a0317SBjorn Helgaas &child_l1ss_cap);
5419e2a0317SBjorn Helgaas
5429e2a0317SBjorn Helgaas if (!(parent_l1ss_cap & PCI_L1SS_CAP_L1_PM_SS))
5439e2a0317SBjorn Helgaas parent_l1ss_cap = 0;
5449e2a0317SBjorn Helgaas if (!(child_l1ss_cap & PCI_L1SS_CAP_L1_PM_SS))
5459e2a0317SBjorn Helgaas child_l1ss_cap = 0;
5469e2a0317SBjorn Helgaas
5479e2a0317SBjorn Helgaas /*
5489e2a0317SBjorn Helgaas * If we don't have LTR for the entire path from the Root Complex
5499e2a0317SBjorn Helgaas * to this device, we can't use ASPM L1.2 because it relies on the
5509e2a0317SBjorn Helgaas * LTR_L1.2_THRESHOLD. See PCIe r4.0, secs 5.5.4, 6.18.
5519e2a0317SBjorn Helgaas */
5529e2a0317SBjorn Helgaas if (!child->ltr_path)
5539e2a0317SBjorn Helgaas child_l1ss_cap &= ~PCI_L1SS_CAP_ASPM_L1_2;
5549e2a0317SBjorn Helgaas
5559e2a0317SBjorn Helgaas if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_ASPM_L1_1)
5569e2a0317SBjorn Helgaas link->aspm_support |= ASPM_STATE_L1_1;
5579e2a0317SBjorn Helgaas if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_ASPM_L1_2)
5589e2a0317SBjorn Helgaas link->aspm_support |= ASPM_STATE_L1_2;
5599e2a0317SBjorn Helgaas if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_1)
5609e2a0317SBjorn Helgaas link->aspm_support |= ASPM_STATE_L1_1_PCIPM;
5619e2a0317SBjorn Helgaas if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_2)
5629e2a0317SBjorn Helgaas link->aspm_support |= ASPM_STATE_L1_2_PCIPM;
5639e2a0317SBjorn Helgaas
5649e2a0317SBjorn Helgaas if (parent_l1ss_cap)
5659e2a0317SBjorn Helgaas pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
5669e2a0317SBjorn Helgaas &parent_l1ss_ctl1);
5679e2a0317SBjorn Helgaas if (child_l1ss_cap)
5689e2a0317SBjorn Helgaas pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL1,
5699e2a0317SBjorn Helgaas &child_l1ss_ctl1);
5709e2a0317SBjorn Helgaas
5719e2a0317SBjorn Helgaas if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_1)
5729e2a0317SBjorn Helgaas link->aspm_enabled |= ASPM_STATE_L1_1;
5739e2a0317SBjorn Helgaas if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_2)
5749e2a0317SBjorn Helgaas link->aspm_enabled |= ASPM_STATE_L1_2;
5759e2a0317SBjorn Helgaas if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_1)
5769e2a0317SBjorn Helgaas link->aspm_enabled |= ASPM_STATE_L1_1_PCIPM;
5779e2a0317SBjorn Helgaas if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_2)
5789e2a0317SBjorn Helgaas link->aspm_enabled |= ASPM_STATE_L1_2_PCIPM;
5799e2a0317SBjorn Helgaas
580911afb9fSAjay Agarwal if (link->aspm_support & ASPM_STATE_L1_2_MASK)
58105a55d9cSAjay Agarwal aspm_calc_l12_info(link, parent_l1ss_cap, child_l1ss_cap);
5829e2a0317SBjorn Helgaas }
5839e2a0317SBjorn Helgaas
pcie_aspm_cap_init(struct pcie_link_state * link,int blacklist)5848d349aceSKenji Kaneshige static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
5857d715a6cSShaohua Li {
5863bd7db63SYinghai Lu struct pci_dev *child = link->downstream, *parent = link->pdev;
587c6e5f02bSSaheed O. Bolarinwa u32 parent_lnkcap, child_lnkcap;
58867bcc9adSSaheed O. Bolarinwa u16 parent_lnkctl, child_lnkctl;
5895aa63583SKenji Kaneshige struct pci_bus *linkbus = parent->subordinate;
5907d715a6cSShaohua Li
5918d349aceSKenji Kaneshige if (blacklist) {
592f1c0ca29SKenji Kaneshige /* Set enabled/disable so that we will disable ASPM later */
593ac18018aSKenji Kaneshige link->aspm_enabled = ASPM_STATE_ALL;
594ac18018aSKenji Kaneshige link->aspm_disable = ASPM_STATE_ALL;
5958d349aceSKenji Kaneshige return;
5968d349aceSKenji Kaneshige }
5978d349aceSKenji Kaneshige
598ac18018aSKenji Kaneshige /*
599e53f9a28SDavid Daney * If ASPM not supported, don't mess with the clocks and link,
600e53f9a28SDavid Daney * bail out now.
601e53f9a28SDavid Daney */
602c6e5f02bSSaheed O. Bolarinwa pcie_capability_read_dword(parent, PCI_EXP_LNKCAP, &parent_lnkcap);
603c6e5f02bSSaheed O. Bolarinwa pcie_capability_read_dword(child, PCI_EXP_LNKCAP, &child_lnkcap);
604c6e5f02bSSaheed O. Bolarinwa if (!(parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPMS))
605e53f9a28SDavid Daney return;
606e53f9a28SDavid Daney
607e53f9a28SDavid Daney /* Configure common clock before checking latencies */
608e53f9a28SDavid Daney pcie_aspm_configure_common_clock(link);
609e53f9a28SDavid Daney
610e53f9a28SDavid Daney /*
611c6e5f02bSSaheed O. Bolarinwa * Re-read upstream/downstream components' register state after
612c6e5f02bSSaheed O. Bolarinwa * clock configuration. L0s & L1 exit latencies in the otherwise
613c6e5f02bSSaheed O. Bolarinwa * read-only Link Capabilities may change depending on common clock
614c6e5f02bSSaheed O. Bolarinwa * configuration (PCIe r5.0, sec 7.5.3.6).
615e53f9a28SDavid Daney */
616c6e5f02bSSaheed O. Bolarinwa pcie_capability_read_dword(parent, PCI_EXP_LNKCAP, &parent_lnkcap);
617c6e5f02bSSaheed O. Bolarinwa pcie_capability_read_dword(child, PCI_EXP_LNKCAP, &child_lnkcap);
61867bcc9adSSaheed O. Bolarinwa pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &parent_lnkctl);
61967bcc9adSSaheed O. Bolarinwa pcie_capability_read_word(child, PCI_EXP_LNKCTL, &child_lnkctl);
620e53f9a28SDavid Daney
621e53f9a28SDavid Daney /*
622ac18018aSKenji Kaneshige * Setup L0s state
623ac18018aSKenji Kaneshige *
624ac18018aSKenji Kaneshige * Note that we must not enable L0s in either direction on a
625ac18018aSKenji Kaneshige * given link unless components on both sides of the link each
626ac18018aSKenji Kaneshige * support L0s.
627ac18018aSKenji Kaneshige */
628c6e5f02bSSaheed O. Bolarinwa if (parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPM_L0S)
629ac18018aSKenji Kaneshige link->aspm_support |= ASPM_STATE_L0S;
630c6e5f02bSSaheed O. Bolarinwa
63167bcc9adSSaheed O. Bolarinwa if (child_lnkctl & PCI_EXP_LNKCTL_ASPM_L0S)
632ac18018aSKenji Kaneshige link->aspm_enabled |= ASPM_STATE_L0S_UP;
63367bcc9adSSaheed O. Bolarinwa if (parent_lnkctl & PCI_EXP_LNKCTL_ASPM_L0S)
634ac18018aSKenji Kaneshige link->aspm_enabled |= ASPM_STATE_L0S_DW;
635ac18018aSKenji Kaneshige
636ac18018aSKenji Kaneshige /* Setup L1 state */
637c6e5f02bSSaheed O. Bolarinwa if (parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPM_L1)
638ac18018aSKenji Kaneshige link->aspm_support |= ASPM_STATE_L1;
639c6e5f02bSSaheed O. Bolarinwa
64067bcc9adSSaheed O. Bolarinwa if (parent_lnkctl & child_lnkctl & PCI_EXP_LNKCTL_ASPM_L1)
641ac18018aSKenji Kaneshige link->aspm_enabled |= ASPM_STATE_L1;
64280bfdbe3SKenji Kaneshige
6439e2a0317SBjorn Helgaas aspm_l1ss_init(link);
644f1f0366dSRajat Jain
645b127bd55SKenji Kaneshige /* Save default state */
646b127bd55SKenji Kaneshige link->aspm_default = link->aspm_enabled;
64707d92760SKenji Kaneshige
64807d92760SKenji Kaneshige /* Setup initial capable state. Will be updated later */
64907d92760SKenji Kaneshige link->aspm_capable = link->aspm_support;
650b127bd55SKenji Kaneshige
651b7206cbfSKenji Kaneshige /* Get and check endpoint acceptable latencies */
6525aa63583SKenji Kaneshige list_for_each_entry(child, &linkbus->devices, bus_list) {
65362f87c0eSYijing Wang if (pci_pcie_type(child) != PCI_EXP_TYPE_ENDPOINT &&
65462f87c0eSYijing Wang pci_pcie_type(child) != PCI_EXP_TYPE_LEG_END)
6557d715a6cSShaohua Li continue;
6567d715a6cSShaohua Li
65707d92760SKenji Kaneshige pcie_aspm_check_latency(child);
6587d715a6cSShaohua Li }
6597d715a6cSShaohua Li }
6607d715a6cSShaohua Li
661aeda9adeSRajat Jain /* Configure the ASPM L1 substates */
pcie_config_aspm_l1ss(struct pcie_link_state * link,u32 state)662aeda9adeSRajat Jain static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
663aeda9adeSRajat Jain {
664aeda9adeSRajat Jain u32 val, enable_req;
665aeda9adeSRajat Jain struct pci_dev *child = link->downstream, *parent = link->pdev;
666aeda9adeSRajat Jain
667aeda9adeSRajat Jain enable_req = (link->aspm_enabled ^ state) & state;
668aeda9adeSRajat Jain
669aeda9adeSRajat Jain /*
670aeda9adeSRajat Jain * Here are the rules specified in the PCIe spec for enabling L1SS:
671aeda9adeSRajat Jain * - When enabling L1.x, enable bit at parent first, then at child
672aeda9adeSRajat Jain * - When disabling L1.x, disable bit at child first, then at parent
673aeda9adeSRajat Jain * - When enabling ASPM L1.x, need to disable L1
674aeda9adeSRajat Jain * (at child followed by parent).
675aeda9adeSRajat Jain * - The ASPM/PCIPM L1.2 must be disabled while programming timing
676aeda9adeSRajat Jain * parameters
677aeda9adeSRajat Jain *
678aeda9adeSRajat Jain * To keep it simple, disable all L1SS bits first, and later enable
679aeda9adeSRajat Jain * what is needed.
680aeda9adeSRajat Jain */
681aeda9adeSRajat Jain
682aeda9adeSRajat Jain /* Disable all L1 substates */
683ecdf57b4SSaheed O. Bolarinwa pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
684aeda9adeSRajat Jain PCI_L1SS_CTL1_L1SS_MASK, 0);
685ecdf57b4SSaheed O. Bolarinwa pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
686aeda9adeSRajat Jain PCI_L1SS_CTL1_L1SS_MASK, 0);
687aeda9adeSRajat Jain /*
688aeda9adeSRajat Jain * If needed, disable L1, and it gets enabled later
689aeda9adeSRajat Jain * in pcie_config_aspm_link().
690aeda9adeSRajat Jain */
691aeda9adeSRajat Jain if (enable_req & (ASPM_STATE_L1_1 | ASPM_STATE_L1_2)) {
6924afc65cfSIlpo Järvinen pcie_capability_clear_word(child, PCI_EXP_LNKCTL,
6934afc65cfSIlpo Järvinen PCI_EXP_LNKCTL_ASPM_L1);
6944afc65cfSIlpo Järvinen pcie_capability_clear_word(parent, PCI_EXP_LNKCTL,
6954afc65cfSIlpo Järvinen PCI_EXP_LNKCTL_ASPM_L1);
696aeda9adeSRajat Jain }
697aeda9adeSRajat Jain
698aeda9adeSRajat Jain val = 0;
699aeda9adeSRajat Jain if (state & ASPM_STATE_L1_1)
700aeda9adeSRajat Jain val |= PCI_L1SS_CTL1_ASPM_L1_1;
701aeda9adeSRajat Jain if (state & ASPM_STATE_L1_2)
702aeda9adeSRajat Jain val |= PCI_L1SS_CTL1_ASPM_L1_2;
703aeda9adeSRajat Jain if (state & ASPM_STATE_L1_1_PCIPM)
704aeda9adeSRajat Jain val |= PCI_L1SS_CTL1_PCIPM_L1_1;
705aeda9adeSRajat Jain if (state & ASPM_STATE_L1_2_PCIPM)
706aeda9adeSRajat Jain val |= PCI_L1SS_CTL1_PCIPM_L1_2;
707aeda9adeSRajat Jain
708aeda9adeSRajat Jain /* Enable what we need to enable */
709ecdf57b4SSaheed O. Bolarinwa pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
71058a3862aSYicong Yang PCI_L1SS_CTL1_L1SS_MASK, val);
711ecdf57b4SSaheed O. Bolarinwa pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
71258a3862aSYicong Yang PCI_L1SS_CTL1_L1SS_MASK, val);
713aeda9adeSRajat Jain }
714aeda9adeSRajat Jain
pcie_config_aspm_dev(struct pci_dev * pdev,u32 val)715ac18018aSKenji Kaneshige static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val)
7167d715a6cSShaohua Li {
71775083206SBjorn Helgaas pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL,
71875083206SBjorn Helgaas PCI_EXP_LNKCTL_ASPMC, val);
7197d715a6cSShaohua Li }
7207d715a6cSShaohua Li
pcie_config_aspm_link(struct pcie_link_state * link,u32 state)721b7206cbfSKenji Kaneshige static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state)
7227d715a6cSShaohua Li {
723ac18018aSKenji Kaneshige u32 upstream = 0, dwstream = 0;
724aeda9adeSRajat Jain struct pci_dev *child = link->downstream, *parent = link->pdev;
7255aa63583SKenji Kaneshige struct pci_bus *linkbus = parent->subordinate;
7267d715a6cSShaohua Li
727aeda9adeSRajat Jain /* Enable only the states that were not explicitly disabled */
728b7206cbfSKenji Kaneshige state &= (link->aspm_capable & ~link->aspm_disable);
729aeda9adeSRajat Jain
730aeda9adeSRajat Jain /* Can't enable any substates if L1 is not enabled */
731aeda9adeSRajat Jain if (!(state & ASPM_STATE_L1))
732aeda9adeSRajat Jain state &= ~ASPM_STATE_L1SS;
733aeda9adeSRajat Jain
734aeda9adeSRajat Jain /* Spec says both ports must be in D0 before enabling PCI PM substates*/
735aeda9adeSRajat Jain if (parent->current_state != PCI_D0 || child->current_state != PCI_D0) {
736aeda9adeSRajat Jain state &= ~ASPM_STATE_L1_SS_PCIPM;
737aeda9adeSRajat Jain state |= (link->aspm_enabled & ASPM_STATE_L1_SS_PCIPM);
738aeda9adeSRajat Jain }
739aeda9adeSRajat Jain
740aeda9adeSRajat Jain /* Nothing to do if the link is already in the requested state */
741f1c0ca29SKenji Kaneshige if (link->aspm_enabled == state)
7427d715a6cSShaohua Li return;
743ac18018aSKenji Kaneshige /* Convert ASPM state to upstream/downstream ASPM register state */
744ac18018aSKenji Kaneshige if (state & ASPM_STATE_L0S_UP)
74575083206SBjorn Helgaas dwstream |= PCI_EXP_LNKCTL_ASPM_L0S;
746ac18018aSKenji Kaneshige if (state & ASPM_STATE_L0S_DW)
74775083206SBjorn Helgaas upstream |= PCI_EXP_LNKCTL_ASPM_L0S;
748ac18018aSKenji Kaneshige if (state & ASPM_STATE_L1) {
74975083206SBjorn Helgaas upstream |= PCI_EXP_LNKCTL_ASPM_L1;
75075083206SBjorn Helgaas dwstream |= PCI_EXP_LNKCTL_ASPM_L1;
751ac18018aSKenji Kaneshige }
752aeda9adeSRajat Jain
753aeda9adeSRajat Jain if (link->aspm_capable & ASPM_STATE_L1SS)
754aeda9adeSRajat Jain pcie_config_aspm_l1ss(link, state);
755aeda9adeSRajat Jain
7567d715a6cSShaohua Li /*
7575aa63583SKenji Kaneshige * Spec 2.0 suggests all functions should be configured the
7585aa63583SKenji Kaneshige * same setting for ASPM. Enabling ASPM L1 should be done in
7595aa63583SKenji Kaneshige * upstream component first and then downstream, and vice
7605aa63583SKenji Kaneshige * versa for disabling ASPM L1. Spec doesn't mention L0S.
7617d715a6cSShaohua Li */
762ac18018aSKenji Kaneshige if (state & ASPM_STATE_L1)
763ac18018aSKenji Kaneshige pcie_config_aspm_dev(parent, upstream);
7645aa63583SKenji Kaneshige list_for_each_entry(child, &linkbus->devices, bus_list)
765ac18018aSKenji Kaneshige pcie_config_aspm_dev(child, dwstream);
766ac18018aSKenji Kaneshige if (!(state & ASPM_STATE_L1))
767ac18018aSKenji Kaneshige pcie_config_aspm_dev(parent, upstream);
7687d715a6cSShaohua Li
7695aa63583SKenji Kaneshige link->aspm_enabled = state;
7707d715a6cSShaohua Li }
7717d715a6cSShaohua Li
pcie_config_aspm_path(struct pcie_link_state * link)772b7206cbfSKenji Kaneshige static void pcie_config_aspm_path(struct pcie_link_state *link)
7737d715a6cSShaohua Li {
774b7206cbfSKenji Kaneshige while (link) {
775b7206cbfSKenji Kaneshige pcie_config_aspm_link(link, policy_to_aspm_state(link));
776b7206cbfSKenji Kaneshige link = link->parent;
77746bbdfa4SShaohua Li }
7787d715a6cSShaohua Li }
7797d715a6cSShaohua Li
free_link_state(struct pcie_link_state * link)7805aa63583SKenji Kaneshige static void free_link_state(struct pcie_link_state *link)
7817d715a6cSShaohua Li {
7825aa63583SKenji Kaneshige link->pdev->link_state = NULL;
7835aa63583SKenji Kaneshige kfree(link);
7847d715a6cSShaohua Li }
7857d715a6cSShaohua Li
pcie_aspm_sanity_check(struct pci_dev * pdev)786ddc9753fSShaohua Li static int pcie_aspm_sanity_check(struct pci_dev *pdev)
787ddc9753fSShaohua Li {
7883647584dSKenji Kaneshige struct pci_dev *child;
789149e1637SShaohua Li u32 reg32;
7902f671e2dSMatthew Garrett
791ddc9753fSShaohua Li /*
79245e829eaSStefan Assmann * Some functions in a slot might not all be PCIe functions,
7933647584dSKenji Kaneshige * very strange. Disable ASPM for the whole slot
794ddc9753fSShaohua Li */
7953647584dSKenji Kaneshige list_for_each_entry(child, &pdev->subordinate->devices, bus_list) {
796f12eb72aSJiang Liu if (!pci_is_pcie(child))
797ddc9753fSShaohua Li return -EINVAL;
798c9651e70SMatthew Garrett
799c9651e70SMatthew Garrett /*
800c9651e70SMatthew Garrett * If ASPM is disabled then we're not going to change
801c9651e70SMatthew Garrett * the BIOS state. It's safe to continue even if it's a
802c9651e70SMatthew Garrett * pre-1.1 device
803c9651e70SMatthew Garrett */
804c9651e70SMatthew Garrett
805c9651e70SMatthew Garrett if (aspm_disabled)
806c9651e70SMatthew Garrett continue;
807c9651e70SMatthew Garrett
808149e1637SShaohua Li /*
809149e1637SShaohua Li * Disable ASPM for pre-1.1 PCIe device, we follow MS to use
810149e1637SShaohua Li * RBER bit to determine if a function is 1.1 version device
811149e1637SShaohua Li */
812f12eb72aSJiang Liu pcie_capability_read_dword(child, PCI_EXP_DEVCAP, ®32);
813e1f4f59dSSitsofe Wheeler if (!(reg32 & PCI_EXP_DEVCAP_RBER) && !aspm_force) {
8147506dc79SFrederick Lawler pci_info(child, "disabling ASPM on pre-1.1 PCIe device. You can enable it with 'pcie_aspm=force'\n");
815149e1637SShaohua Li return -EINVAL;
816149e1637SShaohua Li }
817ddc9753fSShaohua Li }
818ddc9753fSShaohua Li return 0;
819ddc9753fSShaohua Li }
820ddc9753fSShaohua Li
alloc_pcie_link_state(struct pci_dev * pdev)821b7206cbfSKenji Kaneshige static struct pcie_link_state *alloc_pcie_link_state(struct pci_dev *pdev)
8228d349aceSKenji Kaneshige {
8238d349aceSKenji Kaneshige struct pcie_link_state *link;
8248d349aceSKenji Kaneshige
8258d349aceSKenji Kaneshige link = kzalloc(sizeof(*link), GFP_KERNEL);
8268d349aceSKenji Kaneshige if (!link)
8278d349aceSKenji Kaneshige return NULL;
828030305d6SBjorn Helgaas
8298d349aceSKenji Kaneshige INIT_LIST_HEAD(&link->sibling);
8308d349aceSKenji Kaneshige link->pdev = pdev;
8313bd7db63SYinghai Lu link->downstream = pci_function_0(pdev->subordinate);
832030305d6SBjorn Helgaas
833030305d6SBjorn Helgaas /*
834030305d6SBjorn Helgaas * Root Ports and PCI/PCI-X to PCIe Bridges are roots of PCIe
835ee8bdfb6SArd Biesheuvel * hierarchies. Note that some PCIe host implementations omit
836ee8bdfb6SArd Biesheuvel * the root ports entirely, in which case a downstream port on
837ee8bdfb6SArd Biesheuvel * a switch may become the root of the link state chain for all
838ee8bdfb6SArd Biesheuvel * its subordinate endpoints.
839030305d6SBjorn Helgaas */
840030305d6SBjorn Helgaas if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT ||
841ee8bdfb6SArd Biesheuvel pci_pcie_type(pdev) == PCI_EXP_TYPE_PCIE_BRIDGE ||
842ee8bdfb6SArd Biesheuvel !pdev->bus->parent->self) {
843030305d6SBjorn Helgaas link->root = link;
844030305d6SBjorn Helgaas } else {
8458d349aceSKenji Kaneshige struct pcie_link_state *parent;
846030305d6SBjorn Helgaas
8478d349aceSKenji Kaneshige parent = pdev->bus->parent->self->link_state;
8488d349aceSKenji Kaneshige if (!parent) {
8498d349aceSKenji Kaneshige kfree(link);
8508d349aceSKenji Kaneshige return NULL;
8518d349aceSKenji Kaneshige }
852030305d6SBjorn Helgaas
8538d349aceSKenji Kaneshige link->parent = parent;
854030305d6SBjorn Helgaas link->root = link->parent->root;
8558d349aceSKenji Kaneshige }
8565c92ffb1SKenji Kaneshige
8578d349aceSKenji Kaneshige list_add(&link->sibling, &link_list);
8588d349aceSKenji Kaneshige pdev->link_state = link;
8598d349aceSKenji Kaneshige return link;
8608d349aceSKenji Kaneshige }
8618d349aceSKenji Kaneshige
pcie_aspm_update_sysfs_visibility(struct pci_dev * pdev)86272ea91afSHeiner Kallweit static void pcie_aspm_update_sysfs_visibility(struct pci_dev *pdev)
86372ea91afSHeiner Kallweit {
86472ea91afSHeiner Kallweit struct pci_dev *child;
86572ea91afSHeiner Kallweit
86672ea91afSHeiner Kallweit list_for_each_entry(child, &pdev->subordinate->devices, bus_list)
86772ea91afSHeiner Kallweit sysfs_update_group(&child->dev.kobj, &aspm_ctrl_attr_group);
86872ea91afSHeiner Kallweit }
86972ea91afSHeiner Kallweit
8707d715a6cSShaohua Li /*
8717d715a6cSShaohua Li * pcie_aspm_init_link_state: Initiate PCI express link state.
872f7625980SBjorn Helgaas * It is called after the pcie and its children devices are scanned.
8737d715a6cSShaohua Li * @pdev: the root port or switch downstream port
8747d715a6cSShaohua Li */
pcie_aspm_init_link_state(struct pci_dev * pdev)8757d715a6cSShaohua Li void pcie_aspm_init_link_state(struct pci_dev *pdev)
8767d715a6cSShaohua Li {
8778d349aceSKenji Kaneshige struct pcie_link_state *link;
878b7206cbfSKenji Kaneshige int blacklist = !!pcie_aspm_sanity_check(pdev);
8797d715a6cSShaohua Li
880b07b864eSBjorn Helgaas if (!aspm_support_enabled)
881a26d5ecbSJoe Lawrence return;
882a26d5ecbSJoe Lawrence
883c8fc9339SYijing Wang if (pdev->link_state)
8847d715a6cSShaohua Li return;
885c8fc9339SYijing Wang
886c8fc9339SYijing Wang /*
887c8fc9339SYijing Wang * We allocate pcie_link_state for the component on the upstream
888ca784104SMika Westerberg * end of a Link, so there's nothing to do unless this device is
889ca784104SMika Westerberg * downstream port.
890c8fc9339SYijing Wang */
891ca784104SMika Westerberg if (!pcie_downstream_port(pdev))
8927d715a6cSShaohua Li return;
8938d349aceSKenji Kaneshige
8948e822df7SShaohua Li /* VIA has a strange chipset, root port is under a bridge */
89562f87c0eSYijing Wang if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT &&
8968e822df7SShaohua Li pdev->bus->self)
8978e822df7SShaohua Li return;
8988d349aceSKenji Kaneshige
8997d715a6cSShaohua Li down_read(&pci_bus_sem);
9007d715a6cSShaohua Li if (list_empty(&pdev->subordinate->devices))
9017d715a6cSShaohua Li goto out;
9027d715a6cSShaohua Li
9037d715a6cSShaohua Li mutex_lock(&aspm_lock);
904b7206cbfSKenji Kaneshige link = alloc_pcie_link_state(pdev);
9058d349aceSKenji Kaneshige if (!link)
9068d349aceSKenji Kaneshige goto unlock;
90746bbdfa4SShaohua Li /*
908b7206cbfSKenji Kaneshige * Setup initial ASPM state. Note that we need to configure
909b7206cbfSKenji Kaneshige * upstream links also because capable state of them can be
910b7206cbfSKenji Kaneshige * update through pcie_aspm_cap_init().
9118d349aceSKenji Kaneshige */
912b7206cbfSKenji Kaneshige pcie_aspm_cap_init(link, blacklist);
91346bbdfa4SShaohua Li
9148d349aceSKenji Kaneshige /* Setup initial Clock PM state */
915b7206cbfSKenji Kaneshige pcie_clkpm_cap_init(link, blacklist);
91641cd766bSMatthew Garrett
91741cd766bSMatthew Garrett /*
91841cd766bSMatthew Garrett * At this stage drivers haven't had an opportunity to change the
91941cd766bSMatthew Garrett * link policy setting. Enabling ASPM on broken hardware can cripple
92041cd766bSMatthew Garrett * it even before the driver has had a chance to disable ASPM, so
92141cd766bSMatthew Garrett * default to a safe level right now. If we're enabling ASPM beyond
92241cd766bSMatthew Garrett * the BIOS's expectation, we'll do so once pci_enable_device() is
92341cd766bSMatthew Garrett * called.
92441cd766bSMatthew Garrett */
925b2103ccbSRajat Jain if (aspm_policy != POLICY_POWERSAVE &&
926b2103ccbSRajat Jain aspm_policy != POLICY_POWER_SUPERSAVE) {
92741cd766bSMatthew Garrett pcie_config_aspm_path(link);
928b7206cbfSKenji Kaneshige pcie_set_clkpm(link, policy_to_clkpm_state(link));
92941cd766bSMatthew Garrett }
93041cd766bSMatthew Garrett
93172ea91afSHeiner Kallweit pcie_aspm_update_sysfs_visibility(pdev);
93272ea91afSHeiner Kallweit
9338d349aceSKenji Kaneshige unlock:
9347d715a6cSShaohua Li mutex_unlock(&aspm_lock);
9357d715a6cSShaohua Li out:
9367d715a6cSShaohua Li up_read(&pci_bus_sem);
9377d715a6cSShaohua Li }
9387d715a6cSShaohua Li
93907d92760SKenji Kaneshige /* Recheck latencies and update aspm_capable for links under the root */
pcie_update_aspm_capable(struct pcie_link_state * root)94007d92760SKenji Kaneshige static void pcie_update_aspm_capable(struct pcie_link_state *root)
94107d92760SKenji Kaneshige {
94207d92760SKenji Kaneshige struct pcie_link_state *link;
94307d92760SKenji Kaneshige BUG_ON(root->parent);
94407d92760SKenji Kaneshige list_for_each_entry(link, &link_list, sibling) {
94507d92760SKenji Kaneshige if (link->root != root)
94607d92760SKenji Kaneshige continue;
94707d92760SKenji Kaneshige link->aspm_capable = link->aspm_support;
94807d92760SKenji Kaneshige }
94907d92760SKenji Kaneshige list_for_each_entry(link, &link_list, sibling) {
95007d92760SKenji Kaneshige struct pci_dev *child;
95107d92760SKenji Kaneshige struct pci_bus *linkbus = link->pdev->subordinate;
95207d92760SKenji Kaneshige if (link->root != root)
95307d92760SKenji Kaneshige continue;
95407d92760SKenji Kaneshige list_for_each_entry(child, &linkbus->devices, bus_list) {
95562f87c0eSYijing Wang if ((pci_pcie_type(child) != PCI_EXP_TYPE_ENDPOINT) &&
95662f87c0eSYijing Wang (pci_pcie_type(child) != PCI_EXP_TYPE_LEG_END))
95707d92760SKenji Kaneshige continue;
95807d92760SKenji Kaneshige pcie_aspm_check_latency(child);
95907d92760SKenji Kaneshige }
96007d92760SKenji Kaneshige }
96107d92760SKenji Kaneshige }
96207d92760SKenji Kaneshige
9637d715a6cSShaohua Li /* @pdev: the endpoint device */
pcie_aspm_exit_link_state(struct pci_dev * pdev)9647d715a6cSShaohua Li void pcie_aspm_exit_link_state(struct pci_dev *pdev)
9657d715a6cSShaohua Li {
9667d715a6cSShaohua Li struct pci_dev *parent = pdev->bus->self;
967b7206cbfSKenji Kaneshige struct pcie_link_state *link, *root, *parent_link;
9687d715a6cSShaohua Li
96984fb913cSMyron Stowe if (!parent || !parent->link_state)
9707d715a6cSShaohua Li return;
971fc87e919SKenji Kaneshige
9727d715a6cSShaohua Li down_read(&pci_bus_sem);
9737d715a6cSShaohua Li mutex_lock(&aspm_lock);
9747d715a6cSShaohua Li
975fc87e919SKenji Kaneshige link = parent->link_state;
97607d92760SKenji Kaneshige root = link->root;
977b7206cbfSKenji Kaneshige parent_link = link->parent;
978fc87e919SKenji Kaneshige
979456d8aa3SDing Hui /*
980456d8aa3SDing Hui * link->downstream is a pointer to the pci_dev of function 0. If
981456d8aa3SDing Hui * we remove that function, the pci_dev is about to be deallocated,
982456d8aa3SDing Hui * so we can't use link->downstream again. Free the link state to
983456d8aa3SDing Hui * avoid this.
984456d8aa3SDing Hui *
985456d8aa3SDing Hui * If we're removing a non-0 function, it's possible we could
986456d8aa3SDing Hui * retain the link state, but PCIe r6.0, sec 7.5.3.7, recommends
987456d8aa3SDing Hui * programming the same ASPM Control value for all functions of
988456d8aa3SDing Hui * multi-function devices, so disable ASPM for all of them.
989456d8aa3SDing Hui */
990b7206cbfSKenji Kaneshige pcie_config_aspm_link(link, 0);
991fc87e919SKenji Kaneshige list_del(&link->sibling);
992fc87e919SKenji Kaneshige free_link_state(link);
99307d92760SKenji Kaneshige
99407d92760SKenji Kaneshige /* Recheck latencies and configure upstream links */
995b26a34aaSKenji Kaneshige if (parent_link) {
99607d92760SKenji Kaneshige pcie_update_aspm_capable(root);
997b7206cbfSKenji Kaneshige pcie_config_aspm_path(parent_link);
998b26a34aaSKenji Kaneshige }
999456d8aa3SDing Hui
10007d715a6cSShaohua Li mutex_unlock(&aspm_lock);
10017d715a6cSShaohua Li up_read(&pci_bus_sem);
10027d715a6cSShaohua Li }
10037d715a6cSShaohua Li
1004*b0f44788SJohan Hovold /*
1005*b0f44788SJohan Hovold * @pdev: the root port or switch downstream port
1006*b0f44788SJohan Hovold * @locked: whether pci_bus_sem is held
1007*b0f44788SJohan Hovold */
pcie_aspm_pm_state_change(struct pci_dev * pdev,bool locked)1008*b0f44788SJohan Hovold void pcie_aspm_pm_state_change(struct pci_dev *pdev, bool locked)
10098cc22ba3SBjorn Helgaas {
10108cc22ba3SBjorn Helgaas struct pcie_link_state *link = pdev->link_state;
10118cc22ba3SBjorn Helgaas
10128cc22ba3SBjorn Helgaas if (aspm_disabled || !link)
10138cc22ba3SBjorn Helgaas return;
10148cc22ba3SBjorn Helgaas /*
10158cc22ba3SBjorn Helgaas * Devices changed PM state, we should recheck if latency
10168cc22ba3SBjorn Helgaas * meets all functions' requirement
10178cc22ba3SBjorn Helgaas */
1018*b0f44788SJohan Hovold if (!locked)
10198cc22ba3SBjorn Helgaas down_read(&pci_bus_sem);
10208cc22ba3SBjorn Helgaas mutex_lock(&aspm_lock);
10218cc22ba3SBjorn Helgaas pcie_update_aspm_capable(link->root);
10228cc22ba3SBjorn Helgaas pcie_config_aspm_path(link);
10238cc22ba3SBjorn Helgaas mutex_unlock(&aspm_lock);
1024*b0f44788SJohan Hovold if (!locked)
10258cc22ba3SBjorn Helgaas up_read(&pci_bus_sem);
10268cc22ba3SBjorn Helgaas }
10278cc22ba3SBjorn Helgaas
pcie_aspm_powersave_config_link(struct pci_dev * pdev)10281a680b7cSNaga Chumbalkar void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
10291a680b7cSNaga Chumbalkar {
10301a680b7cSNaga Chumbalkar struct pcie_link_state *link = pdev->link_state;
10311a680b7cSNaga Chumbalkar
1032f9b8cd7cSYijing Wang if (aspm_disabled || !link)
10331a680b7cSNaga Chumbalkar return;
10341a680b7cSNaga Chumbalkar
1035b2103ccbSRajat Jain if (aspm_policy != POLICY_POWERSAVE &&
1036b2103ccbSRajat Jain aspm_policy != POLICY_POWER_SUPERSAVE)
10371a680b7cSNaga Chumbalkar return;
10381a680b7cSNaga Chumbalkar
10391a680b7cSNaga Chumbalkar down_read(&pci_bus_sem);
10401a680b7cSNaga Chumbalkar mutex_lock(&aspm_lock);
10411a680b7cSNaga Chumbalkar pcie_config_aspm_path(link);
10421a680b7cSNaga Chumbalkar pcie_set_clkpm(link, policy_to_clkpm_state(link));
10431a680b7cSNaga Chumbalkar mutex_unlock(&aspm_lock);
10441a680b7cSNaga Chumbalkar up_read(&pci_bus_sem);
10451a680b7cSNaga Chumbalkar }
10461a680b7cSNaga Chumbalkar
pcie_aspm_get_link(struct pci_dev * pdev)1047687aaf38SHeiner Kallweit static struct pcie_link_state *pcie_aspm_get_link(struct pci_dev *pdev)
10487d715a6cSShaohua Li {
1049687aaf38SHeiner Kallweit struct pci_dev *bridge;
10507d715a6cSShaohua Li
10513c076351SMatthew Garrett if (!pci_is_pcie(pdev))
1052687aaf38SHeiner Kallweit return NULL;
10533c076351SMatthew Garrett
1054687aaf38SHeiner Kallweit bridge = pci_upstream_bridge(pdev);
1055687aaf38SHeiner Kallweit if (!bridge || !pci_is_pcie(bridge))
1056687aaf38SHeiner Kallweit return NULL;
1057687aaf38SHeiner Kallweit
1058687aaf38SHeiner Kallweit return bridge->link_state;
1059687aaf38SHeiner Kallweit }
1060687aaf38SHeiner Kallweit
__pci_disable_link_state(struct pci_dev * pdev,int state,bool sem)1061687aaf38SHeiner Kallweit static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
1062687aaf38SHeiner Kallweit {
1063687aaf38SHeiner Kallweit struct pcie_link_state *link = pcie_aspm_get_link(pdev);
1064687aaf38SHeiner Kallweit
1065687aaf38SHeiner Kallweit if (!link)
10664cfd2188SHeiner Kallweit return -EINVAL;
10672add0ec1SBjorn Helgaas /*
10682add0ec1SBjorn Helgaas * A driver requested that ASPM be disabled on this device, but
10692add0ec1SBjorn Helgaas * if we don't have permission to manage ASPM (e.g., on ACPI
10702add0ec1SBjorn Helgaas * systems we have to observe the FADT ACPI_FADT_NO_ASPM bit and
10712add0ec1SBjorn Helgaas * the _OSC method), we can't honor that request. Windows has
10722add0ec1SBjorn Helgaas * a similar mechanism using "PciASPMOptOut", which is also
10732add0ec1SBjorn Helgaas * ignored in this situation.
10742add0ec1SBjorn Helgaas */
1075e127a04fSBjorn Helgaas if (aspm_disabled) {
10767506dc79SFrederick Lawler pci_warn(pdev, "can't disable ASPM; OS doesn't have ASPM control\n");
10774cfd2188SHeiner Kallweit return -EPERM;
10782add0ec1SBjorn Helgaas }
10792add0ec1SBjorn Helgaas
10809f728f53SYinghai Lu if (sem)
10817d715a6cSShaohua Li down_read(&pci_bus_sem);
10827d715a6cSShaohua Li mutex_lock(&aspm_lock);
1083ac18018aSKenji Kaneshige if (state & PCIE_LINK_STATE_L0S)
1084ac18018aSKenji Kaneshige link->aspm_disable |= ASPM_STATE_L0S;
1085ac18018aSKenji Kaneshige if (state & PCIE_LINK_STATE_L1)
108684d24fe4SHeiner Kallweit /* L1 PM substates require L1 */
108784d24fe4SHeiner Kallweit link->aspm_disable |= ASPM_STATE_L1 | ASPM_STATE_L1SS;
1088aff5d055SHeiner Kallweit if (state & PCIE_LINK_STATE_L1_1)
1089aff5d055SHeiner Kallweit link->aspm_disable |= ASPM_STATE_L1_1;
1090aff5d055SHeiner Kallweit if (state & PCIE_LINK_STATE_L1_2)
1091aff5d055SHeiner Kallweit link->aspm_disable |= ASPM_STATE_L1_2;
1092aff5d055SHeiner Kallweit if (state & PCIE_LINK_STATE_L1_1_PCIPM)
1093aff5d055SHeiner Kallweit link->aspm_disable |= ASPM_STATE_L1_1_PCIPM;
1094aff5d055SHeiner Kallweit if (state & PCIE_LINK_STATE_L1_2_PCIPM)
1095aff5d055SHeiner Kallweit link->aspm_disable |= ASPM_STATE_L1_2_PCIPM;
1096b7206cbfSKenji Kaneshige pcie_config_aspm_link(link, policy_to_aspm_state(link));
1097b7206cbfSKenji Kaneshige
109835efea32SHeiner Kallweit if (state & PCIE_LINK_STATE_CLKPM)
109935efea32SHeiner Kallweit link->clkpm_disable = 1;
110035efea32SHeiner Kallweit pcie_set_clkpm(link, policy_to_clkpm_state(link));
11017d715a6cSShaohua Li mutex_unlock(&aspm_lock);
11029f728f53SYinghai Lu if (sem)
11037d715a6cSShaohua Li up_read(&pci_bus_sem);
11044cfd2188SHeiner Kallweit
11054cfd2188SHeiner Kallweit return 0;
11067d715a6cSShaohua Li }
11079f728f53SYinghai Lu
pci_disable_link_state_locked(struct pci_dev * pdev,int state)11084cfd2188SHeiner Kallweit int pci_disable_link_state_locked(struct pci_dev *pdev, int state)
11099f728f53SYinghai Lu {
11104cfd2188SHeiner Kallweit return __pci_disable_link_state(pdev, state, false);
11119f728f53SYinghai Lu }
11129f728f53SYinghai Lu EXPORT_SYMBOL(pci_disable_link_state_locked);
11139f728f53SYinghai Lu
11142dfca877SYijing Wang /**
11152dfca877SYijing Wang * pci_disable_link_state - Disable device's link state, so the link will
11162dfca877SYijing Wang * never enter specific states. Note that if the BIOS didn't grant ASPM
11172dfca877SYijing Wang * control to the OS, this does nothing because we can't touch the LNKCTL
11184cfd2188SHeiner Kallweit * register. Returns 0 or a negative errno.
11192dfca877SYijing Wang *
11202dfca877SYijing Wang * @pdev: PCI device
11212dfca877SYijing Wang * @state: ASPM link state to disable
11222dfca877SYijing Wang */
pci_disable_link_state(struct pci_dev * pdev,int state)11234cfd2188SHeiner Kallweit int pci_disable_link_state(struct pci_dev *pdev, int state)
11249f728f53SYinghai Lu {
11254cfd2188SHeiner Kallweit return __pci_disable_link_state(pdev, state, true);
11269f728f53SYinghai Lu }
11277d715a6cSShaohua Li EXPORT_SYMBOL(pci_disable_link_state);
11287d715a6cSShaohua Li
__pci_enable_link_state(struct pci_dev * pdev,int state,bool locked)11291e1f461eSJohan Hovold static int __pci_enable_link_state(struct pci_dev *pdev, int state, bool locked)
1130de82f60fSMichael Bottini {
1131de82f60fSMichael Bottini struct pcie_link_state *link = pcie_aspm_get_link(pdev);
1132de82f60fSMichael Bottini
1133de82f60fSMichael Bottini if (!link)
1134de82f60fSMichael Bottini return -EINVAL;
1135de82f60fSMichael Bottini /*
1136de82f60fSMichael Bottini * A driver requested that ASPM be enabled on this device, but
1137de82f60fSMichael Bottini * if we don't have permission to manage ASPM (e.g., on ACPI
1138de82f60fSMichael Bottini * systems we have to observe the FADT ACPI_FADT_NO_ASPM bit and
1139de82f60fSMichael Bottini * the _OSC method), we can't honor that request.
1140de82f60fSMichael Bottini */
1141de82f60fSMichael Bottini if (aspm_disabled) {
1142de82f60fSMichael Bottini pci_warn(pdev, "can't override BIOS ASPM; OS doesn't have ASPM control\n");
1143de82f60fSMichael Bottini return -EPERM;
1144de82f60fSMichael Bottini }
1145de82f60fSMichael Bottini
11461e1f461eSJohan Hovold if (!locked)
1147de82f60fSMichael Bottini down_read(&pci_bus_sem);
1148de82f60fSMichael Bottini mutex_lock(&aspm_lock);
1149de82f60fSMichael Bottini link->aspm_default = 0;
1150de82f60fSMichael Bottini if (state & PCIE_LINK_STATE_L0S)
1151de82f60fSMichael Bottini link->aspm_default |= ASPM_STATE_L0S;
1152de82f60fSMichael Bottini if (state & PCIE_LINK_STATE_L1)
115325edb25dSAjay Agarwal link->aspm_default |= ASPM_STATE_L1;
115480950a54SAjay Agarwal /* L1 PM substates require L1 */
1155de82f60fSMichael Bottini if (state & PCIE_LINK_STATE_L1_1)
115680950a54SAjay Agarwal link->aspm_default |= ASPM_STATE_L1_1 | ASPM_STATE_L1;
1157de82f60fSMichael Bottini if (state & PCIE_LINK_STATE_L1_2)
115880950a54SAjay Agarwal link->aspm_default |= ASPM_STATE_L1_2 | ASPM_STATE_L1;
1159de82f60fSMichael Bottini if (state & PCIE_LINK_STATE_L1_1_PCIPM)
116080950a54SAjay Agarwal link->aspm_default |= ASPM_STATE_L1_1_PCIPM | ASPM_STATE_L1;
1161de82f60fSMichael Bottini if (state & PCIE_LINK_STATE_L1_2_PCIPM)
116280950a54SAjay Agarwal link->aspm_default |= ASPM_STATE_L1_2_PCIPM | ASPM_STATE_L1;
1163de82f60fSMichael Bottini pcie_config_aspm_link(link, policy_to_aspm_state(link));
1164de82f60fSMichael Bottini
1165de82f60fSMichael Bottini link->clkpm_default = (state & PCIE_LINK_STATE_CLKPM) ? 1 : 0;
1166de82f60fSMichael Bottini pcie_set_clkpm(link, policy_to_clkpm_state(link));
1167de82f60fSMichael Bottini mutex_unlock(&aspm_lock);
11681e1f461eSJohan Hovold if (!locked)
1169de82f60fSMichael Bottini up_read(&pci_bus_sem);
1170de82f60fSMichael Bottini
1171de82f60fSMichael Bottini return 0;
1172de82f60fSMichael Bottini }
11731e1f461eSJohan Hovold
11741e1f461eSJohan Hovold /**
11751e1f461eSJohan Hovold * pci_enable_link_state - Clear and set the default device link state so that
11761e1f461eSJohan Hovold * the link may be allowed to enter the specified states. Note that if the
11771e1f461eSJohan Hovold * BIOS didn't grant ASPM control to the OS, this does nothing because we can't
11781e1f461eSJohan Hovold * touch the LNKCTL register. Also note that this does not enable states
11791e1f461eSJohan Hovold * disabled by pci_disable_link_state(). Return 0 or a negative errno.
11801e1f461eSJohan Hovold *
11811e1f461eSJohan Hovold * @pdev: PCI device
11821e1f461eSJohan Hovold * @state: Mask of ASPM link states to enable
11831e1f461eSJohan Hovold */
pci_enable_link_state(struct pci_dev * pdev,int state)11841e1f461eSJohan Hovold int pci_enable_link_state(struct pci_dev *pdev, int state)
11851e1f461eSJohan Hovold {
11861e1f461eSJohan Hovold return __pci_enable_link_state(pdev, state, false);
11871e1f461eSJohan Hovold }
1188de82f60fSMichael Bottini EXPORT_SYMBOL(pci_enable_link_state);
1189de82f60fSMichael Bottini
11901e1f461eSJohan Hovold /**
11911e1f461eSJohan Hovold * pci_enable_link_state_locked - Clear and set the default device link state
11921e1f461eSJohan Hovold * so that the link may be allowed to enter the specified states. Note that if
11931e1f461eSJohan Hovold * the BIOS didn't grant ASPM control to the OS, this does nothing because we
11941e1f461eSJohan Hovold * can't touch the LNKCTL register. Also note that this does not enable states
11951e1f461eSJohan Hovold * disabled by pci_disable_link_state(). Return 0 or a negative errno.
11961e1f461eSJohan Hovold *
11971e1f461eSJohan Hovold * @pdev: PCI device
11981e1f461eSJohan Hovold * @state: Mask of ASPM link states to enable
11991e1f461eSJohan Hovold *
12001e1f461eSJohan Hovold * Context: Caller holds pci_bus_sem read lock.
12011e1f461eSJohan Hovold */
pci_enable_link_state_locked(struct pci_dev * pdev,int state)12021e1f461eSJohan Hovold int pci_enable_link_state_locked(struct pci_dev *pdev, int state)
12031e1f461eSJohan Hovold {
12041e1f461eSJohan Hovold lockdep_assert_held_read(&pci_bus_sem);
12051e1f461eSJohan Hovold
12061e1f461eSJohan Hovold return __pci_enable_link_state(pdev, state, true);
12071e1f461eSJohan Hovold }
12081e1f461eSJohan Hovold EXPORT_SYMBOL(pci_enable_link_state_locked);
12091e1f461eSJohan Hovold
pcie_aspm_set_policy(const char * val,const struct kernel_param * kp)1210e4dca7b7SKees Cook static int pcie_aspm_set_policy(const char *val,
1211e4dca7b7SKees Cook const struct kernel_param *kp)
12127d715a6cSShaohua Li {
12137d715a6cSShaohua Li int i;
1214b7206cbfSKenji Kaneshige struct pcie_link_state *link;
12157d715a6cSShaohua Li
1216bbfa306aSNaga Chumbalkar if (aspm_disabled)
1217bbfa306aSNaga Chumbalkar return -EPERM;
121836131ce9SAndy Shevchenko i = sysfs_match_string(policy_str, val);
121936131ce9SAndy Shevchenko if (i < 0)
122036131ce9SAndy Shevchenko return i;
12217d715a6cSShaohua Li if (i == aspm_policy)
12227d715a6cSShaohua Li return 0;
12237d715a6cSShaohua Li
12247d715a6cSShaohua Li down_read(&pci_bus_sem);
12257d715a6cSShaohua Li mutex_lock(&aspm_lock);
12267d715a6cSShaohua Li aspm_policy = i;
1227b7206cbfSKenji Kaneshige list_for_each_entry(link, &link_list, sibling) {
1228b7206cbfSKenji Kaneshige pcie_config_aspm_link(link, policy_to_aspm_state(link));
1229b7206cbfSKenji Kaneshige pcie_set_clkpm(link, policy_to_clkpm_state(link));
12307d715a6cSShaohua Li }
12317d715a6cSShaohua Li mutex_unlock(&aspm_lock);
12327d715a6cSShaohua Li up_read(&pci_bus_sem);
12337d715a6cSShaohua Li return 0;
12347d715a6cSShaohua Li }
12357d715a6cSShaohua Li
pcie_aspm_get_policy(char * buffer,const struct kernel_param * kp)1236e4dca7b7SKees Cook static int pcie_aspm_get_policy(char *buffer, const struct kernel_param *kp)
12377d715a6cSShaohua Li {
12387d715a6cSShaohua Li int i, cnt = 0;
12397d715a6cSShaohua Li for (i = 0; i < ARRAY_SIZE(policy_str); i++)
12407d715a6cSShaohua Li if (i == aspm_policy)
12417d715a6cSShaohua Li cnt += sprintf(buffer + cnt, "[%s] ", policy_str[i]);
12427d715a6cSShaohua Li else
12437d715a6cSShaohua Li cnt += sprintf(buffer + cnt, "%s ", policy_str[i]);
12443167e3d3SXiongfeng Wang cnt += sprintf(buffer + cnt, "\n");
12457d715a6cSShaohua Li return cnt;
12467d715a6cSShaohua Li }
12477d715a6cSShaohua Li
12487d715a6cSShaohua Li module_param_call(policy, pcie_aspm_set_policy, pcie_aspm_get_policy,
12497d715a6cSShaohua Li NULL, 0644);
12507d715a6cSShaohua Li
1251accd2dd7SRafael J. Wysocki /**
1252accd2dd7SRafael J. Wysocki * pcie_aspm_enabled - Check if PCIe ASPM has been enabled for a device.
1253accd2dd7SRafael J. Wysocki * @pdev: Target device.
12545e0c21c7SBjorn Helgaas *
12555e0c21c7SBjorn Helgaas * Relies on the upstream bridge's link_state being valid. The link_state
12565e0c21c7SBjorn Helgaas * is deallocated only when the last child of the bridge (i.e., @pdev or a
12575e0c21c7SBjorn Helgaas * sibling) is removed, and the caller should be holding a reference to
12585e0c21c7SBjorn Helgaas * @pdev, so this should be safe.
1259accd2dd7SRafael J. Wysocki */
pcie_aspm_enabled(struct pci_dev * pdev)1260accd2dd7SRafael J. Wysocki bool pcie_aspm_enabled(struct pci_dev *pdev)
1261accd2dd7SRafael J. Wysocki {
1262687aaf38SHeiner Kallweit struct pcie_link_state *link = pcie_aspm_get_link(pdev);
1263accd2dd7SRafael J. Wysocki
1264687aaf38SHeiner Kallweit if (!link)
1265accd2dd7SRafael J. Wysocki return false;
1266accd2dd7SRafael J. Wysocki
1267687aaf38SHeiner Kallweit return link->aspm_enabled;
1268accd2dd7SRafael J. Wysocki }
1269accd2dd7SRafael J. Wysocki EXPORT_SYMBOL_GPL(pcie_aspm_enabled);
1270accd2dd7SRafael J. Wysocki
aspm_attr_show_common(struct device * dev,struct device_attribute * attr,char * buf,u8 state)127172ea91afSHeiner Kallweit static ssize_t aspm_attr_show_common(struct device *dev,
127272ea91afSHeiner Kallweit struct device_attribute *attr,
127372ea91afSHeiner Kallweit char *buf, u8 state)
127472ea91afSHeiner Kallweit {
127572ea91afSHeiner Kallweit struct pci_dev *pdev = to_pci_dev(dev);
127672ea91afSHeiner Kallweit struct pcie_link_state *link = pcie_aspm_get_link(pdev);
127772ea91afSHeiner Kallweit
1278f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%d\n", (link->aspm_enabled & state) ? 1 : 0);
127972ea91afSHeiner Kallweit }
128072ea91afSHeiner Kallweit
aspm_attr_store_common(struct device * dev,struct device_attribute * attr,const char * buf,size_t len,u8 state)128172ea91afSHeiner Kallweit static ssize_t aspm_attr_store_common(struct device *dev,
128272ea91afSHeiner Kallweit struct device_attribute *attr,
128372ea91afSHeiner Kallweit const char *buf, size_t len, u8 state)
128472ea91afSHeiner Kallweit {
128572ea91afSHeiner Kallweit struct pci_dev *pdev = to_pci_dev(dev);
128672ea91afSHeiner Kallweit struct pcie_link_state *link = pcie_aspm_get_link(pdev);
128772ea91afSHeiner Kallweit bool state_enable;
128872ea91afSHeiner Kallweit
1289e0f7b192SKrzysztof Wilczyński if (kstrtobool(buf, &state_enable) < 0)
129072ea91afSHeiner Kallweit return -EINVAL;
129172ea91afSHeiner Kallweit
129272ea91afSHeiner Kallweit down_read(&pci_bus_sem);
129372ea91afSHeiner Kallweit mutex_lock(&aspm_lock);
129472ea91afSHeiner Kallweit
129572ea91afSHeiner Kallweit if (state_enable) {
129672ea91afSHeiner Kallweit link->aspm_disable &= ~state;
129772ea91afSHeiner Kallweit /* need to enable L1 for substates */
129872ea91afSHeiner Kallweit if (state & ASPM_STATE_L1SS)
129972ea91afSHeiner Kallweit link->aspm_disable &= ~ASPM_STATE_L1;
130072ea91afSHeiner Kallweit } else {
130172ea91afSHeiner Kallweit link->aspm_disable |= state;
13027fce228cSHeiner Kallweit if (state & ASPM_STATE_L1)
13037fce228cSHeiner Kallweit link->aspm_disable |= ASPM_STATE_L1SS;
130472ea91afSHeiner Kallweit }
130572ea91afSHeiner Kallweit
130672ea91afSHeiner Kallweit pcie_config_aspm_link(link, policy_to_aspm_state(link));
130772ea91afSHeiner Kallweit
130872ea91afSHeiner Kallweit mutex_unlock(&aspm_lock);
130972ea91afSHeiner Kallweit up_read(&pci_bus_sem);
131072ea91afSHeiner Kallweit
131172ea91afSHeiner Kallweit return len;
131272ea91afSHeiner Kallweit }
131372ea91afSHeiner Kallweit
131472ea91afSHeiner Kallweit #define ASPM_ATTR(_f, _s) \
131572ea91afSHeiner Kallweit static ssize_t _f##_show(struct device *dev, \
131672ea91afSHeiner Kallweit struct device_attribute *attr, char *buf) \
131772ea91afSHeiner Kallweit { return aspm_attr_show_common(dev, attr, buf, ASPM_STATE_##_s); } \
131872ea91afSHeiner Kallweit \
131972ea91afSHeiner Kallweit static ssize_t _f##_store(struct device *dev, \
132072ea91afSHeiner Kallweit struct device_attribute *attr, \
132172ea91afSHeiner Kallweit const char *buf, size_t len) \
132272ea91afSHeiner Kallweit { return aspm_attr_store_common(dev, attr, buf, len, ASPM_STATE_##_s); }
132372ea91afSHeiner Kallweit
ASPM_ATTR(l0s_aspm,L0S)132472ea91afSHeiner Kallweit ASPM_ATTR(l0s_aspm, L0S)
132572ea91afSHeiner Kallweit ASPM_ATTR(l1_aspm, L1)
132672ea91afSHeiner Kallweit ASPM_ATTR(l1_1_aspm, L1_1)
132772ea91afSHeiner Kallweit ASPM_ATTR(l1_2_aspm, L1_2)
132872ea91afSHeiner Kallweit ASPM_ATTR(l1_1_pcipm, L1_1_PCIPM)
132972ea91afSHeiner Kallweit ASPM_ATTR(l1_2_pcipm, L1_2_PCIPM)
133072ea91afSHeiner Kallweit
133172ea91afSHeiner Kallweit static ssize_t clkpm_show(struct device *dev,
133272ea91afSHeiner Kallweit struct device_attribute *attr, char *buf)
133372ea91afSHeiner Kallweit {
133472ea91afSHeiner Kallweit struct pci_dev *pdev = to_pci_dev(dev);
133572ea91afSHeiner Kallweit struct pcie_link_state *link = pcie_aspm_get_link(pdev);
133672ea91afSHeiner Kallweit
1337f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%d\n", link->clkpm_enabled);
133872ea91afSHeiner Kallweit }
133972ea91afSHeiner Kallweit
clkpm_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)134072ea91afSHeiner Kallweit static ssize_t clkpm_store(struct device *dev,
134172ea91afSHeiner Kallweit struct device_attribute *attr,
134272ea91afSHeiner Kallweit const char *buf, size_t len)
134372ea91afSHeiner Kallweit {
134472ea91afSHeiner Kallweit struct pci_dev *pdev = to_pci_dev(dev);
134572ea91afSHeiner Kallweit struct pcie_link_state *link = pcie_aspm_get_link(pdev);
134672ea91afSHeiner Kallweit bool state_enable;
134772ea91afSHeiner Kallweit
1348e0f7b192SKrzysztof Wilczyński if (kstrtobool(buf, &state_enable) < 0)
134972ea91afSHeiner Kallweit return -EINVAL;
135072ea91afSHeiner Kallweit
135172ea91afSHeiner Kallweit down_read(&pci_bus_sem);
135272ea91afSHeiner Kallweit mutex_lock(&aspm_lock);
135372ea91afSHeiner Kallweit
135472ea91afSHeiner Kallweit link->clkpm_disable = !state_enable;
135572ea91afSHeiner Kallweit pcie_set_clkpm(link, policy_to_clkpm_state(link));
135672ea91afSHeiner Kallweit
135772ea91afSHeiner Kallweit mutex_unlock(&aspm_lock);
135872ea91afSHeiner Kallweit up_read(&pci_bus_sem);
135972ea91afSHeiner Kallweit
136072ea91afSHeiner Kallweit return len;
136172ea91afSHeiner Kallweit }
136272ea91afSHeiner Kallweit
136372ea91afSHeiner Kallweit static DEVICE_ATTR_RW(clkpm);
136472ea91afSHeiner Kallweit static DEVICE_ATTR_RW(l0s_aspm);
136572ea91afSHeiner Kallweit static DEVICE_ATTR_RW(l1_aspm);
136672ea91afSHeiner Kallweit static DEVICE_ATTR_RW(l1_1_aspm);
136772ea91afSHeiner Kallweit static DEVICE_ATTR_RW(l1_2_aspm);
136872ea91afSHeiner Kallweit static DEVICE_ATTR_RW(l1_1_pcipm);
136972ea91afSHeiner Kallweit static DEVICE_ATTR_RW(l1_2_pcipm);
137072ea91afSHeiner Kallweit
137172ea91afSHeiner Kallweit static struct attribute *aspm_ctrl_attrs[] = {
137272ea91afSHeiner Kallweit &dev_attr_clkpm.attr,
137372ea91afSHeiner Kallweit &dev_attr_l0s_aspm.attr,
137472ea91afSHeiner Kallweit &dev_attr_l1_aspm.attr,
137572ea91afSHeiner Kallweit &dev_attr_l1_1_aspm.attr,
137672ea91afSHeiner Kallweit &dev_attr_l1_2_aspm.attr,
137772ea91afSHeiner Kallweit &dev_attr_l1_1_pcipm.attr,
137872ea91afSHeiner Kallweit &dev_attr_l1_2_pcipm.attr,
137972ea91afSHeiner Kallweit NULL
138072ea91afSHeiner Kallweit };
138172ea91afSHeiner Kallweit
aspm_ctrl_attrs_are_visible(struct kobject * kobj,struct attribute * a,int n)138272ea91afSHeiner Kallweit static umode_t aspm_ctrl_attrs_are_visible(struct kobject *kobj,
138372ea91afSHeiner Kallweit struct attribute *a, int n)
138472ea91afSHeiner Kallweit {
138572ea91afSHeiner Kallweit struct device *dev = kobj_to_dev(kobj);
138672ea91afSHeiner Kallweit struct pci_dev *pdev = to_pci_dev(dev);
138772ea91afSHeiner Kallweit struct pcie_link_state *link = pcie_aspm_get_link(pdev);
138872ea91afSHeiner Kallweit static const u8 aspm_state_map[] = {
138972ea91afSHeiner Kallweit ASPM_STATE_L0S,
139072ea91afSHeiner Kallweit ASPM_STATE_L1,
139172ea91afSHeiner Kallweit ASPM_STATE_L1_1,
139272ea91afSHeiner Kallweit ASPM_STATE_L1_2,
139372ea91afSHeiner Kallweit ASPM_STATE_L1_1_PCIPM,
139472ea91afSHeiner Kallweit ASPM_STATE_L1_2_PCIPM,
139572ea91afSHeiner Kallweit };
139672ea91afSHeiner Kallweit
139772ea91afSHeiner Kallweit if (aspm_disabled || !link)
139872ea91afSHeiner Kallweit return 0;
139972ea91afSHeiner Kallweit
140072ea91afSHeiner Kallweit if (n == 0)
140172ea91afSHeiner Kallweit return link->clkpm_capable ? a->mode : 0;
140272ea91afSHeiner Kallweit
140372ea91afSHeiner Kallweit return link->aspm_capable & aspm_state_map[n - 1] ? a->mode : 0;
140472ea91afSHeiner Kallweit }
140572ea91afSHeiner Kallweit
140672ea91afSHeiner Kallweit const struct attribute_group aspm_ctrl_attr_group = {
140772ea91afSHeiner Kallweit .name = "link",
140872ea91afSHeiner Kallweit .attrs = aspm_ctrl_attrs,
140972ea91afSHeiner Kallweit .is_visible = aspm_ctrl_attrs_are_visible,
141072ea91afSHeiner Kallweit };
141172ea91afSHeiner Kallweit
pcie_aspm_disable(char * str)14127d715a6cSShaohua Li static int __init pcie_aspm_disable(char *str)
14137d715a6cSShaohua Li {
1414d6d38574SShaohua Li if (!strcmp(str, "off")) {
14153c076351SMatthew Garrett aspm_policy = POLICY_DEFAULT;
14167d715a6cSShaohua Li aspm_disabled = 1;
14178b8bae90SRafael J. Wysocki aspm_support_enabled = false;
1418d6d38574SShaohua Li printk(KERN_INFO "PCIe ASPM is disabled\n");
1419d6d38574SShaohua Li } else if (!strcmp(str, "force")) {
1420d6d38574SShaohua Li aspm_force = 1;
14218072ba1bSMichael Witten printk(KERN_INFO "PCIe ASPM is forcibly enabled\n");
1422d6d38574SShaohua Li }
14237d715a6cSShaohua Li return 1;
14247d715a6cSShaohua Li }
14257d715a6cSShaohua Li
1426d6d38574SShaohua Li __setup("pcie_aspm=", pcie_aspm_disable);
14277d715a6cSShaohua Li
pcie_no_aspm(void)14285fde244dSShaohua Li void pcie_no_aspm(void)
14295fde244dSShaohua Li {
14303c076351SMatthew Garrett /*
14313c076351SMatthew Garrett * Disabling ASPM is intended to prevent the kernel from modifying
14323c076351SMatthew Garrett * existing hardware state, not to clear existing state. To that end:
14333c076351SMatthew Garrett * (a) set policy to POLICY_DEFAULT in order to avoid changing state
14343c076351SMatthew Garrett * (b) prevent userspace from changing policy
14353c076351SMatthew Garrett */
14363c076351SMatthew Garrett if (!aspm_force) {
14373c076351SMatthew Garrett aspm_policy = POLICY_DEFAULT;
14385fde244dSShaohua Li aspm_disabled = 1;
14395fde244dSShaohua Li }
14403c076351SMatthew Garrett }
14415fde244dSShaohua Li
pcie_aspm_support_enabled(void)14428b8bae90SRafael J. Wysocki bool pcie_aspm_support_enabled(void)
14438b8bae90SRafael J. Wysocki {
14448b8bae90SRafael J. Wysocki return aspm_support_enabled;
14458b8bae90SRafael J. Wysocki }
1446