diff mbox series

[1/3] Bluetooth: btusb: Add reset_hci handler

Message ID 20210209133629.12784-2-hui.wang@canonical.com (mailing list archive)
State New, archived
Headers show
Series Add reset hci through mgmt experimental feature | expand

Commit Message

Hui Wang Feb. 9, 2021, 1:36 p.m. UTC
After users update the bluetooth firmware, they want the driver to
load the new firmware, with the current driver, users could not make
sure the driver will load the new firmware, on some laptops, they have
to run poweroff and cold boot the machine, on some desktops, they have
to wait for a couple of seconds between poweroff and cold boot, it is
very annoying to users.

Here adding a reset_hci handler, for hci on the USB bus, we provide
a generic method, this could make the device reset over the USB bus,
it will introduce calling disconnect() and probe(), but this doesn't
guarantee the hci enters bootloader mode and load the new firmware.
For Intel_new and Intel_newgen hcis, there is a method to make them
enter bootloader mode and reset over the USB bus, so we use specific
method to overwrite the generic method for those hcis.

If we have more specific methods to make some hcis enter bootloader
mode in future, we could overwrite the generic method for them like
Intel hcis.

Signed-off-by: Hui Wang <hui.wang@canonical.com>
---
 drivers/bluetooth/btusb.c        | 60 ++++++++++++++++++++++++++++++++
 include/net/bluetooth/hci_core.h |  1 +
 2 files changed, 61 insertions(+)

Comments

bluez.test.bot@gmail.com Feb. 9, 2021, 2:13 p.m. UTC | #1
This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=430719

---Test result---

##############################
    Test: CheckPatch - PASS
    

    ##############################
    Test: CheckGitLint - PASS
    

    ##############################
    Test: CheckBuildK - PASS
    

    ##############################
    Test: CheckTestRunner: Setup - PASS
    

    ##############################
    Test: CheckTestRunner: l2cap-tester - PASS
    Total: 40, Passed: 34 (85.0%), Failed: 0, Not Run: 6

    ##############################
    Test: CheckTestRunner: bnep-tester - PASS
    Total: 1, Passed: 1 (100.0%), Failed: 0, Not Run: 0

    ##############################
    Test: CheckTestRunner: mgmt-tester - PASS
    Total: 416, Passed: 400 (96.2%), Failed: 0, Not Run: 16

    ##############################
    Test: CheckTestRunner: rfcomm-tester - PASS
    Total: 9, Passed: 9 (100.0%), Failed: 0, Not Run: 0

    ##############################
    Test: CheckTestRunner: sco-tester - PASS
    Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0

    ##############################
    Test: CheckTestRunner: smp-tester - PASS
    Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0

    ##############################
    Test: CheckTestRunner: userchan-tester - PASS
    Total: 3, Passed: 3 (100.0%), Failed: 0, Not Run: 0

    

---
Regards,
Linux Bluetooth
diff mbox series

Patch

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 20ef9377694f..79ec73e3d321 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -520,6 +520,7 @@  struct btusb_data {
 
 	struct work_struct work;
 	struct work_struct waker;
+	struct delayed_work reset_work;
 
 	struct usb_anchor deferred;
 	struct usb_anchor tx_anchor;
@@ -561,6 +562,8 @@  struct btusb_data {
 
 	int (*setup_on_usb)(struct hci_dev *hdev);
 
+	void (*btusb_reset_hci_to_bootloader)(struct btusb_data *data);
+
 	int oob_wake_irq;   /* irq for out-of-band wake-on-bt */
 	unsigned cmd_timeout_cnt;
 };
@@ -1384,6 +1387,7 @@  static int btusb_close(struct hci_dev *hdev)
 
 	cancel_work_sync(&data->work);
 	cancel_work_sync(&data->waker);
+	cancel_delayed_work(&data->reset_work);
 
 	clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
 	clear_bit(BTUSB_BULK_RUNNING, &data->flags);
@@ -3105,6 +3109,43 @@  static int btusb_shutdown_intel(struct hci_dev *hdev)
 	return 0;
 }
 
