Linux-Bluetooth Archive on lore.kernel.org
 help / Atom feed
* [PATCH 0/5] Reset Intel BT controller if it gets stuck
@ 2018-11-17  1:07 Rajat Jain
  2018-11-17  1:07 ` [PATCH 1/5] usb: split code locating ACPI companion into port and device Rajat Jain
                   ` (6 more replies)
  0 siblings, 7 replies; 20+ messages in thread
From: Rajat Jain @ 2018-11-17  1:07 UTC (permalink / raw)
  To: Marcel Holtmann, Johan Hedberg, Greg Kroah-Hartman,
	David S. Miller, Dmitry Torokhov, Rajat Jain, Alex Hung,
	linux-bluetooth, linux-kernel, linux-usb, netdev
  Cc: rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan, sukumar.ghorai

There can be error conditions within Intel BT firmware that can cause it
to get stuck, with the only way out being toggle the reset pin to the
device. (I do not have the details about the issues that lead to such
conditions, Intel folks copied here can elaborate if needed). Thus, this
is an effor to be able to toggle the reset line from the driver if it
detects such a situation. It makes few enhancements to the common
framework which I think may be useful for other unrelated problems.

Dmitry Torokhov (2):
  usb: split code locating ACPI companion into port and device
  usb: assign ACPI companions for embedded USB devices
  (This basically allows ACPI nodes to be attached to the USB devices,
   thus useful for any onboard / embedded USB devices that wants to get
   some info from the ACPI).

Rajat Jain (3):
  Bluetooth: Reset Bluetooth chip after multiple command timeouts
  Bluetooth: btusb: Collect the common Intel assignments together
  Bluetooth: btusb: Use the hw_reset method to allow resetting the BT
    chip

 drivers/bluetooth/btusb.c        |  63 +++++++++---
 drivers/usb/core/usb-acpi.c      | 163 +++++++++++++++++++------------
 include/net/bluetooth/hci.h      |   8 ++
 include/net/bluetooth/hci_core.h |   2 +
 net/bluetooth/hci_core.c         |  15 ++-
 5 files changed, 171 insertions(+), 80 deletions(-)

-- 
2.19.1.1215.g8438c0b245-goog


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 1/5] usb: split code locating ACPI companion into port and device
  2018-11-17  1:07 [PATCH 0/5] Reset Intel BT controller if it gets stuck Rajat Jain
@ 2018-11-17  1:07 ` Rajat Jain
  2018-11-17  1:07 ` [PATCH 2/5] usb: assign ACPI companions for embedded USB devices Rajat Jain
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 20+ messages in thread
From: Rajat Jain @ 2018-11-17  1:07 UTC (permalink / raw)
  To: Marcel Holtmann, Johan Hedberg, Greg Kroah-Hartman,
	David S. Miller, Dmitry Torokhov, Rajat Jain, Alex Hung,
	linux-bluetooth, linux-kernel, linux-usb, netdev
  Cc: rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan, sukumar.ghorai

From: Dmitry Torokhov <dtor@chromium.org>

In preparation for handling embedded USB devices let's split
usb_acpi_find_companion() into usb_acpi_find_companion_for_device() and
usb_acpi_find_companion_for_port().

Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
Signed-off-by: Rajat Jain <rajatja@google.com>
---
 drivers/usb/core/usb-acpi.c | 133 +++++++++++++++++++-----------------
 1 file changed, 72 insertions(+), 61 deletions(-)

diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
index e221861b3187..8ff73c83e8e8 100644
--- a/drivers/usb/core/usb-acpi.c
+++ b/drivers/usb/core/usb-acpi.c
@@ -139,12 +139,79 @@ static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent,
 	return acpi_find_child_device(parent, raw, false);
 }
 
-static struct acpi_device *usb_acpi_find_companion(struct device *dev)
+static struct acpi_device *
+usb_acpi_get_companion_for_port(struct usb_port *port_dev)
 {
 	struct usb_device *udev;
 	struct acpi_device *adev;
 	acpi_handle *parent_handle;
+	int port1;
+
+	/* Get the struct usb_device point of port's hub */
+	udev = to_usb_device(port_dev->dev.parent->parent);
+
+	/*
+	 * The root hub ports' parent is the root hub. The non-root-hub
+	 * ports' parent is the parent hub port which the hub is
+	 * connected to.
+	 */
+	if (!udev->parent) {
+		adev = ACPI_COMPANION(&udev->dev);
+		port1 = usb_hcd_find_raw_port_number(bus_to_hcd(udev->bus),
+						     port_dev->portnum);
+	} else {
+		parent_handle = usb_get_hub_port_acpi_handle(udev->parent,
+							     udev->portnum);
+		if (!parent_handle)
+			return NULL;
+
+		acpi_bus_get_device(parent_handle, &adev);
+		port1 = port_dev->portnum;
+	}
+
+	return usb_acpi_find_port(adev, port1);
+}
+
+static struct acpi_device *
+usb_acpi_find_companion_for_port(struct usb_port *port_dev)
+{
+	struct acpi_device *adev;
+	struct acpi_pld_info *pld;
+	acpi_handle *handle;
+	acpi_status status;
+
+	adev = usb_acpi_get_companion_for_port(port_dev);
+	if (!adev)
+		return NULL;
+
+	handle = adev->handle;
+	status = acpi_get_physical_device_location(handle, &pld);
+	if (!ACPI_FAILURE(status) && pld) {
+		port_dev->location = USB_ACPI_LOCATION_VALID
+			| pld->group_token << 8 | pld->group_position;
+		port_dev->connect_type = usb_acpi_get_connect_type(handle, pld);
+		ACPI_FREE(pld);
+	}
 
+	return adev;
+}
+
+static struct acpi_device *
+usb_acpi_find_companion_for_device(struct usb_device *udev)
+{
+	struct acpi_device *adev;
+
+	if (!udev->parent)
+		return NULL;
+
+	/* root hub is only child (_ADR=0) under its parent, the HC */
+	adev = ACPI_COMPANION(udev->dev.parent);
+	return acpi_find_child_device(adev, 0, false);
+}
+
+
+static struct acpi_device *usb_acpi_find_companion(struct device *dev)
+{
 	/*
 	 * In the ACPI DSDT table, only usb root hub and usb ports are
 	 * acpi device nodes. The hierarchy like following.
@@ -158,66 +225,10 @@ static struct acpi_device *usb_acpi_find_companion(struct device *dev)
 	 * So all binding process is divided into two parts. binding
 	 * root hub and usb ports.
 	 */
-	if (is_usb_device(dev)) {
-		udev = to_usb_device(dev);
-		if (udev->parent)
-			return NULL;
-
-		/* root hub is only child (_ADR=0) under its parent, the HC */
-		adev = ACPI_COMPANION(dev->parent);
-		return acpi_find_child_device(adev, 0, false);
-	} else if (is_usb_port(dev)) {
-		struct usb_port *port_dev = to_usb_port(dev);
-		int port1 = port_dev->portnum;
-		struct acpi_pld_info *pld;
-		acpi_handle *handle;
-		acpi_status status;
-
-		/* Get the struct usb_device point of port's hub */
-		udev = to_usb_device(dev->parent->parent);
-
-		/*
-		 * The root hub ports' parent is the root hub. The non-root-hub
-		 * ports' parent is the parent hub port which the hub is
-		 * connected to.
-		 */
-		if (!udev->parent) {
-			struct usb_hcd *hcd = bus_to_hcd(udev->bus);
-			int raw;
-
-			raw = usb_hcd_find_raw_port_number(hcd, port1);
-
-			adev = usb_acpi_find_port(ACPI_COMPANION(&udev->dev),
-						  raw);
-
-			if (!adev)
-				return NULL;
-		} else {
-			parent_handle =
-				usb_get_hub_port_acpi_handle(udev->parent,
-				udev->portnum);
-			if (!parent_handle)
-				return NULL;
-
-			acpi_bus_get_device(parent_handle, &adev);
-
-			adev = usb_acpi_find_port(adev, port1);
-
-			if (!adev)
-				return NULL;
-		}
-		handle = adev->handle;
-		status = acpi_get_physical_device_location(handle, &pld);
-		if (ACPI_FAILURE(status) || !pld)
-			return adev;
-
-		port_dev->location = USB_ACPI_LOCATION_VALID
-			| pld->group_token << 8 | pld->group_position;
-		port_dev->connect_type = usb_acpi_get_connect_type(handle, pld);
-		ACPI_FREE(pld);
-
-		return adev;
-	}
+	if (is_usb_device(dev))
+		return usb_acpi_find_companion_for_device(to_usb_device(dev));
+	else if (is_usb_port(dev))
+		return usb_acpi_find_companion_for_port(to_usb_port(dev));
 
 	return NULL;
 }
