From: Rafał Miłecki Date: Wed, 24 Aug 2016 06:42:10 +0000 (+0200) Subject: kernel: backport patch for specifying USB ports/devices in DT X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=8765c1060655d899b2cf3297cd69cf0993491a0e;p=openwrt%2Fstaging%2Flinusw.git 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 --- diff --git a/target/linux/generic/patches-4.4/082-0001-USB-core-let-USB-device-know-device-node.patch b/target/linux/generic/patches-4.4/082-0001-USB-core-let-USB-device-know-device-node.patch new file mode 100644 index 0000000000..901cdf7e83 --- /dev/null +++ b/target/linux/generic/patches-4.4/082-0001-USB-core-let-USB-device-know-device-node.patch @@ -0,0 +1,179 @@ +From 69bec725985324e79b1c47ea287815ac4ddb0521 Mon Sep 17 00:00:00 2001 +From: Peter Chen +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 +Acked-by: Philipp Zabel +Acked-by: Alan Stern +Acked-by: Rob Herring +Acked-by: Arnd Bergmann +Signed-off-by: Greg Kroah-Hartman +--- + .../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 ++ * ++ * 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 . ++ */ ++ ++#include ++ ++/** ++ * 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 + #include + #include ++#include + + #include + #include +@@ -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) diff --git a/target/linux/generic/patches-4.4/082-0002-usb-core-usb_alloc_dev-fix-setting-of-portnum.patch b/target/linux/generic/patches-4.4/082-0002-usb-core-usb_alloc_dev-fix-setting-of-portnum.patch new file mode 100644 index 0000000000..15cf4cae56 --- /dev/null +++ b/target/linux/generic/patches-4.4/082-0002-usb-core-usb_alloc_dev-fix-setting-of-portnum.patch @@ -0,0 +1,108 @@ +From 7222c832254a75dcd67d683df75753d4a4e125bb Mon Sep 17 00:00:00 2001 +From: Nicolai Stange +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: + [] dump_stack+0xdc/0x15e + [] ? _atomic_dec_and_lock+0xa2/0xa2 + [] ? print_section+0x61/0xb0 + [] print_trailer+0x179/0x2c0 + [] object_err+0x34/0x40 + [] kasan_report_error+0x2f8/0x8b0 + [] ? __slab_alloc+0x5e/0x90 + [] ? __lock_is_held+0x90/0x130 + [] kasan_report+0x71/0xa0 + [] ? kmem_cache_alloc_trace+0x212/0x560 + [] ? xhci_find_raw_port_number+0x98/0x170 + [] __asan_load8+0x64/0x70 + [] xhci_find_raw_port_number+0x98/0x170 + [] xhci_setup_addressable_virt_dev+0x235/0xa10 + [] xhci_setup_device+0x3c1/0x1430 + [] ? trace_hardirqs_on+0xd/0x10 + [] ? xhci_setup_device+0x1430/0x1430 + [] xhci_address_device+0x13/0x20 + [] hub_port_init+0x55a/0x1550 + [] hub_event+0xef5/0x24d0 + [] ? hub_port_debounce+0x2f0/0x2f0 + [] ? debug_object_deactivate+0x1be/0x270 + [] ? print_rt_rq+0x53/0x2d0 + [] ? trace_hardirqs_off+0xd/0x10 + [] ? _raw_spin_unlock_irqrestore+0x5b/0x60 + [] ? irq_domain_set_hwirq_and_chip+0x30/0xb0 + [] ? debug_lockdep_rcu_enabled+0x39/0x40 + [] ? __lock_is_held+0x90/0x130 + [] 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 +Acked-by: Alan Stern +Signed-off-by: Greg Kroah-Hartman +--- + 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 */ + }