~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/of/pdt.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* pdt.c: OF PROM device tree support code.
 
2
 *
 
3
 * Paul Mackerras       August 1996.
 
4
 * Copyright (C) 1996-2005 Paul Mackerras.
 
5
 *
 
6
 *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
 
7
 *    {engebret|bergner}@us.ibm.com
 
8
 *
 
9
 *  Adapted for sparc by David S. Miller davem@davemloft.net
 
10
 *  Adapted for multiple architectures by Andres Salomon <dilinger@queued.net>
 
11
 *
 
12
 *      This program is free software; you can redistribute it and/or
 
13
 *      modify it under the terms of the GNU General Public License
 
14
 *      as published by the Free Software Foundation; either version
 
15
 *      2 of the License, or (at your option) any later version.
 
16
 */
 
17
 
 
18
#include <linux/kernel.h>
 
19
#include <linux/module.h>
 
20
#include <linux/errno.h>
 
21
#include <linux/mutex.h>
 
22
#include <linux/slab.h>
 
23
#include <linux/of.h>
 
24
#include <linux/of_pdt.h>
 
25
#include <asm/prom.h>
 
26
 
 
27
static struct of_pdt_ops *of_pdt_prom_ops __initdata;
 
28
 
 
29
void __initdata (*of_pdt_build_more)(struct device_node *dp,
 
30
                struct device_node ***nextp);
 
31
 
 
32
#if defined(CONFIG_SPARC)
 
33
unsigned int of_pdt_unique_id __initdata;
 
34
 
 
35
#define of_pdt_incr_unique_id(p) do { \
 
36
        (p)->unique_id = of_pdt_unique_id++; \
 
37
} while (0)
 
38
 
 
39
static char * __init of_pdt_build_full_name(struct device_node *dp)
 
40
{
 
41
        int len, ourlen, plen;
 
42
        char *n;
 
43
 
 
44
        dp->path_component_name = build_path_component(dp);
 
45
 
 
46
        plen = strlen(dp->parent->full_name);
 
47
        ourlen = strlen(dp->path_component_name);
 
48
        len = ourlen + plen + 2;
 
49
 
 
50
        n = prom_early_alloc(len);
 
51
        strcpy(n, dp->parent->full_name);
 
52
        if (!of_node_is_root(dp->parent)) {
 
53
                strcpy(n + plen, "/");
 
54
                plen++;
 
55
        }
 
56
        strcpy(n + plen, dp->path_component_name);
 
57
 
 
58
        return n;
 
59
}
 
60
 
 
61
#else /* CONFIG_SPARC */
 
62
 
 
63
static inline void of_pdt_incr_unique_id(void *p) { }
 
64
static inline void irq_trans_init(struct device_node *dp) { }
 
65
 
 
66
static char * __init of_pdt_build_full_name(struct device_node *dp)
 
67
{
 
68
        static int failsafe_id = 0; /* for generating unique names on failure */
 
69
        char *buf;
 
70
        int len;
 
71
 
 
72
        if (of_pdt_prom_ops->pkg2path(dp->phandle, NULL, 0, &len))
 
73
                goto failsafe;
 
74
 
 
75
        buf = prom_early_alloc(len + 1);
 
76
        if (of_pdt_prom_ops->pkg2path(dp->phandle, buf, len, &len))
 
77
                goto failsafe;
 
78
        return buf;
 
79
 
 
80
 failsafe:
 
81
        buf = prom_early_alloc(strlen(dp->parent->full_name) +
 
82
                               strlen(dp->name) + 16);
 
83
        sprintf(buf, "%s/%s@unknown%i",
 
84
                of_node_is_root(dp->parent) ? "" : dp->parent->full_name,
 
85
                dp->name, failsafe_id++);
 
86
        pr_err("%s: pkg2path failed; assigning %s\n", __func__, buf);
 
87
        return buf;
 
88
}
 
89
 
 
90
#endif /* !CONFIG_SPARC */
 
91
 
 
92
static struct property * __init of_pdt_build_one_prop(phandle node, char *prev,
 
93
                                               char *special_name,
 
94
                                               void *special_val,
 
95
                                               int special_len)
 
96
{
 
97
        static struct property *tmp = NULL;
 
98
        struct property *p;
 
99
        int err;
 
100
 
 
101
        if (tmp) {
 
102
                p = tmp;
 
103
                memset(p, 0, sizeof(*p) + 32);
 
104
                tmp = NULL;
 
105
        } else {
 
106
                p = prom_early_alloc(sizeof(struct property) + 32);
 
107
                of_pdt_incr_unique_id(p);
 
108
        }
 
109
 
 
110
        p->name = (char *) (p + 1);
 
111
        if (special_name) {
 
112
                strcpy(p->name, special_name);
 
113
                p->length = special_len;
 
114
                p->value = prom_early_alloc(special_len);
 
115
                memcpy(p->value, special_val, special_len);
 
116
        } else {
 
117
                err = of_pdt_prom_ops->nextprop(node, prev, p->name);
 
118
                if (err) {
 
119
                        tmp = p;
 
120
                        return NULL;
 
121
                }
 
122
                p->length = of_pdt_prom_ops->getproplen(node, p->name);
 
123
                if (p->length <= 0) {
 
124
                        p->length = 0;
 
125
                } else {
 
126
                        int len;
 
127
 
 
128
                        p->value = prom_early_alloc(p->length + 1);
 
129
                        len = of_pdt_prom_ops->getproperty(node, p->name,
 
130
                                        p->value, p->length);
 
131
                        if (len <= 0)
 
132
                                p->length = 0;
 
133
                        ((unsigned char *)p->value)[p->length] = '\0';
 
134
                }
 
135
        }
 
136
        return p;
 
137
}
 
