From: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
To: Manivannan Sadhasivam <mani@kernel.org>
Cc: "Rafael J. Wysocki" <rafael@kernel.org>,
Len Brown <lenb@kernel.org>, Pavel Machek <pavel@kernel.org>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Danilo Krummrich <dakr@kernel.org>,
Bjorn Helgaas <bhelgaas@google.com>,
Bartosz Golaszewski <brgl@bgdev.pl>,
Linus Walleij <linusw@kernel.org>,
Bartosz Golaszewski <brgl@kernel.org>,
Rob Herring <robh@kernel.org>,
Saravana Kannan <saravanak@kernel.org>,
linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-pci@vger.kernel.org, linux-gpio@vger.kernel.org,
quic_vbadigan@quicinc.com, sherry.sun@nxp.com,
driver-core@lists.linux.dev, devicetree@vger.kernel.org
Subject: Re: [PATCH v8 3/3] PCI: Add support for PCIe WAKE# interrupt
Date: Mon, 16 Mar 2026 17:46:58 +0530 [thread overview]
Message-ID: <be9980f3-f036-4260-980f-5d996bc034cb@oss.qualcomm.com> (raw)
In-Reply-To: <53uy2vdzc25frf5rpwbybaor5n6jesapl2x7xusnn5zfaqnfy7@udq7ln2a42n5>
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
>>
>>
next prev parent reply other threads:[~2026-03-16 12:17 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
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 13:55 ` Bartosz Golaszewski
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 [this message]
2026-03-17 7:07 ` Manivannan Sadhasivam
2026-03-17 7:26 ` Manivannan Sadhasivam
2026-03-24 12:03 ` Krishna Chaitanya Chundru
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=be9980f3-f036-4260-980f-5d996bc034cb@oss.qualcomm.com \
--to=krishna.chundru@oss.qualcomm.com \
--cc=bhelgaas@google.com \
--cc=brgl@bgdev.pl \
--cc=brgl@kernel.org \
--cc=dakr@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=driver-core@lists.linux.dev \
--cc=gregkh@linuxfoundation.org \
--cc=lenb@kernel.org \
--cc=linusw@kernel.org \
--cc=linux-gpio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=mani@kernel.org \
--cc=pavel@kernel.org \
--cc=quic_vbadigan@quicinc.com \
--cc=rafael@kernel.org \
--cc=robh@kernel.org \
--cc=saravanak@kernel.org \
--cc=sherry.sun@nxp.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox