Skip to contentSkip to conversation

x86: OLPC: add OLPC device-tree support (v3)

PATCH In review Andres Salomon 4 participants 8 messages Oct 22, 2010 – Oct 27, 2010

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 x86: OLPC: add OLPC device-tree support (v3)

Make use of PROC_DEVICETREE to export the tree, and sparc's PROMTREE code to call into OLPC's Open Firmware to build the tree.

v3: rename olpc_prom to olpc_dt
- rework Kconfig entries
- drop devtree build hook from proc, instead adding a call to x86's paging_init (similarly to how sparc64 does it)
- switch allocation from using slab to alloc_bootmem. this allows the DT to be built earlier during boot (during setup_arch); the downside is that there are some 1200 bootmem reservations that are done during boot. Not ideal..
- add a helper olpc_ofw_is_installed function to test for the existence and successful detection of OLPC's OFW.

---
 arch/x86/Kconfig                |    6 ++
 arch/x86/include/asm/olpc_ofw.h |    9 ++
 arch/x86/include/asm/prom.h     |    1 +
 arch/x86/kernel/Makefile        |    1 +
 arch/x86/kernel/olpc_dt.c       |  165 +++++++++++++++++++++++++++++++++++++++
 arch/x86/kernel/olpc_ofw.c      |    5 +
 arch/x86/mm/init_32.c           |    2 +
 7 files changed, 189 insertions(+), 0 deletions(-)
 create mode 100644 arch/x86/include/asm/prom.h
 create mode 100644 arch/x86/kernel/olpc_dt.c
arch/x86/Kconfig +6 -0
index cea0cd9..1d57e2b 100644
@@ -2069,11 +2069,17 @@ config OLPC_OPENFIRMWARE
 	bool "Support for OLPC's Open Firmware"
 	depends on !X86_64 && !X86_PAE
 	default y if OLPC
+	select OF
 	help
 	  This option adds support for the implementation of Open Firmware
 	  that is used on the OLPC XO-1 Children's Machine.
 	  If unsure, say N here.
 
+config OLPC_OPENFIRMWARE_DT
+	bool
+	default y if OLPC_OPENFIRMWARE && PROC_DEVICETREE
+	select OF_PROMTREE
+
 endif # X86_32
 
 config K8_NB
arch/x86/include/asm/olpc_ofw.h +9 -0
index 08fde47..a41250e 100644
@@ -8,6 +8,8 @@
 
 #ifdef CONFIG_OLPC_OPENFIRMWARE
 
+extern bool olpc_ofw_is_installed(void);
+
 /* run an OFW command by calling into the firmware */
 #define olpc_ofw(name, args, res) \
 	__olpc_ofw((name), ARRAY_SIZE(args), args, ARRAY_SIZE(res), res)
@@ -23,9 +25,16 @@ extern void setup_olpc_ofw_pgd(void);
 
 #else /* !CONFIG_OLPC_OPENFIRMWARE */
 
+static inline bool olpc_ofw_is_installed(void) { return false; }
 static inline void olpc_ofw_detect(void) { }
 static inline void setup_olpc_ofw_pgd(void) { }
 
 #endif /* !CONFIG_OLPC_OPENFIRMWARE */
 
+#ifdef CONFIG_OLPC_OPENFIRMWARE_DT
+extern void olpc_dt_build_devicetree(void);
+#else
+static inline void olpc_dt_build_devicetree(void) { }
+#endif /* CONFIG_OLPC_OPENFIRMWARE_DT */
+
 #endif /* _ASM_X86_OLPC_OFW_H */
arch/x86/include/asm/prom.h new file +1 -0
new file mode 100644
index 0000000..b4ec95f
@@ -0,0 +1 @@
+/* dummy prom.h; here to make linux/of.h's #includes happy */
arch/x86/kernel/Makefile +1 -0
index fedf32a..519539a 100644
@@ -107,6 +107,7 @@ scx200-y			+= scx200_32.o
 
 obj-$(CONFIG_OLPC)		+= olpc.o
 obj-$(CONFIG_OLPC_OPENFIRMWARE)	+= olpc_ofw.o
+obj-$(CONFIG_OLPC_OPENFIRMWARE_DT)	+= olpc_dt.o
 obj-$(CONFIG_X86_MRST)		+= mrst.o
 
 microcode-y				:= microcode_core.o
arch/x86/kernel/olpc_dt.c new file +165 -0

165 lines not on this page · raw message

arch/x86/kernel/olpc_ofw.c +5 -0
index 3218aa7..2176048 100644
@@ -104,3 +104,8 @@ void __init olpc_ofw_detect(void)
 			(unsigned long)olpc_ofw_cif, (-start) >> 20);
 	reserve_top_address(-start);
 }
+
+bool __init olpc_ofw_is_installed(void)
+{
+	return olpc_ofw_cif != NULL;
+}
arch/x86/mm/init_32.c +2 -0
index bca7909..41bf85f 100644
@@ -44,6 +44,7 @@
 #include <asm/bugs.h>
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
+#include <asm/olpc_ofw.h>
 #include <asm/pgalloc.h>
 #include <asm/sections.h>
 #include <asm/paravirt.h>
@@ -833,6 +834,7 @@ void __init paging_init(void)
 	/*
 	 * NOTE: at this point the bootmem allocator is fully available.
 	 */
+	olpc_dt_build_devicetree();
 	sparse_init();
 	zone_sizes_init();
 }
Signature · 1 line
1.5.6.5
#1 lore raw

PATCH 1/1 x86: OLPC: speed up device tree creation during boot

Calling alloc_bootmem() for tiny chunks of memory over and over is really slow; on an XO-1, it caused the time between when the kernel started booting and when the display came alive (post-lxfb probe) to increase to 44s. This patch optimizes the prom_early_alloc function by calling alloc_bootmem for 4k-sized blocks of memory, and handing out chunks of that to callers. With this hack, the time between kernel load and display initialization decreased to 23s. If there's a better way to do this early in the boot process, please let me know.