138
 
 
139
static struct property * __init of_pdt_build_prop_list(phandle node)
 
140
{
 
141
        struct property *head, *tail;
 
142
 
 
143
        head = tail = of_pdt_build_one_prop(node, NULL,
 
144
                                     ".node", &node, sizeof(node));
 
145
 
 
146
        tail->next = of_pdt_build_one_prop(node, NULL, NULL, NULL, 0);
 
147
        tail = tail->next;
 
148
        while(tail) {
 
149
                tail->next = of_pdt_build_one_prop(node, tail->name,
 
150
                                            NULL, NULL, 0);
 
151
                tail = tail->next;
 
152
        }
 
153
 
 
154
        return head;
 
155
}
 
156
 
 
157
static char * __init of_pdt_get_one_property(phandle node, const char *name)
 
158
{
 
159
        char *buf = "<NULL>";
 
160
        int len;
 
161
 
 
162
        len = of_pdt_prom_ops->getproplen(node, name);
 
163
        if (len > 0) {
 
164
                buf = prom_early_alloc(len);
 
165
                len = of_pdt_prom_ops->getproperty(node, name, buf, len);
 
166
        }
 
167
 
 
168
        return buf;
 
169
}
 
170
 
 
171
static struct device_node * __init of_pdt_create_node(phandle node,
 
172
                                                    struct device_node *parent)
 
173
{
 
174
        struct device_node *dp;
 
175
 
 
176
        if (!node)
 
177
                return NULL;
 
178
 
 
179
        dp = prom_early_alloc(sizeof(*dp));
 
180
        of_pdt_incr_unique_id(dp);
 
181
        dp->parent = parent;
 
182
 
 
183
        kref_init(&dp->kref);
 
184
 
 
185
        dp->name = of_pdt_get_one_property(node, "name");
 
186
        dp->type = of_pdt_get_one_property(node, "device_type");
 
187
        dp->phandle = node;
 
188
 
 
189
        dp->properties = of_pdt_build_prop_list(node);
 
190
 
 
191
        irq_trans_init(dp);
 
192
 
 
193
        return dp;
 
194
}
 
195
 
 
196
static struct device_node * __init of_pdt_build_tree(struct device_node *parent,
 
197
                                                   phandle node,
 
198
                                                   struct device_node ***nextp)
 
199
{
 
200
        struct device_node *ret = NULL, *prev_sibling = NULL;
 
201
        struct device_node *dp;
 
202
 
 
203
        while (1) {
 
204
                dp = of_pdt_create_node(node, parent);
 
205
                if (!dp)
 
206
                        break;
 
207
 
 
208
                if (prev_sibling)
 
209
                        prev_sibling->sibling = dp;
 
210
 
 
211
                if (!ret)
 
212
                        ret = dp;
 
213
                prev_sibling = dp;
 
214
 
 
215
                *(*nextp) = dp;
 
216
                *nextp = &dp->allnext;
 
217
 
 
218
                dp->full_name = of_pdt_build_full_name(dp);
 
219
 
 
220
                dp->child = of_pdt_build_tree(dp,
 
221
                                of_pdt_prom_ops->getchild(node), nextp);
 
222
 
 
223
                if (of_pdt_build_more)
 
224
                        of_pdt_build_more(dp, nextp);
 
225
 
 
226
                node = of_pdt_prom_ops->getsibling(node);
 
227
        }
 
228
 
 
229
        return ret;
 
230
}
 
231
 
 
232
static void *kernel_tree_alloc(u64 size, u64 align)
 
233
{
 
234
        return prom_early_alloc(size);
 
235
}
 
236
 
 
237
void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops)
 
238
{
 
239
        struct device_node **nextp;
 
240
 
 
241
        BUG_ON(!ops);
 
242
        of_pdt_prom_ops = ops;
 
243
 
 
244
        allnodes = of_pdt_create_node(root_node, NULL);
 
245
#if defined(CONFIG_SPARC)
 
246
        allnodes->path_component_name = "";
 
247
#endif
 
248
        allnodes->full_name = "/";
 
249
 
 
250
        nextp = &allnodes->allnext;
 
251
        allnodes->child = of_pdt_build_tree(allnodes,
 
252
                        of_pdt_prom_ops->getchild(allnodes->phandle), &nextp);
 
253
 
 
254
        /* Get pointer to "/chosen" and "/aliasas" nodes for use everywhere */
 
255
        of_alias_scan(kernel_tree_alloc);
 
256
}