-- 
2.19.1.1215.g8438c0b245-goog


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 2/5] usb: assign ACPI companions for embedded USB devices
  2018-11-17  1:07 [PATCH 0/5] Reset Intel BT controller if it gets stuck Rajat Jain
  2018-11-17  1:07 ` [PATCH 1/5] usb: split code locating ACPI companion into port and device Rajat Jain
@ 2018-11-17  1:07 ` Rajat Jain
  2018-11-17  1:07 ` [PATCH 3/5] Bluetooth: Reset Bluetooth chip after multiple command timeouts Rajat Jain
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 20+ messages in thread
From: Rajat Jain @ 2018-11-17  1:07 UTC (permalink / raw)
  To: Marcel Holtmann, Johan Hedberg, Greg Kroah-Hartman,
	David S. Miller, Dmitry Torokhov, Rajat Jain, Alex Hung,
	linux-bluetooth, linux-kernel, linux-usb, netdev
  Cc: rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan, sukumar.ghorai

From: Dmitry Torokhov <dtor@chromium.org>

USB devices permanently connected to USB ports may be described in ACPI
tables and share ACPI devices with ports they are connected to. See [1]
for details.

This will allow us to describe sideband resources for devices, such as,
for example, hard reset line for BT USB controllers.

[1] https://docs.microsoft.com/en-us/windows-hardware/drivers/bringup/other-acpi-namespace-objects#acpi-namespace-hierarchy-and-adr-for-embedded-usb-devices

Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
Signed-off-by: Rajat Jain <rajatja@google.com> (changed how we get the usb_port)
---
 drivers/usb/core/usb-acpi.c | 44 +++++++++++++++++++++++++++++--------
 1 file changed, 35 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
index 8ff73c83e8e8..9043d7242d67 100644
--- a/drivers/usb/core/usb-acpi.c
+++ b/drivers/usb/core/usb-acpi.c
@@ -200,30 +200,56 @@ static struct acpi_device *
 usb_acpi_find_companion_for_device(struct usb_device *udev)
 {
 	struct acpi_device *adev;
+	struct usb_port *port_dev;
+	struct usb_hub *hub;
+
+	if (!udev->parent) {
+		/* root hub is only child (_ADR=0) under its parent, the HC */
+		adev = ACPI_COMPANION(udev->dev.parent);
+		return acpi_find_child_device(adev, 0, false);
+	}
 
-	if (!udev->parent)
+	hub = usb_hub_to_struct_hub(udev->parent);
+	if (!hub)
 		return NULL;
 
-	/* root hub is only child (_ADR=0) under its parent, the HC */
-	adev = ACPI_COMPANION(udev->dev.parent);
-	return acpi_find_child_device(adev, 0, false);
+	/*
+	 * This is an embedded USB device connected to a port and such
+	 * devices share port's ACPI companion.
+	 */
+	port_dev = hub->ports[udev->portnum - 1];
+	return usb_acpi_get_companion_for_port(port_dev);
 }
 
-
 static struct acpi_device *usb_acpi_find_companion(struct device *dev)
 {
 	/*
-	 * In the ACPI DSDT table, only usb root hub and usb ports are
-	 * acpi device nodes. The hierarchy like following.
+	 * The USB hierarchy like following:
+	 *
 	 * Device (EHC1)
 	 *	Device (HUBN)
 	 *		Device (PR01)
 	 *			Device (PR11)
 	 *			Device (PR12)
+	 *				Device (FN12)
+	 *				Device (FN13)
 	 *			Device (PR13)
 	 *			...
-	 * So all binding process is divided into two parts. binding
-	 * root hub and usb ports.
+	 * where HUBN is root hub, and PRNN are USB ports and devices
+	 * connected to them, and FNNN are individualk functions for
+	 * connected composite USB devices. PRNN and FNNN may contain
+	 * _CRS and other methods describing sideband resources for
+	 * the connected device.
+	 *
+	 * On the kernel side both root hub and embedded USB devices are
+	 * represented as instances of usb_device structure, and ports
+	 * are represented as usb_port structures, so the whole process
+	 * is split into 2 parts: finding companions for devices and
+	 * finding companions for ports.
+	 *
+	 * Note that we do not handle individual functions of composite
+	 * devices yet, for that we would need to assign companions to
+	 * devices corresponding to USB interfaces.
 	 */
 	if (is_usb_device(dev))
 		return usb_acpi_find_companion_for_device(to_usb_device(dev));
-- 
2.19.1.1215.g8438c0b245-goog


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 3/5] Bluetooth: Reset Bluetooth chip after multiple command timeouts
  2018-11-17  1:07 [PATCH 0/5] Reset Intel BT controller if it gets stuck Rajat Jain
  2018-11-17  1:07 ` [PATCH 1/5] usb: split code locating ACPI companion into port and device Rajat Jain
  2018-11-17  1:07 ` [PATCH 2/5] usb: assign ACPI companions for embedded USB devices Rajat Jain
@ 2018-11-17  1:07 ` Rajat Jain
  2018-11-17  1:07 ` [PATCH 4/5] Bluetooth: btusb: Collect the common Intel assignments together Rajat Jain
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 20+ messages in thread
From: Rajat Jain @ 2018-11-17  1:07 UTC (permalink / raw)
  To: Marcel Holtmann, Johan Hedberg, Greg Kroah-Hartman,
	David S. Miller, Dmitry Torokhov, Rajat Jain, Alex Hung,
	linux-bluetooth, linux-kernel, linux-usb, netdev
  Cc: rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan, sukumar.ghorai

Add a quirk and a hook to allow the HCI core to reset the BT chip
if needed (after a number of timed out commands). Use that new hook to
initiate BT chip reset if the controller fails to respond to certain
number of commands (currently 5) including the HCI reset commands.
This is done based on a newly introduced quirk. This is done based
on some initial work by Intel.

Signed-off-by: Rajat Jain <rajatja@google.com>
---
 include/net/bluetooth/hci.h      |  8 ++++++++
 include/net/bluetooth/hci_core.h |  2 ++
 net/bluetooth/hci_core.c         | 15 +++++++++++++--
 3 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index c36dc1e20556..af02fa5ffe54 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -192,6 +192,14 @@ enum {
 	 *
 	 */
 	HCI_QUIRK_NON_PERSISTENT_SETUP,
+
+	/* When this quirk is set, hw_reset() would be run to reset the
+	 * hardware, after a certain number of commands (currently 5)
+	 * time out because the device fails to respond.
+	 *
+	 * This quirk should be set before hci_register_dev is called.
+	 */
+	HCI_QUIRK_HW_RESET_ON_TIMEOUT,
 };
 
 /* HCI device flags */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index e5ea633ea368..b86218304b80 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -313,6 +313,7 @@ struct hci_dev {
 	unsigned int	acl_cnt;
 	unsigned int	sco_cnt;
 	unsigned int	le_cnt;
+	unsigned int	timeout_cnt;
 
 	unsigned int	acl_mtu;
 	unsigned int	sco_mtu;
@@ -437,6 +438,7 @@ struct hci_dev {
 	int (*post_init)(struct hci_dev *hdev);
 	int (*set_diag)(struct hci_dev *hdev, bool enable);
 	int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);
+	void (*hw_reset)(struct hci_dev *hdev);
 };
 
 #define HCI_PHY_HANDLE(handle)	(handle & 0xff)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 7352fe85674b..ab3a6a8b7ba6 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2569,13 +2569,24 @@ static void hci_cmd_timeout(struct work_struct *work)
 	struct hci_dev *hdev = container_of(work, struct hci_dev,
 					    cmd_timer.work);
 
+	hdev->timeout_cnt++;
 	if (hdev->sent_cmd) {
 		struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data;
 		u16 opcode = __le16_to_cpu(sent->opcode);
 
-		bt_dev_err(hdev, "command 0x%4.4x tx timeout", opcode);
+		bt_dev_err(hdev, "command 0x%4.4x tx timeout (cnt = %u)",
+			   opcode, hdev->timeout_cnt);
 	} else {
-		bt_dev_err(hdev, "command tx timeout");
+		bt_dev_err(hdev, "command tx timeout (cnt = %u)",
+			   hdev->timeout_cnt);
+	}
+
+	if (test_bit(HCI_QUIRK_HW_RESET_ON_TIMEOUT, &hdev->quirks) &&
+	    hdev->timeout_cnt >= 5) {
+		hdev->timeout_cnt = 0;
+		if (hdev->hw_reset)
+			hdev->hw_reset(hdev);
+		return;
 	}
 
 	atomic_set(&hdev->cmd_cnt, 1);
-- 
2.19.1.1215.g8438c0b245-goog


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 4/5] Bluetooth: btusb: Collect the common Intel assignments together
  2018-11-17  1:07 [PATCH 0/5] Reset Intel BT controller if it gets stuck Rajat Jain
                   ` (2 preceding siblings ...)
  2018-11-17  1:07 ` [PATCH 3/5] Bluetooth: Reset Bluetooth chip after multiple command timeouts Rajat Jain
@ 2018-11-17  1:07 ` Rajat Jain
  2018-11-17  1:07 ` [PATCH 5/5] Bluetooth: btusb: Use the hw_reset method to allow resetting the BT chip Rajat Jain
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 20+ messages in thread
From: Rajat Jain @ 2018-11-17  1:07 UTC (permalink / raw)
  To: Marcel Holtmann, Johan Hedberg, Greg Kroah-Hartman,
	David S. Miller, Dmitry Torokhov, Rajat Jain, Alex Hung,
	linux-bluetooth, linux-kernel, linux-usb, netdev
  Cc: rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan, sukumar.ghorai

The BTUSB_INTEL and BTUSB_INTEL_NEW have common functions & quirks are
assigned to hdev structure. Lets collect them together instead of
repeating them in different code branches.

Signed-off-by: Rajat Jain <rajatja@google.com>
---
 drivers/bluetooth/btusb.c | 27 ++++++++++++---------------
 1 file changed, 12 insertions(+), 15 deletions(-)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 7439a7eb50ac..e8e148480c91 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -3077,28 +3077,25 @@ static int btusb_probe(struct usb_interface *intf,
 		data->diag = usb_ifnum_to_if(data->udev, ifnum_base + 2);
 	}
 #endif
+	if (id->driver_info & BTUSB_INTEL ||
+	    id->driver_info & BTUSB_INTEL_NEW) {
 
-	if (id->driver_info & BTUSB_INTEL) {
 		hdev->manufacturer = 2;
-		hdev->setup = btusb_setup_intel;
-		hdev->shutdown = btusb_shutdown_intel;
-		hdev->set_diag = btintel_set_diag_mfg;
 		hdev->set_bdaddr = btintel_set_bdaddr;
 		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);
-	}
 
-	if (id->driver_info & BTUSB_INTEL_NEW) {
-		hdev->manufacturer = 2;
-		hdev->send = btusb_send_frame_intel;
-		hdev->setup = btusb_setup_intel_new;
-		hdev->hw_error = btintel_hw_error;
-		hdev->set_diag = btintel_set_diag;
-		hdev->set_bdaddr = btintel_set_bdaddr;
-		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);
+		if (id->driver_info & BTUSB_INTEL) {
+			hdev->setup = btusb_setup_intel;
+			hdev->shutdown = btusb_shutdown_intel;
+			hdev->set_diag = btintel_set_diag_mfg;
+		} else {
+			hdev->send = btusb_send_frame_intel;
+			hdev->setup = btusb_setup_intel_new;
+			hdev->hw_error = btintel_hw_error;
+			hdev->set_diag = btintel_set_diag;
+		}
 	}
 
 	if (id->driver_info & BTUSB_MARVELL)
-- 
2.19.1.1215.g8438c0b245-goog


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 5/5] Bluetooth: btusb: Use the hw_reset method to allow resetting the BT chip
  2018-11-17  1:07 [PATCH 0/5] Reset Intel BT controller if it gets stuck Rajat Jain
                   ` (3 preceding siblings ...)
  2018-11-17  1:07 ` [PATCH 4/5] Bluetooth: btusb: Collect the common Intel assignments together Rajat Jain
@ 2018-11-17  1:07 ` Rajat Jain
  2018-11-19 23:04 ` [PATCH v2 1/5] usb: split code locating ACPI companion into port and device Rajat Jain
  2018-11-21 23:50 ` [PATCH v3 1/5] usb: split code locating ACPI companion into port and device Rajat Jain
  6 siblings, 0 replies; 20+ messages in thread
