aspm.c 24.9 KB
Newer Older
S
Shaohua Li 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * File:	drivers/pci/pcie/aspm.c
 * Enabling PCIE link L0s/L1 state and Clock Power Management
 *
 * Copyright (C) 2007 Intel
 * Copyright (C) Zhang Yanmin (yanmin.zhang@intel.com)
 * Copyright (C) Shaohua Li (shaohua.li@intel.com)
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
#include <linux/pci_regs.h>
#include <linux/errno.h>
#include <linux/pm.h>
#include <linux/init.h>
#include <linux/slab.h>
19
#include <linux/jiffies.h>
20
#include <linux/delay.h>
S
Shaohua Li 已提交
21 22 23 24 25 26 27 28
#include <linux/pci-aspm.h>
#include "../pci.h"

#ifdef MODULE_PARAM_PREFIX
#undef MODULE_PARAM_PREFIX
#endif
#define MODULE_PARAM_PREFIX "pcie_aspm."

29 30 31 32 33 34 35
/* Note: those are not register definitions */
#define ASPM_STATE_L0S_UP	(1)	/* Upstream direction L0s state */
#define ASPM_STATE_L0S_DW	(2)	/* Downstream direction L0s state */
#define ASPM_STATE_L1		(4)	/* L1 state */
#define ASPM_STATE_L0S		(ASPM_STATE_L0S_UP | ASPM_STATE_L0S_DW)
#define ASPM_STATE_ALL		(ASPM_STATE_L0S | ASPM_STATE_L1)

36 37 38
struct aspm_latency {
	u32 l0s;			/* L0s latency (nsec) */
	u32 l1;				/* L1 latency (nsec) */
S
Shaohua Li 已提交
39 40 41
};

struct pcie_link_state {
42
	struct pci_dev *pdev;		/* Upstream component of the Link */
43
	struct pcie_link_state *root;	/* pointer to the root port link */
44 45 46 47
	struct pcie_link_state *parent;	/* pointer to the parent Link state */
	struct list_head sibling;	/* node in link_list */
	struct list_head children;	/* list of child link states */
	struct list_head link;		/* node in parent's children list */
S
Shaohua Li 已提交
48 49

	/* ASPM state */
50 51 52 53 54
	u32 aspm_support:3;		/* Supported ASPM state */
	u32 aspm_enabled:3;		/* Enabled ASPM state */
	u32 aspm_capable:3;		/* Capable ASPM state with latency */
	u32 aspm_default:3;		/* Default ASPM state by BIOS */
	u32 aspm_disable:3;		/* Disabled ASPM state */
55

56 57 58 59 60
	/* Clock PM state */
	u32 clkpm_capable:1;		/* Clock PM capable? */
	u32 clkpm_enabled:1;		/* Current Clock PM state */
	u32 clkpm_default:1;		/* Default Clock PM state by BIOS */

61 62 63
	/* Exit latencies */
	struct aspm_latency latency_up;	/* Upstream direction exit latency */
	struct aspm_latency latency_dw;	/* Downstream direction exit latency */
S
Shaohua Li 已提交
64
	/*
65 66
	 * Endpoint acceptable latencies. A pcie downstream port only
	 * has one slot under it, so at most there are 8 functions.
S
Shaohua Li 已提交
67
	 */
68
	struct aspm_latency acceptable[8];
S
Shaohua Li 已提交
69 70
};

71
static int aspm_disabled, aspm_force;
S
Shaohua Li 已提交
72 73 74 75 76 77 78 79 80 81 82 83 84
static DEFINE_MUTEX(aspm_lock);
static LIST_HEAD(link_list);

#define POLICY_DEFAULT 0	/* BIOS default setting */
#define POLICY_PERFORMANCE 1	/* high performance */
#define POLICY_POWERSAVE 2	/* high power saving */
static int aspm_policy;
static const char *policy_str[] = {
	[POLICY_DEFAULT] = "default",
	[POLICY_PERFORMANCE] = "performance",
	[POLICY_POWERSAVE] = "powersave"
};

85 86
#define LINK_RETRAIN_TIMEOUT HZ

87
static int policy_to_aspm_state(struct pcie_link_state *link)
S
Shaohua Li 已提交
88 89 90 91 92 93 94
{
	switch (aspm_policy) {
	case POLICY_PERFORMANCE:
		/* Disable ASPM and Clock PM */
		return 0;
	case POLICY_POWERSAVE:
		/* Enable ASPM L0s/L1 */
95
		return ASPM_STATE_ALL;
S
Shaohua Li 已提交
96
	case POLICY_DEFAULT:
97
		return link->aspm_default;
S
Shaohua Li 已提交
98 99 100 101
	}
	return 0;
}

