Commit e3c48910 authored by Neeraj Sanjay Kale's avatar Neeraj Sanjay Kale Committed by Luiz Augusto von Dentz

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: default avatarNeeraj Sanjay Kale <neeraj.sanjaykale@nxp.com>
Tested-by: default avatarGuillaume Legoupil <guillaume.legoupil@nxp.com>
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
parent 2684dd61
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#define BTNXPUART_CHECK_BOOT_SIGNATURE 3 #define BTNXPUART_CHECK_BOOT_SIGNATURE 3
#define BTNXPUART_SERDEV_OPEN 4 #define BTNXPUART_SERDEV_OPEN 4
#define BTNXPUART_IR_IN_PROGRESS 5 #define BTNXPUART_IR_IN_PROGRESS 5
#define BTNXPUART_FW_DOWNLOAD_ABORT 6
/* NXP HW err codes */ /* NXP HW err codes */
#define BTNXPUART_IR_HW_ERR 0xb0 #define BTNXPUART_IR_HW_ERR 0xb0
...@@ -159,6 +160,7 @@ struct btnxpuart_dev { ...@@ -159,6 +160,7 @@ struct btnxpuart_dev {
u8 fw_name[MAX_FW_FILE_NAME_LEN]; u8 fw_name[MAX_FW_FILE_NAME_LEN];
u32 fw_dnld_v1_offset; u32 fw_dnld_v1_offset;
u32 fw_v1_sent_bytes; u32 fw_v1_sent_bytes;
u32 fw_dnld_v3_offset;
u32 fw_v3_offset_correction; u32 fw_v3_offset_correction;
u32 fw_v1_expected_len; u32 fw_v1_expected_len;
u32 boot_reg_offset; u32 boot_reg_offset;
...@@ -550,6 +552,7 @@ static int nxp_download_firmware(struct hci_dev *hdev) ...@@ -550,6 +552,7 @@ static int nxp_download_firmware(struct hci_dev *hdev)
nxpdev->fw_v1_sent_bytes = 0; nxpdev->fw_v1_sent_bytes = 0;
nxpdev->fw_v1_expected_len = HDR_LEN; nxpdev->fw_v1_expected_len = HDR_LEN;
nxpdev->boot_reg_offset = 0; nxpdev->boot_reg_offset = 0;
nxpdev->fw_dnld_v3_offset = 0;
nxpdev->fw_v3_offset_correction = 0; nxpdev->fw_v3_offset_correction = 0;
nxpdev->baudrate_changed = false; nxpdev->baudrate_changed = false;
nxpdev->timeout_changed = false; nxpdev->timeout_changed = false;
...@@ -564,14 +567,23 @@ static int nxp_download_firmware(struct hci_dev *hdev) ...@@ -564,14 +567,23 @@ static int nxp_download_firmware(struct hci_dev *hdev)
!test_bit(BTNXPUART_FW_DOWNLOADING, !test_bit(BTNXPUART_FW_DOWNLOADING,
&nxpdev->tx_state), &nxpdev->tx_state),
msecs_to_jiffies(60000)); msecs_to_jiffies(60000));
release_firmware(nxpdev->fw);
memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name));
if (err == 0) { if (err == 0) {
bt_dev_err(hdev, "FW Download Timeout."); bt_dev_err(hdev, "FW Download Timeout. offset: %d",
nxpdev->fw_dnld_v1_offset ?
nxpdev->fw_dnld_v1_offset :
nxpdev->fw_dnld_v3_offset);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
if (test_bit(BTNXPUART_FW_DOWNLOAD_ABORT, &nxpdev->tx_state)) {
bt_dev_err(hdev, "FW Download Aborted");
return -EINTR;
}
serdev_device_set_flow_control(nxpdev->serdev, true); serdev_device_set_flow_control(nxpdev->serdev, true);
release_firmware(nxpdev->fw);
memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name));
/* Allow the downloaded FW to initialize */ /* Allow the downloaded FW to initialize */
msleep(1200); msleep(1200);
...@@ -955,8 +967,9 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -955,8 +967,9 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb)
goto free_skb; goto free_skb;
} }
serdev_device_write_buf(nxpdev->serdev, nxpdev->fw->data + offset - nxpdev->fw_dnld_v3_offset = offset - nxpdev->fw_v3_offset_correction;
nxpdev->fw_v3_offset_correction, len); serdev_device_write_buf(nxpdev->serdev, nxpdev->fw->data +
nxpdev->fw_dnld_v3_offset, len);
free_skb: free_skb:
kfree_skb(skb); kfree_skb(skb);
...@@ -1390,6 +1403,12 @@ static void nxp_serdev_remove(struct serdev_device *serdev) ...@@ -1390,6 +1403,12 @@ static void nxp_serdev_remove(struct serdev_device *serdev)
struct btnxpuart_dev *nxpdev = serdev_device_get_drvdata(serdev); struct btnxpuart_dev *nxpdev = serdev_device_get_drvdata(serdev);
struct hci_dev *hdev = nxpdev->hdev; struct hci_dev *hdev = nxpdev->hdev;
if (is_fw_downloading(nxpdev)) {
set_bit(BTNXPUART_FW_DOWNLOAD_ABORT, &nxpdev->tx_state);
clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
wake_up_interruptible(&nxpdev->check_boot_sign_wait_q);
wake_up_interruptible(&nxpdev->fw_dnld_done_wait_q);
} else {
/* Restore FW baudrate to fw_init_baudrate if changed. /* Restore FW baudrate to fw_init_baudrate if changed.
* This will ensure FW baudrate is in sync with * This will ensure FW baudrate is in sync with
* driver baudrate in case this driver is re-inserted. * driver baudrate in case this driver is re-inserted.
...@@ -1398,8 +1417,8 @@ static void nxp_serdev_remove(struct serdev_device *serdev) ...@@ -1398,8 +1417,8 @@ static void nxp_serdev_remove(struct serdev_device *serdev)
nxpdev->new_baudrate = nxpdev->fw_init_baudrate; nxpdev->new_baudrate = nxpdev->fw_init_baudrate;
nxp_set_baudrate_cmd(hdev, NULL); nxp_set_baudrate_cmd(hdev, NULL);
} }
ps_cancel_timer(nxpdev); ps_cancel_timer(nxpdev);
}
hci_unregister_dev(hdev); hci_unregister_dev(hdev);
hci_free_dev(hdev); hci_free_dev(hdev);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment