Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 15 Feb 2010 17:53:30 GMT
From:      Rafal Jaworowski <raj@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 174731 for review
Message-ID:  <201002151753.o1FHrUEx061091@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/chv.cgi?CH=174731

Change 174731 by raj@raj_fdt on 2010/02/15 17:53:15

	Refactor and optimize FDT infrastructure.
	
	- Extend 'compatible'-related routines so that we can do strict
	  checking i.e. if a node is only compatible with a single entry. This
	  is required for nodes like 'simple-bus' as sometimes other nodes
	  claim their compatibility and we need to have a way to identify such
	  cases.
	
	- Push fixups handling from simplebus level to much earlier stage, so
	  that the DT is complete for further use at the very beginnig of its
	  processing; this way the early init code (console, GPIO etc.) can
	  safely retrieve final information from the device tree.
	
	- Provide a fake capability of OF_interpret(): FDT does not support
	  this notion, but we abuse the interface to perform various
	  non-standard operations on the device tree. In this case it will
	  allow for fine grained control over when device tree fixups are
	  performed.
	
	- Other improvements and corrections.

Affected files ...

.. //depot/projects/fdt/sys/arm/mv/common.c#4 edit
.. //depot/projects/fdt/sys/arm/mv/mv_machdep.c#7 edit
.. //depot/projects/fdt/sys/dev/fdt/fdt_arm.c#4 edit
.. //depot/projects/fdt/sys/dev/fdt/fdt_common.c#10 edit
.. //depot/projects/fdt/sys/dev/fdt/fdt_common.h#6 edit
.. //depot/projects/fdt/sys/dev/fdt/fdt_powerpc.c#3 edit
.. //depot/projects/fdt/sys/dev/fdt/simplebus.c#7 edit
.. //depot/projects/fdt/sys/dev/ofw/ofw_bus_subr.c#3 edit
.. //depot/projects/fdt/sys/dev/ofw/ofw_bus_subr.h#3 edit
.. //depot/projects/fdt/sys/dev/ofw/ofw_fdt.c#4 edit
.. //depot/projects/fdt/sys/dev/ofw/openfirm.c#5 edit
.. //depot/projects/fdt/sys/powerpc/booke/machdep.c#6 edit

Differences ...

==== //depot/projects/fdt/sys/arm/mv/common.c#4 (text+ko) ====

@@ -78,7 +78,6 @@
 static void decode_win_usb_dump(void);
 
 static int fdt_get_ranges(const char *, void *, int, int *, int *);
-static int fdt_get_regsize(phandle_t, u_long *, u_long *);
 
 static int win_cpu_from_dt(void);
 static int win_soc_from_dt(void);
@@ -1704,27 +1703,6 @@
 }
 
 static int
-fdt_get_regsize(phandle_t node, u_long *base, u_long *size)
-{
-	pcell_t reg[4];
-	int addr_cells, len, size_cells;
-
-	if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells))
-		return (ENXIO);
-
-	if ((sizeof(pcell_t) * (addr_cells + size_cells)) > sizeof(reg))
-		return (ENOMEM);
-
-	len = OF_getprop(node, "reg", &reg, sizeof(reg));
-	if (len <= 0)
-		return (EINVAL);
-
-	*base = fdt_data_get(&reg[0], addr_cells);
-	*size = fdt_data_get(&reg[addr_cells], size_cells);
-	return (0);
-}
-
-static int
 win_soc_from_dt(void)
 {
 	phandle_t node, child;
@@ -1736,7 +1714,7 @@
 	if (node == 0)
 		panic("win_soc_from_dt: no root node");
 
-	node = fdt_find_compatible(node, "simple-bus");
+	node = fdt_find_compatible(node, "simple-bus", 0);
 	if (node == 0)
 		return (ENXIO);
 

==== //depot/projects/fdt/sys/arm/mv/mv_machdep.c#7 (text+ko) ====

@@ -563,6 +563,12 @@
 	cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL * 2));
 
 	/*
+	 * Only after the SOC registers block is mapped we can perform device
+	 * tree fixups, as they may attempt to read parameters from hardware.
+	 */
+	OF_interpret("perform-fixup", 0);
+
+	/*
 	 * Re-initialise MPP. It is important to call this prior to using
 	 * console as the physical connection can be routed via MPP.
 	 */
