Skip site navigation (1)Skip section navigation (2)
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>