kernel: backport patch for specifying USB ports/devices in DT
This allows referencing USB ports/devices that are always present in a device. This applies to some internal devices, root hub ports and internal USB hubs. Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
This commit is contained in:
parent
00e8571f2b
commit
8765c10606
@ -0,0 +1,179 @@
|
||||
From 69bec725985324e79b1c47ea287815ac4ddb0521 Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chen <peter.chen@freescale.com>
|
||||
Date: Fri, 19 Feb 2016 17:26:15 +0800
|
||||
Subject: [PATCH] USB: core: let USB device know device node
|
||||
|
||||
Although most of USB devices are hot-plug's, there are still some devices
|
||||
are hard wired on the board, eg, for HSIC and SSIC interface USB devices.
|
||||
If these kinds of USB devices are multiple functions, and they can supply
|
||||
other interfaces like i2c, gpios for other devices, we may need to
|
||||
describe these at device tree.
|
||||
|
||||
In this commit, it uses "reg" in dts as physical port number to match
|
||||
the phyiscal port number decided by USB core, if they are the same,
|
||||
then the device node is for the device we are creating for USB core.
|
||||
|
||||
Signed-off-by: Peter Chen <peter.chen@freescale.com>
|
||||
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
|
||||
Acked-by: Alan Stern <stern@rowland.harvard.edu>
|
||||
Acked-by: Rob Herring <robh@kernel.org>
|
||||
Acked-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
---
|
||||
.../devicetree/bindings/usb/usb-device.txt | 28 +++++++++++++
|
||||
drivers/usb/core/Makefile | 2 +-
|
||||
drivers/usb/core/of.c | 47 ++++++++++++++++++++++
|
||||
drivers/usb/core/usb.c | 10 +++++
|
||||
include/linux/usb/of.h | 7 ++++
|
||||
5 files changed, 93 insertions(+), 1 deletion(-)
|
||||
create mode 100644 Documentation/devicetree/bindings/usb/usb-device.txt
|
||||
create mode 100644 drivers/usb/core/of.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/usb/usb-device.txt
|
||||
@@ -0,0 +1,28 @@
|
||||
+Generic USB Device Properties
|
||||
+
|
||||
+Usually, we only use device tree for hard wired USB device.
|
||||
+The reference binding doc is from:
|
||||
+http://www.firmware.org/1275/bindings/usb/usb-1_0.ps
|
||||
+
|
||||
+Required properties:
|
||||
+- compatible: usbVID,PID. The textual representation of VID, PID shall
|
||||
+ be in lower case hexadecimal with leading zeroes suppressed. The
|
||||
+ other compatible strings from the above standard binding could also
|
||||
+ be used, but a device adhering to this binding may leave out all except
|
||||
+ for usbVID,PID.
|
||||
+- reg: the port number which this device is connecting to, the range
|
||||
+ is 1-31.
|
||||
+
|
||||
+Example:
|
||||
+
|
||||
+&usb1 {
|
||||
+ status = "okay";
|
||||
+
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+
|
||||
+ hub: genesys@1 {
|
||||
+ compatible = "usb5e3,608";
|
||||
+ reg = <1>;
|
||||
+ };
|
||||
+}
|
||||
--- a/drivers/usb/core/Makefile
|
||||
+++ b/drivers/usb/core/Makefile
|
||||
@@ -5,7 +5,7 @@
|
||||
usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o
|
||||
usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o
|
||||
usbcore-y += devio.o notify.o generic.o quirks.o devices.o
|
||||
-usbcore-y += port.o
|
||||
+usbcore-y += port.o of.o
|
||||
|
||||
usbcore-$(CONFIG_PCI) += hcd-pci.o
|
||||
usbcore-$(CONFIG_ACPI) += usb-acpi.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/usb/core/of.c
|
||||
@@ -0,0 +1,47 @@
|
||||
+/*
|
||||
+ * of.c The helpers for hcd device tree support
|
||||
+ *
|
||||
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||||
+ * Author: Peter Chen <peter.chen@freescale.com>
|
||||
+ *
|
||||
+ * This program is free software: you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 of
|
||||
+ * the License as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/of.h>
|
||||
+
|
||||
+/**
|
||||
+ * usb_of_get_child_node - Find the device node match port number
|
||||
+ * @parent: the parent device node
|
||||
+ * @portnum: the port number which device is connecting
|
||||
+ *
|
||||
+ * Find the node from device tree according to its port number.
|
||||
+ *
|
||||
+ * Return: On success, a pointer to the device node, %NULL on failure.
|
||||
+ */
|
||||
+struct device_node *usb_of_get_child_node(struct device_node *parent,
|
||||
+ int portnum)
|
||||
+{
|
||||
+ struct device_node *node;
|
||||
+ u32 port;
|
||||
+
|
||||
+ for_each_child_of_node(parent, node) {
|
||||
+ if (!of_property_read_u32(node, "reg", &port)) {
|
||||
+ if (port == portnum)
|
||||
+ return node;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(usb_of_get_child_node);
|
||||
+
|
||||
--- a/drivers/usb/core/usb.c
|
||||
+++ b/drivers/usb/core/usb.c
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/debugfs.h>
|
||||
+#include <linux/usb/of.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <linux/scatterlist.h>
|
||||
@@ -469,6 +470,7 @@ struct usb_device *usb_alloc_dev(struct
|
||||
dev->route = 0;
|
||||
|
||||
dev->dev.parent = bus->controller;
|
||||
+ dev->dev.of_node = bus->controller->of_node;
|
||||
dev_set_name(&dev->dev, "usb%d", bus->busnum);
|
||||
root_hub = 1;
|
||||
} else {
|
||||
@@ -493,6 +495,14 @@ struct usb_device *usb_alloc_dev(struct
|
||||
dev->dev.parent = &parent->dev;
|
||||
dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);
|
||||
|
||||
+ if (!parent->parent) {
|
||||
+ /* device under root hub's port */
|
||||
+ port1 = usb_hcd_find_raw_port_number(usb_hcd,
|
||||
+ port1);
|
||||
+ }
|
||||
+ dev->dev.of_node = usb_of_get_child_node(parent->dev.of_node,
|
||||
+ port1);
|
||||
+
|
||||
/* hub driver sets up TT records */
|
||||
}
|
||||
|
||||
--- a/include/linux/usb/of.h
|
||||
+++ b/include/linux/usb/of.h
|
||||
@@ -15,6 +15,8 @@
|
||||
bool of_usb_host_tpl_support(struct device_node *np);
|
||||
int of_usb_update_otg_caps(struct device_node *np,
|
||||
struct usb_otg_caps *otg_caps);
|
||||
+struct device_node *usb_of_get_child_node(struct device_node *parent,
|
||||
+ int portnum);
|
||||
#else
|
||||
static inline bool of_usb_host_tpl_support(struct device_node *np)
|
||||
{
|
||||
@@ -25,6 +27,11 @@ static inline int of_usb_update_otg_caps
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
+static inline struct device_node *usb_of_get_child_node
|
||||
+ (struct device_node *parent, int portnum)
|
||||
+{
|
||||
+ return NULL;
|
||||
+}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_SUPPORT)
|
@ -0,0 +1,108 @@
|
||||
From 7222c832254a75dcd67d683df75753d4a4e125bb Mon Sep 17 00:00:00 2001
|
||||
From: Nicolai Stange <nicstange@gmail.com>
|
||||
Date: Thu, 17 Mar 2016 23:53:02 +0100
|
||||
Subject: [PATCH] usb/core: usb_alloc_dev(): fix setting of ->portnum
|
||||
|
||||
With commit 69bec7259853 ("USB: core: let USB device know device node"),
|
||||
the port1 argument of usb_alloc_dev() gets overwritten as follows:
|
||||
|
||||
... usb_alloc_dev(..., unsigned port1)
|
||||
{
|
||||
...
|
||||
if (!parent->parent) {
|
||||
port1 = usb_hcd_find_raw_port_number(..., port1);
|
||||
}
|
||||
...
|
||||
}
|
||||
|
||||
Later on, this now overwritten port1 gets assigned to ->portnum:
|
||||
|
||||
dev->portnum = port1;
|
||||
|
||||
However, since xhci_find_raw_port_number() isn't idempotent, the
|
||||
aforementioned commit causes a number of KASAN splats like the following:
|
||||
|
||||
BUG: KASAN: slab-out-of-bounds in xhci_find_raw_port_number+0x98/0x170
|
||||
at addr ffff8801d9311670
|
||||
Read of size 8 by task kworker/2:1/87
|
||||
[...]
|
||||
Workqueue: usb_hub_wq hub_event
|
||||
0000000000000188 000000005814b877 ffff8800cba17588 ffffffff8191447e
|
||||
0000000041b58ab3 ffffffff82a03209 ffffffff819143a2 ffffffff82a252f4
|
||||
ffff8801d93115e0 0000000000000188 ffff8801d9311628 ffff8800cba17588
|
||||
Call Trace:
|
||||
[<ffffffff8191447e>] dump_stack+0xdc/0x15e
|
||||
[<ffffffff819143a2>] ? _atomic_dec_and_lock+0xa2/0xa2
|
||||
[<ffffffff814e2cd1>] ? print_section+0x61/0xb0
|
||||
[<ffffffff814e4939>] print_trailer+0x179/0x2c0
|
||||
[<ffffffff814f0d84>] object_err+0x34/0x40
|
||||
[<ffffffff814f4388>] kasan_report_error+0x2f8/0x8b0
|
||||
[<ffffffff814eb91e>] ? __slab_alloc+0x5e/0x90
|
||||
[<ffffffff812178c0>] ? __lock_is_held+0x90/0x130
|
||||
[<ffffffff814f5091>] kasan_report+0x71/0xa0
|
||||
[<ffffffff814ec082>] ? kmem_cache_alloc_trace+0x212/0x560
|
||||
[<ffffffff81d99468>] ? xhci_find_raw_port_number+0x98/0x170
|
||||
[<ffffffff814f33d4>] __asan_load8+0x64/0x70
|
||||
[<ffffffff81d99468>] xhci_find_raw_port_number+0x98/0x170
|
||||
[<ffffffff81db0105>] xhci_setup_addressable_virt_dev+0x235/0xa10
|
||||
[<ffffffff81d9ea51>] xhci_setup_device+0x3c1/0x1430
|
||||
[<ffffffff8121cddd>] ? trace_hardirqs_on+0xd/0x10
|
||||
[<ffffffff81d9fac0>] ? xhci_setup_device+0x1430/0x1430
|
||||
[<ffffffff81d9fad3>] xhci_address_device+0x13/0x20
|
||||
[<ffffffff81d2081a>] hub_port_init+0x55a/0x1550
|
||||
[<ffffffff81d28705>] hub_event+0xef5/0x24d0
|
||||
[<ffffffff81d27810>] ? hub_port_debounce+0x2f0/0x2f0
|
||||
[<ffffffff8195e1ee>] ? debug_object_deactivate+0x1be/0x270
|
||||
[<ffffffff81210203>] ? print_rt_rq+0x53/0x2d0
|
||||
[<ffffffff8121657d>] ? trace_hardirqs_off+0xd/0x10
|
||||
[<ffffffff8226acfb>] ? _raw_spin_unlock_irqrestore+0x5b/0x60
|
||||
[<ffffffff81250000>] ? irq_domain_set_hwirq_and_chip+0x30/0xb0
|
||||
[<ffffffff81256339>] ? debug_lockdep_rcu_enabled+0x39/0x40
|
||||
[<ffffffff812178c0>] ? __lock_is_held+0x90/0x130
|
||||
[<ffffffff81196877>] process_one_work+0x567/0xec0
|
||||
[...]
|
||||
|
||||
Afterwards, xhci reports some functional errors:
|
||||
|
||||
xhci_hcd 0000:00:14.0: ERROR: unexpected setup address command completion
|
||||
code 0x11.
|
||||
xhci_hcd 0000:00:14.0: ERROR: unexpected setup address command completion
|
||||
code 0x11.
|
||||
usb 4-3: device not accepting address 2, error -22
|
||||
|
||||
Fix this by not overwriting the port1 argument in usb_alloc_dev(), but
|
||||
storing the raw port number as required by OF in an additional variable,
|
||||
raw_port.
|
||||
|
||||
Fixes: 69bec7259853 ("USB: core: let USB device know device node")
|
||||
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
|
||||
Acked-by: Alan Stern <stern@rowland.harvard.edu>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
---
|
||||
drivers/usb/core/usb.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/usb/core/usb.c
|
||||
+++ b/drivers/usb/core/usb.c
|
||||
@@ -423,6 +423,7 @@ struct usb_device *usb_alloc_dev(struct
|
||||
struct usb_device *dev;
|
||||
struct usb_hcd *usb_hcd = bus_to_hcd(bus);
|
||||
unsigned root_hub = 0;
|
||||
+ unsigned raw_port = port1;
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
@@ -497,11 +498,11 @@ struct usb_device *usb_alloc_dev(struct
|
||||
|
||||
if (!parent->parent) {
|
||||
/* device under root hub's port */
|
||||
- port1 = usb_hcd_find_raw_port_number(usb_hcd,
|
||||
+ raw_port = usb_hcd_find_raw_port_number(usb_hcd,
|
||||
port1);
|
||||
}
|
||||
dev->dev.of_node = usb_of_get_child_node(parent->dev.of_node,
|
||||
- port1);
|
||||
+ raw_port);
|
||||
|
||||
/* hub driver sets up TT records */
|
||||
}
|
Loading…
Reference in New Issue
Block a user