From: Rajat Jain @ 2018-11-17  1:07 UTC (permalink / raw)
  To: Marcel Holtmann, Johan Hedberg, Greg Kroah-Hartman,
	David S. Miller, Dmitry Torokhov, Rajat Jain, Alex Hung,
	linux-bluetooth, linux-kernel, linux-usb, netdev
  Cc: rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan, sukumar.ghorai

If the platform provides it, use the reset gpio to reset the BT
chip (requested by the HCI core if needed). This has been found helpful
on some of Intel bluetooth controllers where the firmware gets stuck and
the only way out is a hard reset pin provided by the platform.

Signed-off-by: Rajat Jain <rajatja@google.com>
---
 drivers/bluetooth/btusb.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index e8e148480c91..8aad02d9e211 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -29,6 +29,7 @@
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
 #include <linux/suspend.h>
+#include <linux/gpio/consumer.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -475,6 +476,8 @@ struct btusb_data {
 	struct usb_endpoint_descriptor *diag_tx_ep;
 	struct usb_endpoint_descriptor *diag_rx_ep;
 
+	struct gpio_desc *reset_gpio;
+
 	__u8 cmdreq_type;
 	__u8 cmdreq;
 
@@ -490,6 +493,28 @@ struct btusb_data {
 	int oob_wake_irq;   /* irq for out-of-band wake-on-bt */
 };
 
+
+static void btusb_hw_reset(struct hci_dev *hdev)
+{
+	struct btusb_data *data = hci_get_drvdata(hdev);
+	struct gpio_desc *reset_gpio = data->reset_gpio;
+
+	/*
+	 * Toggle the hard reset line if the platform provides one. The reset
+	 * is going to yank the device off the USB and then replug. So doing
+	 * once is enough. The cleanup is handled correctly on the way out
+	 * (standard USB disconnect), and the new device is detected cleanly
+	 * and bound to the driver again like it should be.
+	 */
+	if (reset_gpio) {
+		bt_dev_dbg(hdev, "%s: Initiating HW reset via gpio", __func__);
+		clear_bit(HCI_QUIRK_HW_RESET_ON_TIMEOUT, &hdev->quirks);
+		gpiod_set_value(reset_gpio, 1);
+		mdelay(100);
+		gpiod_set_value(reset_gpio, 0);
+	}
+}
+
 static inline void btusb_free_frags(struct btusb_data *data)
 {
 	unsigned long flags;
@@ -3030,6 +3055,11 @@ static int btusb_probe(struct usb_interface *intf,
 
 	SET_HCIDEV_DEV(hdev, &intf->dev);
 
+	data->reset_gpio = gpiod_get_optional(&data->udev->dev, "reset",
+					      GPIOD_OUT_LOW);
+	if (data->reset_gpio)
+		hdev->hw_reset = btusb_hw_reset;
+
 	hdev->open   = btusb_open;
 	hdev->close  = btusb_close;
 	hdev->flush  = btusb_flush;
@@ -3085,6 +3115,7 @@ static int btusb_probe(struct usb_interface *intf,
 		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);
+		set_bit(HCI_QUIRK_HW_RESET_ON_TIMEOUT, &hdev->quirks);
 
 		if (id->driver_info & BTUSB_INTEL) {
 			hdev->setup = btusb_setup_intel;
@@ -3225,6 +3256,8 @@ static int btusb_probe(struct usb_interface *intf,
 	return 0;
 
 out_free_dev:
+	if (data->reset_gpio)
+		gpiod_put(data->reset_gpio);
 	hci_free_dev(hdev);
 	return err;
 }
@@ -3268,6 +3301,9 @@ static void btusb_disconnect(struct usb_interface *intf)
 	if (data->oob_wake_irq)
 		device_init_wakeup(&data->udev->dev, false);
 
+	if (data->reset_gpio)
+		gpiod_put(data->reset_gpio);
+
 	hci_free_dev(hdev);
 }
 
-- 
2.19.1.1215.g8438c0b245-goog


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 1/5] usb: split code locating ACPI companion into port and device
  2018-11-17  1:07 [PATCH 0/5] Reset Intel BT controller if it gets stuck Rajat Jain
                   ` (4 preceding siblings ...)
  2018-11-17  1:07 ` [PATCH 5/5] Bluetooth: btusb: Use the hw_reset method to allow resetting the BT chip Rajat Jain
@ 2018-11-19 23:04 ` Rajat Jain
  2018-11-19 23:04   ` [PATCH v2 2/5] usb: assign ACPI companions for embedded USB devices Rajat Jain
                     ` (3 more replies)
  2018-11-21 23:50 ` [PATCH v3 1/5] usb: split code locating ACPI companion into port and device Rajat Jain
  6 siblings, 4 replies; 20+ messages in thread
From: Rajat Jain @ 2018-11-19 23:04 UTC (permalink / raw)
  To: Marcel Holtmann, Johan Hedberg, Greg Kroah-Hartman,
	David S. Miller, Dmitry Torokhov, Rajat Jain, Alex Hung,
	linux-bluetooth, linux-kernel, linux-usb, netdev
  Cc: rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan, sukumar.ghorai

From: Dmitry Torokhov <dtor@chromium.org>

In preparation for handling embedded USB devices let's split
usb_acpi_find_companion() into usb_acpi_find_companion_for_device() and
usb_acpi_find_companion_for_port().

Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
Signed-off-by: Rajat Jain <rajatja@google.com>
---
v2: same as v1

 drivers/usb/core/usb-acpi.c | 133 +++++++++++++++++++-----------------
 1 file changed, 72 insertions(+), 61 deletions(-)

diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
index e221861b3187..8ff73c83e8e8 100644
--- a/drivers/usb/core/usb-acpi.c
+++ b/drivers/usb/core/usb-acpi.c
@@ -139,12 +139,79 @@ static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent,
 	return acpi_find_child_device(parent, raw, false);
 }
 
-static struct acpi_device *usb_acpi_find_companion(struct device *dev)
+static struct acpi_device *
+usb_acpi_get_companion_for_port(struct usb_port *port_dev)
 {
 	struct usb_device *udev;
 	struct acpi_device *adev;
 	acpi_handle *parent_handle;
+	int port1;
+
+	/* Get the struct usb_device point of port's hub */
+	udev = to_usb_device(port_dev->dev.parent->parent);
+
+	/*
+	 * The root hub ports' parent is the root hub. The non-root-hub
+	 * ports' parent is the parent hub port which the hub is
+	 * connected to.
+	 */
+	if (!udev->parent) {
+		adev = ACPI_COMPANION(&udev->dev);
+		port1 = usb_hcd_find_raw_port_number(bus_to_hcd(udev->bus),
+						     port_dev->portnum);
+	} else {
+		parent_handle = usb_get_hub_port_acpi_handle(udev->parent,
+							     udev->portnum);
+		if (!parent_handle)
+			return NULL;
+
+		acpi_bus_get_device(parent_handle, &adev);
+		port1 = port_dev->portnum;
+	}
+
+	return usb_acpi_find_port(adev, port1);
+}
+
+static struct acpi_device *
+usb_acpi_find_companion_for_port(struct usb_port *port_dev)
+{
+	struct acpi_device *adev;
+	struct acpi_pld_info *pld;
+	acpi_handle *handle;
+	acpi_status status;
+
+	adev = usb_acpi_get_companion_for_port(port_dev);
+	if (!adev)
+		return NULL;
+
+	handle = adev->handle;
+	status = acpi_get_physical_device_location(handle, &pld);
+	if (!ACPI_FAILURE(status) && pld) {
+		port_dev->location = USB_ACPI_LOCATION_VALID
+			| pld->group_token << 8 | pld->group_position;
+		port_dev->connect_type = usb_acpi_get_connect_type(handle, pld);
+		ACPI_FREE(pld);
+	}
 
+	return adev;
+}
+
+static struct acpi_device *
+usb_acpi_find_companion_for_device(struct usb_device *udev)
+{
+	struct acpi_device *adev;
+
+	if (!udev->parent)
+		return NULL;
+
+	/* root hub is only child (_ADR=0) under its parent, the HC */
+	adev = ACPI_COMPANION(udev->dev.parent);
+	return acpi_find_child_device(adev, 0, false);
+}
+
+
+static struct acpi_device *usb_acpi_find_companion(struct device *dev)
+{
 	/*
 	 * In the ACPI DSDT table, only usb root hub and usb ports are
 	 * acpi device nodes. The hierarchy like following.
@@ -158,66 +225,10 @@ static struct acpi_device *usb_acpi_find_companion(struct device *dev)
 	 * So all binding process is divided into two parts. binding
 	 * root hub and usb ports.
 	 */
-	if (is_usb_device(dev)) {
-		udev = to_usb_device(dev);
-		if (udev->parent)
-			return NULL;
-
-		/* root hub is only child (_ADR=0) under its parent, the HC */
-		adev = ACPI_COMPANION(dev->parent);
-		return acpi_find_child_device(adev, 0, false);
-	} else if (is_usb_port(dev)) {
-		struct usb_port *port_dev = to_usb_port(dev);
-		int port1 = port_dev->portnum;
-		struct acpi_pld_info *pld;
-		acpi_handle *handle;
-		acpi_status status;
-
-		/* Get the struct usb_device point of port's hub */
-		udev = to_usb_device(dev->parent->parent);
-
-		/*
-		 * The root hub ports' parent is the root hub. The non-root-hub
-		 * ports' parent is the parent hub port which the hub is
-		 * connected to.
-		 */
-		if (!udev->parent) {
-			struct usb_hcd *hcd = bus_to_hcd(udev->bus);
-			int raw;
-
-			raw = usb_hcd_find_raw_port_number(hcd, port1);
-
-			adev = usb_acpi_find_port(ACPI_COMPANION(&udev->dev),
-						  raw);
-
-			if (!adev)
-				return NULL;
-		} else {
-			parent_handle =
-				usb_get_hub_port_acpi_handle(udev->parent,
-				udev->portnum);
-			if (!parent_handle)
-				return NULL;
-
-			acpi_bus_get_device(parent_handle, &adev);
-
-			adev = usb_acpi_find_port(adev, port1);
-
-			if (!adev)
-				return NULL;
-		}
-		handle = adev->handle;
-		status = acpi_get_physical_device_location(handle, &pld);
-		if (ACPI_FAILURE(status) || !pld)
-			return adev;
-
-		port_dev->location = USB_ACPI_LOCATION_VALID
-			| pld->group_token << 8 | pld->group_position;
-		port_dev->connect_type = usb_acpi_get_connect_type(handle, pld);
-		ACPI_FREE(pld);
-
-		return adev;
-	}
+	if (is_usb_device(dev))
+		return usb_acpi_find_companion_for_device(to_usb_device(dev));
+	else if (is_usb_port(dev))
+		return usb_acpi_find_companion_for_port(to_usb_port(dev));
 
 	return NULL;
 }
