Statistics
| Branch: | Revision:

root / hw / intc / arm_gic_kvm.c @ 2c9b15ca

History | View | Annotate | Download (5.4 kB)

1 ed466761 Peter Maydell
/*
2 ed466761 Peter Maydell
 * ARM Generic Interrupt Controller using KVM in-kernel support
3 ed466761 Peter Maydell
 *
4 ed466761 Peter Maydell
 * Copyright (c) 2012 Linaro Limited
5 ed466761 Peter Maydell
 * Written by Peter Maydell
6 ed466761 Peter Maydell
 *
7 ed466761 Peter Maydell
 * This program is free software; you can redistribute it and/or modify
8 ed466761 Peter Maydell
 * it under the terms of the GNU General Public License as published by
9 ed466761 Peter Maydell
 * the Free Software Foundation, either version 2 of the License, or
10 ed466761 Peter Maydell
 * (at your option) any later version.
11 ed466761 Peter Maydell
 *
12 ed466761 Peter Maydell
 * This program is distributed in the hope that it will be useful,
13 ed466761 Peter Maydell
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ed466761 Peter Maydell
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ed466761 Peter Maydell
 * GNU General Public License for more details.
16 ed466761 Peter Maydell
 *
17 ed466761 Peter Maydell
 * You should have received a copy of the GNU General Public License along
18 ed466761 Peter Maydell
 * with this program; if not, see <http://www.gnu.org/licenses/>.
19 ed466761 Peter Maydell
 */
20 ed466761 Peter Maydell
21 ed466761 Peter Maydell
#include "hw/sysbus.h"
22 ed466761 Peter Maydell
#include "sysemu/kvm.h"
23 ed466761 Peter Maydell
#include "kvm_arm.h"
24 47b43a1f Paolo Bonzini
#include "gic_internal.h"
25 ed466761 Peter Maydell
26 ed466761 Peter Maydell
#define TYPE_KVM_ARM_GIC "kvm-arm-gic"
27 ed466761 Peter Maydell
#define KVM_ARM_GIC(obj) \
28 ed466761 Peter Maydell
     OBJECT_CHECK(GICState, (obj), TYPE_KVM_ARM_GIC)
29 ed466761 Peter Maydell
#define KVM_ARM_GIC_CLASS(klass) \
30 ed466761 Peter Maydell
     OBJECT_CLASS_CHECK(KVMARMGICClass, (klass), TYPE_KVM_ARM_GIC)
31 ed466761 Peter Maydell
#define KVM_ARM_GIC_GET_CLASS(obj) \
32 ed466761 Peter Maydell
     OBJECT_GET_CLASS(KVMARMGICClass, (obj), TYPE_KVM_ARM_GIC)
