Skip to content

Commit

Permalink
Bluetooth: btusb: Add Intel devcoredump support
Browse files Browse the repository at this point in the history
Intercept debug exception events from the controller and put them into
a devcoredump using hci devcoredump APIs. The debug exception contains
data in a TLV format and it will be parsed in userspace.

Signed-off-by: Abhishek Pandit-Subedi <abhishekpandit@chromium.org>
Signed-off-by: Manish Mandlik <mmandlik@google.com>
Reviewed-by: Abhishek Pandit-Subedi <abhishekpandit@chromium.org>
Reviewed-by: Chethan Tumkur Narayan <chethan.tumkur.narayan@intel.com>
  • Loading branch information
apandit authored and intel-lab-lkp committed Mar 21, 2022
1 parent ac170a5 commit 677f482
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 6 deletions.
60 changes: 60 additions & 0 deletions drivers/bluetooth/btintel.c
Expand Up @@ -32,6 +32,11 @@ struct cmd_write_boot_params {
u8 fw_build_yy;
} __packed;

#define DRIVER_NAME_LEN 16
static char driver_name[DRIVER_NAME_LEN];
static u8 hw_variant;
static u32 fw_build_num;

int btintel_check_bdaddr(struct hci_dev *hdev)
{
struct hci_rp_read_bd_addr *bda;
Expand Down Expand Up @@ -304,6 +309,9 @@ int btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
return -EINVAL;
}

hw_variant = ver->hw_variant;
fw_build_num = ver->fw_build_num;

bt_dev_info(hdev, "%s revision %u.%u build %u week %u %u",
variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f,
ver->fw_build_num, ver->fw_build_ww,
Expand Down Expand Up @@ -497,6 +505,9 @@ static int btintel_version_info_tlv(struct hci_dev *hdev,
return -EINVAL;
}

hw_variant = INTEL_HW_VARIANT(version->cnvi_bt);
fw_build_num = version->build_num;

bt_dev_info(hdev, "%s timestamp %u.%u buildtype %u build %u", variant,
2000 + (version->timestamp >> 8), version->timestamp & 0xff,
version->build_type, version->build_num);
Expand Down Expand Up @@ -1391,6 +1402,55 @@ int btintel_set_quality_report(struct hci_dev *hdev, bool enable)
}
EXPORT_SYMBOL_GPL(btintel_set_quality_report);

static int btintel_dmp_hdr(struct hci_dev *hdev, char *buf, size_t size)
{
char *ptr = buf;
size_t rem = size;
size_t read = 0;

read = snprintf(ptr, rem, "Controller Name: 0x%X\n", hw_variant);
rem -= read;
ptr += read;

read = snprintf(ptr, rem, "Firmware Version: 0x%X\n", fw_build_num);
rem -= read;
ptr += read;

read = snprintf(ptr, rem, "Driver: %s\n", driver_name);
rem -= read;
ptr += read;

read = snprintf(ptr, rem, "Vendor: Intel\n");
rem -= read;
ptr += read;

return size - rem;
}

int btintel_register_devcoredump_support(struct hci_dev *hdev,
const char *driver)
{
struct intel_debug_features features;
int err;

err = btintel_read_debug_features(hdev, &features);
if (err) {
bt_dev_info(hdev, "Error reading debug features");
return err;
}

if (!(features.page1[0] & 0x3f)) {
bt_dev_info(hdev, "Telemetry exception format not supported");
return -EOPNOTSUPP;
}

strncpy(driver_name, driver, DRIVER_NAME_LEN);
hci_devcoredump_register(hdev, btintel_dmp_hdr, NULL);

return err;
}
EXPORT_SYMBOL_GPL(btintel_register_devcoredump_support);

