Commit b9a2562f authored by Amit K Bag's avatar Amit K Bag Committed by Marcel Holtmann

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: default avatarRaghuram Hegde <raghuram.hegde@intel.com>
Signed-off-by: default avatarChethan T N <chethan.tumkur.narayan@intel.com>
Signed-off-by: default avatarAmit K Bag <amit.k.bag@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent eb8c101e
...@@ -709,6 +709,51 @@ int btintel_download_firmware(struct hci_dev *hdev, const struct firmware *fw, ...@@ -709,6 +709,51 @@ int btintel_download_firmware(struct hci_dev *hdev, const struct firmware *fw,
} }
EXPORT_SYMBOL_GPL(btintel_download_firmware); EXPORT_SYMBOL_GPL(btintel_download_firmware);
void btintel_reset_to_bootloader(struct hci_dev *hdev)
{
struct intel_reset params;
struct sk_buff *skb;
/* Send Intel Reset command. This will result in
* re-enumeration of BT controller.
*
* Intel Reset parameter description:
* reset_type : 0x00 (Soft reset),
* 0x01 (Hard reset)
* patch_enable : 0x00 (Do not enable),
* 0x01 (Enable)
* ddc_reload : 0x00 (Do not reload),
* 0x01 (Reload)
* boot_option: 0x00 (Current image),
* 0x01 (Specified boot address)
* boot_param: Boot address
*
*/
params.reset_type = 0x01;
params.patch_enable = 0x01;
params.ddc_reload = 0x01;
params.boot_option = 0x00;
params.boot_param = cpu_to_le32(0x00000000);
skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(params),
&params, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "FW download error recovery failed (%ld)",
PTR_ERR(skb));
return;
}
bt_dev_info(hdev, "Intel reset sent to retry FW download");
kfree_skb(skb);
/* Current Intel BT controllers(ThP/JfP) hold the USB reset
* lines for 2ms when it receives Intel Reset in bootloader mode.
* Whereas, the upcoming Intel BT controllers will hold USB reset
* for 150ms. To keep the delay generic, 150ms is chosen here.
*/
msleep(150);
}
EXPORT_SYMBOL_GPL(btintel_reset_to_bootloader);
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION); MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION);
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
......
...@@ -87,6 +87,7 @@ int btintel_read_boot_params(struct hci_dev *hdev, ...@@ -87,6 +87,7 @@ int btintel_read_boot_params(struct hci_dev *hdev,
struct intel_boot_params *params); struct intel_boot_params *params);
int btintel_download_firmware(struct hci_dev *dev, const struct firmware *fw, int btintel_download_firmware(struct hci_dev *dev, const struct firmware *fw,
u32 *boot_param); u32 *boot_param);
void btintel_reset_to_bootloader(struct hci_dev *hdev);
#else #else
static inline int btintel_check_bdaddr(struct hci_dev *hdev) static inline int btintel_check_bdaddr(struct hci_dev *hdev)
...@@ -181,4 +182,9 @@ static inline int btintel_download_firmware(struct hci_dev *dev, ...@@ -181,4 +182,9 @@ static inline int btintel_download_firmware(struct hci_dev *dev,
{ {
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static inline void btintel_reset_to_bootloader(struct hci_dev *hdev)
{
return -EOPNOTSUPP;
}
#endif #endif
...@@ -2182,8 +2182,11 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) ...@@ -2182,8 +2182,11 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
* loaded. * loaded.
*/ */
err = btintel_read_version(hdev, &ver); err = btintel_read_version(hdev, &ver);
if (err) if (err) {
bt_dev_err(hdev, "Intel Read version failed (%d)", err);
btintel_reset_to_bootloader(hdev);
return err; return err;
}
/* The hardware platform number has a fixed value of 0x37 and /* The hardware platform number has a fixed value of 0x37 and
* for now only accept this single value. * for now only accept this single value.
...@@ -2326,9 +2329,13 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) ...@@ -2326,9 +2329,13 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
/* Start firmware downloading and get boot parameter */ /* Start firmware downloading and get boot parameter */
err = btintel_download_firmware(hdev, fw, &boot_param); err = btintel_download_firmware(hdev, fw, &boot_param);
if (err < 0) if (err < 0) {
/* When FW download fails, send Intel Reset to retry
* FW download.
*/
btintel_reset_to_bootloader(hdev);
goto done; goto done;
}
set_bit(BTUSB_FIRMWARE_LOADED, &data->flags); set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);
bt_dev_info(hdev, "Waiting for firmware download to complete"); bt_dev_info(hdev, "Waiting for firmware download to complete");
...@@ -2355,6 +2362,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) ...@@ -2355,6 +2362,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
if (err) { if (err) {
bt_dev_err(hdev, "Firmware loading timeout"); bt_dev_err(hdev, "Firmware loading timeout");
err = -ETIMEDOUT; err = -ETIMEDOUT;
btintel_reset_to_bootloader(hdev);
goto done; goto done;
} }
...@@ -2381,8 +2389,11 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) ...@@ -2381,8 +2389,11 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
set_bit(BTUSB_BOOTING, &data->flags); set_bit(BTUSB_BOOTING, &data->flags);
err = btintel_send_intel_reset(hdev, boot_param); err = btintel_send_intel_reset(hdev, boot_param);
if (err) if (err) {
bt_dev_err(hdev, "Intel Soft Reset failed (%d)", err);
btintel_reset_to_bootloader(hdev);
return err; return err;
}
/* The bootloader will not indicate when the device is ready. This /* The bootloader will not indicate when the device is ready. This
* is done by the operational firmware sending bootup notification. * is done by the operational firmware sending bootup notification.
...@@ -2404,6 +2415,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) ...@@ -2404,6 +2415,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
if (err) { if (err) {
bt_dev_err(hdev, "Device boot timeout"); bt_dev_err(hdev, "Device boot timeout");
btintel_reset_to_bootloader(hdev);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment