diff options
-rw-r--r-- | drivers/pci/pci-acpi.c | 3 | ||||
-rw-r--r-- | drivers/pci/pci.c | 41 | ||||
-rw-r--r-- | drivers/pci/pcie/pme.c | 9 | ||||
-rw-r--r-- | include/linux/pci.h | 1 |
4 files changed, 33 insertions, 21 deletions
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index d36f41ea8cbf..cd3c4f1cdf1b 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c | |||
@@ -46,6 +46,9 @@ static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context) | |||
46 | struct pci_dev *pci_dev = context; | 46 | struct pci_dev *pci_dev = context; |
47 | 47 | ||
48 | if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_dev) { | 48 | if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_dev) { |
49 | if (pci_dev->pme_poll) | ||
50 | pci_dev->pme_poll = false; | ||
51 | |||
49 | pci_wakeup_event(pci_dev); | 52 | pci_wakeup_event(pci_dev); |
50 | pci_check_pme_status(pci_dev); | 53 | pci_check_pme_status(pci_dev); |
51 | pm_runtime_resume(&pci_dev->dev); | 54 | pm_runtime_resume(&pci_dev->dev); |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e9651f0a8817..7cd417e94058 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -1407,13 +1407,16 @@ bool pci_check_pme_status(struct pci_dev *dev) | |||
1407 | /** | 1407 | /** |
1408 | * pci_pme_wakeup - Wake up a PCI device if its PME Status bit is set. | 1408 | * pci_pme_wakeup - Wake up a PCI device if its PME Status bit is set. |
1409 | * @dev: Device to handle. | 1409 | * @dev: Device to handle. |
1410 | * @ign: Ignored. | 1410 | * @pme_poll_reset: Whether or not to reset the device's pme_poll flag. |
1411 | * | 1411 | * |
1412 | * Check if @dev has generated PME and queue a resume request for it in that | 1412 | * Check if @dev has generated PME and queue a resume request for it in that |
1413 | * case. | 1413 | * case. |
1414 | */ | 1414 | */ |
1415 | static int pci_pme_wakeup(struct pci_dev *dev, void *ign) | 1415 | static int pci_pme_wakeup(struct pci_dev *dev, void *pme_poll_reset) |
1416 | { | 1416 | { |
1417 | if (pme_poll_reset && dev->pme_poll) | ||
1418 | dev->pme_poll = false; | ||
1419 | |||
1417 | if (pci_check_pme_status(dev)) { | 1420 | if (pci_check_pme_status(dev)) { |
1418 | pci_wakeup_event(dev); | 1421 | pci_wakeup_event(dev); |
1419 | pm_request_resume(&dev->dev); | 1422 | pm_request_resume(&dev->dev); |
@@ -1428,7 +1431,7 @@ static int pci_pme_wakeup(struct pci_dev *dev, void *ign) | |||
1428 | void pci_pme_wakeup_bus(struct pci_bus *bus) | 1431 | void pci_pme_wakeup_bus(struct pci_bus *bus) |
1429 | { | 1432 | { |
1430 | if (bus) | 1433 | if (bus) |
1431 | pci_walk_bus(bus, pci_pme_wakeup, NULL); | 1434 | pci_walk_bus(bus, pci_pme_wakeup, (void *)true); |
1432 | } | 1435 | } |
1433 | 1436 | ||
1434 | /** | 1437 | /** |
@@ -1446,31 +1449,26 @@ bool pci_pme_capable(struct pci_dev *dev, pci_power_t state) | |||
1446 | 1449 | ||
1447 | static void pci_pme_list_scan(struct work_struct *work) | 1450 | static void pci_pme_list_scan(struct work_struct *work) |
1448 | { | 1451 | { |
1449 | struct pci_pme_device *pme_dev; | 1452 | struct pci_pme_device *pme_dev, *n; |
1450 | 1453 | ||
1451 | mutex_lock(&pci_pme_list_mutex); | 1454 | mutex_lock(&pci_pme_list_mutex); |
1452 | if (!list_empty(&pci_pme_list)) { | 1455 | if (!list_empty(&pci_pme_list)) { |
1453 | list_for_each_entry(pme_dev, &pci_pme_list, list) | 1456 | list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) { |
1454 | pci_pme_wakeup(pme_dev->dev, NULL); | 1457 | if (pme_dev->dev->pme_poll) { |
1455 | schedule_delayed_work(&pci_pme_work, msecs_to_jiffies(PME_TIMEOUT)); | 1458 | pci_pme_wakeup(pme_dev->dev, NULL); |
1459 | } else { | ||
1460 | list_del(&pme_dev->list); | ||
1461 | kfree(pme_dev); | ||
1462 | } | ||
1463 | } | ||
1464 | if (!list_empty(&pci_pme_list)) | ||
1465 | schedule_delayed_work(&pci_pme_work, | ||
1466 | msecs_to_jiffies(PME_TIMEOUT)); | ||
1456 | } | 1467 | } |
1457 | mutex_unlock(&pci_pme_list_mutex); | 1468 | mutex_unlock(&pci_pme_list_mutex); |
1458 | } | 1469 | } |
1459 | 1470 | ||
1460 | /** | 1471 | /** |
1461 | * pci_external_pme - is a device an external PCI PME source? | ||
1462 | * @dev: PCI device to check | ||
1463 | * | ||
1464 | */ | ||
1465 | |||
1466 | static bool pci_external_pme(struct pci_dev *dev) | ||
1467 | { | ||
1468 | if (pci_is_pcie(dev) || dev->bus->number == 0) | ||
1469 | return false; | ||
1470 | return true; | ||
1471 | } | ||
1472 | |||
1473 | /** | ||
1474 | * pci_pme_active - enable or disable PCI device's PME# function | 1472 | * pci_pme_active - enable or disable PCI device's PME# function |
1475 | * @dev: PCI device to handle. | 1473 | * @dev: PCI device to handle. |
1476 | * @enable: 'true' to enable PME# generation; 'false' to disable it. | 1474 | * @enable: 'true' to enable PME# generation; 'false' to disable it. |
@@ -1503,7 +1501,7 @@ void pci_pme_active(struct pci_dev *dev, bool enable) | |||
1503 | hit, and the power savings from the devices will still be a | 1501 | hit, and the power savings from the devices will still be a |
1504 | win. */ | 1502 | win. */ |
1505 | 1503 | ||
1506 | if (pci_external_pme(dev)) { | 1504 | if (dev->pme_poll) { |
1507 | struct pci_pme_device *pme_dev; | 1505 | struct pci_pme_device *pme_dev; |
1508 | if (enable) { | 1506 | if (enable) { |
1509 | pme_dev = kmalloc(sizeof(struct pci_pme_device), | 1507 | pme_dev = kmalloc(sizeof(struct pci_pme_device), |
@@ -1821,6 +1819,7 @@ void pci_pm_init(struct pci_dev *dev) | |||
1821 | (pmc & PCI_PM_CAP_PME_D3) ? " D3hot" : "", | 1819 | (pmc & PCI_PM_CAP_PME_D3) ? " D3hot" : "", |
1822 | (pmc & PCI_PM_CAP_PME_D3cold) ? " D3cold" : ""); | 1820 | (pmc & PCI_PM_CAP_PME_D3cold) ? " D3cold" : ""); |
1823 | dev->pme_support = pmc >> PCI_PM_CAP_PME_SHIFT; | 1821 | dev->pme_support = pmc >> PCI_PM_CAP_PME_SHIFT; |
1822 | dev->pme_poll = true; | ||
1824 | /* | 1823 | /* |
1825 | * Make device's PM flags reflect the wake-up capability, but | 1824 | * Make device's PM flags reflect the wake-up capability, but |
1826 | * let the user space enable it to wake up the system as needed. | 1825 | * let the user space enable it to wake up the system as needed. |
diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index 0057344a3fcb..001f1b78f39c 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c | |||
@@ -84,6 +84,9 @@ static bool pcie_pme_walk_bus(struct pci_bus *bus) | |||
84 | list_for_each_entry(dev, &bus->devices, bus_list) { | 84 | list_for_each_entry(dev, &bus->devices, bus_list) { |
85 | /* Skip PCIe devices in case we started from a root port. */ | 85 | /* Skip PCIe devices in case we started from a root port. */ |
86 | if (!pci_is_pcie(dev) && pci_check_pme_status(dev)) { | 86 | if (!pci_is_pcie(dev) && pci_check_pme_status(dev)) { |
87 | if (dev->pme_poll) | ||
88 | dev->pme_poll = false; | ||
89 | |||
87 | pci_wakeup_event(dev); | 90 | pci_wakeup_event(dev); |
88 | pm_request_resume(&dev->dev); | 91 | pm_request_resume(&dev->dev); |
89 | ret = true; | 92 | ret = true; |
@@ -142,6 +145,9 @@ static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id) | |||
142 | 145 | ||
143 | /* First, check if the PME is from the root port itself. */ | 146 | /* First, check if the PME is from the root port itself. */ |
144 | if (port->devfn == devfn && port->bus->number == busnr) { | 147 | if (port->devfn == devfn && port->bus->number == busnr) { |
148 | if (port->pme_poll) | ||
149 | port->pme_poll = false; | ||
150 | |||
145 | if (pci_check_pme_status(port)) { | 151 | if (pci_check_pme_status(port)) { |
146 | pm_request_resume(&port->dev); | 152 | pm_request_resume(&port->dev); |
147 | found = true; | 153 | found = true; |
@@ -187,6 +193,9 @@ static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id) | |||
187 | /* The device is there, but we have to check its PME status. */ | 193 | /* The device is there, but we have to check its PME status. */ |
188 | found = pci_check_pme_status(dev); | 194 | found = pci_check_pme_status(dev); |
189 | if (found) { | 195 | if (found) { |
196 | if (dev->pme_poll) | ||
197 | dev->pme_poll = false; | ||
198 | |||
190 | pci_wakeup_event(dev); | 199 | pci_wakeup_event(dev); |
191 | pm_request_resume(&dev->dev); | 200 | pm_request_resume(&dev->dev); |
192 | } | 201 | } |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 4ff6d4e9455c..176c981a90d4 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -273,6 +273,7 @@ struct pci_dev { | |||
273 | unsigned int pme_support:5; /* Bitmask of states from which PME# | 273 | unsigned int pme_support:5; /* Bitmask of states from which PME# |
274 | can be generated */ | 274 | can be generated */ |
275 | unsigned int pme_interrupt:1; | 275 | unsigned int pme_interrupt:1; |
276 | unsigned int pme_poll:1; /* Poll device's PME status bit */ | ||
276 | unsigned int d1_support:1; /* Low power state D1 is supported */ | 277 | unsigned int d1_support:1; /* Low power state D1 is supported */ |
277 | unsigned int d2_support:1; /* Low power state D2 is supported */ | 278 | unsigned int d2_support:1; /* Low power state D2 is supported */ |
278 | unsigned int no_d1d2:1; /* Only allow D0 and D3 */ | 279 | unsigned int no_d1d2:1; /* Only allow D0 and D3 */ |