DEFINE_BMP_ALLOCFROM_OP(gic_bmp);
-
-/* ++++++ GIC device-tree retrieval ++++++ */
-
-static void
-__setup_pe_rdist(struct dt_prop_iter* prop)
-{
- ptr_t base;
- size_t len, off;
- int i;
-
- base = dtprop_reg_nextaddr(prop);
- len = dtprop_reg_nextlen(prop);
-
- assert(len >= NR_CPU * FRAME_SIZE * 2);
-
- i = 0;
- base = ioremap(base, len);
- off = base;
-
- for (; i < NR_CPU; i++) {
- gic.pes[i]._rd = (struct gic_rd*) (base + off);
- off += sizeof(struct gic_rd);
- }
-}
-
-static void
-__create_its(struct dt_node* gic_node)
-{
- struct dt_node* its_node;
- struct dt_node_iter iter;
- struct dt_prop_iter prop;
- ptr_t its_base;
- size_t its_size;
-
- dt_begin_find(&iter, gic_node, "its");
-
- if (!dt_find_next(&iter, (struct dt_node_base**)&its_node)) {
- return;
- }
-
- dt_decode_reg(&prop, its_node, reg);
-
- its_base = dtprop_reg_nextaddr(&prop);
- its_size = dtprop_reg_nextlen(&prop);
-
- assert(its_size >= sizeof(struct gic_its));
-
- gic.mmrs.its = (struct gic_its*)ioremap(its_base, its_size);
-}
-
-static void
-gic_create_from_dt()
-{
- struct dt_node* gic_node;
- struct dt_node_iter iter;
- struct dt_prop_iter prop;
- ptr_t ptr;
- size_t sz;
-
- dt_begin_find(&iter, NULL, "interrupt-controller");
-
- if (!dt_find_next(&iter, (struct dt_node_base**)&gic_node)) {
- fail("expected /interrupt-controller node, but found none");
- }
-
- dt_decode_reg(&prop, gic_node, reg);
-
- ptr = dtprop_reg_nextaddr(&prop);
- sz = dtprop_reg_nextlen(&prop);
- gic.mmrs.dist_base = (gicreg_t*)ioremap(ptr, sz);
-
- __setup_pe_rdist(&prop);
-
- // ignore cpu_if, as we use sysreg to access them
- dtprop_next_n(&prop, 2);
-
- // ignore vcpu_if, as we dont do any EL2 stuff
-
- __create_its(gic_node);
-
- gic.gic_node = gic_node;
-}
-
-
/* ++++++ GIC dirver ++++++ */
/* ****** Interrupt Management ****** */
}
}
+static inline struct gic_interrupt*
+__get_interrupt(struct gic_idomain* domain, unsigned int rel_intid)
+{
+ struct gic_interrupt *pos, *n;
+ unsigned int intid;
+
+ intid = rel_intid + domain->base;
+ hashtable_hash_foreach(domain->recs, intid, pos, n, node)
+ {
+ if (pos->intid == intid) {
+ return pos;
+ }
+ }
+
+ return NULL;
+}
static struct gic_interrupt*
__find_interrupt_record(unsigned int intid)
return NULL;
}
- struct gic_interrupt *pos, *n;
-
- hashtable_hash_foreach(domain->recs, intid, pos, n, node)
- {
- if (pos->intid == intid) {
- return pos;
- }
- }
-
- return NULL;
+ return __get_interrupt(domain, intid - domain->base);
}
static inline struct gic_interrupt*
/* ****** Interrupt Life-cycle Management ****** */
-struct gic_interrupt*
-aa64_isrm_ivalloc(struct gic_int_param* param, isr_cb handler)
+
+static struct gic_interrupt*
+__gic_install_int(struct gic_int_param* param, isr_cb handler, bool alloc)
{
unsigned int iv;
struct gic_idomain* domain;
+ struct gic_interrupt* ent;
+ struct gic_distributor* dist;
int cpu;
cpu = param->cpu_id;
break;
}
- if (!bitmap_alloc(gic_bmp, &domain->ivmap, 0, &iv)) {
- FATAL("out of usable iv for class=%d", param->class);
+ if (alloc) {
+ if (!bitmap_alloc(gic_bmp, &domain->ivmap, 0, &iv)) {
+ FATAL("out of usable iv for class=%d", param->class);
+ }
+ }
+ else {
+ iv = param->rel_intid;
+ if ((ent = __get_interrupt(domain, iv))) {
+ return ent;
+ }
+
+ bitmap_set(gic_bmp, &domain->ivmap, iv, true);
}
iv += domain->base;
param->ext_range = true;
}
- struct gic_interrupt* ent;
- struct gic_distributor* dist;
-
ent = __register_interrupt(domain, iv, param);
dist = __attached_distributor(cpu, ent);
ent->handler = handler;
- return iv;
+ return ent;
}
static void
.trigger = GIC_TRIG_EDGE,
};
- intr = aa64_isrm_ivalloc(¶m, handler);
+ intr = __gic_install_int(¶m, handler, true);
return intr->intid;
}
if (gic.msi_via_spi) {
param.class = GIC_SPI;
- intid = aa64_isrm_ivalloc(¶m, handler);
+ intid = __gic_install_int(¶m, handler, true);
msiv.msi_addr = gic_regptr(gic.mmrs.dist_base, GICD_SETSPI_NSR);
goto done;
}
}
param.class = GIC_LPI;
- intid = aa64_isrm_ivalloc(¶m, handler);
+ intid = __gic_install_int(¶m, handler, true);
msiv.msi_addr = gic_regptr(gic.pes[0]._rd->base, GICR_SETLPIR);
done:
}
int
-isrm_bind_dtnode(struct dt_intr_node* node)
+isrm_bind_dtnode(struct dt_intr_node* node, isr_cb handler)
{
- // TODO
+ struct dt_prop_val* val;
+ struct gic_int_param param;
+ struct gic_interrupt* installed;
+
+ val = resolve_interrupt(INTR_TO_DTNODE(node));
+ if (!val) {
+ return EINVAL;
+ }
+
+ if (node->intr.extended) {
+ WARN("binding of multi interrupt is yet to supported");
+ return EINVAL;
+ }
+
+ gic_dtprop_interpret(¶m, val, 3);
+ param.cpu_id = 0;
+
+ installed = __gic_install_int(¶m, handler, false);
+
+ return installed->intid;
}
/* ****** Device Definition & Export ****** */
{
memset(&gic, 0, sizeof(gic));
- gic_create_from_dt();
+ gic_create_from_dt(&gic);
// configure the system interfaces
gic_configure_icc();
--- /dev/null
+#include <lunaix/types.h>
+#include <asm/soc/gic.h>
+
+#include <klibc/string.h>
+
+static bool
+__gic_predicate(struct dt_node_iter* iter, struct dt_node_base* pos)
+{
+ if (likely(!pos->intr_controll)) {
+ return false;
+ }
+
+ return strneq(pos->compat.str_val, "arm,gic-", 8);
+}
+
+static bool
+__its_predicate(struct dt_node_iter* iter, struct dt_node_base* pos)
+{
+ return strneq(pos->compat.str_val, "arm,gic-v3-its", 14);
+}
+
+static void
+__setup_pe_rdist(struct arm_gic* gic, struct dt_prop_iter* prop)
+{
+ ptr_t base;
+ size_t len, off;
+ int i;
+
+ base = dtprop_reg_nextaddr(prop);
+ len = dtprop_reg_nextlen(prop);
+
+ assert(len >= NR_CPU * FRAME_SIZE * 2);
+
+ i = 0;
+ base = ioremap(base, len);
+ off = base;
+
+ for (; i < NR_CPU; i++) {
+ gic->pes[i]._rd = (struct gic_rd*) (base + off);
+ off += sizeof(struct gic_rd);
+ }
+}
+
+static void
+__create_its(struct arm_gic* gic, struct dt_node* gic_node)
+{
+ struct dt_node* its_node;
+ struct dt_node_iter iter;
+ struct dt_prop_iter prop;
+ ptr_t its_base;
+ size_t its_size;
+
+ dt_begin_find(&iter, gic_node, __its_predicate, NULL);
+
+ if (!dt_find_next(&iter, (struct dt_node_base**)&its_node)) {
+ return;
+ }
+
+ dt_end_find(&iter);
+
+ dt_decode_reg(&prop, its_node, reg);
+
+ its_base = dtprop_reg_nextaddr(&prop);
+ its_size = dtprop_reg_nextlen(&prop);
+
+ assert(its_size >= sizeof(struct gic_its));
+
+ gic->mmrs.its = (struct gic_its*)ioremap(its_base, its_size);
+}
+
+void
+gic_create_from_dt(struct arm_gic* gic)
+{
+ struct dt_node* gic_node;
+ struct dt_node_iter iter;
+ struct dt_prop_iter prop;
+ ptr_t ptr;
+ size_t sz;
+
+ dt_begin_find(&iter, NULL, __gic_predicate, NULL);
+
+ if (!dt_find_next(&iter, (struct dt_node_base**)&gic_node)) {
+ fail("expected 'arm,gic-*' compatible node, but found none");
+ }
+
+ dt_end_find(&iter);
+
+ dt_decode_reg(&prop, gic_node, reg);
+
+ ptr = dtprop_reg_nextaddr(&prop);
+ sz = dtprop_reg_nextlen(&prop);
+ gic->mmrs.dist_base = (gicreg_t*)ioremap(ptr, sz);
+
+ __setup_pe_rdist(gic, &prop);
+
+ // ignore cpu_if, as we use sysreg to access them
+ dtprop_next_n(&prop, 2);
+
+ // ignore vcpu_if, as we dont do any EL2 stuff
+
+ __create_its(gic, gic_node);
+
+ dt_bind_object(&gic_node->base, gic);
+}
+
+unsigned int;
+gic_dtprop_interpret(struct gic_int_param* param,
+ struct dt_prop_val* val, int width)
+{
+ struct dt_prop_iter* iter;
+ unsigned int v;
+
+ dt_decode(&iter, NULL, val, 1);
+
+ v = dtprop_u32_at(&iter, 0);
+ switch (v)
+ {
+ case 0:
+ param->class = GIC_SPI;
+ break;
+ case 1:
+ param->class = GIC_PPI;
+ break;
+ case 2:
+ param->class = GIC_SPI;
+ param->ext_range = true;
+
+ default:
+ fail("invalid interrupt type");
+ break;
+ }
+
+ v = dtprop_u32_at(&iter, 2);
+ param->trigger = v == 1 ? GIC_TRIG_EDGE : GIC_TRIG_LEVEL;
+
+ param->group = GIC_G1NS;
+ param->rel_intid = dtprop_u32_at(&iter, 1);
+
+ return param->rel_intid;
+}
\ No newline at end of file