2 * Arm Generic Interrupt Controller v3
5 #include <lunaix/mm/page.h>
6 #include <lunaix/mm/valloc.h>
7 #include <lunaix/mm/mmio.h>
8 #include <klibc/string.h>
13 __gic_bitmap_setf(u32_t* bmp, intid_t intid, bool flag)
16 bmp[intid / 32] |= 1 << (intid % 32);
18 bmp[intid / 32] &= ~(1 << (intid % 32));
23 __gic_bitmap_getf(u32_t* bmp, intid_t intid)
25 return !!(bmp[intid / 32] & (1 << (intid % 32)));
29 __gic_bitmap_setv(u32_t* bmp, intid_t intid, int val, u32_t width_bits)
31 u32_t slots = 32 / width_bits;
32 u32_t mask = (1 << width_bits) - 1;
35 _val = bmp[intid / slots];
36 _val &= ~(mask << (intid % slots));
37 bmp[intid / slots] = (_val & mask) << (intid % slots);
41 __gic_bitmap_getv(u32_t* bmp, intid_t intid, u32_t width_bits)
43 u32_t slots = 32 / width_bits;
44 u32_t mask = (1 << width_bits) - 1;
46 return !!(bmp[intid / slots] & (mask << (intid % slots)));
50 __spi_set_group(struct gic_int_class* class,
51 intid_t intid, enum gic_intgrp grp)
53 struct v3_distr* distr = v3distr_class(class);
54 if (grp == GIC_INT_GROUP0) {
55 __gic_bitmap_setf(distr->gicd->igrpmodr, intid, 0);
56 __gic_bitmap_setf(distr->gicd->igroupr, intid, 0);
58 else if (grp == GIC_INT_GROUP1_S) {
59 __gic_bitmap_setf(distr->gicd->igrpmodr, intid, 1);
60 __gic_bitmap_setf(distr->gicd->igroupr, intid, 0);
62 else if (grp == GIC_INT_GROUP1_NS) {
63 __gic_bitmap_setf(distr->gicd->igrpmodr, intid, 0);
64 __gic_bitmap_setf(distr->gicd->igroupr, intid, 1);
74 __spi_set_enabled(struct gic_int_class* class, intid_t intid, bool en)
76 struct v3_distr* distr = v3distr_class(class);
79 __gic_bitmap_setf(distr->gicd->isenabler, intid, true);
81 __gic_bitmap_setf(distr->gicd->icenabler, intid, true);
88 __spi_set_prority(struct gic_int_class* class, intid_t intid, int prio)
90 struct v3_distr* distr = v3distr_class(class);
91 __gic_bitmap_setv(distr->gicd->ipriorityr, intid, prio, 8);
97 __spi_set_nmi(struct gic_int_class* class, intid_t intid, bool nmi)
99 struct v3_distr* distr = v3distr_class(class);
100 __gic_bitmap_setf(distr->gicd->isenabler, intid, nmi);
106 __spi_set_route(struct gic_int_class* class,
107 intid_t intid, struct gic_pe* target)
109 int aff_val = target->affinity;
110 int aff3 = aff_val >> 24;
111 int aff210 = aff_val & ((1 << 24) - 1);
113 struct v3_distr* distr = v3distr_class(class);
114 distr->gicd->irouter[intid - 32] = ((u64_t)aff3 << 32) | aff210;
120 __spi_set_trigger(struct gic_int_class* class,
121 intid_t intid, enum gic_trigger trig)
123 int trig_val = trig == GIC_TRIG_EDGE ? 0b10 : 0b00;
125 struct v3_distr* distr = v3distr_class(class);
126 __gic_bitmap_setv(distr->gicd->icfgr, intid, trig_val, 2);
133 __spi_retrieve(struct gic_int_class* class,
134 struct gic_interrupt* intr, intid_t intid)
137 struct v3_distr* distr = v3distr_class(class);
138 union v3_gicd_map* gicd = distr->gicd;
140 intr->enabled = __gic_bitmap_getf(gicd->isenabler, intid);
141 intr->nmi = __gic_bitmap_getf(gicd->inmir, intid);
143 intr->priority = __gic_bitmap_getv(gicd->ipriorityr, intid, 8);
145 u64_t affr = gicd->irouter[intid - 32];
146 val = (((affr >> 32) & 0xff) << 24) | (affr & ((1 << 24) - 1));
147 gic_intr_set_raw_affval(intr, val);
149 val = __gic_bitmap_getv(gicd->icfgr, intid, 2);
150 intr->trig = val == 0b10 ? GIC_TRIG_EDGE : GIC_TRIG_LEVEL;
152 val = __gic_bitmap_getf(gicd->igrpmodr, intid);
153 val = (val << 1) | __gic_bitmap_getf(gicd->igroupr, intid);
155 intr->grp = GIC_INT_GROUP0;
157 else if (val == 0b01) {
158 intr->grp = GIC_INT_GROUP1_NS;
160 else if (val == 0b10) {
161 intr->grp = GIC_INT_GROUP1_S;
171 __spi_install(struct gic_int_class* class, struct gic_interrupt* intr)
173 __spi_set_group(class, intr->intid, intr->grp);
174 __spi_set_nmi(class, intr->intid, intr->nmi);
175 __spi_set_prority(class, intr->intid, intr->priority);
176 __spi_set_route(class, intr->intid, intr->affinity.pe);
177 __spi_set_trigger(class, intr->intid, intr->trig);
183 __spi_delete(struct gic_int_class* class, intid_t intid)
185 __spi_set_enabled(class, intid, false);
189 __lpi_write_invlpir(struct v3_pe* pe, intid_t intid)
191 // ensure coherent for configuration write
194 // flush the redistributor cache (only directLPI).
195 if (pe->direct_lpi) {
196 pe->gicr->invlpir = intid;
199 // ITS cache is flushed in upstream caller.
204 __lpi_set_enabled(struct gic_int_class* class, intid_t intid, bool en)
206 struct v3_pe* pe = v3pe_class(class);
211 val = pe->lpi_tab[intid - 8192];
212 pe->lpi_tab[intid - 8192] = (val & ~1) | (en & 1);
214 __lpi_write_invlpir(pe, intid);
218 __lpi_set_prority(struct gic_int_class* class, intid_t intid, int prio)
220 struct v3_pe* pe = v3pe_class(class);
224 pe->lpi_tab[intid - 8192] = prio & 0xfc;
226 __lpi_write_invlpir(pe, intid);
230 __lpi_retrieve(struct gic_int_class* class,
231 struct gic_interrupt* intr, intid_t intid)
233 struct v3_pe* pe = v3pe_class(class);
238 val = pe->lpi_tab[intid - 8192];
240 intr->enabled = !!(val & 1);
241 intr->priority = val & 0xfc;
242 intr->trig = GIC_TRIG_EDGE;
243 intr->grp = GIC_INT_GROUP1_NS;
244 intr->affinity.pe = pe;
251 __lpi_install(struct gic_int_class* class, struct gic_interrupt* intr)
253 struct v3_pe* pe = v3pe_class(class);
254 struct irq_object* irq = intr->irq;
256 __lpi_set_prority(class, intr->intid, intr->priority);
258 if (pe->direct_lpi) {
259 irq->msi->message = intr->intid;
260 irq->msi->wr_addr = __ptr(&pe->gicr->setlpir);
263 // for ITS backed LPI, it will installed separately, so we are done.
268 __pe_ack_interrupt(struct gic_pe* pe)
272 id = read_sysreg(ICC_IAR1_EL1);
276 id == read_sysreg(ICC_NMIAR1_EL1);
284 fail("impossible intid");
293 __pe_notify_eoi(struct gic_pe* pe)
295 if (!pe->has_active_int) {
299 assert(pe->active_int.grp == GIC_INT_GROUP1_NS);
301 set_sysreg(ICC_EOIR1_EL1, pe->active_id);
302 set_sysreg(ICC_DIR_EL1, pe->active_id);
307 __pe_set_priority_mask(struct gic_pe* pe, int mask)
309 set_sysreg(ICC_PMR_EL1, mask & 0xff);
313 static struct gic_int_class_ops spi_ops = {
314 .set_enabled = __spi_set_enabled,
315 .set_nmi = __spi_set_nmi,
316 .set_prority = __spi_set_prority,
317 .set_route = __spi_set_route,
318 .set_trigger = __spi_set_trigger,
319 .install = __spi_install,
320 .retrieve = __spi_retrieve,
321 .delete = __spi_delete
324 static struct gic_int_class_ops lpi_ops = {
325 .set_enabled = __lpi_set_enabled,
326 .set_nmi = __fallback_set_nmi,
327 .set_prority = __lpi_set_prority,
328 .set_route = __fallback_set_route,
329 .set_trigger = __fallback_set_trigger,
330 .install = __lpi_install,
331 .retrieve = __lpi_retrieve,
332 .delete = __fallback_delete
335 static struct gic_pe_ops pe_ops = {
336 .ack_int = __pe_ack_interrupt,
337 .notify_eoi = __pe_notify_eoi,
338 .set_priority_mask = __pe_set_priority_mask
342 v3_enable_interrupt(struct gic* gic)
345 struct v3_distr* distr;
347 set_sysreg(ICC_IGRPEN1_EL1, ICC_IGRPEN_ENABLE);
349 for (int i = 0; i < gic->nr_cpus; i++)
351 assert(gic->cores[i]);
353 v3pe = (struct v3_pe*)gic->cores[i]->impl;
354 v3pe->gicr->ctlr |= GICR_CTLR_EnLPI;
357 distr = (struct v3_distr*)gic->impl;
358 distr->gicd->ctlr |= GICD_CTLR_G1NSEN;
362 v3_config_redistr(struct v3_pe* v3_pe)
365 struct leaflet* page;
367 int nr_pages, nr_lpis;
371 // Configure LPI Tables
373 if (!gic_valid_int_class(&pe->lpi)) {
377 // We only use at most 8192 LPIs
379 nr_pages = page_count(8192, PAGE_SIZE);
383 We map all the LPI tables as device memory (nGnRnE),
384 and Non-shareable. However, these combination implies
385 Outer-Shareable (R_PYFVQ), which ensure visibility across
389 // 8192 LPIs, two 4K pages
390 page = alloc_leaflet_pinned(to_napot_order(nr_pages));
392 val = leaflet_addr(page) | (ilog2(nr_lpis) + 1);
393 v3_pe->gicr->propbaser = val;
395 // 8192 LPIs, 1024K sized bmp, consider 64K alignment
396 nr_pages = page_count(PAGE_64K, PAGE_SIZE);
397 page = alloc_leaflet_pinned(to_napot_order(nr_pages));
399 v3_pe->lpi_tab_ptr = vmap(page, KERNEL_DATA);
402 Alignment correction,
403 given a 64K-unaligned base address of 64K leaflet
404 any upalignment to 64K boundary still falls within the
405 leaflet, thus always leaving at least one free base-page
407 val = leaflet_addr(page);
408 if (val & (PAGE_64K - 1)) {
409 val = napot_upaligned(val, PAGE_64K);
412 val = val | GICR_PENDBASER_PTZ | (ilog2(nr_lpis) + 1);
413 v3_pe->gicr->pendbaser = val;
417 v3_config_icc(struct v3_pe* pe)
419 sysreg_flagging(ICC_CTLR_EL1, 0, ICC_CTRL_EOImode);
420 sysreg_flagging(ICC_CTLR_EL1, ICC_CTRL_CBPR, 0);
421 sysreg_flagging(ICC_CTLR_EL1, ICC_CTRL_PMHE, 0);
423 set_sysreg(ICC_PMR_EL1, 0xff); // all 256 priority values
424 set_sysreg(ICC_BPR0_EL1, 7); // no preemption
428 v3_config_distr(struct gic* gic, struct v3_distr* distr)
431 union v3_gicd_map* gicd;
432 unsigned int intid_max, lpi_max;
436 ctlr = GICD_CTLR_DS | GICD_CTLR_ARE_NS;
439 intid_max = BITS_GET(gicd->typer, GICD_TYPER_nSPI);
441 intid_max = 32 * (intid_max + 1) - 1;
442 gic_init_int_class(&gic->spi, GIC_INT_SPI, 32, intid_max);
443 gic->spi.ops = &spi_ops;
446 intid_max = BITS_GET(gicd->typer, GICD_TYPER_nESPI);
447 if ((gicd->typer & GICD_TYPER_ESPI)) {
448 intid_max = 32 * (intid_max + 1) + 4095;
449 gic_init_int_class(&gic->spi_e, GIC_INT_SPI_EXT, 4096, intid_max);
454 v3_config_pe(struct gic* gic, struct gic_pe* pe)
457 unsigned int affval, ppi_num;
458 unsigned int intid_max, lpi_max;
460 union v3_rdbase_map *gicr;
461 union v3_gicd_map* gicd;
464 gicd = v3distr(gic)->gicd;
467 affval = BITS_GET(gicr->typer, GICR_TYPER_AffVal);
468 ppi_num = BITS_GET(gicr->typer, GICR_TYPER_PPInum);
470 pe->affinity = affval;
471 v3_pe->direct_lpi = !!(gicr->typer & GICR_TYPER_DirectLPI);
473 gic_init_int_class(&pe->sgi, GIC_INT_SGI, 0, 15);
474 gic_init_int_class(&pe->ppi, GIC_INT_PPI, 16, 31);
479 gic_init_int_class(&pe->ppi_e, GIC_INT_PPI_EXT, 1056, 1087);
483 gic_init_int_class(&pe->ppi_e, GIC_INT_PPI_EXT, 1056, 1119);
487 intid_max = BITS_GET(gicd->typer, GICD_TYPER_IDbits);
488 intid_max = 1 << (intid_max + 1);
490 if (intid_max > 8192) {
491 // NOTE the minimum support of 8192 LPIs is far enough.
493 // lpi_max = BITS_GET(gicd->typer, GICD_TYPER_nLPI);
495 // lpi_max = ((1 << (lpi_max + 1)) - 1) + 8192;
497 // lpi_max = intid_max - 1;
500 gic_init_int_class(&pe->lpi, GIC_INT_LPI, 8192, 8192 * 2);
501 pe->lpi.ops = &lpi_ops;
504 v3_config_redistr(pe);
513 __its_alloc_itt(struct v3_its* its)
515 struct leaflet* leaflet;
516 struct v3_itt_alloc* ita;
518 ita = &its->itt_alloc;
521 if (unlikely(ita->page)) {
522 leaflet = alloc_leaflet_pinned(0);
523 leaflet_wipe(leaflet);
525 ita->page = leaflet_addr(leaflet);
526 memset(ita->free_map, 0, sizeof(ita->free_map));
529 for (int i = 0; i < sizeof(ita->free_map); i++)
531 if (ita->free_map[i] == 0xff)
534 for (int j = 0; j < 8; j++) {
535 if (ita->free_map[i] & (1 << j)) {
539 ita->free_map[i] |= 1 << j;
540 return ita->page + (i * 8 + j) * 256;
548 #define irq_devid(irq) ((irq)->msi->sideband)
549 #define irq_evtid(irq) ((irq)->msi->message)
552 __its_cmd_inv(struct v3_its_cmd* cmd, irq_t irq)
554 *cmd = (struct v3_its_cmd) {
555 .dw0 = (u64_t)irq_devid(irq) << 32 | 0xc,
556 .dw1 = irq_evtid(irq)
561 __its_cmd_mapc(struct v3_its_cmd* cmd, struct v3_pe* v3_pe)
563 *cmd = (struct v3_its_cmd) {
565 .dw2 = (1UL << 63) | v3_pe->pe->index | v3_pe->rd_base
570 __its_cmd_mapd(struct v3_its_cmd* cmd, struct v3_its* its, irq_t irq)
572 *cmd = (struct v3_its_cmd) {
573 .dw0 = (u64_t)irq_devid(irq) << 32 | 0x8,
575 .dw2 = (1UL << 63) | __its_alloc_itt(its)
580 __its_cmd_mapti(struct v3_its_cmd* cmd, irq_t irq, int pe_index)
582 *cmd = (struct v3_its_cmd) {
583 .dw0 = (u64_t)irq_devid(irq) << 32 | 0xa,
584 .dw1 = (u64_t)irq->vector << 32 | irq_evtid(irq),
590 __its_issue_cmd(struct v3_its* its, struct v3_its_cmd* cmd)
594 wr = its->gits->cwriter >> 5;
596 rd = its->gits->creadr >> 5;
597 } while (wr > rd && wr - rd == 1);
599 its->cmdq[wr] = *cmd;
600 wr = (wr + 1) % its->cmdq_size;
602 its->gits->cwriter = wr << 5;
606 __its_domain_install_irq(struct irq_domain *itsd, irq_t irq)
610 struct v3_its_cmd cmd;
612 struct gic_interrupt gici;
614 its = irq_domain_obj(itsd, struct v3_its);
616 if (irq->type != IRQ_MESSAGE) {
620 pe = its->gic->cores[0];
621 err = gic_assign_intid(&pe->lpi, irq);
626 gici.intid = irq->vector;
630 __lpi_install(&pe->lpi, &gici);
632 __its_cmd_mapd(&cmd, its, irq);
633 __its_issue_cmd(its, &cmd);
635 __its_cmd_mapti(&cmd, irq, 0);
636 __its_issue_cmd(its, &cmd);
638 __its_cmd_inv(&cmd, irq);
639 __its_issue_cmd(its, &cmd);
641 __lpi_set_enabled(&pe->lpi, irq->vector, true);
643 irq->msi->wr_addr = __ptr(&its->gtrn->translater);
649 __its_domain_remove_irq(struct irq_domain *itsd, irq_t irq)
655 static struct irq_domain_ops its_ops = {
656 .install_irq = __its_domain_install_irq,
657 .remove_irq = __its_domain_remove_irq
661 __setup_basern_memory(struct v3_its* its, size_t ent_sz, size_t nr_ents)
663 u64_t val, *ind_pages;
664 int nr_pages, pgsize;
665 struct leaflet* page, *sub_page;
667 nr_pages = page_count(ent_sz * nr_ents, PAGE_SIZE);
668 page = alloc_leaflet_pinned(0);
671 val = GITS_BASER_VALID;
680 BITS_SET(val, GITS_BASERn_PGSZ, pgsize);
683 val |= leaflet_addr(page);
687 ind_pages = (u64_t*)vmap(page, KERNEL_DATA);
688 for (int i = 0; i < nr_pages; i++)
690 sub_page = alloc_leaflet_pinned(0);
691 leaflet_wipe(sub_page);
692 ind_pages[i] = val | leaflet_addr(sub_page);
695 vunmap(__ptr(ind_pages), page);
696 val |= GITS_BASER_Ind | leaflet_addr(page);
701 static struct irq_domain*
702 v3_init_its_domain(struct gic* gic,
703 struct device* its_dev, struct v3_its* its)
706 struct leaflet* page;
707 struct irq_domain* domain;
708 union v3_its_regs* gits;
709 struct v3_its_cmd cmd;
711 domain = irq_create_domain(its_dev, &its_ops);
714 page = alloc_leaflet_pinned(0);
717 val = GITS_BASER_VALID | leaflet_addr(page);
719 its->cmdq = vmap(page, KERNEL_DATA);
720 its->cmdq_size = PAGE_SIZE / sizeof(struct v3_its_cmd);
725 size_t ent_sz, nr_ents;
726 for (int i = 0; i < 8; i++)
728 val = gits->basern[i];
730 type = BITS_GET(val, GITS_BASERn_TYPE);
731 if (!type || type == 0b010) {
736 nr_ents = BITS_GET(gits->typer, GITS_TYPER_Devbits);
739 nr_ents = gic->nr_cpus;
742 ent_sz = BITS_GET(val, GITS_BASERn_EntSz);
743 gits->basern[i] = __setup_basern_memory(its, ent_sz, nr_ents);
746 // enable ITS command engine
750 gits->ctlr |= GITS_CTLR_EN;
752 // map each core to a collection
754 for (int i = 0; i < gic->nr_cpus; i++)
756 __its_cmd_mapc(&cmd, v3pe(gic->cores[i]));
757 __its_issue_cmd(its, &cmd);
761 irq_set_domain_object(domain, its);
767 v3_map_reg(struct dtpropi* reg_dtpi, struct dtn* dtn,
768 ptr_t* phy_base_out, size_t* size_out)
772 assert(dtpi_has_next(reg_dtpi));
774 base = dtpi_next_integer(reg_dtpi, dtn->base.addr_c);
775 size = dtpi_next_integer(reg_dtpi, dtn->base.sz_c);
781 *phy_base_out = base;
783 return ioremap(base, size);
786 static struct v3_distr*
787 v3_map_distributor(struct gic* gic,
788 struct dtpropi* reg_dtpi, struct dtn* dtn)
790 struct v3_distr* distr;
792 distr = valloc(sizeof(*distr));
794 distr->dist_ptr = v3_map_reg(reg_dtpi, dtn, NULL, NULL);
803 v3_map_redistributors(struct gic* gic,
804 struct dtpropi* reg_dtpi, struct dtn* dtn)
808 int red_stride, nr_red_regions, nr_reds;
809 size_t region_sz, step;
810 ptr_t region_base, region_base_phy;
812 val = dt_getprop(dtn, "#redistributor-regions");
813 nr_red_regions = val ? val->ref->u32_val : 1;
815 val = dt_getprop(dtn, "redistributor-stride");
816 red_stride = val ? val->ref->u32_val : 0;
818 struct gic_pe *pe, *pes[16];
819 for (int i = 0; i < nr_red_regions; i++)
822 region_base = v3_map_reg(reg_dtpi, dtn, ®ion_base_phy, ®ion_sz);
825 v3_pe = valloc(sizeof(*v3_pe));
826 v3_pe->rd_base = region_base_phy + step;
827 v3_pe->red_ptr = region_base + step;
828 v3_pe->sgi_ptr = region_base + step + GIC_FRAME_SIZE;
830 pe = gic_create_pe_context(gic, v3_pe);
838 } while (red_stride && step < region_sz);
841 gic->cores = vcalloc(sizeof(struct gic_pe*), nr_reds);
842 gic->nr_cpus = nr_reds;
844 memcpy(gic->cores, pes, sizeof(pes));
848 __its_predicate(struct dtn_iter* iter, struct dtn_base* pos)
850 return strneq(pos->compat.str_val, "arm,gic-v3-its", 14);
853 static struct devclass its_class = DEVCLASS(ARM, CFG, ITS);
856 v3_init_its_device(struct gic* gic,
857 struct dtpropi* reg_dtpi, struct dtn* dtn)
860 struct device* itsdev;
863 its = valloc(sizeof(*its));
864 its->base_ptr = v3_map_reg(®_dtpi, dtn, &base_phys, NULL);
865 its->trns_phys_ptr = base_phys + GIC_FRAME_SIZE;
868 itsdev = device_allocsys(NULL, its);
869 device_set_devtree_node(itsdev, dtn);
870 register_device_var(itsdev, &its_class, "gic-its");
872 v3_init_its_domain(gic, itsdev, its);
876 v3_probe_its_devices(struct gic* gic, struct dtn* dtn)
878 struct dtpropi* dtpi;
879 struct dtn* its_node;
880 struct dtn_iter iter;
882 dt_begin_find(&iter, dtn, __its_predicate, NULL);
884 while (dt_find_next(&iter, (struct dtn_base**)&its_node))
886 dtpi_init(&dtpi, &its_node->reg);
887 v3_init_its_device(gic, &dtpi, its_node);
894 v3_init(struct device_def* def, struct dtn* dtn)
897 struct device* v3dev;
898 struct dtpropi* dtpi;
900 v3dev = device_allocsys(NULL, NULL);
901 device_set_devtree_node(v3dev, dtn);
902 register_device(v3dev, &def->class, "gic");
904 gic = gic_create_context(v3dev);
906 dtpi_init(&dtpi, &dtn->reg);
907 v3_map_distributor(gic, &dtpi, dtn);
908 v3_map_redistributors(gic, &dtpi, dtn);
910 v3_probe_its_devices(gic, dtn);
916 gic_register(struct device_def* def)
918 dtm_register_entry(def, "arm,gic-v3");
922 gic_init(struct device_def* def, morph_t* mobj)
927 node = changeling_try_reveal(mobj, dt_morpher);
932 gic = v3_init(def, node);
934 v3_config_distr(gic, v3distr(gic));
935 for (int i = 0; i < gic->nr_cpus; i++)
937 v3_config_pe(gic, gic->cores[i]);
940 v3_enable_interrupt(gic);
944 static struct device_def dev_arm_gic = {
945 def_device_name("arm gic-v3"),
946 def_device_class(ARM, CFG, GIC),
948 def_on_register(gic_register),
949 def_on_create(gic_init)
951 EXPORT_DEVICE(arm_gic, &dev_arm_gic, load_sysconf);