-- 
2.19.1.1215.g8438c0b245-goog


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 2/5] usb: assign ACPI companions for embedded USB devices
  2018-11-19 23:04 ` [PATCH v2 1/5] usb: split code locating ACPI companion into port and device Rajat Jain
@ 2018-11-19 23:04   ` Rajat Jain
  2018-11-19 23:04   ` [PATCH v2 3/5] Bluetooth: Reset Bluetooth chip after multiple command timeouts Rajat Jain
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 20+ messages in thread
From: Rajat Jain @ 2018-11-19 23:04 UTC (permalink / raw)
  To: Marcel Holtmann, Johan Hedberg, Greg Kroah-Hartman,
	David S. Miller, Dmitry Torokhov, Rajat Jain, Alex Hung,
	linux-bluetooth, linux-kernel, linux-usb, netdev
  Cc: rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan, sukumar.ghorai

From: Dmitry Torokhov <dtor@chromium.org>

USB devices permanently connected to USB ports may be described in ACPI
tables and share ACPI devices with ports they are connected to. See [1]
for details.

This will allow us to describe sideband resources for devices, such as,
for example, hard reset line for BT USB controllers.

[1] https://docs.microsoft.com/en-us/windows-hardware/drivers/bringup/other-acpi-namespace-objects#acpi-namespace-hierarchy-and-adr-for-embedded-usb-devices

Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
Signed-off-by: Rajat Jain <rajatja@google.com> (changed how we get the usb_port)
---
v2: same as v1

 drivers/usb/core/usb-acpi.c | 44 +++++++++++++++++++++++++++++--------
 1 file changed, 35 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
index 8ff73c83e8e8..9043d7242d67 100644
--- a/drivers/usb/core/usb-acpi.c
+++ b/drivers/usb/core/usb-acpi.c
@@ -200,30 +200,56 @@ static struct acpi_device *
 usb_acpi_find_companion_for_device(struct usb_device *udev)
 {
 	struct acpi_device *adev;
+	struct usb_port *port_dev;
+	struct usb_hub *hub;
+
+	if (!udev->parent) {
+		/* root hub is only child (_ADR=0) under its parent, the HC */
+		adev = ACPI_COMPANION(udev->dev.parent);
+		return acpi_find_child_device(adev, 0, false);
+	}
 
-	if (!udev->parent)
+	hub = usb_hub_to_struct_hub(udev->parent);
+	if (!hub)
 		return NULL;
 
-	/* root hub is only child (_ADR=0) under its parent, the HC */
-	adev = ACPI_COMPANION(udev->dev.parent);
-	return acpi_find_child_device(adev, 0, false);
+	/*
+	 * This is an embedded USB device connected to a port and such
+	 * devices share port's ACPI companion.
+	 */
+	port_dev = hub->ports[udev->portnum - 1];
+	return usb_acpi_get_companion_for_port(port_dev);
 }
 
-
 static struct acpi_device *usb_acpi_find_companion(struct device *dev)
 {
 	/*
-	 * In the ACPI DSDT table, only usb root hub and usb ports are
-	 * acpi device nodes. The hierarchy like following.
+	 * The USB hierarchy like following:
+	 *
 	 * Device (EHC1)
 	 *	Device (HUBN)
 	 *		Device (PR01)
 	 *			Device (PR11)
 	 *			Device (PR12)
+	 *				Device (FN12)
+	 *				Device (FN13)
 	 *			Device (PR13)
 	 *			...
-	 * So all binding process is divided into two parts. binding
-	 * root hub and usb ports.
+	 * where HUBN is root hub, and PRNN are USB ports and devices
+	 * connected to them, and FNNN are individualk functions for
+	 * connected composite USB devices. PRNN and FNNN may contain
+	 * _CRS and other methods describing sideband resources for
+	 * the connected device.
+	 *
+	 * On the kernel side both root hub and embedded USB devices are
+	 * represented as instances of usb_device structure, and ports
+	 * are represented as usb_port structures, so the whole process
+	 * is split into 2 parts: finding companions for devices and
+	 * finding companions for ports.
+	 *
+	 * Note that we do not handle individual functions of composite
+	 * devices yet, for that we would need to assign companions to
+	 * devices corresponding to USB interfaces.
 	 */
 	if (is_usb_device(dev))
 		return usb_acpi_find_companion_for_device(to_usb_device(dev));
-- 
2.19.1.1215.g8438c0b245-goog


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 3/5] Bluetooth: Reset Bluetooth chip after multiple command timeouts
  2018-11-19 23:04 ` [PATCH v2 1/5] usb: split code locating ACPI companion into port and device Rajat Jain
  2018-11-19 23:04   ` [PATCH v2 2/5] usb: assign ACPI companions for embedded USB devices Rajat Jain
@ 2018-11-19 23:04   ` Rajat Jain
  2018-11-19 23:04   ` [PATCH v2 4/5] Bluetooth: btusb: Collect the common Intel assignments together Rajat Jain
  2018-11-19 23:04   ` [PATCH v2 5/5] Bluetooth: btusb: Use the hw_reset method to allow resetting the BT chip Rajat Jain
  3 siblings, 0 replies; 20+ messages in thread
From: Rajat Jain @ 2018-11-19 23:04 UTC (permalink / raw)
  To: Marcel Holtmann, Johan Hedberg, Greg Kroah-Hartman,
	David S. Miller, Dmitry Torokhov, Rajat Jain, Alex Hung,
	linux-bluetooth, linux-kernel, linux-usb, netdev
  Cc: rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan, sukumar.ghorai

Add a quirk and a hook to allow the HCI core to reset the BT chip
if needed (after a number of timed out commands). Use that new hook to
initiate BT chip reset if the controller fails to respond to certain
number of commands (currently 5) including the HCI reset commands.
This is done based on a newly introduced quirk. This is done based
on some initial work by Intel.

Signed-off-by: Rajat Jain <rajatja@google.com>
---
v2: same as v1

 include/net/bluetooth/hci.h      |  8 ++++++++
 include/net/bluetooth/hci_core.h |  2 ++
 net/bluetooth/hci_core.c         | 15 +++++++++++++--
 3 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index c36dc1e20556..af02fa5ffe54 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -192,6 +192,14 @@ enum {
 	 *
 	 */
 	HCI_QUIRK_NON_PERSISTENT_SETUP,
+
+	/* When this quirk is set, hw_reset() would be run to reset the
+	 * hardware, after a certain number of commands (currently 5)
+	 * time out because the device fails to respond.
+	 *
+	 * This quirk should be set before hci_register_dev is called.
+	 */
+	HCI_QUIRK_HW_RESET_ON_TIMEOUT,
 };
 
 /* HCI device flags */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index e5ea633ea368..b86218304b80 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -313,6 +313,7 @@ struct hci_dev {
 	unsigned int	acl_cnt;
 	unsigned int	sco_cnt;
 	unsigned int	le_cnt;
+	unsigned int	timeout_cnt;
 
 	unsigned int	acl_mtu;
 	unsigned int	sco_mtu;
@@ -437,6 +438,7 @@ struct hci_dev {
 	int (*post_init)(struct hci_dev *hdev);
 	int (*set_diag)(struct hci_dev *hdev, bool enable);
 	int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);
+	void (*hw_reset)(struct hci_dev *hdev);
 };
 
 #define HCI_PHY_HANDLE(handle)	(handle & 0xff)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 7352fe85674b..ab3a6a8b7ba6 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2569,13 +2569,24 @@ static void hci_cmd_timeout(struct work_struct *work)
 	struct hci_dev *hdev = container_of(work, struct hci_dev,
 					    cmd_timer.work);
 
+	hdev->timeout_cnt++;
 	if (hdev->sent_cmd) {
 		struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data;
 		u16 opcode = __le16_to_cpu(sent->opcode);
 
-		bt_dev_err(hdev, "command 0x%4.4x tx timeout", opcode);
+		bt_dev_err(hdev, "command 0x%4.4x tx timeout (cnt = %u)",
+			   opcode, hdev->timeout_cnt);
 	} else {
-		bt_dev_err(hdev, "command tx timeout");
+		bt_dev_err(hdev, "command tx timeout (cnt = %u)",
+			   hdev->timeout_cnt);
+	}
+
+	if (test_bit(HCI_QUIRK_HW_RESET_ON_TIMEOUT, &hdev->quirks) &&
+	    hdev->timeout_cnt >= 5) {
+		hdev->timeout_cnt = 0;
+		if (hdev->hw_reset)
+			hdev->hw_reset(hdev);
+		return;
 	}
 
 	atomic_set(&hdev->cmd_cnt, 1);