(Note: increasing the chunk size to 16k didn't noticably affect boot time, and wasted 9k.)

---
 arch/x86/kernel/olpc_dt.c |   27 +++++++++++++++++++++++----
 1 files changed, 23 insertions(+), 4 deletions(-)
arch/x86/kernel/olpc_dt.c +23 -4
index f660a11..44dd2ae 100644
@@ -123,16 +123,35 @@ static int __init olpc_dt_pkg2path(phandle node, char *buf,
 }
 
 static unsigned int prom_early_allocated __initdata;
+#define DT_CHUNK_SIZE (1<<12)
 
 void * __init prom_early_alloc(unsigned long size)
 {
+	static u8 *mem = NULL;
+	static size_t free_mem = 0;
 	void *res;
 
-	res = alloc_bootmem(size);
-	if (res)
-		memset(res, 0, size);
+	if (free_mem >= size) {
+		/* allocate from the local cache */
+		free_mem -= size;
+		res = mem;
+		mem += size;
+		return res;
+	}
 
-	prom_early_allocated += size;
+	/*
+	 * To mimimize the number of allocations, grab 4k of memory (that's
+	 * an arbitrary choice that matches PAGE_SIZE on the platforms we care
+	 * about, and minimizes wasted bootmem) and hand off chunks of it to
+	 * callers.
+	 */
+	res = alloc_bootmem(DT_CHUNK_SIZE);
+	if (res) {
+		prom_early_allocated += DT_CHUNK_SIZE;
+		memset(res, 0, DT_CHUNK_SIZE);
+		free_mem = DT_CHUNK_SIZE - size;
+		mem = res + size;
+	}
 
 	return res;
 }
Signature · 1 line
1.5.6.5
#2 lore raw

Re: [PATCH] x86: OLPC: speed up device tree creation during boot

Quoted 23 lines · Andres Salomon

Calling alloc_bootmem() for tiny chunks of memory over and over is really slow; on an XO-1, it caused the time between when the kernel started booting and when the display came alive (post-lxfb probe) to increase to 44s. This patch optimizes the prom_early_alloc function by calling alloc_bootmem for 4k-sized blocks of memory, and handing out chunks of that to callers. With this hack, the time between kernel load and display initialization decreased to 23s. If there's a better way to do this early in the boot process, please let me know.

(Note: increasing the chunk size to 16k didn't noticably affect boot time, and wasted 9k.)

---
 arch/x86/kernel/olpc_dt.c |   27 +++++++++++++++++++++++----
 1 files changed, 23 insertions(+), 4 deletions(-)
arch/x86/kernel/olpc_dt.c +0 -0
index f660a11..44dd2ae 100644

arch/x86/kernel/olpc_dt.c static int __init olpc_dt_pkg2path(phandle node, char *buf, · line 126

Quoted 4 lines
arch/x86/kernel/olpc_dt.c +1 -0
@@ -123,16 +123,35 @@ static int __init olpc_dt_pkg2path(phandle node, char *buf,
 }
 
 static unsigned int prom_early_allocated __initdata;
+#define DT_CHUNK_SIZE (1<<12)

PAGE_SIZE perhaps?

Quoted 22 lines
arch/x86/kernel/olpc_dt.c +12 -4
 void * __init prom_early_alloc(unsigned long size)
 {
+	static u8 *mem = NULL;
+	static size_t free_mem = 0;
 	void *res;
 
-	res = alloc_bootmem(size);
-	if (res)
-		memset(res, 0, size);
+	if (free_mem >= size) {
+		/* allocate from the local cache */
+		free_mem -= size;
+		res = mem;
+		mem += size;
+		return res;
+	}
 
-	prom_early_allocated += size;
+	/*
+	 * To mimimize the number of allocations, grab 4k of memory (that's
+	 * an arbitrary choice that matches PAGE_SIZE on the platforms we care

arch/x86/kernel/olpc_dt.c static int __init olpc_dt_pkg2path(phandle node, char *buf, · line 154

Quoted 10 lines
arch/x86/kernel/olpc_dt.c +10 -0
+	 * about, and minimizes wasted bootmem) and hand off chunks of it to
+	 * callers.
+	 */
+	res = alloc_bootmem(DT_CHUNK_SIZE);
+	if (res) {
+		prom_early_allocated += DT_CHUNK_SIZE;
+		memset(res, 0, DT_CHUNK_SIZE);
+		free_mem = DT_CHUNK_SIZE - size;
+		mem = res + size;
+	}

These two hunks should be flipped around so that only one chunk does the allocation from the pool. As so:

	/*
	 * To mimimize the number of allocations, grab 4k of memory (that's
	 * an arbitrary choice that matches PAGE_SIZE on the platforms we care
	 * about, and minimizes wasted bootmem) and hand off chunks of it to
	 * callers.
	 */
	if (free_mem < size) {
		free_mem = max(DT_CHUNK_SIZE, size);
		mem = alloc_bootmem(free_mem);
		if (!mem) {
			free_mem = 0;
			return NULL;
		}
		memset(mem, 0, free_mem);
		prom_early_allocated += free_mem;
	}

	res = mem;
	free_mem -= size;
	mem += size;
	return res;

g.

#3 lore raw

Re: [PATCH] x86: OLPC: speed up device tree creation during boot

Quoted 27 lines · On Wed, 27 Oct 2010 11:39:24 +0100 Grant Likely…
Quoted 26 lines · Andres Salomon

Calling alloc_bootmem() for tiny chunks of memory over and over is really slow; on an XO-1, it caused the time between when the kernel started booting and when the display came alive (post-lxfb probe) to increase to 44s. This patch optimizes the prom_early_alloc function by calling alloc_bootmem for 4k-sized blocks of memory, and handing out chunks of that to callers. With this hack, the time between kernel load and display initialization decreased to 23s. If there's a better way to do this early in the boot process, please let me know.

(Note: increasing the chunk size to 16k didn't noticably affect boot time, and wasted 9k.)

---
 arch/x86/kernel/olpc_dt.c |   27 +++++++++++++++++++++++----
 1 files changed, 23 insertions(+), 4 deletions(-)
arch/x86/kernel/olpc_dt.c +0 -0
index f660a11..44dd2ae 100644
@@ -123,16 +123,35 @@ static int __init olpc_dt_pkg2path(phandle
 node, char *buf, }
 
Quoted 5 lines

arch/x86/kernel/olpc_dt.c static int __init olpc_dt_pkg2path(phandle node, char *buf, · line 126

Quoted 2 lines
arch/x86/kernel/olpc_dt.c +1 -0
 static unsigned int prom_early_allocated __initdata;
+#define DT_CHUNK_SIZE (1<<12)

PAGE_SIZE perhaps?

I'd rather not imply that it's anything but completely arbitrary..

Quoted 64 lines
Quoted 26 lines
arch/x86/kernel/olpc_dt.c +11 -4
 void * __init prom_early_alloc(unsigned long size)
 {
+	static u8 *mem = NULL;
+	static size_t free_mem = 0;
 	void *res;
 
-	res = alloc_bootmem(size);
-	if (res)
-		memset(res, 0, size);
+	if (free_mem >= size) {
+		/* allocate from the local cache */
+		free_mem -= size;
+		res = mem;
+		mem += size;
+		return res;
+	}
 
-	prom_early_allocated += size;
+	/*
+	 * To mimimize the number of allocations, grab 4k of

memory (that's

arch/x86/kernel/olpc_dt.c +1 -0
+	 * an arbitrary choice that matches PAGE_SIZE on the

platforms we care

arch/x86/kernel/olpc_dt.c +1 -0
+	 * about, and minimizes wasted bootmem) and hand off

chunks of it to

arch/x86/kernel/olpc_dt.c static int __init olpc_dt_pkg2path(phandle node, char *buf, · line 154

Quoted 9 lines
arch/x86/kernel/olpc_dt.c +9 -0
+	 * callers.
+	 */
+	res = alloc_bootmem(DT_CHUNK_SIZE);
+	if (res) {
+		prom_early_allocated += DT_CHUNK_SIZE;
+		memset(res, 0, DT_CHUNK_SIZE);
+		free_mem = DT_CHUNK_SIZE - size;
+		mem = res + size;
+	}

These two hunks should be flipped around so that only one chunk does the allocation from the pool. As so:

	/*
	 * To mimimize the number of allocations, grab 4k of memory

(that's
* an arbitrary choice that matches PAGE_SIZE on the
platforms we care
* about, and minimizes wasted bootmem) and hand off chunks
of it to

	 * callers.
	 */
	if (free_mem < size) {
		free_mem = max(DT_CHUNK_SIZE, size);
		mem = alloc_bootmem(free_mem);
		if (!mem) {
			free_mem = 0;
			return NULL;
		}
		memset(mem, 0, free_mem);
		prom_early_allocated += free_mem;
	}

	res = mem;
	free_mem -= size;
	mem += size;
	return res;
Quoted 1 line

g.

Makes sense, thanks.

#4 lore raw
In reply to Andres Salomon
Quoted 15 lines · Andres Salomon

Make use of PROC_DEVICETREE to export the tree, and sparc's PROMTREE code to call into OLPC's Open Firmware to build the tree.

v3: rename olpc_prom to olpc_dt
- rework Kconfig entries
- drop devtree build hook from proc, instead adding a call to x86's paging_init (similarly to how sparc64 does it)
- switch allocation from using slab to alloc_bootmem. this allows the DT to be built earlier during boot (during setup_arch); the downside is that there are some 1200 bootmem reservations that are done during boot. Not ideal..
- add a helper olpc_ofw_is_installed function to test for the existence and successful detection of OLPC's OFW.

Quoted 1 line

Overall this patch looks fine, but it needs to be acked from the x86 maintainers, and I'd like it to have a cycle through linux-next before it gets merged, so that means 2.6.38 because the 2.6.37 merge window has already been open for almost a week.

The promtree patches have been merged though.

Comments below.

g.

Quoted 76 lines
---
 arch/x86/Kconfig                |    6 ++
 arch/x86/include/asm/olpc_ofw.h |    9 ++
 arch/x86/include/asm/prom.h     |    1 +
 arch/x86/kernel/Makefile        |    1 +
 arch/x86/kernel/olpc_dt.c       |  165 +++++++++++++++++++++++++++++++++++++++
 arch/x86/kernel/olpc_ofw.c      |    5 +
 arch/x86/mm/init_32.c           |    2 +
 7 files changed, 189 insertions(+), 0 deletions(-)
 create mode 100644 arch/x86/include/asm/prom.h
 create mode 100644 arch/x86/kernel/olpc_dt.c
arch/x86/Kconfig +6 -0
index cea0cd9..1d57e2b 100644
@@ -2069,11 +2069,17 @@ config OLPC_OPENFIRMWARE
 	bool "Support for OLPC's Open Firmware"
 	depends on !X86_64 && !X86_PAE
 	default y if OLPC
+	select OF
 	help
 	  This option adds support for the implementation of Open Firmware
 	  that is used on the OLPC XO-1 Children's Machine.
 	  If unsure, say N here.
 
+config OLPC_OPENFIRMWARE_DT
+	bool
+	default y if OLPC_OPENFIRMWARE && PROC_DEVICETREE
+	select OF_PROMTREE
+
 endif # X86_32
 
 config K8_NB
arch/x86/include/asm/olpc_ofw.h +9 -0
index 08fde47..a41250e 100644
@@ -8,6 +8,8 @@
 
 #ifdef CONFIG_OLPC_OPENFIRMWARE
 
+extern bool olpc_ofw_is_installed(void);
+
 /* run an OFW command by calling into the firmware */
 #define olpc_ofw(name, args, res) \
 	__olpc_ofw((name), ARRAY_SIZE(args), args, ARRAY_SIZE(res), res)
@@ -23,9 +25,16 @@ extern void setup_olpc_ofw_pgd(void);
 
 #else /* !CONFIG_OLPC_OPENFIRMWARE */
 
+static inline bool olpc_ofw_is_installed(void) { return false; }
 static inline void olpc_ofw_detect(void) { }
 static inline void setup_olpc_ofw_pgd(void) { }
 
 #endif /* !CONFIG_OLPC_OPENFIRMWARE */
 
+#ifdef CONFIG_OLPC_OPENFIRMWARE_DT
+extern void olpc_dt_build_devicetree(void);
+#else
+static inline void olpc_dt_build_devicetree(void) { }
+#endif /* CONFIG_OLPC_OPENFIRMWARE_DT */
+
 #endif /* _ASM_X86_OLPC_OFW_H */
arch/x86/include/asm/prom.h new file +1 -0
new file mode 100644
index 0000000..b4ec95f
@@ -0,0 +1 @@
+/* dummy prom.h; here to make linux/of.h's #includes happy */
arch/x86/kernel/Makefile +0 -0
index fedf32a..519539a 100644

arch/x86/kernel/Makefile scx200-y += scx200_32.o · line 110

Quoted 4 lines
arch/x86/kernel/Makefile +1 -0
@@ -107,6 +107,7 @@ scx200-y			+= scx200_32.o
 
 obj-$(CONFIG_OLPC)		+= olpc.o
 obj-$(CONFIG_OLPC_OPENFIRMWARE)	+= olpc_ofw.o
+obj-$(CONFIG_OLPC_OPENFIRMWARE_DT)	+= olpc_dt.o

olpc_ofw_dt.o perhaps?

arch/x86/kernel/olpc_dt.c line 2

Quoted 11 lines
arch/x86/kernel/Makefile +0 -0
 obj-$(CONFIG_X86_MRST)		+= mrst.o
 
 microcode-y				:= microcode_core.o
arch/x86/kernel/olpc_dt.c new file +2 -0
new file mode 100644
index 0000000..f660a11
@@ -0,0 +1,165 @@
+/*
+ * olpc_dt.c: OLPC-specific OFW device tree support code.

Nit: I personally prefer not to see the file name encoded in the header block.

Quoted 19 lines
arch/x86/kernel/olpc_dt.c new file +19 -0
+ *
+ * Paul Mackerras	August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ *    {engebret|bergner}@us.ibm.com
+ *
+ *  Adapted for sparc by David S. Miller davem-fT/PcQaiUtIeIZ0/[email protected]
+ *  Adapted for x86/OLPC by Andres Salomon <[email protected]>
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bootmem.h>
+#include <linux/of.h>

arch/x86/kernel/olpc_dt.c line 31

Quoted 10 lines
arch/x86/kernel/olpc_dt.c new file +10 -0
+#include <linux/of_pdt.h>
+#include <asm/olpc_ofw.h>
+
+static phandle __init olpc_dt_getsibling(phandle node)
+{
+	const void *args[] = { (void *)node };
+	void *res[] = { &node };
+
+	if (node == -1)
+		return 0;

phandle is a u32, so testing against a negative value is not sane.

Quoted 39 lines
arch/x86/kernel/olpc_dt.c new file +39 -0
+
+	if (olpc_ofw("peer", args, res) || node == -1)
+		return 0;
+
+	return node;
+}
+
+static phandle __init olpc_dt_getchild(phandle node)
+{
+	const void *args[] = { (void *)node };
+	void *res[] = { &node };
+
+	if (node == -1)
+		return 0;
+
+	if (olpc_ofw("child", args, res) || node == -1) {
+		pr_err("PROM: %s: fetching child failed!\n", __func__);
+		return 0;
+	}
+
+	return node;
+}
+
+static int __init olpc_dt_getproplen(phandle node, const char *prop)
+{
+	const void *args[] = { (void *)node, prop };
+	int len;
+	void *res[] = { &len };
+
+	if (node == -1)
+		return -1;
+
+	if (olpc_ofw("getproplen", args, res)) {
+		pr_err("PROM: %s: getproplen failed!\n", __func__);
+		return -1;
+	}
+
+	return len;
+}

arch/x86/kernel/olpc_dt.c line 80

Quoted 10 lines
arch/x86/kernel/olpc_dt.c new file +10 -0
+
+static int __init olpc_dt_getproperty(phandle node, const char *prop,
+		char *buf, int bufsize)
+{
+	int plen;
+
+	plen = olpc_dt_getproplen(node, prop);
+	if (plen > bufsize || plen < 1)
+		return -1;
+	else {

Nit: If there are braces on the else clause, then please use them on the if() clause also.

Quoted 5 lines
arch/x86/kernel/olpc_dt.c new file +5 -0
+		const void *args[] = { (void *)node, prop, buf, (void *)plen };
+		void *res[] = { &plen };
+
+		if (olpc_ofw("getprop", args, res)) {
+			pr_err("PROM: %s: getprop failed!\n", __func__);

arch/x86/kernel/olpc_dt.c line 95

Quoted 10 lines
arch/x86/kernel/olpc_dt.c new file +10 -0
+			return -1;
+		}
+	}
+
+	return plen;
+}
+
+static int __init olpc_dt_nextprop(phandle node, char *prev, char *buf)
+{
+	const void *args[] = { (void *)node, prev, buf };

This looks wrong. It does not look sane to cast node as a pointer (which won't be the same size on x86_64), and then recast it to an int inside __olpc_ofw(). Do you know why the api is implemented in this way?

Quoted 106 lines
arch/x86/kernel/olpc_dt.c new file +70 -0
+	int success;
+	void *res[] = { &success };
+
+	buf[0] = '\0';
+
+	if (node == -1)
+		return -1;
+
+	if (olpc_ofw("nextprop", args, res) || success != 1)
+		return -1;
+
+	return 0;
+}
+
+static int __init olpc_dt_pkg2path(phandle node, char *buf,
+		const int buflen, int *len)
+{
+	const void *args[] = { (void *)node, buf, (void *)buflen };
+	void *res[] = { len };
+
+	if (node == -1)
+		return -1;
+
+	if (olpc_ofw("package-to-path", args, res) || *len < 1)
+		return -1;
+
+	return 0;
+}
+
+static unsigned int prom_early_allocated __initdata;
+
+void * __init prom_early_alloc(unsigned long size)
+{
+	void *res;
+
+	res = alloc_bootmem(size);
+	if (res)
+		memset(res, 0, size);
+
+	prom_early_allocated += size;
+
+	return res;
+}
+
+static struct of_pdt_ops prom_olpc_ops __initdata = {
+	.nextprop = olpc_dt_nextprop,
+	.getproplen = olpc_dt_getproplen,
+	.getproperty = olpc_dt_getproperty,
+	.getchild = olpc_dt_getchild,
+	.getsibling = olpc_dt_getsibling,
+	.pkg2path = olpc_dt_pkg2path,
+};
+
+void __init olpc_dt_build_devicetree(void)
+{
+	phandle root;
+
+	if (!olpc_ofw_is_installed())
+		return;
+
+	root = olpc_dt_getsibling(0);
+	if (root < 0) {
+		pr_err("PROM: unable to get root node from OFW!\n");
+		return;
+	}
+	of_pdt_build_devicetree(root, &prom_olpc_ops);
+
+	pr_info("PROM DT: Built device tree with %u bytes of memory.\n",
+			prom_early_allocated);
+}
arch/x86/kernel/olpc_ofw.c +5 -0
index 3218aa7..2176048 100644
@@ -104,3 +104,8 @@ void __init olpc_ofw_detect(void)
 			(unsigned long)olpc_ofw_cif, (-start) >> 20);
 	reserve_top_address(-start);
 }
+
+bool __init olpc_ofw_is_installed(void)
+{
+	return olpc_ofw_cif != NULL;
+}
arch/x86/mm/init_32.c +2 -0
index bca7909..41bf85f 100644
@@ -44,6 +44,7 @@
 #include <asm/bugs.h>
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
+#include <asm/olpc_ofw.h>
 #include <asm/pgalloc.h>
 #include <asm/sections.h>
 #include <asm/paravirt.h>
@@ -833,6 +834,7 @@ void __init paging_init(void)
 	/*
 	 * NOTE: at this point the bootmem allocator is fully available.
 	 */
+	olpc_dt_build_devicetree();
 	sparse_init();
 	zone_sizes_init();
 }
Signature · 1 line
1.5.6.5
#5 lore raw
Quoted 16 lines · Grant Likely
Quoted 15 lines · Andres Salomon

Make use of PROC_DEVICETREE to export the tree, and sparc's PROMTREE code to call into OLPC's Open Firmware to build the tree.

v3: rename olpc_prom to olpc_dt
- rework Kconfig entries
- drop devtree build hook from proc, instead adding a call to x86's paging_init (similarly to how sparc64 does it)
- switch allocation from using slab to alloc_bootmem. this allows the DT to be built earlier during boot (during setup_arch); the downside is that there are some 1200 bootmem reservations that are done during boot. Not ideal..
- add a helper olpc_ofw_is_installed function to test for the existence and successful detection of OLPC's OFW.

Quoted 6 lines
Quoted 1 line

Overall this patch looks fine, but it needs to be acked from the x86 maintainers, and I'd like it to have a cycle through linux-next before it gets merged, so that means 2.6.38 because the 2.6.37 merge window has already been open for almost a week.

Fine with me. That's sufficiently self contained :) So

Quoted 317 lines

The promtree patches have been merged though.

Comments below.

g.

Quoted 76 lines
---
 arch/x86/Kconfig                |    6 ++
 arch/x86/include/asm/olpc_ofw.h |    9 ++
 arch/x86/include/asm/prom.h     |    1 +
 arch/x86/kernel/Makefile        |    1 +
 arch/x86/kernel/olpc_dt.c       |  165 +++++++++++++++++++++++++++++++++++++++
 arch/x86/kernel/olpc_ofw.c      |    5 +
 arch/x86/mm/init_32.c           |    2 +
 7 files changed, 189 insertions(+), 0 deletions(-)
 create mode 100644 arch/x86/include/asm/prom.h
 create mode 100644 arch/x86/kernel/olpc_dt.c
arch/x86/Kconfig +6 -0
index cea0cd9..1d57e2b 100644
@@ -2069,11 +2069,17 @@ config OLPC_OPENFIRMWARE
 	bool "Support for OLPC's Open Firmware"
 	depends on !X86_64 && !X86_PAE
 	default y if OLPC
+	select OF
 	help
 	  This option adds support for the implementation of Open Firmware
 	  that is used on the OLPC XO-1 Children's Machine.
 	  If unsure, say N here.
 
+config OLPC_OPENFIRMWARE_DT
+	bool
+	default y if OLPC_OPENFIRMWARE && PROC_DEVICETREE
+	select OF_PROMTREE
+
 endif # X86_32
 
 config K8_NB
arch/x86/include/asm/olpc_ofw.h +9 -0
index 08fde47..a41250e 100644
@@ -8,6 +8,8 @@
 
 #ifdef CONFIG_OLPC_OPENFIRMWARE
 
+extern bool olpc_ofw_is_installed(void);
+
 /* run an OFW command by calling into the firmware */
 #define olpc_ofw(name, args, res) \
 	__olpc_ofw((name), ARRAY_SIZE(args), args, ARRAY_SIZE(res), res)
@@ -23,9 +25,16 @@ extern void setup_olpc_ofw_pgd(void);
 
 #else /* !CONFIG_OLPC_OPENFIRMWARE */
 
+static inline bool olpc_ofw_is_installed(void) { return false; }
 static inline void olpc_ofw_detect(void) { }
 static inline void setup_olpc_ofw_pgd(void) { }
 
 #endif /* !CONFIG_OLPC_OPENFIRMWARE */
 
+#ifdef CONFIG_OLPC_OPENFIRMWARE_DT
+extern void olpc_dt_build_devicetree(void);
+#else
+static inline void olpc_dt_build_devicetree(void) { }
+#endif /* CONFIG_OLPC_OPENFIRMWARE_DT */
+
 #endif /* _ASM_X86_OLPC_OFW_H */
arch/x86/include/asm/prom.h new file +1 -0
new file mode 100644
index 0000000..b4ec95f
@@ -0,0 +1 @@
+/* dummy prom.h; here to make linux/of.h's #includes happy */
arch/x86/kernel/Makefile +0 -0
index fedf32a..519539a 100644

arch/x86/kernel/Makefile scx200-y += scx200_32.o · line 110

Quoted 4 lines
arch/x86/kernel/Makefile +1 -0
@@ -107,6 +107,7 @@ scx200-y			+= scx200_32.o
 
 obj-$(CONFIG_OLPC)		+= olpc.o
 obj-$(CONFIG_OLPC_OPENFIRMWARE)	+= olpc_ofw.o
+obj-$(CONFIG_OLPC_OPENFIRMWARE_DT)	+= olpc_dt.o

olpc_ofw_dt.o perhaps?

arch/x86/kernel/olpc_dt.c line 2

Quoted 11 lines
arch/x86/kernel/Makefile +0 -0
 obj-$(CONFIG_X86_MRST)		+= mrst.o
 
 microcode-y				:= microcode_core.o
arch/x86/kernel/olpc_dt.c new file +2 -0
new file mode 100644
index 0000000..f660a11
@@ -0,0 +1,165 @@
+/*
+ * olpc_dt.c: OLPC-specific OFW device tree support code.

Nit: I personally prefer not to see the file name encoded in the header block.

Quoted 19 lines
arch/x86/kernel/olpc_dt.c new file +19 -0
+ *
+ * Paul Mackerras	August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ *    {engebret|bergner}@us.ibm.com
+ *
+ *  Adapted for sparc by David S. Miller davem-fT/PcQaiUtIeIZ0/[email protected]
+ *  Adapted for x86/OLPC by Andres Salomon <[email protected]>
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bootmem.h>
+#include <linux/of.h>

arch/x86/kernel/olpc_dt.c line 31

Quoted 10 lines
arch/x86/kernel/olpc_dt.c new file +10 -0
+#include <linux/of_pdt.h>
+#include <asm/olpc_ofw.h>
+
+static phandle __init olpc_dt_getsibling(phandle node)
+{
+	const void *args[] = { (void *)node };
+	void *res[] = { &node };
+
+	if (node == -1)
+		return 0;

phandle is a u32, so testing against a negative value is not sane.

Quoted 39 lines
arch/x86/kernel/olpc_dt.c new file +39 -0
+
+	if (olpc_ofw("peer", args, res) || node == -1)
+		return 0;
+
+	return node;
+}
+
+static phandle __init olpc_dt_getchild(phandle node)
+{
+	const void *args[] = { (void *)node };
+	void *res[] = { &node };
+
+	if (node == -1)
+		return 0;
+
+	if (olpc_ofw("child", args, res) || node == -1) {
+		pr_err("PROM: %s: fetching child failed!\n", __func__);
+		return 0;
+	}
+
+	return node;
+}
+
+static int __init olpc_dt_getproplen(phandle node, const char *prop)
+{
+	const void *args[] = { (void *)node, prop };
+	int len;
+	void *res[] = { &len };
+
+	if (node == -1)
+		return -1;
+
+	if (olpc_ofw("getproplen", args, res)) {
+		pr_err("PROM: %s: getproplen failed!\n", __func__);
+		return -1;
+	}
+
+	return len;
+}

arch/x86/kernel/olpc_dt.c line 80

Quoted 10 lines
arch/x86/kernel/olpc_dt.c new file +10 -0
+
+static int __init olpc_dt_getproperty(phandle node, const char *prop,
+		char *buf, int bufsize)
+{
+	int plen;
+
+	plen = olpc_dt_getproplen(node, prop);
+	if (plen > bufsize || plen < 1)
+		return -1;
+	else {

Nit: If there are braces on the else clause, then please use them on the if() clause also.

Quoted 5 lines
arch/x86/kernel/olpc_dt.c new file +5 -0
+		const void *args[] = { (void *)node, prop, buf, (void *)plen };
+		void *res[] = { &plen };
+
+		if (olpc_ofw("getprop", args, res)) {
+			pr_err("PROM: %s: getprop failed!\n", __func__);

arch/x86/kernel/olpc_dt.c line 95

Quoted 10 lines
arch/x86/kernel/olpc_dt.c new file +10 -0
+			return -1;
+		}
+	}
+
+	return plen;
+}
+
+static int __init olpc_dt_nextprop(phandle node, char *prev, char *buf)
+{
+	const void *args[] = { (void *)node, prev, buf };

This looks wrong. It does not look sane to cast node as a pointer (which won't be the same size on x86_64), and then recast it to an int inside __olpc_ofw(). Do you know why the api is implemented in this way?

Quoted 106 lines
arch/x86/kernel/olpc_dt.c new file +70 -0
+	int success;
+	void *res[] = { &success };
+
+	buf[0] = '\0';
+
+	if (node == -1)
+		return -1;
+
+	if (olpc_ofw("nextprop", args, res) || success != 1)
+		return -1;
+
+	return 0;
+}
+
+static int __init olpc_dt_pkg2path(phandle node, char *buf,
+		const int buflen, int *len)
+{
+	const void *args[] = { (void *)node, buf, (void *)buflen };
+	void *res[] = { len };
+
+	if (node == -1)
+		return -1;
+
+	if (olpc_ofw("package-to-path", args, res) || *len < 1)
+		return -1;
+
+	return 0;
+}
+
+static unsigned int prom_early_allocated __initdata;
+
+void * __init prom_early_alloc(unsigned long size)
+{
+	void *res;
+
+	res = alloc_bootmem(size);
+	if (res)
+		memset(res, 0, size);
+
+	prom_early_allocated += size;
+
+	return res;
+}
+
+static struct of_pdt_ops prom_olpc_ops __initdata = {
+	.nextprop = olpc_dt_nextprop,
+	.getproplen = olpc_dt_getproplen,
+	.getproperty = olpc_dt_getproperty,
+	.getchild = olpc_dt_getchild,
+	.getsibling = olpc_dt_getsibling,
+	.pkg2path = olpc_dt_pkg2path,
+};
+
+void __init olpc_dt_build_devicetree(void)
+{
+	phandle root;
+
+	if (!olpc_ofw_is_installed())
+		return;
+
+	root = olpc_dt_getsibling(0);
+	if (root < 0) {
+		pr_err("PROM: unable to get root node from OFW!\n");
+		return;
+	}
+	of_pdt_build_devicetree(root, &prom_olpc_ops);
+
+	pr_info("PROM DT: Built device tree with %u bytes of memory.\n",
+			prom_early_allocated);
+}
arch/x86/kernel/olpc_ofw.c +5 -0
index 3218aa7..2176048 100644
@@ -104,3 +104,8 @@ void __init olpc_ofw_detect(void)
 			(unsigned long)olpc_ofw_cif, (-start) >> 20);
 	reserve_top_address(-start);
 }
+
+bool __init olpc_ofw_is_installed(void)
+{
+	return olpc_ofw_cif != NULL;
+}
arch/x86/mm/init_32.c +2 -0
index bca7909..41bf85f 100644
@@ -44,6 +44,7 @@
 #include <asm/bugs.h>
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
+#include <asm/olpc_ofw.h>
 #include <asm/pgalloc.h>
 #include <asm/sections.h>
 #include <asm/paravirt.h>
@@ -833,6 +834,7 @@ void __init paging_init(void)
 	/*
 	 * NOTE: at this point the bootmem allocator is fully available.
 	 */
+	olpc_dt_build_devicetree();
 	sparse_init();
 	zone_sizes_init();
 }
Signature · 1 line
1.5.6.5
#6 lore raw
In reply to Grant Likely
Quoted 16 lines · Grant Likely
Quoted 15 lines · Andres Salomon

Make use of PROC_DEVICETREE to export the tree, and sparc's PROMTREE code to call into OLPC's Open Firmware to build the tree.

v3: rename olpc_prom to olpc_dt
- rework Kconfig entries
- drop devtree build hook from proc, instead adding a call to x86's paging_init (similarly to how sparc64 does it)
- switch allocation from using slab to alloc_bootmem. this allows the DT to be built earlier during boot (during setup_arch); the downside is that there are some 1200 bootmem reservations that are done during boot. Not ideal..
- add a helper olpc_ofw_is_installed function to test for the existence and successful detection of OLPC's OFW.

Quoted 7 lines
Quoted 1 line

Overall this patch looks fine, but it needs to be acked from the x86 maintainers, and I'd like it to have a cycle through linux-next before it gets merged, so that means 2.6.38 because the 2.6.37 merge window has already been open for almost a week.

Right... which means that our attention is going to be elsewhere for a bit -- probably until after KS/LPC. Sorry, just immediate prioritization and nothing to do with the relative importance.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#7 lore raw
In reply to Grant Likely
Quoted 16 lines · On Wed, 27 Oct 2010 11:19:33 +0100 Grant Likely…
Quoted 15 lines · Andres Salomon

Make use of PROC_DEVICETREE to export the tree, and sparc's PROMTREE code to call into OLPC's Open Firmware to build the tree.

v3: rename olpc_prom to olpc_dt
- rework Kconfig entries
- drop devtree build hook from proc, instead adding a call to
x86's paging_init (similarly to how sparc64 does it)
- switch allocation from using slab to alloc_bootmem. this allows the DT to be built earlier during boot (during setup_arch); the downside is that there are some 1200 bootmem reservations that
are done during boot. Not ideal..
- add a helper olpc_ofw_is_installed function to test for the existence and successful detection of OLPC's OFW.

Quoted 8 lines
Quoted 1 line

Overall this patch looks fine, but it needs to be acked from the x86 maintainers, and I'd like it to have a cycle through linux-next before it gets merged, so that means 2.6.38 because the 2.6.37 merge window has already been open for almost a week.

The promtree patches have been merged though.

I saw that; thanks!

It would be good to get an Ack on that additional x86 patch, too..

Quoted 208 lines

Comments below.

g.

Quoted 77 lines
---
 arch/x86/Kconfig                |    6 ++
 arch/x86/include/asm/olpc_ofw.h |    9 ++
 arch/x86/include/asm/prom.h     |    1 +
 arch/x86/kernel/Makefile        |    1 +
 arch/x86/kernel/olpc_dt.c       |  165
+++++++++++++++++++++++++++++++++++++++
arch/x86/kernel/olpc_ofw.c      |    5 +
arch/x86/mm/init_32.c           |    2 + 7 files changed, 189

insertions(+), 0 deletions(-) create mode 100644
arch/x86/include/asm/prom.h create mode 100644
arch/x86/kernel/olpc_dt.c

arch/x86/Kconfig +1 -0
index cea0cd9..1d57e2b 100644
@@ -2069,11 +2069,17 @@ config OLPC_OPENFIRMWARE
 	bool "Support for OLPC's Open Firmware"
 	depends on !X86_64 && !X86_PAE
 	default y if OLPC
+	select OF
 	help
 	  This option adds support for the implementation of Open

Firmware that is used on the OLPC XO-1 Children's Machine.

arch/x86/Kconfig +5 -0
 	  If unsure, say N here.
 
+config OLPC_OPENFIRMWARE_DT
+	bool
+	default y if OLPC_OPENFIRMWARE && PROC_DEVICETREE
+	select OF_PROMTREE
+
 endif # X86_32
 
 config K8_NB
(quoted diff) +0 -0

b/arch/x86/include/asm/olpc_ofw.h index 08fde47..a41250e 100644

arch/x86/include/asm/olpc_ofw.h +2 -0
@@ -8,6 +8,8 @@
 
 #ifdef CONFIG_OLPC_OPENFIRMWARE
 
+extern bool olpc_ofw_is_installed(void);
+
 /* run an OFW command by calling into the firmware */
 #define olpc_ofw(name, args, res) \
 	__olpc_ofw((name), ARRAY_SIZE(args), args,

ARRAY_SIZE(res), res) @@ -23,9 +25,16 @@ extern void setup_olpc_ofw_pgd(void);
#else /* !CONFIG_OLPC_OPENFIRMWARE */

arch/x86/include/asm/olpc_ofw.h +7 -0
+static inline bool olpc_ofw_is_installed(void) { return false; }
 static inline void olpc_ofw_detect(void) { }
 static inline void setup_olpc_ofw_pgd(void) { }
 
 #endif /* !CONFIG_OLPC_OPENFIRMWARE */
 
+#ifdef CONFIG_OLPC_OPENFIRMWARE_DT
+extern void olpc_dt_build_devicetree(void);
+#else
+static inline void olpc_dt_build_devicetree(void) { }
+#endif /* CONFIG_OLPC_OPENFIRMWARE_DT */
+
 #endif /* _ASM_X86_OLPC_OFW_H */
(quoted diff) +0 -0

b/arch/x86/include/asm/prom.h new file mode 100644 index 0000000..b4ec95f

arch/x86/include/asm/prom.h new file +1 -0
@@ -0,0 +1 @@
+/* dummy prom.h; here to make linux/of.h's #includes happy */
arch/x86/kernel/Makefile +0 -0
index fedf32a..519539a 100644

arch/x86/kernel/Makefile scx200-y += scx200_32.o · line 110

Quoted 4 lines
arch/x86/kernel/Makefile +1 -0
@@ -107,6 +107,7 @@ scx200-y			+= scx200_32.o
 
 obj-$(CONFIG_OLPC)		+= olpc.o
 obj-$(CONFIG_OLPC_OPENFIRMWARE)	+= olpc_ofw.o
+obj-$(CONFIG_OLPC_OPENFIRMWARE_DT)	+= olpc_dt.o

olpc_ofw_dt.o perhaps?

arch/x86/kernel/olpc_dt.c line 2

Quoted 11 lines
arch/x86/kernel/Makefile +0 -0
 obj-$(CONFIG_X86_MRST)		+= mrst.o
 
 microcode-y				:= microcode_core.o
arch/x86/kernel/olpc_dt.c new file +2 -0
new file mode 100644
index 0000000..f660a11
@@ -0,0 +1,165 @@
+/*
+ * olpc_dt.c: OLPC-specific OFW device tree support code.

Nit: I personally prefer not to see the file name encoded in the header block.

Quoted 22 lines
arch/x86/kernel/olpc_dt.c new file +5 -0
+ *
+ * Paul Mackerras	August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter

Bergner.
+ * {engebret|bergner}@us.ibm.com
+ *
+ * Adapted for sparc by David S. Miller davem-fT/PcQaiUtIeIZ0/[email protected]
+ * Adapted for x86/OLPC by Andres Salomon <[email protected]>
+ *
+ * This program is free software; you can redistribute it
and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either
version
+ * 2 of the License, or (at your option) any later version.
+ */

arch/x86/kernel/olpc_dt.c new file +4 -0
+
+#include <linux/kernel.h>
+#include <linux/bootmem.h>
+#include <linux/of.h>

arch/x86/kernel/olpc_dt.c line 31

Quoted 10 lines
arch/x86/kernel/olpc_dt.c new file +10 -0
+#include <linux/of_pdt.h>
+#include <asm/olpc_ofw.h>
+
+static phandle __init olpc_dt_getsibling(phandle node)
+{
+	const void *args[] = { (void *)node };
+	void *res[] = { &node };
+
+	if (node == -1)
+		return 0;

phandle is a u32, so testing against a negative value is not sane.

Quoted 43 lines
arch/x86/kernel/olpc_dt.c new file +17 -0
+
+	if (olpc_ofw("peer", args, res) || node == -1)
+		return 0;
+
+	return node;
+}
+
+static phandle __init olpc_dt_getchild(phandle node)
+{
+	const void *args[] = { (void *)node };
+	void *res[] = { &node };
+
+	if (node == -1)
+		return 0;
+
+	if (olpc_ofw("child", args, res) || node == -1) {
+		pr_err("PROM: %s: fetching child failed!\n",

__func__);

arch/x86/kernel/olpc_dt.c new file +7 -0
+		return 0;
+	}
+
+	return node;
+}
+
+static int __init olpc_dt_getproplen(phandle node, const char

*prop) +{

arch/x86/kernel/olpc_dt.c new file +16 -0
+	const void *args[] = { (void *)node, prop };
+	int len;
+	void *res[] = { &len };
+
+	if (node == -1)
+		return -1;
+
+	if (olpc_ofw("getproplen", args, res)) {
+		pr_err("PROM: %s: getproplen failed!\n", __func__);
+		return -1;
+	}
+
+	return len;
+}
+
+static int __init olpc_dt_getproperty(phandle node, const char

*prop,

arch/x86/kernel/olpc_dt.c line 80

Quoted 8 lines
arch/x86/kernel/olpc_dt.c new file +8 -0
+		char *buf, int bufsize)
+{
+	int plen;
+
+	plen = olpc_dt_getproplen(node, prop);
+	if (plen > bufsize || plen < 1)
+		return -1;
+	else {

Nit: If there are braces on the else clause, then please use them on the if() clause also.

Quoted 14 lines
arch/x86/kernel/olpc_dt.c new file +1 -0
+		const void *args[] = { (void *)node, prop, buf,

(void *)plen };

arch/x86/kernel/olpc_dt.c new file +4 -0
+		void *res[] = { &plen };
+
+		if (olpc_ofw("getprop", args, res)) {
+			pr_err("PROM: %s: getprop failed!\n",

__func__);

arch/x86/kernel/olpc_dt.c new file +7 -0
+			return -1;
+		}
+	}
+
+	return plen;
+}
+
Quoted 9 lines

arch/x86/kernel/olpc_dt.c line 95

Quoted 3 lines

+static int __init olpc_dt_nextprop(phandle node, char *prev, char *buf) +{

arch/x86/kernel/olpc_dt.c new file +1 -0
+	const void *args[] = { (void *)node, prev, buf };

This looks wrong. It does not look sane to cast node as a pointer (which won't be the same size on x86_64), and then recast it to an int inside __olpc_ofw(). Do you know why the api is implemented in this way?

The __olpc_ofw API is implemented this way because Ingo didn't like the original one which used varargs. Using an array like this is cleaner in terms of not needing to manually pass the number of arguments (as the olpc_ofw macro deduces them using ARRAY_SIZE).

The recast to an int is required by OFW's cif interface. I don't know why it's done that way; I've cc'd Mitch on that.