Linux PCI subsystem development
 help / color / mirror / Atom feed
From: Manivannan Sadhasivam via B4 Relay <devnull+manivannan.sadhasivam.oss.qualcomm.com@kernel.org>
To: Bartosz Golaszewski <brgl@kernel.org>,
	 Manivannan Sadhasivam <mani@kernel.org>,
	 Marcel Holtmann <marcel@holtmann.org>,
	 Luiz Augusto von Dentz <luiz.dentz@gmail.com>,
	 Shuai Zhang <quic_shuaz@quicinc.com>
Cc: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org,
	 linux-pci@vger.kernel.org, linux-arm-msm@vger.kernel.org,
	 linux-bluetooth@vger.kernel.org,
	Wei Deng <wei.deng@oss.qualcomm.com>,
	 Luiz Augusto von Dentz <luiz.von.dentz@intel.com>,
	 Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Subject: [PATCH v2 2/9] power: sequencing: pcie-m2: Allow creating serdev for multiple PCI devices
Date: Thu, 07 May 2026 21:36:10 +0530	[thread overview]
Message-ID: <20260507-pwrseq-m2-bt-v2-2-1740bd478539@oss.qualcomm.com> (raw)
In-Reply-To: <20260507-pwrseq-m2-bt-v2-0-1740bd478539@oss.qualcomm.com>

From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>

Current code makes it possible to create serdev for only one PCI device.
But for scaling this driver, it is necessary to allow creating serdev for
multiple PCI devices.

Hence, add provision for it by creating 'struct pwrseq_pci_dev' for each
PCI device that requires serdev and add them to
'pwrseq_pcie_m2_ctx::pci_devices' list.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
 drivers/power/sequencing/pwrseq-pcie-m2.c | 127 +++++++++++++++++++++---------
 1 file changed, 88 insertions(+), 39 deletions(-)

diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index b2ed336fd5ad..469e130330fa 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -7,6 +7,7 @@
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/gpio/consumer.h>
+#include <linux/list.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -19,6 +20,13 @@
 #include <linux/serdev.h>
 #include <linux/slab.h>
 
+struct pwrseq_pci_dev {
+	struct serdev_device *serdev;
+	struct of_changeset *ocs;
+	struct pci_dev *pdev;
+	struct list_head list;
+};
+
 struct pwrseq_pcie_m2_pdata {
 	const struct pwrseq_target_data **targets;
 };
@@ -32,9 +40,9 @@ struct pwrseq_pcie_m2_ctx {
 	struct notifier_block nb;
 	struct gpio_desc *w_disable1_gpio;
 	struct gpio_desc *w_disable2_gpio;
-	struct serdev_device *serdev;
-	struct of_changeset *ocs;
 	struct device *dev;
+	struct list_head pci_devices;
+	struct mutex list_lock;
 };
 
 static int pwrseq_pcie_m2_vregs_enable(struct pwrseq_device *pwrseq)
@@ -178,38 +186,39 @@ static int pwrseq_pcie_m2_match(struct pwrseq_device *pwrseq,
 }
 
 static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
+					struct pwrseq_pci_dev *pci_dev,
 					struct device_node *parent)
 {
 	struct device *dev = ctx->dev;
 	struct device_node *np;
 	int ret;
 
-	ctx->ocs = kzalloc_obj(*ctx->ocs);
-	if (!ctx->ocs)
+	pci_dev->ocs = kzalloc_obj(*pci_dev->ocs);
+	if (!pci_dev->ocs)
 		return -ENOMEM;
 
-	of_changeset_init(ctx->ocs);
+	of_changeset_init(pci_dev->ocs);
 
-	np = of_changeset_create_node(ctx->ocs, parent, "bluetooth");
+	np = of_changeset_create_node(pci_dev->ocs, parent, "bluetooth");
 	if (!np) {
 		dev_err(dev, "Failed to create bluetooth node\n");
 		ret = -ENODEV;
 		goto err_destroy_changeset;
 	}
 
-	ret = of_changeset_add_prop_string(ctx->ocs, np, "compatible", "qcom,wcn7850-bt");
+	ret = of_changeset_add_prop_string(pci_dev->ocs, np, "compatible", "qcom,wcn7850-bt");
 	if (ret) {
 		dev_err(dev, "Failed to add bluetooth compatible: %d\n", ret);
 		goto err_destroy_changeset;
 	}
 
-	ret = of_changeset_apply(ctx->ocs);
+	ret = of_changeset_apply(pci_dev->ocs);
 	if (ret) {
 		dev_err(dev, "Failed to apply changeset: %d\n", ret);
 		goto err_destroy_changeset;
 	}
 
-	ret = device_add_of_node(&ctx->serdev->dev, np);
+	ret = device_add_of_node(&pci_dev->serdev->dev, np);
 	if (ret) {
 		dev_err(dev, "Failed to add OF node: %d\n", ret);
 		goto err_revert_changeset;
@@ -218,19 +227,21 @@ static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
 	return 0;
 
 err_revert_changeset:
-	of_changeset_revert(ctx->ocs);
+	of_changeset_revert(pci_dev->ocs);
 err_destroy_changeset:
-	of_changeset_destroy(ctx->ocs);
-	kfree(ctx->ocs);
-	ctx->ocs = NULL;
+	of_changeset_destroy(pci_dev->ocs);
+	kfree(pci_dev->ocs);
+	pci_dev->ocs = NULL;
 
 	return ret;
 }
 
-static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
+static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx,
+					struct pci_dev *pdev)
 {
 	struct serdev_controller *serdev_ctrl;
 	struct device *dev = ctx->dev;
+	struct pwrseq_pci_dev *pci_dev;
 	int ret;
 
 	struct device_node *serdev_parent __free(device_node) =
@@ -248,17 +259,23 @@ static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
 		return 0;
 	}
 