102
static int policy_to_clkpm_state(struct pcie_link_state *link)
S
Shaohua Li 已提交
103 104 105 106 107 108 109 110 111
{
	switch (aspm_policy) {
	case POLICY_PERFORMANCE:
		/* Disable ASPM and Clock PM */
		return 0;
	case POLICY_POWERSAVE:
		/* Disable Clock PM */
		return 1;
	case POLICY_DEFAULT:
112
		return link->clkpm_default;
S
Shaohua Li 已提交
113 114 115 116
	}
	return 0;
}

K
Kenji Kaneshige 已提交
117
static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable)
S
Shaohua Li 已提交
118 119 120
{
	int pos;
	u16 reg16;
121 122
	struct pci_dev *child;
	struct pci_bus *linkbus = link->pdev->subordinate;
S
Shaohua Li 已提交
123

124
	list_for_each_entry(child, &linkbus->devices, bus_list) {
K
Kenji Kaneshige 已提交
125
		pos = pci_pcie_cap(child);
S
Shaohua Li 已提交
126 127
		if (!pos)
			return;
128
		pci_read_config_word(child, pos + PCI_EXP_LNKCTL, &reg16);
S
Shaohua Li 已提交
129 130 131 132
		if (enable)
			reg16 |= PCI_EXP_LNKCTL_CLKREQ_EN;
		else
			reg16 &= ~PCI_EXP_LNKCTL_CLKREQ_EN;
133
		pci_write_config_word(child, pos + PCI_EXP_LNKCTL, reg16);
S
Shaohua Li 已提交
134
	}
135
	link->clkpm_enabled = !!enable;
S
Shaohua Li 已提交
136 137
}

K
Kenji Kaneshige 已提交
138 139 140 141 142 143 144 145 146 147 148
static void pcie_set_clkpm(struct pcie_link_state *link, int enable)
{
	/* Don't enable Clock PM if the link is not Clock PM capable */
	if (!link->clkpm_capable && enable)
		return;
	/* Need nothing if the specified equals to current state */
	if (link->clkpm_enabled == enable)
		return;
	pcie_set_clkpm_nocheck(link, enable);
}

149
static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist)
S
Shaohua Li 已提交
150
{
151
	int pos, capable = 1, enabled = 1;
S
Shaohua Li 已提交
152 153
	u32 reg32;
	u16 reg16;
154 155
	struct pci_dev *child;
	struct pci_bus *linkbus = link->pdev->subordinate;
S
Shaohua Li 已提交
156 157

	/* All functions should have the same cap and state, take the worst */
158
	list_for_each_entry(child, &linkbus->devices, bus_list) {
K
Kenji Kaneshige 已提交
159
		pos = pci_pcie_cap(child);
S
Shaohua Li 已提交
160 161
		if (!pos)
			return;
162
		pci_read_config_dword(child, pos + PCI_EXP_LNKCAP, &reg32);
S
Shaohua Li 已提交
163 164 165 166 167
		if (!(reg32 & PCI_EXP_LNKCAP_CLKPM)) {
			capable = 0;
			enabled = 0;
			break;
		}
168
		pci_read_config_word(child, pos + PCI_EXP_LNKCTL, &reg16);
S
Shaohua Li 已提交
169 170 171
		if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN))
			enabled = 0;
	}
172 173
	link->clkpm_enabled = enabled;
	link->clkpm_default = enabled;
174
	link->clkpm_capable = (blacklist) ? 0 : capable;
175 176
}

S
Shaohua Li 已提交
177 178 179 180 181
/*
 * pcie_aspm_configure_common_clock: check if the 2 ends of a link
 *   could use common clock. If they are, configure them to use the
 *   common clock. That will reduce the ASPM state exit latency.
 */
