• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this list of
9  *    conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12  *    of conditions and the following disclaimer in the documentation and/or other materials
13  *    provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16  *    to endorse or promote products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "gic_common.h"
33 #include "gic_v3.h"
34 #include "los_typedef.h"
35 #include "los_hwi.h"
36 #include "los_hwi_pri.h"
37 #include "los_mp.h"
38 
39 #ifdef LOSCFG_ARCH_GIC_V3
40 
41 STATIC UINT32 g_curIrqNum = 0;
42 
MpidrToAffinity(UINT64 mpidr)43 STATIC INLINE UINT64 MpidrToAffinity(UINT64 mpidr)
44 {
45     return ((MPIDR_AFF_LEVEL(mpidr, 3) << 32) | /* 3: Serial number, 32: Register bit offset */
46             (MPIDR_AFF_LEVEL(mpidr, 2) << 16) | /* 2: Serial number, 16: Register bit offset */
47             (MPIDR_AFF_LEVEL(mpidr, 1) << 8)  | /* 1: Serial number, 8: Register bit offset */
48             (MPIDR_AFF_LEVEL(mpidr, 0)));
49 }
50 
51 #ifdef LOSCFG_KERNEL_SMP
52 
NextCpu(UINT32 cpu,UINT32 cpuMask)53 STATIC UINT32 NextCpu(UINT32 cpu, UINT32 cpuMask)
54 {
55     UINT32 next = cpu + 1;
56 
57     while (next < LOSCFG_KERNEL_CORE_NUM) {
58         if (cpuMask & (1U << next)) {
59             goto OUT;
60         }
61 
62         next++;
63     }
64 
65 OUT:
66     return next;
67 }
68 
GicTargetList(UINT32 * base,UINT32 cpuMask,UINT64 cluster)69 STATIC UINT16 GicTargetList(UINT32 *base, UINT32 cpuMask, UINT64 cluster)
70 {
71     UINT32 nextCpu;
72     UINT16 tList = 0;
73     UINT32 cpu = *base;
74     UINT64 mpidr = CPU_MAP_GET(cpu);
75     while (cpu < LOSCFG_KERNEL_CORE_NUM) {
76         tList |= 1U << (mpidr & 0xf);
77 
78         nextCpu = NextCpu(cpu, cpuMask);
79         if (nextCpu >= LOSCFG_KERNEL_CORE_NUM) {
80             goto out;
81         }
82 
83         cpu = nextCpu;
84         mpidr = CPU_MAP_GET(cpu);
85         if (cluster != (mpidr & ~0xffUL)) {
86             cpu--;
87             goto out;
88         }
89     }
90 
91 out:
92     *base = cpu;
93     return tList;
94 }
95 
GicSgi(UINT32 irq,UINT32 cpuMask)96 STATIC VOID GicSgi(UINT32 irq, UINT32 cpuMask)
97 {
98     UINT16 tList;
99     UINT32 cpu = 0;
100     UINT64 val, cluster;
101 
102     while (cpuMask && (cpu < LOSCFG_KERNEL_CORE_NUM)) {
103         if (cpuMask & (1U << cpu)) {
104             cluster = CPU_MAP_GET(cpu) & ~0xffUL;
105 
106             tList = GicTargetList(&cpu, cpuMask, cluster);
107 
108             /* Generates a Group 1 interrupt for the current security state */
109             val = ((MPIDR_AFF_LEVEL(cluster, 3) << 48) | /* 3: Serial number, 48: Register bit offset */
110                    (MPIDR_AFF_LEVEL(cluster, 2) << 32) | /* 2: Serial number, 32: Register bit offset */
111                    (MPIDR_AFF_LEVEL(cluster, 1) << 16) | /* 1: Serial number, 16: Register bit offset */
112                    (irq << 24) | tList); /* 24: Register bit offset */
113 
114             GiccSetSgi1r(val);
115         }
116 
117         cpu++;
118     }
119 }
120 
HalIrqSendIpi(UINT32 target,UINT32 ipi)121 VOID HalIrqSendIpi(UINT32 target, UINT32 ipi)
122 {
123     GicSgi(ipi, target);
124 }
125 
HalIrqSetAffinity(UINT32 irq,UINT32 cpuMask)126 VOID HalIrqSetAffinity(UINT32 irq, UINT32 cpuMask)
127 {
128     UINT64 affinity = MpidrToAffinity(NextCpu(0, cpuMask));
129 
130     /* When ARE is on, use router */
131     GIC_REG_64(GICD_IROUTER(irq)) = affinity;
132 }
133 
134 #endif
135 
GicWaitForRwp(UINT64 reg)136 STATIC VOID GicWaitForRwp(UINT64 reg)
137 {
138     INT32 count = 1000000; /* 1s */
139 
140     while (GIC_REG_32(reg) & GICD_CTLR_RWP) {
141         count -= 1;
142         if (!count) {
143             PRINTK("gic_v3: rwp timeout 0x%x\n", GIC_REG_32(reg));
144             return;
145         }
146     }
147 }
148 
GicdSetGroup(UINT32 irq)149 STATIC INLINE VOID GicdSetGroup(UINT32 irq)
150 {
151     /* configure spi as group 0 on secure mode and group 1 on unsecure mode */
152 #ifdef LOSCFG_ARCH_SECURE_MONITOR_MODE
153     GIC_REG_32(GICD_IGROUPR(irq / 32)) = 0; /* 32: Interrupt bit width */
154 #else
155     GIC_REG_32(GICD_IGROUPR(irq / 32)) = 0xffffffff; /* 32: Interrupt bit width */
156 #endif
157 }
158 
GicrSetWaker(UINT32 cpu)159 STATIC INLINE VOID GicrSetWaker(UINT32 cpu)
160 {
161     GIC_REG_32(GICR_WAKER(cpu)) &= ~GICR_WAKER_PROCESSORSLEEP;
162     DSB;
163     ISB;
164     while ((GIC_REG_32(GICR_WAKER(cpu)) & 0x4) == GICR_WAKER_CHILDRENASLEEP);
165 }
166 
GicrSetGroup(UINT32 cpu)167 STATIC INLINE VOID GicrSetGroup(UINT32 cpu)
168 {
169     /* configure sgi/ppi as group 0 on secure mode and group 1 on unsecure mode */
170 #ifdef LOSCFG_ARCH_SECURE_MONITOR_MODE
171     GIC_REG_32(GICR_IGROUPR0(cpu)) = 0;
172     GIC_REG_32(GICR_IGRPMOD0(cpu)) = 0;
173 #else
174     GIC_REG_32(GICR_IGROUPR0(cpu)) = 0xffffffff;
175 #endif
176 }
177 
GicdSetPmr(UINT32 irq,UINT8 priority)178 STATIC VOID GicdSetPmr(UINT32 irq, UINT8 priority)
179 {
180     UINT32 pos = irq >> 2; /* one irq have the 8-bit interrupt priority field */
181     UINT32 newPri = GIC_REG_32(GICD_IPRIORITYR(pos));
182 
183     /* Shift and mask the correct bits for the priority */
184     newPri &= ~(GIC_PRIORITY_MASK << ((irq % 4) * GIC_PRIORITY_OFFSET));
185     newPri |= priority << ((irq % 4) * GIC_PRIORITY_OFFSET);
186 
187     GIC_REG_32(GICD_IPRIORITYR(pos)) = newPri;
188 }
189 
GicrSetPmr(UINT32 irq,UINT8 priority)190 STATIC VOID GicrSetPmr(UINT32 irq, UINT8 priority)
191 {
192     UINT32 cpu = ArchCurrCpuid();
193     UINT32 pos = irq >> 2; /* one irq have the 8-bit interrupt priority field */
194     UINT32 newPri = GIC_REG_32(GICR_IPRIORITYR0(cpu) + pos * 4);
195 
196     /* Clear priority offset bits and set new priority */
197     newPri &= ~(GIC_PRIORITY_MASK << ((irq % 4) * GIC_PRIORITY_OFFSET));
198     newPri |= priority << ((irq % 4) * GIC_PRIORITY_OFFSET);
199 
200     GIC_REG_32(GICR_IPRIORITYR0(cpu) + pos * 4) = newPri;
201 }
202 
GiccInitPercpu(VOID)203 STATIC VOID GiccInitPercpu(VOID)
204 {
205     /* enable system register interface */
206     UINT32 sre = GiccGetSre();
207     if (!(sre & 0x1)) {
208         GiccSetSre(sre | 0x1);
209 
210         /*
211          * Need to check that the SRE bit has actually been set. If
212          * not, it means that SRE is disabled at up EL level. We're going to
213          * die painfully, and there is nothing we can do about it.
214          */
215         sre = GiccGetSre();
216         LOS_ASSERT(sre & 0x1);
217     }
218 
219 #ifdef LOSCFG_ARCH_SECURE_MONITOR_MODE
220     /* Enable group 0 and disable grp1ns grp1s interrupts */
221     GiccSetIgrpen0(1);
222     GiccSetIgrpen1(0);
223 
224     /*
225      * For priority grouping.
226      * The value of this field control show the 8-bit interrupt priority field
227      * is split into a group priority field, that determines interrupt preemption,
228      * and a subpriority field.
229      */
230     GiccSetBpr0(MAX_BINARY_POINT_VALUE);
231 #else
232     /* enable group 1 interrupts */
233     GiccSetIgrpen1(1);
234 #endif
235 
236     /* set priority threshold to max */
237     GiccSetPmr(0xff);
238 
239     /* EOI deactivates interrupt too (mode 0) */
240     GiccSetCtlr(0);
241 }
242 
HalCurIrqGet(VOID)243 UINT32 HalCurIrqGet(VOID)
244 {
245     return g_curIrqNum;
246 }
247 
HalIrqMask(UINT32 vector)248 VOID HalIrqMask(UINT32 vector)
249 {
250     INT32 i;
251     const UINT32 mask = 1U << (vector % 32); /* 32: Interrupt bit width */
252 
253     if ((vector > OS_USER_HWI_MAX) || (vector < OS_USER_HWI_MIN)) {
254         return;
255     }
256 
257     if (vector < 32) { /* 32: Interrupt bit width */
258         for (i = 0; i < LOSCFG_KERNEL_CORE_NUM; i++) {
259             GIC_REG_32(GICR_ICENABLER0(i)) = mask;
260             GicWaitForRwp(GICR_CTLR(i));
261         }
262     } else {
263         GIC_REG_32(GICD_ICENABLER(vector >> 5)) = mask;
264         GicWaitForRwp(GICD_CTLR);
265     }
266 }
267 
HalIrqUnmask(UINT32 vector)268 VOID HalIrqUnmask(UINT32 vector)
269 {
270     INT32 i;
271     const UINT32 mask = 1U << (vector % 32); /* 32: Interrupt bit width */
272 
273     if ((vector > OS_USER_HWI_MAX) || (vector < OS_USER_HWI_MIN)) {
274         return;
275     }
276 
277     if (vector < 32) { /* 32: Interrupt bit width */
278         for (i = 0; i < LOSCFG_KERNEL_CORE_NUM; i++) {
279             GIC_REG_32(GICR_ISENABLER0(i)) = mask;
280             GicWaitForRwp(GICR_CTLR(i));
281         }
282     } else {
283         GIC_REG_32(GICD_ISENABLER(vector >> 5)) = mask; /* 5: Register bit offset */
284         GicWaitForRwp(GICD_CTLR);
285     }
286 }
287 
HalIrqPending(UINT32 vector)288 VOID HalIrqPending(UINT32 vector)
289 {
290     if ((vector > OS_USER_HWI_MAX) || (vector < OS_USER_HWI_MIN)) {
291         return;
292     }
293 
294     GIC_REG_32(GICD_ISPENDR(vector >> 5)) = 1U << (vector % 32); /* 5: Register bit offset, 32: Interrupt bit width */
295 }
296 
HalIrqClear(UINT32 vector)297 VOID HalIrqClear(UINT32 vector)
298 {
299     GiccSetEoir(vector);
300     ISB;
301 }
302 
HalIrqSetPrio(UINT32 vector,UINT8 priority)303 UINT32 HalIrqSetPrio(UINT32 vector, UINT8 priority)
304 {
305     UINT8 prio = priority;
306 
307     if (vector > OS_HWI_MAX_NUM) {
308         PRINT_ERR("Invalid irq value %u, max irq is %u\n", vector, OS_HWI_MAX_NUM);
309         return LOS_NOK;
310     }
311 
312     prio = prio & (UINT8)GIC_INTR_PRIO_MASK;
313 
314     if (vector >= GIC_MIN_SPI_NUM) {
315         GicdSetPmr(vector, prio);
316     } else {
317         GicrSetPmr(vector, prio);
318     }
319 
320     return LOS_OK;
321 }
322 
HalIrqInitPercpu(VOID)323 VOID HalIrqInitPercpu(VOID)
324 {
325     INT32 idx;
326     UINT32 cpu = ArchCurrCpuid();
327 
328     /* GICR init */
329     GicrSetWaker(cpu);
330     GicrSetGroup(cpu);
331     GicWaitForRwp(GICR_CTLR(cpu));
332 
333     /* GICR: clear and mask sgi/ppi */
334     GIC_REG_32(GICR_ICENABLER0(cpu)) = 0xffffffff;
335     GIC_REG_32(GICR_ICPENDR0(cpu)) = 0xffffffff;
336 
337     GIC_REG_32(GICR_ISENABLER0(cpu)) = 0xffffffff;
338 
339     for (idx = 0; idx < GIC_MIN_SPI_NUM; idx += 1) {
340         GicrSetPmr(idx, MIN_INTERRUPT_PRIORITY);
341     }
342 
343     GicWaitForRwp(GICR_CTLR(cpu));
344 
345     /* GICC init */
346     GiccInitPercpu();
347 
348 #ifdef LOSCFG_KERNEL_SMP
349     /* unmask ipi interrupts */
350     HalIrqUnmask(LOS_MP_IPI_WAKEUP);
351     HalIrqUnmask(LOS_MP_IPI_HALT);
352 #endif
353 }
354 
HalIrqInit(VOID)355 VOID HalIrqInit(VOID)
356 {
357     UINT32 i;
358     UINT64 affinity;
359 
360     /* disable distributor */
361     GIC_REG_32(GICD_CTLR) = 0;
362     GicWaitForRwp(GICD_CTLR);
363     ISB;
364 
365     /* set external interrupts to be level triggered, active low. */
366     for (i = 32; i < OS_HWI_MAX_NUM; i += 16) { /* 32: Start interrupt number, 16: Interrupt bit width */
367         GIC_REG_32(GICD_ICFGR(i / 16)) = 0;
368     }
369 
370     /* config distributer, mask and clear all spis, set group x */
371     for (i = 32; i < OS_HWI_MAX_NUM; i += 32) { /* 32: Start interrupt number, 32: Interrupt bit width */
372         GIC_REG_32(GICD_ICENABLER(i / 32)) = 0xffffffff; /* 32: Interrupt bit width */
373         GIC_REG_32(GICD_ICPENDR(i / 32)) = 0xffffffff; /* 32: Interrupt bit width */
374         GIC_REG_32(GICD_IGRPMODR(i / 32)) = 0; /* 32: Interrupt bit width */
375 
376         GicdSetGroup(i);
377     }
378 
379     /* set spi priority as default */
380     for (i = 32; i < OS_HWI_MAX_NUM; i++) { /* 32: Start interrupt number */
381         GicdSetPmr(i, MIN_INTERRUPT_PRIORITY);
382     }
383 
384     GicWaitForRwp(GICD_CTLR);
385 
386     /* disable all interrupts. */
387     for (i = 0; i < OS_HWI_MAX_NUM; i += 32) { /* 32: Interrupt bit width */
388         GIC_REG_32(GICD_ICENABLER(i / 32)) = 0xffffffff; /* 32: Interrupt bit width */
389     }
390 
391     /* enable distributor with ARE, group 1 enabled */
392     GIC_REG_32(GICD_CTLR) = CTLR_ENALBE_G0 | CTLR_ENABLE_G1NS | CTLR_ARE_S;
393 
394     /* set spi to boot cpu only. ARE must be enabled */
395     affinity = MpidrToAffinity(AARCH64_SYSREG_READ(mpidr_el1));
396     for (i = 32; i < OS_HWI_MAX_NUM; i++) { /* 32: Start interrupt number */
397         GIC_REG_64(GICD_IROUTER(i)) = affinity;
398     }
399 
400     HalIrqInitPercpu();
401 
402 #ifdef LOSCFG_KERNEL_SMP
403     /* register inter-processor interrupt */
404     (VOID)LOS_HwiCreate(LOS_MP_IPI_WAKEUP, 0xa0, 0, OsMpWakeHandler, 0);
405     (VOID)LOS_HwiCreate(LOS_MP_IPI_SCHEDULE, 0xa0, 0, OsMpScheduleHandler, 0);
406     (VOID)LOS_HwiCreate(LOS_MP_IPI_HALT, 0xa0, 0, OsMpScheduleHandler, 0);
407 #ifdef LOSCFG_KERNEL_SMP_CALL
408     (VOID)LOS_HwiCreate(LOS_MP_IPI_FUNC_CALL, 0xa0, 0, OsMpFuncCallHandler, 0);
409 #endif
410 #endif
411 }
412 
HalIrqHandler(VOID)413 VOID HalIrqHandler(VOID)
414 {
415     UINT32 iar = GiccGetIar();
416     UINT32 vector = iar & 0x3FFU;
417 
418     /*
419      * invalid irq number, mainly the spurious interrupts 0x3ff,
420      * valid irq ranges from 0~1019, we use OS_HWI_MAX_NUM to do
421      * the checking.
422      */
423     if (vector >= OS_HWI_MAX_NUM) {
424         return;
425     }
426     g_curIrqNum = vector;
427 
428     OsInterrupt(vector);
429     GiccSetEoir(vector);
430 }
431 
HalIrqVersion(VOID)432 CHAR *HalIrqVersion(VOID)
433 {
434     UINT32 pidr = GIC_REG_32(GICD_PIDR2V3);
435     CHAR *irqVerString = NULL;
436 
437     switch (pidr >> GIC_REV_OFFSET) {
438         case GICV3:
439             irqVerString = "GICv3";
440             break;
441         case GICV4:
442             irqVerString = "GICv4";
443             break;
444         default:
445             irqVerString = "unknown";
446     }
447     return irqVerString;
448 }
449 
450 #endif
451