Received: by 2002:a05:6a10:af89:0:0:0:0 with SMTP id iu9csp1613659pxb; Sat, 22 Jan 2022 01:19:45 -0800 (PST) X-Google-Smtp-Source: ABdhPJypnwhpmqgM17vI6OW+acLuYWetM8b8k4y8Z5Qr113ZJc0+nyoij+RcEusz+zqozI7X2j8A X-Received: by 2002:a05:6a00:1312:b0:4c4:cffa:a4c0 with SMTP id j18-20020a056a00131200b004c4cffaa4c0mr6797695pfu.79.1642843185288; Sat, 22 Jan 2022 01:19:45 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1642843185; cv=none; d=google.com; s=arc-20160816; b=sxkzm0vQ2x2uVCOVONquHc1oNAvbgGv4kccRet6dAkAMR0QBYxInQZbipbWKRYC8RT MTxxMXAaA4fh2kRaMeBVYA1vzg1189+HIF7D2tdns+/flWwD7yAW9h/r5kkgtDS+WZtD KOolDx3YGCxbQF89OFve22S29o4Cg/eLdtyenJFgkhGKVXYB58sYu19PVpVmnVnusetA nZ0MBGljUkR4LHG/KVuaHoiZTLvqYlqxiwwee1JcSmrDigukxRLyBl5yUFzjMepZIhI2 s8ozK1YenUshaC0krTU0i/K4YDfsEIpdoJ6txKOaof8pgvPAfa8zSTllcU/tWJ6gGVdz 5CjA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:subject:message-id:date:from:in-reply-to :references:mime-version:dkim-signature; bh=fQ+GmLkXJapzIS354NK2MMOO/unTseSGpKwz8CNvbQo=; b=txen2JDf+vFXMR0EbLMEbU60lxqgGtREHz7BleqN3QvO+mxZCS8J9PfsX+MIWOVEIt dwfUlAs0vgcBFIVPeMGXt98mskbLdYIXkP6Wdrsz6OQmWkMkhjPJghXa1jD77jr4lY1y XxdEn42IY2zgI1lb32XJnaKQ7lHEf9DzepvFZv+MiSVYOlkjzF7mrWWPkkFm86DSQSYm ffscI1Utqo71cU1lXToPF6d/lDFHKn8nUqAm+us3q6c0TETTs9PSCnszNzJc0cINdhvl 5IYzEPcMuIoQbEKzc/qhY1wxH3XBvN0Iy/1VgAvTM0jdavNMW0HuaIiiBVl1bIBfzI2+ x6uA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=Qcbz4Rx4; spf=pass (google.com: domain of linux-bluetooth-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-bluetooth-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id c9si7818425plo.491.2022.01.22.01.19.25; Sat, 22 Jan 2022 01:19:45 -0800 (PST) Received-SPF: pass (google.com: domain of linux-bluetooth-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=Qcbz4Rx4; spf=pass (google.com: domain of linux-bluetooth-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-bluetooth-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229587AbiAUVLP (ORCPT + 99 others); Fri, 21 Jan 2022 16:11:15 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51236 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229520AbiAUVLO (ORCPT ); Fri, 21 Jan 2022 16:11:14 -0500 Received: from mail-yb1-xb2b.google.com (mail-yb1-xb2b.google.com [IPv6:2607:f8b0:4864:20::b2b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8AEEEC06173B for ; Fri, 21 Jan 2022 13:11:14 -0800 (PST) Received: by mail-yb1-xb2b.google.com with SMTP id g81so31032940ybg.10 for ; Fri, 21 Jan 2022 13:11:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=fQ+GmLkXJapzIS354NK2MMOO/unTseSGpKwz8CNvbQo=; b=Qcbz4Rx4eOwZ68+yTUi3HhzSQ5a/PQyhK6VKbqmyExoavDZY9B82LDQd5PQuKpfCnS DlfjUXf0Gx0HNEpcDxFttamiBLCwCoyxOSMbRrFoGd+6hZ+22E2a7fSwRoL+/iHLjF9R HalmSvTtLwkslIYnTptkHxFisxRaS0TZEQQh75QGHYVIwAgDUVaee2pKD/Xfmj8zUGjB 8km3oe+DvTbvAtZsfkAOyfDajAe1dltz5xL/i9vFpfeH86I/BfdW9Psqs7gwDzyJZua5 PntLAYoJZkWLK29Kry2B8x0qEGWzydHbYGfjaYTNxWTCnt3I8PG41K1DIcHME7sU3q8b kgtw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=fQ+GmLkXJapzIS354NK2MMOO/unTseSGpKwz8CNvbQo=; b=QA2djSVzCkdMJ/XYDrN+U42r2RkFwafopUHypMM2j4B4vjign6vOA+qJRPoUpzirfR SY6oJNHKJj/j410bKjWRy54P10DkMZCSmuansaduYAG58Z2WuF2CN3lKK80TX0RK0sew aFLXvJ5+eZLw0kgHMKDjOPbDm22pB8vyQhPIbCNLGMBqPfaKGQUhWc5FKbxk3spzktjI JMWCFIvkAfGCHoFhLH21CvXKmZsvBXbnOo+t+IASh8tALKBZNdYr9LsQugxvn7hB6Xyi aYPuqxw4fvHLjFVaD+Qa3KbSs66sPN9Z+bbo+QTFGhjetA8VuESGU4S1RVcYFuQG9Kyu P9hA== X-Gm-Message-State: AOAM532+j1kClbeU3Tka0eYDfkmkznp7T0F4C60PhgaCWDRYrh5MPull fqvjUWrGslXWI7JFb+s8t+9HNkGL5UNYXKHAIGg= X-Received: by 2002:a25:bd8d:: with SMTP id f13mr8814031ybh.573.1642799473457; Fri, 21 Jan 2022 13:11:13 -0800 (PST) MIME-Version: 1.0 References: <20220121192352.BlueZ.v1.1.Ie4d1be8ced51f0aa92ee6d8eacf9666a121a1292@changeid> <20220121192352.BlueZ.v1.2.Ifdf5cf89a14b4f293d868910c6cb85e802f7eb9e@changeid> In-Reply-To: <20220121192352.BlueZ.v1.2.Ifdf5cf89a14b4f293d868910c6cb85e802f7eb9e@changeid> From: Luiz Augusto von Dentz Date: Fri, 21 Jan 2022 13:11:02 -0800 Message-ID: Subject: Re: [BlueZ PATCH v1 2/2] adapter: support Intel MGMT_EV_QUALITY_REPORT To: Joseph Hwang Cc: "linux-bluetooth@vger.kernel.org" , Marcel Holtmann , =?UTF-8?Q?Pali_Roh=C3=A1r?= , ChromeOS Bluetooth Upstreaming , Joseph Hwang , Archie Pusaka Content-Type: text/plain; charset="UTF-8" Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org Hi Joseph, On Fri, Jan 21, 2022 at 3:24 AM Joseph Hwang wrote: > > This patch supports a new MGMT event of Intel telemetry report. > > An ACL telemetry report looks like: > > quality: Intel Extended Telemetry Event > quality: ACL connection handle: 0x0100 > quality: Rx HEC errors: 0 > quality: Rx CRC errors: 0 > quality: Packets from host: 424 > quality: Tx packets: 425 > quality: Tx packets 0 retries: 391 > quality: Tx packets 1 retries: 33 > quality: Tx packets 2 retries: 1 > quality: Tx packets 3 retries: 0 > quality: Tx packets 4 retries: 0 > quality: Tx DH1 packets: 0 > quality: Tx DH3 packets: 0 > quality: Tx DH5 packets: 0 > quality: Tx 2DH1 packets: 0 > quality: Tx 2DH3 packets: 0 > quality: Tx 2DH5 packets: 0 > quality: Tx 3DH1 packets: 9 > quality: Tx 3DH3 packets: 0 > quality: Tx 3DH5 packets: 415 > quality: Rx packets: 1568 > quality: ACL link throughput: 34071 > quality: ACL max packet latency: 44375 > quality: ACL avg packet latency: 13 > > A SCO telemetry report looks like: > > quality: Intel Extended Telemetry Event > quality: SCO connection handle: 0x010a > quality: Packets from host: 667 > quality: Tx packets: 667 > quality: Rx payload lost: 5 > quality: Tx payload lost: 36 > quality: Rx No SYNC errors (slot 0): 11 > quality: Rx No SYNC errors (slot 1): 32 > quality: Rx No SYNC errors (slot 2): 33 > quality: Rx No SYNC errors (slot 3): 13 > quality: Rx No SYNC errors (slot 4): 0 > quality: Rx HEC errors (slot 0): 9 > quality: Rx HEC errors (slot 1): 4 > quality: Rx HEC errors (slot 2): 0 > quality: Rx HEC errors (slot 3): 0 > quality: Rx HEC errors (slot 4): 0 > quality: Rx CRC errors (slot 0): 9 > quality: Rx CRC errors (slot 1): 2 > quality: Rx CRC errors (slot 2): 0 > quality: Rx CRC errors (slot 3): 0 > quality: Rx CRC errors (slot 4): 0 > quality: Rx NAK errors (slot 0): 647 > quality: Rx NAK errors (slot 1): 14 > quality: Rx NAK errors (slot 2): 2 > quality: Rx NAK errors (slot 3): 0 > quality: Rx NAK errors (slot 4): 0 > quality: Failed Tx due to Wifi coex (slot 0): 0 > quality: Failed Tx due to Wifi coex (slot 1): 0 > quality: Failed Tx due to Wifi coex (slot 2): 0 > quality: Failed Tx due to Wifi coex (slot 3): 0 > quality: Failed Tx due to Wifi coex (slot 4): 0 > quality: Failed Rx due to Wifi coex (slot 0): 0 > quality: Failed Rx due to Wifi coex (slot 1): 0 > quality: Failed Rx due to Wifi coex (slot 2): 0 > quality: Failed Rx due to Wifi coex (slot 3): 0 > quality: Failed Rx due to Wifi coex (slot 4): 0 > quality: Late samples inserted based on CDC: 0 > quality: Samples dropped: 0 > quality: Mute samples sent at initial connection: 0 > quality: PLC injection data: 0 > > Reviewed-by: Archie Pusaka > Signed-off-by: Joseph Hwang > --- > > Makefile.am | 3 +- > src/adapter.c | 9 +- > src/shared/intel.c | 327 +++++++++++++++++++++++++++++++++++++++++++++ > src/shared/intel.h | 155 +++++++++++++++++++++ > 4 files changed, 492 insertions(+), 2 deletions(-) > create mode 100644 src/shared/intel.c > create mode 100644 src/shared/intel.h > > diff --git a/Makefile.am b/Makefile.am > index baab40369..abbe3897b 100644 > --- a/Makefile.am > +++ b/Makefile.am > @@ -231,7 +231,8 @@ shared_sources = src/shared/io.h src/shared/timeout.h \ > src/shared/gap.h src/shared/gap.c \ > src/shared/log.h src/shared/log.c \ > src/shared/tty.h \ > - src/shared/aosp.h src/shared/aosp.c > + src/shared/aosp.h src/shared/aosp.c \ > + src/shared/intel.h src/shared/intel.c > > if READLINE > shared_sources += src/shared/shell.c src/shared/shell.h > diff --git a/src/adapter.c b/src/adapter.c > index 03f0e1ca6..6f3bf495d 100644 > --- a/src/adapter.c > +++ b/src/adapter.c > @@ -48,6 +48,7 @@ > #include "src/shared/gatt-db.h" > #include "src/shared/timeout.h" > #include "src/shared/aosp.h" > +#include "src/shared/intel.h" > > #include "btio/btio.h" > #include "btd.h" > @@ -9331,6 +9332,9 @@ static void quality_report_callback(uint16_t index, uint16_t length, > if (ev->quality_spec == QUALITY_SPEC_AOSP_BQR) { > if (!process_aosp_quality_report(ev)) > error("processing aosp quality report"); > + } else if (ev->quality_spec == QUALITY_SPEC_INTEL_TELEMETRY) { > + if (!process_intel_telemetry_report(ev)) > + error("processing intel telemetry report"); > } else { > error("quality report spec %u not supported.", > ev->quality_spec); > @@ -9929,7 +9933,10 @@ static void quality_report_debug(const char *str, void *user_data) > > static void quality_set_debug(struct btd_adapter *adapter) > { > - aosp_set_debug(quality_report_debug, "quality: "); > + if (is_manufacturer_intel(adapter->manufacturer)) > + intel_set_debug(quality_report_debug, "quality: "); > + else > + aosp_set_debug(quality_report_debug, "quality: "); > } > > static void read_info_complete(uint8_t status, uint16_t length, > diff --git a/src/shared/intel.c b/src/shared/intel.c > new file mode 100644 > index 000000000..87cc300dc > --- /dev/null > +++ b/src/shared/intel.c > @@ -0,0 +1,327 @@ > +// SPDX-License-Identifier: LGPL-2.1-or-later > +/* > + * > + * BlueZ - Bluetooth protocol stack for Linux > + * > + * Copyright (C) 2021 Google LLC > + * > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + */ > + > +#include > +#include > +#include > +#include > + > +#include "lib/bluetooth.h" > +#include "lib/mgmt.h" > + > +#include "src/shared/intel.h" > +#include "src/shared/util.h" > + > +#define COMPANY_ID_INTEL 0x0002 > + > +struct intel_ext_telemetry_event tev; > + > +static struct { > + intel_debug_func_t callback; > + void *data; > +} intel_debug; > + > +static char *bredr_packet_type[INTEL_NUM_PACKET_TYPES] = { > + "DH1", > + "DH3", > + "DH5", > + "2DH1", > + "2DH3", > + "2DH5", > + "3DH1", > + "3DH3", > + "3DH5", > +}; > + > +/* Use offsetof to access the attributes of structures. This makes > + * simple traversing and assigning values to the attributes. > + */ > +#define TELEM_OFFSET(a) offsetof(struct intel_ext_telemetry_event, a) > +#define TELEM_ATTR(a) (((uint8_t *)&tev) + TELEM_OFFSET(a)) > + > +#define ACL_OFFSET(a) offsetof(struct intel_acl_event, a) > +#define ACL_ATTR(a) (((uint8_t *)&tev.conn.acl) + ACL_OFFSET(a)) > +#define ACL_ATTR_ARRAY(a, i) (ACL_ATTR(a) + i * sizeof(tev.conn.acl.a[0])) > + > +#define SCO_OFFSET(a) offsetof(struct intel_sco_event, a) > +#define SCO_ATTR(a) (((uint8_t *)&tev.conn.sco) + SCO_OFFSET(a)) > + > +static const struct intel_ext_subevent { > + uint8_t id; > + uint8_t size; > + uint8_t elements; > + uint8_t *attr; /* address of the attribute in tev */ > +} intel_ext_subevent_table[] = { > + { 0x01, 1, 1, TELEM_ATTR(telemetry_ev_type) }, > + > + /* ACL audio link quality subevents */ > + { 0x4a, 2, 1, ACL_ATTR(conn_handle) }, > + { 0x4b, 4, 1, ACL_ATTR(rx_hec_error) }, > + { 0x4c, 4, 1, ACL_ATTR(rx_crc_error) }, > + { 0x4d, 4, 1, ACL_ATTR(packets_from_host) }, > + { 0x4e, 4, 1, ACL_ATTR(tx_packets) }, > + { 0x4f, 4, 1, ACL_ATTR_ARRAY(tx_packets_retry, 0) }, > + { 0x50, 4, 1, ACL_ATTR_ARRAY(tx_packets_retry, 1) }, > + { 0x51, 4, 1, ACL_ATTR_ARRAY(tx_packets_retry, 2) }, > + { 0x52, 4, 1, ACL_ATTR_ARRAY(tx_packets_retry, 3) }, > + { 0x53, 4, 1, ACL_ATTR_ARRAY(tx_packets_retry, 4) }, > + { 0x54, 4, 1, ACL_ATTR_ARRAY(tx_packets_by_type, 0) }, > + { 0x55, 4, 1, ACL_ATTR_ARRAY(tx_packets_by_type, 1) }, > + { 0x56, 4, 1, ACL_ATTR_ARRAY(tx_packets_by_type, 2) }, > + { 0x57, 4, 1, ACL_ATTR_ARRAY(tx_packets_by_type, 3) }, > + { 0x58, 4, 1, ACL_ATTR_ARRAY(tx_packets_by_type, 4) }, > + { 0x59, 4, 1, ACL_ATTR_ARRAY(tx_packets_by_type, 5) }, > + { 0x5a, 4, 1, ACL_ATTR_ARRAY(tx_packets_by_type, 6) }, > + { 0x5b, 4, 1, ACL_ATTR_ARRAY(tx_packets_by_type, 7) }, > + { 0x5c, 4, 1, ACL_ATTR_ARRAY(tx_packets_by_type, 8) }, > + { 0x5d, 4, 1, ACL_ATTR(rx_packets) }, > + { 0x5e, 4, 1, ACL_ATTR(link_throughput) }, > + { 0x5f, 4, 1, ACL_ATTR(max_packet_letency) }, > + { 0x60, 4, 1, ACL_ATTR(avg_packet_letency) }, > + > + /* SCO/eSCO audio link quality subevents */ > + { 0x6a, 2, 1, SCO_ATTR(conn_handle) }, > + { 0x6b, 4, 1, SCO_ATTR(packets_from_host) }, > + { 0x6c, 4, 1, SCO_ATTR(tx_packets) }, > + { 0x6d, 4, 1, SCO_ATTR(rx_payload_lost) }, > + { 0x6e, 4, 1, SCO_ATTR(tx_payload_lost) }, > + { 0x6f, 4, 5, SCO_ATTR(rx_no_sync_error) }, > + { 0x70, 4, 5, SCO_ATTR(rx_hec_error) }, > + { 0x71, 4, 5, SCO_ATTR(rx_crc_error) }, > + { 0x72, 4, 5, SCO_ATTR(rx_nak_error) }, > + { 0x73, 4, 5, SCO_ATTR(tx_failed_wifi_coex) }, > + { 0x74, 4, 5, SCO_ATTR(rx_failed_wifi_coex) }, > + { 0x75, 4, 1, SCO_ATTR(samples_inserted_by_CDC) }, > + { 0x76, 4, 1, SCO_ATTR(samples_dropped) }, > + { 0x77, 4, 1, SCO_ATTR(mute_samples) }, > + { 0x78, 4, 1, SCO_ATTR(plc_injection) }, > + > + /* end */ > + { 0x0, 0, 0 } > +}; > + > +bool is_manufacturer_intel(uint16_t manufacturer) > +{ > + return manufacturer == COMPANY_ID_INTEL; > +} > + > +void intel_set_debug(intel_debug_func_t callback, void *user_data) > +{ > + intel_debug.callback = callback; > + intel_debug.data = user_data; > +} > + > +static void debug(const char *format, ...) > +{ > + va_list ap; > + char str[256]; > + > + if (!intel_debug.callback || !intel_debug.data) > + return; > + > + va_start(ap, format); > + vsnprintf(str, sizeof(str), format, ap); > + intel_debug.callback(str, intel_debug.data); > + va_end(ap); > +} > + > +static void print_intel_telemetry_evt(struct intel_ext_telemetry_event *tev) > +{ > + if (!tev) > + return; > + > + if (tev->link_type == TELEMETRY_ACL_LINK) { > + struct intel_acl_event *acl = &tev->conn.acl; > + int i; > + > + debug("Intel Extended Telemetry Event"); > + debug(" ACL connection handle: 0x%4.4x", acl->conn_handle); > + debug(" Rx HEC errors: %u", acl->rx_hec_error); > + debug(" Rx CRC errors: %u", acl->rx_crc_error); > + debug(" Packets from host: %u", acl->packets_from_host); > + debug(" Tx packets: %u", acl->tx_packets); > + > + for (i = 0; i < INTEL_NUM_RETRIES; i++) > + debug(" Tx packets %u retries: %u", > + i, acl->tx_packets_retry[i]); > + > + for (i = 0; i < INTEL_NUM_PACKET_TYPES; i++) > + debug(" Tx %s packets: %u", bredr_packet_type[i], > + acl->tx_packets_by_type[i]); > + > + debug(" Rx packets: %u", acl->rx_packets); > + debug(" ACL link throughput: %u", acl->link_throughput); > + debug(" ACL max packet latency: %u", acl->max_packet_letency); > + debug(" ACL avg packet latency: %u", acl->avg_packet_letency); > + > + } else if (tev->link_type == TELEMETRY_SCO_LINK) { > + struct intel_sco_event *sco = &tev->conn.sco; > + int i; > + > + debug("Intel Extended Telemetry Event"); > + debug(" SCO connection handle: 0x%4.4x", sco->conn_handle); > + debug(" Packets from host: %u", sco->packets_from_host); > + debug(" Tx packets: %u", sco->tx_packets); > + debug(" Rx payload lost: %u", sco->rx_payload_lost); > + debug(" Tx payload lost: %u", sco->tx_payload_lost); > + > + for (i = 0; i < INTEL_NUM_SLOTS; i++) > + debug(" Rx No SYNC errors (slot %u): %u", > + i, sco->rx_no_sync_error[i]); > + > + for (i = 0; i < INTEL_NUM_SLOTS; i++) > + debug(" Rx HEC errors (slot %u): %u", > + i, sco->rx_hec_error[i]); > + > + for (i = 0; i < INTEL_NUM_SLOTS; i++) > + debug(" Rx CRC errors (slot %u): %u", > + i, sco->rx_crc_error[i]); > + > + for (i = 0; i < INTEL_NUM_SLOTS; i++) > + debug(" Rx NAK errors (slot %u): %u", > + i, sco->rx_nak_error[i]); > + > + for (i = 0; i < INTEL_NUM_SLOTS; i++) > + debug(" Failed Tx due to Wifi coex (slot %u): %u", > + i, sco->tx_failed_wifi_coex[i]); > + > + for (i = 0; i < INTEL_NUM_SLOTS; i++) > + debug(" Failed Rx due to Wifi coex (slot %u): %u", > + i, sco->rx_failed_wifi_coex[i]); > + > + debug(" Late samples inserted based on CDC: %u", > + sco->samples_inserted_by_CDC); > + debug(" Samples dropped: %u", sco->samples_dropped); > + debug(" Mute samples sent at initial connection: %u", > + sco->mute_samples); > + debug(" PLC injection data: %u", sco->plc_injection); > + } > +} > + > +static const struct intel_tlv *process_ext_subevent( > + struct intel_ext_telemetry_event *tev, > + const struct intel_tlv *tlv, > + const struct intel_tlv *last_tlv) > +{ > + const struct intel_tlv *next_tlv = NEXT_TLV(tlv); > + const struct intel_ext_subevent *subevent = NULL; > + int i; > + > + for (i = 0; intel_ext_subevent_table[i].size > 0; i++) { > + if (intel_ext_subevent_table[i].id == tlv->id) { > + subevent = &intel_ext_subevent_table[i]; > + break; > + } > + } > + > + if (!subevent) { > + debug("error: unknown Intel telemetry subevent 0x%2.2x", > + tlv->id); > + return NULL; > + } > + > + if (tlv->length != subevent->size * subevent->elements) { > + debug("error: invalid length %d of subevent 0x%2.2x", > + tlv->length, tlv->id); > + return NULL; > + } > + > + if (next_tlv > last_tlv) { > + debug("error: subevent 0x%2.2x exceeds the buffer size.", > + tlv->id); > + return NULL; > + } > + > + /* Assign tlv value to the corresponding attribute of acl/sco struct. */ > + switch (subevent->size) { > + case 1: > + *subevent->attr = get_u8(tlv->value); > + break; > + > + case 2: > + *((uint16_t *)subevent->attr) = get_le16(tlv->value); > + break; > + > + case 4: > + if (subevent->elements == 1) { > + *((uint32_t *)subevent->attr) = get_le32(tlv->value); > + break; > + } > + > + for (i = 0; i < subevent->elements; i++) { > + /* Both acl and sco structs are __packed such that > + * the addresses of array elements can be calculated. > + */ > + *((uint32_t *)(subevent->attr + i * subevent->size)) = > + get_le32((uint32_t *)tlv->value + i); > + } > + break; > + > + default: > + debug("error: subevent id %u: size %u not supported", > + subevent->id, subevent->size); > + break; > + > + } > + > + switch (subevent->id) { > + case EXT_EVT_TYPE: > + /* Only interested in the LINK_QUALITY_REPORT type for now. */ > + if (*subevent->attr != LINK_QUALITY_REPORT) > + return NULL; > + break; > + > + case ACL_CONNECTION_HANDLE: > + tev->link_type = TELEMETRY_ACL_LINK; > + break; > + > + case SCO_CONNECTION_HANDLE: > + tev->link_type = TELEMETRY_SCO_LINK; > + break; > + > + default: > + break; > + } > + > + return next_tlv; > +} > + > +bool process_intel_telemetry_report(const struct mgmt_ev_quality_report *ev) > +{ > + /* The ev->report points to a number of consecutive tlv.*/ > + const struct intel_tlv *tlv = (const struct intel_tlv *)ev->report; > + const struct intel_tlv *last_tlv = > + (const struct intel_tlv *)(ev->report + ev->report_len); > + > + /* Read every tlv subevent into tev. > + * The decoding process terminates normally when tlv == last_tlv. > + */ > + memset(&tev, 0, sizeof(tev)); > + while (tlv && tlv < last_tlv) > + tlv = process_ext_subevent(&tev, tlv, last_tlv); > + > + /* If the decoding completes successfully, tlv would be non-NULL */ > + if (tlv) { > + print_intel_telemetry_evt(&tev); > + return true; > + } > + > + return false; > +} > diff --git a/src/shared/intel.h b/src/shared/intel.h > new file mode 100644 > index 000000000..2b20f803e > --- /dev/null > +++ b/src/shared/intel.h > @@ -0,0 +1,155 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * > + * BlueZ - Bluetooth protocol stack for Linux > + * > + * Copyright (C) 2021 Google LLC > + * > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + */ > + > +#ifndef __INTEL_H > +#define __INTEL_H > + > +#include > + > +struct mgmt_ev_quality_report; > + > +enum intel_telemetry_event_type { > + SYSTEM_EXCEPTION, > + FATAL_EXCEPTION, > + DEBUG_EXCEPTION, > + CONNECTION_EVENT, > + DISCONNECTION_EVENT, > + LINK_QUALITY_REPORT, > +}; > + > +enum intel_telemetry_link_type { > + TELEMETRY_UNKNOWN_LINK, > + TELEMETRY_ACL_LINK, > + TELEMETRY_SCO_LINK, > +}; > + > +/* The subevent indices of the complete list of Intel telemetry subevents. */ > +enum intel_subevt_list { > + EXT_EVT_TYPE = 0x01, > + > + ACL_CONNECTION_HANDLE = 0x4a, > + ACL_HEC_ERRORS, > + ACL_CRC_ERRORS, > + ACL_PACKETS_FROM_HOST, > + ACL_TX_PACKETS_TO_AIR, > + ACL_TX_PACKETS_0_RETRY, > + ACL_TX_PACKETS_1_RETRY, > + ACL_TX_PACKETS_2_RETRY, > + ACL_TX_PACKETS_3_RETRY, > + ACL_TX_PACKETS_MORE_RETRY, > + ACL_TX_PACKETS_DH1, > + ACL_TX_PACKETS_DH3, > + ACL_TX_PACKETS_DH5, > + ACL_TX_PACKETS_2DH1, > + ACL_TX_PACKETS_2DH3, > + ACL_TX_PACKETS_2DH5, > + ACL_TX_PACKETS_3DH1, > + ACL_TX_PACKETS_3DH3, > + ACL_TX_PACKETS_3DH5, > + ACL_RX_PACKETS, > + ACL_LINK_THROUGHPUT, > + ACL_MAX_PACKET_LATENCY, > + ACL_AVG_PACKET_LATENCY, > + > + SCO_CONNECTION_HANDLE = 0x6a, > + SCO_RX_PACKETS, > + SCO_TX_PACKETS, > + SCO_RX_PACKETS_LOST, > + SCO_TX_PACKETS_LOST, > + SCO_RX_NO_SYNC_ERROR, > + SCO_RX_HEC_ERROR, > + SCO_RX_CRC_ERROR, > + SCO_RX_NAK_ERROR, > + SCO_TX_FAILED_BY_WIFI, > + SCO_RX_FAILED_BY_WIFI, > + SCO_SAMPLES_INSERTED, > + SCO_SAMPLES_DROPPED, > + SCO_MUTE_SAMPLES, > + SCO_PLC_INJECTION_DATA, > +}; > + > +#define INTEL_NUM_SLOTS 5 > +#define INTEL_NUM_RETRIES 5 > +#define INTEL_NUM_PACKET_TYPES 9 > + > +/* An Intel telemetry subevent is of the TLV format. > + * - id: takes 1 byte. This is the subevent id. > + * - length: takes 1 byte. > + * - value: takes |length| bytes. > + */ > +struct intel_tlv { > + uint8_t id; > + uint8_t length; > + uint8_t value[0]; > +}; > + > +#define TLV_SIZE(tlv) (*((const uint8_t *) tlv + 1) + 2 * sizeof(uint8_t)) > +#define NEXT_TLV(tlv) ((const struct intel_tlv *)\ > + ((const uint8_t *)tlv + TLV_SIZE(tlv))) > + > +struct intel_acl_event { > + uint16_t conn_handle; > + uint32_t rx_hec_error; > + uint32_t rx_crc_error; > + uint32_t packets_from_host; > + uint32_t tx_packets; > + uint32_t tx_packets_retry[INTEL_NUM_RETRIES]; > + uint32_t tx_packets_by_type[INTEL_NUM_PACKET_TYPES]; > + uint32_t rx_packets; > + uint32_t link_throughput; > + uint32_t max_packet_letency; > + uint32_t avg_packet_letency; > +} __packed; > + > +struct intel_sco_event { > + uint16_t conn_handle; > + uint32_t packets_from_host; > + uint32_t tx_packets; > + uint32_t rx_payload_lost; > + uint32_t tx_payload_lost; > + uint32_t rx_no_sync_error[INTEL_NUM_SLOTS]; > + uint32_t rx_hec_error[INTEL_NUM_SLOTS]; > + uint32_t rx_crc_error[INTEL_NUM_SLOTS]; > + uint32_t rx_nak_error[INTEL_NUM_SLOTS]; > + uint32_t tx_failed_wifi_coex[INTEL_NUM_SLOTS]; > + uint32_t rx_failed_wifi_coex[INTEL_NUM_SLOTS]; > + uint32_t samples_inserted_by_CDC; > + uint32_t samples_dropped; > + uint32_t mute_samples; > + uint32_t plc_injection; > +} __packed; > + > +struct intel_ext_telemetry_event { > + uint8_t telemetry_ev_type; /* one in enum intel_telemetry_event_type */ > + uint8_t link_type; > + union { > + struct intel_sco_event sco; > + struct intel_acl_event acl; > + } conn; > +} __packed; > + > +typedef void (*intel_debug_func_t)(const char *str, void *user_data); > + > +bool is_manufacturer_intel(uint16_t manufacturer); > +void intel_set_debug(intel_debug_func_t callback, void *user_data); > + > +bool process_intel_telemetry_report(const struct mgmt_ev_quality_report *ev); > Same thing here, not sure where you got this idea that it would be nice to print the telemetry as bluetoothd output rather than on btmon like everything else. > +#endif /* __INTEL_H */ > -- > 2.35.0.rc0.227.g00780c9af4-goog > -- Luiz Augusto von Dentz