Merge remote-tracking branch 'origin/master' into isa/arm64
[lunaix-os.git] / lunaix-os / arch / aarch64 / soc / gic / gic.c
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>
8
9 #include <hal/devtree.h>
10
11 #include <asm/aa64_isrm.h>
12 #include <asm/soc/gic.h>
13
14 static struct arm_gic gic;
15
16 LOG_MODULE("gic")
17
18 DEFINE_BMP_INIT_OP(gic_bmp, valloc);
19
20 DEFINE_BMP_QUERY_OP(gic_bmp);
21
22 DEFINE_BMP_SET_OP(gic_bmp);
23
24 DEFINE_BMP_ALLOCFROM_OP(gic_bmp);
25
26 /* ++++++ GIC dirver ++++++ */
27
28 /* ****** Interrupt Management ****** */
29
30 static void
31 __config_interrupt(struct arm_gic* gic, struct gic_distributor* dist, 
32                     struct gic_interrupt* ent)
33 {
34     unsigned int intid_rel;
35     unsigned long trig_index;
36
37     intid_rel = ent->intid - ent->domain->base;
38
39     if (ent->config.class == GIC_LPI) {
40         lpi_entry_t entry = 0;
41
42         entry |= LPI_EN;
43         
44         gic->lpi_tables.prop_table[intid_rel] = entry;
45
46         // clear any pending when we (re-)configuring
47         bitmap_set(gic_bmp, &gic->lpi_tables.pendings, intid_rel, false);
48
49         return;
50     }
51
52
53     bitmap_set(gic_bmp, &dist->group, intid_rel, 0);
54     bitmap_set(gic_bmp, &dist->grpmod, intid_rel, 1);
55
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);
60     } else {
61         bitmap_set(gic_bmp, &dist->icfg, trig_index + 1, 0);
62     }
63
64     if (gic->nmi_ready) {
65         bitmap_set(gic_bmp, &dist->nmi, intid_rel, ent->config.as_nmi);
66     }
67
68     bitmap_set(gic_bmp, &dist->enable, intid_rel, true);
69 }
70
71 static void
72 __undone_interrupt(struct arm_gic* gic, struct gic_distributor* dist, 
73                     struct gic_interrupt* ent)
74 {
75     unsigned int intid_rel;
76
77     intid_rel = ent->intid - ent->domain->base;
78     
79     if (ent->config.class == GIC_LPI) {
80         gic->lpi_tables.prop_table[intid_rel] = 0;
81
82         // clear any pending when we (re-)configuring
83         bitmap_set(gic_bmp, &gic->lpi_tables.pendings, intid_rel, false);
84
85         return;
86     }
87
88     bitmap_set(gic_bmp, &dist->disable, intid_rel, true);
89     
90     if (gic->nmi_ready) {
91         bitmap_set(gic_bmp, &dist->nmi, intid_rel, false);
92     }
93 }
94
95 static inline struct gic_interrupt*
96 __get_interrupt(struct gic_idomain* domain, unsigned int rel_intid)
97 {
98     struct gic_interrupt *pos, *n;
99     unsigned int intid;
100
101     intid = rel_intid + domain->base;
102     hashtable_hash_foreach(domain->recs, intid, pos, n, node)
103     {
104         if (pos->intid == intid) {
105             return pos;
106         }
107     }
108
109     return NULL;
110 }
111
112 static struct gic_interrupt*
113 __find_interrupt_record(unsigned int intid)
114 {
115     struct gic_idomain* domain;
116
117     domain = __deduce_domain(intid);
118     
119     if (!domain) {
120         return NULL;
121     }
122
123     return __get_interrupt(domain, intid - domain->base);
124 }
125
126 static inline struct gic_interrupt*
127 __register_interrupt(struct gic_idomain* domain, 
128                             unsigned int intid, struct gic_int_param* param)
129 {
130     struct gic_interrupt* interrupt;
131
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
138     };
139
140     interrupt->intid = intid;
141     interrupt->domain = domain;
142
143     hashtable_hash_in(domain->recs, &interrupt->node, intid);
144
145     return interrupt;
146 }
147
148
149 /* ****** Interrupt Domain Management ****** */
150
151 static struct gic_idomain*
152 __deduce_domain(unsigned int intid)
153 {
154     if (intid <= INITID_SGI_END) {
155         return gic.pes[0].idomain.local_ints;
156     }
157
158     if (intid <= INITID_PPI_END) {
159         return gic.pes[0].idomain.local_ints;
160     }
161
162     if (intid <= INITID_SPI_END) {
163         return gic.idomain.spi;
164     }
165
166     if (INITID_ePPI_BASE <= intid && intid <= INITID_ePPI_END) {
167         return gic.pes[0].idomain.eppi;
168     }
169
170     if (INITID_eSPI_BASE <= intid && intid <= INITID_eSPI_END) {
171         return gic.idomain.espi;
172     }
173
174     if (intid >= INITID_LPI_BASE) {
175         return gic.idomain.lpi;
176     }
177
178     return NULL;
179 }
180
181 static struct gic_idomain*
182 __idomain(int nr_ints, unsigned int base, bool extended)
183 {
184     struct gic_idomain* rec;
185
186     rec = valloc(sizeof(*rec));
187     
188     bitmap_init(gic_bmp, &rec->ivmap, nr_ints);
189     hashtable_init(rec->recs);
190
191     rec->base = base;
192     rec->extended = extended;
193
194     return rec;
195 }
196
197
198 /* ****** Distributor-Related Management ****** */
199
200 static inline void
201 __init_distributor(struct gic_distributor* d, 
202                    gicreg_t* base, unsigned int nr_ints)
203 {
204     bitmap_init_ptr(gic_bmp,
205         &d->group, nr_ints, gic_regptr(base, GICD_IGROUPRn));
206
207     bitmap_init_ptr(gic_bmp,
208         &d->grpmod, nr_ints, gic_regptr(base, GICD_IGRPMODRn));
209
210     bitmap_init_ptr(gic_bmp,
211         &d->enable, nr_ints, gic_regptr(base, GICD_ISENABLER));
212     
213     bitmap_init_ptr(gic_bmp,
214         &d->disable, nr_ints, gic_regptr(base, GICD_ICENABLER));
215
216     bitmap_init_ptr(gic_bmp,
217         &d->icfg, nr_ints * 2, gic_regptr(base, GICD_ICFGR));
218     
219     bitmap_init_ptr(gic_bmp,
220         &d->nmi, nr_ints, gic_regptr(base, GICD_INMIR));
221 }
222
223 static inline struct leaflet*
224 __alloc_lpi_table(size_t table_sz)
225 {
226     unsigned int val;
227     struct leaflet* tab;
228
229     val = page_aligned(table_sz);
230     tab = alloc_leaflet(count_order(leaf_count(val)));
231     leaflet_wipe(tab);
232
233     return leaflet_addr(tab);
234 }
235
236 static inline void
237 __toggle_lpi_enable(struct gic_rd* rdist, bool en)
238 {
239     gicreg_t val;
240
241     if (!en) {
242         while ((val = rdist->base[GICR_CTLR]) & GICR_CTLR_RWP);
243         rdist->base[GICR_CTLR] = val & ~GICR_CTLR_EnLPI;
244     }
245     else {
246         rdist->base[GICR_CTLR] = val | GICR_CTLR_EnLPI;
247     }
248 }
249
250 static struct gic_distributor*
251 __attached_distributor(int cpu, struct gic_interrupt* ent)
252 {
253     enum gic_int_type iclass;
254
255     iclass = ent->config.class;
256
257     if (iclass == GIC_PPI || iclass == GIC_SGI) {
258         return &gic.pes[cpu].rdist;
259     }
260     
261     if (ent->domain->extended) {
262         return &gic.dist_e;
263     }
264     
265     return &gic.dist;
266 }
267
268
269 /* ****** GIC Components Configuration ****** */
270
271 static void
272 gic_configure_icc()
273 {
274     reg_t v;
275
276     v =
277     sysreg_flagging(ICC_SRE_EL1, 
278                     ICC_SRE_SRE | ICC_SRE_DFB | ICC_SRE_DIB, 
279                     0);
280     
281
282     v = 
283     sysreg_flagging(ICC_CTLR_EL1,
284                     ICC_CTRL_CBPR,
285                     ICC_CTRL_EOImode | ICC_CTRL_PMHE);
286
287     // disable all group 0 interrupts as those are meant for EL3
288     v=
289     sysreg_flagging(ICC_IGRPEN0_EL1, 0, ICC_IGRPEN_ENABLE);
290
291     // enable all group 1 interrupts, we'll stick with EL1_NS
292     v=
293     sysreg_flagging(ICC_IGRPEN1_EL1, ICC_IGRPEN_ENABLE, 0);
294 }
295
296 static void
297 gic_configure_global(struct arm_gic* gic)
298 {
299     gicreg64_t reg;
300     unsigned int val, max_nr_spi;
301
302     reg = gic->mmrs.dist_base[GICD_TYPER];
303     
304     // check if eSPI supported
305     gic->has_espi = (reg & GICD_TYPER_ESPI);
306     if (gic->has_espi) {
307         val = BITS_GET(reg, GICD_TYPER_nESPI);
308         gic->espi_nr = 32 * (val + 1);
309     }
310
311     // Parse IDbits
312     val = BITS_GET(reg, GICD_TYPER_IDbits);
313     gic->max_intid = 1 << (val + 1) - 1;
314
315     // LPI is supported
316     if (val + 1 >= 14) {
317         val = BITS_GET(reg, GICD_TYPER_nLPI);
318         if (val) {
319             gic->lpi_nr = 1 << (val + 1);
320         }
321         else {
322             gic->lpi_nr = gic->max_intid - INITID_LPI_BASE + 1;
323         }
324     }
325
326     // check if SPI supported
327     val = BITS_GET(reg, GICD_TYPER_nSPI);
328     if (val) {
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;
332     } else {
333         gic->spi_nr = 0;
334     }
335
336     gic->nmi_ready = (reg & GICD_TYPER_NMI);
337     gic->msi_via_spi = (reg & GICD_TYPER_MBIS);
338
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);
341
342
343     if (gic->spi_nr) {
344         gic->idomain.spi  = __idomain(gic->spi_nr, INITID_SPI_BASE, false);
345     }
346     if (gic->espi_nr) {
347         gic->idomain.espi = __idomain(gic->espi_nr, INITID_eSPI_BASE, true);
348     }
349     if (gic->lpi_nr) {
350         gic->idomain.lpi  = __idomain(gic->lpi_nr, INITID_LPI_BASE, false);
351     }
352
353     struct leaflet* tab;
354
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);
358
359     tab = __alloc_lpi_table(gic->lpi_nr / 8);
360     gic->lpi_tables.pend = leaflet_addr(tab);
361
362     bitmap_init_ptr(gic_bmp, 
363         &gic->lpi_tables.pendings, gic->lpi_nr, gic->lpi_tables.pend);
364 }
365
366 static void
367 gic_configure_pe(struct arm_gic* gic, struct gic_pe* pe)
368 {
369     unsigned int nr_local_ints;
370     gicreg64_t reg;
371
372     reg = gic_reg64(pe->_rd, GICR_TYPER);
373
374     pe->affinity = BITS_GET(reg, GICR_TYPER_AffVal);
375     pe->ppi_nr   = INITID_PPI_BASE;
376     switch (BITS_GET(reg, GICR_TYPER_PPInum))
377     {
378         case 1:
379             pe->ppi_nr += 1088 - INITID_ePPI_BASE;
380             pe->eppi_ready = true;
381             break;
382         case 2:
383             pe->ppi_nr += 1120 - INITID_ePPI_BASE;
384             pe->eppi_ready = true;
385             break;
386     }
387
388     nr_local_ints = pe->ppi_nr + INITID_PPI_BASE;
389     
390     pe->idomain.local_ints = __idomain(32, 0, false);
391     pe->idomain.eppi = __idomain(nr_local_ints - 32, INITID_ePPI_BASE, true);
392
393     __init_distributor(&pe->rdist, pe->_rd->sgi_base, nr_local_ints);
394
395     __toggle_lpi_enable(pe->_rd, false);
396
397     reg = 0;
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;
402
403     reg  = 0;
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;
408
409     __toggle_lpi_enable(pe->_rd, true);
410 }
411
412
413 /* ****** Interrupt Life-cycle Management ****** */
414
415
416 struct gic_interrupt*
417 gic_install_int(struct gic_int_param* param, isr_cb handler, bool alloc)
418 {
419     unsigned int iv;
420     struct gic_idomain* domain;
421     struct gic_interrupt* ent;
422     struct gic_distributor* dist;
423     int cpu;
424
425     cpu = param->cpu_id;
426
427     assert(cpu == 0);
428
429     switch (param->class)
430     {
431     case GIC_PPI:
432         if (!param->ext_range) {
433             domain = gic.pes[cpu].idomain.local_ints;
434         }
435         else {
436             domain = gic.pes[cpu].idomain.eppi;
437         }
438         break;
439
440     case GIC_SGI:
441         domain = gic.pes[cpu].idomain.local_ints;
442         break;
443
444     case GIC_SPI:
445         if (!param->ext_range) {
446             assert(gic.spi_nr > 0);
447             domain = gic.idomain.spi;
448         } 
449         else {
450             assert(gic.has_espi);
451             domain = gic.idomain.espi;
452         }
453         break;
454
455     case GIC_LPI:
456         assert(gic.lpi_ready);
457         domain = gic.idomain.lpi;
458         break;
459         
460     default:
461         fail("unknown interrupt class");
462         break;
463     }
464
465     if (alloc) {
466         if (!bitmap_alloc(gic_bmp, &domain->ivmap, 0, &iv)) {
467             FATAL("out of usable iv for class=%d", param->class);
468         }
469     }
470     else {
471         iv = param->rel_intid;
472         if ((ent = __get_interrupt(domain, iv))) {
473             return ent;
474         }
475         
476         bitmap_set(gic_bmp, &domain->ivmap, iv, true);
477     }
478
479     iv += domain->base;
480
481     if (param->class == GIC_SPI && !param->ext_range && iv >= INITID_ePPI_BASE) 
482     {
483         WARN("PPI vector=%d falls in extended range, while not requested.", iv);
484         param->ext_range = true;
485     }
486
487     ent  = __register_interrupt(domain, iv, param);
488     dist = __attached_distributor(cpu, ent);
489     
490     __config_interrupt(&gic, dist, ent);
491
492     ent->handler = handler;
493
494     return ent;
495 }
496
497 static void
498 gic_update_active()
499 {
500     reg_t val;
501     unsigned int intid;
502     struct gic_interrupt* intr;
503     struct gic_pe* pe;
504
505     pe  = &gic.pes[0];
506     val = read_sysreg(ICC_IAR1_EL1);
507     intid = (unsigned int)val & ((1 << 24) - 1);
508
509     if (check_special_intid(intid)) {
510         return;
511     }
512
513     intr = __find_interrupt_record(intid);
514     pe->active = intr;
515     pe->iar_val = val;
516 }
517
518 static inline void
519 gic_signal_eoi()
520 {
521     struct gic_pe* pe;
522
523     pe  = &gic.pes[0];
524     if (!pe->active) {
525         return;
526     }
527
528     pe->active = NULL;
529     set_sysreg(ICC_EOIR1_EL1, pe->iar_val);
530 }
531
532 /* ****** Lunaix ISRM Interfacing ****** */
533
534 void
535 isrm_init()
536 {
537     // nothing to do
538 }
539
540 void
541 isrm_ivfree(int iv)
542 {
543     struct gic_interrupt* ent;
544     struct gic_distributor* dist;
545     
546     ent  = __find_interrupt_record(iv);
547     if (!ent) {
548         return;
549     }
550
551     dist = __attached_distributor(0, ent);
552     __undone_interrupt(&gic, dist, ent);
553
554     hlist_delete(&ent->node);
555     vfree(ent);
556 }
557
558 int
559 isrm_ivosalloc(isr_cb handler)
560 {
561     return isrm_ivexalloc(handler);
562 }
563
564 int
565 isrm_ivexalloc(isr_cb handler)
566 {
567     struct gic_int_param param;
568     struct gic_interrupt* intr;
569
570     param = (struct gic_int_param) {
571         .class = GIC_SPI,
572         .group = GIC_G1NS,
573         .trigger = GIC_TRIG_EDGE,
574     };
575
576     intr = gic_install_int(&param, handler, true);
577     
578     return intr->intid;
579 }
580
581 isr_cb
582 isrm_get(int iv)
583 {
584     struct gic_interrupt* intr;
585
586     intr = __find_interrupt_record(iv);
587     if (!intr) {
588         return NULL;
589     }
590
591     return intr->handler;
592 }
593
594 ptr_t
595 isrm_get_payload(const struct hart_state* state)
596 {
597     struct gic_interrupt* active;
598
599     active = gic.pes[0].active;
600     assert(active);
601
602     return active->handler;
603 }
604
605 void
606 isrm_set_payload(int iv, ptr_t payload)
607 {
608     struct gic_interrupt* intr;
609
610     intr = __find_interrupt_record(iv);
611     if (!intr) {
612         return NULL;
613     }
614
615     intr->payload = payload;
616 }
617
618 void
619 isrm_notify_eoi(cpu_t id, int iv)
620 {
621     gic_signal_eoi();
622 }
623
624 void
625 isrm_notify_eos(cpu_t id)
626 {
627     isrm_notify_eoi(id, 0);
628 }
629
630 msi_vector_t
631 isrm_msialloc(isr_cb handler)
632 {
633     int intid;
634     msi_vector_t msiv;
635     struct gic_int_param param;
636
637     param = (struct gic_int_param) {
638         .group = GIC_G1NS,
639         .trigger = GIC_TRIG_EDGE
640     };
641
642     if (gic.msi_via_spi) {
643         param.class = GIC_SPI;
644
645         intid = gic_install_int(&param, handler, true);
646         msiv.msi_addr  = gic_regptr(gic.mmrs.dist_base, GICD_SETSPI_NSR);
647         goto done;
648     }
649     
650     if (unlikely(!gic.lpi_ready)) {
651         return invalid_msi_vector;
652     }
653
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;
658     }
659
660     param.class = GIC_LPI;
661     intid = gic_install_int(&param, handler, true);
662     msiv.msi_addr = gic_regptr(gic.pes[0]._rd->base, GICR_SETLPIR);
663
664 done:
665     msiv.mapped_iv = intid;
666     msiv.msi_data  = intid;
667
668     return msiv;
669 }
670
671 int
672 isrm_bind_dtnode(struct dt_intr_node* node, isr_cb handler)
673 {
674     struct dt_prop_val* val;
675     struct gic_int_param param;
676     struct gic_interrupt* installed;
677
678     val = dt_resolve_interrupt(INTR_TO_DTNODE(node));
679     if (!val) {
680         return EINVAL;
681     }
682
683     if (node->intr.extended) {
684         WARN("binding of multi interrupt is yet to supported");
685         return EINVAL;
686     }
687
688     gic_dtprop_interpret(&param, val, 3);
689     param.cpu_id = 0;
690
691     installed = gic_install_int(&param, handler, false);
692
693     return installed->intid;
694 }
695
696 /* ****** Device Definition & Export ****** */
697
698 static void
699 gic_init()
700 {
701     memset(&gic, 0, sizeof(gic));
702
703     gic_create_from_dt(&gic);
704
705     // configure the system interfaces
706     gic_configure_icc();
707
708     // configure global distributor
709     gic_configure_global(&gic);
710     
711     // configure per-PE local distributor (redistributor)
712     for (int i = 0; i < NR_CPU; i++)
713     {
714         gic_configure_pe(&gic, &gic.pes[i]);
715     }
716
717     gic_configure_its(&gic);
718 }
719
720 static struct device_def dev_arm_gic = {
721     .name = "ARM Generic Interrupt Controller",
722     .class = DEVCLASS(DEVIF_SOC, DEVFN_CFG, DEV_INTC),
723     .init = gic_init
724 };
725 EXPORT_DEVICE(arm_gic, &dev_arm_gic, load_sysconf);