@@ -696,10 +702,10 @@
 	if ((node = OF_finddevice("/")) == 0)
 		return (ENXIO);
 
-	if ((node = fdt_find_compatible(node, "simple-bus")) == 0)
+	if ((node = fdt_find_compatible(node, "simple-bus", 0)) == 0)
 		return (ENXIO);
 
-	if ((node = fdt_find_compatible(node, "mrvl,mpp")) == 0)
+	if ((node = fdt_find_compatible(node, "mrvl,mpp", 0)) == 0)
 		return (ENXIO);
 
 moveon:

==== //depot/projects/fdt/sys/dev/fdt/fdt_arm.c#4 (text+ko) ====

@@ -48,15 +48,20 @@
 #include "ofw_bus_if.h"
 
 static void
-fdt_fixup_busfreq(phandle_t node)
+fdt_fixup_busfreq(phandle_t root)
 {
+	phandle_t sb;
 	pcell_t freq;
 
 	/*
 	 * This fixup sets the simple-bus bus-frequency property.
 	 */
+
+	if ((sb = fdt_find_compatible(root, "simple-bus", 1)) == 0)
+		return;
+
 	freq = cpu_to_fdt32(get_tclk());
-	OF_setprop(node, "bus-frequency", (void *)&freq, sizeof(freq));
+	OF_setprop(sb, "bus-frequency", (void *)&freq, sizeof(freq));
 }
 
 struct fdt_fixup_entry fdt_fixup_table[] = {

==== //depot/projects/fdt/sys/dev/fdt/fdt_common.c#10 (text+ko) ====

@@ -65,7 +65,7 @@
 fdt_is_compatible(phandle_t node, const char *compatstr)
 {
 #define FDT_COMPAT_LEN 255
-	char *buf[FDT_COMPAT_LEN];
+	char buf[FDT_COMPAT_LEN];
 	char *compat;
 	int len, onelen, l, rv;
 
@@ -75,7 +75,7 @@
 	compat = (char *)&buf;
 	bzero(compat, FDT_COMPAT_LEN);
 
-	if (OF_getprop(node, "compatible", compat, len) < 0)
+	if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0)
 		return (0);
 
 	onelen = strlen(compatstr);
@@ -95,8 +95,26 @@
 	return (rv);
 }
 
+int
+fdt_is_compatible_strict(phandle_t node, const char *compatible)
+{
+	char compat[FDT_COMPAT_LEN];
+
+	if (OF_getproplen(node, "compatible") <= 0)
+		return (0);
+
+	if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0)
+		return (0);
+
+	if (strncasecmp(compat, compatible, FDT_COMPAT_LEN) == 0)
+		/* This fits. */
+		return (1);
+
+	return (0);
+}
+
 phandle_t
-fdt_find_compatible(phandle_t start, const char *compat)
+fdt_find_compatible(phandle_t start, const char *compat, int strict)
 {
 	phandle_t child;
 
@@ -105,8 +123,12 @@
 	 * matching 'compatible' property.
 	 */
 	for (child = OF_child(start); child != 0; child = OF_peer(child))
-		if (fdt_is_compatible(child, compat))
+		if (fdt_is_compatible(child, compat)) {
+			if (strict)
+				if (!fdt_is_compatible_strict(child, compat))
+					continue;
 			return (child);
+		}
 	return (0);
 }
 
@@ -282,6 +304,27 @@
 }
 
 int
