* [PATCH v8 1/3] PM: sleep: wakeirq: Add support for dedicated shared wake IRQ setup
2026-03-13 7:08 [PATCH v8 0/3] PCI: Add support for PCIe WAKE# interrupt Krishna Chaitanya Chundru
@ 2026-03-13 7:08 ` Krishna Chaitanya Chundru
2026-03-13 7:08 ` [PATCH v8 2/3] gpio: Add fwnode_gpiod_get() helper Krishna Chaitanya Chundru
2026-03-13 7:08 ` [PATCH v8 3/3] PCI: Add support for PCIe WAKE# interrupt Krishna Chaitanya Chundru
2 siblings, 0 replies; 10+ messages in thread
From: Krishna Chaitanya Chundru @ 2026-03-13 7:08 UTC (permalink / raw)
To: Rafael J. Wysocki, Len Brown, Pavel Machek, Greg Kroah-Hartman,
Danilo Krummrich, Bjorn Helgaas, Bartosz Golaszewski,
Linus Walleij, Bartosz Golaszewski, Rob Herring, Saravana Kannan,
Linus Walleij
Cc: linux-pm, linux-kernel, linux-pci, linux-gpio, quic_vbadigan,
sherry.sun, driver-core, devicetree, Krishna Chaitanya Chundru
Some devices require more flexibility when configuring their dedicated
wake-up interrupts, such as support for IRQF_SHARED or other IRQ flags.
This is particularly useful in PCIe systems where multiple endpoints
(e.g., Wi-Fi and Bluetooth controllers) share a common WAKE# signal
line which requests platform to re-establish power and reference clocks
to the components. In such cases, drivers can use this new API
dev_pm_set_dedicated_shared_wake_irq() to register a shared wake IRQ.
Update the internal helper __dev_pm_set_dedicated_wake_irq() to accept an
irq_flags argument. Modify the existing dev_pm_set_dedicated_wake_irq()
and dev_pm_set_dedicated_wake_irq_reverse() to preserve current behavior.
When IRQ registered with IRQF_SHARED we can't use IRQF_NO_AUTOEN flag,
so after registering for irq, disable it explicitly.
Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
Acked-by: Rafael J. Wysocki (Intel) <rafael@kernel.org>
---
drivers/base/power/wakeirq.c | 39 ++++++++++++++++++++++++++++++++++-----
include/linux/pm_wakeirq.h | 6 ++++++
2 files changed, 40 insertions(+), 5 deletions(-)
diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c
index ad23f0fa5d1a5a9eb49b1af2288ee4908082b13e..b7b106f55559a7c85cb35d9e5ed22fe37970662d 100644
--- a/drivers/base/power/wakeirq.c
+++ b/drivers/base/power/wakeirq.c
@@ -171,7 +171,8 @@ static irqreturn_t handle_threaded_wake_irq(int irq, void *_wirq)
return IRQ_HANDLED;
}
-static int __dev_pm_set_dedicated_wake_irq(struct device *dev, int irq, unsigned int flag)
+static int __dev_pm_set_dedicated_wake_irq(struct device *dev, int irq, unsigned int flag,
+ unsigned int irq_flags)
{
struct wake_irq *wirq;
int err;
@@ -200,8 +201,7 @@ static int __dev_pm_set_dedicated_wake_irq(struct device *dev, int irq, unsigned
* so we use a threaded irq.
*/
err = request_threaded_irq(irq, NULL, handle_threaded_wake_irq,
- IRQF_ONESHOT | IRQF_NO_AUTOEN,
- wirq->name, wirq);
+ IRQF_ONESHOT | irq_flags, wirq->name, wirq);
if (err)
goto err_free_name;
@@ -237,7 +237,7 @@ static int __dev_pm_set_dedicated_wake_irq(struct device *dev, int irq, unsigned
*/
int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
{
- return __dev_pm_set_dedicated_wake_irq(dev, irq, 0);
+ return __dev_pm_set_dedicated_wake_irq(dev, irq, 0, IRQF_NO_AUTOEN);
}
EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq);
@@ -258,10 +258,39 @@ EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq);
*/
int dev_pm_set_dedicated_wake_irq_reverse(struct device *dev, int irq)
{
- return __dev_pm_set_dedicated_wake_irq(dev, irq, WAKE_IRQ_DEDICATED_REVERSE);
+ return __dev_pm_set_dedicated_wake_irq(dev, irq, WAKE_IRQ_DEDICATED_REVERSE,
+ IRQF_NO_AUTOEN);
}
EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq_reverse);
+/**
+ * dev_pm_set_dedicated_shared_wake_irq - Request a dedicated shared wake-up interrupt
+ * @dev: Device entry
+ * @irq: Device wake-up interrupt
+ * @flags: Custom IRQ flags (e.g., IRQ_TYPE_EDGE_FALLING)
+ *
+ * This API sets up a threaded interrupt handler for a device that has
+ * a shared wake-up interrupt in addition to the device IO interrupt. It also
+ * sets IRQ flags like IRQ_TYPE_EDGE_FALLING passed by the caller.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int dev_pm_set_dedicated_shared_wake_irq(struct device *dev, int irq, unsigned long flags)
+{
+ struct wake_irq *wirq;
+ int ret;
+
+ ret = __dev_pm_set_dedicated_wake_irq(dev, irq, 0, IRQF_SHARED | flags);
+ if (ret)
+ return ret;
+
+ wirq = dev->power.wakeirq;
+ disable_irq_nosync(wirq->irq);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_shared_wake_irq);
+
/**
* dev_pm_enable_wake_irq_check - Checks and enables wake-up interrupt
* @dev: Device
diff --git a/include/linux/pm_wakeirq.h b/include/linux/pm_wakeirq.h
index 25b63ed51b765c2c6919f259668a12675330835e..61f1e840745b56baa57db37563e450cb2d757a85 100644
--- a/include/linux/pm_wakeirq.h
+++ b/include/linux/pm_wakeirq.h
@@ -11,6 +11,7 @@ extern int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq);
extern int dev_pm_set_dedicated_wake_irq_reverse(struct device *dev, int irq);
extern void dev_pm_clear_wake_irq(struct device *dev);
extern int devm_pm_set_wake_irq(struct device *dev, int irq);
+extern int dev_pm_set_dedicated_shared_wake_irq(struct device *dev, int irq, unsigned long flags);
#else /* !CONFIG_PM */
@@ -38,5 +39,10 @@ static inline int devm_pm_set_wake_irq(struct device *dev, int irq)
return 0;
}
+static inline int dev_pm_set_dedicated_shared_wake_irq(struct device *dev,
+ int irq, unsigned long flags)
+{
+ return 0;
+}
#endif /* CONFIG_PM */
#endif /* _LINUX_PM_WAKEIRQ_H */
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v8 2/3] gpio: Add fwnode_gpiod_get() helper
2026-03-13 7:08 [PATCH v8 0/3] PCI: Add support for PCIe WAKE# interrupt Krishna Chaitanya Chundru
2026-03-13 7:08 ` [PATCH v8 1/3] PM: sleep: wakeirq: Add support for dedicated shared wake IRQ setup Krishna Chaitanya Chundru
@ 2026-03-13 7:08 ` Krishna Chaitanya Chundru
2026-03-13 13:55 ` Bartosz Golaszewski
2026-03-13 7:08 ` [PATCH v8 3/3] PCI: Add support for PCIe WAKE# interrupt Krishna Chaitanya Chundru
2 siblings, 1 reply; 10+ messages in thread
From: Krishna Chaitanya Chundru @ 2026-03-13 7:08 UTC (permalink / raw)
To: Rafael J. Wysocki, Len Brown, Pavel Machek, Greg Kroah-Hartman,
Danilo Krummrich, Bjorn Helgaas, Bartosz Golaszewski,
Linus Walleij, Bartosz Golaszewski, Rob Herring, Saravana Kannan,
Linus Walleij
Cc: linux-pm, linux-kernel, linux-pci, linux-gpio, quic_vbadigan,
sherry.sun, driver-core, devicetree, Krishna Chaitanya Chundru,
Manivannan Sadhasivam
Add fwnode_gpiod_get() as a convenience wrapper around
fwnode_gpiod_get_index() for the common case where only the
first GPIO is required.
This mirrors existing gpiod_get() and devm_gpiod_get() helpers
and avoids open-coding index 0 at call sites.
Suggested-by: Manivannan Sadhasivam <mani@kernel.org>
Acked-by: Manivannan Sadhasivam <mani@kernel.org>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
---
include/linux/gpio/consumer.h | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
index 0d8408582918680bfea6a04ccedfc0c75211907a..fee926c0262ce9dc4b9a3c151e74f2cf37470a49 100644
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -596,6 +596,15 @@ static inline int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc,
}
#endif /* CONFIG_GPIOLIB && CONFIG_HTE */
+static inline
+struct gpio_desc *fwnode_gpiod_get(struct fwnode_handle *fwnode,
+ const char *con_id,
+ enum gpiod_flags flags,
+ const char *label)
+{
+ return fwnode_gpiod_get_index(fwnode, con_id, 0, flags, label);
+}
+
static inline
struct gpio_desc *devm_fwnode_gpiod_get(struct device *dev,
struct fwnode_handle *fwnode,
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v8 2/3] gpio: Add fwnode_gpiod_get() helper
2026-03-13 7:08 ` [PATCH v8 2/3] gpio: Add fwnode_gpiod_get() helper Krishna Chaitanya Chundru
@ 2026-03-13 13:55 ` Bartosz Golaszewski
0 siblings, 0 replies; 10+ messages in thread
From: Bartosz Golaszewski @ 2026-03-13 13:55 UTC (permalink / raw)
To: Krishna Chaitanya Chundru
Cc: linux-pm, linux-kernel, linux-pci, linux-gpio, quic_vbadigan,
sherry.sun, driver-core, devicetree, Manivannan Sadhasivam,
Rafael J. Wysocki, Len Brown, Pavel Machek, Greg Kroah-Hartman,
Danilo Krummrich, Bjorn Helgaas, Bartosz Golaszewski,
Linus Walleij, Bartosz Golaszewski, Rob Herring, Saravana Kannan
On Fri, 13 Mar 2026 08:08:41 +0100, Krishna Chaitanya Chundru
<krishna.chundru@oss.qualcomm.com> said:
> Add fwnode_gpiod_get() as a convenience wrapper around
> fwnode_gpiod_get_index() for the common case where only the
> first GPIO is required.
>
> This mirrors existing gpiod_get() and devm_gpiod_get() helpers
> and avoids open-coding index 0 at call sites.
>
> Suggested-by: Manivannan Sadhasivam <mani@kernel.org>
> Acked-by: Manivannan Sadhasivam <mani@kernel.org>
> Reviewed-by: Linus Walleij <linusw@kernel.org>
> Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
> ---
> include/linux/gpio/consumer.h | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
> index 0d8408582918680bfea6a04ccedfc0c75211907a..fee926c0262ce9dc4b9a3c151e74f2cf37470a49 100644
> --- a/include/linux/gpio/consumer.h
> +++ b/include/linux/gpio/consumer.h
> @@ -596,6 +596,15 @@ static inline int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc,
> }
> #endif /* CONFIG_GPIOLIB && CONFIG_HTE */
>
> +static inline
> +struct gpio_desc *fwnode_gpiod_get(struct fwnode_handle *fwnode,
> + const char *con_id,
> + enum gpiod_flags flags,
> + const char *label)
> +{
> + return fwnode_gpiod_get_index(fwnode, con_id, 0, flags, label);
> +}
> +
> static inline
> struct gpio_desc *devm_fwnode_gpiod_get(struct device *dev,
> struct fwnode_handle *fwnode,
>
> --
> 2.34.1
>
>
Acked-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v8 3/3] PCI: Add support for PCIe WAKE# interrupt
2026-03-13 7:08 [PATCH v8 0/3] PCI: Add support for PCIe WAKE# interrupt Krishna Chaitanya Chundru
2026-03-13 7:08 ` [PATCH v8 1/3] PM: sleep: wakeirq: Add support for dedicated shared wake IRQ setup Krishna Chaitanya Chundru
2026-03-13 7:08 ` [PATCH v8 2/3] gpio: Add fwnode_gpiod_get() helper Krishna Chaitanya Chundru
@ 2026-03-13 7:08 ` Krishna Chaitanya Chundru
2026-03-13 13:58 ` Manivannan Sadhasivam
2026-03-17 7:26 ` Manivannan Sadhasivam
2 siblings, 2 replies; 10+ messages in thread
From: Krishna Chaitanya Chundru @ 2026-03-13 7:08 UTC (permalink / raw)
To: Rafael J. Wysocki, Len Brown, Pavel Machek, Greg Kroah-Hartman,
Danilo Krummrich, Bjorn Helgaas, Bartosz Golaszewski,
Linus Walleij, Bartosz Golaszewski, Rob Herring, Saravana Kannan,
Linus Walleij
Cc: linux-pm, linux-kernel, linux-pci, linux-gpio, quic_vbadigan,
sherry.sun, driver-core, devicetree, Krishna Chaitanya Chundru
According to the PCI Express specification (PCIe r7.0, Section 5.3.3.2),
two link wakeup mechanisms are defined: Beacon and WAKE#. Beacon is a
hardware-only mechanism and is invisible to software (PCIe r7.0,
Section 4.2.7.8.1). This change adds support for the WAKE# mechanism in
the PCI core.
According to the PCIe specification, multiple WAKE# signals can exist in
a system or each component in the hierarchy could share a single WAKE#
signal. In configurations involving a PCIe switch, each downstream port
(DSP) of the switch may be connected to a separate WAKE# line, allowing
each endpoint to signal WAKE# independently. From figure 5.4 in sec
5.3.3.2, WAKE# can also be terminated at the switch itself. To support
this, the WAKE# should be described in the device tree node of the
endpoint/bridge. If all endpoints share a single WAKE# line, then each
endpoint node should describe the same WAKE# signal or a single WAKE# in
the Root Port node.
In pci_device_add(), PCI framework will search for the WAKE# in device
node, If not found, it searches in its upstream port only if upstream port
is Root Port. Once found, register for the wake IRQ in shared mode, as the
WAKE# may be shared among multiple endpoints.
dev_pm_set_dedicated_shared_wake_irq() associates a wakeup IRQ with a
device and requests it, but the PM core keeps the IRQ disabled by default.
The IRQ is enabled only when the device is permitted to wake the system,
i.e. during system suspend and after runtime suspend, and only when 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, such as transitioning from
D3cold to D0. Once the device is active and the link is usable, the
endpoint may generate a PME, which is then handled by the PCI core through
PME polling or the PCIe PME service driver to complete the wakeup of the
endpoint.
WAKE# is added in dts schema and merged based on below links.
Link: https://lore.kernel.org/all/20250515090517.3506772-1-krishna.chundru@oss.qualcomm.com/
Link: https://github.com/devicetree-org/dt-schema/pull/170
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
---
drivers/pci/of.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++
drivers/pci/pci.c | 10 +++++++
drivers/pci/pci.h | 2 ++
drivers/pci/probe.c | 2 ++
drivers/pci/remove.c | 1 +
include/linux/of_pci.h | 4 +++
include/linux/pci.h | 2 ++
7 files changed, 95 insertions(+)
diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index 9f8eb5df279ed28db7a3b2fd29c65da9975c2efa..b7199d3598b31b62245716c178a5a73565efc89e 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -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,78 @@ 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;
+
+ wake_irq = gpiod_to_irq(wake);
+ if (wake_irq < 0) {
+ pci_err(pdev, "Failed to get wake irq: %d\n", wake_irq);
+ return;
+ }
+
+ device_init_wakeup(&pdev->dev, true);
+
+ /*
+ * dev_pm_set_dedicated_shared_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 particular endpoint.
+ */
+ ret = dev_pm_set_dedicated_shared_wake_irq(&pdev->dev, wake_irq,
+ IRQ_TYPE_EDGE_FALLING);
+ if (ret < 0) {
+ pci_err(pdev, "Failed to set wake IRQ: %d\n", ret);
+ device_init_wakeup(&pdev->dev, false);
+ }
+}
+
+void pci_configure_of_wake_gpio(struct pci_dev *dev)
+{
+ struct device_node *dn = pci_device_to_OF_node(dev);
+ struct pci_dev *upstream;
+ struct gpio_desc *gpio;
+
+ if (!dn)
+ return;
+
+ /*
+ * The devices in a hierarchy expose wakeup capability through the 'wake-gpios'
+ * property defined either in the device node or in the Slot node. So first check
+ * for the property in device node and if not available, check in the Slot node.
+ */
+ gpio = fwnode_gpiod_get(of_fwnode_handle(dn), "wake",
+ GPIOD_IN | GPIOD_FLAGS_BIT_NONEXCLUSIVE, NULL);
+ if (IS_ERR(gpio)) {
+ upstream = pci_upstream_bridge(dev);
+ if (upstream && pci_is_root_bus(upstream->bus) && upstream->wake)
+ pci_configure_wake_irq(dev, upstream->wake);
+ } else {
+ 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;
+
+ dev_pm_clear_wake_irq(&dev->dev);
+ device_init_wakeup(&dev->dev, false);
+ gpiod_put(dev->wake);
+ dev->wake = NULL;
+}
#endif /* CONFIG_OF_IRQ */
static int pci_parse_request_of_pci_ranges(struct device *dev,
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 8479c2e1f74f1044416281aba11bf071ea89488a..3d858f36ab48a6daec645574ca9027d9d6f071de 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -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>
@@ -1123,6 +1124,15 @@ 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)
+{
+ return pci_configure_of_wake_gpio(dev);
+}
+
+void platform_pci_remove_wake(struct pci_dev *dev)
+{
+ return pci_remove_of_wake_gpio(dev);
+}
/**
* pci_update_current_state - Read power state of given device and cache it
* @dev: PCI device to handle.
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 13d998fbacce6698514d92500dfea03cc562cdc2..65ca9551e558d2e3331fab0a968620d6b2a2522a 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -282,6 +282,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)
{
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index bccc7a4bdd794384b7877d453c7989941471c999..372b0d2f4531ea53c0570608306a547101d59e7b 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2771,6 +2771,8 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
/* Establish pdev->tsm for newly added (e.g. new SR-IOV VFs) */
pci_tsm_init(dev);
+ platform_pci_configure_wake(dev);
+
pci_npem_create(dev);
pci_doe_sysfs_init(dev);
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index e9d519993853f92f1810d3eff9f44ca7e3e1abd9..d781b41e57c4444077075690cec926a9fe15334f 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -35,6 +35,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);
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
index 29658c0ee71ff10122760214d04ee2bab01709fd..0efd6e9cb4d3d3beaafb42ea411303139f1150d5 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -30,12 +30,16 @@ 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
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 1c270f1d512301de4d462fe7e5097c32af5c6f8d..d1e08df8a8deaa87780589f23242767fdcdba541 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -586,6 +586,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; /* Holds WAKE# gpio */
+
#ifdef CONFIG_PCIE_TPH
u16 tph_cap; /* TPH capability offset */
u8 tph_mode; /* TPH mode */
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v8 3/3] PCI: Add support for PCIe WAKE# interrupt
2026-03-13 7:08 ` [PATCH v8 3/3] PCI: Add support for PCIe WAKE# interrupt Krishna Chaitanya Chundru
@ 2026-03-13 13:58 ` Manivannan Sadhasivam
2026-03-16 12:16 ` Krishna Chaitanya Chundru
2026-03-17 7:26 ` Manivannan Sadhasivam
1 sibling, 1 reply; 10+ messages in thread
From: Manivannan Sadhasivam @ 2026-03-13 13:58 UTC (permalink / raw)
To: Krishna Chaitanya Chundru
Cc: Rafael J. Wysocki, Len Brown, Pavel Machek, Greg Kroah-Hartman,
Danilo Krummrich, Bjorn Helgaas, Bartosz Golaszewski,
Linus Walleij, Bartosz Golaszewski, Rob Herring, Saravana Kannan,
linux-pm, linux-kernel, linux-pci, linux-gpio, quic_vbadigan,
sherry.sun, driver-core, devicetree
On Fri, Mar 13, 2026 at 12:38:42PM +0530, Krishna Chaitanya Chundru wrote:
> According to the PCI Express specification (PCIe r7.0, Section 5.3.3.2),
> two link wakeup mechanisms are defined: Beacon and WAKE#. Beacon is a
> hardware-only mechanism and is invisible to software (PCIe r7.0,
> Section 4.2.7.8.1). This change adds support for the WAKE# mechanism in
> the PCI core.
>
> According to the PCIe specification, multiple WAKE# signals can exist in
> a system or each component in the hierarchy could share a single WAKE#
> signal. In configurations involving a PCIe switch, each downstream port
> (DSP) of the switch may be connected to a separate WAKE# line, allowing
> each endpoint to signal WAKE# independently. From figure 5.4 in sec
> 5.3.3.2, WAKE# can also be terminated at the switch itself. To support
> this, the WAKE# should be described in the device tree node of the
> endpoint/bridge. If all endpoints share a single WAKE# line, then each
> endpoint node should describe the same WAKE# signal or a single WAKE# in
> the Root Port node.
>
> In pci_device_add(), PCI framework will search for the WAKE# in device
> node, If not found, it searches in its upstream port only if upstream port
> is Root Port. Once found, register for the wake IRQ in shared mode, as the
> WAKE# may be shared among multiple endpoints.
>
> dev_pm_set_dedicated_shared_wake_irq() associates a wakeup IRQ with a
> device and requests it, but the PM core keeps the IRQ disabled by default.
> The IRQ is enabled only when the device is permitted to wake the system,
> i.e. during system suspend and after runtime suspend, and only when 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, such as transitioning from
> D3cold to D0. Once the device is active and the link is usable, the
> endpoint may generate a PME, which is then handled by the PCI core through
> PME polling or the PCIe PME service driver to complete the wakeup of the
> endpoint.
>
> WAKE# is added in dts schema and merged based on below links.
>
> Link: https://lore.kernel.org/all/20250515090517.3506772-1-krishna.chundru@oss.qualcomm.com/
> Link: https://github.com/devicetree-org/dt-schema/pull/170
> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
No. Linus never gave this tag for *this* patch.
- Mani
> Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
> ---
> drivers/pci/of.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++
> drivers/pci/pci.c | 10 +++++++
> drivers/pci/pci.h | 2 ++
> drivers/pci/probe.c | 2 ++
> drivers/pci/remove.c | 1 +
> include/linux/of_pci.h | 4 +++
> include/linux/pci.h | 2 ++
> 7 files changed, 95 insertions(+)
>
> diff --git a/drivers/pci/of.c b/drivers/pci/of.c
> index 9f8eb5df279ed28db7a3b2fd29c65da9975c2efa..b7199d3598b31b62245716c178a5a73565efc89e 100644
> --- a/drivers/pci/of.c
> +++ b/drivers/pci/of.c
> @@ -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,78 @@ 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;
> +
> + wake_irq = gpiod_to_irq(wake);
> + if (wake_irq < 0) {
> + pci_err(pdev, "Failed to get wake irq: %d\n", wake_irq);
> + return;
> + }
> +
> + device_init_wakeup(&pdev->dev, true);
> +
> + /*
> + * dev_pm_set_dedicated_shared_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 particular endpoint.
> + */
> + ret = dev_pm_set_dedicated_shared_wake_irq(&pdev->dev, wake_irq,
> + IRQ_TYPE_EDGE_FALLING);
> + if (ret < 0) {
> + pci_err(pdev, "Failed to set wake IRQ: %d\n", ret);
> + device_init_wakeup(&pdev->dev, false);
> + }
> +}
> +
> +void pci_configure_of_wake_gpio(struct pci_dev *dev)
> +{
> + struct device_node *dn = pci_device_to_OF_node(dev);
> + struct pci_dev *upstream;
> + struct gpio_desc *gpio;
> +
> + if (!dn)
> + return;
> +
> + /*
> + * The devices in a hierarchy expose wakeup capability through the 'wake-gpios'
> + * property defined either in the device node or in the Slot node. So first check
> + * for the property in device node and if not available, check in the Slot node.
> + */
> + gpio = fwnode_gpiod_get(of_fwnode_handle(dn), "wake",
> + GPIOD_IN | GPIOD_FLAGS_BIT_NONEXCLUSIVE, NULL);
> + if (IS_ERR(gpio)) {
> + upstream = pci_upstream_bridge(dev);
> + if (upstream && pci_is_root_bus(upstream->bus) && upstream->wake)
> + pci_configure_wake_irq(dev, upstream->wake);
> + } else {
> + 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;
> +
> + dev_pm_clear_wake_irq(&dev->dev);
> + device_init_wakeup(&dev->dev, false);
> + gpiod_put(dev->wake);
> + dev->wake = NULL;
> +}
> #endif /* CONFIG_OF_IRQ */
>
> static int pci_parse_request_of_pci_ranges(struct device *dev,
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 8479c2e1f74f1044416281aba11bf071ea89488a..3d858f36ab48a6daec645574ca9027d9d6f071de 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -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>
> @@ -1123,6 +1124,15 @@ 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)
> +{
> + return pci_configure_of_wake_gpio(dev);
> +}
> +
> +void platform_pci_remove_wake(struct pci_dev *dev)
> +{
> + return pci_remove_of_wake_gpio(dev);
> +}
> /**
> * pci_update_current_state - Read power state of given device and cache it
> * @dev: PCI device to handle.
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index 13d998fbacce6698514d92500dfea03cc562cdc2..65ca9551e558d2e3331fab0a968620d6b2a2522a 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -282,6 +282,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)
> {
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index bccc7a4bdd794384b7877d453c7989941471c999..372b0d2f4531ea53c0570608306a547101d59e7b 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -2771,6 +2771,8 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
> /* Establish pdev->tsm for newly added (e.g. new SR-IOV VFs) */
> pci_tsm_init(dev);
>
> + platform_pci_configure_wake(dev);
> +
> pci_npem_create(dev);
>
> pci_doe_sysfs_init(dev);
> diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
> index e9d519993853f92f1810d3eff9f44ca7e3e1abd9..d781b41e57c4444077075690cec926a9fe15334f 100644
> --- a/drivers/pci/remove.c
> +++ b/drivers/pci/remove.c
> @@ -35,6 +35,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);
>
> diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
> index 29658c0ee71ff10122760214d04ee2bab01709fd..0efd6e9cb4d3d3beaafb42ea411303139f1150d5 100644
> --- a/include/linux/of_pci.h
> +++ b/include/linux/of_pci.h
> @@ -30,12 +30,16 @@ 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
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 1c270f1d512301de4d462fe7e5097c32af5c6f8d..d1e08df8a8deaa87780589f23242767fdcdba541 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -586,6 +586,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; /* Holds WAKE# gpio */
> +
> #ifdef CONFIG_PCIE_TPH
> u16 tph_cap; /* TPH capability offset */
> u8 tph_mode; /* TPH mode */
>
> --
> 2.34.1
>
>
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v8 3/3] PCI: Add support for PCIe WAKE# interrupt
2026-03-13 13:58 ` Manivannan Sadhasivam
@ 2026-03-16 12:16 ` Krishna Chaitanya Chundru
2026-03-17 7:07 ` Manivannan Sadhasivam
0 siblings, 1 reply; 10+ messages in thread
From: Krishna Chaitanya Chundru @ 2026-03-16 12:16 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Rafael J. Wysocki, Len Brown, Pavel Machek, Greg Kroah-Hartman,
Danilo Krummrich, Bjorn Helgaas, Bartosz Golaszewski,
Linus Walleij, Bartosz Golaszewski, Rob Herring, Saravana Kannan,
linux-pm, linux-kernel, linux-pci, linux-gpio, quic_vbadigan,
sherry.sun, driver-core, devicetree
On 3/13/2026 7:28 PM, Manivannan Sadhasivam wrote:
> On Fri, Mar 13, 2026 at 12:38:42PM +0530, Krishna Chaitanya Chundru wrote:
>> According to the PCI Express specification (PCIe r7.0, Section 5.3.3.2),
>> two link wakeup mechanisms are defined: Beacon and WAKE#. Beacon is a
>> hardware-only mechanism and is invisible to software (PCIe r7.0,
>> Section 4.2.7.8.1). This change adds support for the WAKE# mechanism in
>> the PCI core.
>>
>> According to the PCIe specification, multiple WAKE# signals can exist in
>> a system or each component in the hierarchy could share a single WAKE#
>> signal. In configurations involving a PCIe switch, each downstream port
>> (DSP) of the switch may be connected to a separate WAKE# line, allowing
>> each endpoint to signal WAKE# independently. From figure 5.4 in sec
>> 5.3.3.2, WAKE# can also be terminated at the switch itself. To support
>> this, the WAKE# should be described in the device tree node of the
>> endpoint/bridge. If all endpoints share a single WAKE# line, then each
>> endpoint node should describe the same WAKE# signal or a single WAKE# in
>> the Root Port node.
>>
>> In pci_device_add(), PCI framework will search for the WAKE# in device
>> node, If not found, it searches in its upstream port only if upstream port
>> is Root Port. Once found, register for the wake IRQ in shared mode, as the
>> WAKE# may be shared among multiple endpoints.
>>
>> dev_pm_set_dedicated_shared_wake_irq() associates a wakeup IRQ with a
>> device and requests it, but the PM core keeps the IRQ disabled by default.
>> The IRQ is enabled only when the device is permitted to wake the system,
>> i.e. during system suspend and after runtime suspend, and only when 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, such as transitioning from
>> D3cold to D0. Once the device is active and the link is usable, the
>> endpoint may generate a PME, which is then handled by the PCI core through
>> PME polling or the PCIe PME service driver to complete the wakeup of the
>> endpoint.
>>
>> WAKE# is added in dts schema and merged based on below links.
>>
>> Link: https://lore.kernel.org/all/20250515090517.3506772-1-krishna.chundru@oss.qualcomm.com/
>> Link: https://github.com/devicetree-org/dt-schema/pull/170
>> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
> No. Linus never gave this tag for *this* patch.
Linus gave this on v5 [1], might be a overlook.
[1] Re: [PATCH v5 2/2] PCI: Add support for PCIe WAKE# interrupt - Linus
Walleij
<https://lore.kernel.org/all/CACRpkdY9HsnG=xo=swnMcVha+unmvmxR6e6Ynsj09srM_tPmWA@mail.gmail.com/>
- Krishna Chaitanya.
> - Mani
>
>> Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
>> ---
>> drivers/pci/of.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++
>> drivers/pci/pci.c | 10 +++++++
>> drivers/pci/pci.h | 2 ++
>> drivers/pci/probe.c | 2 ++
>> drivers/pci/remove.c | 1 +
>> include/linux/of_pci.h | 4 +++
>> include/linux/pci.h | 2 ++
>> 7 files changed, 95 insertions(+)
>>
>> diff --git a/drivers/pci/of.c b/drivers/pci/of.c
>> index 9f8eb5df279ed28db7a3b2fd29c65da9975c2efa..b7199d3598b31b62245716c178a5a73565efc89e 100644
>> --- a/drivers/pci/of.c
>> +++ b/drivers/pci/of.c
>> @@ -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,78 @@ 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;
>> +
>> + wake_irq = gpiod_to_irq(wake);
>> + if (wake_irq < 0) {
>> + pci_err(pdev, "Failed to get wake irq: %d\n", wake_irq);
>> + return;
>> + }
>> +
>> + device_init_wakeup(&pdev->dev, true);
>> +
>> + /*
>> + * dev_pm_set_dedicated_shared_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 particular endpoint.
>> + */
>> + ret = dev_pm_set_dedicated_shared_wake_irq(&pdev->dev, wake_irq,
>> + IRQ_TYPE_EDGE_FALLING);
>> + if (ret < 0) {
>> + pci_err(pdev, "Failed to set wake IRQ: %d\n", ret);
>> + device_init_wakeup(&pdev->dev, false);
>> + }
>> +}
>> +
>> +void pci_configure_of_wake_gpio(struct pci_dev *dev)
>> +{
>> + struct device_node *dn = pci_device_to_OF_node(dev);
>> + struct pci_dev *upstream;
>> + struct gpio_desc *gpio;
>> +
>> + if (!dn)
>> + return;
>> +
>> + /*
>> + * The devices in a hierarchy expose wakeup capability through the 'wake-gpios'
>> + * property defined either in the device node or in the Slot node. So first check
>> + * for the property in device node and if not available, check in the Slot node.
>> + */
>> + gpio = fwnode_gpiod_get(of_fwnode_handle(dn), "wake",
>> + GPIOD_IN | GPIOD_FLAGS_BIT_NONEXCLUSIVE, NULL);
>> + if (IS_ERR(gpio)) {
>> + upstream = pci_upstream_bridge(dev);
>> + if (upstream && pci_is_root_bus(upstream->bus) && upstream->wake)
>> + pci_configure_wake_irq(dev, upstream->wake);
>> + } else {
>> + 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;
>> +
>> + dev_pm_clear_wake_irq(&dev->dev);
>> + device_init_wakeup(&dev->dev, false);
>> + gpiod_put(dev->wake);
>> + dev->wake = NULL;
>> +}
>> #endif /* CONFIG_OF_IRQ */
>>
>> static int pci_parse_request_of_pci_ranges(struct device *dev,
>> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
>> index 8479c2e1f74f1044416281aba11bf071ea89488a..3d858f36ab48a6daec645574ca9027d9d6f071de 100644
>> --- a/drivers/pci/pci.c
>> +++ b/drivers/pci/pci.c
>> @@ -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>
>> @@ -1123,6 +1124,15 @@ 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)
>> +{
>> + return pci_configure_of_wake_gpio(dev);
>> +}
>> +
>> +void platform_pci_remove_wake(struct pci_dev *dev)
>> +{
>> + return pci_remove_of_wake_gpio(dev);
>> +}
>> /**
>> * pci_update_current_state - Read power state of given device and cache it
>> * @dev: PCI device to handle.
>> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
>> index 13d998fbacce6698514d92500dfea03cc562cdc2..65ca9551e558d2e3331fab0a968620d6b2a2522a 100644
>> --- a/drivers/pci/pci.h
>> +++ b/drivers/pci/pci.h
>> @@ -282,6 +282,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)
>> {
>> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
>> index bccc7a4bdd794384b7877d453c7989941471c999..372b0d2f4531ea53c0570608306a547101d59e7b 100644
>> --- a/drivers/pci/probe.c
>> +++ b/drivers/pci/probe.c
>> @@ -2771,6 +2771,8 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
>> /* Establish pdev->tsm for newly added (e.g. new SR-IOV VFs) */
>> pci_tsm_init(dev);
>>
>> + platform_pci_configure_wake(dev);
>> +
>> pci_npem_create(dev);
>>
>> pci_doe_sysfs_init(dev);
>> diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
>> index e9d519993853f92f1810d3eff9f44ca7e3e1abd9..d781b41e57c4444077075690cec926a9fe15334f 100644
>> --- a/drivers/pci/remove.c
>> +++ b/drivers/pci/remove.c
>> @@ -35,6 +35,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);
>>
>> diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
>> index 29658c0ee71ff10122760214d04ee2bab01709fd..0efd6e9cb4d3d3beaafb42ea411303139f1150d5 100644
>> --- a/include/linux/of_pci.h
>> +++ b/include/linux/of_pci.h
>> @@ -30,12 +30,16 @@ 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
>> diff --git a/include/linux/pci.h b/include/linux/pci.h
>> index 1c270f1d512301de4d462fe7e5097c32af5c6f8d..d1e08df8a8deaa87780589f23242767fdcdba541 100644
>> --- a/include/linux/pci.h
>> +++ b/include/linux/pci.h
>> @@ -586,6 +586,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; /* Holds WAKE# gpio */
>> +
>> #ifdef CONFIG_PCIE_TPH
>> u16 tph_cap; /* TPH capability offset */
>> u8 tph_mode; /* TPH mode */
>>
>> --
>> 2.34.1
>>
>>
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v8 3/3] PCI: Add support for PCIe WAKE# interrupt
2026-03-16 12:16 ` Krishna Chaitanya Chundru
@ 2026-03-17 7:07 ` Manivannan Sadhasivam
0 siblings, 0 replies; 10+ messages in thread
From: Manivannan Sadhasivam @ 2026-03-17 7:07 UTC (permalink / raw)
To: Krishna Chaitanya Chundru
Cc: Rafael J. Wysocki, Len Brown, Pavel Machek, Greg Kroah-Hartman,
Danilo Krummrich, Bjorn Helgaas, Bartosz Golaszewski,
Linus Walleij, Bartosz Golaszewski, Rob Herring, Saravana Kannan,
linux-pm, linux-kernel, linux-pci, linux-gpio, quic_vbadigan,
sherry.sun, driver-core, devicetree
On Mon, Mar 16, 2026 at 05:46:58PM +0530, Krishna Chaitanya Chundru wrote:
>
>
> On 3/13/2026 7:28 PM, Manivannan Sadhasivam wrote:
> > On Fri, Mar 13, 2026 at 12:38:42PM +0530, Krishna Chaitanya Chundru wrote:
> > > According to the PCI Express specification (PCIe r7.0, Section 5.3.3.2),
> > > two link wakeup mechanisms are defined: Beacon and WAKE#. Beacon is a
> > > hardware-only mechanism and is invisible to software (PCIe r7.0,
> > > Section 4.2.7.8.1). This change adds support for the WAKE# mechanism in
> > > the PCI core.
> > >
> > > According to the PCIe specification, multiple WAKE# signals can exist in
> > > a system or each component in the hierarchy could share a single WAKE#
> > > signal. In configurations involving a PCIe switch, each downstream port
> > > (DSP) of the switch may be connected to a separate WAKE# line, allowing
> > > each endpoint to signal WAKE# independently. From figure 5.4 in sec
> > > 5.3.3.2, WAKE# can also be terminated at the switch itself. To support
> > > this, the WAKE# should be described in the device tree node of the
> > > endpoint/bridge. If all endpoints share a single WAKE# line, then each
> > > endpoint node should describe the same WAKE# signal or a single WAKE# in
> > > the Root Port node.
> > >
> > > In pci_device_add(), PCI framework will search for the WAKE# in device
> > > node, If not found, it searches in its upstream port only if upstream port
> > > is Root Port. Once found, register for the wake IRQ in shared mode, as the
> > > WAKE# may be shared among multiple endpoints.
> > >
> > > dev_pm_set_dedicated_shared_wake_irq() associates a wakeup IRQ with a
> > > device and requests it, but the PM core keeps the IRQ disabled by default.
> > > The IRQ is enabled only when the device is permitted to wake the system,
> > > i.e. during system suspend and after runtime suspend, and only when 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, such as transitioning from
> > > D3cold to D0. Once the device is active and the link is usable, the
> > > endpoint may generate a PME, which is then handled by the PCI core through
> > > PME polling or the PCIe PME service driver to complete the wakeup of the
> > > endpoint.
> > >
> > > WAKE# is added in dts schema and merged based on below links.
> > >
> > > Link: https://lore.kernel.org/all/20250515090517.3506772-1-krishna.chundru@oss.qualcomm.com/
> > > Link: https://github.com/devicetree-org/dt-schema/pull/170
> > > Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
> > No. Linus never gave this tag for *this* patch.
> Linus gave this on v5 [1], might be a overlook.
>
> [1] Re: [PATCH v5 2/2] PCI: Add support for PCIe WAKE# interrupt - Linus
> Walleij <https://lore.kernel.org/all/CACRpkdY9HsnG=xo=swnMcVha+unmvmxR6e6Ynsj09srM_tPmWA@mail.gmail.com/>
>
Oh yes. I didn't check it properly. Please ignore my comment.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v8 3/3] PCI: Add support for PCIe WAKE# interrupt
2026-03-13 7:08 ` [PATCH v8 3/3] PCI: Add support for PCIe WAKE# interrupt Krishna Chaitanya Chundru
2026-03-13 13:58 ` Manivannan Sadhasivam
@ 2026-03-17 7:26 ` Manivannan Sadhasivam
2026-03-24 12:03 ` Krishna Chaitanya Chundru
1 sibling, 1 reply; 10+ messages in thread
From: Manivannan Sadhasivam @ 2026-03-17 7:26 UTC (permalink / raw)
To: Krishna Chaitanya Chundru
Cc: Rafael J. Wysocki, Len Brown, Pavel Machek, Greg Kroah-Hartman,
Danilo Krummrich, Bjorn Helgaas, Bartosz Golaszewski,
Linus Walleij, Bartosz Golaszewski, Rob Herring, Saravana Kannan,
linux-pm, linux-kernel, linux-pci, linux-gpio, quic_vbadigan,
sherry.sun, driver-core, devicetree
On Fri, Mar 13, 2026 at 12:38:42PM +0530, Krishna Chaitanya Chundru wrote:
> According to the PCI Express specification (PCIe r7.0, Section 5.3.3.2),
> two link wakeup mechanisms are defined: Beacon and WAKE#. Beacon is a
> hardware-only mechanism and is invisible to software (PCIe r7.0,
> Section 4.2.7.8.1). This change adds support for the WAKE# mechanism in
> the PCI core.
>
> According to the PCIe specification, multiple WAKE# signals can exist in
> a system or each component in the hierarchy could share a single WAKE#
> signal. In configurations involving a PCIe switch, each downstream port
> (DSP) of the switch may be connected to a separate WAKE# line, allowing
> each endpoint to signal WAKE# independently. From figure 5.4 in sec
> 5.3.3.2, WAKE# can also be terminated at the switch itself. To support
> this, the WAKE# should be described in the device tree node of the
> endpoint/bridge. If all endpoints share a single WAKE# line, then each
> endpoint node should describe the same WAKE# signal or a single WAKE# in
> the Root Port node.
>
> In pci_device_add(), PCI framework will search for the WAKE# in device
> node, If not found, it searches in its upstream port only if upstream port
> is Root Port. Once found, register for the wake IRQ in shared mode, as the
> WAKE# may be shared among multiple endpoints.
>
> dev_pm_set_dedicated_shared_wake_irq() associates a wakeup IRQ with a
> device and requests it, but the PM core keeps the IRQ disabled by default.
> The IRQ is enabled only when the device is permitted to wake the system,
> i.e. during system suspend and after runtime suspend, and only when 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, such as transitioning from
> D3cold to D0. Once the device is active and the link is usable, the
> endpoint may generate a PME, which is then handled by the PCI core through
> PME polling or the PCIe PME service driver to complete the wakeup of the
> endpoint.
>
> WAKE# is added in dts schema and merged based on below links.
>
> Link: https://lore.kernel.org/all/20250515090517.3506772-1-krishna.chundru@oss.qualcomm.com/
> Link: https://github.com/devicetree-org/dt-schema/pull/170
> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
> Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
> ---
> drivers/pci/of.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++
> drivers/pci/pci.c | 10 +++++++
> drivers/pci/pci.h | 2 ++
> drivers/pci/probe.c | 2 ++
> drivers/pci/remove.c | 1 +
> include/linux/of_pci.h | 4 +++
> include/linux/pci.h | 2 ++
> 7 files changed, 95 insertions(+)
>
> diff --git a/drivers/pci/of.c b/drivers/pci/of.c
> index 9f8eb5df279ed28db7a3b2fd29c65da9975c2efa..b7199d3598b31b62245716c178a5a73565efc89e 100644
> --- a/drivers/pci/of.c
> +++ b/drivers/pci/of.c
> @@ -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,78 @@ 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;
> +
> + wake_irq = gpiod_to_irq(wake);
> + if (wake_irq < 0) {
> + pci_err(pdev, "Failed to get wake irq: %d\n", wake_irq);
> + return;
> + }
> +
> + device_init_wakeup(&pdev->dev, true);
Just set wakeup only if dev_pm_set_dedicated_shared_wake_irq() succeeds.
> +
> + /*
> + * dev_pm_set_dedicated_shared_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 particular endpoint.
> + */
> + ret = dev_pm_set_dedicated_shared_wake_irq(&pdev->dev, wake_irq,
> + IRQ_TYPE_EDGE_FALLING);
Isn't WAKE# a level triggered signal?
> + if (ret < 0) {
> + pci_err(pdev, "Failed to set wake IRQ: %d\n", ret);
s/wake/WAKE#
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v8 3/3] PCI: Add support for PCIe WAKE# interrupt
2026-03-17 7:26 ` Manivannan Sadhasivam
@ 2026-03-24 12:03 ` Krishna Chaitanya Chundru
0 siblings, 0 replies; 10+ messages in thread
From: Krishna Chaitanya Chundru @ 2026-03-24 12:03 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Rafael J. Wysocki, Len Brown, Pavel Machek, Greg Kroah-Hartman,
Danilo Krummrich, Bjorn Helgaas, Bartosz Golaszewski,
Linus Walleij, Bartosz Golaszewski, Rob Herring, Saravana Kannan,
linux-pm, linux-kernel, linux-pci, linux-gpio, quic_vbadigan,
sherry.sun, driver-core, devicetree
On 3/17/2026 12:56 PM, Manivannan Sadhasivam wrote:
> On Fri, Mar 13, 2026 at 12:38:42PM +0530, Krishna Chaitanya Chundru wrote:
>> According to the PCI Express specification (PCIe r7.0, Section 5.3.3.2),
>> two link wakeup mechanisms are defined: Beacon and WAKE#. Beacon is a
>> hardware-only mechanism and is invisible to software (PCIe r7.0,
>> Section 4.2.7.8.1). This change adds support for the WAKE# mechanism in
>> the PCI core.
>>
>> According to the PCIe specification, multiple WAKE# signals can exist in
>> a system or each component in the hierarchy could share a single WAKE#
>> signal. In configurations involving a PCIe switch, each downstream port
>> (DSP) of the switch may be connected to a separate WAKE# line, allowing
>> each endpoint to signal WAKE# independently. From figure 5.4 in sec
>> 5.3.3.2, WAKE# can also be terminated at the switch itself. To support
>> this, the WAKE# should be described in the device tree node of the
>> endpoint/bridge. If all endpoints share a single WAKE# line, then each
>> endpoint node should describe the same WAKE# signal or a single WAKE# in
>> the Root Port node.
>>
>> In pci_device_add(), PCI framework will search for the WAKE# in device
>> node, If not found, it searches in its upstream port only if upstream port
>> is Root Port. Once found, register for the wake IRQ in shared mode, as the
>> WAKE# may be shared among multiple endpoints.
>>
>> dev_pm_set_dedicated_shared_wake_irq() associates a wakeup IRQ with a
>> device and requests it, but the PM core keeps the IRQ disabled by default.
>> The IRQ is enabled only when the device is permitted to wake the system,
>> i.e. during system suspend and after runtime suspend, and only when 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, such as transitioning from
>> D3cold to D0. Once the device is active and the link is usable, the
>> endpoint may generate a PME, which is then handled by the PCI core through
>> PME polling or the PCIe PME service driver to complete the wakeup of the
>> endpoint.
>>
>> WAKE# is added in dts schema and merged based on below links.
>>
>> Link: https://lore.kernel.org/all/20250515090517.3506772-1-krishna.chundru@oss.qualcomm.com/
>> Link: https://github.com/devicetree-org/dt-schema/pull/170
>> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
>> Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
>> ---
>> drivers/pci/of.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++
>> drivers/pci/pci.c | 10 +++++++
>> drivers/pci/pci.h | 2 ++
>> drivers/pci/probe.c | 2 ++
>> drivers/pci/remove.c | 1 +
>> include/linux/of_pci.h | 4 +++
>> include/linux/pci.h | 2 ++
>> 7 files changed, 95 insertions(+)
>>
>> diff --git a/drivers/pci/of.c b/drivers/pci/of.c
>> index 9f8eb5df279ed28db7a3b2fd29c65da9975c2efa..b7199d3598b31b62245716c178a5a73565efc89e 100644
>> --- a/drivers/pci/of.c
>> +++ b/drivers/pci/of.c
>> @@ -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,78 @@ 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;
>> +
>> + wake_irq = gpiod_to_irq(wake);
>> + if (wake_irq < 0) {
>> + pci_err(pdev, "Failed to get wake irq: %d\n", wake_irq);
>> + return;
>> + }
>> +
>> + device_init_wakeup(&pdev->dev, true);
> Just set wakeup only if dev_pm_set_dedicated_shared_wake_irq() succeeds.
ack.
>> +
>> + /*
>> + * dev_pm_set_dedicated_shared_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 particular endpoint.
>> + */
>> + ret = dev_pm_set_dedicated_shared_wake_irq(&pdev->dev, wake_irq,
>> + IRQ_TYPE_EDGE_FALLING);
> Isn't WAKE# a level triggered signal?
Ack. I will change IRQ_TYPE_EDGE_FALLING to IRQ_TYPE_LEVEL_LOW.
>> + if (ret < 0) {
>> + pci_err(pdev, "Failed to set wake IRQ: %d\n", ret);
> s/wake/WAKE#
ack.
- Krishna Chaitanya.
> - Mani
>
^ permalink raw reply [flat|nested] 10+ messages in thread