aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/pci_root.c9
-rw-r--r--drivers/pci/hotplug/acpi_pcihp.c4
-rw-r--r--drivers/pci/hotplug/pciehp.h12
-rw-r--r--drivers/pci/hotplug/pciehp_acpi.c4
-rw-r--r--drivers/pci/hotplug/pciehp_core.c4
-rw-r--r--drivers/pci/pcie/Makefile1
-rw-r--r--drivers/pci/pcie/aer/aerdrv_acpi.c36
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c14
-rw-r--r--drivers/pci/pcie/pme/Makefile5
-rw-r--r--drivers/pci/pcie/pme/pcie_pme.c64
-rw-r--r--drivers/pci/pcie/pme/pcie_pme.h28
-rw-r--r--drivers/pci/pcie/pme/pcie_pme_acpi.c56
-rw-r--r--drivers/pci/pcie/portdrv.h20
-rw-r--r--drivers/pci/pcie/portdrv_acpi.c77
-rw-r--r--drivers/pci/pcie/portdrv_core.c25
-rw-r--r--drivers/pci/pcie/portdrv_pci.c20
16 files changed, 149 insertions, 230 deletions
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
180static 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);
59MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not"); 59MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not");
60MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); 60MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not");
61MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); 61MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
62MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing"); 62MODULE_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 @@
6obj-$(CONFIG_PCIEASPM) += aspm.o 6obj-$(CONFIG_PCIEASPM) += aspm.o
7 7
8pcieportdrv-y := portdrv_core.o portdrv_pci.o portdrv_bus.o 8pcieportdrv-y := portdrv_core.o portdrv_pci.o portdrv_bus.o
9pcieportdrv-$(CONFIG_ACPI) += portdrv_acpi.o
9 10
10obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o 11obj-$(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 **/
31int 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
59static inline int hest_match_pci(struct acpi_hest_aer_common *p, 23static 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 */
773int aer_init(struct pcie_device *dev) 773int 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;
785out:
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
5obj-$(CONFIG_PCIE_PME) += pmedriver.o 5obj-$(CONFIG_PCIE_PME) += pcie_pme.o
6
7pmedriver-objs := pcie_pme.o
8pmedriver-$(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 */
37static 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 */
55static 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
65static int __init pcie_pme_setup(char *str) 40static 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 */
92static 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
99struct pcie_pme_service_data { 49struct 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 */
111static void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable) 61void 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 */
510static int __init pcie_pme_service_init(void) 457static 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
516module_init(pcie_pme_service_init); 462module_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
12struct pcie_device;
13
14#ifdef CONFIG_ACPI
15extern int pcie_pme_acpi_setup(struct pcie_device *srv);
16
17static inline int pcie_pme_platform_notify(struct pcie_device *srv)
18{
19 return pcie_pme_acpi_setup(srv);
20}
21#else /* !CONFIG_ACPI */
22static 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 */
26int 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
23extern bool pcie_ports_disabled; 23extern bool pcie_ports_disabled;
24extern bool pcie_ports_auto;
24 25
25extern struct bus_type pcie_port_bus_type; 26extern struct bus_type pcie_port_bus_type;
26extern int pcie_port_device_register(struct pci_dev *dev); 27extern int pcie_port_device_register(struct pci_dev *dev);
@@ -32,6 +33,8 @@ extern void pcie_port_device_remove(struct pci_dev *dev);
32extern int __must_check pcie_port_bus_register(void); 33extern int __must_check pcie_port_bus_register(void);
33extern void pcie_port_bus_unregister(void); 34extern void pcie_port_bus_unregister(void);
34 35
36struct pci_dev;
37
35#ifdef CONFIG_PCIE_PME 38#ifdef CONFIG_PCIE_PME
36extern bool pcie_pme_msi_disabled; 39extern 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
51extern void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable);
47#else /* !CONFIG_PCIE_PME */ 52#else /* !CONFIG_PCIE_PME */
48static inline void pcie_pme_disable_msi(void) {} 53static inline void pcie_pme_disable_msi(void) {}
49static inline bool pcie_pme_no_msi(void) { return false; } 54static inline bool pcie_pme_no_msi(void) { return false; }
55static 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
59extern int pcie_port_acpi_setup(struct pci_dev *port, int *mask);
60
61static 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 */
66static 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 */
34int 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, &reg16); 258 pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
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, &reg32); 261 pci_read_config_dword(dev, pos + PCI_EXP_SLTCAP, &reg32);
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. */
33bool pcie_ports_disabled; 34bool 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 */
40bool pcie_ports_auto = true;
41
35static int __init pcie_port_setup(char *str) 42static 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