-- 
2.19.1.1215.g8438c0b245-goog


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 4/5] Bluetooth: btusb: Collect the common Intel assignments together
  2018-11-19 23:04 ` [PATCH v2 1/5] usb: split code locating ACPI companion into port and device Rajat Jain
  2018-11-19 23:04   ` [PATCH v2 2/5] usb: assign ACPI companions for embedded USB devices Rajat Jain
  2018-11-19 23:04   ` [PATCH v2 3/5] Bluetooth: Reset Bluetooth chip after multiple command timeouts Rajat Jain
@ 2018-11-19 23:04   ` Rajat Jain
  2018-11-19 23:04   ` [PATCH v2 5/5] Bluetooth: btusb: Use the hw_reset method to allow resetting the BT chip Rajat Jain
  3 siblings, 0 replies; 20+ messages in thread
From: Rajat Jain @ 2018-11-19 23:04 UTC (permalink / raw)
  To: Marcel Holtmann, Johan Hedberg, Greg Kroah-Hartman,
	David S. Miller, Dmitry Torokhov, Rajat Jain, Alex Hung,
	linux-bluetooth, linux-kernel, linux-usb, netdev
  Cc: rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan, sukumar.ghorai

The BTUSB_INTEL and BTUSB_INTEL_NEW have common functions & quirks are
assigned to hdev structure. Lets collect them together instead of
repeating them in different code branches.

Signed-off-by: Rajat Jain <rajatja@google.com>
---
v2: same as v1

 drivers/bluetooth/btusb.c | 27 ++++++++++++---------------
 1 file changed, 12 insertions(+), 15 deletions(-)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 7439a7eb50ac..e8e148480c91 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -3077,28 +3077,25 @@ static int btusb_probe(struct usb_interface *intf,
 		data->diag = usb_ifnum_to_if(data->udev, ifnum_base + 2);
 	}
 #endif
+	if (id->driver_info & BTUSB_INTEL ||
+	    id->driver_info & BTUSB_INTEL_NEW) {
 
-	if (id->driver_info & BTUSB_INTEL) {
 		hdev->manufacturer = 2;
-		hdev->setup = btusb_setup_intel;
-		hdev->shutdown = btusb_shutdown_intel;
-		hdev->set_diag = btintel_set_diag_mfg;
 		hdev->set_bdaddr = btintel_set_bdaddr;
 		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);
-	}
 
-	if (id->driver_info & BTUSB_INTEL_NEW) {
-		hdev->manufacturer = 2;
-		hdev->send = btusb_send_frame_intel;
-		hdev->setup = btusb_setup_intel_new;
-		hdev->hw_error = btintel_hw_error;
-		hdev->set_diag = btintel_set_diag;
-		hdev->set_bdaddr = btintel_set_bdaddr;
-		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);
+		if (id->driver_info & BTUSB_INTEL) {
+			hdev->setup = btusb_setup_intel;
+			hdev->shutdown = btusb_shutdown_intel;
+			hdev->set_diag = btintel_set_diag_mfg;
+		} else {
+			hdev->send = btusb_send_frame_intel;
+			hdev->setup = btusb_setup_intel_new;
+			hdev->hw_error = btintel_hw_error;
+			hdev->set_diag = btintel_set_diag;
+		}
 	}
 
 	if (id->driver_info & BTUSB_MARVELL)
-- 
2.19.1.1215.g8438c0b245-goog


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 5/5] Bluetooth: btusb: Use the hw_reset method to allow resetting the BT chip
  2018-11-19 23:04 ` [PATCH v2 1/5] usb: split code locating ACPI companion into port and device Rajat Jain
                     ` (2 preceding siblings ...)
  2018-11-19 23:04   ` [PATCH v2 4/5] Bluetooth: btusb: Collect the common Intel assignments together Rajat Jain
@ 2018-11-19 23:04   ` Rajat Jain
  3 siblings, 0 replies; 20+ messages in thread
From: Rajat Jain @ 2018-11-19 23:04 UTC (permalink / raw)
  To: Marcel Holtmann, Johan Hedberg, Greg Kroah-Hartman,
	David S. Miller, Dmitry Torokhov, Rajat Jain, Alex Hung,
	linux-bluetooth, linux-kernel, linux-usb, netdev
  Cc: rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan, sukumar.ghorai

If the platform provides it, use the reset gpio to reset the BT
chip (requested by the HCI core if needed). This has been found helpful
on some of Intel bluetooth controllers where the firmware gets stuck and
the only way out is a hard reset pin provided by the platform.

Signed-off-by: Rajat Jain <rajatja@google.com>
---
v2: Handle the EPROBE_DEFER case.

 drivers/bluetooth/btusb.c | 42 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index e8e148480c91..bf522cfe68c1 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -29,6 +29,7 @@
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
 #include <linux/suspend.h>
+#include <linux/gpio/consumer.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -475,6 +476,8 @@ struct btusb_data {
 	struct usb_endpoint_descriptor *diag_tx_ep;
 	struct usb_endpoint_descriptor *diag_rx_ep;
 
+	struct gpio_desc *reset_gpio;
+
 	__u8 cmdreq_type;
 	__u8 cmdreq;
 
@@ -490,6 +493,28 @@ struct btusb_data {
 	int oob_wake_irq;   /* irq for out-of-band wake-on-bt */
 };
 
+
+static void btusb_hw_reset(struct hci_dev *hdev)
+{
+	struct btusb_data *data = hci_get_drvdata(hdev);
+	struct gpio_desc *reset_gpio = data->reset_gpio;
+
+	/*
+	 * Toggle the hard reset line if the platform provides one. The reset
+	 * is going to yank the device off the USB and then replug. So doing
+	 * once is enough. The cleanup is handled correctly on the way out
+	 * (standard USB disconnect), and the new device is detected cleanly
+	 * and bound to the driver again like it should be.
+	 */
+	if (reset_gpio) {
+		bt_dev_dbg(hdev, "%s: Initiating HW reset via gpio", __func__);
+		clear_bit(HCI_QUIRK_HW_RESET_ON_TIMEOUT, &hdev->quirks);
+		gpiod_set_value(reset_gpio, 1);
+		mdelay(100);
+		gpiod_set_value(reset_gpio, 0);
+	}
+}
+
 static inline void btusb_free_frags(struct btusb_data *data)
 {
 	unsigned long flags;
@@ -2917,6 +2942,7 @@ static int btusb_probe(struct usb_interface *intf,
 		       const struct usb_device_id *id)
 {
 	struct usb_endpoint_descriptor *ep_desc;
+	struct gpio_desc *reset_gpio;
 	struct btusb_data *data;
 	struct hci_dev *hdev;
 	unsigned ifnum_base;
@@ -3030,6 +3056,16 @@ static int btusb_probe(struct usb_interface *intf,
 
 	SET_HCIDEV_DEV(hdev, &intf->dev);
 
+	reset_gpio = gpiod_get_optional(&data->udev->dev, "reset",
+					GPIOD_OUT_LOW);
+	if (PTR_ERR(reset_gpio) == -EPROBE_DEFER) {
+		err = -EPROBE_DEFER;
+		goto out_free_dev;
+	} else if (!IS_ERR(reset_gpio)) {
+		data->reset_gpio = reset_gpio;
+		hdev->hw_reset = btusb_hw_reset;
+	}
+
 	hdev->open   = btusb_open;
 	hdev->close  = btusb_close;
 	hdev->flush  = btusb_flush;
@@ -3085,6 +3121,7 @@ static int btusb_probe(struct usb_interface *intf,
 		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);
+		set_bit(HCI_QUIRK_HW_RESET_ON_TIMEOUT, &hdev->quirks);
 
 		if (id->driver_info & BTUSB_INTEL) {
 			hdev->setup = btusb_setup_intel;
@@ -3225,6 +3262,8 @@ static int btusb_probe(struct usb_interface *intf,
 	return 0;
 
 out_free_dev:
+	if (data->reset_gpio)
+		gpiod_put(data->reset_gpio);
 	hci_free_dev(hdev);
 	return err;
 }
@@ -3268,6 +3307,9 @@ static void btusb_disconnect(struct usb_interface *intf)
 	if (data->oob_wake_irq)
 		device_init_wakeup(&data->udev->dev, false);
 
+	if (data->reset_gpio)
+		gpiod_put(data->reset_gpio);
+
 	hci_free_dev(hdev);
 }
 
-- 
2.19.1.1215.g8438c0b245-goog


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 1/5] usb: split code locating ACPI companion into port and device
  2018-11-17  1:07 [PATCH 0/5] Reset Intel BT controller if it gets stuck Rajat Jain
                   ` (5 preceding siblings ...)
  2018-11-19 23:04 ` [PATCH v2 1/5] usb: split code locating ACPI companion into port and device Rajat Jain
@ 2018-11-21 23:50 ` Rajat Jain
  2018-11-21 23:50   ` [PATCH v3 2/5] usb: assign ACPI companions for embedded USB devices Rajat Jain
                     ` (4 more replies)
  6 siblings, 5 replies; 20+ messages in thread
From: Rajat Jain @ 2018-11-21 23:50 UTC (permalink / raw)
  To: Marcel Holtmann, Johan Hedberg, Greg Kroah-Hartman,
	David S. Miller, Dmitry Torokhov, Rajat Jain, Alex Hung,
	linux-bluetooth, linux-kernel, linux-usb, netdev
  Cc: rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan, sukumar.ghorai

From: Dmitry Torokhov <dtor@chromium.org>

In preparation for handling embedded USB devices let's split
usb_acpi_find_companion() into usb_acpi_find_companion_for_device() and
usb_acpi_find_companion_for_port().

Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
Signed-off-by: Rajat Jain <rajatja@google.com>
---
v3: same as v1
v2: same as v1

 drivers/usb/core/usb-acpi.c | 133 +++++++++++++++++++-----------------
 1 file changed, 72 insertions(+), 61 deletions(-)

diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
index e221861b3187..8ff73c83e8e8 100644
--- a/drivers/usb/core/usb-acpi.c
+++ b/drivers/usb/core/usb-acpi.c
@@ -139,12 +139,79 @@ static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent,
 	return acpi_find_child_device(parent, raw, false);
 }
 
