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: btnxpuart: Handle FW Download Abort scenario

This adds a new flag BTNXPUART_FW_DOWNLOAD_ABORT which handles the
situation where driver is removed while firmware download is in
progress.

logs:
modprobe btnxpuart
[65239.230431] Bluetooth: hci0: ChipID: 7601, Version: 0
[65239.236670] Bluetooth: hci0: Request Firmware: nxp/uartspi_n61x_v1.bin.se
rmmod btnxpuart
[65241.425300] Bluetooth: hci0: FW Download Aborted

Signed-off-by: Neeraj Sanjay Kale <neeraj.sanjaykale@nxp.com>
Tested-by: Guillaume Legoupil <guillaume.legoupil@nxp.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

authored by

Neeraj Sanjay Kale and committed by
Luiz Augusto von Dentz
e3c48910 2684dd61

+33 -14
+33 -14
drivers/bluetooth/btnxpuart.c
··· 29 29 #define BTNXPUART_CHECK_BOOT_SIGNATURE 3 30 30 #define BTNXPUART_SERDEV_OPEN 4 31 31 #define BTNXPUART_IR_IN_PROGRESS 5 32 + #define BTNXPUART_FW_DOWNLOAD_ABORT 6 32 33 33 34 /* NXP HW err codes */ 34 35 #define BTNXPUART_IR_HW_ERR 0xb0 ··· 160 159 u8 fw_name[MAX_FW_FILE_NAME_LEN]; 161 160 u32 fw_dnld_v1_offset; 162 161 u32 fw_v1_sent_bytes; 162 + u32 fw_dnld_v3_offset; 163 163 u32 fw_v3_offset_correction; 164 164 u32 fw_v1_expected_len; 165 165 u32 boot_reg_offset; ··· 552 550 nxpdev->fw_v1_sent_bytes = 0; 553 551 nxpdev->fw_v1_expected_len = HDR_LEN; 554 552 nxpdev->boot_reg_offset = 0; 553 + nxpdev->fw_dnld_v3_offset = 0; 555 554 nxpdev->fw_v3_offset_correction = 0; 556 555 nxpdev->baudrate_changed = false; 557 556 nxpdev->timeout_changed = false; ··· 567 564 !test_bit(BTNXPUART_FW_DOWNLOADING, 568 565 &nxpdev->tx_state), 569 566 msecs_to_jiffies(60000)); 567 + 568 + release_firmware(nxpdev->fw); 569 + memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name)); 570 + 570 571 if (err == 0) { 571 - bt_dev_err(hdev, "FW Download Timeout."); 572 + bt_dev_err(hdev, "FW Download Timeout. offset: %d", 573 + nxpdev->fw_dnld_v1_offset ? 574 + nxpdev->fw_dnld_v1_offset : 575 + nxpdev->fw_dnld_v3_offset); 572 576 return -ETIMEDOUT; 577 + } 578 + if (test_bit(BTNXPUART_FW_DOWNLOAD_ABORT, &nxpdev->tx_state)) { 579 + bt_dev_err(hdev, "FW Download Aborted"); 580 + return -EINTR; 573 581 } 574 582 575 583 serdev_device_set_flow_control(nxpdev->serdev, true); 576 - release_firmware(nxpdev->fw); 577 - memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name)); 578 584 579 585 /* Allow the downloaded FW to initialize */ 580 586 msleep(1200); ··· 967 955 goto free_skb; 968 956 } 969 957 970 - serdev_device_write_buf(nxpdev->serdev, nxpdev->fw->data + offset - 971 - nxpdev->fw_v3_offset_correction, len); 958 + nxpdev->fw_dnld_v3_offset = offset - nxpdev->fw_v3_offset_correction; 959 + serdev_device_write_buf(nxpdev->serdev, nxpdev->fw->data + 960 + nxpdev->fw_dnld_v3_offset, len); 972 961 973 962 free_skb: 974 963 kfree_skb(skb); ··· 1403 1390 struct btnxpuart_dev *nxpdev = serdev_device_get_drvdata(serdev); 1404 1391 struct hci_dev *hdev = nxpdev->hdev; 1405 1392 1406 - /* Restore FW baudrate to fw_init_baudrate if changed. 1407 - * This will ensure FW baudrate is in sync with 1408 - * driver baudrate in case this driver is re-inserted. 1409 - */ 1410 - if (nxpdev->current_baudrate != nxpdev->fw_init_baudrate) { 1411 - nxpdev->new_baudrate = nxpdev->fw_init_baudrate; 1412 - nxp_set_baudrate_cmd(hdev, NULL); 1393 + if (is_fw_downloading(nxpdev)) { 1394 + set_bit(BTNXPUART_FW_DOWNLOAD_ABORT, &nxpdev->tx_state); 1395 + clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); 1396 + wake_up_interruptible(&nxpdev->check_boot_sign_wait_q); 1397 + wake_up_interruptible(&nxpdev->fw_dnld_done_wait_q); 1398 + } else { 1399 + /* Restore FW baudrate to fw_init_baudrate if changed. 1400 + * This will ensure FW baudrate is in sync with 1401 + * driver baudrate in case this driver is re-inserted. 1402 + */ 1403 + if (nxpdev->current_baudrate != nxpdev->fw_init_baudrate) { 1404 + nxpdev->new_baudrate = nxpdev->fw_init_baudrate; 1405 + nxp_set_baudrate_cmd(hdev, NULL); 1406 + } 1407 + ps_cancel_timer(nxpdev); 1413 1408 } 1414 - 1415 - ps_cancel_timer(nxpdev); 1416 1409 hci_unregister_dev(hdev); 1417 1410 hci_free_dev(hdev); 1418 1411 }