diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pcie/pme.c | 27 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv.h | 2 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_core.c | 25 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_pci.c | 37 |
4 files changed, 53 insertions, 38 deletions
diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index 2f3c90407227..073f0308c6b2 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c | |||
@@ -26,9 +26,6 @@ | |||
26 | #include "../pci.h" | 26 | #include "../pci.h" |
27 | #include "portdrv.h" | 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 | * If this switch is set, MSI will not be used for PCIe PME signaling. This | 30 | * If this switch is set, MSI will not be used for PCIe PME signaling. This |
34 | * causes the PCIe port driver to use INTx interrupts only, but it turns out | 31 | * causes the PCIe port driver to use INTx interrupts only, but it turns out |
@@ -74,22 +71,6 @@ void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable) | |||
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 | * pcie_pme_walk_bus - Scan a PCI bus for devices asserting PME#. | 74 | * pcie_pme_walk_bus - Scan a PCI bus for devices asserting PME#. |
94 | * @bus: PCI bus to scan. | 75 | * @bus: PCI bus to scan. |
95 | * | 76 | * |
@@ -253,7 +234,7 @@ static void pcie_pme_work_fn(struct work_struct *work) | |||
253 | * Clear PME status of the port. If there are other | 234 | * Clear PME status of the port. If there are other |
254 | * pending PMEs, the status will be set again. | 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 | spin_unlock_irq(&data->lock); | 239 | spin_unlock_irq(&data->lock); |
259 | pcie_pme_handle_request(port, rtsta & 0xffff); | 240 | pcie_pme_handle_request(port, rtsta & 0xffff); |
@@ -378,7 +359,7 @@ static int pcie_pme_probe(struct pcie_device *srv) | |||
378 | 359 | ||
379 | port = srv->port; | 360 | port = srv->port; |
380 | pcie_pme_interrupt_enable(port, false); | 361 | pcie_pme_interrupt_enable(port, false); |
381 | pcie_pme_clear_status(port); | 362 | pcie_clear_root_pme_status(port); |
382 | 363 | ||
383 | ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED, "PCIe PME", srv); | 364 | ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED, "PCIe PME", srv); |
384 | if (ret) { | 365 | if (ret) { |
@@ -402,7 +383,7 @@ static int pcie_pme_suspend(struct pcie_device *srv) | |||
402 | 383 | ||
403 | spin_lock_irq(&data->lock); | 384 | spin_lock_irq(&data->lock); |
404 | pcie_pme_interrupt_enable(port, false); | 385 | pcie_pme_interrupt_enable(port, false); |
405 | pcie_pme_clear_status(port); | 386 | pcie_clear_root_pme_status(port); |
406 | data->noirq = true; | 387 | data->noirq = true; |
407 | spin_unlock_irq(&data->lock); | 388 | spin_unlock_irq(&data->lock); |
408 | 389 | ||
@@ -422,7 +403,7 @@ static int pcie_pme_resume(struct pcie_device *srv) | |||
422 | 403 | ||
423 | spin_lock_irq(&data->lock); | 404 | spin_lock_irq(&data->lock); |
424 | data->noirq = false; | 405 | data->noirq = false; |
425 | pcie_pme_clear_status(port); | 406 | pcie_clear_root_pme_status(port); |
426 | pcie_pme_interrupt_enable(port, true); | 407 | pcie_pme_interrupt_enable(port, true); |
427 | spin_unlock_irq(&data->lock); | 408 | spin_unlock_irq(&data->lock); |
428 | 409 | ||
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index 7b5aba0a3291..8fcc03598b29 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h | |||
@@ -35,6 +35,8 @@ extern void pcie_port_bus_unregister(void); | |||
35 | 35 | ||
36 | struct pci_dev; | 36 | struct pci_dev; |
37 | 37 | ||
38 | extern void pcie_clear_root_pme_status(struct pci_dev *dev); | ||
39 | |||
38 | #ifdef CONFIG_PCIE_PME | 40 | #ifdef CONFIG_PCIE_PME |
39 | extern bool pcie_pme_msi_disabled; | 41 | extern bool pcie_pme_msi_disabled; |
40 | 42 | ||
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index a9c222d79ebc..5130d0d22390 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c | |||
@@ -241,17 +241,17 @@ static int get_port_device_capability(struct pci_dev *dev) | |||
241 | int cap_mask; | 241 | int cap_mask; |
242 | int err; | 242 | int err; |
243 | 243 | ||
244 | if (pcie_ports_disabled) | ||
245 | return 0; | ||
246 | |||
244 | err = pcie_port_platform_notify(dev, &cap_mask); | 247 | err = pcie_port_platform_notify(dev, &cap_mask); |
245 | if (pcie_ports_auto) { | 248 | 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 | 249 | cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP |
252 | | PCIE_PORT_SERVICE_VC; | 250 | | PCIE_PORT_SERVICE_VC; |
253 | if (pci_aer_available()) | 251 | if (pci_aer_available()) |
254 | cap_mask |= PCIE_PORT_SERVICE_AER; | 252 | cap_mask |= PCIE_PORT_SERVICE_AER; |
253 | } else if (err) { | ||
254 | return 0; | ||
255 | } | 255 | } |
256 | 256 | ||
257 | pos = pci_pcie_cap(dev); | 257 | pos = pci_pcie_cap(dev); |
@@ -349,15 +349,18 @@ int pcie_port_device_register(struct pci_dev *dev) | |||
349 | int status, capabilities, i, nr_service; | 349 | int status, capabilities, i, nr_service; |
350 | int irqs[PCIE_PORT_DEVICE_MAXSERVICES]; | 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 | /* Enable PCI Express port device */ | 352 | /* Enable PCI Express port device */ |
358 | status = pci_enable_device(dev); | 353 | status = pci_enable_device(dev); |
359 | if (status) | 354 | if (status) |
360 | return status; | 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 | pci_set_master(dev); | 364 | pci_set_master(dev); |
362 | /* | 365 | /* |
363 | * Initialize service irqs. Don't use service devices that | 366 | * Initialize service irqs. Don't use service devices that |
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index f9033e190fb6..e0610bda1dea 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c | |||
@@ -57,6 +57,22 @@ __setup("pcie_ports=", pcie_port_setup); | |||
57 | 57 | ||
58 | /* global data */ | 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 | static int pcie_portdrv_restore_config(struct pci_dev *dev) | 76 | static int pcie_portdrv_restore_config(struct pci_dev *dev) |
61 | { | 77 | { |
62 | int retval; | 78 | int retval; |
@@ -69,6 +85,20 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev) | |||
69 | } | 85 | } |
70 | 86 | ||
71 | #ifdef CONFIG_PM | 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 | static const struct dev_pm_ops pcie_portdrv_pm_ops = { | 102 | static const struct dev_pm_ops pcie_portdrv_pm_ops = { |
73 | .suspend = pcie_port_device_suspend, | 103 | .suspend = pcie_port_device_suspend, |
74 | .resume = pcie_port_device_resume, | 104 | .resume = pcie_port_device_resume, |
@@ -76,6 +106,7 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = { | |||
76 | .thaw = pcie_port_device_resume, | 106 | .thaw = pcie_port_device_resume, |
77 | .poweroff = pcie_port_device_suspend, | 107 | .poweroff = pcie_port_device_suspend, |
78 | .restore = pcie_port_device_resume, | 108 | .restore = pcie_port_device_resume, |
109 | .resume_noirq = pcie_port_resume_noirq, | ||
79 | }; | 110 | }; |
80 | 111 | ||
81 | #define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops) | 112 | #define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops) |
@@ -327,10 +358,8 @@ static int __init pcie_portdrv_init(void) | |||
327 | { | 358 | { |
328 | int retval; | 359 | int retval; |
329 | 360 | ||
330 | if (pcie_ports_disabled) { | 361 | if (pcie_ports_disabled) |
331 | pcie_no_aspm(); | 362 | return pci_register_driver(&pcie_portdriver); |
332 | return -EACCES; | ||
333 | } | ||
334 | 363 | ||
335 | dmi_check_system(pcie_portdrv_dmi_table); | 364 | dmi_check_system(pcie_portdrv_dmi_table); |
336 | 365 | ||