182
static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
S
Shaohua Li 已提交
183
{
184 185
	int ppos, cpos, same_clock = 1;
	u16 reg16, parent_reg, child_reg[8];
186
	unsigned long start_jiffies;
187 188
	struct pci_dev *child, *parent = link->pdev;
	struct pci_bus *linkbus = parent->subordinate;
S
Shaohua Li 已提交
189
	/*
190
	 * All functions of a slot should have the same Slot Clock
S
Shaohua Li 已提交
191
	 * Configuration, so just check one function
192 193 194
	 */
	child = list_entry(linkbus->devices.next, struct pci_dev, bus_list);
	BUG_ON(!child->is_pcie);
S
Shaohua Li 已提交
195 196

	/* Check downstream component if bit Slot Clock Configuration is 1 */
K
Kenji Kaneshige 已提交
197
	cpos = pci_pcie_cap(child);
198
	pci_read_config_word(child, cpos + PCI_EXP_LNKSTA, &reg16);
S
Shaohua Li 已提交
199 200 201 202
	if (!(reg16 & PCI_EXP_LNKSTA_SLC))
		same_clock = 0;

	/* Check upstream component if bit Slot Clock Configuration is 1 */
K
Kenji Kaneshige 已提交
203
	ppos = pci_pcie_cap(parent);
204
	pci_read_config_word(parent, ppos + PCI_EXP_LNKSTA, &reg16);
S
Shaohua Li 已提交
205 206 207 208
	if (!(reg16 & PCI_EXP_LNKSTA_SLC))
		same_clock = 0;

	/* Configure downstream component, all functions */
209
	list_for_each_entry(child, &linkbus->devices, bus_list) {
K
Kenji Kaneshige 已提交
210
		cpos = pci_pcie_cap(child);
211 212
		pci_read_config_word(child, cpos + PCI_EXP_LNKCTL, &reg16);
		child_reg[PCI_FUNC(child->devfn)] = reg16;
S
Shaohua Li 已提交
213 214 215 216
		if (same_clock)
			reg16 |= PCI_EXP_LNKCTL_CCC;
		else
			reg16 &= ~PCI_EXP_LNKCTL_CCC;
217
		pci_write_config_word(child, cpos + PCI_EXP_LNKCTL, reg16);
S
Shaohua Li 已提交
218 219 220
	}

	/* Configure upstream component */
221
	pci_read_config_word(parent, ppos + PCI_EXP_LNKCTL, &reg16);
222
	parent_reg = reg16;
S
Shaohua Li 已提交
223 224 225 226
	if (same_clock)
		reg16 |= PCI_EXP_LNKCTL_CCC;
	else
		reg16 &= ~PCI_EXP_LNKCTL_CCC;
227
	pci_write_config_word(parent, ppos + PCI_EXP_LNKCTL, reg16);
S
Shaohua Li 已提交
228

229
	/* Retrain link */
S
Shaohua Li 已提交
230
	reg16 |= PCI_EXP_LNKCTL_RL;
231
	pci_write_config_word(parent, ppos + PCI_EXP_LNKCTL, reg16);
S
Shaohua Li 已提交
232

233
	/* Wait for link training end. Break out after waiting for timeout */
234
	start_jiffies = jiffies;
235
	for (;;) {
236
		pci_read_config_word(parent, ppos + PCI_EXP_LNKSTA, &reg16);
S
Shaohua Li 已提交
237 238
		if (!(reg16 & PCI_EXP_LNKSTA_LT))
			break;
239 240 241
		if (time_after(jiffies, start_jiffies + LINK_RETRAIN_TIMEOUT))
			break;
		msleep(1);
S
Shaohua Li 已提交
242
	}
243 244 245 246 247 248 249
	if (!(reg16 & PCI_EXP_LNKSTA_LT))
		return;

	/* Training failed. Restore common clock configurations */
	dev_printk(KERN_ERR, &parent->dev,
		   "ASPM: Could not configure common clock\n");
	list_for_each_entry(child, &linkbus->devices, bus_list) {
K
Kenji Kaneshige 已提交
250
		cpos = pci_pcie_cap(child);
251 252
		pci_write_config_word(child, cpos + PCI_EXP_LNKCTL,
				      child_reg[PCI_FUNC(child->devfn)]);
253
	}
254
	pci_write_config_word(parent, ppos + PCI_EXP_LNKCTL, parent_reg);
S
Shaohua Li 已提交
255 256
}

257 258
/* Convert L0s latency encoding to ns */
static u32 calc_l0s_latency(u32 encoding)
S
Shaohua Li 已提交
259
{
260 261 262 263
	if (encoding == 0x7)
		return (5 * 1000);	/* > 4us */
	return (64 << encoding);
}
S
Shaohua Li 已提交
264

265 266 267 268 269 270
/* Convert L0s acceptable latency encoding to ns */
static u32 calc_l0s_acceptable(u32 encoding)
{
	if (encoding == 0x7)
		return -1U;
	return (64 << encoding);
S
Shaohua Li 已提交
271 272
}

273 274
/* Convert L1 latency encoding to ns */
static u32 calc_l1_latency(u32 encoding)
S
Shaohua Li 已提交
275
{
276 277 278 279
	if (encoding == 0x7)
		return (65 * 1000);	/* > 64us */
	return (1000 << encoding);
}
S
Shaohua Li 已提交
280

281 282 283 284 285 286
/* Convert L1 acceptable latency encoding to ns */
static u32 calc_l1_acceptable(u32 encoding)
{
	if (encoding == 0x7)
		return -1U;
	return (1000 << encoding);
S
Shaohua Li 已提交
287 288
}

289 290 291 292 293 294 295 296 297
struct aspm_register_info {
	u32 support:2;
	u32 enabled:2;
	u32 latency_encoding_l0s;
	u32 latency_encoding_l1;
};

static void pcie_get_aspm_reg(struct pci_dev *pdev,
			      struct aspm_register_info *info)
S
Shaohua Li 已提交
298 299 300
{
	int pos;
	u16 reg16;
301
	u32 reg32;
S
Shaohua Li 已提交
302

K
Kenji Kaneshige 已提交
303
	pos = pci_pcie_cap(pdev);
S
Shaohua Li 已提交
304
	pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, &reg32);
305 306 307
	info->support = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10;
	info->latency_encoding_l0s = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12;
	info->latency_encoding_l1  = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15;
