From a2e1b0681f3f65975cb3ed2f4f9708ac8f9ff070 Mon Sep 17 00:00:00 2001 From: Lunaixsky Date: Wed, 9 Oct 2024 17:40:09 +0100 Subject: [PATCH] rework parsing of interupt-map in interrupt node. * parsing of the interrupt-map has been re-worked to accommodate the dynamic-nature of each map entry for which the length is depends on not only the current interrupt nexus but also the interrupt parent it referenced. --- lunaix-os/hal/devtree/devtree.h | 9 + lunaix-os/hal/{devtree.c => devtree/dt.c} | 115 ++++++------ lunaix-os/hal/devtree/dt_interrupt.c | 215 ++++++++++++++++++++++ lunaix-os/includes/hal/devtree.h | 151 ++++++++------- 4 files changed, 366 insertions(+), 124 deletions(-) create mode 100644 lunaix-os/hal/devtree/devtree.h rename lunaix-os/hal/{devtree.c => devtree/dt.c} (90%) create mode 100644 lunaix-os/hal/devtree/dt_interrupt.c diff --git a/lunaix-os/hal/devtree/devtree.h b/lunaix-os/hal/devtree/devtree.h new file mode 100644 index 0000000..3b1df08 --- /dev/null +++ b/lunaix-os/hal/devtree/devtree.h @@ -0,0 +1,9 @@ +#ifndef __LUNAIX_DEVTREE_INTERNAL_H +#define __LUNAIX_DEVTREE_INTERNAL_H + +#include + +bool +parse_stdintr_prop(struct fdt_iter* it, struct dt_intr_node* node); + +#endif /* __LUNAIX_DEVTREE_H */ diff --git a/lunaix-os/hal/devtree.c b/lunaix-os/hal/devtree/dt.c similarity index 90% rename from lunaix-os/hal/devtree.c rename to lunaix-os/hal/devtree/dt.c index 81712ec..7be880b 100644 --- a/lunaix-os/hal/devtree.c +++ b/lunaix-os/hal/devtree/dt.c @@ -3,7 +3,7 @@ #include -#include +#include "devtree.h" LOG_MODULE("dtb") @@ -241,37 +241,6 @@ __parse_stdnode_prop(struct fdt_iter* it, struct dt_node* node) return true; } -static bool -__parse_stdintr_prop(struct fdt_iter* it, struct dt_intr_node* node) -{ - if (propeq(it, "interrupt-map")) { - __mkprop_ptr(it, &node->intr_map); - } - - else if (propeq(it, "interrupt-map-mask")) { - __mkprop_ptr(it, &node->intr_map_mask); - } - - else if (propeq(it, "interrupt-parent")) { - node->parent_hnd = __prop_getu32(it); - } - - else if (propeq(it, "interrupt-extended")) { - node->intr.extended = true; - __mkprop_ptr(it, &node->intr.arr); - } - - else if (!node->intr.extended && propeq(it, "interrupts")) { - __mkprop_ptr(it, &node->intr.arr); - } - - else { - return false; - } - - return true; -} - static bool __parse_stdflags(struct fdt_iter* it, struct dt_node_base* node) { @@ -365,6 +334,9 @@ __init_node(struct dt_node_base* node) { hashtable_init(node->_op_bucket); llist_init_head(&node->children); + + if (node->parent) + node->_std = node->parent->_std; } static inline void @@ -388,14 +360,14 @@ __expand_extended_intr(struct dt_intr_node* intrupt) } arr = intrupt->intr.arr; - node = DT_NODE(intrupt); + node = INTR_TO_DTNODE(intrupt); llist_init_head(&intrupt->intr.values); dt_decode(&it, &node->base, &arr, 1); dt_phnd_t phnd; - while(dtprop_next(&it)) { + do { phnd = dtprop_to_u32(it.prop_loc); master = dt_resolve_phandle(phnd); @@ -414,7 +386,8 @@ __expand_extended_intr(struct dt_intr_node* intrupt) llist_append(&intrupt->intr.values, &intr_prop->props); dtprop_next_n(&it, intr_prop->val.size); - } + + } while(dtprop_next(&it)); } static void @@ -427,8 +400,9 @@ __resolve_phnd_references() llist_for_each(pos, n, &dtctx.nodes, nodes) { - node = (struct dt_node*)pos; + node = BASE_TO_DTNODE(pos); intrupt = &node->intr; + if (!node->base.intr_c) { continue; } @@ -452,6 +426,17 @@ __resolve_phnd_references() } } +static void +__resolve_inter_map() +{ + struct dt_node_base *pos, *n; + + llist_for_each(pos, n, &dtctx.nodes, nodes) + { + resolve_interrupt_map(BASE_TO_DTNODE(pos)); + } +} + bool dt_load(ptr_t dtb_dropoff) { @@ -494,16 +479,16 @@ dt_load(ptr_t dtb_dropoff) if (!node) { // need new node if (unlikely(is_root_level)) { - node = valloc(sizeof(struct dt_root)); + node = vzalloc(sizeof(struct dt_root)); __init_node(node); } else { - node = valloc(sizeof(struct dt_node)); + node = vzalloc(sizeof(struct dt_node)); prev = depth[it.depth - 2]; + node->parent = prev; __init_node_regular((struct dt_node*)node); llist_append(&prev->children, &node->siblings); - node->parent = prev; llist_append(&dtctx.nodes, &node->nodes); } @@ -524,54 +509,68 @@ dt_load(ptr_t dtb_dropoff) dtctx.root = (struct dt_root*)depth[0]; __resolve_phnd_references(); + __resolve_inter_map(); + + INFO("device tree loaded"); return true; } +struct dt_node* +dt_resolve_phandle(dt_phnd_t phandle) +{ + struct dt_node_base *pos, *n; + hashtable_hash_foreach(dtctx.phnds_table, phandle, pos, n, phnd_link) + { + if (pos->phandle == phandle) { + return (struct dt_node*)pos; + } + } + + return NULL; +} + static bool -__name_starts_with(struct dt_node_base* node, const char* name) +__byname_predicate(struct dt_node_iter* iter, struct dt_node_base* node) { int i = 0; const char* be_matched = node->name; + const char* name = (const char*)iter->closure; while (be_matched[i] && name[i]) { if (be_matched[i] != name[i]) { return false; } + + i++; } return true; } -struct dt_node* -dt_resolve_phandle(dt_phnd_t phandle) +void +dt_begin_find_byname(struct dt_node_iter* iter, + struct dt_node* node, const char* name) { - struct dt_node_base *pos, *n; - hashtable_hash_foreach(dtctx.phnds_table, phandle, pos, n, phnd_link) - { - if (pos->phandle == phandle) { - return (struct dt_node*)pos; - } - } - - return NULL; + dt_begin_find(iter, node, __byname_predicate, name); } void -dt_begin_find(struct dt_node_iter* iter, - struct dt_node* node, const char* name) +dt_begin_find(struct dt_node_iter* iter, struct dt_node* node, + node_predicate_t pred, void* closure) { node = node ? : (struct dt_node*)dtctx.root; iter->head = &node->base; iter->matched = NULL; - iter->name = name; + iter->closure = closure; + iter->pred = pred; struct dt_node_base *pos, *n; llist_for_each(pos, n, &node->base.children, siblings) { - if (__name_starts_with(pos, name)) { + if (pred(iter, pos)) { iter->matched = pos; break; } @@ -596,7 +595,7 @@ dt_find_next(struct dt_node_iter* iter, { pos = list_next(pos, struct dt_node_base, siblings); - if (!__name_starts_with(pos, iter->name)) { + if (!iter->pred(iter, pos)) { continue; } @@ -608,7 +607,7 @@ dt_find_next(struct dt_node_iter* iter, } struct dt_prop_val* -dt_getprop(struct dt_node* node, const char* name) +dt_getprop(struct dt_node_base* base, const char* name) { struct hstr hashed_name; struct dt_prop *pos, *n; @@ -618,7 +617,7 @@ dt_getprop(struct dt_node* node, const char* name) hstr_rehash(&hashed_name, HSTR_FULL_HASH); hash = hashed_name.hash; - hashtable_hash_foreach(node->base._op_bucket, hash, pos, n, ht) + hashtable_hash_foreach(base->_op_bucket, hash, pos, n, ht) { if (HSTR_EQ(&pos->key, &hashed_name)) { return &pos->val; diff --git a/lunaix-os/hal/devtree/dt_interrupt.c b/lunaix-os/hal/devtree/dt_interrupt.c new file mode 100644 index 0000000..d2db72d --- /dev/null +++ b/lunaix-os/hal/devtree/dt_interrupt.c @@ -0,0 +1,215 @@ +#include "devtree.h" + +#include + +#include + +static struct dt_intr_map* +__get_map(struct dt_intr_node* node) +{ + if (!node->map) { + node->map = valloc(sizeof(struct dt_intr_map)); + + node->map->resolved = false; + llist_init_head(&node->map->mapent); + + INTR_TO_DTNODE(node)->base.intr_neuxs = true; + } + + return node->map; +} + +static void +__prepare_key(struct dt_intr_mapkey* key, + dt_enc_t key_raw, unsigned int keylen) +{ + *key = (struct dt_intr_mapkey) { + .val = valloc(keylen * sizeof(int)), + .size = keylen + }; + + memcpy(key->val, key_raw, keylen * sizeof(int)); +} + +static inline void +__destory_key(struct dt_intr_mapkey* key) +{ + vfree(key->val); +} + +static inline unsigned int +__interrupt_keysize(struct dt_node_base* base) +{ + return base->addr_c + base->intr_c; +} + +static void +__mask_key(struct dt_intr_mapkey* k, struct dt_intr_mapkey* mask) +{ + for (int i = 0; i < k->size; i++) + { + k->val[i] &= mask->val[i]; + } +} + +static bool +__compare_key(struct dt_intr_mapkey* k1, struct dt_intr_mapkey* k2) +{ + if (k1->size != k2->size) { + return false; + } + + for (int i = 0; i < k1->size; i++) + { + if (k1->val[i] != k2->val[i]) { + return false; + } + } + + return true; +} + +static struct dt_node_base* +__get_connected_nexus(struct dt_node_base* base) +{ + struct dt_node_base* current; + + current = base; + while (current && !current->intr_neuxs) { + current = current->parent; + } + + return current; +} + +void +resolve_interrupt_map(struct dt_node* node) +{ + struct dt_intr_node* inode; + struct dt_intr_map* imap; + struct dt_prop_iter iter; + + struct dt_intr_mapent *ent; + + unsigned int keysize, parent_keysize; + unsigned int advance; + dt_phnd_t parent_hnd; + + inode = &node->intr; + if (likely(!inode->map)) { + return; + } + + imap = inode->map; + keysize = __interrupt_keysize(&node->base); + + __prepare_key(&imap->key_mask, imap->raw_mask.encoded, keysize); + + dt_decode(&iter, &node->base, &imap->raw, 1); + + advance = 0; + do + { + advance = keysize; + ent = valloc(sizeof(*ent)); + + __prepare_key(&ent->key, iter.prop_loc, advance); + __mask_key(&ent->key, &imap->key_mask); + + parent_hnd = dtprop_to_phnd(dtprop_extract(&iter, advance)); + ent->parent = &dt_resolve_phandle(parent_hnd)->base; + + advance++; + parent_keysize = __interrupt_keysize(ent->parent); + + ent->parent_props.encoded = dtprop_extract(&iter, advance); + ent->parent_props.size = parent_keysize; + + advance += parent_keysize; + + llist_append(&imap->mapent, &ent->ents); + + } while (dtprop_next_n(&iter, advance)); + + imap->resolved = true; +} + +struct dt_prop_val* +resolve_interrupt(struct dt_node* node) +{ + struct dt_node_base* nexus; + struct dt_intr_node* i_nexus, *i_node; + struct dt_intr_mapkey key; + unsigned int keylen; + + if (!node->intr.intr.valid) { + return NULL; + } + + nexus = __get_connected_nexus(&node->base); + i_nexus = &BASE_TO_DTNODE(nexus)->intr; + i_node = &node->intr; + + if (!nexus) { + return &i_node->intr.arr; + } + + keylen = nexus->addr_c + nexus->intr_c; + key = (struct dt_intr_mapkey) { + .val = valloc(keylen * sizeof(int)), + .size = keylen + }; + + memcpy( key.val, + node->reg.encoded, nexus->addr_c * sizeof(int)); + + memcpy(&key.val[nexus->addr_c], + i_node->intr.arr.encoded, nexus->intr_c * sizeof(int)); + + __mask_key(&key, &i_nexus->map->key_mask); + + struct dt_intr_mapent *pos, *n; + + llist_for_each(pos, n, &i_nexus->map->mapent, ents) { + if (__compare_key(&pos->key, &key)) + { + return &pos->parent_props; + } + } +} + +bool +parse_stdintr_prop(struct fdt_iter* it, struct dt_intr_node* node) +{ + struct dt_intr_map* map; + + if (propeq(it, "interrupt-map")) { + map = __get_map(node); + __mkprop_ptr(it, &map->raw); + } + + else if (propeq(it, "interrupt-map-mask")) { + map = __get_map(node); + __mkprop_ptr(it, &map->raw_mask); + } + + else if (propeq(it, "interrupt-parent")) { + node->parent_hnd = __prop_getu32(it); + } + + else if (propeq(it, "interrupt-extended")) { + node->intr.extended = true; + __mkprop_ptr(it, &node->intr.arr); + } + + else if (!node->intr.extended && propeq(it, "interrupts")) { + node->intr.valid = true; + __mkprop_ptr(it, &node->intr.arr); + } + + else { + return false; + } + + return true; +} \ No newline at end of file diff --git a/lunaix-os/includes/hal/devtree.h b/lunaix-os/includes/hal/devtree.h index 0a132da..5203d1a 100644 --- a/lunaix-os/includes/hal/devtree.h +++ b/lunaix-os/includes/hal/devtree.h @@ -34,6 +34,8 @@ typedef unsigned int* dt_enc_t; typedef unsigned int dt_phnd_t; +typedef bool (*node_predicate_t)(struct dt_node_iter*, struct dt_node*); + #define PHND_NULL ((dt_phnd_t)-1) @@ -122,6 +124,7 @@ struct dt_node_base bool dma_coherent : 1; bool dma_ncoherent : 1; bool intr_controll : 1; + bool intr_neuxs : 1; unsigned int other : 29; }; unsigned int flags; @@ -143,6 +146,8 @@ struct dt_node_base struct hbucket other_props[0]; struct hbucket _op_bucket[8]; }; + + void* obj; }; struct dt_root @@ -155,6 +160,33 @@ struct dt_root struct dt_intr_prop; +struct dt_intr_mapkey +{ + unsigned int* val; + unsigned int size; +}; + +struct dt_intr_mapent +{ + struct llist_header ents; + + struct dt_intr_mapkey key; + + struct dt_node_base* parent; + struct dt_prop_val parent_props; +}; + +struct dt_intr_map +{ + struct dt_prop_val raw; + struct dt_prop_val raw_mask; + + struct dt_intr_mapkey key_mask; + struct llist_header mapent; + + bool resolved; +}; + struct dt_intr_node { union { @@ -164,18 +196,20 @@ struct dt_intr_node struct { bool extended; + bool valid; union { struct dt_prop_val arr; struct llist_header values; }; } intr; - struct dt_prop_val intr_map; - struct dt_prop_val intr_map_mask; + struct dt_intr_map* map; }; -#define DT_NODE(intr_node) \ +#define INTR_TO_DTNODE(intr_node) \ (container_of(intr_node, struct dt_node, intr)) +#define BASE_TO_DTNODE(base_node) \ + (container_of(base_node, struct dt_node, base)) struct dt_node { @@ -241,7 +275,8 @@ struct dt_node_iter { struct dt_node_base* head; struct dt_node_base* matched; - const char *name; + void* closure; + node_predicate_t pred; }; #define dtnode_child_foreach(node_base, pos, n) \ @@ -282,11 +317,27 @@ struct dt_node* dt_resolve_phandle(dt_phnd_t phandle); struct dt_prop_val* -dt_getprop(struct dt_node* node, const char* name); +dt_getprop(struct dt_node_base* base, const char* name); + +void +dt_begin_find_byname(struct dt_node_iter* iter, + struct dt_node* node, const char* name); + +void +dt_begin_find(struct dt_node_iter* iter, struct dt_node* node, + node_predicate_t pred, void* closure); + +struct dt_prop_val* +resolve_interrupt(struct dt_node* node); void -dt_begin_find(struct dt_node_iter* iter, - struct dt_node* node, const char* name); +resolve_interrupt_map(struct dt_node* node); + +static inline void +dt_end_find(struct dt_node_iter* iter) +{ + // currently do nothing, keep only for semantic +} bool dt_find_next(struct dt_node_iter* iter, @@ -299,6 +350,21 @@ dt_found_any(struct dt_node_iter* iter) } +static inline void +dt_bind_object(struct dt_node_base* base, void* obj) +{ + base->obj = obj; +} + +static inline bool +dt_has_binding(struct dt_node_base* base) +{ + return base->obj != NULL; +} + +#define dt_binding_of(node_base, type) \ + ((type)(node_base)->obj) + static inline char* fdtit_prop_key(struct fdt_iter* fdti) { @@ -326,21 +392,6 @@ dt_decode(struct dt_prop_iter* dtpi, struct dt_node_base* node, dt_decode(dtpi, &(node)->base, &(node)->field, \ (node)->base.sz_c * 2 + (node)->base.addr_c); -static inline void -dt_decode_intrmap(struct dt_prop_iter* dtpi, - struct dt_intr_node* intr_node) -{ - unsigned int size; - struct dt_node* node; - struct dt_node_base* base; - - node = DT_NODE(intr_node); - base = &node->base; - size = (base->addr_c + base->intr_c) * 2 + 1; - - dt_decode(dtpi, base, &intr_node->intr_map, size); -} - #define dtprop_off(dtpi) \ (unsigned int)(\ __ptr(dtpi->prop_loc_next) - __ptr(dtpi->prop->encoded) \ @@ -404,6 +455,18 @@ dtprop_to_u64(dt_enc_t enc_val) return le64(*(u64_t*)enc_val); } +static inline u32_t +dtprop_u32_at(struct dt_prop_iter* dtpi, int index) +{ + return dtprop_to_u32(dtprop_extract(dtpi, index)); +} + +static inline u32_t +dtprop_u64_at(struct dt_prop_iter* dtpi, int index) +{ + return dtprop_to_u64(dtprop_extract(dtpi, index)); +} + static inline dt_enc_t dtprop_reg_addr(struct dt_prop_iter* dtpi) { @@ -456,48 +519,4 @@ dtprop_range_len(struct dt_prop_iter* dtpi) return dtprop_extract(dtpi, dtpi->node->addr_c * 2); } -static inline dt_enc_t -dtprop_intr_cuaddr(struct dt_prop_iter* dtpi) -{ - return dtprop_extract(dtpi, 0); -} - -static inline dt_enc_t -dtprop_intr_cispec(struct dt_prop_iter* dtpi) -{ - return dtprop_extract(dtpi, dtpi->node->addr_c); -} - -static inline struct dt_intr_node* -dtprop_intr_parent(struct dt_prop_iter* dtpi) -{ - unsigned off; - struct dt_node* node; - dt_enc_t enc_val; - - off = dtpi->node->addr_c + dtpi->node->intr_c; - enc_val = dtprop_extract(dtpi, off); - node = dt_resolve_phandle(dtprop_to_phnd(enc_val)); - - return &node->intr; -} - -static inline dt_enc_t -dtprop_intr_puaddr(struct dt_prop_iter* dtpi) -{ - unsigned off; - - off = dtpi->node->addr_c + dtpi->node->intr_c + 1; - return dtprop_extract(dtpi, off); -} - -static inline dt_enc_t -dtprop_intr_pispec(struct dt_prop_iter* dtpi) -{ - unsigned off; - - off = dtpi->node->addr_c * 2 + dtpi->node->intr_c + 1; - return dtprop_extract(dtpi, off); -} - #endif /* __LUNAIX_DEVTREE_H */ -- 2.27.0