blob: 63d6618a4804acc42fd9ab2b44aa3df41a530422 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * File: pci-acpi.c
Len Browna406d9e2005-03-23 16:16:03 -05003 * Purpose: Provide PCI support in ACPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
David Shaohua Li84df749f2005-03-18 18:53:36 -05005 * Copyright (C) 2005 David Shaohua Li <shaohua.li@intel.com>
6 * Copyright (C) 2004 Tom Long Nguyen <tom.l.nguyen@intel.com>
7 * Copyright (C) 2004 Intel Corp.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 */
9
10#include <linux/delay.h>
11#include <linux/init.h>
12#include <linux/pci.h>
13#include <linux/module.h>
Shaohua Li5fde2442008-07-23 10:32:24 +080014#include <linux/pci-aspm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <acpi/acpi.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <acpi/acpi_bus.h>
17
18#include <linux/pci-acpi.h>
Rafael J. Wysockib67ea762010-02-17 23:44:09 +010019#include <linux/pm_runtime.h>
Rafael J. Wysocki8b713a82012-10-24 02:08:38 +020020#include <linux/pm_qos.h>
David Shaohua Li0f644742005-03-19 00:15:48 -050021#include "pci.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
Rafael J. Wysockib67ea762010-02-17 23:44:09 +010023static DEFINE_MUTEX(pci_acpi_pm_notify_mtx);
24
25/**
26 * pci_acpi_wake_bus - Wake-up notification handler for root buses.
27 * @handle: ACPI handle of a device the notification is for.
28 * @event: Type of the signaled event.
29 * @context: PCI root bus to wake up devices on.
30 */
31static void pci_acpi_wake_bus(acpi_handle handle, u32 event, void *context)
32{
33 struct pci_bus *pci_bus = context;
34
35 if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_bus)
36 pci_pme_wakeup_bus(pci_bus);
37}
38
39/**
40 * pci_acpi_wake_dev - Wake-up notification handler for PCI devices.
41 * @handle: ACPI handle of a device the notification is for.
42 * @event: Type of the signaled event.
43 * @context: PCI device object to wake up.
44 */
45static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
46{
47 struct pci_dev *pci_dev = context;
48
Rafael J. Wysockia4249482011-11-06 22:21:46 +010049 if (event != ACPI_NOTIFY_DEVICE_WAKE || !pci_dev)
50 return;
51
Huang Ying448bd852012-06-23 10:23:51 +080052 if (pci_dev->current_state == PCI_D3cold) {
53 pci_wakeup_event(pci_dev);
54 pm_runtime_resume(&pci_dev->dev);
55 return;
56 }
57
Rafael J. Wysockia4249482011-11-06 22:21:46 +010058 if (!pci_dev->pm_cap || !pci_dev->pme_support
59 || pci_check_pme_status(pci_dev)) {
Rafael J. Wysocki379021d2011-10-03 23:16:33 +020060 if (pci_dev->pme_poll)
61 pci_dev->pme_poll = false;
62
Rafael J. Wysocki0f953bf2010-12-29 13:22:08 +010063 pci_wakeup_event(pci_dev);
Rafael J. Wysockib67ea762010-02-17 23:44:09 +010064 pm_runtime_resume(&pci_dev->dev);
Rafael J. Wysockib67ea762010-02-17 23:44:09 +010065 }
Rafael J. Wysockia4249482011-11-06 22:21:46 +010066
67 if (pci_dev->subordinate)
68 pci_pme_wakeup_bus(pci_dev->subordinate);
Rafael J. Wysockib67ea762010-02-17 23:44:09 +010069}
70
71/**
72 * add_pm_notifier - Register PM notifier for given ACPI device.
73 * @dev: ACPI device to add the notifier for.
74 * @context: PCI device or bus to check for PME status if an event is signaled.
75 *
76 * NOTE: @dev need not be a run-wake or wake-up device to be a valid source of
77 * PM wake-up events. For example, wake-up events may be generated for bridges
78 * if one of the devices below the bridge is signaling PME, even if the bridge
79 * itself doesn't have a wake-up GPE associated with it.
80 */
81static acpi_status add_pm_notifier(struct acpi_device *dev,
82 acpi_notify_handler handler,
83 void *context)
84{
85 acpi_status status = AE_ALREADY_EXISTS;
86
87 mutex_lock(&pci_acpi_pm_notify_mtx);
88
89 if (dev->wakeup.flags.notifier_present)
90 goto out;
91
92 status = acpi_install_notify_handler(dev->handle,
93 ACPI_SYSTEM_NOTIFY,
94 handler, context);
95 if (ACPI_FAILURE(status))
96 goto out;
97
98 dev->wakeup.flags.notifier_present = true;
99
100 out:
101 mutex_unlock(&pci_acpi_pm_notify_mtx);
102 return status;
103}
104
105/**
106 * remove_pm_notifier - Unregister PM notifier from given ACPI device.
107 * @dev: ACPI device to remove the notifier from.
108 */
109static acpi_status remove_pm_notifier(struct acpi_device *dev,
110 acpi_notify_handler handler)
111{
112 acpi_status status = AE_BAD_PARAMETER;
113
114 mutex_lock(&pci_acpi_pm_notify_mtx);
115
116 if (!dev->wakeup.flags.notifier_present)
117 goto out;
118
119 status = acpi_remove_notify_handler(dev->handle,
120 ACPI_SYSTEM_NOTIFY,
121 handler);
122 if (ACPI_FAILURE(status))
123 goto out;
124
125 dev->wakeup.flags.notifier_present = false;
126
127 out:
128 mutex_unlock(&pci_acpi_pm_notify_mtx);
129 return status;
130}
131
132/**
133 * pci_acpi_add_bus_pm_notifier - Register PM notifier for given PCI bus.
134 * @dev: ACPI device to add the notifier for.
135 * @pci_bus: PCI bus to walk checking for PME status if an event is signaled.
136 */
137acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev,
138 struct pci_bus *pci_bus)
139{
140 return add_pm_notifier(dev, pci_acpi_wake_bus, pci_bus);
141}
142
143/**
144 * pci_acpi_remove_bus_pm_notifier - Unregister PCI bus PM notifier.
145 * @dev: ACPI device to remove the notifier from.
146 */
147acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev)
148{
149 return remove_pm_notifier(dev, pci_acpi_wake_bus);
150}
151
152/**
153 * pci_acpi_add_pm_notifier - Register PM notifier for given PCI device.
154 * @dev: ACPI device to add the notifier for.
155 * @pci_dev: PCI device to check for the PME status if an event is signaled.
156 */
157acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev,
158 struct pci_dev *pci_dev)
159{
160 return add_pm_notifier(dev, pci_acpi_wake_dev, pci_dev);
161}
162
163/**
164 * pci_acpi_remove_pm_notifier - Unregister PCI device PM notifier.
165 * @dev: ACPI device to remove the notifier from.
166 */
167acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev)
168{
169 return remove_pm_notifier(dev, pci_acpi_wake_dev);
170}
171
Jiang Liuf4b57a32012-06-22 14:55:16 +0800172phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
173{
174 acpi_status status = AE_NOT_EXIST;
175 unsigned long long mcfg_addr;
176
177 if (handle)
178 status = acpi_evaluate_integer(handle, METHOD_NAME__CBA,
179 NULL, &mcfg_addr);
180 if (ACPI_FAILURE(status))
181 return 0;
182
183 return (phys_addr_t)mcfg_addr;
184}
185
David Shaohua Li0f644742005-03-19 00:15:48 -0500186/*
187 * _SxD returns the D-state with the highest power
188 * (lowest D-state number) supported in the S-state "x".
189 *
190 * If the devices does not have a _PRW
191 * (Power Resources for Wake) supporting system wakeup from "x"
192 * then the OS is free to choose a lower power (higher number
193 * D-state) than the return value from _SxD.
194 *
195 * But if _PRW is enabled at S-state "x", the OS
196 * must not choose a power lower than _SxD --
197 * unless the device has an _SxW method specifying
198 * the lowest power (highest D-state number) the device
199 * may enter while still able to wake the system.
200 *
201 * ie. depending on global OS policy:
202 *
203 * if (_PRW at S-state x)
204 * choose from highest power _SxD to lowest power _SxW
205 * else // no _PRW at S-state x
206 * choose highest power _SxD or any lower power
David Shaohua Li0f644742005-03-19 00:15:48 -0500207 */
208
Rafael J. Wysocki8d2bdf42008-06-05 01:16:37 +0200209static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev)
David Shaohua Li0f644742005-03-19 00:15:48 -0500210{
Huang Ying448bd852012-06-23 10:23:51 +0800211 int acpi_state, d_max;
David Shaohua Li0f644742005-03-19 00:15:48 -0500212
Huang Ying448bd852012-06-23 10:23:51 +0800213 if (pdev->no_d3cold)
214 d_max = ACPI_STATE_D3_HOT;
215 else
216 d_max = ACPI_STATE_D3_COLD;
217 acpi_state = acpi_pm_device_sleep_state(&pdev->dev, NULL, d_max);
Shaohua Liab826ca2007-07-20 10:03:22 +0800218 if (acpi_state < 0)
219 return PCI_POWER_ERROR;
220
221 switch (acpi_state) {
222 case ACPI_STATE_D0:
223 return PCI_D0;
224 case ACPI_STATE_D1:
225 return PCI_D1;
226 case ACPI_STATE_D2:
227 return PCI_D2;
Lin Ming1cc0c992012-04-23 09:03:49 +0800228 case ACPI_STATE_D3_HOT:
Shaohua Liab826ca2007-07-20 10:03:22 +0800229 return PCI_D3hot;
Lin Ming28c21032011-05-04 22:56:43 +0800230 case ACPI_STATE_D3_COLD:
231 return PCI_D3cold;
Shaohua Liab826ca2007-07-20 10:03:22 +0800232 }
233 return PCI_POWER_ERROR;
David Shaohua Li0f644742005-03-19 00:15:48 -0500234}
Rafael J. Wysocki961d9122008-07-07 03:32:02 +0200235
236static bool acpi_pci_power_manageable(struct pci_dev *dev)
237{
238 acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
239
240 return handle ? acpi_bus_power_manageable(handle) : false;
241}
David Shaohua Li0f644742005-03-19 00:15:48 -0500242
David Shaohua Lib9131002005-03-19 00:16:18 -0500243static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
244{
245 acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
Shaohua Li10b3dca2007-07-20 10:03:25 +0800246 acpi_handle tmp;
David Brownell583c3772008-02-22 21:41:51 -0800247 static const u8 state_conv[] = {
248 [PCI_D0] = ACPI_STATE_D0,
249 [PCI_D1] = ACPI_STATE_D1,
250 [PCI_D2] = ACPI_STATE_D2,
Rafael J. Wysocki5c7dd712012-05-18 00:39:35 +0200251 [PCI_D3hot] = ACPI_STATE_D3,
David Brownell583c3772008-02-22 21:41:51 -0800252 [PCI_D3cold] = ACPI_STATE_D3
David Shaohua Lib9131002005-03-19 00:16:18 -0500253 };
Rafael J. Wysocki44e4e662008-07-07 03:32:52 +0200254 int error = -EINVAL;
David Shaohua Lib9131002005-03-19 00:16:18 -0500255
Shaohua Li10b3dca2007-07-20 10:03:25 +0800256 /* If the ACPI device has _EJ0, ignore the device */
Rafael J. Wysocki44e4e662008-07-07 03:32:52 +0200257 if (!handle || ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp)))
258 return -ENODEV;
David Brownell583c3772008-02-22 21:41:51 -0800259
260 switch (state) {
Rafael J. Wysocki8b713a82012-10-24 02:08:38 +0200261 case PCI_D3cold:
262 if (dev_pm_qos_flags(&dev->dev, PM_QOS_FLAG_NO_POWER_OFF) ==
263 PM_QOS_FLAGS_ALL) {
264 error = -EBUSY;
265 break;
266 }
David Brownell583c3772008-02-22 21:41:51 -0800267 case PCI_D0:
268 case PCI_D1:
269 case PCI_D2:
270 case PCI_D3hot:
Rafael J. Wysocki44e4e662008-07-07 03:32:52 +0200271 error = acpi_bus_set_power(handle, state_conv[state]);
David Brownell583c3772008-02-22 21:41:51 -0800272 }
Rafael J. Wysocki44e4e662008-07-07 03:32:52 +0200273
274 if (!error)
Rafael J. Wysocki3d0882c2012-08-04 23:27:32 +0200275 dev_info(&dev->dev, "power state changed by ACPI to %s\n",
276 pci_power_name(state));
Rafael J. Wysocki44e4e662008-07-07 03:32:52 +0200277
278 return error;
David Shaohua Lib9131002005-03-19 00:16:18 -0500279}
280
Rafael J. Wysockieb9d0fe2008-07-07 03:34:48 +0200281static bool acpi_pci_can_wakeup(struct pci_dev *dev)
282{
283 acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
284
285 return handle ? acpi_bus_can_wakeup(handle) : false;
286}
287
Rafael J. Wysocki0baed8d2009-09-08 23:16:24 +0200288static void acpi_pci_propagate_wakeup_enable(struct pci_bus *bus, bool enable)
289{
290 while (bus->parent) {
Rafael J. Wysockidc1a94a2009-11-29 16:35:54 +0100291 if (!acpi_pm_device_sleep_wake(&bus->self->dev, enable))
Rafael J. Wysocki0baed8d2009-09-08 23:16:24 +0200292 return;
293 bus = bus->parent;
294 }
295
296 /* We have reached the root bus. */
297 if (bus->bridge)
298 acpi_pm_device_sleep_wake(bus->bridge, enable);
299}
300
Rafael J. Wysockieb9d0fe2008-07-07 03:34:48 +0200301static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable)
302{
Rafael J. Wysocki0baed8d2009-09-08 23:16:24 +0200303 if (acpi_pci_can_wakeup(dev))
304 return acpi_pm_device_sleep_wake(&dev->dev, enable);
305
Rafael J. Wysockidc1a94a2009-11-29 16:35:54 +0100306 acpi_pci_propagate_wakeup_enable(dev->bus, enable);
Rafael J. Wysocki0baed8d2009-09-08 23:16:24 +0200307 return 0;
Rafael J. Wysockieb9d0fe2008-07-07 03:34:48 +0200308}
309
Rafael J. Wysockib67ea762010-02-17 23:44:09 +0100310static void acpi_pci_propagate_run_wake(struct pci_bus *bus, bool enable)
311{
312 while (bus->parent) {
313 struct pci_dev *bridge = bus->self;
314
315 if (bridge->pme_interrupt)
316 return;
Lin Mingb24e5092012-03-27 15:43:25 +0800317 if (!acpi_pm_device_run_wake(&bridge->dev, enable))
Rafael J. Wysockib67ea762010-02-17 23:44:09 +0100318 return;
319 bus = bus->parent;
320 }
321
322 /* We have reached the root bus. */
323 if (bus->bridge)
Lin Mingb24e5092012-03-27 15:43:25 +0800324 acpi_pm_device_run_wake(bus->bridge, enable);
Rafael J. Wysockib67ea762010-02-17 23:44:09 +0100325}
326
327static int acpi_pci_run_wake(struct pci_dev *dev, bool enable)
328{
Huang Ying448bd852012-06-23 10:23:51 +0800329 /*
330 * Per PCI Express Base Specification Revision 2.0 section
331 * 5.3.3.2 Link Wakeup, platform support is needed for D3cold
332 * waking up to power on the main link even if there is PME
333 * support for D3cold
334 */
335 if (dev->pme_interrupt && !dev->runtime_d3cold)
Rafael J. Wysockib67ea762010-02-17 23:44:09 +0100336 return 0;
337
Lin Mingb24e5092012-03-27 15:43:25 +0800338 if (!acpi_pm_device_run_wake(&dev->dev, enable))
Rafael J. Wysockib67ea762010-02-17 23:44:09 +0100339 return 0;
340
341 acpi_pci_propagate_run_wake(dev->bus, enable);
342 return 0;
343}
344
Rafael J. Wysocki961d9122008-07-07 03:32:02 +0200345static struct pci_platform_pm_ops acpi_pci_platform_pm = {
346 .is_manageable = acpi_pci_power_manageable,
347 .set_state = acpi_pci_set_power_state,
348 .choose_state = acpi_pci_choose_state,
Rafael J. Wysockieb9d0fe2008-07-07 03:34:48 +0200349 .can_wakeup = acpi_pci_can_wakeup,
350 .sleep_wake = acpi_pci_sleep_wake,
Rafael J. Wysockib67ea762010-02-17 23:44:09 +0100351 .run_wake = acpi_pci_run_wake,
Rafael J. Wysocki961d9122008-07-07 03:32:02 +0200352};
David Shaohua Lib9131002005-03-19 00:16:18 -0500353
David Shaohua Li84df749f2005-03-18 18:53:36 -0500354/* ACPI bus type */
Muthu Kumar9c273b92006-04-28 00:42:21 -0700355static int acpi_pci_find_device(struct device *dev, acpi_handle *handle)
David Shaohua Li84df749f2005-03-18 18:53:36 -0500356{
357 struct pci_dev * pci_dev;
Lin Ming439913f2010-01-28 10:53:19 +0800358 u64 addr;
David Shaohua Li84df749f2005-03-18 18:53:36 -0500359
360 pci_dev = to_pci_dev(dev);
361 /* Please ref to ACPI spec for the syntax of _ADR */
362 addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn);
363 *handle = acpi_get_child(DEVICE_ACPI_HANDLE(dev->parent), addr);
364 if (!*handle)
365 return -ENODEV;
366 return 0;
367}
368
Muthu Kumar9c273b92006-04-28 00:42:21 -0700369static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle)
David Shaohua Li84df749f2005-03-18 18:53:36 -0500370{
371 int num;
372 unsigned int seg, bus;
373
374 /*
375 * The string should be the same as root bridge's name
376 * Please look at 'pci_scan_bus_parented'
377 */
Kay Sievers1a927132008-10-30 02:17:49 +0100378 num = sscanf(dev_name(dev), "pci%04x:%02x", &seg, &bus);
David Shaohua Li84df749f2005-03-18 18:53:36 -0500379 if (num != 2)
380 return -ENODEV;
381 *handle = acpi_get_pci_rootbridge_handle(seg, bus);
382 if (!*handle)
383 return -ENODEV;
384 return 0;
385}
386
Muthu Kumar9c273b92006-04-28 00:42:21 -0700387static struct acpi_bus_type acpi_pci_bus = {
David Shaohua Li84df749f2005-03-18 18:53:36 -0500388 .bus = &pci_bus_type,
Muthu Kumar9c273b92006-04-28 00:42:21 -0700389 .find_device = acpi_pci_find_device,
390 .find_bridge = acpi_pci_find_root_bridge,
David Shaohua Li84df749f2005-03-18 18:53:36 -0500391};
392
Muthu Kumar9c273b92006-04-28 00:42:21 -0700393static int __init acpi_pci_init(void)
David Shaohua Li84df749f2005-03-18 18:53:36 -0500394{
395 int ret;
396
Bob Moore993958f2009-02-03 15:14:33 +0800397 if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_MSI) {
Shaohua Lif8993af2007-04-25 11:05:12 +0800398 printk(KERN_INFO"ACPI FADT declares the system doesn't support MSI, so disable it\n");
399 pci_no_msi();
400 }
Shaohua Li5fde2442008-07-23 10:32:24 +0800401
Bob Moore993958f2009-02-03 15:14:33 +0800402 if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
Shaohua Li5fde2442008-07-23 10:32:24 +0800403 printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n");
404 pcie_no_aspm();
405 }
406
Muthu Kumar9c273b92006-04-28 00:42:21 -0700407 ret = register_acpi_bus_type(&acpi_pci_bus);
David Shaohua Li84df749f2005-03-18 18:53:36 -0500408 if (ret)
409 return 0;
Rafael J. Wysocki961d9122008-07-07 03:32:02 +0200410 pci_set_platform_pm(&acpi_pci_platform_pm);
David Shaohua Li84df749f2005-03-18 18:53:36 -0500411 return 0;
412}
Muthu Kumar9c273b92006-04-28 00:42:21 -0700413arch_initcall(acpi_pci_init);