]> rtime.felk.cvut.cz Git - jailhouse.git/blob - hypervisor/arch/arm/irqchip.c
jailhouse: inmates: bench: Add -R option -- repeats count.
[jailhouse.git] / hypervisor / arch / arm / irqchip.c
1 /*
2  * Jailhouse, a Linux-based partitioning hypervisor
3  *
4  * Copyright (c) ARM Limited, 2014
5  * Copyright (c) Siemens AG, 2016
6  *
7  * Authors:
8  *  Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
9  *  Jan Kiszka <jan.kiszka@siemens.com>
10  *
11  * This work is licensed under the terms of the GNU GPL, version 2.  See
12  * the COPYING file in the top-level directory.
13  */
14
15 #include <jailhouse/entry.h>
16 #include <jailhouse/mmio.h>
17 #include <jailhouse/paging.h>
18 #include <jailhouse/printk.h>
19 #include <jailhouse/string.h>
20 #include <asm/control.h>
21 #include <asm/gic_common.h>
22 #include <asm/irqchip.h>
23 #include <asm/platform.h>
24 #include <asm/setup.h>
25 #include <asm/sysregs.h>
26
27 /* AMBA's biosfood */
28 #define AMBA_DEVICE     0xb105f00d
29
30 #define for_each_irqchip(chip, config, counter)                         \
31         for ((chip) = jailhouse_cell_irqchips(config), (counter) = 0;   \
32              (counter) < (config)->num_irqchips;                        \
33              (chip)++, (counter)++)
34
35 extern struct irqchip_ops irqchip;
36
37 void *gicd_base;
38 unsigned long gicd_size;
39
40 /*
41  * The init function must be called after the MMU setup, and whilst in the
42  * per-cpu setup, which means that a bool must be set by the master CPU
43  */
44 static bool irqchip_is_init;
45
46 bool irqchip_irq_in_cell(struct cell *cell, unsigned int irq_id)
47 {
48         if (irq_id >= sizeof(cell->arch.irq_bitmap) * 8)
49                 return false;
50
51         return (cell->arch.irq_bitmap[irq_id / 32] & (1 << (irq_id % 32))) != 0;
52 }
53
54 void irqchip_set_pending(struct per_cpu *cpu_data, u16 irq_id)
55 {
56         bool local_injection = (this_cpu_data() == cpu_data);
57         unsigned int new_tail;
58
59         if (local_injection && irqchip.inject_irq(cpu_data, irq_id) != -EBUSY)
60                 return;
61
62         spin_lock(&cpu_data->pending_irqs_lock);
63
64         new_tail = (cpu_data->pending_irqs_tail + 1) % MAX_PENDING_IRQS;
65
66         /* Queue space available? */
67         if (new_tail != cpu_data->pending_irqs_head) {
68                 cpu_data->pending_irqs[cpu_data->pending_irqs_tail] = irq_id;
69                 cpu_data->pending_irqs_tail = new_tail;
70                 /*
71                  * Make the change to pending_irqs_tail visible before the
72                  * caller sends SGI_INJECT.
73                  */
74                 memory_barrier();
75         }
76
77         spin_unlock(&cpu_data->pending_irqs_lock);
78
79         /*
80          * The list registers are full, trigger maintenance interrupt if we are
81          * on the target CPU. In the other case, the caller will send a
82          * SGI_INJECT, and irqchip_inject_pending will take care.
83          */
84         if (local_injection)
85                 irqchip.enable_maint_irq(true);
86 }
87
88 void irqchip_inject_pending(struct per_cpu *cpu_data)
89 {
90         u16 irq_id;
91
92         while (cpu_data->pending_irqs_head != cpu_data->pending_irqs_tail) {
93                 irq_id = cpu_data->pending_irqs[cpu_data->pending_irqs_head];
94
95                 if (irqchip.inject_irq(cpu_data, irq_id) == -EBUSY) {
96                         /*
97                          * The list registers are full, trigger maintenance
98                          * interrupt and leave.
99                          */
100                         irqchip.enable_maint_irq(true);
101                         return;
102                 }
103
104                 cpu_data->pending_irqs_head =
105                         (cpu_data->pending_irqs_head + 1) % MAX_PENDING_IRQS;
106         }
107
108         /*
109          * The software interrupt queue is empty - turn off the maintenance
110          * interrupt.
111          */
112         irqchip.enable_maint_irq(false);
113 }
114
115 void irqchip_handle_irq(struct per_cpu *cpu_data)
116 {
117         irqchip.handle_irq(cpu_data);
118 }
119
120 void irqchip_eoi_irq(u32 irqn, bool deactivate)
121 {
122         irqchip.eoi_irq(irqn, deactivate);
123 }
124
125 int irqchip_send_sgi(struct sgi *sgi)
126 {
127         return irqchip.send_sgi(sgi);
128 }
129
130 int irqchip_cpu_init(struct per_cpu *cpu_data)
131 {
132         return irqchip.cpu_init(cpu_data);
133 }
134
135 int irqchip_cpu_reset(struct per_cpu *cpu_data)
136 {
137         cpu_data->pending_irqs_head = cpu_data->pending_irqs_tail = 0;
138
139         return irqchip.cpu_reset(cpu_data, false);
140 }
141
142 void irqchip_cpu_shutdown(struct per_cpu *cpu_data)
143 {
144         /*
145          * The GIC backend must take care of only resetting the hyp interface if
146          * it has been initialised: this function may be executed during the
147          * setup phase.
148          */
149         irqchip.cpu_reset(cpu_data, true);
150 }
151
152 int irqchip_cell_init(struct cell *cell)
153 {
154         const struct jailhouse_irqchip *chip;
155         unsigned int n, pos;
156         int err;
157
158         for_each_irqchip(chip, cell->config, n) {
159                 if (chip->address != (unsigned long)gicd_base)
160                         continue;
161                 if (chip->pin_base % 32 != 0 ||
162                     chip->pin_base + sizeof(chip->pin_bitmap) * 8 >
163                     sizeof(cell->arch.irq_bitmap) * 8)
164                         return trace_error(-EINVAL);
165                 memcpy(&cell->arch.irq_bitmap[chip->pin_base / 32],
166                        chip->pin_bitmap, sizeof(chip->pin_bitmap));
167         }
168         /*
169          * Permit direct access to all SGIs and PPIs except for those used by
170          * the hypervisor.
171          */
172         cell->arch.irq_bitmap[0] = ~((1 << SGI_INJECT) | (1 << SGI_CPU_OFF) |
173                                      (1 << MAINTENANCE_IRQ));
174
175         err = irqchip.cell_init(cell);
176         if (err)
177                 return err;
178
179         if (cell != &root_cell) {
180                 for_each_irqchip(chip, cell->config, n) {
181                         if (chip->address != (unsigned long)gicd_base)
182                                 continue;
183                         for (pos = 0; pos < ARRAY_SIZE(chip->pin_bitmap); pos++)
184                                 root_cell.arch.irq_bitmap[chip->pin_base/32] &=
185                                         ~chip->pin_bitmap[pos];
186                 }
187
188                 for (n = 32; n < sizeof(cell->arch.irq_bitmap) * 8; n++) {
189                         if (irqchip_irq_in_cell(cell, n))
190                                 irqchip.adjust_irq_target(cell, n);
191                         if (irqchip_irq_in_cell(&root_cell, n))
192                                 irqchip.adjust_irq_target(&root_cell, n);
193                 }
194         }
195
196         return 0;
197 }
198
199 void irqchip_cell_exit(struct cell *cell)
200 {
201         const struct jailhouse_irqchip *chip;
202         unsigned int n, pos;
203
204         /* might be called by arch_shutdown while rolling back
205          * a failed setup */
206         if (!irqchip_is_init)
207                 return;
208
209         /* set all pins of the old cell in the root cell */
210         for_each_irqchip(chip, cell->config, n) {
211                 if (chip->address != (unsigned long)gicd_base)
212                         continue;
213                 for (pos = 0; pos < ARRAY_SIZE(chip->pin_bitmap); pos++)
214                         root_cell.arch.irq_bitmap[chip->pin_base / 32] |=
215                                 chip->pin_bitmap[pos];
216         }
217
218         /* mask out pins again that actually didn't belong to the root cell */
219         for_each_irqchip(chip, root_cell.config, n) {
220                 if (chip->address != (unsigned long)gicd_base)
221                         continue;
222                 for (pos = 0; pos < ARRAY_SIZE(chip->pin_bitmap); pos++)
223                         root_cell.arch.irq_bitmap[chip->pin_base / 32] &=
224                                 chip->pin_bitmap[pos];
225         }
226
227         if (irqchip.cell_exit)
228                 irqchip.cell_exit(cell);
229 }
230
231 int irqchip_init(void)
232 {
233         int i, err;
234         u32 pidr2, cidr;
235         u32 dev_id = 0;
236
237         /* Only executed on master CPU */
238         if (irqchip_is_init)
239                 return 0;
240
241         /* FIXME: parse device tree */
242         gicd_base = GICD_BASE;
243         gicd_size = GICD_SIZE;
244
245         if ((err = arch_map_device(gicd_base, gicd_base, gicd_size)) != 0)
246                 return err;
247
248         for (i = 3; i >= 0; i--) {
249                 cidr = mmio_read32(gicd_base + GICD_CIDR0 + i * 4);
250                 dev_id |= cidr << i * 8;
251         }
252         if (dev_id != AMBA_DEVICE)
253                 goto err_no_distributor;
254
255         /* Probe the GIC version */
256         pidr2 = mmio_read32(gicd_base + GICD_PIDR2);
257         switch (GICD_PIDR2_ARCH(pidr2)) {
258         case 0x2:
259         case 0x3:
260         case 0x4:
261                 break;
262         default:
263                 goto err_no_distributor;
264         }
265
266         if (irqchip.init) {
267                 err = irqchip.init();
268                 irqchip_is_init = true;
269
270                 return err;
271         }
272
273 err_no_distributor:
274         printk("GIC: no supported distributor found\n");
275         arch_unmap_device(gicd_base, gicd_size);
276
277         return -ENODEV;
278 }