fix dependency check logic cause config always disabled
[lunaix-os.git] / lunaix-os / hal / devtree / dt.c
1 #include <lunaix/mm/valloc.h>
2 #include <lunaix/syslog.h>
3 #include <lunaix/owloysius.h>
4
5 #include "devtree.h"
6
7 LOG_MODULE("dtb")
8
9 static morph_t* devtree_obj_root;
10 static struct dt_context dtctx;
11
12 void
13 fdt_load(struct fdt_blob* fdt, ptr_t base)
14 {
15     struct fdt_header* hdr;
16
17     fdt->fdt_base = base;
18
19     hdr = fdt->header;
20     if (hdr->magic != FDT_MAGIC) {
21         FATAL("invalid dtb, unexpected magic: 0x%x, expect: 0x%x", 
22                 hdr->magic, FDT_MAGIC);
23     }
24
25     fdt->plat_rsvd_base = base + hdr->off_mem_rsvmap;
26     fdt->str_block_base = base + hdr->off_dt_strings;
27     fdt->root.ptr       = base + hdr->off_dt_struct;
28 }
29
30 bool
31 fdt_next_boot_rsvdmem(struct fdt_blob* fdt, fdt_loc_t* loc, 
32                       struct dt_memory_node* mem)
33 {
34     fdt_loc_t current;
35
36     current = *loc;
37
38     if (!current.rsvd_ent->addr && !current.rsvd_ent->addr) {
39         return false;
40     }
41
42     mem->base = current.rsvd_ent->addr;
43     mem->size = current.rsvd_ent->size;
44     mem->type = FDT_MEM_RSVD;
45
46     current.rsvd_ent++;
47     *loc = current;
48
49     return true;
50 }
51
52 fdt_loc_t
53 fdt_next_token(fdt_loc_t loc, int* delta_depth)
54 {
55     int d = 0;
56
57     do {
58         if (fdt_node(loc.token)) {
59             d++;
60             loc.ptr += strlen(loc.node->name) + 1;
61             loc.ptr  = ROUNDUP(loc.ptr, sizeof(int));
62         }
63         else if (fdt_node_end(loc.token)) {
64             d--;
65         }
66         else if (fdt_prop(loc.token)) {
67             loc.ptr   += loc.prop->len + 2 * sizeof(int);
68             loc.ptr    = ROUNDUP(loc.ptr, sizeof(int));
69         }
70
71         loc.token++;
72     } while (fdt_nope(loc.token));
73
74     *delta_depth = d;
75     return loc;
76 }
77
78 bool
79 fdt_next_sibling(fdt_loc_t loc, fdt_loc_t* loc_out)
80 {
81     int depth = 0, new_depth = 0;
82
83     do {
84         loc = fdt_next_token(loc, &new_depth);
85         depth += new_depth;
86     } while (depth > 0);
87
88     *loc_out = loc;
89     return !fdt_node_end(loc.token);
90 }
91
92 fdt_loc_t
93 fdt_descend_into(fdt_loc_t loc) 
94 {
95     fdt_loc_t new_loc;
96     int depth = 0;
97
98     new_loc = fdt_next_token(loc, &depth);
99
100     return depth != 1 ? loc : new_loc;
101 }
102
103 bool
104 fdt_find_prop(const struct fdt_blob* fdt, fdt_loc_t loc, 
105               const char* name, struct dtp_val* val)
106 {
107     char* prop_name;
108
109     loc = fdt_descend_into(loc);
110
111     do
112     {
113         if (!fdt_prop(loc.token)) {
114             continue;
115         }
116
117         prop_name = fdt_prop_key(fdt, loc);
118         
119         if (!streq(prop_name, name)) {
120             continue;
121         }
122         
123         if (likely(val)) {
124             val->encoded = (dt_enc_t)__prop_val_ptr(loc.prop);
125             val->size    = loc.prop->len;
126         }
127         return true;
128         
129     } while (fdt_next_sibling(loc, &loc));
130
131     return false;
132 }
133
134 bool
135 fdt_memscan_begin(struct fdt_memscan* mscan, const struct fdt_blob* fdt)
136 {
137     struct dtp_val val;
138     fdt_loc_t loc;
139
140     loc  = fdt->root;
141     loc  = fdt_descend_into(loc);
142
143     if (fdt_find_prop(fdt, loc, "#address-cells", &val))
144     {
145         mscan->root_addr_c = val.ref->u32_val;
146     }
147
148     if (fdt_find_prop(fdt, loc, "#size-cells", &val))
149     {
150         mscan->root_size_c = val.ref->u32_val;
151     }
152
153     mscan->loc = loc;
154     mscan->node_type = FDT_MEM_FREE;
155
156     return true;
157 }
158
159 #define get_size(mscan, val)    \
160     (mscan->root_size_c == 1 ? (val)->ref->u32_val : (val)->ref->u64_val)
161
162 #define get_addr(mscan, val)    \
163     (mscan->root_addr_c == 1 ? (val)->ref->u32_val : (val)->ref->u64_val)
164
165 bool
166 fdt_memscan_nextnode(struct fdt_memscan* mscan, struct fdt_blob* fdt)
167 {
168     char* prop_name;
169
170     struct dtp_val val, reg_val;
171     fdt_loc_t loc, next;
172     struct dtpropi dtpi;
173     bool has_reg = false, found = false;
174
175     next = mscan->loc;
176
177 restart:
178     do
179     {
180         loc = next;
181         
182         if (!fdt_node(loc.token))
183             continue;
184
185         if (mscan->node_type != FDT_MEM_FREE) {
186             found = true;
187             continue;
188         }
189
190         if (streq(loc.node->name, "reserved-memory")) {
191             // dived into /reserved-memory, walking for childrens
192             mscan->node_type = FDT_MEM_RSVD;
193             loc = fdt_descend_into(loc);
194             continue;
195         }
196
197         if (!fdt_find_prop(fdt, loc, "device_type", &val))
198             continue;
199
200         if (!streq(val.str_val, "memory"))
201             continue;
202
203         found = true;
204     } while (fdt_next_sibling(loc, &next) && !found);
205
206     if (found) goto _found;
207
208     // emerged from /reserved-memory, resume walking for /memory
209     if (mscan->node_type != FDT_MEM_FREE) {
210         mscan->node_type = FDT_MEM_FREE;
211         goto restart;
212     }
213
214     return false;
215
216 _found:
217
218     dtpi_init_empty(&mscan->regit);
219     mscan->found = loc;
220     mscan->loc   = next;
221
222     has_reg = fdt_find_prop(fdt, loc, "reg", &val);
223     if (mscan->node_type == FDT_MEM_RSVD) {
224         goto do_rsvd_child;
225     }
226
227     if (!has_reg)
228     {
229         WARN("malformed memory node");
230         goto restart;
231     }
232
233     dtpi_init(&mscan->regit, &val);
234
235     return true;
236
237 do_rsvd_child:
238
239     mscan->node_attr.nomap = fdt_find_prop(fdt, loc, "no-map", NULL);
240     mscan->node_attr.reusable = fdt_find_prop(fdt, loc, "reusable", NULL);
241
242     if (has_reg)
243     {
244         dtpi_init(&mscan->regit, &val);
245         mscan->node_type = FDT_MEM_RSVD;
246         return true;
247     }
248     
249     if (!fdt_find_prop(fdt, loc, "size", &val)) 
250     {
251         WARN("malformed reserved memory child node");
252         goto restart;
253     }
254     
255     mscan->node_type = FDT_MEM_RSVD_DYNAMIC;
256     mscan->node_attr.total_size = get_size(mscan, &val);
257
258     if (fdt_find_prop(fdt, loc, "alignment", &val)) {
259         mscan->node_attr.alignment = get_size(mscan, &val);
260     }
261
262     if (fdt_find_prop(fdt, loc, "alloc-ranges", &val)) {
263         dtpi_init(&mscan->regit, &val);
264     }
265
266     return true;
267 }
268
269 bool
270 fdt_memscan_nextrange(struct fdt_memscan* mscan, struct dt_memory_node* mem)
271 {
272     struct dtp_val val;
273
274     if (dtpi_is_empty(&mscan->regit)) {
275         return false;
276     }
277
278     if (!dtpi_has_next(&mscan->regit)) {
279         return false;
280     }
281
282     if (dtpi_next_val(&mscan->regit, &val, mscan->root_addr_c)) {
283         mem->base = get_addr(mscan, &val);
284     }
285
286     if (dtpi_next_val(&mscan->regit, &val, mscan->root_size_c)) {
287         mem->size = get_size(mscan, &val);
288     }
289
290     mem->type = mscan->node_type;
291     
292     if (mem->type == FDT_MEM_RSVD_DYNAMIC) {
293         mem->dyn_alloc_attr = mscan->node_attr;
294     }
295
296     return true;
297 }
298
299 static bool
300 __parse_stdbase_prop(struct fdt_blob* fdt, fdt_loc_t loc, 
301                      struct dtn_base* node)
302 {
303     if (propeq(fdt, loc, "compatible")) {
304         __mkprop_ptr(loc, &node->compat);
305     } 
306
307     else if (propeq(fdt, loc, "phandle")) {
308         node->phandle = __prop_getu32(loc);
309     }
310     
311     else if (propeq(fdt, loc, "#address-cells")) {
312         node->addr_c = (char)__prop_getu32(loc);
313     } 
314     
315     else if (propeq(fdt, loc, "#size-cells")) {
316         node->sz_c = (char)__prop_getu32(loc);
317     } 
318     
319     else if (propeq(fdt, loc, "#interrupt-cells")) {
320         node->intr_c = (char)__prop_getu32(loc);
321     } 
322     
323     else if (propeq(fdt, loc, "status")) {
324         char peek = loc.prop->val_str[0];
325         if (peek == 'o') {
326             node->status = STATUS_OK;
327         }
328         else if (peek == 'r') {
329             node->status = STATUS_RSVD;
330         }
331         else if (peek == 'd') {
332             node->status = STATUS_DISABLE;
333         }
334         else if (peek == 'f') {
335             node->status = STATUS_FAIL;
336         }
337     }
338
339     else {
340         return false;
341     }
342
343     return true;
344 }
345
346 static bool
347 __parse_stdnode_prop(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn* node)
348 {
349     if (propeq(fdt, loc, "reg")) {
350         __mkprop_ptr(loc, &node->reg);
351     }
352
353     else if (propeq(fdt, loc, "ranges")) {
354         __mkprop_ptr(loc, &node->ranges);
355     }
356
357     else if (propeq(fdt, loc, "dma-ranges")) {
358         __mkprop_ptr(loc, &node->dma_ranges);
359     }
360
361     else {
362         return false;
363     }
364
365     return true;
366 }
367
368 static bool
369 __parse_stdflags(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn_base* node)
370 {
371     if (propeq(fdt, loc, "dma-coherent")) {
372         node->dma_coherent = true;
373     }
374
375     else if (propeq(fdt, loc, "dma-noncoherent")) {
376         node->dma_ncoherent = true;
377     }
378
379     else if (propeq(fdt, loc, "interrupt-controller")) {
380         node->intr_controll = true;
381     }
382
383     else {
384         return false;
385     }
386
387     return true;
388 }
389
390 static inline void
391 __dt_node_set_name(struct dtn* node, const char* name)
392 {
393     changeling_setname(&node->mobj, name);
394 }
395
396 static inline void
397 __init_prop_table(struct dtn_base* node)
398 {
399     struct dtp_table* propt;
400
401     propt = valloc(sizeof(*propt));
402     hashtable_init(propt->_op_bucket);
403
404     node->props = propt;
405 }
406
407 #define prop_table_add(node, prop)                                             \
408             hashtable_hash_in( (node)->props->_op_bucket,                      \
409                               &(prop)->ht, (prop)->key.hash);
410
411 static void
412 __parse_other_prop(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn_base* node)
413 {
414     struct dtp* prop;
415     const char* key;
416     unsigned int hash;
417
418     prop = valloc(sizeof(*prop));
419     key  = fdt_prop_key(fdt, loc);
420
421     prop->key = HSTR(key, strlen(key));
422     __mkprop_ptr(loc, &prop->val);
423
424     hstr_rehash(&prop->key, HSTR_FULL_HASH);
425
426     prop_table_add(node, prop);
427 }
428
429 static void
430 __fill_node(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn* node)
431 {
432     if (__parse_stdflags(fdt, loc, &node->base)) {
433         return;
434     }
435
436     if (__parse_stdbase_prop(fdt, loc, &node->base)) {
437         return;
438     }
439
440     if (__parse_stdnode_prop(fdt, loc, node)) {
441         return;
442     }
443
444     if (parse_stdintr_prop(fdt, loc, &node->intr)) {
445         return;
446     }
447
448     __parse_other_prop(fdt, loc, &node->base);
449 }
450
451 static inline void
452 __set_parent(struct dtn_base* parent, struct dtn_base* node)
453 {
454     morph_t* parent_obj;
455     
456     parent_obj   = devtree_obj_root;
457     node->parent = parent;
458     
459     if (parent) {
460         node->addr_c = parent->addr_c;
461         node->sz_c = parent->sz_c;
462         node->intr_c = parent->intr_c;
463         parent_obj = dt_mobj(parent);
464     }
465
466     changeling_attach(parent_obj, dt_mobj(node));
467 }
468
469 static inline void
470 __init_node_regular(struct dtn* node)
471 {
472     __init_prop_table(&node->base);
473     changeling_morph_anon(NULL, node->mobj, dt_morpher);
474  
475     node->intr.parent_hnd = PHND_NULL;
476 }
477
478 static void
479 __expand_extended_intr(struct dtn_intr* intrupt)
480 {
481     struct dtpropi it;
482     struct dtp_val  arr;
483     struct dtn *domain;
484     struct dtspec_intr* ispec;
485     int nr_intrs = 0;
486
487     if (!intrupt->extended) {
488         nr_intrs  = intrupt->raw_ispecs.size / sizeof(u32_t);
489         nr_intrs /= intrupt->parent->base.intr_c; 
490         goto done;
491     }
492
493     arr = intrupt->raw_ispecs;
494
495     llist_init_head(&intrupt->ext_ispecs);
496     
497     dtpi_init(&it, &arr);
498
499     while(dtpi_has_next(&it)) 
500     {
501         domain = dtpi_next_hnd(&it);
502
503         if (!domain) {
504             WARN("(intr_extended) malformed phandle");
505             continue;
506         }
507
508         ispec = valloc(sizeof(*ispec));
509         
510         ispec->domain = domain;
511         dtpi_next_val(&it, &ispec->val, domain->base.intr_c);
512
513         llist_append(&intrupt->ext_ispecs, &ispec->ispecs);
514         nr_intrs++;
515     };
516
517 done:
518     intrupt->nr_intrs = nr_intrs;
519 }
520
521 static void
522 __resolve_phnd_references()
523 {
524     struct dtn_base *pos, *n;
525     struct dtn *node, *parent, *default_parent;
526     struct dtn_intr* intrupt;
527     dt_phnd_t phnd;
528     
529     llist_for_each(pos, n, &dtctx.nodes, nodes)
530     {
531         node = dtn_from(pos);
532         intrupt = &node->intr;
533
534         if (intrupt->parent_hnd == PHND_NULL) {
535             continue;
536         }
537
538         phnd = intrupt->parent_hnd;
539         default_parent = (struct dtn*)node->base.parent;
540         parent = default_parent;
541
542         if (phnd != PHND_NULL) {
543             parent = dt_resolve_phandle(phnd);
544         }
545
546         if (!parent) {
547             WARN("dtb: (phnd_resolve) malformed phandle: %d", phnd);
548             parent = default_parent;
549         }
550
551         intrupt->parent = parent;
552
553         __expand_extended_intr(intrupt);
554     }
555 }
556
557 static void
558 __resolve_inter_map()
559 {
560     struct dtn_base *pos, *n;
561
562     llist_for_each(pos, n, &dtctx.nodes, nodes)
563     {
564         dt_resolve_interrupt_map(dtn_from(pos));
565     }
566 }
567
568 bool
569 dt_load(ptr_t dtb_dropoff)
570 {
571     llist_init_head(&dtctx.nodes);
572     hashtable_init(dtctx.phnds_table);
573
574     struct fdt_blob *fdt;
575     struct dtn      *node,
576                     *stack[16] = { NULL };
577     
578     int depth = 0, delta = 0, nr_nodes = 0;
579     fdt_loc_t  loc, next_loc;
580
581     fdt = &dtctx.fdt;
582     fdt_load(&dtctx.fdt, dtb_dropoff);
583
584     loc = fdt->root;
585     
586     while (!fdt_eof(loc.token)) 
587     {
588         next_loc = fdt_next_token(loc, &delta);
589
590         if (depth >= 16) {
591             // tree too deep
592             ERROR("strange dtb, too deep to dive.");
593             return false;
594         }
595
596         assert(depth >= 0);
597         node = stack[depth];
598
599         if (fdt_node(loc.token))
600         {
601             assert(!node);
602
603             node = vzalloc(sizeof(struct dtn));
604             __init_node_regular(node);
605             llist_append(&dtctx.nodes, &node->base.nodes);
606
607             __dt_node_set_name(node, loc.node->name);
608
609             if (depth) {
610                 __set_parent(&stack[depth - 1]->base, &node->base);
611             }
612
613             nr_nodes++;
614             stack[depth] = node;
615         }
616
617         else if (depth > 1 && fdt_node_end(loc.token))
618         {
619             stack[depth - 1] = NULL;
620         }
621
622         else if (fdt_prop(loc.token))
623         {
624             node = stack[depth - 1];
625
626             assert(depth && node);
627             __fill_node(fdt, loc, node);
628         }
629
630         depth += delta;
631         loc = next_loc;
632     }
633
634     dtctx.root = stack[0];
635
636     __resolve_phnd_references();
637     __resolve_inter_map();
638
639     INFO("%d nodes loaded.", nr_nodes);
640
641     return true;
642 }
643
644 struct dtn*
645 dt_resolve_phandle(dt_phnd_t phandle)
646 {
647     struct dtn_base *pos, *n;
648     llist_for_each(pos, n, &dtctx.nodes, nodes)
649     {
650         if (pos->phandle == phandle) {
651             return (struct dtn*)pos;
652         }
653     }
654
655     return NULL;
656 }
657
658 static bool
659 __byname_predicate(struct dtn_iter* iter, struct dtn_base* node)
660 {
661     int i = 0;
662     const char* be_matched = HSTR_VAL(node->mobj.name);
663     const char* name = (const char*)iter->closure;
664
665     while (be_matched[i] && name[i])
666     {
667         if (be_matched[i] != name[i]) {
668             return false;
669         }
670
671         i++;
672     }
673
674     return true;
675 }
676
677 void
678 dt_begin_find_byname(struct dtn_iter* iter, 
679               struct dtn* node, const char* name)
680 {
681     dt_begin_find(iter, node, __byname_predicate, name);
682 }
683
684 void
685 dt_begin_find(struct dtn_iter* iter, struct dtn* node, 
686               node_predicate_t pred, void* closure)
687 {
688     node = node ? : (struct dtn*)dtctx.root;
689
690     iter->head = &node->base;
691     iter->matched = NULL;
692     iter->closure = closure;
693     iter->pred = pred;
694
695     morph_t *pos, *n;
696     struct dtn_base* base;
697     changeling_for_each(pos, n, &node->mobj)
698     {
699         base = &changeling_reveal(pos, dt_morpher)->base;
700         if (pred(iter, base)) {
701             iter->matched = base;
702             break;
703         }
704     }
705 }
706
707 bool
708 dt_find_next(struct dtn_iter* iter,
709              struct dtn_base** matched)
710 {
711     if (!dt_found_any(iter)) {
712         return false;
713     }
714
715     struct dtn *node;
716     morph_t *pos, *head;
717
718     head = dt_mobj(iter->head);
719     pos  = dt_mobj(iter->matched);
720     *matched = iter->matched;
721
722     while (&pos->sibs != &head->subs)
723     {
724         pos = list_next(pos, morph_t, sibs);
725         node = changeling_reveal(pos, dt_morpher);
726
727         if (!iter->pred(iter, &node->base)) {
728             continue;
729         }
730
731         iter->matched = &node->base;
732         return true;
733     }
734
735     return false;
736 }
737
738 struct dtp_val*
739 dt_getprop(struct dtn_base* base, const char* name)
740 {
741     struct hstr hashed_name;
742     struct dtp *pos, *n;
743     unsigned int hash;
744
745     hashed_name = HSTR(name, strlen(name));
746     hstr_rehash(&hashed_name, HSTR_FULL_HASH);
747     hash = hashed_name.hash;
748
749     hashtable_hash_foreach(base->props->_op_bucket, hash, pos, n, ht)
750     {
751         if (HSTR_EQ(&pos->key, &hashed_name)) {
752             return &pos->val;
753         }
754     }
755
756     return NULL;
757 }
758
759 void
760 dtpx_compile_proplet(struct dtprop_def* proplet)
761 {
762     int i;
763     unsigned int acc = 0;
764     
765     for (i = 0; proplet[i].type && i < 10; ++i)
766     {
767         proplet[i].acc_sz = acc;
768         acc += proplet[i].cell;
769     }
770
771     if (proplet[i - 1].type && i == 10) {
772         FATAL("invalid proplet: no terminator detected");
773     }
774
775     proplet[i].acc_sz = acc;
776 }
777
778 void
779 dtpx_prepare_with(struct dtpropx* propx, struct dtp_val* prop,
780                   struct dtprop_def* proplet)
781 {
782     int i;
783     bool has_str = false;
784     
785     for (i = 0; proplet[i].type; ++i);
786
787     propx->proplet = proplet;
788     propx->proplet_len = i;
789     propx->proplet_sz = proplet[i].acc_sz;
790     propx->raw = prop;
791     propx->row_loc = 0;
792 }
793
794 bool
795 dtpx_goto_row(struct dtpropx* propx, int row)
796 {
797     off_t loc;
798
799     loc  = propx->proplet_sz;
800     loc *= row;
801
802     if (loc * sizeof(u32_t) >= propx->raw->size) {
803         return false;
804     }
805
806     propx->row_loc = loc;
807     return true;
808 }
809
810 bool
811 dtpx_next_row(struct dtpropx* propx)
812 {
813     off_t loc;
814
815     loc  = propx->row_loc;
816     loc += propx->proplet_sz;
817
818     if (loc * sizeof(u32_t) >= propx->raw->size) {
819         return false;
820     }
821
822     propx->row_loc = loc;
823     return true;
824 }
825
826 bool
827 dtpx_extract_at(struct dtpropx* propx, 
828                 struct dtprop_xval* val, int col)
829 {
830     struct dtprop_def* def;
831     union dtp_baseval* raw;
832     dt_enc_t enc;
833
834     if (unlikely(col >= propx->proplet_len)) {
835         return false;
836     }
837
838     def = &propx->proplet[col];
839     enc = &propx->raw->encoded[propx->row_loc + def->acc_sz];
840     raw = (union dtp_baseval*)enc;
841
842     val->archetype = def;
843
844     switch (def->type)
845     {
846         case DTP_U32:
847             val->u32 = raw->u32_val;
848             break;
849
850         case DTP_U64:
851             val->u64 = raw->u64_val;
852             break;
853
854         case DTP_PHANDLE:
855         {
856             ptr_t hnd = raw->phandle;
857             val->phandle = dt_resolve_phandle(hnd);
858         } break;
859
860         case DTP_COMPX:
861             val->composite = enc;
862             break;
863         
864         default:
865             break;
866     }
867
868     return true;
869 }
870
871 bool
872 dtpx_extract_loc(struct dtpropx* propx, 
873                  struct dtprop_xval* val, int row, int col)
874 {
875     ptr_t loc = propx->row_loc;
876
877     if (!dtpx_goto_row(propx, row))
878         return false;
879
880     
881     bool r = dtpx_extract_at(propx, val, col);
882     propx->row_loc = loc;
883     return r;
884 }
885
886 bool
887 dtpx_extract_row(struct dtpropx* propx, struct dtprop_xval* vals, int len)
888 {
889     assert(len == propx->proplet_len);
890
891     for (int i = 0; i < len; i++)
892     {
893         if (!dtpx_extract_at(propx, &vals[i], i)) {
894             return false;
895         }
896     }
897     
898     return true;
899 }
900
901 struct dt_context*
902 dt_main_context()
903 {
904     return &dtctx;
905 }
906
907 static void
908 __init_devtree()
909 {
910     devtree_obj_root = changeling_spawn(NULL, NULL);
911 }
912 owloysius_fetch_init(__init_devtree, on_sysconf);