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

« back to all changes in this revision

Viewing changes to scripts/dtc/checks.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
/*
 
2
 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2007.
 
3
 *
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU General Public License as
 
7
 * published by the Free Software Foundation; either version 2 of the
 
8
 * License, or (at your option) any later version.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 *  General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 
18
 *                                                                   USA
 
19
 */
 
20
 
 
21
#include "dtc.h"
 
22
 
 
23
#ifdef TRACE_CHECKS
 
24
#define TRACE(c, ...) \
 
25
        do { \
 
26
                fprintf(stderr, "=== %s: ", (c)->name); \
 
27
                fprintf(stderr, __VA_ARGS__); \
 
28
                fprintf(stderr, "\n"); \
 
29
        } while (0)
 
30
#else
 
31
#define TRACE(c, fmt, ...)      do { } while (0)
 
32
#endif
 
33
 
 
34
enum checklevel {
 
35
        IGNORE = 0,
 
36
        WARN = 1,
 
37
        ERROR = 2,
 
38
};
 
39
 
 
40
enum checkstatus {
 
41
        UNCHECKED = 0,
 
42
        PREREQ,
 
43
        PASSED,
 
44
        FAILED,
 
45
};
 
46
 
 
47
struct check;
 
48
 
 
49
typedef void (*tree_check_fn)(struct check *c, struct node *dt);
 
50
typedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node);
 
51
typedef void (*prop_check_fn)(struct check *c, struct node *dt,
 
52
                              struct node *node, struct property *prop);
 
53
 
 
54
struct check {
 
55
        const char *name;
 
56
        tree_check_fn tree_fn;
 
57
        node_check_fn node_fn;
 
58
        prop_check_fn prop_fn;
 
59
        void *data;
 
60
        enum checklevel level;
 
61
        enum checkstatus status;
 
62
        int inprogress;
 
63
        int num_prereqs;
 
64
        struct check **prereq;
 
65
};
 
66
 
 
67
#define CHECK(nm, tfn, nfn, pfn, d, lvl, ...) \
 
68
        static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \
 
