x86: OLPC: add OLPC device-tree support (v3)
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
@@ -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
@@ -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
@@ -0,0 +1 @@ +/* dummy prom.h; here to make linux/of.h's #includes happy */
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 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
@@ -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
@@ -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
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
@@ -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
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 theprom_early_allocfunction by callingalloc_bootmemfor 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.)
Signed-off-by Andres Salomon <[email protected]>--- arch/x86/kernel/olpc_dt.c | 27 +++++++++++++++++++++++---- 1 files changed, 23 insertions(+), 4 deletions(-)arch/x86/kernel/olpc_dt.c +0
-0
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
-4void *__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.
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 theprom_early_allocfunction by callingalloc_bootmemfor 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.)
Signed-off-by Andres Salomon <[email protected]>--- arch/x86/kernel/olpc_dt.c | 27 +++++++++++++++++++++++---- 1 files changed, 23 insertions(+), 4 deletions(-)arch/x86/kernel/olpc_dt.c +0
-0@@ -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
-0static unsigned int prom_early_allocated__initdata ; +#define DT_CHUNK_SIZE (1<<12)
PAGE_SIZEperhaps?
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
-4void *__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 matchesPAGE_SIZEon 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.
Quoted 15 lines · Andres Salomon
Make use of
PROC_DEVICETREEto export the tree, and sparc's PROMTREE code to call into OLPC's Open Firmware to build the tree.v3: rename
olpc_promtoolpc_dt
- reworkKconfigentries
- drop devtree build hook from proc, instead adding a call to x86'spaging_init(similarly to how sparc64 does it)
- switch allocation from using slab toalloc_bootmem. this allows the DT to be built earlier during boot (duringsetup_arch); the downside is that there are some 1200 bootmem reservations that are done during boot. Not ideal..
- add a helperolpc_ofw_is_installedfunction to test for the existence and successful detection of OLPC's OFW.
Quoted 1 line
Signed-off-by Andres Salomon <[email protected]>
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.carch/x86/Kconfig +6
-0@@ -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_NBarch/x86/include/asm/olpc_ofw.h +9
-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 */ +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@@ -0,0 +1 @@ +/* dummy prom.h; here to make linux/of.h's #includes happy */ arch/x86/kernel/Makefile +0
-0
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
-0obj-$(CONFIG_X86_MRST) += mrst.o microcode-y := microcode_core.oarch/x86/kernel/olpc_dt.c new file +2
-0@@ -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@@ -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@@ -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
Thomas Gleixner
Acked-byQuoted 16 lines · Grant Likely
Quoted 15 lines · Andres Salomon
Make use of
PROC_DEVICETREEto export the tree, and sparc's PROMTREE code to call into OLPC's Open Firmware to build the tree.v3: rename
olpc_promtoolpc_dt
- reworkKconfigentries
- drop devtree build hook from proc, instead adding a call to x86'spaging_init(similarly to how sparc64 does it)
- switch allocation from using slab toalloc_bootmem. this allows the DT to be built earlier during boot (duringsetup_arch); the downside is that there are some 1200 bootmem reservations that are done during boot. Not ideal..
- add a helperolpc_ofw_is_installedfunction to test for the existence and successful detection of OLPC's OFW.
Quoted 6 lines
Quoted 1 line
Signed-off-by Andres Salomon <[email protected]>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.carch/x86/Kconfig +6
-0@@ -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_NBarch/x86/include/asm/olpc_ofw.h +9
-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 */ +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@@ -0,0 +1 @@ +/* dummy prom.h; here to make linux/of.h's #includes happy */ arch/x86/kernel/Makefile +0
-0arch/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.oolpc_ofw_dt.o perhaps?
arch/x86/kernel/olpc_dt.c line 2
Quoted 11 lines
arch/x86/kernel/Makefile +0
-0obj-$(CONFIG_X86_MRST) += mrst.o microcode-y := microcode_core.oarch/x86/kernel/olpc_dt.c new file +2
-0@@ -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@@ -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@@ -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
H. Peter Anvin
reviewerQuoted 16 lines · Grant Likely
Quoted 15 lines · Andres Salomon
Make use of
PROC_DEVICETREEto export the tree, and sparc's PROMTREE code to call into OLPC's Open Firmware to build the tree.v3: rename
olpc_promtoolpc_dt
- reworkKconfigentries
- drop devtree build hook from proc, instead adding a call to x86'spaging_init(similarly to how sparc64 does it)
- switch allocation from using slab toalloc_bootmem. this allows the DT to be built earlier during boot (duringsetup_arch); the downside is that there are some 1200 bootmem reservations that are done during boot. Not ideal..
- add a helperolpc_ofw_is_installedfunction to test for the existence and successful detection of OLPC's OFW.
Quoted 7 lines
Quoted 1 line
Signed-off-by Andres Salomon <[email protected]>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.
Quoted 16 lines · On Wed, 27 Oct 2010 11:19:33 +0100 Grant Likely…
Quoted 15 lines · Andres Salomon
Make use of
PROC_DEVICETREEto export the tree, and sparc's PROMTREE code to call into OLPC's Open Firmware to build the tree.v3: rename
olpc_promtoolpc_dt
- reworkKconfigentries
- drop devtree build hook from proc, instead adding a call to
x86'spaging_init(similarly to how sparc64 does it)
- switch allocation from using slab toalloc_bootmem. this allows the DT to be built earlier during boot (duringsetup_arch); the downside is that there are some 1200 bootmem reservations that
are done during boot. Not ideal..
- add a helperolpc_ofw_is_installedfunction to test for the existence and successful detection of OLPC's OFW.
Quoted 8 lines
Quoted 1 line
Signed-off-by Andres Salomon <[email protected]>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, 189insertions(+), 0 deletions(-) create mode 100644
arch/x86/include/asm/prom.hcreate mode 100644arch/x86/kernel/olpc_dt.carch/x86/Kconfig +1
-0@@ -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 OpenFirmware that is used on the OLPC XO-1 Children's Machine.
arch/x86/Kconfig +5
-0If 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.hindex 08fde47..a41250e 100644arch/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 voidsetup_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.hnew file mode 100644 index 0000000..b4ec95farch/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
-0arch/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.oolpc_ofw_dt.o perhaps?
arch/x86/kernel/olpc_dt.c line 2
Quoted 11 lines
arch/x86/kernel/Makefile +0
-0obj-$(CONFIG_X86_MRST) += mrst.o microcode-y := microcode_core.oarch/x86/kernel/olpc_dt.c new file +2
-0@@ -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
__initolpc_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.