1 #include <lunaix/types.h>
2 #include <lunaix/device.h>
3 #include <lunaix/spike.h>
4 #include <lunaix/mm/valloc.h>
5 #include <lunaix/mm/page.h>
6 #include <lunaix/mm/mmio.h>
7 #include <lunaix/syslog.h>
9 #include <hal/devtree.h>
11 #include <asm/aa64_isrm.h>
12 #include <asm/soc/gic.h>
14 static struct arm_gic gic;
18 DEFINE_BMP_INIT_OP(gic_bmp, valloc);
20 DEFINE_BMP_QUERY_OP(gic_bmp);
22 DEFINE_BMP_SET_OP(gic_bmp);
24 DEFINE_BMP_ALLOCFROM_OP(gic_bmp);
26 /* ++++++ GIC dirver ++++++ */
28 /* ****** Interrupt Management ****** */
31 __config_interrupt(struct arm_gic* gic, struct gic_distributor* dist,
32 struct gic_interrupt* ent)
34 unsigned int intid_rel;
35 unsigned long trig_index;
37 intid_rel = ent->intid - ent->domain->base;
39 if (ent->config.class == GIC_LPI) {
40 lpi_entry_t entry = 0;
44 gic->lpi_tables.prop_table[intid_rel] = entry;
46 // clear any pending when we (re-)configuring
47 bitmap_set(gic_bmp, &gic->lpi_tables.pendings, intid_rel, false);
53 bitmap_set(gic_bmp, &dist->group, intid_rel, 0);
54 bitmap_set(gic_bmp, &dist->grpmod, intid_rel, 1);
56 trig_index = intid_rel * 2;
57 bitmap_set(gic_bmp, &dist->icfg, trig_index, 0);
58 if (ent->config.trigger == GIC_TRIG_EDGE) {
59 bitmap_set(gic_bmp, &dist->icfg, trig_index + 1, 1);
61 bitmap_set(gic_bmp, &dist->icfg, trig_index + 1, 0);
65 bitmap_set(gic_bmp, &dist->nmi, intid_rel, ent->config.as_nmi);
68 bitmap_set(gic_bmp, &dist->enable, intid_rel, true);
72 __undone_interrupt(struct arm_gic* gic, struct gic_distributor* dist,
73 struct gic_interrupt* ent)
75 unsigned int intid_rel;
77 intid_rel = ent->intid - ent->domain->base;
79 if (ent->config.class == GIC_LPI) {
80 gic->lpi_tables.prop_table[intid_rel] = 0;
82 // clear any pending when we (re-)configuring
83 bitmap_set(gic_bmp, &gic->lpi_tables.pendings, intid_rel, false);
88 bitmap_set(gic_bmp, &dist->disable, intid_rel, true);
91 bitmap_set(gic_bmp, &dist->nmi, intid_rel, false);
95 static inline struct gic_interrupt*
96 __get_interrupt(struct gic_idomain* domain, unsigned int rel_intid)
98 struct gic_interrupt *pos, *n;
101 intid = rel_intid + domain->base;
102 hashtable_hash_foreach(domain->recs, intid, pos, n, node)
104 if (pos->intid == intid) {
112 static struct gic_interrupt*
113 __find_interrupt_record(unsigned int intid)
115 struct gic_idomain* domain;
117 domain = __deduce_domain(intid);
123 return __get_interrupt(domain, intid - domain->base);
126 static inline struct gic_interrupt*
127 __register_interrupt(struct gic_idomain* domain,
128 unsigned int intid, struct gic_int_param* param)
130 struct gic_interrupt* interrupt;
132 interrupt = valloc(sizeof(*interrupt));
133 interrupt->config = (struct gic_intcfg) {
134 .class = param->class,
135 .trigger = param->trigger,
136 .group = param->group,
137 .as_nmi = param->as_nmi
140 interrupt->intid = intid;
141 interrupt->domain = domain;
143 hashtable_hash_in(domain->recs, &interrupt->node, intid);
149 /* ****** Interrupt Domain Management ****** */
151 static struct gic_idomain*
152 __deduce_domain(unsigned int intid)
154 if (intid <= INITID_SGI_END) {
155 return gic.pes[0].idomain.local_ints;
158 if (intid <= INITID_PPI_END) {
159 return gic.pes[0].idomain.local_ints;
162 if (intid <= INITID_SPI_END) {
163 return gic.idomain.spi;
166 if (INITID_ePPI_BASE <= intid && intid <= INITID_ePPI_END) {
167 return gic.pes[0].idomain.eppi;
170 if (INITID_eSPI_BASE <= intid && intid <= INITID_eSPI_END) {
171 return gic.idomain.espi;
174 if (intid >= INITID_LPI_BASE) {
175 return gic.idomain.lpi;
181 static struct gic_idomain*
182 __idomain(int nr_ints, unsigned int base, bool extended)
184 struct gic_idomain* rec;
186 rec = valloc(sizeof(*rec));
188 bitmap_init(gic_bmp, &rec->ivmap, nr_ints);
189 hashtable_init(rec->recs);
192 rec->extended = extended;
198 /* ****** Distributor-Related Management ****** */
201 __init_distributor(struct gic_distributor* d,
202 gicreg_t* base, unsigned int nr_ints)
204 bitmap_init_ptr(gic_bmp,
205 &d->group, nr_ints, gic_regptr(base, GICD_IGROUPRn));
207 bitmap_init_ptr(gic_bmp,
208 &d->grpmod, nr_ints, gic_regptr(base, GICD_IGRPMODRn));
210 bitmap_init_ptr(gic_bmp,
211 &d->enable, nr_ints, gic_regptr(base, GICD_ISENABLER));
213 bitmap_init_ptr(gic_bmp,
214 &d->disable, nr_ints, gic_regptr(base, GICD_ICENABLER));
216 bitmap_init_ptr(gic_bmp,
217 &d->icfg, nr_ints * 2, gic_regptr(base, GICD_ICFGR));
219 bitmap_init_ptr(gic_bmp,
220 &d->nmi, nr_ints, gic_regptr(base, GICD_INMIR));
223 static inline struct leaflet*
224 __alloc_lpi_table(size_t table_sz)
229 val = page_aligned(table_sz);
230 tab = alloc_leaflet(count_order(leaf_count(val)));
233 return leaflet_addr(tab);
237 __toggle_lpi_enable(struct gic_rd* rdist, bool en)
242 while ((val = rdist->base[GICR_CTLR]) & GICR_CTLR_RWP);
243 rdist->base[GICR_CTLR] = val & ~GICR_CTLR_EnLPI;
246 rdist->base[GICR_CTLR] = val | GICR_CTLR_EnLPI;
250 static struct gic_distributor*
251 __attached_distributor(int cpu, struct gic_interrupt* ent)
253 enum gic_int_type iclass;
255 iclass = ent->config.class;
257 if (iclass == GIC_PPI || iclass == GIC_SGI) {
258 return &gic.pes[cpu].rdist;
261 if (ent->domain->extended) {
269 /* ****** GIC Components Configuration ****** */
277 sysreg_flagging(ICC_SRE_EL1,
278 ICC_SRE_SRE | ICC_SRE_DFB | ICC_SRE_DIB,
283 sysreg_flagging(ICC_CTLR_EL1,
285 ICC_CTRL_EOImode | ICC_CTRL_PMHE);
287 // disable all group 0 interrupts as those are meant for EL3
289 sysreg_flagging(ICC_IGRPEN0_EL1, 0, ICC_IGRPEN_ENABLE);
291 // enable all group 1 interrupts, we'll stick with EL1_NS
293 sysreg_flagging(ICC_IGRPEN1_EL1, ICC_IGRPEN_ENABLE, 0);
297 gic_configure_global(struct arm_gic* gic)
300 unsigned int val, max_nr_spi;
302 reg = gic->mmrs.dist_base[GICD_TYPER];
304 // check if eSPI supported
305 gic->has_espi = (reg & GICD_TYPER_ESPI);
307 val = BITS_GET(reg, GICD_TYPER_nESPI);
308 gic->espi_nr = 32 * (val + 1);
312 val = BITS_GET(reg, GICD_TYPER_IDbits);
313 gic->max_intid = 1 << (val + 1) - 1;
317 val = BITS_GET(reg, GICD_TYPER_nLPI);
319 gic->lpi_nr = 1 << (val + 1);
322 gic->lpi_nr = gic->max_intid - INITID_LPI_BASE + 1;
326 // check if SPI supported
327 val = BITS_GET(reg, GICD_TYPER_nSPI);
329 max_nr_spi = 32 * (val + 1);
330 gic->spi_nr = MIN(max_nr_spi, INITID_SPEC_BASE);
331 gic->spi_nr -= INITID_SPI_BASE;
336 gic->nmi_ready = (reg & GICD_TYPER_NMI);
337 gic->msi_via_spi = (reg & GICD_TYPER_MBIS);
339 __init_distributor(&gic->dist, gic->mmrs.dist_base, gic->spi_nr);
340 __init_distributor(&gic->dist_e, gic->mmrs.dist_base, gic->espi_nr);
344 gic->idomain.spi = __idomain(gic->spi_nr, INITID_SPI_BASE, false);
347 gic->idomain.espi = __idomain(gic->espi_nr, INITID_eSPI_BASE, true);
350 gic->idomain.lpi = __idomain(gic->lpi_nr, INITID_LPI_BASE, false);
355 tab = __alloc_lpi_table(gic->lpi_nr);
356 gic->lpi_tables.prop_table = vmap(tab, KERNEL_DATA);
357 gic->lpi_tables.prop_pa = leaflet_addr(tab);
359 tab = __alloc_lpi_table(gic->lpi_nr / 8);
360 gic->lpi_tables.pend = leaflet_addr(tab);
362 bitmap_init_ptr(gic_bmp,
363 &gic->lpi_tables.pendings, gic->lpi_nr, gic->lpi_tables.pend);
367 gic_configure_pe(struct arm_gic* gic, struct gic_pe* pe)
369 unsigned int nr_local_ints;
372 reg = gic_reg64(pe->_rd, GICR_TYPER);
374 pe->affinity = BITS_GET(reg, GICR_TYPER_AffVal);
375 pe->ppi_nr = INITID_PPI_BASE;
376 switch (BITS_GET(reg, GICR_TYPER_PPInum))
379 pe->ppi_nr += 1088 - INITID_ePPI_BASE;
380 pe->eppi_ready = true;
383 pe->ppi_nr += 1120 - INITID_ePPI_BASE;
384 pe->eppi_ready = true;
388 nr_local_ints = pe->ppi_nr + INITID_PPI_BASE;
390 pe->idomain.local_ints = __idomain(32, 0, false);
391 pe->idomain.eppi = __idomain(nr_local_ints - 32, INITID_ePPI_BASE, true);
393 __init_distributor(&pe->rdist, pe->_rd->sgi_base, nr_local_ints);
395 __toggle_lpi_enable(pe->_rd, false);
398 BITS_SET(reg, GICR_BASER_PAddr, gic->lpi_tables.prop_pa);
399 BITS_SET(reg, GICR_BASER_Share, 0b01);
400 BITS_SET(reg, GICR_PROPBASER_IDbits, ilog2(gic->max_intid));
401 pe->_rd->sgi_base[GICR_PROPBASER] = reg;
404 reg |= GICR_PENDBASER_PTZ;
405 BITS_SET(reg, GICR_BASER_PAddr, gic->lpi_tables.pend);
406 BITS_SET(reg, GICR_BASER_Share, 0b01);
407 pe->_rd->sgi_base[GICR_PENDBASER] = reg;
409 __toggle_lpi_enable(pe->_rd, true);
413 /* ****** Interrupt Life-cycle Management ****** */
416 struct gic_interrupt*
417 gic_install_int(struct gic_int_param* param, isr_cb handler, bool alloc)
420 struct gic_idomain* domain;
421 struct gic_interrupt* ent;
422 struct gic_distributor* dist;
429 switch (param->class)
432 if (!param->ext_range) {
433 domain = gic.pes[cpu].idomain.local_ints;
436 domain = gic.pes[cpu].idomain.eppi;
441 domain = gic.pes[cpu].idomain.local_ints;
445 if (!param->ext_range) {
446 assert(gic.spi_nr > 0);
447 domain = gic.idomain.spi;
450 assert(gic.has_espi);
451 domain = gic.idomain.espi;
456 assert(gic.lpi_ready);
457 domain = gic.idomain.lpi;
461 fail("unknown interrupt class");
466 if (!bitmap_alloc(gic_bmp, &domain->ivmap, 0, &iv)) {
467 FATAL("out of usable iv for class=%d", param->class);
471 iv = param->rel_intid;
472 if ((ent = __get_interrupt(domain, iv))) {
476 bitmap_set(gic_bmp, &domain->ivmap, iv, true);
481 if (param->class == GIC_SPI && !param->ext_range && iv >= INITID_ePPI_BASE)
483 WARN("PPI vector=%d falls in extended range, while not requested.", iv);
484 param->ext_range = true;
487 ent = __register_interrupt(domain, iv, param);
488 dist = __attached_distributor(cpu, ent);
490 __config_interrupt(&gic, dist, ent);
492 ent->handler = handler;
502 struct gic_interrupt* intr;
506 val = read_sysreg(ICC_IAR1_EL1);
507 intid = (unsigned int)val & ((1 << 24) - 1);
509 if (check_special_intid(intid)) {
513 intr = __find_interrupt_record(intid);
529 set_sysreg(ICC_EOIR1_EL1, pe->iar_val);
532 /* ****** Lunaix ISRM Interfacing ****** */
543 struct gic_interrupt* ent;
544 struct gic_distributor* dist;
546 ent = __find_interrupt_record(iv);
551 dist = __attached_distributor(0, ent);
552 __undone_interrupt(&gic, dist, ent);
554 hlist_delete(&ent->node);
559 isrm_ivosalloc(isr_cb handler)
561 return isrm_ivexalloc(handler);
565 isrm_ivexalloc(isr_cb handler)
567 struct gic_int_param param;
568 struct gic_interrupt* intr;
570 param = (struct gic_int_param) {
573 .trigger = GIC_TRIG_EDGE,
576 intr = gic_install_int(¶m, handler, true);
584 struct gic_interrupt* intr;
586 intr = __find_interrupt_record(iv);
591 return intr->handler;
595 isrm_get_payload(const struct hart_state* state)
597 struct gic_interrupt* active;
599 active = gic.pes[0].active;
602 return active->handler;
606 isrm_set_payload(int iv, ptr_t payload)
608 struct gic_interrupt* intr;
610 intr = __find_interrupt_record(iv);
615 intr->payload = payload;
619 isrm_notify_eoi(cpu_t id, int iv)
625 isrm_notify_eos(cpu_t id)
627 isrm_notify_eoi(id, 0);
631 isrm_msialloc(isr_cb handler)
635 struct gic_int_param param;
637 param = (struct gic_int_param) {
639 .trigger = GIC_TRIG_EDGE
642 if (gic.msi_via_spi) {
643 param.class = GIC_SPI;
645 intid = gic_install_int(¶m, handler, true);
646 msiv.msi_addr = gic_regptr(gic.mmrs.dist_base, GICD_SETSPI_NSR);
650 if (unlikely(!gic.lpi_ready)) {
651 return invalid_msi_vector;
654 if (unlikely(llist_empty(&gic.its))) {
655 // FIXME The MSI interface need rework
656 WARN("ITS-base MSI is yet unsupported.");
657 return invalid_msi_vector;
660 param.class = GIC_LPI;
661 intid = gic_install_int(¶m, handler, true);
662 msiv.msi_addr = gic_regptr(gic.pes[0]._rd->base, GICR_SETLPIR);
665 msiv.mapped_iv = intid;
666 msiv.msi_data = intid;
672 isrm_bind_dtnode(struct dt_intr_node* node, isr_cb handler)
674 struct dt_prop_val* val;
675 struct gic_int_param param;
676 struct gic_interrupt* installed;
678 val = dt_resolve_interrupt(INTR_TO_DTNODE(node));
683 if (node->intr.extended) {
684 WARN("binding of multi interrupt is yet to supported");
688 gic_dtprop_interpret(¶m, val, 3);
691 installed = gic_install_int(¶m, handler, false);
693 return installed->intid;
696 /* ****** Device Definition & Export ****** */
701 memset(&gic, 0, sizeof(gic));
703 gic_create_from_dt(&gic);
705 // configure the system interfaces
708 // configure global distributor
709 gic_configure_global(&gic);
711 // configure per-PE local distributor (redistributor)
712 for (int i = 0; i < NR_CPU; i++)
714 gic_configure_pe(&gic, &gic.pes[i]);
717 gic_configure_its(&gic);
720 static struct device_def dev_arm_gic = {
721 .name = "ARM Generic Interrupt Controller",
722 .class = DEVCLASS(DEVIF_SOC, DEVFN_CFG, DEV_INTC),
725 EXPORT_DEVICE(arm_gic, &dev_arm_gic, load_sysconf);