Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Bluetooth: btintel_pcie: Add support for device coredump

1. Driver registers device coredump callback
2. Dumps firmware traces as part of coredump

Co-developed-by: Vijay Satija <vijay.satija@intel.com>
Signed-off-by: Vijay Satija <vijay.satija@intel.com>
Signed-off-by: Kiran K <kiran.k@intel.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

authored by

Kiran K and committed by
Luiz Augusto von Dentz
07e6bddb 1f04b0e5

+291 -7
-1
drivers/bluetooth/btintel.h
··· 190 190 struct btintel_data { 191 191 DECLARE_BITMAP(flags, __INTEL_NUM_FLAGS); 192 192 int (*acpi_reset_method)(struct hci_dev *hdev); 193 - u32 cnvi_top; 194 193 }; 195 194 196 195 #define btintel_set_flag(hdev, nr) \
+253 -6
drivers/bluetooth/btintel_pcie.c
··· 59 59 60 60 #define BTINTEL_PCIE_MAGIC_NUM 0xA5A5A5A5 61 61 62 + #define BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER 0x17A2 63 + 62 64 /* Alive interrupt context */ 63 65 enum { 64 66 BTINTEL_PCIE_ROM, ··· 377 375 btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg); 378 376 } 379 377 378 + static int btintel_pcie_add_dmp_data(struct hci_dev *hdev, const void *data, int size) 379 + { 380 + struct sk_buff *skb; 381 + int err; 382 + 383 + skb = alloc_skb(size, GFP_ATOMIC); 384 + if (!skb) 385 + return -ENOMEM; 386 + 387 + skb_put_data(skb, data, size); 388 + err = hci_devcd_append(hdev, skb); 389 + if (err) { 390 + bt_dev_err(hdev, "Failed to append data in the coredump"); 391 + return err; 392 + } 393 + 394 + return 0; 395 + } 396 + 380 397 static int btintel_pcie_get_mac_access(struct btintel_pcie_data *data) 381 398 { 382 399 u32 reg; ··· 438 417 reg &= ~BTINTEL_PCIE_CSR_FUNC_CTRL_XTAL_CLK_REQ; 439 418 440 419 btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg); 420 + } 421 + 422 + static void btintel_pcie_copy_tlv(struct sk_buff *skb, enum btintel_pcie_tlv_type type, 423 + void *data, int size) 424 + { 425 + struct intel_tlv *tlv; 426 + 427 + tlv = skb_put(skb, sizeof(*tlv) + size); 428 + tlv->type = type; 429 + tlv->len = size; 430 + memcpy(tlv->val, data, tlv->len); 431 + } 432 + 433 + static int btintel_pcie_read_dram_buffers(struct btintel_pcie_data *data) 434 + { 435 + u32 offset, prev_size, wr_ptr_status, dump_size, i; 436 + struct btintel_pcie_dbgc *dbgc = &data->dbgc; 437 + u8 buf_idx, dump_time_len, fw_build; 438 + struct hci_dev *hdev = data->hdev; 439 + struct intel_tlv *tlv; 440 + struct timespec64 now; 441 + struct sk_buff *skb; 442 + struct tm tm_now; 443 + char buf[256]; 444 + u16 hdr_len; 445 + int ret; 446 + 447 + wr_ptr_status = btintel_pcie_rd_dev_mem(data, BTINTEL_PCIE_DBGC_CUR_DBGBUFF_STATUS); 448 + offset = wr_ptr_status & BTINTEL_PCIE_DBG_OFFSET_BIT_MASK; 449 + 450 + buf_idx = BTINTEL_PCIE_DBGC_DBG_BUF_IDX(wr_ptr_status); 451 + if (buf_idx > dbgc->count) { 452 + bt_dev_warn(hdev, "Buffer index is invalid"); 453 + return -EINVAL; 454 + } 455 + 456 + prev_size = buf_idx * BTINTEL_PCIE_DBGC_BUFFER_SIZE; 457 + if (prev_size + offset >= prev_size) 458 + data->dmp_hdr.write_ptr = prev_size + offset; 459 + else 460 + return -EINVAL; 461 + 462 + ktime_get_real_ts64(&now); 463 + time64_to_tm(now.tv_sec, 0, &tm_now); 464 + dump_time_len = snprintf(buf, sizeof(buf), "Dump Time: %02d-%02d-%04ld %02d:%02d:%02d", 465 + tm_now.tm_mday, tm_now.tm_mon + 1, tm_now.tm_year + 1900, 466 + tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec); 467 + 468 + fw_build = snprintf(buf + dump_time_len, sizeof(buf) - dump_time_len, 469 + "Firmware Timestamp: Year %u WW %02u buildtype %u build %u", 470 + 2000 + (data->dmp_hdr.fw_timestamp >> 8), 471 + data->dmp_hdr.fw_timestamp & 0xff, data->dmp_hdr.fw_build_type, 472 + data->dmp_hdr.fw_build_num); 473 + 474 + hdr_len = sizeof(*tlv) + sizeof(data->dmp_hdr.cnvi_bt) + 475 + sizeof(*tlv) + sizeof(data->dmp_hdr.write_ptr) + 476 + sizeof(*tlv) + sizeof(data->dmp_hdr.wrap_ctr) + 477 + sizeof(*tlv) + sizeof(data->dmp_hdr.trigger_reason) + 478 + sizeof(*tlv) + sizeof(data->dmp_hdr.fw_git_sha1) + 479 + sizeof(*tlv) + sizeof(data->dmp_hdr.cnvr_top) + 480 + sizeof(*tlv) + sizeof(data->dmp_hdr.cnvi_top) + 481 + sizeof(*tlv) + dump_time_len + 482 + sizeof(*tlv) + fw_build; 483 + 484 + dump_size = hdr_len + sizeof(hdr_len); 485 + 486 + skb = alloc_skb(dump_size, GFP_KERNEL); 487 + if (!skb) 488 + return -ENOMEM; 489 + 490 + /* Add debug buffers data length to dump size */ 491 + dump_size += BTINTEL_PCIE_DBGC_BUFFER_SIZE * dbgc->count; 492 + 493 + ret = hci_devcd_init(hdev, dump_size); 494 + if (ret) { 495 + bt_dev_err(hdev, "Failed to init devcoredump, err %d", ret); 496 + kfree_skb(skb); 497 + return ret; 498 + } 499 + 500 + skb_put_data(skb, &hdr_len, sizeof(hdr_len)); 501 + 502 + btintel_pcie_copy_tlv(skb, BTINTEL_CNVI_BT, &data->dmp_hdr.cnvi_bt, 503 + sizeof(data->dmp_hdr.cnvi_bt)); 504 + 505 + btintel_pcie_copy_tlv(skb, BTINTEL_WRITE_PTR, &data->dmp_hdr.write_ptr, 506 + sizeof(data->dmp_hdr.write_ptr)); 507 + 508 + data->dmp_hdr.wrap_ctr = btintel_pcie_rd_dev_mem(data, 509 + BTINTEL_PCIE_DBGC_DBGBUFF_WRAP_ARND); 510 + 511 + btintel_pcie_copy_tlv(skb, BTINTEL_WRAP_CTR, &data->dmp_hdr.wrap_ctr, 512 + sizeof(data->dmp_hdr.wrap_ctr)); 513 + 514 + btintel_pcie_copy_tlv(skb, BTINTEL_TRIGGER_REASON, &data->dmp_hdr.trigger_reason, 515 + sizeof(data->dmp_hdr.trigger_reason)); 516 + 517 + btintel_pcie_copy_tlv(skb, BTINTEL_FW_SHA, &data->dmp_hdr.fw_git_sha1, 518 + sizeof(data->dmp_hdr.fw_git_sha1)); 519 + 520 + btintel_pcie_copy_tlv(skb, BTINTEL_CNVR_TOP, &data->dmp_hdr.cnvr_top, 521 + sizeof(data->dmp_hdr.cnvr_top)); 522 + 523 + btintel_pcie_copy_tlv(skb, BTINTEL_CNVI_TOP, &data->dmp_hdr.cnvi_top, 524 + sizeof(data->dmp_hdr.cnvi_top)); 525 + 526 + btintel_pcie_copy_tlv(skb, BTINTEL_DUMP_TIME, buf, dump_time_len); 527 + 528 + btintel_pcie_copy_tlv(skb, BTINTEL_FW_BUILD, buf + dump_time_len, fw_build); 529 + 530 + ret = hci_devcd_append(hdev, skb); 531 + if (ret) 532 + goto exit_err; 533 + 534 + for (i = 0; i < dbgc->count; i++) { 535 + ret = btintel_pcie_add_dmp_data(hdev, dbgc->bufs[i].data, 536 + BTINTEL_PCIE_DBGC_BUFFER_SIZE); 537 + if (ret) 538 + break; 539 + } 540 + 541 + exit_err: 542 + hci_devcd_complete(hdev); 543 + return ret; 544 + } 545 + 546 + static void btintel_pcie_dump_traces(struct hci_dev *hdev) 547 + { 548 + struct btintel_pcie_data *data = hci_get_drvdata(hdev); 549 + int ret = 0; 550 + 551 + ret = btintel_pcie_get_mac_access(data); 552 + if (ret) { 553 + bt_dev_err(hdev, "Failed to get mac access: (%d)", ret); 554 + return; 555 + } 556 + 557 + ret = btintel_pcie_read_dram_buffers(data); 558 + 559 + btintel_pcie_release_mac_access(data); 560 + 561 + if (ret) 562 + bt_dev_err(hdev, "Failed to dump traces: (%d)", ret); 563 + } 564 + 565 + static void btintel_pcie_dump_hdr(struct hci_dev *hdev, struct sk_buff *skb) 566 + { 567 + struct btintel_pcie_data *data = hci_get_drvdata(hdev); 568 + u16 len = skb->len; 569 + u16 *hdrlen_ptr; 570 + char buf[80]; 571 + 572 + hdrlen_ptr = skb_put_zero(skb, sizeof(len)); 573 + 574 + snprintf(buf, sizeof(buf), "Controller Name: 0x%X\n", 575 + INTEL_HW_VARIANT(data->dmp_hdr.cnvi_bt)); 576 + skb_put_data(skb, buf, strlen(buf)); 577 + 578 + snprintf(buf, sizeof(buf), "Firmware Build Number: %u\n", 579 + data->dmp_hdr.fw_build_num); 580 + skb_put_data(skb, buf, strlen(buf)); 581 + 582 + snprintf(buf, sizeof(buf), "Driver: %s\n", data->dmp_hdr.driver_name); 583 + skb_put_data(skb, buf, strlen(buf)); 584 + 585 + snprintf(buf, sizeof(buf), "Vendor: Intel\n"); 586 + skb_put_data(skb, buf, strlen(buf)); 587 + 588 + *hdrlen_ptr = skb->len - len; 589 + } 590 + 591 + static void btintel_pcie_dump_notify(struct hci_dev *hdev, int state) 592 + { 593 + struct btintel_pcie_data *data = hci_get_drvdata(hdev); 594 + 595 + switch (state) { 596 + case HCI_DEVCOREDUMP_IDLE: 597 + data->dmp_hdr.state = HCI_DEVCOREDUMP_IDLE; 598 + break; 599 + case HCI_DEVCOREDUMP_ACTIVE: 600 + data->dmp_hdr.state = HCI_DEVCOREDUMP_ACTIVE; 601 + break; 602 + case HCI_DEVCOREDUMP_TIMEOUT: 603 + case HCI_DEVCOREDUMP_ABORT: 604 + case HCI_DEVCOREDUMP_DONE: 605 + data->dmp_hdr.state = HCI_DEVCOREDUMP_IDLE; 606 + break; 607 + } 441 608 } 442 609 443 610 /* This function enables BT function by setting BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT bit in ··· 1092 883 1093 884 static void btintel_pcie_read_hwexp(struct btintel_pcie_data *data) 1094 885 { 1095 - struct btintel_data *intel_data = hci_get_priv(data->hdev); 1096 886 int len, err, offset, pending; 1097 887 struct sk_buff *skb; 1098 888 u8 *buf, prefix[64]; ··· 1106 898 1107 899 struct tlv *tlv; 1108 900 1109 - switch (intel_data->cnvi_top & 0xfff) { 901 + switch (data->dmp_hdr.cnvi_top & 0xfff) { 1110 902 case BTINTEL_CNVI_BLAZARI: 1111 903 case BTINTEL_CNVI_BLAZARIW: 1112 904 /* only from step B0 onwards */ 1113 - if (INTEL_CNVX_TOP_STEP(intel_data->cnvi_top) != 0x01) 905 + if (INTEL_CNVX_TOP_STEP(data->dmp_hdr.cnvi_top) != 0x01) 1114 906 return; 1115 907 len = BTINTEL_PCIE_BLZR_HWEXP_SIZE; /* exception data length */ 1116 908 addr = BTINTEL_PCIE_BLZR_HWEXP_DMP_ADDR; ··· 1120 912 addr = BTINTEL_PCIE_SCP_HWEXP_DMP_ADDR; 1121 913 break; 1122 914 default: 1123 - bt_dev_err(data->hdev, "Unsupported cnvi 0x%8.8x", intel_data->cnvi_top); 915 + bt_dev_err(data->hdev, "Unsupported cnvi 0x%8.8x", data->dmp_hdr.cnvi_top); 1124 916 return; 1125 917 } 1126 918 ··· 1223 1015 */ 1224 1016 btintel_pcie_read_hwexp(data); 1225 1017 clear_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags); 1018 + } 1019 + 1020 + if (test_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) { 1021 + btintel_pcie_dump_traces(data->hdev); 1022 + clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags); 1226 1023 } 1227 1024 1228 1025 /* Process the sk_buf in queue and send to the HCI layer */ ··· 1915 1702 1916 1703 static int btintel_pcie_setup_internal(struct hci_dev *hdev) 1917 1704 { 1918 - struct btintel_data *data = hci_get_priv(hdev); 1705 + struct btintel_pcie_data *data = hci_get_drvdata(hdev); 1919 1706 const u8 param[1] = { 0xFF }; 1920 1707 struct intel_version_tlv ver_tlv; 1921 1708 struct sk_buff *skb; ··· 1954 1741 goto exit_error; 1955 1742 } 1956 1743 1957 - data->cnvi_top = ver_tlv.cnvi_top; 1958 1744 switch (INTEL_HW_PLATFORM(ver_tlv.cnvi_bt)) { 1959 1745 case 0x37: 1960 1746 break; ··· 1997 1785 err = -EINVAL; 1998 1786 goto exit_error; 1999 1787 break; 1788 + } 1789 + 1790 + data->dmp_hdr.cnvi_top = ver_tlv.cnvi_top; 1791 + data->dmp_hdr.cnvr_top = ver_tlv.cnvr_top; 1792 + data->dmp_hdr.fw_timestamp = ver_tlv.timestamp; 1793 + data->dmp_hdr.fw_build_type = ver_tlv.build_type; 1794 + data->dmp_hdr.fw_build_num = ver_tlv.build_num; 1795 + data->dmp_hdr.cnvi_bt = ver_tlv.cnvi_bt; 1796 + 1797 + if (ver_tlv.img_type == 0x02 || ver_tlv.img_type == 0x03) 1798 + data->dmp_hdr.fw_git_sha1 = ver_tlv.git_sha1; 1799 + 1800 + err = hci_devcd_register(hdev, btintel_pcie_dump_traces, btintel_pcie_dump_hdr, 1801 + btintel_pcie_dump_notify); 1802 + if (err) { 1803 + bt_dev_err(hdev, "Failed to register coredump (%d)", err); 1804 + goto exit_error; 2000 1805 } 2001 1806 2002 1807 btintel_print_fseq_info(hdev); ··· 2080 1851 goto exit_error; 2081 1852 } 2082 1853 1854 + data->dmp_hdr.driver_name = KBUILD_MODNAME; 2083 1855 return 0; 2084 1856 2085 1857 exit_error: ··· 2193 1963 pci_set_drvdata(pdev, NULL); 2194 1964 } 2195 1965 1966 + #ifdef CONFIG_DEV_COREDUMP 1967 + static void btintel_pcie_coredump(struct device *dev) 1968 + { 1969 + struct pci_dev *pdev = to_pci_dev(dev); 1970 + struct btintel_pcie_data *data = pci_get_drvdata(pdev); 1971 + 1972 + if (test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) 1973 + return; 1974 + 1975 + data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER; 1976 + queue_work(data->workqueue, &data->rx_work); 1977 + } 1978 + #endif 1979 + 2196 1980 static struct pci_driver btintel_pcie_driver = { 2197 1981 .name = KBUILD_MODNAME, 2198 1982 .id_table = btintel_pcie_table, 2199 1983 .probe = btintel_pcie_probe, 2200 1984 .remove = btintel_pcie_remove, 1985 + #ifdef CONFIG_DEV_COREDUMP 1986 + .driver.coredump = btintel_pcie_coredump 1987 + #endif 2201 1988 }; 2202 1989 module_pci_driver(btintel_pcie_driver); 2203 1990
+38
drivers/bluetooth/btintel_pcie.h
··· 56 56 #define BTINTEL_PCIE_CSR_MSIX_IVAR_BASE (BTINTEL_PCIE_CSR_MSIX_BASE + 0x0880) 57 57 #define BTINTEL_PCIE_CSR_MSIX_IVAR(cause) (BTINTEL_PCIE_CSR_MSIX_IVAR_BASE + (cause)) 58 58 59 + /* IOSF Debug Register */ 60 + #define BTINTEL_PCIE_DBGC_BASE_ADDR (0xf3800300) 61 + #define BTINTEL_PCIE_DBGC_CUR_DBGBUFF_STATUS (BTINTEL_PCIE_DBGC_BASE_ADDR + 0x1C) 62 + #define BTINTEL_PCIE_DBGC_DBGBUFF_WRAP_ARND (BTINTEL_PCIE_DBGC_BASE_ADDR + 0x2C) 63 + 64 + #define BTINTEL_PCIE_DBG_IDX_BIT_MASK 0x0F 65 + #define BTINTEL_PCIE_DBGC_DBG_BUF_IDX(data) (((data) >> 24) & BTINTEL_PCIE_DBG_IDX_BIT_MASK) 66 + #define BTINTEL_PCIE_DBG_OFFSET_BIT_MASK 0xFFFFFF 67 + 59 68 /* The DRAM buffer count, each buffer size, and 60 69 * fragment buffer size 61 70 */ ··· 106 97 enum { 107 98 BTINTEL_PCIE_CORE_HALTED, 108 99 BTINTEL_PCIE_HWEXP_INPROGRESS, 100 + BTINTEL_PCIE_COREDUMP_INPROGRESS 101 + }; 102 + 103 + enum btintel_pcie_tlv_type { 104 + BTINTEL_CNVI_BT, 105 + BTINTEL_WRITE_PTR, 106 + BTINTEL_WRAP_CTR, 107 + BTINTEL_TRIGGER_REASON, 108 + BTINTEL_FW_SHA, 109 + BTINTEL_CNVR_TOP, 110 + BTINTEL_CNVI_TOP, 111 + BTINTEL_DUMP_TIME, 112 + BTINTEL_FW_BUILD, 109 113 }; 110 114 111 115 #define BTINTEL_PCIE_MSIX_NON_AUTO_CLEAR_CAUSE BIT(7) ··· 393 371 struct data_buf *bufs; 394 372 }; 395 373 374 + struct btintel_pcie_dump_header { 375 + const char *driver_name; 376 + u32 cnvi_top; 377 + u32 cnvr_top; 378 + u16 fw_timestamp; 379 + u8 fw_build_type; 380 + u32 fw_build_num; 381 + u32 fw_git_sha1; 382 + u32 cnvi_bt; 383 + u32 write_ptr; 384 + u32 wrap_ctr; 385 + u16 trigger_reason; 386 + int state; 387 + }; 388 + 396 389 /* struct btintel_pcie_data 397 390 * @pdev: pci device 398 391 * @hdev: hdev device ··· 489 452 struct rxq rxq; 490 453 u32 alive_intr_ctxt; 491 454 struct btintel_pcie_dbgc dbgc; 455 + struct btintel_pcie_dump_header dmp_hdr; 492 456 }; 493 457 494 458 static inline u32 btintel_pcie_rd_reg32(struct btintel_pcie_data *data,