rewrite the gic implementation, some other fix ups
[lunaix-os.git] / lunaix-os / arch / aarch64 / soc / gic / gic_v3.c
1 /**
2  * Arm Generic Interrupt Controller v3
3  */
4
5 #include <lunaix/mm/page.h>
6 #include <lunaix/mm/valloc.h>
7 #include <lunaix/mm/mmio.h>
8 #include <klibc/string.h>
9
10 #include "v3.h"
11
12 static inline void
13 __gic_bitmap_setf(u32_t* bmp, intid_t intid, bool flag)
14 {
15     if (flag) {
16         bmp[intid / 32] |= 1 << (intid % 32);
17     } else {
18         bmp[intid / 32] &= ~(1 << (intid % 32));
19     }
20 }
21
22 static inline bool
23 __gic_bitmap_getf(u32_t* bmp, intid_t intid)
24 {
25     return !!(bmp[intid / 32] & (1 << (intid % 32)));
26 }
27
28 static inline void
29 __gic_bitmap_setv(u32_t* bmp, intid_t intid, int val, u32_t width_bits)
30 {
31     u32_t slots = 32 / width_bits;
32     u32_t mask = (1 << width_bits) - 1;
33     u32_t _val;
34
35     _val  = bmp[intid / slots];
36     _val &= ~(mask << (intid % slots));
37     bmp[intid / slots] =  (_val & mask) << (intid % slots);
38 }
39
40 static inline int
41 __gic_bitmap_getv(u32_t* bmp, intid_t intid, u32_t width_bits)
42 {
43     u32_t slots = 32 / width_bits;
44     u32_t mask = (1 << width_bits) - 1;
45
46     return !!(bmp[intid / slots] & (mask << (intid % slots)));
47 }
48
49 static inline int 
50 __spi_set_group(struct gic_int_class* class, 
51                  intid_t intid, enum gic_intgrp grp)
52 {
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);
57     }
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);
61     }
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);
65     }
66     else {
67         return EINVAL;
68     }
69     
70     return 0;
71 }
72
73 static int 
74 __spi_set_enabled(struct gic_int_class* class, intid_t intid, bool en)
75 {
76     struct v3_distr* distr = v3distr_class(class);
77     
78     if (en) {
79         __gic_bitmap_setf(distr->gicd->isenabler, intid, true);
80     } else {
81         __gic_bitmap_setf(distr->gicd->icenabler, intid, true);
82     }
83
84     return 0;
85 }
86
87 static int 
88 __spi_set_prority(struct gic_int_class* class, intid_t intid, int prio)
89 {
90     struct v3_distr* distr = v3distr_class(class);
91     __gic_bitmap_setv(distr->gicd->ipriorityr, intid, prio, 8);
92
93     return 0;
94 }
95
96 static int 
97 __spi_set_nmi(struct gic_int_class* class, intid_t intid, bool nmi)
98 {
99     struct v3_distr* distr = v3distr_class(class);
100     __gic_bitmap_setf(distr->gicd->isenabler, intid, nmi);
101
102     return 0;
103 }
104
105 static int 
106 __spi_set_route(struct gic_int_class* class, 
107                intid_t intid, struct gic_pe* target)
108 {
109     int aff_val = target->affinity;
110     int aff3 = aff_val >> 24;
111     int aff210 = aff_val & ((1 << 24) - 1);
112
113     struct v3_distr* distr = v3distr_class(class);
114     distr->gicd->irouter[intid - 32] = ((u64_t)aff3 << 32) | aff210;
115
116     return 0;
117 }
118
119 static int 
120 __spi_set_trigger(struct gic_int_class* class, 
121                  intid_t intid, enum gic_trigger trig)
122 {
123     int trig_val = trig == GIC_TRIG_EDGE ? 0b10 : 0b00;
124
125     struct v3_distr* distr = v3distr_class(class);
126     __gic_bitmap_setv(distr->gicd->icfgr, intid, trig_val, 2);
127
128     return 0;
129 }
130
131
132 static int 
133 __spi_retrieve(struct gic_int_class* class, 
134               struct gic_interrupt* intr, intid_t intid)
135 {
136     int val;
137     struct v3_distr* distr = v3distr_class(class);
138     union v3_gicd_map* gicd = distr->gicd;
139     
140     intr->enabled = __gic_bitmap_getf(gicd->isenabler, intid);
141     intr->nmi = __gic_bitmap_getf(gicd->inmir, intid);
142
143     intr->priority = __gic_bitmap_getv(gicd->ipriorityr, intid, 8);
144
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);
148
149     val = __gic_bitmap_getv(gicd->icfgr, intid, 2);
150     intr->trig = val == 0b10 ? GIC_TRIG_EDGE : GIC_TRIG_LEVEL;
151
152     val = __gic_bitmap_getf(gicd->igrpmodr, intid);
153     val = (val << 1) | __gic_bitmap_getf(gicd->igroupr, intid);
154     if (val == 0b00) {
155         intr->grp = GIC_INT_GROUP0;
156     }
157     else if (val == 0b01) {
158         intr->grp = GIC_INT_GROUP1_NS;
159     }
160     else if (val == 0b10) {
161         intr->grp = GIC_INT_GROUP1_S;
162     }
163     else {
164         return EINVAL;
165     }
166
167     return 0;
168 }
169
170 static int 
171 __spi_install(struct gic_int_class* class, struct gic_interrupt* intr)
172 {
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);
178
179     return 0;
180 }
181
182 static int 
183 __spi_delete(struct gic_int_class* class, intid_t intid)
184 {
185     __spi_set_enabled(class, intid, false);
186 }
187
188 static inline void
189 __lpi_write_invlpir(struct v3_pe* pe, intid_t intid)
190 {
191     // ensure coherent for configuration write
192     asm ("dsb");
193
194     // flush the redistributor cache (only directLPI).
195     if (pe->direct_lpi) {
196         pe->gicr->invlpir = intid;
197     }
198
199     // ITS cache is flushed in upstream caller.
200     return;
201 }
202
203 static int 
204 __lpi_set_enabled(struct gic_int_class* class, intid_t intid, bool en)
205 {
206     struct v3_pe* pe = v3pe_class(class);
207     u32_t val;
208     
209     assert(pe->lpi_tab);
210     
211     val = pe->lpi_tab[intid - 8192];
212     pe->lpi_tab[intid - 8192] = (val & ~1) | (en & 1);
213
214     __lpi_write_invlpir(pe, intid);
215 }
216
217 static int 
218 __lpi_set_prority(struct gic_int_class* class, intid_t intid, int prio)
219 {
220     struct v3_pe* pe = v3pe_class(class);
221     
222     assert(pe->lpi_tab);
223
224     pe->lpi_tab[intid - 8192] = prio & 0xfc;
225
226     __lpi_write_invlpir(pe, intid);
227 }
228
229 static int 
230 __lpi_retrieve(struct gic_int_class* class, 
231                struct gic_interrupt* intr, intid_t intid)
232 {
233     struct v3_pe* pe = v3pe_class(class);
234     u32_t val;
235     
236     assert(pe->lpi_tab);
237
238     val = pe->lpi_tab[intid - 8192];
239
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;
245     intr->nmi = false;
246
247     return 0;
248 }
249
250 static inline int 
251 __lpi_install(struct gic_int_class* class, struct gic_interrupt* intr)
252 {
253     struct v3_pe* pe = v3pe_class(class);
254     struct irq_object* irq = intr->irq;
255
256     __lpi_set_prority(class, intr->intid, intr->priority);
257     
258     if (pe->direct_lpi) {
259         irq->msi->message = intr->intid;
260         irq->msi->wr_addr = __ptr(&pe->gicr->setlpir);
261     }
262     
263     // for ITS backed LPI, it will installed separately, so we are done.
264     return 0;
265 }
266
267 static bool
268 __pe_ack_interrupt(struct gic_pe* pe)
269 {
270     intid_t id;
271     
272     id = read_sysreg(ICC_IAR1_EL1);
273     switch (id)
274     {
275     case INTID_IAR1_NMI:
276         id == read_sysreg(ICC_NMIAR1_EL1);
277         break;
278     
279     case INTID_NOTHING:
280         return false;
281
282     case INTID_ACKED_NS:
283     case INTID_ACKED_S:
284         fail("impossible intid");
285         break;
286     }
287
288     pe->active_id = id;
289     return true;
290 }
291
292 static int
293 __pe_notify_eoi(struct gic_pe* pe)
294 {
295     if (!pe->has_active_int) {
296         return 0;
297     }
298
299     assert(pe->active_int.grp == GIC_INT_GROUP1_NS);
300     
301     set_sysreg(ICC_EOIR1_EL1, pe->active_id);
302     set_sysreg(ICC_DIR_EL1, pe->active_id);
303     return 0;
304 }
305
306 static int 
307 __pe_set_priority_mask(struct gic_pe* pe, int mask)
308 {
309     set_sysreg(ICC_PMR_EL1, mask & 0xff);
310     return 0;
311 }
312
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
322 };
323
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
333 };
334
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
339 };
340
341 static void
342 v3_enable_interrupt(struct gic* gic)
343 {
344     struct v3_pe* v3pe;
345     struct v3_distr* distr;
346
347     set_sysreg(ICC_IGRPEN1_EL1, ICC_IGRPEN_ENABLE);
348
349     for (int i = 0; i < gic->nr_cpus; i++)
350     {
351         assert(gic->cores[i]);
352
353         v3pe = (struct v3_pe*)gic->cores[i]->impl;
354         v3pe->gicr->ctlr |= GICR_CTLR_EnLPI;
355     }
356
357     distr = (struct v3_distr*)gic->impl;
358     distr->gicd->ctlr |= GICD_CTLR_G1NSEN;
359 }
360
361 static void
362 v3_config_redistr(struct v3_pe* v3_pe)
363 {
364     struct gic_pe* pe;
365     struct leaflet* page;
366     u64_t val;
367     int nr_pages, nr_lpis;
368
369     pe = v3_pe->pe;
370
371     // Configure LPI Tables
372
373     if (!gic_valid_int_class(&pe->lpi)) {
374         return;
375     }
376
377     // We only use at most 8192 LPIs
378     nr_lpis = 8192;
379     nr_pages = page_count(8192, PAGE_SIZE);
380
381     
382     /*
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
386         all PEs and clusters
387     */
388
389     // 8192 LPIs, two 4K pages
390     page = alloc_leaflet_pinned(to_napot_order(nr_pages));
391     leaflet_wipe(page);
392     val = leaflet_addr(page) | (ilog2(nr_lpis) + 1);
393     v3_pe->gicr->propbaser = val;
394
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));
398     leaflet_wipe(page);
399     v3_pe->lpi_tab_ptr = vmap(page, KERNEL_DATA);
400
401     /*
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
406     */
407     val = leaflet_addr(page);
408     if (val & (PAGE_64K - 1)) {
409         val = napot_upaligned(val, PAGE_64K);
410     }
411
412     val = val | GICR_PENDBASER_PTZ | (ilog2(nr_lpis) + 1);
413     v3_pe->gicr->pendbaser = val;
414 }
415
416 static void
417 v3_config_icc(struct v3_pe* pe)
418 {
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);
422     
423     set_sysreg(ICC_PMR_EL1, 0xff);  // all 256 priority values
424     set_sysreg(ICC_BPR0_EL1, 7);    // no preemption
425 }
426
427 static void
428 v3_config_distr(struct gic* gic, struct v3_distr* distr)
429 {
430     u32_t ctlr;
431     union v3_gicd_map* gicd;
432     unsigned int intid_max, lpi_max;
433
434     gicd = distr->gicd;
435
436     ctlr = GICD_CTLR_DS | GICD_CTLR_ARE_NS;
437     gicd->ctlr = ctlr;
438
439     intid_max = BITS_GET(gicd->typer, GICD_TYPER_nSPI);
440     if (intid_max) {
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;
444     }
445
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);
450     }
451 }
452
453 static void
454 v3_config_pe(struct gic* gic, struct gic_pe* pe)
455 {
456     struct v3_pe* v3_pe;
457     unsigned int affval, ppi_num;
458     unsigned int intid_max, lpi_max;
459
460     union v3_rdbase_map *gicr;
461     union v3_gicd_map* gicd;
462
463     v3_pe = v3pe(pe);
464     gicd  = v3distr(gic)->gicd;
465     gicr  = v3_pe->gicr;
466     
467     affval  = BITS_GET(gicr->typer, GICR_TYPER_AffVal);
468     ppi_num = BITS_GET(gicr->typer, GICR_TYPER_PPInum);
469
470     pe->affinity = affval;
471     v3_pe->direct_lpi = !!(gicr->typer & GICR_TYPER_DirectLPI);
472
473     gic_init_int_class(&pe->sgi, GIC_INT_SGI, 0, 15);
474     gic_init_int_class(&pe->ppi, GIC_INT_PPI, 16, 31);
475
476     switch (ppi_num)
477     {
478     case 0b00001:
479         gic_init_int_class(&pe->ppi_e, GIC_INT_PPI_EXT, 1056, 1087);
480         break;
481         
482     case 0b00010:
483         gic_init_int_class(&pe->ppi_e, GIC_INT_PPI_EXT, 1056, 1119);
484         break;
485     }
486
487     intid_max = BITS_GET(gicd->typer, GICD_TYPER_IDbits);
488     intid_max = 1 << (intid_max + 1);
489
490     if (intid_max > 8192) {
491         // NOTE the minimum support of 8192 LPIs is far enough.
492
493         // lpi_max = BITS_GET(gicd->typer, GICD_TYPER_nLPI);
494         // if (lpi_max) {
495         //     lpi_max = ((1 << (lpi_max + 1)) - 1) + 8192;
496         // } else {
497         //     lpi_max = intid_max - 1;
498         // }
499
500         gic_init_int_class(&pe->lpi, GIC_INT_LPI, 8192, 8192 * 2);
501         pe->lpi.ops = &lpi_ops;
502     }
503
504     v3_config_redistr(pe);
505     v3_config_icc(pe);
506 }
507
508 /*
509  *      ITS specifics
510  */
511
512 static ptr_t
513 __its_alloc_itt(struct v3_its* its)
514 {
515     struct leaflet* leaflet;
516     struct v3_itt_alloc* ita;
517
518     ita = &its->itt_alloc;
519
520 restart:
521     if (unlikely(ita->page)) {
522         leaflet = alloc_leaflet_pinned(0);
523         leaflet_wipe(leaflet);
524
525         ita->page = leaflet_addr(leaflet);
526         memset(ita->free_map, 0, sizeof(ita->free_map));
527     }
528
529     for (int i = 0; i < sizeof(ita->free_map); i++)
530     {
531         if (ita->free_map[i] == 0xff)
532             continue;
533
534         for (int j = 0; j < 8; j++) {
535             if (ita->free_map[i] & (1 << j)) {
536                 continue;
537             }
538
539             ita->free_map[i] |= 1 << j;
540             return ita->page + (i * 8 + j) * 256;
541         }
542     }
543     
544     ita->page = NULL;
545     goto restart;
546 }
547
548 #define irq_devid(irq)  ((irq)->msi->sideband)
549 #define irq_evtid(irq)  ((irq)->msi->message)
550
551 static void
552 __its_cmd_inv(struct v3_its_cmd* cmd, irq_t irq)
553 {
554     *cmd = (struct v3_its_cmd) {
555         .dw0 = (u64_t)irq_devid(irq) << 32 | 0xc,
556         .dw1 = irq_evtid(irq)
557     };
558 }
559
560 static void
561 __its_cmd_mapc(struct v3_its_cmd* cmd, struct v3_pe* v3_pe)
562 {
563     *cmd = (struct v3_its_cmd) {
564         .dw0 = 0x9,
565         .dw2 = (1UL << 63) | v3_pe->pe->index | v3_pe->rd_base
566     };
567 }
568
569 static void
570 __its_cmd_mapd(struct v3_its_cmd* cmd, struct v3_its* its, irq_t irq)
571 {
572     *cmd = (struct v3_its_cmd) {
573         .dw0 = (u64_t)irq_devid(irq) << 32 | 0x8,
574         .dw1 = ilog2(8) - 1,
575         .dw2 = (1UL << 63) | __its_alloc_itt(its)
576     };
577 }
578
579 static void
580 __its_cmd_mapti(struct v3_its_cmd* cmd, irq_t irq, int pe_index)
581 {
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),
585         .dw2 = pe_index
586     };
587 }
588
589 static void
590 __its_issue_cmd(struct v3_its* its, struct v3_its_cmd* cmd)
591 {
592     ptr_t wr, rd, base;
593
594     wr = its->gits->cwriter >> 5;
595     do {
596         rd = its->gits->creadr >> 5;
597     } while (wr > rd && wr - rd == 1);
598
599     its->cmdq[wr] = *cmd;
600     wr = (wr + 1) % its->cmdq_size;
601
602     its->gits->cwriter = wr << 5;
603 }
604
605 static int
606 __its_domain_install_irq(struct irq_domain *itsd, irq_t irq)
607 {
608     int err;
609     struct v3_its* its;
610     struct v3_its_cmd cmd;
611     struct gic_pe* pe;
612     struct gic_interrupt gici;
613
614     its = irq_domain_obj(itsd, struct v3_its);
615
616     if (irq->type != IRQ_MESSAGE) {
617         return EINVAL;
618     }
619
620     pe = its->gic->cores[0];
621     err = gic_assign_intid(&pe->lpi, irq);
622
623     if (err) 
624         return err;
625
626     gici.intid = irq->vector;
627     gici.irq = irq;
628     gici.priority = 255;
629
630     __lpi_install(&pe->lpi, &gici);
631
632     __its_cmd_mapd(&cmd, its, irq);
633     __its_issue_cmd(its, &cmd);
634
635     __its_cmd_mapti(&cmd, irq, 0);
636     __its_issue_cmd(its, &cmd);
637
638     __its_cmd_inv(&cmd, irq);
639     __its_issue_cmd(its, &cmd);
640
641     __lpi_set_enabled(&pe->lpi, irq->vector, true);
642
643     irq->msi->wr_addr = __ptr(&its->gtrn->translater);
644
645     return 0;
646 }
647
648 static int
649 __its_domain_remove_irq(struct irq_domain *itsd, irq_t irq)
650 {
651     // TODO
652     return 0;
653 }
654
655 static struct irq_domain_ops its_ops = {
656     .install_irq = __its_domain_install_irq,
657     .remove_irq = __its_domain_remove_irq
658 };
659
660 static u64_t
661 __setup_basern_memory(struct v3_its* its, size_t ent_sz, size_t nr_ents)
662 {
663     u64_t val, *ind_pages;
664     int nr_pages, pgsize;
665     struct leaflet* page, *sub_page;
666
667     nr_pages = page_count(ent_sz * nr_ents, PAGE_SIZE);
668     page = alloc_leaflet_pinned(0);
669     leaflet_wipe(page);
670
671     val = GITS_BASER_VALID;
672     switch (PAGE_SIZE) {
673         case 4096 * 4:
674             pgsize = 0b01;
675             break;
676         case 4096 * 16:
677             pgsize = 0b10;
678             break;
679     }
680     BITS_SET(val, GITS_BASERn_PGSZ, pgsize);
681
682     if (nr_pages == 1) {
683         val |= leaflet_addr(page);
684         return val;
685     }
686
687     ind_pages = (u64_t*)vmap(page, KERNEL_DATA);
688     for (int i = 0; i < nr_pages; i++)
689     {
690         sub_page = alloc_leaflet_pinned(0);
691         leaflet_wipe(sub_page);
692         ind_pages[i] = val | leaflet_addr(sub_page);
693     }
694
695     vunmap(__ptr(ind_pages), page);
696     val |= GITS_BASER_Ind | leaflet_addr(page);
697     
698     return val;
699 }
700
701 static struct irq_domain*
702 v3_init_its_domain(struct gic* gic, 
703                    struct device* its_dev, struct v3_its* its)
704 {
705     u64_t val;
706     struct leaflet* page;
707     struct irq_domain* domain;
708     union v3_its_regs* gits;
709     struct v3_its_cmd cmd;
710
711     domain = irq_create_domain(its_dev, &its_ops);
712     gits = its->gits;
713
714     page = alloc_leaflet_pinned(0);
715     leaflet_wipe(page);
716
717     val = GITS_BASER_VALID | leaflet_addr(page);
718     gits->cbaser = val;
719     its->cmdq = vmap(page, KERNEL_DATA);
720     its->cmdq_size = PAGE_SIZE / sizeof(struct v3_its_cmd);
721
722     // Setup BASER<n>
723
724     int type;
725     size_t ent_sz, nr_ents;
726     for (int i = 0; i < 8; i++)
727     {
728         val = gits->basern[i];
729         
730         type = BITS_GET(val, GITS_BASERn_TYPE);
731         if (!type || type == 0b010) {
732             continue;
733         }
734
735         if (type == 0b001) {
736             nr_ents = BITS_GET(gits->typer, GITS_TYPER_Devbits);
737         }
738         else if (type) {
739             nr_ents = gic->nr_cpus;
740         }
741
742         ent_sz = BITS_GET(val, GITS_BASERn_EntSz);
743         gits->basern[i] = __setup_basern_memory(its, ent_sz, nr_ents);
744     }
745
746     // enable ITS command engine
747
748     gits->creadr = 0;
749     gits->cwriter = 0;
750     gits->ctlr |= GITS_CTLR_EN;
751
752     // map each core to a collection
753
754     for (int i = 0; i < gic->nr_cpus; i++)
755     {
756         __its_cmd_mapc(&cmd, v3pe(gic->cores[i]));
757         __its_issue_cmd(its, &cmd);
758     }
759     
760     its->gic = gic;
761     irq_set_domain_object(domain, its);
762
763     return domain;
764 }
765
766 static inline ptr_t
767 v3_map_reg(struct dtpropi* reg_dtpi, struct dtn* dtn, 
768                  ptr_t* phy_base_out, size_t* size_out)
769 {
770     ptr_t base, size;
771
772     assert(dtpi_has_next(reg_dtpi));
773
774     base = dtpi_next_integer(reg_dtpi, dtn->base.addr_c);
775     size = dtpi_next_integer(reg_dtpi, dtn->base.sz_c);
776
777     if (size_out)
778         *size_out = size;
779
780     if (phy_base_out)
781         *phy_base_out = base;
782
783     return ioremap(base, size);
784 }
785
786 static struct v3_distr*
787 v3_map_distributor(struct gic* gic, 
788                    struct dtpropi* reg_dtpi, struct dtn* dtn)
789 {
790     struct v3_distr* distr;
791
792     distr = valloc(sizeof(*distr));
793
794     distr->dist_ptr = v3_map_reg(reg_dtpi, dtn, NULL, NULL);
795
796     distr->gic = gic;
797     gic->impl = distr;
798
799     return distr;
800 }
801
802 static void
803 v3_map_redistributors(struct gic* gic, 
804                       struct dtpropi* reg_dtpi, struct dtn* dtn)
805 {
806     struct dtp_val* val;
807     struct v3_pe* v3_pe;
808     int red_stride, nr_red_regions, nr_reds;
809     size_t region_sz, step;
810     ptr_t region_base, region_base_phy;
811
812     val = dt_getprop(dtn, "#redistributor-regions");
813     nr_red_regions = val ? val->ref->u32_val : 1;
814
815     val = dt_getprop(dtn, "redistributor-stride");
816     red_stride = val ? val->ref->u32_val : 0;
817
818     struct gic_pe *pe, *pes[16];
819     for (int i = 0; i < nr_red_regions; i++)
820     {
821         step = 0;
822         region_base = v3_map_reg(reg_dtpi, dtn, &region_base_phy, &region_sz);
823
824         do {
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;
829
830             pe = gic_create_pe_context(gic, v3_pe);
831             pe->index = nr_reds;
832             
833             v3_pe->pe = pe;
834             pes[nr_reds] = pe;
835
836             nr_reds++;
837             step += red_stride;
838         } while (red_stride && step < region_sz);
839     }
840     
841     gic->cores = vcalloc(sizeof(struct gic_pe*), nr_reds);
842     gic->nr_cpus = nr_reds;
843
844     memcpy(gic->cores, pes, sizeof(pes));
845 }
846
847 static bool
848 __its_predicate(struct dtn_iter* iter, struct dtn_base* pos)
849 {
850     return strneq(pos->compat.str_val, "arm,gic-v3-its", 14);
851 }
852
853 static struct devclass its_class = DEVCLASS(ARM, CFG, ITS);
854
855 static void
856 v3_init_its_device(struct gic* gic, 
857                    struct dtpropi* reg_dtpi, struct dtn* dtn)
858 {
859     struct v3_its* its;
860     struct device* itsdev;
861     ptr_t base_phys;
862
863     its = valloc(sizeof(*its));
864     its->base_ptr = v3_map_reg(&reg_dtpi, dtn, &base_phys, NULL);
865     its->trns_phys_ptr = base_phys + GIC_FRAME_SIZE;
866     its->gic = gic;
867
868     itsdev = device_allocsys(NULL, its);
869     device_set_devtree_node(itsdev, dtn);
870     register_device_var(itsdev, &its_class, "gic-its");
871
872     v3_init_its_domain(gic, itsdev, its);
873 }
874
875 static void
876 v3_probe_its_devices(struct gic* gic, struct dtn* dtn)
877 {
878     struct dtpropi* dtpi;
879     struct dtn* its_node;
880     struct dtn_iter iter;
881
882     dt_begin_find(&iter, dtn, __its_predicate, NULL);
883
884     while (dt_find_next(&iter, (struct dtn_base**)&its_node))
885     {
886         dtpi_init(&dtpi, &its_node->reg);
887         v3_init_its_device(gic, &dtpi, its_node);
888     }
889     
890     dt_end_find(&iter);
891 }
892
893 static struct gic*
894 v3_init(struct device_def* def, struct dtn* dtn)
895 {
896     struct gic* gic;
897     struct device* v3dev;
898     struct dtpropi* dtpi;
899
900     v3dev = device_allocsys(NULL, NULL);
901     device_set_devtree_node(v3dev, dtn);
902     register_device(v3dev, &def->class, "gic");
903
904     gic = gic_create_context(v3dev);
905
906     dtpi_init(&dtpi, &dtn->reg);
907     v3_map_distributor(gic, &dtpi, dtn);
908     v3_map_redistributors(gic, &dtpi, dtn);
909     
910     v3_probe_its_devices(gic, dtn);
911
912     return gic;
913 }
914
915 static void
916 gic_register(struct device_def* def)
917 {
918     dtm_register_entry(def, "arm,gic-v3");
919 }
920
921 static void
922 gic_init(struct device_def* def, morph_t* mobj)
923 {
924     struct gic* gic;
925     struct dtn* node;
926
927     node = changeling_try_reveal(mobj, dt_morpher);
928     if (!node) {
929         return;
930     }
931
932     gic = v3_init(def, node);
933
934     v3_config_distr(gic, v3distr(gic));
935     for (int i = 0; i < gic->nr_cpus; i++)
936     {
937         v3_config_pe(gic, gic->cores[i]);
938     }
939     
940     v3_enable_interrupt(gic);
941 }
942
943
944 static struct device_def dev_arm_gic = {
945     def_device_name("arm gic-v3"),
946     def_device_class(ARM, CFG, GIC),
947
948     def_on_register(gic_register),
949     def_on_create(gic_init)
950 };
951 EXPORT_DEVICE(arm_gic, &dev_arm_gic, load_sysconf);