S
Shaohua Li 已提交
308
	pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &reg16);
309
	info->enabled = reg16 & PCI_EXP_LNKCTL_ASPMC;
S
Shaohua Li 已提交
310 311
}

312 313
static void pcie_aspm_check_latency(struct pci_dev *endpoint)
{
314
	u32 latency, l1_switch_latency = 0;
315 316 317 318 319 320 321 322 323 324 325 326
	struct aspm_latency *acceptable;
	struct pcie_link_state *link;

	/* Device not in D0 doesn't need latency check */
	if ((endpoint->current_state != PCI_D0) &&
	    (endpoint->current_state != PCI_UNKNOWN))
		return;

	link = endpoint->bus->self->link_state;
	acceptable = &link->acceptable[PCI_FUNC(endpoint->devfn)];

	while (link) {
327 328 329 330 331 332 333 334 335
		/* Check upstream direction L0s latency */
		if ((link->aspm_capable & ASPM_STATE_L0S_UP) &&
		    (link->latency_up.l0s > acceptable->l0s))
			link->aspm_capable &= ~ASPM_STATE_L0S_UP;

		/* Check downstream direction L0s latency */
		if ((link->aspm_capable & ASPM_STATE_L0S_DW) &&
		    (link->latency_dw.l0s > acceptable->l0s))
			link->aspm_capable &= ~ASPM_STATE_L0S_DW;
336 337 338 339 340
		/*
		 * Check L1 latency.
		 * Every switch on the path to root complex need 1
		 * more microsecond for L1. Spec doesn't mention L0s.
		 */
341 342 343 344
		latency = max_t(u32, link->latency_up.l1, link->latency_dw.l1);
		if ((link->aspm_capable & ASPM_STATE_L1) &&
		    (latency + l1_switch_latency > acceptable->l1))
			link->aspm_capable &= ~ASPM_STATE_L1;
345 346 347 348 349 350
		l1_switch_latency += 1000;

		link = link->parent;
	}
}

351
static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
S
Shaohua Li 已提交
352
{
353 354
	struct pci_dev *child, *parent = link->pdev;
	struct pci_bus *linkbus = parent->subordinate;
355
	struct aspm_register_info upreg, dwreg;
S
Shaohua Li 已提交
356

357
	if (blacklist) {
358
		/* Set enabled/disable so that we will disable ASPM later */
359 360
		link->aspm_enabled = ASPM_STATE_ALL;
		link->aspm_disable = ASPM_STATE_ALL;
361 362 363 364 365 366
		return;
	}

	/* Configure common clock before checking latencies */
	pcie_aspm_configure_common_clock(link);

367 368
	/* Get upstream/downstream components' register state */
	pcie_get_aspm_reg(parent, &upreg);
369
	child = list_entry(linkbus->devices.next, struct pci_dev, bus_list);
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
	pcie_get_aspm_reg(child, &dwreg);

	/*
	 * Setup L0s state
	 *
	 * Note that we must not enable L0s in either direction on a
	 * given link unless components on both sides of the link each
	 * support L0s.
	 */
	if (dwreg.support & upreg.support & PCIE_LINK_STATE_L0S)
		link->aspm_support |= ASPM_STATE_L0S;
	if (dwreg.enabled & PCIE_LINK_STATE_L0S)
		link->aspm_enabled |= ASPM_STATE_L0S_UP;
	if (upreg.enabled & PCIE_LINK_STATE_L0S)
		link->aspm_enabled |= ASPM_STATE_L0S_DW;
	link->latency_up.l0s = calc_l0s_latency(upreg.latency_encoding_l0s);
	link->latency_dw.l0s = calc_l0s_latency(dwreg.latency_encoding_l0s);

	/* Setup L1 state */
	if (upreg.support & dwreg.support & PCIE_LINK_STATE_L1)
		link->aspm_support |= ASPM_STATE_L1;
	if (upreg.enabled & dwreg.enabled & PCIE_LINK_STATE_L1)
		link->aspm_enabled |= ASPM_STATE_L1;
	link->latency_up.l1 = calc_l1_latency(upreg.latency_encoding_l1);
	link->latency_dw.l1 = calc_l1_latency(dwreg.latency_encoding_l1);
395

396 397
	/* Save default state */
	link->aspm_default = link->aspm_enabled;
398 399 400

	/* Setup initial capable state. Will be updated later */
	link->aspm_capable = link->aspm_support;
401 402 403 404 405 406
	/*
	 * If the downstream component has pci bridge function, don't
	 * do ASPM for now.
	 */
	list_for_each_entry(child, &linkbus->devices, bus_list) {
		if (child->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) {
407
			link->aspm_disable = ASPM_STATE_ALL;
408 409 410
			break;
		}
	}
411

412
	/* Get and check endpoint acceptable latencies */
413
	list_for_each_entry(child, &linkbus->devices, bus_list) {
S
Shaohua Li 已提交
414
		int pos;
415
		u32 reg32, encoding;
416
		struct aspm_latency *acceptable =
417
			&link->acceptable[PCI_FUNC(child->devfn)];
S
Shaohua Li 已提交
418

419 420
		if (child->pcie_type != PCI_EXP_TYPE_ENDPOINT &&
		    child->pcie_type != PCI_EXP_TYPE_LEG_END)
S
Shaohua Li 已提交
421 422
			continue;

K
Kenji Kaneshige 已提交
423
		pos = pci_pcie_cap(child);
424
		pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, &reg32);
425
		/* Calculate endpoint L0s acceptable latency */
426 427
		encoding = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6;
		acceptable->l0s = calc_l0s_acceptable(encoding);
428 429 430 431 432
		/* Calculate endpoint L1 acceptable latency */
		encoding = (reg32 & PCI_EXP_DEVCAP_L1) >> 9;
		acceptable->l1 = calc_l1_acceptable(encoding);

		pcie_aspm_check_latency(child);
S
Shaohua Li 已提交
433 434 435
	}
}

