@@ -733,6 +733,16 @@ static const struct dmi_system_id btusb_needs_reset_resume_table[] = {
733
733
{}
734
734
};
735
735
736
+ struct qca_dump_info {
737
+ /* fields for dump collection */
738
+ u16 id_vendor ;
739
+ u16 id_product ;
740
+ u32 fw_version ;
741
+ u32 controller_id ;
742
+ u32 ram_dump_size ;
743
+ u16 ram_dump_seqno ;
744
+ };
745
+
736
746
#define BTUSB_MAX_ISOC_FRAMES 10
737
747
738
748
#define BTUSB_INTR_RUNNING 0
@@ -752,6 +762,7 @@ static const struct dmi_system_id btusb_needs_reset_resume_table[] = {
752
762
#define BTUSB_WAKEUP_AUTOSUSPEND 14
753
763
#define BTUSB_USE_ALT3_FOR_WBS 15
754
764
#define BTUSB_ALT6_CONTINUOUS_TX 16
765
+ #define BTUSB_HW_SSR_ACTIVE 17
755
766
756
767
struct btusb_data {
757
768
struct hci_dev * hdev ;
@@ -814,6 +825,8 @@ struct btusb_data {
814
825
815
826
int oob_wake_irq ; /* irq for out-of-band wake-on-bt */
816
827
unsigned cmd_timeout_cnt ;
828
+
829
+ struct qca_dump_info qca_dump ;
817
830
};
818
831
819
832
static void btusb_reset (struct hci_dev * hdev )
@@ -904,6 +917,11 @@ static void btusb_qca_cmd_timeout(struct hci_dev *hdev)
904
917
struct btusb_data * data = hci_get_drvdata (hdev );
905
918
struct gpio_desc * reset_gpio = data -> reset_gpio ;
906
919
920
+ if (test_bit (BTUSB_HW_SSR_ACTIVE , & data -> flags )) {
921
+ bt_dev_info (hdev , "Ramdump in progress, defer cmd_timeout" );
922
+ return ;
923
+ }
924
+
907
925
if (++ data -> cmd_timeout_cnt < 5 )
908
926
return ;
909
927
@@ -3294,6 +3312,202 @@ static int btusb_set_bdaddr_wcn6855(struct hci_dev *hdev,
3294
3312
return 0 ;
3295
3313
}
3296
3314
3315
+ #define QCA_MEMDUMP_ACL_HANDLE 0x2EDD
3316
+ #define QCA_MEMDUMP_SIZE_MAX 0x100000
3317
+ #define QCA_MEMDUMP_VSE_CLASS 0x01
3318
+ #define QCA_MEMDUMP_MSG_TYPE 0x08
3319
+ #define QCA_MEMDUMP_PKT_SIZE 248
3320
+ #define QCA_LAST_SEQUENCE_NUM 0xffff
3321
+
3322
+ struct qca_dump_hdr {
3323
+ u8 vse_class ;
3324
+ u8 msg_type ;
3325
+ __le16 seqno ;
3326
+ u8 reserved ;
3327
+ union {
3328
+ u8 data [0 ];
3329
+ struct {
3330
+ __le32 ram_dump_size ;
3331
+ u8 data0 [0 ];
3332
+ } __packed ;
3333
+ };
3334
+ } __packed ;
3335
+
3336
+
3337
+ static void btusb_dump_hdr_qca (struct hci_dev * hdev , struct sk_buff * skb )
3338
+ {
3339
+ char buf [128 ];
3340
+ struct btusb_data * btdata = hci_get_drvdata (hdev );
3341
+
3342
+ snprintf (buf , sizeof (buf ), "Controller Name: 0x%x\n" ,
3343
+ btdata -> qca_dump .controller_id );
3344
+ skb_put_data (skb , buf , strlen (buf ));
3345
+
3346
+ snprintf (buf , sizeof (buf ), "Firmware Version: 0x%x\n" ,
3347
+ btdata -> qca_dump .fw_version );
3348
+ skb_put_data (skb , buf , strlen (buf ));
3349
+
3350
+ snprintf (buf , sizeof (buf ), "Driver: %s\nVendor: qca\n" ,
3351
+ btusb_driver .name );
3352
+ skb_put_data (skb , buf , strlen (buf ));
3353
+
3354
+ snprintf (buf , sizeof (buf ), "VID: 0x%x\nPID:0x%x\n" ,
3355
+ btdata -> qca_dump .id_vendor , btdata -> qca_dump .id_product );
3356
+ skb_put_data (skb , buf , strlen (buf ));
3357
+
3358
+ snprintf (buf , sizeof (buf ), "Lmp Subversion: 0x%x\n" ,
3359
+ hdev -> lmp_subver );
3360
+ skb_put_data (skb , buf , strlen (buf ));
3361
+ }
3362
+
3363
+ static void btusb_coredump_qca (struct hci_dev * hdev )
3364
+ {
3365
+ static const u8 param [] = { 0x26 };
3366
+ struct sk_buff * skb ;
3367
+
3368
+ skb = __hci_cmd_sync (hdev , 0xfc0c , 1 , param , HCI_CMD_TIMEOUT );
3369
+ if (IS_ERR (skb ))
3370
+ bt_dev_err (hdev , "%s: triggle crash failed (%ld)" , __func__ , PTR_ERR (skb ));
3371
+ kfree_skb (skb );
3372
+ }
3373
+
3374
+ /*
3375
+ * ==0: not a dump pkt.
3376
+ * < 0: fails to handle a dump pkt
3377
+ * > 0: otherwise.
3378
+ */
3379
+ static int handle_dump_pkt_qca (struct hci_dev * hdev , struct sk_buff * skb )
3380
+ {
3381
+ int ret = 1 ;
3382
+ u8 pkt_type ;
3383
+ u8 * sk_ptr ;
3384
+ unsigned int sk_len ;
3385
+ u16 seqno ;
3386
+ u32 dump_size ;
3387
+
3388
+ struct hci_event_hdr * event_hdr ;
3389
+ struct hci_acl_hdr * acl_hdr ;
3390
+ struct qca_dump_hdr * dump_hdr ;
3391
+ struct btusb_data * btdata = hci_get_drvdata (hdev );
3392
+ struct usb_device * udev = btdata -> udev ;
3393
+
3394
+ pkt_type = hci_skb_pkt_type (skb );
3395
+ sk_ptr = skb -> data ;
3396
+ sk_len = skb -> len ;
3397
+
3398
+ if (pkt_type == HCI_ACLDATA_PKT ) {
3399
+ acl_hdr = hci_acl_hdr (skb );
3400
+ if (le16_to_cpu (acl_hdr -> handle ) != QCA_MEMDUMP_ACL_HANDLE )
3401
+ return 0 ;
3402
+ sk_ptr += HCI_ACL_HDR_SIZE ;
3403
+ sk_len -= HCI_ACL_HDR_SIZE ;
3404
+ event_hdr = (struct hci_event_hdr * )sk_ptr ;
3405
+ } else {
3406
+ event_hdr = hci_event_hdr (skb );
3407
+ }
3408
+
3409
+ if ((event_hdr -> evt != HCI_VENDOR_PKT )
3410
+ || (event_hdr -> plen != (sk_len - HCI_EVENT_HDR_SIZE )))
3411
+ return 0 ;
3412
+
3413
+ sk_ptr += HCI_EVENT_HDR_SIZE ;
3414
+ sk_len -= HCI_EVENT_HDR_SIZE ;
3415
+
3416
+ dump_hdr = (struct qca_dump_hdr * )sk_ptr ;
3417
+ if ((sk_len < offsetof(struct qca_dump_hdr , data ))
3418
+ || (dump_hdr -> vse_class != QCA_MEMDUMP_VSE_CLASS )
3419
+ || (dump_hdr -> msg_type != QCA_MEMDUMP_MSG_TYPE ))
3420
+ return 0 ;
3421
+
3422
+ /*it is dump pkt now*/
3423
+ seqno = le16_to_cpu (dump_hdr -> seqno );
3424
+ if (seqno == 0 ) {
3425
+ set_bit (BTUSB_HW_SSR_ACTIVE , & btdata -> flags );
3426
+ dump_size = le32_to_cpu (dump_hdr -> ram_dump_size );
3427
+ if (!dump_size || (dump_size > QCA_MEMDUMP_SIZE_MAX )) {
3428
+ ret = - EILSEQ ;
3429
+ bt_dev_err (hdev , "Invalid memdump size(%u)" ,
3430
+ dump_size );
3431
+ goto out ;
3432
+ }
3433
+
3434
+ ret = hci_devcd_init (hdev , dump_size );
3435
+ if (ret < 0 ) {
3436
+ bt_dev_err (hdev , "memdump init error(%d)" , ret );
3437
+ goto out ;
3438
+ }
3439
+
3440
+ btdata -> qca_dump .ram_dump_size = dump_size ;
3441
+ btdata -> qca_dump .ram_dump_seqno = 0 ;
3442
+ sk_ptr += offsetof(struct qca_dump_hdr , data0 );
3443
+ sk_len -= offsetof(struct qca_dump_hdr , data0 );
3444
+
3445
+ usb_disable_autosuspend (udev );
3446
+ bt_dev_info (hdev , "%s memdump size(%u)\n" ,
3447
+ (pkt_type == HCI_ACLDATA_PKT ) ? "ACL" : "event" ,
3448
+ dump_size );
3449
+ } else {
3450
+ sk_ptr += offsetof(struct qca_dump_hdr , data );
3451
+ sk_len -= offsetof(struct qca_dump_hdr , data );
3452
+ }
3453
+
3454
+ if (!btdata -> qca_dump .ram_dump_size ) {
3455
+ ret = - EINVAL ;
3456
+ bt_dev_err (hdev , "memdump is not active" );
3457
+ goto out ;
3458
+ }
3459
+
3460
+ if ((seqno > btdata -> qca_dump .ram_dump_seqno + 1 ) && (seqno != QCA_LAST_SEQUENCE_NUM )) {
3461
+ dump_size = QCA_MEMDUMP_PKT_SIZE * (seqno - btdata -> qca_dump .ram_dump_seqno - 1 );
3462
+ hci_devcd_append_pattern (hdev , 0x0 , dump_size );
3463
+ bt_dev_err (hdev ,
3464
+ "expected memdump seqno(%u) is not received(%u)\n" ,
3465
+ btdata -> qca_dump .ram_dump_seqno , seqno );
3466
+ btdata -> qca_dump .ram_dump_seqno = seqno ;
3467
+ kfree_skb (skb );
3468
+ return ret ;
3469
+ }
3470
+
3471
+ skb_pull (skb , skb -> len - sk_len );
3472
+ hci_devcd_append (hdev , skb );
3473
+ btdata -> qca_dump .ram_dump_seqno ++ ;
3474
+ if (seqno == QCA_LAST_SEQUENCE_NUM ) {
3475
+ bt_dev_info (hdev ,
3476
+ "memdump done: pkts(%u), total(%u)\n" ,
3477
+ btdata -> qca_dump .ram_dump_seqno , btdata -> qca_dump .ram_dump_size );
3478
+
3479
+ hci_devcd_complete (hdev );
3480
+ goto out ;
3481
+ }
3482
+ return ret ;
3483
+
3484
+ out :
3485
+ if (btdata -> qca_dump .ram_dump_size )
3486
+ usb_enable_autosuspend (udev );
3487
+ btdata -> qca_dump .ram_dump_size = 0 ;
3488
+ btdata -> qca_dump .ram_dump_seqno = 0 ;
3489
+ clear_bit (BTUSB_HW_SSR_ACTIVE , & btdata -> flags );
3490
+
3491
+ if (ret < 0 )
3492
+ kfree_skb (skb );
3493
+ return ret ;
3494
+ }
3495
+
3496
+ static int btusb_recv_acl_qca (struct hci_dev * hdev , struct sk_buff * skb )
3497
+ {
3498
+ if (handle_dump_pkt_qca (hdev , skb ))
3499
+ return 0 ;
3500
+ return hci_recv_frame (hdev , skb );
3501
+ }
3502
+
3503
+ static int btusb_recv_evt_qca (struct hci_dev * hdev , struct sk_buff * skb )
3504
+ {
3505
+ if (handle_dump_pkt_qca (hdev , skb ))
3506
+ return 0 ;
3507
+ return hci_recv_frame (hdev , skb );
3508
+ }
3509
+
3510
+
3297
3511
#define QCA_DFU_PACKET_LEN 4096
3298
3512
3299
3513
#define QCA_GET_TARGET_VERSION 0x09
@@ -3628,6 +3842,9 @@ static int btusb_setup_qca(struct hci_dev *hdev)
3628
3842
if (err < 0 )
3629
3843
return err ;
3630
3844
3845
+ btdata -> qca_dump .fw_version = le32_to_cpu (ver .patch_version );
3846
+ btdata -> qca_dump .controller_id = le32_to_cpu (ver .rom_version );
3847
+
3631
3848
if (!(status & QCA_SYSCFG_UPDATED )) {
3632
3849
err = btusb_setup_qca_load_nvm (hdev , & ver , info );
3633
3850
if (err < 0 )
@@ -4117,6 +4334,11 @@ static int btusb_probe(struct usb_interface *intf,
4117
4334
}
4118
4335
4119
4336
if (id -> driver_info & BTUSB_QCA_WCN6855 ) {
4337
+ data -> qca_dump .id_vendor = id -> idVendor ;
4338
+ data -> qca_dump .id_product = id -> idProduct ;
4339
+ data -> recv_event = btusb_recv_evt_qca ;
4340
+ data -> recv_acl = btusb_recv_acl_qca ;
4341
+ hci_devcd_register (hdev , btusb_coredump_qca , btusb_dump_hdr_qca , NULL );
4120
4342
data -> setup_on_usb = btusb_setup_qca ;
4121
4343
hdev -> shutdown = btusb_shutdown_qca ;
4122
4344
hdev -> set_bdaddr = btusb_set_bdaddr_wcn6855 ;
0 commit comments