Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH 11/12] Bluetooth: hci_qca: Check whether the M.2 UART interface is fixed or not
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
  To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
	Luiz Augusto von Dentz, Shuai Zhang
  Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
	Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
In-Reply-To: <20260422-pwrseq-m2-bt-v1-0-720d02545a64@oss.qualcomm.com>

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

In the M.2 connector, the UART interface is controlled through the
W_DISABLE2# signal. But the BT driver cannot know directly whether this
signal is available or not.

Hence, use the new pwrseq API 'pwrseq_is_fixed()' to check whether the UART
interface on the M.2 connector is fixed or controllable and set the
'bt_en_available' flag accordingly.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
 drivers/bluetooth/hci_qca.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 3e71a72ea7c7..27e52b08ec47 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -2453,6 +2453,10 @@ static int qca_serdev_probe(struct serdev_device *serdev)
 								   "uart");
 			if (IS_ERR(qcadev->bt_power->pwrseq))
 				return PTR_ERR(qcadev->bt_power->pwrseq);
+
+			if (pwrseq_is_fixed(qcadev->bt_power->pwrseq))
+				bt_en_available = false;
+
 			break;
 		}
 

-- 
2.51.0



^ permalink raw reply related

* [PATCH 06/12] power: sequencing: pcie-m2: Improve PCI device ID check
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
  To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
	Luiz Augusto von Dentz, Shuai Zhang
  Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
	Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
In-Reply-To: <20260422-pwrseq-m2-bt-v1-0-720d02545a64@oss.qualcomm.com>

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

Instead of hardcoding the PCI device check, use pci_match_id() to check for
the known IDs using the pwrseq_m2_pci_ids[] array.

This makes adding support for new devices easier.

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

diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index d4d246a30a97..bdc4391c87c9 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -351,6 +351,11 @@ static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx,
 	mutex_unlock(&ctx->list_lock);
 }
 
+static const struct pci_device_id pwrseq_m2_pci_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x1107) },
+	{ } /* Sentinel */
+};
+
 static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action,
 			      void *data)
 {
@@ -370,16 +375,14 @@ static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action
 
 	switch (action) {
 	case BUS_NOTIFY_ADD_DEVICE:
-		/* Create serdev device for WCN7850 */
-		if (pdev->vendor == PCI_VENDOR_ID_QCOM && pdev->device == 0x1107) {
+		if (pci_match_id(pwrseq_m2_pci_ids, pdev)) {
 			ret = pwrseq_pcie_m2_create_serdev(ctx, pdev);
 			if (ret)
 				return notifier_from_errno(ret);
 		}
 		break;
 	case BUS_NOTIFY_REMOVED_DEVICE:
-		/* Destroy serdev device for WCN7850 */
-		if (pdev->vendor == PCI_VENDOR_ID_QCOM && pdev->device == 0x1107)
+		if (pci_match_id(pwrseq_m2_pci_ids, pdev))
 			pwrseq_pcie_m2_remove_serdev(ctx, pdev);
 
 		break;

-- 
2.51.0



^ permalink raw reply related

* [PATCH 12/12] Bluetooth: hci_qca: Fix the broken BT_EN GPIO detection for Qcom WCN devices
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
  To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
	Luiz Augusto von Dentz, Shuai Zhang
  Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
	Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam,
	stable+noautosel
In-Reply-To: <20260422-pwrseq-m2-bt-v1-0-720d02545a64@oss.qualcomm.com>

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

Commit 'db0ff7e15923 ("driver: bluetooth: hci_qca:fix unable to load the BT
driver")' tried to check the presence of the BT_EN GPIO in Qcom WCN devices
to indicate the HCI layer whether this BT device can be power controlled or
not.

But it was broken for two reasons:

1. Assumes that when devm_pwrseq_get() API returns an error, BT_EN is not
controllable. This is no way true as the API can fail for various reasons
and also the pwrseq-qcom-wcn driver treats the BT_EN GPIO as optional. So
even if the GPIO is not present, it will not fail the probe and this API
will not fail.

2. By skipping the error return, probe deferral is completely broken as the
API may return -EPROBE_DEFER to indicate the caller that the pwrseq driver
is not yet probed. Skipping the return value means, this driver is not
going to depend on pwrseq driver probing again and it just assumes that
the pwrseq is not available.

So to fix these issues, fail the probe if devm_pwrseq_get() returns an
error and if it succeeds, use the newly introduced pwrseq_is_fixed() API to
check whether the power sequencer is fixed or not (i.e., whether the
Bluetooth interface on the Qcom WCN device is controllable using BT_EN GPIO
or not) and set the 'bt_en_available' flag accordingly.

Cc: <stable+noautosel@kernel.org> # Depends on pwrseq change
Fixes: db0ff7e15923 ("driver: bluetooth: hci_qca:fix unable to load the BT driver")
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
 drivers/bluetooth/hci_qca.c | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 27e52b08ec47..dd1d93cbb3d8 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -2470,16 +2470,13 @@ static int qca_serdev_probe(struct serdev_device *serdev)
 			qcadev->bt_power->pwrseq = devm_pwrseq_get(&serdev->dev,
 								   "bluetooth");
 
-			/*
-			 * Some modules have BT_EN enabled via a hardware pull-up,
-			 * meaning it is not defined in the DTS and is not controlled
-			 * through the power sequence. In such cases, fall through
-			 * to follow the legacy flow.
-			 */
 			if (IS_ERR(qcadev->bt_power->pwrseq))
-				qcadev->bt_power->pwrseq = NULL;
-			else
-				break;
+				return PTR_ERR(qcadev->bt_power->pwrseq);
+
+			if (pwrseq_is_fixed(qcadev->bt_power->pwrseq))
+				bt_en_available = false;
+
+			break;
 		}
 
 		qcadev->bt_power->dev = &serdev->dev;

-- 
2.51.0



^ permalink raw reply related

* [PATCH 10/12] Bluetooth: hci_qca: Rename 'power_ctrl_enabled' to 'bt_en_available'
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
  To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
	Luiz Augusto von Dentz, Shuai Zhang
  Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
	Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
In-Reply-To: <20260422-pwrseq-m2-bt-v1-0-720d02545a64@oss.qualcomm.com>

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

'power_ctrl_enabled' flag is used to indicate the availability of the BT_EN
GPIO in devicetree. But the naming causes confusion with the new pwrctrl
framework.

So rename it to 'bt_en_available' to make it clear and explicit.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
 drivers/bluetooth/hci_qca.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index c83fe72bc549..3e71a72ea7c7 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -2391,7 +2391,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
 	struct hci_dev *hdev;
 	const struct qca_device_data *data;
 	int err;
-	bool power_ctrl_enabled = true;
+	bool bt_en_available = true;
 
 	qcadev = devm_kzalloc(&serdev->dev, sizeof(*qcadev), GFP_KERNEL);
 	if (!qcadev)
@@ -2499,7 +2499,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
 		    (data->soc_type == QCA_WCN6750 ||
 		     data->soc_type == QCA_WCN6855 ||
 		     data->soc_type == QCA_WCN7850))
-			power_ctrl_enabled = false;
+			bt_en_available = false;
 
 		qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl",
 					       GPIOD_IN);
@@ -2537,7 +2537,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
 		}
 
 		if (!qcadev->bt_en)
-			power_ctrl_enabled = false;
+			bt_en_available = false;
 
 		qcadev->susclk = devm_clk_get_optional_enabled_with_rate(
 					&serdev->dev, NULL, SUSCLK_RATE_32KHZ);
@@ -2555,7 +2555,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
 
 	hdev = qcadev->serdev_hu.hdev;
 
-	if (power_ctrl_enabled) {
+	if (bt_en_available) {
 		hci_set_quirk(hdev, HCI_QUIRK_NON_PERSISTENT_SETUP);
 		hdev->shutdown = qca_hci_shutdown;
 	}

-- 
2.51.0



^ permalink raw reply related

* [PATCH 05/12] power: sequencing: pcie-m2: Allow creating serdev for multiple PCI devices
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
  To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
	Luiz Augusto von Dentz, Shuai Zhang
  Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
	Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
In-Reply-To: <20260422-pwrseq-m2-bt-v1-0-720d02545a64@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 49c326a6e445..d4d246a30a97 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)
@@ -186,38 +194,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;
@@ -226,19 +235,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) =
@@ -256,17 +267,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;
@@ -274,37 +291,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,
@@ -328,7 +372,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);
 		}
@@ -336,7 +380,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;
 	}
@@ -440,16 +484,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);
 
@@ -461,7 +509,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



^ permalink raw reply related

* [PATCH 09/12] Bluetooth: hci_qca: Add M.2 Bluetooth device support using pwrseq
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
  To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
	Luiz Augusto von Dentz, Shuai Zhang
  Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
	Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam,
	Bartosz Golaszewski
In-Reply-To: <20260422-pwrseq-m2-bt-v1-0-720d02545a64@oss.qualcomm.com>

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

Power supply to the M.2 Bluetooth device attached to the host using M.2
connector is controlled using the 'uart' pwrseq device. So add support for
getting the pwrseq device if the OF graph link is present. Once obtained,
the existing pwrseq APIs can be used to control the power supplies of the
M.2 card.

Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
 drivers/bluetooth/hci_qca.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index cd1834246b47..c83fe72bc549 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -26,6 +26,7 @@
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_graph.h>
 #include <linux/acpi.h>
 #include <linux/platform_device.h>
 #include <linux/pwrseq/consumer.h>
@@ -2443,6 +2444,18 @@ static int qca_serdev_probe(struct serdev_device *serdev)
 	case QCA_WCN6750:
 	case QCA_WCN6855:
 	case QCA_WCN7850:
+		/*
+		 * OF graph link is only present for BT devices attached through
+		 * the M.2 Key E connector.
+		 */
+		if (of_graph_is_present(dev_of_node(&serdev->ctrl->dev))) {
+			qcadev->bt_power->pwrseq = devm_pwrseq_get(&serdev->ctrl->dev,
+								   "uart");
+			if (IS_ERR(qcadev->bt_power->pwrseq))
+				return PTR_ERR(qcadev->bt_power->pwrseq);
+			break;
+		}
+
 		if (!device_property_present(&serdev->dev, "enable-gpios")) {
 			/*
 			 * Backward compatibility with old DT sources. If the

-- 
2.51.0



^ permalink raw reply related

* [PATCH 08/12] power: sequencing: pcie-m2: Create BT node based on the pci_device_id[] table
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
  To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
	Luiz Augusto von Dentz, Shuai Zhang
  Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
	Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
In-Reply-To: <20260422-pwrseq-m2-bt-v1-0-720d02545a64@oss.qualcomm.com>

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

Currently, pwrseq_pcie_m2_create_bt_node() hardcodes the BT compatible for
creating the devicetree node. But to allow adding support for more devices
in the future, create the BT node based on the pci_device_id[] table. The
BT compatible is passed using 'driver_data'.

Co-developed-by: Wei Deng <wei.deng@oss.qualcomm.com>
Signed-off-by: Wei Deng <wei.deng@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
 drivers/power/sequencing/pwrseq-pcie-m2.c | 29 ++++++++++++++++++++---------
 1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index b21fcc089580..23dc91e2b128 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -193,14 +193,29 @@ static int pwrseq_pcie_m2_match(struct pwrseq_device *pwrseq,
 	return PWRSEQ_NO_MATCH;
 }
 
+static const struct pci_device_id pwrseq_m2_pci_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x1107),
+	  .driver_data = (kernel_ulong_t)"qcom,wcn7850-bt" },
+	{ } /* Sentinel */
+};
+
 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_node *parent,
+					struct pci_dev *pdev)
 {
+	const struct pci_device_id *id;
 	struct device *dev = ctx->dev;
+	const char *compatible;
 	struct device_node *np;
 	int ret;
 
+	id = pci_match_id(pwrseq_m2_pci_ids, pdev);
+	if (WARN_ON_ONCE(!id)) /* Shouldn't happen */
+		return -ENODEV;
+
+	compatible = (const char *)id->driver_data;
+
 	pci_dev->ocs = kzalloc_obj(*pci_dev->ocs);
 	if (!pci_dev->ocs)
 		return -ENOMEM;
@@ -214,7 +229,7 @@ static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
 		goto err_destroy_changeset;
 	}
 
-	ret = of_changeset_add_prop_string(pci_dev->ocs, np, "compatible", "qcom,wcn7850-bt");
+	ret = of_changeset_add_prop_string(pci_dev->ocs, np, "compatible", compatible);
 	if (ret) {
 		dev_err(dev, "Failed to add bluetooth compatible: %d\n", ret);
 		goto err_destroy_changeset;
@@ -289,13 +304,14 @@ static int __pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx,
 		goto err_free_pci_dev;
 	}
 
