]> rtime.felk.cvut.cz Git - jailhouse.git/blob - hypervisor/arch/arm/irqchip.c
7a6d4cadf6098146402f8b2cb6ce7487aafa3e57
[jailhouse.git] / hypervisor / arch / arm / irqchip.c
1 /*
2  * Jailhouse, a Linux-based partitioning hypervisor
3  *
4  * Copyright (c) ARM Limited, 2014
5  *
6  * Authors:
7  *  Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2.  See
10  * the COPYING file in the top-level directory.
11  */
12
13 #include <jailhouse/entry.h>
14 #include <jailhouse/mmio.h>
15 #include <jailhouse/paging.h>
16 #include <jailhouse/printk.h>
17 #include <jailhouse/string.h>
18 #include <asm/gic_common.h>
19 #include <asm/irqchip.h>
20 #include <asm/platform.h>
21 #include <asm/setup.h>
22 #include <asm/sysregs.h>
23
24 /* AMBA's biosfood */
25 #define AMBA_DEVICE     0xb105f00d
26
27 void *gicd_base;
28 unsigned long gicd_size;
29
30 /*
31  * The init function must be called after the MMU setup, and whilst in the
32  * per-cpu setup, which means that a bool must be set by the master CPU
33  */
34 static bool irqchip_is_init;
35 static struct irqchip_ops irqchip;
36
37 bool spi_in_cell(struct cell *cell, unsigned int spi)
38 {
39         /* FIXME: Change the configuration to a bitmask range */
40         u32 spi_mask;
41
42         if (spi >= 64)
43                 return false;
44         else if (spi >= 32)
45                 spi_mask = cell->arch.spis >> 32;
46         else
47                 spi_mask = cell->arch.spis;
48
49         return spi_mask & (1 << (spi & 31));
50 }
51
52 static int irqchip_init_pending(struct per_cpu *cpu_data)
53 {
54         struct pending_irq *pend_array;
55
56         if (cpu_data->pending_irqs == NULL) {
57                 cpu_data->pending_irqs = pend_array = page_alloc(&mem_pool, 1);
58                 if (pend_array == NULL)
59                         return -ENOMEM;
60         } else {
61                 pend_array = cpu_data->pending_irqs;
62         }
63
64         memset(pend_array, 0, PAGE_SIZE);
65
66         cpu_data->pending_irqs = pend_array;
67         cpu_data->first_pending = NULL;
68
69         return 0;
70 }
71
72 /*
73  * Find the first available pending struct for insertion. The `prev' pointer is
74  * set to the previous pending interrupt, if any, to help inserting the new one
75  * into the list.
76  * Returns NULL when no slot is available
77  */
78 static struct pending_irq* get_pending_slot(struct per_cpu *cpu_data,
79                                             struct pending_irq **prev)
80 {
81         u32 i, pending_idx;
82         struct pending_irq *pending = cpu_data->first_pending;
83
84         *prev = NULL;
85
86         for (i = 0; i < MAX_PENDING_IRQS; i++) {
87                 pending_idx = pending - cpu_data->pending_irqs;
88                 if (pending == NULL || i < pending_idx)
89                         return cpu_data->pending_irqs + i;
90
91                 *prev = pending;
92                 pending = pending->next;
93         }
94
95         return NULL;
96 }
97
98 int irqchip_insert_pending(struct per_cpu *cpu_data, struct pending_irq *irq)
99 {
100         struct pending_irq *prev = NULL;
101         struct pending_irq *slot;
102
103         spin_lock(&cpu_data->gic_lock);
104
105         slot = get_pending_slot(cpu_data, &prev);
106         if (slot == NULL) {
107                 spin_unlock(&cpu_data->gic_lock);
108                 return -ENOMEM;
109         }
110
111         /*
112          * Don't override the pointers yet, they may be read by the injection
113          * loop. Odds are astronomically low, but hey.
114          */
115         memcpy(slot, irq, sizeof(struct pending_irq) - 2 * sizeof(void *));
116         slot->prev = prev;
117         if (prev) {
118                 slot->next = prev->next;
119                 prev->next = slot;
120         } else {
121                 slot->next = cpu_data->first_pending;
122                 cpu_data->first_pending = slot;
123         }
124         if (slot->next)
125                 slot->next->prev = slot;
126
127         spin_unlock(&cpu_data->gic_lock);
128
129         return 0;
130 }
131
132 int irqchip_set_pending(struct per_cpu *cpu_data, u32 irq_id, bool try_inject)
133 {
134         struct pending_irq pending;
135
136         pending.virt_id = irq_id;
137         /* Priority must be less than ICC_PMR */
138         pending.priority = 0;
139
140         if (is_sgi(irq_id)) {
141                 pending.hw = 0;
142                 pending.type.sgi.maintenance = 0;
143                 pending.type.sgi.cpuid = 0;
144         } else {
145                 pending.hw = 1;
146                 pending.type.irq = irq_id;
147         }
148
149         if (try_inject && irqchip.inject_irq(cpu_data, &pending) == 0)
150                 return 0;
151
152         return irqchip_insert_pending(cpu_data, &pending);
153 }
154
155 /*
156  * Only executed by `irqchip_inject_pending' on a CPU to inject its own stuff.
157  */
158 int irqchip_remove_pending(struct per_cpu *cpu_data, struct pending_irq *irq)
159 {
160         spin_lock(&cpu_data->gic_lock);
161
162         if (cpu_data->first_pending == irq)
163                 cpu_data->first_pending = irq->next;
164         if (irq->prev)
165                 irq->prev->next = irq->next;
166         if (irq->next)
167                 irq->next->prev = irq->prev;
168
169         spin_unlock(&cpu_data->gic_lock);
170
171         return 0;
172 }
173
174 int irqchip_inject_pending(struct per_cpu *cpu_data)
175 {
176         int err;
177         struct pending_irq *pending = cpu_data->first_pending;
178
179         while (pending != NULL) {
180                 err = irqchip.inject_irq(cpu_data, pending);
181                 if (err == -EBUSY)
182                         /* The list registers are full. */
183                         break;
184                 else
185                         /*
186                          * Removal only changes the pointers, but does not
187                          * deallocate anything.
188                          * Concurrent accesses are avoided with the spinlock,
189                          * but the `next' pointer of the current pending object
190                          * may be rewritten by an external insert before or
191                          * after this removal, which isn't an issue.
192                          */
193                         irqchip_remove_pending(cpu_data, pending);
194
195                 pending = pending->next;
196         }
197
198         return 0;
199 }
200
201 void irqchip_handle_irq(struct per_cpu *cpu_data)
202 {
203         irqchip.handle_irq(cpu_data);
204 }
205
206 void irqchip_eoi_irq(u32 irqn, bool deactivate)
207 {
208         irqchip.eoi_irq(irqn, deactivate);
209 }
210
211 int irqchip_send_sgi(struct sgi *sgi)
212 {
213         return irqchip.send_sgi(sgi);
214 }
215
216 int irqchip_cpu_init(struct per_cpu *cpu_data)
217 {
218         int err;
219
220         err = irqchip_init_pending(cpu_data);
221         if (err)
222                 return err;
223
224         if (irqchip.cpu_init)
225                 return irqchip.cpu_init(cpu_data);
226
227         return 0;
228 }
229
230 int irqchip_cpu_reset(struct per_cpu *cpu_data)
231 {
232         int err;
233
234         err = irqchip_init_pending(cpu_data);
235         if (err)
236                 return err;
237
238         if (irqchip.cpu_reset)
239                 return irqchip.cpu_reset(cpu_data, false);
240
241         return 0;
242 }
243
244 void irqchip_cpu_shutdown(struct per_cpu *cpu_data)
245 {
246         /*
247          * The GIC backend must take care of only resetting the hyp interface if
248          * it has been initialised: this function may be executed during the
249          * setup phase.
250          */
251         if (irqchip.cpu_reset)
252                 irqchip.cpu_reset(cpu_data, true);
253 }
254
255 static const struct jailhouse_irqchip *
256 irqchip_find_config(struct jailhouse_cell_desc *config)
257 {
258         const struct jailhouse_irqchip *irq_config =
259                 jailhouse_cell_irqchips(config);
260
261         if (config->num_irqchips)
262                 return irq_config;
263         else
264                 return NULL;
265 }
266
267 int irqchip_cell_init(struct cell *cell)
268 {
269         const struct jailhouse_irqchip *pins = irqchip_find_config(cell->config);
270
271         cell->arch.spis = (pins ? pins->pin_bitmap : 0);
272
273         return irqchip.cell_init(cell);
274 }
275
276 void irqchip_cell_exit(struct cell *cell)
277 {
278         const struct jailhouse_irqchip *root_pins =
279                 irqchip_find_config(root_cell.config);
280
281         /* might be called by arch_shutdown while rolling back
282          * a failed setup */
283         if (!irqchip_is_init)
284                 return;
285
286         if (root_pins)
287                 root_cell.arch.spis |= cell->arch.spis & root_pins->pin_bitmap;
288
289         irqchip.cell_exit(cell);
290 }
291
292 void irqchip_root_cell_shrink(struct cell *cell)
293 {
294         root_cell.arch.spis &= ~(cell->arch.spis);
295 }
296
297 /* Only the GIC is implemented */
298 extern struct irqchip_ops gic_irqchip;
299
300 int irqchip_init(void)
301 {
302         int i, err;
303         u32 pidr2, cidr;
304         u32 dev_id = 0;
305
306         /* Only executed on master CPU */
307         if (irqchip_is_init)
308                 return 0;
309
310         /* FIXME: parse device tree */
311         gicd_base = GICD_BASE;
312         gicd_size = GICD_SIZE;
313
314         if ((err = arch_map_device(gicd_base, gicd_base, gicd_size)) != 0)
315                 return err;
316
317         for (i = 3; i >= 0; i--) {
318                 cidr = mmio_read32(gicd_base + GICD_CIDR0 + i * 4);
319                 dev_id |= cidr << i * 8;
320         }
321         if (dev_id != AMBA_DEVICE)
322                 goto err_no_distributor;
323
324         /* Probe the GIC version */
325         pidr2 = mmio_read32(gicd_base + GICD_PIDR2);
326         switch (GICD_PIDR2_ARCH(pidr2)) {
327         case 0x2:
328         case 0x3:
329         case 0x4:
330                 memcpy(&irqchip, &gic_irqchip, sizeof(struct irqchip_ops));
331                 break;
332         }
333
334         if (irqchip.init) {
335                 err = irqchip.init();
336                 irqchip_is_init = true;
337
338                 return err;
339         }
340
341 err_no_distributor:
342         printk("GIC: no distributor found\n");
343         arch_unmap_device(gicd_base, gicd_size);
344
345         return -ENODEV;
346 }