Commit fe31e69740eddc7316071ed5165fed6703c8cd12
Committed by
Jesse Barnes
1 parent
99a0fadf56
Exists in
master
and in
4 other branches
PCI/PCIe: Clear Root PME Status bits early during system resume
I noticed that PCI Express PMEs don't work on my Toshiba Portege R500 after the system has been woken up from a sleep state by a PME (through Wake-on-LAN). After some investigation it turned out that the BIOS didn't clear the Root PME Status bit in the root port that received the wakeup PME and since the Requester ID was also set in the port's Root Status register, any subsequent PMEs didn't trigger interrupts. This problem can be avoided by clearing the Root PME Status bits in all PCI Express root ports during early resume. For this purpose, add an early resume routine to the PCIe port driver and make this driver be always registered, even if pci_ports_disable is set (in which case the driver's only function is to provide the early resume callback). Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Showing 5 changed files with 55 additions and 38 deletions Side-by-side Diff
drivers/pci/pcie/pme.c
... | ... | @@ -26,9 +26,6 @@ |
26 | 26 | #include "../pci.h" |
27 | 27 | #include "portdrv.h" |
28 | 28 | |
29 | -#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */ | |
30 | -#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ | |
31 | - | |
32 | 29 | /* |
33 | 30 | * If this switch is set, MSI will not be used for PCIe PME signaling. This |
34 | 31 | * causes the PCIe port driver to use INTx interrupts only, but it turns out |
... | ... | @@ -74,22 +71,6 @@ |
74 | 71 | } |
75 | 72 | |
76 | 73 | /** |
77 | - * pcie_pme_clear_status - Clear root port PME interrupt status. | |
78 | - * @dev: PCIe root port or event collector. | |
79 | - */ | |
80 | -static void pcie_pme_clear_status(struct pci_dev *dev) | |
81 | -{ | |
82 | - int rtsta_pos; | |
83 | - u32 rtsta; | |
84 | - | |
85 | - rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA; | |
86 | - | |
87 | - pci_read_config_dword(dev, rtsta_pos, &rtsta); | |
88 | - rtsta |= PCI_EXP_RTSTA_PME; | |
89 | - pci_write_config_dword(dev, rtsta_pos, rtsta); | |
90 | -} | |
91 | - | |
92 | -/** | |
93 | 74 | * pcie_pme_walk_bus - Scan a PCI bus for devices asserting PME#. |
94 | 75 | * @bus: PCI bus to scan. |
95 | 76 | * |
... | ... | @@ -253,7 +234,7 @@ |
253 | 234 | * Clear PME status of the port. If there are other |
254 | 235 | * pending PMEs, the status will be set again. |
255 | 236 | */ |
256 | - pcie_pme_clear_status(port); | |
237 | + pcie_clear_root_pme_status(port); | |
257 | 238 | |
258 | 239 | spin_unlock_irq(&data->lock); |
259 | 240 | pcie_pme_handle_request(port, rtsta & 0xffff); |
... | ... | @@ -378,7 +359,7 @@ |
378 | 359 | |
379 | 360 | port = srv->port; |
380 | 361 | pcie_pme_interrupt_enable(port, false); |
381 | - pcie_pme_clear_status(port); | |
362 | + pcie_clear_root_pme_status(port); | |
382 | 363 | |
383 | 364 | ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED, "PCIe PME", srv); |
384 | 365 | if (ret) { |
... | ... | @@ -402,7 +383,7 @@ |
402 | 383 | |
403 | 384 | spin_lock_irq(&data->lock); |
404 | 385 | pcie_pme_interrupt_enable(port, false); |
405 | - pcie_pme_clear_status(port); | |
386 | + pcie_clear_root_pme_status(port); | |
406 | 387 | data->noirq = true; |
407 | 388 | spin_unlock_irq(&data->lock); |
408 | 389 | |
... | ... | @@ -422,7 +403,7 @@ |
422 | 403 | |
423 | 404 | spin_lock_irq(&data->lock); |
424 | 405 | data->noirq = false; |
425 | - pcie_pme_clear_status(port); | |
406 | + pcie_clear_root_pme_status(port); | |
426 | 407 | pcie_pme_interrupt_enable(port, true); |
427 | 408 | spin_unlock_irq(&data->lock); |
428 | 409 |
drivers/pci/pcie/portdrv.h
drivers/pci/pcie/portdrv_core.c
... | ... | @@ -241,17 +241,17 @@ |
241 | 241 | int cap_mask; |
242 | 242 | int err; |
243 | 243 | |
244 | + if (pcie_ports_disabled) | |
245 | + return 0; | |
246 | + | |
244 | 247 | 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 { | |
248 | + if (!pcie_ports_auto) { | |
251 | 249 | cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP |
252 | 250 | | PCIE_PORT_SERVICE_VC; |
253 | 251 | if (pci_aer_available()) |
254 | 252 | cap_mask |= PCIE_PORT_SERVICE_AER; |
253 | + } else if (err) { | |
254 | + return 0; | |
255 | 255 | } |
256 | 256 | |
257 | 257 | pos = pci_pcie_cap(dev); |
258 | 258 | |
... | ... | @@ -349,15 +349,18 @@ |
349 | 349 | int status, capabilities, i, nr_service; |
350 | 350 | int irqs[PCIE_PORT_DEVICE_MAXSERVICES]; |
351 | 351 | |
352 | - /* Get and check PCI Express port services */ | |
353 | - capabilities = get_port_device_capability(dev); | |
354 | - if (!capabilities) | |
355 | - return -ENODEV; | |
356 | - | |
357 | 352 | /* Enable PCI Express port device */ |
358 | 353 | status = pci_enable_device(dev); |
359 | 354 | if (status) |
360 | 355 | return status; |
356 | + | |
357 | + /* Get and check PCI Express port services */ | |
358 | + capabilities = get_port_device_capability(dev); | |
359 | + if (!capabilities) { | |
360 | + pcie_no_aspm(); | |
361 | + return 0; | |
362 | + } | |
363 | + | |
361 | 364 | pci_set_master(dev); |
362 | 365 | /* |
363 | 366 | * Initialize service irqs. Don't use service devices that |
drivers/pci/pcie/portdrv_pci.c
... | ... | @@ -57,6 +57,22 @@ |
57 | 57 | |
58 | 58 | /* global data */ |
59 | 59 | |
60 | +/** | |
61 | + * pcie_clear_root_pme_status - Clear root port PME interrupt status. | |
62 | + * @dev: PCIe root port or event collector. | |
63 | + */ | |
64 | +void pcie_clear_root_pme_status(struct pci_dev *dev) | |
65 | +{ | |
66 | + int rtsta_pos; | |
67 | + u32 rtsta; | |
68 | + | |
69 | + rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA; | |
70 | + | |
71 | + pci_read_config_dword(dev, rtsta_pos, &rtsta); | |
72 | + rtsta |= PCI_EXP_RTSTA_PME; | |
73 | + pci_write_config_dword(dev, rtsta_pos, rtsta); | |
74 | +} | |
75 | + | |
60 | 76 | static int pcie_portdrv_restore_config(struct pci_dev *dev) |
61 | 77 | { |
62 | 78 | int retval; |
... | ... | @@ -69,6 +85,20 @@ |
69 | 85 | } |
70 | 86 | |
71 | 87 | #ifdef CONFIG_PM |
88 | +static int pcie_port_resume_noirq(struct device *dev) | |
89 | +{ | |
90 | + struct pci_dev *pdev = to_pci_dev(dev); | |
91 | + | |
92 | + /* | |
93 | + * Some BIOSes forget to clear Root PME Status bits after system wakeup | |
94 | + * which breaks ACPI-based runtime wakeup on PCI Express, so clear those | |
95 | + * bits now just in case (shouldn't hurt). | |
96 | + */ | |
97 | + if(pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) | |
98 | + pcie_clear_root_pme_status(pdev); | |
99 | + return 0; | |
100 | +} | |
101 | + | |
72 | 102 | static const struct dev_pm_ops pcie_portdrv_pm_ops = { |
73 | 103 | .suspend = pcie_port_device_suspend, |
74 | 104 | .resume = pcie_port_device_resume, |
... | ... | @@ -76,6 +106,7 @@ |
76 | 106 | .thaw = pcie_port_device_resume, |
77 | 107 | .poweroff = pcie_port_device_suspend, |
78 | 108 | .restore = pcie_port_device_resume, |
109 | + .resume_noirq = pcie_port_resume_noirq, | |
79 | 110 | }; |
80 | 111 | |
81 | 112 | #define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops) |
... | ... | @@ -327,10 +358,8 @@ |
327 | 358 | { |
328 | 359 | int retval; |
329 | 360 | |
330 | - if (pcie_ports_disabled) { | |
331 | - pcie_no_aspm(); | |
332 | - return -EACCES; | |
333 | - } | |
361 | + if (pcie_ports_disabled) | |
362 | + return pci_register_driver(&pcie_portdriver); | |
334 | 363 | |
335 | 364 | dmi_check_system(pcie_portdrv_dmi_table); |
336 | 365 |
include/linux/pci_regs.h
... | ... | @@ -504,6 +504,8 @@ |
504 | 504 | #define PCI_EXP_RTCTL_CRSSVE 0x10 /* CRS Software Visibility Enable */ |
505 | 505 | #define PCI_EXP_RTCAP 30 /* Root Capabilities */ |
506 | 506 | #define PCI_EXP_RTSTA 32 /* Root Status */ |
507 | +#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */ | |
508 | +#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ | |
507 | 509 | #define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */ |
508 | 510 | #define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */ |
509 | 511 | #define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ |