mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Manivannan Sadhasivam <mani@kernel.org>
To: "Bartosz Golaszewski" <brgl@bgdev.pl>,
	"Bjorn Helgaas" <bhelgaas@google.com>,
	"Jingoo Han" <jingoohan1@gmail.com>,
	"Lorenzo Pieralisi" <lpieralisi@kernel.org>,
	"Krzysztof Wilczyński" <kwilczynski@kernel.org>,
	"Rob Herring" <robh@kernel.org>
Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org,
	 linux-arm-msm@vger.kernel.org,
	 Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>,
	 Brian Norris <briannorris@chromium.org>,
	 Manivannan Sadhasivam <mani@kernel.org>
Subject: [PATCH RFC 2/3] PCI/pwrctrl: Allow pwrctrl core to control PERST# GPIO if available
Date: Mon, 07 Jul 2025 23:48:39 +0530	[thread overview]
Message-ID: <20250707-pci-pwrctrl-perst-v1-2-c3c7e513e312@kernel.org> (raw)
In-Reply-To: <20250707-pci-pwrctrl-perst-v1-0-c3c7e513e312@kernel.org>

PERST# is an (optional) auxiliary signal provided by the PCIe host to
components for signalling 'Fundamental Reset' as per the PCIe spec r6.0,
sec 6.6.1.

If PERST# is available, it's state will be toggled during the component
power-up and power-down scenarios as per the PCI Express Card
Electromechanical Spec v4.0, sec 2.2.

Historically, the PCIe controller drivers were directly controlling the
PERST# signal together with the power supplies. But with the advent of the
pwrctrl framework, the power supply control is now moved to the pwrctrl,
but controller drivers still ended up toggling the PERST# signal. This only
happens on Qcom platforms where pwrctrl framework is being used. But
nevertheseless, it is wrong to toggle PERST# (especially deassert) without
controlling the power supplies.

So allow the pwrctrl core to control the PERST# GPIO is available. The
controller drivers still need to parse them and populate the
'host_bridge->perst' GPIO descriptor array based on the available slots.
Unfortunately, we cannot just move the PERST# handling from controller
drivers as most of the controller drivers need to assert PERST# during the
controller initialization.

Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
---
 drivers/pci/pwrctrl/core.c  | 39 +++++++++++++++++++++++++++++++++++++++
 include/linux/pci-pwrctrl.h |  2 ++
 include/linux/pci.h         |  2 ++
 3 files changed, 43 insertions(+)

diff --git a/drivers/pci/pwrctrl/core.c b/drivers/pci/pwrctrl/core.c
index 6bdbfed584d6d79ce28ba9e384a596b065ca69a4..abdb46399a96c8281916f971329d5460fcff3f6e 100644
--- a/drivers/pci/pwrctrl/core.c
+++ b/drivers/pci/pwrctrl/core.c
@@ -3,14 +3,19 @@
  * Copyright (C) 2024 Linaro Ltd.
  */
 
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/export.h>
+#include <linux/gpio/consumer.h>
 #include <linux/kernel.h>
+#include <linux/of_pci.h>
 #include <linux/pci.h>
 #include <linux/pci-pwrctrl.h>
 #include <linux/property.h>
 #include <linux/slab.h>
 