-static struct acpi_device *usb_acpi_find_companion(struct device *dev)
+static struct acpi_device *
+usb_acpi_get_companion_for_port(struct usb_port *port_dev)
 {
 	struct usb_device *udev;
 	struct acpi_device *adev;
 	acpi_handle *parent_handle;
+	int port1;
+
+	/* Get the struct usb_device point of port's hub */
+	udev = to_usb_device(port_dev->dev.parent->parent);
+
+	/*
+	 * The root hub ports' parent is the root hub. The non-root-hub
+	 * ports' parent is the parent hub port which the hub is
+	 * connected to.
+	 */
+	if (!udev->parent) {
+		adev = ACPI_COMPANION(&udev->dev);
+		port1 = usb_hcd_find_raw_port_number(bus_to_hcd(udev->bus),
+						     port_dev->portnum);
+	} else {
+		parent_handle = usb_get_hub_port_acpi_handle(udev->parent,
+							     udev->portnum);
+		if (!parent_handle)
+			return NULL;
+
+		acpi_bus_get_device(parent_handle, &adev);
+		port1 = port_dev->portnum;
+	}
+
+	return usb_acpi_find_port(adev, port1);
+}
+
+static struct acpi_device *
+usb_acpi_find_companion_for_port(struct usb_port *port_dev)
+{
+	struct acpi_device *adev;
+	struct acpi_pld_info *pld;
+	acpi_handle *handle;
+	acpi_status status;
+
+	adev = usb_acpi_get_companion_for_port(port_dev);
+	if (!adev)
+		return NULL;
+
+	handle = adev->handle;
+	status = acpi_get_physical_device_location(handle, &pld);
+	if (!ACPI_FAILURE(status) && pld) {
+		port_dev->location = USB_ACPI_LOCATION_VALID
+			| pld->group_token << 8 | pld->group_position;
+		port_dev->connect_type = usb_acpi_get_connect_type(handle, pld);
+		ACPI_FREE(pld);
+	}
 
+	return adev;
+}
+
+static struct acpi_device *
+usb_acpi_find_companion_for_device(struct usb_device *udev)
+{
+	struct acpi_device *adev;
+
+	if (!udev->parent)
+		return NULL;
+
+	/* root hub is only child (_ADR=0) under its parent, the HC */
+	adev = ACPI_COMPANION(udev->dev.parent);
+	return acpi_find_child_device(adev, 0, false);
+}
+
+
+static struct acpi_device *usb_acpi_find_companion(struct device *dev)
+{
 	/*
 	 * In the ACPI DSDT table, only usb root hub and usb ports are
 	 * acpi device nodes. The hierarchy like following.
@@ -158,66 +225,10 @@ static struct acpi_device *usb_acpi_find_companion(struct device *dev)
 	 * So all binding process is divided into two parts. binding
 	 * root hub and usb ports.
 	 */
-	if (is_usb_device(dev)) {
-		udev = to_usb_device(dev);
-		if (udev->parent)
-			return NULL;
-
-		/* root hub is only child (_ADR=0) under its parent, the HC */
-		adev = ACPI_COMPANION(dev->parent);
-		return acpi_find_child_device(adev, 0, false);
-	} else if (is_usb_port(dev)) {
-		struct usb_port *port_dev = to_usb_port(dev);
-		int port1 = port_dev->portnum;
-		struct acpi_pld_info *pld;
-		acpi_handle *handle;
-		acpi_status status;
-
-		/* Get the struct usb_device point of port's hub */
-		udev = to_usb_device(dev->parent->parent);
-
-		/*
-		 * The root hub ports' parent is the root hub. The non-root-hub
-		 * ports' parent is the parent hub port which the hub is
-		 * connected to.
-		 */
-		if (!udev->parent) {
-			struct usb_hcd *hcd = bus_to_hcd(udev->bus);
-			int raw;
-
-			raw = usb_hcd_find_raw_port_number(hcd, port1);
-
-			adev = usb_acpi_find_port(ACPI_COMPANION(&udev->dev),
-						  raw);
-
-			if (!adev)
-				return NULL;
-		} else {
-			parent_handle =
-				usb_get_hub_port_acpi_handle(udev->parent,
-				udev->portnum);
-			if (!parent_handle)
-				return NULL;
-
-			acpi_bus_get_device(parent_handle, &adev);
-
-			adev = usb_acpi_find_port(adev, port1);
-
-			if (!adev)
-				return NULL;
-		}
-		handle = adev->handle;
-		status = acpi_get_physical_device_location(handle, &pld);
-		if (ACPI_FAILURE(status) || !pld)
-			return adev;
-
-		port_dev->location = USB_ACPI_LOCATION_VALID
-			| pld->group_token << 8 | pld->group_position;
-		port_dev->connect_type = usb_acpi_get_connect_type(handle, pld);
-		ACPI_FREE(pld);
-
-		return adev;
-	}
+	if (is_usb_device(dev))
+		return usb_acpi_find_companion_for_device(to_usb_device(dev));
+	else if (is_usb_port(dev))
+		return usb_acpi_find_companion_for_port(to_usb_port(dev));
 
 	return NULL;
 }
-- 
2.19.1.1215.g8438c0b245-goog


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 2/5] usb: assign ACPI companions for embedded USB devices
  2018-11-21 23:50 ` [PATCH v3 1/5] usb: split code locating ACPI companion into port and device Rajat Jain
@ 2018-11-21 23:50   ` Rajat Jain
  2018-12-05  9:32     ` Greg Kroah-Hartman
  2018-11-21 23:50   ` [PATCH v3 3/5] Bluetooth: Reset Bluetooth chip after multiple command timeouts Rajat Jain
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 20+ messages in thread
From: Rajat Jain @ 2018-11-21 23:50 UTC (permalink / raw)
  To: Marcel Holtmann, Johan Hedberg, Greg Kroah-Hartman,
	David S. Miller, Dmitry Torokhov, Rajat Jain, Alex Hung,
	linux-bluetooth, linux-kernel, linux-usb, netdev
  Cc: rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan, sukumar.ghorai

From: Dmitry Torokhov <dtor@chromium.org>

USB devices permanently connected to USB ports may be described in ACPI
tables and share ACPI devices with ports they are connected to. See [1]
for details.

This will allow us to describe sideband resources for devices, such as,
for example, hard reset line for BT USB controllers.

[1] https://docs.microsoft.com/en-us/windows-hardware/drivers/bringup/other-acpi-namespace-objects#acpi-namespace-hierarchy-and-adr-for-embedded-usb-devices

Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
Signed-off-by: Rajat Jain <rajatja@google.com> (changed how we get the usb_port)
---
v3: same as v1
v2: same as v1

 drivers/usb/core/usb-acpi.c | 44 +++++++++++++++++++++++++++++--------
 1 file changed, 35 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
index 8ff73c83e8e8..9043d7242d67 100644
--- a/drivers/usb/core/usb-acpi.c
+++ b/drivers/usb/core/usb-acpi.c
@@ -200,30 +200,56 @@ static struct acpi_device *
 usb_acpi_find_companion_for_device(struct usb_device *udev)
 {
 	struct acpi_device *adev;
+	struct usb_port *port_dev;
+	struct usb_hub *hub;
+
+	if (!udev->parent) {
+		/* root hub is only child (_ADR=0) under its parent, the HC */
+		adev = ACPI_COMPANION(udev->dev.parent);
+		return acpi_find_child_device(adev, 0, false);
+	}
 
-	if (!udev->parent)
+	hub = usb_hub_to_struct_hub(udev->parent);
+	if (!hub)
 		return NULL;
 
-	/* root hub is only child (_ADR=0) under its parent, the HC */
-	adev = ACPI_COMPANION(udev->dev.parent);
-	return acpi_find_child_device(adev, 0, false);
+	/*
+	 * This is an embedded USB device connected to a port and such
+	 * devices share port's ACPI companion.
+	 */
+	port_dev = hub->ports[udev->portnum - 1];
+	return usb_acpi_get_companion_for_port(port_dev);
 }
 
-
 static struct acpi_device *usb_acpi_find_companion(struct device *dev)
 {
 	/*
-	 * In the ACPI DSDT table, only usb root hub and usb ports are
-	 * acpi device nodes. The hierarchy like following.
+	 * The USB hierarchy like following:
+	 *
 	 * Device (EHC1)
 	 *	Device (HUBN)
 	 *		Device (PR01)
 	 *			Device (PR11)
 	 *			Device (PR12)
+	 *				Device (FN12)
+	 *				Device (FN13)
 	 *			Device (PR13)
 	 *			...
-	 * So all binding process is divided into two parts. binding
-	 * root hub and usb ports.
+	 * where HUBN is root hub, and PRNN are USB ports and devices
+	 * connected to them, and FNNN are individualk functions for
+	 * connected composite USB devices. PRNN and FNNN may contain
+	 * _CRS and other methods describing sideband resources for
+	 * the connected device.
+	 *
+	 * On the kernel side both root hub and embedded USB devices are
+	 * represented as instances of usb_device structure, and ports
+	 * are represented as usb_port structures, so the whole process
+	 * is split into 2 parts: finding companions for devices and
+	 * finding companions for ports.
+	 *
+	 * Note that we do not handle individual functions of composite
+	 * devices yet, for that we would need to assign companions to
+	 * devices corresponding to USB interfaces.
 	 */
 	if (is_usb_device(dev))
 		return usb_acpi_find_companion_for_device(to_usb_device(dev));
-- 
2.19.1.1215.g8438c0b245-goog


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 3/5] Bluetooth: Reset Bluetooth chip after multiple command timeouts
  2018-11-21 23:50 ` [PATCH v3 1/5] usb: split code locating ACPI companion into port and device Rajat Jain
  2018-11-21 23:50   ` [PATCH v3 2/5] usb: assign ACPI companions for embedded USB devices Rajat Jain
@ 2018-11-21 23:50   ` Rajat Jain
  2018-11-21 23:50   ` [PATCH v3 4/5] Bluetooth: btusb: Collect the common Intel assignments together Rajat Jain
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 20+ messages in thread
From: Rajat Jain @ 2018-11-21 23:50 UTC (permalink / raw)
  To: Marcel Holtmann, Johan Hedberg, Greg Kroah-Hartman,
	David S. Miller, Dmitry Torokhov, Rajat Jain, Alex Hung,
	linux-bluetooth, linux-kernel, linux-usb, netdev
  Cc: rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan, sukumar.ghorai

