aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>2009-08-18 22:00:25 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-09-09 16:29:47 -0400
commit07d92760d2ee542fe932f4e8b5807dd98481d1fd (patch)
tree47d94230d73567b16f9c9a307d1c8f08eff47184 /drivers/pci
parentf1c0ca29ae72bc0c10282eada66c8a792ee98482 (diff)
PCI ASPM: introduce capable flag
Introduce 'aspm_capable' field to maintain the capable ASPM setting of the link. By the 'aspm_capable', we don't need to recheck latency every time ASPM policy is changed. Each bit in 'aspm_capable' is associated to ASPM state (L0S/L1). The bit is set if the associated ASPM state is supported by the link and it satisfies the latency requirement (i.e. exit latency < endpoint acceptable latency). The 'aspm_capable' is updated when - an endpoint device is added (boot time or hot-plug time) - an endpoint device is removed (hot-unplug time) - PCI power state is changed. Acked-by: Shaohua Li <shaohua.li@intel.com> Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/pcie/aspm.c117
1 files changed, 86 insertions, 31 deletions
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 8f7884a8bc2..79f6d61798f 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -42,6 +42,7 @@ struct pcie_link_state {
42 /* ASPM state */ 42 /* ASPM state */
43 u32 aspm_support:2; /* Supported ASPM state */ 43 u32 aspm_support:2; /* Supported ASPM state */
44 u32 aspm_enabled:2; /* Enabled ASPM state */ 44 u32 aspm_enabled:2; /* Enabled ASPM state */
45 u32 aspm_capable:2; /* Capable ASPM state with latency */
45 u32 aspm_default:2; /* Default ASPM state by BIOS */ 46 u32 aspm_default:2; /* Default ASPM state by BIOS */
46 u32 aspm_disable:2; /* Disabled ASPM state */ 47 u32 aspm_disable:2; /* Disabled ASPM state */
47 48
@@ -316,6 +317,39 @@ static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state,
316 *enabled = reg16 & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); 317 *enabled = reg16 & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
317} 318}
318 319
320static void pcie_aspm_check_latency(struct pci_dev *endpoint)
321{
322 u32 l1_switch_latency = 0;
323 struct aspm_latency *acceptable;
324 struct pcie_link_state *link;
325
326 /* Device not in D0 doesn't need latency check */
327 if ((endpoint->current_state != PCI_D0) &&
328 (endpoint->current_state != PCI_UNKNOWN))
329 return;
330
331 link = endpoint->bus->self->link_state;
332 acceptable = &link->acceptable[PCI_FUNC(endpoint->devfn)];
333
334 while (link) {
335 /* Check L0s latency */
336 if ((link->aspm_capable & PCIE_LINK_STATE_L0S) &&
337 (link->latency.l0s > acceptable->l0s))
338 link->aspm_capable &= ~PCIE_LINK_STATE_L0S;
339 /*
340 * Check L1 latency.
341 * Every switch on the path to root complex need 1
342 * more microsecond for L1. Spec doesn't mention L0s.
343 */
344 if ((link->aspm_capable & PCIE_LINK_STATE_L1) &&
345 (link->latency.l1 + l1_switch_latency > acceptable->l1))
346 link->aspm_capable &= ~PCIE_LINK_STATE_L1;
347 l1_switch_latency += 1000;
348
349 link = link->parent;
350 }
351}
352
319static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) 353static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
320{ 354{
321 u32 support, l0s, l1, enabled; 355 u32 support, l0s, l1, enabled;
@@ -348,6 +382,9 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
348 382
349 /* Save default state */ 383 /* Save default state */
350 link->aspm_default = link->aspm_enabled; 384 link->aspm_default = link->aspm_enabled;
385
386 /* Setup initial capable state. Will be updated later */
387 link->aspm_capable = link->aspm_support;
351 /* 388 /*
352 * If the downstream component has pci bridge function, don't 389 * If the downstream component has pci bridge function, don't
353 * do ASPM for now. 390 * do ASPM for now.
@@ -376,12 +413,14 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
376 413
377 pos = pci_find_capability(child, PCI_CAP_ID_EXP); 414 pos = pci_find_capability(child, PCI_CAP_ID_EXP);
378 pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, &reg32); 415 pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, &reg32);
416 /* Calculate endpoint L0s acceptable latency */
379 encoding = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; 417 encoding = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6;
380 acceptable->l0s = calc_l0s_acceptable(encoding); 418 acceptable->l0s = calc_l0s_acceptable(encoding);
381 if (link->aspm_support & PCIE_LINK_STATE_L1) { 419 /* Calculate endpoint L1 acceptable latency */
382 encoding = (reg32 & PCI_EXP_DEVCAP_L1) >> 9; 420 encoding = (reg32 & PCI_EXP_DEVCAP_L1) >> 9;
383 acceptable->l1 = calc_l1_acceptable(encoding); 421 acceptable->l1 = calc_l1_acceptable(encoding);
384 } 422
423 pcie_aspm_check_latency(child);
385 } 424 }
386} 425}
387 426
@@ -397,27 +436,10 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
397 */ 436 */
398static u32 __pcie_aspm_check_state_one(struct pci_dev *endpoint, u32 state) 437static u32 __pcie_aspm_check_state_one(struct pci_dev *endpoint, u32 state)
399{ 438{
400 u32 l1_switch_latency = 0; 439 struct pcie_link_state *link = endpoint->bus->self->link_state;
401 struct aspm_latency *acceptable;
402 struct pcie_link_state *link;
403
404 link = endpoint->bus->self->link_state;
405 state &= link->aspm_support;
406 acceptable = &link->acceptable[PCI_FUNC(endpoint->devfn)];
407
408 while (link && state) { 440 while (link && state) {
409 if ((state & PCIE_LINK_STATE_L0S) && 441 state &= link->aspm_capable;
410 (link->latency.l0s > acceptable->l0s))
411 state &= ~PCIE_LINK_STATE_L0S;
412 if ((state & PCIE_LINK_STATE_L1) &&
413 (link->latency.l1 + l1_switch_latency > acceptable->l1))
414 state &= ~PCIE_LINK_STATE_L1;
415 link = link->parent; 442 link = link->parent;
416 /*
417 * Every switch on the path to root complex need 1
418 * more microsecond for L1. Spec doesn't mention L0s.
419 */
420 l1_switch_latency += 1000;
421 } 443 }
422 return state; 444 return state;
423} 445}
@@ -668,11 +690,35 @@ out:
668 up_read(&pci_bus_sem); 690 up_read(&pci_bus_sem);
669} 691}
670 692
693/* Recheck latencies and update aspm_capable for links under the root */
694static void pcie_update_aspm_capable(struct pcie_link_state *root)
695{
696 struct pcie_link_state *link;
697 BUG_ON(root->parent);
698 list_for_each_entry(link, &link_list, sibling) {
699 if (link->root != root)
700 continue;
701 link->aspm_capable = link->aspm_support;
702 }
703 list_for_each_entry(link, &link_list, sibling) {
704 struct pci_dev *child;
705 struct pci_bus *linkbus = link->pdev->subordinate;
706 if (link->root != root)
707 continue;
708 list_for_each_entry(child, &linkbus->devices, bus_list) {
709 if ((child->pcie_type != PCI_EXP_TYPE_ENDPOINT) &&
710 (child->pcie_type != PCI_EXP_TYPE_LEG_END))
711 continue;
712 pcie_aspm_check_latency(child);
713 }
714 }
715}
716
671/* @pdev: the endpoint device */ 717/* @pdev: the endpoint device */
672void pcie_aspm_exit_link_state(struct pci_dev *pdev) 718void pcie_aspm_exit_link_state(struct pci_dev *pdev)
673{ 719{
674 struct pci_dev *parent = pdev->bus->self; 720 struct pci_dev *parent = pdev->bus->self;
675 struct pcie_link_state *link; 721 struct pcie_link_state *link, *root;
676 722
677 if (aspm_disabled || !pdev->is_pcie || !parent || !parent->link_state) 723 if (aspm_disabled || !pdev->is_pcie || !parent || !parent->link_state)
678 return; 724 return;
@@ -690,6 +736,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
690 goto out; 736 goto out;
691 737
692 link = parent->link_state; 738 link = parent->link_state;
739 root = link->root;
693 740
694 /* All functions are removed, so just disable ASPM for the link */ 741 /* All functions are removed, so just disable ASPM for the link */
695 __pcie_aspm_config_one_dev(parent, 0); 742 __pcie_aspm_config_one_dev(parent, 0);
@@ -697,6 +744,9 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
697 list_del(&link->link); 744 list_del(&link->link);
698 /* Clock PM is for endpoint device */ 745 /* Clock PM is for endpoint device */
699 free_link_state(link); 746 free_link_state(link);
747
748 /* Recheck latencies and configure upstream links */
749 pcie_update_aspm_capable(root);
700out: 750out:
701 mutex_unlock(&aspm_lock); 751 mutex_unlock(&aspm_lock);
702 up_read(&pci_bus_sem); 752 up_read(&pci_bus_sem);
@@ -705,18 +755,23 @@ out:
705/* @pdev: the root port or switch downstream port */ 755/* @pdev: the root port or switch downstream port */
706void pcie_aspm_pm_state_change(struct pci_dev *pdev) 756void pcie_aspm_pm_state_change(struct pci_dev *pdev)
707{ 757{
708 struct pcie_link_state *link_state = pdev->link_state; 758 struct pcie_link_state *link = pdev->link_state;
709 759
710 if (aspm_disabled || !pdev->is_pcie || !pdev->link_state) 760 if (aspm_disabled || !pdev->is_pcie || !link)
711 return; 761 return;
712 if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && 762 if ((pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
713 pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) 763 (pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
714 return; 764 return;
715 /* 765 /*
716 * devices changed PM state, we should recheck if latency meets all 766 * Devices changed PM state, we should recheck if latency
717 * functions' requirement 767 * meets all functions' requirement
718 */ 768 */
719 pcie_aspm_configure_link_state(link_state, link_state->aspm_enabled); 769 down_read(&pci_bus_sem);
770 mutex_lock(&aspm_lock);
771 pcie_update_aspm_capable(link->root);
772 __pcie_aspm_configure_link_state(link, link->aspm_enabled);
773 mutex_unlock(&aspm_lock);
774 up_read(&pci_bus_sem);
720} 775}
721 776
722/* 777/*