-	ret = pwrseq_pcie_m2_create_bt_node(ctx, pci_dev, serdev_parent);
+	ret = pwrseq_pcie_m2_create_bt_node(ctx, pci_dev, serdev_parent, pdev);
 	if (ret)
 		goto err_free_serdev;
 
 	ret = serdev_device_add(pci_dev->serdev);
 	if (ret) {
-		dev_err(dev, "Failed to add serdev for WCN7850: %d\n", ret);
+		dev_err(dev, "Failed to add serdev for PCI device (%s): %d\n",
+			pci_name(pdev), ret);
 		goto err_free_dt_node;
 	}
 
@@ -361,11 +377,6 @@ static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx,
 	mutex_unlock(&ctx->list_lock);
 }
 
-static const struct pci_device_id pwrseq_m2_pci_ids[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x1107) },
-	{ } /* Sentinel */
-};
-
 static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action,
 			      void *data)
 {

-- 
2.51.0



^ permalink raw reply related

* [PATCH 07/12] power: sequencing: pcie-m2: Create serdev for PCI devices present before probe
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
  To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
	Luiz Augusto von Dentz, Shuai Zhang
  Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
	Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
In-Reply-To: <20260422-pwrseq-m2-bt-v1-0-720d02545a64@oss.qualcomm.com>

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

So far, the driver is registering a notifier to create serdev for the PCI
devices that are going to be attached after probe. But it doesn't handle
the devices present before probe. Due to this, serdev is not getting
created for those existing devices.

Hence, create serdev for PCI devices available before probe as well.

Note that the serdev for available devices are created before
registering the notifier. There is a small window where a device could
appear after pwrseq_pcie_m2_create_serdev(), before notifier registration.
But since M.2 cards are fixed to a slot, they are mostly added either
before booting the host or after using hotplug. So this window is mostly
theoretical.

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

diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index bdc4391c87c9..b21fcc089580 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -244,7 +244,7 @@ static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
 	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;
@@ -267,6 +267,16 @@ static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx,
 		return 0;
 	}
 
