Re: [PATCH 2/3] sparc: make driver/of/pdt no longer sparc-specific
From: Grant Likely
Date: Mon Aug 09 2010 - 01:12:50 EST
Hi Andres, thanks for the patch. Comments below.
g.
On Sun, Aug 8, 2010 at 9:11 PM, Andres Salomon <dilinger@xxxxxxxxxx> wrote:
>
> 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@xxxxxxxxxx>
> ---
> 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
Group this with the select OF from earlier in the config SPARC option.
> 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);
> +}
Rather than having both prom_common_{firstprop,nextprop}(), there only
needs to be one hook; prom_common_nextprop(). Make it use the
firstprop behaviour when it is passed a NULL in the prev pointer.
This will simplify the users of this code further down.
> +
> 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,
If you have to explicitly cast these function pointers, then you're
doing it wrong. :-) Listen to and fix the compiler complaint here.
> +};
> +
> +void __init prom_build_devicetree(void)
> +{
> + of_pdt_set_ops(&prom_sparc_ops);
> + of_pdt_build_devicetree(prom_root_node);
Maybe I'm being nitpicky here, but I would pass the ops structure into
of_pdt_build_devicetree() directly. I don't like the implied state of
setting the ops pointer separate from parsing the tree.
> +
> + of_console_init();
> +
> + printk(KERN_INFO "PROM: Built device tree with %u bytes of memory.\n",
> + prom_early_allocated);
pr_info()
> +}
> 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
> +
I can tell from the context here you're working from an older tree.
Please rebase onto Linus' current top-of-tree. :-) A bunch of OF
related patches have been merged for 2.6.36 that will conflict with
this patch.
> 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.
> - *
> +/*
You should still retain a one-line description of what this file is for.
> * 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@xxxxxxxxxxxxx
> + * Adapted for multiple architectures by Andres Salomon <dilinger@xxxxxxxxxx>
> *
> * 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;
Why a full copy of the structure instead of a pointer?
> +
> +#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)
Use a static inline. C code is preferred over preprocessor code.
Also preserver the namespace and use the of_pdt_ prefix (that goes for
all the new functions here in this file).
> +
> +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;
> +}
It would be nice to rationalize the differences between how sparc and
powerpc use the ->name/->path_component_name fields; but I haven't
investigated what the differences are.
> +
> +static inline void irq_trans_init(struct device_node *dp)
> +{
> + /* unused on non-SPARC architectures */
> +}
For empty statics like this; I'm fine with this more concise form:
+static inline void inc_unique_id(void *p) { }
+static inline void irq_trans_init(struct device_node *dp) { }
(again, add the of_pdt_ prefix)
>
> -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);
As mentioned earlier, this is better with a single .nextprop() hook
that behaves differently when a NULL prev pointer is passed.
> + 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;
As mentioned above, why is the structure copied instead of just
storing the pointer.
> }
> -
> 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@xxxxxxxxxx>
> + *
> + * 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
>
>
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/