~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/skiboot/core/fdt.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2013-2014 IBM Corp.
 
2
 *
 
3
 * Licensed under the Apache License, Version 2.0 (the "License");
 
4
 * you may not use this file except in compliance with the License.
 
5
 * You may obtain a copy of the License at
 
6
 *
 
7
 *      http://www.apache.org/licenses/LICENSE-2.0
 
8
 *
 
9
 * Unless required by applicable law or agreed to in writing, software
 
10
 * distributed under the License is distributed on an "AS IS" BASIS,
 
11
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 
12
 * implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
 
 
17
#include <skiboot.h>
 
18
#include <stdarg.h>
 
19
#include <libfdt.h>
 
20
#include <device.h>
 
21
#include <cpu.h>
 
22
#include <opal.h>
 
23
#include <interrupts.h>
 
24
#include <fsp.h>
 
25
#include <cec.h>
 
26
#include <vpd.h>
 
27
#include <ccan/str/str.h>
 
28
 
 
29
static int fdt_error;
 
30
 
 
31
#undef DEBUG_FDT
 
32
#ifdef DEBUG_FDT
 
33
#define FDT_DBG(fmt, a...)      prlog(PR_DEBUG, "FDT: " fmt, ##a)
 
34
#else
 
35
#define FDT_DBG(fmt, a...)
 
36
#endif
 
37
 
 
38
static void __save_err(int err, const char *str)
 
39
{
 
40
        FDT_DBG("rc: %d from \"%s\"\n", err, str);
 
41
        if (err && !fdt_error) {
 
42
                prerror("FDT: Error %d from \"%s\"\n", err, str);
 
43
                fdt_error = err;
 
44
        }
 
45
}
 
46
 
 
47
#define save_err(...) __save_err(__VA_ARGS__, #__VA_ARGS__)
 
48
 
 
49
static void dt_property_cell(void *fdt, const char *name, u32 cell)
 
50
{
 
51
        save_err(fdt_property_cell(fdt, name, cell));
 
52
}
 
53
 
 
54
static void dt_begin_node(void *fdt, const struct dt_node *dn)
 
55
{
 
56
        save_err(fdt_begin_node(fdt, dn->name));
 
57
 
 
58
        dt_property_cell(fdt, "phandle", dn->phandle);
 
59
}
 
60
 
 
61
static void dt_property(void *fdt, const struct dt_property *p)
 
62
{
 
63
        save_err(fdt_property(fdt, p->name, p->prop, p->len));
 
64
}
 
65
 
 
66
static void dt_end_node(void *fdt)
 
67
{
 
68
        save_err(fdt_end_node(fdt));
 
69
}
 
70
 
 
71
#ifdef DEBUG_FDT
 
72
static void dump_fdt(void *fdt)
 
73
{
 
74
        int i, off, depth, err;
 
75
 
 
76
        prlog(PR_INFO, "Device tree %u@%p\n", fdt_totalsize(fdt), fdt);
 
77
        err = fdt_check_header(fdt);
 
78
        if (err) {
 
79
                prerror("fdt_check_header: %s\n", fdt_strerror(err));
 
80
                return;
 
81
        }
 
82
        prlog(PR_INFO, "fdt_check_header passed\n");
 
83
 
 
84
        prlog(PR_INFO, "fdt_num_mem_rsv = %u\n", fdt_num_mem_rsv(fdt));
 
85
        for (i = 0; i < fdt_num_mem_rsv(fdt); i++) {
 
86
                u64 addr, size;
 
87
 
 
88
                err = fdt_get_mem_rsv(fdt, i, &addr, &size);
 
89
                if (err) {
 
90
                        prlog(PR_INFO, " ERR %s\n", fdt_strerror(err));
 
91
                        return;
 
92
                }
 
93
                prlog(PR_INFO, "  mem_rsv[%i] = %lu@%#lx\n",
 
94
                      i, (long)addr, (long)size);
 
95
        }
 
96
 
 
97
        for (off = fdt_next_node(fdt, 0, &depth);
 
98
             off > 0;
 
99
             off = fdt_next_node(fdt, off, &depth)) {
 
100
                int len;
 
101
                const char *name;
 
102
 
 
103
                name = fdt_get_name(fdt, off, &len);
 
104
                if (!name) {
 
105
                        prerror("fdt: offset %i no name!\n", off);
 
106
                        return;
 
107
                }
 
108
                prlog(PR_INFO, "name: %s [%u]\n", name, off);
 
109
        }
 
110
}
 
111
#else
 
112
static inline void dump_fdt(void *fdt __unused) { }
 
113
#endif
 
114
 
 
115
static void flatten_dt_properties(void *fdt, const struct dt_node *dn)
 
116
{
 
117
        const struct dt_property *p;
 
118
 
 
119
        list_for_each(&dn->properties, p, list) {
 
120
                if (strstarts(p->name, DT_PRIVATE))
 
121
                        continue;
 
122
 
 
123
                FDT_DBG("  prop: %s size: %ld\n", p->name, p->len);
 
124
                dt_property(fdt, p);
 
125
        }
 
126
}
 
