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> 117d715a6cSShaohua Li #include <linux/module.h> 127d715a6cSShaohua Li #include <linux/moduleparam.h> 137d715a6cSShaohua Li #include <linux/pci.h> 147d715a6cSShaohua Li #include <linux/pci_regs.h> 157d715a6cSShaohua Li #include <linux/errno.h> 167d715a6cSShaohua Li #include <linux/pm.h> 177d715a6cSShaohua Li #include <linux/init.h> 187d715a6cSShaohua Li #include <linux/slab.h> 192a42d9dbSThomas Renninger #include <linux/jiffies.h> 20987a4c78SAndrew Patterson #include <linux/delay.h> 217d715a6cSShaohua Li #include "../pci.h" 227d715a6cSShaohua Li 237d715a6cSShaohua Li #ifdef MODULE_PARAM_PREFIX 247d715a6cSShaohua Li #undef MODULE_PARAM_PREFIX 257d715a6cSShaohua Li #endif 267d715a6cSShaohua Li #define MODULE_PARAM_PREFIX "pcie_aspm." 277d715a6cSShaohua Li 28ac18018aSKenji Kaneshige /* Note: those are not register definitions */ 29ac18018aSKenji Kaneshige #define ASPM_STATE_L0S_UP (1) /* Upstream direction L0s state */ 30ac18018aSKenji Kaneshige #define ASPM_STATE_L0S_DW (2) /* Downstream direction L0s state */ 31ac18018aSKenji Kaneshige #define ASPM_STATE_L1 (4) /* L1 state */ 32b2103ccbSRajat Jain #define ASPM_STATE_L1_1 (8) /* ASPM L1.1 state */ 33b2103ccbSRajat Jain #define ASPM_STATE_L1_2 (0x10) /* ASPM L1.2 state */ 34b2103ccbSRajat Jain #define ASPM_STATE_L1_1_PCIPM (0x20) /* PCI PM L1.1 state */ 35b2103ccbSRajat Jain #define ASPM_STATE_L1_2_PCIPM (0x40) /* PCI PM L1.2 state */ 36b2103ccbSRajat Jain #define ASPM_STATE_L1_SS_PCIPM (ASPM_STATE_L1_1_PCIPM | ASPM_STATE_L1_2_PCIPM) 37b2103ccbSRajat Jain #define ASPM_STATE_L1_2_MASK (ASPM_STATE_L1_2 | ASPM_STATE_L1_2_PCIPM) 38b2103ccbSRajat Jain #define ASPM_STATE_L1SS (ASPM_STATE_L1_1 | ASPM_STATE_L1_1_PCIPM |\ 39b2103ccbSRajat Jain ASPM_STATE_L1_2_MASK) 40ac18018aSKenji Kaneshige #define ASPM_STATE_L0S (ASPM_STATE_L0S_UP | ASPM_STATE_L0S_DW) 41b2103ccbSRajat Jain #define ASPM_STATE_ALL (ASPM_STATE_L0S | ASPM_STATE_L1 | \ 42b2103ccbSRajat Jain ASPM_STATE_L1SS) 43ac18018aSKenji Kaneshige 447d715a6cSShaohua Li struct pcie_link_state { 455cde89d8SKenji Kaneshige struct pci_dev *pdev; /* Upstream component of the Link */ 46b5a0a9b5SRajat Jain struct pci_dev *downstream; /* Downstream component, function 0 */ 475c92ffb1SKenji Kaneshige struct pcie_link_state *root; /* pointer to the root port link */ 485cde89d8SKenji Kaneshige struct pcie_link_state *parent; /* pointer to the parent Link state */ 495cde89d8SKenji Kaneshige struct list_head sibling; /* node in link_list */ 507d715a6cSShaohua Li 517d715a6cSShaohua Li /* ASPM state */ 52b2103ccbSRajat Jain u32 aspm_support:7; /* Supported ASPM state */ 53b2103ccbSRajat Jain u32 aspm_enabled:7; /* Enabled ASPM state */ 54b2103ccbSRajat Jain u32 aspm_capable:7; /* Capable ASPM state with latency */ 55b2103ccbSRajat Jain u32 aspm_default:7; /* Default ASPM state by BIOS */ 56b2103ccbSRajat Jain u32 aspm_disable:7; /* Disabled ASPM state */ 5780bfdbe3SKenji Kaneshige 584d246e45SKenji Kaneshige /* Clock PM state */ 594d246e45SKenji Kaneshige u32 clkpm_capable:1; /* Clock PM capable? */ 604d246e45SKenji Kaneshige u32 clkpm_enabled:1; /* Current Clock PM state */ 614d246e45SKenji Kaneshige u32 clkpm_default:1; /* Default Clock PM state by BIOS */ 6235efea32SHeiner Kallweit u32 clkpm_disable:1; /* Clock PM disabled */ 637d715a6cSShaohua Li }; 647d715a6cSShaohua Li 653c076351SMatthew Garrett static int aspm_disabled, aspm_force; 668b8bae90SRafael J. Wysocki static bool aspm_support_enabled = true; 677d715a6cSShaohua Li static DEFINE_MUTEX(aspm_lock); 687d715a6cSShaohua Li static LIST_HEAD(link_list); 697d715a6cSShaohua Li 707d715a6cSShaohua Li #define POLICY_DEFAULT 0 /* BIOS default setting */ 717d715a6cSShaohua Li #define POLICY_PERFORMANCE 1 /* high performance */ 727d715a6cSShaohua Li #define POLICY_POWERSAVE 2 /* high power saving */ 73b2103ccbSRajat Jain #define POLICY_POWER_SUPERSAVE 3 /* possibly even more power saving */ 74ad71c962SMatthew Garrett 75ad71c962SMatthew Garrett #ifdef CONFIG_PCIEASPM_PERFORMANCE 76ad71c962SMatthew Garrett static int aspm_policy = POLICY_PERFORMANCE; 77ad71c962SMatthew Garrett #elif defined CONFIG_PCIEASPM_POWERSAVE 78ad71c962SMatthew Garrett static int aspm_policy = POLICY_POWERSAVE; 79b2103ccbSRajat Jain #elif defined CONFIG_PCIEASPM_POWER_SUPERSAVE 80b2103ccbSRajat Jain static int aspm_policy = POLICY_POWER_SUPERSAVE; 81ad71c962SMatthew Garrett #else 827d715a6cSShaohua Li static int aspm_policy; 83ad71c962SMatthew Garrett #endif 84ad71c962SMatthew Garrett 857d715a6cSShaohua Li static const char *policy_str[] = { 867d715a6cSShaohua Li [POLICY_DEFAULT] = "default", 877d715a6cSShaohua Li [POLICY_PERFORMANCE] = "performance", 88b2103ccbSRajat Jain [POLICY_POWERSAVE] = "powersave", 89b2103ccbSRajat Jain [POLICY_POWER_SUPERSAVE] = "powersupersave" 907d715a6cSShaohua Li }; 917d715a6cSShaohua Li 92987a4c78SAndrew Patterson #define LINK_RETRAIN_TIMEOUT HZ 93987a4c78SAndrew Patterson 9443262f00SBolarinwa O. Saheed /* 9543262f00SBolarinwa O. Saheed * The L1 PM substate capability is only implemented in function 0 in a 9643262f00SBolarinwa O. Saheed * multi function device. 9743262f00SBolarinwa O. Saheed */ 9843262f00SBolarinwa O. Saheed static struct pci_dev *pci_function_0(struct pci_bus *linkbus) 9943262f00SBolarinwa O. Saheed { 10043262f00SBolarinwa O. Saheed struct pci_dev *child; 10143262f00SBolarinwa O. Saheed 10243262f00SBolarinwa O. Saheed list_for_each_entry(child, &linkbus->devices, bus_list) 10343262f00SBolarinwa O. Saheed if (PCI_FUNC(child->devfn) == 0) 10443262f00SBolarinwa O. Saheed return child; 10543262f00SBolarinwa O. Saheed return NULL; 10643262f00SBolarinwa O. Saheed } 10743262f00SBolarinwa O. Saheed 1085aa63583SKenji Kaneshige static int policy_to_aspm_state(struct pcie_link_state *link) 1097d715a6cSShaohua Li { 1107d715a6cSShaohua Li switch (aspm_policy) { 1117d715a6cSShaohua Li case POLICY_PERFORMANCE: 1127d715a6cSShaohua Li /* Disable ASPM and Clock PM */ 1137d715a6cSShaohua Li return 0; 1147d715a6cSShaohua Li case POLICY_POWERSAVE: 1157d715a6cSShaohua Li /* Enable ASPM L0s/L1 */ 116b2103ccbSRajat Jain return (ASPM_STATE_L0S | ASPM_STATE_L1); 117b2103ccbSRajat Jain case POLICY_POWER_SUPERSAVE: 118b2103ccbSRajat Jain /* Enable Everything */ 119ac18018aSKenji Kaneshige return ASPM_STATE_ALL; 1207d715a6cSShaohua Li case POLICY_DEFAULT: 1215aa63583SKenji Kaneshige return link->aspm_default; 1227d715a6cSShaohua Li } 1237d715a6cSShaohua Li return 0; 1247d715a6cSShaohua Li } 1257d715a6cSShaohua Li 1265aa63583SKenji Kaneshige static int policy_to_clkpm_state(struct pcie_link_state *link) 1277d715a6cSShaohua Li { 1287d715a6cSShaohua Li switch (aspm_policy) { 1297d715a6cSShaohua Li case POLICY_PERFORMANCE: 1307d715a6cSShaohua Li /* Disable ASPM and Clock PM */ 1317d715a6cSShaohua Li return 0; 1327d715a6cSShaohua Li case POLICY_POWERSAVE: 133b2103ccbSRajat Jain case POLICY_POWER_SUPERSAVE: 134b2103ccbSRajat Jain /* Enable Clock PM */ 1357d715a6cSShaohua Li return 1; 1367d715a6cSShaohua Li case POLICY_DEFAULT: 1375aa63583SKenji Kaneshige return link->clkpm_default; 1387d715a6cSShaohua Li } 1397d715a6cSShaohua Li return 0; 1407d715a6cSShaohua Li } 1417d715a6cSShaohua Li 142430842e2SKenji Kaneshige static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable) 1437d715a6cSShaohua Li { 1445aa63583SKenji Kaneshige struct pci_dev *child; 1455aa63583SKenji Kaneshige struct pci_bus *linkbus = link->pdev->subordinate; 1460c0cbb6cSBjorn Helgaas u32 val = enable ? PCI_EXP_LNKCTL_CLKREQ_EN : 0; 1477d715a6cSShaohua Li 1480c0cbb6cSBjorn Helgaas list_for_each_entry(child, &linkbus->devices, bus_list) 1490c0cbb6cSBjorn Helgaas pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL, 1500c0cbb6cSBjorn Helgaas PCI_EXP_LNKCTL_CLKREQ_EN, 1510c0cbb6cSBjorn Helgaas val); 1525aa63583SKenji Kaneshige link->clkpm_enabled = !!enable; 1537d715a6cSShaohua Li } 1547d715a6cSShaohua Li 155430842e2SKenji Kaneshige static void pcie_set_clkpm(struct pcie_link_state *link, int enable) 156430842e2SKenji Kaneshige { 15735efea32SHeiner Kallweit /* 15835efea32SHeiner Kallweit * Don't enable Clock PM if the link is not Clock PM capable 15935efea32SHeiner Kallweit * or Clock PM is disabled 16035efea32SHeiner Kallweit */ 16135efea32SHeiner Kallweit if (!link->clkpm_capable || link->clkpm_disable) 1622f671e2dSMatthew Garrett enable = 0; 163430842e2SKenji Kaneshige /* Need nothing if the specified equals to current state */ 164430842e2SKenji Kaneshige if (link->clkpm_enabled == enable) 165430842e2SKenji Kaneshige return; 166430842e2SKenji Kaneshige pcie_set_clkpm_nocheck(link, enable); 167430842e2SKenji Kaneshige } 168430842e2SKenji Kaneshige 1698d349aceSKenji Kaneshige static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) 1707d715a6cSShaohua Li { 171f12eb72aSJiang Liu int capable = 1, enabled = 1; 1727d715a6cSShaohua Li u32 reg32; 1737d715a6cSShaohua Li u16 reg16; 1745aa63583SKenji Kaneshige struct pci_dev *child; 1755aa63583SKenji Kaneshige struct pci_bus *linkbus = link->pdev->subordinate; 1767d715a6cSShaohua Li 1777d715a6cSShaohua Li /* All functions should have the same cap and state, take the worst */ 1785aa63583SKenji Kaneshige list_for_each_entry(child, &linkbus->devices, bus_list) { 179f12eb72aSJiang Liu pcie_capability_read_dword(child, PCI_EXP_LNKCAP, ®32); 1807d715a6cSShaohua Li if (!(reg32 & PCI_EXP_LNKCAP_CLKPM)) { 1817d715a6cSShaohua Li capable = 0; 1827d715a6cSShaohua Li enabled = 0; 1837d715a6cSShaohua Li break; 1847d715a6cSShaohua Li } 185f12eb72aSJiang Liu pcie_capability_read_word(child, PCI_EXP_LNKCTL, ®16); 1867d715a6cSShaohua Li if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN)) 1877d715a6cSShaohua Li enabled = 0; 1887d715a6cSShaohua Li } 1895aa63583SKenji Kaneshige link->clkpm_enabled = enabled; 1905aa63583SKenji Kaneshige link->clkpm_default = enabled; 19135efea32SHeiner Kallweit link->clkpm_capable = capable; 19235efea32SHeiner Kallweit link->clkpm_disable = blacklist ? 1 : 0; 19346bbdfa4SShaohua Li } 19446bbdfa4SShaohua Li 19586fa6a34SStefan Mätje static bool pcie_retrain_link(struct pcie_link_state *link) 19686fa6a34SStefan Mätje { 19786fa6a34SStefan Mätje struct pci_dev *parent = link->pdev; 198658eec83SStefan Mätje unsigned long end_jiffies; 19986fa6a34SStefan Mätje u16 reg16; 20086fa6a34SStefan Mätje 20186fa6a34SStefan Mätje pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16); 20286fa6a34SStefan Mätje reg16 |= PCI_EXP_LNKCTL_RL; 20386fa6a34SStefan Mätje pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); 2044ec73791SStefan Mätje if (parent->clear_retrain_link) { 2054ec73791SStefan Mätje /* 2064ec73791SStefan Mätje * Due to an erratum in some devices the Retrain Link bit 2074ec73791SStefan Mätje * needs to be cleared again manually to allow the link 2084ec73791SStefan Mätje * training to succeed. 2094ec73791SStefan Mätje */ 2104ec73791SStefan Mätje reg16 &= ~PCI_EXP_LNKCTL_RL; 2114ec73791SStefan Mätje pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); 2124ec73791SStefan Mätje } 21386fa6a34SStefan Mätje 21486fa6a34SStefan Mätje /* Wait for link training end. Break out after waiting for timeout */ 215658eec83SStefan Mätje end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT; 216658eec83SStefan Mätje do { 21786fa6a34SStefan Mätje pcie_capability_read_word(parent, PCI_EXP_LNKSTA, ®16); 21886fa6a34SStefan Mätje if (!(reg16 & PCI_EXP_LNKSTA_LT)) 21986fa6a34SStefan Mätje break; 22086fa6a34SStefan Mätje msleep(1); 221658eec83SStefan Mätje } while (time_before(jiffies, end_jiffies)); 22286fa6a34SStefan Mätje return !(reg16 & PCI_EXP_LNKSTA_LT); 22386fa6a34SStefan Mätje } 22486fa6a34SStefan Mätje 2257d715a6cSShaohua Li /* 2267d715a6cSShaohua Li * pcie_aspm_configure_common_clock: check if the 2 ends of a link 2277d715a6cSShaohua Li * could use common clock. If they are, configure them to use the 2287d715a6cSShaohua Li * common clock. That will reduce the ASPM state exit latency. 2297d715a6cSShaohua Li */ 2305aa63583SKenji Kaneshige static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) 2317d715a6cSShaohua Li { 232f12eb72aSJiang Liu int same_clock = 1; 2335aa63583SKenji Kaneshige u16 reg16, parent_reg, child_reg[8]; 2345aa63583SKenji Kaneshige struct pci_dev *child, *parent = link->pdev; 2355aa63583SKenji Kaneshige struct pci_bus *linkbus = parent->subordinate; 2367d715a6cSShaohua Li /* 2375aa63583SKenji Kaneshige * All functions of a slot should have the same Slot Clock 2387d715a6cSShaohua Li * Configuration, so just check one function 2395aa63583SKenji Kaneshige */ 2405aa63583SKenji Kaneshige child = list_entry(linkbus->devices.next, struct pci_dev, bus_list); 2418b06477dSKenji Kaneshige BUG_ON(!pci_is_pcie(child)); 2427d715a6cSShaohua Li 2437d715a6cSShaohua Li /* Check downstream component if bit Slot Clock Configuration is 1 */ 244f12eb72aSJiang Liu pcie_capability_read_word(child, PCI_EXP_LNKSTA, ®16); 2457d715a6cSShaohua Li if (!(reg16 & PCI_EXP_LNKSTA_SLC)) 2467d715a6cSShaohua Li same_clock = 0; 2477d715a6cSShaohua Li 2487d715a6cSShaohua Li /* Check upstream component if bit Slot Clock Configuration is 1 */ 249f12eb72aSJiang Liu pcie_capability_read_word(parent, PCI_EXP_LNKSTA, ®16); 2507d715a6cSShaohua Li if (!(reg16 & PCI_EXP_LNKSTA_SLC)) 2517d715a6cSShaohua Li same_clock = 0; 2527d715a6cSShaohua Li 25304875177SSinan Kaya /* Port might be already in common clock mode */ 25404875177SSinan Kaya pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16); 25504875177SSinan Kaya if (same_clock && (reg16 & PCI_EXP_LNKCTL_CCC)) { 25604875177SSinan Kaya bool consistent = true; 25704875177SSinan Kaya 25804875177SSinan Kaya list_for_each_entry(child, &linkbus->devices, bus_list) { 25904875177SSinan Kaya pcie_capability_read_word(child, PCI_EXP_LNKCTL, 26004875177SSinan Kaya ®16); 26104875177SSinan Kaya if (!(reg16 & PCI_EXP_LNKCTL_CCC)) { 26204875177SSinan Kaya consistent = false; 26304875177SSinan Kaya break; 26404875177SSinan Kaya } 26504875177SSinan Kaya } 26604875177SSinan Kaya if (consistent) 26704875177SSinan Kaya return; 2683b364c65SChris Packham pci_info(parent, "ASPM: current common clock configuration is inconsistent, reconfiguring\n"); 26904875177SSinan Kaya } 27004875177SSinan Kaya 2717d715a6cSShaohua Li /* Configure downstream component, all functions */ 2725aa63583SKenji Kaneshige list_for_each_entry(child, &linkbus->devices, bus_list) { 273f12eb72aSJiang Liu pcie_capability_read_word(child, PCI_EXP_LNKCTL, ®16); 2745aa63583SKenji Kaneshige child_reg[PCI_FUNC(child->devfn)] = reg16; 2757d715a6cSShaohua Li if (same_clock) 2767d715a6cSShaohua Li reg16 |= PCI_EXP_LNKCTL_CCC; 2777d715a6cSShaohua Li else 2787d715a6cSShaohua Li reg16 &= ~PCI_EXP_LNKCTL_CCC; 279f12eb72aSJiang Liu pcie_capability_write_word(child, PCI_EXP_LNKCTL, reg16); 2807d715a6cSShaohua Li } 2817d715a6cSShaohua Li 2827d715a6cSShaohua Li /* Configure upstream component */ 283f12eb72aSJiang Liu pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16); 2842a42d9dbSThomas Renninger parent_reg = reg16; 2857d715a6cSShaohua Li if (same_clock) 2867d715a6cSShaohua Li reg16 |= PCI_EXP_LNKCTL_CCC; 2877d715a6cSShaohua Li else 2887d715a6cSShaohua Li reg16 &= ~PCI_EXP_LNKCTL_CCC; 289f12eb72aSJiang Liu pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); 2907d715a6cSShaohua Li 29186fa6a34SStefan Mätje if (pcie_retrain_link(link)) 2925aa63583SKenji Kaneshige return; 2935aa63583SKenji Kaneshige 2945aa63583SKenji Kaneshige /* Training failed. Restore common clock configurations */ 2957506dc79SFrederick Lawler pci_err(parent, "ASPM: Could not configure common clock\n"); 296f12eb72aSJiang Liu list_for_each_entry(child, &linkbus->devices, bus_list) 297f12eb72aSJiang Liu pcie_capability_write_word(child, PCI_EXP_LNKCTL, 2985aa63583SKenji Kaneshige child_reg[PCI_FUNC(child->devfn)]); 299f12eb72aSJiang Liu pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_reg); 3007d715a6cSShaohua Li } 3017d715a6cSShaohua Li 3025e0eaa7dSKenji Kaneshige /* Convert L0s latency encoding to ns */ 3035f7875d6SSaheed O. Bolarinwa static u32 calc_l0s_latency(u32 lnkcap) 3047d715a6cSShaohua Li { 3055f7875d6SSaheed O. Bolarinwa u32 encoding = (lnkcap & PCI_EXP_LNKCAP_L0SEL) >> 12; 3065f7875d6SSaheed O. Bolarinwa 3075e0eaa7dSKenji Kaneshige if (encoding == 0x7) 3085e0eaa7dSKenji Kaneshige return (5 * 1000); /* > 4us */ 3095e0eaa7dSKenji Kaneshige return (64 << encoding); 3107d715a6cSShaohua Li } 3117d715a6cSShaohua Li 3125e0eaa7dSKenji Kaneshige /* Convert L0s acceptable latency encoding to ns */ 3135e0eaa7dSKenji Kaneshige static u32 calc_l0s_acceptable(u32 encoding) 3147d715a6cSShaohua Li { 3155e0eaa7dSKenji Kaneshige if (encoding == 0x7) 3165e0eaa7dSKenji Kaneshige return -1U; 3175e0eaa7dSKenji Kaneshige return (64 << encoding); 3185e0eaa7dSKenji Kaneshige } 3197d715a6cSShaohua Li 3205e0eaa7dSKenji Kaneshige /* Convert L1 latency encoding to ns */ 3215f7875d6SSaheed O. Bolarinwa static u32 calc_l1_latency(u32 lnkcap) 3225e0eaa7dSKenji Kaneshige { 3235f7875d6SSaheed O. Bolarinwa u32 encoding = (lnkcap & PCI_EXP_LNKCAP_L1EL) >> 15; 3245f7875d6SSaheed O. Bolarinwa 3255e0eaa7dSKenji Kaneshige if (encoding == 0x7) 3265e0eaa7dSKenji Kaneshige return (65 * 1000); /* > 64us */ 3275e0eaa7dSKenji Kaneshige return (1000 << encoding); 3285e0eaa7dSKenji Kaneshige } 3295e0eaa7dSKenji Kaneshige 3305e0eaa7dSKenji Kaneshige /* Convert L1 acceptable latency encoding to ns */ 3315e0eaa7dSKenji Kaneshige static u32 calc_l1_acceptable(u32 encoding) 3325e0eaa7dSKenji Kaneshige { 3335e0eaa7dSKenji Kaneshige if (encoding == 0x7) 3345e0eaa7dSKenji Kaneshige return -1U; 3355e0eaa7dSKenji Kaneshige return (1000 << encoding); 3367d715a6cSShaohua Li } 3377d715a6cSShaohua Li 338f1f0366dSRajat Jain /* Convert L1SS T_pwr encoding to usec */ 339f1f0366dSRajat Jain static u32 calc_l1ss_pwron(struct pci_dev *pdev, u32 scale, u32 val) 340f1f0366dSRajat Jain { 341f1f0366dSRajat Jain switch (scale) { 342f1f0366dSRajat Jain case 0: 343f1f0366dSRajat Jain return val * 2; 344f1f0366dSRajat Jain case 1: 345f1f0366dSRajat Jain return val * 10; 346f1f0366dSRajat Jain case 2: 347f1f0366dSRajat Jain return val * 100; 348f1f0366dSRajat Jain } 3497506dc79SFrederick Lawler pci_err(pdev, "%s: Invalid T_PwrOn scale: %u\n", __func__, scale); 350f1f0366dSRajat Jain return 0; 351f1f0366dSRajat Jain } 352f1f0366dSRajat Jain 35380d7d7a9SBjorn Helgaas static void encode_l12_threshold(u32 threshold_us, u32 *scale, u32 *value) 35480d7d7a9SBjorn Helgaas { 355f51af8a6SGustavo A. R. Silva u32 threshold_ns = threshold_us * 1000; 35680d7d7a9SBjorn Helgaas 35780d7d7a9SBjorn Helgaas /* See PCIe r3.1, sec 7.33.3 and sec 6.18 */ 35880d7d7a9SBjorn Helgaas if (threshold_ns < 32) { 35980d7d7a9SBjorn Helgaas *scale = 0; 36080d7d7a9SBjorn Helgaas *value = threshold_ns; 36180d7d7a9SBjorn Helgaas } else if (threshold_ns < 1024) { 36280d7d7a9SBjorn Helgaas *scale = 1; 36380d7d7a9SBjorn Helgaas *value = threshold_ns >> 5; 36480d7d7a9SBjorn Helgaas } else if (threshold_ns < 32768) { 36580d7d7a9SBjorn Helgaas *scale = 2; 36680d7d7a9SBjorn Helgaas *value = threshold_ns >> 10; 36780d7d7a9SBjorn Helgaas } else if (threshold_ns < 1048576) { 36880d7d7a9SBjorn Helgaas *scale = 3; 36980d7d7a9SBjorn Helgaas *value = threshold_ns >> 15; 37080d7d7a9SBjorn Helgaas } else if (threshold_ns < 33554432) { 37180d7d7a9SBjorn Helgaas *scale = 4; 37280d7d7a9SBjorn Helgaas *value = threshold_ns >> 20; 37380d7d7a9SBjorn Helgaas } else { 37480d7d7a9SBjorn Helgaas *scale = 5; 37580d7d7a9SBjorn Helgaas *value = threshold_ns >> 25; 37680d7d7a9SBjorn Helgaas } 37780d7d7a9SBjorn Helgaas } 37880d7d7a9SBjorn Helgaas 37907d92760SKenji Kaneshige static void pcie_aspm_check_latency(struct pci_dev *endpoint) 38007d92760SKenji Kaneshige { 3816e332df7SSaheed O. Bolarinwa u32 latency, encoding, lnkcap_up, lnkcap_dw; 382fa285bafSSaheed O. Bolarinwa u32 l1_switch_latency = 0, latency_up_l0s; 383fa285bafSSaheed O. Bolarinwa u32 latency_up_l1, latency_dw_l0s, latency_dw_l1; 384fa285bafSSaheed O. Bolarinwa u32 acceptable_l0s, acceptable_l1; 38507d92760SKenji Kaneshige struct pcie_link_state *link; 38607d92760SKenji Kaneshige 38707d92760SKenji Kaneshige /* Device not in D0 doesn't need latency check */ 38807d92760SKenji Kaneshige if ((endpoint->current_state != PCI_D0) && 38907d92760SKenji Kaneshige (endpoint->current_state != PCI_UNKNOWN)) 39007d92760SKenji Kaneshige return; 39107d92760SKenji Kaneshige 39207d92760SKenji Kaneshige link = endpoint->bus->self->link_state; 3936e332df7SSaheed O. Bolarinwa 3946e332df7SSaheed O. Bolarinwa /* Calculate endpoint L0s acceptable latency */ 3956e332df7SSaheed O. Bolarinwa encoding = (endpoint->devcap & PCI_EXP_DEVCAP_L0S) >> 6; 396fa285bafSSaheed O. Bolarinwa acceptable_l0s = calc_l0s_acceptable(encoding); 3976e332df7SSaheed O. Bolarinwa 3986e332df7SSaheed O. Bolarinwa /* Calculate endpoint L1 acceptable latency */ 3996e332df7SSaheed O. Bolarinwa encoding = (endpoint->devcap & PCI_EXP_DEVCAP_L1) >> 9; 400fa285bafSSaheed O. Bolarinwa acceptable_l1 = calc_l1_acceptable(encoding); 40107d92760SKenji Kaneshige 40207d92760SKenji Kaneshige while (link) { 403222578daSSaheed O. Bolarinwa struct pci_dev *dev = pci_function_0(link->pdev->subordinate); 404222578daSSaheed O. Bolarinwa 405222578daSSaheed O. Bolarinwa /* Read direction exit latencies */ 406222578daSSaheed O. Bolarinwa pcie_capability_read_dword(link->pdev, PCI_EXP_LNKCAP, 407222578daSSaheed O. Bolarinwa &lnkcap_up); 408222578daSSaheed O. Bolarinwa pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, 409222578daSSaheed O. Bolarinwa &lnkcap_dw); 410fa285bafSSaheed O. Bolarinwa latency_up_l0s = calc_l0s_latency(lnkcap_up); 411fa285bafSSaheed O. Bolarinwa latency_up_l1 = calc_l1_latency(lnkcap_up); 412fa285bafSSaheed O. Bolarinwa latency_dw_l0s = calc_l0s_latency(lnkcap_dw); 413fa285bafSSaheed O. Bolarinwa latency_dw_l1 = calc_l1_latency(lnkcap_dw); 414222578daSSaheed O. Bolarinwa 415ac18018aSKenji Kaneshige /* Check upstream direction L0s latency */ 416ac18018aSKenji Kaneshige if ((link->aspm_capable & ASPM_STATE_L0S_UP) && 417fa285bafSSaheed O. Bolarinwa (latency_up_l0s > acceptable_l0s)) 418ac18018aSKenji Kaneshige link->aspm_capable &= ~ASPM_STATE_L0S_UP; 419ac18018aSKenji Kaneshige 420ac18018aSKenji Kaneshige /* Check downstream direction L0s latency */ 421ac18018aSKenji Kaneshige if ((link->aspm_capable & ASPM_STATE_L0S_DW) && 422fa285bafSSaheed O. Bolarinwa (latency_dw_l0s > acceptable_l0s)) 423ac18018aSKenji Kaneshige link->aspm_capable &= ~ASPM_STATE_L0S_DW; 42407d92760SKenji Kaneshige /* 42507d92760SKenji Kaneshige * Check L1 latency. 42607d92760SKenji Kaneshige * Every switch on the path to root complex need 1 42707d92760SKenji Kaneshige * more microsecond for L1. Spec doesn't mention L0s. 428a142f4d3SRajat Jain * 429a142f4d3SRajat Jain * The exit latencies for L1 substates are not advertised 430a142f4d3SRajat Jain * by a device. Since the spec also doesn't mention a way 431a142f4d3SRajat Jain * to determine max latencies introduced by enabling L1 432a142f4d3SRajat Jain * substates on the components, it is not clear how to do 433a142f4d3SRajat Jain * a L1 substate exit latency check. We assume that the 434a142f4d3SRajat Jain * L1 exit latencies advertised by a device include L1 435a142f4d3SRajat Jain * substate latencies (and hence do not do any check). 43607d92760SKenji Kaneshige */ 437fa285bafSSaheed O. Bolarinwa latency = max_t(u32, latency_up_l1, latency_dw_l1); 438ac18018aSKenji Kaneshige if ((link->aspm_capable & ASPM_STATE_L1) && 439fa285bafSSaheed O. Bolarinwa (latency + l1_switch_latency > acceptable_l1)) 440ac18018aSKenji Kaneshige link->aspm_capable &= ~ASPM_STATE_L1; 44107d92760SKenji Kaneshige l1_switch_latency += 1000; 44207d92760SKenji Kaneshige 44307d92760SKenji Kaneshige link = link->parent; 44407d92760SKenji Kaneshige } 44507d92760SKenji Kaneshige } 44607d92760SKenji Kaneshige 4470f1619cfSBjorn Helgaas static void pci_clear_and_set_dword(struct pci_dev *pdev, int pos, 4480f1619cfSBjorn Helgaas u32 clear, u32 set) 4490f1619cfSBjorn Helgaas { 4500f1619cfSBjorn Helgaas u32 val; 4510f1619cfSBjorn Helgaas 4520f1619cfSBjorn Helgaas pci_read_config_dword(pdev, pos, &val); 4530f1619cfSBjorn Helgaas val &= ~clear; 4540f1619cfSBjorn Helgaas val |= set; 4550f1619cfSBjorn Helgaas pci_write_config_dword(pdev, pos, val); 4560f1619cfSBjorn Helgaas } 4570f1619cfSBjorn Helgaas 458f1f0366dSRajat Jain /* Calculate L1.2 PM substate timing parameters */ 459f1f0366dSRajat Jain static void aspm_calc_l1ss_info(struct pcie_link_state *link, 4601e8955fdSBjorn Helgaas u32 parent_l1ss_cap, u32 child_l1ss_cap) 461f1f0366dSRajat Jain { 462190cd42cSBjorn Helgaas struct pci_dev *child = link->downstream, *parent = link->pdev; 463f1f0366dSRajat Jain u32 val1, val2, scale1, scale2; 46480d7d7a9SBjorn Helgaas u32 t_common_mode, t_power_on, l1_2_threshold, scale, value; 465df8f1058SSaheed O. Bolarinwa u32 ctl1 = 0, ctl2 = 0; 466df8f1058SSaheed O. Bolarinwa u32 pctl1, pctl2, cctl1, cctl2; 467df8f1058SSaheed O. Bolarinwa u32 pl1_2_enables, cl1_2_enables; 468f1f0366dSRajat Jain 469f1f0366dSRajat Jain if (!(link->aspm_support & ASPM_STATE_L1_2_MASK)) 470f1f0366dSRajat Jain return; 471f1f0366dSRajat Jain 472a48f3d5bSBjorn Helgaas /* Choose the greater of the two Port Common_Mode_Restore_Times */ 4731e8955fdSBjorn Helgaas val1 = (parent_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8; 4741e8955fdSBjorn Helgaas val2 = (child_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8; 47580d7d7a9SBjorn Helgaas t_common_mode = max(val1, val2); 476f1f0366dSRajat Jain 477a48f3d5bSBjorn Helgaas /* Choose the greater of the two Port T_POWER_ON times */ 4781e8955fdSBjorn Helgaas val1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19; 4791e8955fdSBjorn Helgaas scale1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16; 4801e8955fdSBjorn Helgaas val2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19; 4811e8955fdSBjorn Helgaas scale2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16; 482f1f0366dSRajat Jain 483190cd42cSBjorn Helgaas if (calc_l1ss_pwron(parent, scale1, val1) > 484190cd42cSBjorn Helgaas calc_l1ss_pwron(child, scale2, val2)) { 485df8f1058SSaheed O. Bolarinwa ctl2 |= scale1 | (val1 << 3); 486190cd42cSBjorn Helgaas t_power_on = calc_l1ss_pwron(parent, scale1, val1); 48780d7d7a9SBjorn Helgaas } else { 488df8f1058SSaheed O. Bolarinwa ctl2 |= scale2 | (val2 << 3); 489190cd42cSBjorn Helgaas t_power_on = calc_l1ss_pwron(child, scale2, val2); 49080d7d7a9SBjorn Helgaas } 49180d7d7a9SBjorn Helgaas 49280d7d7a9SBjorn Helgaas /* 49380d7d7a9SBjorn Helgaas * Set LTR_L1.2_THRESHOLD to the time required to transition the 49480d7d7a9SBjorn Helgaas * Link from L0 to L1.2 and back to L0 so we enter L1.2 only if 49580d7d7a9SBjorn Helgaas * downstream devices report (via LTR) that they can tolerate at 49680d7d7a9SBjorn Helgaas * least that much latency. 49780d7d7a9SBjorn Helgaas * 49880d7d7a9SBjorn Helgaas * Based on PCIe r3.1, sec 5.5.3.3.1, Figures 5-16 and 5-17, and 49980d7d7a9SBjorn Helgaas * Table 5-11. T(POWER_OFF) is at most 2us and T(L1.2) is at 50080d7d7a9SBjorn Helgaas * least 4us. 50180d7d7a9SBjorn Helgaas */ 50280d7d7a9SBjorn Helgaas l1_2_threshold = 2 + 4 + t_common_mode + t_power_on; 50380d7d7a9SBjorn Helgaas encode_l12_threshold(l1_2_threshold, &scale, &value); 504df8f1058SSaheed O. Bolarinwa ctl1 |= t_common_mode << 8 | scale << 29 | value << 16; 505df8f1058SSaheed O. Bolarinwa 5064353594eSRajat Jain /* Some broken devices only support dword access to L1 SS */ 507df8f1058SSaheed O. Bolarinwa pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, &pctl1); 508df8f1058SSaheed O. Bolarinwa pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, &pctl2); 509df8f1058SSaheed O. Bolarinwa pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL1, &cctl1); 510df8f1058SSaheed O. Bolarinwa pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL2, &cctl2); 511df8f1058SSaheed O. Bolarinwa 512df8f1058SSaheed O. Bolarinwa if (ctl1 == pctl1 && ctl1 == cctl1 && 513df8f1058SSaheed O. Bolarinwa ctl2 == pctl2 && ctl2 == cctl2) 514df8f1058SSaheed O. Bolarinwa return; 515df8f1058SSaheed O. Bolarinwa 516df8f1058SSaheed O. Bolarinwa /* Disable L1.2 while updating. See PCIe r5.0, sec 5.5.4, 7.8.3.3 */ 517df8f1058SSaheed O. Bolarinwa pl1_2_enables = pctl1 & PCI_L1SS_CTL1_L1_2_MASK; 518df8f1058SSaheed O. Bolarinwa cl1_2_enables = cctl1 & PCI_L1SS_CTL1_L1_2_MASK; 519df8f1058SSaheed O. Bolarinwa 520df8f1058SSaheed O. Bolarinwa if (pl1_2_enables || cl1_2_enables) { 521df8f1058SSaheed O. Bolarinwa pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, 522df8f1058SSaheed O. Bolarinwa PCI_L1SS_CTL1_L1_2_MASK, 0); 523df8f1058SSaheed O. Bolarinwa pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, 524df8f1058SSaheed O. Bolarinwa PCI_L1SS_CTL1_L1_2_MASK, 0); 525df8f1058SSaheed O. Bolarinwa } 526df8f1058SSaheed O. Bolarinwa 527df8f1058SSaheed O. Bolarinwa /* Program T_POWER_ON times in both ports */ 528df8f1058SSaheed O. Bolarinwa pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, ctl2); 529df8f1058SSaheed O. Bolarinwa pci_write_config_dword(child, child->l1ss + PCI_L1SS_CTL2, ctl2); 530df8f1058SSaheed O. Bolarinwa 531df8f1058SSaheed O. Bolarinwa /* Program Common_Mode_Restore_Time in upstream device */ 532df8f1058SSaheed O. Bolarinwa pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, 533df8f1058SSaheed O. Bolarinwa PCI_L1SS_CTL1_CM_RESTORE_TIME, ctl1); 534df8f1058SSaheed O. Bolarinwa 535df8f1058SSaheed O. Bolarinwa /* Program LTR_L1.2_THRESHOLD time in both ports */ 536df8f1058SSaheed O. Bolarinwa pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, 537df8f1058SSaheed O. Bolarinwa PCI_L1SS_CTL1_LTR_L12_TH_VALUE | 538df8f1058SSaheed O. Bolarinwa PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1); 539df8f1058SSaheed O. Bolarinwa pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, 540df8f1058SSaheed O. Bolarinwa PCI_L1SS_CTL1_LTR_L12_TH_VALUE | 541df8f1058SSaheed O. Bolarinwa PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1); 542df8f1058SSaheed O. Bolarinwa 543df8f1058SSaheed O. Bolarinwa if (pl1_2_enables || cl1_2_enables) { 544df8f1058SSaheed O. Bolarinwa pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, 0, 545df8f1058SSaheed O. Bolarinwa pl1_2_enables); 546df8f1058SSaheed O. Bolarinwa pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, 0, 547df8f1058SSaheed O. Bolarinwa cl1_2_enables); 548df8f1058SSaheed O. Bolarinwa } 549f1f0366dSRajat Jain } 550f1f0366dSRajat Jain 5518d349aceSKenji Kaneshige static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) 5527d715a6cSShaohua Li { 5533bd7db63SYinghai Lu struct pci_dev *child = link->downstream, *parent = link->pdev; 554c6e5f02bSSaheed O. Bolarinwa u32 parent_lnkcap, child_lnkcap; 55567bcc9adSSaheed O. Bolarinwa u16 parent_lnkctl, child_lnkctl; 556187f91dbSSaheed O. Bolarinwa u32 parent_l1ss_cap, child_l1ss_cap; 55728a1488eSSaheed O. Bolarinwa u32 parent_l1ss_ctl1 = 0, child_l1ss_ctl1 = 0; 5585aa63583SKenji Kaneshige struct pci_bus *linkbus = parent->subordinate; 5597d715a6cSShaohua Li 5608d349aceSKenji Kaneshige if (blacklist) { 561f1c0ca29SKenji Kaneshige /* Set enabled/disable so that we will disable ASPM later */ 562ac18018aSKenji Kaneshige link->aspm_enabled = ASPM_STATE_ALL; 563ac18018aSKenji Kaneshige link->aspm_disable = ASPM_STATE_ALL; 5648d349aceSKenji Kaneshige return; 5658d349aceSKenji Kaneshige } 5668d349aceSKenji Kaneshige 567ac18018aSKenji Kaneshige /* 568e53f9a28SDavid Daney * If ASPM not supported, don't mess with the clocks and link, 569e53f9a28SDavid Daney * bail out now. 570e53f9a28SDavid Daney */ 571c6e5f02bSSaheed O. Bolarinwa pcie_capability_read_dword(parent, PCI_EXP_LNKCAP, &parent_lnkcap); 572c6e5f02bSSaheed O. Bolarinwa pcie_capability_read_dword(child, PCI_EXP_LNKCAP, &child_lnkcap); 573c6e5f02bSSaheed O. Bolarinwa if (!(parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPMS)) 574e53f9a28SDavid Daney return; 575e53f9a28SDavid Daney 576e53f9a28SDavid Daney /* Configure common clock before checking latencies */ 577e53f9a28SDavid Daney pcie_aspm_configure_common_clock(link); 578e53f9a28SDavid Daney 579e53f9a28SDavid Daney /* 580c6e5f02bSSaheed O. Bolarinwa * Re-read upstream/downstream components' register state after 581c6e5f02bSSaheed O. Bolarinwa * clock configuration. L0s & L1 exit latencies in the otherwise 582c6e5f02bSSaheed O. Bolarinwa * read-only Link Capabilities may change depending on common clock 583c6e5f02bSSaheed O. Bolarinwa * configuration (PCIe r5.0, sec 7.5.3.6). 584e53f9a28SDavid Daney */ 585c6e5f02bSSaheed O. Bolarinwa pcie_capability_read_dword(parent, PCI_EXP_LNKCAP, &parent_lnkcap); 586c6e5f02bSSaheed O. Bolarinwa pcie_capability_read_dword(child, PCI_EXP_LNKCAP, &child_lnkcap); 58767bcc9adSSaheed O. Bolarinwa pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &parent_lnkctl); 58867bcc9adSSaheed O. Bolarinwa pcie_capability_read_word(child, PCI_EXP_LNKCTL, &child_lnkctl); 589e53f9a28SDavid Daney 590e53f9a28SDavid Daney /* 591ac18018aSKenji Kaneshige * Setup L0s state 592ac18018aSKenji Kaneshige * 593ac18018aSKenji Kaneshige * Note that we must not enable L0s in either direction on a 594ac18018aSKenji Kaneshige * given link unless components on both sides of the link each 595ac18018aSKenji Kaneshige * support L0s. 596ac18018aSKenji Kaneshige */ 597c6e5f02bSSaheed O. Bolarinwa if (parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPM_L0S) 598ac18018aSKenji Kaneshige link->aspm_support |= ASPM_STATE_L0S; 599c6e5f02bSSaheed O. Bolarinwa 60067bcc9adSSaheed O. Bolarinwa if (child_lnkctl & PCI_EXP_LNKCTL_ASPM_L0S) 601ac18018aSKenji Kaneshige link->aspm_enabled |= ASPM_STATE_L0S_UP; 60267bcc9adSSaheed O. Bolarinwa if (parent_lnkctl & PCI_EXP_LNKCTL_ASPM_L0S) 603ac18018aSKenji Kaneshige link->aspm_enabled |= ASPM_STATE_L0S_DW; 604ac18018aSKenji Kaneshige 605ac18018aSKenji Kaneshige /* Setup L1 state */ 606c6e5f02bSSaheed O. Bolarinwa if (parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPM_L1) 607ac18018aSKenji Kaneshige link->aspm_support |= ASPM_STATE_L1; 608c6e5f02bSSaheed O. Bolarinwa 60967bcc9adSSaheed O. Bolarinwa if (parent_lnkctl & child_lnkctl & PCI_EXP_LNKCTL_ASPM_L1) 610ac18018aSKenji Kaneshige link->aspm_enabled |= ASPM_STATE_L1; 61180bfdbe3SKenji Kaneshige 612187f91dbSSaheed O. Bolarinwa /* Setup L1 substate */ 613187f91dbSSaheed O. Bolarinwa pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CAP, 614187f91dbSSaheed O. Bolarinwa &parent_l1ss_cap); 615187f91dbSSaheed O. Bolarinwa pci_read_config_dword(child, child->l1ss + PCI_L1SS_CAP, 616187f91dbSSaheed O. Bolarinwa &child_l1ss_cap); 617187f91dbSSaheed O. Bolarinwa 618187f91dbSSaheed O. Bolarinwa if (!(parent_l1ss_cap & PCI_L1SS_CAP_L1_PM_SS)) 619187f91dbSSaheed O. Bolarinwa parent_l1ss_cap = 0; 620187f91dbSSaheed O. Bolarinwa if (!(child_l1ss_cap & PCI_L1SS_CAP_L1_PM_SS)) 621187f91dbSSaheed O. Bolarinwa child_l1ss_cap = 0; 622187f91dbSSaheed O. Bolarinwa 623187f91dbSSaheed O. Bolarinwa /* 62408e869eeSBjorn Helgaas * If we don't have LTR for the entire path from the Root Complex 62508e869eeSBjorn Helgaas * to this device, we can't use ASPM L1.2 because it relies on the 62608e869eeSBjorn Helgaas * LTR_L1.2_THRESHOLD. See PCIe r4.0, secs 5.5.4, 6.18. 62708e869eeSBjorn Helgaas */ 62808e869eeSBjorn Helgaas if (!child->ltr_path) 629187f91dbSSaheed O. Bolarinwa child_l1ss_cap &= ~PCI_L1SS_CAP_ASPM_L1_2; 63008e869eeSBjorn Helgaas 631187f91dbSSaheed O. Bolarinwa if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_ASPM_L1_1) 632b5a0a9b5SRajat Jain link->aspm_support |= ASPM_STATE_L1_1; 633187f91dbSSaheed O. Bolarinwa if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_ASPM_L1_2) 634b5a0a9b5SRajat Jain link->aspm_support |= ASPM_STATE_L1_2; 635187f91dbSSaheed O. Bolarinwa if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_1) 636b5a0a9b5SRajat Jain link->aspm_support |= ASPM_STATE_L1_1_PCIPM; 637187f91dbSSaheed O. Bolarinwa if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_2) 638b5a0a9b5SRajat Jain link->aspm_support |= ASPM_STATE_L1_2_PCIPM; 639b5a0a9b5SRajat Jain 640187f91dbSSaheed O. Bolarinwa if (parent_l1ss_cap) 64128a1488eSSaheed O. Bolarinwa pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, 64228a1488eSSaheed O. Bolarinwa &parent_l1ss_ctl1); 643187f91dbSSaheed O. Bolarinwa if (child_l1ss_cap) 64428a1488eSSaheed O. Bolarinwa pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL1, 64528a1488eSSaheed O. Bolarinwa &child_l1ss_ctl1); 64628a1488eSSaheed O. Bolarinwa 64728a1488eSSaheed O. Bolarinwa if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_1) 648b5a0a9b5SRajat Jain link->aspm_enabled |= ASPM_STATE_L1_1; 64928a1488eSSaheed O. Bolarinwa if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_2) 650b5a0a9b5SRajat Jain link->aspm_enabled |= ASPM_STATE_L1_2; 65128a1488eSSaheed O. Bolarinwa if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_1) 652b5a0a9b5SRajat Jain link->aspm_enabled |= ASPM_STATE_L1_1_PCIPM; 65328a1488eSSaheed O. Bolarinwa if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_2) 654b5a0a9b5SRajat Jain link->aspm_enabled |= ASPM_STATE_L1_2_PCIPM; 655b5a0a9b5SRajat Jain 656f1f0366dSRajat Jain if (link->aspm_support & ASPM_STATE_L1SS) 657187f91dbSSaheed O. Bolarinwa aspm_calc_l1ss_info(link, parent_l1ss_cap, child_l1ss_cap); 658f1f0366dSRajat Jain 659b127bd55SKenji Kaneshige /* Save default state */ 660b127bd55SKenji Kaneshige link->aspm_default = link->aspm_enabled; 66107d92760SKenji Kaneshige 66207d92760SKenji Kaneshige /* Setup initial capable state. Will be updated later */ 66307d92760SKenji Kaneshige link->aspm_capable = link->aspm_support; 664b127bd55SKenji Kaneshige 665b7206cbfSKenji Kaneshige /* Get and check endpoint acceptable latencies */ 6665aa63583SKenji Kaneshige list_for_each_entry(child, &linkbus->devices, bus_list) { 66762f87c0eSYijing Wang if (pci_pcie_type(child) != PCI_EXP_TYPE_ENDPOINT && 66862f87c0eSYijing Wang pci_pcie_type(child) != PCI_EXP_TYPE_LEG_END) 6697d715a6cSShaohua Li continue; 6707d715a6cSShaohua Li 67107d92760SKenji Kaneshige pcie_aspm_check_latency(child); 6727d715a6cSShaohua Li } 6737d715a6cSShaohua Li } 6747d715a6cSShaohua Li 675aeda9adeSRajat Jain /* Configure the ASPM L1 substates */ 676aeda9adeSRajat Jain static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state) 677aeda9adeSRajat Jain { 678aeda9adeSRajat Jain u32 val, enable_req; 679aeda9adeSRajat Jain struct pci_dev *child = link->downstream, *parent = link->pdev; 680aeda9adeSRajat Jain 681aeda9adeSRajat Jain enable_req = (link->aspm_enabled ^ state) & state; 682aeda9adeSRajat Jain 683aeda9adeSRajat Jain /* 684aeda9adeSRajat Jain * Here are the rules specified in the PCIe spec for enabling L1SS: 685aeda9adeSRajat Jain * - When enabling L1.x, enable bit at parent first, then at child 686aeda9adeSRajat Jain * - When disabling L1.x, disable bit at child first, then at parent 687aeda9adeSRajat Jain * - When enabling ASPM L1.x, need to disable L1 688aeda9adeSRajat Jain * (at child followed by parent). 689aeda9adeSRajat Jain * - The ASPM/PCIPM L1.2 must be disabled while programming timing 690aeda9adeSRajat Jain * parameters 691aeda9adeSRajat Jain * 692aeda9adeSRajat Jain * To keep it simple, disable all L1SS bits first, and later enable 693aeda9adeSRajat Jain * what is needed. 694aeda9adeSRajat Jain */ 695aeda9adeSRajat Jain 696aeda9adeSRajat Jain /* Disable all L1 substates */ 697ecdf57b4SSaheed O. Bolarinwa pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, 698aeda9adeSRajat Jain PCI_L1SS_CTL1_L1SS_MASK, 0); 699ecdf57b4SSaheed O. Bolarinwa pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, 700aeda9adeSRajat Jain PCI_L1SS_CTL1_L1SS_MASK, 0); 701aeda9adeSRajat Jain /* 702aeda9adeSRajat Jain * If needed, disable L1, and it gets enabled later 703aeda9adeSRajat Jain * in pcie_config_aspm_link(). 704aeda9adeSRajat Jain */ 705aeda9adeSRajat Jain if (enable_req & (ASPM_STATE_L1_1 | ASPM_STATE_L1_2)) { 706aeda9adeSRajat Jain pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL, 707aeda9adeSRajat Jain PCI_EXP_LNKCTL_ASPM_L1, 0); 708aeda9adeSRajat Jain pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL, 709aeda9adeSRajat Jain PCI_EXP_LNKCTL_ASPM_L1, 0); 710aeda9adeSRajat Jain } 711aeda9adeSRajat Jain 712aeda9adeSRajat Jain val = 0; 713aeda9adeSRajat Jain if (state & ASPM_STATE_L1_1) 714aeda9adeSRajat Jain val |= PCI_L1SS_CTL1_ASPM_L1_1; 715aeda9adeSRajat Jain if (state & ASPM_STATE_L1_2) 716aeda9adeSRajat Jain val |= PCI_L1SS_CTL1_ASPM_L1_2; 717aeda9adeSRajat Jain if (state & ASPM_STATE_L1_1_PCIPM) 718aeda9adeSRajat Jain val |= PCI_L1SS_CTL1_PCIPM_L1_1; 719aeda9adeSRajat Jain if (state & ASPM_STATE_L1_2_PCIPM) 720aeda9adeSRajat Jain val |= PCI_L1SS_CTL1_PCIPM_L1_2; 721aeda9adeSRajat Jain 722aeda9adeSRajat Jain /* Enable what we need to enable */ 723ecdf57b4SSaheed O. Bolarinwa pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, 72458a3862aSYicong Yang PCI_L1SS_CTL1_L1SS_MASK, val); 725ecdf57b4SSaheed O. Bolarinwa pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, 72658a3862aSYicong Yang PCI_L1SS_CTL1_L1SS_MASK, val); 727aeda9adeSRajat Jain } 728aeda9adeSRajat Jain 729ac18018aSKenji Kaneshige static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val) 7307d715a6cSShaohua Li { 73175083206SBjorn Helgaas pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL, 73275083206SBjorn Helgaas PCI_EXP_LNKCTL_ASPMC, val); 7337d715a6cSShaohua Li } 7347d715a6cSShaohua Li 735b7206cbfSKenji Kaneshige static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state) 7367d715a6cSShaohua Li { 737ac18018aSKenji Kaneshige u32 upstream = 0, dwstream = 0; 738aeda9adeSRajat Jain struct pci_dev *child = link->downstream, *parent = link->pdev; 7395aa63583SKenji Kaneshige struct pci_bus *linkbus = parent->subordinate; 7407d715a6cSShaohua Li 741aeda9adeSRajat Jain /* Enable only the states that were not explicitly disabled */ 742b7206cbfSKenji Kaneshige state &= (link->aspm_capable & ~link->aspm_disable); 743aeda9adeSRajat Jain 744aeda9adeSRajat Jain /* Can't enable any substates if L1 is not enabled */ 745aeda9adeSRajat Jain if (!(state & ASPM_STATE_L1)) 746aeda9adeSRajat Jain state &= ~ASPM_STATE_L1SS; 747aeda9adeSRajat Jain 748aeda9adeSRajat Jain /* Spec says both ports must be in D0 before enabling PCI PM substates*/ 749aeda9adeSRajat Jain if (parent->current_state != PCI_D0 || child->current_state != PCI_D0) { 750aeda9adeSRajat Jain state &= ~ASPM_STATE_L1_SS_PCIPM; 751aeda9adeSRajat Jain state |= (link->aspm_enabled & ASPM_STATE_L1_SS_PCIPM); 752aeda9adeSRajat Jain } 753aeda9adeSRajat Jain 754aeda9adeSRajat Jain /* Nothing to do if the link is already in the requested state */ 755f1c0ca29SKenji Kaneshige if (link->aspm_enabled == state) 7567d715a6cSShaohua Li return; 757ac18018aSKenji Kaneshige /* Convert ASPM state to upstream/downstream ASPM register state */ 758ac18018aSKenji Kaneshige if (state & ASPM_STATE_L0S_UP) 75975083206SBjorn Helgaas dwstream |= PCI_EXP_LNKCTL_ASPM_L0S; 760ac18018aSKenji Kaneshige if (state & ASPM_STATE_L0S_DW) 76175083206SBjorn Helgaas upstream |= PCI_EXP_LNKCTL_ASPM_L0S; 762ac18018aSKenji Kaneshige if (state & ASPM_STATE_L1) { 76375083206SBjorn Helgaas upstream |= PCI_EXP_LNKCTL_ASPM_L1; 76475083206SBjorn Helgaas dwstream |= PCI_EXP_LNKCTL_ASPM_L1; 765ac18018aSKenji Kaneshige } 766aeda9adeSRajat Jain 767aeda9adeSRajat Jain if (link->aspm_capable & ASPM_STATE_L1SS) 768aeda9adeSRajat Jain pcie_config_aspm_l1ss(link, state); 769aeda9adeSRajat Jain 7707d715a6cSShaohua Li /* 7715aa63583SKenji Kaneshige * Spec 2.0 suggests all functions should be configured the 7725aa63583SKenji Kaneshige * same setting for ASPM. Enabling ASPM L1 should be done in 7735aa63583SKenji Kaneshige * upstream component first and then downstream, and vice 7745aa63583SKenji Kaneshige * versa for disabling ASPM L1. Spec doesn't mention L0S. 7757d715a6cSShaohua Li */ 776ac18018aSKenji Kaneshige if (state & ASPM_STATE_L1) 777ac18018aSKenji Kaneshige pcie_config_aspm_dev(parent, upstream); 7785aa63583SKenji Kaneshige list_for_each_entry(child, &linkbus->devices, bus_list) 779ac18018aSKenji Kaneshige pcie_config_aspm_dev(child, dwstream); 780ac18018aSKenji Kaneshige if (!(state & ASPM_STATE_L1)) 781ac18018aSKenji Kaneshige pcie_config_aspm_dev(parent, upstream); 7827d715a6cSShaohua Li 7835aa63583SKenji Kaneshige link->aspm_enabled = state; 7847d715a6cSShaohua Li } 7857d715a6cSShaohua Li 786b7206cbfSKenji Kaneshige static void pcie_config_aspm_path(struct pcie_link_state *link) 7877d715a6cSShaohua Li { 788b7206cbfSKenji Kaneshige while (link) { 789b7206cbfSKenji Kaneshige pcie_config_aspm_link(link, policy_to_aspm_state(link)); 790b7206cbfSKenji Kaneshige link = link->parent; 79146bbdfa4SShaohua Li } 7927d715a6cSShaohua Li } 7937d715a6cSShaohua Li 7945aa63583SKenji Kaneshige static void free_link_state(struct pcie_link_state *link) 7957d715a6cSShaohua Li { 7965aa63583SKenji Kaneshige link->pdev->link_state = NULL; 7975aa63583SKenji Kaneshige kfree(link); 7987d715a6cSShaohua Li } 7997d715a6cSShaohua Li 800ddc9753fSShaohua Li static int pcie_aspm_sanity_check(struct pci_dev *pdev) 801ddc9753fSShaohua Li { 8023647584dSKenji Kaneshige struct pci_dev *child; 803149e1637SShaohua Li u32 reg32; 8042f671e2dSMatthew Garrett 805ddc9753fSShaohua Li /* 80645e829eaSStefan Assmann * Some functions in a slot might not all be PCIe functions, 8073647584dSKenji Kaneshige * very strange. Disable ASPM for the whole slot 808ddc9753fSShaohua Li */ 8093647584dSKenji Kaneshige list_for_each_entry(child, &pdev->subordinate->devices, bus_list) { 810f12eb72aSJiang Liu if (!pci_is_pcie(child)) 811ddc9753fSShaohua Li return -EINVAL; 812c9651e70SMatthew Garrett 813c9651e70SMatthew Garrett /* 814c9651e70SMatthew Garrett * If ASPM is disabled then we're not going to change 815c9651e70SMatthew Garrett * the BIOS state. It's safe to continue even if it's a 816c9651e70SMatthew Garrett * pre-1.1 device 817c9651e70SMatthew Garrett */ 818c9651e70SMatthew Garrett 819c9651e70SMatthew Garrett if (aspm_disabled) 820c9651e70SMatthew Garrett continue; 821c9651e70SMatthew Garrett 822149e1637SShaohua Li /* 823149e1637SShaohua Li * Disable ASPM for pre-1.1 PCIe device, we follow MS to use 824149e1637SShaohua Li * RBER bit to determine if a function is 1.1 version device 825149e1637SShaohua Li */ 826f12eb72aSJiang Liu pcie_capability_read_dword(child, PCI_EXP_DEVCAP, ®32); 827e1f4f59dSSitsofe Wheeler if (!(reg32 & PCI_EXP_DEVCAP_RBER) && !aspm_force) { 8287506dc79SFrederick Lawler pci_info(child, "disabling ASPM on pre-1.1 PCIe device. You can enable it with 'pcie_aspm=force'\n"); 829149e1637SShaohua Li return -EINVAL; 830149e1637SShaohua Li } 831ddc9753fSShaohua Li } 832ddc9753fSShaohua Li return 0; 833ddc9753fSShaohua Li } 834ddc9753fSShaohua Li 835b7206cbfSKenji Kaneshige static struct pcie_link_state *alloc_pcie_link_state(struct pci_dev *pdev) 8368d349aceSKenji Kaneshige { 8378d349aceSKenji Kaneshige struct pcie_link_state *link; 8388d349aceSKenji Kaneshige 8398d349aceSKenji Kaneshige link = kzalloc(sizeof(*link), GFP_KERNEL); 8408d349aceSKenji Kaneshige if (!link) 8418d349aceSKenji Kaneshige return NULL; 842030305d6SBjorn Helgaas 8438d349aceSKenji Kaneshige INIT_LIST_HEAD(&link->sibling); 8448d349aceSKenji Kaneshige link->pdev = pdev; 8453bd7db63SYinghai Lu link->downstream = pci_function_0(pdev->subordinate); 846030305d6SBjorn Helgaas 847030305d6SBjorn Helgaas /* 848030305d6SBjorn Helgaas * Root Ports and PCI/PCI-X to PCIe Bridges are roots of PCIe 849ee8bdfb6SArd Biesheuvel * hierarchies. Note that some PCIe host implementations omit 850ee8bdfb6SArd Biesheuvel * the root ports entirely, in which case a downstream port on 851ee8bdfb6SArd Biesheuvel * a switch may become the root of the link state chain for all 852ee8bdfb6SArd Biesheuvel * its subordinate endpoints. 853030305d6SBjorn Helgaas */ 854030305d6SBjorn Helgaas if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT || 855ee8bdfb6SArd Biesheuvel pci_pcie_type(pdev) == PCI_EXP_TYPE_PCIE_BRIDGE || 856ee8bdfb6SArd Biesheuvel !pdev->bus->parent->self) { 857030305d6SBjorn Helgaas link->root = link; 858030305d6SBjorn Helgaas } else { 8598d349aceSKenji Kaneshige struct pcie_link_state *parent; 860030305d6SBjorn Helgaas 8618d349aceSKenji Kaneshige parent = pdev->bus->parent->self->link_state; 8628d349aceSKenji Kaneshige if (!parent) { 8638d349aceSKenji Kaneshige kfree(link); 8648d349aceSKenji Kaneshige return NULL; 8658d349aceSKenji Kaneshige } 866030305d6SBjorn Helgaas 8678d349aceSKenji Kaneshige link->parent = parent; 868030305d6SBjorn Helgaas link->root = link->parent->root; 8698d349aceSKenji Kaneshige } 8705c92ffb1SKenji Kaneshige 8718d349aceSKenji Kaneshige list_add(&link->sibling, &link_list); 8728d349aceSKenji Kaneshige pdev->link_state = link; 8738d349aceSKenji Kaneshige return link; 8748d349aceSKenji Kaneshige } 8758d349aceSKenji Kaneshige 87672ea91afSHeiner Kallweit static void pcie_aspm_update_sysfs_visibility(struct pci_dev *pdev) 87772ea91afSHeiner Kallweit { 87872ea91afSHeiner Kallweit struct pci_dev *child; 87972ea91afSHeiner Kallweit 88072ea91afSHeiner Kallweit list_for_each_entry(child, &pdev->subordinate->devices, bus_list) 88172ea91afSHeiner Kallweit sysfs_update_group(&child->dev.kobj, &aspm_ctrl_attr_group); 88272ea91afSHeiner Kallweit } 88372ea91afSHeiner Kallweit 8847d715a6cSShaohua Li /* 8857d715a6cSShaohua Li * pcie_aspm_init_link_state: Initiate PCI express link state. 886f7625980SBjorn Helgaas * It is called after the pcie and its children devices are scanned. 8877d715a6cSShaohua Li * @pdev: the root port or switch downstream port 8887d715a6cSShaohua Li */ 8897d715a6cSShaohua Li void pcie_aspm_init_link_state(struct pci_dev *pdev) 8907d715a6cSShaohua Li { 8918d349aceSKenji Kaneshige struct pcie_link_state *link; 892b7206cbfSKenji Kaneshige int blacklist = !!pcie_aspm_sanity_check(pdev); 8937d715a6cSShaohua Li 894b07b864eSBjorn Helgaas if (!aspm_support_enabled) 895a26d5ecbSJoe Lawrence return; 896a26d5ecbSJoe Lawrence 897c8fc9339SYijing Wang if (pdev->link_state) 8987d715a6cSShaohua Li return; 899c8fc9339SYijing Wang 900c8fc9339SYijing Wang /* 901c8fc9339SYijing Wang * We allocate pcie_link_state for the component on the upstream 902ca784104SMika Westerberg * end of a Link, so there's nothing to do unless this device is 903ca784104SMika Westerberg * downstream port. 904c8fc9339SYijing Wang */ 905ca784104SMika Westerberg if (!pcie_downstream_port(pdev)) 9067d715a6cSShaohua Li return; 9078d349aceSKenji Kaneshige 9088e822df7SShaohua Li /* VIA has a strange chipset, root port is under a bridge */ 90962f87c0eSYijing Wang if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT && 9108e822df7SShaohua Li pdev->bus->self) 9118e822df7SShaohua Li return; 9128d349aceSKenji Kaneshige 9137d715a6cSShaohua Li down_read(&pci_bus_sem); 9147d715a6cSShaohua Li if (list_empty(&pdev->subordinate->devices)) 9157d715a6cSShaohua Li goto out; 9167d715a6cSShaohua Li 9177d715a6cSShaohua Li mutex_lock(&aspm_lock); 918b7206cbfSKenji Kaneshige link = alloc_pcie_link_state(pdev); 9198d349aceSKenji Kaneshige if (!link) 9208d349aceSKenji Kaneshige goto unlock; 92146bbdfa4SShaohua Li /* 922b7206cbfSKenji Kaneshige * Setup initial ASPM state. Note that we need to configure 923b7206cbfSKenji Kaneshige * upstream links also because capable state of them can be 924b7206cbfSKenji Kaneshige * update through pcie_aspm_cap_init(). 9258d349aceSKenji Kaneshige */ 926b7206cbfSKenji Kaneshige pcie_aspm_cap_init(link, blacklist); 92746bbdfa4SShaohua Li 9288d349aceSKenji Kaneshige /* Setup initial Clock PM state */ 929b7206cbfSKenji Kaneshige pcie_clkpm_cap_init(link, blacklist); 93041cd766bSMatthew Garrett 93141cd766bSMatthew Garrett /* 93241cd766bSMatthew Garrett * At this stage drivers haven't had an opportunity to change the 93341cd766bSMatthew Garrett * link policy setting. Enabling ASPM on broken hardware can cripple 93441cd766bSMatthew Garrett * it even before the driver has had a chance to disable ASPM, so 93541cd766bSMatthew Garrett * default to a safe level right now. If we're enabling ASPM beyond 93641cd766bSMatthew Garrett * the BIOS's expectation, we'll do so once pci_enable_device() is 93741cd766bSMatthew Garrett * called. 93841cd766bSMatthew Garrett */ 939b2103ccbSRajat Jain if (aspm_policy != POLICY_POWERSAVE && 940b2103ccbSRajat Jain aspm_policy != POLICY_POWER_SUPERSAVE) { 94141cd766bSMatthew Garrett pcie_config_aspm_path(link); 942b7206cbfSKenji Kaneshige pcie_set_clkpm(link, policy_to_clkpm_state(link)); 94341cd766bSMatthew Garrett } 94441cd766bSMatthew Garrett 94572ea91afSHeiner Kallweit pcie_aspm_update_sysfs_visibility(pdev); 94672ea91afSHeiner Kallweit 9478d349aceSKenji Kaneshige unlock: 9487d715a6cSShaohua Li mutex_unlock(&aspm_lock); 9497d715a6cSShaohua Li out: 9507d715a6cSShaohua Li up_read(&pci_bus_sem); 9517d715a6cSShaohua Li } 9527d715a6cSShaohua Li 95307d92760SKenji Kaneshige /* Recheck latencies and update aspm_capable for links under the root */ 95407d92760SKenji Kaneshige static void pcie_update_aspm_capable(struct pcie_link_state *root) 95507d92760SKenji Kaneshige { 95607d92760SKenji Kaneshige struct pcie_link_state *link; 95707d92760SKenji Kaneshige BUG_ON(root->parent); 95807d92760SKenji Kaneshige list_for_each_entry(link, &link_list, sibling) { 95907d92760SKenji Kaneshige if (link->root != root) 96007d92760SKenji Kaneshige continue; 96107d92760SKenji Kaneshige link->aspm_capable = link->aspm_support; 96207d92760SKenji Kaneshige } 96307d92760SKenji Kaneshige list_for_each_entry(link, &link_list, sibling) { 96407d92760SKenji Kaneshige struct pci_dev *child; 96507d92760SKenji Kaneshige struct pci_bus *linkbus = link->pdev->subordinate; 96607d92760SKenji Kaneshige if (link->root != root) 96707d92760SKenji Kaneshige continue; 96807d92760SKenji Kaneshige list_for_each_entry(child, &linkbus->devices, bus_list) { 96962f87c0eSYijing Wang if ((pci_pcie_type(child) != PCI_EXP_TYPE_ENDPOINT) && 97062f87c0eSYijing Wang (pci_pcie_type(child) != PCI_EXP_TYPE_LEG_END)) 97107d92760SKenji Kaneshige continue; 97207d92760SKenji Kaneshige pcie_aspm_check_latency(child); 97307d92760SKenji Kaneshige } 97407d92760SKenji Kaneshige } 97507d92760SKenji Kaneshige } 97607d92760SKenji Kaneshige 9777d715a6cSShaohua Li /* @pdev: the endpoint device */ 9787d715a6cSShaohua Li void pcie_aspm_exit_link_state(struct pci_dev *pdev) 9797d715a6cSShaohua Li { 9807d715a6cSShaohua Li struct pci_dev *parent = pdev->bus->self; 981b7206cbfSKenji Kaneshige struct pcie_link_state *link, *root, *parent_link; 9827d715a6cSShaohua Li 98384fb913cSMyron Stowe if (!parent || !parent->link_state) 9847d715a6cSShaohua Li return; 985fc87e919SKenji Kaneshige 9867d715a6cSShaohua Li down_read(&pci_bus_sem); 9877d715a6cSShaohua Li mutex_lock(&aspm_lock); 9887d715a6cSShaohua Li /* 9897d715a6cSShaohua Li * All PCIe functions are in one slot, remove one function will remove 9903419c75eSAlex Chiang * the whole slot, so just wait until we are the last function left. 9917d715a6cSShaohua Li */ 992aeae4f3eSLukas Wunner if (!list_empty(&parent->subordinate->devices)) 9937d715a6cSShaohua Li goto out; 9947d715a6cSShaohua Li 995fc87e919SKenji Kaneshige link = parent->link_state; 99607d92760SKenji Kaneshige root = link->root; 997b7206cbfSKenji Kaneshige parent_link = link->parent; 998fc87e919SKenji Kaneshige 9997d715a6cSShaohua Li /* All functions are removed, so just disable ASPM for the link */ 1000b7206cbfSKenji Kaneshige pcie_config_aspm_link(link, 0); 1001fc87e919SKenji Kaneshige list_del(&link->sibling); 10027d715a6cSShaohua Li /* Clock PM is for endpoint device */ 1003fc87e919SKenji Kaneshige free_link_state(link); 100407d92760SKenji Kaneshige 100507d92760SKenji Kaneshige /* Recheck latencies and configure upstream links */ 1006b26a34aaSKenji Kaneshige if (parent_link) { 100707d92760SKenji Kaneshige pcie_update_aspm_capable(root); 1008b7206cbfSKenji Kaneshige pcie_config_aspm_path(parent_link); 1009b26a34aaSKenji Kaneshige } 10107d715a6cSShaohua Li out: 10117d715a6cSShaohua Li mutex_unlock(&aspm_lock); 10127d715a6cSShaohua Li up_read(&pci_bus_sem); 10137d715a6cSShaohua Li } 10147d715a6cSShaohua Li 10157d715a6cSShaohua Li /* @pdev: the root port or switch downstream port */ 10167d715a6cSShaohua Li void pcie_aspm_pm_state_change(struct pci_dev *pdev) 10177d715a6cSShaohua Li { 101807d92760SKenji Kaneshige struct pcie_link_state *link = pdev->link_state; 10197d715a6cSShaohua Li 1020f9b8cd7cSYijing Wang if (aspm_disabled || !link) 10217d715a6cSShaohua Li return; 10227d715a6cSShaohua Li /* 102307d92760SKenji Kaneshige * Devices changed PM state, we should recheck if latency 102407d92760SKenji Kaneshige * meets all functions' requirement 10257d715a6cSShaohua Li */ 102607d92760SKenji Kaneshige down_read(&pci_bus_sem); 102707d92760SKenji Kaneshige mutex_lock(&aspm_lock); 102807d92760SKenji Kaneshige pcie_update_aspm_capable(link->root); 1029b7206cbfSKenji Kaneshige pcie_config_aspm_path(link); 103007d92760SKenji Kaneshige mutex_unlock(&aspm_lock); 103107d92760SKenji Kaneshige up_read(&pci_bus_sem); 10327d715a6cSShaohua Li } 10337d715a6cSShaohua Li 10341a680b7cSNaga Chumbalkar void pcie_aspm_powersave_config_link(struct pci_dev *pdev) 10351a680b7cSNaga Chumbalkar { 10361a680b7cSNaga Chumbalkar struct pcie_link_state *link = pdev->link_state; 10371a680b7cSNaga Chumbalkar 1038f9b8cd7cSYijing Wang if (aspm_disabled || !link) 10391a680b7cSNaga Chumbalkar return; 10401a680b7cSNaga Chumbalkar 1041b2103ccbSRajat Jain if (aspm_policy != POLICY_POWERSAVE && 1042b2103ccbSRajat Jain aspm_policy != POLICY_POWER_SUPERSAVE) 10431a680b7cSNaga Chumbalkar return; 10441a680b7cSNaga Chumbalkar 10451a680b7cSNaga Chumbalkar down_read(&pci_bus_sem); 10461a680b7cSNaga Chumbalkar mutex_lock(&aspm_lock); 10471a680b7cSNaga Chumbalkar pcie_config_aspm_path(link); 10481a680b7cSNaga Chumbalkar pcie_set_clkpm(link, policy_to_clkpm_state(link)); 10491a680b7cSNaga Chumbalkar mutex_unlock(&aspm_lock); 10501a680b7cSNaga Chumbalkar up_read(&pci_bus_sem); 10511a680b7cSNaga Chumbalkar } 10521a680b7cSNaga Chumbalkar 1053687aaf38SHeiner Kallweit static struct pcie_link_state *pcie_aspm_get_link(struct pci_dev *pdev) 10547d715a6cSShaohua Li { 1055687aaf38SHeiner Kallweit struct pci_dev *bridge; 10567d715a6cSShaohua Li 10573c076351SMatthew Garrett if (!pci_is_pcie(pdev)) 1058687aaf38SHeiner Kallweit return NULL; 10593c076351SMatthew Garrett 1060687aaf38SHeiner Kallweit bridge = pci_upstream_bridge(pdev); 1061687aaf38SHeiner Kallweit if (!bridge || !pci_is_pcie(bridge)) 1062687aaf38SHeiner Kallweit return NULL; 1063687aaf38SHeiner Kallweit 1064687aaf38SHeiner Kallweit return bridge->link_state; 1065687aaf38SHeiner Kallweit } 1066687aaf38SHeiner Kallweit 1067687aaf38SHeiner Kallweit static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem) 1068687aaf38SHeiner Kallweit { 1069687aaf38SHeiner Kallweit struct pcie_link_state *link = pcie_aspm_get_link(pdev); 1070687aaf38SHeiner Kallweit 1071687aaf38SHeiner Kallweit if (!link) 10724cfd2188SHeiner Kallweit return -EINVAL; 10732add0ec1SBjorn Helgaas /* 10742add0ec1SBjorn Helgaas * A driver requested that ASPM be disabled on this device, but 10752add0ec1SBjorn Helgaas * if we don't have permission to manage ASPM (e.g., on ACPI 10762add0ec1SBjorn Helgaas * systems we have to observe the FADT ACPI_FADT_NO_ASPM bit and 10772add0ec1SBjorn Helgaas * the _OSC method), we can't honor that request. Windows has 10782add0ec1SBjorn Helgaas * a similar mechanism using "PciASPMOptOut", which is also 10792add0ec1SBjorn Helgaas * ignored in this situation. 10802add0ec1SBjorn Helgaas */ 1081e127a04fSBjorn Helgaas if (aspm_disabled) { 10827506dc79SFrederick Lawler pci_warn(pdev, "can't disable ASPM; OS doesn't have ASPM control\n"); 10834cfd2188SHeiner Kallweit return -EPERM; 10842add0ec1SBjorn Helgaas } 10852add0ec1SBjorn Helgaas 10869f728f53SYinghai Lu if (sem) 10877d715a6cSShaohua Li down_read(&pci_bus_sem); 10887d715a6cSShaohua Li mutex_lock(&aspm_lock); 1089ac18018aSKenji Kaneshige if (state & PCIE_LINK_STATE_L0S) 1090ac18018aSKenji Kaneshige link->aspm_disable |= ASPM_STATE_L0S; 1091ac18018aSKenji Kaneshige if (state & PCIE_LINK_STATE_L1) 1092aff5d055SHeiner Kallweit /* L1 PM substates require L1 */ 1093aff5d055SHeiner Kallweit link->aspm_disable |= ASPM_STATE_L1 | ASPM_STATE_L1SS; 1094aff5d055SHeiner Kallweit if (state & PCIE_LINK_STATE_L1_1) 1095aff5d055SHeiner Kallweit link->aspm_disable |= ASPM_STATE_L1_1; 1096aff5d055SHeiner Kallweit if (state & PCIE_LINK_STATE_L1_2) 1097aff5d055SHeiner Kallweit link->aspm_disable |= ASPM_STATE_L1_2; 1098aff5d055SHeiner Kallweit if (state & PCIE_LINK_STATE_L1_1_PCIPM) 1099aff5d055SHeiner Kallweit link->aspm_disable |= ASPM_STATE_L1_1_PCIPM; 1100aff5d055SHeiner Kallweit if (state & PCIE_LINK_STATE_L1_2_PCIPM) 1101aff5d055SHeiner Kallweit link->aspm_disable |= ASPM_STATE_L1_2_PCIPM; 1102b7206cbfSKenji Kaneshige pcie_config_aspm_link(link, policy_to_aspm_state(link)); 1103b7206cbfSKenji Kaneshige 110435efea32SHeiner Kallweit if (state & PCIE_LINK_STATE_CLKPM) 110535efea32SHeiner Kallweit link->clkpm_disable = 1; 110635efea32SHeiner Kallweit pcie_set_clkpm(link, policy_to_clkpm_state(link)); 11077d715a6cSShaohua Li mutex_unlock(&aspm_lock); 11089f728f53SYinghai Lu if (sem) 11097d715a6cSShaohua Li up_read(&pci_bus_sem); 11104cfd2188SHeiner Kallweit 11114cfd2188SHeiner Kallweit return 0; 11127d715a6cSShaohua Li } 11139f728f53SYinghai Lu 11144cfd2188SHeiner Kallweit int pci_disable_link_state_locked(struct pci_dev *pdev, int state) 11159f728f53SYinghai Lu { 11164cfd2188SHeiner Kallweit return __pci_disable_link_state(pdev, state, false); 11179f728f53SYinghai Lu } 11189f728f53SYinghai Lu EXPORT_SYMBOL(pci_disable_link_state_locked); 11199f728f53SYinghai Lu 11202dfca877SYijing Wang /** 11212dfca877SYijing Wang * pci_disable_link_state - Disable device's link state, so the link will 11222dfca877SYijing Wang * never enter specific states. Note that if the BIOS didn't grant ASPM 11232dfca877SYijing Wang * control to the OS, this does nothing because we can't touch the LNKCTL 11244cfd2188SHeiner Kallweit * register. Returns 0 or a negative errno. 11252dfca877SYijing Wang * 11262dfca877SYijing Wang * @pdev: PCI device 11272dfca877SYijing Wang * @state: ASPM link state to disable 11282dfca877SYijing Wang */ 11294cfd2188SHeiner Kallweit int pci_disable_link_state(struct pci_dev *pdev, int state) 11309f728f53SYinghai Lu { 11314cfd2188SHeiner Kallweit return __pci_disable_link_state(pdev, state, true); 11329f728f53SYinghai Lu } 11337d715a6cSShaohua Li EXPORT_SYMBOL(pci_disable_link_state); 11347d715a6cSShaohua Li 1135e4dca7b7SKees Cook static int pcie_aspm_set_policy(const char *val, 1136e4dca7b7SKees Cook const struct kernel_param *kp) 11377d715a6cSShaohua Li { 11387d715a6cSShaohua Li int i; 1139b7206cbfSKenji Kaneshige struct pcie_link_state *link; 11407d715a6cSShaohua Li 1141bbfa306aSNaga Chumbalkar if (aspm_disabled) 1142bbfa306aSNaga Chumbalkar return -EPERM; 114336131ce9SAndy Shevchenko i = sysfs_match_string(policy_str, val); 114436131ce9SAndy Shevchenko if (i < 0) 114536131ce9SAndy Shevchenko return i; 11467d715a6cSShaohua Li if (i == aspm_policy) 11477d715a6cSShaohua Li return 0; 11487d715a6cSShaohua Li 11497d715a6cSShaohua Li down_read(&pci_bus_sem); 11507d715a6cSShaohua Li mutex_lock(&aspm_lock); 11517d715a6cSShaohua Li aspm_policy = i; 1152b7206cbfSKenji Kaneshige list_for_each_entry(link, &link_list, sibling) { 1153b7206cbfSKenji Kaneshige pcie_config_aspm_link(link, policy_to_aspm_state(link)); 1154b7206cbfSKenji Kaneshige pcie_set_clkpm(link, policy_to_clkpm_state(link)); 11557d715a6cSShaohua Li } 11567d715a6cSShaohua Li mutex_unlock(&aspm_lock); 11577d715a6cSShaohua Li up_read(&pci_bus_sem); 11587d715a6cSShaohua Li return 0; 11597d715a6cSShaohua Li } 11607d715a6cSShaohua Li 1161e4dca7b7SKees Cook static int pcie_aspm_get_policy(char *buffer, const struct kernel_param *kp) 11627d715a6cSShaohua Li { 11637d715a6cSShaohua Li int i, cnt = 0; 11647d715a6cSShaohua Li for (i = 0; i < ARRAY_SIZE(policy_str); i++) 11657d715a6cSShaohua Li if (i == aspm_policy) 11667d715a6cSShaohua Li cnt += sprintf(buffer + cnt, "[%s] ", policy_str[i]); 11677d715a6cSShaohua Li else 11687d715a6cSShaohua Li cnt += sprintf(buffer + cnt, "%s ", policy_str[i]); 11693167e3d3SXiongfeng Wang cnt += sprintf(buffer + cnt, "\n"); 11707d715a6cSShaohua Li return cnt; 11717d715a6cSShaohua Li } 11727d715a6cSShaohua Li 11737d715a6cSShaohua Li module_param_call(policy, pcie_aspm_set_policy, pcie_aspm_get_policy, 11747d715a6cSShaohua Li NULL, 0644); 11757d715a6cSShaohua Li 1176accd2dd7SRafael J. Wysocki /** 1177accd2dd7SRafael J. Wysocki * pcie_aspm_enabled - Check if PCIe ASPM has been enabled for a device. 1178accd2dd7SRafael J. Wysocki * @pdev: Target device. 11795e0c21c7SBjorn Helgaas * 11805e0c21c7SBjorn Helgaas * Relies on the upstream bridge's link_state being valid. The link_state 11815e0c21c7SBjorn Helgaas * is deallocated only when the last child of the bridge (i.e., @pdev or a 11825e0c21c7SBjorn Helgaas * sibling) is removed, and the caller should be holding a reference to 11835e0c21c7SBjorn Helgaas * @pdev, so this should be safe. 1184accd2dd7SRafael J. Wysocki */ 1185accd2dd7SRafael J. Wysocki bool pcie_aspm_enabled(struct pci_dev *pdev) 1186accd2dd7SRafael J. Wysocki { 1187687aaf38SHeiner Kallweit struct pcie_link_state *link = pcie_aspm_get_link(pdev); 1188accd2dd7SRafael J. Wysocki 1189687aaf38SHeiner Kallweit if (!link) 1190accd2dd7SRafael J. Wysocki return false; 1191accd2dd7SRafael J. Wysocki 1192687aaf38SHeiner Kallweit return link->aspm_enabled; 1193accd2dd7SRafael J. Wysocki } 1194accd2dd7SRafael J. Wysocki EXPORT_SYMBOL_GPL(pcie_aspm_enabled); 1195accd2dd7SRafael J. Wysocki 119672ea91afSHeiner Kallweit static ssize_t aspm_attr_show_common(struct device *dev, 119772ea91afSHeiner Kallweit struct device_attribute *attr, 119872ea91afSHeiner Kallweit char *buf, u8 state) 119972ea91afSHeiner Kallweit { 120072ea91afSHeiner Kallweit struct pci_dev *pdev = to_pci_dev(dev); 120172ea91afSHeiner Kallweit struct pcie_link_state *link = pcie_aspm_get_link(pdev); 120272ea91afSHeiner Kallweit 1203f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%d\n", (link->aspm_enabled & state) ? 1 : 0); 120472ea91afSHeiner Kallweit } 120572ea91afSHeiner Kallweit 120672ea91afSHeiner Kallweit static ssize_t aspm_attr_store_common(struct device *dev, 120772ea91afSHeiner Kallweit struct device_attribute *attr, 120872ea91afSHeiner Kallweit const char *buf, size_t len, u8 state) 120972ea91afSHeiner Kallweit { 121072ea91afSHeiner Kallweit struct pci_dev *pdev = to_pci_dev(dev); 121172ea91afSHeiner Kallweit struct pcie_link_state *link = pcie_aspm_get_link(pdev); 121272ea91afSHeiner Kallweit bool state_enable; 121372ea91afSHeiner Kallweit 1214e0f7b192SKrzysztof Wilczyński if (kstrtobool(buf, &state_enable) < 0) 121572ea91afSHeiner Kallweit return -EINVAL; 121672ea91afSHeiner Kallweit 121772ea91afSHeiner Kallweit down_read(&pci_bus_sem); 121872ea91afSHeiner Kallweit mutex_lock(&aspm_lock); 121972ea91afSHeiner Kallweit 122072ea91afSHeiner Kallweit if (state_enable) { 122172ea91afSHeiner Kallweit link->aspm_disable &= ~state; 122272ea91afSHeiner Kallweit /* need to enable L1 for substates */ 122372ea91afSHeiner Kallweit if (state & ASPM_STATE_L1SS) 122472ea91afSHeiner Kallweit link->aspm_disable &= ~ASPM_STATE_L1; 122572ea91afSHeiner Kallweit } else { 122672ea91afSHeiner Kallweit link->aspm_disable |= state; 122772ea91afSHeiner Kallweit } 122872ea91afSHeiner Kallweit 122972ea91afSHeiner Kallweit pcie_config_aspm_link(link, policy_to_aspm_state(link)); 123072ea91afSHeiner Kallweit 123172ea91afSHeiner Kallweit mutex_unlock(&aspm_lock); 123272ea91afSHeiner Kallweit up_read(&pci_bus_sem); 123372ea91afSHeiner Kallweit 123472ea91afSHeiner Kallweit return len; 123572ea91afSHeiner Kallweit } 123672ea91afSHeiner Kallweit 123772ea91afSHeiner Kallweit #define ASPM_ATTR(_f, _s) \ 123872ea91afSHeiner Kallweit static ssize_t _f##_show(struct device *dev, \ 123972ea91afSHeiner Kallweit struct device_attribute *attr, char *buf) \ 124072ea91afSHeiner Kallweit { return aspm_attr_show_common(dev, attr, buf, ASPM_STATE_##_s); } \ 124172ea91afSHeiner Kallweit \ 124272ea91afSHeiner Kallweit static ssize_t _f##_store(struct device *dev, \ 124372ea91afSHeiner Kallweit struct device_attribute *attr, \ 124472ea91afSHeiner Kallweit const char *buf, size_t len) \ 124572ea91afSHeiner Kallweit { return aspm_attr_store_common(dev, attr, buf, len, ASPM_STATE_##_s); } 124672ea91afSHeiner Kallweit 124772ea91afSHeiner Kallweit ASPM_ATTR(l0s_aspm, L0S) 124872ea91afSHeiner Kallweit ASPM_ATTR(l1_aspm, L1) 124972ea91afSHeiner Kallweit ASPM_ATTR(l1_1_aspm, L1_1) 125072ea91afSHeiner Kallweit ASPM_ATTR(l1_2_aspm, L1_2) 125172ea91afSHeiner Kallweit ASPM_ATTR(l1_1_pcipm, L1_1_PCIPM) 125272ea91afSHeiner Kallweit ASPM_ATTR(l1_2_pcipm, L1_2_PCIPM) 125372ea91afSHeiner Kallweit 125472ea91afSHeiner Kallweit static ssize_t clkpm_show(struct device *dev, 125572ea91afSHeiner Kallweit struct device_attribute *attr, char *buf) 125672ea91afSHeiner Kallweit { 125772ea91afSHeiner Kallweit struct pci_dev *pdev = to_pci_dev(dev); 125872ea91afSHeiner Kallweit struct pcie_link_state *link = pcie_aspm_get_link(pdev); 125972ea91afSHeiner Kallweit 1260f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%d\n", link->clkpm_enabled); 126172ea91afSHeiner Kallweit } 126272ea91afSHeiner Kallweit 126372ea91afSHeiner Kallweit static ssize_t clkpm_store(struct device *dev, 126472ea91afSHeiner Kallweit struct device_attribute *attr, 126572ea91afSHeiner Kallweit const char *buf, size_t len) 126672ea91afSHeiner Kallweit { 126772ea91afSHeiner Kallweit struct pci_dev *pdev = to_pci_dev(dev); 126872ea91afSHeiner Kallweit struct pcie_link_state *link = pcie_aspm_get_link(pdev); 126972ea91afSHeiner Kallweit bool state_enable; 127072ea91afSHeiner Kallweit 1271e0f7b192SKrzysztof Wilczyński if (kstrtobool(buf, &state_enable) < 0) 127272ea91afSHeiner Kallweit return -EINVAL; 127372ea91afSHeiner Kallweit 127472ea91afSHeiner Kallweit down_read(&pci_bus_sem); 127572ea91afSHeiner Kallweit mutex_lock(&aspm_lock); 127672ea91afSHeiner Kallweit 127772ea91afSHeiner Kallweit link->clkpm_disable = !state_enable; 127872ea91afSHeiner Kallweit pcie_set_clkpm(link, policy_to_clkpm_state(link)); 127972ea91afSHeiner Kallweit 128072ea91afSHeiner Kallweit mutex_unlock(&aspm_lock); 128172ea91afSHeiner Kallweit up_read(&pci_bus_sem); 128272ea91afSHeiner Kallweit 128372ea91afSHeiner Kallweit return len; 128472ea91afSHeiner Kallweit } 128572ea91afSHeiner Kallweit 128672ea91afSHeiner Kallweit static DEVICE_ATTR_RW(clkpm); 128772ea91afSHeiner Kallweit static DEVICE_ATTR_RW(l0s_aspm); 128872ea91afSHeiner Kallweit static DEVICE_ATTR_RW(l1_aspm); 128972ea91afSHeiner Kallweit static DEVICE_ATTR_RW(l1_1_aspm); 129072ea91afSHeiner Kallweit static DEVICE_ATTR_RW(l1_2_aspm); 129172ea91afSHeiner Kallweit static DEVICE_ATTR_RW(l1_1_pcipm); 129272ea91afSHeiner Kallweit static DEVICE_ATTR_RW(l1_2_pcipm); 129372ea91afSHeiner Kallweit 129472ea91afSHeiner Kallweit static struct attribute *aspm_ctrl_attrs[] = { 129572ea91afSHeiner Kallweit &dev_attr_clkpm.attr, 129672ea91afSHeiner Kallweit &dev_attr_l0s_aspm.attr, 129772ea91afSHeiner Kallweit &dev_attr_l1_aspm.attr, 129872ea91afSHeiner Kallweit &dev_attr_l1_1_aspm.attr, 129972ea91afSHeiner Kallweit &dev_attr_l1_2_aspm.attr, 130072ea91afSHeiner Kallweit &dev_attr_l1_1_pcipm.attr, 130172ea91afSHeiner Kallweit &dev_attr_l1_2_pcipm.attr, 130272ea91afSHeiner Kallweit NULL 130372ea91afSHeiner Kallweit }; 130472ea91afSHeiner Kallweit 130572ea91afSHeiner Kallweit static umode_t aspm_ctrl_attrs_are_visible(struct kobject *kobj, 130672ea91afSHeiner Kallweit struct attribute *a, int n) 130772ea91afSHeiner Kallweit { 130872ea91afSHeiner Kallweit struct device *dev = kobj_to_dev(kobj); 130972ea91afSHeiner Kallweit struct pci_dev *pdev = to_pci_dev(dev); 131072ea91afSHeiner Kallweit struct pcie_link_state *link = pcie_aspm_get_link(pdev); 131172ea91afSHeiner Kallweit static const u8 aspm_state_map[] = { 131272ea91afSHeiner Kallweit ASPM_STATE_L0S, 131372ea91afSHeiner Kallweit ASPM_STATE_L1, 131472ea91afSHeiner Kallweit ASPM_STATE_L1_1, 131572ea91afSHeiner Kallweit ASPM_STATE_L1_2, 131672ea91afSHeiner Kallweit ASPM_STATE_L1_1_PCIPM, 131772ea91afSHeiner Kallweit ASPM_STATE_L1_2_PCIPM, 131872ea91afSHeiner Kallweit }; 131972ea91afSHeiner Kallweit 132072ea91afSHeiner Kallweit if (aspm_disabled || !link) 132172ea91afSHeiner Kallweit return 0; 132272ea91afSHeiner Kallweit 132372ea91afSHeiner Kallweit if (n == 0) 132472ea91afSHeiner Kallweit return link->clkpm_capable ? a->mode : 0; 132572ea91afSHeiner Kallweit 132672ea91afSHeiner Kallweit return link->aspm_capable & aspm_state_map[n - 1] ? a->mode : 0; 132772ea91afSHeiner Kallweit } 132872ea91afSHeiner Kallweit 132972ea91afSHeiner Kallweit const struct attribute_group aspm_ctrl_attr_group = { 133072ea91afSHeiner Kallweit .name = "link", 133172ea91afSHeiner Kallweit .attrs = aspm_ctrl_attrs, 133272ea91afSHeiner Kallweit .is_visible = aspm_ctrl_attrs_are_visible, 133372ea91afSHeiner Kallweit }; 133472ea91afSHeiner Kallweit 13357d715a6cSShaohua Li static int __init pcie_aspm_disable(char *str) 13367d715a6cSShaohua Li { 1337d6d38574SShaohua Li if (!strcmp(str, "off")) { 13383c076351SMatthew Garrett aspm_policy = POLICY_DEFAULT; 13397d715a6cSShaohua Li aspm_disabled = 1; 13408b8bae90SRafael J. Wysocki aspm_support_enabled = false; 1341d6d38574SShaohua Li printk(KERN_INFO "PCIe ASPM is disabled\n"); 1342d6d38574SShaohua Li } else if (!strcmp(str, "force")) { 1343d6d38574SShaohua Li aspm_force = 1; 13448072ba1bSMichael Witten printk(KERN_INFO "PCIe ASPM is forcibly enabled\n"); 1345d6d38574SShaohua Li } 13467d715a6cSShaohua Li return 1; 13477d715a6cSShaohua Li } 13487d715a6cSShaohua Li 1349d6d38574SShaohua Li __setup("pcie_aspm=", pcie_aspm_disable); 13507d715a6cSShaohua Li 13515fde244dSShaohua Li void pcie_no_aspm(void) 13525fde244dSShaohua Li { 13533c076351SMatthew Garrett /* 13543c076351SMatthew Garrett * Disabling ASPM is intended to prevent the kernel from modifying 13553c076351SMatthew Garrett * existing hardware state, not to clear existing state. To that end: 13563c076351SMatthew Garrett * (a) set policy to POLICY_DEFAULT in order to avoid changing state 13573c076351SMatthew Garrett * (b) prevent userspace from changing policy 13583c076351SMatthew Garrett */ 13593c076351SMatthew Garrett if (!aspm_force) { 13603c076351SMatthew Garrett aspm_policy = POLICY_DEFAULT; 13615fde244dSShaohua Li aspm_disabled = 1; 13625fde244dSShaohua Li } 13633c076351SMatthew Garrett } 13645fde244dSShaohua Li 13658b8bae90SRafael J. Wysocki bool pcie_aspm_support_enabled(void) 13668b8bae90SRafael J. Wysocki { 13678b8bae90SRafael J. Wysocki return aspm_support_enabled; 13688b8bae90SRafael J. Wysocki } 13698b8bae90SRafael J. Wysocki EXPORT_SYMBOL(pcie_aspm_support_enabled); 1370