From owner-p4-projects@FreeBSD.ORG Mon Feb 15 17:53:30 2010 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id ABF611065692; Mon, 15 Feb 2010 17:53:30 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6E3F61065672 for ; Mon, 15 Feb 2010 17:53:30 +0000 (UTC) (envelope-from raj@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 555D78FC1A for ; Mon, 15 Feb 2010 17:53:30 +0000 (UTC) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id o1FHrUDF061093 for ; Mon, 15 Feb 2010 17:53:30 GMT (envelope-from raj@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id o1FHrUEx061091 for perforce@freebsd.org; Mon, 15 Feb 2010 17:53:30 GMT (envelope-from raj@freebsd.org) Date: Mon, 15 Feb 2010 17:53:30 GMT Message-Id: <201002151753.o1FHrUEx061091@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to raj@freebsd.org using -f From: Rafal Jaworowski To: Perforce Change Reviews Precedence: bulk Cc: Subject: PERFORCE change 174731 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 15 Feb 2010 17:53:30 -0000 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", ®, sizeof(reg)); - if (len <= 0) - return (EINVAL); - - *base = fdt_data_get(®[0], addr_cells); - *size = fdt_data_get(®[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", ®, sizeof(reg)); + if (len <= 0) + return (EINVAL); + + *base = fdt_data_get(®[0], addr_cells); + *size = fdt_data_get(®[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 +#include #include #include @@ -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);