436
static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val)
S
Shaohua Li 已提交
437 438
{
	u16 reg16;
K
Kenji Kaneshige 已提交
439
	int pos = pci_pcie_cap(pdev);
S
Shaohua Li 已提交
440 441 442

	pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &reg16);
	reg16 &= ~0x3;
443
	reg16 |= val;
S
Shaohua Li 已提交
444 445 446
	pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16);
}

447
static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state)
S
Shaohua Li 已提交
448
{
449
	u32 upstream = 0, dwstream = 0;
450 451
	struct pci_dev *child, *parent = link->pdev;
	struct pci_bus *linkbus = parent->subordinate;
S
Shaohua Li 已提交
452

453
	/* Nothing to do if the link is already in the requested state */
454
	state &= (link->aspm_capable & ~link->aspm_disable);
455 456
	if (link->aspm_enabled == state)
		return;
457 458 459 460 461 462 463 464 465
	/* Convert ASPM state to upstream/downstream ASPM register state */
	if (state & ASPM_STATE_L0S_UP)
		dwstream |= PCIE_LINK_STATE_L0S;
	if (state & ASPM_STATE_L0S_DW)
		upstream |= PCIE_LINK_STATE_L0S;
	if (state & ASPM_STATE_L1) {
		upstream |= PCIE_LINK_STATE_L1;
		dwstream |= PCIE_LINK_STATE_L1;
	}
S
Shaohua Li 已提交
466
	/*
467 468 469 470
	 * Spec 2.0 suggests all functions should be configured the
	 * same setting for ASPM. Enabling ASPM L1 should be done in
	 * upstream component first and then downstream, and vice
	 * versa for disabling ASPM L1. Spec doesn't mention L0S.
S
Shaohua Li 已提交
471
	 */
472 473
	if (state & ASPM_STATE_L1)
		pcie_config_aspm_dev(parent, upstream);
474
	list_for_each_entry(child, &linkbus->devices, bus_list)
475 476 477
		pcie_config_aspm_dev(child, dwstream);
	if (!(state & ASPM_STATE_L1))
		pcie_config_aspm_dev(parent, upstream);
S
Shaohua Li 已提交
478

479
	link->aspm_enabled = state;
S
Shaohua Li 已提交
480 481
}

482
static void pcie_config_aspm_path(struct pcie_link_state *link)
S
Shaohua Li 已提交
483
{
484 485 486
	while (link) {
		pcie_config_aspm_link(link, policy_to_aspm_state(link));
		link = link->parent;
487
	}
S
Shaohua Li 已提交
488 489
}

490
static void free_link_state(struct pcie_link_state *link)
S
Shaohua Li 已提交
491
{
492 493
	link->pdev->link_state = NULL;
	kfree(link);
S
Shaohua Li 已提交
494 495
}

496 497
static int pcie_aspm_sanity_check(struct pci_dev *pdev)
{
498 499
	struct pci_dev *child;
	int pos;
500
	u32 reg32;
501
	/*
502 503
	 * Some functions in a slot might not all be PCIE functions,
	 * very strange. Disable ASPM for the whole slot
504
	 */
505
	list_for_each_entry(child, &pdev->subordinate->devices, bus_list) {
K
Kenji Kaneshige 已提交
506
		pos = pci_pcie_cap(child);
507
		if (!pos)
508
			return -EINVAL;
509 510 511 512
		/*
		 * Disable ASPM for pre-1.1 PCIe device, we follow MS to use
		 * RBER bit to determine if a function is 1.1 version device
		 */
513
		pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, &reg32);
S
Sitsofe Wheeler 已提交
514
		if (!(reg32 & PCI_EXP_DEVCAP_RBER) && !aspm_force) {
515
			dev_printk(KERN_INFO, &child->dev, "disabling ASPM"
516 517
				" on pre-1.1 PCIe device.  You can enable it"
				" with 'pcie_aspm=force'\n");
518 519
			return -EINVAL;
		}
520 521 522 523
	}
	return 0;
}

