add implementation of ARM GIC driver.
authorLunaixsky <lunaixsky@qq.com>
Mon, 7 Oct 2024 23:59:06 +0000 (00:59 +0100)
committerLunaixsky <lunaixsky@qq.com>
Mon, 7 Oct 2024 23:59:06 +0000 (00:59 +0100)
Supported feature:
   1. Basic SGI, PPI, SPI, LPI enablement
   2. extended ranges (ePPI, eSPI)
   3. FEAT_NMI compatibility
   4. Per-PE redistributor config
   5. MBIs capable.

lunaix-os/arch/aarch64/includes/asm/aa64_gic.h [new file with mode: 0644]
lunaix-os/arch/aarch64/includes/asm/aa64_isrm.h [new file with mode: 0644]
lunaix-os/arch/aarch64/includes/asm/aa64_mmu.h
lunaix-os/arch/aarch64/includes/asm/soc/gic.h [new file with mode: 0644]
lunaix-os/arch/aarch64/soc/gic.c [new file with mode: 0644]
lunaix-os/includes/hal/devtree.h
lunaix-os/includes/lunaix/bits.h
lunaix-os/includes/lunaix/compiler.h
lunaix-os/includes/lunaix/device_num.h
lunaix-os/includes/lunaix/ds/bitmap.h [new file with mode: 0644]

diff --git a/lunaix-os/arch/aarch64/includes/asm/aa64_gic.h b/lunaix-os/arch/aarch64/includes/asm/aa64_gic.h
new file mode 100644 (file)
index 0000000..ea9f691
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef __LUNAIX_AA64_GIC_H
+#define __LUNAIX_AA64_GIC_H
+
+#include <lunaix/bits.h>
+#include "aa64_msrs.h"
+
+#define FRAME_SIZE  0x10000
+
+typedef unsigned int gicreg_t;
+typedef unsigned long gicreg64_t;
+#define FRAME_LEN   (FRAME_SIZE / sizeof(gicreg_t))
+#define REG_INDEX(addr)     ((addr) / sizeof(gicreg_t))
+
+#define ICC_CTLR_EL1        __sr_encode(3, 0, 12, 12, 4)
+#define ICC_SRE_EL1         __sr_encode(3, 0, 12, 12, 5)
+#define ICC_IGRPEN0_EL1     __sr_encode(3, 0, 12, 12, 6)
+#define ICC_IGRPEN1_EL1     __sr_encode(3, 0, 12, 12, 7)
+
+#define ICC_IAR1_EL1        __sr_encode(3, 0, 12, 12, 0)
+#define ICC_EOIR1_EL1       __sr_encode(3, 0, 12, 12, 1)
+
+#define INTID_ACKED_S        1020
+#define INTID_ACKED_NS       1021
+#define INTID_IAR1_NMI       1022
+#define INTID_NOTHING        1023
+#define check_special_intid(intid)  \
+        ((intid) >= INTID_ACKED_S && (intid) <= INTID_NOTHING)
+
+#define LPI_PRIORITY         BITFIELD(7, 2)
+#define LPI_EN               1UL
+
+#define ICC_SRE_SRE          BITFLAG(0)
+#define ICC_SRE_DFB          BITFLAG(1)
+#define ICC_SRE_DIB          BITFLAG(2)
+
+#define ICC_CTRL_EXTRAN      BITFLAG(19)
+#define ICC_CTRL_IDbits      BITFIELD(13, 11)
+#define ICC_CTRL_PRIbits     BITFIELD(10, 8)
+#define ICC_CTRL_PMHE        BITFLAG(6)
+#define ICC_CTRL_EOImode     BITFLAG(1)
+#define ICC_CTRL_CBPR        BITFLAG(0)
+
+#define ICC_IGRPEN_ENABLE    BITFLAG(0)
+
+#define GICD_CTLR            REG_INDEX(0x0000)
+#define GICD_TYPER           REG_INDEX(0x0004)
+#define GICD_IIDR            REG_INDEX(0x0008)
+
+#define GICD_IGROUPRn        REG_INDEX(0x0080)
+#define GICD_ISENABLER       REG_INDEX(0x0100)
+#define GICD_ICENABLER       REG_INDEX(0x0180)
+#define GICD_IPRIORITYR      REG_INDEX(0x0400)
+#define GICD_ICFGR           REG_INDEX(0x0C00)
+#define GICD_IGRPMODRn       REG_INDEX(0x0D00)
+#define GICD_INMIR           REG_INDEX(0x0F80)
+
+#define GICR_CTLR            REG_INDEX(0x0000)
+#define GICR_TYPER           REG_INDEX(0x0008)
+#define GICR_PROPBASER       REG_INDEX(0x0070)
+#define GICR_PENDBASER       REG_INDEX(0x0078)
+
+#define GICD_CTLR_G1SEN      BITFLAG(2)
+#define GICD_CTLR_G1NSEN     BITFLAG(1)
+#define GICD_CTLR_G0EN       BITFLAG(0)
+
+#define GICD_TYPER_nESPI     BITFIELD(31, 27)
+#define GICD_TYPER_No1N      BITFLAG(25)
+#define GICD_TYPER_LPIS      BITFLAG(17)
+#define GICD_TYPER_MBIS      BITFLAG(16)
+#define GICD_TYPER_nLPI      BITFIELD(15, 11)
+#define GICD_TYPER_NMI       BITFLAG(9)
+#define GICD_TYPER_ESPI      BITFLAG(8)
+#define GICD_TYPER_nSPI      BITFIELD(4, 0)
+#define GICD_TYPER_IDbits    BITFIELD(23, 19)
+
+#define GICR_TYPER_AffVal    BITFIELD(63, 32)
+#define GICR_TYPER_PPInum    BITFIELD(31, 27)
+
+#define GICR_BASER_PAddr     BITFIELD(51, 12)
+#define GICR_BASER_Share     BITFIELD(11, 10)
+#define GICR_PENDBASER_PTZ   BITFLAG(62)
+#define GICR_PROPBASER_IDbits\
+                             BITFIELD(4,  0)
+
+#endif /* __LUNAIX_AA64_GIC_H */
diff --git a/lunaix-os/arch/aarch64/includes/asm/aa64_isrm.h b/lunaix-os/arch/aarch64/includes/asm/aa64_isrm.h
new file mode 100644 (file)
index 0000000..2ab1367
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __LUNAIX_AA64_ISRM_H
+#define __LUNAIX_AA64_ISRM_H
+
+#include <asm-generic/isrm.h>
+#include "soc/gic.h"
+
+unsigned int
+aa64_isrm_ivalloc(struct gic_int_param* ivcfg, isr_cb handler);
+
+#endif /* __LUNAIX_AA64_ISRM_H */
index 25885cf09193e1201c291e2624f45ab0b40d929d..9f5c914cca0772cf82814c8addd748995afbef80 100644 (file)
@@ -33,7 +33,7 @@
 #define TCR_G16K            (0b10)
 #define TCR_G64K            (0b11)
 
-#define TCR_SHNS            (0b01)
+#define TCR_SHNS            (0b00)
 #define TCR_SHOS            (0b10)
 #define TCR_SHIS            (0b11)
 
diff --git a/lunaix-os/arch/aarch64/includes/asm/soc/gic.h b/lunaix-os/arch/aarch64/includes/asm/soc/gic.h
new file mode 100644 (file)
index 0000000..35b9dc5
--- /dev/null
@@ -0,0 +1,204 @@
+#ifndef __LUNAIX_GIC_H
+#define __LUNAIX_GIC_H
+
+#include <lunaix/types.h>
+#include <lunaix/ds/bitmap.h>
+#include <lunaix/ds/hashtable.h>
+#include <asm/aa64_gic.h>
+#include <asm-generic/isrm.h>
+
+#define NR_CPU      1
+#define gic_bmp     PREP_BITMAP(gicreg_t, gic_intr, BMP_ORIENT_LSB)
+
+#define INITID_SGI_BASE     0
+#define INITID_SGI_END      15
+
+#define INITID_PPI_BASE     16
+#define INITID_PPI_END      31
+
+#define INITID_SPI_BASE     32
+#define INITID_SPI_END      1019
+
+#define INITID_SPEC_BASE    1020
+#define INITID_SPEC_END     1023
+
+#define INITID_ePPI_BASE    1056
+#define INITID_ePPI_END     1119
+
+#define INITID_eSPI_BASE    4096
+#define INITID_eSPI_END     5119
+
+#define INITID_LPI_BASE     8192
+
+#define INITID_SPI_NR       (INITID_SPEC_BASE - INITID_SPI_BASE)
+
+enum gic_int_type
+{
+    GIC_IDL,
+    GIC_LPI,
+    GIC_SPI,
+    GIC_PPI,
+    GIC_SGI,
+    GIC_RSV
+} compact;
+
+enum gic_tri_type
+{
+    GIC_TRIG_EDGE,
+    GIC_TRIG_LEVEL
+} compact;
+
+enum gic_grp_type
+{
+    GIC_G0,
+    GIC_G1S,
+    GIC_G1NS
+} compact;
+
+DECLARE_BITMAP(gic_bmp);
+
+struct gic_int_param
+{
+    enum gic_int_type class;
+    enum gic_tri_type trigger;
+    enum gic_grp_type group;
+    unsigned int priority;
+    int cpu_id;
+    bool as_nmi;
+    bool ext_range;
+};
+
+struct gic_intcfg {
+    enum gic_int_type class;
+    enum gic_tri_type trigger;
+    enum gic_grp_type group;
+    bool as_nmi;
+};
+
+struct gic_idomain
+{
+    DECLARE_HASHTABLE(recs, 32);
+    BITMAP(gic_bmp) ivmap;
+    unsigned int base;
+    bool extended;
+};
+
+struct gic_interrupt
+{
+    struct hlist_node node;
+
+    struct gic_idomain* domain;
+    
+    unsigned int intid;
+    struct gic_intcfg config;
+    
+    isr_cb handler;
+    void* payload;
+};
+
+struct gic_distributor
+{
+    BITMAP(gic_bmp) group;
+    BITMAP(gic_bmp) grpmod;
+    BITMAP(gic_bmp) enable;
+    BITMAP(gic_bmp) disable;
+    BITMAP(gic_bmp) icfg;
+    BITMAP(gic_bmp) nmi;
+};
+
+struct gic_rd
+{
+    gicreg_t base[FRAME_LEN];
+    gicreg_t sgi_base[FRAME_LEN];
+} compact align(4);
+
+struct gic_cpuif
+{
+    gicreg_t base[FRAME_LEN];
+} compact align(4);
+
+#define gic_reg64(base, index) (*(gicreg64_t*)(&base[index]))
+#define gic_regptr(base, index) (__ptr(&base[index]))
+
+struct gic_pe
+{
+    struct gic_interrupt* active;
+    reg_t iar_val;
+    unsigned int priority;
+
+    struct gic_rd* _rd;
+    struct gic_cpuif* _if;
+
+    struct gic_distributor rdist;
+
+    struct {
+        struct gic_idomain* local_ints;
+        struct gic_idomain* eppi;
+    } idomain;
+
+    struct {
+        unsigned int affinity;
+        unsigned int ppi_nr;
+        bool eppi_ready;
+    };
+};
+
+struct gic_its
+{
+    gicreg_t base[FRAME_LEN];        // control regs
+    gicreg_t trn_space[FRAME_LEN];   // translation space
+} compact align(4);
+
+struct gic_its_v41
+{
+    gicreg_t base[FRAME_LEN];        // control regs
+    gicreg_t trn_space[FRAME_LEN];   // translation space
+    gicreg_t vsgi_space[FRAME_LEN];  // vSGI space (v4.1+)
+} compact align(4);
+
+typedef unsigned char lpi_entry_t;
+
+struct arm_gic
+{
+    unsigned int max_intid;
+    struct gic_pe pes[NR_CPU];
+
+    struct {
+        unsigned int lpi_nr;
+        unsigned int spi_nr;
+        unsigned int espi_nr;
+        bool lpi_ready;
+        bool nmi_ready;
+        bool has_espi;
+        bool msi_via_spi;
+    };
+
+    struct {
+        gicreg_t* dist_base;
+        union {
+            struct gic_its* its;
+            struct gic_its_v41* its_v41;
+        };
+    } mmrs;
+
+    struct {
+        union {
+            ptr_t prop;
+            lpi_entry_t* property;
+        };
+        
+        ptr_t pend;
+        BITMAP(gic_bmp) pendings;
+    } lpi_tables;
+
+    struct gic_distributor dist;
+    struct gic_distributor dist_e;
+
+    struct {
+        struct gic_idomain* lpi;
+        struct gic_idomain* spi;
+        struct gic_idomain* espi;
+    } idomain;
+};
+
+#endif /* __LUNAIX_GIC_H */
diff --git a/lunaix-os/arch/aarch64/soc/gic.c b/lunaix-os/arch/aarch64/soc/gic.c
new file mode 100644 (file)
index 0000000..ce666ea
--- /dev/null
@@ -0,0 +1,701 @@
+#include <lunaix/types.h>
+#include <lunaix/device.h>
+#include <lunaix/spike.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/mm/page.h>
+#include <lunaix/mm/mmio.h>
+#include <lunaix/syslog.h>
+
+#include <hal/devtree.h>
+
+#include <asm/aa64_isrm.h>
+#include <asm/soc/gic.h>
+
+static struct arm_gic gic;
+
+LOG_MODULE("gic")
+
+DEFINE_BMP_INIT_OP(gic_bmp, valloc);
+
+DEFINE_BMP_QUERY_OP(gic_bmp);
+
+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 dirver ++++++ */
+
+static void
+__config_interrupt(struct arm_gic* gic, struct gic_distributor* dist, 
+                    struct gic_interrupt* ent)
+{
+    unsigned int intid_rel;
+    unsigned long trig_index;
+
+    intid_rel = ent->intid - ent->domain->base;
+
+    if (ent->config.class == GIC_LPI) {
+        lpi_entry_t entry = 0;
+
+        entry |= LPI_EN;
+        
+        gic->lpi_tables.property[intid_rel] = entry;
+
+        // clear any pending when we (re-)configuring
+        bitmap_set(gic_bmp, &gic->lpi_tables.pendings, intid_rel, false);
+
+        return;
+    }
+
+
+    bitmap_set(gic_bmp, &dist->group, intid_rel, 0);
+    bitmap_set(gic_bmp, &dist->grpmod, intid_rel, 1);
+
+    trig_index = intid_rel * 2;
+    bitmap_set(gic_bmp, &dist->icfg, trig_index, 0);
+    if (ent->config.trigger == GIC_TRIG_EDGE) {
+        bitmap_set(gic_bmp, &dist->icfg, trig_index + 1, 1);
+    } else {
+        bitmap_set(gic_bmp, &dist->icfg, trig_index + 1, 0);
+    }
+
+    if (gic->nmi_ready) {
+        bitmap_set(gic_bmp, &dist->nmi, intid_rel, ent->config.as_nmi);
+    }
+
+    bitmap_set(gic_bmp, &dist->enable, intid_rel, true);
+}
+
+static void
+__undone_interrupt(struct arm_gic* gic, struct gic_distributor* dist, 
+                    struct gic_interrupt* ent)
+{
+    unsigned int intid_rel;
+
+    intid_rel = ent->intid - ent->domain->base;
+    
+    if (ent->config.class == GIC_LPI) {
+        gic->lpi_tables.property[intid_rel] = 0;
+
+        // clear any pending when we (re-)configuring
+        bitmap_set(gic_bmp, &gic->lpi_tables.pendings, intid_rel, false);
+
+        return;
+    }
+
+    bitmap_set(gic_bmp, &dist->disable, intid_rel, true);
+    
+    if (gic->nmi_ready) {
+        bitmap_set(gic_bmp, &dist->nmi, intid_rel, false);
+    }
+}
+
+static struct gic_idomain*
+__idomain(int nr_ints, unsigned int base, bool extended)
+{
+    struct gic_idomain* rec;
+
+    rec = valloc(sizeof(*rec));
+    
+    bitmap_init(gic_bmp, &rec->ivmap, nr_ints);
+    hashtable_init(rec->recs);
+
+    rec->base = base;
+    rec->extended = extended;
+
+    return rec;
+}
+
+static inline void
+__init_distributor(struct gic_distributor* d, 
+                   gicreg_t* base, unsigned int nr_ints)
+{
+    bitmap_init_ptr(gic_bmp,
+        &d->group, nr_ints, gic_regptr(base, GICD_IGROUPRn));
+
+    bitmap_init_ptr(gic_bmp,
+        &d->grpmod, nr_ints, gic_regptr(base, GICD_IGRPMODRn));
+
+    bitmap_init_ptr(gic_bmp,
+        &d->enable, nr_ints, gic_regptr(base, GICD_ISENABLER));
+    
+    bitmap_init_ptr(gic_bmp,
+        &d->disable, nr_ints, gic_regptr(base, GICD_ICENABLER));
+
+    bitmap_init_ptr(gic_bmp,
+        &d->icfg, nr_ints * 2, gic_regptr(base, GICD_ICFGR));
+    
+    bitmap_init_ptr(gic_bmp,
+        &d->nmi, nr_ints, gic_regptr(base, GICD_INMIR));
+}
+
+static inline struct leaflet*
+__alloc_lpi_table(size_t table_sz)
+{
+    unsigned int val;
+    struct leaflet* tab;
+
+    val = page_aligned(table_sz);
+    tab = alloc_leaflet(count_order(leaf_count(val)));
+    leaflet_wipe(tab);
+
+    return leaflet_addr(tab);
+}
+
+static struct gic_idomain*
+__deduce_domain(unsigned int intid)
+{
+    if (intid <= INITID_SGI_END) {
+        return gic.pes[0].idomain.local_ints;
+    }
+
+    if (intid <= INITID_PPI_END) {
+        return gic.pes[0].idomain.local_ints;
+    }
+
+    if (intid <= INITID_SPI_END) {
+        return gic.idomain.spi;
+    }
+
+    if (INITID_ePPI_BASE <= intid && intid <= INITID_ePPI_END) {
+        return gic.pes[0].idomain.eppi;
+    }
+
+    if (INITID_eSPI_BASE <= intid && intid <= INITID_eSPI_END) {
+        return gic.idomain.espi;
+    }
+
+    if (intid >= INITID_LPI_BASE) {
+        return gic.idomain.lpi;
+    }
+
+    return NULL;
+}
+
+static struct gic_interrupt*
+__find_interrupt_record(unsigned int intid)
+{
+    struct gic_idomain* domain;
+
+    domain = __deduce_domain(intid);
+    
+    if (!domain) {
+        return NULL;
+    }
+
+    struct gic_interrupt *pos, *n;
+
+    hashtable_hash_foreach(domain->recs, intid, pos, n, node)
+    {
+        if (pos->intid == intid) {
+            return pos;
+        }
+    }
+
+    return NULL;
+}
+
+static inline struct gic_interrupt*
+__register_interrupt(struct gic_idomain* domain, 
+                            unsigned int intid, struct gic_int_param* param)
+{
+    struct gic_interrupt* interrupt;
+
+    interrupt = valloc(sizeof(*interrupt));
+    interrupt->config = (struct gic_intcfg) {
+        .class   = param->class,
+        .trigger = param->trigger,
+        .group   = param->group,
+        .as_nmi  = param->as_nmi
+    };
+
+    interrupt->intid = intid;
+    interrupt->domain = domain;
+
+    hashtable_hash_in(domain->recs, &interrupt->node, intid);
+
+    return interrupt;
+}
+
+static struct gic_distributor*
+__attached_distributor(int cpu, struct gic_interrupt* ent)
+{
+    enum gic_int_type iclass;
+
+    iclass = ent->config.class;
+
+    if (iclass == GIC_PPI || iclass == GIC_SGI) {
+        return &gic.pes[cpu].rdist;
+    }
+    
+    if (ent->domain->extended) {
+        return &gic.dist_e;
+    }
+    
+    return &gic.dist;
+}
+
+static void
+gic_configure_icc()
+{
+    reg_t v;
+
+    v =
+    sysreg_flagging(ICC_SRE_EL1, 
+                    ICC_SRE_SRE | ICC_SRE_DFB | ICC_SRE_DIB, 
+                    0);
+    
+
+    v = 
+    sysreg_flagging(ICC_CTLR_EL1,
+                    ICC_CTRL_CBPR,
+                    ICC_CTRL_EOImode | ICC_CTRL_PMHE);
+
+    // disable all group 0 interrupts as those are meant for EL3
+    v=
+    sysreg_flagging(ICC_IGRPEN0_EL1, 0, ICC_IGRPEN_ENABLE);
+
+    // enable all group 1 interrupts, we'll stick with EL1_NS
+    v=
+    sysreg_flagging(ICC_IGRPEN1_EL1, ICC_IGRPEN_ENABLE, 0);
+}
+
+static void
+gic_configure_global(struct arm_gic* gic)
+{
+    gicreg64_t reg;
+    unsigned int val, max_nr_spi;
+
+    reg = gic->mmrs.dist_base[GICD_TYPER];
+    
+    // check if eSPI supported
+    gic->has_espi = (reg & GICD_TYPER_ESPI);
+    if (gic->has_espi) {
+        val = BITS_GET(reg, GICD_TYPER_nESPI);
+        gic->espi_nr = 32 * (val + 1);
+    }
+
+    // Parse IDbits
+    val = BITS_GET(reg, GICD_TYPER_IDbits);
+    gic->max_intid = 1 << (val + 1) - 1;
+
+    // LPI is supported
+    if (val + 1 >= 14) {
+        val = BITS_GET(reg, GICD_TYPER_nLPI);
+        if (val) {
+            gic->lpi_nr = 1 << (val + 1);
+        }
+        else {
+            gic->lpi_nr = gic->max_intid - INITID_LPI_BASE + 1;
+        }
+    }
+
+    // check if SPI supported
+    val = BITS_GET(reg, GICD_TYPER_nSPI);
+    if (val) {
+        max_nr_spi = 32 * (val + 1);
+        gic->spi_nr = MIN(max_nr_spi, INITID_SPEC_BASE);
+        gic->spi_nr -= INITID_SPI_BASE;
+    } else {
+        gic->spi_nr = 0;
+    }
+
+    gic->nmi_ready = (reg & GICD_TYPER_NMI);
+    gic->msi_via_spi = (reg & GICD_TYPER_MBIS);
+
+    __init_distributor(&gic->dist, gic->mmrs.dist_base, gic->spi_nr);
+    __init_distributor(&gic->dist_e, gic->mmrs.dist_base, gic->espi_nr);
+
+
+    if (gic->spi_nr) {
+        gic->idomain.spi  = __idomain(gic->spi_nr, INITID_SPI_BASE, false);
+    }
+    if (gic->espi_nr) {
+        gic->idomain.espi = __idomain(gic->espi_nr, INITID_eSPI_BASE, true);
+    }
+    if (gic->lpi_nr) {
+        gic->idomain.lpi  = __idomain(gic->lpi_nr, INITID_LPI_BASE, false);
+    }
+
+    gic->lpi_tables.prop = __alloc_lpi_table(gic->lpi_nr);
+    gic->lpi_tables.pend = __alloc_lpi_table(gic->lpi_nr / 8);
+
+    bitmap_init_ptr(gic_bmp, 
+        &gic->lpi_tables.pendings, gic->lpi_nr, gic->lpi_tables.pend);
+}
+
+static void
+gic_configure_pe(struct arm_gic* gic, struct gic_pe* pe)
+{
+    unsigned int nr_local_ints;
+    gicreg64_t reg;
+
+    reg = gic_reg64(pe->_rd, GICR_TYPER);
+
+    pe->affinity = BITS_GET(reg, GICR_TYPER_AffVal);
+    pe->ppi_nr   = INITID_PPI_BASE;
+    switch (BITS_GET(reg, GICR_TYPER_PPInum))
+    {
+        case 1:
+            pe->ppi_nr += 1088 - INITID_ePPI_BASE;
+            pe->eppi_ready = true;
+            break;
+        case 2:
+            pe->ppi_nr += 1120 - INITID_ePPI_BASE;
+            pe->eppi_ready = true;
+            break;
+    }
+
+    nr_local_ints = pe->ppi_nr + INITID_PPI_BASE;
+    
+    pe->idomain.local_ints = __idomain(32, 0, false);
+    pe->idomain.eppi = __idomain(nr_local_ints - 32, INITID_ePPI_BASE, true);
+
+    __init_distributor(&pe->rdist, pe->_rd->sgi_base, nr_local_ints);
+
+    reg = 0;
+    BITS_SET(reg, GICR_BASER_PAddr, gic->lpi_tables.prop);
+    BITS_SET(reg, GICR_BASER_Share, 0b01);
+    BITS_SET(reg, GICR_PROPBASER_IDbits, ilog2(gic->max_intid));
+    pe->_rd->sgi_base[GICR_PROPBASER] = reg;
+
+    reg  = 0;
+    reg |= GICR_PENDBASER_PTZ;
+    BITS_SET(reg, GICR_BASER_PAddr, gic->lpi_tables.pend);
+    BITS_SET(reg, GICR_BASER_Share, 0b01);
+    pe->_rd->sgi_base[GICR_PENDBASER] = reg;
+}
+
+struct gic_interrupt*
+aa64_isrm_ivalloc(struct gic_int_param* param, isr_cb handler)
+{
+    unsigned int iv;
+    struct gic_idomain* domain;
+    int cpu;
+
+    cpu = param->cpu_id;
+
+    assert(cpu == 0);
+
+    switch (param->class)
+    {
+    case GIC_PPI:
+        if (!param->ext_range) {
+            domain = gic.pes[cpu].idomain.local_ints;
+        }
+        else {
+            domain = gic.pes[cpu].idomain.eppi;
+        }
+        break;
+
+    case GIC_SGI:
+        domain = gic.pes[cpu].idomain.local_ints;
+        break;
+
+    case GIC_SPI:
+        if (!param->ext_range) {
+            assert(gic.spi_nr > 0);
+            domain = gic.idomain.spi;
+        } 
+        else {
+            assert(gic.has_espi);
+            domain = gic.idomain.espi;
+        }
+        break;
+
+    case GIC_LPI:
+        assert(gic.lpi_ready);
+        domain = gic.idomain.lpi;
+        break;
+        
+    default:
+        fail("unknown interrupt class");
+        break;
+    }
+
+    if (!bitmap_alloc(gic_bmp, &domain->ivmap, 0, &iv)) {
+        FATAL("out of usable iv for class=%d", param->class);
+    }
+
+    iv += domain->base;
+
+    if (param->class == GIC_SPI && !param->ext_range && iv >= INITID_ePPI_BASE) 
+    {
+        WARN("PPI vector=%d falls in extended range, while not requested.", iv);
+        param->ext_range = true;
+    }
+
+    struct gic_interrupt* ent;
+    struct gic_distributor* dist;
+
+    ent  = __register_interrupt(domain, iv, param);
+    dist = __attached_distributor(cpu, ent);
+    
+    __config_interrupt(&gic, dist, ent);
+
+    ent->handler = handler;
+
+    return iv;
+}
+
+static void
+gic_update_active()
+{
+    reg_t val;
+    unsigned int intid;
+    struct gic_interrupt* intr;
+    struct gic_pe* pe;
+
+    pe  = &gic.pes[0];
+    val = read_sysreg(ICC_IAR1_EL1);
+    intid = (unsigned int)val & ((1 << 24) - 1);
+
+    if (check_special_intid(intid)) {
+        return;
+    }
+
+    intr = __find_interrupt_record(intid);
+    pe->active = intr;
+    pe->iar_val = val;
+}
+
+static void
+gic_signal_eoi()
+{
+    struct gic_pe* pe;
+
+    pe  = &gic.pes[0];
+    if (!pe->active) {
+        return;
+    }
+
+    pe->active = NULL;
+    set_sysreg(ICC_EOIR1_EL1, pe->iar_val);
+}
+
+void
+isrm_init()
+{
+    // nothing to do
+}
+
+void
+isrm_ivfree(int iv)
+{
+    struct gic_interrupt* ent;
+    struct gic_distributor* dist;
+    
+    ent  = __find_interrupt_record(iv);
+    if (!ent) {
+        return;
+    }
+
+    dist = __attached_distributor(0, ent);
+    __undone_interrupt(&gic, dist, ent);
+
+    hlist_delete(&ent->node);
+    vfree(ent);
+}
+
+int
+isrm_ivosalloc(isr_cb handler)
+{
+    return isrm_ivexalloc(handler);
+}
+
+int
+isrm_ivexalloc(isr_cb handler)
+{
+    struct gic_int_param param;
+    struct gic_interrupt* intr;
+
+    param = (struct gic_int_param) {
+        .class = GIC_SPI,
+        .group = GIC_G1NS,
+        .trigger = GIC_TRIG_EDGE,
+    };
+
+    intr = aa64_isrm_ivalloc(&param, handler);
+    
+    return intr->intid;
+}
+
+int
+isrm_bindirq(int irq, isr_cb irq_handler)
+{
+    // Not supported
+}
+
+void
+isrm_bindiv(int iv, isr_cb handler)
+{
+    // Not supported
+}
+
+isr_cb
+isrm_get(int iv)
+{
+    struct gic_interrupt* intr;
+
+    intr = __find_interrupt_record(iv);
+    if (!intr) {
+        return NULL;
+    }
+
+    return intr->handler;
+}
+
+ptr_t
+isrm_get_payload(const struct hart_state* state)
+{
+    struct gic_interrupt* active;
+
+    active = gic.pes[0].active;
+    assert(active);
+
+    return active->handler;
+}
+
+void
+isrm_set_payload(int iv, ptr_t payload)
+{
+    struct gic_interrupt* intr;
+
+    intr = __find_interrupt_record(iv);
+    if (!intr) {
+        return NULL;
+    }
+
+    intr->payload = payload;
+}
+
+void
+isrm_irq_attach(int irq, int iv, cpu_t dest, u32_t flags)
+{
+    // Not supported
+}
+
+void
+isrm_notify_eoi(cpu_t id, int iv)
+{
+    struct gic_interrupt* active;
+
+    active = gic.pes[0].active;
+    assert(active);
+}
+
+void
+isrm_notify_eos(cpu_t id)
+{
+    isrm_notify_eoi(id, 0);
+}
+
+
+static void
+gic_init()
+{
+    memset(&gic, 0, sizeof(gic));
+
+    gic_create_from_dt();
+
+    // configure the system interfaces
+    gic_configure_icc();
+
+    // configure global distributor
+    gic_configure_global(&gic);
+    
+    // configure per-PE local distributor (redistributor)
+    for (int i = 0; i < NR_CPU; i++)
+    {
+        gic_configure_pe(&gic, &gic.pes[i]);
+    }
+}
+
+static struct device_def dev_arm_gic = {
+    .name = "ARM Generic Interrupt Controller",
+    .class = DEVCLASS(DEVIF_SOC, DEVFN_CFG, DEV_INTC),
+    .init = gic_init
+};
+EXPORT_DEVICE(arm_gic, &dev_arm_gic, load_sysconf);
\ No newline at end of file
index 3a92116eeb4fc744be07297c6b0664b49591b3cb..0a132da5f2e805f7a08a3f0327dd971f1c8838af 100644 (file)
@@ -319,11 +319,11 @@ dt_decode(struct dt_prop_iter* dtpi, struct dt_node_base* node,
 }
 
 #define dt_decode_reg(dtpi, node, field) \
