Prev: [PATCH 1/3] sparc: break out some PROM device-tree building code out into drivers/of
Next: [PATCH] regulator: tps6507x - add missing platform_set_drvdata in tps6507x_pmic_probe
From: Andres Salomon on 8 Aug 2010 23:20 Clean up pdt.c: - make build dependent upon config OF_PROMTREE - #ifdef out the sparc-specific stuff - create pdt-specific header - create a pdt_ops struct that pdt uses to call arch-specific prom routines Signed-off-by: Andres Salomon <dilinger(a)queued.net> --- arch/sparc/Kconfig | 1 + arch/sparc/include/asm/prom.h | 5 +- arch/sparc/kernel/prom.h | 6 -- arch/sparc/kernel/prom_common.c | 57 ++++++++++++++++++++++- drivers/of/Kconfig | 4 ++ drivers/of/Makefile | 1 + drivers/of/pdt.c | 98 +++++++++++++++++++++++++------------- include/linux/of_pdt.h | 42 +++++++++++++++++ 8 files changed, 171 insertions(+), 43 deletions(-) create mode 100644 include/linux/of_pdt.h diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 13a9f2f..ed3f009 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -24,6 +24,7 @@ config SPARC select HAVE_ARCH_KGDB if !SMP || SPARC64 select HAVE_ARCH_TRACEHOOK select ARCH_WANT_OPTIONAL_GPIOLIB + select OF_PROMTREE select RTC_CLASS select RTC_DRV_M48T59 select HAVE_PERF_EVENTS diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h index f845828..329a976 100644 --- a/arch/sparc/include/asm/prom.h +++ b/arch/sparc/include/asm/prom.h @@ -18,6 +18,7 @@ * 2 of the License, or (at your option) any later version. */ #include <linux/types.h> +#include <linux/of_pdt.h> #include <linux/proc_fs.h> #include <linux/mutex.h> #include <asm/atomic.h> @@ -65,8 +66,8 @@ extern struct device_node *of_console_device; extern char *of_console_path; extern char *of_console_options; -extern void (*prom_build_more)(struct device_node *dp, struct device_node ***nextp); -extern char *build_full_name(struct device_node *dp); +extern void irq_trans_init(struct device_node *dp); +extern char *build_path_component(struct device_node *dp); #endif /* __KERNEL__ */ #endif /* _SPARC_PROM_H */ diff --git a/arch/sparc/kernel/prom.h b/arch/sparc/kernel/prom.h index eeb04a7..cf5fe1c 100644 --- a/arch/sparc/kernel/prom.h +++ b/arch/sparc/kernel/prom.h @@ -4,12 +4,6 @@ #include <linux/spinlock.h> #include <asm/prom.h> -extern void * prom_early_alloc(unsigned long size); -extern void irq_trans_init(struct device_node *dp); - -extern unsigned int prom_unique_id; - -extern char *build_path_component(struct device_node *dp); extern void of_console_init(void); extern unsigned int prom_early_allocated; diff --git a/arch/sparc/kernel/prom_common.c b/arch/sparc/kernel/prom_common.c index 7b454f6..4c5f67f 100644 --- a/arch/sparc/kernel/prom_common.c +++ b/arch/sparc/kernel/prom_common.c @@ -20,6 +20,7 @@ #include <linux/mutex.h> #include <linux/slab.h> #include <linux/of.h> +#include <linux/of_pdt.h> #include <asm/prom.h> #include <asm/oplib.h> #include <asm/leon.h> @@ -117,6 +118,60 @@ int of_find_in_proplist(const char *list, const char *match, int len) } EXPORT_SYMBOL(of_find_in_proplist); +/* + * SPARC32 and SPARC64's prom_firstprop/prom_nextprop do things differently + * here, despite sharing the same interface. SPARC32 doesn't fill in 'buf', + * returning NULL on an error. SPARC64 fills in 'buf', but sets it to an + * empty string upon error. + */ +static int __init handle_prop_quirks(char *buf, const char *name) +{ + if (!name || strlen(name) == 0) + return -1; + +#ifdef CONFIG_SPARC32 + strcpy(buf, name); +#endif + return 0; +} + +static int __init prom_common_firstprop(phandle node, char *buf) +{ + const char *name; + + buf[0] = '\0'; + name = prom_firstprop(node, buf); + return handle_prop_quirks(buf, name); +} + +static int __init prom_common_nextprop(phandle node, const char *prev, + char *buf) +{ + const char *name; + + buf[0] = '\0'; + name = prom_nextprop(node, prev, buf); + return handle_prop_quirks(buf, name); +} + unsigned int prom_early_allocated __initdata; -#include "../../../drivers/of/pdt.c" +static struct of_pdt_ops prom_sparc_ops __initdata = { + .firstprop = prom_common_firstprop, + .nextprop = prom_common_nextprop, + .getproplen = (int (*)(phandle, const char *))prom_getproplen, + .getproperty = (int (*)(phandle, const char *, char *, int))prom_getproperty, + .getchild = (phandle (*)(phandle))prom_getchild, + .getsibling = (phandle (*)(phandle))prom_getsibling, +}; + +void __init prom_build_devicetree(void) +{ + of_pdt_set_ops(&prom_sparc_ops); + of_pdt_build_devicetree(prom_root_node); + + of_console_init(); + + printk(KERN_INFO "PROM: Built device tree with %u bytes of memory.\n", + prom_early_allocated); +} diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 1678dbc..c8a4b7c 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -5,6 +5,10 @@ config OF_FLATTREE bool depends on OF +config OF_PROMTREE + bool + depends on OF + config OF_DYNAMIC def_bool y depends on OF && PPC_OF diff --git a/drivers/of/Makefile b/drivers/of/Makefile index f232cc9..54e8517 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -1,5 +1,6 @@ obj-y = base.o obj-$(CONFIG_OF_FLATTREE) += fdt.o +obj-$(CONFIG_OF_PROMTREE) += pdt.o obj-$(CONFIG_OF_DEVICE) += device.o platform.o obj-$(CONFIG_OF_GPIO) += gpio.o obj-$(CONFIG_OF_I2C) += of_i2c.o diff --git a/drivers/of/pdt.c b/drivers/of/pdt.c index 61d9477..22f46fb 100644 --- a/drivers/of/pdt.c +++ b/drivers/of/pdt.c @@ -1,5 +1,4 @@ -/* prom_common.c: OF device tree support common code. - * +/* * Paul Mackerras August 1996. * Copyright (C) 1996-2005 Paul Mackerras. * @@ -7,6 +6,7 @@ * {engebret|bergner}@us.ibm.com * * Adapted for sparc by David S. Miller davem(a)davemloft.net + * Adapted for multiple architectures by Andres Salomon <dilinger(a)queued.net> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,13 +20,44 @@ #include <linux/mutex.h> #include <linux/slab.h> #include <linux/of.h> +#include <linux/of_pdt.h> #include <asm/prom.h> -#include <asm/oplib.h> -#include <asm/leon.h> -void (*prom_build_more)(struct device_node *dp, struct device_node ***nextp); +void __initdata (*prom_build_more)(struct device_node *dp, + struct device_node ***nextp); + +static struct of_pdt_ops prom_ops __initdata; + +#if defined(CONFIG_SPARC) +static unsigned int prom_unique_id __initdata; + +#define inc_unique_id(p) do { \ + (p)->unique_id = prom_unique_id++; \ +} while (0) + +static inline const char *fetch_node_name(struct device_node *dp) +{ + return dp->path_component_name; +} + +#else + +static inline void inc_unique_id(void *p) +{ + /* unused on non-SPARC architectures */ +} + +static inline const char *fetch_node_name(struct device_node *dp) +{ + return dp->name; +} + +static inline void irq_trans_init(struct device_node *dp) +{ + /* unused on non-SPARC architectures */ +} -unsigned int prom_unique_id; +#endif /* !CONFIG_SPARC */ static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, @@ -35,7 +66,6 @@ static struct property * __init build_one_prop(phandle node, char *prev, { static struct property *tmp = NULL; struct property *p; - const char *name; if (tmp) { p = tmp; @@ -43,7 +73,7 @@ static struct property * __init build_one_prop(phandle node, char *prev, tmp = NULL; } else { p = prom_early_alloc(sizeof(struct property) + 32); - p->unique_id = prom_unique_id++; + inc_unique_id(p); } p->name = (char *) (p + 1); @@ -53,27 +83,24 @@ static struct property * __init build_one_prop(phandle node, char *prev, p->value = prom_early_alloc(special_len); memcpy(p->value, special_val, special_len); } else { - if (prev == NULL) { - name = prom_firstprop(node, p->name); - } else { - name = prom_nextprop(node, prev, p->name); - } + int err; - if (!name || strlen(name) == 0) { + if (prev == NULL) + err = prom_ops.firstprop(node, p->name); + else + err = prom_ops.nextprop(node, prev, p->name); + if (err) { tmp = p; return NULL; } -#ifdef CONFIG_SPARC32 - strcpy(p->name, name); -#endif - p->length = prom_getproplen(node, p->name); + p->length = prom_ops.getproplen(node, p->name); if (p->length <= 0) { p->length = 0; } else { int len; p->value = prom_early_alloc(p->length + 1); - len = prom_getproperty(node, p->name, p->value, + len = prom_ops.getproperty(node, p->name, p->value, p->length); if (len <= 0) p->length = 0; @@ -106,10 +133,10 @@ static char * __init get_one_property(phandle node, const char *name) char *buf = "<NULL>"; int len; - len = prom_getproplen(node, name); + len = prom_ops.getproplen(node, name); if (len > 0) { buf = prom_early_alloc(len); - len = prom_getproperty(node, name, buf, len); + len = prom_ops.getproperty(node, name, buf, len); } return buf; @@ -124,7 +151,7 @@ static struct device_node * __init prom_create_node(phandle node, return NULL; dp = prom_early_alloc(sizeof(*dp)); - dp->unique_id = prom_unique_id++; + inc_unique_id(dp); dp->parent = parent; kref_init(&dp->kref); @@ -140,13 +167,13 @@ static struct device_node * __init prom_create_node(phandle node, return dp; } -char * __init build_full_name(struct device_node *dp) +static char * __init build_full_name(struct device_node *dp) { int len, ourlen, plen; char *n; plen = strlen(dp->parent->full_name); - ourlen = strlen(dp->path_component_name); + ourlen = strlen(fetch_node_name(dp)); len = ourlen + plen + 2; n = prom_early_alloc(len); @@ -155,7 +182,7 @@ char * __init build_full_name(struct device_node *dp) strcpy(n + plen, "/"); plen++; } - strcpy(n + plen, dp->path_component_name); + strcpy(n + plen, fetch_node_name(dp)); return n; } @@ -182,36 +209,39 @@ static struct device_node * __init prom_build_tree(struct device_node *parent, *(*nextp) = dp; *nextp = &dp->allnext; +#if defined(CONFIG_SPARC) dp->path_component_name = build_path_component(dp); +#endif dp->full_name = build_full_name(dp); - dp->child = prom_build_tree(dp, prom_getchild(node), nextp); + dp->child = prom_build_tree(dp, prom_ops.getchild(node), nextp); if (prom_build_more) prom_build_more(dp, nextp); - node = prom_getsibling(node); + node = prom_ops.getsibling(node); } return ret; } -void __init prom_build_devicetree(void) +void __init of_pdt_build_devicetree(int root_node) { struct device_node **nextp; - allnodes = prom_create_node(prom_root_node, NULL); + allnodes = prom_create_node(root_node, NULL); allnodes->path_component_name = ""; allnodes->full_name = "/"; nextp = &allnodes->allnext; allnodes->child = prom_build_tree(allnodes, - prom_getchild(allnodes->phandle), + prom_ops.getchild(allnodes->phandle), &nextp); +} - of_console_init(); +void __init of_pdt_set_ops(struct of_pdt_ops *ops) +{ + BUG_ON(!ops); - printk("PROM: Built device tree with %u bytes of memory.\n", - prom_early_allocated); + prom_ops = *ops; } - diff --git a/include/linux/of_pdt.h b/include/linux/of_pdt.h new file mode 100644 index 0000000..1324ba5 --- /dev/null +++ b/include/linux/of_pdt.h @@ -0,0 +1,42 @@ +/* + * Definitions for building a device tree by calling into the + * Open Firmware PROM. + * + * Copyright (C) 2010 Andres Salomon <dilinger(a)queued.net> + * + * 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. + */ + +#ifndef _LINUX_OF_PDT_H +#define _LINUX_OF_PDT_H + +extern void *prom_early_alloc(unsigned long size); + +/* overridable operations for calling into the PROM */ +struct of_pdt_ops { + /* buffers passed should be 32 bytes; return 0 on success */ + int (*firstprop)(phandle node, char *buf); + int (*nextprop)(phandle node, const char *prev, char *buf); + + /* for both functions, return proplen on success; -1 on error */ + int (*getproplen)(phandle node, const char *prop); + int (*getproperty)(phandle node, const char *prop, char *buf, + int bufsize); + + /* phandles are 0 if no child or sibling exists */ + phandle (*getchild)(phandle parent); + phandle (*getsibling)(phandle node); +}; + +extern void of_pdt_set_ops(struct of_pdt_ops *ops); + +/* for building the device tree */ +extern void of_pdt_build_devicetree(int root_node); + +extern void (*prom_build_more)(struct device_node *dp, + struct device_node ***nextp); + +#endif /* _LINUX_OF_PDT_H */ -- 1.5.6.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo(a)vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/ |