+	/* Bail out if the serdev device was already created for the PCI dev */
+	mutex_lock(&ctx->list_lock);
+	list_for_each_entry(pci_dev, &ctx->pci_devices, list) {
+		if (pci_dev->pdev == pdev) {
+			mutex_unlock(&ctx->list_lock);
+			return 0;
+		}
+	}
+	mutex_unlock(&ctx->list_lock);
+
 	pci_dev = kzalloc(sizeof(*pci_dev), GFP_KERNEL);
 	if (!pci_dev) {
 		ret = -ENOMEM;
@@ -376,7 +386,7 @@ static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action
 	switch (action) {
 	case BUS_NOTIFY_ADD_DEVICE:
 		if (pci_match_id(pwrseq_m2_pci_ids, pdev)) {
-			ret = pwrseq_pcie_m2_create_serdev(ctx, pdev);
+			ret = __pwrseq_pcie_m2_create_serdev(ctx, pdev);
 			if (ret)
 				return notifier_from_errno(ret);
 		}
@@ -408,7 +418,7 @@ static bool pwrseq_pcie_m2_check_remote_node(struct device *dev, u8 port, u8 end
  * protocol device needs to be created manually with the help of the notifier
  * of the discoverable bus like PCIe.
  */
-static int pwrseq_pcie_m2_register_notifier(struct pwrseq_pcie_m2_ctx *ctx, struct device *dev)
+static int pwrseq_pcie_m2_register_notifier(struct pwrseq_pcie_m2_ctx *ctx)
 {
 	int ret;
 
@@ -416,18 +426,56 @@ static int pwrseq_pcie_m2_register_notifier(struct pwrseq_pcie_m2_ctx *ctx, stru
 	 * Register a PCI notifier for Key E connector that has PCIe as Port
 	 * 0/Endpoint 0 interface and Serial as Port 3/Endpoint 0 interface.
 	 */
-	if (pwrseq_pcie_m2_check_remote_node(dev, 3, 0, "serial")) {
-		if (pwrseq_pcie_m2_check_remote_node(dev, 0, 0, "pcie")) {
-			ctx->dev = dev;
-			ctx->nb.notifier_call = pwrseq_pcie_m2_notify;
-			ret = bus_register_notifier(&pci_bus_type, &ctx->nb);
-			if (ret)
-				return dev_err_probe(dev, ret,
-						     "Failed to register notifier for serdev\n");
+	if (!pwrseq_pcie_m2_check_remote_node(ctx->dev, 3, 0, "serial") ||
+	    !pwrseq_pcie_m2_check_remote_node(ctx->dev, 0, 0, "pcie"))
+		return 0;
+
+	ctx->nb.notifier_call = pwrseq_pcie_m2_notify;
+	ret = bus_register_notifier(&pci_bus_type, &ctx->nb);
+	if (ret)
+		return dev_err_probe(ctx->dev, ret,
+				     "Failed to register notifier for serdev\n");
+	return 0;
+}
+
+static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
+{
+	struct pci_dev *pdev = NULL;
+	int ret;
+
+	if (!pwrseq_pcie_m2_check_remote_node(ctx->dev, 3, 0, "serial") ||
+	    !pwrseq_pcie_m2_check_remote_node(ctx->dev, 0, 0, "pcie"))
+		return 0;
+
+	struct device_node *pci_parent __free(device_node) =
+				of_graph_get_remote_node(dev_of_node(ctx->dev), 0, 0);
+	if (!pci_parent)
+		return 0;
+
+	/* Create serdev for existing PCI devices if required */
+	for_each_pci_dev(pdev) {
+		if (!pdev->dev.parent || pci_parent != pdev->dev.parent->of_node)
+			continue;
+
+		if (!pci_match_id(pwrseq_m2_pci_ids, pdev))
+			continue;
+
+		ret = __pwrseq_pcie_m2_create_serdev(ctx, pdev);
+		if (ret) {
+			dev_err_probe(ctx->dev, ret,
+				      "Failed to create serdev for PCI device (%s)\n",
+				      pci_name(pdev));
+			pci_dev_put(pdev);
+			goto err_remove_serdev;
 		}
 	}
 
 	return 0;
+
+err_remove_serdev:
+	pwrseq_pcie_m2_remove_serdev(ctx, NULL);
+
+	return ret;
 }
 
 static int pwrseq_pcie_m2_probe(struct platform_device *pdev)
@@ -489,16 +537,25 @@ static int pwrseq_pcie_m2_probe(struct platform_device *pdev)
 
 	mutex_init(&ctx->list_lock);
 	INIT_LIST_HEAD(&ctx->pci_devices);
+	ctx->dev = dev;
+
+	/* Create serdev for available PCI devices (if required) */
+	ret = pwrseq_pcie_m2_create_serdev(ctx);
+	if (ret)
+		goto err_destroy_mutex;
+
 	/*
 	 * Register a notifier for creating protocol devices for
 	 * non-discoverable busses like UART.
 	 */
-	ret = pwrseq_pcie_m2_register_notifier(ctx, dev);
+	ret = pwrseq_pcie_m2_register_notifier(ctx);
 	if (ret)
-		goto err_destroy_mutex;
+		goto err_remove_serdev;
 
 	return 0;
 
+err_remove_serdev:
+	pwrseq_pcie_m2_remove_serdev(ctx, NULL);
 err_destroy_mutex:
 	mutex_destroy(&ctx->list_lock);
 err_free_regulators:

-- 
2.51.0



^ permalink raw reply related

* [PATCH 04/12] power: sequencing: pcie-m2: Fix inconsistent function prefixes
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
  To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
	Luiz Augusto von Dentz, Shuai Zhang
  Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
	Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
In-Reply-To: <20260422-pwrseq-m2-bt-v1-0-720d02545a64@oss.qualcomm.com>

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

All functions in this driver follow 'pwrseq_pcie_m2' prefix except a few.
Fix them to avoid inconsistency.

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

diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index 2b79f2e34079..49c326a6e445 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -185,7 +185,7 @@ static int pwrseq_pcie_m2_match(struct pwrseq_device *pwrseq,
 	return PWRSEQ_NO_MATCH;
 }
 
-static int pwrseq_m2_pcie_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
+static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
 					struct device_node *parent)
 {
 	struct device *dev = ctx->dev;
@@ -262,7 +262,7 @@ static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
 		goto err_put_ctrl;
 	}
 
-	ret = pwrseq_m2_pcie_create_bt_node(ctx, serdev_parent);
+	ret = pwrseq_pcie_m2_create_bt_node(ctx, serdev_parent);
 	if (ret)
 		goto err_free_serdev;
 
@@ -307,7 +307,7 @@ static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx)
 	}
 }
 
-static int pwrseq_m2_pcie_notify(struct notifier_block *nb, unsigned long action,
+static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action,
 			      void *data)
 {
 	struct pwrseq_pcie_m2_ctx *ctx = container_of(nb, struct pwrseq_pcie_m2_ctx, nb);
@@ -372,7 +372,7 @@ static int pwrseq_pcie_m2_register_notifier(struct pwrseq_pcie_m2_ctx *ctx, stru
 	if (pwrseq_pcie_m2_check_remote_node(dev, 3, 0, "serial")) {
 		if (pwrseq_pcie_m2_check_remote_node(dev, 0, 0, "pcie")) {
 			ctx->dev = dev;
-			ctx->nb.notifier_call = pwrseq_m2_pcie_notify;
+			ctx->nb.notifier_call = pwrseq_pcie_m2_notify;
 			ret = bus_register_notifier(&pci_bus_type, &ctx->nb);
 			if (ret)
 				return dev_err_probe(dev, ret,

-- 
2.51.0



^ permalink raw reply related

* [PATCH 02/12] power: sequencing: pcie-m2: Add support for 'is_fixed()' callback to 'uart' target
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
  To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
	Luiz Augusto von Dentz, Shuai Zhang
  Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
	Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
In-Reply-To: <20260422-pwrseq-m2-bt-v1-0-720d02545a64@oss.qualcomm.com>

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

Add support for 'is_fixed()' callback to tell the consumers whether this
power sequencer target 'uart' is fixed or controllable. This is decided
based on the availability of the 'W_DISABLE2#' GPIO in DT.

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

diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index ef69ae268059..2b79f2e34079 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -121,10 +121,18 @@ static int pwrseq_pcie_m2_e_pwup_delay(struct pwrseq_device *pwrseq)
 	return 0;
 }
 
+static bool pwrseq_pcie_m2_e_uart_is_fixed(struct pwrseq_device *pwrseq)
+{
+	struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
+
+	return !ctx->w_disable2_gpio;
+}
+
 static const struct pwrseq_target_data pwrseq_pcie_m2_e_uart_target_data = {
 	.name = "uart",
 	.unit = &pwrseq_pcie_m2_e_uart_unit_data,
 	.post_enable = pwrseq_pcie_m2_e_pwup_delay,
+	.is_fixed = pwrseq_pcie_m2_e_uart_is_fixed,
 };
 
 static const struct pwrseq_target_data pwrseq_pcie_m2_e_pcie_target_data = {

-- 
2.51.0



^ permalink raw reply related

* [PATCH 00/12] Fixes/improvements for the PCI M.2 power sequencing driver
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
  To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
	Luiz Augusto von Dentz, Shuai Zhang
  Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
	Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam,
	Bartosz Golaszewski, stable+noautosel

Hi,

This series has several key improvements and fixes to the M.2 power sequencing
driver and also the BT HCI_QCA driver. Notably, this series allows the M.2 power
sequencing driver to work with more M.2 cards, not just WCN7850. It also allows
the BT HCI_QCA driver to detect whether it can control BT_EN (or W_DISABLE2#)
signal on the connector and set the HCI_QUIRK_NON_PERSISTENT_SETUP quirk.

Testing
=======

This series was tested on Lenovo Thinkpad T14s together with the below DTS
patches:
https://github.com/Mani-Sadhasivam/linux/commit/29534d15307551b2355eb254601dec511169f0aa
https://github.com/Mani-Sadhasivam/linux/commit/f4eaacfe647674be200847092b43cdef2194fc55

Merge Strategy
==============

Since the BT HCI_QCA changes depend on the pwrseq changes, it would be good to
merge the whole series through pwrseq tree or through an immutable branch.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
Manivannan Sadhasivam (12):
      power: sequencing: Introduce an API to check whether the pwrseq is fixed or controllable
      power: sequencing: pcie-m2: Add support for 'is_fixed()' callback to 'uart' target
      power: sequencing: qcom-wcn: Add support for 'is_fixed()' callback to 'bluetooth' target
      power: sequencing: pcie-m2: Fix inconsistent function prefixes
      power: sequencing: pcie-m2: Allow creating serdev for multiple PCI devices
      power: sequencing: pcie-m2: Improve PCI device ID check
      power: sequencing: pcie-m2: Create serdev for PCI devices present before probe
      power: sequencing: pcie-m2: Create BT node based on the pci_device_id[] table
      Bluetooth: hci_qca: Add M.2 Bluetooth device support using pwrseq
      Bluetooth: hci_qca: Rename 'power_ctrl_enabled' to 'bt_en_available'
      Bluetooth: hci_qca: Check whether the M.2 UART interface is fixed or not
      Bluetooth: hci_qca: Fix the broken BT_EN GPIO detection for Qcom WCN devices

 drivers/bluetooth/hci_qca.c                |  40 +++--
 drivers/power/sequencing/core.c            |  33 ++++
 drivers/power/sequencing/pwrseq-pcie-m2.c  | 242 ++++++++++++++++++++++-------
 drivers/power/sequencing/pwrseq-qcom-wcn.c |   9 ++
 include/linux/pwrseq/consumer.h            |   6 +
 include/linux/pwrseq/provider.h            |   2 +
 6 files changed, 262 insertions(+), 70 deletions(-)
---
base-commit: 6596a02b207886e9e00bb0161c7fd59fea53c081
change-id: 20260422-pwrseq-m2-bt-abdaa71094eb

Best regards,
--  
Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>



^ permalink raw reply

* [PATCH 01/12] power: sequencing: Introduce an API to check whether the pwrseq is fixed or controllable
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
  To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
	Luiz Augusto von Dentz, Shuai Zhang
  Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
	Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
In-Reply-To: <20260422-pwrseq-m2-bt-v1-0-720d02545a64@oss.qualcomm.com>

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

Introduce an API pwrseq_is_fixed() so that the consumers can check whether
the given power sequencer is fixed or controllable. This will come handy
in situations where the consumers need to know whether the specific power
sequencer like 'Bluetooth' can be controllable using properties like BT_EN.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
 drivers/power/sequencing/core.c | 33 +++++++++++++++++++++++++++++++++
 include/linux/pwrseq/consumer.h |  6 ++++++
 include/linux/pwrseq/provider.h |  2 ++
 3 files changed, 41 insertions(+)

diff --git a/drivers/power/sequencing/core.c b/drivers/power/sequencing/core.c
index 4dff71be11b6..20af9643f1ac 100644
--- a/drivers/power/sequencing/core.c
+++ b/drivers/power/sequencing/core.c
@@ -182,12 +182,14 @@ static void pwrseq_unit_release(struct kref *ref)
  *               the state lock has been released. It's useful for implementing
  *               boot-up delays without blocking other users from powering up
  *               using the same power sequencer.
+ * @is_fixed: Check whether this target is fixed or not.
  */
 struct pwrseq_target {
 	struct list_head list;
 	const char *name;
 	struct pwrseq_unit *unit;
 	pwrseq_power_state_func post_enable;
+	bool (*is_fixed)(struct pwrseq_device *pwrseq);
 };
 
 static struct pwrseq_target *
@@ -206,6 +208,7 @@ pwrseq_target_new(const struct pwrseq_target_data *data)
 	}
 
 	target->post_enable = data->post_enable;
+	target->is_fixed = data->is_fixed;
 
 	return target;
 }
@@ -965,6 +968,36 @@ int pwrseq_power_off(struct pwrseq_desc *desc)
 }
 EXPORT_SYMBOL_GPL(pwrseq_power_off);
 
+/**
+ * pwrseq_is_fixed() - Check whether the power sequencer is fixed or
+ * controllable.
+ * @desc: Descriptor referencing the power sequencer.
+ *
+ * This API can be used to check whether a specific power sequencer like
+ * 'Bluetooth' is fixed or controllable through properties like 'BT_EN' GPIO.
+ *
+ * Returns: true if fixed, false if controllable.
+ */
+bool pwrseq_is_fixed(struct pwrseq_desc *desc)
+{
+	/*
+	 * If there is no power sequencer, then the consumer cannot control
+	 * the power, so it is effectively fixed.
+	 */
+	if (!desc)
+		return true;
+
+	/*
+	 * If the provider hasn't implemented the callback, assume it acts
+	 * like a controllable power sequencer (for backward compatibility).
+	 */
+	if (!desc->target->is_fixed)
+		return false;
+
+	return desc->target->is_fixed(desc->pwrseq);
+}
+EXPORT_SYMBOL_GPL(pwrseq_is_fixed);
+
 #if IS_ENABLED(CONFIG_DEBUG_FS)
 
 struct pwrseq_debugfs_count_ctx {
diff --git a/include/linux/pwrseq/consumer.h b/include/linux/pwrseq/consumer.h
index 7d583b4f266e..7c24958880d7 100644
--- a/include/linux/pwrseq/consumer.h
+++ b/include/linux/pwrseq/consumer.h
@@ -22,6 +22,7 @@ devm_pwrseq_get(struct device *dev, const char *target);
 
 int pwrseq_power_on(struct pwrseq_desc *desc);
 int pwrseq_power_off(struct pwrseq_desc *desc);
+bool pwrseq_is_fixed(struct pwrseq_desc *desc);
 
 #else /* CONFIG_POWER_SEQUENCING */
 
@@ -51,6 +52,11 @@ static inline int pwrseq_power_off(struct pwrseq_desc *desc)
 	return -ENOSYS;
 }
 
+static inline bool pwrseq_is_fixed(struct pwrseq_desc *desc)
+{
+	return true;
+}
+
 #endif /* CONFIG_POWER_SEQUENCING */
 
 #endif /* __POWER_SEQUENCING_CONSUMER_H__ */
diff --git a/include/linux/pwrseq/provider.h b/include/linux/pwrseq/provider.h
index 33b3d2c2e39d..11165e98cde0 100644
--- a/include/linux/pwrseq/provider.h
+++ b/include/linux/pwrseq/provider.h
@@ -43,11 +43,13 @@ struct pwrseq_unit_data {
  *               the state lock has been released. It's useful for implementing
  *               boot-up delays without blocking other users from powering up
  *               using the same power sequencer.
+ * @is_fixed: Callback to check whether this power sequencer is fixed or not.
  */
 struct pwrseq_target_data {
 	const char *name;
 	const struct pwrseq_unit_data *unit;
 	pwrseq_power_state_func post_enable;
+	bool (*is_fixed)(struct pwrseq_device *pwrseq);
 };
 
 /**

-- 
2.51.0



^ permalink raw reply related

* [PATCH 03/12] power: sequencing: qcom-wcn: Add support for 'is_fixed()' callback to 'bluetooth' target
From: Manivannan Sadhasivam via B4 Relay @ 2026-04-22 11:24 UTC (permalink / raw)
  To: Bartosz Golaszewski, Manivannan Sadhasivam, Marcel Holtmann,
	Luiz Augusto von Dentz, Shuai Zhang
  Cc: linux-pm, linux-kernel, linux-pci, linux-arm-msm, linux-bluetooth,
	Wei Deng, Luiz Augusto von Dentz, Manivannan Sadhasivam
In-Reply-To: <20260422-pwrseq-m2-bt-v1-0-720d02545a64@oss.qualcomm.com>

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

Add support for 'is_fixed()' callback to indicate the consumers whether
this power sequencer target 'bluetooth' is fixed or controllable. This is
decided based on the availability of the 'bt-enable' GPIO in DT.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
 drivers/power/sequencing/pwrseq-qcom-wcn.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/power/sequencing/pwrseq-qcom-wcn.c b/drivers/power/sequencing/pwrseq-qcom-wcn.c
index b55b4317e21b..50ac5973b8e7 100644
--- a/drivers/power/sequencing/pwrseq-qcom-wcn.c
+++ b/drivers/power/sequencing/pwrseq-qcom-wcn.c
@@ -254,10 +254,18 @@ static int pwrseq_qcom_wcn6855_xo_clk_deassert(struct pwrseq_device *pwrseq)
 	return pwrseq_qcom_wcn_pwup_delay(pwrseq);
 }
 
+static bool pwrseq_qcom_wcn_bt_is_fixed(struct pwrseq_device *pwrseq)
+{
+	struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
+
+	return !ctx->bt_gpio;
+}
+
 static const struct pwrseq_target_data pwrseq_qcom_wcn_bt_target_data = {
 	.name = "bluetooth",
 	.unit = &pwrseq_qcom_wcn_bt_unit_data,
 	.post_enable = pwrseq_qcom_wcn_pwup_delay,
+	.is_fixed = pwrseq_qcom_wcn_bt_is_fixed,
 };
 
 static const struct pwrseq_target_data pwrseq_qcom_wcn_wlan_target_data = {
@@ -281,6 +289,7 @@ static const struct pwrseq_target_data pwrseq_qcom_wcn6855_bt_target_data = {
 	.name = "bluetooth",
 	.unit = &pwrseq_qcom_wcn6855_bt_unit_data,
 	.post_enable = pwrseq_qcom_wcn6855_xo_clk_deassert,
+	.is_fixed = pwrseq_qcom_wcn_bt_is_fixed,
 };
 
 static const struct pwrseq_target_data pwrseq_qcom_wcn6855_wlan_target_data = {

-- 
2.51.0



^ permalink raw reply related

* Re: [PATCH v1 1/6] sdio: Add syntactic sugar to store a pointer in sdio_driver_id
From: Christian A. Ehrhardt @ 2026-04-22 10:56 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Uwe Kleine-König (The Capable Hub), Luiz Augusto von Dentz,
	Ulf Hansson, Christian A. Ehrhardt, linux-mmc, Greg Kroah-Hartman,
	Wolfram Sang, linux-kernel, Marcel Holtmann, linux-bluetooth,
	Matthias Brugger, AngeloGioacchino Del Regno, linux-mediatek,
	Ping-Ke Shih, linux-wireless, Felix Fietkau, Lorenzo Bianconi,
	Ryder Lee, Shayne Chen, Sean Wang, Brian Norris,
	Francesco Dolcini
In-Reply-To: <aehwG2Egt93-sPVB@ashevche-desk.local>


Hi,

On Wed, Apr 22, 2026 at 09:52:11AM +0300, Andy Shevchenko wrote:
> > To be honest, with the involved void* this isn't really type-safe
> > either, but at least the data keeps being a pointer which is really
> > helpful on CHERI. FTR: The alternative would be to use uintptr_t instead
> > of unsigned long, which also has proponents in the CHERI community and
> > which is used in the current vendor patch stack.
> 
> FWIW, Linus categorically told that it has to be no uintptr_t in the
> Linux kernel.

This is probably not the correct context to discuss this but
I will point out that if/when CHERI support is added to the
kernel we will need a way to distinguish between
* A (fat) pointer converted to an integer type (in order to do
  integer arithmetic on the address) that might be converted back
  to a pointer in the future and
* A plain address "extracted" from a fat pointer.
Using `uintptr_t` for the former and `unsigned long` for the
latter seems like a reasonable choice but there are certainly
other options.

Sorting out the difference between the two is a very large
part of the diff required to port Linux (or in fact any piece
of low-level software) to a CHERI system.

Best regards,
Christian



^ permalink raw reply

* Re: [PATCH net-deletions] net: remove ISDN subsystem and Bluetooth CMTP
From: Simon Horman @ 2026-04-22 10:55 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, edumazet, pabeni, andrew+netdev, corbet, skhan,
	marcel, luiz.dentz, mchehab+huawei, jani.nikula, gregkh, demarchi,
	rdunlap, justonli, ivecera, jonathan.cameron, kees,
	marco.crivellari, ferr.lambarginio, nihaal, mingo, tglx, linmq006,
	linux-doc, linux-bluetooth
In-Reply-To: <20260421022108.1299678-1-kuba@kernel.org>

On Mon, Apr 20, 2026 at 07:21:07PM -0700, Jakub Kicinski wrote:
> Remove the ISDN (mISDN, CAPI) subsystem and Bluetooth CMTP protocol
> from the kernel tree.
> 
> ISDN is a pretty old technology and it's unclear whether anyone still
> uses it. I went over the last few years of git history and all the
> commits are either tree-wide conversions or syzbot/static analyzer
> fixes.
> 
> When we discussed removal in the past IIRC there were some concerns
> about ISDN still being used in parts of Germany. Unfortunately, the
> code base is quite old, none of the current maintainers are familiar
> with it and AI tools will have a field day finding bugs here.
> 
> Delete this code and preserve it in an out-of-tree repository
> for any remaining users:
> https://github.com/linux-netdev/mod-orphan
> 
> UAPI constants AF_ISDN/PF_ISDN and the SELinux isdn_socket class
> are preserved for ABI stability, but the rest of uAPI is removed.
> 
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>

Reviewed-by: Simon Horman <horms@kernel.org>


^ permalink raw reply

* [Bug 221339] AX200 -19 errors on boot after firmware 20260313-1.1
From: bugzilla-daemon @ 2026-04-22  8:44 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <bug-221339-62941@https.bugzilla.kernel.org/>

https://bugzilla.kernel.org/show_bug.cgi?id=221339

--- Comment #13 from Kiran (kiran.k@intel.com) ---
Raised PR to revert the faulty commit.
https://gitlab.com/kernel-firmware/linux-firmware/-/merge_requests/1011

-- 
You may reply to this email to add a comment.

You are receiving this mail because:
You are the assignee for the bug.

^ permalink raw reply

* Re: [PATCH v1 1/6] sdio: Add syntactic sugar to store a pointer in sdio_driver_id
From: Uwe Kleine-König (The Capable Hub) @ 2026-04-22  8:39 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Luiz Augusto von Dentz, Ulf Hansson, Christian A. Ehrhardt,
	linux-mmc, Greg Kroah-Hartman, Wolfram Sang, linux-kernel,
	Marcel Holtmann, linux-bluetooth, Matthias Brugger,
	AngeloGioacchino Del Regno, linux-mediatek, Ping-Ke Shih,
	linux-wireless, Felix Fietkau, Lorenzo Bianconi, Ryder Lee,
	Shayne Chen, Sean Wang, Brian Norris, Francesco Dolcini
In-Reply-To: <aehwG2Egt93-sPVB@ashevche-desk.local>

[-- Attachment #1: Type: text/plain, Size: 1577 bytes --]

On Wed, Apr 22, 2026 at 09:52:11AM +0300, Andy Shevchenko wrote:
> On Tue, Apr 21, 2026 at 10:12:41AM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> > On Mon, Apr 20, 2026 at 04:46:56PM -0400, Luiz Augusto von Dentz wrote:
> > > On Mon, Apr 20, 2026 at 4:31 PM Uwe Kleine-König (The Capable Hub)
> > > <u.kleine-koenig@baylibre.com> wrote:
> > > > On Fri, Apr 17, 2026 at 03:10:47PM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> > > > > On all current Linux architectures sizeof(long) == sizeof(void *) and
> > > > > this is used a lot through the kernel. For example it enables the usual
> > > > > practice to store pointers in sdio_driver_id's .driver_data member.
> > > > >
> > > > > This works fine, but involves casting and thus isn't type-safe.
> > 
> > To be honest, with the involved void* this isn't really type-safe
> > either, but at least the data keeps being a pointer which is really
> > helpful on CHERI. FTR: The alternative would be to use uintptr_t instead
> > of unsigned long, which also has proponents in the CHERI community and
> > which is used in the current vendor patch stack.
> 
> FWIW, Linus categorically told that it has to be no uintptr_t in the Linux kernel.

Then I'm lucky that this patch set doesn't introduce uintptr_t and so we
can delay the discussion with Linus about that. (And we will have to
hold that discussion at some point, because on CHERI we have
sizeof(unsigned long) = 8 < sizeof(void *) = 16. I didn't check, but I
think also unsigned long long cannot hold a void*.

Best regards
Uwe

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: [PATCH BlueZ v1] input: Fix checking LE bonding on HIDP
From: Bastien Nocera @ 2026-04-22  8:01 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, linux-bluetooth
In-Reply-To: <20260421202253.1957689-1-luiz.dentz@gmail.com>

On Tue, 2026-04-21 at 16:22 -0400, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> HIDP is classic only, LE uses HOG, so there is no point in checking
> the
> bonding with the address type which in case the device supports
> dual-mode will map to LE random/public address.
> 
> Fixes: https://github.com/bluez/bluez/issues/2034
> ---
>  profiles/input/device.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/profiles/input/device.c b/profiles/input/device.c
> index 6bdc5ee3aaf3..0ee6988c4e90 100644
> --- a/profiles/input/device.c
> +++ b/profiles/input/device.c
> @@ -127,8 +127,7 @@ static int connection_disconnect(struct
> input_device *idev, uint32_t flags);
>  
>  static bool input_device_bonded(struct input_device *idev)
>  {
> -	return device_is_bonded(idev->device,
> -				btd_device_get_bdaddr_type(idev-
> >device));
> +	return device_is_bonded(idev->device, BDADDR_BREDR);

Do we want to do the same in virtual_cable_unplug() in that same file?

Do we also want to apply this to hog_accept() with BDADDR_LE in
profiles/input/hog.c ?

>  }
>  
>  static void input_device_free(struct input_device *idev)

^ permalink raw reply

* Re: [PATCH v1 1/6] sdio: Add syntactic sugar to store a pointer in sdio_driver_id
From: Andy Shevchenko @ 2026-04-22  6:52 UTC (permalink / raw)
  To: Uwe Kleine-König (The Capable Hub)
  Cc: Luiz Augusto von Dentz, Ulf Hansson, Christian A. Ehrhardt,
	linux-mmc, Greg Kroah-Hartman, Wolfram Sang, linux-kernel,
	Marcel Holtmann, linux-bluetooth, Matthias Brugger,
	AngeloGioacchino Del Regno, linux-mediatek, Ping-Ke Shih,
	linux-wireless, Felix Fietkau, Lorenzo Bianconi, Ryder Lee,
	Shayne Chen, Sean Wang, Brian Norris, Francesco Dolcini
In-Reply-To: <aecu1ixyHP2hQvgE@monoceros>

On Tue, Apr 21, 2026 at 10:12:41AM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> On Mon, Apr 20, 2026 at 04:46:56PM -0400, Luiz Augusto von Dentz wrote:
> > On Mon, Apr 20, 2026 at 4:31 PM Uwe Kleine-König (The Capable Hub)
> > <u.kleine-koenig@baylibre.com> wrote:
> > > On Fri, Apr 17, 2026 at 03:10:47PM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> > > > On all current Linux architectures sizeof(long) == sizeof(void *) and
> > > > this is used a lot through the kernel. For example it enables the usual
> > > > practice to store pointers in sdio_driver_id's .driver_data member.
> > > >
> > > > This works fine, but involves casting and thus isn't type-safe.
> 
> To be honest, with the involved void* this isn't really type-safe
> either, but at least the data keeps being a pointer which is really
> helpful on CHERI. FTR: The alternative would be to use uintptr_t instead
> of unsigned long, which also has proponents in the CHERI community and
> which is used in the current vendor patch stack.

FWIW, Linus categorically told that it has to be no uintptr_t in the Linux kernel.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply

* [bluetooth-next:master] BUILD SUCCESS 006b9943b9822c8e6230010c1753aa577b4df6fc
From: kernel test robot @ 2026-04-22  6:28 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master
branch HEAD: 006b9943b9822c8e6230010c1753aa577b4df6fc  Bluetooth: btmtk: validate WMT event SKB length before struct access

elapsed time: 769m

configs tested: 77
configs skipped: 2

The following configs have been built successfully.
More configs may be tested in the coming days.

tested configs:
alpha                             allnoconfig    gcc-15.2.0
alpha                            allyesconfig    gcc-15.2.0
arc                              allmodconfig    gcc-15.2.0
arc                               allnoconfig    gcc-15.2.0
arc                              allyesconfig    gcc-15.2.0
arc                   randconfig-001-20260422    gcc-9.5.0
arc                   randconfig-002-20260422    gcc-11.5.0
arm                               allnoconfig    clang-23
arm                              allyesconfig    gcc-15.2.0
arm                   randconfig-001-20260422    gcc-8.5.0
arm                   randconfig-002-20260422    gcc-8.5.0
arm                   randconfig-003-20260422    clang-20
arm64                            allmodconfig    clang-19
arm64                             allnoconfig    gcc-15.2.0
csky                             allmodconfig    gcc-15.2.0
csky                              allnoconfig    gcc-15.2.0
hexagon                          allmodconfig    clang-17
hexagon                           allnoconfig    clang-23
i386                             allmodconfig    gcc-14
i386                              allnoconfig    gcc-14
i386                             allyesconfig    gcc-14
loongarch                        allmodconfig    clang-19
loongarch                         allnoconfig    clang-23
m68k                             allmodconfig    gcc-15.2.0
m68k                              allnoconfig    gcc-15.2.0
m68k                             allyesconfig    gcc-15.2.0
microblaze                        allnoconfig    gcc-15.2.0
microblaze                       allyesconfig    gcc-15.2.0
mips                             allmodconfig    gcc-15.2.0
mips                              allnoconfig    gcc-15.2.0
mips                             allyesconfig    gcc-15.2.0
nios2                            allmodconfig    gcc-11.5.0
nios2                             allnoconfig    gcc-11.5.0
openrisc                         allmodconfig    gcc-15.2.0
openrisc                          allnoconfig    gcc-15.2.0
parisc                           allmodconfig    gcc-15.2.0
parisc                            allnoconfig    gcc-15.2.0
parisc                           allyesconfig    gcc-15.2.0
parisc                randconfig-001-20260422    gcc-14.3.0
parisc                randconfig-002-20260422    gcc-9.5.0
powerpc                          allmodconfig    gcc-15.2.0
powerpc                           allnoconfig    gcc-15.2.0
powerpc               randconfig-001-20260422    gcc-13.4.0
powerpc               randconfig-002-20260422    gcc-14.3.0
powerpc64             randconfig-001-20260422    clang-23
powerpc64             randconfig-002-20260422    gcc-15.2.0
riscv                            allmodconfig    clang-23
riscv                             allnoconfig    gcc-15.2.0
riscv                            allyesconfig    clang-16
s390                             allmodconfig    clang-18
s390                              allnoconfig    clang-23
s390                             allyesconfig    gcc-15.2.0
sh                               allmodconfig    gcc-15.2.0
sh                                allnoconfig    gcc-15.2.0
sh                               allyesconfig    gcc-15.2.0
sparc                             allnoconfig    gcc-15.2.0
sparc64                          allmodconfig    clang-23
um                               allmodconfig    clang-19
um                                allnoconfig    clang-23
um                               allyesconfig    gcc-14
x86_64                           allmodconfig    clang-20
x86_64                            allnoconfig    clang-20
x86_64                           allyesconfig    clang-20
x86_64      buildonly-randconfig-001-20260422    gcc-14
x86_64      buildonly-randconfig-002-20260422    gcc-14
x86_64      buildonly-randconfig-003-20260422    gcc-14
x86_64      buildonly-randconfig-004-20260422    clang-20
x86_64      buildonly-randconfig-005-20260422    gcc-14
x86_64                randconfig-001-20260422    clang-20
x86_64                randconfig-002-20260422    gcc-14
x86_64                randconfig-003-20260422    gcc-14
x86_64                randconfig-004-20260422    clang-20
x86_64                randconfig-005-20260422    gcc-14
x86_64                randconfig-006-20260422    clang-20
x86_64                          rhel-9.4-rust    clang-20
xtensa                            allnoconfig    gcc-15.2.0
xtensa                           allyesconfig    gcc-15.2.0

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* RE: Bluetooth: HIDP: guard session->conn in hidp_connection_del
From: bluez.test.bot @ 2026-04-22  4:13 UTC (permalink / raw)
  To: linux-bluetooth, michael.bommarito
In-Reply-To: <20260422011437.176643-1-michael.bommarito@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 4405 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1084091

---Test result---

Test Summary:
CheckPatch                    FAIL      0.55 seconds
GitLint                       PASS      0.20 seconds
SubjectPrefix                 PASS      0.08 seconds
BuildKernel                   PASS      26.22 seconds
CheckAllWarning               PASS      28.58 seconds
CheckSparse                   PASS      27.49 seconds
BuildKernel32                 PASS      25.59 seconds
TestRunnerSetup               PASS      574.90 seconds
TestRunner_l2cap-tester       PASS      27.87 seconds
TestRunner_iso-tester         PASS      42.34 seconds
TestRunner_bnep-tester        PASS      6.48 seconds
TestRunner_mgmt-tester        FAIL      114.28 seconds
TestRunner_rfcomm-tester      PASS      9.83 seconds
TestRunner_sco-tester         PASS      14.50 seconds
TestRunner_ioctl-tester       PASS      10.22 seconds
TestRunner_mesh-tester        FAIL      12.18 seconds
TestRunner_smp-tester         PASS      8.81 seconds
TestRunner_userchan-tester    PASS      6.92 seconds
TestRunner_6lowpan-tester     FAIL      8.68 seconds
IncrementalBuild              PASS      25.52 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
Bluetooth: HIDP: guard session->conn in hidp_connection_del
WARNING: Non-standard signature: Assisted-by:
#140: 
Assisted-by: Claude:claude-opus-4-7

ERROR: Unrecognized email address: 'Claude:claude-opus-4-7'
#140: 
Assisted-by: Claude:claude-opus-4-7

total: 1 errors, 1 warnings, 0 checks, 8 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/patch/14533271.patch has style problems, please review.

NOTE: Ignored message types: UNKNOWN_COMMIT_ID

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.


##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner
Output:
Total: 494, Passed: 489 (99.0%), Failed: 1, Not Run: 4

Failed Test Cases
Read Exp Feature - Success                           Failed       0.112 seconds
##############################
Test: TestRunner_mesh-tester - FAIL
Desc: Run mesh-tester with test-runner
Output:
Total: 10, Passed: 8 (80.0%), Failed: 2, Not Run: 0

Failed Test Cases
Mesh - Send cancel - 1                               Timed out    2.627 seconds
Mesh - Send cancel - 2                               Timed out    1.994 seconds
##############################
Test: TestRunner_6lowpan-tester - FAIL
Desc: Run 6lowpan-tester with test-runner
Output:
WARNING: possible circular locking dependency detected
7.0.0-rc7-gcdeca5510265 #1 Not tainted
------------------------------------------------------
kworker/0:1/11 is trying to acquire lock:
ffff888002735940 ((wq_completion)hci0#2){+.+.}-{0:0}, at: touch_wq_lockdep_map+0x75/0x180

but task is already holding lock:
ffffffff9d84f9e0 (rtnl_mutex){+.+.}-{4:4}, at: lowpan_unregister_netdev+0xd/0x30

which lock already depends on the new lock.


the existing dependency chain (in reverse order) is:

-> #4 (rtnl_mutex){+.+.}-{4:4}:
       lock_acquire+0xf7/0x2c0
       __mutex_lock+0x16b/0x1fc0
       lowpan_register_netdev+0x11/0x30
       chan_ready_cb+0x836/0xd00
       l2cap_recv_frame+0x61bb/0x88e0
       l2cap_recv_acldata+0x790/0xdf0
       hci_rx_work+0x500/0xd00
       process_scheduled_works+0xba7/0x1a90
       worker_thread+0x514/0xbb0
       kthread+0x368/0x490
       ret_from_fork+0x498/0x7e0
       ret_from_fork_asm+0x19/0x30

-> #3 (&chan->lock#3/1){+.+.}-{4:4}:
       lock_acquire+0xf7/0x2c0
       __mutex_lock+0x16b/0x1fc0
       l2cap_chan_connect+0x74e/0x1980
       lowpan_control_write+0x523/0x660
       full_proxy_write+0x10b/0x190
       vfs_write+0x1c0/0xf60
       ksys_write+0xf1/0x1d0
       do_syscall_64+0xa0/0x570
       entry_SYSCALL_64_after_hwframe+0x74/0x7c

-> #2 (&conn->lock){+.+.}-{4:4}:
...
Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0


https://github.com/bluez/bluetooth-next/pull/115

---
Regards,
Linux Bluetooth


^ permalink raw reply

* [PATCH] Bluetooth: HIDP: guard session->conn in hidp_connection_del
From: Michael Bommarito @ 2026-04-22  1:14 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: Luiz Augusto von Dentz, linux-bluetooth, linux-kernel
In-Reply-To: <20260306023155.554597-1-luiz.dentz@gmail.com>

commit dbf666e4fc9b ("Bluetooth: HIDP: Fix possible UAF") changed
hidp_session_remove() to drop the L2CAP reference and set
session->conn = NULL once the session is considered removed, and
added an if (session->conn) guard around the l2cap_unregister_user()
call at the kthread-exit site in hidp_session_thread().

The sibling call site in hidp_connection_del() still invokes
l2cap_unregister_user(session->conn, &session->user) unconditionally.
hidp_session_find() takes the session refcount under
down_read(&hidp_session_sem) and returns; between the find() and the
call at :1421, hidp_session_remove() can run on another thread
(driven by the remote peer disconnecting or local teardown), take
down_write(&hidp_session_sem), set session->conn to NULL, and return.
The HIDPCONNDEL ioctl path then dereferences a NULL l2cap_conn inside
l2cap_unregister_user(), which acquires conn->lock without a NULL
check.  Result: kernel NULL-pointer dereference.

Apply the same if (session->conn) guard used at the twin site.  No
functional change when session->conn is non-NULL.

Discovery and verification:

- Found via static audit of every session->conn read in hidp/core.c
  after the referenced commit landed.  The other reads are safe
  (creation-time in hidp_session_dev_init, already-guarded in
  session_free / hidp_session_thread / hidp_session_remove; the other
  hidp_session_find callers do not touch session->conn at all), so
  :1421 is the only remaining unguarded site.
- Runtime A/B confirmed in UML with CONFIG_BT_HIDP=y + CONFIG_KASAN=y:
  a late_initcall stub that injects a fake hidp_session with
  conn=NULL into hidp_session_list and invokes hidp_connection_del()
  panics on the pre-fix tree at __mutex_lock from
  l2cap_unregister_user+0x2d, and returns cleanly on the post-fix
  tree with the new guard short-circuiting before the deref.

Fixes: dbf666e4fc9b ("Bluetooth: HIDP: Fix possible UAF")
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Assisted-by: Claude:claude-opus-4-7
---
 net/bluetooth/hidp/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 7bcf8c5ceaee..9192efd1b156 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -1417,7 +1417,7 @@ int hidp_connection_del(struct hidp_conndel_req *req)
 				       HIDP_TRANS_HID_CONTROL |
 				         HIDP_CTRL_VIRTUAL_CABLE_UNPLUG,
 				       NULL, 0);
-	else
+	else if (session->conn)
 		l2cap_unregister_user(session->conn, &session->user);
 
 	hidp_session_put(session);
-- 
2.53.0


^ permalink raw reply related

* [bluez/bluez]
From: BluezTestBot @ 2026-04-22  1:09 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1070581
  Home:   https://github.com/bluez/bluez

To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply

* RE: Bluetooth: Use AES-CMAC library API
From: bluez.test.bot @ 2026-04-22  0:08 UTC (permalink / raw)
  To: linux-bluetooth, ebiggers
In-Reply-To: <20260421230917.7057-2-ebiggers@kernel.org>

[-- Attachment #1: Type: text/plain, Size: 10779 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1084071

---Test result---

Test Summary:
CheckPatch                    PASS      1.56 seconds
GitLint                       PASS      0.49 seconds
SubjectPrefix                 PASS      0.17 seconds
BuildKernel                   FAIL      20.93 seconds
CheckAllWarning               FAIL      23.01 seconds
CheckSparse                   FAIL      22.09 seconds
BuildKernel32                 FAIL      20.31 seconds
TestRunnerSetup               FAIL      488.99 seconds
TestRunner_l2cap-tester       FAIL      0.11 seconds
TestRunner_iso-tester         FAIL      0.11 seconds
TestRunner_bnep-tester        FAIL      0.53 seconds
TestRunner_mgmt-tester        FAIL      0.11 seconds
TestRunner_rfcomm-tester      FAIL      0.11 seconds
TestRunner_sco-tester         FAIL      0.11 seconds
TestRunner_ioctl-tester       FAIL      0.11 seconds
TestRunner_mesh-tester        FAIL      0.11 seconds
TestRunner_smp-tester         FAIL      0.10 seconds
TestRunner_userchan-tester    FAIL      0.10 seconds
TestRunner_6lowpan-tester     FAIL      0.11 seconds
IncrementalBuild              FAIL      26.35 seconds

Details
##############################
Test: BuildKernel - FAIL
Desc: Build Kernel for Bluetooth
Output:

net/bluetooth/smp.c:25:10: fatal error: crypto/aes-cbc-macs.h: No such file or directory
   25 | #include <crypto/aes-cbc-macs.h>
      |          ^~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[4]: *** [scripts/Makefile.build:289: net/bluetooth/smp.o] Error 1
make[4]: *** Waiting for unfinished jobs....
make[3]: *** [scripts/Makefile.build:548: net/bluetooth] Error 2
make[2]: *** [scripts/Makefile.build:548: net] Error 2
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [/github/workspace/src/src/Makefile:2105: .] Error 2
make: *** [Makefile:248: __sub-make] Error 2
##############################
Test: CheckAllWarning - FAIL
Desc: Run linux kernel with all warning enabled
Output:

net/bluetooth/smp.c:25:10: fatal error: crypto/aes-cbc-macs.h: No such file or directory
   25 | #include <crypto/aes-cbc-macs.h>
      |          ^~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[4]: *** [scripts/Makefile.build:289: net/bluetooth/smp.o] Error 1
make[4]: *** Waiting for unfinished jobs....
make[3]: *** [scripts/Makefile.build:548: net/bluetooth] Error 2
make[2]: *** [scripts/Makefile.build:548: net] Error 2
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [/github/workspace/src/src/Makefile:2105: .] Error 2
make: *** [Makefile:248: __sub-make] Error 2
##############################
Test: CheckSparse - FAIL
Desc: Run sparse tool with linux kernel
Output:

/github/workspace/src/src/Makefile:1208: C=1 specified, but sparse is not available or not up to date
/github/workspace/src/src/Makefile:1208: C=1 specified, but sparse is not available or not up to date
net/bluetooth/smp.c:25:10: fatal error: crypto/aes-cbc-macs.h: No such file or directory
   25 | #include <crypto/aes-cbc-macs.h>
      |          ^~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[4]: *** [scripts/Makefile.build:289: net/bluetooth/smp.o] Error 1
make[4]: *** Waiting for unfinished jobs....
make[3]: *** [scripts/Makefile.build:548: net/bluetooth] Error 2
make[2]: *** [scripts/Makefile.build:548: net] Error 2
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [/github/workspace/src/src/Makefile:2105: .] Error 2
make: *** [Makefile:248: __sub-make] Error 2
##############################
Test: BuildKernel32 - FAIL
Desc: Build 32bit Kernel for Bluetooth
Output:

net/bluetooth/smp.c:25:10: fatal error: crypto/aes-cbc-macs.h: No such file or directory
   25 | #include <crypto/aes-cbc-macs.h>
      |          ^~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[4]: *** [scripts/Makefile.build:289: net/bluetooth/smp.o] Error 1
make[4]: *** Waiting for unfinished jobs....
make[3]: *** [scripts/Makefile.build:548: net/bluetooth] Error 2
make[2]: *** [scripts/Makefile.build:548: net] Error 2
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [/github/workspace/src/src/Makefile:2105: .] Error 2
make: *** [Makefile:248: __sub-make] Error 2
##############################
Test: TestRunnerSetup - FAIL
Desc: Setup kernel and bluez for test-runner
Output:
Kernel: 
net/bluetooth/smp.c:25:10: fatal error: crypto/aes-cbc-macs.h: No such file or directory
   25 | #include <crypto/aes-cbc-macs.h>
      |          ^~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[4]: *** [scripts/Makefile.build:289: net/bluetooth/smp.o] Error 1
make[3]: *** [scripts/Makefile.build:548: net/bluetooth] Error 2
make[3]: *** Waiting for unfinished jobs....
make[2]: *** [scripts/Makefile.build:548: net] Error 2
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [/github/workspace/src/src/Makefile:2105: .] Error 2
make: *** [Makefile:248: __sub-make] Error 2
##############################
Test: TestRunner_l2cap-tester - FAIL
Desc: Run l2cap-tester with test-runner
Output:

Could not access KVM kernel module: No such file or directory
qemu-system-x86_64: failed to initialize KVM: No such file or directory
qemu-system-x86_64: Back to tcg accelerator
qemu: could not open kernel file '/github/workspace/src/src/arch/x86/boot/bzImage': No such file or directory
##############################
Test: TestRunner_iso-tester - FAIL
Desc: Run iso-tester with test-runner
Output:

Could not access KVM kernel module: No such file or directory
qemu-system-x86_64: failed to initialize KVM: No such file or directory
qemu-system-x86_64: Back to tcg accelerator
qemu: could not open kernel file '/github/workspace/src/src/arch/x86/boot/bzImage': No such file or directory
##############################
Test: TestRunner_bnep-tester - FAIL
Desc: Run bnep-tester with test-runner
Output:

Could not access KVM kernel module: No such file or directory
qemu-system-x86_64: failed to initialize KVM: No such file or directory
qemu-system-x86_64: Back to tcg accelerator
qemu: could not open kernel file '/github/workspace/src/src/arch/x86/boot/bzImage': No such file or directory
##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner
Output:

Could not access KVM kernel module: No such file or directory
qemu-system-x86_64: failed to initialize KVM: No such file or directory
qemu-system-x86_64: Back to tcg accelerator
qemu: could not open kernel file '/github/workspace/src/src/arch/x86/boot/bzImage': No such file or directory
##############################
Test: TestRunner_rfcomm-tester - FAIL
Desc: Run rfcomm-tester with test-runner
Output:

Could not access KVM kernel module: No such file or directory
qemu-system-x86_64: failed to initialize KVM: No such file or directory
qemu-system-x86_64: Back to tcg accelerator
qemu: could not open kernel file '/github/workspace/src/src/arch/x86/boot/bzImage': No such file or directory
##############################
Test: TestRunner_sco-tester - FAIL
Desc: Run sco-tester with test-runner
Output:

Could not access KVM kernel module: No such file or directory
qemu-system-x86_64: failed to initialize KVM: No such file or directory
qemu-system-x86_64: Back to tcg accelerator
qemu: could not open kernel file '/github/workspace/src/src/arch/x86/boot/bzImage': No such file or directory
##############################
Test: TestRunner_ioctl-tester - FAIL
Desc: Run ioctl-tester with test-runner
Output:

Could not access KVM kernel module: No such file or directory
qemu-system-x86_64: failed to initialize KVM: No such file or directory
qemu-system-x86_64: Back to tcg accelerator
qemu: could not open kernel file '/github/workspace/src/src/arch/x86/boot/bzImage': No such file or directory
##############################
Test: TestRunner_mesh-tester - FAIL
Desc: Run mesh-tester with test-runner
Output:

Could not access KVM kernel module: No such file or directory
qemu-system-x86_64: failed to initialize KVM: No such file or directory
qemu-system-x86_64: Back to tcg accelerator
qemu: could not open kernel file '/github/workspace/src/src/arch/x86/boot/bzImage': No such file or directory
##############################
Test: TestRunner_smp-tester - FAIL
Desc: Run smp-tester with test-runner
Output:

Could not access KVM kernel module: No such file or directory
qemu-system-x86_64: failed to initialize KVM: No such file or directory
qemu-system-x86_64: Back to tcg accelerator
qemu: could not open kernel file '/github/workspace/src/src/arch/x86/boot/bzImage': No such file or directory
##############################
Test: TestRunner_userchan-tester - FAIL
Desc: Run userchan-tester with test-runner
Output:

Could not access KVM kernel module: No such file or directory
qemu-system-x86_64: failed to initialize KVM: No such file or directory
qemu-system-x86_64: Back to tcg accelerator
qemu: could not open kernel file '/github/workspace/src/src/arch/x86/boot/bzImage': No such file or directory
##############################
Test: TestRunner_6lowpan-tester - FAIL
Desc: Run 6lowpan-tester with test-runner
Output:

Could not access KVM kernel module: No such file or directory
qemu-system-x86_64: failed to initialize KVM: No such file or directory
qemu-system-x86_64: Back to tcg accelerator
qemu: could not open kernel file '/github/workspace/src/src/arch/x86/boot/bzImage': No such file or directory
##############################
Test: IncrementalBuild - FAIL
Desc: Incremental build with the patches in the series
Output:

net/bluetooth/smp.c:25:10: fatal error: crypto/aes-cbc-macs.h: No such file or directory
   25 | #include <crypto/aes-cbc-macs.h>
      |          ^~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[4]: *** [scripts/Makefile.build:289: net/bluetooth/smp.o] Error 1
make[3]: *** [scripts/Makefile.build:548: net/bluetooth] Error 2
make[2]: *** [scripts/Makefile.build:548: net] Error 2
make[1]: *** [/github/workspace/src/src/Makefile:2105: .] Error 2
make: *** [Makefile:248: __sub-make] Error 2
[v2,2/2] Bluetooth: SMP: Use AES-CMAC library API

net/bluetooth/smp.c:25:10: fatal error: crypto/aes-cbc-macs.h: No such file or directory
   25 | #include <crypto/aes-cbc-macs.h>
      |          ^~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[4]: *** [scripts/Makefile.build:289: net/bluetooth/smp.o] Error 1
make[3]: *** [scripts/Makefile.build:548: net/bluetooth] Error 2
make[2]: *** [scripts/Makefile.build:548: net] Error 2
make[1]: *** [/github/workspace/src/src/Makefile:2105: .] Error 2
make: *** [Makefile:248: __sub-make] Error 2


https://github.com/bluez/bluetooth-next/pull/114

---
Regards,
Linux Bluetooth


^ permalink raw reply

* [PATCH v2 2/2] Bluetooth: SMP: Use AES-CMAC library API
From: Eric Biggers @ 2026-04-21 23:09 UTC (permalink / raw)
  To: linux-bluetooth, Marcel Holtmann, Luiz Augusto von Dentz
  Cc: linux-crypto, linux-kernel, Eric Biggers, Ard Biesheuvel
In-Reply-To: <20260421230917.7057-1-ebiggers@kernel.org>

Now that AES-CMAC has a library API, convert net/bluetooth/smp.c to use
it instead of the "cmac(aes)" crypto_shash.  Since the library API
doesn't require dynamic memory allocation, we no longer need to pass a
crypto_shash object down the call stack and can simply allocate the
aes_cmac_key on the stack in smp_aes_cmac() (renamed from aes_cmac()).

The result is simpler and faster code that no longer relies on the
error-prone loading of algorithms by name.

Note that the maximum stack usage actually decreases slightly, despite
the expanded AES key being moved to the stack.  This is because the old
code called crypto_shash_tfm_digest(), which allocates 384 bytes on the
stack for a maximally-sized hash descriptor for any algorithm.  The new
code instead declares a 288-byte aes_cmac_key, then calls aes_cmac()
which declares a 32-byte aes_cmac_ctx.  Since 288 + 32 < 384, the
maximum stack usage decreases.  I.e. the entire expanded AES key easily
fits in the space that the generic crypto API was wasting before.

I didn't add zeroization of the aes_cmac_key, since smp_aes_cmac()
already copies the raw key to the stack without zeroizing it.

Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 net/bluetooth/Kconfig |   3 +-
 net/bluetooth/smp.c   | 180 +++++++++++++++---------------------------
 2 files changed, 65 insertions(+), 118 deletions(-)

diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig
index 8bd0f2891161..884356938d74 100644
--- a/net/bluetooth/Kconfig
+++ b/net/bluetooth/Kconfig
@@ -8,12 +8,11 @@ menuconfig BT
 	depends on !S390
 	depends on RFKILL || !RFKILL
 	select CRC16
 	select CRYPTO
 	select CRYPTO_LIB_AES
-	imply CRYPTO_AES
-	select CRYPTO_CMAC
+	select CRYPTO_LIB_AES_CBC_MACS
 	select CRYPTO_ECDH
 	help
 	  Bluetooth is low-cost, low-power, short-range wireless technology.
 	  It was designed as a replacement for cables and other short-range
 	  technologies like IrDA.  Bluetooth operates in personal area range
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 98f1da4f5f55..1739c1989dbd 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -20,12 +20,12 @@
    SOFTWARE IS DISCLAIMED.
 */
 
 #include <linux/debugfs.h>
 #include <linux/scatterlist.h>
+#include <crypto/aes-cbc-macs.h>
 #include <crypto/aes.h>
-#include <crypto/hash.h>
 #include <crypto/kpp.h>
 #include <crypto/utils.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -61,11 +61,11 @@
 
 #define AUTH_REQ_MASK(dev)	(hci_dev_test_flag(dev, HCI_SC_ENABLED) ? \
 				 0x3f : 0x07)
 #define KEY_DIST_MASK		0x07
 
-/* Maximum message length that can be passed to aes_cmac */
+/* Maximum message length that can be passed to smp_aes_cmac */
 #define CMAC_MSG_MAX	80
 
 enum {
 	SMP_FLAG_TK_VALID,
 	SMP_FLAG_CFM_PENDING,
@@ -87,11 +87,10 @@ struct smp_dev {
 	bool			local_oob;
 	u8			local_pk[64];
 	u8			local_rand[16];
 	bool			debug_key;
 
-	struct crypto_shash	*tfm_cmac;
 	struct crypto_kpp	*tfm_ecdh;
 };
 
 struct smp_chan {
 	struct l2cap_conn	*conn;
@@ -125,11 +124,10 @@ struct smp_chan {
 	u8			local_pk[64];
 	u8			remote_pk[64];
 	u8			dhkey[32];
 	u8			mackey[16];
 
-	struct crypto_shash	*tfm_cmac;
 	struct crypto_kpp	*tfm_ecdh;
 };
 
 /* These debug key values are defined in the SMP section of the core
  * specification. debug_pk is the public debug key and debug_sk the
@@ -164,52 +162,40 @@ static inline void swap_buf(const u8 *src, u8 *dst, size_t len)
 
 /* The following functions map to the LE SC SMP crypto functions
  * AES-CMAC, f4, f5, f6, g2 and h6.
  */
 
-static int aes_cmac(struct crypto_shash *tfm, const u8 k[16], const u8 *m,
-		    size_t len, u8 mac[16])
+static int smp_aes_cmac(const u8 k[16], const u8 *m, size_t len, u8 mac[16])
 {
 	uint8_t tmp[16], mac_msb[16], msg_msb[CMAC_MSG_MAX];
+	struct aes_cmac_key key;
 	int err;
 
 	if (len > CMAC_MSG_MAX)
 		return -EFBIG;
 
-	if (!tfm) {
-		BT_ERR("tfm %p", tfm);
-		return -EINVAL;
-	}
-
 	/* Swap key and message from LSB to MSB */
 	swap_buf(k, tmp, 16);
 	swap_buf(m, msg_msb, len);
 
 	SMP_DBG("msg (len %zu) %*phN", len, (int) len, m);
 	SMP_DBG("key %16phN", k);
 
-	err = crypto_shash_setkey(tfm, tmp, 16);
-	if (err) {
-		BT_ERR("cipher setkey failed: %d", err);
+	err = aes_cmac_preparekey(&key, tmp, 16);
+	if (WARN_ON_ONCE(err)) /* Should never happen, as 16 is valid keylen */
 		return err;
-	}
-
-	err = crypto_shash_tfm_digest(tfm, msg_msb, len, mac_msb);
-	if (err) {
-		BT_ERR("Hash computation error %d", err);
-		return err;
-	}
+	aes_cmac(&key, msg_msb, len, mac_msb);
 
 	swap_buf(mac_msb, mac, 16);
 
 	SMP_DBG("mac %16phN", mac);
 
 	return 0;
 }
 
-static int smp_f4(struct crypto_shash *tfm_cmac, const u8 u[32],
-		  const u8 v[32], const u8 x[16], u8 z, u8 res[16])
+static int smp_f4(const u8 u[32], const u8 v[32], const u8 x[16], u8 z,
+		  u8 res[16])
 {
 	u8 m[65];
 	int err;
 
 	SMP_DBG("u %32phN", u);
@@ -218,22 +204,21 @@ static int smp_f4(struct crypto_shash *tfm_cmac, const u8 u[32],
 
 	m[0] = z;
 	memcpy(m + 1, v, 32);
 	memcpy(m + 33, u, 32);
 
-	err = aes_cmac(tfm_cmac, x, m, sizeof(m), res);
+	err = smp_aes_cmac(x, m, sizeof(m), res);
 	if (err)
 		return err;
 
 	SMP_DBG("res %16phN", res);
 
 	return err;
 }
 
-static int smp_f5(struct crypto_shash *tfm_cmac, const u8 w[32],
-		  const u8 n1[16], const u8 n2[16], const u8 a1[7],
-		  const u8 a2[7], u8 mackey[16], u8 ltk[16])
+static int smp_f5(const u8 w[32], const u8 n1[16], const u8 n2[16],
+		  const u8 a1[7], const u8 a2[7], u8 mackey[16], u8 ltk[16])
 {
 	/* The btle, salt and length "magic" values are as defined in
 	 * the SMP section of the Bluetooth core specification. In ASCII
 	 * the btle value ends up being 'btle'. The salt is just a
 	 * random number whereas length is the value 256 in little
@@ -248,11 +233,11 @@ static int smp_f5(struct crypto_shash *tfm_cmac, const u8 w[32],
 
 	SMP_DBG("w %32phN", w);
 	SMP_DBG("n1 %16phN n2 %16phN", n1, n2);
 	SMP_DBG("a1 %7phN a2 %7phN", a1, a2);
 
-	err = aes_cmac(tfm_cmac, salt, w, 32, t);
+	err = smp_aes_cmac(salt, w, 32, t);
 	if (err)
 		return err;
 
 	SMP_DBG("t %16phN", t);
 
@@ -263,31 +248,30 @@ static int smp_f5(struct crypto_shash *tfm_cmac, const u8 w[32],
 	memcpy(m + 32, n1, 16);
 	memcpy(m + 48, btle, 4);
 
 	m[52] = 0; /* Counter */
 
-	err = aes_cmac(tfm_cmac, t, m, sizeof(m), mackey);
+	err = smp_aes_cmac(t, m, sizeof(m), mackey);
 	if (err)
 		return err;
 
 	SMP_DBG("mackey %16phN", mackey);
 
 	m[52] = 1; /* Counter */
 
-	err = aes_cmac(tfm_cmac, t, m, sizeof(m), ltk);
+	err = smp_aes_cmac(t, m, sizeof(m), ltk);
 	if (err)
 		return err;
 
 	SMP_DBG("ltk %16phN", ltk);
 
 	return 0;
 }
 
-static int smp_f6(struct crypto_shash *tfm_cmac, const u8 w[16],
-		  const u8 n1[16], const u8 n2[16], const u8 r[16],
-		  const u8 io_cap[3], const u8 a1[7], const u8 a2[7],
-		  u8 res[16])
+static int smp_f6(const u8 w[16], const u8 n1[16], const u8 n2[16],
+		  const u8 r[16], const u8 io_cap[3], const u8 a1[7],
+		  const u8 a2[7], u8 res[16])
 {
 	u8 m[65];
 	int err;
 
 	SMP_DBG("w %16phN", w);
@@ -299,21 +283,21 @@ static int smp_f6(struct crypto_shash *tfm_cmac, const u8 w[16],
 	memcpy(m + 14, io_cap, 3);
 	memcpy(m + 17, r, 16);
 	memcpy(m + 33, n2, 16);
 	memcpy(m + 49, n1, 16);
 
-	err = aes_cmac(tfm_cmac, w, m, sizeof(m), res);
+	err = smp_aes_cmac(w, m, sizeof(m), res);
 	if (err)
 		return err;
 
 	SMP_DBG("res %16phN", res);
 
 	return err;
 }
 
-static int smp_g2(struct crypto_shash *tfm_cmac, const u8 u[32], const u8 v[32],
-		  const u8 x[16], const u8 y[16], u32 *val)
+static int smp_g2(const u8 u[32], const u8 v[32], const u8 x[16],
+		  const u8 y[16], u32 *val)
 {
 	u8 m[80], tmp[16];
 	int err;
 
 	SMP_DBG("u %32phN", u);
@@ -322,11 +306,11 @@ static int smp_g2(struct crypto_shash *tfm_cmac, const u8 u[32], const u8 v[32],
 
 	memcpy(m, y, 16);
 	memcpy(m + 16, v, 32);
 	memcpy(m + 48, u, 32);
 
-	err = aes_cmac(tfm_cmac, x, m, sizeof(m), tmp);
+	err = smp_aes_cmac(x, m, sizeof(m), tmp);
 	if (err)
 		return err;
 
 	*val = get_unaligned_le32(tmp);
 	*val %= 1000000;
@@ -334,34 +318,32 @@ static int smp_g2(struct crypto_shash *tfm_cmac, const u8 u[32], const u8 v[32],
 	SMP_DBG("val %06u", *val);
 
 	return 0;
 }
 
-static int smp_h6(struct crypto_shash *tfm_cmac, const u8 w[16],
-		  const u8 key_id[4], u8 res[16])
+static int smp_h6(const u8 w[16], const u8 key_id[4], u8 res[16])
 {
 	int err;
 
 	SMP_DBG("w %16phN key_id %4phN", w, key_id);
 
-	err = aes_cmac(tfm_cmac, w, key_id, 4, res);
+	err = smp_aes_cmac(w, key_id, 4, res);
 	if (err)
 		return err;
 
 	SMP_DBG("res %16phN", res);
 
 	return err;
 }
 
-static int smp_h7(struct crypto_shash *tfm_cmac, const u8 w[16],
-		  const u8 salt[16], u8 res[16])
+static int smp_h7(const u8 w[16], const u8 salt[16], u8 res[16])
 {
 	int err;
 
 	SMP_DBG("w %16phN salt %16phN", w, salt);
 
-	err = aes_cmac(tfm_cmac, salt, w, 16, res);
+	err = smp_aes_cmac(salt, w, 16, res);
 	if (err)
 		return err;
 
 	SMP_DBG("res %16phN", res);
 
@@ -572,12 +554,11 @@ int smp_generate_oob(struct hci_dev *hdev, u8 hash[16], u8 rand[16])
 	SMP_DBG("OOB Public Key X: %32phN", smp->local_pk);
 	SMP_DBG("OOB Public Key Y: %32phN", smp->local_pk + 32);
 
 	get_random_bytes(smp->local_rand, 16);
 
-	err = smp_f4(smp->tfm_cmac, smp->local_pk, smp->local_pk,
-		     smp->local_rand, 0, hash);
+	err = smp_f4(smp->local_pk, smp->local_pk, smp->local_rand, 0, hash);
 	if (err < 0)
 		return err;
 
 	memcpy(rand, smp->local_rand, 16);
 
@@ -755,11 +736,10 @@ static void smp_chan_destroy(struct l2cap_conn *conn)
 
 	kfree_sensitive(smp->csrk);
 	kfree_sensitive(smp->responder_csrk);
 	kfree_sensitive(smp->link_key);
 
-	crypto_free_shash(smp->tfm_cmac);
 	crypto_free_kpp(smp->tfm_ecdh);
 
 	/* Ensure that we don't leave any debug key around if debug key
 	 * support hasn't been explicitly enabled.
 	 */
@@ -1158,27 +1138,27 @@ static void sc_generate_link_key(struct smp_chan *smp)
 
 	if (test_bit(SMP_FLAG_CT2, &smp->flags)) {
 		/* SALT = 0x000000000000000000000000746D7031 */
 		const u8 salt[16] = { 0x31, 0x70, 0x6d, 0x74 };
 
-		if (smp_h7(smp->tfm_cmac, smp->tk, salt, smp->link_key)) {
+		if (smp_h7(smp->tk, salt, smp->link_key)) {
 			kfree_sensitive(smp->link_key);
 			smp->link_key = NULL;
 			return;
 		}
 	} else {
 		/* From core spec. Spells out in ASCII as 'tmp1'. */
 		const u8 tmp1[4] = { 0x31, 0x70, 0x6d, 0x74 };
 
-		if (smp_h6(smp->tfm_cmac, smp->tk, tmp1, smp->link_key)) {
+		if (smp_h6(smp->tk, tmp1, smp->link_key)) {
 			kfree_sensitive(smp->link_key);
 			smp->link_key = NULL;
 			return;
 		}
 	}
 
-	if (smp_h6(smp->tfm_cmac, smp->link_key, lebr, smp->link_key)) {
+	if (smp_h6(smp->link_key, lebr, smp->link_key)) {
 		kfree_sensitive(smp->link_key);
 		smp->link_key = NULL;
 		return;
 	}
 }
@@ -1216,21 +1196,21 @@ static void sc_generate_ltk(struct smp_chan *smp)
 
 	if (test_bit(SMP_FLAG_CT2, &smp->flags)) {
 		/* SALT = 0x000000000000000000000000746D7032 */
 		const u8 salt[16] = { 0x32, 0x70, 0x6d, 0x74 };
 
-		if (smp_h7(smp->tfm_cmac, key->val, salt, smp->tk))
+		if (smp_h7(key->val, salt, smp->tk))
 			return;
 	} else {
 		/* From core spec. Spells out in ASCII as 'tmp2'. */
 		const u8 tmp2[4] = { 0x32, 0x70, 0x6d, 0x74 };
 
-		if (smp_h6(smp->tfm_cmac, key->val, tmp2, smp->tk))
+		if (smp_h6(key->val, tmp2, smp->tk))
 			return;
 	}
 
-	if (smp_h6(smp->tfm_cmac, smp->tk, brle, smp->tk))
+	if (smp_h6(smp->tk, brle, smp->tk))
 		return;
 
 	sc_add_ltk(smp);
 }
 
@@ -1387,20 +1367,14 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
 
 	smp = kzalloc_obj(*smp, GFP_ATOMIC);
 	if (!smp)
 		return NULL;
 
-	smp->tfm_cmac = crypto_alloc_shash("cmac(aes)", 0, 0);
-	if (IS_ERR(smp->tfm_cmac)) {
-		bt_dev_err(hcon->hdev, "Unable to create CMAC crypto context");
-		goto zfree_smp;
-	}
-
 	smp->tfm_ecdh = crypto_alloc_kpp("ecdh-nist-p256", 0, 0);
 	if (IS_ERR(smp->tfm_ecdh)) {
 		bt_dev_err(hcon->hdev, "Unable to create ECDH crypto context");
-		goto free_shash;
+		goto zfree_smp;
 	}
 
 	smp->conn = conn;
 	chan->data = smp;
 
@@ -1410,12 +1384,10 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
 
 	hci_conn_hold(hcon);
 
 	return smp;
 
-free_shash:
-	crypto_free_shash(smp->tfm_cmac);
 zfree_smp:
 	kfree_sensitive(smp);
 	return NULL;
 }
 
@@ -1435,11 +1407,11 @@ static int sc_mackey_and_ltk(struct smp_chan *smp, u8 mackey[16], u8 ltk[16])
 	memcpy(a, &hcon->init_addr, 6);
 	memcpy(b, &hcon->resp_addr, 6);
 	a[6] = hcon->init_addr_type;
 	b[6] = hcon->resp_addr_type;
 
-	return smp_f5(smp->tfm_cmac, smp->dhkey, na, nb, a, b, mackey, ltk);
+	return smp_f5(smp->dhkey, na, nb, a, b, mackey, ltk);
 }
 
 static void sc_dhkey_check(struct smp_chan *smp)
 {
 	struct hci_conn *hcon = smp->conn->hcon;
@@ -1468,12 +1440,12 @@ static void sc_dhkey_check(struct smp_chan *smp)
 		put_unaligned_le32(hcon->passkey_notify, r);
 
 	if (smp->method == REQ_OOB)
 		memcpy(r, smp->rr, 16);
 
-	smp_f6(smp->tfm_cmac, smp->mackey, smp->prnd, smp->rrnd, r, io_cap,
-	       local_addr, remote_addr, check.e);
+	smp_f6(smp->mackey, smp->prnd, smp->rrnd, r, io_cap, local_addr,
+	       remote_addr, check.e);
 
 	smp_send_cmd(smp->conn, SMP_CMD_DHKEY_CHECK, sizeof(check), &check);
 }
 
 static u8 sc_passkey_send_confirm(struct smp_chan *smp)
@@ -1486,11 +1458,11 @@ static u8 sc_passkey_send_confirm(struct smp_chan *smp)
 	r = ((hcon->passkey_notify >> smp->passkey_round) & 0x01);
 	r |= 0x80;
 
 	get_random_bytes(smp->prnd, sizeof(smp->prnd));
 
-	if (smp_f4(smp->tfm_cmac, smp->local_pk, smp->remote_pk, smp->prnd, r,
+	if (smp_f4(smp->local_pk, smp->remote_pk, smp->prnd, r,
 		   cfm.confirm_val))
 		return SMP_UNSPECIFIED;
 
 	smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cfm), &cfm);
 
@@ -1511,12 +1483,11 @@ static u8 sc_passkey_round(struct smp_chan *smp, u8 smp_op)
 	switch (smp_op) {
 	case SMP_CMD_PAIRING_RANDOM:
 		r = ((hcon->passkey_notify >> smp->passkey_round) & 0x01);
 		r |= 0x80;
 
-		if (smp_f4(smp->tfm_cmac, smp->remote_pk, smp->local_pk,
-			   smp->rrnd, r, cfm))
+		if (smp_f4(smp->remote_pk, smp->local_pk, smp->rrnd, r, cfm))
 			return SMP_UNSPECIFIED;
 
 		if (crypto_memneq(smp->pcnf, cfm, 16))
 			return SMP_CONFIRM_FAILED;
 
@@ -2176,12 +2147,11 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 		return sc_passkey_round(smp, SMP_CMD_PAIRING_RANDOM);
 
 	if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
 		u8 cfm[16];
 
-		err = smp_f4(smp->tfm_cmac, smp->remote_pk, smp->local_pk,
-			     smp->rrnd, 0, cfm);
+		err = smp_f4(smp->remote_pk, smp->local_pk, smp->rrnd, 0, cfm);
 		if (err)
 			return SMP_UNSPECIFIED;
 
 		if (crypto_memneq(smp->pcnf, cfm, 16))
 			return SMP_CONFIRM_FAILED;
@@ -2203,11 +2173,11 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 			SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
 		}
 		return 0;
 	}
 
-	err = smp_g2(smp->tfm_cmac, pkax, pkbx, na, nb, &passkey);
+	err = smp_g2(pkax, pkbx, na, nb, &passkey);
 	if (err)
 		return SMP_UNSPECIFIED;
 
 	/* Always require user confirmation for Just-Works pairing to prevent
 	 * impersonation attacks, or in case of a legitimate device that is
@@ -2748,12 +2718,12 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
 	}
 
 	memcpy(smp->remote_pk, key, 64);
 
 	if (test_bit(SMP_FLAG_REMOTE_OOB, &smp->flags)) {
-		err = smp_f4(smp->tfm_cmac, smp->remote_pk, smp->remote_pk,
-			     smp->rr, 0, cfm.confirm_val);
+		err = smp_f4(smp->remote_pk, smp->remote_pk, smp->rr, 0,
+			     cfm.confirm_val);
 		if (err)
 			return SMP_UNSPECIFIED;
 
 		if (crypto_memneq(cfm.confirm_val, smp->pcnf, 16))
 			return SMP_CONFIRM_FAILED;
@@ -2849,12 +2819,12 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
 	 * send the confirm value.
 	 */
 	if (test_bit(SMP_FLAG_INITIATOR, &smp->flags))
 		return 0;
 
-	err = smp_f4(smp->tfm_cmac, smp->local_pk, smp->remote_pk, smp->prnd,
-		     0, cfm.confirm_val);
+	err = smp_f4(smp->local_pk, smp->remote_pk, smp->prnd, 0,
+		     cfm.confirm_val);
 	if (err)
 		return SMP_UNSPECIFIED;
 
 	smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cfm), &cfm);
 	SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM);
@@ -2897,12 +2867,12 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)
 	if (smp->method == REQ_PASSKEY || smp->method == DSP_PASSKEY)
 		put_unaligned_le32(hcon->passkey_notify, r);
 	else if (smp->method == REQ_OOB)
 		memcpy(r, smp->lr, 16);
 
-	err = smp_f6(smp->tfm_cmac, smp->mackey, smp->rrnd, smp->prnd, r,
-		     io_cap, remote_addr, local_addr, e);
+	err = smp_f6(smp->mackey, smp->rrnd, smp->prnd, r, io_cap, remote_addr,
+		     local_addr, e);
 	if (err)
 		return SMP_UNSPECIFIED;
 
 	if (crypto_memneq(check->e, e, 16))
 		return SMP_DHKEY_CHECK_FAILED;
@@ -3284,11 +3254,10 @@ static const struct l2cap_ops smp_root_chan_ops = {
 
 static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
 {
 	struct l2cap_chan *chan;
 	struct smp_dev *smp;
-	struct crypto_shash *tfm_cmac;
 	struct crypto_kpp *tfm_ecdh;
 
 	if (cid == L2CAP_CID_SMP_BREDR) {
 		smp = NULL;
 		goto create_chan;
@@ -3296,34 +3265,24 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
 
 	smp = kzalloc_obj(*smp);
 	if (!smp)
 		return ERR_PTR(-ENOMEM);
 
-	tfm_cmac = crypto_alloc_shash("cmac(aes)", 0, 0);
-	if (IS_ERR(tfm_cmac)) {
-		bt_dev_err(hdev, "Unable to create CMAC crypto context");
-		kfree_sensitive(smp);
-		return ERR_CAST(tfm_cmac);
-	}
-
 	tfm_ecdh = crypto_alloc_kpp("ecdh-nist-p256", 0, 0);
 	if (IS_ERR(tfm_ecdh)) {
 		bt_dev_err(hdev, "Unable to create ECDH crypto context");
-		crypto_free_shash(tfm_cmac);
 		kfree_sensitive(smp);
 		return ERR_CAST(tfm_ecdh);
 	}
 
 	smp->local_oob = false;
-	smp->tfm_cmac = tfm_cmac;
 	smp->tfm_ecdh = tfm_ecdh;
 
 create_chan:
 	chan = l2cap_chan_create();
 	if (!chan) {
 		if (smp) {
-			crypto_free_shash(smp->tfm_cmac);
 			crypto_free_kpp(smp->tfm_ecdh);
 			kfree_sensitive(smp);
 		}
 		return ERR_PTR(-ENOMEM);
 	}
@@ -3366,11 +3325,10 @@ static void smp_del_chan(struct l2cap_chan *chan)
 	BT_DBG("chan %p", chan);
 
 	smp = chan->data;
 	if (smp) {
 		chan->data = NULL;
-		crypto_free_shash(smp->tfm_cmac);
 		crypto_free_kpp(smp->tfm_ecdh);
 		kfree_sensitive(smp);
 	}
 
 	l2cap_chan_put(chan);
@@ -3563,11 +3521,11 @@ static int __init test_s1(void)
 		return -EINVAL;
 
 	return 0;
 }
 
-static int __init test_f4(struct crypto_shash *tfm_cmac)
+static int __init test_f4(void)
 {
 	const u8 u[32] = {
 			0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc,
 			0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef,
 			0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e,
@@ -3585,21 +3543,21 @@ static int __init test_f4(struct crypto_shash *tfm_cmac)
 			0x2d, 0x87, 0x74, 0xa9, 0xbe, 0xa1, 0xed, 0xf1,
 			0x1c, 0xbd, 0xa9, 0x07, 0xf1, 0x16, 0xc9, 0xf2 };
 	u8 res[16];
 	int err;
 
-	err = smp_f4(tfm_cmac, u, v, x, z, res);
+	err = smp_f4(u, v, x, z, res);
 	if (err)
 		return err;
 
 	if (crypto_memneq(res, exp, 16))
 		return -EINVAL;
 
 	return 0;
 }
 
-static int __init test_f5(struct crypto_shash *tfm_cmac)
+static int __init test_f5(void)
 {
 	const u8 w[32] = {
 			0x98, 0xa6, 0xbf, 0x73, 0xf3, 0x34, 0x8d, 0x86,
 			0xf1, 0x66, 0xf8, 0xb4, 0x13, 0x6b, 0x79, 0x99,
 			0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34,
@@ -3619,11 +3577,11 @@ static int __init test_f5(struct crypto_shash *tfm_cmac)
 			0x20, 0x6e, 0x63, 0xce, 0x20, 0x6a, 0x3f, 0xfd,
 			0x02, 0x4a, 0x08, 0xa1, 0x76, 0xf1, 0x65, 0x29 };
 	u8 mackey[16], ltk[16];
 	int err;
 
-	err = smp_f5(tfm_cmac, w, n1, n2, a1, a2, mackey, ltk);
+	err = smp_f5(w, n1, n2, a1, a2, mackey, ltk);
 	if (err)
 		return err;
 
 	if (crypto_memneq(mackey, exp_mackey, 16))
 		return -EINVAL;
@@ -3632,11 +3590,11 @@ static int __init test_f5(struct crypto_shash *tfm_cmac)
 		return -EINVAL;
 
 	return 0;
 }
 
-static int __init test_f6(struct crypto_shash *tfm_cmac)
+static int __init test_f6(void)
 {
 	const u8 w[16] = {
 			0x20, 0x6e, 0x63, 0xce, 0x20, 0x6a, 0x3f, 0xfd,
 			0x02, 0x4a, 0x08, 0xa1, 0x76, 0xf1, 0x65, 0x29 };
 	const u8 n1[16] = {
@@ -3655,21 +3613,21 @@ static int __init test_f6(struct crypto_shash *tfm_cmac)
 			0x61, 0x8f, 0x95, 0xda, 0x09, 0x0b, 0x6c, 0xd2,
 			0xc5, 0xe8, 0xd0, 0x9c, 0x98, 0x73, 0xc4, 0xe3 };
 	u8 res[16];
 	int err;
 
-	err = smp_f6(tfm_cmac, w, n1, n2, r, io_cap, a1, a2, res);
+	err = smp_f6(w, n1, n2, r, io_cap, a1, a2, res);
 	if (err)
 		return err;
 
 	if (crypto_memneq(res, exp, 16))
 		return -EINVAL;
 
 	return 0;
 }
 
-static int __init test_g2(struct crypto_shash *tfm_cmac)
+static int __init test_g2(void)
 {
 	const u8 u[32] = {
 			0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc,
 			0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef,
 			0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e,
@@ -3687,21 +3645,21 @@ static int __init test_g2(struct crypto_shash *tfm_cmac)
 			0x6e, 0x5f, 0xa7, 0x25, 0xcc, 0xe7, 0xe8, 0xa6 };
 	const u32 exp_val = 0x2f9ed5ba % 1000000;
 	u32 val;
 	int err;
 
-	err = smp_g2(tfm_cmac, u, v, x, y, &val);
+	err = smp_g2(u, v, x, y, &val);
 	if (err)
 		return err;
 
 	if (val != exp_val)
 		return -EINVAL;
 
 	return 0;
 }
 
-static int __init test_h6(struct crypto_shash *tfm_cmac)
+static int __init test_h6(void)
 {
 	const u8 w[16] = {
 			0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34,
 			0x05, 0xad, 0xc8, 0x57, 0xa3, 0x34, 0x02, 0xec };
 	const u8 key_id[4] = { 0x72, 0x62, 0x65, 0x6c };
@@ -3709,11 +3667,11 @@ static int __init test_h6(struct crypto_shash *tfm_cmac)
 			0x99, 0x63, 0xb1, 0x80, 0xe2, 0xa9, 0xd3, 0xe8,
 			0x1c, 0xc9, 0x6d, 0xe7, 0x02, 0xe1, 0x9a, 0x2d };
 	u8 res[16];
 	int err;
 
-	err = smp_h6(tfm_cmac, w, key_id, res);
+	err = smp_h6(w, key_id, res);
 	if (err)
 		return err;
 
 	if (crypto_memneq(res, exp, 16))
 		return -EINVAL;
@@ -3734,12 +3692,11 @@ static const struct file_operations test_smp_fops = {
 	.open		= simple_open,
 	.read		= test_smp_read,
 	.llseek		= default_llseek,
 };
 
-static int __init run_selftests(struct crypto_shash *tfm_cmac,
-				struct crypto_kpp *tfm_ecdh)
+static int __init run_selftests(struct crypto_kpp *tfm_ecdh)
 {
 	ktime_t calltime, delta, rettime;
 	unsigned long long duration;
 	int err;
 
@@ -3767,35 +3724,35 @@ static int __init run_selftests(struct crypto_shash *tfm_cmac,
 	if (err) {
 		BT_ERR("smp_s1 test failed");
 		goto done;
 	}
 
-	err = test_f4(tfm_cmac);
+	err = test_f4();
 	if (err) {
 		BT_ERR("smp_f4 test failed");
 		goto done;
 	}
 
-	err = test_f5(tfm_cmac);
+	err = test_f5();
 	if (err) {
 		BT_ERR("smp_f5 test failed");
 		goto done;
 	}
 
-	err = test_f6(tfm_cmac);
+	err = test_f6();
 	if (err) {
 		BT_ERR("smp_f6 test failed");
 		goto done;
 	}
 
-	err = test_g2(tfm_cmac);
+	err = test_g2();
 	if (err) {
 		BT_ERR("smp_g2 test failed");
 		goto done;
 	}
 
-	err = test_h6(tfm_cmac);
+	err = test_h6();
 	if (err) {
 		BT_ERR("smp_h6 test failed");
 		goto done;
 	}
 
@@ -3818,30 +3775,21 @@ static int __init run_selftests(struct crypto_shash *tfm_cmac,
 	return err;
 }
 
 int __init bt_selftest_smp(void)
 {
-	struct crypto_shash *tfm_cmac;
 	struct crypto_kpp *tfm_ecdh;
 	int err;
 
-	tfm_cmac = crypto_alloc_shash("cmac(aes)", 0, 0);
-	if (IS_ERR(tfm_cmac)) {
-		BT_ERR("Unable to create CMAC crypto context");
-		return PTR_ERR(tfm_cmac);
-	}
-
 	tfm_ecdh = crypto_alloc_kpp("ecdh-nist-p256", 0, 0);
 	if (IS_ERR(tfm_ecdh)) {
 		BT_ERR("Unable to create ECDH crypto context");
-		crypto_free_shash(tfm_cmac);
 		return PTR_ERR(tfm_ecdh);
 	}
 
-	err = run_selftests(tfm_cmac, tfm_ecdh);
+	err = run_selftests(tfm_ecdh);
 
-	crypto_free_shash(tfm_cmac);
 	crypto_free_kpp(tfm_ecdh);
 
 	return err;
 }
 
-- 
2.53.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox