X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/c50ef1526a29f29b65cf353a590ea36b9d2e963a..79d7be802edee0187df2f775d8f02b54bc49cd4a:/lunaix-os/arch/aarch64/soc/gic.c diff --git a/lunaix-os/arch/aarch64/soc/gic.c b/lunaix-os/arch/aarch64/soc/gic.c index ce666ea..ad24686 100644 --- a/lunaix-os/arch/aarch64/soc/gic.c +++ b/lunaix-os/arch/aarch64/soc/gic.c @@ -102,11 +102,15 @@ gic_create_from_dt() // ignore vcpu_if, as we dont do any EL2 stuff __create_its(gic_node); + + gic.gic_node = gic_node; } /* ++++++ GIC dirver ++++++ */ +/* ****** Interrupt Management ****** */ + static void __config_interrupt(struct arm_gic* gic, struct gic_distributor* dist, struct gic_interrupt* ent) @@ -121,7 +125,7 @@ __config_interrupt(struct arm_gic* gic, struct gic_distributor* dist, entry |= LPI_EN; - gic->lpi_tables.property[intid_rel] = entry; + gic->lpi_tables.prop_table[intid_rel] = entry; // clear any pending when we (re-)configuring bitmap_set(gic_bmp, &gic->lpi_tables.pendings, intid_rel, false); @@ -157,7 +161,7 @@ __undone_interrupt(struct arm_gic* gic, struct gic_distributor* dist, intid_rel = ent->intid - ent->domain->base; if (ent->config.class == GIC_LPI) { - gic->lpi_tables.property[intid_rel] = 0; + gic->lpi_tables.prop_table[intid_rel] = 0; // clear any pending when we (re-)configuring bitmap_set(gic_bmp, &gic->lpi_tables.pendings, intid_rel, false); @@ -172,57 +176,54 @@ __undone_interrupt(struct arm_gic* gic, struct gic_distributor* dist, } } -static struct gic_idomain* -__idomain(int nr_ints, unsigned int base, bool extended) + +static struct gic_interrupt* +__find_interrupt_record(unsigned int intid) { - struct gic_idomain* rec; + struct gic_idomain* domain; - rec = valloc(sizeof(*rec)); + domain = __deduce_domain(intid); - bitmap_init(gic_bmp, &rec->ivmap, nr_ints); - hashtable_init(rec->recs); + if (!domain) { + return NULL; + } - rec->base = base; - rec->extended = extended; + struct gic_interrupt *pos, *n; - return rec; + hashtable_hash_foreach(domain->recs, intid, pos, n, node) + { + if (pos->intid == intid) { + return pos; + } + } + + return NULL; } -static inline void -__init_distributor(struct gic_distributor* d, - gicreg_t* base, unsigned int nr_ints) +static inline struct gic_interrupt* +__register_interrupt(struct gic_idomain* domain, + unsigned int intid, struct gic_int_param* param) { - bitmap_init_ptr(gic_bmp, - &d->group, nr_ints, gic_regptr(base, GICD_IGROUPRn)); + struct gic_interrupt* interrupt; - bitmap_init_ptr(gic_bmp, - &d->grpmod, nr_ints, gic_regptr(base, GICD_IGRPMODRn)); + interrupt = valloc(sizeof(*interrupt)); + interrupt->config = (struct gic_intcfg) { + .class = param->class, + .trigger = param->trigger, + .group = param->group, + .as_nmi = param->as_nmi + }; - 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)); + interrupt->intid = intid; + interrupt->domain = domain; - 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)); -} + hashtable_hash_in(domain->recs, &interrupt->node, intid); -static inline struct leaflet* -__alloc_lpi_table(size_t table_sz) -{ - unsigned int val; - struct leaflet* tab; + return interrupt; +} - val = page_aligned(table_sz); - tab = alloc_leaflet(count_order(leaf_count(val))); - leaflet_wipe(tab); - return leaflet_addr(tab); -} +/* ****** Interrupt Domain Management ****** */ static struct gic_idomain* __deduce_domain(unsigned int intid) @@ -254,49 +255,73 @@ __deduce_domain(unsigned int intid) return NULL; } -static struct gic_interrupt* -__find_interrupt_record(unsigned int intid) +static struct gic_idomain* +__idomain(int nr_ints, unsigned int base, bool extended) { - struct gic_idomain* domain; + struct gic_idomain* rec; - domain = __deduce_domain(intid); + rec = valloc(sizeof(*rec)); - if (!domain) { - return NULL; - } + bitmap_init(gic_bmp, &rec->ivmap, nr_ints); + hashtable_init(rec->recs); - struct gic_interrupt *pos, *n; + rec->base = base; + rec->extended = extended; - hashtable_hash_foreach(domain->recs, intid, pos, n, node) - { - if (pos->intid == intid) { - return pos; - } - } + return rec; +} - return NULL; + +/* ****** Distributor-Related Management ****** */ + +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 gic_interrupt* -__register_interrupt(struct gic_idomain* domain, - unsigned int intid, struct gic_int_param* param) +static inline struct leaflet* +__alloc_lpi_table(size_t table_sz) { - struct gic_interrupt* interrupt; + unsigned int val; + struct leaflet* tab; - interrupt = valloc(sizeof(*interrupt)); - interrupt->config = (struct gic_intcfg) { - .class = param->class, - .trigger = param->trigger, - .group = param->group, - .as_nmi = param->as_nmi - }; + val = page_aligned(table_sz); + tab = alloc_leaflet(count_order(leaf_count(val))); + leaflet_wipe(tab); - interrupt->intid = intid; - interrupt->domain = domain; + return leaflet_addr(tab); +} - hashtable_hash_in(domain->recs, &interrupt->node, intid); +static inline void +__toggle_lpi_enable(struct gic_rd* rdist, bool en) +{ + gicreg_t val; - return interrupt; + if (!en) { + while ((val = rdist->base[GICR_CTLR]) & GICR_CTLR_RWP); + rdist->base[GICR_CTLR] = val & ~GICR_CTLR_EnLPI; + } + else { + rdist->base[GICR_CTLR] = val | GICR_CTLR_EnLPI; + } } static struct gic_distributor* @@ -317,6 +342,9 @@ __attached_distributor(int cpu, struct gic_interrupt* ent) return &gic.dist; } + +/* ****** GIC Components Configuration ****** */ + static void gic_configure_icc() { @@ -399,8 +427,14 @@ gic_configure_global(struct arm_gic* gic) 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); + struct leaflet* tab; + + tab = __alloc_lpi_table(gic->lpi_nr); + gic->lpi_tables.prop_table = vmap(tab, KERNEL_DATA); + gic->lpi_tables.prop_pa = leaflet_addr(tab); + + tab = __alloc_lpi_table(gic->lpi_nr / 8); + gic->lpi_tables.pend = leaflet_addr(tab); bitmap_init_ptr(gic_bmp, &gic->lpi_tables.pendings, gic->lpi_nr, gic->lpi_tables.pend); @@ -435,8 +469,10 @@ gic_configure_pe(struct arm_gic* gic, struct gic_pe* pe) __init_distributor(&pe->rdist, pe->_rd->sgi_base, nr_local_ints); + __toggle_lpi_enable(pe->_rd, false); + reg = 0; - BITS_SET(reg, GICR_BASER_PAddr, gic->lpi_tables.prop); + BITS_SET(reg, GICR_BASER_PAddr, gic->lpi_tables.prop_pa); BITS_SET(reg, GICR_BASER_Share, 0b01); BITS_SET(reg, GICR_PROPBASER_IDbits, ilog2(gic->max_intid)); pe->_rd->sgi_base[GICR_PROPBASER] = reg; @@ -446,8 +482,13 @@ gic_configure_pe(struct arm_gic* gic, struct gic_pe* pe) BITS_SET(reg, GICR_BASER_PAddr, gic->lpi_tables.pend); BITS_SET(reg, GICR_BASER_Share, 0b01); pe->_rd->sgi_base[GICR_PENDBASER] = reg; + + __toggle_lpi_enable(pe->_rd, true); } + +/* ****** Interrupt Life-cycle Management ****** */ + struct gic_interrupt* aa64_isrm_ivalloc(struct gic_int_param* param, isr_cb handler) { @@ -541,7 +582,7 @@ gic_update_active() pe->iar_val = val; } -static void +static inline void gic_signal_eoi() { struct gic_pe* pe; @@ -555,6 +596,8 @@ gic_signal_eoi() set_sysreg(ICC_EOIR1_EL1, pe->iar_val); } +/* ****** Lunaix ISRM Interfacing ****** */ + void isrm_init() { @@ -602,18 +645,6 @@ isrm_ivexalloc(isr_cb 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) { @@ -652,26 +683,65 @@ isrm_set_payload(int iv, ptr_t payload) } void -isrm_irq_attach(int irq, int iv, cpu_t dest, u32_t flags) +isrm_notify_eoi(cpu_t id, int iv) { - // Not supported + gic_signal_eoi(); } void -isrm_notify_eoi(cpu_t id, int iv) +isrm_notify_eos(cpu_t id) { - struct gic_interrupt* active; + isrm_notify_eoi(id, 0); +} - active = gic.pes[0].active; - assert(active); +msi_vector_t +isrm_msialloc(isr_cb handler) +{ + int intid; + msi_vector_t msiv; + struct gic_int_param param; + + param = (struct gic_int_param) { + .group = GIC_G1NS, + .trigger = GIC_TRIG_EDGE + }; + + if (gic.msi_via_spi) { + param.class = GIC_SPI; + + intid = aa64_isrm_ivalloc(¶m, handler); + msiv.msi_addr = gic_regptr(gic.mmrs.dist_base, GICD_SETSPI_NSR); + goto done; + } + + if (unlikely(!gic.lpi_ready)) { + return invalid_msi_vector; + } + + if (unlikely(gic.mmrs.its)) { + // TODO + WARN("ITS-base MSI is yet unsupported."); + return invalid_msi_vector; + } + + param.class = GIC_LPI; + intid = aa64_isrm_ivalloc(¶m, handler); + msiv.msi_addr = gic_regptr(gic.pes[0]._rd->base, GICR_SETLPIR); + +done: + msiv.mapped_iv = intid; + msiv.msi_data = intid; + + return msiv; } -void -isrm_notify_eos(cpu_t id) +int +isrm_bind_dtnode(struct dt_intr_node* node) { - isrm_notify_eoi(id, 0); + // TODO } +/* ****** Device Definition & Export ****** */ static void gic_init()