69
        static struct check nm = { \
 
70
                .name = #nm, \
 
71
                .tree_fn = (tfn), \
 
72
                .node_fn = (nfn), \
 
73
                .prop_fn = (pfn), \
 
74
                .data = (d), \
 
75
                .level = (lvl), \
 
76
                .status = UNCHECKED, \
 
77
                .num_prereqs = ARRAY_SIZE(nm##_prereqs), \
 
78
                .prereq = nm##_prereqs, \
 
79
        };
 
80
 
 
81
#define TREE_CHECK(nm, d, lvl, ...) \
 
82
        CHECK(nm, check_##nm, NULL, NULL, d, lvl, __VA_ARGS__)
 
83
#define NODE_CHECK(nm, d, lvl, ...) \
 
84
        CHECK(nm, NULL, check_##nm, NULL, d, lvl, __VA_ARGS__)
 
85
#define PROP_CHECK(nm, d, lvl, ...) \
 
86
        CHECK(nm, NULL, NULL, check_##nm, d, lvl, __VA_ARGS__)
 
87
#define BATCH_CHECK(nm, lvl, ...) \
 
88
        CHECK(nm, NULL, NULL, NULL, NULL, lvl, __VA_ARGS__)
 
89
 
 
90
#ifdef __GNUC__
 
91
static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
 
92
#endif
 
93
static inline void check_msg(struct check *c, const char *fmt, ...)
 
94
{
 
95
        va_list ap;
 
96
        va_start(ap, fmt);
 
97
 
 
98
        if ((c->level < WARN) || (c->level <= quiet))
 
99
                return; /* Suppress message */
 
100
 
 
101
        fprintf(stderr, "%s (%s): ",
 
102
                (c->level == ERROR) ? "ERROR" : "Warning", c->name);
 
103
        vfprintf(stderr, fmt, ap);
 
104
        fprintf(stderr, "\n");
 
105
}
 
106
 
 
107
#define FAIL(c, ...) \
 
108
        do { \
 
109
                TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \
 
110
                (c)->status = FAILED; \
 
111
                check_msg((c), __VA_ARGS__); \
 
112
        } while (0)
 
113
 
 
114
static void check_nodes_props(struct check *c, struct node *dt, struct node *node)
 
115
{
 
116
        struct node *child;
 
117
        struct property *prop;
 
118
 
 
119
        TRACE(c, "%s", node->fullpath);
 
120
        if (c->node_fn)
 
121
                c->node_fn(c, dt, node);
 
122
 
 
123
        if (c->prop_fn)
 
124
                for_each_property(node, prop) {
 
125
                        TRACE(c, "%s\t'%s'", node->fullpath, prop->name);
 
126
                        c->prop_fn(c, dt, node, prop);
 
127
                }
 
128
 
 
129
        for_each_child(node, child)
 
130
                check_nodes_props(c, dt, child);
 
131
}
 
132
 
 
133
static int run_check(struct check *c, struct node *dt)
 
134
{
 
135
        int error = 0;
 
136
        int i;
 
137
 
 
138
        assert(!c->inprogress);
 
139
 
 
140
        if (c->status != UNCHECKED)
 
141
                goto out;
 
142
 
 
143
        c->inprogress = 1;
 
144
 
 
145
        for (i = 0; i < c->num_prereqs; i++) {
 
146
                struct check *prq = c->prereq[i];
 
147
                error |= run_check(prq, dt);
 
148
                if (prq->status != PASSED) {
 
149
                        c->status = PREREQ;
 
150
                        check_msg(c, "Failed prerequisite '%s'",
 
151
                                  c->prereq[i]->name);
 
152
                }
 
153
        }
 
154
 
 
155
        if (c->status != UNCHECKED)
 
156
                goto out;
 
157
 
 
158
        if (c->node_fn || c->prop_fn)
 
159
                check_nodes_props(c, dt, dt);
 
160
 
 
161
        if (c->tree_fn)
 
162
                c->tree_fn(c, dt);
 
163
        if (c->status == UNCHECKED)
 
164
                c->status = PASSED;
 
165
 
 
166
        TRACE(c, "\tCompleted, status %d", c->status);
 
167
 
 
168
out:
 
169
        c->inprogress = 0;
 
170
        if ((c->status != PASSED) && (c->level == ERROR))
 
171
                error = 1;
 
172
        return error;
 
173
}
 
174
 
 
175
/*
 
176
 * Utility check functions
 
177
 */
 
178
 
 
179
static void check_is_string(struct check *c, struct node *root,
 
180
                            struct node *node)
 
181
{
 
182
        struct property *prop;
 
183
        char *propname = c->data;
 
184
 
 
185
        prop = get_property(node, propname);
 
186
        if (!prop)
 
187
                return; /* Not present, assumed ok */
 
188
 
 
189
        if (!data_is_one_string(prop->val))
 
190
                FAIL(c, "\"%s\" property in %s is not a string",
 
191
                     propname, node->fullpath);
 
192
}
 
193
#define CHECK_IS_STRING(nm, propname, lvl) \
 
194
        CHECK(nm, NULL, check_is_string, NULL, (propname), (lvl))
 
195
 
 
196
static void check_is_cell(struct check *c, struct node *root,
 
197
                          struct node *node)
 
198
{
 
199
        struct property *prop;
 
200
        char *propname = c->data;
 
201
 
 
202
        prop = get_property(node, propname);
 
203
        if (!prop)
 
204
                return; /* Not present, assumed ok */
 
205
 
 
206
        if (prop->val.len != sizeof(cell_t))
 
207
                FAIL(c, "\"%s\" property in %s is not a single cell",
 
208
                     propname, node->fullpath);
 
209
}
 
210
#define CHECK_IS_CELL(nm, propname, lvl) \
 
211
        CHECK(nm, NULL, check_is_cell, NULL, (propname), (lvl))
 
212
 
 
213
/*
 
214
 * Structural check functions
 
215
 */
 
216
 
 
217
static void check_duplicate_node_names(struct check *c, struct node *dt,
 
218
                                       struct node *node)
 
219
{
 
220
        struct node *child, *child2;
 
221
 
 
222
        for_each_child(node, child)
 
223
                for (child2 = child->next_sibling;
 
224
                     child2;
 
225
                     child2 = child2->next_sibling)
 
226
                        if (streq(child->name, child2->name))
 
227
                                FAIL(c, "Duplicate node name %s",
 
228
                                     child->fullpath);
 
229
}
 
230
NODE_CHECK(duplicate_node_names, NULL, ERROR);
 
231
 
 
232
static void check_duplicate_property_names(struct check *c, struct node *dt,
 
233
                                           struct node *node)
 
234
{
 
235
        struct property *prop, *prop2;
 
236
 
 
237
        for_each_property(node, prop)
 
238
                for (prop2 = prop->next; prop2; prop2 = prop2->next)
 
239
                        if (streq(prop->name, prop2->name))
 
240
                                FAIL(c, "Duplicate property name %s in %s",
 
241
                                     prop->name, node->fullpath);
 
242
}
 
243
NODE_CHECK(duplicate_property_names, NULL, ERROR);
 
244
 
 
245
#define LOWERCASE       "abcdefghijklmnopqrstuvwxyz"
 
246
#define UPPERCASE       "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 
247
#define DIGITS          "0123456789"
 
248
#define PROPNODECHARS   LOWERCASE UPPERCASE DIGITS ",._+*#?-"
 
249
 
 
250
static void check_node_name_chars(struct check *c, struct node *dt,
 
251
                                  struct node *node)
 
252
{
 
253
        int n = strspn(node->name, c->data);
 
254
 
 
255
        if (n < strlen(node->name))
 
256
                FAIL(c, "Bad character '%c' in node %s",
 
257
                     node->name[n], node->fullpath);
 
258
}
 
259
NODE_CHECK(node_name_chars, PROPNODECHARS "@", ERROR);
 
260
 
 
261
static void check_node_name_format(struct check *c, struct node *dt,
 
262
                                   struct node *node)
 
263
{
 
264
        if (strchr(get_unitname(node), '@'))
 
265
                FAIL(c, "Node %s has multiple '@' characters in name",
 
266
                     node->fullpath);
 
267
}
 
268
NODE_CHECK(node_name_format, NULL, ERROR, &node_name_chars);
 
269
 
 
270
static void check_property_name_chars(struct check *c, struct node *dt,
 
271
                                      struct node *node, struct property *prop)
 
272
{
 
273
        int n = strspn(prop->name, c->data);
 
274
 
 
275
        if (n < strlen(prop->name))
 
276
                FAIL(c, "Bad character '%c' in property name \"%s\", node %s",
 
277
                     prop->name[n], prop->name, node->fullpath);
 
278
}
 
279
PROP_CHECK(property_name_chars, PROPNODECHARS, ERROR);
 
280
 
 
281
#define DESCLABEL_FMT   "%s%s%s%s%s"
 
282
#define DESCLABEL_ARGS(node,prop,mark)          \
 
283
        ((mark) ? "value of " : ""),            \
 
284
        ((prop) ? "'" : ""), \
 
285
        ((prop) ? (prop)->name : ""), \
 
286
        ((prop) ? "' in " : ""), (node)->fullpath
 
287
 
 
288
static void check_duplicate_label(struct check *c, struct node *dt,
 
289
                                  const char *label, struct node *node,
 
290
                                  struct property *prop, struct marker *mark)
 
291
{
 
292
        struct node *othernode = NULL;
 
293
        struct property *otherprop = NULL;
 
294
        struct marker *othermark = NULL;
 
295
 
 
296
        othernode = get_node_by_label(dt, label);
 
297
 
 
298
        if (!othernode)
 
299
                otherprop = get_property_by_label(dt, label, &othernode);
 
300
        if (!othernode)
 
301
                othermark = get_marker_label(dt, label, &othernode,
 
302
                                               &otherprop);
 
303
 
 
304
        if (!othernode)
 
305
                return;
 
306
 
 
307
        if ((othernode != node) || (otherprop != prop) || (othermark != mark))
 
308
                FAIL(c, "Duplicate label '%s' on " DESCLABEL_FMT
 
309
                     " and " DESCLABEL_FMT,
 
310
                     label, DESCLABEL_ARGS(node, prop, mark),
 
311
                     DESCLABEL_ARGS(othernode, otherprop, othermark));
 
312
}
 
313
 
 
314
static void check_duplicate_label_node(struct check *c, struct node *dt,
 
315
                                       struct node *node)
 
316
{
 
317
        struct label *l;
 
318
 
 
319
        for_each_label(node->labels, l)
 
320
                check_duplicate_label(c, dt, l->label, node, NULL, NULL);
 
321
}
 
322
static void check_duplicate_label_prop(struct check *c, struct node *dt,
 
323
                                       struct node *node, struct property *prop)
 
324
{
 
325
        struct marker *m = prop->val.markers;
 
326
        struct label *l;
 
327
 
 
328
        for_each_label(prop->labels, l)
 
329
                check_duplicate_label(c, dt, l->label, node, prop, NULL);
 
330
 
 
331
        for_each_marker_of_type(m, LABEL)
 
332
                check_duplicate_label(c, dt, m->ref, node, prop, m);
 
333
}
 
334
CHECK(duplicate_label, NULL, check_duplicate_label_node,
 
335
      check_duplicate_label_prop, NULL, ERROR);
 
336
 
 
337
static void check_explicit_phandles(struct check *c, struct node *root,
 
338
                                    struct node *node, struct property *prop)
 
339
{
 
340
        struct marker *m;
 
341
        struct node *other;
 
342
        cell_t phandle;
 
343
 
 
344
        if (!streq(prop->name, "phandle")
 
345
            && !streq(prop->name, "linux,phandle"))
 
346
                return;
 
347
 
 
348
        if (prop->val.len != sizeof(cell_t)) {
 
349
                FAIL(c, "%s has bad length (%d) %s property",
 
350
                     node->fullpath, prop->val.len, prop->name);
 
351
                return;
 
352
        }
 
353
 
 
354
        m = prop->val.markers;
 
355
        for_each_marker_of_type(m, REF_PHANDLE) {
 
356
                assert(m->offset == 0);
 
357
                if (node != get_node_by_ref(root, m->ref))
 
358
                        /* "Set this node's phandle equal to some
 
359
                         * other node's phandle".  That's nonsensical
 
360
                         * by construction. */ {
 
361
                        FAIL(c, "%s in %s is a reference to another node",
 
362
                             prop->name, node->fullpath);
 
363
                        return;
 
364
                }
 
365
                /* But setting this node's phandle equal to its own
 
366
                 * phandle is allowed - that means allocate a unique
 
367
                 * phandle for this node, even if it's not otherwise
 
368
                 * referenced.  The value will be filled in later, so
 
369
                 * no further checking for now. */
 
370
                return;
 
371
        }
 
372
 
 
373
        phandle = propval_cell(prop);
 
374
 
 
375
        if ((phandle == 0) || (phandle == -1)) {
 
376
                FAIL(c, "%s has bad value (0x%x) in %s property",
 
377
                     node->fullpath, phandle, prop->name);
 
378
                return;
 
379
        }
 
380
 
 
381
        if (node->phandle && (node->phandle != phandle))
 
382
                FAIL(c, "%s has %s property which replaces existing phandle information",
 
383
                     node->fullpath, prop->name);
 
384
 
 
385
        other = get_node_by_phandle(root, phandle);
 
386
        if (other && (other != node)) {
 
387
                FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)",
 
388
                     node->fullpath, phandle, other->fullpath);
 
389
                return;
 
390
        }
 
391
 
 
392
        node->phandle = phandle;
 
393
}
 
394
PROP_CHECK(explicit_phandles, NULL, ERROR);
 
395
 
 
396
static void check_name_properties(struct check *c, struct node *root,
 
397
                                  struct node *node)
 
398
{
 
399
        struct property **pp, *prop = NULL;
 
400
 
 
401
        for (pp = &node->proplist; *pp; pp = &((*pp)->next))
 
402
                if (streq((*pp)->name, "name")) {
 
403
                        prop = *pp;
 
404
                        break;
 
405
                }
 
406
 
 
407
        if (!prop)
 
408
                return; /* No name property, that's fine */
 
409
 
 
410
        if ((prop->val.len != node->basenamelen+1)
 
411
            || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) {
 
412
                FAIL(c, "\"name\" property in %s is incorrect (\"%s\" instead"
 
413
                     " of base node name)", node->fullpath, prop->val.val);
 
414
        } else {
 
415
                /* The name property is correct, and therefore redundant.
 
416
                 * Delete it */
 
417
                *pp = prop->next;
 
418
                free(prop->name);
 
419
                data_free(prop->val);
 
420
                free(prop);
 
421
        }
 
422
}
 
423
CHECK_IS_STRING(name_is_string, "name", ERROR);
 
424
NODE_CHECK(name_properties, NULL, ERROR, &name_is_string);
 
425
 
 
426
/*
 
427
 * Reference fixup functions
 
428
 */
 
429
 
 
430
static void fixup_phandle_references(struct check *c, struct node *dt,
 
431
                                     struct node *node, struct property *prop)
 
432
{
 
433
        struct marker *m = prop->val.markers;
 
434
        struct node *refnode;
 
435
        cell_t phandle;
 
436
 
 
437
        for_each_marker_of_type(m, REF_PHANDLE) {
 
438
                assert(m->offset + sizeof(cell_t) <= prop->val.len);
 
439
 
 
440
                refnode = get_node_by_ref(dt, m->ref);
 
441
                if (! refnode) {
 
442
                        FAIL(c, "Reference to non-existent node or label \"%s\"\n",
 
443
                             m->ref);
 
444
                        continue;
 
445
                }
 
446
 
 
447
                phandle = get_node_phandle(dt, refnode);
 
448
                *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
 
449
        }
 
450
}
 
451
CHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR,
 
452
      &duplicate_node_names, &explicit_phandles);
 
453
 
 
454
static void fixup_path_references(struct check *c, struct node *dt,
 
455
                                  struct node *node, struct property *prop)
 
456
{
 
457
        struct marker *m = prop->val.markers;
 
458
        struct node *refnode;
 
459
        char *path;
 
460
 
 
461
        for_each_marker_of_type(m, REF_PATH) {
 
462
                assert(m->offset <= prop->val.len);
 
463
 
 
464
                refnode = get_node_by_ref(dt, m->ref);
 
465
                if (!refnode) {
 
466
                        FAIL(c, "Reference to non-existent node or label \"%s\"\n",
 
467
                             m->ref);
 
468
                        continue;
 
469
                }
 
470
 
 
471
                path = refnode->fullpath;
 
472
                prop->val = data_insert_at_marker(prop->val, m, path,
 
473
                                                  strlen(path) + 1);
 
474
        }
 
475
}
 
476
CHECK(path_references, NULL, NULL, fixup_path_references, NULL, ERROR,
 
477
      &duplicate_node_names);
 
478
 
 
479
/*
 
480
 * Semantic checks
 
481
 */
 
482
CHECK_IS_CELL(address_cells_is_cell, "#address-cells", WARN);
 
483
CHECK_IS_CELL(size_cells_is_cell, "#size-cells", WARN);
 
484
CHECK_IS_CELL(interrupt_cells_is_cell, "#interrupt-cells", WARN);
 
485
 
 
486
CHECK_IS_STRING(device_type_is_string, "device_type", WARN);
 
487
CHECK_IS_STRING(model_is_string, "model", WARN);
 
488
CHECK_IS_STRING(status_is_string, "status", WARN);
 
489
 
 
490
static void fixup_addr_size_cells(struct check *c, struct node *dt,
 
491
                                  struct node *node)
 
492
{
 
493
        struct property *prop;
 
494
 
 
495
        node->addr_cells = -1;
 
496
        node->size_cells = -1;
 
497
 
 
498
        prop = get_property(node, "#address-cells");
 
499
        if (prop)
 
500
                node->addr_cells = propval_cell(prop);
 
501
 
 
502
        prop = get_property(node, "#size-cells");
 
503
        if (prop)
 
504
                node->size_cells = propval_cell(prop);
 
505
}
 
506
CHECK(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, WARN,
 
507
      &address_cells_is_cell, &size_cells_is_cell);
 
508
 
 
509
#define node_addr_cells(n) \
 
510
        (((n)->addr_cells == -1) ? 2 : (n)->addr_cells)
 
511
#define node_size_cells(n) \
 
512
        (((n)->size_cells == -1) ? 1 : (n)->size_cells)
 
513
 
 
514
static void check_reg_format(struct check *c, struct node *dt,
 
515
                             struct node *node)
 
516
{
 
517
        struct property *prop;
 
518
        int addr_cells, size_cells, entrylen;
 
519
 
 
520
        prop = get_property(node, "reg");
 
521
        if (!prop)
 
522
                return; /* No "reg", that's fine */
 
523
 
 
524
        if (!node->parent) {
 
525
                FAIL(c, "Root node has a \"reg\" property");
 
526
                return;
 
527
        }
 
528
 
 
529
        if (prop->val.len == 0)
 
530
                FAIL(c, "\"reg\" property in %s is empty", node->fullpath);
 
531
 
 
532
        addr_cells = node_addr_cells(node->parent);
 
533
        size_cells = node_size_cells(node->parent);
 
534
        entrylen = (addr_cells + size_cells) * sizeof(cell_t);
 
535
 
 
536
        if ((prop->val.len % entrylen) != 0)
 
537
                FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) "
 
538
                     "(#address-cells == %d, #size-cells == %d)",
 
539
                     node->fullpath, prop->val.len, addr_cells, size_cells);
 