+fdt_get_regsize(phandle_t node, u_long *base, u_long *size)
+{
+	pcell_t reg[4];
+	int addr_cells, len, size_cells;
+
+	if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells))
+		return (ENXIO);
+
+	if ((sizeof(pcell_t) * (addr_cells + size_cells)) > sizeof(reg))
+		return (ENOMEM);
+
+	len = OF_getprop(node, "reg", &reg, sizeof(reg));
+	if (len <= 0)
+		return (EINVAL);
+
+	*base = fdt_data_get(&reg[0], addr_cells);
+	*size = fdt_data_get(&reg[addr_cells], size_cells);
+	return (0);
+}
+
+int
 fdt_reg_to_rl(phandle_t node, struct resource_list *rl, u_long base)
 {
 	u_long start, end, count;

==== //depot/projects/fdt/sys/dev/fdt/fdt_common.h#6 (text+ko) ====

@@ -55,11 +55,13 @@
 int fdt_parent_addr_cells(phandle_t);
 void fdt_ranges_dump(pcell_t *, int, int, int, int);
 int fdt_ranges_verify(pcell_t *, int, int, int, int);
+int fdt_get_regsize(phandle_t, u_long *, u_long *);
 int fdt_reg_to_rl(phandle_t, struct resource_list *, u_long);
 int fdt_intr_to_rl(phandle_t, struct resource_list *, struct sense_level *);
 int fdt_data_to_res(pcell_t *, int, int, u_long *, u_long *);
 int fdt_is_compatible(phandle_t, const char *);
+int fdt_is_compatible_strict(phandle_t, const char *);
 int fdt_is_enabled(phandle_t);
-phandle_t fdt_find_compatible(phandle_t start, const char *compat);
+phandle_t fdt_find_compatible(phandle_t, const char *, int);
 
 #endif /* _FDT_COMMON_H_ */

==== //depot/projects/fdt/sys/dev/fdt/fdt_powerpc.c#3 (text+ko) ====

@@ -46,17 +46,24 @@
 #include "fdt_common.h"
 
 static void
-fdt_fixup_busfreq(phandle_t node)
+fdt_fixup_busfreq(phandle_t root)
 {
-	phandle_t cpus, child;
+	phandle_t sb, cpus, child;
 	pcell_t freq;
 
 	/*
+	 * Do a strict check so as to skip non-SOC nodes, which also claim
+	 * simple-bus compatibility such as eLBC etc.
+	 */
+	if ((sb = fdt_find_compatible(root, "simple-bus", 1)) == 0)
+		return;
+
+	/*
 	 * This fixup uses /cpus/ bus-frequency prop value to set simple-bus
 	 * bus-frequency property.
 	 */
 	if ((cpus = OF_finddevice("/cpus")) == 0)
-		panic("simplebus: no /cpus node");
+		return;
 
 	if ((child = OF_child(cpus)) == 0)
 		return;
@@ -65,11 +72,11 @@
 	    sizeof(freq)) <= 0)
 		return;
 
-	OF_setprop(node, "bus-frequency", (void *)&freq, sizeof(freq));
+	OF_setprop(sb, "bus-frequency", (void *)&freq, sizeof(freq));
 }
 
 struct fdt_fixup_entry fdt_fixup_table[] = {
-	{ "fsl,MPC8572DS", &fdt_fixup_busfreq},
+	{ "fsl,MPC8572DS", &fdt_fixup_busfreq },
 	{ "MPC8555CDS", &fdt_fixup_busfreq },
 	{ NULL, NULL }
 };

==== //depot/projects/fdt/sys/dev/fdt/simplebus.c#7 (text+ko) ====

@@ -142,7 +142,7 @@
 {
 	struct simplebus_softc *sc;
 
-	if (!ofw_bus_is_compatible(dev, "simple-bus"))
+	if (!ofw_bus_is_compatible_strict(dev, "simple-bus"))
 		return (ENXIO);
 
 	device_set_desc(dev, "Flattened device tree simple bus");
@@ -153,34 +153,6 @@
 	return (BUS_PROBE_DEFAULT);
 }
 
-static void
-simplebus_fixup(phandle_t node)
-{
-	phandle_t root;
-	char *model;
-	int i, len;
-
-	if ((root = OF_finddevice("/")) == 0)
-		panic("simplebus: no root node");
-
-	len = OF_getprop_alloc(root, "model", 1, (void **)&model);
-	if (len <= 0)
-		return;
-
-	for (i = 0; fdt_fixup_table[i].model != NULL; i++) {
-		if (strcmp(model, fdt_fixup_table[i].model) != 0)
-			continue;
-
-		if (fdt_fixup_table[i].handler != NULL) {
-			if (bootverbose)
-				printf("simplebus: using fixup for '%s'\n",
-				    model);
-			(*fdt_fixup_table[i].handler)(node);
-		}
-	}
-	free(model, M_OFWPROP);
-}
-
 static int
 simplebus_attach(device_t dev)
 {
@@ -200,8 +172,6 @@
 	    &sc->sc_size_cells)) != 0)
 		return (ENXIO);
 
