Re: [PATCH v2 2/2] PCI: Add support for PCIe wake interrupt

From: Krishna Chaitanya Chundru
Date: Tue Jun 03 2025 - 02:27:22 EST




On 6/1/2025 8:51 PM, Manivannan Sadhasivam wrote:
On Sat, Apr 19, 2025 at 11:13:04AM +0530, Krishna Chaitanya Chundru wrote:

Subject prefix should be 'PCI/portdrv'

PCIe wake interrupt is needed for bringing back PCIe device state
from D3cold to D0.

Implement new functions, of_pci_setup_wake_irq() and
of_pci_teardown_wake_irq(), to manage wake interrupts for PCI devices
using the Device Tree.

From the port bus driver call these functions to enable wake support
for bridges.

Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@xxxxxxxxxxxxxxxx>
---
drivers/pci/of.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/pci/pci.h | 6 +++++
drivers/pci/pcie/portdrv.c | 12 +++++++++-
3 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index ab7a8252bf4137a17971c3eb8ab70ce78ca70969..13623797c88a03dfb9d9079518d87a5e1e68df38 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
@@ -966,3 +968,61 @@ u32 of_pci_get_slot_power_limit(struct device_node *node,
return slot_power_limit_mw;
}
EXPORT_SYMBOL_GPL(of_pci_get_slot_power_limit);
+
+/**
+ * of_pci_setup_wake_irq - Set up wake interrupt for PCI device

This function is for setting up the wake interrupt for slot, not for endpoint
devices, isn't it? Then it should be named as such:

of_pci_slot_setup_wake_irq()

+ * @pdev: The PCI device structure
+ *
+ * This function sets up the wake interrupt for a PCI device by getting the
+ * corresponding GPIO pin from the device tree, and configuring it as a

s/GPIO pin/WAKE# GPIO

+ * dedicated wake interrupt.
+ *
+ * Return: 0 if the wake gpio is not available or successfully parsed else

s/wake gpio/WAKE# GPIO

+ * errno otherwise.
+ */
+int of_pci_setup_wake_irq(struct pci_dev *pdev)
+{
+ struct gpio_desc *wake;
+ struct device_node *dn;
+ int ret, wake_irq;
+
+ dn = pci_device_to_OF_node(pdev);
+ if (!dn)
+ return 0;
+
+ wake = devm_fwnode_gpiod_get(&pdev->dev, of_fwnode_handle(dn),
+ "wake", GPIOD_IN, NULL);
+ if (IS_ERR(wake)) {
+ dev_warn(&pdev->dev, "Cannot get wake GPIO\n");

WAKE# is an optional GPIO. So the driver should not warn users if it is not
defined in the root port node. It should however print the error log and return
errno, if the API returns other than -ENOENT.

+ return 0;
+ }
+
+ wake_irq = gpiod_to_irq(wake);
+ device_init_wakeup(&pdev->dev, true);
+
+ ret = dev_pm_set_dedicated_wake_irq(&pdev->dev, wake_irq);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to set wake IRQ: %d\n", ret);
+ device_init_wakeup(&pdev->dev, false);
+ return ret;
+ }
+ irq_set_irq_type(wake_irq, IRQ_TYPE_EDGE_FALLING);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_pci_setup_wake_irq);
+
+/**
+ * of_pci_teardown_wake_irq - Teardown wake interrupt setup for PCI device

Same comment as above.

+ *
+ * @pdev: The PCI device structure
+ *
+ * This function tears down the wake interrupt setup for a PCI device,
+ * clearing the dedicated wake interrupt and disabling device wake-up.
+ */
+void of_pci_teardown_wake_irq(struct pci_dev *pdev)
+{
+ dev_pm_clear_wake_irq(&pdev->dev);
+ device_init_wakeup(&pdev->dev, false);
+}
+EXPORT_SYMBOL_GPL(of_pci_teardown_wake_irq);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index b81e99cd4b62a3022c8b07a09f212f6888674487..b2f65289f4156fa1851c2d2f20c4ca948f36258f 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -888,6 +888,9 @@ void pci_release_of_node(struct pci_dev *dev);
void pci_set_bus_of_node(struct pci_bus *bus);
void pci_release_bus_of_node(struct pci_bus *bus);
+int of_pci_setup_wake_irq(struct pci_dev *pdev);
+void of_pci_teardown_wake_irq(struct pci_dev *pdev);
+
int devm_of_pci_bridge_init(struct device *dev, struct pci_host_bridge *bridge);
bool of_pci_supply_present(struct device_node *np);
@@ -931,6 +934,9 @@ static inline int devm_of_pci_bridge_init(struct device *dev, struct pci_host_br
return 0;
}
+static int of_pci_setup_wake_irq(struct pci_dev *pdev) { return 0; }
+static void of_pci_teardown_wake_irq(struct pci_dev *pdev) { }
+

Provide stub for these APIs if CONFIG_OF is not enabled.

These are the stub functions when CONFIG_OF is not enabled.

- Krishna Chaitanya.
- Mani