Skip to content

Commit 491f9ef

Browse files
NeerajSanjayKaleVudentz
authored andcommitted
Bluetooth: btnxpuart: Improve inband Independent Reset handling
This improves the inband IR command handling for NXP BT chipsets. When the IR vendor command is received, the driver injects a HW error event, which causes a reset sequence in hci_error_reset(). The vendor IR command is sent to the controller while hci dev is been closed, and FW is re-downloaded when nxp_setup() is called during hci_dev_do_open(). The HCI_SETUP flag is set in nxp_hw_err() to make sure that nxp_setup() is been called during hci_dev_do_open(). This also makes the nxp_setup() and power save functions more generic. Signed-off-by: Neeraj Sanjay Kale <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent 8b7630d commit 491f9ef

File tree

1 file changed

+96
-76
lines changed

1 file changed

+96
-76
lines changed

drivers/bluetooth/btnxpuart.c

Lines changed: 96 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
#define BTNXPUART_FW_DOWNLOADING 2
2929
#define BTNXPUART_CHECK_BOOT_SIGNATURE 3
3030
#define BTNXPUART_SERDEV_OPEN 4
31+
#define BTNXPUART_IR_IN_PROGRESS 5
32+
33+
/* NXP HW err codes */
34+
#define BTNXPUART_IR_HW_ERR 0xb0
3135

3236
#define FIRMWARE_W8987 "nxp/uartuart8987_bt.bin"
3337
#define FIRMWARE_W8997 "nxp/uartuart8997_bt_v4.bin"
@@ -380,39 +384,13 @@ static void ps_timeout_func(struct timer_list *t)
380384
}
381385
}
382386

383-
static int ps_init_work(struct hci_dev *hdev)
387+
static void ps_setup(struct hci_dev *hdev)
384388
{
385389
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
386390
struct ps_data *psdata = &nxpdev->psdata;
387391

388-
psdata->h2c_ps_interval = PS_DEFAULT_TIMEOUT_PERIOD_MS;
389-
psdata->ps_state = PS_STATE_AWAKE;
390-
psdata->target_ps_mode = DEFAULT_PS_MODE;
391392
psdata->hdev = hdev;
392-
psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_NONE;
393-
psdata->c2h_wakeup_gpio = 0xff;
394-
395-
switch (DEFAULT_H2C_WAKEUP_MODE) {
396-
case WAKEUP_METHOD_DTR:
397-
psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR;
398-
break;
399-
case WAKEUP_METHOD_BREAK:
400-
default:
401-
psdata->h2c_wakeupmode = WAKEUP_METHOD_BREAK;
402-
break;
403-
}
404-
psdata->cur_psmode = PS_MODE_DISABLE;
405-
psdata->cur_h2c_wakeupmode = WAKEUP_METHOD_INVALID;
406393
INIT_WORK(&psdata->work, ps_work_func);
407-
408-
return 0;
409-
}
410-
411-
static void ps_init_timer(struct hci_dev *hdev)
412-
{
413-
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
414-
struct ps_data *psdata = &nxpdev->psdata;
415-
416394
timer_setup(&psdata->ps_timer, ps_timeout_func, 0);
417395
}
418396

@@ -515,19 +493,31 @@ static void ps_init(struct hci_dev *hdev)
515493
serdev_device_set_tiocm(nxpdev->serdev, TIOCM_RTS, 0);
516494
usleep_range(5000, 10000);
517495

