Skip to content

Commit bf81cf2

Browse files
NeerajSanjayKaleVudentz
authored andcommitted
Bluetooth: btnxpuart: Handle bootloader error during cmd5 and cmd7
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 <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent c59d881 commit bf81cf2

File tree

1 file changed

+43
-18
lines changed

1 file changed

+43
-18
lines changed

drivers/bluetooth/btnxpuart.c

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,12 @@ struct btnxpuart_data {
168168
const char *fw_name_old;
169169
};
170170

171+
enum bootloader_param_change {
172+
not_changed,
173+
cmd_sent,
174+
changed
175+
};
176+
171177
struct btnxpuart_dev {
172178
struct hci_dev *hdev;
173179
struct serdev_device *serdev;
@@ -183,6 +189,7 @@ struct btnxpuart_dev {
183189
u32 fw_v1_sent_bytes;
184190
u32 fw_dnld_v3_offset;
185191
u32 fw_v3_offset_correction;
192+
u32 fw_v3_prev_sent;
186193
u32 fw_v1_expected_len;
187194
u32 boot_reg_offset;
188195
wait_queue_head_t fw_dnld_done_wait_q;
@@ -191,8 +198,8 @@ struct btnxpuart_dev {
191198
u32 new_baudrate;
192199
u32 current_baudrate;
193200
u32 fw_init_baudrate;
194-
bool timeout_changed;
195-
bool baudrate_changed;
201+
enum bootloader_param_change timeout_changed;
202+
enum bootloader_param_change baudrate_changed;
196203
bool helper_downloaded;
197204

198205
struct ps_data psdata;
@@ -680,8 +687,8 @@ static int nxp_download_firmware(struct hci_dev *hdev)
680687
nxpdev->boot_reg_offset = 0;
681688
nxpdev->fw_dnld_v3_offset = 0;
682689
nxpdev->fw_v3_offset_correction = 0;
683-
nxpdev->baudrate_changed = false;
684-
nxpdev->timeout_changed = false;
690+
nxpdev->baudrate_changed = not_changed;
691+
nxpdev->timeout_changed = not_changed;
685692
nxpdev->helper_downloaded = false;
686693

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

915922
if (!nxp_data->helper_fw_name) {
916-
if (!nxpdev->timeout_changed) {
917-
nxpdev->timeout_changed = nxp_fw_change_timeout(hdev,
918-
len);
923+
if (nxpdev->timeout_changed != changed) {
924+
nxp_fw_change_timeout(hdev, len);
925+
nxpdev->timeout_changed = changed;
919926
goto free_skb;
920927
}
921-
if (!nxpdev->baudrate_changed) {
922-
nxpdev->baudrate_changed = nxp_fw_change_baudrate(hdev,
923-
len);
924-
if (nxpdev->baudrate_changed) {
928+
if (nxpdev->baudrate_changed != changed) {
929+
if (nxp_fw_change_baudrate(hdev, len)) {
930+
nxpdev->baudrate_changed = changed;
925931
serdev_device_set_baudrate(nxpdev->serdev,
926932
HCI_NXP_SEC_BAUDRATE);
927933
serdev_device_set_flow_control(nxpdev->serdev, true);
@@ -1127,7 +1133,8 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb)
11271133
{
11281134
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
11291135
struct v3_data_req *req;
1130-
__u16 len;
1136+
__u16 len = 0;
1137+
__u16 err = 0;
11311138
__u32 offset;
11321139

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

1140-
if (!req->error) {
1147+
err = __le16_to_cpu(req->error);
1148+
1149+
if (!err) {
11411150
nxp_send_ack(NXP_ACK_V3, hdev);
1151+
if (nxpdev->timeout_changed == cmd_sent)
1152+
nxpdev->timeout_changed = changed;
1153+
if (nxpdev->baudrate_changed == cmd_sent)
1154+
nxpdev->baudrate_changed = changed;
11421155
} else {
11431156
nxp_handle_fw_download_error(hdev, req);
1157+
if (nxpdev->timeout_changed == cmd_sent &&
1158+
err == NXP_CRC_RX_ERROR) {
1159+
nxpdev->fw_v3_offset_correction -= nxpdev->fw_v3_prev_sent;
1160+
nxpdev->timeout_changed = not_changed;
1161+
}
1162+
if (nxpdev->baudrate_changed == cmd_sent &&
1163+
err == NXP_CRC_RX_ERROR) {
1164+
nxpdev->fw_v3_offset_correction -= nxpdev->fw_v3_prev_sent;
1165+
nxpdev->baudrate_changed = not_changed;
1166+
}
11441167
goto free_skb;
11451168
}
11461169

11471170
len = __le16_to_cpu(req->len);
11481171

1149-
if (!nxpdev->timeout_changed) {
1150-
nxpdev->timeout_changed = nxp_fw_change_timeout(hdev, len);
1172+
if (nxpdev->timeout_changed != changed) {
1173+
nxp_fw_change_timeout(hdev, len);
1174+
nxpdev->timeout_changed = cmd_sent;
11511175
goto free_skb;
11521176
}
11531177

1154-
if (!nxpdev->baudrate_changed) {
1155-
nxpdev->baudrate_changed = nxp_fw_change_baudrate(hdev, len);
1156-
if (nxpdev->baudrate_changed) {
1178+
if (nxpdev->baudrate_changed != changed) {
1179+
if (nxp_fw_change_baudrate(hdev, len)) {
1180+
nxpdev->baudrate_changed = cmd_sent;
11571181
serdev_device_set_baudrate(nxpdev->serdev,
11581182
HCI_NXP_SEC_BAUDRATE);
11591183
serdev_device_set_flow_control(nxpdev->serdev, true);
@@ -1185,6 +1209,7 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb)
11851209
nxpdev->fw_dnld_v3_offset, len);
11861210

11871211
free_skb:
1212+
nxpdev->fw_v3_prev_sent = len;
11881213
kfree_skb(skb);
11891214
return 0;
11901215
}

0 commit comments

Comments
 (0)