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