127
 
 
128
static void flatten_dt_node(void *fdt, const struct dt_node *root,
 
129
                            bool exclusive)
 
130
{
 
131
        const struct dt_node *i;
 
132
 
 
133
        if (!exclusive) {
 
134
                FDT_DBG("node: %s\n", root->name);
 
135
                dt_begin_node(fdt, root);
 
136
                flatten_dt_properties(fdt, root);
 
137
        }
 
138
 
 
139
        list_for_each(&root->children, i, list)
 
140
                flatten_dt_node(fdt, i, false);
 
141
 
 
142
        if (!exclusive)
 
143
                dt_end_node(fdt);
 
144
}
 
145
 
 
146
static void create_dtb_reservemap(void *fdt, const struct dt_node *root)
 
147
{
 
148
        uint64_t base, size;
 
149
        const uint64_t *ranges;
 
150
        const struct dt_property *prop;
 
151
        int i;
 
152
 
 
153
        /* Duplicate the reserved-ranges property into the fdt reservemap */
 
154
        prop = dt_find_property(root, "reserved-ranges");
 
155
        if (prop) {
 
156
                ranges = (const void *)prop->prop;
 
157
 
 
158
                for (i = 0; i < prop->len / (sizeof(uint64_t) * 2); i++) {
 
159
                        base = *(ranges++);
 
160
                        size = *(ranges++);
 
161
                        save_err(fdt_add_reservemap_entry(fdt, base, size));
 
162
                }
 
163
        }
 
164
 
 
165
        save_err(fdt_finish_reservemap(fdt));
 
166
}
 
167
 
 
168
static int __create_dtb(void *fdt, size_t len,
 
169
                        const struct dt_node *root,
 
170
                        bool exclusive)
 
171
{
 
172
        fdt_create(fdt, len);
 
173
        if (root == dt_root && !exclusive)
 
174
                create_dtb_reservemap(fdt, root);
 
175
        flatten_dt_node(fdt, root, exclusive);
 
176
 
 
177
        save_err(fdt_finish(fdt));
 
178
        if (fdt_error) {
 
179
                prerror("dtb: error %s\n", fdt_strerror(fdt_error));
 
180
                return fdt_error;
 
181
        }
 
182
 
 
183
        dump_fdt(fdt);
 
184
        return 0;
 
185
}
 
186
 
 
187
void *create_dtb(const struct dt_node *root, bool exclusive)
 
188
{
 
189
        void *fdt = NULL;
 
190
        size_t len = DEVICE_TREE_MAX_SIZE;
 
191
        uint32_t old_last_phandle = last_phandle;
 
192
        int ret;
 
193
 
 
194
        do {
 
195
                last_phandle = old_last_phandle;
 
196
                fdt_error = 0;
 
197
                fdt = malloc(len);
 
198
                if (!fdt) {
 
199
                        prerror("dtb: could not malloc %lu\n", (long)len);
 
200
                        return NULL;
 
201
                }
 
202
 
 
203
                ret = __create_dtb(fdt, len, root, exclusive);
 
204
                if (ret) {
 
205
                        free(fdt);
 
206
                        fdt = NULL;
 
207
                }
 
208
 
 
209
                len *= 2;
 
210
        } while (ret == -FDT_ERR_NOSPACE);
 
211
 
 
212
        return fdt;
 
213
}
 
214
 
 
215
static int64_t opal_get_device_tree(uint32_t phandle,
 
216
                                    uint64_t buf, uint64_t len)
 
217
{
 
218
        struct dt_node *root;
 
219
        void *fdt = (void *)buf;
 
220
        uint32_t old_last_phandle;
 
221
        int64_t totalsize;
 
222
        int ret;
 
223
 
 
224
        root = dt_find_by_phandle(dt_root, phandle);
 
225
        if (!root)
 
226
                return OPAL_PARAMETER;
 
227
 
 
228
        if (!fdt) {
 
229
                fdt = create_dtb(root, true);
 
230
                if (!fdt)
 
231
                        return OPAL_INTERNAL_ERROR;
 
232
                totalsize = fdt_totalsize(fdt);
 
233
                free(fdt);
 
234
                return totalsize;
 
235
        }
 
236
 
 
237
        if (!len)
 
238
                return OPAL_PARAMETER;
 
239
 
 
240
        fdt_error = 0;
 
241
        old_last_phandle = last_phandle;
 
242
        ret = __create_dtb(fdt, len, root, true);
 
243
        if (ret) {
 
244
                last_phandle = old_last_phandle;
 
245
                if (ret == -FDT_ERR_NOSPACE)
 
246
                        return OPAL_NO_MEM;
 
247
 
 
248
                return OPAL_EMPTY;
 
249
        }
 
250
 
 
251
        return OPAL_SUCCESS;
 
252
}
 
253
opal_call(OPAL_GET_DEVICE_TREE, opal_get_device_tree, 3);