Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 18 Nov 2014 11:16:23 +0000
From:      Andrew Turner <andrew@fubar.geek.nz>
To:        freebsd-arm@freebsd.org, freebsd-embedded@freebsd.org
Subject:   FDT patch for testing
Message-ID:  <20141118111623.398d95ae@bender.lan>

next in thread | raw e-mail | index | archive | help
--MP_/XVDG2gO_jWjC=1=jAs3RNpI
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

I'm looking for a review and testing of the attached fdt patch. It is
from a review at [1].

It updates fdt_get_range to remove the assumption it's parent bus
address is directly usable. Instead it checks if the parent has a
ranges property and looks up the bus address there. If there is no such
property it keeps the existing behaviour.

The two users of this function are the FDT uart and Marvell interrupt
controller. Because it has a chance to stop the uart from woking I
would like it if it could be tested on a few boards before I commit it.
I have tested it on a Pandaboard so would be interested in the results
on other FDT enabled boards.

Andrew

[1] https://reviews.freebsd.org/D1160
--MP_/XVDG2gO_jWjC=1=jAs3RNpI
Content-Type: text/x-patch
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=D1160.diff

Index: sys/dev/fdt/fdt_common.c
===================================================================
--- sys/dev/fdt/fdt_common.c
+++ sys/dev/fdt/fdt_common.c
@@ -64,12 +64,84 @@
 
 struct fdt_ic_list fdt_ic_list_head = SLIST_HEAD_INITIALIZER(fdt_ic_list_head);
 
+static int
+fdt_get_range_by_busaddr(phandle_t node, u_long addr, u_long *base,
+    u_long *size)
+{
+	pcell_t ranges[32], *rangesptr;
+	pcell_t addr_cells, size_cells, par_addr_cells;
+	u_long bus_addr, par_bus_addr, pbase, psize;
+	int err, i, len, tuple_size, tuples;
+
+	if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0)
+		return (ENXIO);
+	/*
+	 * Process 'ranges' property.
+	 */
+	par_addr_cells = fdt_parent_addr_cells(node);
+	if (par_addr_cells > 2) {
+		return (ERANGE);
+	}
+
+	len = OF_getproplen(node, "ranges");
+	if (len < 0)
+		return (-1);
+	if (len > sizeof(ranges))
+		return (ENOMEM);
+	if (len == 0) {
+		*base = 0;
+		*size = ULONG_MAX;
+		return (0);
+	}
+
+	if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0)
+		return (EINVAL);
+
+	tuple_size = addr_cells + par_addr_cells + size_cells;
+	tuples = len / (tuple_size * sizeof(cell_t));
+
+	if (fdt_ranges_verify(ranges, tuples, par_addr_cells,
+	    addr_cells, size_cells)) {
+		return (ERANGE);
+	}
+	*base = 0;
+	*size = 0;
+
+	for (i = 0; i < tuples; i++) {
+		rangesptr = &ranges[i * tuple_size];
+
+		bus_addr = fdt_data_get((void *)rangesptr, addr_cells);
+		if (bus_addr != addr)
+			continue;
+		rangesptr += addr_cells;
+
+		par_bus_addr = fdt_data_get((void *)rangesptr, par_addr_cells);
+		rangesptr += par_addr_cells;
+
+		err = fdt_get_range_by_busaddr(OF_parent(node), par_bus_addr,
+		    &pbase, &psize);
+		if (err > 0)
+			return (err);
+		if (err == 0)
+			*base = pbase;
+		else
+			*base = par_bus_addr;
+
+		*size = fdt_data_get((void *)rangesptr, size_cells);
+
+		return (0);
+	}
+
+	return (EINVAL);
+}
+
 int
 fdt_get_range(phandle_t node, int range_id, u_long *base, u_long *size)
 {
 	pcell_t ranges[6], *rangesptr;
 	pcell_t addr_cells, size_cells, par_addr_cells;
-	int len, tuple_size, tuples;
+	u_long par_bus_addr, pbase, psize;
+	int err, len, tuple_size, tuples;
 
 	if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0)
 		return (ENXIO);
@@ -109,8 +181,17 @@
 
 	*base = fdt_data_get((void *)rangesptr, addr_cells);
 	rangesptr += addr_cells;
-	*base += fdt_data_get((void *)rangesptr, par_addr_cells);
+
+	par_bus_addr = fdt_data_get((void *)rangesptr, par_addr_cells);
 	rangesptr += par_addr_cells;
+
+	err = fdt_get_range_by_busaddr(OF_parent(node), par_bus_addr,
+	   &pbase, &psize);
+	if (err == 0)
+		*base += pbase;
+	else
+		*base += par_bus_addr;
+
 	*size = fdt_data_get((void *)rangesptr, size_cells);
 	return (0);
 }
@@ -292,7 +373,7 @@
 	/* Find out #address-cells of the superior bus. */
 	if (OF_searchprop(OF_parent(node), "#address-cells", &addr_cells,
 	    sizeof(addr_cells)) <= 0)
-		addr_cells = 2;
+		return (2);
 
 	return ((int)fdt32_to_cpu(addr_cells));
 }

--MP_/XVDG2gO_jWjC=1=jAs3RNpI--



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