From: Raghuram Hegde <raghuram.hegde@xxxxxxxxx> Once Firmware download is complete, BULK IN URBs need not be programmed till the Intel Bluetooth controller switches from bootloader to operational firmware, as there will not be any data sent on BULK IN endpoint. If BULK IN URBs are programmed during this time, a USB turn-around time error is seen for BULK IN tokens. This results in XHCI resetting the endpoint data toggle sequence leading to data sequence sync-loss between Host XHCI controller and Bluetooth controller. The following fix is required to prevent data sequence sync-loss: Kill the BULK IN URBs once FW download is complete and re-submit them after Intel BT controller has booted to operational firmware. Signed-off-by: Raghuram Hegde <raghuram.hegde@xxxxxxxxx> Signed-off-by: Chethan T N <chethan.tumkur.narayan@xxxxxxxxx> Cc: stable@xxxxxxxxxxxxxxx --- drivers/bluetooth/btusb.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index ded198328f21..e656acdfd84a 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -2332,6 +2332,15 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) duration = (unsigned long long) ktime_to_ns(delta) >> 10; bt_dev_info(hdev, "Firmware loaded in %llu usecs", duration); + + /* Once Firmware download is complete, Bulk endpoints will not be + * used until the Bluetooth controller boots with operational + * firmware. If we have the Bulk URBs scheduled when Intel Bluetooth + * controller switches from bootloader to operational firmware, we + * observe Bus Turn-around timeouts for Bulk IN tokens.So, to prevent + * such error condition, kill the URBs scheduled on Bulk endpoint. + */ + usb_kill_anchored_urbs(&data->bulk_anchor); done: release_firmware(fw); @@ -2395,6 +2404,18 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) */ btintel_set_event_mask(hdev, false); + /* As the Intel bluetooth controller has now booted in operational + * mode, re-program the URBs for BULK IN endpoint + */ + if (test_bit(BTUSB_BULK_RUNNING, &data->flags)) { + err = btusb_submit_bulk_urb(hdev, GFP_NOIO); + if (err < 0) { + clear_bit(BTUSB_BULK_RUNNING, &data->flags); + return err; + } + btusb_submit_bulk_urb(hdev, GFP_NOIO); + } + return 0; } -- 2.7.4