524
static struct pcie_link_state *alloc_pcie_link_state(struct pci_dev *pdev)
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
{
	struct pcie_link_state *link;

	link = kzalloc(sizeof(*link), GFP_KERNEL);
	if (!link)
		return NULL;
	INIT_LIST_HEAD(&link->sibling);
	INIT_LIST_HEAD(&link->children);
	INIT_LIST_HEAD(&link->link);
	link->pdev = pdev;
	if (pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) {
		struct pcie_link_state *parent;
		parent = pdev->bus->parent->self->link_state;
		if (!parent) {
			kfree(link);
			return NULL;
		}
		link->parent = parent;
		list_add(&link->link, &parent->children);
	}
545 546 547 548 549 550
	/* Setup a pointer to the root port link */
	if (!link->parent)
		link->root = link;
	else
		link->root = link->parent->root;

551 552 553 554 555
	list_add(&link->sibling, &link_list);
	pdev->link_state = link;
	return link;
}

S
Shaohua Li 已提交
556 557 558 559 560 561 562
/*
 * pcie_aspm_init_link_state: Initiate PCI express link state.
 * It is called after the pcie and its children devices are scaned.
 * @pdev: the root port or switch downstream port
 */
void pcie_aspm_init_link_state(struct pci_dev *pdev)
{
563
	struct pcie_link_state *link;
564
	int blacklist = !!pcie_aspm_sanity_check(pdev);
S
Shaohua Li 已提交
565 566 567 568

	if (aspm_disabled || !pdev->is_pcie || pdev->link_state)
		return;
	if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
569
	    pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
S
Shaohua Li 已提交
570
		return;
571

572 573
	/* VIA has a strange chipset, root port is under a bridge */
	if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT &&
574
	    pdev->bus->self)
575
		return;
576

S
Shaohua Li 已提交
577 578 579 580 581
	down_read(&pci_bus_sem);
	if (list_empty(&pdev->subordinate->devices))
		goto out;

	mutex_lock(&aspm_lock);
582
	link = alloc_pcie_link_state(pdev);
583 584 585
	if (!link)
		goto unlock;
	/*
586 587 588
	 * Setup initial ASPM state. Note that we need to configure
	 * upstream links also because capable state of them can be
	 * update through pcie_aspm_cap_init().
589
	 */
590 591
	pcie_aspm_cap_init(link, blacklist);
	pcie_config_aspm_path(link);
S
Shaohua Li 已提交
592

593
	/* Setup initial Clock PM state */
594 595
	pcie_clkpm_cap_init(link, blacklist);
	pcie_set_clkpm(link, policy_to_clkpm_state(link));
596
unlock:
S
Shaohua Li 已提交
597 598 599 600 601
	mutex_unlock(&aspm_lock);
out:
	up_read(&pci_bus_sem);
}

602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
/* Recheck latencies and update aspm_capable for links under the root */
static void pcie_update_aspm_capable(struct pcie_link_state *root)
{
	struct pcie_link_state *link;
	BUG_ON(root->parent);
	list_for_each_entry(link, &link_list, sibling) {
		if (link->root != root)
			continue;
		link->aspm_capable = link->aspm_support;
	}
	list_for_each_entry(link, &link_list, sibling) {
		struct pci_dev *child;
		struct pci_bus *linkbus = link->pdev->subordinate;
		if (link->root != root)
			continue;
		list_for_each_entry(child, &linkbus->devices, bus_list) {
			if ((child->pcie_type != PCI_EXP_TYPE_ENDPOINT) &&
			    (child->pcie_type != PCI_EXP_TYPE_LEG_END))
				continue;
			pcie_aspm_check_latency(child);
		}
	}
}

