Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Bluetooth: btusb: Trigger Intel FW download error recovery

Sometimes during FW data download stage, in case of an error is
encountered the controller device could not be recovered. To recover
from such failures send Intel hard Reset to re-trigger FW download in
following error scenarios:

1. Intel Read version command error
2. Firmware download timeout
3. Failure in Intel Soft Reset for switching to operational FW
4. Boot timeout for switching to operaional FW

Signed-off-by: Raghuram Hegde <raghuram.hegde@intel.com>
Signed-off-by: Chethan T N <chethan.tumkur.narayan@intel.com>
Signed-off-by: Amit K Bag <amit.k.bag@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

authored by

Amit K Bag and committed by
Marcel Holtmann
b9a2562f eb8c101e

+67 -4
+45
drivers/bluetooth/btintel.c
··· 709 709 } 710 710 EXPORT_SYMBOL_GPL(btintel_download_firmware); 711 711 712 + void btintel_reset_to_bootloader(struct hci_dev *hdev) 713 + { 714 + struct intel_reset params; 715 + struct sk_buff *skb; 716 + 717 + /* Send Intel Reset command. This will result in 718 + * re-enumeration of BT controller. 719 + * 720 + * Intel Reset parameter description: 721 + * reset_type : 0x00 (Soft reset), 722 + * 0x01 (Hard reset) 723 + * patch_enable : 0x00 (Do not enable), 724 + * 0x01 (Enable) 725 + * ddc_reload : 0x00 (Do not reload), 726 + * 0x01 (Reload) 727 + * boot_option: 0x00 (Current image), 728 + * 0x01 (Specified boot address) 729 + * boot_param: Boot address 730 + * 731 + */ 732 + params.reset_type = 0x01; 733 + params.patch_enable = 0x01; 734 + params.ddc_reload = 0x01; 735 + params.boot_option = 0x00; 736 + params.boot_param = cpu_to_le32(0x00000000); 737 + 738 + skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(params), 739 + &params, HCI_INIT_TIMEOUT); 740 + if (IS_ERR(skb)) { 741 + bt_dev_err(hdev, "FW download error recovery failed (%ld)", 742 + PTR_ERR(skb)); 743 + return; 744 + } 745 + bt_dev_info(hdev, "Intel reset sent to retry FW download"); 746 + kfree_skb(skb); 747 + 748 + /* Current Intel BT controllers(ThP/JfP) hold the USB reset 749 + * lines for 2ms when it receives Intel Reset in bootloader mode. 750 + * Whereas, the upcoming Intel BT controllers will hold USB reset 751 + * for 150ms. To keep the delay generic, 150ms is chosen here. 752 + */ 753 + msleep(150); 754 + } 755 + EXPORT_SYMBOL_GPL(btintel_reset_to_bootloader); 756 + 712 757 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); 713 758 MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION); 714 759 MODULE_VERSION(VERSION);
+6
drivers/bluetooth/btintel.h
··· 87 87 struct intel_boot_params *params); 88 88 int btintel_download_firmware(struct hci_dev *dev, const struct firmware *fw, 89 89 u32 *boot_param); 90 + void btintel_reset_to_bootloader(struct hci_dev *hdev); 90 91 #else 91 92 92 93 static inline int btintel_check_bdaddr(struct hci_dev *hdev) ··· 179 178 static inline int btintel_download_firmware(struct hci_dev *dev, 180 179 const struct firmware *fw, 181 180 u32 *boot_param) 181 + { 182 + return -EOPNOTSUPP; 183 + } 184 + 185 + static inline void btintel_reset_to_bootloader(struct hci_dev *hdev) 182 186 { 183 187 return -EOPNOTSUPP; 184 188 }
+16 -4
drivers/bluetooth/btusb.c
··· 2182 2182 * loaded. 2183 2183 */ 2184 2184 err = btintel_read_version(hdev, &ver); 2185 - if (err) 2185 + if (err) { 2186 + bt_dev_err(hdev, "Intel Read version failed (%d)", err); 2187 + btintel_reset_to_bootloader(hdev); 2186 2188 return err; 2189 + } 2187 2190 2188 2191 /* The hardware platform number has a fixed value of 0x37 and 2189 2192 * for now only accept this single value. ··· 2329 2326 2330 2327 /* Start firmware downloading and get boot parameter */ 2331 2328 err = btintel_download_firmware(hdev, fw, &boot_param); 2332 - if (err < 0) 2329 + if (err < 0) { 2330 + /* When FW download fails, send Intel Reset to retry 2331 + * FW download. 2332 + */ 2333 + btintel_reset_to_bootloader(hdev); 2333 2334 goto done; 2334 - 2335 + } 2335 2336 set_bit(BTUSB_FIRMWARE_LOADED, &data->flags); 2336 2337 2337 2338 bt_dev_info(hdev, "Waiting for firmware download to complete"); ··· 2362 2355 if (err) { 2363 2356 bt_dev_err(hdev, "Firmware loading timeout"); 2364 2357 err = -ETIMEDOUT; 2358 + btintel_reset_to_bootloader(hdev); 2365 2359 goto done; 2366 2360 } 2367 2361 ··· 2389 2381 set_bit(BTUSB_BOOTING, &data->flags); 2390 2382 2391 2383 err = btintel_send_intel_reset(hdev, boot_param); 2392 - if (err) 2384 + if (err) { 2385 + bt_dev_err(hdev, "Intel Soft Reset failed (%d)", err); 2386 + btintel_reset_to_bootloader(hdev); 2393 2387 return err; 2388 + } 2394 2389 2395 2390 /* The bootloader will not indicate when the device is ready. This 2396 2391 * is done by the operational firmware sending bootup notification. ··· 2415 2404 2416 2405 if (err) { 2417 2406 bt_dev_err(hdev, "Device boot timeout"); 2407 + btintel_reset_to_bootloader(hdev); 2418 2408 return -ETIMEDOUT; 2419 2409 } 2420 2410