-	ctx->serdev = serdev_device_alloc(serdev_ctrl);
-	if (!ctx->serdev) {
+	pci_dev = kzalloc(sizeof(*pci_dev), GFP_KERNEL);
+	if (!pci_dev) {
 		ret = -ENOMEM;
 		goto err_put_ctrl;
 	}
 
-	ret = pwrseq_pcie_m2_create_bt_node(ctx, serdev_parent);
+	pci_dev->serdev = serdev_device_alloc(serdev_ctrl);
+	if (!pci_dev->serdev) {
+		ret = -ENOMEM;
+		goto err_free_pci_dev;
+	}
+
+	ret = pwrseq_pcie_m2_create_bt_node(ctx, pci_dev, serdev_parent);
 	if (ret)
 		goto err_free_serdev;
 
-	ret = serdev_device_add(ctx->serdev);
+	ret = serdev_device_add(pci_dev->serdev);
 	if (ret) {
 		dev_err(dev, "Failed to add serdev for WCN7850: %d\n", ret);
 		goto err_free_dt_node;
@@ -266,37 +283,64 @@ static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
 
 	serdev_controller_put(serdev_ctrl);
 
+	pci_dev->pdev = pci_dev_get(pdev);
+
+	mutex_lock(&ctx->list_lock);
+	list_add_tail(&pci_dev->list, &ctx->pci_devices);
+	mutex_unlock(&ctx->list_lock);
+
 	return 0;
 
 err_free_dt_node:
-	device_remove_of_node(&ctx->serdev->dev);
-	of_changeset_revert(ctx->ocs);
-	of_changeset_destroy(ctx->ocs);
-	kfree(ctx->ocs);
-	ctx->ocs = NULL;
+	device_remove_of_node(&pci_dev->serdev->dev);
+	of_changeset_revert(pci_dev->ocs);
+	of_changeset_destroy(pci_dev->ocs);
+	kfree(pci_dev->ocs);
+	pci_dev->ocs = NULL;
 err_free_serdev:
-	serdev_device_put(ctx->serdev);
-	ctx->serdev = NULL;
+	serdev_device_put(pci_dev->serdev);
+	pci_dev->serdev = NULL;
+err_free_pci_dev:
+	kfree(pci_dev);
 err_put_ctrl:
 	serdev_controller_put(serdev_ctrl);
 
 	return ret;
 }
 
-static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx)
+static void __pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx,
+					   struct pwrseq_pci_dev *pci_dev)
 {
-	if (ctx->serdev) {
-		device_remove_of_node(&ctx->serdev->dev);
-		serdev_device_remove(ctx->serdev);
-		ctx->serdev = NULL;
+	if (pci_dev->serdev) {
+		device_remove_of_node(&pci_dev->serdev->dev);
+		serdev_device_remove(pci_dev->serdev);
 	}
 
-	if (ctx->ocs) {
-		of_changeset_revert(ctx->ocs);
-		of_changeset_destroy(ctx->ocs);
-		kfree(ctx->ocs);
-		ctx->ocs = NULL;
+	if (pci_dev->ocs) {
+		of_changeset_revert(pci_dev->ocs);
+		of_changeset_destroy(pci_dev->ocs);
+		kfree(pci_dev->ocs);
 	}
+
+	pci_dev_put(pci_dev->pdev);
+	list_del(&pci_dev->list);
+	kfree(pci_dev);
+}
+
+static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx,
+					 struct pci_dev *pdev)
+{
+	struct pwrseq_pci_dev *pci_dev, *tmp;
+
+	mutex_lock(&ctx->list_lock);
+	list_for_each_entry_safe(pci_dev, tmp, &ctx->pci_devices, list) {
+		if (!pdev || pci_dev->pdev == pdev) {
+			__pwrseq_pcie_m2_remove_serdev(ctx, pci_dev);
+			if (pdev)
+				break;
+		}
+	}
+	mutex_unlock(&ctx->list_lock);
 }
 
 static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action,
@@ -320,7 +364,7 @@ static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action
 	case BUS_NOTIFY_ADD_DEVICE:
 		/* Create serdev device for WCN7850 */
 		if (pdev->vendor == PCI_VENDOR_ID_QCOM && pdev->device == 0x1107) {
-			ret = pwrseq_pcie_m2_create_serdev(ctx);
+			ret = pwrseq_pcie_m2_create_serdev(ctx, pdev);
 			if (ret)
 				return notifier_from_errno(ret);
 		}
@@ -328,7 +372,7 @@ static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action
 	case BUS_NOTIFY_REMOVED_DEVICE:
 		/* Destroy serdev device for WCN7850 */
 		if (pdev->vendor == PCI_VENDOR_ID_QCOM && pdev->device == 0x1107)
-			pwrseq_pcie_m2_remove_serdev(ctx);
+			pwrseq_pcie_m2_remove_serdev(ctx, pdev);
 
 		break;
 	}