S
Shaohua Li 已提交
626 627 628 629
/* @pdev: the endpoint device */
void pcie_aspm_exit_link_state(struct pci_dev *pdev)
{
	struct pci_dev *parent = pdev->bus->self;
630
	struct pcie_link_state *link, *root, *parent_link;
S
Shaohua Li 已提交
631

632
	if (aspm_disabled || !pdev->is_pcie || !parent || !parent->link_state)
S
Shaohua Li 已提交
633
		return;
634 635
	if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
	    (parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
S
Shaohua Li 已提交
636
		return;
637

S
Shaohua Li 已提交
638 639 640 641
	down_read(&pci_bus_sem);
	mutex_lock(&aspm_lock);
	/*
	 * All PCIe functions are in one slot, remove one function will remove
642
	 * the whole slot, so just wait until we are the last function left.
S
Shaohua Li 已提交
643
	 */
644
	if (!list_is_last(&pdev->bus_list, &parent->subordinate->devices))
S
Shaohua Li 已提交
645 646
		goto out;

647
	link = parent->link_state;
648
	root = link->root;
649
	parent_link = link->parent;
650

S
Shaohua Li 已提交
651
	/* All functions are removed, so just disable ASPM for the link */
652
	pcie_config_aspm_link(link, 0);
653 654
	list_del(&link->sibling);
	list_del(&link->link);
S
Shaohua Li 已提交
655
	/* Clock PM is for endpoint device */
656
	free_link_state(link);
657 658 659

	/* Recheck latencies and configure upstream links */
	pcie_update_aspm_capable(root);
660
	pcie_config_aspm_path(parent_link);
S
Shaohua Li 已提交
661 662 663 664 665 666 667 668
out:
	mutex_unlock(&aspm_lock);
	up_read(&pci_bus_sem);
}

/* @pdev: the root port or switch downstream port */
void pcie_aspm_pm_state_change(struct pci_dev *pdev)
{
669
	struct pcie_link_state *link = pdev->link_state;
S
Shaohua Li 已提交
670

671
	if (aspm_disabled || !pdev->is_pcie || !link)
S
Shaohua Li 已提交
672
		return;
673 674
	if ((pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
	    (pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
S
Shaohua Li 已提交
675 676
		return;
	/*
677 678
	 * Devices changed PM state, we should recheck if latency
	 * meets all functions' requirement
S
Shaohua Li 已提交
679
	 */
680 681 682
	down_read(&pci_bus_sem);
	mutex_lock(&aspm_lock);
	pcie_update_aspm_capable(link->root);
683
	pcie_config_aspm_path(link);
684 685
	mutex_unlock(&aspm_lock);
	up_read(&pci_bus_sem);
S
Shaohua Li 已提交
686 687 688 689 690 691 692 693 694
}

/*
 * pci_disable_link_state - disable pci device's link state, so the link will
 * never enter specific states
 */
void pci_disable_link_state(struct pci_dev *pdev, int state)
{
	struct pci_dev *parent = pdev->bus->self;
695
	struct pcie_link_state *link;
S
Shaohua Li 已提交
696 697 698 699 700 701 702 703 704 705 706

	if (aspm_disabled || !pdev->is_pcie)
		return;
	if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
	    pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)
		parent = pdev;
	if (!parent || !parent->link_state)
		return;

	down_read(&pci_bus_sem);
	mutex_lock(&aspm_lock);
707
	link = parent->link_state;
708 709 710 711
	if (state & PCIE_LINK_STATE_L0S)
		link->aspm_disable |= ASPM_STATE_L0S;
	if (state & PCIE_LINK_STATE_L1)
		link->aspm_disable |= ASPM_STATE_L1;
712 713
	pcie_config_aspm_link(link, policy_to_aspm_state(link));

K
Kenji Kaneshige 已提交
714
	if (state & PCIE_LINK_STATE_CLKPM) {
715 716
		link->clkpm_capable = 0;
		pcie_set_clkpm(link, 0);
K
Kenji Kaneshige 已提交
717
	}
S
Shaohua Li 已提交
718 719 720 721 722 723 724 725
	mutex_unlock(&aspm_lock);
	up_read(&pci_bus_sem);
}
EXPORT_SYMBOL(pci_disable_link_state);

static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp)
{
	int i;
726
	struct pcie_link_state *link;
S
Shaohua Li 已提交
727 728 729 730 731 732 733 734 735 736 737 738

	for (i = 0; i < ARRAY_SIZE(policy_str); i++)
		if (!strncmp(val, policy_str[i], strlen(policy_str[i])))
			break;
	if (i >= ARRAY_SIZE(policy_str))
		return -EINVAL;
	if (i == aspm_policy)
		return 0;

	down_read(&pci_bus_sem);
	mutex_lock(&aspm_lock);
	aspm_policy = i;
739 740 741
	list_for_each_entry(link, &link_list, sibling) {
		pcie_config_aspm_link(link, policy_to_aspm_state(link));
		pcie_set_clkpm(link, policy_to_clkpm_state(link));
S
Shaohua Li 已提交
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769
	}
	mutex_unlock(&aspm_lock);
	up_read(&pci_bus_sem);
	return 0;
}

static int pcie_aspm_get_policy(char *buffer, struct kernel_param *kp)
{
	int i, cnt = 0;
	for (i = 0; i < ARRAY_SIZE(policy_str); i++)
		if (i == aspm_policy)
			cnt += sprintf(buffer + cnt, "[%s] ", policy_str[i]);
		else
			cnt += sprintf(buffer + cnt, "%s ", policy_str[i]);
	return cnt;
}

module_param_call(policy, pcie_aspm_set_policy, pcie_aspm_get_policy,
	NULL, 0644);

#ifdef CONFIG_PCIEASPM_DEBUG
static ssize_t link_state_show(struct device *dev,
		struct device_attribute *attr,
		char *buf)
{
	struct pci_dev *pci_device = to_pci_dev(dev);
	struct pcie_link_state *link_state = pci_device->link_state;

770
	return sprintf(buf, "%d\n", link_state->aspm_enabled);
S
Shaohua Li 已提交
771 772 773 774 775 776 777
}

static ssize_t link_state_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf,
		size_t n)
{
778
	struct pci_dev *pdev = to_pci_dev(dev);
779
	struct pcie_link_state *link, *root = pdev->link_state->root;
780
	u32 val = buf[0] - '0', state = 0;
S
Shaohua Li 已提交
781

782
	if (n < 1 || val > 3)
S
Shaohua Li 已提交
783 784
		return -EINVAL;

785 786 787 788 789 790
	/* Convert requested state to ASPM state */
	if (val & PCIE_LINK_STATE_L0S)
		state |= ASPM_STATE_L0S;
	if (val & PCIE_LINK_STATE_L1)
		state |= ASPM_STATE_L1;

791 792 793 794 795 796 797 798 799 800
	down_read(&pci_bus_sem);
	mutex_lock(&aspm_lock);
	list_for_each_entry(link, &link_list, sibling) {
		if (link->root != root)
			continue;
		pcie_config_aspm_link(link, state);
	}
	mutex_unlock(&aspm_lock);
	up_read(&pci_bus_sem);
	return n;
S
Shaohua Li 已提交
801 802 803 804 805 806 807 808 809
}

static ssize_t clk_ctl_show(struct device *dev,
		struct device_attribute *attr,
		char *buf)
{
	struct pci_dev *pci_device = to_pci_dev(dev);
	struct pcie_link_state *link_state = pci_device->link_state;

810
	return sprintf(buf, "%d\n", link_state->clkpm_enabled);
S
Shaohua Li 已提交
811 812 813 814 815 816 817
}

static ssize_t clk_ctl_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf,
		size_t n)
{
K
Kenji Kaneshige 已提交
818
	struct pci_dev *pdev = to_pci_dev(dev);
S
Shaohua Li 已提交
819 820 821 822 823 824 825 826
	int state;

	if (n < 1)
		return -EINVAL;
	state = buf[0]-'0';

	down_read(&pci_bus_sem);
	mutex_lock(&aspm_lock);
K
Kenji Kaneshige 已提交
827
	pcie_set_clkpm_nocheck(pdev->link_state, !!state);
S
Shaohua Li 已提交
828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845
	mutex_unlock(&aspm_lock);
	up_read(&pci_bus_sem);

	return n;
}