518-
switch (psdata->h2c_wakeupmode) {
496+
psdata->ps_state = PS_STATE_AWAKE;
497+
psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_NONE;
498+
psdata->c2h_wakeup_gpio = 0xff;
499+
500+
psdata->cur_h2c_wakeupmode = WAKEUP_METHOD_INVALID;
501+
psdata->h2c_ps_interval = PS_DEFAULT_TIMEOUT_PERIOD_MS;
502+
switch (DEFAULT_H2C_WAKEUP_MODE) {
519503
case WAKEUP_METHOD_DTR:
504+
psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR;
520505
serdev_device_set_tiocm(nxpdev->serdev, 0, TIOCM_DTR);
521506
serdev_device_set_tiocm(nxpdev->serdev, TIOCM_DTR, 0);
522507
break;
523508
case WAKEUP_METHOD_BREAK:
524509
default:
510+
psdata->h2c_wakeupmode = WAKEUP_METHOD_BREAK;
525511
serdev_device_break_ctl(nxpdev->serdev, -1);
526512
usleep_range(5000, 10000);
527513
serdev_device_break_ctl(nxpdev->serdev, 0);
528514
usleep_range(5000, 10000);
529515
break;
530516
}
517+
518+
psdata->cur_psmode = PS_MODE_DISABLE;
519+
psdata->target_ps_mode = DEFAULT_PS_MODE;
520+
531521
if (psdata->cur_h2c_wakeupmode != psdata->h2c_wakeupmode)
532522
hci_cmd_sync_queue(hdev, send_wakeup_method_cmd, NULL, NULL);
533523
if (psdata->cur_psmode != psdata->target_ps_mode)
@@ -709,7 +699,7 @@ static int nxp_recv_chip_ver_v1(struct hci_dev *hdev, struct sk_buff *skb)
709699
goto free_skb;
710700

711701
chip_id = le16_to_cpu(req->chip_id ^ req->chip_id_comp);
712-
if (chip_id == 0xffff) {
702+
if (chip_id == 0xffff && nxpdev->fw_dnld_v1_offset) {
713703
nxpdev->fw_dnld_v1_offset = 0;
714704
nxpdev->fw_v1_sent_bytes = 0;
715705
nxpdev->fw_v1_expected_len = HDR_LEN;
@@ -987,45 +977,13 @@ static int nxp_set_baudrate_cmd(struct hci_dev *hdev, void *data)
987977
return 0;
988978
}
989979

990-
static int nxp_set_ind_reset(struct hci_dev *hdev, void *data)
991-
{
992-
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
993-
struct sk_buff *skb;
994-
u8 *status;
995-
u8 pcmd = 0;
996-
int err = 0;
997-
998-
skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, &pcmd);
999-
if (IS_ERR(skb))
1000-
return PTR_ERR(skb);
1001-
1002-
status = skb_pull_data(skb, 1);
1003-
if (!status || *status)
1004-
goto free_skb;
1005-
1006-
set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
1007-
err = nxp_download_firmware(hdev);
1008-
if (err < 0)
1009-
goto free_skb;
1010-
serdev_device_set_baudrate(nxpdev->serdev, nxpdev->fw_init_baudrate);
1011-
nxpdev->current_baudrate = nxpdev->fw_init_baudrate;
1012-
if (nxpdev->current_baudrate != HCI_NXP_SEC_BAUDRATE) {
1013-
nxpdev->new_baudrate = HCI_NXP_SEC_BAUDRATE;
1014-
nxp_set_baudrate_cmd(hdev, NULL);
1015-
}
1016-
hci_cmd_sync_queue(hdev, send_wakeup_method_cmd, NULL, NULL);
1017-
hci_cmd_sync_queue(hdev, send_ps_cmd, NULL, NULL);
1018-
1019-
free_skb:
1020-
kfree_skb(skb);
1021-
return err;
1022-
}
1023-
1024-
/* NXP protocol */
1025980
static int nxp_check_boot_sign(struct btnxpuart_dev *nxpdev)
1026981
{
1027982
serdev_device_set_baudrate(nxpdev->serdev, HCI_NXP_PRI_BAUDRATE);
1028-
serdev_device_set_flow_control(nxpdev->serdev, true);
983+
if (test_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state))
984+
serdev_device_set_flow_control(nxpdev->serdev, false);
985+
else
986+
serdev_device_set_flow_control(nxpdev->serdev, true);
1029987
set_bit(BTNXPUART_CHECK_BOOT_SIGNATURE, &nxpdev->tx_state);
1030988

1031989
return wait_event_interruptible_timeout(nxpdev->check_boot_sign_wait_q,
@@ -1034,15 +992,29 @@ static int nxp_check_boot_sign(struct btnxpuart_dev *nxpdev)
1034992
msecs_to_jiffies(1000));
1035993
}
1036994

