> -----Original Message----- > From: Krishna Chaitanya Chundru <krishna.chundru@xxxxxxxxxxxxxxxx> > Sent: Friday, May 9, 2025 3:59 PM > To: Bjorn Helgaas <bhelgaas@xxxxxxxxxx> > Cc: linux-arm-msm@xxxxxxxxxxxxxxx; Konrad Dybcio > <konradybcio@xxxxxxxxxx>; devicetree@xxxxxxxxxxxxxxx; linux- > kernel@xxxxxxxxxxxxxxx; linux-pci@xxxxxxxxxxxxxxx; > quic_vbadigan@xxxxxxxxxxx; quic_mrana@xxxxxxxxxxx; cros-qcom-dts- > watchers@xxxxxxxxxxxx; Conor Dooley <conor+dt@xxxxxxxxxx>; Rob Herring > <robh@xxxxxxxxxx>; Krzysztof Kozlowski <krzk+dt@xxxxxxxxxx>; Bjorn > Andersson <andersson@xxxxxxxxxx> > Subject: Re: [PATCH v2 2/2] PCI: Add support for PCIe wake interrupt > > A Gentle remainder. > > - Krishna Chaitanya. > > On 4/19/2025 11:13 AM, Krishna Chaitanya Chundru wrote: > > 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> Hi Krishna, I have tested the patch set on i.MX platforms, it works. you can add my Tested-by: Sherry Sun <sherry.sun@xxxxxxx>. BTW, as PEWAKE is a standard feature in PCIe bus specification, Suppose you may need to add wake-gpios property into the common PCI root port dt-schema. Best Regards Sherry > > --- > > 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..13623797c88a03dfb9d90795 > 18d8 > > 7a5e1e68df38 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 > > + * @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 > > + * dedicated wake interrupt. > > + * > > + * Return: 0 if the wake gpio is not available or successfully parsed > > +else > > + * 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"); > > + 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 > > + * > > + * @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..b2f65289f4156fa1851c2d2f2 > 0c4 > > ca948f36258f 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) { } > > + > > static inline bool of_pci_supply_present(struct device_node *np) > > { > > return false; > > diff --git a/drivers/pci/pcie/portdrv.c b/drivers/pci/pcie/portdrv.c > > index > > > e8318fd5f6ed537a1b236a3a0f054161d5710abd..33220ecf821c348d49782855 > eb5a > > a3f2fe5c335e 100644 > > --- a/drivers/pci/pcie/portdrv.c > > +++ b/drivers/pci/pcie/portdrv.c > > @@ -694,12 +694,18 @@ static int pcie_portdrv_probe(struct pci_dev *dev, > > (type != PCI_EXP_TYPE_RC_EC))) > > return -ENODEV; > > > > + status = of_pci_setup_wake_irq(dev); > > + if (status) > > + return status; > > + > > if (type == PCI_EXP_TYPE_RC_EC) > > pcie_link_rcec(dev); > > > > status = pcie_port_device_register(dev); > > - if (status) > > + if (status) { > > + of_pci_teardown_wake_irq(dev); > > return status; > > + } > > > > pci_save_state(dev); > > > > @@ -732,6 +738,8 @@ static void pcie_portdrv_remove(struct pci_dev > > *dev) > > > > pcie_port_device_remove(dev); > > > > + of_pci_teardown_wake_irq(dev); > > + > > pci_disable_device(dev); > > } > > > > @@ -744,6 +752,8 @@ static void pcie_portdrv_shutdown(struct pci_dev > *dev) > > } > > > > pcie_port_device_remove(dev); > > + > > + of_pci_teardown_wake_irq(dev); > > } > > > > static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev > > *dev, > >