diff options
Diffstat (limited to 'drivers/pci/pcie/aspm.c')
-rw-r--r-- | drivers/pci/pcie/aspm.c | 211 |
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 | ||
169 | static 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 | /** | 412 | static 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 | */ | ||
437 | static 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 | |||
447 | static 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 | |||
478 | static 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 | ||
489 | static void __pcie_aspm_config_link(struct pcie_link_state *link, u32 state) | 423 | static 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 */ | 450 | static void pcie_config_aspm_path(struct pcie_link_state *link) |
517 | static 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 | */ | ||
555 | static 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 | |||
565 | static void free_link_state(struct pcie_link_state *link) | 458 | static 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 | ||
599 | static struct pcie_link_state *pcie_aspm_setup_link_state(struct pci_dev *pdev) | 492 | static 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 | */ |
645 | void pcie_aspm_init_link_state(struct pci_dev *pdev) | 529 | void 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)); |
687 | unlock: | 564 | unlock: |
688 | mutex_unlock(&aspm_lock); | 565 | mutex_unlock(&aspm_lock); |
689 | out: | 566 | out: |
@@ -718,12 +595,12 @@ static void pcie_update_aspm_capable(struct pcie_link_state *root) | |||
718 | void pcie_aspm_exit_link_state(struct pci_dev *pdev) | 595 | void 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); | ||
750 | out: | 629 | out: |
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); | |||
808 | static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) | 688 | static 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 | ||
879 | static ssize_t clk_ctl_show(struct device *dev, | 762 | static ssize_t clk_ctl_show(struct device *dev, |