static DEVICE_ATTR(link_state, 0644, link_state_show, link_state_store);
static DEVICE_ATTR(clk_ctl, 0644, clk_ctl_show, clk_ctl_store);

static char power_group[] = "power";
void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev)
{
	struct pcie_link_state *link_state = pdev->link_state;

	if (!pdev->is_pcie || (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
		pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state)
		return;

846
	if (link_state->aspm_support)
S
Shaohua Li 已提交
847 848
		sysfs_add_file_to_group(&pdev->dev.kobj,
			&dev_attr_link_state.attr, power_group);
849
	if (link_state->clkpm_capable)
S
Shaohua Li 已提交
850 851 852 853 854 855 856 857 858 859 860 861
		sysfs_add_file_to_group(&pdev->dev.kobj,
			&dev_attr_clk_ctl.attr, power_group);
}

void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev)
{
	struct pcie_link_state *link_state = pdev->link_state;

	if (!pdev->is_pcie || (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
		pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state)
		return;

862
	if (link_state->aspm_support)
S
Shaohua Li 已提交
863 864
		sysfs_remove_file_from_group(&pdev->dev.kobj,
			&dev_attr_link_state.attr, power_group);
865
	if (link_state->clkpm_capable)
S
Shaohua Li 已提交
866 867 868 869 870 871 872
		sysfs_remove_file_from_group(&pdev->dev.kobj,
			&dev_attr_clk_ctl.attr, power_group);
}
#endif

static int __init pcie_aspm_disable(char *str)
{
873 874 875 876 877 878 879
	if (!strcmp(str, "off")) {
		aspm_disabled = 1;
		printk(KERN_INFO "PCIe ASPM is disabled\n");
	} else if (!strcmp(str, "force")) {
		aspm_force = 1;
		printk(KERN_INFO "PCIe ASPM is forcedly enabled\n");
	}
S
Shaohua Li 已提交
880 881 882
	return 1;
}

883
__setup("pcie_aspm=", pcie_aspm_disable);
S
Shaohua Li 已提交
884

885 886
void pcie_no_aspm(void)
{
887 888
	if (!aspm_force)
		aspm_disabled = 1;
889 890
}

891 892 893 894 895 896 897
/**
 * pcie_aspm_enabled - is PCIe ASPM enabled?
 *
 * Returns true if ASPM has not been disabled by the command-line option
 * pcie_aspm=off.
 **/
int pcie_aspm_enabled(void)
S
Shaohua Li 已提交
898
{
899
       return !aspm_disabled;
S
Shaohua Li 已提交
900
}
901
EXPORT_SYMBOL(pcie_aspm_enabled);
S
Shaohua Li 已提交
902