mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 04:46:30 -04:00
Merge branch 'pci/wake'
- Add support for PCIe WAKE# interrupt when described via DT (Krishna Chaitanya Chundru) * pci/wake: PCI: Add support for PCIe WAKE# interrupt
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#define pr_fmt(fmt) "PCI: OF: " fmt
|
||||
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
@@ -15,6 +16,7 @@
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
#include "pci.h"
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
@@ -586,6 +588,83 @@ int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
return irq_create_of_mapping(&oirq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_irq_parse_and_map_pci);
|
||||
|
||||
static void pci_configure_wake_irq(struct pci_dev *pdev, struct gpio_desc *wake)
|
||||
{
|
||||
int ret, wake_irq, irq_type;
|
||||
|
||||
wake_irq = gpiod_to_irq(wake);
|
||||
if (wake_irq < 0) {
|
||||
pci_err(pdev, "Failed to get wake IRQ: %d\n", wake_irq);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* dev_pm_set_dedicated_wake_irq() associates a wakeup IRQ with the
|
||||
* device and requests it, but the PM core keeps it disabled by
|
||||
* default. The IRQ is enabled only when the device is allowed to
|
||||
* wake the system (during system suspend and after runtime
|
||||
* suspend), and only if device wakeup is enabled.
|
||||
*
|
||||
* When the wake IRQ fires, the wakeirq handler invokes
|
||||
* pm_runtime_resume() to bring the device back to an active power
|
||||
* state (e.g. from D3cold to D0). Once the device is active and
|
||||
* the link is usable, the endpoint may signal a PME, which is then
|
||||
* handled by the PCI core (either via PME polling or the PCIe PME
|
||||
* service driver) to wakeup the particular endpoint.
|
||||
*/
|
||||
ret = dev_pm_set_dedicated_wake_irq(&pdev->dev, wake_irq);
|
||||
if (ret < 0) {
|
||||
pci_err(pdev, "Failed to set WAKE# IRQ: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
irq_type = gpiod_is_active_low(wake) ? IRQ_TYPE_LEVEL_LOW :
|
||||
IRQ_TYPE_LEVEL_HIGH;
|
||||
ret = irq_set_irq_type(wake_irq, irq_type);
|
||||
if (ret < 0) {
|
||||
dev_pm_clear_wake_irq(&pdev->dev);
|
||||
pci_err(pdev, "Failed to set irq_type: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
}
|
||||
|
||||
void pci_configure_of_wake_gpio(struct pci_dev *dev)
|
||||
{
|
||||
struct device_node *dn = pci_device_to_OF_node(dev);
|
||||
struct gpio_desc *gpio;
|
||||
|
||||
if (!dn && !dev->wake)
|
||||
return;
|
||||
/*
|
||||
* fwnode_gpiod_get() may fail with -EBUSY (e.g. shared WAKE#), but
|
||||
* the actual WAKE# trigger from the device would still work and
|
||||
* the host controller driver will enable power to the topology.
|
||||
*
|
||||
* -EPROBE_DEFER cannot be propagated here since pci_device_add()
|
||||
* has no retry mechanism.
|
||||
*/
|
||||
gpio = fwnode_gpiod_get(of_fwnode_handle(dn), "wake", GPIOD_IN, NULL);
|
||||
if (!IS_ERR(gpio)) {
|
||||
dev->wake = gpio;
|
||||
pci_configure_wake_irq(dev, gpio);
|
||||
}
|
||||
}
|
||||
|
||||
void pci_remove_of_wake_gpio(struct pci_dev *dev)
|
||||
{
|
||||
struct device_node *dn = pci_device_to_OF_node(dev);
|
||||
|
||||
if (!dn)
|
||||
return;
|
||||
|
||||
device_init_wakeup(&dev->dev, false);
|
||||
dev_pm_clear_wake_irq(&dev->dev);
|
||||
gpiod_put(dev->wake);
|
||||
dev->wake = NULL;
|
||||
}
|
||||
#endif /* CONFIG_OF_IRQ */
|
||||
|
||||
static int pci_parse_request_of_pci_ranges(struct device *dev,
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_pci.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -1114,6 +1115,16 @@ static inline bool platform_pci_bridge_d3(struct pci_dev *dev)
|
||||
return acpi_pci_bridge_d3(dev);
|
||||
}
|
||||
|
||||
void platform_pci_configure_wake(struct pci_dev *dev)
|
||||
{
|
||||
pci_configure_of_wake_gpio(dev);
|
||||
}
|
||||
|
||||
void platform_pci_remove_wake(struct pci_dev *dev)
|
||||
{
|
||||
pci_remove_of_wake_gpio(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_update_current_state - Read power state of given device and cache it
|
||||
* @dev: PCI device to handle.
|
||||
|
||||
@@ -285,6 +285,8 @@ void pci_msix_init(struct pci_dev *dev);
|
||||
bool pci_bridge_d3_possible(struct pci_dev *dev);
|
||||
void pci_bridge_d3_update(struct pci_dev *dev);
|
||||
int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type);
|
||||
void platform_pci_configure_wake(struct pci_dev *dev);
|
||||
void platform_pci_remove_wake(struct pci_dev *dev);
|
||||
|
||||
static inline bool pci_bus_rrs_vendor_id(u32 l)
|
||||
{
|
||||
|
||||
@@ -2749,6 +2749,8 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
|
||||
|
||||
pci_init_capabilities(dev);
|
||||
|
||||
platform_pci_configure_wake(dev);
|
||||
|
||||
/*
|
||||
* Add the device to our list of discovered devices
|
||||
* and the bus list for fixup functions, etc.
|
||||
|
||||
@@ -34,6 +34,7 @@ static void pci_destroy_dev(struct pci_dev *dev)
|
||||
if (pci_dev_test_and_set_removed(dev))
|
||||
return;
|
||||
|
||||
platform_pci_remove_wake(dev);
|
||||
pci_doe_sysfs_teardown(dev);
|
||||
pci_npem_remove(dev);
|
||||
|
||||
|
||||
@@ -30,12 +30,18 @@ static inline void of_pci_check_probe_only(void) { }
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF_IRQ)
|
||||
int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin);
|
||||
void pci_configure_of_wake_gpio(struct pci_dev *dev);
|
||||
void pci_remove_of_wake_gpio(struct pci_dev *dev);
|
||||
#else
|
||||
static inline int
|
||||
of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void pci_configure_of_wake_gpio(struct pci_dev *dev) { }
|
||||
|
||||
static inline void pci_remove_of_wake_gpio(struct pci_dev *dev) { }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -587,6 +587,8 @@ struct pci_dev {
|
||||
/* These methods index pci_reset_fn_methods[] */
|
||||
u8 reset_methods[PCI_NUM_RESET_METHODS]; /* In priority order */
|
||||
|
||||
struct gpio_desc *wake; /* WAKE# GPIO */
|
||||
|
||||
#ifdef CONFIG_PCIE_TPH
|
||||
u16 tph_cap; /* TPH capability offset */
|
||||
u8 tph_mode; /* TPH mode */
|
||||
|
||||
Reference in New Issue
Block a user