blob: 5de8281fbf9db2fb74baf3e353dd51da4c9e56a9 [file] [log] [blame]
From 5198fe367ce13f541e53a9b70d84fc1ce90be296 Mon Sep 17 00:00:00 2001
From: Joseph Hwang <josephsih@chromium.org>
Date: Fri, 12 Nov 2021 23:21:46 +0800
Subject: [PATCH] CHROMIUM: Bluetooth: surface Intel telemetry events through
mgmt
When receiving a HCI vendor event, the kernel checks if it is an
Intel telemetry event. If yes, the event is sent to bluez user
space through the mgmt socket.
BUG=b:203035611,b:208922349,b:242124116
TEST=Run an audio a2dp or hfp test and check logs.
Signed-off-by: Joseph Hwang <josephsih@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/3299654
Reviewed-by: Archie Pusaka <apusaka@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/3554314
Change-Id: I63681490281b2392aa1ac05dff91a126394ab649
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/3823821
[rebase61(tzungbi):
Squashed:
FIXUP: CHROMIUM: Bluetooth: surface Intel telemetry events through mgmt
FIXUP: CHROMIUM: Bluetooth: surface Intel telemetry events through mgmt
]
Signed-off-by: Tzung-Bi Shih <tzungbi@chromium.org>
Kcr-patch: 0650ebbe52de820c61948c817f23a46b6bbd838bf8271e0f2486e21e.patch
Change-Id: I556bd6fc46b534d286044b20a98d8f78d14b41ce
---
drivers/bluetooth/btintel.c | 43 +++++++++++++++++++++++++++++++-
drivers/bluetooth/btintel.h | 11 ++++++++
include/net/bluetooth/hci_core.h | 2 ++
net/bluetooth/hci_event.c | 12 ++++++---
4 files changed, 64 insertions(+), 4 deletions(-)
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index e7a612504ab1d33908521be39790492dd1fb4e40..37186d2c173e1279e382e66a43864e7c4f7a838e 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -1486,6 +1486,45 @@ static int btintel_register_devcoredump_support(struct hci_dev *hdev)
return err;
}
+#define INTEL_PREFIX 0x8087
+#define TELEMETRY_CODE 0x03
+
+struct intel_prefix_evt_data {
+ __le16 vendor_prefix;
+ __u8 code;
+ __u8 data[0]; /* a number of struct intel_tlv subevents */
+} __packed;
+
+bool btintel_is_quality_report_evt(struct sk_buff *skb)
+{
+ struct intel_prefix_evt_data *ev;
+ u16 vendor_prefix;
+
+ if (skb->len < sizeof(struct intel_prefix_evt_data))
+ return false;
+
+ ev = (struct intel_prefix_evt_data *)skb->data;
+ vendor_prefix = __le16_to_cpu(ev->vendor_prefix);
+
+ return vendor_prefix == INTEL_PREFIX && ev->code == TELEMETRY_CODE;
+}
+EXPORT_SYMBOL_GPL(btintel_is_quality_report_evt);
+
+bool btintel_pull_quality_report_data(struct sk_buff *skb)
+{
+ skb_pull(skb, sizeof(struct intel_prefix_evt_data));
+
+ /* A telemetry event contains at least one intel_tlv subevent. */
+ if (skb->len < sizeof(struct intel_tlv)) {
+ BT_ERR("Telemetry event length %u too short (at least %zu)",
+ skb->len, sizeof(struct intel_tlv));
+ return false;
+ }
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(btintel_pull_quality_report_data);
+
static const struct firmware *btintel_legacy_rom_get_fw(struct hci_dev *hdev,
struct intel_version *ver)
{
@@ -2907,8 +2946,10 @@ static int btintel_setup_combined(struct hci_dev *hdev)
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
- /* Set up the quality report callback for Intel devices */
+ /* Set up the quality report callbacks for Intel devices */
hdev->set_quality_report = btintel_set_quality_report;
+ hdev->is_quality_report_evt = btintel_is_quality_report_evt;
+ hdev->pull_quality_report_data = btintel_pull_quality_report_data;
/* For Legacy device, check the HW platform value and size */
if (skb->len == sizeof(ver) && skb->data[1] == 0x37) {
diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h
index aa70e4c27416535ad31f1932d71883cca2c0b959..ff06eaa03c9a1de44f567f211504e750106f373f 100644
--- a/drivers/bluetooth/btintel.h
+++ b/drivers/bluetooth/btintel.h
@@ -249,6 +249,8 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
int btintel_shutdown_combined(struct hci_dev *hdev);
void btintel_hw_error(struct hci_dev *hdev, u8 code);
void btintel_print_fseq_info(struct hci_dev *hdev);
+bool btintel_is_quality_report_evt(struct sk_buff *skb);
+bool btintel_pull_quality_report_data(struct sk_buff *skb);
#else
static inline int btintel_check_bdaddr(struct hci_dev *hdev)
@@ -382,4 +384,13 @@ static inline void btintel_hw_error(struct hci_dev *hdev, u8 code)
static inline void btintel_print_fseq_info(struct hci_dev *hdev)
{
}
+static inline bool btintel_is_quality_report_evt(struct sk_buff *skb)
+{
+ return false;
+}
+
+static inline bool btintel_pull_quality_report_data(struct sk_buff *skb)
+{
+ return false;
+}
#endif
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 4e43d16080c2c5249876424a7c1f4a79c4605f59..d06ac04e418b03d075c3109590663aba0ba79226 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -649,6 +649,8 @@ struct hci_dev {
struct bt_codec *codec, __u8 *vnd_len,
__u8 **vnd_data);
u8 (*classify_pkt_type)(struct hci_dev *hdev, struct sk_buff *skb);
+ bool (*is_quality_report_evt)(struct sk_buff *skb);
+ bool (*pull_quality_report_data)(struct sk_buff *skb);
};
#define HCI_PHY_HANDLE(handle) (handle & 0xff)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index d29bdfee1db8eda02b763e829da7716b5f07aa75..470255f702554038776d525d8de3e9f84ba9ae8b 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -5582,11 +5582,17 @@ static bool quality_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
if (aosp_has_quality_report(hdev) &&
aosp_pull_quality_report_data(skb))
mgmt_quality_report(hdev, skb, QUALITY_SPEC_AOSP_BQR);
-
- return true;
+ } else if (hdev->is_quality_report_evt &&
+ hdev->is_quality_report_evt(skb)) {
+ if (hdev->set_quality_report &&
+ hdev->pull_quality_report_data(skb))
+ mgmt_quality_report(hdev, skb,
+ QUALITY_SPEC_INTEL_TELEMETRY);
+ } else {
+ return false;
}
- return false;
+ return true;
}
static void hci_vendor_evt(struct hci_dev *hdev, void *data,
--
2.46.0.rc2.264.g509ed76dc8-goog