blob: a1ae9b6f3995c3ac13ba7f14c8d48ead647ec69e [file] [log] [blame]
Shaohua Li7d715a62008-02-25 09:46:41 +08001/*
2 * File: drivers/pci/pcie/aspm.c
3 * Enabling PCIE link L0s/L1 state and Clock Power Management
4 *
5 * Copyright (C) 2007 Intel
6 * Copyright (C) Zhang Yanmin (yanmin.zhang@intel.com)
7 * Copyright (C) Shaohua Li (shaohua.li@intel.com)
8 */
9
10#include <linux/kernel.h>
11#include <linux/module.h>
12#include <linux/moduleparam.h>
13#include <linux/pci.h>
14#include <linux/pci_regs.h>
15#include <linux/errno.h>
16#include <linux/pm.h>
17#include <linux/init.h>
18#include <linux/slab.h>
Thomas Renninger2a42d9d2008-12-09 13:05:09 +010019#include <linux/jiffies.h>
Andrew Patterson987a4c72009-01-05 16:21:04 -070020#include <linux/delay.h>
Shaohua Li7d715a62008-02-25 09:46:41 +080021#include <linux/pci-aspm.h>
22#include "../pci.h"
23
24#ifdef MODULE_PARAM_PREFIX
25#undef MODULE_PARAM_PREFIX
26#endif
27#define MODULE_PARAM_PREFIX "pcie_aspm."
28
Kenji Kaneshigeb6c2e542009-05-13 12:14:58 +090029struct aspm_latency {
30 u32 l0s; /* L0s latency (nsec) */
31 u32 l1; /* L1 latency (nsec) */
Shaohua Li7d715a62008-02-25 09:46:41 +080032};
33
34struct pcie_link_state {
Kenji Kaneshige5cde89d2009-05-13 12:17:04 +090035 struct pci_dev *pdev; /* Upstream component of the Link */
36 struct pcie_link_state *parent; /* pointer to the parent Link state */
37 struct list_head sibling; /* node in link_list */
38 struct list_head children; /* list of child link states */
39 struct list_head link; /* node in parent's children list */
Shaohua Li7d715a62008-02-25 09:46:41 +080040
41 /* ASPM state */
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +090042 u32 aspm_support:2; /* Supported ASPM state */
43 u32 aspm_enabled:2; /* Enabled ASPM state */
44 u32 aspm_default:2; /* Default ASPM state by BIOS */
45
Kenji Kaneshige4d246e42009-05-13 12:15:38 +090046 /* Clock PM state */
47 u32 clkpm_capable:1; /* Clock PM capable? */
48 u32 clkpm_enabled:1; /* Current Clock PM state */
49 u32 clkpm_default:1; /* Default Clock PM state by BIOS */
50
Kenji Kaneshige5cde89d2009-05-13 12:17:04 +090051 u32 has_switch:1; /* Downstream has switches? */
52
Kenji Kaneshigeb6c2e542009-05-13 12:14:58 +090053 /* Latencies */
54 struct aspm_latency latency; /* Exit latency */
Shaohua Li7d715a62008-02-25 09:46:41 +080055 /*
Kenji Kaneshigeb6c2e542009-05-13 12:14:58 +090056 * Endpoint acceptable latencies. A pcie downstream port only
57 * has one slot under it, so at most there are 8 functions.
Shaohua Li7d715a62008-02-25 09:46:41 +080058 */
Kenji Kaneshigeb6c2e542009-05-13 12:14:58 +090059 struct aspm_latency acceptable[8];
Shaohua Li7d715a62008-02-25 09:46:41 +080060};
61
Shaohua Lid6d38572008-07-23 10:32:42 +080062static int aspm_disabled, aspm_force;
Shaohua Li7d715a62008-02-25 09:46:41 +080063static DEFINE_MUTEX(aspm_lock);
64static LIST_HEAD(link_list);
65
66#define POLICY_DEFAULT 0 /* BIOS default setting */
67#define POLICY_PERFORMANCE 1 /* high performance */
68#define POLICY_POWERSAVE 2 /* high power saving */
69static int aspm_policy;
70static const char *policy_str[] = {
71 [POLICY_DEFAULT] = "default",
72 [POLICY_PERFORMANCE] = "performance",
73 [POLICY_POWERSAVE] = "powersave"
74};
75
Andrew Patterson987a4c72009-01-05 16:21:04 -070076#define LINK_RETRAIN_TIMEOUT HZ
77
Shaohua Li7d715a62008-02-25 09:46:41 +080078static int policy_to_aspm_state(struct pci_dev *pdev)
79{
80 struct pcie_link_state *link_state = pdev->link_state;
81
82 switch (aspm_policy) {
83 case POLICY_PERFORMANCE:
84 /* Disable ASPM and Clock PM */
85 return 0;
86 case POLICY_POWERSAVE:
87 /* Enable ASPM L0s/L1 */
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +090088 return PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1;
Shaohua Li7d715a62008-02-25 09:46:41 +080089 case POLICY_DEFAULT:
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +090090 return link_state->aspm_default;
Shaohua Li7d715a62008-02-25 09:46:41 +080091 }
92 return 0;
93}
94
95static int policy_to_clkpm_state(struct pci_dev *pdev)
96{
97 struct pcie_link_state *link_state = pdev->link_state;
98
99 switch (aspm_policy) {
100 case POLICY_PERFORMANCE:
101 /* Disable ASPM and Clock PM */
102 return 0;
103 case POLICY_POWERSAVE:
104 /* Disable Clock PM */
105 return 1;
106 case POLICY_DEFAULT:
Kenji Kaneshige4d246e42009-05-13 12:15:38 +0900107 return link_state->clkpm_default;
Shaohua Li7d715a62008-02-25 09:46:41 +0800108 }
109 return 0;
110}
111
112static void pcie_set_clock_pm(struct pci_dev *pdev, int enable)
113{
114 struct pci_dev *child_dev;
115 int pos;
116 u16 reg16;
117 struct pcie_link_state *link_state = pdev->link_state;
118
119 list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
120 pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP);
121 if (!pos)
122 return;
123 pci_read_config_word(child_dev, pos + PCI_EXP_LNKCTL, &reg16);
124 if (enable)
125 reg16 |= PCI_EXP_LNKCTL_CLKREQ_EN;
126 else
127 reg16 &= ~PCI_EXP_LNKCTL_CLKREQ_EN;
128 pci_write_config_word(child_dev, pos + PCI_EXP_LNKCTL, reg16);
129 }
Kenji Kaneshige4d246e42009-05-13 12:15:38 +0900130 link_state->clkpm_enabled = !!enable;
Shaohua Li7d715a62008-02-25 09:46:41 +0800131}
132
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800133static void pcie_check_clock_pm(struct pci_dev *pdev, int blacklist)
Shaohua Li7d715a62008-02-25 09:46:41 +0800134{
135 int pos;
136 u32 reg32;
137 u16 reg16;
138 int capable = 1, enabled = 1;
139 struct pci_dev *child_dev;
140 struct pcie_link_state *link_state = pdev->link_state;
141
142 /* All functions should have the same cap and state, take the worst */
143 list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
144 pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP);
145 if (!pos)
146 return;
147 pci_read_config_dword(child_dev, pos + PCI_EXP_LNKCAP, &reg32);
148 if (!(reg32 & PCI_EXP_LNKCAP_CLKPM)) {
149 capable = 0;
150 enabled = 0;
151 break;
152 }
153 pci_read_config_word(child_dev, pos + PCI_EXP_LNKCTL, &reg16);
154 if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN))
155 enabled = 0;
156 }
Kenji Kaneshige4d246e42009-05-13 12:15:38 +0900157 link_state->clkpm_enabled = enabled;
158 link_state->clkpm_default = enabled;
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800159 if (!blacklist) {
Kenji Kaneshige4d246e42009-05-13 12:15:38 +0900160 link_state->clkpm_capable = capable;
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800161 pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev));
162 } else {
Kenji Kaneshige4d246e42009-05-13 12:15:38 +0900163 link_state->clkpm_capable = 0;
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800164 pcie_set_clock_pm(pdev, 0);
165 }
166}
167
168static bool pcie_aspm_downstream_has_switch(struct pci_dev *pdev)
169{
170 struct pci_dev *child_dev;
171
172 list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
173 if (child_dev->pcie_type == PCI_EXP_TYPE_UPSTREAM)
174 return true;
175 }
176 return false;
Shaohua Li7d715a62008-02-25 09:46:41 +0800177}
178
179/*
180 * pcie_aspm_configure_common_clock: check if the 2 ends of a link
181 * could use common clock. If they are, configure them to use the
182 * common clock. That will reduce the ASPM state exit latency.
183 */
184static void pcie_aspm_configure_common_clock(struct pci_dev *pdev)
185{
Thomas Renninger2a42d9d2008-12-09 13:05:09 +0100186 int pos, child_pos, i = 0;
Shaohua Li7d715a62008-02-25 09:46:41 +0800187 u16 reg16 = 0;
188 struct pci_dev *child_dev;
189 int same_clock = 1;
Thomas Renninger2a42d9d2008-12-09 13:05:09 +0100190 unsigned long start_jiffies;
191 u16 child_regs[8], parent_reg;
Shaohua Li7d715a62008-02-25 09:46:41 +0800192 /*
193 * all functions of a slot should have the same Slot Clock
194 * Configuration, so just check one function
195 * */
196 child_dev = list_entry(pdev->subordinate->devices.next, struct pci_dev,
197 bus_list);
198 BUG_ON(!child_dev->is_pcie);
199
200 /* Check downstream component if bit Slot Clock Configuration is 1 */
201 child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP);
202 pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKSTA, &reg16);
203 if (!(reg16 & PCI_EXP_LNKSTA_SLC))
204 same_clock = 0;
205
206 /* Check upstream component if bit Slot Clock Configuration is 1 */
207 pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
208 pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, &reg16);
209 if (!(reg16 & PCI_EXP_LNKSTA_SLC))
210 same_clock = 0;
211
212 /* Configure downstream component, all functions */
213 list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
214 child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP);
215 pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKCTL,
216 &reg16);
Thomas Renninger2a42d9d2008-12-09 13:05:09 +0100217 child_regs[i] = reg16;
Shaohua Li7d715a62008-02-25 09:46:41 +0800218 if (same_clock)
219 reg16 |= PCI_EXP_LNKCTL_CCC;
220 else
221 reg16 &= ~PCI_EXP_LNKCTL_CCC;
222 pci_write_config_word(child_dev, child_pos + PCI_EXP_LNKCTL,
223 reg16);
Thomas Renninger2a42d9d2008-12-09 13:05:09 +0100224 i++;
Shaohua Li7d715a62008-02-25 09:46:41 +0800225 }
226
227 /* Configure upstream component */
228 pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &reg16);
Thomas Renninger2a42d9d2008-12-09 13:05:09 +0100229 parent_reg = reg16;
Shaohua Li7d715a62008-02-25 09:46:41 +0800230 if (same_clock)
231 reg16 |= PCI_EXP_LNKCTL_CCC;
232 else
233 reg16 &= ~PCI_EXP_LNKCTL_CCC;
234 pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16);
235
236 /* retrain link */
237 reg16 |= PCI_EXP_LNKCTL_RL;
238 pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16);
239
240 /* Wait for link training end */
Andrew Patterson987a4c72009-01-05 16:21:04 -0700241 /* break out after waiting for timeout */
Thomas Renninger2a42d9d2008-12-09 13:05:09 +0100242 start_jiffies = jiffies;
Andrew Patterson987a4c72009-01-05 16:21:04 -0700243 for (;;) {
Shaohua Li7d715a62008-02-25 09:46:41 +0800244 pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, &reg16);
245 if (!(reg16 & PCI_EXP_LNKSTA_LT))
246 break;
Andrew Patterson987a4c72009-01-05 16:21:04 -0700247 if (time_after(jiffies, start_jiffies + LINK_RETRAIN_TIMEOUT))
248 break;
249 msleep(1);
Shaohua Li7d715a62008-02-25 09:46:41 +0800250 }
Thomas Renninger2a42d9d2008-12-09 13:05:09 +0100251 /* training failed -> recover */
Andrew Patterson987a4c72009-01-05 16:21:04 -0700252 if (reg16 & PCI_EXP_LNKSTA_LT) {
Thomas Renninger2a42d9d2008-12-09 13:05:09 +0100253 dev_printk (KERN_ERR, &pdev->dev, "ASPM: Could not configure"
254 " common clock\n");
255 i = 0;
256 list_for_each_entry(child_dev, &pdev->subordinate->devices,
257 bus_list) {
258 child_pos = pci_find_capability(child_dev,
259 PCI_CAP_ID_EXP);
260 pci_write_config_word(child_dev,
261 child_pos + PCI_EXP_LNKCTL,
262 child_regs[i]);
263 i++;
264 }
265 pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, parent_reg);
266 }
Shaohua Li7d715a62008-02-25 09:46:41 +0800267}
268
269/*
270 * calc_L0S_latency: Convert L0s latency encoding to ns
271 */
272static unsigned int calc_L0S_latency(unsigned int latency_encoding, int ac)
273{
274 unsigned int ns = 64;
275
276 if (latency_encoding == 0x7) {
277 if (ac)
278 ns = -1U;
279 else
280 ns = 5*1000; /* > 4us */
281 } else
282 ns *= (1 << latency_encoding);
283 return ns;
284}
285
286/*
287 * calc_L1_latency: Convert L1 latency encoding to ns
288 */
289static unsigned int calc_L1_latency(unsigned int latency_encoding, int ac)
290{
291 unsigned int ns = 1000;
292
293 if (latency_encoding == 0x7) {
294 if (ac)
295 ns = -1U;
296 else
297 ns = 65*1000; /* > 64us */
298 } else
299 ns *= (1 << latency_encoding);
300 return ns;
301}
302
303static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state,
304 unsigned int *l0s, unsigned int *l1, unsigned int *enabled)
305{
306 int pos;
307 u16 reg16;
308 u32 reg32;
309 unsigned int latency;
310
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900311 *l0s = *l1 = *enabled = 0;
Shaohua Li7d715a62008-02-25 09:46:41 +0800312 pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
313 pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, &reg32);
314 *state = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10;
315 if (*state != PCIE_LINK_STATE_L0S &&
316 *state != (PCIE_LINK_STATE_L1|PCIE_LINK_STATE_L0S))
317 *state = 0;
318 if (*state == 0)
319 return;
320
321 latency = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12;
322 *l0s = calc_L0S_latency(latency, 0);
323 if (*state & PCIE_LINK_STATE_L1) {
324 latency = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15;
325 *l1 = calc_L1_latency(latency, 0);
326 }
327 pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &reg16);
328 *enabled = reg16 & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1);
329}
330
331static void pcie_aspm_cap_init(struct pci_dev *pdev)
332{
333 struct pci_dev *child_dev;
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900334 u32 support, l0s, l1, enabled;
Shaohua Li7d715a62008-02-25 09:46:41 +0800335 struct pcie_link_state *link_state = pdev->link_state;
336
337 /* upstream component states */
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900338 pcie_aspm_get_cap_device(pdev, &support, &l0s, &l1, &enabled);
339 link_state->aspm_support = support;
Kenji Kaneshigeb6c2e542009-05-13 12:14:58 +0900340 link_state->latency.l0s = l0s;
341 link_state->latency.l1 = l1;
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900342 link_state->aspm_enabled = enabled;
343
Shaohua Li7d715a62008-02-25 09:46:41 +0800344 /* downstream component states, all functions have the same setting */
345 child_dev = list_entry(pdev->subordinate->devices.next, struct pci_dev,
346 bus_list);
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900347 pcie_aspm_get_cap_device(child_dev, &support, &l0s, &l1, &enabled);
348 link_state->aspm_support &= support;
Kenji Kaneshigeb6c2e542009-05-13 12:14:58 +0900349 link_state->latency.l0s = max_t(u32, link_state->latency.l0s, l0s);
350 link_state->latency.l1 = max_t(u32, link_state->latency.l1, l1);
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900351
352 if (!link_state->aspm_support)
Shaohua Li7d715a62008-02-25 09:46:41 +0800353 return;
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900354
355 link_state->aspm_enabled &= link_state->aspm_support;
356 link_state->aspm_default = link_state->aspm_enabled;
Shaohua Li7d715a62008-02-25 09:46:41 +0800357
358 /* ENDPOINT states*/
359 list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
360 int pos;
361 u32 reg32;
362 unsigned int latency;
Kenji Kaneshigeb6c2e542009-05-13 12:14:58 +0900363 struct aspm_latency *acceptable =
364 &link_state->acceptable[PCI_FUNC(child_dev->devfn)];
Shaohua Li7d715a62008-02-25 09:46:41 +0800365
366 if (child_dev->pcie_type != PCI_EXP_TYPE_ENDPOINT &&
367 child_dev->pcie_type != PCI_EXP_TYPE_LEG_END)
368 continue;
369
370 pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP);
371 pci_read_config_dword(child_dev, pos + PCI_EXP_DEVCAP, &reg32);
372 latency = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6;
373 latency = calc_L0S_latency(latency, 1);
Kenji Kaneshigeb6c2e542009-05-13 12:14:58 +0900374 acceptable->l0s = latency;
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900375 if (link_state->aspm_support & PCIE_LINK_STATE_L1) {
Shaohua Li7d715a62008-02-25 09:46:41 +0800376 latency = (reg32 & PCI_EXP_DEVCAP_L1) >> 9;
377 latency = calc_L1_latency(latency, 1);
Kenji Kaneshigeb6c2e542009-05-13 12:14:58 +0900378 acceptable->l1 = latency;
Shaohua Li7d715a62008-02-25 09:46:41 +0800379 }
380 }
381}
382
383static unsigned int __pcie_aspm_check_state_one(struct pci_dev *pdev,
384 unsigned int state)
385{
386 struct pci_dev *parent_dev, *tmp_dev;
Kenji Kaneshigeb6c2e542009-05-13 12:14:58 +0900387 unsigned int l1_latency = 0;
Shaohua Li7d715a62008-02-25 09:46:41 +0800388 struct pcie_link_state *link_state;
Kenji Kaneshigeb6c2e542009-05-13 12:14:58 +0900389 struct aspm_latency *acceptable;
Shaohua Li7d715a62008-02-25 09:46:41 +0800390
391 parent_dev = pdev->bus->self;
392 link_state = parent_dev->link_state;
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900393 state &= link_state->aspm_support;
Shaohua Li7d715a62008-02-25 09:46:41 +0800394 if (state == 0)
395 return 0;
Kenji Kaneshigeb6c2e542009-05-13 12:14:58 +0900396 acceptable = &link_state->acceptable[PCI_FUNC(pdev->devfn)];
Shaohua Li7d715a62008-02-25 09:46:41 +0800397
398 /*
399 * Check latency for endpoint device.
400 * TBD: The latency from the endpoint to root complex vary per
401 * switch's upstream link state above the device. Here we just do a
402 * simple check which assumes all links above the device can be in L1
403 * state, that is we just consider the worst case. If switch's upstream
404 * link can't be put into L0S/L1, then our check is too strictly.
405 */
406 tmp_dev = pdev;
407 while (state & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) {
408 parent_dev = tmp_dev->bus->self;
409 link_state = parent_dev->link_state;
Kenji Kaneshigeb6c2e542009-05-13 12:14:58 +0900410 if ((state & PCIE_LINK_STATE_L0S) &&
411 (link_state->latency.l0s > acceptable->l0s))
412 state &= ~PCIE_LINK_STATE_L0S;
413
414 if ((state & PCIE_LINK_STATE_L1) &&
415 (link_state->latency.l1 + l1_latency > acceptable->l1))
416 state &= ~PCIE_LINK_STATE_L1;
417
Shaohua Li7d715a62008-02-25 09:46:41 +0800418 if (!parent_dev->bus->self) /* parent_dev is a root port */
419 break;
420 else {
421 /*
422 * parent_dev is the downstream port of a switch, make
423 * tmp_dev the upstream port of the switch
424 */
425 tmp_dev = parent_dev->bus->self;
426 /*
427 * every switch on the path to root complex need 1 more
428 * microsecond for L1. Spec doesn't mention L0S.
429 */
430 if (state & PCIE_LINK_STATE_L1)
431 l1_latency += 1000;
432 }
433 }
434 return state;
435}
436
437static unsigned int pcie_aspm_check_state(struct pci_dev *pdev,
438 unsigned int state)
439{
440 struct pci_dev *child_dev;
441
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800442 /* If no child, ignore the link */
Shaohua Li7d715a62008-02-25 09:46:41 +0800443 if (list_empty(&pdev->subordinate->devices))
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800444 return state;
Shaohua Li7d715a62008-02-25 09:46:41 +0800445 list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
446 if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) {
447 /*
448 * If downstream component of a link is pci bridge, we
449 * disable ASPM for now for the link
450 * */
451 state = 0;
452 break;
453 }
454 if ((child_dev->pcie_type != PCI_EXP_TYPE_ENDPOINT &&
455 child_dev->pcie_type != PCI_EXP_TYPE_LEG_END))
456 continue;
457 /* Device not in D0 doesn't need check latency */
458 if (child_dev->current_state == PCI_D1 ||
459 child_dev->current_state == PCI_D2 ||
460 child_dev->current_state == PCI_D3hot ||
461 child_dev->current_state == PCI_D3cold)
462 continue;
463 state = __pcie_aspm_check_state_one(child_dev, state);
464 }
465 return state;
466}
467
468static void __pcie_aspm_config_one_dev(struct pci_dev *pdev, unsigned int state)
469{
470 u16 reg16;
471 int pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
472
473 pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &reg16);
474 reg16 &= ~0x3;
475 reg16 |= state;
476 pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16);
477}
478
479static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state)
480{
481 struct pci_dev *child_dev;
482 int valid = 1;
483 struct pcie_link_state *link_state = pdev->link_state;
484
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800485 /* If no child, disable the link */
486 if (list_empty(&pdev->subordinate->devices))
487 state = 0;
Shaohua Li7d715a62008-02-25 09:46:41 +0800488 /*
489 * if the downstream component has pci bridge function, don't do ASPM
490 * now
491 */
492 list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
493 if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) {
494 valid = 0;
495 break;
496 }
497 }
498 if (!valid)
499 return;
500
501 /*
502 * spec 2.0 suggests all functions should be configured the same
503 * setting for ASPM. Enabling ASPM L1 should be done in upstream
504 * component first and then downstream, and vice versa for disabling
505 * ASPM L1. Spec doesn't mention L0S.
506 */
507 if (state & PCIE_LINK_STATE_L1)
508 __pcie_aspm_config_one_dev(pdev, state);
509
510 list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list)
511 __pcie_aspm_config_one_dev(child_dev, state);
512
513 if (!(state & PCIE_LINK_STATE_L1))
514 __pcie_aspm_config_one_dev(pdev, state);
515
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900516 link_state->aspm_enabled = state;
Shaohua Li7d715a62008-02-25 09:46:41 +0800517}
518
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800519static struct pcie_link_state *get_root_port_link(struct pcie_link_state *link)
520{
521 struct pcie_link_state *root_port_link = link;
522 while (root_port_link->parent)
523 root_port_link = root_port_link->parent;
524 return root_port_link;
525}
526
527/* check the whole hierarchy, and configure each link in the hierarchy */
Shaohua Li7d715a62008-02-25 09:46:41 +0800528static void __pcie_aspm_configure_link_state(struct pci_dev *pdev,
529 unsigned int state)
530{
531 struct pcie_link_state *link_state = pdev->link_state;
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800532 struct pcie_link_state *root_port_link = get_root_port_link(link_state);
533 struct pcie_link_state *leaf;
Shaohua Li7d715a62008-02-25 09:46:41 +0800534
Shaohua Li7d715a62008-02-25 09:46:41 +0800535 state &= PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1;
536
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800537 /* check all links who have specific root port link */
Kenji Kaneshigedc64cd12009-05-13 12:11:33 +0900538 list_for_each_entry(leaf, &link_list, sibling) {
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800539 if (!list_empty(&leaf->children) ||
540 get_root_port_link(leaf) != root_port_link)
541 continue;
542 state = pcie_aspm_check_state(leaf->pdev, state);
543 }
544 /* check root port link too in case it hasn't children */
545 state = pcie_aspm_check_state(root_port_link->pdev, state);
546
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900547 if (link_state->aspm_enabled == state)
Shaohua Li7d715a62008-02-25 09:46:41 +0800548 return;
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800549
550 /*
551 * we must change the hierarchy. See comments in
552 * __pcie_aspm_config_link for the order
553 **/
554 if (state & PCIE_LINK_STATE_L1) {
Kenji Kaneshigedc64cd12009-05-13 12:11:33 +0900555 list_for_each_entry(leaf, &link_list, sibling) {
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800556 if (get_root_port_link(leaf) == root_port_link)
557 __pcie_aspm_config_link(leaf->pdev, state);
558 }
559 } else {
Kenji Kaneshigedc64cd12009-05-13 12:11:33 +0900560 list_for_each_entry_reverse(leaf, &link_list, sibling) {
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800561 if (get_root_port_link(leaf) == root_port_link)
562 __pcie_aspm_config_link(leaf->pdev, state);
563 }
564 }
Shaohua Li7d715a62008-02-25 09:46:41 +0800565}
566
567/*
568 * pcie_aspm_configure_link_state: enable/disable PCI express link state
569 * @pdev: the root port or switch downstream port
570 */
571static void pcie_aspm_configure_link_state(struct pci_dev *pdev,
572 unsigned int state)
573{
574 down_read(&pci_bus_sem);
575 mutex_lock(&aspm_lock);
576 __pcie_aspm_configure_link_state(pdev, state);
577 mutex_unlock(&aspm_lock);
578 up_read(&pci_bus_sem);
579}
580
581static void free_link_state(struct pci_dev *pdev)
582{
583 kfree(pdev->link_state);
584 pdev->link_state = NULL;
585}
586
Shaohua Liddc97532008-05-21 16:58:40 +0800587static int pcie_aspm_sanity_check(struct pci_dev *pdev)
588{
589 struct pci_dev *child_dev;
590 int child_pos;
Shaohua Li149e1632008-07-23 10:32:31 +0800591 u32 reg32;
Shaohua Liddc97532008-05-21 16:58:40 +0800592
593 /*
594 * Some functions in a slot might not all be PCIE functions, very
595 * strange. Disable ASPM for the whole slot
596 */
597 list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
598 child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP);
599 if (!child_pos)
600 return -EINVAL;
Shaohua Li149e1632008-07-23 10:32:31 +0800601
602 /*
603 * Disable ASPM for pre-1.1 PCIe device, we follow MS to use
604 * RBER bit to determine if a function is 1.1 version device
605 */
606 pci_read_config_dword(child_dev, child_pos + PCI_EXP_DEVCAP,
607 &reg32);
Sitsofe Wheelere1f4f592008-09-16 14:27:13 +0100608 if (!(reg32 & PCI_EXP_DEVCAP_RBER) && !aspm_force) {
Vincent Legollf393d9b2008-10-12 12:26:12 +0200609 dev_printk(KERN_INFO, &child_dev->dev, "disabling ASPM"
610 " on pre-1.1 PCIe device. You can enable it"
611 " with 'pcie_aspm=force'\n");
Shaohua Li149e1632008-07-23 10:32:31 +0800612 return -EINVAL;
613 }
Shaohua Liddc97532008-05-21 16:58:40 +0800614 }
615 return 0;
616}
617
Shaohua Li7d715a62008-02-25 09:46:41 +0800618/*
619 * pcie_aspm_init_link_state: Initiate PCI express link state.
620 * It is called after the pcie and its children devices are scaned.
621 * @pdev: the root port or switch downstream port
622 */
623void pcie_aspm_init_link_state(struct pci_dev *pdev)
624{
625 unsigned int state;
626 struct pcie_link_state *link_state;
627 int error = 0;
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800628 int blacklist;
Shaohua Li7d715a62008-02-25 09:46:41 +0800629
630 if (aspm_disabled || !pdev->is_pcie || pdev->link_state)
631 return;
632 if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
633 pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
634 return;
Shaohua Li8e822df2009-06-08 09:27:25 +0800635 /* VIA has a strange chipset, root port is under a bridge */
636 if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT &&
637 pdev->bus->self)
638 return;
Shaohua Li7d715a62008-02-25 09:46:41 +0800639 down_read(&pci_bus_sem);
640 if (list_empty(&pdev->subordinate->devices))
641 goto out;
642
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800643 blacklist = !!pcie_aspm_sanity_check(pdev);
Shaohua Liddc97532008-05-21 16:58:40 +0800644
Shaohua Li7d715a62008-02-25 09:46:41 +0800645 mutex_lock(&aspm_lock);
646
647 link_state = kzalloc(sizeof(*link_state), GFP_KERNEL);
648 if (!link_state)
649 goto unlock_out;
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800650
Kenji Kaneshige5cde89d2009-05-13 12:17:04 +0900651 link_state->has_switch = pcie_aspm_downstream_has_switch(pdev);
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800652 INIT_LIST_HEAD(&link_state->children);
653 INIT_LIST_HEAD(&link_state->link);
654 if (pdev->bus->self) {/* this is a switch */
655 struct pcie_link_state *parent_link_state;
656
657 parent_link_state = pdev->bus->parent->self->link_state;
658 if (!parent_link_state) {
659 kfree(link_state);
660 goto unlock_out;
661 }
662 list_add(&link_state->link, &parent_link_state->children);
663 link_state->parent = parent_link_state;
664 }
665
Shaohua Li7d715a62008-02-25 09:46:41 +0800666 pdev->link_state = link_state;
667
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800668 if (!blacklist) {
669 pcie_aspm_configure_common_clock(pdev);
670 pcie_aspm_cap_init(pdev);
671 } else {
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900672 link_state->aspm_enabled =
673 (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
674 link_state->aspm_default = 0;
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800675 /* Set support state to 0, so we will disable ASPM later */
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900676 link_state->aspm_support = 0;
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800677 }
Shaohua Li7d715a62008-02-25 09:46:41 +0800678
679 link_state->pdev = pdev;
Kenji Kaneshigedc64cd12009-05-13 12:11:33 +0900680 list_add(&link_state->sibling, &link_list);
Shaohua Li7d715a62008-02-25 09:46:41 +0800681
Kenji Kaneshige5cde89d2009-05-13 12:17:04 +0900682 if (link_state->has_switch) {
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800683 /*
684 * If link has switch, delay the link config. The leaf link
685 * initialization will config the whole hierarchy. but we must
686 * make sure BIOS doesn't set unsupported link state
687 **/
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900688 state = pcie_aspm_check_state(pdev, link_state->aspm_default);
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800689 __pcie_aspm_config_link(pdev, state);
690 } else
691 __pcie_aspm_configure_link_state(pdev,
692 policy_to_aspm_state(pdev));
693
694 pcie_check_clock_pm(pdev, blacklist);
695
Shaohua Li7d715a62008-02-25 09:46:41 +0800696unlock_out:
697 if (error)
698 free_link_state(pdev);
699 mutex_unlock(&aspm_lock);
700out:
701 up_read(&pci_bus_sem);
702}
703
704/* @pdev: the endpoint device */
705void pcie_aspm_exit_link_state(struct pci_dev *pdev)
706{
707 struct pci_dev *parent = pdev->bus->self;
708 struct pcie_link_state *link_state = parent->link_state;
709
710 if (aspm_disabled || !pdev->is_pcie || !parent || !link_state)
711 return;
712 if (parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
713 parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
714 return;
715 down_read(&pci_bus_sem);
716 mutex_lock(&aspm_lock);
717
718 /*
719 * All PCIe functions are in one slot, remove one function will remove
Alex Chiang3419c752009-01-28 14:59:18 -0700720 * the whole slot, so just wait until we are the last function left.
Shaohua Li7d715a62008-02-25 09:46:41 +0800721 */
Alex Chiang3419c752009-01-28 14:59:18 -0700722 if (!list_is_last(&pdev->bus_list, &parent->subordinate->devices))
Shaohua Li7d715a62008-02-25 09:46:41 +0800723 goto out;
724
725 /* All functions are removed, so just disable ASPM for the link */
726 __pcie_aspm_config_one_dev(parent, 0);
Kenji Kaneshigedc64cd12009-05-13 12:11:33 +0900727 list_del(&link_state->sibling);
Shaohua Li46bbdfa2008-12-19 09:27:42 +0800728 list_del(&link_state->link);
Shaohua Li7d715a62008-02-25 09:46:41 +0800729 /* Clock PM is for endpoint device */
730
731 free_link_state(parent);
732out:
733 mutex_unlock(&aspm_lock);
734 up_read(&pci_bus_sem);
735}
736
737/* @pdev: the root port or switch downstream port */
738void pcie_aspm_pm_state_change(struct pci_dev *pdev)
739{
740 struct pcie_link_state *link_state = pdev->link_state;
741
742 if (aspm_disabled || !pdev->is_pcie || !pdev->link_state)
743 return;
744 if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
745 pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
746 return;
747 /*
748 * devices changed PM state, we should recheck if latency meets all
749 * functions' requirement
750 */
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900751 pcie_aspm_configure_link_state(pdev, link_state->aspm_enabled);
Shaohua Li7d715a62008-02-25 09:46:41 +0800752}
753
754/*
755 * pci_disable_link_state - disable pci device's link state, so the link will
756 * never enter specific states
757 */
758void pci_disable_link_state(struct pci_dev *pdev, int state)
759{
760 struct pci_dev *parent = pdev->bus->self;
761 struct pcie_link_state *link_state;
762
763 if (aspm_disabled || !pdev->is_pcie)
764 return;
765 if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
766 pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)
767 parent = pdev;
768 if (!parent || !parent->link_state)
769 return;
770
771 down_read(&pci_bus_sem);
772 mutex_lock(&aspm_lock);
773 link_state = parent->link_state;
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900774 link_state->aspm_support &= ~state;
Shaohua Li7d715a62008-02-25 09:46:41 +0800775 if (state & PCIE_LINK_STATE_CLKPM)
Kenji Kaneshige4d246e42009-05-13 12:15:38 +0900776 link_state->clkpm_capable = 0;
Shaohua Li7d715a62008-02-25 09:46:41 +0800777
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900778 __pcie_aspm_configure_link_state(parent, link_state->aspm_enabled);
Kenji Kaneshige4d246e42009-05-13 12:15:38 +0900779 if (!link_state->clkpm_capable && link_state->clkpm_enabled)
Shaohua Li7d715a62008-02-25 09:46:41 +0800780 pcie_set_clock_pm(parent, 0);
781 mutex_unlock(&aspm_lock);
782 up_read(&pci_bus_sem);
783}
784EXPORT_SYMBOL(pci_disable_link_state);
785
786static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp)
787{
788 int i;
789 struct pci_dev *pdev;
790 struct pcie_link_state *link_state;
791
792 for (i = 0; i < ARRAY_SIZE(policy_str); i++)
793 if (!strncmp(val, policy_str[i], strlen(policy_str[i])))
794 break;
795 if (i >= ARRAY_SIZE(policy_str))
796 return -EINVAL;
797 if (i == aspm_policy)
798 return 0;
799
800 down_read(&pci_bus_sem);
801 mutex_lock(&aspm_lock);
802 aspm_policy = i;
Kenji Kaneshigedc64cd12009-05-13 12:11:33 +0900803 list_for_each_entry(link_state, &link_list, sibling) {
Shaohua Li7d715a62008-02-25 09:46:41 +0800804 pdev = link_state->pdev;
805 __pcie_aspm_configure_link_state(pdev,
806 policy_to_aspm_state(pdev));
Kenji Kaneshige4d246e42009-05-13 12:15:38 +0900807 if (link_state->clkpm_capable &&
808 link_state->clkpm_enabled != policy_to_clkpm_state(pdev))
Shaohua Li7d715a62008-02-25 09:46:41 +0800809 pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev));
810
811 }
812 mutex_unlock(&aspm_lock);
813 up_read(&pci_bus_sem);
814 return 0;
815}
816
817static int pcie_aspm_get_policy(char *buffer, struct kernel_param *kp)
818{
819 int i, cnt = 0;
820 for (i = 0; i < ARRAY_SIZE(policy_str); i++)
821 if (i == aspm_policy)
822 cnt += sprintf(buffer + cnt, "[%s] ", policy_str[i]);
823 else
824 cnt += sprintf(buffer + cnt, "%s ", policy_str[i]);
825 return cnt;
826}
827
828module_param_call(policy, pcie_aspm_set_policy, pcie_aspm_get_policy,
829 NULL, 0644);
830
831#ifdef CONFIG_PCIEASPM_DEBUG
832static ssize_t link_state_show(struct device *dev,
833 struct device_attribute *attr,
834 char *buf)
835{
836 struct pci_dev *pci_device = to_pci_dev(dev);
837 struct pcie_link_state *link_state = pci_device->link_state;
838
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900839 return sprintf(buf, "%d\n", link_state->aspm_enabled);
Shaohua Li7d715a62008-02-25 09:46:41 +0800840}
841
842static ssize_t link_state_store(struct device *dev,
843 struct device_attribute *attr,
844 const char *buf,
845 size_t n)
846{
847 struct pci_dev *pci_device = to_pci_dev(dev);
848 int state;
849
850 if (n < 1)
851 return -EINVAL;
852 state = buf[0]-'0';
853 if (state >= 0 && state <= 3) {
854 /* setup link aspm state */
855 pcie_aspm_configure_link_state(pci_device, state);
856 return n;
857 }
858
859 return -EINVAL;
860}
861
862static ssize_t clk_ctl_show(struct device *dev,
863 struct device_attribute *attr,
864 char *buf)
865{
866 struct pci_dev *pci_device = to_pci_dev(dev);
867 struct pcie_link_state *link_state = pci_device->link_state;
868
Kenji Kaneshige4d246e42009-05-13 12:15:38 +0900869 return sprintf(buf, "%d\n", link_state->clkpm_enabled);
Shaohua Li7d715a62008-02-25 09:46:41 +0800870}
871
872static ssize_t clk_ctl_store(struct device *dev,
873 struct device_attribute *attr,
874 const char *buf,
875 size_t n)
876{
877 struct pci_dev *pci_device = to_pci_dev(dev);
878 int state;
879
880 if (n < 1)
881 return -EINVAL;
882 state = buf[0]-'0';
883
884 down_read(&pci_bus_sem);
885 mutex_lock(&aspm_lock);
886 pcie_set_clock_pm(pci_device, !!state);
887 mutex_unlock(&aspm_lock);
888 up_read(&pci_bus_sem);
889
890 return n;
891}
892
893static DEVICE_ATTR(link_state, 0644, link_state_show, link_state_store);
894static DEVICE_ATTR(clk_ctl, 0644, clk_ctl_show, clk_ctl_store);
895
896static char power_group[] = "power";
897void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev)
898{
899 struct pcie_link_state *link_state = pdev->link_state;
900
901 if (!pdev->is_pcie || (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
902 pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state)
903 return;
904
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900905 if (link_state->aspm_support)
Shaohua Li7d715a62008-02-25 09:46:41 +0800906 sysfs_add_file_to_group(&pdev->dev.kobj,
907 &dev_attr_link_state.attr, power_group);
Kenji Kaneshige4d246e42009-05-13 12:15:38 +0900908 if (link_state->clkpm_capable)
Shaohua Li7d715a62008-02-25 09:46:41 +0800909 sysfs_add_file_to_group(&pdev->dev.kobj,
910 &dev_attr_clk_ctl.attr, power_group);
911}
912
913void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev)
914{
915 struct pcie_link_state *link_state = pdev->link_state;
916
917 if (!pdev->is_pcie || (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
918 pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state)
919 return;
920
Kenji Kaneshige80bfdbe2009-05-13 12:12:43 +0900921 if (link_state->aspm_support)
Shaohua Li7d715a62008-02-25 09:46:41 +0800922 sysfs_remove_file_from_group(&pdev->dev.kobj,
923 &dev_attr_link_state.attr, power_group);
Kenji Kaneshige4d246e42009-05-13 12:15:38 +0900924 if (link_state->clkpm_capable)
Shaohua Li7d715a62008-02-25 09:46:41 +0800925 sysfs_remove_file_from_group(&pdev->dev.kobj,
926 &dev_attr_clk_ctl.attr, power_group);
927}
928#endif
929
930static int __init pcie_aspm_disable(char *str)
931{
Shaohua Lid6d38572008-07-23 10:32:42 +0800932 if (!strcmp(str, "off")) {
933 aspm_disabled = 1;
934 printk(KERN_INFO "PCIe ASPM is disabled\n");
935 } else if (!strcmp(str, "force")) {
936 aspm_force = 1;
937 printk(KERN_INFO "PCIe ASPM is forcedly enabled\n");
938 }
Shaohua Li7d715a62008-02-25 09:46:41 +0800939 return 1;
940}
941
Shaohua Lid6d38572008-07-23 10:32:42 +0800942__setup("pcie_aspm=", pcie_aspm_disable);
Shaohua Li7d715a62008-02-25 09:46:41 +0800943
Shaohua Li5fde2442008-07-23 10:32:24 +0800944void pcie_no_aspm(void)
945{
Shaohua Lid6d38572008-07-23 10:32:42 +0800946 if (!aspm_force)
947 aspm_disabled = 1;
Shaohua Li5fde2442008-07-23 10:32:24 +0800948}
949
Andrew Patterson3e1b1602008-11-10 15:30:55 -0700950/**
951 * pcie_aspm_enabled - is PCIe ASPM enabled?
952 *
953 * Returns true if ASPM has not been disabled by the command-line option
954 * pcie_aspm=off.
955 **/
956int pcie_aspm_enabled(void)
Shaohua Li7d715a62008-02-25 09:46:41 +0800957{
Andrew Patterson3e1b1602008-11-10 15:30:55 -0700958 return !aspm_disabled;
Shaohua Li7d715a62008-02-25 09:46:41 +0800959}
Andrew Patterson3e1b1602008-11-10 15:30:55 -0700960EXPORT_SYMBOL(pcie_aspm_enabled);
Shaohua Li7d715a62008-02-25 09:46:41 +0800961