995+
static int nxp_set_ind_reset(struct hci_dev *hdev, void *data)
996+
{
997+
static const u8 ir_hw_err[] = { HCI_EV_HARDWARE_ERROR,
998+
0x01, BTNXPUART_IR_HW_ERR };
999+
struct sk_buff *skb;
1000+
1001+
skb = bt_skb_alloc(3, GFP_ATOMIC);
1002+
if (!skb)
1003+
return -ENOMEM;
1004+
1005+
hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
1006+
skb_put_data(skb, ir_hw_err, 3);
1007+
1008+
/* Inject Hardware Error to upper stack */
1009+
return hci_recv_frame(hdev, skb);
1010+
}
1011+
1012+
/* NXP protocol */
10371013
static int nxp_setup(struct hci_dev *hdev)
10381014
{
10391015
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
10401016
int err = 0;
10411017

1042-
set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
1043-
init_waitqueue_head(&nxpdev->fw_dnld_done_wait_q);
1044-
init_waitqueue_head(&nxpdev->check_boot_sign_wait_q);
1045-
10461018
if (nxp_check_boot_sign(nxpdev)) {
10471019
bt_dev_dbg(hdev, "Need FW Download.");
10481020
err = nxp_download_firmware(hdev);
@@ -1053,10 +1025,6 @@ static int nxp_setup(struct hci_dev *hdev)
10531025
clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
10541026
}
10551027

1056-
device_property_read_u32(&nxpdev->serdev->dev, "fw-init-baudrate",
1057-
&nxpdev->fw_init_baudrate);
1058-
if (!nxpdev->fw_init_baudrate)
1059-
nxpdev->fw_init_baudrate = FW_INIT_BAUDRATE;
10601028
serdev_device_set_baudrate(nxpdev->serdev, nxpdev->fw_init_baudrate);
10611029
nxpdev->current_baudrate = nxpdev->fw_init_baudrate;
10621030

@@ -1067,6 +1035,46 @@ static int nxp_setup(struct hci_dev *hdev)
10671035

10681036
ps_init(hdev);
10691037

1038+
if (test_and_clear_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state))
1039+
hci_dev_clear_flag(hdev, HCI_SETUP);
1040+
1041+
return 0;
1042+
}
1043+
1044+
static void nxp_hw_err(struct hci_dev *hdev, u8 code)
1045+
{
1046+
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
1047+
1048+
switch (code) {
1049+
case BTNXPUART_IR_HW_ERR:
1050+
set_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state);
1051+
hci_dev_set_flag(hdev, HCI_SETUP);
1052+
break;
1053+
default:
1054+
break;
1055+
}
1056+
}
1057+
1058+
static int nxp_shutdown(struct hci_dev *hdev)
1059+
{
1060+
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
1061+
struct sk_buff *skb;
1062+
u8 *status;
1063+
u8 pcmd = 0;
1064+
1065+
if (test_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state)) {
1066+
skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, &pcmd);
1067+
if (IS_ERR(skb))
1068+
return PTR_ERR(skb);
1069+
1070+
status = skb_pull_data(skb, 1);
1071+
if (status) {
1072+
serdev_device_set_flow_control(nxpdev->serdev, false);
1073+
set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
1074+
}
1075+
kfree_skb(skb);
1076+
}
1077+
10701078
return 0;
10711079
}
10721080

@@ -1274,7 +1282,8 @@ static int btnxpuart_receive_buf(struct serdev_device *serdev, const u8 *data,
12741282
nxpdev->rx_skb = NULL;
12751283
return err;
12761284
}
1277-
nxpdev->hdev->stat.byte_rx += count;
1285+
if (!is_fw_downloading(nxpdev))
1286+
nxpdev->hdev->stat.byte_rx += count;
12781287
return count;
12791288
}
12801289

@@ -1307,6 +1316,16 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
13071316
INIT_WORK(&nxpdev->tx_work, btnxpuart_tx_work);
13081317
skb_queue_head_init(&nxpdev->txq);
13091318

1319+
init_waitqueue_head(&nxpdev->fw_dnld_done_wait_q);
1320+
init_waitqueue_head(&nxpdev->check_boot_sign_wait_q);
1321+
1322+
device_property_read_u32(&nxpdev->serdev->dev, "fw-init-baudrate",
1323+
&nxpdev->fw_init_baudrate);
1324+
if (!nxpdev->fw_init_baudrate)
1325+
nxpdev->fw_init_baudrate = FW_INIT_BAUDRATE;
1326+
1327+
set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
1328+
13101329
crc8_populate_msb(crc8_table, POLYNOMIAL8);
13111330

13121331
/* Initialize and register HCI device */
@@ -1327,6 +1346,8 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
13271346
hdev->flush = btnxpuart_flush;
13281347
hdev->setup = nxp_setup;
13291348
hdev->send = nxp_enqueue;
1349+
hdev->hw_error = nxp_hw_err;
1350+
hdev->shutdown = nxp_shutdown;
13301351
SET_HCIDEV_DEV(hdev, &serdev->dev);
13311352

13321353
if (hci_register_dev(hdev) < 0) {
@@ -1335,8 +1356,7 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
13351356
return -ENODEV;
13361357
}
13371358

1338-
ps_init_work(hdev);
1339-
ps_init_timer(hdev);
1359+
ps_setup(hdev);
13401360

13411361
return 0;
13421362
}

0 commit comments

Comments
 (0)