]> rtime.felk.cvut.cz Git - jailhouse.git/blob - hypervisor/arch/arm/gic-v3.c
arm: GICv3 initialisation
[jailhouse.git] / hypervisor / arch / arm / gic-v3.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/mmio.h>
14 #include <jailhouse/printk.h>
15 #include <jailhouse/processor.h>
16 #include <jailhouse/types.h>
17 #include <asm/gic_common.h>
18 #include <asm/irqchip.h>
19 #include <asm/platform.h>
20 #include <asm/setup.h>
21
22 /*
23  * This implementation assumes that the kernel driver already initialised most
24  * of the GIC.
25  * There is almost no instruction barrier, since IRQs are always disabled in the
26  * hyp, and ERET serves as the context synchronization event.
27  */
28
29 static unsigned int gic_num_lr;
30
31 static void *gicr_base;
32 static unsigned int gicr_size;
33
34 static int gic_init(void)
35 {
36         int err;
37
38         /* FIXME: parse a dt */
39         gicr_base = GICR_BASE;
40         gicr_size = GICR_SIZE;
41
42         /* Let the per-cpu code access the redistributors */
43         err = arch_map_device(gicr_base, gicr_base, gicr_size);
44
45         return err;
46 }
47
48 static int gic_cpu_init(struct per_cpu *cpu_data)
49 {
50         u64 typer;
51         u32 pidr;
52         u32 gic_version;
53         u32 cell_icc_ctlr, cell_icc_pmr, cell_icc_igrpen1;
54         u32 ich_vtr;
55         u32 ich_vmcr;
56         void *redist_base = gicr_base;
57
58         /* Find redistributor */
59         do {
60                 pidr = mmio_read32(redist_base + GICR_PIDR2);
61                 gic_version = GICR_PIDR2_ARCH(pidr);
62                 if (gic_version != 3 && gic_version != 4)
63                         break;
64
65                 typer = mmio_read64(redist_base + GICR_TYPER);
66                 if ((typer >> 32) == cpu_data->cpu_id) {
67                         cpu_data->gicr_base = redist_base;
68                         break;
69                 }
70
71                 redist_base += 0x20000;
72                 if (gic_version == 4)
73                         redist_base += 0x20000;
74         } while (!(typer & GICR_TYPER_Last));
75
76         if (cpu_data->gicr_base == 0) {
77                 printk("GIC: No redist found for CPU%d\n", cpu_data->cpu_id);
78                 return -ENODEV;
79         }
80
81         /* Ensure all IPIs are enabled */
82         mmio_write32(redist_base + GICR_SGI_BASE + GICR_ISENABLER, 0x0000ffff);
83
84         /*
85          * Set EOIMode to 1
86          * This allow to drop the priority of level-triggered interrupts without
87          * deactivating them, and thus ensure that they won't be immediately
88          * re-triggered. (e.g. timer)
89          * They can then be injected into the guest using the LR.HW bit, and
90          * will be deactivated once the guest does an EOI after handling the
91          * interrupt source.
92          */
93         arm_read_sysreg(ICC_CTLR_EL1, cell_icc_ctlr);
94         arm_write_sysreg(ICC_CTLR_EL1, ICC_CTLR_EOImode);
95
96         arm_read_sysreg(ICC_PMR_EL1, cell_icc_pmr);
97         arm_write_sysreg(ICC_PMR_EL1, ICC_PMR_DEFAULT);
98
99         arm_read_sysreg(ICC_IGRPEN1_EL1, cell_icc_igrpen1);
100         arm_write_sysreg(ICC_IGRPEN1_EL1, ICC_IGRPEN1_EN);
101
102         arm_read_sysreg(ICH_VTR_EL2, ich_vtr);
103         gic_num_lr = (ich_vtr & 0xf) + 1;
104
105         ich_vmcr = (cell_icc_pmr & ICC_PMR_MASK) << ICH_VMCR_VPMR_SHIFT;
106         if (cell_icc_igrpen1 & ICC_IGRPEN1_EN)
107                 ich_vmcr |= ICH_VMCR_VENG1;
108         if (cell_icc_ctlr & ICC_CTLR_EOImode)
109                 ich_vmcr |= ICH_VMCR_VEOIM;
110         arm_write_sysreg(ICH_VMCR_EL2, ich_vmcr);
111
112         /* After this, the cells access the virtual interface of the GIC. */
113         arm_write_sysreg(ICH_HCR_EL2, ICH_HCR_EN);
114
115         return 0;
116 }
117
118 static int gic_send_sgi(struct sgi *sgi)
119 {
120         u64 val;
121         u16 targets = sgi->targets;
122
123         if (!is_sgi(sgi->id))
124                 return -EINVAL;
125
126         if (sgi->routing_mode == 2)
127                 targets = 1 << phys_processor_id();
128
129         val = (u64)sgi->aff3 << ICC_SGIR_AFF3_SHIFT
130             | (u64)sgi->aff2 << ICC_SGIR_AFF2_SHIFT
131             | sgi->aff1 << ICC_SGIR_AFF1_SHIFT
132             | (targets & ICC_SGIR_TARGET_MASK)
133             | (sgi->id & 0xf) << ICC_SGIR_IRQN_SHIFT;
134
135         if (sgi->routing_mode == 1)
136                 val |= ICC_SGIR_ROUTING_BIT;
137
138         /*
139          * Ensure the targets see our modifications to their per-cpu
140          * structures.
141          */
142         dsb(ish);
143
144         arm_write_sysreg(ICC_SGI1R_EL1, val);
145         isb();
146
147         return 0;
148 }
149
150 static void gic_handle_irq(struct per_cpu *cpu_data)
151 {
152 }
153
154 struct irqchip_ops gic_irqchip = {
155         .init = gic_init,
156         .cpu_init = gic_cpu_init,
157         .send_sgi = gic_send_sgi,
158         .handle_irq = gic_handle_irq,
159 };