| 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 |
| |