+static void btusb_intel_reset_hci_to_bootloader(struct btusb_data *btdata)
+{
+	btintel_reset_to_bootloader(btdata->hdev);
+}
+
+static void btusb_generic_reset_hci(struct btusb_data *btdata)
+{
+	struct usb_device *udev = btdata->udev;
+	struct usb_interface *intf = btdata->intf;
+	int r;
+
+	/* make sure the usb device is not rt suspended */
+	r = usb_autopm_get_interface(intf);
+	if (r < 0)
+		return;
+
+	r = usb_lock_device_for_reset(udev, NULL);
+	if (r < 0) {
+		usb_autopm_put_interface(intf);
+		return;
+	}
+
+	usb_reset_device(udev);
+
+	usb_unlock_device(udev);
+
+	usb_autopm_put_interface(intf);
+}
+
+static void btusb_reset_work(struct work_struct *work)
+{
+	struct btusb_data *btdata = container_of(work, struct btusb_data,
+						 reset_work.work);
+
+	btdata->btusb_reset_hci_to_bootloader(btdata);
+}
+
 static int btusb_shutdown_intel_new(struct hci_dev *hdev)
 {
 	struct sk_buff *skb;
@@ -3123,6 +3164,19 @@  static int btusb_shutdown_intel_new(struct hci_dev *hdev)
 	return 0;
 }
 
+static int btusb_reset_controller(struct hci_dev *hdev)
+{
+	struct btusb_data *btdata = hci_get_drvdata(hdev);
+
+	/* reset_work will reset the hci on the USB bus, it will introduce
+	 * calling disconnect() and probe(), so implement it in the process
+	 * context.
+	 */
+	schedule_delayed_work(&btdata->reset_work, 0);
+
+	return 0;
+}
+
 #define FIRMWARE_MT7663		"mediatek/mt7663pr2h.bin"
 #define FIRMWARE_MT7668		"mediatek/mt7668pr2h.bin"
 
@@ -4354,6 +4408,7 @@  static int btusb_probe(struct usb_interface *intf,
 
 	INIT_WORK(&data->work, btusb_work);
 	INIT_WORK(&data->waker, btusb_waker);
+	INIT_DELAYED_WORK(&data->reset_work, btusb_reset_work);
 	init_usb_anchor(&data->deferred);
 	init_usb_anchor(&data->tx_anchor);
 	spin_lock_init(&data->txlock);
@@ -4405,6 +4460,7 @@  static int btusb_probe(struct usb_interface *intf,
 	hdev->send   = btusb_send_frame;
 	hdev->notify = btusb_notify;
 	hdev->prevent_wake = btusb_prevent_wake;
+	hdev->reset_hci = btusb_reset_controller;
 
 #ifdef CONFIG_PM
 	err = btusb_config_oob_wake(hdev);
@@ -4418,6 +4474,8 @@  static int btusb_probe(struct usb_interface *intf,
 			goto out_free_dev;
 	}
 #endif
+	data->btusb_reset_hci_to_bootloader = btusb_generic_reset_hci;
+
 	if (id->driver_info & BTUSB_CW6622)
 		set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks);
 
@@ -4469,6 +4527,7 @@  static int btusb_probe(struct usb_interface *intf,
 		hdev->set_diag = btintel_set_diag;
 		hdev->set_bdaddr = btintel_set_bdaddr;
 		hdev->cmd_timeout = btusb_intel_cmd_timeout;
+		data->btusb_reset_hci_to_bootloader = btusb_intel_reset_hci_to_bootloader;
 		set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
 		set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
 		set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
@@ -4489,6 +4548,7 @@  static int btusb_probe(struct usb_interface *intf,
 
 		data->recv_event = btusb_recv_event_intel;
 		data->recv_bulk = btusb_recv_bulk_intel;
+		data->btusb_reset_hci_to_bootloader = btusb_intel_reset_hci_to_bootloader;
 		set_bit(BTUSB_BOOTLOADER, &data->flags);
 	}
 
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 677a8c50b2ad..8f706baf160e 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -581,6 +581,7 @@  struct hci_dev {
 	int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);
 	void (*cmd_timeout)(struct hci_dev *hdev);
 	bool (*prevent_wake)(struct hci_dev *hdev);
+	int (*reset_hci)(struct hci_dev *hdev);
 };
 
 #define HCI_PHY_HANDLE(handle)	(handle & 0xff)