aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>2009-08-18 22:01:37 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-09-09 16:29:48 -0400
commitb7206cbf024dd43c42f9585e2017db1c1facd566 (patch)
treecf84dccb916f90e445c08b244939a25203874aec /drivers
parent07d92760d2ee542fe932f4e8b5807dd98481d1fd (diff)
PCI ASPM: support partial aspm enablement
In the current implementation, ASPM L0s/L1 is disabled for all links in the hierarchy if one of the link doesn't meet latency requirement. But we can partially enable ASPM L0s/L1 on sub-tree in the hierarchy. This patch allows partial L0s/L1 enablement in the hierarchy. And it also reduce the calculation cost of ASPM configuration very much. In the previous implementation, all links were enabled with the same state. With this patch, enabled state for each link is determined simply as follows (the 'requested' is from policy_to_aspm_state()). enabled = requested & (link->aspm_capable & link->aspm_disable) 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')
-rw-r--r--drivers/pci/pcie/aspm.c211
1 files changed, 47 insertions, 164 deletions
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 79f6d61798fa..08d293f60fe8 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -166,18 +166,6 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist)
166 link->clkpm_capable = (blacklist) ? 0 : capable; 166 link->clkpm_capable = (blacklist) ? 0 : capable;
167} 167}
168 168
169static bool pcie_aspm_downstream_has_switch(struct pcie_link_state *link)
170{
171 struct pci_dev *child;
172 struct pci_bus *linkbus = link->pdev->subordinate;
173
174 list_for_each_entry(child, &linkbus->devices, bus_list) {
175 if (child->pcie_type == PCI_EXP_TYPE_UPSTREAM)
176 return true;
177 }
178 return false;
179}
180
181/* 169/*
182 * pcie_aspm_configure_common_clock: check if the 2 ends of a link 170 * pcie_aspm_configure_common_clock: check if the 2 ends of a link
183 * could use common clock. If they are, configure them to use the 171 * could use common clock. If they are, configure them to use the
@@ -397,10 +385,7 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
397 } 385 }
398 } 386 }
399 387
400 if (!link->aspm_support) 388 /* Get and check endpoint acceptable latencies */
401 return;
402
403 /* ENDPOINT states*/
404 list_for_each_entry(child, &linkbus->devices, bus_list) { 389 list_for_each_entry(child, &linkbus->devices, bus_list) {
405 int pos; 390 int pos;
406 u32 reg32, encoding; 391 u32 reg32, encoding;
@@ -424,58 +409,7 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
424 } 409 }
425} 410}
426 411
427/** 412static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 state)
428 * __pcie_aspm_check_state_one - check latency for endpoint device.
429 * @endpoint: pointer to the struct pci_dev of endpoint device
430 *
431 * TBD: The latency from the endpoint to root complex vary per switch's
432 * upstream link state above the device. Here we just do a simple check
433 * which assumes all links above the device can be in L1 state, that
434 * is we just consider the worst case. If switch's upstream link can't
435 * be put into L0S/L1, then our check is too strictly.
436 */
437static u32 __pcie_aspm_check_state_one(struct pci_dev *endpoint, u32 state)
438{
439 struct pcie_link_state *link = endpoint->bus->self->link_state;
440 while (link && state) {
441 state &= link->aspm_capable;
442 link = link->parent;
443 }
444 return state;
445}
446
447static u32 pcie_aspm_check_state(struct pcie_link_state *link, u32 state)
448{
449 pci_power_t power_state;
450 struct pci_dev *child;
451 struct pci_bus *linkbus = link->pdev->subordinate;
452
453 /* If no child, ignore the link */
454 if (list_empty(&linkbus->devices))
455 return state;
456
457 list_for_each_entry(child, &linkbus->devices, bus_list) {
458 /*
459 * If downstream component of a link is pci bridge, we
460 * disable ASPM for now for the link
461 */
462 if (child->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE)
463 return 0;
464
465 if ((child->pcie_type != PCI_EXP_TYPE_ENDPOINT &&
466 child->pcie_type != PCI_EXP_TYPE_LEG_END))
467 continue;
468 /* Device not in D0 doesn't need check latency */
469 power_state = child->current_state;
470 if (power_state == PCI_D1 || power_state == PCI_D2 ||
471 power_state == PCI_D3hot || power_state == PCI_D3cold)
472 continue;
473 state = __pcie_aspm_check_state_one(child, state);
474 }
475 return state;
476}
477
478static void __pcie_aspm_config_one_dev(struct pci_dev *pdev, unsigned int state)
479{ 413{
480 u16 reg16; 414 u16 reg16;
481 int pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); 415 int pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
@@ -486,13 +420,13 @@ static void __pcie_aspm_config_one_dev(struct pci_dev *pdev, unsigned int state)
486 pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); 420 pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16);
487} 421}
488 422
489static void __pcie_aspm_config_link(struct pcie_link_state *link, u32 state) 423static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state)
490{ 424{
491 struct pci_dev *child, *parent = link->pdev; 425 struct pci_dev *child, *parent = link->pdev;
492 struct pci_bus *linkbus = parent->subordinate; 426 struct pci_bus *linkbus = parent->subordinate;
493 427
494 state &= ~link->aspm_disable;
495 /* Nothing to do if the link is already in the requested state */ 428 /* Nothing to do if the link is already in the requested state */
429 state &= (link->aspm_capable & ~link->aspm_disable);
496 if (link->aspm_enabled == state) 430 if (link->aspm_enabled == state)
497 return; 431 return;
498 /* 432 /*
@@ -502,66 +436,25 @@ static void __pcie_aspm_config_link(struct pcie_link_state *link, u32 state)
502 * versa for disabling ASPM L1. Spec doesn't mention L0S. 436 * versa for disabling ASPM L1. Spec doesn't mention L0S.
503 */ 437 */
504 if (state & PCIE_LINK_STATE_L1) 438 if (state & PCIE_LINK_STATE_L1)
505 __pcie_aspm_config_one_dev(parent, state); 439 pcie_config_aspm_dev(parent, state);
506 440
507 list_for_each_entry(child, &linkbus->devices, bus_list) 441 list_for_each_entry(child, &linkbus->devices, bus_list)
508 __pcie_aspm_config_one_dev(child, state); 442 pcie_config_aspm_dev(child, state);
509 443
510 if (!(state & PCIE_LINK_STATE_L1)) 444 if (!(state & PCIE_LINK_STATE_L1))
511 __pcie_aspm_config_one_dev(parent, state); 445 pcie_config_aspm_dev(parent, state);
512 446
513 link->aspm_enabled = state; 447 link->aspm_enabled = state;
514} 448}
515 449
516/* Check the whole hierarchy, and configure each link in the hierarchy */ 450static void pcie_config_aspm_path(struct pcie_link_state *link)
517static void __pcie_aspm_configure_link_state(struct pcie_link_state *link,
518 u32 state)
519{ 451{
520 struct pcie_link_state *leaf, *root = link->root; 452 while (link) {
521 453 pcie_config_aspm_link(link, policy_to_aspm_state(link));
522 state &= (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); 454 link = link->parent;
523
524 /* Check all links who have specific root port link */
525 list_for_each_entry(leaf, &link_list, sibling) {
526 if (!list_empty(&leaf->children) || (leaf->root != root))
527 continue;
528 state = pcie_aspm_check_state(leaf, state);
529 }
530 /* Check root port link too in case it hasn't children */
531 state = pcie_aspm_check_state(root, state);
532 if (link->aspm_enabled == state)
533 return;
534 /*
535 * We must change the hierarchy. See comments in
536 * __pcie_aspm_config_link for the order
537 **/
538 if (state & PCIE_LINK_STATE_L1) {
539 list_for_each_entry(leaf, &link_list, sibling) {
540 if (leaf->root == root)
541 __pcie_aspm_config_link(leaf, state);
542 }
543 } else {
544 list_for_each_entry_reverse(leaf, &link_list, sibling) {
545 if (leaf->root == root)
546 __pcie_aspm_config_link(leaf, state);
547 }
548 } 455 }
549} 456}
550 457
551/*
552 * pcie_aspm_configure_link_state: enable/disable PCI express link state
553 * @pdev: the root port or switch downstream port
554 */
555static void pcie_aspm_configure_link_state(struct pcie_link_state *link,
556 u32 state)
557{
558 down_read(&pci_bus_sem);
559 mutex_lock(&aspm_lock);
560 __pcie_aspm_configure_link_state(link, state);
561 mutex_unlock(&aspm_lock);
562 up_read(&pci_bus_sem);
563}
564
565static void free_link_state(struct pcie_link_state *link) 458static void free_link_state(struct pcie_link_state *link)
566{ 459{
567 link->pdev->link_state = NULL; 460 link->pdev->link_state = NULL;
@@ -596,10 +489,9 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev)
596 return 0; 489 return 0;
597} 490}
598 491
599static struct pcie_link_state *pcie_aspm_setup_link_state(struct pci_dev *pdev) 492static struct pcie_link_state *alloc_pcie_link_state(struct pci_dev *pdev)
600{ 493{
601 struct pcie_link_state *link; 494 struct pcie_link_state *link;
602 int blacklist = !!pcie_aspm_sanity_check(pdev);
603 495
604 link = kzalloc(sizeof(*link), GFP_KERNEL); 496 link = kzalloc(sizeof(*link), GFP_KERNEL);
605 if (!link) 497 if (!link)
@@ -625,15 +517,7 @@ static struct pcie_link_state *pcie_aspm_setup_link_state(struct pci_dev *pdev)
625 link->root = link->parent->root; 517 link->root = link->parent->root;
626 518
627 list_add(&link->sibling, &link_list); 519 list_add(&link->sibling, &link_list);
628
629 pdev->link_state = link; 520 pdev->link_state = link;
630
631 /* Check ASPM capability */
632 pcie_aspm_cap_init(link, blacklist);
633
634 /* Check Clock PM capability */
635 pcie_clkpm_cap_init(link, blacklist);
636
637 return link; 521 return link;
638} 522}
639 523
@@ -644,8 +528,8 @@ static struct pcie_link_state *pcie_aspm_setup_link_state(struct pci_dev *pdev)
644 */ 528 */
645void pcie_aspm_init_link_state(struct pci_dev *pdev) 529void pcie_aspm_init_link_state(struct pci_dev *pdev)
646{ 530{
647 u32 state;
648 struct pcie_link_state *link; 531 struct pcie_link_state *link;
532 int blacklist = !!pcie_aspm_sanity_check(pdev);
649 533
650 if (aspm_disabled || !pdev->is_pcie || pdev->link_state) 534 if (aspm_disabled || !pdev->is_pcie || pdev->link_state)
651 return; 535 return;
@@ -663,27 +547,20 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
663 goto out; 547 goto out;
664 548
665 mutex_lock(&aspm_lock); 549 mutex_lock(&aspm_lock);
666 link = pcie_aspm_setup_link_state(pdev); 550 link = alloc_pcie_link_state(pdev);
667 if (!link) 551 if (!link)
668 goto unlock; 552 goto unlock;
669 /* 553 /*
670 * Setup initial ASPM state 554 * Setup initial ASPM state. Note that we need to configure
671 * 555 * upstream links also because capable state of them can be
672 * If link has switch, delay the link config. The leaf link 556 * update through pcie_aspm_cap_init().
673 * initialization will config the whole hierarchy. But we must
674 * make sure BIOS doesn't set unsupported link state.
675 */ 557 */
676 if (pcie_aspm_downstream_has_switch(link)) { 558 pcie_aspm_cap_init(link, blacklist);
677 state = pcie_aspm_check_state(link, link->aspm_default); 559 pcie_config_aspm_path(link);
678 __pcie_aspm_config_link(link, state);
679 } else {
680 state = policy_to_aspm_state(link);
681 __pcie_aspm_configure_link_state(link, state);
682 }
683 560
684 /* Setup initial Clock PM state */ 561 /* Setup initial Clock PM state */
685 state = (link->clkpm_capable) ? policy_to_clkpm_state(link) : 0; 562 pcie_clkpm_cap_init(link, blacklist);
686 pcie_set_clkpm(link, state); 563 pcie_set_clkpm(link, policy_to_clkpm_state(link));
687unlock: 564unlock:
688 mutex_unlock(&aspm_lock); 565 mutex_unlock(&aspm_lock);
689out: 566out:
@@ -718,12 +595,12 @@ static void pcie_update_aspm_capable(struct pcie_link_state *root)
718void pcie_aspm_exit_link_state(struct pci_dev *pdev) 595void pcie_aspm_exit_link_state(struct pci_dev *pdev)
719{ 596{
720 struct pci_dev *parent = pdev->bus->self; 597 struct pci_dev *parent = pdev->bus->self;
721 struct pcie_link_state *link, *root; 598 struct pcie_link_state *link, *root, *parent_link;
722 599
723 if (aspm_disabled || !pdev->is_pcie || !parent || !parent->link_state) 600 if (aspm_disabled || !pdev->is_pcie || !parent || !parent->link_state)
724 return; 601 return;
725 if (parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT && 602 if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
726 parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) 603 (parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
727 return; 604 return;
728 605
729 down_read(&pci_bus_sem); 606 down_read(&pci_bus_sem);
@@ -737,9 +614,10 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
737 614
738 link = parent->link_state; 615 link = parent->link_state;
739 root = link->root; 616 root = link->root;
617 parent_link = link->parent;
740 618
741 /* All functions are removed, so just disable ASPM for the link */ 619 /* All functions are removed, so just disable ASPM for the link */
742 __pcie_aspm_config_one_dev(parent, 0); 620 pcie_config_aspm_link(link, 0);
743 list_del(&link->sibling); 621 list_del(&link->sibling);
744 list_del(&link->link); 622 list_del(&link->link);
745 /* Clock PM is for endpoint device */ 623 /* Clock PM is for endpoint device */
@@ -747,6 +625,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
747 625
748 /* Recheck latencies and configure upstream links */ 626 /* Recheck latencies and configure upstream links */
749 pcie_update_aspm_capable(root); 627 pcie_update_aspm_capable(root);
628 pcie_config_aspm_path(parent_link);
750out: 629out:
751 mutex_unlock(&aspm_lock); 630 mutex_unlock(&aspm_lock);
752 up_read(&pci_bus_sem); 631 up_read(&pci_bus_sem);
@@ -769,7 +648,7 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev)
769 down_read(&pci_bus_sem); 648 down_read(&pci_bus_sem);
770 mutex_lock(&aspm_lock); 649 mutex_lock(&aspm_lock);
771 pcie_update_aspm_capable(link->root); 650 pcie_update_aspm_capable(link->root);
772 __pcie_aspm_configure_link_state(link, link->aspm_enabled); 651 pcie_config_aspm_path(link);
773 mutex_unlock(&aspm_lock); 652 mutex_unlock(&aspm_lock);
774 up_read(&pci_bus_sem); 653 up_read(&pci_bus_sem);
775} 654}
@@ -795,7 +674,8 @@ void pci_disable_link_state(struct pci_dev *pdev, int state)
795 mutex_lock(&aspm_lock); 674 mutex_lock(&aspm_lock);
796 link = parent->link_state; 675 link = parent->link_state;
797 link->aspm_disable |= state; 676 link->aspm_disable |= state;
798 __pcie_aspm_configure_link_state(link, link->aspm_enabled); 677 pcie_config_aspm_link(link, policy_to_aspm_state(link));
678
799 if (state & PCIE_LINK_STATE_CLKPM) { 679 if (state & PCIE_LINK_STATE_CLKPM) {
800 link->clkpm_capable = 0; 680 link->clkpm_capable = 0;
801 pcie_set_clkpm(link, 0); 681 pcie_set_clkpm(link, 0);
@@ -808,7 +688,7 @@ EXPORT_SYMBOL(pci_disable_link_state);
808static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) 688static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp)
809{ 689{
810 int i; 690 int i;
811 struct pcie_link_state *link_state; 691 struct pcie_link_state *link;
812 692
813 for (i = 0; i < ARRAY_SIZE(policy_str); i++) 693 for (i = 0; i < ARRAY_SIZE(policy_str); i++)
814 if (!strncmp(val, policy_str[i], strlen(policy_str[i]))) 694 if (!strncmp(val, policy_str[i], strlen(policy_str[i])))
@@ -821,10 +701,9 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp)
821 down_read(&pci_bus_sem); 701 down_read(&pci_bus_sem);
822 mutex_lock(&aspm_lock); 702 mutex_lock(&aspm_lock);
823 aspm_policy = i; 703 aspm_policy = i;
824 list_for_each_entry(link_state, &link_list, sibling) { 704 list_for_each_entry(link, &link_list, sibling) {
825 __pcie_aspm_configure_link_state(link_state, 705 pcie_config_aspm_link(link, policy_to_aspm_state(link));
826 policy_to_aspm_state(link_state)); 706 pcie_set_clkpm(link, policy_to_clkpm_state(link));
827 pcie_set_clkpm(link_state, policy_to_clkpm_state(link_state));
828 } 707 }
829 mutex_unlock(&aspm_lock); 708 mutex_unlock(&aspm_lock);
830 up_read(&pci_bus_sem); 709 up_read(&pci_bus_sem);
@@ -862,18 +741,22 @@ static ssize_t link_state_store(struct device *dev,
862 size_t n) 741 size_t n)
863{ 742{
864 struct pci_dev *pdev = to_pci_dev(dev); 743 struct pci_dev *pdev = to_pci_dev(dev);
865 int state; 744 struct pcie_link_state *link, *root = pdev->link_state->root;
745 u32 state = buf[0] - '0';
866 746
867 if (n < 1) 747 if (n < 1 || state > 3)
868 return -EINVAL; 748 return -EINVAL;
869 state = buf[0]-'0';
870 if (state >= 0 && state <= 3) {
871 /* setup link aspm state */
872 pcie_aspm_configure_link_state(pdev->link_state, state);
873 return n;
874 }
875 749
876 return -EINVAL; 750 down_read(&pci_bus_sem);
751 mutex_lock(&aspm_lock);
752 list_for_each_entry(link, &link_list, sibling) {
753 if (link->root != root)
754 continue;
755 pcie_config_aspm_link(link, state);
756 }
757 mutex_unlock(&aspm_lock);
758 up_read(&pci_bus_sem);
759 return n;
877} 760}
878 761
879static ssize_t clk_ctl_show(struct device *dev, 762static ssize_t clk_ctl_show(struct device *dev,