-	simplebus_fixup(node);
-
 	/*
 	 * Process 'ranges' property.
 	 */

==== //depot/projects/fdt/sys/dev/ofw/ofw_bus_subr.c#3 (text+ko) ====

@@ -178,6 +178,20 @@
 	return (0);
 }
 
+int
+ofw_bus_is_compatible_strict(device_t dev, const char *compatible)
+{
+	const char *compat;
+
+	if ((compat = ofw_bus_get_compat(dev)) == NULL)
+		return (0);
+
+	if (strncasecmp(compat, compatible, strlen(compatible)) == 0)
+		return (1);
+
+	return (0);
+}
+
 void
 ofw_bus_setup_iinfo(phandle_t node, struct ofw_bus_iinfo *ii, int intrsz)
 {

==== //depot/projects/fdt/sys/dev/ofw/ofw_bus_subr.h#3 (text+ko) ====

@@ -69,5 +69,6 @@
 
 /* Helper routine for checking compat prop */
 int ofw_bus_is_compatible(device_t, const char *);
+int ofw_bus_is_compatible_strict(device_t, const char *);
 
 #endif /* !_DEV_OFW_OFW_BUS_SUBR_H_ */

==== //depot/projects/fdt/sys/dev/ofw/ofw_fdt.c#4 (text+ko) ====

@@ -39,6 +39,7 @@
 
 #include <machine/stdarg.h>
 
+#include <dev/fdt/fdt_common.h>
 #include <dev/ofw/ofwvar.h>
 #include <dev/ofw/openfirm.h>
 
@@ -54,26 +55,21 @@
 #define debugf(fmt, args...)
 #endif
 
-static int ofw_fdt_init(ofw_t ofw, void *openfirm);
-static phandle_t ofw_fdt_peer(ofw_t ofw, phandle_t node);
-static phandle_t ofw_fdt_child(ofw_t ofw, phandle_t node);
-static phandle_t ofw_fdt_parent(ofw_t ofw, phandle_t node);
-static phandle_t ofw_fdt_instance_to_package(ofw_t ofw, ihandle_t instance);
-static ssize_t ofw_fdt_getproplen(ofw_t ofw, phandle_t package,
-    const char *propname);
-static ssize_t ofw_fdt_getprop(ofw_t ofw, phandle_t package,
-    const char *propname, void *buf, size_t buflen);
-static int ofw_fdt_nextprop(ofw_t ofw, phandle_t package, const char *previous,
-    char *buf, size_t);
-static int ofw_fdt_setprop(ofw_t ofw, phandle_t package, const char *propname,
-    const void *buf, size_t len);
-static ssize_t ofw_fdt_canon(ofw_t ofw, const char *device, char *buf,
-    size_t len);
-static phandle_t ofw_fdt_finddevice(ofw_t ofw, const char *device);
-static ssize_t ofw_fdt_instance_to_path(ofw_t ofw, ihandle_t instance,
-    char *buf, size_t len);
-static ssize_t ofw_fdt_package_to_path(ofw_t ofw, phandle_t package, char *buf,
-    size_t len);
+static int ofw_fdt_init(ofw_t, void *);
+static phandle_t ofw_fdt_peer(ofw_t, phandle_t);
+static phandle_t ofw_fdt_child(ofw_t, phandle_t);
+static phandle_t ofw_fdt_parent(ofw_t, phandle_t);
+static phandle_t ofw_fdt_instance_to_package(ofw_t, ihandle_t);
+static ssize_t ofw_fdt_getproplen(ofw_t, phandle_t, const char *);
+static ssize_t ofw_fdt_getprop(ofw_t, phandle_t, const char *, void *, size_t);
+static int ofw_fdt_nextprop(ofw_t, phandle_t, const char *, char *, size_t);
+static int ofw_fdt_setprop(ofw_t, phandle_t, const char *, const void *,
+    size_t);
+static ssize_t ofw_fdt_canon(ofw_t, const char *, char *, size_t);
+static phandle_t ofw_fdt_finddevice(ofw_t, const char *);
+static ssize_t ofw_fdt_instance_to_path(ofw_t, ihandle_t, char *, size_t);
+static ssize_t ofw_fdt_package_to_path(ofw_t, phandle_t, char *, size_t);
+static int ofw_fdt_interpret(ofw_t, const char *, int, unsigned long *);
 
 static ofw_method_t ofw_fdt_methods[] = {
 	OFWMETHOD(ofw_init,			ofw_fdt_init),
@@ -89,7 +85,7 @@
 	OFWMETHOD(ofw_finddevice,		ofw_fdt_finddevice),
 	OFWMETHOD(ofw_instance_to_path,		ofw_fdt_instance_to_path),
 	OFWMETHOD(ofw_package_to_path,		ofw_fdt_package_to_path),
-
+	OFWMETHOD(ofw_interpret,		ofw_fdt_interpret),
 	{ 0, 0 }
 };
 
@@ -406,3 +402,60 @@
 
 	return (-1);
 }