540
}
 
541
NODE_CHECK(reg_format, NULL, WARN, &addr_size_cells);
 
542
 
 
543
static void check_ranges_format(struct check *c, struct node *dt,
 
544
                                struct node *node)
 
545
{
 
546
        struct property *prop;
 
547
        int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen;
 
548
 
 
549
        prop = get_property(node, "ranges");
 
550
        if (!prop)
 
551
                return;
 
552
 
 
553
        if (!node->parent) {
 
554
                FAIL(c, "Root node has a \"ranges\" property");
 
555
                return;
 
556
        }
 
557
 
 
558
        p_addr_cells = node_addr_cells(node->parent);
 
559
        p_size_cells = node_size_cells(node->parent);
 
560
        c_addr_cells = node_addr_cells(node);
 
561
        c_size_cells = node_size_cells(node);
 
562
        entrylen = (p_addr_cells + c_addr_cells + c_size_cells) * sizeof(cell_t);
 
563
 
 
564
        if (prop->val.len == 0) {
 
565
                if (p_addr_cells != c_addr_cells)
 
566
                        FAIL(c, "%s has empty \"ranges\" property but its "
 
567
                             "#address-cells (%d) differs from %s (%d)",
 
568
                             node->fullpath, c_addr_cells, node->parent->fullpath,
 
569
                             p_addr_cells);
 
570
                if (p_size_cells != c_size_cells)
 
571
                        FAIL(c, "%s has empty \"ranges\" property but its "
 
572
                             "#size-cells (%d) differs from %s (%d)",
 
573
                             node->fullpath, c_size_cells, node->parent->fullpath,
 
574
                             p_size_cells);
 
575
        } else if ((prop->val.len % entrylen) != 0) {
 
576
                FAIL(c, "\"ranges\" property in %s has invalid length (%d bytes) "
 
577
                     "(parent #address-cells == %d, child #address-cells == %d, "
 
578
                     "#size-cells == %d)", node->fullpath, prop->val.len,
 
579
                     p_addr_cells, c_addr_cells, c_size_cells);
 
580
        }
 
581
}
 
