* [PATCH v2] bluetooth: btintel: Add Bluetooth SAR revision 2 support
@ 2026-06-01 12:48 Kiran K
2026-06-01 18:48 ` [v2] " bluez.test.bot
2026-06-01 20:02 ` [PATCH v2] " Luiz Augusto von Dentz
0 siblings, 2 replies; 3+ messages in thread
From: Kiran K @ 2026-06-01 12:48 UTC (permalink / raw)
To: linux-bluetooth
Cc: ravishankar.srivatsa, chethan.tumkur.narayan, Kiran K, Ravindra
BRDS revision 2 introduces per-chain (Chain A and Chain B) TX power
limits across five sub-bands (2.4G, 5.2G, 5.8/5.9G, 6G-low, 6G-high),
replacing the single-chain per-modulation model of revisions 0 and 1.
- Add btintel_set_sar_rev2() which sends the full Rev2 DDC sequence:
0x019e inc-power-mode enable flag (1 byte)
0x0311 2.4 GHz sub-band limits (2 bytes)
0x0312 5.2 GHz sub-band limits (2 bytes)
0x0313 5.8/5.9 GHz sub-band limits (2 bytes)
0x0314 5.8/5.9 GHz sub-band limits again (2 bytes, duplicate FW reg)
0x0315 6 GHz low sub-band limits (2 bytes)
0x0316 6 GHz high sub-band limits (2 bytes)
followed by the SAR-init-complete command (0xfe25).
logs from dmesg when BTSAR2 is enabled in Coreboot/BIOS:
Bluetooth: hci0: BT SAR Rev2: revision=2 bt_sar_bios=1 inc_power_mode=1
Bluetooth: hci0: BT SAR Rev2 Chain A: 2g4=76 5g2=0 5g8_5g9=0 6g1=0 6g3=0
Bluetooth: hci0: BT SAR Rev2 Chain B: 2g4=102 5g2=0 5g8_5g9=0 6g1=0 6g3=0
Signed-off-by: Ravindra <ravindra@intel.com>
Signed-off-by: Kiran K <kiran.k@intel.com>
---
changes in v2:
- Update commit message to include logs
- Validate the ACPI types/size before accessing.
drivers/bluetooth/btintel.c | 195 +++++++++++++++++++++++++++++++++++-
drivers/bluetooth/btintel.h | 18 ++++
2 files changed, 212 insertions(+), 1 deletion(-)
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index 5e9cac090bd8..3f6e5285c780 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -51,6 +51,7 @@ enum {
#define BTINTEL_BT_DOMAIN 0x12
#define BTINTEL_SAR_LEGACY 0
#define BTINTEL_SAR_INC_PWR 1
+#define BTINTEL_SAR_REV2 2
#define BTINTEL_SAR_INC_PWR_SUPPORTED 0
#define CMD_WRITE_BOOT_PARAMS 0xfc0e
@@ -3104,6 +3105,111 @@ static int btintel_set_mutual_sar(struct hci_dev *hdev, struct btintel_sar_inc_p
return 0;
}
+/* btintel_send_sar_rev2_band - send DDC command for one Rev2 sub-band
+ *
+ * Each DDC 0x0311-0x0316 carries 2 bytes: [ChainA_value, ChainB_value].
+ * cmd->len = 4 (2 id + 2 data)
+ * HCI total = 5 bytes (1 len + 4)
+ */
+static int btintel_send_sar_rev2_band(struct hci_dev *hdev,
+ struct btintel_cp_ddc_write *cmd,
+ u16 id, u8 chain_a, u8 chain_b)
+{
+ cmd->len = 4;
+ cmd->id = cpu_to_le16(id);
+ cmd->data[0] = chain_a;
+ cmd->data[1] = chain_b;
+ return btintel_send_sar_ddc(hdev, cmd, 5);
+}
+
+static int btintel_set_sar_rev2(struct hci_dev *hdev,
+ struct btintel_sar_rev2 *sar)
+{
+ struct btintel_cp_ddc_write *cmd;
+ struct sk_buff *skb;
+ u8 buffer[64];
+ u8 enable;
+ int ret;
+
+ cmd = (void *)buffer;
+
+ /* DDC 0x019e: enable/disable increased power mode SAR (1 byte) */
+ cmd->len = 3;
+ cmd->id = cpu_to_le16(0x019e);
+ cmd->data[0] = (sar->inc_power_mode == BTINTEL_SAR_INC_PWR_SUPPORTED) ?
+ 0x01 : 0x00;
+ ret = btintel_send_sar_ddc(hdev, cmd, 4);
+ if (ret)
+ return ret;
+
+ /* DDC 0x0311-0x0316: per sub-band ChainA + ChainB limits */
+ ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0311,
+ sar->chain_a.subband_2g4,
+ sar->chain_b.subband_2g4);
+ if (ret)
+ return ret;
+
+ ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0312,
+ sar->chain_a.subband_5g2,
+ sar->chain_b.subband_5g2);
+ if (ret)
+ return ret;
+
+ /* 0x0313 and 0x0314 both carry the 5G8/5G9 value */
+ ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0313,
+ sar->chain_a.subband_5g8_5g9,
+ sar->chain_b.subband_5g8_5g9);
+ if (ret)
+ return ret;
+
+ ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0314,
+ sar->chain_a.subband_5g8_5g9,
+ sar->chain_b.subband_5g8_5g9);
+ if (ret)
+ return ret;
+
+ ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0315,
+ sar->chain_a.subband_6g1,
+ sar->chain_b.subband_6g1);
+ if (ret)
+ return ret;
+
+ ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0316,
+ sar->chain_a.subband_6g3,
+ sar->chain_b.subband_6g3);
+ if (ret)
+ return ret;
+
+ /* Notify firmware that SAR initialisation is complete */
+ enable = 0x01;
+ skb = __hci_cmd_sync(hdev, 0xfe25, sizeof(enable), &enable, HCI_CMD_TIMEOUT);
+ if (IS_ERR(skb)) {
+ bt_dev_warn(hdev, "Failed to send Intel SAR Rev2 Enable (%ld)",
+ PTR_ERR(skb));
+ return PTR_ERR(skb);
+ }
+
+ kfree_skb(skb);
+ return 0;
+}
+
+static int btintel_sar_rev2_send_to_device(struct hci_dev *hdev,
+ struct btintel_sar_rev2 *sar,
+ struct intel_version_tlv *ver)
+{
+ u16 cnvi = ver->cnvi_top & 0xfff;
+ u16 cnvr = ver->cnvr_top & 0xfff;
+
+ if (cnvi < BTINTEL_CNVI_BLAZARI || cnvr != BTINTEL_CNVR_WHP2) {
+ bt_dev_dbg(hdev, "BT SAR Rev2 not supported on this platform (cnvi=0x%x cnvr=0x%x)",
+ cnvi, cnvr);
+ return -EOPNOTSUPP;
+ }
+
+ bt_dev_info(hdev, "Applying Bluetooth SAR Rev2");
+ return btintel_set_sar_rev2(hdev, sar);
+}
+
static int btintel_sar_send_to_device(struct hci_dev *hdev, struct btintel_sar_inc_pwr *sar,
struct intel_version_tlv *ver)
{
@@ -3130,6 +3236,7 @@ static int btintel_acpi_set_sar(struct hci_dev *hdev, struct intel_version_tlv *
{
union acpi_object *bt_pkg, *buffer = NULL;
struct btintel_sar_inc_pwr sar;
+ struct btintel_sar_rev2 sar_rev2;
acpi_status status;
u8 revision;
int ret;
@@ -3150,14 +3257,100 @@ static int btintel_acpi_set_sar(struct hci_dev *hdev, struct intel_version_tlv *
goto error;
}
+ if (buffer->package.elements[0].type != ACPI_TYPE_INTEGER) {
+ bt_dev_warn(hdev, "BT_SAR: unexpected ACPI type for revision field");
+ ret = -EINVAL;
+ goto error;
+ }
+
revision = buffer->package.elements[0].integer.value;
- if (revision > BTINTEL_SAR_INC_PWR) {
+ if (revision > BTINTEL_SAR_REV2) {
bt_dev_dbg(hdev, "BT_SAR: revision: 0x%2.2x not supported", revision);
ret = -EOPNOTSUPP;
goto error;
}
+ if (revision == BTINTEL_SAR_REV2 && bt_pkg->package.count == 13) {
+ /* Element layout: 0 = revision, 1 = bt_sar_bios (u32),
+ * 2 = inc_power_mode (u32), 3..12 = per-chain sub-band
+ * limits (u8 each). Validate each ACPI element is an
+ * integer and fits its destination width before we read
+ * the union; otherwise we could misinterpret string
+ * lengths or buffer pointers as TX power limits, or
+ * silently truncate out-of-range BIOS values into a
+ * regulatory-critical sub-band field.
+ */
+ static const u64 rev2_max[13] = {
+ U8_MAX, /* revision */
+ U32_MAX, U32_MAX, /* bt_sar_bios, inc_power_mode */
+ U8_MAX, U8_MAX, U8_MAX, U8_MAX, U8_MAX, /* chain A */
+ U8_MAX, U8_MAX, U8_MAX, U8_MAX, U8_MAX, /* chain B */
+ };
+ union acpi_object *e;
+ int i;
+
+ for (i = 0; i < 13; i++) {
+ e = &bt_pkg->package.elements[i];
+ if (e->type != ACPI_TYPE_INTEGER) {
+ bt_dev_warn(hdev, "BT SAR Rev2: unexpected ACPI type at element %d",
+ i);
+ ret = -EINVAL;
+ goto error;
+ }
+ if (e->integer.value > rev2_max[i]) {
+ bt_dev_warn(hdev, "BT SAR Rev2: element %d value 0x%llx out of range",
+ i, e->integer.value);
+ ret = -ERANGE;
+ goto error;
+ }
+ }
+
+ memset(&sar_rev2, 0, sizeof(sar_rev2));
+ sar_rev2.revision = revision;
+ sar_rev2.bt_sar_bios = bt_pkg->package.elements[1].integer.value;
+ sar_rev2.inc_power_mode = bt_pkg->package.elements[2].integer.value;
+
+ sar_rev2.chain_a.subband_2g4 = bt_pkg->package.elements[3].integer.value;
+ sar_rev2.chain_a.subband_5g2 = bt_pkg->package.elements[4].integer.value;
+ sar_rev2.chain_a.subband_5g8_5g9 = bt_pkg->package.elements[5].integer.value;
+ sar_rev2.chain_a.subband_6g1 = bt_pkg->package.elements[6].integer.value;
+ sar_rev2.chain_a.subband_6g3 = bt_pkg->package.elements[7].integer.value;
+
+ sar_rev2.chain_b.subband_2g4 = bt_pkg->package.elements[8].integer.value;
+ sar_rev2.chain_b.subband_5g2 = bt_pkg->package.elements[9].integer.value;
+ sar_rev2.chain_b.subband_5g8_5g9 = bt_pkg->package.elements[10].integer.value;
+ sar_rev2.chain_b.subband_6g1 = bt_pkg->package.elements[11].integer.value;
+ sar_rev2.chain_b.subband_6g3 = bt_pkg->package.elements[12].integer.value;
+
+ bt_dev_dbg(hdev, "BT SAR Rev2: revision=%u bt_sar_bios=%u inc_power_mode=%u",
+ sar_rev2.revision, sar_rev2.bt_sar_bios, sar_rev2.inc_power_mode);
+ bt_dev_dbg(hdev, "BT SAR Rev2 Chain A: 2g4=%u 5g2=%u 5g8_5g9=%u 6g1=%u 6g3=%u",
+ sar_rev2.chain_a.subband_2g4, sar_rev2.chain_a.subband_5g2,
+ sar_rev2.chain_a.subband_5g8_5g9, sar_rev2.chain_a.subband_6g1,
+ sar_rev2.chain_a.subband_6g3);
+ bt_dev_dbg(hdev, "BT SAR Rev2 Chain B: 2g4=%u 5g2=%u 5g8_5g9=%u 6g1=%u 6g3=%u",
+ sar_rev2.chain_b.subband_2g4, sar_rev2.chain_b.subband_5g2,
+ sar_rev2.chain_b.subband_5g8_5g9, sar_rev2.chain_b.subband_6g1,
+ sar_rev2.chain_b.subband_6g3);
+
+ if (sar_rev2.bt_sar_bios != 1) {
+ bt_dev_info(hdev, "Bluetooth SAR Rev2 is not enabled");
+ ret = -EOPNOTSUPP;
+ goto error;
+ }
+
+ ret = btintel_sar_rev2_send_to_device(hdev, &sar_rev2, ver);
+ goto error;
+ }
+
+ if (revision == BTINTEL_SAR_REV2) {
+ bt_dev_warn(hdev, "BT SAR Rev2: unexpected ACPI package count %d (expected 13)",
+ bt_pkg->package.count);
+ ret = -EINVAL;
+ goto error;
+ }
+
memset(&sar, 0, sizeof(sar));
if (revision == BTINTEL_SAR_LEGACY && bt_pkg->package.count == 8) {
diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h
index 70d812ad36a2..3b5a228ca3c0 100644
--- a/drivers/bluetooth/btintel.h
+++ b/drivers/bluetooth/btintel.h
@@ -64,6 +64,7 @@ struct intel_tlv {
/* CNVR */
#define BTINTEL_CNVR_FMP2 0x910
+#define BTINTEL_CNVR_WHP2 0xA10 /* Whale Peak2 - Panther Lake */
#define BTINTEL_IMG_BOOTLOADER 0x01 /* Bootloader image */
#define BTINTEL_IMG_IML 0x02 /* Intermediate image */
@@ -202,6 +203,23 @@ struct btintel_sar_inc_pwr {
u8 le_lr;
};
+/* Bluetooth SAR feature (BRDS), Revision 2 - per-chain sub-band power limits */
+struct btintel_sar_band_limits {
+ u8 subband_2g4;
+ u8 subband_5g2;
+ u8 subband_5g8_5g9;
+ u8 subband_6g1;
+ u8 subband_6g3;
+};
+
+struct btintel_sar_rev2 {
+ u8 revision;
+ u32 bt_sar_bios; /* 1: BIOS-managed SAR enabled */
+ u32 inc_power_mode; /* 0: supported, 1: disabled */
+ struct btintel_sar_band_limits chain_a;
+ struct btintel_sar_band_limits chain_b;
+};
+
#define INTEL_HW_PLATFORM(cnvx_bt) ((u8)(((cnvx_bt) & 0x0000ff00) >> 8))
#define INTEL_HW_VARIANT(cnvx_bt) ((u8)(((cnvx_bt) & 0x003f0000) >> 16))
#define INTEL_CNVX_TOP_TYPE(cnvx_top) ((cnvx_top) & 0x00000fff)
--
2.54.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* RE: [v2] bluetooth: btintel: Add Bluetooth SAR revision 2 support
2026-06-01 12:48 [PATCH v2] bluetooth: btintel: Add Bluetooth SAR revision 2 support Kiran K
@ 2026-06-01 18:48 ` bluez.test.bot
2026-06-01 20:02 ` [PATCH v2] " Luiz Augusto von Dentz
1 sibling, 0 replies; 3+ messages in thread
From: bluez.test.bot @ 2026-06-01 18:48 UTC (permalink / raw)
To: linux-bluetooth, kiran.k
[-- Attachment #1: Type: text/plain, Size: 1163 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=1104005
---Test result---
Test Summary:
CheckPatch PASS 1.19 seconds
VerifyFixes PASS 0.16 seconds
VerifySignedoff PASS 0.14 seconds
GitLint PASS 0.36 seconds
SubjectPrefix FAIL 0.13 seconds
BuildKernel PASS 28.45 seconds
CheckAllWarning PASS 29.87 seconds
CheckSparse PASS 26.84 seconds
BuildKernel32 PASS 24.85 seconds
TestRunnerSetup PASS 536.15 seconds
IncrementalBuild PASS 24.15 seconds
Details
##############################
Test: SubjectPrefix - FAIL
Desc: Check subject contains "Bluetooth" prefix
Output:
"Bluetooth: " prefix is not specified in the subject
https://github.com/bluez/bluetooth-next/pull/267
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v2] bluetooth: btintel: Add Bluetooth SAR revision 2 support
2026-06-01 12:48 [PATCH v2] bluetooth: btintel: Add Bluetooth SAR revision 2 support Kiran K
2026-06-01 18:48 ` [v2] " bluez.test.bot
@ 2026-06-01 20:02 ` Luiz Augusto von Dentz
1 sibling, 0 replies; 3+ messages in thread
From: Luiz Augusto von Dentz @ 2026-06-01 20:02 UTC (permalink / raw)
To: Kiran K
Cc: linux-bluetooth, ravishankar.srivatsa, chethan.tumkur.narayan,
Ravindra
Hi Kiran,
On Mon, Jun 1, 2026 at 8:29 AM Kiran K <kiran.k@intel.com> wrote:
>
> BRDS revision 2 introduces per-chain (Chain A and Chain B) TX power
> limits across five sub-bands (2.4G, 5.2G, 5.8/5.9G, 6G-low, 6G-high),
> replacing the single-chain per-modulation model of revisions 0 and 1.
>
> - Add btintel_set_sar_rev2() which sends the full Rev2 DDC sequence:
> 0x019e inc-power-mode enable flag (1 byte)
> 0x0311 2.4 GHz sub-band limits (2 bytes)
> 0x0312 5.2 GHz sub-band limits (2 bytes)
> 0x0313 5.8/5.9 GHz sub-band limits (2 bytes)
> 0x0314 5.8/5.9 GHz sub-band limits again (2 bytes, duplicate FW reg)
> 0x0315 6 GHz low sub-band limits (2 bytes)
> 0x0316 6 GHz high sub-band limits (2 bytes)
> followed by the SAR-init-complete command (0xfe25).
>
> logs from dmesg when BTSAR2 is enabled in Coreboot/BIOS:
>
> Bluetooth: hci0: BT SAR Rev2: revision=2 bt_sar_bios=1 inc_power_mode=1
> Bluetooth: hci0: BT SAR Rev2 Chain A: 2g4=76 5g2=0 5g8_5g9=0 6g1=0 6g3=0
> Bluetooth: hci0: BT SAR Rev2 Chain B: 2g4=102 5g2=0 5g8_5g9=0 6g1=0 6g3=0
>
> Signed-off-by: Ravindra <ravindra@intel.com>
> Signed-off-by: Kiran K <kiran.k@intel.com>
> ---
> changes in v2:
> - Update commit message to include logs
> - Validate the ACPI types/size before accessing.
>
> drivers/bluetooth/btintel.c | 195 +++++++++++++++++++++++++++++++++++-
> drivers/bluetooth/btintel.h | 18 ++++
> 2 files changed, 212 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
> index 5e9cac090bd8..3f6e5285c780 100644
> --- a/drivers/bluetooth/btintel.c
> +++ b/drivers/bluetooth/btintel.c
> @@ -51,6 +51,7 @@ enum {
> #define BTINTEL_BT_DOMAIN 0x12
> #define BTINTEL_SAR_LEGACY 0
> #define BTINTEL_SAR_INC_PWR 1
> +#define BTINTEL_SAR_REV2 2
> #define BTINTEL_SAR_INC_PWR_SUPPORTED 0
>
> #define CMD_WRITE_BOOT_PARAMS 0xfc0e
> @@ -3104,6 +3105,111 @@ static int btintel_set_mutual_sar(struct hci_dev *hdev, struct btintel_sar_inc_p
> return 0;
> }
>
> +/* btintel_send_sar_rev2_band - send DDC command for one Rev2 sub-band
> + *
> + * Each DDC 0x0311-0x0316 carries 2 bytes: [ChainA_value, ChainB_value].
> + * cmd->len = 4 (2 id + 2 data)
> + * HCI total = 5 bytes (1 len + 4)
> + */
> +static int btintel_send_sar_rev2_band(struct hci_dev *hdev,
> + struct btintel_cp_ddc_write *cmd,
> + u16 id, u8 chain_a, u8 chain_b)
> +{
> + cmd->len = 4;
> + cmd->id = cpu_to_le16(id);
> + cmd->data[0] = chain_a;
> + cmd->data[1] = chain_b;
> + return btintel_send_sar_ddc(hdev, cmd, 5);
> +}
> +
> +static int btintel_set_sar_rev2(struct hci_dev *hdev,
> + struct btintel_sar_rev2 *sar)
> +{
> + struct btintel_cp_ddc_write *cmd;
> + struct sk_buff *skb;
> + u8 buffer[64];
> + u8 enable;
> + int ret;
> +
> + cmd = (void *)buffer;
> +
> + /* DDC 0x019e: enable/disable increased power mode SAR (1 byte) */
> + cmd->len = 3;
> + cmd->id = cpu_to_le16(0x019e);
> + cmd->data[0] = (sar->inc_power_mode == BTINTEL_SAR_INC_PWR_SUPPORTED) ?
> + 0x01 : 0x00;
> + ret = btintel_send_sar_ddc(hdev, cmd, 4);
> + if (ret)
> + return ret;
> +
> + /* DDC 0x0311-0x0316: per sub-band ChainA + ChainB limits */
> + ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0311,
> + sar->chain_a.subband_2g4,
> + sar->chain_b.subband_2g4);
> + if (ret)
> + return ret;
> +
> + ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0312,
> + sar->chain_a.subband_5g2,
> + sar->chain_b.subband_5g2);
> + if (ret)
> + return ret;
> +
> + /* 0x0313 and 0x0314 both carry the 5G8/5G9 value */
> + ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0313,
> + sar->chain_a.subband_5g8_5g9,
> + sar->chain_b.subband_5g8_5g9);
> + if (ret)
> + return ret;
> +
> + ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0314,
> + sar->chain_a.subband_5g8_5g9,
> + sar->chain_b.subband_5g8_5g9);
> + if (ret)
> + return ret;
> +
> + ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0315,
> + sar->chain_a.subband_6g1,
> + sar->chain_b.subband_6g1);
> + if (ret)
> + return ret;
> +
> + ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0316,
> + sar->chain_a.subband_6g3,
> + sar->chain_b.subband_6g3);
> + if (ret)
> + return ret;
> +
> + /* Notify firmware that SAR initialisation is complete */
> + enable = 0x01;
> + skb = __hci_cmd_sync(hdev, 0xfe25, sizeof(enable), &enable, HCI_CMD_TIMEOUT);
> + if (IS_ERR(skb)) {
> + bt_dev_warn(hdev, "Failed to send Intel SAR Rev2 Enable (%ld)",
> + PTR_ERR(skb));
> + return PTR_ERR(skb);
> + }
> +
> + kfree_skb(skb);
> + return 0;
> +}
> +
> +static int btintel_sar_rev2_send_to_device(struct hci_dev *hdev,
> + struct btintel_sar_rev2 *sar,
> + struct intel_version_tlv *ver)
> +{
> + u16 cnvi = ver->cnvi_top & 0xfff;
> + u16 cnvr = ver->cnvr_top & 0xfff;
> +
> + if (cnvi < BTINTEL_CNVI_BLAZARI || cnvr != BTINTEL_CNVR_WHP2) {
> + bt_dev_dbg(hdev, "BT SAR Rev2 not supported on this platform (cnvi=0x%x cnvr=0x%x)",
> + cnvi, cnvr);
> + return -EOPNOTSUPP;
> + }
> +
> + bt_dev_info(hdev, "Applying Bluetooth SAR Rev2");
> + return btintel_set_sar_rev2(hdev, sar);
> +}
> +
> static int btintel_sar_send_to_device(struct hci_dev *hdev, struct btintel_sar_inc_pwr *sar,
> struct intel_version_tlv *ver)
> {
> @@ -3130,6 +3236,7 @@ static int btintel_acpi_set_sar(struct hci_dev *hdev, struct intel_version_tlv *
> {
> union acpi_object *bt_pkg, *buffer = NULL;
> struct btintel_sar_inc_pwr sar;
> + struct btintel_sar_rev2 sar_rev2;
> acpi_status status;
> u8 revision;
> int ret;
> @@ -3150,14 +3257,100 @@ static int btintel_acpi_set_sar(struct hci_dev *hdev, struct intel_version_tlv *
> goto error;
> }
>
> + if (buffer->package.elements[0].type != ACPI_TYPE_INTEGER) {
> + bt_dev_warn(hdev, "BT_SAR: unexpected ACPI type for revision field");
> + ret = -EINVAL;
> + goto error;
> + }
> +
> revision = buffer->package.elements[0].integer.value;
>
> - if (revision > BTINTEL_SAR_INC_PWR) {
> + if (revision > BTINTEL_SAR_REV2) {
> bt_dev_dbg(hdev, "BT_SAR: revision: 0x%2.2x not supported", revision);
> ret = -EOPNOTSUPP;
> goto error;
> }
>
> + if (revision == BTINTEL_SAR_REV2 && bt_pkg->package.count == 13) {
> + /* Element layout: 0 = revision, 1 = bt_sar_bios (u32),
> + * 2 = inc_power_mode (u32), 3..12 = per-chain sub-band
> + * limits (u8 each). Validate each ACPI element is an
> + * integer and fits its destination width before we read
> + * the union; otherwise we could misinterpret string
> + * lengths or buffer pointers as TX power limits, or
> + * silently truncate out-of-range BIOS values into a
> + * regulatory-critical sub-band field.
> + */
> + static const u64 rev2_max[13] = {
> + U8_MAX, /* revision */
https://sashiko.dev/#/patchset/20260601124825.216489-1-kiran.k%40intel.com
Looks like Sashiko has some comments regarding this.
> + U32_MAX, U32_MAX, /* bt_sar_bios, inc_power_mode */
> + U8_MAX, U8_MAX, U8_MAX, U8_MAX, U8_MAX, /* chain A */
> + U8_MAX, U8_MAX, U8_MAX, U8_MAX, U8_MAX, /* chain B */
> + };
> + union acpi_object *e;
> + int i;
> +
> + for (i = 0; i < 13; i++) {
> + e = &bt_pkg->package.elements[i];
> + if (e->type != ACPI_TYPE_INTEGER) {
> + bt_dev_warn(hdev, "BT SAR Rev2: unexpected ACPI type at element %d",
> + i);
> + ret = -EINVAL;
> + goto error;
> + }
> + if (e->integer.value > rev2_max[i]) {
> + bt_dev_warn(hdev, "BT SAR Rev2: element %d value 0x%llx out of range",
> + i, e->integer.value);
> + ret = -ERANGE;
> + goto error;
> + }
> + }
> +
> + memset(&sar_rev2, 0, sizeof(sar_rev2));
> + sar_rev2.revision = revision;
> + sar_rev2.bt_sar_bios = bt_pkg->package.elements[1].integer.value;
> + sar_rev2.inc_power_mode = bt_pkg->package.elements[2].integer.value;
> +
> + sar_rev2.chain_a.subband_2g4 = bt_pkg->package.elements[3].integer.value;
> + sar_rev2.chain_a.subband_5g2 = bt_pkg->package.elements[4].integer.value;
> + sar_rev2.chain_a.subband_5g8_5g9 = bt_pkg->package.elements[5].integer.value;
> + sar_rev2.chain_a.subband_6g1 = bt_pkg->package.elements[6].integer.value;
> + sar_rev2.chain_a.subband_6g3 = bt_pkg->package.elements[7].integer.value;
> +
> + sar_rev2.chain_b.subband_2g4 = bt_pkg->package.elements[8].integer.value;
> + sar_rev2.chain_b.subband_5g2 = bt_pkg->package.elements[9].integer.value;
> + sar_rev2.chain_b.subband_5g8_5g9 = bt_pkg->package.elements[10].integer.value;
> + sar_rev2.chain_b.subband_6g1 = bt_pkg->package.elements[11].integer.value;
> + sar_rev2.chain_b.subband_6g3 = bt_pkg->package.elements[12].integer.value;
> +
> + bt_dev_dbg(hdev, "BT SAR Rev2: revision=%u bt_sar_bios=%u inc_power_mode=%u",
> + sar_rev2.revision, sar_rev2.bt_sar_bios, sar_rev2.inc_power_mode);
> + bt_dev_dbg(hdev, "BT SAR Rev2 Chain A: 2g4=%u 5g2=%u 5g8_5g9=%u 6g1=%u 6g3=%u",
> + sar_rev2.chain_a.subband_2g4, sar_rev2.chain_a.subband_5g2,
> + sar_rev2.chain_a.subband_5g8_5g9, sar_rev2.chain_a.subband_6g1,
> + sar_rev2.chain_a.subband_6g3);
> + bt_dev_dbg(hdev, "BT SAR Rev2 Chain B: 2g4=%u 5g2=%u 5g8_5g9=%u 6g1=%u 6g3=%u",
> + sar_rev2.chain_b.subband_2g4, sar_rev2.chain_b.subband_5g2,
> + sar_rev2.chain_b.subband_5g8_5g9, sar_rev2.chain_b.subband_6g1,
> + sar_rev2.chain_b.subband_6g3);
> +
> + if (sar_rev2.bt_sar_bios != 1) {
> + bt_dev_info(hdev, "Bluetooth SAR Rev2 is not enabled");
If you are going to return an erro I guess a bt_dev_warn is probably
better here, if this is not an unexpected error then bt_dev_dbg is
probably better. Actually shouldn't you stop loading if bt_sar_bios
doesn't match? Otherwise you might print entries that don't correspond
to the expected fields above, so I'd just bail out early and stop
loading after checking it.
> + ret = -EOPNOTSUPP;
> + goto error;
> + }
> +
> + ret = btintel_sar_rev2_send_to_device(hdev, &sar_rev2, ver);
> + goto error;
> + }
> +
> + if (revision == BTINTEL_SAR_REV2) {
> + bt_dev_warn(hdev, "BT SAR Rev2: unexpected ACPI package count %d (expected 13)",
> + bt_pkg->package.count);
> + ret = -EINVAL;
> + goto error;
> + }
> +
> memset(&sar, 0, sizeof(sar));
>
> if (revision == BTINTEL_SAR_LEGACY && bt_pkg->package.count == 8) {
> diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h
> index 70d812ad36a2..3b5a228ca3c0 100644
> --- a/drivers/bluetooth/btintel.h
> +++ b/drivers/bluetooth/btintel.h
> @@ -64,6 +64,7 @@ struct intel_tlv {
>
> /* CNVR */
> #define BTINTEL_CNVR_FMP2 0x910
> +#define BTINTEL_CNVR_WHP2 0xA10 /* Whale Peak2 - Panther Lake */
>
> #define BTINTEL_IMG_BOOTLOADER 0x01 /* Bootloader image */
> #define BTINTEL_IMG_IML 0x02 /* Intermediate image */
> @@ -202,6 +203,23 @@ struct btintel_sar_inc_pwr {
> u8 le_lr;
> };
>
> +/* Bluetooth SAR feature (BRDS), Revision 2 - per-chain sub-band power limits */
> +struct btintel_sar_band_limits {
> + u8 subband_2g4;
> + u8 subband_5g2;
> + u8 subband_5g8_5g9;
> + u8 subband_6g1;
> + u8 subband_6g3;
> +};
> +
> +struct btintel_sar_rev2 {
> + u8 revision;
> + u32 bt_sar_bios; /* 1: BIOS-managed SAR enabled */
> + u32 inc_power_mode; /* 0: supported, 1: disabled */
> + struct btintel_sar_band_limits chain_a;
> + struct btintel_sar_band_limits chain_b;
> +};
> +
> #define INTEL_HW_PLATFORM(cnvx_bt) ((u8)(((cnvx_bt) & 0x0000ff00) >> 8))
> #define INTEL_HW_VARIANT(cnvx_bt) ((u8)(((cnvx_bt) & 0x003f0000) >> 16))
> #define INTEL_CNVX_TOP_TYPE(cnvx_top) ((cnvx_top) & 0x00000fff)
> --
> 2.54.0
>
>
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-06-01 20:03 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-01 12:48 [PATCH v2] bluetooth: btintel: Add Bluetooth SAR revision 2 support Kiran K
2026-06-01 18:48 ` [v2] " bluez.test.bot
2026-06-01 20:02 ` [PATCH v2] " Luiz Augusto von Dentz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox