diff options
-rw-r--r-- | Documentation/kernel-parameters.txt | 13 | ||||
-rw-r--r-- | drivers/acpi/pci_root.c | 9 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpi_pcihp.c | 4 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp.h | 12 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_acpi.c | 4 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_core.c | 4 | ||||
-rw-r--r-- | drivers/pci/pcie/Makefile | 1 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_acpi.c | 36 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_core.c | 14 | ||||
-rw-r--r-- | drivers/pci/pcie/pme/Makefile | 5 | ||||
-rw-r--r-- | drivers/pci/pcie/pme/pcie_pme.c | 64 | ||||
-rw-r--r-- | drivers/pci/pcie/pme/pcie_pme.h | 28 | ||||
-rw-r--r-- | drivers/pci/pcie/pme/pcie_pme_acpi.c | 56 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv.h | 20 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_acpi.c | 77 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_core.c | 25 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_pci.c | 20 |
17 files changed, 155 insertions, 237 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index b9008fc3a53d..8f126e878dbe 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -2043,18 +2043,17 @@ and is between 256 and 4096 characters. It is defined in the file | |||
2043 | WARNING: Forcing ASPM on may cause system lockups. | 2043 | WARNING: Forcing ASPM on may cause system lockups. |
2044 | 2044 | ||
2045 | pcie_ports= [PCIE] PCIe ports handling: | 2045 | pcie_ports= [PCIE] PCIe ports handling: |
2046 | auto Ask the BIOS whether or not to use native PCIe services | ||
2047 | associated with PCIe ports (PME, hot-plug, AER). Use | ||
2048 | them only if that is allowed by the BIOS. | ||
2049 | native Use native PCIe services associated with PCIe ports | ||
2050 | unconditionally. | ||
2046 | compat Treat PCIe ports as PCI-to-PCI bridges, disable the PCIe | 2051 | compat Treat PCIe ports as PCI-to-PCI bridges, disable the PCIe |
2047 | ports driver. | 2052 | ports driver. |
2048 | 2053 | ||
2049 | pcie_pme= [PCIE,PM] Native PCIe PME signaling options: | 2054 | pcie_pme= [PCIE,PM] Native PCIe PME signaling options: |
2050 | Format: {auto|force}[,nomsi] | ||
2051 | auto Use native PCIe PME signaling if the BIOS allows the | ||
2052 | kernel to control PCIe config registers of root ports. | ||
2053 | force Use native PCIe PME signaling even if the BIOS refuses | ||
2054 | to allow the kernel to control the relevant PCIe config | ||
2055 | registers. | ||
2056 | nomsi Do not use MSI for native PCIe PME signaling (this makes | 2055 | nomsi Do not use MSI for native PCIe PME signaling (this makes |
2057 | all PCIe root ports use INTx for everything). | 2056 | all PCIe root ports use INTx for all services). |
2058 | 2057 | ||
2059 | pcmv= [HW,PCMCIA] BadgePAD 4 | 2058 | pcmv= [HW,PCMCIA] BadgePAD 4 |
2060 | 2059 | ||
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index c34713112520..3ba8d1f44a73 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c | |||
@@ -33,7 +33,6 @@ | |||
33 | #include <linux/pm_runtime.h> | 33 | #include <linux/pm_runtime.h> |
34 | #include <linux/pci.h> | 34 | #include <linux/pci.h> |
35 | #include <linux/pci-acpi.h> | 35 | #include <linux/pci-acpi.h> |
36 | #include <linux/pci-aspm.h> | ||
37 | #include <linux/acpi.h> | 36 | #include <linux/acpi.h> |
38 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
39 | #include <acpi/acpi_bus.h> | 38 | #include <acpi/acpi_bus.h> |
@@ -568,14 +567,6 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) | |||
568 | if (flags != base_flags) | 567 | if (flags != base_flags) |
569 | acpi_pci_osc_support(root, flags); | 568 | acpi_pci_osc_support(root, flags); |
570 | 569 | ||
571 | flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL; | ||
572 | status = acpi_pci_osc_control_set(root->device->handle, &flags, flags); | ||
573 | |||
574 | if (ACPI_FAILURE(status)) { | ||
575 | printk(KERN_INFO "Unable to assume PCIe control: Disabling ASPM\n"); | ||
576 | pcie_no_aspm(); | ||
577 | } | ||
578 | |||
579 | pci_acpi_add_bus_pm_notifier(device, root->bus); | 570 | pci_acpi_add_bus_pm_notifier(device, root->bus); |
580 | if (device->wakeup.flags.run_wake) | 571 | if (device->wakeup.flags.run_wake) |
581 | device_set_run_wake(root->bus->bridge, true); | 572 | device_set_run_wake(root->bus->bridge, true); |
diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 3d93d529a7bd..3bc72d18b121 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c | |||
@@ -338,9 +338,7 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags) | |||
338 | acpi_handle chandle, handle; | 338 | acpi_handle chandle, handle; |
339 | struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; | 339 | struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; |
340 | 340 | ||
341 | flags &= (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | | 341 | flags &= OSC_SHPC_NATIVE_HP_CONTROL; |
342 | OSC_SHPC_NATIVE_HP_CONTROL | | ||
343 | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); | ||
344 | if (!flags) { | 342 | if (!flags) { |
345 | err("Invalid flags %u specified!\n", flags); | 343 | err("Invalid flags %u specified!\n", flags); |
346 | return -EINVAL; | 344 | return -EINVAL; |
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 4ed76b47b6dc..653de6ff8ac6 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h | |||
@@ -176,19 +176,7 @@ static inline void pciehp_firmware_init(void) | |||
176 | { | 176 | { |
177 | pciehp_acpi_slot_detection_init(); | 177 | pciehp_acpi_slot_detection_init(); |
178 | } | 178 | } |
179 | |||
180 | static inline int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev) | ||
181 | { | ||
182 | int retval; | ||
183 | u32 flags = (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | | ||
184 | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); | ||
185 | retval = acpi_get_hp_hw_control_from_firmware(dev, flags); | ||
186 | if (retval) | ||
187 | return retval; | ||
188 | return pciehp_acpi_slot_detection_check(dev); | ||
189 | } | ||
190 | #else | 179 | #else |
191 | #define pciehp_firmware_init() do {} while (0) | 180 | #define pciehp_firmware_init() do {} while (0) |
192 | #define pciehp_get_hp_hw_control_from_firmware(dev) 0 | ||
193 | #endif /* CONFIG_ACPI */ | 181 | #endif /* CONFIG_ACPI */ |
194 | #endif /* _PCIEHP_H */ | 182 | #endif /* _PCIEHP_H */ |
diff --git a/drivers/pci/hotplug/pciehp_acpi.c b/drivers/pci/hotplug/pciehp_acpi.c index 1f4000a5a108..2574700db461 100644 --- a/drivers/pci/hotplug/pciehp_acpi.c +++ b/drivers/pci/hotplug/pciehp_acpi.c | |||
@@ -85,9 +85,7 @@ static int __init dummy_probe(struct pcie_device *dev) | |||
85 | acpi_handle handle; | 85 | acpi_handle handle; |
86 | struct dummy_slot *slot, *tmp; | 86 | struct dummy_slot *slot, *tmp; |
87 | struct pci_dev *pdev = dev->port; | 87 | struct pci_dev *pdev = dev->port; |
88 | /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */ | 88 | |
89 | if (pciehp_get_hp_hw_control_from_firmware(pdev)) | ||
90 | return -ENODEV; | ||
91 | pos = pci_pcie_cap(pdev); | 89 | pos = pci_pcie_cap(pdev); |
92 | if (!pos) | 90 | if (!pos) |
93 | return -ENODEV; | 91 | return -ENODEV; |
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 3588ea61b0dd..aa5f3ff629ff 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c | |||
@@ -59,7 +59,7 @@ module_param(pciehp_force, bool, 0644); | |||
59 | MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not"); | 59 | MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not"); |
60 | MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); | 60 | MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); |
61 | MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); | 61 | MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); |
62 | MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing"); | 62 | MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if OSHP is missing"); |
63 | 63 | ||
64 | #define PCIE_MODULE_NAME "pciehp" | 64 | #define PCIE_MODULE_NAME "pciehp" |
65 | 65 | ||
@@ -235,7 +235,7 @@ static int pciehp_probe(struct pcie_device *dev) | |||
235 | dev_info(&dev->device, | 235 | dev_info(&dev->device, |
236 | "Bypassing BIOS check for pciehp use on %s\n", | 236 | "Bypassing BIOS check for pciehp use on %s\n", |
237 | pci_name(dev->port)); | 237 | pci_name(dev->port)); |
238 | else if (pciehp_get_hp_hw_control_from_firmware(dev->port)) | 238 | else if (pciehp_acpi_slot_detection_check(dev->port)) |
239 | goto err_out_none; | 239 | goto err_out_none; |
240 | 240 | ||
241 | ctrl = pcie_init(dev); | 241 | ctrl = pcie_init(dev); |
diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile index ea654545e7c4..4d2b18704c47 100644 --- a/drivers/pci/pcie/Makefile +++ b/drivers/pci/pcie/Makefile | |||
@@ -6,6 +6,7 @@ | |||
6 | obj-$(CONFIG_PCIEASPM) += aspm.o | 6 | obj-$(CONFIG_PCIEASPM) += aspm.o |
7 | 7 | ||
8 | pcieportdrv-y := portdrv_core.o portdrv_pci.o portdrv_bus.o | 8 | pcieportdrv-y := portdrv_core.o portdrv_pci.o portdrv_bus.o |
9 | pcieportdrv-$(CONFIG_ACPI) += portdrv_acpi.o | ||
9 | 10 | ||
10 | obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o | 11 | obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o |
11 | 12 | ||
diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c index 3a276a0cea93..2bb9b8972211 100644 --- a/drivers/pci/pcie/aer/aerdrv_acpi.c +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c | |||
@@ -19,42 +19,6 @@ | |||
19 | #include <acpi/apei.h> | 19 | #include <acpi/apei.h> |
20 | #include "aerdrv.h" | 20 | #include "aerdrv.h" |
21 | 21 | ||
22 | /** | ||
23 | * aer_osc_setup - run ACPI _OSC method | ||
24 | * @pciedev: pcie_device which AER is being enabled on | ||
25 | * | ||
26 | * @return: Zero on success. Nonzero otherwise. | ||
27 | * | ||
28 | * Invoked when PCIe bus loads AER service driver. To avoid conflict with | ||
29 | * BIOS AER support requires BIOS to yield AER control to OS native driver. | ||
30 | **/ | ||
31 | int aer_osc_setup(struct pcie_device *pciedev) | ||
32 | { | ||
33 | acpi_status status = AE_NOT_FOUND; | ||
34 | struct pci_dev *pdev = pciedev->port; | ||
35 | acpi_handle handle = NULL; | ||
36 | |||
37 | if (acpi_pci_disabled) | ||
38 | return -1; | ||
39 | |||
40 | handle = acpi_find_root_bridge_handle(pdev); | ||
41 | if (handle) { | ||
42 | u32 flags = OSC_PCI_EXPRESS_AER_CONTROL | | ||
43 | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL; | ||
44 | status = acpi_pci_osc_control_set(handle, &flags, flags); | ||
45 | } | ||
46 | |||
47 | if (ACPI_FAILURE(status)) { | ||
48 | dev_printk(KERN_DEBUG, &pciedev->device, "AER service couldn't " | ||
49 | "init device: %s\n", | ||
50 | (status == AE_SUPPORT || status == AE_NOT_FOUND) ? | ||
51 | "no _OSC support" : "_OSC failed"); | ||
52 | return -1; | ||
53 | } | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | #ifdef CONFIG_ACPI_APEI | 22 | #ifdef CONFIG_ACPI_APEI |
59 | static inline int hest_match_pci(struct acpi_hest_aer_common *p, | 23 | static inline int hest_match_pci(struct acpi_hest_aer_common *p, |
60 | struct pci_dev *pci) | 24 | struct pci_dev *pci) |
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index fc0b5a93e1de..29e268fadf14 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c | |||
@@ -772,22 +772,10 @@ void aer_isr(struct work_struct *work) | |||
772 | */ | 772 | */ |
773 | int aer_init(struct pcie_device *dev) | 773 | int aer_init(struct pcie_device *dev) |
774 | { | 774 | { |
775 | if (pcie_aer_get_firmware_first(dev->port)) { | ||
776 | dev_printk(KERN_DEBUG, &dev->device, | ||
777 | "PCIe errors handled by platform firmware.\n"); | ||
778 | goto out; | ||
779 | } | ||
780 | |||
781 | if (aer_osc_setup(dev)) | ||
782 | goto out; | ||
783 | |||
784 | return 0; | ||
785 | out: | ||
786 | if (forceload) { | 775 | if (forceload) { |
787 | dev_printk(KERN_DEBUG, &dev->device, | 776 | dev_printk(KERN_DEBUG, &dev->device, |
788 | "aerdrv forceload requested.\n"); | 777 | "aerdrv forceload requested.\n"); |
789 | pcie_aer_force_firmware_first(dev->port, 0); | 778 | pcie_aer_force_firmware_first(dev->port, 0); |
790 | return 0; | ||
791 | } | 779 | } |
792 | return -ENXIO; | 780 | return 0; |
793 | } | 781 | } |
diff --git a/drivers/pci/pcie/pme/Makefile b/drivers/pci/pcie/pme/Makefile index 8b9238053080..3c67bf4d26cf 100644 --- a/drivers/pci/pcie/pme/Makefile +++ b/drivers/pci/pcie/pme/Makefile | |||
@@ -2,7 +2,4 @@ | |||
2 | # Makefile for PCI-Express Root Port PME signaling driver | 2 | # Makefile for PCI-Express Root Port PME signaling driver |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_PCIE_PME) += pmedriver.o | 5 | obj-$(CONFIG_PCIE_PME) += pcie_pme.o |
6 | |||
7 | pmedriver-objs := pcie_pme.o | ||
8 | pmedriver-$(CONFIG_ACPI) += pcie_pme_acpi.o | ||
diff --git a/drivers/pci/pcie/pme/pcie_pme.c b/drivers/pci/pcie/pme/pcie_pme.c index bbdea18693d9..9d1361e1a776 100644 --- a/drivers/pci/pcie/pme/pcie_pme.c +++ b/drivers/pci/pcie/pme/pcie_pme.c | |||
@@ -24,37 +24,12 @@ | |||
24 | #include <linux/pm_runtime.h> | 24 | #include <linux/pm_runtime.h> |
25 | 25 | ||
26 | #include "../../pci.h" | 26 | #include "../../pci.h" |
27 | #include "pcie_pme.h" | 27 | #include "../portdrv.h" |
28 | 28 | ||
29 | #define PCI_EXP_RTSTA_PME 0x10000 /* PME status */ | 29 | #define PCI_EXP_RTSTA_PME 0x10000 /* PME status */ |
30 | #define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ | 30 | #define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ |
31 | 31 | ||
32 | /* | 32 | /* |
33 | * If set, this switch will prevent the PCIe root port PME service driver from | ||
34 | * being registered. Consequently, the interrupt-based PCIe PME signaling will | ||
35 | * not be used by any PCIe root ports in that case. | ||
36 | */ | ||
37 | static bool pcie_pme_disabled = true; | ||
38 | |||
39 | /* | ||
40 | * The PCI Express Base Specification 2.0, Section 6.1.8, states the following: | ||
41 | * "In order to maintain compatibility with non-PCI Express-aware system | ||
42 | * software, system power management logic must be configured by firmware to use | ||
43 | * the legacy mechanism of signaling PME by default. PCI Express-aware system | ||
44 | * software must notify the firmware prior to enabling native, interrupt-based | ||
45 | * PME signaling." However, if the platform doesn't provide us with a suitable | ||
46 | * notification mechanism or the notification fails, it is not clear whether or | ||
47 | * not we are supposed to use the interrupt-based PCIe PME signaling. The | ||
48 | * switch below can be used to indicate the desired behaviour. When set, it | ||
49 | * will make the kernel use the interrupt-based PCIe PME signaling regardless of | ||
50 | * the platform notification status, although the kernel will attempt to notify | ||
51 | * the platform anyway. When unset, it will prevent the kernel from using the | ||
52 | * the interrupt-based PCIe PME signaling if the platform notification fails, | ||
53 | * which is the default. | ||
54 | */ | ||
55 | static bool pcie_pme_force_enable; | ||
56 | |||
57 | /* | ||
58 | * If this switch is set, MSI will not be used for PCIe PME signaling. This | 33 | * If this switch is set, MSI will not be used for PCIe PME signaling. This |
59 | * causes the PCIe port driver to use INTx interrupts only, but it turns out | 34 | * causes the PCIe port driver to use INTx interrupts only, but it turns out |
60 | * that using MSI for PCIe PME signaling doesn't play well with PCIe PME-based | 35 | * that using MSI for PCIe PME signaling doesn't play well with PCIe PME-based |
@@ -64,38 +39,13 @@ bool pcie_pme_msi_disabled; | |||
64 | 39 | ||
65 | static int __init pcie_pme_setup(char *str) | 40 | static int __init pcie_pme_setup(char *str) |
66 | { | 41 | { |
67 | if (!strncmp(str, "auto", 4)) | 42 | if (!strncmp(str, "nomsi", 5)) |
68 | pcie_pme_disabled = false; | 43 | pcie_pme_msi_disabled = true; |
69 | else if (!strncmp(str, "force", 5)) | ||
70 | pcie_pme_force_enable = true; | ||
71 | |||
72 | str = strchr(str, ','); | ||
73 | if (str) { | ||
74 | str++; | ||
75 | str += strspn(str, " \t"); | ||
76 | if (*str && !strcmp(str, "nomsi")) | ||
77 | pcie_pme_msi_disabled = true; | ||
78 | } | ||
79 | 44 | ||
80 | return 1; | 45 | return 1; |
81 | } | 46 | } |
82 | __setup("pcie_pme=", pcie_pme_setup); | 47 | __setup("pcie_pme=", pcie_pme_setup); |
83 | 48 | ||
84 | /** | ||
85 | * pcie_pme_platform_setup - Ensure that the kernel controls the PCIe PME. | ||
86 | * @srv: PCIe PME root port service to use for carrying out the check. | ||
87 | * | ||
88 | * Notify the platform that the native PCIe PME is going to be used and return | ||
89 | * 'true' if the control of the PCIe PME registers has been acquired from the | ||
90 | * platform. | ||
91 | */ | ||
92 | static bool pcie_pme_platform_setup(struct pcie_device *srv) | ||
93 | { | ||
94 | if (!pcie_pme_platform_notify(srv)) | ||
95 | return true; | ||
96 | return pcie_pme_force_enable; | ||
97 | } | ||
98 | |||
99 | struct pcie_pme_service_data { | 49 | struct pcie_pme_service_data { |
100 | spinlock_t lock; | 50 | spinlock_t lock; |
101 | struct pcie_device *srv; | 51 | struct pcie_device *srv; |
@@ -108,7 +58,7 @@ struct pcie_pme_service_data { | |||
108 | * @dev: PCIe root port or event collector. | 58 | * @dev: PCIe root port or event collector. |
109 | * @enable: Enable or disable the interrupt. | 59 | * @enable: Enable or disable the interrupt. |
110 | */ | 60 | */ |
111 | static void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable) | 61 | void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable) |
112 | { | 62 | { |
113 | int rtctl_pos; | 63 | int rtctl_pos; |
114 | u16 rtctl; | 64 | u16 rtctl; |
@@ -417,9 +367,6 @@ static int pcie_pme_probe(struct pcie_device *srv) | |||
417 | struct pcie_pme_service_data *data; | 367 | struct pcie_pme_service_data *data; |
418 | int ret; | 368 | int ret; |
419 | 369 | ||
420 | if (!pcie_pme_platform_setup(srv)) | ||
421 | return -EACCES; | ||
422 | |||
423 | data = kzalloc(sizeof(*data), GFP_KERNEL); | 370 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
424 | if (!data) | 371 | if (!data) |
425 | return -ENOMEM; | 372 | return -ENOMEM; |
@@ -509,8 +456,7 @@ static struct pcie_port_service_driver pcie_pme_driver = { | |||
509 | */ | 456 | */ |
510 | static int __init pcie_pme_service_init(void) | 457 | static int __init pcie_pme_service_init(void) |
511 | { | 458 | { |
512 | return pcie_pme_disabled ? | 459 | return pcie_port_service_register(&pcie_pme_driver); |
513 | -ENODEV : pcie_port_service_register(&pcie_pme_driver); | ||
514 | } | 460 | } |
515 | 461 | ||
516 | module_init(pcie_pme_service_init); | 462 | module_init(pcie_pme_service_init); |
diff --git a/drivers/pci/pcie/pme/pcie_pme.h b/drivers/pci/pcie/pme/pcie_pme.h deleted file mode 100644 index b30d2b7c9775..000000000000 --- a/drivers/pci/pcie/pme/pcie_pme.h +++ /dev/null | |||
@@ -1,28 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/pci/pcie/pme/pcie_pme.h | ||
3 | * | ||
4 | * PCI Express Root Port PME signaling support | ||
5 | * | ||
6 | * Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. | ||
7 | */ | ||
8 | |||
9 | #ifndef _PCIE_PME_H_ | ||
10 | #define _PCIE_PME_H_ | ||
11 | |||
12 | struct pcie_device; | ||
13 | |||
14 | #ifdef CONFIG_ACPI | ||
15 | extern int pcie_pme_acpi_setup(struct pcie_device *srv); | ||
16 | |||
17 | static inline int pcie_pme_platform_notify(struct pcie_device *srv) | ||
18 | { | ||
19 | return pcie_pme_acpi_setup(srv); | ||
20 | } | ||
21 | #else /* !CONFIG_ACPI */ | ||
22 | static inline int pcie_pme_platform_notify(struct pcie_device *srv) | ||
23 | { | ||
24 | return 0; | ||
25 | } | ||
26 | #endif /* !CONFIG_ACPI */ | ||
27 | |||
28 | #endif | ||
diff --git a/drivers/pci/pcie/pme/pcie_pme_acpi.c b/drivers/pci/pcie/pme/pcie_pme_acpi.c deleted file mode 100644 index be20222b12d3..000000000000 --- a/drivers/pci/pcie/pme/pcie_pme_acpi.c +++ /dev/null | |||
@@ -1,56 +0,0 @@ | |||
1 | /* | ||
2 | * PCIe Native PME support, ACPI-related part | ||
3 | * | ||
4 | * Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License V2. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/pci.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/errno.h> | ||
14 | #include <linux/acpi.h> | ||
15 | #include <linux/pci-acpi.h> | ||
16 | #include <linux/pcieport_if.h> | ||
17 | |||
18 | /** | ||
19 | * pcie_pme_acpi_setup - Request the ACPI BIOS to release control over PCIe PME. | ||
20 | * @srv - PCIe PME service for a root port or event collector. | ||
21 | * | ||
22 | * Invoked when the PCIe bus type loads PCIe PME service driver. To avoid | ||
23 | * conflict with the BIOS PCIe support requires the BIOS to yield PCIe PME | ||
24 | * control to the kernel. | ||
25 | */ | ||
26 | int pcie_pme_acpi_setup(struct pcie_device *srv) | ||
27 | { | ||
28 | acpi_status status = AE_NOT_FOUND; | ||
29 | struct pci_dev *port = srv->port; | ||
30 | acpi_handle handle; | ||
31 | u32 flags; | ||
32 | int error = 0; | ||
33 | |||
34 | if (acpi_pci_disabled) | ||
35 | return -ENOSYS; | ||
36 | |||
37 | dev_info(&port->dev, "Requesting control of PCIe PME from ACPI BIOS\n"); | ||
38 | |||
39 | handle = acpi_find_root_bridge_handle(port); | ||
40 | if (!handle) | ||
41 | return -EINVAL; | ||
42 | |||
43 | flags = OSC_PCI_EXPRESS_PME_CONTROL | | ||
44 | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL; | ||
45 | |||
46 | status = acpi_pci_osc_control_set(handle, &flags, flags); | ||
47 | if (ACPI_FAILURE(status)) { | ||
48 | dev_info(&port->dev, | ||
49 | "Failed to receive control of PCIe PME service: %s\n", | ||
50 | (status == AE_SUPPORT || status == AE_NOT_FOUND) ? | ||
51 | "no _OSC support" : "ACPI _OSC failed"); | ||
52 | error = -ENODEV; | ||
53 | } | ||
54 | |||
55 | return error; | ||
56 | } | ||
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index 966f6e9761c8..7b5aba0a3291 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h | |||
@@ -21,6 +21,7 @@ | |||
21 | #define get_descriptor_id(type, service) (((type - 4) << 4) | service) | 21 | #define get_descriptor_id(type, service) (((type - 4) << 4) | service) |
22 | 22 | ||
23 | extern bool pcie_ports_disabled; | 23 | extern bool pcie_ports_disabled; |
24 | extern bool pcie_ports_auto; | ||
24 | 25 | ||
25 | extern struct bus_type pcie_port_bus_type; | 26 | extern struct bus_type pcie_port_bus_type; |
26 | extern int pcie_port_device_register(struct pci_dev *dev); | 27 | extern int pcie_port_device_register(struct pci_dev *dev); |
@@ -32,6 +33,8 @@ extern void pcie_port_device_remove(struct pci_dev *dev); | |||
32 | extern int __must_check pcie_port_bus_register(void); | 33 | extern int __must_check pcie_port_bus_register(void); |
33 | extern void pcie_port_bus_unregister(void); | 34 | extern void pcie_port_bus_unregister(void); |
34 | 35 | ||
36 | struct pci_dev; | ||
37 | |||
35 | #ifdef CONFIG_PCIE_PME | 38 | #ifdef CONFIG_PCIE_PME |
36 | extern bool pcie_pme_msi_disabled; | 39 | extern bool pcie_pme_msi_disabled; |
37 | 40 | ||
@@ -44,9 +47,26 @@ static inline bool pcie_pme_no_msi(void) | |||
44 | { | 47 | { |
45 | return pcie_pme_msi_disabled; | 48 | return pcie_pme_msi_disabled; |
46 | } | 49 | } |
50 | |||
51 | extern void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable); | ||
47 | #else /* !CONFIG_PCIE_PME */ | 52 | #else /* !CONFIG_PCIE_PME */ |
48 | static inline void pcie_pme_disable_msi(void) {} | 53 | static inline void pcie_pme_disable_msi(void) {} |
49 | static inline bool pcie_pme_no_msi(void) { return false; } | 54 | static inline bool pcie_pme_no_msi(void) { return false; } |
55 | static inline void pcie_pme_interrupt_enable(struct pci_dev *dev, bool en) {} | ||
50 | #endif /* !CONFIG_PCIE_PME */ | 56 | #endif /* !CONFIG_PCIE_PME */ |
51 | 57 | ||
58 | #ifdef CONFIG_ACPI | ||
59 | extern int pcie_port_acpi_setup(struct pci_dev *port, int *mask); | ||
60 | |||
61 | static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask) | ||
62 | { | ||
63 | return pcie_port_acpi_setup(port, mask); | ||
64 | } | ||
65 | #else /* !CONFIG_ACPI */ | ||
66 | static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask) | ||
67 | { | ||
68 | return 0; | ||
69 | } | ||
70 | #endif /* !CONFIG_ACPI */ | ||
71 | |||
52 | #endif /* _PORTDRV_H_ */ | 72 | #endif /* _PORTDRV_H_ */ |
diff --git a/drivers/pci/pcie/portdrv_acpi.c b/drivers/pci/pcie/portdrv_acpi.c new file mode 100644 index 000000000000..b7c4cb1ccb23 --- /dev/null +++ b/drivers/pci/pcie/portdrv_acpi.c | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * PCIe Port Native Services Support, ACPI-Related Part | ||
3 | * | ||
4 | * Copyright (C) 2010 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License V2. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/pci.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/errno.h> | ||
14 | #include <linux/acpi.h> | ||
15 | #include <linux/pci-acpi.h> | ||
16 | #include <linux/pcieport_if.h> | ||
17 | |||
18 | #include "aer/aerdrv.h" | ||
19 | #include "../pci.h" | ||
20 | |||
21 | /** | ||
22 | * pcie_port_acpi_setup - Request the BIOS to release control of PCIe services. | ||
23 | * @port: PCIe Port service for a root port or event collector. | ||
24 | * @srv_mask: Bit mask of services that can be enabled for @port. | ||
25 | * | ||
26 | * Invoked when @port is identified as a PCIe port device. To avoid conflicts | ||
27 | * with the BIOS PCIe port native services support requires the BIOS to yield | ||
28 | * control of these services to the kernel. The mask of services that the BIOS | ||
29 | * allows to be enabled for @port is written to @srv_mask. | ||
30 | * | ||
31 | * NOTE: It turns out that we cannot do that for individual port services | ||
32 | * separately, because that would make some systems work incorrectly. | ||
33 | */ | ||
34 | int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask) | ||
35 | { | ||
36 | acpi_status status; | ||
37 | acpi_handle handle; | ||
38 | u32 flags; | ||
39 | |||
40 | if (acpi_pci_disabled) | ||
41 | return 0; | ||
42 | |||
43 | handle = acpi_find_root_bridge_handle(port); | ||
44 | if (!handle) | ||
45 | return -EINVAL; | ||
46 | |||
47 | flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL | ||
48 | | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | ||
49 | | OSC_PCI_EXPRESS_PME_CONTROL; | ||
50 | |||
51 | if (pci_aer_available()) { | ||
52 | if (pcie_aer_get_firmware_first(port)) | ||
53 | dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n"); | ||
54 | else | ||
55 | flags |= OSC_PCI_EXPRESS_AER_CONTROL; | ||
56 | } | ||
57 | |||
58 | status = acpi_pci_osc_control_set(handle, &flags, | ||
59 | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); | ||
60 | if (ACPI_FAILURE(status)) { | ||
61 | dev_dbg(&port->dev, "ACPI _OSC request failed (code %d)\n", | ||
62 | status); | ||
63 | return -ENODEV; | ||
64 | } | ||
65 | |||
66 | dev_info(&port->dev, "ACPI _OSC control granted for 0x%02x\n", flags); | ||
67 | |||
68 | *srv_mask = PCIE_PORT_SERVICE_VC; | ||
69 | if (flags & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL) | ||
70 | *srv_mask |= PCIE_PORT_SERVICE_HP; | ||
71 | if (flags & OSC_PCI_EXPRESS_PME_CONTROL) | ||
72 | *srv_mask |= PCIE_PORT_SERVICE_PME; | ||
73 | if (flags & OSC_PCI_EXPRESS_AER_CONTROL) | ||
74 | *srv_mask |= PCIE_PORT_SERVICE_AER; | ||
75 | |||
76 | return 0; | ||
77 | } | ||
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 2bf2fe510e15..d0245c83b621 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c | |||
@@ -14,6 +14,8 @@ | |||
14 | #include <linux/string.h> | 14 | #include <linux/string.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/pcieport_if.h> | 16 | #include <linux/pcieport_if.h> |
17 | #include <linux/aer.h> | ||
18 | #include <linux/pci-aspm.h> | ||
17 | 19 | ||
18 | #include "../pci.h" | 20 | #include "../pci.h" |
19 | #include "portdrv.h" | 21 | #include "portdrv.h" |
@@ -236,23 +238,40 @@ static int get_port_device_capability(struct pci_dev *dev) | |||
236 | int services = 0, pos; | 238 | int services = 0, pos; |
237 | u16 reg16; | 239 | u16 reg16; |
238 | u32 reg32; | 240 | u32 reg32; |
241 | int cap_mask; | ||
242 | int err; | ||
243 | |||
244 | err = pcie_port_platform_notify(dev, &cap_mask); | ||
245 | if (pcie_ports_auto) { | ||
246 | if (err) { | ||
247 | pcie_no_aspm(); | ||
248 | return 0; | ||
249 | } | ||
250 | } else { | ||
251 | cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP | ||
252 | | PCIE_PORT_SERVICE_VC; | ||
253 | if (pci_aer_available()) | ||
254 | cap_mask |= PCIE_PORT_SERVICE_AER; | ||
255 | } | ||
239 | 256 | ||
240 | pos = pci_pcie_cap(dev); | 257 | pos = pci_pcie_cap(dev); |
241 | pci_read_config_word(dev, pos + PCI_EXP_FLAGS, ®16); | 258 | pci_read_config_word(dev, pos + PCI_EXP_FLAGS, ®16); |
242 | /* Hot-Plug Capable */ | 259 | /* Hot-Plug Capable */ |
243 | if (reg16 & PCI_EXP_FLAGS_SLOT) { | 260 | if ((cap_mask & PCIE_PORT_SERVICE_HP) && (reg16 & PCI_EXP_FLAGS_SLOT)) { |
244 | pci_read_config_dword(dev, pos + PCI_EXP_SLTCAP, ®32); | 261 | pci_read_config_dword(dev, pos + PCI_EXP_SLTCAP, ®32); |
245 | if (reg32 & PCI_EXP_SLTCAP_HPC) | 262 | if (reg32 & PCI_EXP_SLTCAP_HPC) |
246 | services |= PCIE_PORT_SERVICE_HP; | 263 | services |= PCIE_PORT_SERVICE_HP; |
247 | } | 264 | } |
248 | /* AER capable */ | 265 | /* AER capable */ |
249 | if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR)) | 266 | if ((cap_mask & PCIE_PORT_SERVICE_AER) |
267 | && pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR)) | ||
250 | services |= PCIE_PORT_SERVICE_AER; | 268 | services |= PCIE_PORT_SERVICE_AER; |
251 | /* VC support */ | 269 | /* VC support */ |
252 | if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC)) | 270 | if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC)) |
253 | services |= PCIE_PORT_SERVICE_VC; | 271 | services |= PCIE_PORT_SERVICE_VC; |
254 | /* Root ports are capable of generating PME too */ | 272 | /* Root ports are capable of generating PME too */ |
255 | if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) | 273 | if ((cap_mask & PCIE_PORT_SERVICE_PME) |
274 | && dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) | ||
256 | services |= PCIE_PORT_SERVICE_PME; | 275 | services |= PCIE_PORT_SERVICE_PME; |
257 | 276 | ||
258 | return services; | 277 | return services; |
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index a04392da6ce1..8f1338d1c53f 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/pcieport_if.h> | 15 | #include <linux/pcieport_if.h> |
16 | #include <linux/aer.h> | 16 | #include <linux/aer.h> |
17 | #include <linux/dmi.h> | 17 | #include <linux/dmi.h> |
18 | #include <linux/pci-aspm.h> | ||
18 | 19 | ||
19 | #include "portdrv.h" | 20 | #include "portdrv.h" |
20 | #include "aer/aerdrv.h" | 21 | #include "aer/aerdrv.h" |
@@ -32,10 +33,23 @@ MODULE_LICENSE("GPL"); | |||
32 | /* If this switch is set, PCIe port native services should not be enabled. */ | 33 | /* If this switch is set, PCIe port native services should not be enabled. */ |
33 | bool pcie_ports_disabled; | 34 | bool pcie_ports_disabled; |
34 | 35 | ||
36 | /* | ||
37 | * If this switch is set, ACPI _OSC will be used to determine whether or not to | ||
38 | * enable PCIe port native services. | ||
39 | */ | ||
40 | bool pcie_ports_auto = true; | ||
41 | |||
35 | static int __init pcie_port_setup(char *str) | 42 | static int __init pcie_port_setup(char *str) |
36 | { | 43 | { |
37 | if (!strncmp(str, "compat", 6)) | 44 | if (!strncmp(str, "compat", 6)) { |
38 | pcie_ports_disabled = true; | 45 | pcie_ports_disabled = true; |
46 | } else if (!strncmp(str, "native", 6)) { | ||
47 | pcie_ports_disabled = false; | ||
48 | pcie_ports_auto = false; | ||
49 | } else if (!strncmp(str, "auto", 4)) { | ||
50 | pcie_ports_disabled = false; | ||
51 | pcie_ports_auto = true; | ||
52 | } | ||
39 | 53 | ||
40 | return 1; | 54 | return 1; |
41 | } | 55 | } |
@@ -313,8 +327,10 @@ static int __init pcie_portdrv_init(void) | |||
313 | { | 327 | { |
314 | int retval; | 328 | int retval; |
315 | 329 | ||
316 | if (pcie_ports_disabled) | 330 | if (pcie_ports_disabled) { |
331 | pcie_no_aspm(); | ||
317 | return -EACCES; | 332 | return -EACCES; |
333 | } | ||
318 | 334 | ||
319 | dmi_check_system(pcie_portdrv_dmi_table); | 335 | dmi_check_system(pcie_portdrv_dmi_table); |
320 | 336 | ||