+#include "../pci.h"
+
 static int pci_pwrctrl_notify(struct notifier_block *nb, unsigned long action,
 			      void *data)
 {
@@ -56,11 +61,42 @@ static void rescan_work_func(struct work_struct *work)
  */
 void pci_pwrctrl_init(struct pci_pwrctrl *pwrctrl, struct device *dev)
 {
+	struct pci_host_bridge *host_bridge = to_pci_host_bridge(dev->parent);
+	int devfn;
+
 	pwrctrl->dev = dev;
 	INIT_WORK(&pwrctrl->work, rescan_work_func);
+
+	if (!host_bridge->perst)
+		return;
+
+	devfn = of_pci_get_devfn(dev_of_node(dev));
+	if (devfn >= 0 && host_bridge->perst[PCI_SLOT(devfn)])
+		pwrctrl->perst = host_bridge->perst[PCI_SLOT(devfn)];
 }
 EXPORT_SYMBOL_GPL(pci_pwrctrl_init);
 
+static void pci_pwrctrl_perst_deassert(struct pci_pwrctrl *pwrctrl)
+{
+	/* Bail out early to avoid the delay if PERST# is not available */
+	if (!pwrctrl->perst)
+		return;
+
+	msleep(PCIE_T_PVPERL_MS);
+	gpiod_set_value_cansleep(pwrctrl->perst, 0);
+	/*
+	 * FIXME: The following delay is only required for downstream ports not
+	 * supporting link speed greater than 5.0 GT/s.
+	 */
+	msleep(PCIE_RESET_CONFIG_DEVICE_WAIT_MS);
+}
+
+static void pci_pwrctrl_perst_assert(struct pci_pwrctrl *pwrctrl)
+{
+	/* No need to validate desc here as gpiod APIs handle it for us */
+	gpiod_set_value_cansleep(pwrctrl->perst, 1);
+}
+
 /**
  * pci_pwrctrl_device_set_ready() - Notify the pwrctrl subsystem that the PCI
  * device is powered-up and ready to be detected.
@@ -82,6 +118,8 @@ int pci_pwrctrl_device_set_ready(struct pci_pwrctrl *pwrctrl)
 	if (!pwrctrl->dev)
 		return -ENODEV;
 
+	pci_pwrctrl_perst_deassert(pwrctrl);
+
 	pwrctrl->nb.notifier_call = pci_pwrctrl_notify;
 	ret = bus_register_notifier(&pci_bus_type, &pwrctrl->nb);
 	if (ret)
@@ -103,6 +141,7 @@ void pci_pwrctrl_device_unset_ready(struct pci_pwrctrl *pwrctrl)
 {
 	cancel_work_sync(&pwrctrl->work);
 
+	pci_pwrctrl_perst_assert(pwrctrl);
 	/*
 	 * We don't have to delete the link here. Typically, this function
 	 * is only called when the power control device is being detached. If
diff --git a/include/linux/pci-pwrctrl.h b/include/linux/pci-pwrctrl.h
index 7d439b0675e91e920737287eaf1937f38e47f2ce..1ce6aec343fea1b77a146682f499ece791be70dc 100644
--- a/include/linux/pci-pwrctrl.h
+++ b/include/linux/pci-pwrctrl.h
@@ -31,6 +31,7 @@ struct device_link;
 /**
  * struct pci_pwrctrl - PCI device power control context.
  * @dev: Address of the power controlling device.
+ * @perst: PERST# GPIO connected to the PCI device.
  *
  * An object of this type must be allocated by the PCI power control device and
  * passed to the pwrctrl subsystem to trigger a bus rescan and setup a device
@@ -38,6 +39,7 @@ struct device_link;
  */
 struct pci_pwrctrl {
 	struct device *dev;
+	struct gpio_desc *perst;
 
 	/* Private: don't use. */
 	struct notifier_block nb;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 05e68f35f39238f8b9ce08df97b384d1c1e89bbe..fcce106c7e2985ee1dd79bfcd241f133e5599fe1 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -39,6 +39,7 @@
 #include <linux/io.h>
 #include <linux/resource_ext.h>
 #include <linux/msi_api.h>
+#include <linux/gpio/consumer.h>
 #include <uapi/linux/pci.h>
 
 #include <linux/pci_ids.h>
@@ -600,6 +601,7 @@ struct pci_host_bridge {
 	int (*enable_device)(struct pci_host_bridge *bridge, struct pci_dev *dev);
 	void (*disable_device)(struct pci_host_bridge *bridge, struct pci_dev *dev);
 	void		*release_data;
+	struct gpio_desc **perst;
 	unsigned int	ignore_reset_delay:1;	/* For entire hierarchy */
 	unsigned int	no_ext_tags:1;		/* No Extended Tags */
 	unsigned int	no_inc_mrrs:1;		/* No Increase MRRS */

-- 
2.45.2


  parent reply	other threads:[~2025-07-07 18:18 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-07-07 18:18 [PATCH RFC 0/3] PCI/pwrctrl: Allow pwrctrl framework " Manivannan Sadhasivam
2025-07-07 18:18 ` [PATCH RFC 1/3] PCI/pwrctrl: Move pci_pwrctrl_init() before turning ON the supplies Manivannan Sadhasivam
2025-07-11  9:39   ` Bartosz Golaszewski
2025-07-07 18:18 ` Manivannan Sadhasivam [this message]
2025-07-09  3:15   ` [PATCH RFC 2/3] PCI/pwrctrl: Allow pwrctrl core to control PERST# GPIO if available Brian Norris
2025-07-09  8:05     ` Manivannan Sadhasivam
2025-07-11 23:49       ` Brian Norris
2025-07-12  0:38   ` Brian Norris
2025-07-12  8:29     ` Manivannan Sadhasivam
2025-07-24 14:13       ` Manivannan Sadhasivam
2025-07-25 21:04         ` Brian Norris
2025-07-28  4:48           ` Manivannan Sadhasivam
2025-07-07 18:18 ` [PATCH RFC 3/3] PCI: qcom: Allow pwrctrl framework to control PERST# Manivannan Sadhasivam
2025-07-09  3:18   ` Brian Norris
2025-07-09  8:23     ` Manivannan Sadhasivam
2025-07-11 23:42   ` Brian Norris
2025-07-12  6:20     ` Manivannan Sadhasivam
2025-07-25 20:53       ` Brian Norris
2025-07-28  5:06         ` Manivannan Sadhasivam
2025-07-09  1:39 ` [PATCH RFC 0/3] PCI/pwrctrl: Allow pwrctrl framework to control PERST# GPIO if available Brian Norris
2025-07-09  6:48   ` Manivannan Sadhasivam
2025-07-12  0:04     ` Brian Norris
2025-07-12  6:06       ` Manivannan Sadhasivam

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=20250707-pci-pwrctrl-perst-v1-2-c3c7e513e312@kernel.org \
    --to=mani@kernel.org \
    --cc=bhelgaas@google.com \
    --cc=brgl@bgdev.pl \
    --cc=briannorris@chromium.org \
    --cc=jingoohan1@gmail.com \
    --cc=krishna.chundru@oss.qualcomm.com \
    --cc=kwilczynski@kernel.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=lpieralisi@kernel.org \
    --cc=robh@kernel.org \
    /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

all inboxes | Powered by JetHome®