@@ -432,16 +476,20 @@ static int pwrseq_pcie_m2_probe(struct platform_device *pdev)
 		goto err_free_regulators;
 	}
 
+	mutex_init(&ctx->list_lock);
+	INIT_LIST_HEAD(&ctx->pci_devices);
 	/*
 	 * Register a notifier for creating protocol devices for
 	 * non-discoverable busses like UART.
 	 */
 	ret = pwrseq_pcie_m2_register_notifier(ctx, dev);
 	if (ret)
-		goto err_free_regulators;
+		goto err_destroy_mutex;
 
 	return 0;
 
+err_destroy_mutex:
+	mutex_destroy(&ctx->list_lock);
 err_free_regulators:
 	regulator_bulk_free(ctx->num_vregs, ctx->regs);
 
@@ -453,7 +501,8 @@ static void pwrseq_pcie_m2_remove(struct platform_device *pdev)
 	struct pwrseq_pcie_m2_ctx *ctx = platform_get_drvdata(pdev);
 
 	bus_unregister_notifier(&pci_bus_type, &ctx->nb);
-	pwrseq_pcie_m2_remove_serdev(ctx);
+	pwrseq_pcie_m2_remove_serdev(ctx, NULL);
+	mutex_destroy(&ctx->list_lock);
 
 	regulator_bulk_free(ctx->num_vregs, ctx->regs);
 }

-- 
2.51.0



  parent reply	other threads:[~2026-05-07 16:06 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-07 16:06 [PATCH v2 0/9] Fixes/improvements for the PCI M.2 power sequencing driver Manivannan Sadhasivam via B4 Relay
2026-05-07 16:06 ` [PATCH v2 1/9] power: sequencing: pcie-m2: Fix inconsistent function prefixes Manivannan Sadhasivam via B4 Relay
2026-05-07 16:06 ` Manivannan Sadhasivam via B4 Relay [this message]
2026-05-07 23:28   ` [PATCH v2 2/9] power: sequencing: pcie-m2: Allow creating serdev for multiple PCI devices sashiko-bot
2026-05-07 16:06 ` [PATCH v2 3/9] power: sequencing: pcie-m2: Improve PCI device ID check Manivannan Sadhasivam via B4 Relay
2026-05-07 16:06 ` [PATCH v2 4/9] power: sequencing: pcie-m2: Create serdev for PCI devices present before probe Manivannan Sadhasivam via B4 Relay
2026-05-07 23:54   ` sashiko-bot
2026-05-07 16:06 ` [PATCH v2 5/9] power: sequencing: pcie-m2: Create BT node based on the pci_device_id[] table Manivannan Sadhasivam via B4 Relay
2026-05-07 16:06 ` [PATCH v2 6/9] Bluetooth: hci_qca: Add M.2 Bluetooth device support using pwrseq Manivannan Sadhasivam via B4 Relay
2026-05-08  0:44   ` sashiko-bot
2026-05-07 16:06 ` [PATCH v2 7/9] Bluetooth: hci_qca: Rename 'power_ctrl_enabled' to 'bt_en_available' Manivannan Sadhasivam via B4 Relay
2026-05-08  0:53   ` sashiko-bot
2026-05-11 11:34   ` Bartosz Golaszewski
2026-05-07 16:06 ` [PATCH v2 8/9] power: sequencing: Add an API to return the pwrseq device's 'dev' pointer Manivannan Sadhasivam via B4 Relay
2026-05-08  1:16   ` sashiko-bot
2026-05-11 11:34   ` Bartosz Golaszewski
2026-05-07 16:06 ` [PATCH v2 9/9] Bluetooth: hci_qca: Set 'bt_en_available' based on W_DISABLE2# presence in M.2 connector Manivannan Sadhasivam via B4 Relay
2026-05-08  2:06   ` sashiko-bot
2026-05-11 11:36   ` Bartosz Golaszewski
2026-05-08 12:49 ` [PATCH v2 0/9] Fixes/improvements for the PCI M.2 power sequencing driver Wei Deng

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=20260507-pwrseq-m2-bt-v2-2-1740bd478539@oss.qualcomm.com \
    --to=devnull+manivannan.sadhasivam.oss.qualcomm.com@kernel.org \
    --cc=brgl@kernel.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=luiz.dentz@gmail.com \
    --cc=luiz.von.dentz@intel.com \
    --cc=mani@kernel.org \
    --cc=manivannan.sadhasivam@oss.qualcomm.com \
    --cc=marcel@holtmann.org \
    --cc=quic_shuaz@quicinc.com \
    --cc=wei.deng@oss.qualcomm.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