-            dt_decode(dtpi, &(node)->base, (node)->(field), \
+            dt_decode(dtpi, &(node)->base, &(node)->field, \
                             (node)->base.sz_c + (node)->base.addr_c);
 
 #define dt_decode_range(dtpi, node, field) \
-            dt_decode(dtpi, &(node)->base, (node)->field, \
+            dt_decode(dtpi, &(node)->base, &(node)->field, \
                             (node)->base.sz_c * 2 + (node)->base.addr_c);
 
 static inline void
@@ -410,12 +410,34 @@ dtprop_reg_addr(struct dt_prop_iter* dtpi)
     return dtprop_extract(dtpi, 0);
 }
 
+static inline ptr_t
+dtprop_reg_nextaddr(struct dt_prop_iter* dtpi)
+{
+    ptr_t t;
+
+    t = (ptr_t)dtprop_to_u64(dtprop_reg_addr(dtpi));
+    dtprop_next(dtpi);
+
+    return t;
+}
+
 static inline dt_enc_t
 dtprop_reg_len(struct dt_prop_iter* dtpi)
 {
     return dtprop_extract(dtpi, dtpi->node->addr_c);
 }
 
+static inline size_t
+dtprop_reg_nextlen(struct dt_prop_iter* dtpi)
+{
+    size_t t;
+
+    t = (size_t)dtprop_to_u64(dtprop_reg_len(dtpi));
+    dtprop_next(dtpi);
+
+    return t;
+}
+
 static inline dt_enc_t
 dtprop_range_childbus(struct dt_prop_iter* dtpi)
 {
index ddc28004945fac665a3182a3f3190d09749a168b..65a6ef81ff513a0962233f3cbb2ff2c878af2e67 100644 (file)
@@ -4,14 +4,15 @@
 #include <lunaix/compiler.h>
 #include <asm/bits.h>
 
-#define BITFIELD(h, l)              (h), (l)
+#define BITFIELD(h, l)               (h), (l)
 
-#define BIT(p)                   BITFIELD(p, p)
+#define BIT(p)                       BITFIELD(p, p)
+#define BITFLAG(p)                   (1UL << (p))
 
-#define BITS_GENMASK(bits)       _BITS_GENMASK(bits)
+#define BITS_GENMASK(bitfield)       _BITS_GENMASK(bitfield)
 
-#define BITS_GET(from, bits)     _BITS_EXTRACT(from, bits)
+#define BITS_GET(from, bitfield)     _BITS_EXTRACT(from, bitfield)
 
-#define BITS_SET(to, bits, val)  _BITS_INSERT(to, val, bits)
+#define BITS_SET(to, bitfield, val)  _BITS_INSERT(to, val, bitfield)
 
 #endif /* __LUNAIX_BITS_H */
index f644112c4300cc594e9e448d1a6a8da6971e36d1..d498f536bbfef5ba362aed8296905a03d15222a4 100644 (file)
@@ -13,6 +13,7 @@
 #define must_emit               __attribute__((used))
 #define unreachable             __builtin_unreachable()
 #define no_inline               __attribute__((noinline))
+#define asmlinkage              
 
 #define _default                weak
 
@@ -35,6 +36,8 @@
 #define umul_of(a, b, of)       __builtin_umul_overflow(a, b, of)
 #define umull_of(a, b, of)      __builtin_umull_overflow(a, b, of)
 #define offsetof(f, m)          __builtin_offsetof(f, m)
+#define select(cond, y, n)      __builtin_choose_expr(cond, y, n)
+#define is_const(v)             __builtin_constant_p(v)
 
 #define prefetch_rd(ptr, ll)    __builtin_prefetch((ptr), 0, ll)
 #define prefetch_wr(ptr, ll)    __builtin_prefetch((ptr), 1, ll)
@@ -61,4 +64,9 @@ spin()
     unreachable;
 }
 
+#ifdef CONFIG_ARCH_X86_32
+#undef  asmlinkage
+#define asmlinkage      __attribute__((regparm(0)))
+#endif
+
 #endif /* __LUNAIX_COMPILER_H */
index b59c857bae2205a37c3af28ca9c83f6e61c72559..6e9f7f9791dd17437e968b913163e5e785a5d1ea 100644 (file)
 #define DEV_GFXA 12
 #define DEV_VGA 13
 #define DEV_ACPI 14
+#define DEV_INTC 15
 
 struct devident
 {
diff --git a/lunaix-os/includes/lunaix/ds/bitmap.h b/lunaix-os/includes/lunaix/ds/bitmap.h
new file mode 100644 (file)
index 0000000..68d98ba
--- /dev/null
@@ -0,0 +1,147 @@
+#ifndef __LUNAIX_BITMAP_H
+#define __LUNAIX_BITMAP_H
+
+#include <lunaix/types.h>
+#include <lunaix/spike.h>
+#include <klibc/string.h>
+
+// first bit of a bitmap chunk placed at the most significant bit
+#define BMP_ORIENT_MSB      0
+// first bit of a bitmap chunk placed at the least significant bit
+#define BMP_ORIENT_LSB      1
+
+#define BMP_NAME(name)          bitmap_##name
+#define BMP_PARAM_NAME          bmp
+#define BMP_PARAM(name)         struct BMP_NAME(name) *BMP_PARAM_NAME
+#define BMP_RAWBYTES(bits)      (((bits) + 7) / 8)
+#define BMP_SIZE(t, bits)       \
+            (BMP_RAWBYTES(bits) + (BMP_RAWBYTES(bits) % sizeof(t)))
+
+#define BMP_LEN(t, bits)        (BMP_SIZE(t, bits) / sizeof(t))
+
+#define _BITMAP_STRUCT(type, size, name, orient)  struct BMP_NAME(name)
+
+
+#define _DECLARE_BMP(type, size, name, orient)                                  \
+struct BMP_NAME(name) {                                                         \
+    type *_map;                                                                 \
+    unsigned long nr_bits;                                                      \
+}
+
+#define _DECLARE_BMP_STATIC(type, nr_bits, name, orient)                        \
+struct BMP_NAME(name) {                                                         \
+    type _map[BMP_LEN(type, nr_bits)];                                          \
+}
+
+#define BMP_STRCUT_MAP          BMP_PARAM_NAME->_map
+#define BMP_STRCUT_NRB          BMP_PARAM_NAME->nr_bits
+
+#define _BMP_OP_CALL(type, size, name, orient, suffix, ...)                     \
+bitmap_##name##_##suffix##(__VA_ARGS__)
+
+#define _DEFINE_BMP_INIT_OP(type, size, name, orient, allocfn)                  \
+static inline void                                                              \
+bitmap_##name##_init_with(BMP_PARAM(name), unsigned long nr_bits, ptr_t map)    \
+{                                                                               \
+(void)(is_const(size) ? ({                                                      \
+    BMP_STRCUT_MAP = map;                                                       \
+    BMP_STRCUT_NRB = nr_bits;                                                   \
+    memset(BMP_STRCUT_MAP, 0, BMP_SIZE(type, nr_bits) * sizeof(type));0;        \
+}) : ({                                                                         \
+    memset(BMP_STRCUT_MAP, 0, sizeof(BMP_STRCUT_MAP));0;                        \
+}));                                                                            \
+}                                                                               \
+static inline void                                                              \
+bitmap_##name##_init(BMP_PARAM(name), unsigned long nr_bits)                    \
+{                                                                               \
+(void)(is_const(size) ? ({                                                      \
+    bitmap_##name##_init_with(BMP_PARAM_NAME, nr_bits,                          \
+                            allocfn(BMP_SIZE(type, nr_bits)));0;                \
+}) : ({                                                                         \
+    bitmap_##name##_init_with(BMP_PARAM_NAME, nr_bits, NULL);0;                 \
+}));                                                                            \
+}
+
+
+#define _DEFINE_BMP_QUERY_OP(type, size, name, orient)                          \
+static inline bool                                                              \
+bitmap_##name##_query(BMP_PARAM(name), unsigned long pos)                       \
+{                                                                               \
+    assert(pos < size);                                                         \
+    unsigned long n = pos / (sizeof(type) * 8);                                 \
+    int i = pos % (sizeof(type) * 8);                                           \
+    type at = BMP_STRCUT_MAP[n];                                                     \
+    type msk = 1 << select(orient == BMP_ORIENT_MSB,                            \
+                            sizeof(type) * 8 - 1 - i, i );                      \
+    return !!(at & msk);                                                        \
+}
+
+
+#define _DEFINE_BMP_SET_OP(type, size, name, orient)                            \
+static inline void                                                              \
+bitmap_##name##_set(BMP_PARAM(name), unsigned long pos, bool val)               \
+{                                                                               \
+    assert(pos < size);                                                         \
+    unsigned long n = pos / (sizeof(type) * 8);                                 \
+    int i = pos % (sizeof(type) * 8);                                           \
+    type at = BMP_STRCUT_MAP[n];                                          \
+    unsigned int off = select(orient == BMP_ORIENT_MSB,                         \
+                            sizeof(type) * 8 - 1 - i, i );                      \
+    BMP_STRCUT_MAP[n] = (at & ~(1 << off)) | (!!val << off);              \
+}
+
+
+#define _DEFINE_BMP_ALLOCFROM_OP(type, size, name, orient)                      \
+static inline bool                                                              \
+bitmap_##name##_alloc_from(BMP_PARAM(name), unsigned long start,                \
+                            unsigned long* _out)                                \
+{                                                                               \
+    unsigned long i, p = 0;                                                     \
+    int shift;                                                                  \
+    type u;                                                                     \
+    i = start / 8 / sizeof(type);                                               \
+    shift = select(orient == BMP_ORIENT_MSB, sizeof(type) * 8 - 1, 0);          \
+    while ((u = BMP_STRCUT_MAP[i]) == (type)-1) i++;                            \
+    while ((u & (type)(1U << shift)) && p++ < sizeof(type) * 8)                 \
+        select(orient == BMP_ORIENT_MSB, u <<= 1, u >>= 1);                     \
+    if (p < sizeof(type) * 8)                                                   \
+        return false;                                                           \
+    BMP_STRCUT_MAP[i] |= 1UL << shift;                                          \
+    *_out = (i + p);                                                            \
+    return true;                                                                \
+}
+
+
+#define PREP_STATIC_BITMAP(type, name, nr_bits, orient)                         \
+            type, (nr_bits), name, orient
+#define PREP_BITMAP(type, name, orient)                                         \
+            type, (BMP_STRCUT_NRB), name, orient
+
+
+#define DECLARE_BITMAP(bmpdef)              _DECLARE_BMP(bmpdef)
+#define DECLARE_STATIC_BITMAP(bmpdef)       _DECLARE_BMP_STATIC(bmpdef)
+#define BITMAP(bmpdef)                      _BITMAP_STRUCT(bmpdef)
+
+#define DEFINE_BMP_INIT_OP(bmpdef, allocfn) _DEFINE_BMP_INIT_OP(bmpdef, allocfn)
+
+#define DEFINE_BMP_QUERY_OP(bmpdef)         _DEFINE_BMP_QUERY_OP(bmpdef)
+#define DEFINE_BMP_SET_OP(bmpdef)           _DEFINE_BMP_SET_OP(bmpdef)
+#define DEFINE_BMP_ALLOCFROM_OP(bmpdef)     _DEFINE_BMP_ALLOCFROM_OP(bmpdef)
+
+#define bitmap_query(bitmap, bmp, pos)      \
+    _BMP_OP_CALL(bitmap, query, bmp, pos) 
+
+#define bitmap_set(bitmap, bmp, pos, val)      \
+    _BMP_OP_CALL(bitmap, set, bmp, pos, val) 
+
+#define bitmap_alloc(bitmap, bmp, start, out)      \
+    _BMP_OP_CALL(bitmap, alloc_from, bmp, start, out) 
+
+#define bitmap_init(bitmap, bmp, nr_bits)      \
+    _BMP_OP_CALL(bitmap, init, bmp, nr_bits) 
+
+#define bitmap_init_ptr(bitmap, bmp, nr_bits, ptr)      \
+    _BMP_OP_CALL(bitmap, init_with, bmp, nr_bits, ptr) 
+
+
+#endif /* __LUNAIX_BITMAP_H */