31
31
#define BTNXPUART_SERDEV_OPEN 4
32
32
#define BTNXPUART_IR_IN_PROGRESS 5
33
33
#define BTNXPUART_FW_DOWNLOAD_ABORT 6
34
+ #define BTNXPUART_FW_DUMP_IN_PROGRESS 7
34
35
35
36
/* NXP HW err codes */
36
37
#define BTNXPUART_IR_HW_ERR 0xb0
106
107
#define HCI_NXP_SET_OPER_SPEED 0xfc09
107
108
/* Bluetooth vendor command: Independent Reset */
108
109
#define HCI_NXP_IND_RESET 0xfcfc
110
+ /* Bluetooth vendor command: Trigger FW dump */
111
+ #define HCI_NXP_TRIGGER_DUMP 0xfe91
109
112
110
113
/* Bluetooth Power State : Vendor cmd params */
111
114
#define BT_PS_ENABLE 0x02
@@ -310,6 +313,16 @@ union nxp_v3_rx_timeout_nak_u {
310
313
u8 buf [6 ];
311
314
};
312
315
316
+ /* FW dump */
317
+ #define NXP_FW_DUMP_SIZE (1024 * 1000)
318
+
319
+ struct nxp_fw_dump_hdr {
320
+ __le16 seq_num ;
321
+ __le16 reserved ;
322
+ __le16 buf_type ;
323
+ __le16 buf_len ;
324
+ };
325
+
313
326
static u8 crc8_table [CRC8_TABLE_SIZE ];
314
327
315
328
/* Default configurations */
@@ -774,6 +787,16 @@ static bool is_fw_downloading(struct btnxpuart_dev *nxpdev)
774
787
return test_bit (BTNXPUART_FW_DOWNLOADING , & nxpdev -> tx_state );
775
788
}
776
789
790
+ static bool ind_reset_in_progress (struct btnxpuart_dev * nxpdev )
791
+ {
792
+ return test_bit (BTNXPUART_IR_IN_PROGRESS , & nxpdev -> tx_state );
793
+ }
794
+
795
+ static bool fw_dump_in_progress (struct btnxpuart_dev * nxpdev )
796
+ {
797
+ return test_bit (BTNXPUART_FW_DUMP_IN_PROGRESS , & nxpdev -> tx_state );
798
+ }
799
+
777
800
static bool process_boot_signature (struct btnxpuart_dev * nxpdev )
778
801
{
779
802
if (test_bit (BTNXPUART_CHECK_BOOT_SIGNATURE , & nxpdev -> tx_state )) {
@@ -1175,7 +1198,7 @@ static int nxp_set_baudrate_cmd(struct hci_dev *hdev, void *data)
1175
1198
static int nxp_check_boot_sign (struct btnxpuart_dev * nxpdev )
1176
1199
{
1177
1200
serdev_device_set_baudrate (nxpdev -> serdev , HCI_NXP_PRI_BAUDRATE );
1178
- if (test_bit ( BTNXPUART_IR_IN_PROGRESS , & nxpdev -> tx_state ))
1201
+ if (ind_reset_in_progress ( nxpdev ))
1179
1202
serdev_device_set_flow_control (nxpdev -> serdev , false);
1180
1203
else
1181
1204
serdev_device_set_flow_control (nxpdev -> serdev , true);
@@ -1204,6 +1227,73 @@ static int nxp_set_ind_reset(struct hci_dev *hdev, void *data)
1204
1227
return hci_recv_frame (hdev , skb );
1205
1228
}
1206
1229
1230
+ /* Firmware dump */
1231
+ static void nxp_coredump (struct hci_dev * hdev )
1232
+ {
1233
+ struct sk_buff * skb ;
1234
+ u8 pcmd = 2 ;
1235
+
1236
+ skb = nxp_drv_send_cmd (hdev , HCI_NXP_TRIGGER_DUMP , 1 , & pcmd );
1237
+ if (!IS_ERR (skb ))
1238
+ kfree_skb (skb );
1239
+ }
1240
+
1241
+ static void nxp_coredump_hdr (struct hci_dev * hdev , struct sk_buff * skb )
1242
+ {
1243
+ /* Nothing to be added in FW dump header */
1244
+ }
1245
+
1246
+ static int nxp_process_fw_dump (struct hci_dev * hdev , struct sk_buff * skb )
1247
+ {
1248
+ struct hci_acl_hdr * acl_hdr = (struct hci_acl_hdr * )skb_pull_data (skb ,
1249
+ sizeof (* acl_hdr ));
1250
+ struct nxp_fw_dump_hdr * fw_dump_hdr = (struct nxp_fw_dump_hdr * )skb -> data ;
1251
+ struct btnxpuart_dev * nxpdev = hci_get_drvdata (hdev );
1252
+ __u16 seq_num = __le16_to_cpu (fw_dump_hdr -> seq_num );
1253
+ __u16 buf_len = __le16_to_cpu (fw_dump_hdr -> buf_len );
1254
+ int err ;
1255
+
1256
+ if (seq_num == 0x0001 ) {
1257
+ if (test_and_set_bit (BTNXPUART_FW_DUMP_IN_PROGRESS , & nxpdev -> tx_state )) {
1258
+ bt_dev_err (hdev , "FW dump already in progress" );
1259
+ goto free_skb ;
1260
+ }
1261
+ bt_dev_warn (hdev , "==== Start FW dump ===" );
1262
+ err = hci_devcd_init (hdev , NXP_FW_DUMP_SIZE );
1263
+ if (err < 0 )
1264
+ goto free_skb ;
1265
+
1266
+ schedule_delayed_work (& hdev -> dump .dump_timeout ,
1267
+ msecs_to_jiffies (20000 ));
1268
+ }
1269
+
1270
+ err = hci_devcd_append (hdev , skb_clone (skb , GFP_ATOMIC ));
1271
+ if (err < 0 )
1272
+ goto free_skb ;
1273
+
1274
+ if (buf_len == 0 ) {
1275
+ bt_dev_warn (hdev , "==== FW dump complete ===" );
1276
+ clear_bit (BTNXPUART_FW_DUMP_IN_PROGRESS , & nxpdev -> tx_state );
1277
+ hci_devcd_complete (hdev );
1278
+ nxp_set_ind_reset (hdev , NULL );
1279
+ }
1280
+
1281
+ free_skb :
1282
+ kfree_skb (skb );
1283
+ return 0 ;
1284
+ }
1285
+
1286
+ static int nxp_recv_acl_pkt (struct hci_dev * hdev , struct sk_buff * skb )
1287
+ {
1288
+ __u16 handle = __le16_to_cpu (hci_acl_hdr (skb )-> handle );
1289
+
1290
+ /* FW dump chunks are ACL packets with conn handle 0xfff */
1291
+ if ((handle & 0x0FFF ) == 0xFFF )
1292
+ return nxp_process_fw_dump (hdev , skb );
1293
+ else
1294
+ return hci_recv_frame (hdev , skb );
1295
+ }
1296
+
1207
1297
/* NXP protocol */
1208
1298
static int nxp_setup (struct hci_dev * hdev )
1209
1299
{
@@ -1265,20 +1355,15 @@ static int nxp_shutdown(struct hci_dev *hdev)
1265
1355
{
1266
1356
struct btnxpuart_dev * nxpdev = hci_get_drvdata (hdev );
1267
1357
struct sk_buff * skb ;
1268
- u8 * status ;
1269
1358
u8 pcmd = 0 ;
1270
1359
1271
- if (test_bit ( BTNXPUART_IR_IN_PROGRESS , & nxpdev -> tx_state )) {
1360
+ if (ind_reset_in_progress ( nxpdev )) {
1272
1361
skb = nxp_drv_send_cmd (hdev , HCI_NXP_IND_RESET , 1 , & pcmd );
1273
- if (IS_ERR (skb ))
1274
- return PTR_ERR (skb );
1275
-
1276
- status = skb_pull_data (skb , 1 );
1277
- if (status ) {
1278
- serdev_device_set_flow_control (nxpdev -> serdev , false);
1279
- set_bit (BTNXPUART_FW_DOWNLOADING , & nxpdev -> tx_state );
1280
- }
1281
- kfree_skb (skb );
1362
+ serdev_device_set_flow_control (nxpdev -> serdev , false);
1363
+ set_bit (BTNXPUART_FW_DOWNLOADING , & nxpdev -> tx_state );
1364
+ /* HCI_NXP_IND_RESET command may not returns any response */
1365
+ if (!IS_ERR (skb ))
1366
+ kfree_skb (skb );
1282
1367
} else if (nxpdev -> current_baudrate != nxpdev -> fw_init_baudrate ) {
1283
1368
nxpdev -> new_baudrate = nxpdev -> fw_init_baudrate ;
1284
1369
nxp_set_baudrate_cmd (hdev , NULL );
@@ -1298,6 +1383,16 @@ static bool nxp_wakeup(struct hci_dev *hdev)
1298
1383
return false;
1299
1384
}
1300
1385
1386
+ static void nxp_reset (struct hci_dev * hdev )
1387
+ {
1388
+ struct btnxpuart_dev * nxpdev = hci_get_drvdata (hdev );
1389
+
1390
+ if (!ind_reset_in_progress (nxpdev ) && !fw_dump_in_progress (nxpdev )) {
1391
+ bt_dev_dbg (hdev , "CMD Timeout detected. Resetting." );
1392
+ nxp_set_ind_reset (hdev , NULL );
1393
+ }
1394
+ }
1395
+
1301
1396
static int btnxpuart_queue_skb (struct hci_dev * hdev , struct sk_buff * skb )
1302
1397
{
1303
1398
struct btnxpuart_dev * nxpdev = hci_get_drvdata (hdev );
@@ -1318,6 +1413,9 @@ static int nxp_enqueue(struct hci_dev *hdev, struct sk_buff *skb)
1318
1413
struct wakeup_cmd_payload wakeup_parm ;
1319
1414
__le32 baudrate_parm ;
1320
1415
1416
+ if (fw_dump_in_progress (nxpdev ))
1417
+ return - EBUSY ;
1418
+
1321
1419
/* if vendor commands are received from user space (e.g. hcitool), update
1322
1420
* driver flags accordingly and ask driver to re-send the command to FW.
1323
1421
* In case the payload for any command does not match expected payload
@@ -1486,7 +1584,7 @@ static int btnxpuart_flush(struct hci_dev *hdev)
1486
1584
}
1487
1585
1488
1586
static const struct h4_recv_pkt nxp_recv_pkts [] = {
1489
- { H4_RECV_ACL , .recv = hci_recv_frame },
1587
+ { H4_RECV_ACL , .recv = nxp_recv_acl_pkt },
1490
1588
{ H4_RECV_SCO , .recv = hci_recv_frame },
1491
1589
{ H4_RECV_EVENT , .recv = hci_recv_frame },
1492
1590
{ H4_RECV_ISO , .recv = hci_recv_frame },
@@ -1508,11 +1606,13 @@ static size_t btnxpuart_receive_buf(struct serdev_device *serdev,
1508
1606
if (IS_ERR (nxpdev -> rx_skb )) {
1509
1607
int err = PTR_ERR (nxpdev -> rx_skb );
1510
1608
/* Safe to ignore out-of-sync bootloader signatures */
1511
- if (!is_fw_downloading (nxpdev ))
1609
+ if (!is_fw_downloading (nxpdev ) &&
1610
+ !ind_reset_in_progress (nxpdev ))
1512
1611
bt_dev_err (nxpdev -> hdev , "Frame reassembly failed (%d)" , err );
1513
1612
return count ;
1514
1613
}
1515
- if (!is_fw_downloading (nxpdev ))
1614
+ if (!is_fw_downloading (nxpdev ) &&
1615
+ !ind_reset_in_progress (nxpdev ))
1516
1616
nxpdev -> hdev -> stat .byte_rx += count ;
1517
1617
return count ;
1518
1618
}
@@ -1580,6 +1680,7 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
1580
1680
hdev -> hw_error = nxp_hw_err ;
1581
1681
hdev -> shutdown = nxp_shutdown ;
1582
1682
hdev -> wakeup = nxp_wakeup ;
1683
+ hdev -> reset = nxp_reset ;
1583
1684
SET_HCIDEV_DEV (hdev , & serdev -> dev );
1584
1685
1585
1686
if (hci_register_dev (hdev ) < 0 ) {
@@ -1590,6 +1691,8 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
1590
1691
if (ps_setup (hdev ))
1591
1692
goto probe_fail ;
1592
1693
1694
+ hci_devcd_register (hdev , nxp_coredump , nxp_coredump_hdr , NULL );
1695
+
1593
1696
return 0 ;
1594
1697
1595
1698
probe_fail :
@@ -1641,6 +1744,17 @@ static int nxp_serdev_resume(struct device *dev)
1641
1744
}
1642
1745
#endif
1643
1746
1747
+ #ifdef CONFIG_DEV_COREDUMP
1748
+ static void nxp_serdev_coredump (struct device * dev )
1749
+ {
1750
+ struct btnxpuart_dev * nxpdev = dev_get_drvdata (dev );
1751
+ struct hci_dev * hdev = nxpdev -> hdev ;
1752
+
1753
+ if (hdev -> dump .coredump )
1754
+ hdev -> dump .coredump (hdev );
1755
+ }
1756
+ #endif
1757
+
1644
1758
static struct btnxpuart_data w8987_data __maybe_unused = {
1645
1759
.helper_fw_name = NULL ,
1646
1760
.fw_name = FIRMWARE_W8987 ,
@@ -1671,6 +1785,9 @@ static struct serdev_device_driver nxp_serdev_driver = {
1671
1785
.name = "btnxpuart" ,
1672
1786
.of_match_table = of_match_ptr (nxpuart_of_match_table ),
1673
1787
.pm = & nxp_pm_ops ,
1788
+ #ifdef CONFIG_DEV_COREDUMP
1789
+ .coredump = nxp_serdev_coredump ,
1790
+ #endif
1674
1791
},
1675
1792
};
1676
1793
0 commit comments