static const struct firmware *btintel_legacy_rom_get_fw(struct hci_dev *hdev,
struct intel_version *ver)
{
Expand Down
14 changes: 14 additions & 0 deletions drivers/bluetooth/btintel.h
Expand Up @@ -137,6 +137,12 @@ struct intel_offload_use_cases {
__u8 preset[8];
} __packed;

#define INTEL_TLV_TYPE_ID 0x1

#define INTEL_TLV_SYSTEM_EXCEPTION 0x0
#define INTEL_TLV_FATAL_EXCEPTION 0x1
#define INTEL_TLV_DEBUG_EXCEPTION 0x2

#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)
Expand Down Expand Up @@ -205,6 +211,8 @@ int btintel_read_boot_params(struct hci_dev *hdev,
struct intel_boot_params *params);
int btintel_download_firmware(struct hci_dev *dev, struct intel_version *ver,
const struct firmware *fw, u32 *boot_param);
int btintel_register_devcoredump_support(struct hci_dev *hdev,
const char *driver);
int btintel_configure_setup(struct hci_dev *hdev);
void btintel_bootup(struct hci_dev *hdev, const void *ptr, unsigned int len);
void btintel_secure_send_result(struct hci_dev *hdev,
Expand Down Expand Up @@ -301,6 +309,12 @@ static inline void btintel_secure_send_result(struct hci_dev *hdev,
{
}

static int btintel_register_devcoredump_support(struct hci_dev *hdev,
const char *driver)
{
return -EOPNOTSUPP;
}

static inline int btintel_set_quality_report(struct hci_dev *hdev, bool enable)
{
return -ENODEV;
Expand Down
47 changes: 41 additions & 6 deletions drivers/bluetooth/btusb.c
Expand Up @@ -2136,16 +2136,42 @@ static int btusb_recv_bulk_intel(struct btusb_data *data, void *buffer,
return btusb_recv_bulk(data, buffer, count);
}

static int btusb_intel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
{
struct intel_tlv *tlv = (void *)&skb->data[5];

/* The first event is always an event type TLV */
if (tlv->type != INTEL_TLV_TYPE_ID)
goto recv_frame;

switch (tlv->val[0]) {
case INTEL_TLV_SYSTEM_EXCEPTION:
case INTEL_TLV_FATAL_EXCEPTION:
case INTEL_TLV_DEBUG_EXCEPTION:
/* Generate devcoredump from exception */
if (!hci_devcoredump_init(hdev, skb->len)) {
hci_devcoredump_append(hdev, skb);
hci_devcoredump_complete(hdev);
return 0;
}
break;
}

recv_frame:
return hci_recv_frame(hdev, skb);
}

static int btusb_recv_event_intel(struct hci_dev *hdev, struct sk_buff *skb)
{
if (btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
struct hci_event_hdr *hdr = (void *)skb->data;
struct hci_event_hdr *hdr = (void *)skb->data;
const char diagnostics_hdr[] = { 0x87, 0x80, 0x03 };

if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff &&
hdr->plen > 0) {
const void *ptr = skb->data + HCI_EVENT_HDR_SIZE + 1;
unsigned int len = skb->len - HCI_EVENT_HDR_SIZE - 1;
if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff &&
hdr->plen > 0) {
const void *ptr = skb->data + HCI_EVENT_HDR_SIZE + 1;
unsigned int len = skb->len - HCI_EVENT_HDR_SIZE - 1;

if (btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
switch (skb->data[2]) {
case 0x02:
/* When switching to the operational firmware
Expand All @@ -2164,6 +2190,15 @@ static int btusb_recv_event_intel(struct hci_dev *hdev, struct sk_buff *skb)
break;
}
}

/* Handle all diagnostics events separately. May still call
* hci_recv_frame.
*/
if (len >= sizeof(diagnostics_hdr) &&
memcmp(&skb->data[2], diagnostics_hdr,
sizeof(diagnostics_hdr)) == 0) {
return btusb_intel_diagnostics(hdev, skb);
}
}

return hci_recv_frame(hdev, skb);
Expand Down

0 comments on commit 677f482

Please sign in to comment.