Add a quirk and a hook to allow the HCI core to reset the BT chip
if needed (after a number of timed out commands). Use that new hook to
initiate BT chip reset if the controller fails to respond to certain
number of commands (currently 5) including the HCI reset commands.
This is done based on a newly introduced quirk. This is done based
on some initial work by Intel.

Signed-off-by: Rajat Jain <rajatja@google.com>
---
v3: same as v1
v2: same as v1

 include/net/bluetooth/hci.h      |  8 ++++++++
 include/net/bluetooth/hci_core.h |  2 ++
 net/bluetooth/hci_core.c         | 15 +++++++++++++--
 3 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index c36dc1e20556..af02fa5ffe54 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -192,6 +192,14 @@ enum {
 	 *
 	 */
 	HCI_QUIRK_NON_PERSISTENT_SETUP,
+
+	/* When this quirk is set, hw_reset() would be run to reset the
+	 * hardware, after a certain number of commands (currently 5)
+	 * time out because the device fails to respond.
+	 *
+	 * This quirk should be set before hci_register_dev is called.
+	 */
+	HCI_QUIRK_HW_RESET_ON_TIMEOUT,
 };
 
 /* HCI device flags */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index e5ea633ea368..b86218304b80 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -313,6 +313,7 @@ struct hci_dev {
 	unsigned int	acl_cnt;
 	unsigned int	sco_cnt;
 	unsigned int	le_cnt;
+	unsigned int	timeout_cnt;
 
 	unsigned int	acl_mtu;
 	unsigned int	sco_mtu;
@@ -437,6 +438,7 @@ struct hci_dev {
 	int (*post_init)(struct hci_dev *hdev);
 	int (*set_diag)(struct hci_dev *hdev, bool enable);
 	int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);
+	void (*hw_reset)(struct hci_dev *hdev);
 };
 
 #define HCI_PHY_HANDLE(handle)	(handle & 0xff)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 7352fe85674b..ab3a6a8b7ba6 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2569,13 +2569,24 @@ static void hci_cmd_timeout(struct work_struct *work)
 	struct hci_dev *hdev = container_of(work, struct hci_dev,
 					    cmd_timer.work);
 
+	hdev->timeout_cnt++;
 	if (hdev->sent_cmd) {
 		struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data;
 		u16 opcode = __le16_to_cpu(sent->opcode);
 
-		bt_dev_err(hdev, "command 0x%4.4x tx timeout", opcode);
+		bt_dev_err(hdev, "command 0x%4.4x tx timeout (cnt = %u)",
+			   opcode, hdev->timeout_cnt);
 	} else {
-		bt_dev_err(hdev, "command tx timeout");
+		bt_dev_err(hdev, "command tx timeout (cnt = %u)",
+			   hdev->timeout_cnt);
+	}
+
+	if (test_bit(HCI_QUIRK_HW_RESET_ON_TIMEOUT, &hdev->quirks) &&
+	    hdev->timeout_cnt >= 5) {
+		hdev->timeout_cnt = 0;
+		if (hdev->hw_reset)
+			hdev->hw_reset(hdev);
+		return;
 	}
 
 	atomic_set(&hdev->cmd_cnt, 1);
-- 
2.19.1.1215.g8438c0b245-goog


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 4/5] Bluetooth: btusb: Collect the common Intel assignments together
  2018-11-21 23:50 ` [PATCH v3 1/5] usb: split code locating ACPI companion into port and device Rajat Jain
  2018-11-21 23:50   ` [PATCH v3 2/5] usb: assign ACPI companions for embedded USB devices Rajat Jain
  2018-11-21 23:50   ` [PATCH v3 3/5] Bluetooth: Reset Bluetooth chip after multiple command timeouts Rajat Jain
@ 2018-11-21 23:50   ` Rajat Jain
  2018-11-21 23:50   ` [PATCH v3 5/5] Bluetooth: btusb: Use the hw_reset method to allow resetting the BT chip Rajat Jain
  2018-12-05  9:32   ` [PATCH v3 1/5] usb: split code locating ACPI companion into port and device Greg Kroah-Hartman
  4 siblings, 0 replies; 20+ messages in thread
From: Rajat Jain @ 2018-11-21 23:50 UTC (permalink / raw)
  To: Marcel Holtmann, Johan Hedberg, Greg Kroah-Hartman,
	David S. Miller, Dmitry Torokhov, Rajat Jain, Alex Hung,
	linux-bluetooth, linux-kernel, linux-usb, netdev
  Cc: rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan, sukumar.ghorai

The BTUSB_INTEL and BTUSB_INTEL_NEW have common functions & quirks are
assigned to hdev structure. Lets collect them together instead of
repeating them in different code branches.

Signed-off-by: Rajat Jain <rajatja@google.com>
---
v3: same as v1
v2: same as v1

 drivers/bluetooth/btusb.c | 27 ++++++++++++---------------
 1 file changed, 12 insertions(+), 15 deletions(-)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 7439a7eb50ac..e8e148480c91 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -3077,28 +3077,25 @@ static int btusb_probe(struct usb_interface *intf,
 		data->diag = usb_ifnum_to_if(data->udev, ifnum_base + 2);
 	}
 #endif
+	if (id->driver_info & BTUSB_INTEL ||
+	    id->driver_info & BTUSB_INTEL_NEW) {
 
-	if (id->driver_info & BTUSB_INTEL) {
 		hdev->manufacturer = 2;
-		hdev->setup = btusb_setup_intel;
-		hdev->shutdown = btusb_shutdown_intel;
-		hdev->set_diag = btintel_set_diag_mfg;
 		hdev->set_bdaddr = btintel_set_bdaddr;
 		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);
-	}
 
-	if (id->driver_info & BTUSB_INTEL_NEW) {
-		hdev->manufacturer = 2;
-		hdev->send = btusb_send_frame_intel;
-		hdev->setup = btusb_setup_intel_new;
-		hdev->hw_error = btintel_hw_error;
-		hdev->set_diag = btintel_set_diag;
-		hdev->set_bdaddr = btintel_set_bdaddr;
-		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);
+		if (id->driver_info & BTUSB_INTEL) {
+			hdev->setup = btusb_setup_intel;
+			hdev->shutdown = btusb_shutdown_intel;
+			hdev->set_diag = btintel_set_diag_mfg;
+		} else {
+			hdev->send = btusb_send_frame_intel;
+			hdev->setup = btusb_setup_intel_new;
+			hdev->hw_error = btintel_hw_error;
+			hdev->set_diag = btintel_set_diag;
+		}
 	}
 
 	if (id->driver_info & BTUSB_MARVELL)
-- 
2.19.1.1215.g8438c0b245-goog


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 5/5] Bluetooth: btusb: Use the hw_reset method to allow resetting the BT chip
  2018-11-21 23:50 ` [PATCH v3 1/5] usb: split code locating ACPI companion into port and device Rajat Jain
                     ` (2 preceding siblings ...)
  2018-11-21 23:50   ` [PATCH v3 4/5] Bluetooth: btusb: Collect the common Intel assignments together Rajat Jain
@ 2018-11-21 23:50   ` Rajat Jain
  2018-12-05  9:32   ` [PATCH v3 1/5] usb: split code locating ACPI companion into port and device Greg Kroah-Hartman
  4 siblings, 0 replies; 20+ messages in thread
From: Rajat Jain @ 2018-11-21 23:50 UTC (permalink / raw)
  To: Marcel Holtmann, Johan Hedberg, Greg Kroah-Hartman,
	David S. Miller, Dmitry Torokhov, Rajat Jain, Alex Hung,
	linux-bluetooth, linux-kernel, linux-usb, netdev
  Cc: rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan, sukumar.ghorai

If the platform provides it, use the reset gpio to reset the BT
chip (requested by the HCI core if needed). This has been found helpful
on some of Intel bluetooth controllers where the firmware gets stuck and
the only way out is a hard reset pin provided by the platform.

Signed-off-by: Rajat Jain <rajatja@google.com>
---
v3: Better error handling for gpiod_get_optional()
v2: Handle the EPROBE_DEFER case.

 drivers/bluetooth/btusb.c | 40 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index e8e148480c91..e7631f770fae 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -29,6 +29,7 @@
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
 #include <linux/suspend.h>
+#include <linux/gpio/consumer.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -475,6 +476,8 @@ struct btusb_data {
 	struct usb_endpoint_descriptor *diag_tx_ep;
 	struct usb_endpoint_descriptor *diag_rx_ep;
 
+	struct gpio_desc *reset_gpio;
+
 	__u8 cmdreq_type;
 	__u8 cmdreq;
 
@@ -490,6 +493,26 @@ struct btusb_data {
 	int oob_wake_irq;   /* irq for out-of-band wake-on-bt */
 };
 
+
+static void btusb_hw_reset(struct hci_dev *hdev)
+{
+	struct btusb_data *data = hci_get_drvdata(hdev);
+	struct gpio_desc *reset_gpio = data->reset_gpio;
+
+	/*
+	 * Toggle the hard reset line if the platform provides one. The reset
+	 * is going to yank the device off the USB and then replug. So doing
+	 * once is enough. The cleanup is handled correctly on the way out
+	 * (standard USB disconnect), and the new device is detected cleanly
+	 * and bound to the driver again like it should be.
+	 */
+	bt_dev_dbg(hdev, "%s: Initiating HW reset via gpio", __func__);
+	clear_bit(HCI_QUIRK_HW_RESET_ON_TIMEOUT, &hdev->quirks);
+	gpiod_set_value(reset_gpio, 1);
+	mdelay(100);
+	gpiod_set_value(reset_gpio, 0);
+}
+
 static inline void btusb_free_frags(struct btusb_data *data)
 {
 	unsigned long flags;
@@ -2917,6 +2940,7 @@ static int btusb_probe(struct usb_interface *intf,
 		       const struct usb_device_id *id)
 {
 	struct usb_endpoint_descriptor *ep_desc;
+	struct gpio_desc *reset_gpio;
 	struct btusb_data *data;
 	struct hci_dev *hdev;
 	unsigned ifnum_base;
@@ -3030,6 +3054,16 @@ static int btusb_probe(struct usb_interface *intf,
 
 	SET_HCIDEV_DEV(hdev, &intf->dev);
 
+	reset_gpio = gpiod_get_optional(&data->udev->dev, "reset",
+					GPIOD_OUT_LOW);
+	if (IS_ERR(reset_gpio)) {
+		err = PTR_ERR(reset_gpio);
+		goto out_free_dev;
+	} else if (reset_gpio) {
+		data->reset_gpio = reset_gpio;
+		hdev->hw_reset = btusb_hw_reset;
+	}
+
 	hdev->open   = btusb_open;
 	hdev->close  = btusb_close;
 	hdev->flush  = btusb_flush;
@@ -3085,6 +3119,7 @@ static int btusb_probe(struct usb_interface *intf,
 		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);
+		set_bit(HCI_QUIRK_HW_RESET_ON_TIMEOUT, &hdev->quirks);
 
 		if (id->driver_info & BTUSB_INTEL) {
 			hdev->setup = btusb_setup_intel;
@@ -3225,6 +3260,8 @@ static int btusb_probe(struct usb_interface *intf,
 	return 0;
 
 out_free_dev:
+	if (data->reset_gpio)
+		gpiod_put(data->reset_gpio);
 	hci_free_dev(hdev);
 	return err;
 }
@@ -3268,6 +3305,9 @@ static void btusb_disconnect(struct usb_interface *intf)
 	if (data->oob_wake_irq)
 		device_init_wakeup(&data->udev->dev, false);
 
+	if (data->reset_gpio)
+		gpiod_put(data->reset_gpio);
+
 	hci_free_dev(hdev);
 }
 
-- 
2.19.1.1215.g8438c0b245-goog


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v3 1/5] usb: split code locating ACPI companion into port and device
  2018-11-21 23:50 ` [PATCH v3 1/5] usb: split code locating ACPI companion into port and device Rajat Jain
                     ` (3 preceding siblings ...)
  2018-11-21 23:50   ` [PATCH v3 5/5] Bluetooth: btusb: Use the hw_reset method to allow resetting the BT chip Rajat Jain
