]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/bcm64/gic.c
kernel: page counts a ulong, not usize
[plan9front.git] / sys / src / 9 / bcm64 / gic.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/pci.h"
8 #include "ureg.h"
9 #include "sysreg.h"
10 #include "../port/error.h"
11
12 enum {
13         GICD_CTLR       = 0x000/4,      /* RW, Distributor Control Register */
14         GICD_TYPER      = 0x004/4,      /* RO, Interrupt Controller Type */
15         GICD_IIDR       = 0x008/4,      /* RO, Distributor Implementer Identification Register */
16
17         GICD_IGROUPR0   = 0x080/4,      /* RW, Interrupt Group Registers (0x80-0xBC) */
18
19         GICD_ISENABLER0 = 0x100/4,      /* RW, Interrupt Set-Enable Registers (0x100-0x13C) */
20         GICD_ICENABLER0 = 0x180/4,      /* RW, Interrupt Clear-Enable Registers (0x180-0x1BC) */
21
22         GICD_ISPENDR0   = 0x200/4,      /* RW, Interrupt Set-Pending Registers (0x200-0x23C) */
23         GICD_ICPENDR0   = 0x280/4,      /* RW, Interrupt Clear-Pending Registers (0x280-0x2BC) */
24
25         GICD_ISACTIVER0 = 0x300/4,      /* RW, Interrupt Set-Active Registers (0x300-0x33C) */
26         GICD_ICACTIVER0 = 0x380/4,      /* RW, Interrupt Clear-Active Registers (0x380-0x3BC) */
27
28         GICD_IPRIORITYR0= 0x400/4,      /* RW, Interrupt Priority Registers (0x400-0x5FC) */
29         GICD_TARGETSR0  = 0x800/4,      /* RW, Interrupt Target Registers (0x800-0x9FC) */
30         GICD_ICFGR0     = 0xC00/4,      /* RW, Interrupt Configuration Registers (0xC00-0xC7C) */
31
32         GICD_ISR0       = 0xD00/4,
33         GICD_PPISR      = GICD_ISR0,    /* RO, Private Peripheral Interrupt Status Register */
34         GICD_SPISR0     = GICD_ISR0+1,  /* RO, Shared Peripheral Interrupt Status Register */
35         GICD_SGIR       = 0xF00/4,      /* WO, Software Generated Interrupt Register */
36
37         GICD_CPENDSGIR0 = 0xF10/4,      /* RW, SGI Clear-Pending Registers (0xF10-0xF1C) */
38         GICD_SPENDSGIR0 = 0xF20/4,      /* RW, SGI Set-Pending Registers (0xF20-0xF2C) */
39
40         GICD_PIDR4      = 0xFD0/4,      /* RO, Perpheral ID Registers */
41         GICD_PIDR5      = 0xFD4/4,
42         GICD_PIDR6      = 0xFD8/4,
43         GICD_PIDR7      = 0xFDC/4,
44         GICD_PIDR0      = 0xFE0/4,
45         GICD_PIDR1      = 0xFE4/4,
46         GICD_PIDR2      = 0xFE8/4,
47         GICD_PIDR3      = 0xFEC/4,
48
49         GICD_CIDR0      = 0xFF0/4,      /* RO, Component ID Registers */
50         GICD_CIDR1      = 0xFF4/4,
51         GICD_CIDR2      = 0xFF8/4,
52         GICD_CIDR3      = 0xFFC/4,
53
54         GICC_CTLR       = 0x000/4,      /* RW, CPU Interace Control Register */
55         GICC_PMR        = 0x004/4,      /* RW, Interrupt Priority Mask Register */
56         GICC_BPR        = 0x008/4,      /* RW, Binary Point Register */
57         GICC_IAR        = 0x00C/4,      /* RO, Interrupt Acknowledge Register */
58         GICC_EOIR       = 0x010/4,      /* WO, End of Interrupt Register */
59         GICC_RPR        = 0x014/4,      /* RO, Running Priority Register */
60         GICC_HPPIR      = 0x018/4,      /* RO, Highest Priority Pending Interrupt Register */
61         GICC_ABPR       = 0x01C/4,      /* RW, Aliased Binary Point Register */
62         GICC_AIAR       = 0x020/4,      /* RO, Aliased Interrupt Acknowledge Register */
63         GICC_AEOIR      = 0x024/4,      /* WO, Aliased End of Interrupt Register */
64         GICC_AHPPIR     = 0x028/4,      /* RO, Aliased Highest Priority Pending Interrupt Register */
65         GICC_APR0       = 0x0D0/4,      /* RW, Active Priority Register */
66         GICC_NSAPR0     = 0x0E0/4,      /* RW, Non-Secure Active Priority Register */
67         GICC_IIDR       = 0x0FC/4,      /* RO, CPU Interface Identification Register */
68         GICC_DIR        = 0x1000/4,     /* WO, Deactivate Interrupt Register */
69
70         GICH_HCR        = 0x000/4,      /* RW, Hypervisor Control Register */
71         GICH_VTR        = 0x004/4,      /* RO, VGIC Type Register */
72         GICH_VMCR       = 0x008/4,      /* RW, Virtual Machine Control Register */
73         GICH_MISR       = 0x010/4,      /* RO, Maintenance Interrupt Status Register */
74         GICH_EISR0      = 0x020/4,      /* RO, End of Interrupt Status Register */
75         GICH_ELSR0      = 0x030/4,      /* RO, Empty List Register Status Register */
76         GICH_APR0       = 0x0F0/4,      /* RW, Active Priority Register */
77         GICH_LR0        = 0x100/4,      /* RW, List Registers (0x100-0x10C) */
78
79         GICV_CTLR       = 0x000/4,      /* RW, Virtual Machine Control Register */
80         GICV_PMR        = 0x004/4,      /* RW, VM Priority Mask Register */
81         GICV_BPR        = 0x008/4,      /* RW, VM Binary Point Register */
82         GICV_IAR        = 0x00C/4,      /* RO, VM Interrupt Acknowledge Register */
83         GICV_EOIR       = 0x010/4,      /* WO, VM End of Interrupt Register */
84         GICV_RPR        = 0x014/4,      /* RO, VM Running Priority Register */
85         GICV_HPPIR      = 0x018/4,      /* RO, VM Highest Piority Pending Interrupt Register */
86         GICV_ABPR       = 0x01C/4,      /* RW, VM Aliased Binary Point Register */
87         GICV_AIAR       = 0x020/4,      /* RO, VM Aliased Interrupt Acknowledge Register */
88         GICV_AEOIR      = 0x024/4,      /* WO, VM Aliased End of Interrupt Register */
89         GICV_AHPPIR     = 0x028/4,      /* RO, VM Aliaed Highest Piority Pending Interrupt Register */
90         GICV_APR0       = 0x0D0/4,      /* RW, VM Active Priority Register */
91         GICV_IIDR       = 0x0FC/4,      /* RO, VM CPU Interface Identification Register */
92         GICV_DIR        = 0x1000/4,     /* WO, VM Deactivate Interrupt Register */
93 };
94
95 typedef struct Vctl Vctl;
96 struct Vctl {
97         Vctl    *next;
98         void    (*f)(Ureg*, void*);
99         void    *a;
100         int     irq;
101         u32int  intid;
102 };
103
104 static Lock vctllock;
105 static Vctl *vctl[MAXMACH][32], *vfiq;
106 static u32int *cregs, *dregs;
107
108 void
109 intrcpushutdown(void)
110 {
111         if(cregs == nil || dregs == nil){
112                 uintptr va, pa;
113
114                 pa = sysrd(CBAR_EL1);
115                 va = ARMLOCAL + (pa - soc.armlocal);
116                 dregs = (u32int*)(va + 0x1000);
117                 cregs = (u32int*)(va + 0x2000);
118         }
119
120         /* disable cpu interface */
121         cregs[GICC_CTLR] &= ~1;
122         coherence();
123 }
124
125 void
126 intrsoff(void)
127 {
128         int i, n;
129
130         intrcpushutdown();
131
132         /* disable distributor */
133         dregs[GICD_CTLR] &= ~1;
134         coherence();
135
136         /* clear all interrupts */
137         n = ((dregs[GICD_TYPER] & 0x1F)+1) << 5;
138         for(i = 0; i < n; i += 32){
139                 dregs[GICD_ISENABLER0 + (i/32)] = -1;
140                 coherence();
141                 dregs[GICD_ICENABLER0 + (i/32)] = -1;
142                 coherence();
143         }
144         for(i = 0; i < n; i += 4){
145                 dregs[GICD_IPRIORITYR0 + (i/4)] = 0;
146                 dregs[GICD_TARGETSR0 + (i/4)] = 0;
147         }
148         for(i = 32; i < n; i += 16)
149                 dregs[GICD_ICFGR0 + (i/16)] = 0;
150         coherence();
151 }
152
153 /*
154  *  called by trap to handle irq interrupts.
155  *  returns true iff a clock interrupt, thus maybe reschedule.
156  */
157 int
158 irq(Ureg* ureg)
159 {
160         Vctl *v;
161         int clockintr;
162         u32int intid;
163
164         m->intr++;
165         intid = cregs[GICC_IAR] & 0xFFFFFF;
166         if((intid & ~3) == 1020)
167                 return 0; // spurious
168         clockintr = 0;
169         for(v = vctl[m->machno][intid%32]; v != nil; v = v->next)
170                 if(v->intid == intid){
171                         coherence();
172                         v->f(ureg, v->a);
173                         coherence();
174                         if(v->irq == IRQclock || v->irq == IRQcntps || v->irq == IRQcntpns)
175                                 clockintr = 1;
176                 }
177         coherence();
178         cregs[GICC_EOIR] = intid;
179         return clockintr;
180 }
181
182 /*
183  * called direct from lexception.s to handle fiq interrupt.
184  */
185 void
186 fiq(Ureg *ureg)
187 {
188         Vctl *v;
189         u32int intid;
190
191         m->intr++;
192         intid = cregs[GICC_IAR] & 0xFFFFFF;
193         if((intid & ~3) == 1020)
194                 return; // spurious
195         v = vfiq;
196         if(v != nil && v->intid == intid && m->machno == 0){
197                 coherence();
198                 v->f(ureg, v->a);
199                 coherence();
200         }
201         cregs[GICC_EOIR] = intid;
202 }
203
204 void
205 intrenable(int irq, void (*f)(Ureg*, void*), void *a, int tbdf, char*)
206 {
207         Vctl *v;
208         u32int intid;
209         int cpu, prio;
210
211         if(BUSTYPE(tbdf) == BusPCI){
212                 pciintrenable(tbdf, f, a);
213                 return;
214         }
215         if(tbdf != BUSUNKNOWN)
216                 return;
217
218         cpu = 0;
219         prio = 0x80;
220         intid = irq;
221         switch(irq){
222         case IRQcntps:
223                 intid = 16 + 13;
224                 break;
225         case IRQcntpns:
226                 intid = 16 + 14;
227                 break;
228
229         case IRQmbox0:
230         case IRQmbox1:
231         case IRQmbox2:
232         case IRQmbox3:
233         case IRQlocaltmr:
234                 print("irqenable: missing documentation for local irq %d\n", irq);
235                 return;
236
237         default:
238                 if(irq < IRQgic){
239                         if(irq < 64)
240                                 intid += IRQgic-64;
241                         else if(irq >= IRQbasic)
242                                 intid += IRQgic-64-32-8-IRQbasic;
243                 }
244         }
245         if(intid < 32)
246                 cpu = m->machno;
247
248         if((v = xalloc(sizeof(Vctl))) == nil)
249                 panic("irqenable: no mem");
250         v->irq = irq;
251         v->intid = intid;
252         v->f = f;
253         v->a = a;
254
255         lock(&vctllock);
256         if(irq == IRQfiq){
257                 vfiq = v;
258                 prio = 0;
259         }else{
260                 v->next = vctl[cpu][intid%32];
261                 vctl[cpu][intid%32] = v;
262         }
263
264         /* enable cpu interface */
265         cregs[GICC_PMR] = 0xFF;
266         coherence();
267
268         cregs[GICC_CTLR] |= 1;
269         coherence();
270
271         cregs[GICC_EOIR] = intid;
272
273         /* enable distributor */
274         dregs[GICD_CTLR] |= 1;
275         coherence();
276
277         /* setup */
278         dregs[GICD_IPRIORITYR0 + (intid/4)] |= prio << ((intid%4) << 3);
279         dregs[GICD_TARGETSR0 + (intid/4)] |= (1<<cpu) << ((intid%4) << 3);
280         coherence();
281
282         /* turn on */
283         dregs[GICD_ISENABLER0 + (intid/32)] = 1 << (intid%32);
284         coherence();
285
286         unlock(&vctllock);
287 }
288
289 void
290 intrdisable(int, void (*f)(Ureg*, void*), void *a, int tbdf, char*)
291 {
292         if(BUSTYPE(tbdf) == BusPCI){
293                 pciintrdisable(tbdf, f, a);
294                 return;
295         }
296 }