aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pcie/aspm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/pcie/aspm.c')
-rw-r--r--drivers/pci/pcie/aspm.c125
1 files changed, 106 insertions, 19 deletions
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index e361c7dc726f..4d8e2c7b2ad1 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -33,6 +33,11 @@ struct endpoint_state {
33struct pcie_link_state { 33struct pcie_link_state {
34 struct list_head sibiling; 34 struct list_head sibiling;
35 struct pci_dev *pdev; 35 struct pci_dev *pdev;
36 bool downstream_has_switch;
37
38 struct pcie_link_state *parent;
39 struct list_head children;
40 struct list_head link;
36 41
37 /* ASPM state */ 42 /* ASPM state */
38 unsigned int support_state; 43 unsigned int support_state;
@@ -125,7 +130,7 @@ static void pcie_set_clock_pm(struct pci_dev *pdev, int enable)
125 link_state->clk_pm_enabled = !!enable; 130 link_state->clk_pm_enabled = !!enable;
126} 131}
127 132
128static void pcie_check_clock_pm(struct pci_dev *pdev) 133static void pcie_check_clock_pm(struct pci_dev *pdev, int blacklist)
129{ 134{
130 int pos; 135 int pos;
131 u32 reg32; 136 u32 reg32;
@@ -149,10 +154,26 @@ static void pcie_check_clock_pm(struct pci_dev *pdev)
149 if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN)) 154 if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN))
150 enabled = 0; 155 enabled = 0;
151 } 156 }
152 link_state->clk_pm_capable = capable;
153 link_state->clk_pm_enabled = enabled; 157 link_state->clk_pm_enabled = enabled;
154 link_state->bios_clk_state = enabled; 158 link_state->bios_clk_state = enabled;
155 pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); 159 if (!blacklist) {
160 link_state->clk_pm_capable = capable;
161 pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev));
162 } else {
163 link_state->clk_pm_capable = 0;
164 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;
156} 177}
157 178
158/* 179/*
@@ -419,9 +440,9 @@ static unsigned int pcie_aspm_check_state(struct pci_dev *pdev,
419{ 440{
420 struct pci_dev *child_dev; 441 struct pci_dev *child_dev;
421 442
422 /* If no child, disable the link */ 443 /* If no child, ignore the link */
423 if (list_empty(&pdev->subordinate->devices)) 444 if (list_empty(&pdev->subordinate->devices))
424 return 0; 445 return state;
425 list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { 446 list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
426 if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { 447 if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) {
427 /* 448 /*
@@ -462,6 +483,9 @@ static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state)
462 int valid = 1; 483 int valid = 1;
463 struct pcie_link_state *link_state = pdev->link_state; 484 struct pcie_link_state *link_state = pdev->link_state;
464 485
486 /* If no child, disable the link */
487 if (list_empty(&pdev->subordinate->devices))
488 state = 0;
465 /* 489 /*
466 * if the downstream component has pci bridge function, don't do ASPM 490 * if the downstream component has pci bridge function, don't do ASPM
467 * now 491 * now
@@ -493,20 +517,52 @@ static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state)
493 link_state->enabled_state = state; 517 link_state->enabled_state = state;
494} 518}
495 519
520static struct pcie_link_state *get_root_port_link(struct pcie_link_state *link)
521{
522 struct pcie_link_state *root_port_link = link;
523 while (root_port_link->parent)
524 root_port_link = root_port_link->parent;
525 return root_port_link;
526}
527
528/* check the whole hierarchy, and configure each link in the hierarchy */
496static void __pcie_aspm_configure_link_state(struct pci_dev *pdev, 529static void __pcie_aspm_configure_link_state(struct pci_dev *pdev,
497 unsigned int state) 530 unsigned int state)
498{ 531{
499 struct pcie_link_state *link_state = pdev->link_state; 532 struct pcie_link_state *link_state = pdev->link_state;
533 struct pcie_link_state *root_port_link = get_root_port_link(link_state);
534 struct pcie_link_state *leaf;
500 535
501 if (link_state->support_state == 0)
502 return;
503 state &= PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; 536 state &= PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1;
504 537
505 /* state 0 means disabling aspm */ 538 /* check all links who have specific root port link */
506 state = pcie_aspm_check_state(pdev, state); 539 list_for_each_entry(leaf, &link_list, sibiling) {
540 if (!list_empty(&leaf->children) ||
541 get_root_port_link(leaf) != root_port_link)
542 continue;
543 state = pcie_aspm_check_state(leaf->pdev, state);
544 }
545 /* check root port link too in case it hasn't children */
546 state = pcie_aspm_check_state(root_port_link->pdev, state);
547
507 if (link_state->enabled_state == state) 548 if (link_state->enabled_state == state)
508 return; 549 return;
509 __pcie_aspm_config_link(pdev, state); 550
551 /*
552 * we must change the hierarchy. See comments in
553 * __pcie_aspm_config_link for the order
554 **/
555 if (state & PCIE_LINK_STATE_L1) {
556 list_for_each_entry(leaf, &link_list, sibiling) {
557 if (get_root_port_link(leaf) == root_port_link)
558 __pcie_aspm_config_link(leaf->pdev, state);
559 }
560 } else {
561 list_for_each_entry_reverse(leaf, &link_list, sibiling) {
562 if (get_root_port_link(leaf) == root_port_link)
563 __pcie_aspm_config_link(leaf->pdev, state);
564 }
565 }
510} 566}
511 567
512/* 568/*
@@ -570,6 +626,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
570 unsigned int state; 626 unsigned int state;
571 struct pcie_link_state *link_state; 627 struct pcie_link_state *link_state;
572 int error = 0; 628 int error = 0;
629 int blacklist;
573 630
574 if (aspm_disabled || !pdev->is_pcie || pdev->link_state) 631 if (aspm_disabled || !pdev->is_pcie || pdev->link_state)
575 return; 632 return;
@@ -580,29 +637,58 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
580 if (list_empty(&pdev->subordinate->devices)) 637 if (list_empty(&pdev->subordinate->devices))
581 goto out; 638 goto out;
582 639
583 if (pcie_aspm_sanity_check(pdev)) 640 blacklist = !!pcie_aspm_sanity_check(pdev);
584 goto out;
585 641
586 mutex_lock(&aspm_lock); 642 mutex_lock(&aspm_lock);
587 643
588 link_state = kzalloc(sizeof(*link_state), GFP_KERNEL); 644 link_state = kzalloc(sizeof(*link_state), GFP_KERNEL);
589 if (!link_state) 645 if (!link_state)
590 goto unlock_out; 646 goto unlock_out;
591 pdev->link_state = link_state;
592 647
593 pcie_aspm_configure_common_clock(pdev); 648 link_state->downstream_has_switch = pcie_aspm_downstream_has_switch(pdev);
649 INIT_LIST_HEAD(&link_state->children);
650 INIT_LIST_HEAD(&link_state->link);
651 if (pdev->bus->self) {/* this is a switch */
652 struct pcie_link_state *parent_link_state;
594 653
595 pcie_aspm_cap_init(pdev); 654 parent_link_state = pdev->bus->parent->self->link_state;
655 if (!parent_link_state) {
656 kfree(link_state);
657 goto unlock_out;
658 }
659 list_add(&link_state->link, &parent_link_state->children);
660 link_state->parent = parent_link_state;
661 }
596 662
597 /* config link state to avoid BIOS error */ 663 pdev->link_state = link_state;
598 state = pcie_aspm_check_state(pdev, policy_to_aspm_state(pdev));
599 __pcie_aspm_config_link(pdev, state);
600 664
601 pcie_check_clock_pm(pdev); 665 if (!blacklist) {
666 pcie_aspm_configure_common_clock(pdev);
667 pcie_aspm_cap_init(pdev);
668 } else {
669 link_state->enabled_state = PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1;
670 link_state->bios_aspm_state = 0;
671 /* Set support state to 0, so we will disable ASPM later */
672 link_state->support_state = 0;
673 }
602 674
603 link_state->pdev = pdev; 675 link_state->pdev = pdev;
604 list_add(&link_state->sibiling, &link_list); 676 list_add(&link_state->sibiling, &link_list);
605 677
678 if (link_state->downstream_has_switch) {
679 /*
680 * If link has switch, delay the link config. The leaf link
681 * initialization will config the whole hierarchy. but we must
682 * make sure BIOS doesn't set unsupported link state
683 **/
684 state = pcie_aspm_check_state(pdev, link_state->bios_aspm_state);
685 __pcie_aspm_config_link(pdev, state);
686 } else
687 __pcie_aspm_configure_link_state(pdev,
688 policy_to_aspm_state(pdev));
689
690 pcie_check_clock_pm(pdev, blacklist);
691
606unlock_out: 692unlock_out:
607 if (error) 693 if (error)
608 free_link_state(pdev); 694 free_link_state(pdev);
@@ -635,6 +721,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
635 /* All functions are removed, so just disable ASPM for the link */ 721 /* All functions are removed, so just disable ASPM for the link */
636 __pcie_aspm_config_one_dev(parent, 0); 722 __pcie_aspm_config_one_dev(parent, 0);
637 list_del(&link_state->sibiling); 723 list_del(&link_state->sibiling);
724 list_del(&link_state->link);
638 /* Clock PM is for endpoint device */ 725 /* Clock PM is for endpoint device */
639 726
640 free_link_state(parent); 727 free_link_state(parent);