Skip to content

Commit

Permalink
Bluetooth: btnxpuart: Handle bootloader error during cmd5 and cmd7
Browse files Browse the repository at this point in the history
This handles the scenario where the driver receives an error code after
sending cmd5 or cmd7 in the bootloader signature during FW download.
The bootloader error code is handled by the driver and FW offset is
corrected accordingly, and the cmd5 or cmd7 is re-sent to the controller
in case of CRC error.

Fixes: 689ca16 ("Bluetooth: NXP: Add protocol support for NXP Bluetooth chipsets")
Signed-off-by: Neeraj Sanjay Kale <neeraj.sanjaykale@nxp.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  • Loading branch information
Neeraj Sanjay Kale authored and Luiz Augusto von Dentz committed Mar 25, 2025
1 parent c59d881 commit bf81cf2
Showing 1 changed file with 43 additions and 18 deletions.
61 changes: 43 additions & 18 deletions drivers/bluetooth/btnxpuart.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,12 @@ struct btnxpuart_data {
const char *fw_name_old;
};

enum bootloader_param_change {
not_changed,
cmd_sent,
changed
};

struct btnxpuart_dev {
struct hci_dev *hdev;
struct serdev_device *serdev;
Expand All @@ -183,6 +189,7 @@ struct btnxpuart_dev {
u32 fw_v1_sent_bytes;
u32 fw_dnld_v3_offset;
u32 fw_v3_offset_correction;
u32 fw_v3_prev_sent;
u32 fw_v1_expected_len;
u32 boot_reg_offset;
wait_queue_head_t fw_dnld_done_wait_q;
Expand All @@ -191,8 +198,8 @@ struct btnxpuart_dev {
u32 new_baudrate;
u32 current_baudrate;
u32 fw_init_baudrate;
bool timeout_changed;
bool baudrate_changed;
enum bootloader_param_change timeout_changed;
enum bootloader_param_change baudrate_changed;
bool helper_downloaded;

struct ps_data psdata;
Expand Down Expand Up @@ -680,8 +687,8 @@ static int nxp_download_firmware(struct hci_dev *hdev)
nxpdev->boot_reg_offset = 0;
nxpdev->fw_dnld_v3_offset = 0;
nxpdev->fw_v3_offset_correction = 0;
nxpdev->baudrate_changed = false;
nxpdev->timeout_changed = false;
nxpdev->baudrate_changed = not_changed;
nxpdev->timeout_changed = not_changed;
nxpdev->helper_downloaded = false;

serdev_device_set_baudrate(nxpdev->serdev, HCI_NXP_PRI_BAUDRATE);
Expand Down Expand Up @@ -913,15 +920,14 @@ static int nxp_recv_fw_req_v1(struct hci_dev *hdev, struct sk_buff *skb)
len = __le16_to_cpu(req->len);

if (!nxp_data->helper_fw_name) {
if (!nxpdev->timeout_changed) {
nxpdev->timeout_changed = nxp_fw_change_timeout(hdev,
len);
if (nxpdev->timeout_changed != changed) {
nxp_fw_change_timeout(hdev, len);
nxpdev->timeout_changed = changed;
goto free_skb;
}
if (!nxpdev->baudrate_changed) {
nxpdev->baudrate_changed = nxp_fw_change_baudrate(hdev,
len);
if (nxpdev->baudrate_changed) {
if (nxpdev->baudrate_changed != changed) {
if (nxp_fw_change_baudrate(hdev, len)) {
nxpdev->baudrate_changed = changed;
serdev_device_set_baudrate(nxpdev->serdev,
HCI_NXP_SEC_BAUDRATE);
serdev_device_set_flow_control(nxpdev->serdev, true);
Expand Down Expand Up @@ -1127,7 +1133,8 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb)
{
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
struct v3_data_req *req;
__u16 len;
__u16 len = 0;
__u16 err = 0;
__u32 offset;

if (!process_boot_signature(nxpdev))
Expand All @@ -1137,23 +1144,40 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb)
if (!req || !nxpdev->fw)
goto free_skb;

if (!req->error) {
err = __le16_to_cpu(req->error);

if (!err) {
nxp_send_ack(NXP_ACK_V3, hdev);
if (nxpdev->timeout_changed == cmd_sent)
nxpdev->timeout_changed = changed;
if (nxpdev->baudrate_changed == cmd_sent)
nxpdev->baudrate_changed = changed;
} else {
nxp_handle_fw_download_error(hdev, req);
if (nxpdev->timeout_changed == cmd_sent &&
err == NXP_CRC_RX_ERROR) {
nxpdev->fw_v3_offset_correction -= nxpdev->fw_v3_prev_sent;
nxpdev->timeout_changed = not_changed;
}
if (nxpdev->baudrate_changed == cmd_sent &&
err == NXP_CRC_RX_ERROR) {
nxpdev->fw_v3_offset_correction -= nxpdev->fw_v3_prev_sent;
nxpdev->baudrate_changed = not_changed;
}
goto free_skb;
}

len = __le16_to_cpu(req->len);

if (!nxpdev->timeout_changed) {
nxpdev->timeout_changed = nxp_fw_change_timeout(hdev, len);
if (nxpdev->timeout_changed != changed) {
nxp_fw_change_timeout(hdev, len);
nxpdev->timeout_changed = cmd_sent;
goto free_skb;
}

if (!nxpdev->baudrate_changed) {
nxpdev->baudrate_changed = nxp_fw_change_baudrate(hdev, len);
if (nxpdev->baudrate_changed) {
if (nxpdev->baudrate_changed != changed) {
if (nxp_fw_change_baudrate(hdev, len)) {
nxpdev->baudrate_changed = cmd_sent;
serdev_device_set_baudrate(nxpdev->serdev,
HCI_NXP_SEC_BAUDRATE);
serdev_device_set_flow_control(nxpdev->serdev, true);
Expand Down Expand Up @@ -1185,6 +1209,7 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb)
nxpdev->fw_dnld_v3_offset, len);

free_skb:
nxpdev->fw_v3_prev_sent = len;
kfree_skb(skb);
return 0;
}
Expand Down

0 comments on commit bf81cf2

Please sign in to comment.