33 ed466761 Peter Maydell
34 ed466761 Peter Maydell
typedef struct KVMARMGICClass {
35 ed466761 Peter Maydell
    ARMGICCommonClass parent_class;
36 ed466761 Peter Maydell
    DeviceRealize parent_realize;
37 ed466761 Peter Maydell
    void (*parent_reset)(DeviceState *dev);
38 ed466761 Peter Maydell
} KVMARMGICClass;
39 ed466761 Peter Maydell
40 ed466761 Peter Maydell
static void kvm_arm_gic_set_irq(void *opaque, int irq, int level)
41 ed466761 Peter Maydell
{
42 ed466761 Peter Maydell
    /* Meaning of the 'irq' parameter:
43 ed466761 Peter Maydell
     *  [0..N-1] : external interrupts
44 ed466761 Peter Maydell
     *  [N..N+31] : PPI (internal) interrupts for CPU 0
45 ed466761 Peter Maydell
     *  [N+32..N+63] : PPI (internal interrupts for CPU 1
46 ed466761 Peter Maydell
     *  ...
47 ed466761 Peter Maydell
     * Convert this to the kernel's desired encoding, which
48 ed466761 Peter Maydell
     * has separate fields in the irq number for type,
49 ed466761 Peter Maydell
     * CPU number and interrupt number.
50 ed466761 Peter Maydell
     */
51 ed466761 Peter Maydell
    GICState *s = (GICState *)opaque;
52 ed466761 Peter Maydell
    int kvm_irq, irqtype, cpu;
53 ed466761 Peter Maydell
54 ed466761 Peter Maydell
    if (irq < (s->num_irq - GIC_INTERNAL)) {
55 ed466761 Peter Maydell
        /* External interrupt. The kernel numbers these like the GIC
56 ed466761 Peter Maydell
         * hardware, with external interrupt IDs starting after the
57 ed466761 Peter Maydell
         * internal ones.
58 ed466761 Peter Maydell
         */
59 ed466761 Peter Maydell
        irqtype = KVM_ARM_IRQ_TYPE_SPI;
60 ed466761 Peter Maydell
        cpu = 0;
61 ed466761 Peter Maydell
        irq += GIC_INTERNAL;
62 ed466761 Peter Maydell
    } else {
63 ed466761 Peter Maydell
        /* Internal interrupt: decode into (cpu, interrupt id) */
64 ed466761 Peter Maydell
        irqtype = KVM_ARM_IRQ_TYPE_PPI;
65 ed466761 Peter Maydell
        irq -= (s->num_irq - GIC_INTERNAL);
66 ed466761 Peter Maydell
        cpu = irq / GIC_INTERNAL;
67 ed466761 Peter Maydell
        irq %= GIC_INTERNAL;
68 ed466761 Peter Maydell
    }
69 ed466761 Peter Maydell
    kvm_irq = (irqtype << KVM_ARM_IRQ_TYPE_SHIFT)
70 ed466761 Peter Maydell
        | (cpu << KVM_ARM_IRQ_VCPU_SHIFT) | irq;
71 ed466761 Peter Maydell
72 ed466761 Peter Maydell
    kvm_set_irq(kvm_state, kvm_irq, !!level);
73 ed466761 Peter Maydell
}
74 ed466761 Peter Maydell
75 ed466761 Peter Maydell
static void kvm_arm_gic_put(GICState *s)
76 ed466761 Peter Maydell
{
77 ed466761 Peter Maydell
    /* TODO: there isn't currently a kernel interface to set the GIC state */
78 ed466761 Peter Maydell
}
79 ed466761 Peter Maydell
80 ed466761 Peter Maydell
static void kvm_arm_gic_get(GICState *s)
81 ed466761 Peter Maydell
{
82 ed466761 Peter Maydell
    /* TODO: there isn't currently a kernel interface to get the GIC state */
83 ed466761 Peter Maydell
}
84 ed466761 Peter Maydell
85 ed466761 Peter Maydell
static void kvm_arm_gic_reset(DeviceState *dev)
86 ed466761 Peter Maydell
{
87 ed466761 Peter Maydell
    GICState *s = ARM_GIC_COMMON(dev);
88 ed466761 Peter Maydell
    KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
89 ed466761 Peter Maydell
90 ed466761 Peter Maydell
    kgc->parent_reset(dev);
91 ed466761 Peter Maydell
    kvm_arm_gic_put(s);
92 ed466761 Peter Maydell
}
93 ed466761 Peter Maydell
94 ed466761 Peter Maydell
static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
95 ed466761 Peter Maydell
{
96 ed466761 Peter Maydell
    int i;
97 ed466761 Peter Maydell
    GICState *s = KVM_ARM_GIC(dev);
98 ed466761 Peter Maydell
    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
99 ed466761 Peter Maydell
    KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
100 ed466761 Peter Maydell
101 ed466761 Peter Maydell
    kgc->parent_realize(dev, errp);
102 ed466761 Peter Maydell
    if (error_is_set(errp)) {
103 ed466761 Peter Maydell
        return;
104 ed466761 Peter Maydell
    }
105 ed466761 Peter Maydell
106 ed466761 Peter Maydell
    i = s->num_irq - GIC_INTERNAL;
107 ed466761 Peter Maydell
    /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
108 ed466761 Peter Maydell
     * GPIO array layout is thus:
109 ed466761 Peter Maydell
     *  [0..N-1] SPIs
110 ed466761 Peter Maydell
     *  [N..N+31] PPIs for CPU 0
111 ed466761 Peter Maydell
     *  [N+32..N+63] PPIs for CPU 1
112 ed466761 Peter Maydell
     *   ...
113 ed466761 Peter Maydell
     */
114 ed466761 Peter Maydell
    i += (GIC_INTERNAL * s->num_cpu);
115 ed466761 Peter Maydell
    qdev_init_gpio_in(dev, kvm_arm_gic_set_irq, i);
116 ed466761 Peter Maydell
    /* We never use our outbound IRQ lines but provide them so that
117 ed466761 Peter Maydell
     * we maintain the same interface as the non-KVM GIC.
118 ed466761 Peter Maydell
     */
119 ed466761 Peter Maydell
    for (i = 0; i < s->num_cpu; i++) {
120 ed466761 Peter Maydell
        sysbus_init_irq(sbd, &s->parent_irq[i]);
121 ed466761 Peter Maydell
    }
122 ed466761 Peter Maydell
    /* Distributor */
123 2c9b15ca Paolo Bonzini
    memory_region_init_reservation(&s->iomem, NULL, "kvm-gic_dist", 0x1000);
124 ed466761 Peter Maydell
    sysbus_init_mmio(sbd, &s->iomem);
125 ed466761 Peter Maydell
    kvm_arm_register_device(&s->iomem,
126 ed466761 Peter Maydell
                            (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
127 ed466761 Peter Maydell
                            | KVM_VGIC_V2_ADDR_TYPE_DIST);
128 ed466761 Peter Maydell
    /* CPU interface for current core. Unlike arm_gic, we don't
129 ed466761 Peter Maydell
     * provide the "interface for core #N" memory regions, because
130 ed466761 Peter Maydell
     * cores with a VGIC don't have those.
131 ed466761 Peter Maydell
     */
132 2c9b15ca Paolo Bonzini
    memory_region_init_reservation(&s->cpuiomem[0], NULL, "kvm-gic_cpu", 0x1000);
133 ed466761 Peter Maydell
    sysbus_init_mmio(sbd, &s->cpuiomem[0]);
134 ed466761 Peter Maydell
    kvm_arm_register_device(&s->cpuiomem[0],
135 ed466761 Peter Maydell
                            (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
136 ed466761 Peter Maydell
                            | KVM_VGIC_V2_ADDR_TYPE_CPU);
137 ed466761 Peter Maydell
}
138 ed466761 Peter Maydell
139 ed466761 Peter Maydell
static void kvm_arm_gic_class_init(ObjectClass *klass, void *data)
140 ed466761 Peter Maydell
{
141 ed466761 Peter Maydell
    DeviceClass *dc = DEVICE_CLASS(klass);
142 ed466761 Peter Maydell
    ARMGICCommonClass *agcc = ARM_GIC_COMMON_CLASS(klass);
143 ed466761 Peter Maydell
    KVMARMGICClass *kgc = KVM_ARM_GIC_CLASS(klass);
144 ed466761 Peter Maydell
145 ed466761 Peter Maydell
    agcc->pre_save = kvm_arm_gic_get;
146 ed466761 Peter Maydell
    agcc->post_load = kvm_arm_gic_put;
147 ed466761 Peter Maydell
    kgc->parent_realize = dc->realize;
148 ed466761 Peter Maydell
    kgc->parent_reset = dc->reset;
149 ed466761 Peter Maydell
    dc->realize = kvm_arm_gic_realize;
150 ed466761 Peter Maydell
    dc->reset = kvm_arm_gic_reset;
151 ed466761 Peter Maydell
    dc->no_user = 1;
152 ed466761 Peter Maydell
}
153 ed466761 Peter Maydell
154 ed466761 Peter Maydell
static const TypeInfo kvm_arm_gic_info = {
155 ed466761 Peter Maydell
    .name = TYPE_KVM_ARM_GIC,
156 ed466761 Peter Maydell
    .parent = TYPE_ARM_GIC_COMMON,
157 ed466761 Peter Maydell
    .instance_size = sizeof(GICState),
158 ed466761 Peter Maydell
    .class_init = kvm_arm_gic_class_init,
159 ed466761 Peter Maydell
    .class_size = sizeof(KVMARMGICClass),
160 ed466761 Peter Maydell
};
161 ed466761 Peter Maydell
162 ed466761 Peter Maydell
static void kvm_arm_gic_register_types(void)
163 ed466761 Peter Maydell
{
164 ed466761 Peter Maydell
    type_register_static(&kvm_arm_gic_info);
165 ed466761 Peter Maydell
}
166 ed466761 Peter Maydell
167 ed466761 Peter Maydell
type_init(kvm_arm_gic_register_types)