+
+static int
+ofw_fdt_fixup(ofw_t ofw)
+{
+#define FDT_MODEL_LEN	80
+	char model[FDT_MODEL_LEN];
+	phandle_t root;
+	ssize_t len;
+	int i;
+
+	if ((root = ofw_fdt_finddevice(ofw, "/")) == 0)
+		return (ENODEV);
+
+	if ((len = ofw_fdt_getproplen(ofw, root, "model")) <= 0)
+		return (0);
+
+	bzero(model, FDT_MODEL_LEN);
+	if (ofw_fdt_getprop(ofw, root, "model", model, FDT_MODEL_LEN) <= 0)
+		return (0);
+
+	/*
+	 * Search fixup table and call handler if appropriate.
+	 */
+	for (i = 0; fdt_fixup_table[i].model != NULL; i++) {
+		if (strncmp(model, fdt_fixup_table[i].model,
+		    FDT_MODEL_LEN) != 0)
+			continue;
+
+		if (fdt_fixup_table[i].handler != NULL)
+			(*fdt_fixup_table[i].handler)(root);
+	}
+
+	return (0);
+}
+
+static int
+ofw_fdt_interpret(ofw_t ofw, const char *cmd, int nret, unsigned long *retvals)
+{
+	int rv;
+
+	/*
+	 * Note: FDT does not have the possibility to 'interpret' commands,
+	 * but we abuse the interface a bit to use it for doing non-standard
+	 * operations on the device tree blob.
+	 *
+	 * Currently the only supported 'command' is to trigger performing
+	 * fixups.
+	 */
+	if (strncmp("perform-fixup", cmd, 13) != 0)
+		return (0);
+
+	rv = ofw_fdt_fixup(ofw);
+	if (nret > 0)
+		retvals[0] = rv;
+
+	return (rv);
+}

==== //depot/projects/fdt/sys/dev/ofw/openfirm.c#5 (text+ko) ====

@@ -159,6 +159,7 @@
 
 	return (OFW_TEST(ofw_obj, name));
 }
+#endif
 
 int
 OF_interpret(const char *cmd, int nreturns, ...)
@@ -179,7 +180,6 @@
 
 	return (status);
 }
-#endif
 
 /*
  * Device tree functions

==== //depot/projects/fdt/sys/powerpc/booke/machdep.c#6 (text+ko) ====

@@ -313,22 +313,6 @@
 	return ((struct bi_mem_region *)bootinfo->bi_data);
 }
 
-struct bi_eth_addr *
-bootinfo_eth(void)
-{
-	struct bi_mem_region *mr;
-	struct bi_eth_addr *eth;
-	int i;
-
-	/* Advance to the eth section */
-	mr = bootinfo_mr();
-	for (i = 0; i < bootinfo->bi_mem_reg_no; i++, mr++)
-		;
-
-	eth = (struct bi_eth_addr *)mr;
-	return (eth);
-}
-
 u_int
 e500_init(u_int32_t startkernel, u_int32_t endkernel, void *mdp)
 {
@@ -383,6 +367,8 @@
 	if (OF_init((void *)dtbp) != 0)
 		while (1);
 
+	OF_interpret("perform-fixup", 0);
+
 	/* Initialize TLB1 handling */
 	tlb1_init(bootinfo->bi_bar_base);
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201002151753.o1FHrUEx061091>