2 * Jailhouse, a Linux-based partitioning hypervisor
4 * Copyright (c) ARM Limited, 2014
7 * Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
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>
23 * This implementation assumes that the kernel driver already initialised most
25 * There is almost no instruction barrier, since IRQs are always disabled in the
26 * hyp, and ERET serves as the context synchronization event.
29 static unsigned int gic_num_lr;
31 static void *gicr_base;
32 static unsigned int gicr_size;
34 static int gic_init(void)
38 /* FIXME: parse a dt */
39 gicr_base = GICR_BASE;
40 gicr_size = GICR_SIZE;
42 /* Let the per-cpu code access the redistributors */
43 err = arch_map_device(gicr_base, gicr_base, gicr_size);
48 static int gic_cpu_init(struct per_cpu *cpu_data)
53 u32 cell_icc_ctlr, cell_icc_pmr, cell_icc_igrpen1;
56 void *redist_base = gicr_base;
58 /* Find redistributor */
60 pidr = mmio_read32(redist_base + GICR_PIDR2);
61 gic_version = GICR_PIDR2_ARCH(pidr);
62 if (gic_version != 3 && gic_version != 4)
65 typer = mmio_read64(redist_base + GICR_TYPER);
66 if ((typer >> 32) == cpu_data->cpu_id) {
67 cpu_data->gicr_base = redist_base;
71 redist_base += 0x20000;
73 redist_base += 0x20000;
74 } while (!(typer & GICR_TYPER_Last));
76 if (cpu_data->gicr_base == 0) {
77 printk("GIC: No redist found for CPU%d\n", cpu_data->cpu_id);
81 /* Ensure all IPIs are enabled */
82 mmio_write32(redist_base + GICR_SGI_BASE + GICR_ISENABLER, 0x0000ffff);
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
93 arm_read_sysreg(ICC_CTLR_EL1, cell_icc_ctlr);
94 arm_write_sysreg(ICC_CTLR_EL1, ICC_CTLR_EOImode);
96 arm_read_sysreg(ICC_PMR_EL1, cell_icc_pmr);
97 arm_write_sysreg(ICC_PMR_EL1, ICC_PMR_DEFAULT);
99 arm_read_sysreg(ICC_IGRPEN1_EL1, cell_icc_igrpen1);
100 arm_write_sysreg(ICC_IGRPEN1_EL1, ICC_IGRPEN1_EN);
102 arm_read_sysreg(ICH_VTR_EL2, ich_vtr);
103 gic_num_lr = (ich_vtr & 0xf) + 1;
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);
112 /* After this, the cells access the virtual interface of the GIC. */
113 arm_write_sysreg(ICH_HCR_EL2, ICH_HCR_EN);
118 static int gic_send_sgi(struct sgi *sgi)
121 u16 targets = sgi->targets;
123 if (!is_sgi(sgi->id))
126 if (sgi->routing_mode == 2)
127 targets = 1 << phys_processor_id();
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;
135 if (sgi->routing_mode == 1)
136 val |= ICC_SGIR_ROUTING_BIT;
139 * Ensure the targets see our modifications to their per-cpu
144 arm_write_sysreg(ICC_SGI1R_EL1, val);
150 static void gic_handle_irq(struct per_cpu *cpu_data)
154 struct irqchip_ops gic_irqchip = {
156 .cpu_init = gic_cpu_init,
157 .send_sgi = gic_send_sgi,
158 .handle_irq = gic_handle_irq,