@ 2018-12-05  9:32   ` Greg Kroah-Hartman
  2018-12-05 17:41     ` Ghorai, Sukumar
  4 siblings, 1 reply; 20+ messages in thread
From: Greg Kroah-Hartman @ 2018-12-05  9:32 UTC (permalink / raw)
  To: Rajat Jain
  Cc: Marcel Holtmann, Johan Hedberg, David S. Miller, Dmitry Torokhov,
	Alex Hung, linux-bluetooth, linux-kernel, linux-usb, netdev,
	rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan,
	sukumar.ghorai

On Wed, Nov 21, 2018 at 03:50:16PM -0800, Rajat Jain wrote:
> From: Dmitry Torokhov <dtor@chromium.org>
> 
> In preparation for handling embedded USB devices let's split
> usb_acpi_find_companion() into usb_acpi_find_companion_for_device() and
> usb_acpi_find_companion_for_port().
> 
> Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
> Signed-off-by: Rajat Jain <rajatja@google.com>

Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v3 2/5] usb: assign ACPI companions for embedded USB devices
  2018-11-21 23:50   ` [PATCH v3 2/5] usb: assign ACPI companions for embedded USB devices Rajat Jain
@ 2018-12-05  9:32     ` Greg Kroah-Hartman
  2018-12-05 17:19       ` Ghorai, Sukumar
  0 siblings, 1 reply; 20+ messages in thread
From: Greg Kroah-Hartman @ 2018-12-05  9:32 UTC (permalink / raw)
  To: Rajat Jain
  Cc: Marcel Holtmann, Johan Hedberg, David S. Miller, Dmitry Torokhov,
	Alex Hung, linux-bluetooth, linux-kernel, linux-usb, netdev,
	rajatxjain, dtor, raghuram.hegde, chethan.tumkur.narayan,
	sukumar.ghorai

On Wed, Nov 21, 2018 at 03:50:17PM -0800, Rajat Jain wrote:
> From: Dmitry Torokhov <dtor@chromium.org>
> 
> USB devices permanently connected to USB ports may be described in ACPI
> tables and share ACPI devices with ports they are connected to. See [1]
> for details.
> 
> This will allow us to describe sideband resources for devices, such as,
> for example, hard reset line for BT USB controllers.
> 
> [1] https://docs.microsoft.com/en-us/windows-hardware/drivers/bringup/other-acpi-namespace-objects#acpi-namespace-hierarchy-and-adr-for-embedded-usb-devices
> 
> Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
> Signed-off-by: Rajat Jain <rajatja@google.com> (changed how we get the usb_port)

Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* RE: [PATCH v3 2/5] usb: assign ACPI companions for embedded USB devices
  2018-12-05  9:32     ` Greg Kroah-Hartman
@ 2018-12-05 17:19       ` Ghorai, Sukumar
  0 siblings, 0 replies; 20+ messages in thread
From: Ghorai, Sukumar @ 2018-12-05 17:19 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Rajat Jain
  Cc: Marcel Holtmann, Johan Hedberg, David S. Miller, Dmitry Torokhov,
	Alex Hung, linux-bluetooth, linux-kernel, linux-usb, netdev,
	rajatxjain, dtor, Hegde, Raghuram, Tumkur Narayan, Chethan

>On Wed, Nov 21, 2018 at 03:50:17PM -0800, Rajat Jain wrote:
>> From: Dmitry Torokhov <dtor@chromium.org>
>>
>> USB devices permanently connected to USB ports may be described in
>> ACPI tables and share ACPI devices with ports they are connected to.
>> See [1] for details.
>>
>> This will allow us to describe sideband resources for devices, such
>> as, for example, hard reset line for BT USB controllers.
>>
>> [1]
>> https://docs.microsoft.com/en-us/windows-hardware/drivers/bringup/othe
>> r-acpi-namespace-objects#acpi-namespace-hierarchy-and-adr-for-
>embedded
>> -usb-devices
>>
>> Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
>> Signed-off-by: Rajat Jain <rajatja@google.com> (changed how we get the
>> usb_port)
>
>Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Tested-by: Sukumar Ghorai <sukumar.ghorai@intel.com>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* RE: [PATCH v3 1/5] usb: split code locating ACPI companion into port and device
  2018-12-05  9:32   ` [PATCH v3 1/5] usb: split code locating ACPI companion into port and device Greg Kroah-Hartman
@ 2018-12-05 17:41     ` Ghorai, Sukumar
  0 siblings, 0 replies; 20+ messages in thread
From: Ghorai, Sukumar @ 2018-12-05 17:41 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Rajat Jain
  Cc: Marcel Holtmann, Johan Hedberg, David S. Miller, Dmitry Torokhov,
	Alex Hung, linux-bluetooth, linux-kernel, linux-usb, netdev,
	rajatxjain, dtor, Hegde, Raghuram, Tumkur Narayan, Chethan

>On Wed, Nov 21, 2018 at 03:50:16PM -0800, Rajat Jain wrote:
>> From: Dmitry Torokhov <dtor@chromium.org>
>>
>> In preparation for handling embedded USB devices let's split
>> usb_acpi_find_companion() into usb_acpi_find_companion_for_device()
>> and usb_acpi_find_companion_for_port().
>>
>> Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
>> Signed-off-by: Rajat Jain <rajatja@google.com>
>
>Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Tested-by: Sukumar Ghorai <sukumar.ghorai@intel.com>

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, back to index

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-17  1:07 [PATCH 0/5] Reset Intel BT controller if it gets stuck Rajat Jain
2018-11-17  1:07 ` [PATCH 1/5] usb: split code locating ACPI companion into port and device Rajat Jain
2018-11-17  1:07 ` [PATCH 2/5] usb: assign ACPI companions for embedded USB devices Rajat Jain
2018-11-17  1:07 ` [PATCH 3/5] Bluetooth: Reset Bluetooth chip after multiple command timeouts Rajat Jain
2018-11-17  1:07 ` [PATCH 4/5] Bluetooth: btusb: Collect the common Intel assignments together Rajat Jain
2018-11-17  1:07 ` [PATCH 5/5] Bluetooth: btusb: Use the hw_reset method to allow resetting the BT chip Rajat Jain
2018-11-19 23:04 ` [PATCH v2 1/5] usb: split code locating ACPI companion into port and device Rajat Jain
2018-11-19 23:04   ` [PATCH v2 2/5] usb: assign ACPI companions for embedded USB devices Rajat Jain
2018-11-19 23:04   ` [PATCH v2 3/5] Bluetooth: Reset Bluetooth chip after multiple command timeouts Rajat Jain
2018-11-19 23:04   ` [PATCH v2 4/5] Bluetooth: btusb: Collect the common Intel assignments together Rajat Jain
2018-11-19 23:04   ` [PATCH v2 5/5] Bluetooth: btusb: Use the hw_reset method to allow resetting the BT chip Rajat Jain
2018-11-21 23:50 ` [PATCH v3 1/5] usb: split code locating ACPI companion into port and device Rajat Jain
2018-11-21 23:50   ` [PATCH v3 2/5] usb: assign ACPI companions for embedded USB devices Rajat Jain
2018-12-05  9:32     ` Greg Kroah-Hartman
2018-12-05 17:19       ` Ghorai, Sukumar
2018-11-21 23:50   ` [PATCH v3 3/5] Bluetooth: Reset Bluetooth chip after multiple command timeouts Rajat Jain
2018-11-21 23:50   ` [PATCH v3 4/5] Bluetooth: btusb: Collect the common Intel assignments together Rajat Jain
2018-11-21 23:50   ` [PATCH v3 5/5] Bluetooth: btusb: Use the hw_reset method to allow resetting the BT chip Rajat Jain
2018-12-05  9:32   ` [PATCH v3 1/5] usb: split code locating ACPI companion into port and device Greg Kroah-Hartman
2018-12-05 17:41     ` Ghorai, Sukumar

Linux-Bluetooth Archive on lore.kernel.org

Archives are clonable: git clone --mirror https://lore.kernel.org/linux-bluetooth/0 linux-bluetooth/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-bluetooth linux-bluetooth/ https://lore.kernel.org/linux-bluetooth \
		linux-bluetooth@vger.kernel.org linux-bluetooth@archiver.kernel.org
	public-inbox-index linux-bluetooth


Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-bluetooth


AGPL code for this site: git clone https://public-inbox.org/ public-inbox