add ability to do intr-binding based on given device tree node
authorLunaixsky <lunaixsky@qq.com>
Wed, 9 Oct 2024 16:43:24 +0000 (17:43 +0100)
committerLunaixsky <lunaixsky@qq.com>
Wed, 9 Oct 2024 16:43:24 +0000 (17:43 +0100)
* separated the devtree retrieval of gic into another source file.

lunaix-os/arch/aarch64/LBuild
lunaix-os/arch/aarch64/includes/asm/soc/gic.h
lunaix-os/arch/aarch64/soc/gic/gic.c [moved from lunaix-os/arch/aarch64/soc/gic.c with 86% similarity]
lunaix-os/arch/aarch64/soc/gic/gic_dt.c [new file with mode: 0644]
lunaix-os/arch/generic/includes/asm-generic/isrm.h

index 6dae92410e9cd8e2644409b789410267dfc67d72..cdf286ab77cbe3d629d7a09aacaa2af20afd1e10 100644 (file)
@@ -12,7 +12,8 @@ sources([
 ])
 
 sources([
-    "soc/gic.c",
+    "soc/gic/gic.c",
+    "soc/gic/gic_dt.c",
 ])
 
 sources([
index cabcfc4a49fb157a5d72c44ce8be3fb85bb71a2f..f7c50684366c70b912448b4b0e4d7942923fe1e8 100644 (file)
@@ -66,6 +66,7 @@ struct gic_int_param
     enum gic_tri_type trigger;
     enum gic_grp_type group;
     unsigned int priority;
+    unsigned int rel_intid;
     int cpu_id;
     bool as_nmi;
     bool ext_range;
@@ -200,8 +201,13 @@ struct arm_gic
         struct gic_idomain* spi;
         struct gic_idomain* espi;
     } idomain;
-
-    struct dt_node* gic_node;
 };
 
+void
+gic_create_from_dt(struct arm_gic* gic);
+
+unsigned int;
+gic_dtprop_interpret(struct gic_int_param* param, 
+                     struct dt_prop_val* val, int width);
+
 #endif /* __LUNAIX_GIC_H */
similarity index 86%
rename from lunaix-os/arch/aarch64/soc/gic.c
rename to lunaix-os/arch/aarch64/soc/gic/gic.c
index ad246863e3ff3e8aff845ee13911b3a7220f381f..1c1dd07f335b69affbe11e5d796154e2121dddea 100644 (file)
@@ -23,90 +23,6 @@ DEFINE_BMP_SET_OP(gic_bmp);
 
 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 ****** */
@@ -176,6 +92,22 @@ __undone_interrupt(struct arm_gic* gic, struct gic_distributor* dist,
     }
 }
 
+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)
@@ -188,16 +120,7 @@ __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*
@@ -489,11 +412,14 @@ gic_configure_pe(struct arm_gic* gic, struct gic_pe* pe)
 
 /* ****** 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;
@@ -536,8 +462,18 @@ aa64_isrm_ivalloc(struct gic_int_param* param, isr_cb handler)
         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;
@@ -548,9 +484,6 @@ aa64_isrm_ivalloc(struct gic_int_param* param, isr_cb handler)
         param->ext_range = true;
     }
 
-    struct gic_interrupt* ent;
-    struct gic_distributor* dist;
-
     ent  = __register_interrupt(domain, iv, param);
     dist = __attached_distributor(cpu, ent);
     
@@ -558,7 +491,7 @@ aa64_isrm_ivalloc(struct gic_int_param* param, isr_cb handler)
 
     ent->handler = handler;
 
-    return iv;
+    return ent;
 }
 
 static void
@@ -640,7 +573,7 @@ isrm_ivexalloc(isr_cb handler)
         .trigger = GIC_TRIG_EDGE,
     };
 
-    intr = aa64_isrm_ivalloc(&param, handler);
+    intr = __gic_install_int(&param, handler, true);
     
     return intr->intid;
 }
@@ -709,7 +642,7 @@ isrm_msialloc(isr_cb handler)
     if (gic.msi_via_spi) {
         param.class = GIC_SPI;
 
-        intid = aa64_isrm_ivalloc(&param, handler);
+        intid = __gic_install_int(&param, handler, true);
         msiv.msi_addr  = gic_regptr(gic.mmrs.dist_base, GICD_SETSPI_NSR);
         goto done;
     }
@@ -725,7 +658,7 @@ isrm_msialloc(isr_cb handler)
     }
 
     param.class = GIC_LPI;
-    intid = aa64_isrm_ivalloc(&param, handler);
+    intid = __gic_install_int(&param, handler, true);
     msiv.msi_addr = gic_regptr(gic.pes[0]._rd->base, GICR_SETLPIR);
 
 done:
@@ -736,9 +669,28 @@ 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(&param, val, 3);
+    param.cpu_id = 0;
+
+    installed = __gic_install_int(&param, handler, false);
+
+    return installed->intid;
 }
 
 /* ****** Device Definition & Export ****** */
@@ -748,7 +700,7 @@ gic_init()
 {
     memset(&gic, 0, sizeof(gic));
 
-    gic_create_from_dt();
+    gic_create_from_dt(&gic);
 
     // configure the system interfaces
     gic_configure_icc();
diff --git a/lunaix-os/arch/aarch64/soc/gic/gic_dt.c b/lunaix-os/arch/aarch64/soc/gic/gic_dt.c
new file mode 100644 (file)
index 0000000..863aa03
--- /dev/null
@@ -0,0 +1,140 @@
+#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
index 8cca7b00ef66df3e6942d2a071ae19dbb332e9e6..88c1db03b9b655b948bf1efe54e03eca7209f678 100644 (file)
@@ -70,7 +70,7 @@ isrm_msialloc(isr_cb handler);
  * @param node
  */
 int
-isrm_bind_dtnode(struct dt_intr_node* node);
+isrm_bind_dtnode(struct dt_intr_node* node, isr_cb handler);
 
 /**
  * @brief Get the handler associated with the given iv