154976b75SPaolo Bonzini /*
254976b75SPaolo Bonzini * KVM in-kernel PIC (i8259) support
354976b75SPaolo Bonzini *
454976b75SPaolo Bonzini * Copyright (c) 2011 Siemens AG
554976b75SPaolo Bonzini *
654976b75SPaolo Bonzini * Authors:
754976b75SPaolo Bonzini * Jan Kiszka <jan.kiszka@siemens.com>
854976b75SPaolo Bonzini *
954976b75SPaolo Bonzini * This work is licensed under the terms of the GNU GPL version 2.
1054976b75SPaolo Bonzini * See the COPYING file in the top-level directory.
1154976b75SPaolo Bonzini */
120b8fa32fSMarkus Armbruster
13b6a0aa05SPeter Maydell #include "qemu/osdep.h"
1454976b75SPaolo Bonzini #include "hw/isa/i8259_internal.h"
15852c27e2SPaolo Bonzini #include "hw/intc/i8259.h"
160b8fa32fSMarkus Armbruster #include "qemu/module.h"
17*2b85e0cdSThomas Huth #include "hw/intc/kvm_irqcount.h"
1864552b6bSMarkus Armbruster #include "hw/irq.h"
1954976b75SPaolo Bonzini #include "sysemu/kvm.h"
20db1015e9SEduardo Habkost #include "qom/object.h"
2154976b75SPaolo Bonzini
2249fdb0c1SAndreas Färber #define TYPE_KVM_I8259 "kvm-i8259"
23db1015e9SEduardo Habkost typedef struct KVMPICClass KVMPICClass;
248110fa1dSEduardo Habkost DECLARE_CLASS_CHECKERS(KVMPICClass, KVM_PIC,
258110fa1dSEduardo Habkost TYPE_KVM_I8259)
26d2628b7dSAndreas Färber
27d2628b7dSAndreas Färber /**
28d2628b7dSAndreas Färber * KVMPICClass:
29d2628b7dSAndreas Färber * @parent_realize: The parent's realizefn.
30d2628b7dSAndreas Färber */
31db1015e9SEduardo Habkost struct KVMPICClass {
32d2628b7dSAndreas Färber PICCommonClass parent_class;
33d2628b7dSAndreas Färber
34d2628b7dSAndreas Färber DeviceRealize parent_realize;
35db1015e9SEduardo Habkost };
3649fdb0c1SAndreas Färber
kvm_pic_get(PICCommonState * s)3754976b75SPaolo Bonzini static void kvm_pic_get(PICCommonState *s)
3854976b75SPaolo Bonzini {
3954976b75SPaolo Bonzini struct kvm_irqchip chip;
4054976b75SPaolo Bonzini struct kvm_pic_state *kpic;
4154976b75SPaolo Bonzini int ret;
4254976b75SPaolo Bonzini
4354976b75SPaolo Bonzini chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE;
4454976b75SPaolo Bonzini ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip);
4554976b75SPaolo Bonzini if (ret < 0) {
46d84451d3SDmitry Voronetskiy fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(-ret));
4754976b75SPaolo Bonzini abort();
4854976b75SPaolo Bonzini }
4954976b75SPaolo Bonzini
5054976b75SPaolo Bonzini kpic = &chip.chip.pic;
5154976b75SPaolo Bonzini
5254976b75SPaolo Bonzini s->last_irr = kpic->last_irr;
5354976b75SPaolo Bonzini s->irr = kpic->irr;
5454976b75SPaolo Bonzini s->imr = kpic->imr;
5554976b75SPaolo Bonzini s->isr = kpic->isr;
5654976b75SPaolo Bonzini s->priority_add = kpic->priority_add;
5754976b75SPaolo Bonzini s->irq_base = kpic->irq_base;
5854976b75SPaolo Bonzini s->read_reg_select = kpic->read_reg_select;
5954976b75SPaolo Bonzini s->poll = kpic->poll;
6054976b75SPaolo Bonzini s->special_mask = kpic->special_mask;
6154976b75SPaolo Bonzini s->init_state = kpic->init_state;
6254976b75SPaolo Bonzini s->auto_eoi = kpic->auto_eoi;
6354976b75SPaolo Bonzini s->rotate_on_auto_eoi = kpic->rotate_on_auto_eoi;
6454976b75SPaolo Bonzini s->special_fully_nested_mode = kpic->special_fully_nested_mode;
6554976b75SPaolo Bonzini s->init4 = kpic->init4;
6654976b75SPaolo Bonzini s->elcr = kpic->elcr;
6754976b75SPaolo Bonzini s->elcr_mask = kpic->elcr_mask;
6854976b75SPaolo Bonzini }
6954976b75SPaolo Bonzini
kvm_pic_put(PICCommonState * s)7054976b75SPaolo Bonzini static void kvm_pic_put(PICCommonState *s)
7154976b75SPaolo Bonzini {
7254976b75SPaolo Bonzini struct kvm_irqchip chip;
7354976b75SPaolo Bonzini struct kvm_pic_state *kpic;
7454976b75SPaolo Bonzini int ret;
7554976b75SPaolo Bonzini
7654976b75SPaolo Bonzini chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE;
7754976b75SPaolo Bonzini
7854976b75SPaolo Bonzini kpic = &chip.chip.pic;
7954976b75SPaolo Bonzini
8054976b75SPaolo Bonzini kpic->last_irr = s->last_irr;
8154976b75SPaolo Bonzini kpic->irr = s->irr;
8254976b75SPaolo Bonzini kpic->imr = s->imr;
8354976b75SPaolo Bonzini kpic->isr = s->isr;
8454976b75SPaolo Bonzini kpic->priority_add = s->priority_add;
8554976b75SPaolo Bonzini kpic->irq_base = s->irq_base;
8654976b75SPaolo Bonzini kpic->read_reg_select = s->read_reg_select;
8754976b75SPaolo Bonzini kpic->poll = s->poll;
8854976b75SPaolo Bonzini kpic->special_mask = s->special_mask;
8954976b75SPaolo Bonzini kpic->init_state = s->init_state;
9054976b75SPaolo Bonzini kpic->auto_eoi = s->auto_eoi;
9154976b75SPaolo Bonzini kpic->rotate_on_auto_eoi = s->rotate_on_auto_eoi;
9254976b75SPaolo Bonzini kpic->special_fully_nested_mode = s->special_fully_nested_mode;
9354976b75SPaolo Bonzini kpic->init4 = s->init4;
9454976b75SPaolo Bonzini kpic->elcr = s->elcr;
9554976b75SPaolo Bonzini kpic->elcr_mask = s->elcr_mask;
9654976b75SPaolo Bonzini
9754976b75SPaolo Bonzini ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip);
9854976b75SPaolo Bonzini if (ret < 0) {
99d84451d3SDmitry Voronetskiy fprintf(stderr, "KVM_SET_IRQCHIP failed: %s\n", strerror(-ret));
10054976b75SPaolo Bonzini abort();
10154976b75SPaolo Bonzini }
10254976b75SPaolo Bonzini }
10354976b75SPaolo Bonzini
kvm_pic_reset(DeviceState * dev)10454976b75SPaolo Bonzini static void kvm_pic_reset(DeviceState *dev)
10554976b75SPaolo Bonzini {
10629bb5317SAndreas Färber PICCommonState *s = PIC_COMMON(dev);
10754976b75SPaolo Bonzini
10854976b75SPaolo Bonzini s->elcr = 0;
10954976b75SPaolo Bonzini pic_reset_common(s);
11054976b75SPaolo Bonzini
11154976b75SPaolo Bonzini kvm_pic_put(s);
11254976b75SPaolo Bonzini }
11354976b75SPaolo Bonzini
kvm_pic_set_irq(void * opaque,int irq,int level)11454976b75SPaolo Bonzini static void kvm_pic_set_irq(void *opaque, int irq, int level)
11554976b75SPaolo Bonzini {
11654976b75SPaolo Bonzini int delivered;
11754976b75SPaolo Bonzini
118e267d164SPeter Xu pic_stat_update_irq(irq, level);
11954976b75SPaolo Bonzini delivered = kvm_set_irq(kvm_state, irq, level);
120*2b85e0cdSThomas Huth kvm_report_irq_delivered(delivered);
12154976b75SPaolo Bonzini }
12254976b75SPaolo Bonzini
kvm_pic_realize(DeviceState * dev,Error ** errp)123d2628b7dSAndreas Färber static void kvm_pic_realize(DeviceState *dev, Error **errp)
12454976b75SPaolo Bonzini {
125d2628b7dSAndreas Färber PICCommonState *s = PIC_COMMON(dev);
126d2628b7dSAndreas Färber KVMPICClass *kpc = KVM_PIC_GET_CLASS(dev);
127d2628b7dSAndreas Färber
128257a7430SPaolo Bonzini memory_region_init_io(&s->base_io, OBJECT(dev), NULL, NULL, "kvm-pic", 2);
129257a7430SPaolo Bonzini memory_region_init_io(&s->elcr_io, OBJECT(dev), NULL, NULL, "kvm-elcr", 1);
130d2628b7dSAndreas Färber
131d2628b7dSAndreas Färber kpc->parent_realize(dev, errp);
13254976b75SPaolo Bonzini }
13354976b75SPaolo Bonzini
kvm_i8259_init(ISABus * bus)13454976b75SPaolo Bonzini qemu_irq *kvm_i8259_init(ISABus *bus)
13554976b75SPaolo Bonzini {
13649fdb0c1SAndreas Färber i8259_init_chip(TYPE_KVM_I8259, bus, true);
13749fdb0c1SAndreas Färber i8259_init_chip(TYPE_KVM_I8259, bus, false);
13854976b75SPaolo Bonzini
13954976b75SPaolo Bonzini return qemu_allocate_irqs(kvm_pic_set_irq, NULL, ISA_NUM_IRQS);
14054976b75SPaolo Bonzini }
14154976b75SPaolo Bonzini
kvm_i8259_class_init(ObjectClass * klass,void * data)14254976b75SPaolo Bonzini static void kvm_i8259_class_init(ObjectClass *klass, void *data)
14354976b75SPaolo Bonzini {
144d2628b7dSAndreas Färber KVMPICClass *kpc = KVM_PIC_CLASS(klass);
14554976b75SPaolo Bonzini PICCommonClass *k = PIC_COMMON_CLASS(klass);
14654976b75SPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
14754976b75SPaolo Bonzini
14854976b75SPaolo Bonzini dc->reset = kvm_pic_reset;
149bf853881SPhilippe Mathieu-Daudé device_class_set_parent_realize(dc, kvm_pic_realize, &kpc->parent_realize);
15054976b75SPaolo Bonzini k->pre_save = kvm_pic_get;
15154976b75SPaolo Bonzini k->post_load = kvm_pic_put;
15254976b75SPaolo Bonzini }
15354976b75SPaolo Bonzini
15454976b75SPaolo Bonzini static const TypeInfo kvm_i8259_info = {
15549fdb0c1SAndreas Färber .name = TYPE_KVM_I8259,
15654976b75SPaolo Bonzini .parent = TYPE_PIC_COMMON,
15754976b75SPaolo Bonzini .instance_size = sizeof(PICCommonState),
15854976b75SPaolo Bonzini .class_init = kvm_i8259_class_init,
159d2628b7dSAndreas Färber .class_size = sizeof(KVMPICClass),
16054976b75SPaolo Bonzini };
16154976b75SPaolo Bonzini
kvm_pic_register_types(void)16254976b75SPaolo Bonzini static void kvm_pic_register_types(void)
16354976b75SPaolo Bonzini {
16454976b75SPaolo Bonzini type_register_static(&kvm_i8259_info);
16554976b75SPaolo Bonzini }
16654976b75SPaolo Bonzini
16754976b75SPaolo Bonzini type_init(kvm_pic_register_types)
168