Date: Sat, 15 Oct 2011 01:11:27 GMT From: Jakub Wojciech Klama <jceel@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 200220 for review Message-ID: <201110150111.p9F1BRR5094464@skunkworks.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@200220?ac=10 Change 200220 by jceel@jceel_cyclone on 2011/10/15 01:10:46 Improvements in FDT bus ranges handling code. Affected files ... .. //depot/projects/soc2011/jceel_lpc/sys/dev/fdt/fdt_common.c#3 edit .. //depot/projects/soc2011/jceel_lpc/sys/dev/fdt/fdt_common.h#3 edit .. //depot/projects/soc2011/jceel_lpc/sys/dev/fdt/fdtbus.c#3 edit .. //depot/projects/soc2011/jceel_lpc/sys/dev/fdt/simplebus.c#3 edit .. //depot/projects/soc2011/jceel_lpc/sys/dev/uart/uart_bus_fdt.c#3 edit Differences ... ==== //depot/projects/soc2011/jceel_lpc/sys/dev/fdt/fdt_common.c#3 (text+ko) ==== @@ -130,6 +130,58 @@ return (0); } + int +fdt_read_ranges(phandle_t node, struct fdt_range **ranges, int addr_cells, + int par_addr_cells, int size_cells) +{ + static pcell_t data[128]; + pcell_t *ptr; + int i, len, tuple_size, ranges_count; + + len = OF_getprop(node, "ranges", (void *)&data, sizeof data); + tuple_size = addr_cells + par_addr_cells + size_cells; + ranges_count = len / tuple_size / sizeof(pcell_t); + + debugf("tuple_size=%d ranges_count=%d\n", tuple_size, ranges_count); + + ptr = data; + + if (*ranges == NULL) + *ranges = malloc(sizeof(struct fdt_range) * ranges_count, + M_TEMP, M_WAITOK | M_ZERO); + + for (i = 0; i < ranges_count; i++) { + (*ranges)[i].base = fdt_data_get((void *)ptr, addr_cells); + ptr += addr_cells; + (*ranges)[i].parent = fdt_data_get((void *)ptr, par_addr_cells); + ptr += par_addr_cells; + (*ranges)[i].size = fdt_data_get((void *)ptr, size_cells); + ptr += size_cells; + + debugf("new range: base=%lx parent=%lx size=%lx\n", + (*ranges)[i].base, (*ranges[i]).parent, + (*ranges)[i].size); + } + + return (ranges_count); +} + +__inline u_long +fdt_ranges_lookup(struct fdt_range *ranges, int nranges, u_long addr, + u_long size) +{ + int n; + + for (n = 0; n < nranges; n++) { + if (ranges[n].base <= addr && (ranges[n].base + + ranges[n].size >= addr + size - 1)) { + return ranges[n].parent; + } + } + + return 0; +} + /* * This routine is an early-usage version of the ofw_bus_is_compatible() when * the ofw_bus I/F is not available (like early console routines and similar). @@ -410,7 +462,7 @@ pcell_t *reg, *regptr; pcell_t addr_cells, size_cells; int tuple_size, tuples; - int i, n, rv; + int i, rv; if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0) return (ENXIO); @@ -440,13 +492,8 @@ if (ranges == NULL) goto moveon; - for (n = 0; n < ranges_count; n++) { - if (ranges[n].base <= start && (ranges[n].base + - ranges[n].size >= start + count - 1)) { - parent = ranges[n].parent; - break; - } - } + parent = fdt_ranges_lookup(ranges, ranges_count, start, count); + moveon: start = parent + start; ==== //depot/projects/soc2011/jceel_lpc/sys/dev/fdt/fdt_common.h#3 (text+ko) ==== @@ -97,6 +97,10 @@ int fdt_get_mem_regions(struct mem_region *, int *, uint32_t *); int fdt_get_phyaddr(phandle_t node, int *); int fdt_immr_addr(vm_offset_t); +int fdt_read_ranges(phandle_t node, struct fdt_range **ranges, int addr_cells, + int par_addr_cells, int size_cels); +u_long fdt_ranges_lookup(struct fdt_range *ranges, int nranges, u_long addr, + u_long size); int fdt_regsize(phandle_t, u_long *, u_long *); int fdt_intr_decode(phandle_t, pcell_t *, int *, int *, int *); int fdt_intr_to_rl(phandle_t, struct resource_list *, struct fdt_sense_level *); ==== //depot/projects/soc2011/jceel_lpc/sys/dev/fdt/fdtbus.c#3 (text+ko) ==== @@ -381,9 +381,7 @@ } /* Calculate address range relative to base. */ - //par_base &= 0x000ffffful; - //start &= 0x000ffffful; - start += par_base;// + fdt_immr_va; + start += par_base; if (count == 0) count = par_size; end = start + count - 1; ==== //depot/projects/soc2011/jceel_lpc/sys/dev/fdt/simplebus.c#3 (text+ko) ==== @@ -154,8 +154,7 @@ struct simplebus_devinfo *di; struct simplebus_softc *sc; phandle_t dt_node, dt_child; - pcell_t *ranges, *ptr; - int i, tuple_size, len, par_addr_cells; + int par_addr_cells; sc = device_get_softc(dev); dt_node = ofw_bus_get_node(dev); @@ -170,33 +169,11 @@ if (par_addr_cells > 2) return (ERANGE); - len = OF_getprop_alloc(dt_node, "ranges", sizeof(pcell_t), (void **)&ranges); - if (len <= 0) - device_printf(dev, "WARNING: bus has no 'ranges' property\n"); - - tuple_size = sc->sc_addr_cells + par_addr_cells + sc->sc_size_cells; - sc->sc_ranges_count = len / tuple_size; - - printf("### tuple_size=%d ranges_count=%d\n", tuple_size, sc->sc_ranges_count); - - ptr = ranges; + sc->sc_ranges_count = fdt_read_ranges(dt_node, &sc->sc_ranges, + sc->sc_addr_cells, par_addr_cells, sc->sc_size_cells); + if (sc->sc_ranges_count <= 0) + device_printf(dev, "WARNING: could not read bus ranges."); - sc->sc_ranges = malloc(sizeof(struct fdt_range) * sc->sc_ranges_count, - M_SIMPLEBUS, M_WAITOK | M_ZERO); - - for (i = 0; i < sc->sc_ranges_count; i++) { - sc->sc_ranges[i].base = fdt_data_get((void *)ptr, sc->sc_addr_cells); - ptr += sc->sc_addr_cells; - sc->sc_ranges[i].parent = fdt_data_get((void *)ptr, par_addr_cells); - ptr += par_addr_cells; - sc->sc_ranges[i].size = fdt_data_get((void *)ptr, sc->sc_size_cells); - ptr += sc->sc_size_cells; - - printf("### new range: base=%lx parent=%lx size=%lx\n", - sc->sc_ranges[i].base, sc->sc_ranges[i].parent, - sc->sc_ranges[i].size); - } - /* * Walk simple-bus and add direct subordinates as our children. */ ==== //depot/projects/soc2011/jceel_lpc/sys/dev/uart/uart_bus_fdt.c#3 (text+ko) ==== @@ -135,10 +135,13 @@ { char buf[64]; struct uart_class *class; - phandle_t node, chosen; + phandle_t node, parent, chosen; pcell_t shift, br, rclk; u_long start, size; - int err; + struct fdt_range ranges[8]; + struct fdt_range *rptr = ranges; + int err, addr_cells, par_addr_cells, size_cells; + int nranges; uart_bus_space_mem = fdtbus_bs_tag; uart_bus_space_io = NULL; @@ -166,6 +169,24 @@ if (OF_finddevice(buf) != node) /* Only stdin == stdout is supported. */ return (ENXIO); + + /* + * Retrieve UART device parent bus + */ + if ((parent = OF_parent(node)) <= 0) + return (ENXIO); + + if (fdt_addrsize_cells(parent, &addr_cells, &size_cells)) + return (ENXIO); + + if ((par_addr_cells = fdt_parent_addr_cells(parent)) > 2) + return (ENXIO); + + nranges = fdt_read_ranges(parent, &rptr, addr_cells, + par_addr_cells, size_cells); + if (nranges <= 0) + return (ENXIO); + /* * Retrieve serial attributes. */ @@ -197,7 +218,12 @@ err = fdt_regsize(node, &start, &size); if (err) return (ENXIO); - start += fdt_immr_pa; + + /* + * XXX this will not work with uart sitting on + * simplebus nested in other simplebus. + */ + start += fdt_ranges_lookup(ranges, nranges, start, size); return (bus_space_map(di->bas.bst, start, size, 0, &di->bas.bsh)); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201110150111.p9F1BRR5094464>