582
NODE_CHECK(ranges_format, NULL, WARN, &addr_size_cells);
 
583
 
 
584
/*
 
585
 * Style checks
 
586
 */
 
587
static void check_avoid_default_addr_size(struct check *c, struct node *dt,
 
588
                                          struct node *node)
 
589
{
 
590
        struct property *reg, *ranges;
 
591
 
 
592
        if (!node->parent)
 
593
                return; /* Ignore root node */
 
594
 
 
595
        reg = get_property(node, "reg");
 
596
        ranges = get_property(node, "ranges");
 
597
 
 
598
        if (!reg && !ranges)
 
599
                return;
 
600
 
 
601
        if ((node->parent->addr_cells == -1))
 
602
                FAIL(c, "Relying on default #address-cells value for %s",
 
603
                     node->fullpath);
 
604
 
 
605
        if ((node->parent->size_cells == -1))
 
606
                FAIL(c, "Relying on default #size-cells value for %s",
 
607
                     node->fullpath);
 
608
}
 
609
NODE_CHECK(avoid_default_addr_size, NULL, WARN, &addr_size_cells);
 
610
 
 
611
static void check_obsolete_chosen_interrupt_controller(struct check *c,
 
612
                                                       struct node *dt)
 
613
{
 
614
        struct node *chosen;
 
615
        struct property *prop;
 
616
 
 
617
        chosen = get_node_by_path(dt, "/chosen");
 
618
        if (!chosen)
 
619
                return;
 
620
 
 
621
        prop = get_property(chosen, "interrupt-controller");
 
622
        if (prop)
 
623
                FAIL(c, "/chosen has obsolete \"interrupt-controller\" "
 
624
                     "property");
 
625
}
 
