diff options
Diffstat (limited to 'drivers/pci/pcie')
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_acpi.c | 1 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_errprint.c | 2 | ||||
-rw-r--r-- | drivers/pci/pcie/aspm.c | 165 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_bus.c | 32 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_core.c | 240 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_pci.c | 21 |
6 files changed, 290 insertions, 171 deletions
diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c index 6dd7b13e9808..ebce26c37049 100644 --- a/drivers/pci/pcie/aer/aerdrv_acpi.c +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c | |||
@@ -38,7 +38,6 @@ int aer_osc_setup(struct pcie_device *pciedev) | |||
38 | 38 | ||
39 | handle = acpi_find_root_bridge_handle(pdev); | 39 | handle = acpi_find_root_bridge_handle(pdev); |
40 | if (handle) { | 40 | if (handle) { |
41 | pcie_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT); | ||
42 | status = pci_osc_control_set(handle, | 41 | status = pci_osc_control_set(handle, |
43 | OSC_PCI_EXPRESS_AER_CONTROL | | 42 | OSC_PCI_EXPRESS_AER_CONTROL | |
44 | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); | 43 | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); |
diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c index 3933d4f30e8c..0fc29ae80df8 100644 --- a/drivers/pci/pcie/aer/aerdrv_errprint.c +++ b/drivers/pci/pcie/aer/aerdrv_errprint.c | |||
@@ -233,7 +233,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) | |||
233 | 233 | ||
234 | if (info->flags & AER_TLP_HEADER_VALID_FLAG) { | 234 | if (info->flags & AER_TLP_HEADER_VALID_FLAG) { |
235 | unsigned char *tlp = (unsigned char *) &info->tlp; | 235 | unsigned char *tlp = (unsigned char *) &info->tlp; |
236 | printk("%sTLB Header:\n", loglevel); | 236 | printk("%sTLP Header:\n", loglevel); |
237 | printk("%s%02x%02x%02x%02x %02x%02x%02x%02x" | 237 | printk("%s%02x%02x%02x%02x %02x%02x%02x%02x" |
238 | " %02x%02x%02x%02x %02x%02x%02x%02x\n", | 238 | " %02x%02x%02x%02x %02x%02x%02x%02x\n", |
239 | loglevel, | 239 | loglevel, |
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 9aad608bcf3f..586b6f75910d 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/jiffies.h> | 19 | #include <linux/jiffies.h> |
20 | #include <linux/delay.h> | ||
20 | #include <linux/pci-aspm.h> | 21 | #include <linux/pci-aspm.h> |
21 | #include "../pci.h" | 22 | #include "../pci.h" |
22 | 23 | ||
@@ -33,6 +34,11 @@ struct endpoint_state { | |||
33 | struct pcie_link_state { | 34 | struct pcie_link_state { |
34 | struct list_head sibiling; | 35 | struct list_head sibiling; |
35 | struct pci_dev *pdev; | 36 | struct pci_dev *pdev; |
37 | bool downstream_has_switch; | ||
38 | |||
39 | struct pcie_link_state *parent; | ||
40 | struct list_head children; | ||
41 | struct list_head link; | ||
36 | 42 | ||
37 | /* ASPM state */ | 43 | /* ASPM state */ |
38 | unsigned int support_state; | 44 | unsigned int support_state; |
@@ -70,6 +76,8 @@ static const char *policy_str[] = { | |||
70 | [POLICY_POWERSAVE] = "powersave" | 76 | [POLICY_POWERSAVE] = "powersave" |
71 | }; | 77 | }; |
72 | 78 | ||
79 | #define LINK_RETRAIN_TIMEOUT HZ | ||
80 | |||
73 | static int policy_to_aspm_state(struct pci_dev *pdev) | 81 | static int policy_to_aspm_state(struct pci_dev *pdev) |
74 | { | 82 | { |
75 | struct pcie_link_state *link_state = pdev->link_state; | 83 | struct pcie_link_state *link_state = pdev->link_state; |
@@ -125,7 +133,7 @@ static void pcie_set_clock_pm(struct pci_dev *pdev, int enable) | |||
125 | link_state->clk_pm_enabled = !!enable; | 133 | link_state->clk_pm_enabled = !!enable; |
126 | } | 134 | } |
127 | 135 | ||
128 | static void pcie_check_clock_pm(struct pci_dev *pdev) | 136 | static void pcie_check_clock_pm(struct pci_dev *pdev, int blacklist) |
129 | { | 137 | { |
130 | int pos; | 138 | int pos; |
131 | u32 reg32; | 139 | u32 reg32; |
@@ -149,10 +157,26 @@ static void pcie_check_clock_pm(struct pci_dev *pdev) | |||
149 | if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN)) | 157 | if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN)) |
150 | enabled = 0; | 158 | enabled = 0; |
151 | } | 159 | } |
152 | link_state->clk_pm_capable = capable; | ||
153 | link_state->clk_pm_enabled = enabled; | 160 | link_state->clk_pm_enabled = enabled; |
154 | link_state->bios_clk_state = enabled; | 161 | link_state->bios_clk_state = enabled; |
155 | pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); | 162 | if (!blacklist) { |
163 | link_state->clk_pm_capable = capable; | ||
164 | pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); | ||
165 | } else { | ||
166 | link_state->clk_pm_capable = 0; | ||
167 | pcie_set_clock_pm(pdev, 0); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | static bool pcie_aspm_downstream_has_switch(struct pci_dev *pdev) | ||
172 | { | ||
173 | struct pci_dev *child_dev; | ||
174 | |||
175 | list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { | ||
176 | if (child_dev->pcie_type == PCI_EXP_TYPE_UPSTREAM) | ||
177 | return true; | ||
178 | } | ||
179 | return false; | ||
156 | } | 180 | } |
157 | 181 | ||
158 | /* | 182 | /* |
@@ -217,16 +241,18 @@ static void pcie_aspm_configure_common_clock(struct pci_dev *pdev) | |||
217 | pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); | 241 | pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); |
218 | 242 | ||
219 | /* Wait for link training end */ | 243 | /* Wait for link training end */ |
220 | /* break out after waiting for 1 second */ | 244 | /* break out after waiting for timeout */ |
221 | start_jiffies = jiffies; | 245 | start_jiffies = jiffies; |
222 | while ((jiffies - start_jiffies) < HZ) { | 246 | for (;;) { |
223 | pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, ®16); | 247 | pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, ®16); |
224 | if (!(reg16 & PCI_EXP_LNKSTA_LT)) | 248 | if (!(reg16 & PCI_EXP_LNKSTA_LT)) |
225 | break; | 249 | break; |
226 | cpu_relax(); | 250 | if (time_after(jiffies, start_jiffies + LINK_RETRAIN_TIMEOUT)) |
251 | break; | ||
252 | msleep(1); | ||
227 | } | 253 | } |
228 | /* training failed -> recover */ | 254 | /* training failed -> recover */ |
229 | if ((jiffies - start_jiffies) >= HZ) { | 255 | if (reg16 & PCI_EXP_LNKSTA_LT) { |
230 | dev_printk (KERN_ERR, &pdev->dev, "ASPM: Could not configure" | 256 | dev_printk (KERN_ERR, &pdev->dev, "ASPM: Could not configure" |
231 | " common clock\n"); | 257 | " common clock\n"); |
232 | i = 0; | 258 | i = 0; |
@@ -419,9 +445,9 @@ static unsigned int pcie_aspm_check_state(struct pci_dev *pdev, | |||
419 | { | 445 | { |
420 | struct pci_dev *child_dev; | 446 | struct pci_dev *child_dev; |
421 | 447 | ||
422 | /* If no child, disable the link */ | 448 | /* If no child, ignore the link */ |
423 | if (list_empty(&pdev->subordinate->devices)) | 449 | if (list_empty(&pdev->subordinate->devices)) |
424 | return 0; | 450 | return state; |
425 | list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { | 451 | list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { |
426 | if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { | 452 | if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { |
427 | /* | 453 | /* |
@@ -462,6 +488,9 @@ static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state) | |||
462 | int valid = 1; | 488 | int valid = 1; |
463 | struct pcie_link_state *link_state = pdev->link_state; | 489 | struct pcie_link_state *link_state = pdev->link_state; |
464 | 490 | ||
491 | /* If no child, disable the link */ | ||
492 | if (list_empty(&pdev->subordinate->devices)) | ||
493 | state = 0; | ||
465 | /* | 494 | /* |
466 | * if the downstream component has pci bridge function, don't do ASPM | 495 | * if the downstream component has pci bridge function, don't do ASPM |
467 | * now | 496 | * now |
@@ -493,20 +522,52 @@ static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state) | |||
493 | link_state->enabled_state = state; | 522 | link_state->enabled_state = state; |
494 | } | 523 | } |
495 | 524 | ||
525 | static struct pcie_link_state *get_root_port_link(struct pcie_link_state *link) | ||
526 | { | ||
527 | struct pcie_link_state *root_port_link = link; | ||
528 | while (root_port_link->parent) | ||
529 | root_port_link = root_port_link->parent; | ||
530 | return root_port_link; | ||
531 | } | ||
532 | |||
533 | /* check the whole hierarchy, and configure each link in the hierarchy */ | ||
496 | static void __pcie_aspm_configure_link_state(struct pci_dev *pdev, | 534 | static void __pcie_aspm_configure_link_state(struct pci_dev *pdev, |
497 | unsigned int state) | 535 | unsigned int state) |
498 | { | 536 | { |
499 | struct pcie_link_state *link_state = pdev->link_state; | 537 | struct pcie_link_state *link_state = pdev->link_state; |
538 | struct pcie_link_state *root_port_link = get_root_port_link(link_state); | ||
539 | struct pcie_link_state *leaf; | ||
500 | 540 | ||
501 | if (link_state->support_state == 0) | ||
502 | return; | ||
503 | state &= PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; | 541 | state &= PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; |
504 | 542 | ||
505 | /* state 0 means disabling aspm */ | 543 | /* check all links who have specific root port link */ |
506 | state = pcie_aspm_check_state(pdev, state); | 544 | list_for_each_entry(leaf, &link_list, sibiling) { |
545 | if (!list_empty(&leaf->children) || | ||
546 | get_root_port_link(leaf) != root_port_link) | ||
547 | continue; | ||
548 | state = pcie_aspm_check_state(leaf->pdev, state); | ||
549 | } | ||
550 | /* check root port link too in case it hasn't children */ | ||
551 | state = pcie_aspm_check_state(root_port_link->pdev, state); | ||
552 | |||
507 | if (link_state->enabled_state == state) | 553 | if (link_state->enabled_state == state) |
508 | return; | 554 | return; |
509 | __pcie_aspm_config_link(pdev, state); | 555 | |
556 | /* | ||
557 | * we must change the hierarchy. See comments in | ||
558 | * __pcie_aspm_config_link for the order | ||
559 | **/ | ||
560 | if (state & PCIE_LINK_STATE_L1) { | ||
561 | list_for_each_entry(leaf, &link_list, sibiling) { | ||
562 | if (get_root_port_link(leaf) == root_port_link) | ||
563 | __pcie_aspm_config_link(leaf->pdev, state); | ||
564 | } | ||
565 | } else { | ||
566 | list_for_each_entry_reverse(leaf, &link_list, sibiling) { | ||
567 | if (get_root_port_link(leaf) == root_port_link) | ||
568 | __pcie_aspm_config_link(leaf->pdev, state); | ||
569 | } | ||
570 | } | ||
510 | } | 571 | } |
511 | 572 | ||
512 | /* | 573 | /* |
@@ -570,6 +631,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) | |||
570 | unsigned int state; | 631 | unsigned int state; |
571 | struct pcie_link_state *link_state; | 632 | struct pcie_link_state *link_state; |
572 | int error = 0; | 633 | int error = 0; |
634 | int blacklist; | ||
573 | 635 | ||
574 | if (aspm_disabled || !pdev->is_pcie || pdev->link_state) | 636 | if (aspm_disabled || !pdev->is_pcie || pdev->link_state) |
575 | return; | 637 | return; |
@@ -580,29 +642,58 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) | |||
580 | if (list_empty(&pdev->subordinate->devices)) | 642 | if (list_empty(&pdev->subordinate->devices)) |
581 | goto out; | 643 | goto out; |
582 | 644 | ||
583 | if (pcie_aspm_sanity_check(pdev)) | 645 | blacklist = !!pcie_aspm_sanity_check(pdev); |
584 | goto out; | ||
585 | 646 | ||
586 | mutex_lock(&aspm_lock); | 647 | mutex_lock(&aspm_lock); |
587 | 648 | ||
588 | link_state = kzalloc(sizeof(*link_state), GFP_KERNEL); | 649 | link_state = kzalloc(sizeof(*link_state), GFP_KERNEL); |
589 | if (!link_state) | 650 | if (!link_state) |
590 | goto unlock_out; | 651 | goto unlock_out; |
591 | pdev->link_state = link_state; | ||
592 | 652 | ||
593 | pcie_aspm_configure_common_clock(pdev); | 653 | link_state->downstream_has_switch = pcie_aspm_downstream_has_switch(pdev); |
654 | INIT_LIST_HEAD(&link_state->children); | ||
655 | INIT_LIST_HEAD(&link_state->link); | ||
656 | if (pdev->bus->self) {/* this is a switch */ | ||
657 | struct pcie_link_state *parent_link_state; | ||
594 | 658 | ||
595 | pcie_aspm_cap_init(pdev); | 659 | parent_link_state = pdev->bus->parent->self->link_state; |
660 | if (!parent_link_state) { | ||
661 | kfree(link_state); | ||
662 | goto unlock_out; | ||
663 | } | ||
664 | list_add(&link_state->link, &parent_link_state->children); | ||
665 | link_state->parent = parent_link_state; | ||
666 | } | ||
596 | 667 | ||
597 | /* config link state to avoid BIOS error */ | 668 | 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 | 669 | ||
601 | pcie_check_clock_pm(pdev); | 670 | if (!blacklist) { |
671 | pcie_aspm_configure_common_clock(pdev); | ||
672 | pcie_aspm_cap_init(pdev); | ||
673 | } else { | ||
674 | link_state->enabled_state = PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; | ||
675 | link_state->bios_aspm_state = 0; | ||
676 | /* Set support state to 0, so we will disable ASPM later */ | ||
677 | link_state->support_state = 0; | ||
678 | } | ||
602 | 679 | ||
603 | link_state->pdev = pdev; | 680 | link_state->pdev = pdev; |
604 | list_add(&link_state->sibiling, &link_list); | 681 | list_add(&link_state->sibiling, &link_list); |
605 | 682 | ||
683 | if (link_state->downstream_has_switch) { | ||
684 | /* | ||
685 | * If link has switch, delay the link config. The leaf link | ||
686 | * initialization will config the whole hierarchy. but we must | ||
687 | * make sure BIOS doesn't set unsupported link state | ||
688 | **/ | ||
689 | state = pcie_aspm_check_state(pdev, link_state->bios_aspm_state); | ||
690 | __pcie_aspm_config_link(pdev, state); | ||
691 | } else | ||
692 | __pcie_aspm_configure_link_state(pdev, | ||
693 | policy_to_aspm_state(pdev)); | ||
694 | |||
695 | pcie_check_clock_pm(pdev, blacklist); | ||
696 | |||
606 | unlock_out: | 697 | unlock_out: |
607 | if (error) | 698 | if (error) |
608 | free_link_state(pdev); | 699 | free_link_state(pdev); |
@@ -635,6 +726,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) | |||
635 | /* All functions are removed, so just disable ASPM for the link */ | 726 | /* All functions are removed, so just disable ASPM for the link */ |
636 | __pcie_aspm_config_one_dev(parent, 0); | 727 | __pcie_aspm_config_one_dev(parent, 0); |
637 | list_del(&link_state->sibiling); | 728 | list_del(&link_state->sibiling); |
729 | list_del(&link_state->link); | ||
638 | /* Clock PM is for endpoint device */ | 730 | /* Clock PM is for endpoint device */ |
639 | 731 | ||
640 | free_link_state(parent); | 732 | free_link_state(parent); |
@@ -857,24 +949,15 @@ void pcie_no_aspm(void) | |||
857 | aspm_disabled = 1; | 949 | aspm_disabled = 1; |
858 | } | 950 | } |
859 | 951 | ||
860 | #ifdef CONFIG_ACPI | 952 | /** |
861 | #include <acpi/acpi_bus.h> | 953 | * pcie_aspm_enabled - is PCIe ASPM enabled? |
862 | #include <linux/pci-acpi.h> | 954 | * |
863 | static void pcie_aspm_platform_init(void) | 955 | * Returns true if ASPM has not been disabled by the command-line option |
864 | { | 956 | * pcie_aspm=off. |
865 | pcie_osc_support_set(OSC_ACTIVE_STATE_PWR_SUPPORT| | 957 | **/ |
866 | OSC_CLOCK_PWR_CAPABILITY_SUPPORT); | 958 | int pcie_aspm_enabled(void) |
867 | } | ||
868 | #else | ||
869 | static inline void pcie_aspm_platform_init(void) { } | ||
870 | #endif | ||
871 | |||
872 | static int __init pcie_aspm_init(void) | ||
873 | { | 959 | { |
874 | if (aspm_disabled) | 960 | return !aspm_disabled; |
875 | return 0; | ||
876 | pcie_aspm_platform_init(); | ||
877 | return 0; | ||
878 | } | 961 | } |
962 | EXPORT_SYMBOL(pcie_aspm_enabled); | ||
879 | 963 | ||
880 | fs_initcall(pcie_aspm_init); | ||
diff --git a/drivers/pci/pcie/portdrv_bus.c b/drivers/pci/pcie/portdrv_bus.c index 359fe5568df1..eec89b767f9f 100644 --- a/drivers/pci/pcie/portdrv_bus.c +++ b/drivers/pci/pcie/portdrv_bus.c | |||
@@ -16,14 +16,10 @@ | |||
16 | #include "portdrv.h" | 16 | #include "portdrv.h" |
17 | 17 | ||
18 | static int pcie_port_bus_match(struct device *dev, struct device_driver *drv); | 18 | static int pcie_port_bus_match(struct device *dev, struct device_driver *drv); |
19 | static int pcie_port_bus_suspend(struct device *dev, pm_message_t state); | ||
20 | static int pcie_port_bus_resume(struct device *dev); | ||
21 | 19 | ||
22 | struct bus_type pcie_port_bus_type = { | 20 | struct bus_type pcie_port_bus_type = { |
23 | .name = "pci_express", | 21 | .name = "pci_express", |
24 | .match = pcie_port_bus_match, | 22 | .match = pcie_port_bus_match, |
25 | .suspend = pcie_port_bus_suspend, | ||
26 | .resume = pcie_port_bus_resume, | ||
27 | }; | 23 | }; |
28 | EXPORT_SYMBOL_GPL(pcie_port_bus_type); | 24 | EXPORT_SYMBOL_GPL(pcie_port_bus_type); |
29 | 25 | ||
@@ -49,32 +45,12 @@ static int pcie_port_bus_match(struct device *dev, struct device_driver *drv) | |||
49 | return 1; | 45 | return 1; |
50 | } | 46 | } |
51 | 47 | ||
52 | static int pcie_port_bus_suspend(struct device *dev, pm_message_t state) | 48 | int pcie_port_bus_register(void) |
53 | { | 49 | { |
54 | struct pcie_device *pciedev; | 50 | return bus_register(&pcie_port_bus_type); |
55 | struct pcie_port_service_driver *driver; | ||
56 | |||
57 | if (!dev || !dev->driver) | ||
58 | return 0; | ||
59 | |||
60 | pciedev = to_pcie_device(dev); | ||
61 | driver = to_service_driver(dev->driver); | ||
62 | if (driver && driver->suspend) | ||
63 | driver->suspend(pciedev, state); | ||
64 | return 0; | ||
65 | } | 51 | } |
66 | 52 | ||
67 | static int pcie_port_bus_resume(struct device *dev) | 53 | void pcie_port_bus_unregister(void) |
68 | { | 54 | { |
69 | struct pcie_device *pciedev; | 55 | bus_unregister(&pcie_port_bus_type); |
70 | struct pcie_port_service_driver *driver; | ||
71 | |||
72 | if (!dev || !dev->driver) | ||
73 | return 0; | ||
74 | |||
75 | pciedev = to_pcie_device(dev); | ||
76 | driver = to_service_driver(dev->driver); | ||
77 | if (driver && driver->resume) | ||
78 | driver->resume(pciedev); | ||
79 | return 0; | ||
80 | } | 56 | } |
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 2e091e014829..8b3f8c18032f 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c | |||
@@ -19,91 +19,15 @@ | |||
19 | 19 | ||
20 | extern int pcie_mch_quirk; /* MSI-quirk Indicator */ | 20 | extern int pcie_mch_quirk; /* MSI-quirk Indicator */ |
21 | 21 | ||
22 | static int pcie_port_probe_service(struct device *dev) | 22 | /** |
23 | { | 23 | * release_pcie_device - free PCI Express port service device structure |
24 | struct pcie_device *pciedev; | 24 | * @dev: Port service device to release |
25 | struct pcie_port_service_driver *driver; | 25 | * |
26 | int status; | 26 | * Invoked automatically when device is being removed in response to |
27 | 27 | * device_unregister(dev). Release all resources being claimed. | |
28 | if (!dev || !dev->driver) | ||
29 | return -ENODEV; | ||
30 | |||
31 | driver = to_service_driver(dev->driver); | ||
32 | if (!driver || !driver->probe) | ||
33 | return -ENODEV; | ||
34 | |||
35 | pciedev = to_pcie_device(dev); | ||
36 | status = driver->probe(pciedev, driver->id_table); | ||
37 | if (!status) { | ||
38 | dev_printk(KERN_DEBUG, dev, "service driver %s loaded\n", | ||
39 | driver->name); | ||
40 | get_device(dev); | ||
41 | } | ||
42 | return status; | ||
43 | } | ||
44 | |||
45 | static int pcie_port_remove_service(struct device *dev) | ||
46 | { | ||
47 | struct pcie_device *pciedev; | ||
48 | struct pcie_port_service_driver *driver; | ||
49 | |||
50 | if (!dev || !dev->driver) | ||
51 | return 0; | ||
52 | |||
53 | pciedev = to_pcie_device(dev); | ||
54 | driver = to_service_driver(dev->driver); | ||
55 | if (driver && driver->remove) { | ||
56 | dev_printk(KERN_DEBUG, dev, "unloading service driver %s\n", | ||
57 | driver->name); | ||
58 | driver->remove(pciedev); | ||
59 | put_device(dev); | ||
60 | } | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static void pcie_port_shutdown_service(struct device *dev) {} | ||
65 | |||
66 | static int pcie_port_suspend_service(struct device *dev, pm_message_t state) | ||
67 | { | ||
68 | struct pcie_device *pciedev; | ||
69 | struct pcie_port_service_driver *driver; | ||
70 | |||
71 | if (!dev || !dev->driver) | ||
72 | return 0; | ||
73 | |||
74 | pciedev = to_pcie_device(dev); | ||
75 | driver = to_service_driver(dev->driver); | ||
76 | if (driver && driver->suspend) | ||
77 | driver->suspend(pciedev, state); | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static int pcie_port_resume_service(struct device *dev) | ||
82 | { | ||
83 | struct pcie_device *pciedev; | ||
84 | struct pcie_port_service_driver *driver; | ||
85 | |||
86 | if (!dev || !dev->driver) | ||
87 | return 0; | ||
88 | |||
89 | pciedev = to_pcie_device(dev); | ||
90 | driver = to_service_driver(dev->driver); | ||
91 | |||
92 | if (driver && driver->resume) | ||
93 | driver->resume(pciedev); | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * release_pcie_device | ||
99 | * | ||
100 | * Being invoked automatically when device is being removed | ||
101 | * in response to device_unregister(dev) call. | ||
102 | * Release all resources being claimed. | ||
103 | */ | 28 | */ |
104 | static void release_pcie_device(struct device *dev) | 29 | static void release_pcie_device(struct device *dev) |
105 | { | 30 | { |
106 | dev_printk(KERN_DEBUG, dev, "free port service\n"); | ||
107 | kfree(to_pcie_device(dev)); | 31 | kfree(to_pcie_device(dev)); |
108 | } | 32 | } |
109 | 33 | ||
@@ -128,7 +52,16 @@ static int is_msi_quirked(struct pci_dev *dev) | |||
128 | } | 52 | } |
129 | return quirk; | 53 | return quirk; |
130 | } | 54 | } |
131 | 55 | ||
56 | /** | ||
57 | * assign_interrupt_mode - choose interrupt mode for PCI Express port services | ||
58 | * (INTx, MSI-X, MSI) and set up vectors | ||
59 | * @dev: PCI Express port to handle | ||
60 | * @vectors: Array of interrupt vectors to populate | ||
61 | * @mask: Bitmask of port capabilities returned by get_port_device_capability() | ||
62 | * | ||
63 | * Return value: Interrupt mode associated with the port | ||
64 | */ | ||
132 | static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask) | 65 | static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask) |
133 | { | 66 | { |
134 | int i, pos, nvec, status = -EINVAL; | 67 | int i, pos, nvec, status = -EINVAL; |
@@ -150,7 +83,6 @@ static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask) | |||
150 | if (pos) { | 83 | if (pos) { |
151 | struct msix_entry msix_entries[PCIE_PORT_DEVICE_MAXSERVICES] = | 84 | struct msix_entry msix_entries[PCIE_PORT_DEVICE_MAXSERVICES] = |
152 | {{0, 0}, {0, 1}, {0, 2}, {0, 3}}; | 85 | {{0, 0}, {0, 1}, {0, 2}, {0, 3}}; |
153 | dev_info(&dev->dev, "found MSI-X capability\n"); | ||
154 | status = pci_enable_msix(dev, msix_entries, nvec); | 86 | status = pci_enable_msix(dev, msix_entries, nvec); |
155 | if (!status) { | 87 | if (!status) { |
156 | int j = 0; | 88 | int j = 0; |
@@ -165,7 +97,6 @@ static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask) | |||
165 | if (status) { | 97 | if (status) { |
166 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | 98 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); |
167 | if (pos) { | 99 | if (pos) { |
168 | dev_info(&dev->dev, "found MSI capability\n"); | ||
169 | status = pci_enable_msi(dev); | 100 | status = pci_enable_msi(dev); |
170 | if (!status) { | 101 | if (!status) { |
171 | interrupt_mode = PCIE_PORT_MSI_MODE; | 102 | interrupt_mode = PCIE_PORT_MSI_MODE; |
@@ -177,6 +108,16 @@ static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask) | |||
177 | return interrupt_mode; | 108 | return interrupt_mode; |
178 | } | 109 | } |
179 | 110 | ||
111 | /** | ||
112 | * get_port_device_capability - discover capabilities of a PCI Express port | ||
113 | * @dev: PCI Express port to examine | ||
114 | * | ||
115 | * The capabilities are read from the port's PCI Express configuration registers | ||
116 | * as described in PCI Express Base Specification 1.0a sections 7.8.2, 7.8.9 and | ||
117 | * 7.9 - 7.11. | ||
118 | * | ||
119 | * Return value: Bitmask of discovered port capabilities | ||
120 | */ | ||
180 | static int get_port_device_capability(struct pci_dev *dev) | 121 | static int get_port_device_capability(struct pci_dev *dev) |
181 | { | 122 | { |
182 | int services = 0, pos; | 123 | int services = 0, pos; |
@@ -204,6 +145,15 @@ static int get_port_device_capability(struct pci_dev *dev) | |||
204 | return services; | 145 | return services; |
205 | } | 146 | } |
206 | 147 | ||
148 | /** | ||
149 | * pcie_device_init - initialize PCI Express port service device | ||
150 | * @dev: Port service device to initialize | ||
151 | * @parent: PCI Express port to associate the service device with | ||
152 | * @port_type: Type of the port | ||
153 | * @service_type: Type of service to associate with the service device | ||
154 | * @irq: Interrupt vector to associate with the service device | ||
155 | * @irq_mode: Interrupt mode of the service (INTx, MSI-X, MSI) | ||
156 | */ | ||
207 | static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev, | 157 | static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev, |
208 | int port_type, int service_type, int irq, int irq_mode) | 158 | int port_type, int service_type, int irq, int irq_mode) |
209 | { | 159 | { |
@@ -224,11 +174,19 @@ static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev, | |||
224 | device->driver = NULL; | 174 | device->driver = NULL; |
225 | device->driver_data = NULL; | 175 | device->driver_data = NULL; |
226 | device->release = release_pcie_device; /* callback to free pcie dev */ | 176 | device->release = release_pcie_device; /* callback to free pcie dev */ |
227 | snprintf(device->bus_id, sizeof(device->bus_id), "%s:pcie%02x", | 177 | dev_set_name(device, "%s:pcie%02x", |
228 | pci_name(parent), get_descriptor_id(port_type, service_type)); | 178 | pci_name(parent), get_descriptor_id(port_type, service_type)); |
229 | device->parent = &parent->dev; | 179 | device->parent = &parent->dev; |
230 | } | 180 | } |
231 | 181 | ||
182 | /** | ||
183 | * alloc_pcie_device - allocate PCI Express port service device structure | ||
184 | * @parent: PCI Express port to associate the service device with | ||
185 | * @port_type: Type of the port | ||
186 | * @service_type: Type of service to associate with the service device | ||
187 | * @irq: Interrupt vector to associate with the service device | ||
188 | * @irq_mode: Interrupt mode of the service (INTx, MSI-X, MSI) | ||
189 | */ | ||
232 | static struct pcie_device* alloc_pcie_device(struct pci_dev *parent, | 190 | static struct pcie_device* alloc_pcie_device(struct pci_dev *parent, |
233 | int port_type, int service_type, int irq, int irq_mode) | 191 | int port_type, int service_type, int irq, int irq_mode) |
234 | { | 192 | { |
@@ -239,10 +197,13 @@ static struct pcie_device* alloc_pcie_device(struct pci_dev *parent, | |||
239 | return NULL; | 197 | return NULL; |
240 | 198 | ||
241 | pcie_device_init(parent, device, port_type, service_type, irq,irq_mode); | 199 | pcie_device_init(parent, device, port_type, service_type, irq,irq_mode); |
242 | dev_printk(KERN_DEBUG, &device->device, "allocate port service\n"); | ||
243 | return device; | 200 | return device; |
244 | } | 201 | } |
245 | 202 | ||
203 | /** | ||
204 | * pcie_port_device_probe - check if device is a PCI Express port | ||
205 | * @dev: Device to check | ||
206 | */ | ||
246 | int pcie_port_device_probe(struct pci_dev *dev) | 207 | int pcie_port_device_probe(struct pci_dev *dev) |
247 | { | 208 | { |
248 | int pos, type; | 209 | int pos, type; |
@@ -260,6 +221,13 @@ int pcie_port_device_probe(struct pci_dev *dev) | |||
260 | return -ENODEV; | 221 | return -ENODEV; |
261 | } | 222 | } |
262 | 223 | ||
224 | /** | ||
225 | * pcie_port_device_register - register PCI Express port | ||
226 | * @dev: PCI Express port to register | ||
227 | * | ||
228 | * Allocate the port extension structure and register services associated with | ||
229 | * the port. | ||
230 | */ | ||
263 | int pcie_port_device_register(struct pci_dev *dev) | 231 | int pcie_port_device_register(struct pci_dev *dev) |
264 | { | 232 | { |
265 | struct pcie_port_device_ext *p_ext; | 233 | struct pcie_port_device_ext *p_ext; |
@@ -323,6 +291,11 @@ static int suspend_iter(struct device *dev, void *data) | |||
323 | return 0; | 291 | return 0; |
324 | } | 292 | } |
325 | 293 | ||
294 | /** | ||
295 | * pcie_port_device_suspend - suspend port services associated with a PCIe port | ||
296 | * @dev: PCI Express port to handle | ||
297 | * @state: Representation of system power management transition in progress | ||
298 | */ | ||
326 | int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state) | 299 | int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state) |
327 | { | 300 | { |
328 | return device_for_each_child(&dev->dev, &state, suspend_iter); | 301 | return device_for_each_child(&dev->dev, &state, suspend_iter); |
@@ -341,6 +314,10 @@ static int resume_iter(struct device *dev, void *data) | |||
341 | return 0; | 314 | return 0; |
342 | } | 315 | } |
343 | 316 | ||
317 | /** | ||
318 | * pcie_port_device_suspend - resume port services associated with a PCIe port | ||
319 | * @dev: PCI Express port to handle | ||
320 | */ | ||
344 | int pcie_port_device_resume(struct pci_dev *dev) | 321 | int pcie_port_device_resume(struct pci_dev *dev) |
345 | { | 322 | { |
346 | return device_for_each_child(&dev->dev, NULL, resume_iter); | 323 | return device_for_each_child(&dev->dev, NULL, resume_iter); |
@@ -363,6 +340,13 @@ static int remove_iter(struct device *dev, void *data) | |||
363 | return 0; | 340 | return 0; |
364 | } | 341 | } |
365 | 342 | ||
343 | /** | ||
344 | * pcie_port_device_remove - unregister PCI Express port service devices | ||
345 | * @dev: PCI Express port the service devices to unregister are associated with | ||
346 | * | ||
347 | * Remove PCI Express port service devices associated with given port and | ||
348 | * disable MSI-X or MSI for the port. | ||
349 | */ | ||
366 | void pcie_port_device_remove(struct pci_dev *dev) | 350 | void pcie_port_device_remove(struct pci_dev *dev) |
367 | { | 351 | { |
368 | struct device *device; | 352 | struct device *device; |
@@ -386,16 +370,80 @@ void pcie_port_device_remove(struct pci_dev *dev) | |||
386 | pci_disable_msi(dev); | 370 | pci_disable_msi(dev); |
387 | } | 371 | } |
388 | 372 | ||
389 | int pcie_port_bus_register(void) | 373 | /** |
374 | * pcie_port_probe_service - probe driver for given PCI Express port service | ||
375 | * @dev: PCI Express port service device to probe against | ||
376 | * | ||
377 | * If PCI Express port service driver is registered with | ||
378 | * pcie_port_service_register(), this function will be called by the driver core | ||
379 | * whenever match is found between the driver and a port service device. | ||
380 | */ | ||
381 | static int pcie_port_probe_service(struct device *dev) | ||
390 | { | 382 | { |
391 | return bus_register(&pcie_port_bus_type); | 383 | struct pcie_device *pciedev; |
384 | struct pcie_port_service_driver *driver; | ||
385 | int status; | ||
386 | |||
387 | if (!dev || !dev->driver) | ||
388 | return -ENODEV; | ||
389 | |||
390 | driver = to_service_driver(dev->driver); | ||
391 | if (!driver || !driver->probe) | ||
392 | return -ENODEV; | ||
393 | |||
394 | pciedev = to_pcie_device(dev); | ||
395 | status = driver->probe(pciedev, driver->id_table); | ||
396 | if (!status) { | ||
397 | dev_printk(KERN_DEBUG, dev, "service driver %s loaded\n", | ||
398 | driver->name); | ||
399 | get_device(dev); | ||
400 | } | ||
401 | return status; | ||
392 | } | 402 | } |
393 | 403 | ||
394 | void pcie_port_bus_unregister(void) | 404 | /** |
405 | * pcie_port_remove_service - detach driver from given PCI Express port service | ||
406 | * @dev: PCI Express port service device to handle | ||
407 | * | ||
408 | * If PCI Express port service driver is registered with | ||
409 | * pcie_port_service_register(), this function will be called by the driver core | ||
410 | * when device_unregister() is called for the port service device associated | ||
411 | * with the driver. | ||
412 | */ | ||
413 | static int pcie_port_remove_service(struct device *dev) | ||
395 | { | 414 | { |
396 | bus_unregister(&pcie_port_bus_type); | 415 | struct pcie_device *pciedev; |
416 | struct pcie_port_service_driver *driver; | ||
417 | |||
418 | if (!dev || !dev->driver) | ||
419 | return 0; | ||
420 | |||
421 | pciedev = to_pcie_device(dev); | ||
422 | driver = to_service_driver(dev->driver); | ||
423 | if (driver && driver->remove) { | ||
424 | dev_printk(KERN_DEBUG, dev, "unloading service driver %s\n", | ||
425 | driver->name); | ||
426 | driver->remove(pciedev); | ||
427 | put_device(dev); | ||
428 | } | ||
429 | return 0; | ||
397 | } | 430 | } |
398 | 431 | ||
432 | /** | ||
433 | * pcie_port_shutdown_service - shut down given PCI Express port service | ||
434 | * @dev: PCI Express port service device to handle | ||
435 | * | ||
436 | * If PCI Express port service driver is registered with | ||
437 | * pcie_port_service_register(), this function will be called by the driver core | ||
438 | * when device_shutdown() is called for the port service device associated | ||
439 | * with the driver. | ||
440 | */ | ||
441 | static void pcie_port_shutdown_service(struct device *dev) {} | ||
442 | |||
443 | /** | ||
444 | * pcie_port_service_register - register PCI Express port service driver | ||
445 | * @new: PCI Express port service driver to register | ||
446 | */ | ||
399 | int pcie_port_service_register(struct pcie_port_service_driver *new) | 447 | int pcie_port_service_register(struct pcie_port_service_driver *new) |
400 | { | 448 | { |
401 | new->driver.name = (char *)new->name; | 449 | new->driver.name = (char *)new->name; |
@@ -403,15 +451,17 @@ int pcie_port_service_register(struct pcie_port_service_driver *new) | |||
403 | new->driver.probe = pcie_port_probe_service; | 451 | new->driver.probe = pcie_port_probe_service; |
404 | new->driver.remove = pcie_port_remove_service; | 452 | new->driver.remove = pcie_port_remove_service; |
405 | new->driver.shutdown = pcie_port_shutdown_service; | 453 | new->driver.shutdown = pcie_port_shutdown_service; |
406 | new->driver.suspend = pcie_port_suspend_service; | ||
407 | new->driver.resume = pcie_port_resume_service; | ||
408 | 454 | ||
409 | return driver_register(&new->driver); | 455 | return driver_register(&new->driver); |
410 | } | 456 | } |
411 | 457 | ||
412 | void pcie_port_service_unregister(struct pcie_port_service_driver *new) | 458 | /** |
459 | * pcie_port_service_unregister - unregister PCI Express port service driver | ||
460 | * @drv: PCI Express port service driver to unregister | ||
461 | */ | ||
462 | void pcie_port_service_unregister(struct pcie_port_service_driver *drv) | ||
413 | { | 463 | { |
414 | driver_unregister(&new->driver); | 464 | driver_unregister(&drv->driver); |
415 | } | 465 | } |
416 | 466 | ||
417 | EXPORT_SYMBOL(pcie_port_service_register); | 467 | EXPORT_SYMBOL(pcie_port_service_register); |
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 584422da8d8b..99a914a027f8 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c | |||
@@ -41,7 +41,6 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev) | |||
41 | { | 41 | { |
42 | int retval; | 42 | int retval; |
43 | 43 | ||
44 | pci_restore_state(dev); | ||
45 | retval = pci_enable_device(dev); | 44 | retval = pci_enable_device(dev); |
46 | if (retval) | 45 | if (retval) |
47 | return retval; | 46 | return retval; |
@@ -52,11 +51,18 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev) | |||
52 | #ifdef CONFIG_PM | 51 | #ifdef CONFIG_PM |
53 | static int pcie_portdrv_suspend(struct pci_dev *dev, pm_message_t state) | 52 | static int pcie_portdrv_suspend(struct pci_dev *dev, pm_message_t state) |
54 | { | 53 | { |
55 | int ret = pcie_port_device_suspend(dev, state); | 54 | return pcie_port_device_suspend(dev, state); |
56 | 55 | ||
57 | if (!ret) | 56 | } |
58 | ret = pcie_portdrv_save_config(dev); | 57 | |
59 | return ret; | 58 | static int pcie_portdrv_suspend_late(struct pci_dev *dev, pm_message_t state) |
59 | { | ||
60 | return pci_save_state(dev); | ||
61 | } | ||
62 | |||
63 | static int pcie_portdrv_resume_early(struct pci_dev *dev) | ||
64 | { | ||
65 | return pci_restore_state(dev); | ||
60 | } | 66 | } |
61 | 67 | ||
62 | static int pcie_portdrv_resume(struct pci_dev *dev) | 68 | static int pcie_portdrv_resume(struct pci_dev *dev) |
@@ -66,6 +72,8 @@ static int pcie_portdrv_resume(struct pci_dev *dev) | |||
66 | } | 72 | } |
67 | #else | 73 | #else |
68 | #define pcie_portdrv_suspend NULL | 74 | #define pcie_portdrv_suspend NULL |
75 | #define pcie_portdrv_suspend_late NULL | ||
76 | #define pcie_portdrv_resume_early NULL | ||
69 | #define pcie_portdrv_resume NULL | 77 | #define pcie_portdrv_resume NULL |
70 | #endif | 78 | #endif |
71 | 79 | ||
@@ -221,6 +229,7 @@ static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev) | |||
221 | 229 | ||
222 | /* If fatal, restore cfg space for possible link reset at upstream */ | 230 | /* If fatal, restore cfg space for possible link reset at upstream */ |
223 | if (dev->error_state == pci_channel_io_frozen) { | 231 | if (dev->error_state == pci_channel_io_frozen) { |
232 | pci_restore_state(dev); | ||
224 | pcie_portdrv_restore_config(dev); | 233 | pcie_portdrv_restore_config(dev); |
225 | pci_enable_pcie_error_reporting(dev); | 234 | pci_enable_pcie_error_reporting(dev); |
226 | } | 235 | } |
@@ -283,6 +292,8 @@ static struct pci_driver pcie_portdriver = { | |||
283 | .remove = pcie_portdrv_remove, | 292 | .remove = pcie_portdrv_remove, |
284 | 293 | ||
285 | .suspend = pcie_portdrv_suspend, | 294 | .suspend = pcie_portdrv_suspend, |
295 | .suspend_late = pcie_portdrv_suspend_late, | ||
296 | .resume_early = pcie_portdrv_resume_early, | ||
286 | .resume = pcie_portdrv_resume, | 297 | .resume = pcie_portdrv_resume, |
287 | 298 | ||
288 | .err_handler = &pcie_portdrv_err_handler, | 299 | .err_handler = &pcie_portdrv_err_handler, |