* Re: [PATCH v4 08/11] Bluetooth: hci_qca: Support QCA2066 on M.2 connector via pwrseq
From: Bartosz Golaszewski @ 2026-07-17 9:35 UTC (permalink / raw)
To: Loic Poulain
Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam, Manivannan Sadhasivam,
Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
In-Reply-To: <20260716-monza-wireless-v4-8-9b02e6f549d7@oss.qualcomm.com>
On Thu, 16 Jul 2026 18:18:25 +0200, Loic Poulain
<loic.poulain@oss.qualcomm.com> said:
> For QCA2066 (and other QCA chips) on M.2 connectors, the UART enable is
> controlled by the W_DISABLE2# signal managed by the pcie-m2 power sequencer
> rather than a dedicated BT enable GPIO.
>
> When the serdev controller has an OF graph (indicating it is connected to
> an M.2 connector), acquire the 'uart' pwrseq target from the connector's
> power sequencer and use it to control BT power instead of the bt-enable
> GPIO. This is factored out into qca_serdev_get_m2_pwrseq().
>
> Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
> Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> ---
> drivers/bluetooth/hci_qca.c | 41 +++++++++++++++++++++++++++++++----------
> 1 file changed, 31 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> index 25c4387136245fca25e375951f960d7240116781..22f6185a946ef04c45e41b2b34126e3f58d603ca 100644
> --- a/drivers/bluetooth/hci_qca.c
> +++ b/drivers/bluetooth/hci_qca.c
> @@ -1872,6 +1872,9 @@ static int qca_power_on(struct hci_dev *hdev)
> /* Controller needs time to bootup. */
> msleep(150);
> }
> +
> + if (qcadev->bt_power.pwrseq)
> + pwrseq_power_on(qcadev->bt_power.pwrseq);
> }
>
> clear_bit(QCA_BT_OFF, &qca->flags);
> @@ -2387,6 +2390,28 @@ static int qca_init_regulators(struct qca_power *qca,
> return 0;
> }
>
> +static void qca_serdev_put_pwrseq(void *data)
> +{
> + pwrseq_put(data);
> +}
> +
> +static int qca_serdev_get_m2_pwrseq(struct qca_serdev *qcadev)
> +{
> + struct serdev_device *serdev = qcadev->serdev_hu.serdev;
> + struct pwrseq_desc *pwrseq;
> +
> + if (!of_graph_is_present(dev_of_node(&serdev->ctrl->dev)))
> + return 0;
> +
> + pwrseq = pwrseq_get(&serdev->ctrl->dev, "uart");
There's devm_pwrseq_get() you can use instead of scheduling your own action.
> + if (IS_ERR(pwrseq))
> + return PTR_ERR(pwrseq);
> +
> + qcadev->bt_power.pwrseq = pwrseq;
> +
> + return devm_add_action_or_reset(&serdev->dev, qca_serdev_put_pwrseq, pwrseq);
> +}
> +
> static int qca_serdev_probe(struct serdev_device *serdev)
> {
> struct qca_serdev *qcadev;
> @@ -2417,6 +2442,10 @@ static int qca_serdev_probe(struct serdev_device *serdev)
> else
> qcadev->btsoc_type = QCA_ROME;
>
> + err = qca_serdev_get_m2_pwrseq(qcadev);
> + if (err)
> + return err;
> +
> switch (qcadev->btsoc_type) {
> case QCA_WCN3950:
> case QCA_WCN3988:
> @@ -2426,17 +2455,9 @@ 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);
> + /* M.2 connector modules are powered by the pwrseq acquired above. */
> + if (qcadev->bt_power.pwrseq)
> break;
> - }
>
> if (!device_property_present(&serdev->dev, "enable-gpios")) {
> /*
>
> --
> 2.34.1
>
>
Bart
^ permalink raw reply
* Re: [PATCH v4 07/11] Bluetooth: hci_qca: Embed bt_power in struct qca_serdev
From: Bartosz Golaszewski @ 2026-07-17 9:31 UTC (permalink / raw)
To: Loic Poulain
Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam, Manivannan Sadhasivam,
Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
In-Reply-To: <20260716-monza-wireless-v4-7-9b02e6f549d7@oss.qualcomm.com>
On Thu, 16 Jul 2026 18:18:24 +0200, Loic Poulain
<loic.poulain@oss.qualcomm.com> said:
> 'bt_power' is allocated dynamically only for a subset of SOC types, using a
> switch on the SOC type that mirrors the one that follows it. This is about
> to become pointless as the power sequencer path (used by M.2 modules) is
> independent of the SOC type and needs 'bt_power' populated for any type.
>
> Embed 'struct qca_power' directly in 'struct qca_serdev' instead of
> allocating it separately. This drops the extra allocation and its dedicated
> SOC-type switch, and removes the need for NULL checks on the pointer.
>
> No functional change intended.
>
> Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> ---
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH v4 06/11] Bluetooth: hci_qca: Set 'bt_en_available' based on pwrseq power controllability
From: Bartosz Golaszewski @ 2026-07-17 9:30 UTC (permalink / raw)
To: Loic Poulain
Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam, Manivannan Sadhasivam,
Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
In-Reply-To: <20260716-monza-wireless-v4-6-9b02e6f549d7@oss.qualcomm.com>
On Thu, 16 Jul 2026 18:18:23 +0200, Loic Poulain
<loic.poulain@oss.qualcomm.com> said:
> A Bluetooth device only needs the non-persistent setup if the host can
> gate its power, so that it is actually reset on the next power-on. When the
> power is controlled by a power sequencer, whether the host can gate it
> depends on the hardware wiring, e.g. the presence of the BT_EN or
> W_DISABLE2# line.
>
> Query the generic pwrseq_is_controllable() helper whenever the BT power
> comes from a sequencer, regardless of which provider it is (M2, WCN, ...).
> If the power is not controllable, clear 'bt_en_available' so that
> HCI_QUIRK_NON_PERSISTENT_SETUP is not set.
>
> This is based on Manivannan's original patch that keyed the decision off
> the W_DISABLE2# device tree property, it now uses the generic pwrseq helper
> and handles the always-on case.
>
> Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> ---
> drivers/bluetooth/hci_qca.c | 13 ++++++++++++-
> 1 file changed, 12 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> index 17f436484e1e74d1dd690ada22134315abb767c4..41e8c302abc2a820022d1783f1fad76b358ae67c 100644
> --- a/drivers/bluetooth/hci_qca.c
> +++ b/drivers/bluetooth/hci_qca.c
> @@ -2548,7 +2548,18 @@ static int qca_serdev_probe(struct serdev_device *serdev)
> return PTR_ERR(qcadev->susclk);
> }
> }
> -
> +
> + if (qcadev->bt_power->pwrseq) {
> + bt_en_available = pwrseq_is_controllable(qcadev->bt_power->pwrseq);
> + if (!bt_en_available) {
> + /* The host cannot gate the BT power individually.
> + * Treat it as always-on and drop the pwrseq handle.
> + */
> + pwrseq_power_on(qcadev->bt_power->pwrseq);
> + qcadev->bt_power->pwrseq = NULL;
Maybe a little comment saying this will be released by devres? It looks like
a leak otherwise.
Bart
> + }
> + }
> +
> err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
> if (err) {
> BT_ERR("serdev registration failed");
>
> --
> 2.34.1
>
>
^ permalink raw reply
* Re: [PATCH v4 03/11] power: sequencing: Add pwrseq_is_controllable() API
From: Bartosz Golaszewski @ 2026-07-17 9:29 UTC (permalink / raw)
To: Loic Poulain
Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam, Manivannan Sadhasivam,
Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
In-Reply-To: <20260716-monza-wireless-v4-3-9b02e6f549d7@oss.qualcomm.com>
On Thu, 16 Jul 2026 18:18:20 +0200, Loic Poulain
<loic.poulain@oss.qualcomm.com> said:
> On some boards a power sequencing target has no host-controllable enable
> for its function, for instance when the enable line is not wired up to a
> GPIO and is hardwired to an always-on level. The pcie-m2 "uart" target is
> one such example: when the M.2 connector does not route the W_DISABLE2#
> signal to a host GPIO, its enable/disable are no-ops and the consumer
> cannot gate the Bluetooth function at all or exclusively.
>
> Add a generic pwrseq_is_controllable() helper. It reports whether the
> target's final unit provides a host-controllable dedicated power actuator.
> The target can implement a new optional is_controllable() callback,
> reporting whether that actuator is effective on this target (for example
> depending on GPIO presence). If the target does not provide the callback,
> it is assumed to be controllable.
>
> Note this only describes the target's own enable actuator. It does not
> imply that a power-off reaches an electrical OFF state, since a target may
> have multiple consumers. It also does not mean that power is uncontrolled
> for the target's dependencies: those may still be gated on their own. And
> it does not restrict consumers from calling pwrseq_power_off() either,
> which remains valid to drop this consumer's vote on the (possibly shared)
> resources and dependencies of the target.
>
> Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> ---
Thanks, this looks good to me now. This series is a bit all over the place,
what is the merge strategy?
Bart
^ permalink raw reply
* Re: [PATCH v4 09/11] dt-bindings: connector: pcie-m2-e: Add vendor LGA connector compatible
From: Bartosz Golaszewski @ 2026-07-17 9:27 UTC (permalink / raw)
To: Loic Poulain
Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam, Krzysztof Kozlowski,
Manivannan Sadhasivam, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
In-Reply-To: <20260716-monza-wireless-v4-9-9b02e6f549d7@oss.qualcomm.com>
On Thu, 16 Jul 2026 18:18:26 +0200, Loic Poulain
<loic.poulain@oss.qualcomm.com> said:
> Some modules (e.g. the Qualcomm QCA2066/QCNFA765) expose the same M.2
> Key E interface signals but are physically soldered as an LGA package
> rather than plugged into a real M.2 Key E connector socket. Such designs
> are not actual M.2 Key E connectors, so describe them with a dedicated
> vendor-specific compatible while keeping "pcie-m2-e-connector" as a
> fallback for the shared signal semantics.
>
> Add "qcom,pcie-m2-1418-lga-connector" for the M.2 LGA 1418 found on
> Arduino Ventuno Q (Monaco Monza).
>
> Add "qcom,pcie-m2-1620-lga-connector" for the M.2 LGA 1620 found on
> The Lenovo Thinkpad T14s.
>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
> Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
> Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> ---
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
^ permalink raw reply
* RE: Channel Sounding: Aggregate procedure data and expose via D-Bus
From: bluez.test.bot @ 2026-07-17 9:10 UTC (permalink / raw)
To: linux-bluetooth, prathibha.madugonde
In-Reply-To: <20260717072647.255002-2-prathm@qti.qualcomm.com>
[-- Attachment #1: Type: text/plain, Size: 1499 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=1129350
---Test result---
Test Summary:
CheckPatch PASS 1.95 seconds
GitLint FAIL 0.69 seconds
BuildEll PASS 25.67 seconds
BluezMake PASS 541.37 seconds
MakeCheck PASS 1.04 seconds
MakeDistcheck PASS 153.47 seconds
CheckValgrind PASS 146.41 seconds
CheckSmatch PASS 296.61 seconds
bluezmakeextell PASS 95.73 seconds
IncrementalBuild PASS 510.76 seconds
ScanBuild PASS 893.79 seconds
Details
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[BlueZ,v1,1/2] shared/rap: Add bcs_procedure_data aggregation and procedure data API
1: T1 Title exceeds max length (84>80): "[BlueZ,v1,1/2] shared/rap: Add bcs_procedure_data aggregation and procedure data API"
[BlueZ,v1,2/2] profiles/ranging: Add D-Bus ProcedureData signal for Channel Sounding
1: T1 Title exceeds max length (84>80): "[BlueZ,v1,2/2] profiles/ranging: Add D-Bus ProcedureData signal for Channel Sounding"
https://github.com/bluez/bluez/pull/2325
---
Regards,
Linux Bluetooth
^ permalink raw reply
* [PATCH v16 5/7] Bluetooth: btmtk: Improve BT firmware logging
From: Chris Lu @ 2026-07-17 8:39 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Luiz Von Dentz
Cc: Sean Wang, Will Lee, SS Wu, Steve Lee, Paul Menzel,
linux-bluetooth, linux-kernel, linux-mediatek, Chris Lu
In-Reply-To: <20260717083936.2923891-1-chris.lu@mediatek.com>
Improve firmware loading log messages to provide more useful information:
- Add firmware filename before loading to help identify which file
is being loaded
- Display chip ID (dev_id) as HW version instead of firmware's hwver
field, which provides more meaningful hardware identification
- Use %.16s format specifier for hdr->datetime field to prevent
potential buffer over-read, as the field is a 16-byte array that
may not be null-terminated
log output with MT7922
[ 212.878783] Bluetooth: hci1: Loading BT firmware: mediatek/BT_RAM_CODE_MT7922_1_1_hdr.bin
[ 212.889614] Bluetooth: hci1: BT HW ver: 0x7922, SW ver: 0x008a, Build Time: 20260224103448
[ 216.048877] Bluetooth: hci1: Device setup in 3096530 usecs
[ 216.048890] Bluetooth: hci1: HCI Enhanced Setup Synchronous Connection command is advertised, but not supported.
[ 216.114179] Bluetooth: hci1: AOSP extensions version v1.00
[ 216.114220] Bluetooth: hci1: AOSP quality report is supported
[ 216.116782] Bluetooth: MGMT ver 1.23
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
Assisted-by: Claude:Sonnet-4.5
---
drivers/bluetooth/btmtk.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index 3491060b3ae9..0fd6ce09a313 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -154,6 +154,8 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
return err;
}
+ bt_dev_info(hdev, "Loading BT firmware: %s", fwname);
+
/* Validate minimum firmware size for header and global descriptor */
if (fw->size < MTK_FW_ROM_PATCH_HEADER_SIZE + MTK_FW_ROM_PATCH_GD_SIZE) {
bt_dev_err(hdev, "Firmware file too small: size=%zu, expected at least %u bytes",
@@ -188,8 +190,8 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
goto err_release_fw;
}
- bt_dev_info(hdev, "HW/SW Version: 0x%04x%04x, Build Time: %s",
- le16_to_cpu(hdr->hwver), le16_to_cpu(hdr->swver), hdr->datetime);
+ bt_dev_info(hdev, "BT HW ver: 0x%04x, SW ver: 0x%04x, Build Time: %.16s",
+ dev_id & 0xffff, le16_to_cpu(hdr->swver), hdr->datetime);
for (i = 0; i < section_num; i++) {
first_block = 1;
--
2.45.2
^ permalink raw reply related
* [PATCH v16 7/7] Bluetooth: btmtk: Add MT7928 support
From: Chris Lu @ 2026-07-17 8:39 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Luiz Von Dentz
Cc: Sean Wang, Will Lee, SS Wu, Steve Lee, Paul Menzel,
linux-bluetooth, linux-kernel, linux-mediatek, Chris Lu
In-Reply-To: <20260717083936.2923891-1-chris.lu@mediatek.com>
Add support for MT7928 (internal device ID is MT7935) which requires
additional firmware (CBMCU firmware) loading before Bluetooth firmware.
CBMCU is a new component on MT7928 to handle common part shared across
the combo chip (Wi-Fi/Bluetooth's subsystem), providing a better user
experience through improved coordination between subsystems.
Implement two-phase CBMCU firmware download: Phase 1 loads section with
type 0x5 containing global descriptor, section maps and signature data;
Phase 2 loads remaining firmware sections. Add retry mechanism for
concurrent download protection.
After CBMCU firmware loads successfully, the driver continues to load
corresponding BT firmware based on device ID through fallthrough to
case 0x7922/0x7925.
Use %.16s format specifier for hdr->datetime field in CBMCU firmware
logging to prevent potential buffer over-read, as the field is a 16-byte
array that may not be null-terminated.
The firmware(CBMCU_CODE_MT7935_1_1.bin/BT_RAM_CODE_MT7935_1_1_hdr.bin)
required for MT7928 will be scheduled for upload to linux-firmware at
a later stage.
MT7928 bring-up kernel log:
[ 6931.197167] usb 1-3: New USB device found, idVendor=0e8d, idProduct=7935, bcdDevice= 1.00
[ 6931.197212] usb 1-3: New USB device strings: Mfr=5, Product=6, SerialNumber=7
[ 6931.197237] usb 1-3: Product: Wireless_Device
[ 6931.197258] usb 1-3: Manufacturer: MediaTek Inc.
[ 6931.197279] usb 1-3: SerialNumber: 000000000
[ 6931.213478] Bluetooth: hci1: Loading CBMCU firmware: mediatek/mt7928/CBMCU_CODE_MT7935_1_1.bin
[ 6931.215214] Bluetooth: hci1: CBMCU HW ver: 0x7935, SW ver: 0x0000, Build Time: 20260601T161751+
[ 6931.623962] Bluetooth: hci1: CBMCU firmware download completed
[ 6931.643916] Bluetooth: hci1: Loading BT firmware: mediatek/mt7928/BT_RAM_CODE_MT7935_1_1_hdr.bin
[ 6931.650467] Bluetooth: hci1: BT HW ver: 0x7935, SW ver: 0x0000, Build Time: 20260527000816
[ 6935.039790] Bluetooth: hci1: Device setup in 3369644 usecs
[ 6935.039833] Bluetooth: hci1: HCI Enhanced Setup Synchronous Connection command is advertised, but not supported.
[ 6935.160654] Bluetooth: hci1: AOSP extensions version v2.00
[ 6935.160710] Bluetooth: hci1: AOSP quality report is supported
[ 6935.162954] Bluetooth: MGMT ver 1.23
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Reviewed-by: Sean Wang <sean.wang@mediatek.com>
Assisted-by: Claude:Sonnet-4.5
---
drivers/bluetooth/btmtk.c | 370 +++++++++++++++++++++++++++++++++++++-
drivers/bluetooth/btmtk.h | 3 +
2 files changed, 372 insertions(+), 1 deletion(-)
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index e059e72d9dbe..9e17c72d7f40 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -21,6 +21,12 @@
#define MTK_FW_ROM_PATCH_SEC_MAP_SIZE 64
#define MTK_SEC_MAP_COMMON_SIZE 12
#define MTK_SEC_MAP_NEED_SEND_SIZE 52
+#define MTK_SEC_MAP_LENGTH_SIZE 4
+#define MTK_SEC_CBMCU_DESC 0x5
+
+/* CBMCU WMT command flags */
+#define BTMTK_CBMCU_FLAG_QUERY_STATUS 0xF0
+#define BTMTK_CBMCU_FLAG_ENABLE_PATCH 0xF1
/* It is for mt79xx iso data transmission setting */
#define MTK_ISO_THRESHOLD 264
@@ -120,6 +126,11 @@ void btmtk_fw_get_filename(char *buf, size_t size, u32 dev_id, u32 fw_ver,
snprintf(buf, size,
"mediatek/mt%04x/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
dev_id & 0xffff, dev_id & 0xffff, (fw_ver & 0xff) + 1);
+ /* MT7928 */
+ else if (dev_id == 0x7935)
+ snprintf(buf, size,
+ "mediatek/mt7928/BT_RAM_CODE_MT%04x_1_1_hdr.bin",
+ dev_id & 0xffff);
else if (dev_id == 0x7961 && fw_flavor)
snprintf(buf, size,
"mediatek/BT_RAM_CODE_MT%04x_1a_%x_hdr.bin",
@@ -775,6 +786,7 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
status = BTMTK_WMT_ON_UNDONE;
break;
case BTMTK_WMT_PATCH_DWNLD:
+ case BTMTK_WMT_CBMCU_DWNLD:
if (wmt_evt->whdr.flag == 2)
status = BTMTK_WMT_PATCH_DONE;
else if (wmt_evt->whdr.flag == 1)
@@ -911,6 +923,351 @@ static u32 btmtk_usb_reset_done(struct hci_dev *hdev)
return val & MTK_BT_RST_DONE;
}
+static int btmtk_cbmcu_patch_status(struct hci_dev *hdev,
+ wmt_cmd_sync_func_t wmt_cmd_sync,
+ u8 *patch_status)
+{
+ struct btmtk_hci_wmt_params wmt_params;
+ int status, err, retry = 20;
+
+ do {
+ wmt_params.op = BTMTK_WMT_CBMCU_DWNLD;
+ wmt_params.flag = BTMTK_CBMCU_FLAG_QUERY_STATUS;
+ wmt_params.dlen = 0;
+ wmt_params.data = NULL;
+ wmt_params.status = &status;
+
+ err = wmt_cmd_sync(hdev, &wmt_params);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to query CBMCU patch status (%d)", err);
+ return err;
+ }
+
+ *patch_status = (u8)status;
+
+ if (*patch_status == BTMTK_WMT_PATCH_PROGRESS) {
+ msleep(100);
+ retry--;
+ } else {
+ break;
+ }
+ } while (retry > 0);
+
+ if (*patch_status == BTMTK_WMT_PATCH_PROGRESS) {
+ bt_dev_err(hdev, "CBMCU patch status query timeout");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int btmtk_query_cbmcu_section(struct hci_dev *hdev,
+ wmt_cmd_sync_func_t wmt_cmd_sync,
+ u8 cbmcu_type,
+ const u8 *section_map,
+ u32 cert_len)
+{
+ struct btmtk_hci_wmt_params wmt_params;
+ u8 cmd[64];
+ int status, err;
+
+ cmd[0] = 0;
+ cmd[1] = cbmcu_type;
+
+ if (cbmcu_type == 0)
+ put_unaligned_le32(cert_len, &cmd[2]);
+ else
+ memcpy(&cmd[2], section_map, MTK_SEC_MAP_NEED_SEND_SIZE);
+
+ wmt_params.op = BTMTK_WMT_CBMCU_DWNLD;
+ wmt_params.flag = 0;
+ wmt_params.dlen = cbmcu_type ?
+ MTK_SEC_MAP_NEED_SEND_SIZE + 2 :
+ MTK_SEC_MAP_LENGTH_SIZE + 2;
+ wmt_params.data = cmd;
+ wmt_params.status = &status;
+
+ err = wmt_cmd_sync(hdev, &wmt_params);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to query CBMCU section (%d)", err);
+ return err;
+ }
+
+ /* Query should return UNDONE status for successful section query */
+ if (status != BTMTK_WMT_PATCH_UNDONE) {
+ bt_dev_err(hdev, "CBMCU section query status error (%d)", status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int btmtk_download_cbmcu_section(struct hci_dev *hdev,
+ wmt_cmd_sync_func_t wmt_cmd_sync,
+ const u8 *fw_data,
+ u32 dl_size)
+{
+ struct btmtk_hci_wmt_params wmt_params;
+ u32 sent_len, total_size = dl_size;
+ int err;
+
+ wmt_params.op = BTMTK_WMT_CBMCU_DWNLD;
+ wmt_params.status = NULL;
+
+ while (dl_size > 0) {
+ sent_len = min_t(u32, 250, dl_size);
+
+ if (dl_size == total_size)
+ wmt_params.flag = BTMTK_WMT_PKT_START;
+ else if (dl_size == sent_len)
+ wmt_params.flag = BTMTK_WMT_PKT_END;
+ else
+ wmt_params.flag = BTMTK_WMT_PKT_CONTINUE;
+
+ wmt_params.dlen = sent_len;
+ wmt_params.data = fw_data;
+
+ err = wmt_cmd_sync(hdev, &wmt_params);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to send CBMCU section data (%d)", err);
+ return err;
+ }
+
+ dl_size -= sent_len;
+ fw_data += sent_len;
+ }
+
+ return 0;
+}
+
+static int btmtk_enable_cbmcu_patch(struct hci_dev *hdev,
+ wmt_cmd_sync_func_t wmt_cmd_sync)
+{
+ struct btmtk_hci_wmt_params wmt_params;
+ int err;
+
+ wmt_params.op = BTMTK_WMT_CBMCU_DWNLD;
+ wmt_params.flag = BTMTK_CBMCU_FLAG_ENABLE_PATCH;
+ wmt_params.dlen = 0;
+ wmt_params.data = NULL;
+ wmt_params.status = NULL;
+
+ err = wmt_cmd_sync(hdev, &wmt_params);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to enable CBMCU patch (%d)", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int btmtk_load_cbmcu_firmware(struct hci_dev *hdev,
+ const char *fwname,
+ wmt_cmd_sync_func_t wmt_cmd_sync,
+ u32 dev_id)
+{
+ struct btmtk_patch_header *hdr;
+ struct btmtk_global_desc *globaldesc;
+ struct btmtk_section_map *sectionmap;
+ const struct firmware *fw;
+ const u8 *fw_ptr;
+ u8 *cert_buf = NULL;
+ u32 section_num, section_offset, dl_size, cert_len;
+ size_t expected_size;
+ int i, err;
+
+ err = request_firmware(&fw, fwname, &hdev->dev);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to load CBMCU firmware file %s (%d)",
+ fwname, err);
+ return err;
+ }
+
+ if (fw->size < MTK_FW_ROM_PATCH_HEADER_SIZE + MTK_FW_ROM_PATCH_GD_SIZE) {
+ bt_dev_err(hdev, "CBMCU firmware too small: size=%zu, min=%u",
+ fw->size,
+ MTK_FW_ROM_PATCH_HEADER_SIZE + MTK_FW_ROM_PATCH_GD_SIZE);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
+ fw_ptr = fw->data;
+ hdr = (struct btmtk_patch_header *)fw_ptr;
+ globaldesc = (struct btmtk_global_desc *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE);
+ section_num = le32_to_cpu(globaldesc->section_num);
+
+ /* Check for potential integer overflow in size calculation */
+ if (check_mul_overflow((size_t)MTK_FW_ROM_PATCH_SEC_MAP_SIZE,
+ (size_t)section_num, &expected_size) ||
+ check_add_overflow(expected_size,
+ (size_t)(MTK_FW_ROM_PATCH_HEADER_SIZE +
+ MTK_FW_ROM_PATCH_GD_SIZE),
+ &expected_size)) {
+ bt_dev_err(hdev, "CBMCU firmware size calculation overflow (section_num=%u)",
+ section_num);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
+ if (fw->size < expected_size) {
+ bt_dev_err(hdev, "CBMCU firmware truncated: size=%zu, expected=%zu (section_num=%u)",
+ fw->size, expected_size, section_num);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
+ bt_dev_info(hdev, "CBMCU HW ver: 0x%04x, SW ver: 0x%04x, Build Time: %.16s",
+ dev_id & 0xffff, le16_to_cpu(hdr->swver), hdr->datetime);
+
+ /* Phase 1: Download section type MTK_SEC_CBMCU_DESC */
+ for (i = 0; i < section_num; i++) {
+ sectionmap = (struct btmtk_section_map *)
+ (fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE +
+ MTK_FW_ROM_PATCH_GD_SIZE +
+ MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i);
+
+ /* Only process MTK_SEC_CBMCU_DESC section in Phase 1 */
+ if ((le32_to_cpu(sectionmap->sectype) & 0xFFFF) != MTK_SEC_CBMCU_DESC)
+ continue;
+
+ section_offset = le32_to_cpu(sectionmap->secoffset);
+ dl_size = le32_to_cpu(sectionmap->secsize);
+
+ if (dl_size == 0)
+ continue;
+
+ if (section_offset > fw->size ||
+ dl_size > fw->size - section_offset) {
+ bt_dev_err(hdev, "CBMCU Phase 1 section out of bounds");
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
+ cert_len = MTK_FW_ROM_PATCH_GD_SIZE +
+ MTK_FW_ROM_PATCH_SEC_MAP_SIZE * section_num +
+ dl_size;
+
+ /* Query cbmcu section */
+ err = btmtk_query_cbmcu_section(hdev, wmt_cmd_sync, 0, NULL,
+ cert_len);
+ if (err < 0)
+ goto err_release_fw;
+
+ cert_buf = kmalloc(cert_len, GFP_KERNEL);
+ if (!cert_buf) {
+ err = -ENOMEM;
+ goto err_release_fw;
+ }
+
+ /* Copy Global Descriptor + All Section Maps */
+ memcpy(cert_buf,
+ fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE,
+ MTK_FW_ROM_PATCH_GD_SIZE + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * section_num);
+
+ /* Copy Phase 1 section data */
+ memcpy(cert_buf + MTK_FW_ROM_PATCH_GD_SIZE +
+ MTK_FW_ROM_PATCH_SEC_MAP_SIZE * section_num,
+ fw_ptr + section_offset,
+ dl_size);
+
+ /* Download Phase 1 section */
+ err = btmtk_download_cbmcu_section(hdev, wmt_cmd_sync,
+ cert_buf, cert_len);
+ kfree(cert_buf);
+ cert_buf = NULL;
+
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to download CBMCU Phase 1 section (%d)", err);
+ goto err_release_fw;
+ }
+
+ break;
+ }
+
+ /* Phase 2: Download other sections (type != MTK_SEC_CBMCU_DESC) */
+ for (i = 0; i < section_num; i++) {
+ sectionmap = (struct btmtk_section_map *)
+ (fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE +
+ MTK_FW_ROM_PATCH_GD_SIZE +
+ MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i);
+
+ /* Skip MTK_SEC_CBMCU_DESC section in Phase 2 */
+ if ((le32_to_cpu(sectionmap->sectype) & 0xFFFF) == MTK_SEC_CBMCU_DESC)
+ continue;
+
+ section_offset = le32_to_cpu(sectionmap->secoffset);
+ dl_size = le32_to_cpu(sectionmap->bin_info_spec.dlsize);
+
+ if (dl_size == 0)
+ continue;
+
+ if (section_offset > fw->size ||
+ dl_size > fw->size - section_offset) {
+ bt_dev_err(hdev, "CBMCU Phase 2 section %d out of bounds", i);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
+ /* Query cbmcu section */
+ err = btmtk_query_cbmcu_section(hdev, wmt_cmd_sync, 1,
+ (u8 *)§ionmap->bin_info_spec,
+ 0);
+ if (err < 0)
+ goto err_release_fw;
+
+ /* Download section data */
+ err = btmtk_download_cbmcu_section(hdev, wmt_cmd_sync,
+ fw_ptr + section_offset,
+ dl_size);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to download CBMCU section %d (%d)", i, err);
+ goto err_release_fw;
+ }
+ }
+
+ bt_dev_info(hdev, "CBMCU firmware download completed");
+
+err_release_fw:
+ release_firmware(fw);
+ return err;
+}
+
+static int btmtk_setup_cbmcu_firmware(struct hci_dev *hdev,
+ wmt_cmd_sync_func_t wmt_cmd_sync,
+ u32 dev_id)
+{
+ char cbmcu_fwname[64];
+ u8 patch_status;
+ int err;
+
+ err = btmtk_cbmcu_patch_status(hdev, wmt_cmd_sync, &patch_status);
+ if (err < 0)
+ return err;
+
+ bt_dev_dbg(hdev, "CBMCU patch status: 0x%02x", patch_status);
+
+ if (patch_status != BTMTK_WMT_PATCH_UNDONE)
+ return 0;
+
+ snprintf(cbmcu_fwname, sizeof(cbmcu_fwname),
+ "mediatek/mt7928/CBMCU_CODE_MT%04x_1_1.bin",
+ dev_id & 0xffff);
+
+ bt_dev_info(hdev, "Loading CBMCU firmware: %s", cbmcu_fwname);
+
+ err = btmtk_load_cbmcu_firmware(hdev, cbmcu_fwname, wmt_cmd_sync, dev_id);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to download CBMCU firmware (%d)", err);
+ return err;
+ }
+
+ err = btmtk_enable_cbmcu_patch(hdev, wmt_cmd_sync);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
{
u32 val;
@@ -935,7 +1292,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
msleep(100);
- } else if (dev_id == 0x7925 || dev_id == 0x6639) {
+ } else if (dev_id == 0x7925 || dev_id == 0x6639 || dev_id == 0x7935) {
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
if (err < 0)
return err;
@@ -1420,6 +1777,15 @@ int btmtk_usb_setup(struct hci_dev *hdev)
case 0x7668:
fwname = FIRMWARE_MT7668;
break;
+ case 0x7935:
+ /* Requires CBMCU firmware before BT firmware */
+ err = btmtk_setup_cbmcu_firmware(hdev, btmtk_usb_hci_wmt_sync,
+ dev_id);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to set up CBMCU firmware (%d)", err);
+ return err;
+ }
+ fallthrough;
case 0x7922:
case 0x7925:
/*
@@ -1637,3 +2003,5 @@ MODULE_FIRMWARE(FIRMWARE_MT7922);
MODULE_FIRMWARE(FIRMWARE_MT7961);
MODULE_FIRMWARE(FIRMWARE_MT7925);
MODULE_FIRMWARE(FIRMWARE_MT7927);
+MODULE_FIRMWARE(FIRMWARE_MT7928);
+MODULE_FIRMWARE(FIRMWARE_MT7928_CBMCU);
diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h
index c234e5ea27e5..2d087d552d31 100644
--- a/drivers/bluetooth/btmtk.h
+++ b/drivers/bluetooth/btmtk.h
@@ -9,6 +9,8 @@
#define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin"
#define FIRMWARE_MT7925 "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin"
#define FIRMWARE_MT7927 "mediatek/mt7927/BT_RAM_CODE_MT6639_2_1_hdr.bin"
+#define FIRMWARE_MT7928 "mediatek/mt7928/BT_RAM_CODE_MT7935_1_1_hdr.bin"
+#define FIRMWARE_MT7928_CBMCU "mediatek/mt7928/CBMCU_CODE_MT7935_1_1.bin"
#define HCI_EV_WMT 0xe4
#define HCI_WMT_MAX_EVENT_SIZE 64
@@ -54,6 +56,7 @@ enum {
BTMTK_WMT_RST = 0x7,
BTMTK_WMT_REGISTER = 0x8,
BTMTK_WMT_SEMAPHORE = 0x17,
+ BTMTK_WMT_CBMCU_DWNLD = 0x58,
};
enum {
--
2.45.2
^ permalink raw reply related
* [PATCH v16 6/7] Bluetooth: btmtk: Replace magic numbers with WMT packet flag enum
From: Chris Lu @ 2026-07-17 8:39 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Luiz Von Dentz
Cc: Sean Wang, Will Lee, SS Wu, Steve Lee, Paul Menzel,
linux-bluetooth, linux-kernel, linux-mediatek, Chris Lu
In-Reply-To: <20260717083936.2923891-1-chris.lu@mediatek.com>
Add BTMTK_WMT_PKT_* enum to represent WMT download packet sequence flags,
improving code readability. Replace magic numbers (1, 2, 3) in
btmtk_setup_firmware_79xx() and btmtk_setup_firmware() with descriptive
enum values:
- BTMTK_WMT_PKT_START (1): First packet of a sequence
- BTMTK_WMT_PKT_CONTINUE (2): Continuation packet
- BTMTK_WMT_PKT_END (3): Final packet of a sequence
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Assisted-by: Claude:Sonnet-4.5
---
drivers/bluetooth/btmtk.c | 12 ++++++------
drivers/bluetooth/btmtk.h | 6 ++++++
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index 0fd6ce09a313..e059e72d9dbe 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -271,12 +271,12 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
while (dl_size > 0) {
dlen = min_t(int, 250, dl_size);
if (first_block == 1) {
- flag = 1;
+ flag = BTMTK_WMT_PKT_START;
first_block = 0;
} else if (dl_size - dlen <= 0) {
- flag = 3;
+ flag = BTMTK_WMT_PKT_END;
} else {
- flag = 2;
+ flag = BTMTK_WMT_PKT_CONTINUE;
}
wmt_params.flag = flag;
@@ -355,7 +355,7 @@ int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
fw_size -= 30;
fw_ptr += 30;
- flag = 1;
+ flag = BTMTK_WMT_PKT_START;
wmt_params.op = BTMTK_WMT_PATCH_DWNLD;
wmt_params.status = NULL;
@@ -365,9 +365,9 @@ int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
/* Tell device the position in sequence */
if (fw_size - dlen <= 0)
- flag = 3;
+ flag = BTMTK_WMT_PKT_END;
else if (fw_size < fw->size - 30)
- flag = 2;
+ flag = BTMTK_WMT_PKT_CONTINUE;
wmt_params.flag = flag;
wmt_params.dlen = dlen;
diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h
index c83c24897c95..c234e5ea27e5 100644
--- a/drivers/bluetooth/btmtk.h
+++ b/drivers/bluetooth/btmtk.h
@@ -66,6 +66,12 @@ enum {
BTMTK_WMT_ON_PROGRESS,
};
+enum btmtk_wmt_pkt_flag {
+ BTMTK_WMT_PKT_START = 1,
+ BTMTK_WMT_PKT_CONTINUE = 2,
+ BTMTK_WMT_PKT_END = 3,
+};
+
struct btmtk_wmt_hdr {
u8 dir;
u8 op;
--
2.45.2
^ permalink raw reply related
* [PATCH v16 4/7] Bluetooth: btmtksdio: Remove redundant firmware filename override
From: Chris Lu @ 2026-07-17 8:39 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Luiz Von Dentz
Cc: Sean Wang, Will Lee, SS Wu, Steve Lee, Paul Menzel,
linux-bluetooth, linux-kernel, linux-mediatek, Chris Lu
In-Reply-To: <20260717083936.2923891-1-chris.lu@mediatek.com>
btmtksdio_setup() calls btmtk_fw_get_filename() to generate the correct
firmware filename based on device ID and version, then immediately
overwrites it with snprintf() using a generic legacy format.
This redundant override causes newer chips (MT6639, MT7925, MT7928) to
request incorrect firmware filenames, leading to firmware load failures.
For example, MT6639 needs "mediatek/mt7927/BT_RAM_CODE_MT6639_2_1_hdr.bin"
but snprintf() generates "mediatek/BT_RAM_CODE_MT6639_1_1_hdr.bin".
Remove the redundant snprintf() override to use the correct filename
generated by btmtk_fw_get_filename(), matching USB driver behavior.
Fixes: 7f935b21bee4 ("Bluetooth: btmtk: apply the common btmtk_fw_get_filename")
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
---
drivers/bluetooth/btmtksdio.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
index ea6fefffef0f..491a61b43b3d 100644
--- a/drivers/bluetooth/btmtksdio.c
+++ b/drivers/bluetooth/btmtksdio.c
@@ -1184,9 +1184,6 @@ static int btmtksdio_setup(struct hci_dev *hdev)
btmtk_fw_get_filename(fwname, sizeof(fwname), dev_id,
fw_version, 0);
- snprintf(fwname, sizeof(fwname),
- "mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
- dev_id & 0xffff, (fw_version & 0xff) + 1);
err = mt79xx_setup(hdev, fwname, dev_id);
if (err < 0)
return err;
--
2.45.2
^ permalink raw reply related
* [PATCH v16 3/7] Bluetooth: btmtksdio: Pass hardware dev_id to mt79xx_setup()
From: Chris Lu @ 2026-07-17 8:39 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Luiz Von Dentz
Cc: Sean Wang, Will Lee, SS Wu, Steve Lee, Paul Menzel,
linux-bluetooth, linux-kernel, linux-mediatek, Chris Lu
In-Reply-To: <20260717083936.2923891-1-chris.lu@mediatek.com>
mt79xx_setup() hardcodes dev_id=0 when calling btmtk_setup_firmware_79xx(),
causing SDIO devices to log incorrect chip ID "BT HW ver: 0x0000" instead
of the actual hardware version read from register 0x70010200.
Pass the hardware dev_id to mt79xx_setup() and forward it to
btmtk_setup_firmware_79xx() to match USB driver behavior and display
correct chip identification.
Fixes: 28b7c5a6db74 ("Bluetooth: btmtk: Add MT6639 (MT7927) Bluetooth support")
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
---
drivers/bluetooth/btmtksdio.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
index aea7d07b49ad..ea6fefffef0f 100644
--- a/drivers/bluetooth/btmtksdio.c
+++ b/drivers/bluetooth/btmtksdio.c
@@ -921,14 +921,14 @@ static int mt76xx_setup(struct hci_dev *hdev, const char *fwname)
return 0;
}
-static int mt79xx_setup(struct hci_dev *hdev, const char *fwname)
+static int mt79xx_setup(struct hci_dev *hdev, const char *fwname, u32 dev_id)
{
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
struct btmtk_hci_wmt_params wmt_params;
u8 param = 0x1;
int err;
- err = btmtk_setup_firmware_79xx(hdev, fwname, mtk_hci_wmt_sync, 0);
+ err = btmtk_setup_firmware_79xx(hdev, fwname, mtk_hci_wmt_sync, dev_id);
if (err < 0) {
bt_dev_err(hdev, "Failed to setup 79xx firmware (%d)", err);
return err;
@@ -1187,7 +1187,7 @@ static int btmtksdio_setup(struct hci_dev *hdev)
snprintf(fwname, sizeof(fwname),
"mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
dev_id & 0xffff, (fw_version & 0xff) + 1);
- err = mt79xx_setup(hdev, fwname);
+ err = mt79xx_setup(hdev, fwname, dev_id);
if (err < 0)
return err;
--
2.45.2
^ permalink raw reply related
* RE: Bluetooth: btmtk: Add MT7928 support
From: bluez.test.bot @ 2026-07-17 8:52 UTC (permalink / raw)
To: linux-bluetooth, chris.lu
In-Reply-To: <20260717074207.2869999-2-chris.lu@mediatek.com>
[-- Attachment #1: Type: text/plain, Size: 3665 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=1129376
---Test result---
Test Summary:
CheckPatch FAIL 5.55 seconds
VerifyFixes PASS 0.14 seconds
VerifySignedoff PASS 0.13 seconds
GitLint FAIL 2.28 seconds
SubjectPrefix PASS 0.90 seconds
BuildKernel PASS 26.85 seconds
CheckAllWarning PASS 29.15 seconds
CheckSparse PASS 32.43 seconds
BuildKernel32 PASS 26.43 seconds
CheckKernelLLVM SKIP 0.00 seconds
TestRunnerSetup PASS 493.62 seconds
IncrementalBuild PASS 38.33 seconds
Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[v15,1/7] Bluetooth: btmtksdio: Fix SKB handling issues in TX path
WARNING: Reported-by: should be immediately followed by Closes: with a URL to the report
#104:
Reported-by: Sashiko <sashiko-review@kernel.org>
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
total: 0 errors, 1 warnings, 70 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/14693018.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:
[v15,2/7] Bluetooth: btmtk: Add firmware size validation in btmtk_setup_firmware_79xx()
1: T1 Title exceeds max length (87>80): "[v15,2/7] Bluetooth: btmtk: Add firmware size validation in btmtk_setup_firmware_79xx()"
[v15,5/7] Bluetooth: btmtk: Improve BT firmware logging
14: B1 Line exceeds max length (92>80): "[ 212.878783] Bluetooth: hci1: Loading BT firmware: mediatek/BT_RAM_CODE_MT7922_1_1_hdr.bin"
15: B1 Line exceeds max length (93>80): "[ 212.889614] Bluetooth: hci1: BT HW ver: 0x7922, SW ver: 0x008a, Build Time: 20260224103448"
17: B1 Line exceeds max length (115>80): "[ 216.048890] Bluetooth: hci1: HCI Enhanced Setup Synchronous Connection command is advertised, but not supported."
[v15,7/7] Bluetooth: btmtk: Add MT7928 support
28: B1 Line exceeds max length (92>80): "[ 6931.197167] usb 1-3: New USB device found, idVendor=0e8d, idProduct=7935, bcdDevice= 1.00"
33: B1 Line exceeds max length (97>80): "[ 6931.213478] Bluetooth: hci1: Loading CBMCU firmware: mediatek/mt7928/CBMCU_CODE_MT7935_1_1.bin"
34: B1 Line exceeds max length (98>80): "[ 6931.215214] Bluetooth: hci1: CBMCU HW ver: 0x7935, SW ver: 0x0000, Build Time: 20260601T161751+"
36: B1 Line exceeds max length (99>80): "[ 6931.643916] Bluetooth: hci1: Loading BT firmware: mediatek/mt7928/BT_RAM_CODE_MT7935_1_1_hdr.bin"
37: B1 Line exceeds max length (93>80): "[ 6931.650467] Bluetooth: hci1: BT HW ver: 0x7935, SW ver: 0x0000, Build Time: 20260527000816"
39: B1 Line exceeds max length (115>80): "[ 6935.039833] Bluetooth: hci1: HCI Enhanced Setup Synchronous Connection command is advertised, but not supported."
##############################
Test: CheckKernelLLVM - SKIP
Desc: Build kernel with LLVM + context analysis
Output:
Clang not found
https://github.com/bluez/bluetooth-next/pull/448
---
Regards,
Linux Bluetooth
^ permalink raw reply
* [PATCH v16 1/7] Bluetooth: btmtksdio: Fix SKB handling issues in TX path
From: Chris Lu @ 2026-07-17 8:39 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Luiz Von Dentz
Cc: Sean Wang, Will Lee, SS Wu, Steve Lee, Paul Menzel,
linux-bluetooth, linux-kernel, linux-mediatek, Chris Lu, Sashiko
In-Reply-To: <20260717083936.2923891-1-chris.lu@mediatek.com>
Fix two SKB handling issues in btmtksdio_tx_packet():
1. DMA out-of-bounds read: The driver aligns transfer size to 256 bytes
using round_up(), but does not ensure the skb buffer has sufficient
tailroom, causing DMA to read beyond the buffer. Fix by expanding skb
tailroom if needed and zero-filling the padding.
2. Cloned SKB corruption: The driver modifies SKB header (via skb_push)
and tail (via skb_put_zero) without checking if the SKB is cloned.
If the Bluetooth core passes a cloned SKB (e.g., from L2CAP
retransmission queues), the driver corrupts the shared data buffer.
Fix by calling skb_unshare() at function entry to ensure we have a
private copy. Use double-pointer parameter (struct sk_buff **pskb)
to properly update the caller's SKB pointer when skb_unshare()
allocates a new SKB, preventing use-after-free when the caller
requeues the SKB on error.
On error paths, do not free the SKB - leave it valid for the caller
to requeue, avoiding use-after-free in btmtksdio_txrx_work().
Fixes: 9aebfd4a2200 ("Bluetooth: mediatek: add support for MediaTek MT7663S and MT7668S SDIO devices")
Reported-by: Sashiko <sashiko-review@kernel.org>
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
Assisted-by: Claude:Sonnet-4.5
---
drivers/bluetooth/btmtksdio.c | 65 +++++++++++++++++++++++++++++------
1 file changed, 55 insertions(+), 10 deletions(-)
diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
index c6f80c419e90..aea7d07b49ad 100644
--- a/drivers/bluetooth/btmtksdio.c
+++ b/drivers/bluetooth/btmtksdio.c
@@ -269,17 +269,32 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
}
static int btmtksdio_tx_packet(struct btmtksdio_dev *bdev,
- struct sk_buff *skb)
+ struct sk_buff **pskb)
{
+ struct sk_buff *skb = *pskb;
struct mtkbtsdio_hdr *sdio_hdr;
+ unsigned int padded_len, pad_len;
int err;
- /* Make sure that there are enough rooms for SDIO header */
+ /* Ensure SKB is not cloned before any modification.
+ * If cloned (e.g., L2CAP retransmission queues), create a
+ * private copy to avoid corrupting shared data buffer.
+ */
+ skb = skb_unshare(skb, GFP_ATOMIC);
+ if (!skb) {
+ *pskb = NULL;
+ return -ENOMEM;
+ }
+ *pskb = skb;
+
+ /* Make sure that there are enough rooms for SDIO header.
+ * After skb_unshare(), we have exclusive ownership of the buffer.
+ */
if (unlikely(skb_headroom(skb) < sizeof(*sdio_hdr))) {
err = pskb_expand_head(skb, sizeof(*sdio_hdr), 0,
GFP_ATOMIC);
if (err < 0)
- return err;
+ goto err_free_skb;
}
/* Prepend MediaTek SDIO Specific Header */
@@ -290,21 +305,50 @@ static int btmtksdio_tx_packet(struct btmtksdio_dev *bdev,
sdio_hdr->reserved = cpu_to_le16(0);
sdio_hdr->bt_type = hci_skb_pkt_type(skb);
+ /* Calculate padded length for block-aligned DMA transfer.
+ * SDIO requires transfers to be block-aligned (MTK_SDIO_BLOCK_SIZE).
+ * Pad with zeros to prevent DMA from reading beyond skb buffer.
+ */
+ padded_len = round_up(skb->len, MTK_SDIO_BLOCK_SIZE);
+ pad_len = padded_len - skb->len;
+
+ if (pad_len > 0) {
+ /* Ensure sufficient tailroom for padding */
+ if (unlikely(skb_tailroom(skb) < pad_len)) {
+ err = pskb_expand_head(skb, 0, pad_len, GFP_ATOMIC);
+ if (err < 0)
+ goto err_skb_pull;
+ /* Reassign sdio_hdr after buffer reallocation */
+ sdio_hdr = (void *)skb->data;
+ }
+
+ /* Zero-fill padding to prevent information disclosure */
+ skb_put_zero(skb, pad_len);
+ }
+
clear_bit(BTMTKSDIO_HW_TX_READY, &bdev->tx_state);
- err = sdio_writesb(bdev->func, MTK_REG_CTDR, skb->data,
- round_up(skb->len, MTK_SDIO_BLOCK_SIZE));
+ err = sdio_writesb(bdev->func, MTK_REG_CTDR, skb->data, padded_len);
if (err < 0)
- goto err_skb_pull;
+ goto err_skb_trim;
- bdev->hdev->stat.byte_tx += skb->len;
+ /* Record actual transmitted data (excluding padding) */
+ bdev->hdev->stat.byte_tx += le16_to_cpu(sdio_hdr->len);
kfree_skb(skb);
+ *pskb = NULL;
return 0;
+err_skb_trim:
+ if (pad_len > 0)
+ skb_trim(skb, skb->len - pad_len);
err_skb_pull:
skb_pull(skb, sizeof(*sdio_hdr));
-
+err_free_skb:
+ /* On error, keep skb valid for caller to requeue.
+ * Do NOT free skb here - let caller handle it.
+ */
+ *pskb = skb;
return err;
}
@@ -606,10 +650,11 @@ static void btmtksdio_txrx_work(struct work_struct *work)
if (test_bit(BTMTKSDIO_HW_TX_READY, &bdev->tx_state)) {
skb = skb_dequeue(&bdev->txq);
if (skb) {
- err = btmtksdio_tx_packet(bdev, skb);
+ err = btmtksdio_tx_packet(bdev, &skb);
if (err < 0) {
bdev->hdev->stat.err_tx++;
- skb_queue_head(&bdev->txq, skb);
+ if (skb)
+ skb_queue_head(&bdev->txq, skb);
}
}
}
--
2.45.2
^ permalink raw reply related
* [PATCH v16 2/7] Bluetooth: btmtk: Add firmware size validation in btmtk_setup_firmware_79xx()
From: Chris Lu @ 2026-07-17 8:39 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Luiz Von Dentz
Cc: Sean Wang, Will Lee, SS Wu, Steve Lee, Paul Menzel,
linux-bluetooth, linux-kernel, linux-mediatek, Chris Lu
In-Reply-To: <20260717083936.2923891-1-chris.lu@mediatek.com>
Add firmware size validation to prevent out-of-bounds access when loading
truncated or malicious firmware files.
Add three levels of validation:
1. Minimum size check for header and global descriptor
2. Section map bounds check with integer overflow protection using
check_mul_overflow() and check_add_overflow()
3. Section data bounds check before accessing each section
This matches the validation approach used in btmtk_load_cbmcu_firmware().
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
Assisted-by: Claude:Sonnet-4.5
---
drivers/bluetooth/btmtk.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index 02a96342e964..3491060b3ae9 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -145,6 +145,7 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
int err, dlen, i, status;
u8 flag, first_block, retry;
u32 section_num, dl_size, section_offset;
+ size_t expected_size;
u8 cmd[64];
err = request_firmware(&fw, fwname, &hdev->dev);
@@ -153,12 +154,40 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
return err;
}
+ /* Validate minimum firmware size for header and global descriptor */
+ if (fw->size < MTK_FW_ROM_PATCH_HEADER_SIZE + MTK_FW_ROM_PATCH_GD_SIZE) {
+ bt_dev_err(hdev, "Firmware file too small: size=%zu, expected at least %u bytes",
+ fw->size, MTK_FW_ROM_PATCH_HEADER_SIZE + MTK_FW_ROM_PATCH_GD_SIZE);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
fw_ptr = fw->data;
fw_bin_ptr = fw_ptr;
hdr = (struct btmtk_patch_header *)fw_ptr;
globaldesc = (struct btmtk_global_desc *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE);
section_num = le32_to_cpu(globaldesc->section_num);
+ /* Check for potential integer overflow in size calculation */
+ if (check_mul_overflow((size_t)MTK_FW_ROM_PATCH_SEC_MAP_SIZE,
+ (size_t)section_num, &expected_size) ||
+ check_add_overflow(expected_size,
+ (size_t)(MTK_FW_ROM_PATCH_HEADER_SIZE +
+ MTK_FW_ROM_PATCH_GD_SIZE),
+ &expected_size)) {
+ bt_dev_err(hdev, "Firmware size calculation overflow (section_num=%u)",
+ section_num);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
+ if (fw->size < expected_size) {
+ bt_dev_err(hdev, "Firmware truncated: size=%zu, expected=%zu (section_num=%u)",
+ fw->size, expected_size, section_num);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
bt_dev_info(hdev, "HW/SW Version: 0x%04x%04x, Build Time: %s",
le16_to_cpu(hdr->hwver), le16_to_cpu(hdr->swver), hdr->datetime);
@@ -171,6 +200,16 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
section_offset = le32_to_cpu(sectionmap->secoffset);
dl_size = le32_to_cpu(sectionmap->bin_info_spec.dlsize);
+ /* Validate section boundaries to prevent out-of-bounds access */
+ if (dl_size > 0 &&
+ (section_offset > fw->size ||
+ dl_size > fw->size - section_offset)) {
+ bt_dev_err(hdev, "Section %d out of bounds: offset=%u, size=%u, fw_size=%zu",
+ i, section_offset, dl_size, fw->size);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
/* MT6639: only download sections where dlmode byte0 == 0x01,
* matching the Windows driver behavior which skips WiFi/other
* sections that would cause the chip to hang.
--
2.45.2
^ permalink raw reply related
* [PATCH v16 0/7] Bluetooth: btmtk: Add MT7928 support
From: Chris Lu @ 2026-07-17 8:39 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Luiz Von Dentz
Cc: Sean Wang, Will Lee, SS Wu, Steve Lee, Paul Menzel,
linux-bluetooth, linux-kernel, linux-mediatek, Chris Lu
This patch series adds support for MT7928 (device ID 0x7935) to the
btmtk driver, which requires a new two-stage firmware loading process
with CBMCU firmware.
Patch 1 fixes SKB handling issues: DMA out-of-bounds read and cloned
SKB corruption. Fix by calling skb_unshare() and expanding skb tailroom
with zero-padding. Use double-pointer to properly update caller's SKB
pointer, preventing use-after-free.
Patch 2 adds firmware size validation with integer overflow protection
to prevent out-of-bounds access with malicious firmware files.
Patch 3 passes hardware dev_id to mt79xx_setup() to fix incorrect chip
ID logging (was hardcoded to 0).
Patch 4 removes redundant snprintf() that overrides btmtk_fw_get_filename()
result, causing newer chips to request incorrect firmware filenames.
Patch 5 improves firmware logging: adds filename log, uses chip ID as
HW version, and uses %.16s format specifier for datetime field.
Patch 6 replaces magic numbers with BTMTK_WMT_PKT_* enum for better
code readability.
Patch 7 implements MT7928 CBMCU firmware download with two-phase loading
sequence and cert_len overflow protection.
Tested on MT7928 hardware with successful firmware loading and
Bluetooth functionality verification.
Changes in v16:
- Fix Patch 1 SKB ownership issues reported by Sashiko:
* Use double-pointer (struct sk_buff **pskb) to properly update
caller's SKB pointer when skb_unshare() allocates new SKB
* On error paths, do not free SKB - leave it valid for caller
to requeue, preventing use-after-free in btmtksdio_txrx_work()
* Prevents memory leak when pskb_expand_head() fails after
skb_unshare() succeeds
Changes in v15:
- Rebased onto latest bluetooth-next/HEAD (bd8bee79e1fa)
- No functional changes from v14
- Fixed patch application issues reported by Sashiko
Changes in v14:
- Rebased onto latest bluetooth-next tree
- No functional changes from v13
Changes in v13:
- Fix cloned SKB corruption (HIGH severity) by adding skb_unshare() (Patch 1)
- Fix cert_len integer overflow (CRITICAL severity) in CBMCU firmware loading (Patch 7)
Pre-existing issues fixed in subsequent patches:
- Patch 2 introduces format string issue (%s on non-null-terminated field)
-> Fixed in Patch 5 using %.16s format specifier
- Patch 3 context has pre-existing snprintf() override (identified in v12 review)
-> Fixed in Patch 4, resolving firmware load failures on MT6639/MT7925/MT7928
This gradual improvement approach allows independent backporting of each fix.
v12 -> v13:
- Added skb_unshare() to prevent cloned SKB corruption
- Added overflow checks for cert_len calculation
- Split SDIO firmware loading fixes into two patches
Changes in v12:
- Reordered patches to fix dependency: move "Pass dev_id" before
"Improve logging" so dev_id is available when logging
Changes in v11:
- Fixed use-after-free: reassign sdio_hdr after pskb_expand_head()
- Reordered patches for bisectability
Changes in v10:
- Added Patch 1 to fix DMA out-of-bounds access
Changes in v9:
- Reordered patches to group SDIO fixes together
Changes in v8:
- Split firmware validation from dev_id pass-through into separate patches
Changes in v7:
- Added Fixes tag per feedback
Changes in v6:
- Added Fixes tag and restructured parameter comment
Changes in v5:
- Moved documentation to function-level comment
Changes in v4:
- Fixed commit message and expanded description
Changes in v3:
- Changed dev_id type from u16 to u32
Changes in v2:
- Combined MT7928 functionality into single patch
Chris Lu (7):
Bluetooth: btmtksdio: Fix SKB handling issues in TX path
Bluetooth: btmtk: Add firmware size validation in
btmtk_setup_firmware_79xx()
Bluetooth: btmtksdio: Pass hardware dev_id to mt79xx_setup()
Bluetooth: btmtksdio: Remove redundant firmware filename override
Bluetooth: btmtk: Improve BT firmware logging
Bluetooth: btmtk: Replace magic numbers with WMT packet flag enum
Bluetooth: btmtk: Add MT7928 support
drivers/bluetooth/btmtk.c | 427 +++++++++++++++++++++++++++++++++-
drivers/bluetooth/btmtk.h | 9 +
drivers/bluetooth/btmtksdio.c | 74 ++++--
3 files changed, 485 insertions(+), 25 deletions(-)
--
2.45.2
^ permalink raw reply
* Re: [PATCH v8 4/9] nvmem: layouts: Support fixed-layout as the nvmem device node itself
From: Bartosz Golaszewski @ 2026-07-17 8:29 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Loic Poulain, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bjorn Andersson, Konrad Dybcio, Jens Axboe,
Johannes Berg, Jeff Johnson, 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, Christian Marangi
In-Reply-To: <CAMRc=MdNehSRQT3MUs+QtbZsHcUCS8YjyZchTgHCVv-HaLQkeA@mail.gmail.com>
On Wed, 15 Jul 2026 14:07:24 +0200, Bartosz Golaszewski <brgl@kernel.org> said:
> On Fri, 3 Jul 2026 15:45:17 +0200, Loic Poulain <loic.poulain@oss.qualcomm.com> said:
>> of_nvmem_layout_get_container() only looks for a child node named
>> "nvmem-layout" to locate the cell definitions. This does not cover
>> providers whose device tree node is itself the fixed-layout container,
>> such as an eMMC boot partition block device whose fwnode points directly
>> at a "fixed-layout" compatible partitions node.
>>
>> When no "nvmem-layout" child is present, fall back to returning the nvmem
>> device node itself if it is compatible with "fixed-layout", so that its
>> cells are parsed by nvmem_add_cells_from_fixed_layout().
>>
>> Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
>> ---
>> drivers/nvmem/layouts.c | 13 ++++++++++++-
>> 1 file changed, 12 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/nvmem/layouts.c b/drivers/nvmem/layouts.c
>> index b90584e1b99eab4217cbe7ec48373e18a7caf0dc..efa631ce7283bdd6c8ecda75915911b5e3a33c99 100644
>> --- a/drivers/nvmem/layouts.c
>> +++ b/drivers/nvmem/layouts.c
>> @@ -167,7 +167,18 @@ static int nvmem_layout_bus_populate(struct nvmem_device *nvmem,
>>
>> struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)
>> {
>> - return of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout");
>> + struct device_node *np;
>> +
>> + /* Search for nvmem-layout child */
>> + np = of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout");
>> + if (np)
>> + return np;
>> +
>> + /* The nvmem of_node is itself a fixed-layout node */
>> + if (of_device_is_compatible(nvmem->dev.of_node, "fixed-layout"))
>> + return of_node_get(nvmem->dev.of_node);
>> +
>> + return NULL;
>> }
>> EXPORT_SYMBOL_GPL(of_nvmem_layout_get_container);
>>
>>
>> --
>> 2.34.1
>>
>>
>
> I have it on my TODO list to convert nvmem layouts to be fwnode-agnostic. While
> I'm not sure when I'll have the time to look into it, I think it makes sense
> to not introduce any new OF-specific interfaces. Can you make it into:
>
> struct fwnode_handle *nvmem_layout_get_container_node(struct nvmem_device *nvmem);
>
> by replacing of_get_child_by_name() with fwnode_get_name_child_node() and
> of_device_is_compatible() with device_is_compatible()? That would mean less
> churn in the future.
>
> Other than that, it looks good.
>
> Bart
>
Scratch that, I didn't realize this isn't a new function but a rework of an
existing one.
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Bart
^ permalink raw reply
* [bluez/bluez] 5e2434: shared/rap: Add bcs_procedure_data aggregation and...
From: prathibhamadugonde @ 2026-07-17 8:25 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1129350
Home: https://github.com/bluez/bluez
Commit: 5e2434dbf7add97640e9053ee98bf03215ee6e54
https://github.com/bluez/bluez/commit/5e2434dbf7add97640e9053ee98bf03215ee6e54
Author: Prathibha Madugonde <prathibha.madugonde@oss.qualcomm.com>
Date: 2026-07-17 (Fri, 17 Jul 2026)
Changed paths:
M src/shared/rap.c
M src/shared/rap.h
Log Message:
-----------
shared/rap: Add bcs_procedure_data aggregation and procedure data API
Define bcs_procedure_data to hold per-procedure CS results from both
the local initiator and remote reflector, including subevent step data,
selected TX powers, procedure enable config, CS config, sw_time values,
and BLE connection interval.
Add cs_proc_state with a 16-entry ring buffer in cstracker to track
procedures keyed by procedure counter, accumulating results
independently from each side until both report all-results-complete.
Update parse_mode_{0,1,2,3}, parse_step, and parse_subevent_steps with
output pointer parameters to capture remote reflector step data.
Introduce parse_cs_local_initiator_data() to store local HCI subevent
results, handling both initial and continuation events. Update
parse_ras_data_segments() to route decoded RAS subevent data into the
matching cs_proc_state as reflector results.
Add bt_rap_set_procedure_data_cb() to register a callback fired once
both local and remote results are complete for a given procedure.
Add bt_rap_set_local_sw_time(), bt_rap_set_remote_sw_time(), and
bt_rap_set_conn_interval() so callers such as rap_hci.c can supply the
CS capability sw_time and connection interval required by upper-layer
distance calculation algorithms.
Remove unwanted function rap_detached , fix for rap profile level
disconnections
Commit: 27f844638412dc9d65b0bb1f374f7e580a9e07bf
https://github.com/bluez/bluez/commit/27f844638412dc9d65b0bb1f374f7e580a9e07bf
Author: Prathibha Madugonde <prathibha.madugonde@oss.qualcomm.com>
Date: 2026-07-17 (Fri, 17 Jul 2026)
Changed paths:
M profiles/ranging/rap.c
M profiles/ranging/rap_hci.c
Log Message:
-----------
profiles/ranging: Add D-Bus ProcedureData signal for Channel Sounding
Marshal bcs_procedure_data (subevents, steps, mode 0/1/2/3 results,
and CS/procedure-enable config) into an a{sv} dictionary and emit it
as a new ProcedureData signal on the CS D-Bus interface.
Register a procedure_data callback on the RAP HCI state machine so
rap.c is notified when a procedure completes, and propagate the
locally supported T_SW time capability from the read-local-supported-
capabilities response into bt_rap.
Compare: https://github.com/bluez/bluez/compare/5e2434dbf7ad%5E...27f844638412
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* [PATCH BlueZ v2] adapter: Infer BR/EDR only at public LE addresses
From: Philipp Dunkel @ 2026-07-17 8:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Philipp Dunkel
In-Reply-To: <20260716204514.79356-1-pip@pipobscure.com>
btd_adapter_device_found() records BR/EDR support for any LE device
whose advertising Flags lack "BR/EDR Not Supported" (EIR_BREDR_UNSUP).
The address type is not considered:
if (bdaddr_type != BDADDR_BREDR && eir_data.flags &&
!(eir_data.flags & EIR_BREDR_UNSUP)) {
device_set_bredr_support(dev);
When the advertisement uses a random address the device gets a BR/EDR
bearer whose address is that random address, and start_discovery_cb()
then prefers SDP over GATT:
if (device->bredr)
device_browse_sdp(device, NULL);
else
device_browse_gatt(device, NULL);
SDP requires a BR/EDR ACL, so bluetoothd pages the random address. A
random address is not a BD_ADDR and cannot be paged, so the attempt
always ends in Page Timeout, and the failure tears down the working LE
link:
connect_failed_callback() hci0 5A:B4:98:1F:CC:04 status 4
bonding_attempt_complete() hci0 bdaddr 5A:B4:98:1F:CC:04
type 0 status 0x4
device_bonding_complete() bonding (nil) status 0x04
browse_request_cancel()
btd_gatt_database_att_disconnected()
Nothing requested the connection ("bonding (nil)") and the LE link was
healthy. Any LE association that outlives the page timeout is killed by
it; measured on one host, applications get about 4.7 s from connect
before the link disappears, of which GATT discovery already takes 2.3 s.
Current phones advertise Flags 0x1a (LE General Discoverable plus
Simultaneous LE and BR/EDR, with BR/EDR Not Supported clear) from
resolvable private addresses, so this triggers routinely rather than in
some corner case.
The Flags bits describe what the device supports. They do not promise
that the address it is advertising from is a BD_ADDR. A dual-mode device
uses the same Public Device Address for BR/EDR and LE, so the inference
is sound only for BDADDR_LE_PUBLIC. Restrict it to that.
The other two device_set_bredr_support() callers already require the
device to have been seen over BR/EDR (bdaddr_type == BDADDR_BREDR), so
they are unaffected. A device later seen over BR/EDR, or whose RPA is
resolved to a public identity, still gets BR/EDR support recorded there.
---
Changes in v2:
- Commit message only; the code change is byte-for-byte identical to v1.
- Dropped the "Assisted-by:" trailer, which checkpatch rejected as a
non-standard signature with an unrecognized email address. The
disclosure is kept below the --- instead, see the note at the end.
- Quoted the two code excerpts with spaces rather than hard tabs
(gitlint B3).
- Wrapped the bonding_attempt_complete() log line, which was 76 chars,
onto a continuation line to fit 75. The text is unchanged.
This patch was developed with assistance from Claude Code
(claude-opus-4-8). It was reviewed line by line and the results below
reproduced on real hardware by me before submitting; nothing here is
inferred.
Verified on a dual-mode controller with ControllerMode=dual, against iOS and
Android peers advertising Flags 0x1a from resolvable private addresses. A GATT
association that includes a ~7 s user prompt, which previously failed every
time at ~4.7 s with the Page Timeout above, now completes:
before: connect +0.0s, GATT resolved +2.3s, first exchange +2.7s,
Page Timeout +4.7s -> LE link destroyed, transfer never completed
after: same host, same peers, classic still enabled, transfer completes
with the user prompt taking 7.0s of it
Setting ControllerMode=le instead of applying the patch also makes the failure
go away, which independently confirms the mechanism: with no classic radio
there is no page to time out. The patch achieves the same without giving up
BR/EDR, and A2DP/HFP continue to work on the host afterwards.
make is clean with no new warnings in src/adapter.c, and make check passes
39/39.
No unit test is included: src/adapter.c is linked only into bluetoothd and not
into any unit test target, so btd_adapter_device_found() cannot be exercised by
the existing harness. Extracting the check into a unit-testable helper looked
like scope creep for a bug fix, but I am happy to add that if preferred.
src/adapter.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/adapter.c b/src/adapter.c
index 4ffa32a..30e7679 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -7415,8 +7415,17 @@ void btd_adapter_device_found(struct btd_adapter *adapter,
* older kernels send separate adv_ind and scan_rsp. Newer
* kernels send them merged, so once we know which mgmt version
* supports this we can make the non-zero check conditional.
+ *
+ * Only infer BR/EDR support when the LE address is a Public Device
+ * Address. A dual-mode device uses the same Public Device Address for
+ * BR/EDR and LE, so in that case the advertised address is also a valid
+ * BD_ADDR to page. A random address (static, resolvable or
+ * non-resolvable) has no defined relationship to the device's BD_ADDR,
+ * so recording BR/EDR support against it makes the device look pageable
+ * at an address that can never be paged: SDP discovery then fails with
+ * Page Timeout and takes the working LE link down with it.
*/
- if (bdaddr_type != BDADDR_BREDR && eir_data.flags &&
+ if (bdaddr_type == BDADDR_LE_PUBLIC && eir_data.flags &&
!(eir_data.flags & EIR_BREDR_UNSUP)) {
device_set_bredr_support(dev);
/* Update last seen for BR/EDR in case its flag is set */
--
2.55.0
^ permalink raw reply related
* [PATCH v15 1/7] Bluetooth: btmtksdio: Fix SKB handling issues in TX path
From: Chris Lu @ 2026-07-17 7:42 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Luiz Von Dentz
Cc: Sean Wang, Will Lee, SS Wu, Steve Lee, Paul Menzel,
linux-bluetooth, linux-kernel, linux-mediatek, Chris Lu, Sashiko
In-Reply-To: <20260717074207.2869999-1-chris.lu@mediatek.com>
Fix two SKB handling issues in btmtksdio_tx_packet():
1. DMA out-of-bounds read: The driver aligns transfer size to 256 bytes
using round_up(), but does not ensure the skb buffer has sufficient
tailroom, causing DMA to read beyond the buffer. Fix by expanding skb
tailroom if needed and zero-filling the padding.
2. Cloned SKB corruption: The driver modifies SKB header (via skb_push)
and tail (via skb_put_zero) without checking if the SKB is cloned.
If the Bluetooth core passes a cloned SKB (e.g., from L2CAP
retransmission queues), the driver corrupts the shared data buffer
for other subsystems. Fix by calling skb_unshare() at function entry
to ensure we have a private copy before any modifications.
Fixes: 9aebfd4a2200 ("Bluetooth: mediatek: add support for MediaTek MT7663S and MT7668S SDIO devices")
Reported-by: Sashiko <sashiko-review@kernel.org>
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
Assisted-by: Claude:Sonnet-4.5
---
drivers/bluetooth/btmtksdio.c | 46 +++++++++++++++++++++++++++++++----
1 file changed, 41 insertions(+), 5 deletions(-)
diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
index c6f80c419e90..42cb0bbb720f 100644
--- a/drivers/bluetooth/btmtksdio.c
+++ b/drivers/bluetooth/btmtksdio.c
@@ -272,9 +272,20 @@ static int btmtksdio_tx_packet(struct btmtksdio_dev *bdev,
struct sk_buff *skb)
{
struct mtkbtsdio_hdr *sdio_hdr;
+ unsigned int padded_len, pad_len;
int err;
- /* Make sure that there are enough rooms for SDIO header */
+ /* Ensure SKB is not cloned before any modification.
+ * If cloned (e.g., L2CAP retransmission queues), create a
+ * private copy to avoid corrupting shared data buffer.
+ */
+ skb = skb_unshare(skb, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ /* Make sure that there are enough rooms for SDIO header.
+ * After skb_unshare(), we have exclusive ownership of the buffer.
+ */
if (unlikely(skb_headroom(skb) < sizeof(*sdio_hdr))) {
err = pskb_expand_head(skb, sizeof(*sdio_hdr), 0,
GFP_ATOMIC);
@@ -290,20 +301,45 @@ static int btmtksdio_tx_packet(struct btmtksdio_dev *bdev,
sdio_hdr->reserved = cpu_to_le16(0);
sdio_hdr->bt_type = hci_skb_pkt_type(skb);
+ /* Calculate padded length for block-aligned DMA transfer.
+ * SDIO requires transfers to be block-aligned (MTK_SDIO_BLOCK_SIZE).
+ * Pad with zeros to prevent DMA from reading beyond skb buffer.
+ */
+ padded_len = round_up(skb->len, MTK_SDIO_BLOCK_SIZE);
+ pad_len = padded_len - skb->len;
+
+ if (pad_len > 0) {
+ /* Ensure sufficient tailroom for padding */
+ if (unlikely(skb_tailroom(skb) < pad_len)) {
+ err = pskb_expand_head(skb, 0, pad_len, GFP_ATOMIC);
+ if (err < 0)
+ goto err_skb_pull;
+ /* Reassign sdio_hdr after buffer reallocation */
+ sdio_hdr = (void *)skb->data;
+ }
+
+ /* Zero-fill padding to prevent information disclosure */
+ skb_put_zero(skb, pad_len);
+ }
+
clear_bit(BTMTKSDIO_HW_TX_READY, &bdev->tx_state);
- err = sdio_writesb(bdev->func, MTK_REG_CTDR, skb->data,
- round_up(skb->len, MTK_SDIO_BLOCK_SIZE));
+ err = sdio_writesb(bdev->func, MTK_REG_CTDR, skb->data, padded_len);
if (err < 0)
- goto err_skb_pull;
+ goto err_skb_trim;
- bdev->hdev->stat.byte_tx += skb->len;
+ /* Record actual transmitted data (excluding padding) */
+ bdev->hdev->stat.byte_tx += le16_to_cpu(sdio_hdr->len);
kfree_skb(skb);
return 0;
+err_skb_trim:
+ if (pad_len > 0)
+ skb_trim(skb, skb->len - pad_len);
err_skb_pull:
skb_pull(skb, sizeof(*sdio_hdr));
+ kfree_skb(skb);
return err;
}
--
2.45.2
^ permalink raw reply related
* [PATCH v15 3/7] Bluetooth: btmtksdio: Pass hardware dev_id to mt79xx_setup()
From: Chris Lu @ 2026-07-17 7:42 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Luiz Von Dentz
Cc: Sean Wang, Will Lee, SS Wu, Steve Lee, Paul Menzel,
linux-bluetooth, linux-kernel, linux-mediatek, Chris Lu
In-Reply-To: <20260717074207.2869999-1-chris.lu@mediatek.com>
mt79xx_setup() hardcodes dev_id=0 when calling btmtk_setup_firmware_79xx(),
causing SDIO devices to log incorrect chip ID "BT HW ver: 0x0000" instead
of the actual hardware version read from register 0x70010200.
Pass the hardware dev_id to mt79xx_setup() and forward it to
btmtk_setup_firmware_79xx() to match USB driver behavior and display
correct chip identification.
Fixes: 28b7c5a6db74 ("Bluetooth: btmtk: Add MT6639 (MT7927) Bluetooth support")
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
---
drivers/bluetooth/btmtksdio.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
index 42cb0bbb720f..1fdc24545e41 100644
--- a/drivers/bluetooth/btmtksdio.c
+++ b/drivers/bluetooth/btmtksdio.c
@@ -912,14 +912,14 @@ static int mt76xx_setup(struct hci_dev *hdev, const char *fwname)
return 0;
}
-static int mt79xx_setup(struct hci_dev *hdev, const char *fwname)
+static int mt79xx_setup(struct hci_dev *hdev, const char *fwname, u32 dev_id)
{
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
struct btmtk_hci_wmt_params wmt_params;
u8 param = 0x1;
int err;
- err = btmtk_setup_firmware_79xx(hdev, fwname, mtk_hci_wmt_sync, 0);
+ err = btmtk_setup_firmware_79xx(hdev, fwname, mtk_hci_wmt_sync, dev_id);
if (err < 0) {
bt_dev_err(hdev, "Failed to setup 79xx firmware (%d)", err);
return err;
@@ -1178,7 +1178,7 @@ static int btmtksdio_setup(struct hci_dev *hdev)
snprintf(fwname, sizeof(fwname),
"mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
dev_id & 0xffff, (fw_version & 0xff) + 1);
- err = mt79xx_setup(hdev, fwname);
+ err = mt79xx_setup(hdev, fwname, dev_id);
if (err < 0)
return err;
--
2.45.2
^ permalink raw reply related
* [PATCH v15 7/7] Bluetooth: btmtk: Add MT7928 support
From: Chris Lu @ 2026-07-17 7:42 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Luiz Von Dentz
Cc: Sean Wang, Will Lee, SS Wu, Steve Lee, Paul Menzel,
linux-bluetooth, linux-kernel, linux-mediatek, Chris Lu
In-Reply-To: <20260717074207.2869999-1-chris.lu@mediatek.com>
Add support for MT7928 (internal device ID is MT7935) which requires
additional firmware (CBMCU firmware) loading before Bluetooth firmware.
CBMCU is a new component on MT7928 to handle common part shared across
the combo chip (Wi-Fi/Bluetooth's subsystem), providing a better user
experience through improved coordination between subsystems.
Implement two-phase CBMCU firmware download: Phase 1 loads section with
type 0x5 containing global descriptor, section maps and signature data;
Phase 2 loads remaining firmware sections. Add retry mechanism for
concurrent download protection.
After CBMCU firmware loads successfully, the driver continues to load
corresponding BT firmware based on device ID through fallthrough to
case 0x7922/0x7925.
Use %.16s format specifier for hdr->datetime field in CBMCU firmware
logging to prevent potential buffer over-read, as the field is a 16-byte
array that may not be null-terminated.
The firmware(CBMCU_CODE_MT7935_1_1.bin/BT_RAM_CODE_MT7935_1_1_hdr.bin)
required for MT7928 will be scheduled for upload to linux-firmware at
a later stage.
MT7928 bring-up kernel log:
[ 6931.197167] usb 1-3: New USB device found, idVendor=0e8d, idProduct=7935, bcdDevice= 1.00
[ 6931.197212] usb 1-3: New USB device strings: Mfr=5, Product=6, SerialNumber=7
[ 6931.197237] usb 1-3: Product: Wireless_Device
[ 6931.197258] usb 1-3: Manufacturer: MediaTek Inc.
[ 6931.197279] usb 1-3: SerialNumber: 000000000
[ 6931.213478] Bluetooth: hci1: Loading CBMCU firmware: mediatek/mt7928/CBMCU_CODE_MT7935_1_1.bin
[ 6931.215214] Bluetooth: hci1: CBMCU HW ver: 0x7935, SW ver: 0x0000, Build Time: 20260601T161751+
[ 6931.623962] Bluetooth: hci1: CBMCU firmware download completed
[ 6931.643916] Bluetooth: hci1: Loading BT firmware: mediatek/mt7928/BT_RAM_CODE_MT7935_1_1_hdr.bin
[ 6931.650467] Bluetooth: hci1: BT HW ver: 0x7935, SW ver: 0x0000, Build Time: 20260527000816
[ 6935.039790] Bluetooth: hci1: Device setup in 3369644 usecs
[ 6935.039833] Bluetooth: hci1: HCI Enhanced Setup Synchronous Connection command is advertised, but not supported.
[ 6935.160654] Bluetooth: hci1: AOSP extensions version v2.00
[ 6935.160710] Bluetooth: hci1: AOSP quality report is supported
[ 6935.162954] Bluetooth: MGMT ver 1.23
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Reviewed-by: Sean Wang <sean.wang@mediatek.com>
Assisted-by: Claude:Sonnet-4.5
---
drivers/bluetooth/btmtk.c | 370 +++++++++++++++++++++++++++++++++++++-
drivers/bluetooth/btmtk.h | 3 +
2 files changed, 372 insertions(+), 1 deletion(-)
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index e059e72d9dbe..9e17c72d7f40 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -21,6 +21,12 @@
#define MTK_FW_ROM_PATCH_SEC_MAP_SIZE 64
#define MTK_SEC_MAP_COMMON_SIZE 12
#define MTK_SEC_MAP_NEED_SEND_SIZE 52
+#define MTK_SEC_MAP_LENGTH_SIZE 4
+#define MTK_SEC_CBMCU_DESC 0x5
+
+/* CBMCU WMT command flags */
+#define BTMTK_CBMCU_FLAG_QUERY_STATUS 0xF0
+#define BTMTK_CBMCU_FLAG_ENABLE_PATCH 0xF1
/* It is for mt79xx iso data transmission setting */
#define MTK_ISO_THRESHOLD 264
@@ -120,6 +126,11 @@ void btmtk_fw_get_filename(char *buf, size_t size, u32 dev_id, u32 fw_ver,
snprintf(buf, size,
"mediatek/mt%04x/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
dev_id & 0xffff, dev_id & 0xffff, (fw_ver & 0xff) + 1);
+ /* MT7928 */
+ else if (dev_id == 0x7935)
+ snprintf(buf, size,
+ "mediatek/mt7928/BT_RAM_CODE_MT%04x_1_1_hdr.bin",
+ dev_id & 0xffff);
else if (dev_id == 0x7961 && fw_flavor)
snprintf(buf, size,
"mediatek/BT_RAM_CODE_MT%04x_1a_%x_hdr.bin",
@@ -775,6 +786,7 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
status = BTMTK_WMT_ON_UNDONE;
break;
case BTMTK_WMT_PATCH_DWNLD:
+ case BTMTK_WMT_CBMCU_DWNLD:
if (wmt_evt->whdr.flag == 2)
status = BTMTK_WMT_PATCH_DONE;
else if (wmt_evt->whdr.flag == 1)
@@ -911,6 +923,351 @@ static u32 btmtk_usb_reset_done(struct hci_dev *hdev)
return val & MTK_BT_RST_DONE;
}
+static int btmtk_cbmcu_patch_status(struct hci_dev *hdev,
+ wmt_cmd_sync_func_t wmt_cmd_sync,
+ u8 *patch_status)
+{
+ struct btmtk_hci_wmt_params wmt_params;
+ int status, err, retry = 20;
+
+ do {
+ wmt_params.op = BTMTK_WMT_CBMCU_DWNLD;
+ wmt_params.flag = BTMTK_CBMCU_FLAG_QUERY_STATUS;
+ wmt_params.dlen = 0;
+ wmt_params.data = NULL;
+ wmt_params.status = &status;
+
+ err = wmt_cmd_sync(hdev, &wmt_params);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to query CBMCU patch status (%d)", err);
+ return err;
+ }
+
+ *patch_status = (u8)status;
+
+ if (*patch_status == BTMTK_WMT_PATCH_PROGRESS) {
+ msleep(100);
+ retry--;
+ } else {
+ break;
+ }
+ } while (retry > 0);
+
+ if (*patch_status == BTMTK_WMT_PATCH_PROGRESS) {
+ bt_dev_err(hdev, "CBMCU patch status query timeout");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int btmtk_query_cbmcu_section(struct hci_dev *hdev,
+ wmt_cmd_sync_func_t wmt_cmd_sync,
+ u8 cbmcu_type,
+ const u8 *section_map,
+ u32 cert_len)
+{
+ struct btmtk_hci_wmt_params wmt_params;
+ u8 cmd[64];
+ int status, err;
+
+ cmd[0] = 0;
+ cmd[1] = cbmcu_type;
+
+ if (cbmcu_type == 0)
+ put_unaligned_le32(cert_len, &cmd[2]);
+ else
+ memcpy(&cmd[2], section_map, MTK_SEC_MAP_NEED_SEND_SIZE);
+
+ wmt_params.op = BTMTK_WMT_CBMCU_DWNLD;
+ wmt_params.flag = 0;
+ wmt_params.dlen = cbmcu_type ?
+ MTK_SEC_MAP_NEED_SEND_SIZE + 2 :
+ MTK_SEC_MAP_LENGTH_SIZE + 2;
+ wmt_params.data = cmd;
+ wmt_params.status = &status;
+
+ err = wmt_cmd_sync(hdev, &wmt_params);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to query CBMCU section (%d)", err);
+ return err;
+ }
+
+ /* Query should return UNDONE status for successful section query */
+ if (status != BTMTK_WMT_PATCH_UNDONE) {
+ bt_dev_err(hdev, "CBMCU section query status error (%d)", status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int btmtk_download_cbmcu_section(struct hci_dev *hdev,
+ wmt_cmd_sync_func_t wmt_cmd_sync,
+ const u8 *fw_data,
+ u32 dl_size)
+{
+ struct btmtk_hci_wmt_params wmt_params;
+ u32 sent_len, total_size = dl_size;
+ int err;
+
+ wmt_params.op = BTMTK_WMT_CBMCU_DWNLD;
+ wmt_params.status = NULL;
+
+ while (dl_size > 0) {
+ sent_len = min_t(u32, 250, dl_size);
+
+ if (dl_size == total_size)
+ wmt_params.flag = BTMTK_WMT_PKT_START;
+ else if (dl_size == sent_len)
+ wmt_params.flag = BTMTK_WMT_PKT_END;
+ else
+ wmt_params.flag = BTMTK_WMT_PKT_CONTINUE;
+
+ wmt_params.dlen = sent_len;
+ wmt_params.data = fw_data;
+
+ err = wmt_cmd_sync(hdev, &wmt_params);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to send CBMCU section data (%d)", err);
+ return err;
+ }
+
+ dl_size -= sent_len;
+ fw_data += sent_len;
+ }
+
+ return 0;
+}
+
+static int btmtk_enable_cbmcu_patch(struct hci_dev *hdev,
+ wmt_cmd_sync_func_t wmt_cmd_sync)
+{
+ struct btmtk_hci_wmt_params wmt_params;
+ int err;
+
+ wmt_params.op = BTMTK_WMT_CBMCU_DWNLD;
+ wmt_params.flag = BTMTK_CBMCU_FLAG_ENABLE_PATCH;
+ wmt_params.dlen = 0;
+ wmt_params.data = NULL;
+ wmt_params.status = NULL;
+
+ err = wmt_cmd_sync(hdev, &wmt_params);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to enable CBMCU patch (%d)", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int btmtk_load_cbmcu_firmware(struct hci_dev *hdev,
+ const char *fwname,
+ wmt_cmd_sync_func_t wmt_cmd_sync,
+ u32 dev_id)
+{
+ struct btmtk_patch_header *hdr;
+ struct btmtk_global_desc *globaldesc;
+ struct btmtk_section_map *sectionmap;
+ const struct firmware *fw;
+ const u8 *fw_ptr;
+ u8 *cert_buf = NULL;
+ u32 section_num, section_offset, dl_size, cert_len;
+ size_t expected_size;
+ int i, err;
+
+ err = request_firmware(&fw, fwname, &hdev->dev);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to load CBMCU firmware file %s (%d)",
+ fwname, err);
+ return err;
+ }
+
+ if (fw->size < MTK_FW_ROM_PATCH_HEADER_SIZE + MTK_FW_ROM_PATCH_GD_SIZE) {
+ bt_dev_err(hdev, "CBMCU firmware too small: size=%zu, min=%u",
+ fw->size,
+ MTK_FW_ROM_PATCH_HEADER_SIZE + MTK_FW_ROM_PATCH_GD_SIZE);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
+ fw_ptr = fw->data;
+ hdr = (struct btmtk_patch_header *)fw_ptr;
+ globaldesc = (struct btmtk_global_desc *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE);
+ section_num = le32_to_cpu(globaldesc->section_num);
+
+ /* Check for potential integer overflow in size calculation */
+ if (check_mul_overflow((size_t)MTK_FW_ROM_PATCH_SEC_MAP_SIZE,
+ (size_t)section_num, &expected_size) ||
+ check_add_overflow(expected_size,
+ (size_t)(MTK_FW_ROM_PATCH_HEADER_SIZE +
+ MTK_FW_ROM_PATCH_GD_SIZE),
+ &expected_size)) {
+ bt_dev_err(hdev, "CBMCU firmware size calculation overflow (section_num=%u)",
+ section_num);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
+ if (fw->size < expected_size) {
+ bt_dev_err(hdev, "CBMCU firmware truncated: size=%zu, expected=%zu (section_num=%u)",
+ fw->size, expected_size, section_num);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
+ bt_dev_info(hdev, "CBMCU HW ver: 0x%04x, SW ver: 0x%04x, Build Time: %.16s",
+ dev_id & 0xffff, le16_to_cpu(hdr->swver), hdr->datetime);
+
+ /* Phase 1: Download section type MTK_SEC_CBMCU_DESC */
+ for (i = 0; i < section_num; i++) {
+ sectionmap = (struct btmtk_section_map *)
+ (fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE +
+ MTK_FW_ROM_PATCH_GD_SIZE +
+ MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i);
+
+ /* Only process MTK_SEC_CBMCU_DESC section in Phase 1 */
+ if ((le32_to_cpu(sectionmap->sectype) & 0xFFFF) != MTK_SEC_CBMCU_DESC)
+ continue;
+
+ section_offset = le32_to_cpu(sectionmap->secoffset);
+ dl_size = le32_to_cpu(sectionmap->secsize);
+
+ if (dl_size == 0)
+ continue;
+
+ if (section_offset > fw->size ||
+ dl_size > fw->size - section_offset) {
+ bt_dev_err(hdev, "CBMCU Phase 1 section out of bounds");
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
+ cert_len = MTK_FW_ROM_PATCH_GD_SIZE +
+ MTK_FW_ROM_PATCH_SEC_MAP_SIZE * section_num +
+ dl_size;
+
+ /* Query cbmcu section */
+ err = btmtk_query_cbmcu_section(hdev, wmt_cmd_sync, 0, NULL,
+ cert_len);
+ if (err < 0)
+ goto err_release_fw;
+
+ cert_buf = kmalloc(cert_len, GFP_KERNEL);
+ if (!cert_buf) {
+ err = -ENOMEM;
+ goto err_release_fw;
+ }
+
+ /* Copy Global Descriptor + All Section Maps */
+ memcpy(cert_buf,
+ fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE,
+ MTK_FW_ROM_PATCH_GD_SIZE + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * section_num);
+
+ /* Copy Phase 1 section data */
+ memcpy(cert_buf + MTK_FW_ROM_PATCH_GD_SIZE +
+ MTK_FW_ROM_PATCH_SEC_MAP_SIZE * section_num,
+ fw_ptr + section_offset,
+ dl_size);
+
+ /* Download Phase 1 section */
+ err = btmtk_download_cbmcu_section(hdev, wmt_cmd_sync,
+ cert_buf, cert_len);
+ kfree(cert_buf);
+ cert_buf = NULL;
+
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to download CBMCU Phase 1 section (%d)", err);
+ goto err_release_fw;
+ }
+
+ break;
+ }
+
+ /* Phase 2: Download other sections (type != MTK_SEC_CBMCU_DESC) */
+ for (i = 0; i < section_num; i++) {
+ sectionmap = (struct btmtk_section_map *)
+ (fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE +
+ MTK_FW_ROM_PATCH_GD_SIZE +
+ MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i);
+
+ /* Skip MTK_SEC_CBMCU_DESC section in Phase 2 */
+ if ((le32_to_cpu(sectionmap->sectype) & 0xFFFF) == MTK_SEC_CBMCU_DESC)
+ continue;
+
+ section_offset = le32_to_cpu(sectionmap->secoffset);
+ dl_size = le32_to_cpu(sectionmap->bin_info_spec.dlsize);
+
+ if (dl_size == 0)
+ continue;
+
+ if (section_offset > fw->size ||
+ dl_size > fw->size - section_offset) {
+ bt_dev_err(hdev, "CBMCU Phase 2 section %d out of bounds", i);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
+ /* Query cbmcu section */
+ err = btmtk_query_cbmcu_section(hdev, wmt_cmd_sync, 1,
+ (u8 *)§ionmap->bin_info_spec,
+ 0);
+ if (err < 0)
+ goto err_release_fw;
+
+ /* Download section data */
+ err = btmtk_download_cbmcu_section(hdev, wmt_cmd_sync,
+ fw_ptr + section_offset,
+ dl_size);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to download CBMCU section %d (%d)", i, err);
+ goto err_release_fw;
+ }
+ }
+
+ bt_dev_info(hdev, "CBMCU firmware download completed");
+
+err_release_fw:
+ release_firmware(fw);
+ return err;
+}
+
+static int btmtk_setup_cbmcu_firmware(struct hci_dev *hdev,
+ wmt_cmd_sync_func_t wmt_cmd_sync,
+ u32 dev_id)
+{
+ char cbmcu_fwname[64];
+ u8 patch_status;
+ int err;
+
+ err = btmtk_cbmcu_patch_status(hdev, wmt_cmd_sync, &patch_status);
+ if (err < 0)
+ return err;
+
+ bt_dev_dbg(hdev, "CBMCU patch status: 0x%02x", patch_status);
+
+ if (patch_status != BTMTK_WMT_PATCH_UNDONE)
+ return 0;
+
+ snprintf(cbmcu_fwname, sizeof(cbmcu_fwname),
+ "mediatek/mt7928/CBMCU_CODE_MT%04x_1_1.bin",
+ dev_id & 0xffff);
+
+ bt_dev_info(hdev, "Loading CBMCU firmware: %s", cbmcu_fwname);
+
+ err = btmtk_load_cbmcu_firmware(hdev, cbmcu_fwname, wmt_cmd_sync, dev_id);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to download CBMCU firmware (%d)", err);
+ return err;
+ }
+
+ err = btmtk_enable_cbmcu_patch(hdev, wmt_cmd_sync);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
{
u32 val;
@@ -935,7 +1292,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
msleep(100);
- } else if (dev_id == 0x7925 || dev_id == 0x6639) {
+ } else if (dev_id == 0x7925 || dev_id == 0x6639 || dev_id == 0x7935) {
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
if (err < 0)
return err;
@@ -1420,6 +1777,15 @@ int btmtk_usb_setup(struct hci_dev *hdev)
case 0x7668:
fwname = FIRMWARE_MT7668;
break;
+ case 0x7935:
+ /* Requires CBMCU firmware before BT firmware */
+ err = btmtk_setup_cbmcu_firmware(hdev, btmtk_usb_hci_wmt_sync,
+ dev_id);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to set up CBMCU firmware (%d)", err);
+ return err;
+ }
+ fallthrough;
case 0x7922:
case 0x7925:
/*
@@ -1637,3 +2003,5 @@ MODULE_FIRMWARE(FIRMWARE_MT7922);
MODULE_FIRMWARE(FIRMWARE_MT7961);
MODULE_FIRMWARE(FIRMWARE_MT7925);
MODULE_FIRMWARE(FIRMWARE_MT7927);
+MODULE_FIRMWARE(FIRMWARE_MT7928);
+MODULE_FIRMWARE(FIRMWARE_MT7928_CBMCU);
diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h
index c234e5ea27e5..2d087d552d31 100644
--- a/drivers/bluetooth/btmtk.h
+++ b/drivers/bluetooth/btmtk.h
@@ -9,6 +9,8 @@
#define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin"
#define FIRMWARE_MT7925 "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin"
#define FIRMWARE_MT7927 "mediatek/mt7927/BT_RAM_CODE_MT6639_2_1_hdr.bin"
+#define FIRMWARE_MT7928 "mediatek/mt7928/BT_RAM_CODE_MT7935_1_1_hdr.bin"
+#define FIRMWARE_MT7928_CBMCU "mediatek/mt7928/CBMCU_CODE_MT7935_1_1.bin"
#define HCI_EV_WMT 0xe4
#define HCI_WMT_MAX_EVENT_SIZE 64
@@ -54,6 +56,7 @@ enum {
BTMTK_WMT_RST = 0x7,
BTMTK_WMT_REGISTER = 0x8,
BTMTK_WMT_SEMAPHORE = 0x17,
+ BTMTK_WMT_CBMCU_DWNLD = 0x58,
};
enum {
--
2.45.2
^ permalink raw reply related
* [PATCH v15 4/7] Bluetooth: btmtksdio: Remove redundant firmware filename override
From: Chris Lu @ 2026-07-17 7:42 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Luiz Von Dentz
Cc: Sean Wang, Will Lee, SS Wu, Steve Lee, Paul Menzel,
linux-bluetooth, linux-kernel, linux-mediatek, Chris Lu
In-Reply-To: <20260717074207.2869999-1-chris.lu@mediatek.com>
btmtksdio_setup() calls btmtk_fw_get_filename() to generate the correct
firmware filename based on device ID and version, then immediately
overwrites it with snprintf() using a generic legacy format.
This redundant override causes newer chips (MT6639, MT7925, MT7928) to
request incorrect firmware filenames, leading to firmware load failures.
For example, MT6639 needs "mediatek/mt7927/BT_RAM_CODE_MT6639_2_1_hdr.bin"
but snprintf() generates "mediatek/BT_RAM_CODE_MT6639_1_1_hdr.bin".
Remove the redundant snprintf() override to use the correct filename
generated by btmtk_fw_get_filename(), matching USB driver behavior.
Fixes: 7f935b21bee4 ("Bluetooth: btmtk: apply the common btmtk_fw_get_filename")
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
---
drivers/bluetooth/btmtksdio.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
index 1fdc24545e41..d895292103bb 100644
--- a/drivers/bluetooth/btmtksdio.c
+++ b/drivers/bluetooth/btmtksdio.c
@@ -1175,9 +1175,6 @@ static int btmtksdio_setup(struct hci_dev *hdev)
btmtk_fw_get_filename(fwname, sizeof(fwname), dev_id,
fw_version, 0);
- snprintf(fwname, sizeof(fwname),
- "mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
- dev_id & 0xffff, (fw_version & 0xff) + 1);
err = mt79xx_setup(hdev, fwname, dev_id);
if (err < 0)
return err;
--
2.45.2
^ permalink raw reply related
* [PATCH v15 5/7] Bluetooth: btmtk: Improve BT firmware logging
From: Chris Lu @ 2026-07-17 7:42 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Luiz Von Dentz
Cc: Sean Wang, Will Lee, SS Wu, Steve Lee, Paul Menzel,
linux-bluetooth, linux-kernel, linux-mediatek, Chris Lu
In-Reply-To: <20260717074207.2869999-1-chris.lu@mediatek.com>
Improve firmware loading log messages to provide more useful information:
- Add firmware filename before loading to help identify which file
is being loaded
- Display chip ID (dev_id) as HW version instead of firmware's hwver
field, which provides more meaningful hardware identification
- Use %.16s format specifier for hdr->datetime field to prevent
potential buffer over-read, as the field is a 16-byte array that
may not be null-terminated
log output with MT7922
[ 212.878783] Bluetooth: hci1: Loading BT firmware: mediatek/BT_RAM_CODE_MT7922_1_1_hdr.bin
[ 212.889614] Bluetooth: hci1: BT HW ver: 0x7922, SW ver: 0x008a, Build Time: 20260224103448
[ 216.048877] Bluetooth: hci1: Device setup in 3096530 usecs
[ 216.048890] Bluetooth: hci1: HCI Enhanced Setup Synchronous Connection command is advertised, but not supported.
[ 216.114179] Bluetooth: hci1: AOSP extensions version v1.00
[ 216.114220] Bluetooth: hci1: AOSP quality report is supported
[ 216.116782] Bluetooth: MGMT ver 1.23
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
Assisted-by: Claude:Sonnet-4.5
---
drivers/bluetooth/btmtk.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index 3491060b3ae9..0fd6ce09a313 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -154,6 +154,8 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
return err;
}
+ bt_dev_info(hdev, "Loading BT firmware: %s", fwname);
+
/* Validate minimum firmware size for header and global descriptor */
if (fw->size < MTK_FW_ROM_PATCH_HEADER_SIZE + MTK_FW_ROM_PATCH_GD_SIZE) {
bt_dev_err(hdev, "Firmware file too small: size=%zu, expected at least %u bytes",
@@ -188,8 +190,8 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
goto err_release_fw;
}
- bt_dev_info(hdev, "HW/SW Version: 0x%04x%04x, Build Time: %s",
- le16_to_cpu(hdr->hwver), le16_to_cpu(hdr->swver), hdr->datetime);
+ bt_dev_info(hdev, "BT HW ver: 0x%04x, SW ver: 0x%04x, Build Time: %.16s",
+ dev_id & 0xffff, le16_to_cpu(hdr->swver), hdr->datetime);
for (i = 0; i < section_num; i++) {
first_block = 1;
--
2.45.2
^ permalink raw reply related
* [PATCH v15 2/7] Bluetooth: btmtk: Add firmware size validation in btmtk_setup_firmware_79xx()
From: Chris Lu @ 2026-07-17 7:42 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Luiz Von Dentz
Cc: Sean Wang, Will Lee, SS Wu, Steve Lee, Paul Menzel,
linux-bluetooth, linux-kernel, linux-mediatek, Chris Lu
In-Reply-To: <20260717074207.2869999-1-chris.lu@mediatek.com>
Add firmware size validation to prevent out-of-bounds access when loading
truncated or malicious firmware files.
Add three levels of validation:
1. Minimum size check for header and global descriptor
2. Section map bounds check with integer overflow protection using
check_mul_overflow() and check_add_overflow()
3. Section data bounds check before accessing each section
This matches the validation approach used in btmtk_load_cbmcu_firmware().
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
Assisted-by: Claude:Sonnet-4.5
---
drivers/bluetooth/btmtk.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index 02a96342e964..3491060b3ae9 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -145,6 +145,7 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
int err, dlen, i, status;
u8 flag, first_block, retry;
u32 section_num, dl_size, section_offset;
+ size_t expected_size;
u8 cmd[64];
err = request_firmware(&fw, fwname, &hdev->dev);
@@ -153,12 +154,40 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
return err;
}
+ /* Validate minimum firmware size for header and global descriptor */
+ if (fw->size < MTK_FW_ROM_PATCH_HEADER_SIZE + MTK_FW_ROM_PATCH_GD_SIZE) {
+ bt_dev_err(hdev, "Firmware file too small: size=%zu, expected at least %u bytes",
+ fw->size, MTK_FW_ROM_PATCH_HEADER_SIZE + MTK_FW_ROM_PATCH_GD_SIZE);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
fw_ptr = fw->data;
fw_bin_ptr = fw_ptr;
hdr = (struct btmtk_patch_header *)fw_ptr;
globaldesc = (struct btmtk_global_desc *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE);
section_num = le32_to_cpu(globaldesc->section_num);
+ /* Check for potential integer overflow in size calculation */
+ if (check_mul_overflow((size_t)MTK_FW_ROM_PATCH_SEC_MAP_SIZE,
+ (size_t)section_num, &expected_size) ||
+ check_add_overflow(expected_size,
+ (size_t)(MTK_FW_ROM_PATCH_HEADER_SIZE +
+ MTK_FW_ROM_PATCH_GD_SIZE),
+ &expected_size)) {
+ bt_dev_err(hdev, "Firmware size calculation overflow (section_num=%u)",
+ section_num);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
+ if (fw->size < expected_size) {
+ bt_dev_err(hdev, "Firmware truncated: size=%zu, expected=%zu (section_num=%u)",
+ fw->size, expected_size, section_num);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
bt_dev_info(hdev, "HW/SW Version: 0x%04x%04x, Build Time: %s",
le16_to_cpu(hdr->hwver), le16_to_cpu(hdr->swver), hdr->datetime);
@@ -171,6 +200,16 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
section_offset = le32_to_cpu(sectionmap->secoffset);
dl_size = le32_to_cpu(sectionmap->bin_info_spec.dlsize);
+ /* Validate section boundaries to prevent out-of-bounds access */
+ if (dl_size > 0 &&
+ (section_offset > fw->size ||
+ dl_size > fw->size - section_offset)) {
+ bt_dev_err(hdev, "Section %d out of bounds: offset=%u, size=%u, fw_size=%zu",
+ i, section_offset, dl_size, fw->size);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
/* MT6639: only download sections where dlmode byte0 == 0x01,
* matching the Windows driver behavior which skips WiFi/other
* sections that would cause the chip to hang.
--
2.45.2
^ permalink raw reply related
* [PATCH v15 6/7] Bluetooth: btmtk: Replace magic numbers with WMT packet flag enum
From: Chris Lu @ 2026-07-17 7:42 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Luiz Von Dentz
Cc: Sean Wang, Will Lee, SS Wu, Steve Lee, Paul Menzel,
linux-bluetooth, linux-kernel, linux-mediatek, Chris Lu
In-Reply-To: <20260717074207.2869999-1-chris.lu@mediatek.com>
Add BTMTK_WMT_PKT_* enum to represent WMT download packet sequence flags,
improving code readability. Replace magic numbers (1, 2, 3) in
btmtk_setup_firmware_79xx() and btmtk_setup_firmware() with descriptive
enum values:
- BTMTK_WMT_PKT_START (1): First packet of a sequence
- BTMTK_WMT_PKT_CONTINUE (2): Continuation packet
- BTMTK_WMT_PKT_END (3): Final packet of a sequence
Signed-off-by: Chris Lu <chris.lu@mediatek.com>
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Assisted-by: Claude:Sonnet-4.5
---
drivers/bluetooth/btmtk.c | 12 ++++++------
drivers/bluetooth/btmtk.h | 6 ++++++
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index 0fd6ce09a313..e059e72d9dbe 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -271,12 +271,12 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
while (dl_size > 0) {
dlen = min_t(int, 250, dl_size);
if (first_block == 1) {
- flag = 1;
+ flag = BTMTK_WMT_PKT_START;
first_block = 0;
} else if (dl_size - dlen <= 0) {
- flag = 3;
+ flag = BTMTK_WMT_PKT_END;
} else {
- flag = 2;
+ flag = BTMTK_WMT_PKT_CONTINUE;
}
wmt_params.flag = flag;
@@ -355,7 +355,7 @@ int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
fw_size -= 30;
fw_ptr += 30;
- flag = 1;
+ flag = BTMTK_WMT_PKT_START;
wmt_params.op = BTMTK_WMT_PATCH_DWNLD;
wmt_params.status = NULL;
@@ -365,9 +365,9 @@ int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
/* Tell device the position in sequence */
if (fw_size - dlen <= 0)
- flag = 3;
+ flag = BTMTK_WMT_PKT_END;
else if (fw_size < fw->size - 30)
- flag = 2;
+ flag = BTMTK_WMT_PKT_CONTINUE;
wmt_params.flag = flag;
wmt_params.dlen = dlen;
diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h
index c83c24897c95..c234e5ea27e5 100644
--- a/drivers/bluetooth/btmtk.h
+++ b/drivers/bluetooth/btmtk.h
@@ -66,6 +66,12 @@ enum {
BTMTK_WMT_ON_PROGRESS,
};
+enum btmtk_wmt_pkt_flag {
+ BTMTK_WMT_PKT_START = 1,
+ BTMTK_WMT_PKT_CONTINUE = 2,
+ BTMTK_WMT_PKT_END = 3,
+};
+
struct btmtk_wmt_hdr {
u8 dir;
u8 op;
--
2.45.2
^ 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