xref: /linux/drivers/pci/pcie/aspm.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
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, &reg32);
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, &reg16);
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, &reg16);
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, &reg16);
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, &reg16);
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, &reg16);
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, &reg16);
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 						  &reg16);
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, &reg16);
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, &reg16);
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, &reg32);
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