* [PATCH v2 6/8] Bluetooth: hci_sync: Add NVMEM-backed BD address retrieval
From: Loic Poulain @ 2026-05-07 15:24 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
Russell King, Saravana Kannan
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Loic Poulain
In-Reply-To: <20260507-block-as-nvmem-v2-0-bf17edd5134e@oss.qualcomm.com>
Some devices store the Bluetooth BD address in non-volatile
memory, which can be accessed through the NVMEM framework.
Similar to Ethernet or WiFi MAC addresses, add support for
reading the BD address from a 'local-bd-address' NVMEM cell.
As with the device-tree provided BD address, add a quirk to
indicate whether a device or platform should attempt to read
the address from NVMEM when no valid in-chip address is present.
Also add a quirk to indicate if the address is stored in
big-endian byte order.
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
include/net/bluetooth/hci.h | 18 ++++++++++++++++++
net/bluetooth/hci_sync.c | 39 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 56 insertions(+), 1 deletion(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 572b1c620c5d653a1fe10b26c1b0ba33e8f4968f..7686466d1109253b0d75edeb5f6a99fb98ce4cc6 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -164,6 +164,24 @@ enum {
*/
HCI_QUIRK_BDADDR_PROPERTY_BROKEN,
+ /* When this quirk is set, the public Bluetooth address
+ * initially reported by HCI Read BD Address command
+ * is considered invalid. The public BD Address can be
+ * retrieved via a 'local-bd-address' NVMEM cell.
+ *
+ * This quirk can be set before hci_register_dev is called or
+ * during the hdev->setup vendor callback.
+ */
+ HCI_QUIRK_USE_BDADDR_NVMEM,
+
+ /* When this quirk is set, the Bluetooth Device Address provided by
+ * the 'local-bd-address' NVMEM is stored in big-endian order.
+ *
+ * This quirk can be set before hci_register_dev is called or
+ * during the hdev->setup vendor callback.
+ */
+ HCI_QUIRK_BDADDR_NVMEM_BE,
+
/* When this quirk is set, the duplicate filtering during
* scanning is based on Bluetooth devices addresses. To allow
* RSSI based updates, restart scanning if needed.
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index fd3aacdea512a37c22b9a2be90c89ddca4b4d99f..589ccdfa26c1281d6eb979370523fff0d7920302 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -7,6 +7,7 @@
*/
#include <linux/property.h>
+#include <linux/of_net.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -3588,6 +3589,37 @@ int hci_powered_update_sync(struct hci_dev *hdev)
return 0;
}
+/**
+ * hci_dev_get_bd_addr_from_nvmem - Get the Bluetooth Device Address
+ * (BD_ADDR) for a HCI device from
+ * an NVMEM cell.
+ * @hdev: The HCI device
+ *
+ * Search for 'local-bd-address' NVMEM cell in the device firmware node.
+ *
+ * All-zero BD addresses are rejected (unprovisioned).
+ */
+static int hci_dev_get_bd_addr_from_nvmem(struct hci_dev *hdev)
+{
+ struct device_node *np = dev_of_node(hdev->dev.parent);
+ u8 ba[sizeof(bdaddr_t)];
+ int err;
+
+ if (!np)
+ return -ENODEV;
+
+ err = of_get_nvmem_eui48(np, "local-bd-address", ba);
+ if (err)
+ return err;
+
+ if (hci_test_quirk(hdev, HCI_QUIRK_BDADDR_NVMEM_BE))
+ baswap(&hdev->public_addr, (bdaddr_t *)ba);
+ else
+ bacpy(&hdev->public_addr, (bdaddr_t *)ba);
+
+ return 0;
+}
+
/**
* hci_dev_get_bd_addr_from_property - Get the Bluetooth Device Address
* (BD_ADDR) for a HCI device from
@@ -5042,12 +5074,17 @@ static int hci_dev_setup_sync(struct hci_dev *hdev)
* its setup callback.
*/
invalid_bdaddr = hci_test_quirk(hdev, HCI_QUIRK_INVALID_BDADDR) ||
- hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_PROPERTY);
+ hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_PROPERTY) ||
+ hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_NVMEM);
if (!ret) {
if (hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_PROPERTY) &&
!bacmp(&hdev->public_addr, BDADDR_ANY))
hci_dev_get_bd_addr_from_property(hdev);
+ if (hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_NVMEM) &&
+ !bacmp(&hdev->public_addr, BDADDR_ANY))
+ hci_dev_get_bd_addr_from_nvmem(hdev);
+
if (invalid_bdaddr && bacmp(&hdev->public_addr, BDADDR_ANY) &&
hdev->set_bdaddr) {
ret = hdev->set_bdaddr(hdev, &hdev->public_addr);
--
2.34.1
^ permalink raw reply related
* [PATCH v2 7/8] Bluetooth: qca: Set NVMEM BD address quirks when address is invalid
From: Loic Poulain @ 2026-05-07 15:24 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
Russell King, Saravana Kannan
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Loic Poulain
In-Reply-To: <20260507-block-as-nvmem-v2-0-bf17edd5134e@oss.qualcomm.com>
When the controller BD address is invalid (zero or default),
set the NVMEM quirks to allow retrieving the address from a
'local-bd-address' NVMEM cell. The BD address is often stored
alongside the WiFi MAC address in big-endian format, so also
set the big-endian quirk.
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
drivers/bluetooth/btqca.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index dda76365726f0bfe0e80e05fe04859fa4f0592e1..df33eacfd29fa680f393f90215150743e6001d5b 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -721,8 +721,11 @@ static int qca_check_bdaddr(struct hci_dev *hdev, const struct qca_fw_config *co
}
bda = (struct hci_rp_read_bd_addr *)skb->data;
- if (!bacmp(&bda->bdaddr, &config->bdaddr))
+ if (!bacmp(&bda->bdaddr, &config->bdaddr)) {
hci_set_quirk(hdev, HCI_QUIRK_USE_BDADDR_PROPERTY);
+ hci_set_quirk(hdev, HCI_QUIRK_USE_BDADDR_NVMEM);
+ hci_set_quirk(hdev, HCI_QUIRK_BDADDR_NVMEM_BE);
+ }
kfree_skb(skb);
--
2.34.1
^ permalink raw reply related
* [PATCH v2 8/8] arm64: dts: qcom: arduino-imola: Describe NVMEM layout for WiFi/BT addresses
From: Loic Poulain @ 2026-05-07 15:24 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
Russell King, Saravana Kannan
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Loic Poulain, Konrad Dybcio
In-Reply-To: <20260507-block-as-nvmem-v2-0-bf17edd5134e@oss.qualcomm.com>
On Arduino Uno-Q, the eMMC boot1 partition is factory provisioned
with device-specific information such as the WiFi MAC address
and the Bluetooth BD address. This partition can serve as an
alternative to additional non-volatile memory, such as a
dedicated EEPROM.
The eMMC boot partitions are typically good candidates, as they
are relatively small, read-only by default (and can be enforced
as hardware read-only), and are not affected by board reflashing
procedures, which generally target the eMMC user or GP partitions.
Describe the corresponding nvmem-layout for the WiFi and Bluetooth
addresses, and point the WiFi and Bluetooth nodes to the appropriate
NVMEM cells to retrieve them.
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts | 34 ++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts b/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts
index bf088fa9807f040f0c8f405f9111b01790b09377..6ed91cccae2fbf0723629a4db12d2724312d50b2 100644
--- a/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts
+++ b/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts
@@ -409,7 +409,35 @@ &sdhc_1 {
no-sdio;
no-sd;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
status = "okay";
+
+ card@0 {
+ compatible = "mmc-card";
+ reg = <0>;
+
+ partitions-boot1 {
+ nvmem-layout {
+ compatible = "fixed-layout";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ wifi_mac_addr: mac-addr@4400 {
+ compatible = "mac-base";
+ reg = <0x4400 0x6>;
+ #nvmem-cell-cells = <1>;
+ };
+
+ bd_addr: bd-addr@5400 {
+ compatible = "mac-base";
+ reg = <0x5400 0x6>;
+ #nvmem-cell-cells = <1>;
+ };
+ };
+ };
+ };
};
&spi5 {
@@ -512,6 +540,9 @@ bluetooth {
vddch0-supply = <&pm4125_l22>;
enable-gpios = <&tlmm 87 GPIO_ACTIVE_HIGH>;
max-speed = <3000000>;
+
+ nvmem-cells = <&bd_addr 0>;
+ nvmem-cell-names = "local-bd-address";
};
};
@@ -557,6 +588,9 @@ &wifi {
qcom,ath10k-calibration-variant = "ArduinoImola";
firmware-name = "qcm2290";
+ nvmem-cells = <&wifi_mac_addr 0>;
+ nvmem-cell-names = "mac-address";
+
status = "okay";
};
--
2.34.1
^ permalink raw reply related
* [PATCH v2 1/9] power: sequencing: pcie-m2: Fix inconsistent function prefixes
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-07 16:06 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: <20260507-pwrseq-m2-bt-v2-0-1740bd478539@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 ef69ae268059..b2ed336fd5ad 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -177,7 +177,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;
@@ -254,7 +254,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;
@@ -299,7 +299,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);
@@ -364,7 +364,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 v2 2/9] power: sequencing: pcie-m2: Allow creating serdev for multiple PCI devices
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-07 16:06 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: <20260507-pwrseq-m2-bt-v2-0-1740bd478539@oss.qualcomm.com>
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Current code makes it possible to create serdev for only one PCI device.
But for scaling this driver, it is necessary to allow creating serdev for
multiple PCI devices.
Hence, add provision for it by creating 'struct pwrseq_pci_dev' for each
PCI device that requires serdev and add them to
'pwrseq_pcie_m2_ctx::pci_devices' list.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
drivers/power/sequencing/pwrseq-pcie-m2.c | 127 +++++++++++++++++++++---------
1 file changed, 88 insertions(+), 39 deletions(-)
diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index b2ed336fd5ad..469e130330fa 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -7,6 +7,7 @@
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
+#include <linux/list.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -19,6 +20,13 @@
#include <linux/serdev.h>
#include <linux/slab.h>
+struct pwrseq_pci_dev {
+ struct serdev_device *serdev;
+ struct of_changeset *ocs;
+ struct pci_dev *pdev;
+ struct list_head list;
+};
+
struct pwrseq_pcie_m2_pdata {
const struct pwrseq_target_data **targets;
};
@@ -32,9 +40,9 @@ struct pwrseq_pcie_m2_ctx {
struct notifier_block nb;
struct gpio_desc *w_disable1_gpio;
struct gpio_desc *w_disable2_gpio;
- struct serdev_device *serdev;
- struct of_changeset *ocs;
struct device *dev;
+ struct list_head pci_devices;
+ struct mutex list_lock;
};
static int pwrseq_pcie_m2_vregs_enable(struct pwrseq_device *pwrseq)
@@ -178,38 +186,39 @@ static int pwrseq_pcie_m2_match(struct pwrseq_device *pwrseq,
}
static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
+ struct pwrseq_pci_dev *pci_dev,
struct device_node *parent)
{
struct device *dev = ctx->dev;
struct device_node *np;
int ret;
- ctx->ocs = kzalloc_obj(*ctx->ocs);
- if (!ctx->ocs)
+ pci_dev->ocs = kzalloc_obj(*pci_dev->ocs);
+ if (!pci_dev->ocs)
return -ENOMEM;
- of_changeset_init(ctx->ocs);
+ of_changeset_init(pci_dev->ocs);
- np = of_changeset_create_node(ctx->ocs, parent, "bluetooth");
+ np = of_changeset_create_node(pci_dev->ocs, parent, "bluetooth");
if (!np) {
dev_err(dev, "Failed to create bluetooth node\n");
ret = -ENODEV;
goto err_destroy_changeset;
}
- ret = of_changeset_add_prop_string(ctx->ocs, np, "compatible", "qcom,wcn7850-bt");
+ ret = of_changeset_add_prop_string(pci_dev->ocs, np, "compatible", "qcom,wcn7850-bt");
if (ret) {
dev_err(dev, "Failed to add bluetooth compatible: %d\n", ret);
goto err_destroy_changeset;
}
- ret = of_changeset_apply(ctx->ocs);
+ ret = of_changeset_apply(pci_dev->ocs);
if (ret) {
dev_err(dev, "Failed to apply changeset: %d\n", ret);
goto err_destroy_changeset;
}
- ret = device_add_of_node(&ctx->serdev->dev, np);
+ ret = device_add_of_node(&pci_dev->serdev->dev, np);
if (ret) {
dev_err(dev, "Failed to add OF node: %d\n", ret);
goto err_revert_changeset;
@@ -218,19 +227,21 @@ static int pwrseq_pcie_m2_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx,
return 0;
err_revert_changeset:
- of_changeset_revert(ctx->ocs);
+ of_changeset_revert(pci_dev->ocs);
err_destroy_changeset:
- of_changeset_destroy(ctx->ocs);
- kfree(ctx->ocs);
- ctx->ocs = NULL;
+ of_changeset_destroy(pci_dev->ocs);
+ kfree(pci_dev->ocs);
+ pci_dev->ocs = NULL;
return ret;
}
-static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
+static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx,
+ struct pci_dev *pdev)
{
struct serdev_controller *serdev_ctrl;
struct device *dev = ctx->dev;
+ struct pwrseq_pci_dev *pci_dev;
int ret;
struct device_node *serdev_parent __free(device_node) =
@@ -248,17 +259,23 @@ static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
return 0;
}
- ctx->serdev = serdev_device_alloc(serdev_ctrl);
- if (!ctx->serdev) {
+ pci_dev = kzalloc(sizeof(*pci_dev), GFP_KERNEL);
+ if (!pci_dev) {
ret = -ENOMEM;
goto err_put_ctrl;
}
- ret = pwrseq_pcie_m2_create_bt_node(ctx, serdev_parent);
+ pci_dev->serdev = serdev_device_alloc(serdev_ctrl);
+ if (!pci_dev->serdev) {
+ ret = -ENOMEM;
+ goto err_free_pci_dev;
+ }
+
+ ret = pwrseq_pcie_m2_create_bt_node(ctx, pci_dev, serdev_parent);
if (ret)
goto err_free_serdev;
- ret = serdev_device_add(ctx->serdev);
+ ret = serdev_device_add(pci_dev->serdev);
if (ret) {
dev_err(dev, "Failed to add serdev for WCN7850: %d\n", ret);
goto err_free_dt_node;
@@ -266,37 +283,64 @@ static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
serdev_controller_put(serdev_ctrl);
+ pci_dev->pdev = pci_dev_get(pdev);
+
+ mutex_lock(&ctx->list_lock);
+ list_add_tail(&pci_dev->list, &ctx->pci_devices);
+ mutex_unlock(&ctx->list_lock);
+
return 0;
err_free_dt_node:
- device_remove_of_node(&ctx->serdev->dev);
- of_changeset_revert(ctx->ocs);
- of_changeset_destroy(ctx->ocs);
- kfree(ctx->ocs);
- ctx->ocs = NULL;
+ device_remove_of_node(&pci_dev->serdev->dev);
+ of_changeset_revert(pci_dev->ocs);
+ of_changeset_destroy(pci_dev->ocs);
+ kfree(pci_dev->ocs);
+ pci_dev->ocs = NULL;
err_free_serdev:
- serdev_device_put(ctx->serdev);
- ctx->serdev = NULL;
+ serdev_device_put(pci_dev->serdev);
+ pci_dev->serdev = NULL;
+err_free_pci_dev:
+ kfree(pci_dev);
err_put_ctrl:
serdev_controller_put(serdev_ctrl);
return ret;
}
-static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx)
+static void __pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx,
+ struct pwrseq_pci_dev *pci_dev)
{
- if (ctx->serdev) {
- device_remove_of_node(&ctx->serdev->dev);
- serdev_device_remove(ctx->serdev);
- ctx->serdev = NULL;
+ if (pci_dev->serdev) {
+ device_remove_of_node(&pci_dev->serdev->dev);
+ serdev_device_remove(pci_dev->serdev);
}
- if (ctx->ocs) {
- of_changeset_revert(ctx->ocs);
- of_changeset_destroy(ctx->ocs);
- kfree(ctx->ocs);
- ctx->ocs = NULL;
+ if (pci_dev->ocs) {
+ of_changeset_revert(pci_dev->ocs);
+ of_changeset_destroy(pci_dev->ocs);
+ kfree(pci_dev->ocs);
}
+
+ pci_dev_put(pci_dev->pdev);
+ list_del(&pci_dev->list);
+ kfree(pci_dev);
+}
+
+static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx,
+ struct pci_dev *pdev)
+{
+ struct pwrseq_pci_dev *pci_dev, *tmp;
+
+ mutex_lock(&ctx->list_lock);
+ list_for_each_entry_safe(pci_dev, tmp, &ctx->pci_devices, list) {
+ if (!pdev || pci_dev->pdev == pdev) {
+ __pwrseq_pcie_m2_remove_serdev(ctx, pci_dev);
+ if (pdev)
+ break;
+ }
+ }
+ mutex_unlock(&ctx->list_lock);
}
static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action,
@@ -320,7 +364,7 @@ static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action
case BUS_NOTIFY_ADD_DEVICE:
/* Create serdev device for WCN7850 */
if (pdev->vendor == PCI_VENDOR_ID_QCOM && pdev->device == 0x1107) {
- ret = pwrseq_pcie_m2_create_serdev(ctx);
+ ret = pwrseq_pcie_m2_create_serdev(ctx, pdev);
if (ret)
return notifier_from_errno(ret);
}
@@ -328,7 +372,7 @@ static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action
case BUS_NOTIFY_REMOVED_DEVICE:
/* Destroy serdev device for WCN7850 */
if (pdev->vendor == PCI_VENDOR_ID_QCOM && pdev->device == 0x1107)
- pwrseq_pcie_m2_remove_serdev(ctx);
+ pwrseq_pcie_m2_remove_serdev(ctx, pdev);
break;
}
@@ -432,16 +476,20 @@ static int pwrseq_pcie_m2_probe(struct platform_device *pdev)
goto err_free_regulators;
}
+ mutex_init(&ctx->list_lock);
+ INIT_LIST_HEAD(&ctx->pci_devices);
/*
* Register a notifier for creating protocol devices for
* non-discoverable busses like UART.
*/
ret = pwrseq_pcie_m2_register_notifier(ctx, dev);
if (ret)
- goto err_free_regulators;
+ goto err_destroy_mutex;
return 0;
+err_destroy_mutex:
+ mutex_destroy(&ctx->list_lock);
err_free_regulators:
regulator_bulk_free(ctx->num_vregs, ctx->regs);
@@ -453,7 +501,8 @@ static void pwrseq_pcie_m2_remove(struct platform_device *pdev)
struct pwrseq_pcie_m2_ctx *ctx = platform_get_drvdata(pdev);
bus_unregister_notifier(&pci_bus_type, &ctx->nb);
- pwrseq_pcie_m2_remove_serdev(ctx);
+ pwrseq_pcie_m2_remove_serdev(ctx, NULL);
+ mutex_destroy(&ctx->list_lock);
regulator_bulk_free(ctx->num_vregs, ctx->regs);
}
--
2.51.0
^ permalink raw reply related
* [PATCH v2 0/9] Fixes/improvements for the PCI M.2 power sequencing driver
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-07 16:06 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,
Konrad Dybcio, Bartosz Golaszewski, Dmitry Baryshkov
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>
---
Changes in v2:
- Dropped the pwrseq_is_fixed() change in favor or exporting pwrseq device's dev
pointer and using it to check for the presence of W_DISABLE2# property
- Dropped the BT_EN fix for the Qcom WCN devices since it will be handled
separately
- Collected tags
- Link to v1: https://patch.msgid.link/20260422-pwrseq-m2-bt-v1-0-720d02545a64@oss.qualcomm.com
---
Manivannan Sadhasivam (9):
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'
power: sequencing: Add an API to return the pwrseq device's 'dev' pointer
Bluetooth: hci_qca: Set 'bt_en_available' based on W_DISABLE2# presence in M.2 connector
drivers/bluetooth/hci_qca.c | 28 +++-
drivers/power/sequencing/core.c | 9 ++
drivers/power/sequencing/pwrseq-pcie-m2.c | 234 ++++++++++++++++++++++--------
include/linux/pwrseq/consumer.h | 7 +
4 files changed, 217 insertions(+), 61 deletions(-)
---
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
change-id: 20260422-pwrseq-m2-bt-abdaa71094eb
Best regards,
--
Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
^ permalink raw reply
* [PATCH v2 3/9] power: sequencing: pcie-m2: Improve PCI device ID check
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-07 16:06 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,
Konrad Dybcio
In-Reply-To: <20260507-pwrseq-m2-bt-v2-0-1740bd478539@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.
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
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 469e130330fa..038271207a27 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -343,6 +343,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)
{
@@ -362,16 +367,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 v2 4/9] power: sequencing: pcie-m2: Create serdev for PCI devices present before probe
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-07 16:06 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: <20260507-pwrseq-m2-bt-v2-0-1740bd478539@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 038271207a27..0a37a375a89d 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -236,7 +236,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;
@@ -259,6 +259,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;
@@ -368,7 +378,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);
}
@@ -400,7 +410,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;
@@ -408,18 +418,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)
@@ -481,16 +529,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 v2 5/9] power: sequencing: pcie-m2: Create BT node based on the pci_device_id[] table
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-07 16:06 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: <20260507-pwrseq-m2-bt-v2-0-1740bd478539@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 0a37a375a89d..efeb25ba9c79 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -185,14 +185,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;
@@ -206,7 +221,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;
@@ -281,13 +296,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;
}
@@ -353,11 +369,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 v2 7/9] Bluetooth: hci_qca: Rename 'power_ctrl_enabled' to 'bt_en_available'
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-07 16:06 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,
Dmitry Baryshkov
In-Reply-To: <20260507-pwrseq-m2-bt-v2-0-1740bd478539@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.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
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 v2 8/9] power: sequencing: Add an API to return the pwrseq device's 'dev' pointer
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-07 16:06 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: <20260507-pwrseq-m2-bt-v2-0-1740bd478539@oss.qualcomm.com>
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
The consumer drivers can make use of the pwrseq device's 'dev' pointer to
query the pwrseq provider's DT node to check for existence of specific
properties.
Hence, add an API to return the pwrseq device's 'dev' pointer to consumers.
Note that since pwrseq_get() would've increased the pwrseq refcount, there
is no need to increase the refcount in this API again.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
drivers/power/sequencing/core.c | 9 +++++++++
include/linux/pwrseq/consumer.h | 7 +++++++
2 files changed, 16 insertions(+)
diff --git a/drivers/power/sequencing/core.c b/drivers/power/sequencing/core.c
index 4dff71be11b6..96ad557297f5 100644
--- a/drivers/power/sequencing/core.c
+++ b/drivers/power/sequencing/core.c
@@ -965,6 +965,15 @@ int pwrseq_power_off(struct pwrseq_desc *desc)
}
EXPORT_SYMBOL_GPL(pwrseq_power_off);
+struct device *pwrseq_to_device(struct pwrseq_desc *desc)
+{
+ if (!desc)
+ return NULL;
+
+ return &desc->pwrseq->dev;
+}
+EXPORT_SYMBOL_GPL(pwrseq_to_device);
+
#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..3c907c9e1885 100644
--- a/include/linux/pwrseq/consumer.h
+++ b/include/linux/pwrseq/consumer.h
@@ -23,6 +23,8 @@ 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);
+struct device *pwrseq_to_device(struct pwrseq_desc *desc);
+
#else /* CONFIG_POWER_SEQUENCING */
static inline struct pwrseq_desc * __must_check
@@ -51,6 +53,11 @@ static inline int pwrseq_power_off(struct pwrseq_desc *desc)
return -ENOSYS;
}
+static inline struct device *pwrseq_to_device(struct pwrseq_desc *desc)
+{
+ return NULL;
+}
+
#endif /* CONFIG_POWER_SEQUENCING */
#endif /* __POWER_SEQUENCING_CONSUMER_H__ */
--
2.51.0
^ permalink raw reply related
* [PATCH v2 6/9] Bluetooth: hci_qca: Add M.2 Bluetooth device support using pwrseq
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-07 16:06 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, Dmitry Baryshkov
In-Reply-To: <20260507-pwrseq-m2-bt-v2-0-1740bd478539@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>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@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 v2 9/9] Bluetooth: hci_qca: Set 'bt_en_available' based on W_DISABLE2# presence in M.2 connector
From: Manivannan Sadhasivam via B4 Relay @ 2026-05-07 16:06 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: <20260507-pwrseq-m2-bt-v2-0-1740bd478539@oss.qualcomm.com>
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Check if the M.2 connector supports the W_DISABLE2# property or not by
querying the pwrseq provider's DT node. If not available, then set
'bt_en_available' flag to 'false'. This flag is used to set the
HCI_QUIRK_NON_PERSISTENT_SETUP HCI quirk, which informs the HCI layer
whether the shutdown() callback for the device can be triggered or not.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
drivers/bluetooth/hci_qca.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 3e71a72ea7c7..b5439b9956cf 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -2449,10 +2449,17 @@ static int qca_serdev_probe(struct serdev_device *serdev)
* the M.2 Key E connector.
*/
if (of_graph_is_present(dev_of_node(&serdev->ctrl->dev))) {
+ struct device *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);
+
+ dev = pwrseq_to_device(qcadev->bt_power->pwrseq);
+ if (!device_property_present(dev, "w-disable2-gpios"))
+ bt_en_available = false;
+
break;
}
--
2.51.0
^ permalink raw reply related
* Re: [PATCH 12/12] Bluetooth: hci_qca: Fix the broken BT_EN GPIO detection for Qcom WCN devices
From: Manivannan Sadhasivam @ 2026-05-07 16:10 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: manivannan.sadhasivam, Marcel Holtmann, Luiz Augusto von Dentz,
Shuai Zhang, linux-pm, linux-kernel, linux-pci, linux-arm-msm,
linux-bluetooth, Wei Deng, Luiz Augusto von Dentz,
stable+noautosel, Dmitry Baryshkov
In-Reply-To: <CAMRc=MdvhMBpunaitGv7yv3sTqkTYviaeAJzphTS5dBUOFPpHw@mail.gmail.com>
On Thu, May 07, 2026 at 09:55:16AM -0500, Bartosz Golaszewski wrote:
> On Thu, May 7, 2026 at 1:59 PM Manivannan Sadhasivam <mani@kernel.org> wrote:
> > >
> > > This will break the case of WCN399x devices without the PMU in device
> > > tree. There is no enable-gpios since BT is not controllable, but if
> > > there is no PMU, then devm_pwrseq_get() will always return
> > > -EPROBE_DEFER.
> > >
> >
> > Hmm. I missed that the pwrseq returns -EPROBE_DEFER even if the client doesn't
> > require power sequencing. It is because, it has no way to figure it out.
> >
> > But I think the client can parse the regulator phandle, reach the regulator
> > parent, then check for the '-pmu' suffix in the compatible to make sure that it
> > has the power sequencing requirement. Then it can call devm_pwrseq_get() only if
> > that check passes.
> >
>
> I'm wondering if we could maybe provide pwrseq_get_optional() that would only
> really be optional with fw_devlink enabled (where we'd be able to ensure the
> provider is probed before the consumer thus be able to tell right away if the
> device is power-sequenced or not) while with fw_devlink disabled, it would
> just behave like pwrseq_get() and return -EPROBE_DEFER?
>
But if fw_devlink is disabled, then the consumer drivers cannot rely on this API
to decide whether power sequencing is required or not. IOW, the error handling
would be broken in consumer drivers if fw_devlink is not enabled.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH BlueZ v1 1/3] tools/tester: Fix crash when hciemu_new fails
From: patchwork-bot+bluetooth @ 2026-05-07 16:10 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <20260506194150.1701855-1-luiz.dentz@gmail.com>
Hello:
This series was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Wed, 6 May 2026 15:41:48 -0400 you wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> When hciemu_new returns NULL, the mgmt object was not being unreferenced
> before returning from the pre-setup failure path. This could lead to a
> NULL dereference in read_info_callback when it later calls
> hciemu_get_address on the NULL hciemu pointer.
>
> [...]
Here is the summary with links:
- [BlueZ,v1,1/3] tools/tester: Fix crash when hciemu_new fails
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=acd0a49506a1
- [BlueZ,v1,2/3] emulator/hciemu: Add hciemu_new_debug/hciemu_new_num_debug
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=a068db99c46f
- [BlueZ,v1,3/3] tools/tester: Retry with debug on hciemu_new failure
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=e3dec62da2a5
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* RE: [v3,1/2] Bluetooth: HCI: Add initial support for Short Connection Interval feature
From: bluez.test.bot @ 2026-05-07 16:12 UTC (permalink / raw)
To: linux-bluetooth, luiz.dentz
In-Reply-To: <20260507151309.145613-1-luiz.dentz@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 18767 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=1091122
---Test result---
Test Summary:
CheckPatch FAIL 2.11 seconds
GitLint FAIL 0.43 seconds
SubjectPrefix PASS 0.17 seconds
BuildKernel PASS 19.87 seconds
CheckAllWarning PASS 22.02 seconds
CheckSparse PASS 21.33 seconds
BuildKernel32 PASS 19.78 seconds
TestRunnerSetup PASS 412.64 seconds
TestRunner_l2cap-tester FAIL 14.48 seconds
TestRunner_iso-tester PASS 304.01 seconds
TestRunner_bnep-tester FAIL 14.19 seconds
TestRunner_mgmt-tester FAIL 18.33 seconds
TestRunner_rfcomm-tester PASS 36.80 seconds
TestRunner_sco-tester PASS 75.93 seconds
TestRunner_ioctl-tester FAIL 43.57 seconds
TestRunner_mesh-tester PASS 34.73 seconds
TestRunner_smp-tester PASS 14.37 seconds
TestRunner_userchan-tester FAIL 14.40 seconds
TestRunner_6lowpan-tester PASS 30.69 seconds
IncrementalBuild PASS 35.27 seconds
Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[v3,1/2] Bluetooth: HCI: Add initial support for Short Connection Interval feature
WARNING: Possible unnecessary 'out of memory' message
#317: FILE: net/bluetooth/hci_event.c:3989:
+ if (!sgrp) {
+ bt_dev_err(hdev, "can't allocate memory for SCI group");
total: 0 errors, 1 warnings, 0 checks, 330 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/14559599.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: GitLint - FAIL
Desc: Run gitlint
Output:
[v3,1/2] Bluetooth: HCI: Add initial support for Short Connection Interval feature
WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
1: T1 Title exceeds max length (82>80): "[v3,1/2] Bluetooth: HCI: Add initial support for Short Connection Interval feature"
##############################
Test: TestRunner_l2cap-tester - FAIL
Desc: Run l2cap-tester with test-runner
Output:
Crash detected:
==34== by 0x13350F: tester_run (tester.c:1085)
==34== by 0x1142AD: main (l2cap-tester.c:3295)
==34== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==34==
==34==
==34== Process terminating with default action of signal 11 (SIGSEGV)
==34== Access not within mapped region at address 0x0
==34== at 0x483FF54: __strcmp_sse2 (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==34== by 0x115C46: read_info_callback (l2cap-tester.c:156)
==34== by 0x12E860: request_complete (mgmt.c:320)
==34== by 0x12F2F5: can_read_data (mgmt.c:408)
==34== by 0x131D68: watch_callback (io-glib.c:173)
==34== by 0x48A304D: g_main_context_dispatch (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A33FF: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A36F2: g_main_loop_run (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x133B18: mainloop_run (mainloop-glib.c:65)
==34== by 0x133F4F: mainloop_run_with_signal (mainloop-notify.c:196)
==34== by 0x13350F: tester_run (tester.c:1085)
==34== by 0x1142AD: main (l2cap-tester.c:3295)
==34== If you believe this happened as a result of a stack
==34== overflow in your program's main thread (unlikely but
==34== possible), you can try to increase the size of the
==34== main thread stack using the --main-stacksize= flag.
==34== The main thread stack size used in this run was 8388608.
==34==
Valgrind errors:
==34== by 0x115C46: read_info_callback (l2cap-tester.c:156)
==34== by 0x12E860: request_complete (mgmt.c:320)
==34== by 0x12F2F5: can_read_data (mgmt.c:408)
==34== by 0x131D68: watch_callback (io-glib.c:173)
==34== by 0x48A304D: g_main_context_dispatch (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A33FF: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A36F2: g_main_loop_run (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x133B18: mainloop_run (mainloop-glib.c:65)
==34== by 0x133F4F: mainloop_run_with_signal (mainloop-notify.c:196)
==34== by 0x13350F: tester_run (tester.c:1085)
==34== by 0x1142AD: main (l2cap-tester.c:3295)
==34== If you believe this happened as a result of a stack
==34== overflow in your program's main thread (unlikely but
==34== possible), you can try to increase the size of the
==34== main thread stack using the --main-stacksize= flag.
==34== The main thread stack size used in this run was 8388608.
==34==
==34== HEAP SUMMARY:
==34== in use at exit: 66,009 bytes in 462 blocks
==34== total heap usage: 592 allocs, 130 frees, 79,004 bytes allocated
==34==
==34== LEAK SUMMARY:
==34== definitely lost: 0 bytes in 0 blocks
==34== indirectly lost: 0 bytes in 0 blocks
==34== possibly lost: 0 bytes in 0 blocks
==34== still reachable: 66,009 bytes in 462 blocks
==34== suppressed: 0 bytes in 0 blocks
==34== Rerun with --leak-check=full to see details of leaked memory
==34==
==34== For lists of detected and suppressed errors, rerun with: -s
==34== ERROR SUMMARY: 51 errors from 3 contexts (suppressed: 0 from 0)
Crash detected:
==34== suppressed: 0 bytes in 0 blocks
==34== Rerun with --leak-check=full to see details of leaked memory
==34==
==34== For lists of detected and suppressed errors, rerun with: -s
==34== ERROR SUMMARY: 51 errors from 3 contexts (suppressed: 0 from 0)
Segmentation fault
Process 33 exited with status 139
reboot: Restarting system
reboot: machine restart
No test result found
##############################
Test: TestRunner_bnep-tester - FAIL
Desc: Run bnep-tester with test-runner
Output:
Crash detected:
==34== by 0x12CC4F: tester_run (tester.c:1085)
==34== by 0x111CB3: main (bnep-tester.c:298)
==34== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==34==
==34==
==34== Process terminating with default action of signal 11 (SIGSEGV)
==34== Access not within mapped region at address 0x0
==34== at 0x483FF54: __strcmp_sse2 (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==34== by 0x112206: read_info_callback (bnep-tester.c:101)
==34== by 0x1281B0: request_complete (mgmt.c:320)
==34== by 0x128B65: can_read_data (mgmt.c:408)
==34== by 0x12B5D8: watch_callback (io-glib.c:173)
==34== by 0x48A304D: g_main_context_dispatch (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A33FF: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A36F2: g_main_loop_run (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x12D258: mainloop_run (mainloop-glib.c:65)
==34== by 0x12D68F: mainloop_run_with_signal (mainloop-notify.c:196)
==34== by 0x12CC4F: tester_run (tester.c:1085)
==34== by 0x111CB3: main (bnep-tester.c:298)
==34== If you believe this happened as a result of a stack
==34== overflow in your program's main thread (unlikely but
==34== possible), you can try to increase the size of the
==34== main thread stack using the --main-stacksize= flag.
==34== The main thread stack size used in this run was 8388608.
==34==
Valgrind errors:
==34== by 0x112206: read_info_callback (bnep-tester.c:101)
==34== by 0x1281B0: request_complete (mgmt.c:320)
==34== by 0x128B65: can_read_data (mgmt.c:408)
==34== by 0x12B5D8: watch_callback (io-glib.c:173)
==34== by 0x48A304D: g_main_context_dispatch (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A33FF: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A36F2: g_main_loop_run (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x12D258: mainloop_run (mainloop-glib.c:65)
==34== by 0x12D68F: mainloop_run_with_signal (mainloop-notify.c:196)
==34== by 0x12CC4F: tester_run (tester.c:1085)
==34== by 0x111CB3: main (bnep-tester.c:298)
==34== If you believe this happened as a result of a stack
==34== overflow in your program's main thread (unlikely but
==34== possible), you can try to increase the size of the
==34== main thread stack using the --main-stacksize= flag.
==34== The main thread stack size used in this run was 8388608.
==34==
==34== HEAP SUMMARY:
==34== in use at exit: 25,264 bytes in 82 blocks
==34== total heap usage: 212 allocs, 130 frees, 38,256 bytes allocated
==34==
==34== LEAK SUMMARY:
==34== definitely lost: 0 bytes in 0 blocks
==34== indirectly lost: 0 bytes in 0 blocks
==34== possibly lost: 0 bytes in 0 blocks
==34== still reachable: 25,264 bytes in 82 blocks
==34== suppressed: 0 bytes in 0 blocks
==34== Rerun with --leak-check=full to see details of leaked memory
==34==
==34== For lists of detected and suppressed errors, rerun with: -s
==34== ERROR SUMMARY: 51 errors from 3 contexts (suppressed: 0 from 0)
Crash detected:
==34== suppressed: 0 bytes in 0 blocks
==34== Rerun with --leak-check=full to see details of leaked memory
==34==
==34== For lists of detected and suppressed errors, rerun with: -s
==34== ERROR SUMMARY: 51 errors from 3 contexts (suppressed: 0 from 0)
Segmentation fault
Process 33 exited with status 139
reboot: Restarting system
reboot: machine restart
No test result found
##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner
Output:
Crash detected:
==34== by 0x14F4FF: tester_run (tester.c:1085)
==34== by 0x12B999: main (mgmt-tester.c:15134)
==34== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==34==
==34==
==34== Process terminating with default action of signal 11 (SIGSEGV)
==34== Access not within mapped region at address 0x0
==34== at 0x483FF54: __strcmp_sse2 (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==34== by 0x12F8E8: read_info_callback (mgmt-tester.c:181)
==34== by 0x14A740: request_complete (mgmt.c:320)
==34== by 0x14B2F5: can_read_data (mgmt.c:408)
==34== by 0x14DD68: watch_callback (io-glib.c:173)
==34== by 0x48A304D: g_main_context_dispatch (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A33FF: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A36F2: g_main_loop_run (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x14FB08: mainloop_run (mainloop-glib.c:65)
==34== by 0x14FF3F: mainloop_run_with_signal (mainloop-notify.c:196)
==34== by 0x14F4FF: tester_run (tester.c:1085)
==34== by 0x12B999: main (mgmt-tester.c:15134)
==34== If you believe this happened as a result of a stack
==34== overflow in your program's main thread (unlikely but
==34== possible), you can try to increase the size of the
==34== main thread stack using the --main-stacksize= flag.
==34== The main thread stack size used in this run was 8388608.
==34==
Valgrind errors:
==34== by 0x12F8E8: read_info_callback (mgmt-tester.c:181)
==34== by 0x14A740: request_complete (mgmt.c:320)
==34== by 0x14B2F5: can_read_data (mgmt.c:408)
==34== by 0x14DD68: watch_callback (io-glib.c:173)
==34== by 0x48A304D: g_main_context_dispatch (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A33FF: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A36F2: g_main_loop_run (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x14FB08: mainloop_run (mainloop-glib.c:65)
==34== by 0x14FF3F: mainloop_run_with_signal (mainloop-notify.c:196)
==34== by 0x14F4FF: tester_run (tester.c:1085)
==34== by 0x12B999: main (mgmt-tester.c:15134)
==34== If you believe this happened as a result of a stack
==34== overflow in your program's main thread (unlikely but
==34== possible), you can try to increase the size of the
==34== main thread stack using the --main-stacksize= flag.
==34== The main thread stack size used in this run was 8388608.
==34==
==34== HEAP SUMMARY:
==34== in use at exit: 182,263 bytes in 2,112 blocks
==34== total heap usage: 2,389 allocs, 277 frees, 204,641 bytes allocated
==34==
==34== LEAK SUMMARY:
==34== definitely lost: 0 bytes in 0 blocks
==34== indirectly lost: 0 bytes in 0 blocks
==34== possibly lost: 0 bytes in 0 blocks
==34== still reachable: 182,263 bytes in 2,112 blocks
==34== suppressed: 0 bytes in 0 blocks
==34== Rerun with --leak-check=full to see details of leaked memory
==34==
==34== For lists of detected and suppressed errors, rerun with: -s
==34== ERROR SUMMARY: 51 errors from 3 contexts (suppressed: 0 from 0)
Crash detected:
==34== suppressed: 0 bytes in 0 blocks
==34== Rerun with --leak-check=full to see details of leaked memory
==34==
==34== For lists of detected and suppressed errors, rerun with: -s
==34== ERROR SUMMARY: 51 errors from 3 contexts (suppressed: 0 from 0)
Segmentation fault
Process 33 exited with status 139
reboot: Restarting system
reboot: machine restart
No test result found
##############################
Test: TestRunner_ioctl-tester - FAIL
Desc: Run ioctl-tester with test-runner
Output:
Total: 28, Passed: 0 (0.0%), Failed: 11, Not Run: 17
Failed Test Cases
Device List Timed out -29.495 seconds
Device Info Timed out -6.742 seconds
Reset Stat Timed out -6.747 seconds
Set Link Mode - ACCEPT Timed out -6.752 seconds
Set Pkt Type - DM Timed out -14.996 seconds
Set Pkt Type - DH Timed out -15.001 seconds
Set Pkt Type - HV Timed out -15.006 seconds
Set Pkt Type - 2-DH Timed out -15.012 seconds
Set Pkt Type - 2-DH Timed out -15.017 seconds
Set Pkt Type - ALL Timed out -15.022 seconds
Set ACL MTU - 1 Timed out -15.026 seconds
##############################
Test: TestRunner_userchan-tester - FAIL
Desc: Run userchan-tester with test-runner
Output:
Crash detected:
==33== by 0x12D77F: tester_run (tester.c:1085)
==33== by 0x111DFB: main (userchan-tester.c:392)
==33== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==33==
==33==
==33== Process terminating with default action of signal 11 (SIGSEGV)
==33== Access not within mapped region at address 0x0
==33== at 0x483FF54: __strcmp_sse2 (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==33== by 0x11250B: read_info_callback (userchan-tester.c:88)
==33== by 0x128450: request_complete (mgmt.c:320)
==33== by 0x128E95: can_read_data (mgmt.c:408)
==33== by 0x12C108: watch_callback (io-glib.c:173)
==33== by 0x48A304D: g_main_context_dispatch (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==33== by 0x48A33FF: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==33== by 0x48A36F2: g_main_loop_run (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==33== by 0x12DD88: mainloop_run (mainloop-glib.c:65)
==33== by 0x12E1BF: mainloop_run_with_signal (mainloop-notify.c:196)
==33== by 0x12D77F: tester_run (tester.c:1085)
==33== by 0x111DFB: main (userchan-tester.c:392)
==33== If you believe this happened as a result of a stack
==33== overflow in your program's main thread (unlikely but
==33== possible), you can try to increase the size of the
==33== main thread stack using the --main-stacksize= flag.
==33== The main thread stack size used in this run was 8388608.
==33==
Valgrind errors:
==33== by 0x11250B: read_info_callback (userchan-tester.c:88)
==33== by 0x128450: request_complete (mgmt.c:320)
==33== by 0x128E95: can_read_data (mgmt.c:408)
==33== by 0x12C108: watch_callback (io-glib.c:173)
==33== by 0x48A304D: g_main_context_dispatch (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==33== by 0x48A33FF: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==33== by 0x48A36F2: g_main_loop_run (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==33== by 0x12DD88: mainloop_run (mainloop-glib.c:65)
==33== by 0x12E1BF: mainloop_run_with_signal (mainloop-notify.c:196)
==33== by 0x12D77F: tester_run (tester.c:1085)
==33== by 0x111DFB: main (userchan-tester.c:392)
==33== If you believe this happened as a result of a stack
==33== overflow in your program's main thread (unlikely but
==33== possible), you can try to increase the size of the
==33== main thread stack using the --main-stacksize= flag.
==33== The main thread stack size used in this run was 8388608.
==33==
==33== HEAP SUMMARY:
==33== in use at exit: 26,001 bytes in 92 blocks
==33== total heap usage: 222 allocs, 130 frees, 38,997 bytes allocated
==33==
==33== LEAK SUMMARY:
==33== definitely lost: 0 bytes in 0 blocks
==33== indirectly lost: 0 bytes in 0 blocks
==33== possibly lost: 0 bytes in 0 blocks
==33== still reachable: 26,001 bytes in 92 blocks
==33== suppressed: 0 bytes in 0 blocks
==33== Rerun with --leak-check=full to see details of leaked memory
==33==
==33== For lists of detected and suppressed errors, rerun with: -s
==33== ERROR SUMMARY: 51 errors from 3 contexts (suppressed: 0 from 0)
Crash detected:
==33== suppressed: 0 bytes in 0 blocks
==33== Rerun with --leak-check=full to see details of leaked memory
==33==
==33== For lists of detected and suppressed errors, rerun with: -s
==33== ERROR SUMMARY: 51 errors from 3 contexts (suppressed: 0 from 0)
Segmentation fault
Process 32 exited with status 139
reboot: Restarting system
reboot: machine restart
No test result found
https://github.com/bluez/bluetooth-next/pull/151
---
Regards,
Linux Bluetooth
^ permalink raw reply
* [PATCH BlueZ] client/btpclient: Add BTP_EV_GAP_SEC_LEVEL_CHANGED support
From: Frédéric Danis @ 2026-05-07 16:16 UTC (permalink / raw)
To: linux-bluetooth
This allows reduces connection time for the BAP tests.
---
client/btpclient/gap.c | 22 ++++++++++++++++++++++
src/shared/btp.h | 11 +++++++++++
2 files changed, 33 insertions(+)
diff --git a/client/btpclient/gap.c b/client/btpclient/gap.c
index 68e029dcc..1a6c2c2f0 100644
--- a/client/btpclient/gap.c
+++ b/client/btpclient/gap.c
@@ -2538,6 +2538,21 @@ static void btp_gap_device_connection_ev(struct l_dbus_proxy *proxy,
}
}
+static void btp_security_changed_ev(struct l_dbus_proxy *proxy, bool paired)
+{
+ struct btp_device *dev = find_device_by_proxy(proxy);
+ struct btp_adapter *adapter = find_adapter_by_device(dev);
+ struct btp_gap_sec_level_changed_ev ev;
+
+ /* TODO: get real security level */
+ memcpy(&ev.address, &dev->address, sizeof(ev.address));
+ ev.address_type = dev->address_type;
+ ev.sec_level = BTP_GAP_SEC_LEVEL_AUTH_ENC;
+
+ btp_send(btp, BTP_GAP_SERVICE, BTP_EV_GAP_SEC_LEVEL_CHANGED,
+ adapter->index, sizeof(ev), &ev);
+}
+
static void btp_identity_resolved_ev(struct l_dbus_proxy *proxy)
{
struct btp_device *dev = find_device_by_proxy(proxy);
@@ -2709,6 +2724,13 @@ void gap_property_changed(struct l_dbus_proxy *proxy, const char *name,
*/
if (!prop)
btp_gap_device_connection_ev(proxy, prop);
+ } else if (!strcmp(name, "Paired")) {
+ bool prop;
+
+ if (!l_dbus_message_get_arguments(msg, "b", &prop))
+ return;
+
+ btp_security_changed_ev(proxy, prop);
} else if (!strcmp(name, "AddressType")) {
/* Address property change came first along with address
* type.
diff --git a/src/shared/btp.h b/src/shared/btp.h
index b99ad3a28..4d3c4ec6f 100644
--- a/src/shared/btp.h
+++ b/src/shared/btp.h
@@ -286,6 +286,17 @@ struct btp_gap_identity_resolved_ev {
bdaddr_t identity_address;
} __packed;
+#define BTP_GAP_SEC_LEVEL_UNAUTH_ENC 0x01
+#define BTP_GAP_SEC_LEVEL_AUTH_ENC 0x02
+#define BTP_GAP_SEC_LEVEL_AUTH_SC 0x03
+
+#define BTP_EV_GAP_SEC_LEVEL_CHANGED 0x89
+struct btp_gap_sec_level_changed_ev {
+ uint8_t address_type;
+ bdaddr_t address;
+ uint8_t sec_level;
+} __packed;
+
struct btp_gatt_service {
uint16_t start_handle;
uint16_t end_handle;
--
2.43.0
^ permalink raw reply related
* RE: Support for block device NVMEM providers
From: bluez.test.bot @ 2026-05-07 16:19 UTC (permalink / raw)
To: linux-bluetooth, loic.poulain
In-Reply-To: <20260507-block-as-nvmem-v2-1-bf17edd5134e@oss.qualcomm.com>
[-- Attachment #1: Type: text/plain, Size: 19481 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=1091131
---Test result---
Test Summary:
CheckPatch FAIL 6.79 seconds
GitLint FAIL 7.79 seconds
SubjectPrefix FAIL 0.88 seconds
BuildKernel PASS 26.57 seconds
CheckAllWarning PASS 29.41 seconds
CheckSparse PASS 28.88 seconds
BuildKernel32 PASS 26.60 seconds
TestRunnerSetup PASS 578.47 seconds
TestRunner_l2cap-tester FAIL 18.90 seconds
TestRunner_iso-tester PASS 311.40 seconds
TestRunner_bnep-tester FAIL 18.63 seconds
TestRunner_mgmt-tester FAIL 23.51 seconds
TestRunner_rfcomm-tester PASS 41.48 seconds
TestRunner_sco-tester PASS 80.61 seconds
TestRunner_ioctl-tester FAIL 50.25 seconds
TestRunner_mesh-tester PASS 39.48 seconds
TestRunner_smp-tester PASS 18.56 seconds
TestRunner_userchan-tester FAIL 18.58 seconds
TestRunner_6lowpan-tester PASS 35.03 seconds
IncrementalBuild PASS 54.54 seconds
Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[v2,4/8] block: implement NVMEM provider
WARNING: please write a help paragraph that fully describes the config symbol with at least 4 lines
#207: FILE: block/Kconfig:212:
+config BLK_NVMEM
+ bool "Block device NVMEM provider"
+ depends on OF
+ depends on NVMEM
+ help
+ Allow block devices (or partitions) to act as NVMEM providers,
+ typically used with eMMC to store MAC addresses or Wi-Fi
+ calibration data on embedded devices.
+
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#229:
new file mode 100644
total: 0 errors, 2 warnings, 244 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/14559647.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: GitLint - FAIL
Desc: Run gitlint
Output:
[v2,8/8] arm64: dts: qcom: arduino-imola: Describe NVMEM layout for WiFi/BT addresses
WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
1: T1 Title exceeds max length (85>80): "[v2,8/8] arm64: dts: qcom: arduino-imola: Describe NVMEM layout for WiFi/BT addresses"
##############################
Test: SubjectPrefix - FAIL
Desc: Check subject contains "Bluetooth" prefix
Output:
"Bluetooth: " prefix is not specified in the subject
"Bluetooth: " prefix is not specified in the subject
"Bluetooth: " prefix is not specified in the subject
"Bluetooth: " prefix is not specified in the subject
"Bluetooth: " prefix is not specified in the subject
"Bluetooth: " prefix is not specified in the subject
##############################
Test: TestRunner_l2cap-tester - FAIL
Desc: Run l2cap-tester with test-runner
Output:
Crash detected:
==34== by 0x13350F: tester_run (tester.c:1085)
==34== by 0x1142AD: main (l2cap-tester.c:3295)
==34== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==34==
==34==
==34== Process terminating with default action of signal 11 (SIGSEGV)
==34== Access not within mapped region at address 0x0
==34== at 0x483FF54: __strcmp_sse2 (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==34== by 0x115C46: read_info_callback (l2cap-tester.c:156)
==34== by 0x12E860: request_complete (mgmt.c:320)
==34== by 0x12F2F5: can_read_data (mgmt.c:408)
==34== by 0x131D68: watch_callback (io-glib.c:173)
==34== by 0x48A304D: g_main_context_dispatch (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A33FF: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A36F2: g_main_loop_run (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x133B18: mainloop_run (mainloop-glib.c:65)
==34== by 0x133F4F: mainloop_run_with_signal (mainloop-notify.c:196)
==34== by 0x13350F: tester_run (tester.c:1085)
==34== by 0x1142AD: main (l2cap-tester.c:3295)
==34== If you believe this happened as a result of a stack
==34== overflow in your program's main thread (unlikely but
==34== possible), you can try to increase the size of the
==34== main thread stack using the --main-stacksize= flag.
==34== The main thread stack size used in this run was 8388608.
==34==
Valgrind errors:
==34== by 0x115C46: read_info_callback (l2cap-tester.c:156)
==34== by 0x12E860: request_complete (mgmt.c:320)
==34== by 0x12F2F5: can_read_data (mgmt.c:408)
==34== by 0x131D68: watch_callback (io-glib.c:173)
==34== by 0x48A304D: g_main_context_dispatch (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A33FF: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A36F2: g_main_loop_run (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x133B18: mainloop_run (mainloop-glib.c:65)
==34== by 0x133F4F: mainloop_run_with_signal (mainloop-notify.c:196)
==34== by 0x13350F: tester_run (tester.c:1085)
==34== by 0x1142AD: main (l2cap-tester.c:3295)
==34== If you believe this happened as a result of a stack
==34== overflow in your program's main thread (unlikely but
==34== possible), you can try to increase the size of the
==34== main thread stack using the --main-stacksize= flag.
==34== The main thread stack size used in this run was 8388608.
==34==
==34== HEAP SUMMARY:
==34== in use at exit: 66,009 bytes in 462 blocks
==34== total heap usage: 592 allocs, 130 frees, 79,004 bytes allocated
==34==
==34== LEAK SUMMARY:
==34== definitely lost: 0 bytes in 0 blocks
==34== indirectly lost: 0 bytes in 0 blocks
==34== possibly lost: 0 bytes in 0 blocks
==34== still reachable: 66,009 bytes in 462 blocks
==34== suppressed: 0 bytes in 0 blocks
==34== Rerun with --leak-check=full to see details of leaked memory
==34==
==34== For lists of detected and suppressed errors, rerun with: -s
==34== ERROR SUMMARY: 51 errors from 3 contexts (suppressed: 0 from 0)
Crash detected:
==34== suppressed: 0 bytes in 0 blocks
==34== Rerun with --leak-check=full to see details of leaked memory
==34==
==34== For lists of detected and suppressed errors, rerun with: -s
==34== ERROR SUMMARY: 51 errors from 3 contexts (suppressed: 0 from 0)
Segmentation fault
Process 33 exited with status 139
reboot: Restarting system
reboot: machine restart
No test result found
##############################
Test: TestRunner_bnep-tester - FAIL
Desc: Run bnep-tester with test-runner
Output:
Crash detected:
==34== by 0x12CC4F: tester_run (tester.c:1085)
==34== by 0x111CB3: main (bnep-tester.c:298)
==34== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==34==
==34==
==34== Process terminating with default action of signal 11 (SIGSEGV)
==34== Access not within mapped region at address 0x0
==34== at 0x483FF54: __strcmp_sse2 (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==34== by 0x112206: read_info_callback (bnep-tester.c:101)
==34== by 0x1281B0: request_complete (mgmt.c:320)
==34== by 0x128B65: can_read_data (mgmt.c:408)
==34== by 0x12B5D8: watch_callback (io-glib.c:173)
==34== by 0x48A304D: g_main_context_dispatch (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A33FF: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A36F2: g_main_loop_run (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x12D258: mainloop_run (mainloop-glib.c:65)
==34== by 0x12D68F: mainloop_run_with_signal (mainloop-notify.c:196)
==34== by 0x12CC4F: tester_run (tester.c:1085)
==34== by 0x111CB3: main (bnep-tester.c:298)
==34== If you believe this happened as a result of a stack
==34== overflow in your program's main thread (unlikely but
==34== possible), you can try to increase the size of the
==34== main thread stack using the --main-stacksize= flag.
==34== The main thread stack size used in this run was 8388608.
==34==
Valgrind errors:
==34== by 0x112206: read_info_callback (bnep-tester.c:101)
==34== by 0x1281B0: request_complete (mgmt.c:320)
==34== by 0x128B65: can_read_data (mgmt.c:408)
==34== by 0x12B5D8: watch_callback (io-glib.c:173)
==34== by 0x48A304D: g_main_context_dispatch (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A33FF: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A36F2: g_main_loop_run (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x12D258: mainloop_run (mainloop-glib.c:65)
==34== by 0x12D68F: mainloop_run_with_signal (mainloop-notify.c:196)
==34== by 0x12CC4F: tester_run (tester.c:1085)
==34== by 0x111CB3: main (bnep-tester.c:298)
==34== If you believe this happened as a result of a stack
==34== overflow in your program's main thread (unlikely but
==34== possible), you can try to increase the size of the
==34== main thread stack using the --main-stacksize= flag.
==34== The main thread stack size used in this run was 8388608.
==34==
==34== HEAP SUMMARY:
==34== in use at exit: 25,264 bytes in 82 blocks
==34== total heap usage: 212 allocs, 130 frees, 38,256 bytes allocated
==34==
==34== LEAK SUMMARY:
==34== definitely lost: 0 bytes in 0 blocks
==34== indirectly lost: 0 bytes in 0 blocks
==34== possibly lost: 0 bytes in 0 blocks
==34== still reachable: 25,264 bytes in 82 blocks
==34== suppressed: 0 bytes in 0 blocks
==34== Rerun with --leak-check=full to see details of leaked memory
==34==
==34== For lists of detected and suppressed errors, rerun with: -s
==34== ERROR SUMMARY: 51 errors from 3 contexts (suppressed: 0 from 0)
Crash detected:
==34== suppressed: 0 bytes in 0 blocks
==34== Rerun with --leak-check=full to see details of leaked memory
==34==
==34== For lists of detected and suppressed errors, rerun with: -s
==34== ERROR SUMMARY: 51 errors from 3 contexts (suppressed: 0 from 0)
Segmentation fault
Process 33 exited with status 139
reboot: Restarting system
reboot: machine restart
No test result found
##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner
Output:
Crash detected:
==34== by 0x14F4FF: tester_run (tester.c:1085)
==34== by 0x12B999: main (mgmt-tester.c:15134)
==34== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==34==
==34==
==34== Process terminating with default action of signal 11 (SIGSEGV)
==34== Access not within mapped region at address 0x0
==34== at 0x483FF54: __strcmp_sse2 (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==34== by 0x12F8E8: read_info_callback (mgmt-tester.c:181)
==34== by 0x14A740: request_complete (mgmt.c:320)
==34== by 0x14B2F5: can_read_data (mgmt.c:408)
==34== by 0x14DD68: watch_callback (io-glib.c:173)
==34== by 0x48A304D: g_main_context_dispatch (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A33FF: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A36F2: g_main_loop_run (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x14FB08: mainloop_run (mainloop-glib.c:65)
==34== by 0x14FF3F: mainloop_run_with_signal (mainloop-notify.c:196)
==34== by 0x14F4FF: tester_run (tester.c:1085)
==34== by 0x12B999: main (mgmt-tester.c:15134)
==34== If you believe this happened as a result of a stack
==34== overflow in your program's main thread (unlikely but
==34== possible), you can try to increase the size of the
==34== main thread stack using the --main-stacksize= flag.
==34== The main thread stack size used in this run was 8388608.
==34==
Valgrind errors:
==34== by 0x12F8E8: read_info_callback (mgmt-tester.c:181)
==34== by 0x14A740: request_complete (mgmt.c:320)
==34== by 0x14B2F5: can_read_data (mgmt.c:408)
==34== by 0x14DD68: watch_callback (io-glib.c:173)
==34== by 0x48A304D: g_main_context_dispatch (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A33FF: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A36F2: g_main_loop_run (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x14FB08: mainloop_run (mainloop-glib.c:65)
==34== by 0x14FF3F: mainloop_run_with_signal (mainloop-notify.c:196)
==34== by 0x14F4FF: tester_run (tester.c:1085)
==34== by 0x12B999: main (mgmt-tester.c:15134)
==34== If you believe this happened as a result of a stack
==34== overflow in your program's main thread (unlikely but
==34== possible), you can try to increase the size of the
==34== main thread stack using the --main-stacksize= flag.
==34== The main thread stack size used in this run was 8388608.
==34==
==34== HEAP SUMMARY:
==34== in use at exit: 182,263 bytes in 2,112 blocks
==34== total heap usage: 2,389 allocs, 277 frees, 204,641 bytes allocated
==34==
==34== LEAK SUMMARY:
==34== definitely lost: 0 bytes in 0 blocks
==34== indirectly lost: 0 bytes in 0 blocks
==34== possibly lost: 0 bytes in 0 blocks
==34== still reachable: 182,263 bytes in 2,112 blocks
==34== suppressed: 0 bytes in 0 blocks
==34== Rerun with --leak-check=full to see details of leaked memory
==34==
==34== For lists of detected and suppressed errors, rerun with: -s
==34== ERROR SUMMARY: 51 errors from 3 contexts (suppressed: 0 from 0)
Crash detected:
==34== suppressed: 0 bytes in 0 blocks
==34== Rerun with --leak-check=full to see details of leaked memory
==34==
==34== For lists of detected and suppressed errors, rerun with: -s
==34== ERROR SUMMARY: 51 errors from 3 contexts (suppressed: 0 from 0)
Segmentation fault
Process 33 exited with status 139
reboot: Restarting system
reboot: machine restart
No test result found
##############################
Test: TestRunner_ioctl-tester - FAIL
Desc: Run ioctl-tester with test-runner
Output:
Total: 28, Passed: 0 (0.0%), Failed: 11, Not Run: 17
Failed Test Cases
Device List Timed out -31.790 seconds
Device Info Timed out -6.931 seconds
Reset Stat Timed out -6.938 seconds
Set Link Mode - ACCEPT Timed out -6.945 seconds
Set Pkt Type - DM Timed out -15.213 seconds
Set Pkt Type - DH Timed out -15.219 seconds
Set Pkt Type - HV Timed out -15.225 seconds
Set Pkt Type - 2-DH Timed out -15.234 seconds
Set Pkt Type - 2-DH Timed out -15.241 seconds
Set Pkt Type - ALL Timed out -15.247 seconds
Set ACL MTU - 1 Timed out -15.253 seconds
##############################
Test: TestRunner_userchan-tester - FAIL
Desc: Run userchan-tester with test-runner
Output:
Crash detected:
==34== by 0x12D77F: tester_run (tester.c:1085)
==34== by 0x111DFB: main (userchan-tester.c:392)
==34== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==34==
==34==
==34== Process terminating with default action of signal 11 (SIGSEGV)
==34== Access not within mapped region at address 0x0
==34== at 0x483FF54: __strcmp_sse2 (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==34== by 0x11250B: read_info_callback (userchan-tester.c:88)
==34== by 0x128450: request_complete (mgmt.c:320)
==34== by 0x128E95: can_read_data (mgmt.c:408)
==34== by 0x12C108: watch_callback (io-glib.c:173)
==34== by 0x48A304D: g_main_context_dispatch (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A33FF: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A36F2: g_main_loop_run (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x12DD88: mainloop_run (mainloop-glib.c:65)
==34== by 0x12E1BF: mainloop_run_with_signal (mainloop-notify.c:196)
==34== by 0x12D77F: tester_run (tester.c:1085)
==34== by 0x111DFB: main (userchan-tester.c:392)
==34== If you believe this happened as a result of a stack
==34== overflow in your program's main thread (unlikely but
==34== possible), you can try to increase the size of the
==34== main thread stack using the --main-stacksize= flag.
==34== The main thread stack size used in this run was 8388608.
==34==
Valgrind errors:
==34== by 0x11250B: read_info_callback (userchan-tester.c:88)
==34== by 0x128450: request_complete (mgmt.c:320)
==34== by 0x128E95: can_read_data (mgmt.c:408)
==34== by 0x12C108: watch_callback (io-glib.c:173)
==34== by 0x48A304D: g_main_context_dispatch (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A33FF: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x48A36F2: g_main_loop_run (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6400.6)
==34== by 0x12DD88: mainloop_run (mainloop-glib.c:65)
==34== by 0x12E1BF: mainloop_run_with_signal (mainloop-notify.c:196)
==34== by 0x12D77F: tester_run (tester.c:1085)
==34== by 0x111DFB: main (userchan-tester.c:392)
==34== If you believe this happened as a result of a stack
==34== overflow in your program's main thread (unlikely but
==34== possible), you can try to increase the size of the
==34== main thread stack using the --main-stacksize= flag.
==34== The main thread stack size used in this run was 8388608.
==34==
==34== HEAP SUMMARY:
==34== in use at exit: 26,001 bytes in 92 blocks
==34== total heap usage: 222 allocs, 130 frees, 38,997 bytes allocated
==34==
==34== LEAK SUMMARY:
==34== definitely lost: 0 bytes in 0 blocks
==34== indirectly lost: 0 bytes in 0 blocks
==34== possibly lost: 0 bytes in 0 blocks
==34== still reachable: 26,001 bytes in 92 blocks
==34== suppressed: 0 bytes in 0 blocks
==34== Rerun with --leak-check=full to see details of leaked memory
==34==
==34== For lists of detected and suppressed errors, rerun with: -s
==34== ERROR SUMMARY: 51 errors from 3 contexts (suppressed: 0 from 0)
Crash detected:
==34== suppressed: 0 bytes in 0 blocks
==34== Rerun with --leak-check=full to see details of leaked memory
==34==
==34== For lists of detected and suppressed errors, rerun with: -s
==34== ERROR SUMMARY: 51 errors from 3 contexts (suppressed: 0 from 0)
Segmentation fault
Process 33 exited with status 139
reboot: Restarting system
reboot: machine restart
No test result found
https://github.com/bluez/bluetooth-next/pull/152
---
Regards,
Linux Bluetooth
^ permalink raw reply
* Re: [PATCH BlueZ] client/btpclient: Add BTP_EV_GAP_SEC_LEVEL_CHANGED support
From: Luiz Augusto von Dentz @ 2026-05-07 16:56 UTC (permalink / raw)
To: Frédéric Danis; +Cc: linux-bluetooth
In-Reply-To: <20260507161633.437600-1-frederic.danis@collabora.com>
Hi Frédéric,
On Thu, May 7, 2026 at 12:23 PM Frédéric Danis
<frederic.danis@collabora.com> wrote:
>
> This allows reduces connection time for the BAP tests.
> ---
> client/btpclient/gap.c | 22 ++++++++++++++++++++++
> src/shared/btp.h | 11 +++++++++++
> 2 files changed, 33 insertions(+)
>
> diff --git a/client/btpclient/gap.c b/client/btpclient/gap.c
> index 68e029dcc..1a6c2c2f0 100644
> --- a/client/btpclient/gap.c
> +++ b/client/btpclient/gap.c
> @@ -2538,6 +2538,21 @@ static void btp_gap_device_connection_ev(struct l_dbus_proxy *proxy,
> }
> }
>
> +static void btp_security_changed_ev(struct l_dbus_proxy *proxy, bool paired)
> +{
> + struct btp_device *dev = find_device_by_proxy(proxy);
> + struct btp_adapter *adapter = find_adapter_by_device(dev);
> + struct btp_gap_sec_level_changed_ev ev;
> +
> + /* TODO: get real security level */
I guess it wouldn't hurt to expose the security level somehow, not the
key itself just the level.
> + memcpy(&ev.address, &dev->address, sizeof(ev.address));
> + ev.address_type = dev->address_type;
> + ev.sec_level = BTP_GAP_SEC_LEVEL_AUTH_ENC;
> +
> + btp_send(btp, BTP_GAP_SERVICE, BTP_EV_GAP_SEC_LEVEL_CHANGED,
> + adapter->index, sizeof(ev), &ev);
> +}
> +
> static void btp_identity_resolved_ev(struct l_dbus_proxy *proxy)
> {
> struct btp_device *dev = find_device_by_proxy(proxy);
> @@ -2709,6 +2724,13 @@ void gap_property_changed(struct l_dbus_proxy *proxy, const char *name,
> */
> if (!prop)
> btp_gap_device_connection_ev(proxy, prop);
> + } else if (!strcmp(name, "Paired")) {
> + bool prop;
> +
> + if (!l_dbus_message_get_arguments(msg, "b", &prop))
> + return;
> +
> + btp_security_changed_ev(proxy, prop);
> } else if (!strcmp(name, "AddressType")) {
> /* Address property change came first along with address
> * type.
> diff --git a/src/shared/btp.h b/src/shared/btp.h
> index b99ad3a28..4d3c4ec6f 100644
> --- a/src/shared/btp.h
> +++ b/src/shared/btp.h
> @@ -286,6 +286,17 @@ struct btp_gap_identity_resolved_ev {
> bdaddr_t identity_address;
> } __packed;
>
> +#define BTP_GAP_SEC_LEVEL_UNAUTH_ENC 0x01
> +#define BTP_GAP_SEC_LEVEL_AUTH_ENC 0x02
> +#define BTP_GAP_SEC_LEVEL_AUTH_SC 0x03
> +
> +#define BTP_EV_GAP_SEC_LEVEL_CHANGED 0x89
> +struct btp_gap_sec_level_changed_ev {
> + uint8_t address_type;
> + bdaddr_t address;
> + uint8_t sec_level;
> +} __packed;
> +
> struct btp_gatt_service {
> uint16_t start_handle;
> uint16_t end_handle;
> --
> 2.43.0
>
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* [bluez/bluez] acd0a4: tools/tester: Fix crash when hciemu_new fails
From: Luiz Augusto von Dentz @ 2026-05-07 17:00 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/master
Home: https://github.com/bluez/bluez
Commit: acd0a49506a1a24a4fe532d77f6f5a1301b011bb
https://github.com/bluez/bluez/commit/acd0a49506a1a24a4fe532d77f6f5a1301b011bb
Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Date: 2026-05-06 (Wed, 06 May 2026)
Changed paths:
M tools/6lowpan-tester.c
M tools/bnep-tester.c
M tools/ioctl-tester.c
M tools/iso-tester.c
M tools/l2cap-tester.c
M tools/mesh-tester.c
M tools/mgmt-tester.c
M tools/rfcomm-tester.c
M tools/sco-tester.c
M tools/smp-tester.c
M tools/userchan-tester.c
Log Message:
-----------
tools/tester: Fix crash when hciemu_new fails
When hciemu_new returns NULL, the mgmt object was not being unreferenced
before returning from the pre-setup failure path. This could lead to a
NULL dereference in read_info_callback when it later calls
hciemu_get_address on the NULL hciemu pointer.
Add mgmt_unref and return to the error path across all testers.
Commit: a068db99c46f1fc34b1e2f315fd27b29eab0fee5
https://github.com/bluez/bluez/commit/a068db99c46f1fc34b1e2f315fd27b29eab0fee5
Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Date: 2026-05-06 (Wed, 06 May 2026)
Changed paths:
M emulator/hciemu.c
M emulator/hciemu.h
Log Message:
-----------
emulator/hciemu: Add hciemu_new_debug/hciemu_new_num_debug
Add new constructors that accept debug callback and user_data parameters,
setting them up immediately after allocation so errors during early
initialization (create_vhci, hciemu_client_new) are captured by the debug
output.
Commit: e3dec62da2a5170f7c4f94d1eba567f30068f502
https://github.com/bluez/bluez/commit/e3dec62da2a5170f7c4f94d1eba567f30068f502
Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Date: 2026-05-06 (Wed, 06 May 2026)
Changed paths:
M tools/6lowpan-tester.c
M tools/bnep-tester.c
M tools/ioctl-tester.c
M tools/iso-tester.c
M tools/l2cap-tester.c
M tools/mesh-tester.c
M tools/mgmt-tester.c
M tools/rfcomm-tester.c
M tools/sco-tester.c
M tools/smp-tester.c
M tools/userchan-tester.c
Log Message:
-----------
tools/tester: Retry with debug on hciemu_new failure
When hciemu_new fails, retry using hciemu_new_debug to capture early
initialization errors before reporting the failure. This helps diagnose
issues like vhci or client creation failures in CI.
Compare: https://github.com/bluez/bluez/compare/e51115ccd4df...e3dec62da2a5
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* [bluez/bluez] 2fb1b7: client/btpclient: Add BTP_EV_GAP_SEC_LEVEL_CHANGED...
From: fdanis-oss @ 2026-05-07 17:01 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1091167
Home: https://github.com/bluez/bluez
Commit: 2fb1b777c8a379b17f3a0bd478af1f4164ee3b52
https://github.com/bluez/bluez/commit/2fb1b777c8a379b17f3a0bd478af1f4164ee3b52
Author: Frédéric Danis <frederic.danis@collabora.com>
Date: 2026-05-07 (Thu, 07 May 2026)
Changed paths:
M client/btpclient/gap.c
M src/shared/btp.h
Log Message:
-----------
client/btpclient: Add BTP_EV_GAP_SEC_LEVEL_CHANGED support
This allows reduces connection time for the BAP tests.
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* [bluez/bluez]
From: BluezTestBot @ 2026-05-07 17:01 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1090665
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
* [PATCH BlueZ v1] monitor: Add parsing of CS step mode data in RAS Notifications
From: Prathibha Madugonde @ 2026-05-07 17:13 UTC (permalink / raw)
To: linux-bluetooth; +Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg
From: Prathibha Madugonde <prathibha.madugonde@oss.qualcomm.com>
---
monitor/att.c | 512 +++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 491 insertions(+), 21 deletions(-)
diff --git a/monitor/att.c b/monitor/att.c
index 03d46634f..a979ab241 100644
--- a/monitor/att.c
+++ b/monitor/att.c
@@ -4120,16 +4120,18 @@ static void print_ras_segmentation_header(uint8_t header)
print_field(" Segment Index: %u", segment_index);
}
-static void print_ras_ranging_header(const struct l2cap_frame *frame)
+static uint8_t print_ras_ranging_header(const struct l2cap_frame *frame)
{
uint16_t ranging_counter_config;
uint8_t selected_tx_power;
uint8_t antenna_paths_mask;
uint8_t mask;
+ uint8_t num_antenna_paths = 0;
+ uint8_t i;
if (!l2cap_frame_get_le16((void *)frame, &ranging_counter_config)) {
print_text(COLOR_ERROR, " Ranging Header: invalid size");
- return;
+ return 0;
}
/* Lower 12 bits: Ranging Counter, Upper 4 bits: Configuration ID */
@@ -4140,14 +4142,14 @@ static void print_ras_ranging_header(const struct l2cap_frame *frame)
if (!l2cap_frame_get_u8((void *)frame, &selected_tx_power)) {
print_text(COLOR_ERROR, " Selected TX Power: invalid size");
- return;
+ return 0;
}
print_field(" Selected TX Power: %d dBm", (int8_t)selected_tx_power);
if (!l2cap_frame_get_u8((void *)frame, &antenna_paths_mask)) {
print_text(COLOR_ERROR, " Antenna Paths Mask: invalid size");
- return;
+ return 0;
}
print_field(" Antenna Paths Mask: 0x%2.2x", antenna_paths_mask);
@@ -4157,6 +4159,14 @@ static void print_ras_ranging_header(const struct l2cap_frame *frame)
if (mask)
print_text(COLOR_WHITE_BG, " RFU (0x%2.2x)", mask);
+
+ /* Count the number of set bits in antenna_paths_mask */
+ for (i = 0; i < 4; i++) {
+ if (antenna_paths_mask & (1 << i))
+ num_antenna_paths++;
+ }
+
+ return num_antenna_paths;
}
static const char *ras_ranging_done_status_str(uint8_t status)
@@ -4203,7 +4213,7 @@ static const char *ras_abort_reason_str(uint8_t reason)
}
}
-static void print_ras_subevent_header(const struct l2cap_frame *frame)
+static uint8_t print_ras_subevent_header(const struct l2cap_frame *frame)
{
uint16_t start_acl_conn_event;
uint16_t freq_compensation;
@@ -4216,7 +4226,7 @@ static void print_ras_subevent_header(const struct l2cap_frame *frame)
if (!l2cap_frame_get_le16((void *)frame, &start_acl_conn_event)) {
print_text(COLOR_ERROR,
" Start ACL Connection Event: invalid size");
- return;
+ return 0;
}
print_field(" Start ACL Connection Event: %u",
@@ -4225,7 +4235,7 @@ static void print_ras_subevent_header(const struct l2cap_frame *frame)
if (!l2cap_frame_get_le16((void *)frame, &freq_compensation)) {
print_text(COLOR_ERROR,
" Frequency Compensation: invalid size");
- return;
+ return 0;
}
print_field(" Frequency Compensation: %d (0.01 ppm)",
@@ -4233,7 +4243,7 @@ static void print_ras_subevent_header(const struct l2cap_frame *frame)
if (!l2cap_frame_get_u8((void *)frame, &status_byte1)) {
print_text(COLOR_ERROR, " Status: invalid size");
- return;
+ return 0;
}
ranging_done_status = status_byte1 & 0x0F;
@@ -4248,7 +4258,7 @@ static void print_ras_subevent_header(const struct l2cap_frame *frame)
if (!l2cap_frame_get_u8((void *)frame, &status_byte2)) {
print_text(COLOR_ERROR, " Abort Reasons: invalid size");
- return;
+ return 0;
}
ranging_abort_reason = status_byte2 & 0x0F;
@@ -4264,7 +4274,7 @@ static void print_ras_subevent_header(const struct l2cap_frame *frame)
if (!l2cap_frame_get_u8((void *)frame, &ref_power_level)) {
print_text(COLOR_ERROR,
" Reference Power Level: invalid size");
- return;
+ return 0;
}
print_field(" Reference Power Level: %d dBm",
@@ -4273,10 +4283,451 @@ static void print_ras_subevent_header(const struct l2cap_frame *frame)
if (!l2cap_frame_get_u8((void *)frame, &num_steps_reported)) {
print_text(COLOR_ERROR,
" Number of Steps Reported: invalid size");
- return;
+ return 0;
}
print_field(" Number of Steps Reported: %u", num_steps_reported);
+
+ return num_steps_reported;
+}
+
+static const char *packet_quality_str(uint8_t quality)
+{
+ switch (quality & 0x03) {
+ case 0x00:
+ return "CS Access Address check is successful, and all bits "
+ "match the expected sequence";
+ case 0x01:
+ return "CS Access Address check is successful, but some bits "
+ "do not match the expected sequence";
+ case 0x02:
+ return "CS Access Address check failed";
+ default:
+ return "Reserved";
+ }
+}
+
+static const char *tone_quality_str(uint8_t quality)
+{
+ switch (quality & 0x03) {
+ case 0x00:
+ return "Tone quality is high";
+ case 0x01:
+ return "Tone quality is medium";
+ case 0x02:
+ return "Tone quality is low";
+ case 0x03:
+ return "Tone quality indication is not available";
+ default:
+ return "Reserved";
+ }
+}
+
+static const char *tone_extension_str(uint8_t quality)
+{
+ switch ((quality >> 4) & 0x03) {
+ case 0x00:
+ return "Not tone extension slot";
+ case 0x01:
+ return "Tone extension slot; tone not expected to be present";
+ case 0x02:
+ return "Tone extension slot; tone expected to be present";
+ default:
+ return "Reserved";
+ }
+}
+
+static void print_step_mode_0(const struct l2cap_frame *frame, uint8_t len)
+{
+ uint8_t quality, rssi, antenna;
+ uint16_t freq_offset;
+
+ if (len < 3) {
+ print_hex_field(" Raw step data", frame->data, len);
+ return;
+ }
+
+ if (!l2cap_frame_get_u8((void *)frame, &quality)) {
+ print_text(COLOR_ERROR, " Packet Quality: invalid size");
+ return;
+ }
+
+ print_field(" Packet Quality: 0x%02x", quality);
+ print_field(" %s", packet_quality_str(quality));
+ print_field(" Bit errors: %u", (quality >> 2) & 0x3F);
+
+ if (!l2cap_frame_get_u8((void *)frame, &rssi)) {
+ print_text(COLOR_ERROR, " Packet RSSI: invalid size");
+ return;
+ }
+
+ print_field(" Packet RSSI: %d", (int8_t)rssi);
+
+ if (!l2cap_frame_get_u8((void *)frame, &antenna)) {
+ print_text(COLOR_ERROR, " Packet Antenna: invalid size");
+ return;
+ }
+
+ print_field(" Packet Antenna: %u", antenna);
+
+ if (len == 5) {
+ if (!l2cap_frame_get_le16((void *)frame, &freq_offset)) {
+ print_text(COLOR_ERROR,
+ " Measured Freq Offset: invalid size");
+ return;
+ }
+
+ print_field(" Measured Freq Offset: %d (0.01 ppm)",
+ (int16_t)freq_offset);
+ }
+}
+
+static void print_step_mode_1(const struct l2cap_frame *frame, uint8_t len)
+{
+ uint8_t quality, nadm, rssi, antenna;
+ uint16_t toa_tod;
+
+ if (len < 6) {
+ print_hex_field(" Raw step data", frame->data, len);
+ return;
+ }
+
+ if (!l2cap_frame_get_u8((void *)frame, &quality)) {
+ print_text(COLOR_ERROR, " Packet Quality: invalid size");
+ return;
+ }
+
+ print_field(" Packet Quality: 0x%02x", quality);
+ print_field(" %s", packet_quality_str(quality));
+ print_field(" Bit errors: %u", (quality >> 2) & 0x3F);
+
+ if (!l2cap_frame_get_u8((void *)frame, &nadm)) {
+ print_text(COLOR_ERROR, " Packet NADM: invalid size");
+ return;
+ }
+
+ if (nadm == 0xFF)
+ print_field(" Packet NADM: Unknown NADM (0xff)");
+ else
+ print_field(" Packet NADM: %u", nadm);
+
+ if (!l2cap_frame_get_u8((void *)frame, &rssi)) {
+ print_text(COLOR_ERROR, " Packet RSSI: invalid size");
+ return;
+ }
+
+ print_field(" Packet RSSI: %d", (int8_t)rssi);
+
+ if (!l2cap_frame_get_le16((void *)frame, &toa_tod)) {
+ print_text(COLOR_ERROR, " ToA_ToD: invalid size");
+ return;
+ }
+
+ print_field(" ToA_ToD: 0x%08x", toa_tod | 0xFFFF0000);
+
+ if (!l2cap_frame_get_u8((void *)frame, &antenna)) {
+ print_text(COLOR_ERROR, " Packet Antenna: invalid size");
+ return;
+ }
+
+ print_field(" Packet Antenna: %u", antenna);
+}
+
+static void print_step_mode_2(const struct l2cap_frame *frame, uint8_t len,
+ uint8_t num_antenna_paths)
+{
+ uint8_t ant_perm_idx;
+ uint8_t i;
+ uint32_t pct;
+ uint16_t i_sample, q_sample;
+ uint8_t quality;
+
+ if (len < 1) {
+ print_hex_field(" Raw step data", frame->data, len);
+ return;
+ }
+
+ if (!l2cap_frame_get_u8((void *)frame, &ant_perm_idx)) {
+ print_text(COLOR_ERROR, " Antenna Permutation Index: "
+ "invalid size");
+ return;
+ }
+
+ print_field(" Antenna Permutation Index: %u", ant_perm_idx);
+
+ /* Use the antenna paths count from ranging header */
+ for (i = 0; i < (num_antenna_paths + 1); i++) {
+ if (frame->size < 4) {
+ print_text(COLOR_ERROR,
+ " Insufficient data for path %u",
+ i);
+ return;
+ }
+
+ if (!l2cap_frame_get_le24((void *)frame, &pct)) {
+ print_text(COLOR_ERROR, " PCT: invalid size");
+ return;
+ }
+
+ /* Extract 12-bit I and Q samples from 24-bit PCT */
+ i_sample = pct & 0x0FFF;
+ q_sample = (pct >> 12) & 0x0FFF;
+
+ print_field(" Path %u", i);
+ print_field(" PCT: 0x%06x", pct);
+ print_field(" I: 0x%03x", i_sample);
+ print_field(" Q: 0x%03x", q_sample);
+
+ if (!l2cap_frame_get_u8((void *)frame, &quality)) {
+ print_text(COLOR_ERROR, " Tone quality indicator: "
+ "invalid size");
+ return;
+ }
+
+ print_field(" Tone quality indicator: 0x%02x", quality);
+ print_field(" %s (0x%02x)", tone_quality_str(quality),
+ quality & 0x03);
+ print_field(" %s (0x%02x)", tone_extension_str(quality),
+ (quality >> 4) & 0x03);
+ }
+}
+
+static void print_step_mode_3(const struct l2cap_frame *frame, uint8_t len,
+ uint8_t num_antenna_paths)
+{
+ uint8_t quality, nadm, rssi, antenna;
+ uint16_t toa_tod;
+ uint8_t ant_perm_idx;
+ uint8_t i;
+ uint32_t pct;
+ uint16_t i_sample, q_sample;
+ uint8_t tone_quality;
+
+ /* Mode 3 = Mode 1 (6 bytes) + Mode 2 (variable) */
+ if (len < 6) {
+ print_hex_field(" Raw step data", frame->data, len);
+ return;
+ }
+
+ /* Parse Mode 1 data first */
+ if (!l2cap_frame_get_u8((void *)frame, &quality)) {
+ print_text(COLOR_ERROR, " Packet Quality: invalid size");
+ return;
+ }
+
+ print_field(" Packet Quality: 0x%02x", quality);
+ print_field(" %s", packet_quality_str(quality));
+ print_field(" Bit errors: %u", (quality >> 2) & 0x3F);
+
+ if (!l2cap_frame_get_u8((void *)frame, &nadm)) {
+ print_text(COLOR_ERROR, " Packet NADM: invalid size");
+ return;
+ }
+
+ if (nadm == 0xFF)
+ print_field(" Packet NADM: Unknown NADM (0xff)");
+ else
+ print_field(" Packet NADM: %u", nadm);
+
+ if (!l2cap_frame_get_u8((void *)frame, &rssi)) {
+ print_text(COLOR_ERROR, " Packet RSSI: invalid size");
+ return;
+ }
+
+ print_field(" Packet RSSI: %d", (int8_t)rssi);
+
+ if (!l2cap_frame_get_le16((void *)frame, &toa_tod)) {
+ print_text(COLOR_ERROR, " ToA_ToD: invalid size");
+ return;
+ }
+
+ print_field(" ToA_ToD: 0x%08x", toa_tod | 0xFFFF0000);
+
+ if (!l2cap_frame_get_u8((void *)frame, &antenna)) {
+ print_text(COLOR_ERROR, " Packet Antenna: invalid size");
+ return;
+ }
+
+ print_field(" Packet Antenna: %u", antenna);
+
+ /* Now parse Mode 2 data */
+ if (frame->size < 1)
+ return;
+
+ if (!l2cap_frame_get_u8((void *)frame, &ant_perm_idx)) {
+ print_text(COLOR_ERROR, " Antenna Permutation Index: "
+ "invalid size");
+ return;
+ }
+
+ print_field(" Antenna Permutation Index: %u", ant_perm_idx);
+
+ /* Use the antenna paths count from ranging header */
+ for (i = 0; i < (num_antenna_paths + 1); i++) {
+ if (frame->size < 4) {
+ print_text(COLOR_ERROR,
+ " Insufficient data for path %u",
+ i);
+ return;
+ }
+
+ if (!l2cap_frame_get_le24((void *)frame, &pct)) {
+ print_text(COLOR_ERROR, " PCT: invalid size");
+ return;
+ }
+
+ /* Extract 12-bit I and Q samples from 24-bit PCT */
+ i_sample = pct & 0x0FFF;
+ q_sample = (pct >> 12) & 0x0FFF;
+
+ print_field(" Path %u", i);
+ print_field(" PCT: 0x%06x", pct);
+ print_field(" I: 0x%03x", i_sample);
+ print_field(" Q: 0x%03x", q_sample);
+
+ if (!l2cap_frame_get_u8((void *)frame, &tone_quality)) {
+ print_text(COLOR_ERROR, " Tone quality indicator: "
+ "invalid size");
+ return;
+ }
+
+ print_field(" Tone quality indicator: 0x%02x",
+ tone_quality);
+ print_field(" %s (0x%02x)",
+ tone_quality_str(tone_quality),
+ tone_quality & 0x03);
+ print_field(" %s (0x%02x)",
+ tone_extension_str(tone_quality),
+ (tone_quality >> 4) & 0x03);
+ }
+}
+
+static void print_ranging_steps(const struct l2cap_frame *frame,
+ uint8_t num_steps, uint8_t num_antenna_paths)
+{
+ uint8_t step_idx;
+
+ for (step_idx = 0; step_idx < num_steps && frame->size > 0;
+ step_idx++) {
+ uint8_t mode_byte;
+ uint8_t mode_type;
+ bool aborted;
+ uint8_t step_data_len;
+
+ if (!l2cap_frame_get_u8((void *)frame, &mode_byte)) {
+ print_text(COLOR_ERROR, "Step %u: Mode: invalid size",
+ step_idx);
+ return;
+ }
+
+ mode_type = mode_byte & 0x03;
+ aborted = (mode_byte & 0x80) != 0;
+
+ print_field("Step %u", step_idx);
+ print_field(" Mode Type: %u", mode_type);
+ print_field(" Aborted: %s", aborted ? "Yes" : "No");
+
+ /* If aborted, step data length is 0 */
+ if (aborted)
+ continue;
+
+ /* Determine step data length based on mode type
+ * Mode 0: Check if we have 5 bytes (initiator) or 3 bytes
+ * (reflector)
+ * Mode 1: Always 6 bytes
+ * Mode 2: 1 byte (ant_perm_idx) + num_antenna_paths * 4 bytes
+ * Mode 3: 6 bytes (Mode 1) + 1 byte (ant_perm_idx) +
+ * num_antenna_paths * 4 bytes
+ */
+ switch (mode_type) {
+ case 0:
+ /* Mode 0: Default to 3 bytes (reflector)
+ * Only use 5 bytes if we're the last step AND have
+ * exactly 5 bytes remaining
+ */
+ if (step_idx == num_steps - 1 && frame->size == 5) {
+ /* Initiator - last step with exactly 5 bytes */
+ step_data_len = 5;
+ } else if (frame->size >= 3) {
+ /* Reflector - default case */
+ step_data_len = 3;
+ } else {
+ print_text(COLOR_ERROR,
+ " Insufficient data for Mode 0");
+ return;
+ }
+ break;
+ case 1:
+ /* Mode 1: Always 6 bytes */
+ if (frame->size < 6) {
+ print_text(COLOR_ERROR,
+ " Insufficient data for Mode 1");
+ return;
+ }
+ step_data_len = 6;
+ break;
+ case 2:
+ /* Mode 2: 1 byte antenna + num_antenna_paths * 4
+ * bytes per path
+ */
+ step_data_len = 1 + ((num_antenna_paths + 1) * 4);
+ if (frame->size < step_data_len) {
+ print_text(COLOR_ERROR,
+ " Insufficient data for Mode 2 (need %u)",
+ step_data_len);
+ return;
+ }
+ break;
+ case 3:
+ /* Mode 3: 6 bytes Mode 1 + 1 byte antenna +
+ * num_antenna_paths * 4 bytes
+ */
+ step_data_len = 7 + ((num_antenna_paths + 1) * 4);
+ if (frame->size < step_data_len) {
+ print_text(COLOR_ERROR,
+ " Insufficient data for Mode 3 (need %u)",
+ step_data_len);
+ return;
+ }
+ break;
+ default:
+ print_text(COLOR_ERROR, " Unknown mode type");
+ return;
+ }
+
+ if (step_data_len > frame->size) {
+ print_text(COLOR_ERROR, " Invalid step data length");
+ return;
+ }
+
+ if (step_data_len > 0) {
+ struct l2cap_frame step_frame;
+
+ l2cap_frame_clone(&step_frame, frame);
+ step_frame.size = step_data_len;
+
+ switch (mode_type) {
+ case 0:
+ print_step_mode_0(&step_frame, step_data_len);
+ break;
+ case 1:
+ print_step_mode_1(&step_frame, step_data_len);
+ break;
+ case 2:
+ print_step_mode_2(&step_frame, step_data_len,
+ num_antenna_paths);
+ break;
+ case 3:
+ print_step_mode_3(&step_frame, step_data_len,
+ num_antenna_paths);
+ break;
+ }
+
+ if (!l2cap_frame_pull((void *)frame, frame,
+ step_data_len))
+ return;
+ }
+ }
}
static void ras_ranging_data_read(const struct l2cap_frame *frame)
@@ -4292,26 +4743,45 @@ static void ras_ranging_data_read(const struct l2cap_frame *frame)
print_ras_segmentation_header(seg_header);
first_segment = seg_header & 0x01;
-
/* Only try to decode headers if this is the first segment */
- if (first_segment && frame->size >= 6) {
+ if (first_segment && frame->size >= 4) {
+ uint8_t num_steps;
+ uint8_t num_antenna_paths;
+
print_field(" Ranging Data Body:");
- print_ras_ranging_header(frame);
+ num_antenna_paths = print_ras_ranging_header(frame);
/* Try to decode subevent header if enough data remains */
- if (frame->size >= 10) {
+ if (frame->size >= 8) {
print_field(" Subevent #0:");
- print_ras_subevent_header(frame);
+ num_steps = print_ras_subevent_header(frame);
+
+ /* Parse steps if we have num_steps and
+ * num_antenna_paths
+ */
+ if (num_steps > 0 && num_antenna_paths > 0 &&
+ frame->size > 0) {
+ print_ranging_steps((void *)frame, num_steps,
+ num_antenna_paths);
+ }
}
+ } else if (!first_segment && frame->size > 0) {
+ /* For continuation segments, we cannot reliably decode without
+ * full segment reassembly, as steps may be split across
+ * segments.
+ * Just show the raw data.
+ */
+ print_field(" Continuation Segment (raw data - requires "
+ "reassembly for proper decoding):");
+ print_hex_field(" Segment Data", frame->data, frame->size);
}
- if (frame->size > 0) {
- print_hex_field(" Remaining Ranging Data Segment", frame->data,
- frame->size);
- }
+ if (frame->size > 0 && first_segment)
+ print_hex_field(" Remaining Ranging Data Segment",
+ frame->data, frame->size);
done:
- if (frame->size)
+ if (frame->size && first_segment)
print_hex_field(" Remaining Data", frame->data, frame->size);
}
--
2.34.1
^ permalink raw reply related
* [PATCH v4 1/2] Bluetooth: HCI: Add initial support for Short Connection Interval feature
From: Luiz Augusto von Dentz @ 2026-05-07 17:42 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds initial support for SCI related commands, command bits, event
event mask bit and feature bits:
Events:
HCI_LE_Connection_Rate_Change(0x37)
Commands:
HCI_LE_Connection_Rate_Request(0x20a1)
HCI_LE_Set_Default_Rate_Parameters(0x20a2)
HCI_LE_Read_Minimum_Supported_Connection_Interval(0x20a3)
Also update the init sequence to incorporte support for reading SCI
groups and then setting the Default Rate
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
include/net/bluetooth/hci.h | 52 ++++++++++++++++++++
include/net/bluetooth/hci_core.h | 15 ++++++
net/bluetooth/hci_core.c | 14 +++++-
net/bluetooth/hci_event.c | 60 +++++++++++++++++++++++
net/bluetooth/hci_sync.c | 83 +++++++++++++++++++++++++++++++-
5 files changed, 222 insertions(+), 2 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 572b1c620c5d..848ec42de827 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -656,6 +656,7 @@ enum {
#define HCI_LE_LL_EXT_FEATURE 0x80
#define HCI_LE_CS 0x40
#define HCI_LE_CS_HOST 0x80
+#define HCI_LE_SCI 0x01
/* Connection modes */
#define HCI_CM_ACTIVE 0x0000
@@ -2486,6 +2487,46 @@ struct hci_rp_le_cs_test {
#define HCI_OP_LE_CS_TEST_END 0x2096
+#define HCI_OP_LE_CONN_RATE 0x20a1
+struct hci_cp_le_conn_rate {
+ __le16 handle;
+ __le16 interval_min;
+ __le16 interval_max;
+ __le16 subrate_min;
+ __le16 subrate_max;
+ __le16 max_latency;
+ __le16 cont_num;
+ __le16 supv_timeout;
+ __le16 min_ce_len;
+ __le16 max_ce_len;
+} __packed;
+
+#define HCI_OP_LE_SET_DEF_RATE 0x20a2
+struct hci_cp_le_set_def_rate {
+ __le16 interval_min;
+ __le16 interval_max;
+ __le16 subrate_min;
+ __le16 subrate_max;
+ __le16 max_latency;
+ __le16 cont_num;
+ __le16 supv_timeout;
+ __le16 min_ce_len;
+ __le16 max_ce_len;
+} __packed;
+
+#define HCI_OP_LE_READ_CONN_INTERVAL 0x20a3
+struct hci_le_conn_interval_group {
+ __le16 min;
+ __le16 max;
+ __le16 stride;
+} __packed;
+
+struct hci_rp_le_read_conn_interval {
+ __u8 status;
+ __u8 num_grps;
+ struct hci_le_conn_interval_group grps[] __counted_by(num_grps);
+} __packed;
+
/* ---- HCI Events ---- */
struct hci_ev_status {
__u8 status;
@@ -3300,6 +3341,17 @@ struct hci_evt_le_cs_test_end_complete {
__u8 status;
} __packed;
+#define HCI_EVT_LE_CONN_RATE_CHANGE 0x37
+struct hci_evt_le_conn_rate_change {
+ __u8 status;
+ __le16 handle;
+ __le16 interval;
+ __le16 subrate;
+ __le16 latency;
+ __le16 cont_number;
+ __le16 supv_timeout;
+} __packed;
+
#define HCI_EV_VENDOR 0xff
/* Internal events generated by Bluetooth stack */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index aa600fbf9a53..61872403fe65 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -333,6 +333,14 @@ struct adv_monitor {
#define HCI_ADV_MONITOR_EXT_NONE 1
#define HCI_ADV_MONITOR_EXT_MSFT 2
+
+struct sci_group {
+ struct list_head list;
+ __u16 min;
+ __u16 max;
+ __u16 stride;
+};
+
#define HCI_MAX_SHORT_NAME_LENGTH 10
#define HCI_CONN_HANDLE_MAX 0x0eff
@@ -572,6 +580,7 @@ struct hci_dev {
struct list_head pend_le_reports;
struct list_head blocked_keys;
struct list_head local_codecs;
+ struct list_head sci_groups;
struct hci_dev_stats stat;
@@ -2082,6 +2091,12 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define mws_transport_config_capable(dev) (((dev)->commands[30] & 0x08) && \
(!hci_test_quirk((dev), HCI_QUIRK_BROKEN_MWS_TRANSPORT_CONFIG)))
+/* Shorter Connection Intervals support */
+#define le_sci_capable(dev) \
+ ((dev)->le_features[9] & HCI_LE_SCI)
+
+void hci_sci_groups_clear(struct hci_dev *hdev);
+
/* ----- HCI protocols ----- */
#define HCI_PROTO_DEFER 0x01
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index c46c1236ebfa..04c5559ef029 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2543,8 +2543,9 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
INIT_LIST_HEAD(&hdev->adv_instances);
INIT_LIST_HEAD(&hdev->blocked_keys);
INIT_LIST_HEAD(&hdev->monitored_devices);
-
INIT_LIST_HEAD(&hdev->local_codecs);
+ INIT_LIST_HEAD(&hdev->sci_groups);
+
INIT_WORK(&hdev->rx_work, hci_rx_work);
INIT_WORK(&hdev->cmd_work, hci_cmd_work);
INIT_WORK(&hdev->tx_work, hci_tx_work);
@@ -2740,6 +2741,16 @@ void hci_unregister_dev(struct hci_dev *hdev)
}
EXPORT_SYMBOL(hci_unregister_dev);
+void hci_sci_groups_clear(struct hci_dev *hdev)
+{
+ struct sci_group *grp, *tmp;
+
+ list_for_each_entry_safe(grp, tmp, &hdev->sci_groups, list) {
+ list_del(&grp->list);
+ kfree(grp);
+ }
+}
+
/* Release HCI device */
void hci_release_dev(struct hci_dev *hdev)
{
@@ -2766,6 +2777,7 @@ void hci_release_dev(struct hci_dev *hdev)
hci_discovery_filter_clear(hdev);
hci_blocked_keys_clear(hdev);
hci_codec_list_clear(&hdev->local_codecs);
+ hci_sci_groups_clear(hdev);
msft_release(hdev);
hci_dev_unlock(hdev);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index eea2f810aafa..a73c5dad27cd 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3957,6 +3957,49 @@ static u8 hci_cc_le_read_all_local_features(struct hci_dev *hdev, void *data,
return rp->status;
}
+static u8 hci_cc_le_read_conn_interval(struct hci_dev *hdev, void *data,
+ struct sk_buff *skb)
+{
+ struct hci_rp_le_read_conn_interval *rp = data;
+ __u8 i;
+
+ bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
+
+ if (rp->status)
+ return rp->status;
+
+ hci_dev_lock(hdev);
+
+ /* Clear any existing SCI groups before adding new ones. */
+ hci_sci_groups_clear(hdev);
+
+ for (i = 0; i < rp->num_grps; i++) {
+ struct hci_le_conn_interval_group *grp;
+ struct sci_group *sgrp;
+
+ /* Pull HCI event data for the current group. */
+ grp = skb_pull_data(skb, sizeof(*grp));
+ if (!grp) {
+ bt_dev_err(hdev, "invalid data length for SCI group");
+ break;
+ }
+
+ sgrp = kzalloc(sizeof(*sgrp), GFP_KERNEL);
+ if (!sgrp)
+ break;
+
+ sgrp->min = __le16_to_cpu(grp->min);
+ sgrp->max = __le16_to_cpu(grp->max);
+ sgrp->stride = __le16_to_cpu(grp->stride);
+
+ list_add(&sgrp->list, &hdev->sci_groups);
+ }
+
+ hci_dev_unlock(hdev);
+
+ return rp->status;
+}
+
static void hci_cs_le_create_big(struct hci_dev *hdev, u8 status)
{
bt_dev_dbg(hdev, "status 0x%2.2x", status);
@@ -4239,6 +4282,10 @@ static const struct hci_cc {
HCI_CC(HCI_OP_LE_READ_ALL_LOCAL_FEATURES,
hci_cc_le_read_all_local_features,
sizeof(struct hci_rp_le_read_all_local_features)),
+ HCI_CC_VL(HCI_OP_LE_READ_CONN_INTERVAL,
+ hci_cc_le_read_conn_interval,
+ sizeof(struct hci_rp_le_read_conn_interval),
+ HCI_MAX_EVENT_SIZE),
};
static u8 hci_cc_func(struct hci_dev *hdev, const struct hci_cc *cc,
@@ -7372,6 +7419,16 @@ static void hci_le_read_all_remote_features_evt(struct hci_dev *hdev,
hci_dev_unlock(hdev);
}
+static void hci_le_conn_rate_change_evt(struct hci_dev *hdev, void *data,
+ struct sk_buff *skb)
+{
+ struct hci_evt_le_conn_rate_change *ev = data;
+
+ bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
+
+ /* TODO: Store rate to be used for next connection? */
+}
+
#define HCI_LE_EV_VL(_op, _func, _min_len, _max_len) \
[_op] = { \
.func = _func, \
@@ -7483,6 +7540,9 @@ static const struct hci_le_ev {
sizeof(struct
hci_evt_le_read_all_remote_features_complete),
HCI_MAX_EVENT_SIZE),
+ /* [0x37 = HCI_EVT_LE_CONN_RATE_CHANGE] */
+ HCI_LE_EV(HCI_EVT_LE_CONN_RATE_CHANGE, hci_le_conn_rate_change_evt,
+ sizeof(struct hci_evt_le_conn_rate_change)),
};
static void hci_le_meta_evt(struct hci_dev *hdev, void *data,
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index fd3aacdea512..3225bea38215 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -4449,6 +4449,10 @@ static int hci_le_set_event_mask_sync(struct hci_dev *hdev)
events[6] |= 0x02; /* LE CS Subevent Result Continue event */
events[6] |= 0x04; /* LE CS Test End Complete event */
}
+
+ if (le_sci_capable(hdev))
+ events[6] |= 0x40; /* LE Connection Rate Change */
+
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EVENT_MASK,
sizeof(events), events, HCI_CMD_TIMEOUT);
}
@@ -4611,9 +4615,16 @@ static int hci_le_set_host_features_sync(struct hci_dev *hdev)
return err;
}
- if (le_cs_capable(hdev))
+ if (le_cs_capable(hdev)) {
/* Channel Sounding (Host Support) */
err = hci_le_set_host_feature_sync(hdev, 47, 0x01);
+ if (err)
+ return err;
+ }
+
+ if (le_sci_capable(hdev))
+ /* Short Connection Interval (Host Support) */
+ err = hci_le_set_host_feature_sync(hdev, 73, 0x01);
return err;
}
@@ -4896,11 +4907,81 @@ static int hci_le_set_default_phy_sync(struct hci_dev *hdev)
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
}
+/* Read Connection Interval if command is supported and SCI feature bit is
+ * marked as supported.
+ */
+static int hci_le_read_conn_interval_sync(struct hci_dev *hdev)
+{
+ if (!(hdev->commands[48] & BIT(7)) || !le_sci_capable(hdev))
+ return 0;
+
+ return __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_CONN_INTERVAL,
+ 0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Set Default Connection Rate Parameters if command is supported, SCI feature
+ * bit is marked as supported and at least one of the supported SCI groups
+ * exists.
+ */
+static int hci_le_set_def_rate_sync(struct hci_dev *hdev)
+{
+ struct hci_cp_le_set_def_rate cp;
+ struct sci_group *grp, *tmp;
+ __u16 min = 0, max = 0;
+
+ if (!(hdev->commands[48] & BIT(6)) || !le_sci_capable(hdev) ||
+ list_empty(&hdev->sci_groups))
+ return 0;
+
+ memset(&cp, 0, sizeof(cp));
+
+ /* Iterate over the SCI groups and find the widest supported connection
+ * interval range to maximize compatibility with peer devices.
+ */
+ list_for_each_entry_safe(grp, tmp, &hdev->sci_groups, list) {
+ if (!min || grp->min < min)
+ min = grp->min;
+
+ if (!max || grp->max > max)
+ max = grp->max;
+ }
+
+ cp.interval_min = cpu_to_le16(min);
+ cp.interval_max = cpu_to_le16(max);
+
+ /* HOG 1.2 Table 7.4. Modes with recommended parameter values suggests
+ * subrate 1-4 for all modes so use that as default.
+ */
+ cp.subrate_min = cpu_to_le16(0x0001);
+ cp.subrate_max = cpu_to_le16(0x0004);
+
+ /* HIP 1.2 Table 7.5. Modes with recommended parameter values suggests
+ * max latency of 0 for all modes expect low power.
+ */
+ cp.max_latency = 0x0000;
+
+ /* HIP 1.2 Table 7.5. Modes with recommended parameter values suggests
+ * continuation number 1 for full range.
+ */
+ cp.cont_num = cpu_to_le16(0x0001);
+
+ cp.supv_timeout = hdev->le_supv_timeout;
+ cp.min_ce_len = cpu_to_le16(min);
+ cp.max_ce_len = cpu_to_le16(max);
+
+ return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_DEF_RATE,
+ sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
static const struct hci_init_stage le_init4[] = {
/* HCI_OP_LE_WRITE_DEF_DATA_LEN */
HCI_INIT(hci_le_set_write_def_data_len_sync),
/* HCI_OP_LE_SET_DEFAULT_PHY */
HCI_INIT(hci_le_set_default_phy_sync),
+ /* HCI_OP_LE_READ_CONN_INTERVAL */
+ HCI_INIT(hci_le_read_conn_interval_sync),
+ /* HCI_OP_LE_SET_DEF_RATE */
+ HCI_INIT(hci_le_set_def_rate_sync),
{}
};
--
2.53.0
^ permalink raw reply related
* [PATCH v4 2/2] Bluetooth: MGMT: Add SCI setting bit(25)
From: Luiz Augusto von Dentz @ 2026-05-07 17:42 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <20260507174205.209488-1-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds MGMT_SETTING_SCI(25) which indicates that the controller is
support SCI feature.
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
include/net/bluetooth/hci_core.h | 2 ++
include/net/bluetooth/mgmt.h | 1 +
net/bluetooth/mgmt.c | 6 ++++++
3 files changed, 9 insertions(+)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 61872403fe65..84a1ee798da1 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -2094,6 +2094,8 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
/* Shorter Connection Intervals support */
#define le_sci_capable(dev) \
((dev)->le_features[9] & HCI_LE_SCI)
+#define le_sci_enabled(dev) \
+ (le_enabled(dev) && le_sci_capable(dev))
void hci_sci_groups_clear(struct hci_dev *hdev);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 8234915854b6..dfd264f0bac7 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -121,6 +121,7 @@ struct mgmt_rp_read_index_list {
#define MGMT_SETTING_LL_PRIVACY BIT(22)
#define MGMT_SETTING_PAST_SENDER BIT(23)
#define MGMT_SETTING_PAST_RECEIVER BIT(24)
+#define MGMT_SETTING_SCI BIT(25)
#define MGMT_OP_READ_INFO 0x0004
#define MGMT_READ_INFO_SIZE 0
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index b05bb380e5f8..1ea06ae1efdc 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -864,6 +864,9 @@ static u32 get_supported_settings(struct hci_dev *hdev)
if (past_receiver_capable(hdev))
settings |= MGMT_SETTING_PAST_RECEIVER;
+ if (le_sci_capable(hdev))
+ settings |= MGMT_SETTING_SCI;
+
settings |= MGMT_SETTING_PHY_CONFIGURATION;
return settings;
@@ -955,6 +958,9 @@ static u32 get_current_settings(struct hci_dev *hdev)
if (past_receiver_enabled(hdev))
settings |= MGMT_SETTING_PAST_RECEIVER;
+ if (le_sci_enabled(hdev))
+ settings |= MGMT_SETTING_SCI;
+
return settings;
}
--
2.53.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox