// 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)
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);
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);
}
}
-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)
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*
return &gic.dist;
}
+
+/* ****** GIC Components Configuration ****** */
+
static void
gic_configure_icc()
{
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);
__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;
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)
{
pe->iar_val = val;
}
-static void
+static inline void
gic_signal_eoi()
{
struct gic_pe* pe;
set_sysreg(ICC_EOIR1_EL1, pe->iar_val);
}
+/* ****** Lunaix ISRM Interfacing ****** */
+
void
isrm_init()
{
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)
{
}
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()