Page MenuHomeFreeBSD

D20262.diff
No OneTemporary

D20262.diff

Index: head/sys/conf/files
===================================================================
--- head/sys/conf/files
+++ head/sys/conf/files
@@ -3215,6 +3215,7 @@
dev/usb/usb_device.c optional usb
dev/usb/usb_dynamic.c optional usb
dev/usb/usb_error.c optional usb
+dev/usb/usb_fdt_support.c optional usb fdt
dev/usb/usb_generic.c optional usb
dev/usb/usb_handle_request.c optional usb
dev/usb/usb_hid.c optional usb
Index: head/sys/dev/usb/net/if_smsc.c
===================================================================
--- head/sys/dev/usb/net/if_smsc.c
+++ head/sys/dev/usb/net/if_smsc.c
@@ -97,6 +97,7 @@
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/usb/usb_fdt_support.h>
#endif
#include <dev/usb/usb.h>
@@ -1559,148 +1560,7 @@
return (rc);
}
-#ifdef FDT
-/*
- * This is FreeBSD-specific compatibility strings for RPi/RPi2
- */
-static phandle_t
-smsc_fdt_find_eth_node(phandle_t start)
-{
- phandle_t child, node;
-
- /* Traverse through entire tree to find usb ethernet nodes. */
- for (node = OF_child(start); node != 0; node = OF_peer(node)) {
- if ((ofw_bus_node_is_compatible(node, "net,ethernet") &&
- ofw_bus_node_is_compatible(node, "usb,device")) ||
- ofw_bus_node_is_compatible(node, "usb424,ec00"))
- return (node);
- child = smsc_fdt_find_eth_node(node);
- if (child != -1)
- return (child);
- }
-
- return (-1);
-}
-
-/*
- * Check if node's path is <*>/usb/hub/ethernet
- */
-static int
-smsc_fdt_is_usb_eth(phandle_t node)
-{
- char name[16];
- int len;
-
- memset(name, 0, sizeof(name));
- len = OF_getprop(node, "name", name, sizeof(name));
- if (len <= 0)
- return (0);
-
- if (strcmp(name, "ethernet"))
- return (0);
-
- node = OF_parent(node);
- if (node == -1)
- return (0);
- len = OF_getprop(node, "name", name, sizeof(name));
- if (len <= 0)
- return (0);
-
- if (strcmp(name, "hub"))
- return (0);
-
- node = OF_parent(node);
- if (node == -1)
- return (0);
- len = OF_getprop(node, "name", name, sizeof(name));
- if (len <= 0)
- return (0);
-
- if (strcmp(name, "usb"))
- return (0);
-
- return (1);
-}
-
-static phandle_t
-smsc_fdt_find_eth_node_by_path(phandle_t start)
-{
- phandle_t child, node;
-
- /* Traverse through entire tree to find usb ethernet nodes. */
- for (node = OF_child(start); node != 0; node = OF_peer(node)) {
- if (smsc_fdt_is_usb_eth(node))
- return (node);
- child = smsc_fdt_find_eth_node_by_path(node);
- if (child != -1)
- return (child);
- }
-
- return (-1);
-}
-
-/*
- * Look through known names that can contain mac address
- * return 0 if valid MAC address has been found
- */
-static int
-smsc_fdt_read_mac_property(phandle_t node, unsigned char *mac)
-{
- int len;
-
- /* Check if there is property */
- if ((len = OF_getproplen(node, "local-mac-address")) > 0) {
- if (len != ETHER_ADDR_LEN)
- return (EINVAL);
-
- OF_getprop(node, "local-mac-address", mac,
- ETHER_ADDR_LEN);
- return (0);
- }
-
- if ((len = OF_getproplen(node, "mac-address")) > 0) {
- if (len != ETHER_ADDR_LEN)
- return (EINVAL);
-
- OF_getprop(node, "mac-address", mac,
- ETHER_ADDR_LEN);
- return (0);
- }
-
- return (ENXIO);
-}
-
/**
- * Get MAC address from FDT blob. Firmware or loader should fill
- * mac-address or local-mac-address property. Returns 0 if MAC address
- * obtained, error code otherwise.
- */
-static int
-smsc_fdt_find_mac(unsigned char *mac)
-{
- phandle_t node, root;
-
- root = OF_finddevice("/");
- node = smsc_fdt_find_eth_node(root);
- if (node != -1) {
- if (smsc_fdt_read_mac_property(node, mac) == 0)
- return (0);
- }
-
- /*
- * If it's not FreeBSD FDT blob for RPi, try more
- * generic .../usb/hub/ethernet
- */
- node = smsc_fdt_find_eth_node_by_path(root);
-
- if (node != -1)
- return smsc_fdt_read_mac_property(node, mac);
-
- return (ENXIO);
-}
-#endif
-
-/**
* smsc_attach_post - Called after the driver attached to the USB interface
* @ue: the USB ethernet device
*
@@ -1748,7 +1608,7 @@
err = smsc_eeprom_read(sc, 0x01, sc->sc_ue.ue_eaddr, ETHER_ADDR_LEN);
#ifdef FDT
if ((err != 0) || (!ETHER_IS_VALID(sc->sc_ue.ue_eaddr)))
- err = smsc_fdt_find_mac(sc->sc_ue.ue_eaddr);
+ err = usb_fdt_get_mac_addr(sc->sc_ue.ue_dev, &sc->sc_ue);
#endif
if ((err != 0) || (!ETHER_IS_VALID(sc->sc_ue.ue_eaddr))) {
read_random(sc->sc_ue.ue_eaddr, ETHER_ADDR_LEN);
Index: head/sys/dev/usb/usb_fdt_support.h
===================================================================
--- head/sys/dev/usb/usb_fdt_support.h
+++ head/sys/dev/usb/usb_fdt_support.h
@@ -0,0 +1,48 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Ian Lepore <ian@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _USB_FDT_SUPPORT_H_
+#define _USB_FDT_SUPPORT_H_
+
+struct usb_device;
+struct usb_ether;
+
+/*
+ * Get the device's MAC address from the FDT data. Fills in ue->ue_eaddr and
+ * returns 0 on success, otherwise leaves ue_eaddr untouched and returns
+ * non-zero. This first attempts to get the address from the "mac-address"
+ * property, and if that's not valid it tries the "local-mac-address" property;
+ * this matches the linux interpretation of the precedence of those properties.
+ */
+int usb_fdt_get_mac_addr(device_t dev, struct usb_ether* ue);
+
+/* Get the FDT node for dev. Returns -1 if dev is not in the FDT data. */
+phandle_t usb_fdt_get_node(device_t dev, struct usb_device* udev);
+
+#endif
Index: head/sys/dev/usb/usb_fdt_support.c
===================================================================
--- head/sys/dev/usb/usb_fdt_support.c
+++ head/sys/dev/usb/usb_fdt_support.c
@@ -0,0 +1,168 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Ian Lepore <ian@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/condvar.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/openfirm.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_controller.h>
+#include <dev/usb/usb_bus.h>
+#include <dev/usb/usb_device.h>
+#include <dev/usb/usb_freebsd.h>
+#include <dev/usb/usb_fdt_support.h>
+#include <dev/usb/net/usb_ethernet.h>
+
+/*
+ * Define a constant for allocating an array pointers to serve as a stack of
+ * devices between the controller and any arbitrary device on the bus. The
+ * stack ends with the device itself, so add 1 to the max hub nesting depth.
+ */
+#define MAX_UDEV_NEST (MAX(USB_HUB_MAX_DEPTH, USB_SS_HUB_DEPTH_MAX) + 1)
+
+static phandle_t
+find_udev_in_children(phandle_t parent, struct usb_device *udev)
+{
+ phandle_t child;
+ ssize_t proplen;
+ uint32_t port;
+ char compat[16]; /* big enough for "usb1234,abcd" */
+
+ /*
+ * USB device nodes in FDT have a compatible string of "usb" followed by
+ * the vendorId,productId rendered in hex. The port number is encoded
+ * in the standard 'reg' property; it is one-based in the FDT data, but
+ * usb_device.port_index is zero-based. To uniquely identify a device,
+ * both the compatible string and the port number must match.
+ */
+ snprintf(compat, sizeof(compat), "usb%x,%x",
+ UGETW(udev->ddesc.idVendor), UGETW(udev->ddesc.idProduct));
+ for (child = OF_child(parent); child != 0; child = OF_peer(child)) {
+ if (!ofw_bus_node_is_compatible(child, compat))
+ continue;
+ proplen = OF_getencprop(child, "reg", &port, sizeof(port));
+ if (proplen != sizeof(port))
+ continue;
+ if (port == (udev->port_index + 1))
+ return (child);
+ }
+ return (-1);
+}
+
+static bool
+is_valid_mac_addr(uint8_t *addr)
+{
+
+ /*
+ * All-bits-zero and all-bits-one are a couple common cases of what
+ * might get read from unprogrammed eeprom or OTP data, weed them out.
+ */
+ if ((addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]) == 0x00)
+ return (false);
+ if ((addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) == 0xff)
+ return (false);
+ return (true);
+}
+
+int
+usb_fdt_get_mac_addr(device_t dev, struct usb_ether* ue)
+{
+ phandle_t node;
+ ssize_t i, proplen;
+ uint8_t mac[sizeof(ue->ue_eaddr)];
+ static const char *properties[] = {
+ "mac-address",
+ "local-mac-address"
+ };
+
+ if ((node = usb_fdt_get_node(ue->ue_dev, ue->ue_udev)) == -1)
+ return (ENXIO);
+ for (i = 0; i < nitems(properties); ++i) {
+ proplen = OF_getprop(node, properties[i], mac, sizeof(mac));
+ if (proplen == sizeof(mac) && is_valid_mac_addr(mac)) {
+ memcpy(ue->ue_eaddr, mac, sizeof(ue->ue_eaddr));
+ return (0);
+ }
+ }
+ return (ENXIO);
+}
+
+phandle_t
+usb_fdt_get_node(device_t dev, struct usb_device *udev)
+{
+ struct usb_device *ud;
+ struct usb_device *udev_stack[MAX_UDEV_NEST];
+ phandle_t controller_node, node;
+ int idx;
+
+ /*
+ * Start searching at the controller node. The usb_device links to the
+ * bus, and its parent is the controller. If we can't get the
+ * controller node, the requesting device cannot be in the fdt data.
+ */
+ if ((controller_node = ofw_bus_get_node(udev->bus->parent)) == -1)
+ return (-1);
+
+ /*
+ * Walk up the usb hub ancestor hierarchy, building a stack of devices
+ * that begins with the requesting device and includes all the hubs
+ * between it and the controller, NOT including the root hub (the FDT
+ * bindings treat the controller and root hub as the same thing).
+ */
+ for (ud = udev, idx = 0; ud->parent_hub != NULL; ud = ud->parent_hub) {
+ KASSERT(idx < nitems(udev_stack), ("Too many hubs"));
+ udev_stack[idx++] = ud;
+ }
+
+ /*
+ * Now walk down the stack of udevs from the controller to the
+ * requesting device, and also down the hierarchy of nested children of
+ * the controller node in the fdt data. At each nesting level of fdt
+ * data look for a child node whose properties match the vID,pID,portIdx
+ * tuple for the udev at the corresponding layer of the udev stack. As
+ * long as we keep matching up child nodes with udevs, loop and search
+ * within the children of the just-found child for the next-deepest hub.
+ * If at any level we fail to find a matching node, stop searching and
+ * return. When we hit the end of the stack (the requesting device) we
+ * return whatever the result was for the search at that nesting level.
+ */
+ for (node = controller_node;;) {
+ node = find_udev_in_children(node, udev_stack[--idx]);
+ if (idx == 0 || node == -1)
+ break;
+ }
+ return (node);
+}
Index: head/sys/modules/usb/usb/Makefile
===================================================================
--- head/sys/modules/usb/usb/Makefile
+++ head/sys/modules/usb/usb/Makefile
@@ -39,4 +39,8 @@
usb_msctest.c usb_parse.c usb_pf.c usb_process.c usb_request.c \
usb_transfer.c usb_util.c
+.if !empty(OPT_FDT)
+SRCS+= usb_fdt_support.c ofw_bus_if.h
+.endif
+
.include <bsd.kmod.mk>

File Metadata

Mime Type
text/plain
Expires
Wed, Jul 1, 8:51 PM (14 h, 37 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34577269
Default Alt Text
D20262.diff (13 KB)

Event Timeline