aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/sparc/kernel/prom_common.c36
-rw-r--r--drivers/of/pdt.c40
-rw-r--r--include/linux/of_pdt.h20
3 files changed, 72 insertions, 24 deletions
diff --git a/arch/sparc/kernel/prom_common.c b/arch/sparc/kernel/prom_common.c
index fe84d56b7c5a..ed25834328f4 100644
--- a/arch/sparc/kernel/prom_common.c
+++ b/arch/sparc/kernel/prom_common.c
@@ -118,11 +118,45 @@ int of_find_in_proplist(const char *list, const char *match, int len)
118} 118}
119EXPORT_SYMBOL(of_find_in_proplist); 119EXPORT_SYMBOL(of_find_in_proplist);
120 120
121/*
122 * SPARC32 and SPARC64's prom_nextprop() do things differently
123 * here, despite sharing the same interface. SPARC32 doesn't fill in 'buf',
124 * returning NULL on an error. SPARC64 fills in 'buf', but sets it to an
125 * empty string upon error.
126 */
127static int __init handle_nextprop_quirks(char *buf, const char *name)
128{
129 if (!name || strlen(name) == 0)
130 return -1;
131
132#ifdef CONFIG_SPARC32
133 strcpy(buf, name);
134#endif
135 return 0;
136}
137
138static int __init prom_common_nextprop(phandle node, char *prev, char *buf)
139{
140 const char *name;
141
142 buf[0] = '\0';
143 name = prom_nextprop(node, prev, buf);
144 return handle_nextprop_quirks(buf, name);
145}
146
121unsigned int prom_early_allocated __initdata; 147unsigned int prom_early_allocated __initdata;
122 148
149static struct of_pdt_ops prom_sparc_ops __initdata = {
150 .nextprop = prom_common_nextprop,
151 .getproplen = prom_getproplen,
152 .getproperty = prom_getproperty,
153 .getchild = prom_getchild,
154 .getsibling = prom_getsibling,
155};
156
123void __init prom_build_devicetree(void) 157void __init prom_build_devicetree(void)
124{ 158{
125 of_pdt_build_devicetree(prom_root_node); 159 of_pdt_build_devicetree(prom_root_node, &prom_sparc_ops);
126 of_console_init(); 160 of_console_init();
127 161
128 pr_info("PROM: Built device tree with %u bytes of memory.\n", 162 pr_info("PROM: Built device tree with %u bytes of memory.\n",
diff --git a/drivers/of/pdt.c b/drivers/of/pdt.c
index 2fdb1b478d6f..fd02fc1dd891 100644
--- a/drivers/of/pdt.c
+++ b/drivers/of/pdt.c
@@ -23,7 +23,8 @@
23#include <linux/of.h> 23#include <linux/of.h>
24#include <linux/of_pdt.h> 24#include <linux/of_pdt.h>
25#include <asm/prom.h> 25#include <asm/prom.h>
26#include <asm/oplib.h> 26
27static struct of_pdt_ops *of_pdt_prom_ops __initdata;
27 28
28void __initdata (*prom_build_more)(struct device_node *dp, 29void __initdata (*prom_build_more)(struct device_node *dp,
29 struct device_node ***nextp); 30 struct device_node ***nextp);
@@ -59,7 +60,7 @@ static struct property * __init build_one_prop(phandle node, char *prev,
59{ 60{
60 static struct property *tmp = NULL; 61 static struct property *tmp = NULL;
61 struct property *p; 62 struct property *p;
62 const char *name; 63 int err;
63 64
64 if (tmp) { 65 if (tmp) {
65 p = tmp; 66 p = tmp;
@@ -77,28 +78,20 @@ static struct property * __init build_one_prop(phandle node, char *prev,
77 p->value = prom_early_alloc(special_len); 78 p->value = prom_early_alloc(special_len);
78 memcpy(p->value, special_val, special_len); 79 memcpy(p->value, special_val, special_len);
79 } else { 80 } else {
80 if (prev == NULL) { 81 err = of_pdt_prom_ops->nextprop(node, prev, p->name);
81 name = prom_firstprop(node, p->name); 82 if (err) {
82 } else {
83 name = prom_nextprop(node, prev, p->name);
84 }
85
86 if (!name || strlen(name) == 0) {
87 tmp = p; 83 tmp = p;
88 return NULL; 84 return NULL;
89 } 85 }
90#ifdef CONFIG_SPARC32 86 p->length = of_pdt_prom_ops->getproplen(node, p->name);
91 strcpy(p->name, name);
92#endif
93 p->length = prom_getproplen(node, p->name);
94 if (p->length <= 0) { 87 if (p->length <= 0) {
95 p->length = 0; 88 p->length = 0;
96 } else { 89 } else {
97 int len; 90 int len;
98 91
99 p->value = prom_early_alloc(p->length + 1); 92 p->value = prom_early_alloc(p->length + 1);
100 len = prom_getproperty(node, p->name, p->value, 93 len = of_pdt_prom_ops->getproperty(node, p->name,
101 p->length); 94 p->value, p->length);
102 if (len <= 0) 95 if (len <= 0)
103 p->length = 0; 96 p->length = 0;
104 ((unsigned char *)p->value)[p->length] = '\0'; 97 ((unsigned char *)p->value)[p->length] = '\0';
@@ -130,10 +123,10 @@ static char * __init get_one_property(phandle node, const char *name)
130 char *buf = "<NULL>"; 123 char *buf = "<NULL>";
131 int len; 124 int len;
132 125
133 len = prom_getproplen(node, name); 126 len = of_pdt_prom_ops->getproplen(node, name);
134 if (len > 0) { 127 if (len > 0) {
135 buf = prom_early_alloc(len); 128 buf = prom_early_alloc(len);
136 len = prom_getproperty(node, name, buf, len); 129 len = of_pdt_prom_ops->getproperty(node, name, buf, len);
137 } 130 }
138 131
139 return buf; 132 return buf;
@@ -211,21 +204,25 @@ static struct device_node * __init prom_build_tree(struct device_node *parent,
211#endif 204#endif
212 dp->full_name = build_full_name(dp); 205 dp->full_name = build_full_name(dp);
213 206
214 dp->child = prom_build_tree(dp, prom_getchild(node), nextp); 207 dp->child = prom_build_tree(dp,
208 of_pdt_prom_ops->getchild(node), nextp);
215 209
216 if (prom_build_more) 210 if (prom_build_more)
217 prom_build_more(dp, nextp); 211 prom_build_more(dp, nextp);
218 212
219 node = prom_getsibling(node); 213 node = of_pdt_prom_ops->getsibling(node);
220 } 214 }
221 215
222 return ret; 216 return ret;
223} 217}
224 218
225void __init of_pdt_build_devicetree(phandle root_node) 219void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops)
226{ 220{
227 struct device_node **nextp; 221 struct device_node **nextp;
228 222
223 BUG_ON(!ops);
224 of_pdt_prom_ops = ops;
225
229 allnodes = prom_create_node(root_node, NULL); 226 allnodes = prom_create_node(root_node, NULL);
230#if defined(CONFIG_SPARC) 227#if defined(CONFIG_SPARC)
231 allnodes->path_component_name = ""; 228 allnodes->path_component_name = "";
@@ -234,6 +231,5 @@ void __init of_pdt_build_devicetree(phandle root_node)
234 231
235 nextp = &allnodes->allnext; 232 nextp = &allnodes->allnext;
236 allnodes->child = prom_build_tree(allnodes, 233 allnodes->child = prom_build_tree(allnodes,
237 prom_getchild(allnodes->phandle), 234 of_pdt_prom_ops->getchild(allnodes->phandle), &nextp);
238 &nextp);
239} 235}
diff --git a/include/linux/of_pdt.h b/include/linux/of_pdt.h
index c0a8774e45d0..303c5ffae9b4 100644
--- a/include/linux/of_pdt.h
+++ b/include/linux/of_pdt.h
@@ -13,10 +13,28 @@
13#ifndef _LINUX_OF_PDT_H 13#ifndef _LINUX_OF_PDT_H
14#define _LINUX_OF_PDT_H 14#define _LINUX_OF_PDT_H
15 15
16/* overridable operations for calling into the PROM */
17struct of_pdt_ops {
18 /*
19 * buf should be 32 bytes; return 0 on success.
20 * If prev is NULL, the first property will be returned.
21 */
22 int (*nextprop)(phandle node, char *prev, char *buf);
23
24 /* for both functions, return proplen on success; -1 on error */
25 int (*getproplen)(phandle node, const char *prop);
26 int (*getproperty)(phandle node, const char *prop, char *buf,
27 int bufsize);
28
29 /* phandles are 0 if no child or sibling exists */
30 phandle (*getchild)(phandle parent);
31 phandle (*getsibling)(phandle node);
32};
33
16extern void *prom_early_alloc(unsigned long size); 34extern void *prom_early_alloc(unsigned long size);
17 35
18/* for building the device tree */ 36/* for building the device tree */
19extern void of_pdt_build_devicetree(phandle root_node); 37extern void of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops);
20 38
21extern void (*prom_build_more)(struct device_node *dp, 39extern void (*prom_build_more)(struct device_node *dp,
22 struct device_node ***nextp); 40 struct device_node ***nextp);