diff options
author | Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> | 2009-05-12 23:18:22 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2009-06-18 17:02:15 -0400 |
commit | 8d349ace9a5c2a8404bcf4a371fe170480ffbebb (patch) | |
tree | 6495378f6b3255752cd04af22e653ece36c7d8b7 /drivers/pci/pcie/aspm.c | |
parent | 5aa63583cbec27482c6f1d761a0509f59b7969a8 (diff) |
PCI ASPM: cleanup initialization
Clean up ASPM initialization by refactoring some functionality, renaming
functions, and moving things around.
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/pcie/aspm.c')
-rw-r--r-- | drivers/pci/pcie/aspm.c | 142 |
1 files changed, 75 insertions, 67 deletions
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 9eaaf95f65a2..68a4d4b15f9f 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c | |||
@@ -126,7 +126,7 @@ static void pcie_set_clock_pm(struct pcie_link_state *link, int enable) | |||
126 | link->clkpm_enabled = !!enable; | 126 | link->clkpm_enabled = !!enable; |
127 | } | 127 | } |
128 | 128 | ||
129 | static void pcie_check_clock_pm(struct pcie_link_state *link, int blacklist) | 129 | static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) |
130 | { | 130 | { |
131 | int pos, capable = 1, enabled = 1; | 131 | int pos, capable = 1, enabled = 1; |
132 | u32 reg32; | 132 | u32 reg32; |
@@ -151,13 +151,7 @@ static void pcie_check_clock_pm(struct pcie_link_state *link, int blacklist) | |||
151 | } | 151 | } |
152 | link->clkpm_enabled = enabled; | 152 | link->clkpm_enabled = enabled; |
153 | link->clkpm_default = enabled; | 153 | link->clkpm_default = enabled; |
154 | if (!blacklist) { | 154 | link->clkpm_capable = (blacklist) ? 0 : capable; |
155 | link->clkpm_capable = capable; | ||
156 | pcie_set_clock_pm(link, policy_to_clkpm_state(link)); | ||
157 | } else { | ||
158 | link->clkpm_capable = 0; | ||
159 | pcie_set_clock_pm(link, 0); | ||
160 | } | ||
161 | } | 155 | } |
162 | 156 | ||
163 | static bool pcie_aspm_downstream_has_switch(struct pcie_link_state *link) | 157 | static bool pcie_aspm_downstream_has_switch(struct pcie_link_state *link) |
@@ -314,12 +308,23 @@ static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, | |||
314 | *enabled = reg16 & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1); | 308 | *enabled = reg16 & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1); |
315 | } | 309 | } |
316 | 310 | ||
317 | static void pcie_aspm_cap_init(struct pcie_link_state *link) | 311 | static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) |
318 | { | 312 | { |
319 | u32 support, l0s, l1, enabled; | 313 | u32 support, l0s, l1, enabled; |
320 | struct pci_dev *child, *parent = link->pdev; | 314 | struct pci_dev *child, *parent = link->pdev; |
321 | struct pci_bus *linkbus = parent->subordinate; | 315 | struct pci_bus *linkbus = parent->subordinate; |
322 | 316 | ||
317 | if (blacklist) { | ||
318 | /* Set support state to 0, so we will disable ASPM later */ | ||
319 | link->aspm_support = 0; | ||
320 | link->aspm_default = 0; | ||
321 | link->aspm_enabled = PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1; | ||
322 | return; | ||
323 | } | ||
324 | |||
325 | /* Configure common clock before checking latencies */ | ||
326 | pcie_aspm_configure_common_clock(link); | ||
327 | |||
323 | /* upstream component states */ | 328 | /* upstream component states */ |
324 | pcie_aspm_get_cap_device(parent, &support, &l0s, &l1, &enabled); | 329 | pcie_aspm_get_cap_device(parent, &support, &l0s, &l1, &enabled); |
325 | link->aspm_support = support; | 330 | link->aspm_support = support; |
@@ -590,6 +595,42 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) | |||
590 | return 0; | 595 | return 0; |
591 | } | 596 | } |
592 | 597 | ||
598 | static struct pcie_link_state *pcie_aspm_setup_link_state(struct pci_dev *pdev) | ||
599 | { | ||
600 | struct pcie_link_state *link; | ||
601 | int blacklist = !!pcie_aspm_sanity_check(pdev); | ||
602 | |||
603 | link = kzalloc(sizeof(*link), GFP_KERNEL); | ||
604 | if (!link) | ||
605 | return NULL; | ||
606 | INIT_LIST_HEAD(&link->sibling); | ||
607 | INIT_LIST_HEAD(&link->children); | ||
608 | INIT_LIST_HEAD(&link->link); | ||
609 | link->pdev = pdev; | ||
610 | link->has_switch = pcie_aspm_downstream_has_switch(link); | ||
611 | if (pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) { | ||
612 | struct pcie_link_state *parent; | ||
613 | parent = pdev->bus->parent->self->link_state; | ||
614 | if (!parent) { | ||
615 | kfree(link); | ||
616 | return NULL; | ||
617 | } | ||
618 | link->parent = parent; | ||
619 | list_add(&link->link, &parent->children); | ||
620 | } | ||
621 | list_add(&link->sibling, &link_list); | ||
622 | |||
623 | pdev->link_state = link; | ||
624 | |||
625 | /* Check ASPM capability */ | ||
626 | pcie_aspm_cap_init(link, blacklist); | ||
627 | |||
628 | /* Check Clock PM capability */ | ||
629 | pcie_clkpm_cap_init(link, blacklist); | ||
630 | |||
631 | return link; | ||
632 | } | ||
633 | |||
593 | /* | 634 | /* |
594 | * pcie_aspm_init_link_state: Initiate PCI express link state. | 635 | * pcie_aspm_init_link_state: Initiate PCI express link state. |
595 | * It is called after the pcie and its children devices are scaned. | 636 | * It is called after the pcie and its children devices are scaned. |
@@ -597,80 +638,47 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) | |||
597 | */ | 638 | */ |
598 | void pcie_aspm_init_link_state(struct pci_dev *pdev) | 639 | void pcie_aspm_init_link_state(struct pci_dev *pdev) |
599 | { | 640 | { |
600 | unsigned int state; | 641 | u32 state; |
601 | struct pcie_link_state *link_state; | 642 | struct pcie_link_state *link; |
602 | int error = 0; | ||
603 | int blacklist; | ||
604 | 643 | ||
605 | if (aspm_disabled || !pdev->is_pcie || pdev->link_state) | 644 | if (aspm_disabled || !pdev->is_pcie || pdev->link_state) |
606 | return; | 645 | return; |
607 | if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && | 646 | if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && |
608 | pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) | 647 | pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) |
609 | return; | 648 | return; |
649 | |||
610 | /* VIA has a strange chipset, root port is under a bridge */ | 650 | /* VIA has a strange chipset, root port is under a bridge */ |
611 | if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT && | 651 | if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT && |
612 | pdev->bus->self) | 652 | pdev->bus->self) |
613 | return; | 653 | return; |
654 | |||
614 | down_read(&pci_bus_sem); | 655 | down_read(&pci_bus_sem); |
615 | if (list_empty(&pdev->subordinate->devices)) | 656 | if (list_empty(&pdev->subordinate->devices)) |
616 | goto out; | 657 | goto out; |
617 | 658 | ||
618 | blacklist = !!pcie_aspm_sanity_check(pdev); | ||
619 | |||
620 | mutex_lock(&aspm_lock); | 659 | mutex_lock(&aspm_lock); |
621 | 660 | link = pcie_aspm_setup_link_state(pdev); | |
622 | link_state = kzalloc(sizeof(*link_state), GFP_KERNEL); | 661 | if (!link) |
623 | if (!link_state) | 662 | goto unlock; |
624 | goto unlock_out; | 663 | /* |
625 | 664 | * Setup initial ASPM state | |
626 | INIT_LIST_HEAD(&link_state->children); | 665 | * |
627 | INIT_LIST_HEAD(&link_state->link); | 666 | * If link has switch, delay the link config. The leaf link |
628 | if (pdev->bus->self) {/* this is a switch */ | 667 | * initialization will config the whole hierarchy. But we must |
629 | struct pcie_link_state *parent_link_state; | 668 | * make sure BIOS doesn't set unsupported link state. |
630 | 669 | */ | |
631 | parent_link_state = pdev->bus->parent->self->link_state; | 670 | if (link->has_switch) { |
632 | if (!parent_link_state) { | 671 | state = pcie_aspm_check_state(link, link->aspm_default); |
633 | kfree(link_state); | 672 | __pcie_aspm_config_link(link, state); |
634 | goto unlock_out; | ||
635 | } | ||
636 | list_add(&link_state->link, &parent_link_state->children); | ||
637 | link_state->parent = parent_link_state; | ||
638 | } | ||
639 | link_state->pdev = pdev; | ||
640 | link_state->has_switch = pcie_aspm_downstream_has_switch(link_state); | ||
641 | pdev->link_state = link_state; | ||
642 | |||
643 | if (!blacklist) { | ||
644 | pcie_aspm_configure_common_clock(link_state); | ||
645 | pcie_aspm_cap_init(link_state); | ||
646 | } else { | 673 | } else { |
647 | link_state->aspm_enabled = | 674 | state = policy_to_aspm_state(link); |
648 | (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); | 675 | __pcie_aspm_configure_link_state(link, state); |
649 | link_state->aspm_default = 0; | ||
650 | /* Set support state to 0, so we will disable ASPM later */ | ||
651 | link_state->aspm_support = 0; | ||
652 | } | 676 | } |
653 | 677 | ||
654 | list_add(&link_state->sibling, &link_list); | 678 | /* Setup initial Clock PM state */ |
655 | 679 | state = (link->clkpm_capable) ? policy_to_clkpm_state(link) : 0; | |
656 | if (link_state->has_switch) { | 680 | pcie_set_clock_pm(link, state); |
657 | /* | 681 | unlock: |
658 | * If link has switch, delay the link config. The leaf link | ||
659 | * initialization will config the whole hierarchy. but we must | ||
660 | * make sure BIOS doesn't set unsupported link state | ||
661 | **/ | ||
662 | state = pcie_aspm_check_state(link_state, | ||
663 | link_state->aspm_default); | ||
664 | __pcie_aspm_config_link(link_state, state); | ||
665 | } else | ||
666 | __pcie_aspm_configure_link_state(link_state, | ||
667 | policy_to_aspm_state(link_state)); | ||
668 | |||
669 | pcie_check_clock_pm(link_state, blacklist); | ||
670 | |||
671 | unlock_out: | ||
672 | if (error) | ||
673 | free_link_state(link_state); | ||
674 | mutex_unlock(&aspm_lock); | 682 | mutex_unlock(&aspm_lock); |
675 | out: | 683 | out: |
676 | up_read(&pci_bus_sem); | 684 | up_read(&pci_bus_sem); |