X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/35a7d633d3f16c1e0539af6ca5d8e7482926cd93..9daf4fcdae88f72af60aeb0c7722841af02233d4:/lunaix-os/hal/devtree/dt_interrupt.c diff --git a/lunaix-os/hal/devtree/dt_interrupt.c b/lunaix-os/hal/devtree/dt_interrupt.c index ab4d8b3..905eb02 100644 --- a/lunaix-os/hal/devtree/dt_interrupt.c +++ b/lunaix-os/hal/devtree/dt_interrupt.c @@ -1,219 +1,93 @@ #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) +static int +__ispec_sz(struct dtn* node) { - *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); + return node->base.intr_c + node->base.addr_c; } -static inline unsigned int -__interrupt_keysize(struct dt_node_base* base) +static struct dtp_val* +__ispec_mask(struct dtn* node) { - return dt_size_cells(base) + base->intr_c; -} - -static void -__mask_key(struct dt_intr_mapkey* k, struct dt_intr_mapkey* mask) -{ - for (unsigned 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 (unsigned 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; + return dt_getprop(&node->base, "interrupt-map-mask"); } void -dt_resolve_interrupt_map(struct dt_node* node) +dt_resolve_interrupt_map(struct dtn* 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; + struct dtp_val* map; + struct dtspec_create_ops ops = {}; - inode = &node->intr; - if (likely(!inode->map)) { + ops.child_keysz = __ispec_sz; + ops.parent_keysz = __ispec_sz; + ops.get_mask = __ispec_mask; + + map = dt_getprop(&node->base, "interrupt-map"); + if (likely(!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; + node->intr.map = dtspec_create(node, map, &ops); } -struct dt_prop_val* -dt_resolve_interrupt(struct dt_node* node) +struct dtn* +dt_interrupt_at(struct dtn* node, int idx, struct dtp_val* int_spec) { - struct dt_node_base* nexus; - struct dt_intr_node* i_nexus, *i_node; - struct dt_intr_mapkey key; - unsigned int keylen; + int int_cells; + dt_enc_t raw_specs; + struct dtn_intr* intr; + struct dtn* intr_domain; - if (!node->intr.intr.valid) { + intr = &node->intr; + if (!intr->valid || idx >= intr->nr_intrs) { 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 = __interrupt_keysize(nexus); - key = (struct dt_intr_mapkey) { - .val = valloc(keylen * sizeof(int)), - .size = keylen - }; - - memcpy( key.val, - node->reg.encoded, dt_addr_cells(nexus) * sizeof(int)); - memcpy(&key.val[dt_addr_cells(nexus)], - i_node->intr.arr.encoded, nexus->intr_c * sizeof(int)); - - __mask_key(&key, &i_nexus->map->key_mask); + if (!intr->extended) { + intr_domain = intr->parent; + int_cells = intr_domain->base.intr_c; + + raw_specs = &intr->raw_ispecs.encoded[int_cells * idx]; + dtp_val_set(int_spec, raw_specs, int_cells); - struct dt_intr_mapent *pos, *n; + return intr_domain; + } - llist_for_each(pos, n, &i_nexus->map->mapent, ents) { - if (__compare_key(&pos->key, &key)) - { - __destory_key(&key); - return &pos->parent_props; + struct dtspec_intr *p, *n; + llist_for_each(p, n, &intr->ext_ispecs, ispecs) + { + if (!(idx--)) { + *int_spec = p->val; + return p->domain; } } - __destory_key(&key); return NULL; } bool -parse_stdintr_prop(struct fdt_iter* it, struct dt_intr_node* node) +parse_stdintr_prop(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn_intr* 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); + if (propeq(fdt, loc, "interrupt-parent")) { + node->parent_hnd = __prop_getu32(loc); } - else if (propeq(it, "interrupt-extended")) { - node->intr.extended = true; - __mkprop_ptr(it, &node->intr.arr); + else if (propeq(fdt, loc, "interrupts-extended")) { + node->extended = true; + __mkprop_ptr(loc, &node->raw_ispecs); } - else if (!node->intr.extended && propeq(it, "interrupts")) { - node->intr.valid = true; - __mkprop_ptr(it, &node->intr.arr); + else if (!node->extended && propeq(fdt, loc, "interrupts")) { + __mkprop_ptr(loc, &node->raw_ispecs); } else { return false; } + node->valid = true; return true; } \ No newline at end of file