626
TREE_CHECK(obsolete_chosen_interrupt_controller, NULL, WARN);
 
627
 
 
628
static struct check *check_table[] = {
 
629
        &duplicate_node_names, &duplicate_property_names,
 
630
        &node_name_chars, &node_name_format, &property_name_chars,
 
631
        &name_is_string, &name_properties,
 
632
 
 
633
        &duplicate_label,
 
634
 
 
635
        &explicit_phandles,
 
636
        &phandle_references, &path_references,
 
637
 
 
638
        &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell,
 
639
        &device_type_is_string, &model_is_string, &status_is_string,
 
640
 
 
641
        &addr_size_cells, &reg_format, &ranges_format,
 
642
 
 
643
        &avoid_default_addr_size,
 
644
        &obsolete_chosen_interrupt_controller,
 
645
};
 
646
 
 
647
void process_checks(int force, struct boot_info *bi)
 
648
{
 
649
        struct node *dt = bi->dt;
 
650
        int i;
 
651
        int error = 0;
 
652
 
 
653
        for (i = 0; i < ARRAY_SIZE(check_table); i++) {
 
654
                struct check *c = check_table[i];
 
655
 
 
656
                if (c->level != IGNORE)
 
657
                        error = error || run_check(c, dt);
 
658
        }
 
659
 
 
660
        if (error) {
 
661
                if (!force) {
 
662
                        fprintf(stderr, "ERROR: Input tree has errors, aborting "
 
663
                                "(use -f to force output)\n");
 
664
                        exit(2);
 
665
                } else if (quiet < 3) {
 
666
                        fprintf(stderr, "Warning: Input tree has errors, "
 
667
                                "output forced\n");
 
668
                }
 
669
        }
 
670
}