armv8: Port irq cap invocations
[barrelfish] / kernel / arch / arm / gic_v3.c
1 /*
2  * Copyright (c) 2016, ETH Zurich.
3  * All rights reserved.
4  *
5  * This file is distributed under the terms in the attached LICENSE file.
6  * If you do not find this file, copies can be found by writing to:
7  * ETH Zurich D-INFK, Universitaetstr 6, CH-8092 Zurich. Attn: Systems Group.
8  */
9
10 #include <kernel.h>
11 #include <sysreg.h>
12 #include <dev/armv8_dev.h>
13 #include <dev/gic_v3_dist_dev.h>
14 #include <dev/gic_v3_redist_dev.h>
15 #include <arch/arm/platform.h>
16 #include <paging_kernel_arch.h>
17 #include <arch/arm/gic.h>
18 #include <irq.h>
19 #include <getopt/getopt.h>
20
21 static gic_v3_dist_t gic_v3_dist_dev;
22 static gic_v3_redist_t gic_v3_redist_dev;
23
24 extern lpaddr_t platform_gic_distributor_base;
25 extern lpaddr_t platform_gic_redistributor_base;
26
27 // Command line arguments
28 static struct cmdarg cmdargs[] = {
29     {"gicdist", ArgType_ULong, { .ulonginteger = &platform_gic_distributor_base }},
30     {"gicredist", ArgType_ULong, { .ulonginteger = &platform_gic_redistributor_base }}
31 };
32
33 /*
34  * Initialize the global interrupt controller
35  *
36  * There are three types of interrupts
37  * 1) Software generated Interrupts (SGI) - IDs 0-15
38  * 2) Private Peripheral Interrupts (PPI) - IDs 16-31
39  * 3) Shared Peripheral Interrups (SPI) - IDs 32-1019
40  * 4) Special - IDs 1020-1023
41  * 5) Locality-specific Peripheral Interrups (LPI) - IDs 8192-...
42  */
43 void gic_init(void)
44 {
45     printk(LOG_NOTE, "GICv3: Initializing\n");
46     parse_commandline(kernel_command_line, cmdargs);
47     lvaddr_t gic_dist = local_phys_to_mem(platform_gic_distributor_base);
48     gic_v3_dist_initialize(&gic_v3_dist_dev, (char *)gic_dist);
49
50     printf("%s: dist:%lx\n", __func__, gic_dist);
51
52     printk(LOG_NOTE, "GICD IIDR "
53             "implementer=0x%x, revision=0x%x, variant=0x%x,prodid=0x%x\n",
54             gic_v3_dist_GICD_IIDR_Implementer_rdf(&gic_v3_dist_dev),
55             gic_v3_dist_GICD_IIDR_Revision_rdf(&gic_v3_dist_dev),
56             gic_v3_dist_GICD_IIDR_Variant_rdf(&gic_v3_dist_dev),
57             gic_v3_dist_GICD_IIDR_ProductID_rdf(&gic_v3_dist_dev)
58             );
59
60     uint32_t itlines = gic_v3_dist_GICD_TYPER_ITLinesNumber_rdf(&gic_v3_dist_dev);
61     itlines = (itlines + 1) * 32;
62     if (itlines > 1020)
63         itlines = 1020;
64     printk(LOG_NOTE, "gic: #INTIDs supported: %" PRIu32 "\n", itlines);
65
66     // Put all interrupts into Group 1 and disable them
67     #define MASK_32     0xffffffff
68     for (int i = 0; i * 32 < itlines; i++) {
69         // Clear
70         gic_v3_dist_GICD_ICACTIVER_wr(&gic_v3_dist_dev, i, MASK_32);
71         // Disable all interrupts
72         gic_v3_dist_GICD_ICENABLER_wr(&gic_v3_dist_dev, i, MASK_32);
73         // And put in group 1
74         gic_v3_dist_GICD_IGROUPR_rawwr(&gic_v3_dist_dev, i, MASK_32);
75     }
76     gic_v3_dist_GICD_CTLR_secure_t ctrl = 0;
77     // Set affinity routing (redundant on CN88xx)
78     ctrl = gic_v3_dist_GICD_CTLR_secure_ARE_NS_insert(ctrl, 1);
79     // Enable group 1 interrupts
80     ctrl = gic_v3_dist_GICD_CTLR_secure_EnableGrp1NS_insert(ctrl, 1);
81     gic_v3_dist_GICD_CTLR_secure_wr(&gic_v3_dist_dev, ctrl);
82
83     printk(LOG_NOTE, "GICv3: Initialized\n");
84 }
85
86 /*
87  * Returns active interrupt of group 1
88  */
89 uint32_t platform_get_active_irq(void)
90 {
91     return armv8_ICC_IAR1_EL1_INTID_rdf(NULL);
92 }
93
94 /*
95  * ACKs group 1 interrupt
96  */
97 void platform_acknowledge_irq(uint32_t irq)
98 {
99     armv8_ICC_EOIR1_EL1_rawwr(NULL, irq);
100 }
101
102 /*
103  * Raise an SGI on a core.
104  */
105 void gic_raise_softirq(coreid_t cpuid, uint8_t irq)
106 {
107     assert(irq <= 15);
108     armv8_ICC_SGI1R_EL1_t reg = 0;
109     reg = armv8_ICC_SGI1R_EL1_INTID_insert(reg, 1);
110     // TODO: make that work for cpuids > 15
111     reg = armv8_ICC_SGI1R_EL1_TargetList_insert(reg, 1<<cpuid);
112     reg = armv8_ICC_SGI1R_EL1_Aff3_insert(reg, 0);
113     reg = armv8_ICC_SGI1R_EL1_Aff2_insert(reg, 0);
114     reg = armv8_ICC_SGI1R_EL1_Aff1_insert(reg, 0);
115     armv8_ICC_SGI1R_EL1_wr(NULL, reg);
116 }
117
118 /*
119  * Enable GIC CPU-IF and a redistributor
120  */
121 void gic_cpu_interface_enable(void)
122 {
123     printk(LOG_NOTE, "GICv3: Enabling CPU interface\n");
124
125     lvaddr_t gic_redist = local_phys_to_mem(platform_gic_redistributor_base);
126
127     // Enable system register access
128     armv8_ICC_SRE_EL1_SRE_wrf(NULL, 1);
129
130 // second socket of ThunderX hack
131     if (my_core_id >= 48) {
132         gic_v3_redist_initialize(&gic_v3_redist_dev, (char *)gic_redist + 0x100000000000 + 0x20000 * (my_core_id - 48));
133         printf("%s: redist:%lx\n", __func__, (char *)gic_redist + 0x100000000000 + 0x20000 * (my_core_id - 48));
134     } else {
135         gic_v3_redist_initialize(&gic_v3_redist_dev, (char *)gic_redist + 0x20000 * my_core_id);
136         printf("%s: redist:%lx\n", __func__, (char *)gic_redist + 0x20000 * my_core_id);
137     }
138
139     // Linux does:
140     // sets priority mode: PMR to 0xf0
141     armv8_ICC_PMR_EL1_wr(NULL, 0xf0);
142     // Set binary point to 1, 6 group priority bits, 2 subpriority bits
143     armv8_ICC_BPR1_EL1_wr(NULL, 1);
144
145     //Enable group 1
146     armv8_ICC_IGRPEN1_EL1_wr(NULL, 0x1);
147
148     gic_v3_redist_GICR_TYPER_t gicr_typer;
149     gicr_typer = gic_v3_redist_GICR_TYPER_rd(&gic_v3_redist_dev);
150     printf("%s: GICR_TYPER: affinity:%x  cpu_no:%x\n", __func__, gic_v3_redist_GICR_TYPER_Affinity_Value_extract(gicr_typer), gic_v3_redist_GICR_TYPER_Processor_Number_extract(gicr_typer));
151
152     gic_v3_redist_GICR_ICACTIVER0_rawwr(&gic_v3_redist_dev, MASK_32);
153     //Disable PPIs
154     gic_v3_redist_GICR_ICENABLER0_wr(&gic_v3_redist_dev, MASK_32);
155
156     gic_v3_redist_GICR_IGROUPR0_rawwr(&gic_v3_redist_dev, MASK_32);
157     gic_v3_redist_GICR_IGRPMODR0_rawwr(&gic_v3_redist_dev, 0);
158
159     printk(LOG_NOTE, "GICv3: CPU interface enabled\n");
160 }
161
162 /**
163  * \brief Enable an interrupt
164  *
165  * \see ARM Generic Interrupt Controller Architecture Specification v1.0
166  *
167  * \param int_id
168  * \param cpu_targets 8 Bit mask. One bit for each core in the system.
169  *    (chapter 4.3.11)
170  * \param prio Priority of the interrupt (lower is higher). We allow 0..15.
171  *    The number of priority bits is implementation specific, but at least 16
172  *    (using bits [7:4] of the priority field, chapter 3.3)
173  * \param 0 is level-sensitive, 1 is edge-triggered
174  * \param 0 is N-to-N, 1 is 1-N
175  */
176 errval_t platform_enable_interrupt(uint32_t int_id, uint16_t prio,
177                           bool edge_triggered, bool one_to_n)
178 {
179     if(int_id<32) {
180         gic_v3_redist_GICR_ISENABLER0_wr(&gic_v3_redist_dev, 1<<int_id );
181     }
182     else {  
183         gic_v3_dist_GICD_ISENABLER_wr(&gic_v3_dist_dev, int_id/32,
184             1<<(int_id % 32));
185     }
186     return SYS_ERR_OK;
187 }
188
189 errval_t platform_init_ic_bsp(void)
190 {
191     gic_init();
192     gic_cpu_interface_enable();
193     return SYS_ERR_OK;
194 }
195
196 errval_t platform_init_ic_app(void)
197 {
198     gic_cpu_interface_enable();
199     return SYS_ERR_OK;
200 }