]>
Commit | Line | Data |
---|---|---|
a39c1d47 JK |
1 | /* |
2 | * KVM in-kernel IOPIC support | |
3 | * | |
4 | * Copyright (c) 2011 Siemens AG | |
5 | * | |
6 | * Authors: | |
7 | * Jan Kiszka <jan.kiszka@siemens.com> | |
8 | * | |
9 | * This work is licensed under the terms of the GNU GPL version 2. | |
10 | * See the COPYING file in the top-level directory. | |
11 | */ | |
12 | ||
b6a0aa05 | 13 | #include "qemu/osdep.h" |
d665d696 | 14 | #include "monitor/monitor.h" |
89a289c7 | 15 | #include "hw/i386/x86.h" |
a27bd6c7 | 16 | #include "hw/qdev-properties.h" |
0d09e41a PB |
17 | #include "hw/i386/ioapic_internal.h" |
18 | #include "hw/i386/apic_internal.h" | |
9c17d615 | 19 | #include "sysemu/kvm.h" |
a39c1d47 | 20 | |
d8ee0384 JB |
21 | /* PC Utility function */ |
22 | void kvm_pc_setup_irq_routing(bool pci_enabled) | |
23 | { | |
24 | KVMState *s = kvm_state; | |
25 | int i; | |
26 | ||
8981bae2 EH |
27 | assert(kvm_has_gsi_routing()); |
28 | for (i = 0; i < 8; ++i) { | |
29 | if (i == 2) { | |
30 | continue; | |
d8ee0384 | 31 | } |
8981bae2 EH |
32 | kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_MASTER, i); |
33 | } | |
34 | for (i = 8; i < 16; ++i) { | |
35 | kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8); | |
36 | } | |
37 | if (pci_enabled) { | |
38 | for (i = 0; i < 24; ++i) { | |
39 | if (i == 0) { | |
40 | kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, 2); | |
41 | } else if (i != 2) { | |
42 | kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, i); | |
d8ee0384 JB |
43 | } |
44 | } | |
45 | } | |
8981bae2 | 46 | kvm_irqchip_commit_routes(s); |
d8ee0384 | 47 | } |
d8ee0384 | 48 | |
a39c1d47 JK |
49 | typedef struct KVMIOAPICState KVMIOAPICState; |
50 | ||
51 | struct KVMIOAPICState { | |
52 | IOAPICCommonState ioapic; | |
53 | uint32_t kvm_gsi_base; | |
54 | }; | |
55 | ||
56 | static void kvm_ioapic_get(IOAPICCommonState *s) | |
57 | { | |
58 | struct kvm_irqchip chip; | |
59 | struct kvm_ioapic_state *kioapic; | |
60 | int ret, i; | |
61 | ||
62 | chip.chip_id = KVM_IRQCHIP_IOAPIC; | |
63 | ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip); | |
64 | if (ret < 0) { | |
d84451d3 | 65 | fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(-ret)); |
a39c1d47 JK |
66 | abort(); |
67 | } | |
68 | ||
69 | kioapic = &chip.chip.ioapic; | |
70 | ||
71 | s->id = kioapic->id; | |
72 | s->ioregsel = kioapic->ioregsel; | |
73 | s->irr = kioapic->irr; | |
74 | for (i = 0; i < IOAPIC_NUM_PINS; i++) { | |
75 | s->ioredtbl[i] = kioapic->redirtbl[i].bits; | |
76 | } | |
77 | } | |
78 | ||
79 | static void kvm_ioapic_put(IOAPICCommonState *s) | |
80 | { | |
81 | struct kvm_irqchip chip; | |
82 | struct kvm_ioapic_state *kioapic; | |
83 | int ret, i; | |
84 | ||
85 | chip.chip_id = KVM_IRQCHIP_IOAPIC; | |
86 | kioapic = &chip.chip.ioapic; | |
87 | ||
88 | kioapic->id = s->id; | |
89 | kioapic->ioregsel = s->ioregsel; | |
90 | kioapic->base_address = s->busdev.mmio[0].addr; | |
91 | kioapic->irr = s->irr; | |
92 | for (i = 0; i < IOAPIC_NUM_PINS; i++) { | |
93 | kioapic->redirtbl[i].bits = s->ioredtbl[i]; | |
94 | } | |
95 | ||
96 | ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip); | |
97 | if (ret < 0) { | |
d84451d3 | 98 | fprintf(stderr, "KVM_SET_IRQCHIP failed: %s\n", strerror(-ret)); |
a39c1d47 JK |
99 | abort(); |
100 | } | |
101 | } | |
102 | ||
103 | static void kvm_ioapic_reset(DeviceState *dev) | |
104 | { | |
b3119631 | 105 | IOAPICCommonState *s = IOAPIC_COMMON(dev); |
a39c1d47 JK |
106 | |
107 | ioapic_reset_common(dev); | |
108 | kvm_ioapic_put(s); | |
109 | } | |
110 | ||
111 | static void kvm_ioapic_set_irq(void *opaque, int irq, int level) | |
112 | { | |
113 | KVMIOAPICState *s = opaque; | |
cce5405e | 114 | IOAPICCommonState *common = IOAPIC_COMMON(s); |
a39c1d47 JK |
115 | int delivered; |
116 | ||
cce5405e | 117 | ioapic_stat_update_irq(common, irq, level); |
3889c3fa | 118 | delivered = kvm_set_irq(kvm_state, s->kvm_gsi_base + irq, level); |
a39c1d47 JK |
119 | apic_report_irq_delivered(delivered); |
120 | } | |
121 | ||
db0f8888 | 122 | static void kvm_ioapic_realize(DeviceState *dev, Error **errp) |
a39c1d47 | 123 | { |
db0f8888 | 124 | IOAPICCommonState *s = IOAPIC_COMMON(dev); |
f9771858 | 125 | |
257a7430 | 126 | memory_region_init_io(&s->io_memory, OBJECT(dev), NULL, NULL, "kvm-ioapic", 0x1000); |
b7a4104b PX |
127 | /* |
128 | * KVM ioapic only supports 0x11 now. This will only be used when | |
129 | * we want to dump ioapic version. | |
130 | */ | |
131 | s->version = 0x11; | |
a39c1d47 | 132 | |
f9771858 | 133 | qdev_init_gpio_in(dev, kvm_ioapic_set_irq, IOAPIC_NUM_PINS); |
a39c1d47 JK |
134 | } |
135 | ||
39bffca2 AL |
136 | static Property kvm_ioapic_properties[] = { |
137 | DEFINE_PROP_UINT32("gsi_base", KVMIOAPICState, kvm_gsi_base, 0), | |
138 | DEFINE_PROP_END_OF_LIST() | |
139 | }; | |
140 | ||
999e12bb AL |
141 | static void kvm_ioapic_class_init(ObjectClass *klass, void *data) |
142 | { | |
143 | IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass); | |
39bffca2 | 144 | DeviceClass *dc = DEVICE_CLASS(klass); |
999e12bb | 145 | |
db0f8888 | 146 | k->realize = kvm_ioapic_realize; |
999e12bb AL |
147 | k->pre_save = kvm_ioapic_get; |
148 | k->post_load = kvm_ioapic_put; | |
39bffca2 | 149 | dc->reset = kvm_ioapic_reset; |
4f67d30b | 150 | device_class_set_props(dc, kvm_ioapic_properties); |
999e12bb AL |
151 | } |
152 | ||
8c43a6f0 | 153 | static const TypeInfo kvm_ioapic_info = { |
34bec7a8 | 154 | .name = TYPE_KVM_IOAPIC, |
39bffca2 AL |
155 | .parent = TYPE_IOAPIC_COMMON, |
156 | .instance_size = sizeof(KVMIOAPICState), | |
999e12bb | 157 | .class_init = kvm_ioapic_class_init, |
a39c1d47 JK |
158 | }; |
159 | ||
83f7d43a | 160 | static void kvm_ioapic_register_types(void) |
a39c1d47 | 161 | { |
39bffca2 | 162 | type_register_static(&kvm_ioapic_info); |
a39c1d47 JK |
163 | } |
164 | ||
83f7d43a | 165 | type_init(kvm_ioapic_register_types) |