mirror of https://gitee.com/openkylin/qemu.git
i8259: Convert to qdev
This key cleanup step requires to move the IRQ debugging bit from i8259_set_irq directly to the per-PIC pic_set_irq, to pass the PIC parameters (I/O base, ELCR address and mask, master/slave mode) as qdev properties, and to interconnect the PICs with their environment via GPIO pins. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
This commit is contained in:
parent
6835678c25
commit
747c70af78
157
hw/i8259.c
157
hw/i8259.c
|
@ -41,6 +41,7 @@
|
|||
//#define DEBUG_IRQ_COUNT
|
||||
|
||||
struct PicState {
|
||||
ISADevice dev;
|
||||
uint8_t last_irr; /* edge detection */
|
||||
uint8_t irr; /* interrupt request register */
|
||||
uint8_t imr; /* interrupt mask register */
|
||||
|
@ -58,8 +59,10 @@ struct PicState {
|
|||
uint8_t single_mode; /* true if slave pic is not initialized */
|
||||
uint8_t elcr; /* PIIX edge/trigger selection*/
|
||||
uint8_t elcr_mask;
|
||||
qemu_irq int_out;
|
||||
bool master; /* reflects /SP input pin */
|
||||
qemu_irq int_out[1];
|
||||
uint32_t master; /* reflects /SP input pin */
|
||||
uint32_t iobase;
|
||||
uint32_t elcr_addr;
|
||||
MemoryRegion base_io;
|
||||
MemoryRegion elcr_io;
|
||||
};
|
||||
|
@ -70,6 +73,9 @@ static int irq_level[16];
|
|||
#ifdef DEBUG_IRQ_COUNT
|
||||
static uint64_t irq_count[16];
|
||||
#endif
|
||||
#ifdef DEBUG_IRQ_LATENCY
|
||||
static int64_t irq_time[16];
|
||||
#endif
|
||||
PicState *isa_pic;
|
||||
static PicState *slave_pic;
|
||||
|
||||
|
@ -122,17 +128,39 @@ static void pic_update_irq(PicState *s)
|
|||
if (irq >= 0) {
|
||||
DPRINTF("pic%d: imr=%x irr=%x padd=%d\n",
|
||||
s->master ? 0 : 1, s->imr, s->irr, s->priority_add);
|
||||
qemu_irq_raise(s->int_out);
|
||||
qemu_irq_raise(s->int_out[0]);
|
||||
} else {
|
||||
qemu_irq_lower(s->int_out);
|
||||
qemu_irq_lower(s->int_out[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/* set irq level. If an edge is detected, then the IRR is set to 1 */
|
||||
static void pic_set_irq1(PicState *s, int irq, int level)
|
||||
static void pic_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
int mask;
|
||||
mask = 1 << irq;
|
||||
PicState *s = opaque;
|
||||
int mask = 1 << irq;
|
||||
|
||||
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \
|
||||
defined(DEBUG_IRQ_LATENCY)
|
||||
int irq_index = s->master ? irq : irq + 8;
|
||||
#endif
|
||||
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
|
||||
if (level != irq_level[irq_index]) {
|
||||
DPRINTF("pic_set_irq: irq=%d level=%d\n", irq_index, level);
|
||||
irq_level[irq_index] = level;
|
||||
#ifdef DEBUG_IRQ_COUNT
|
||||
if (level == 1) {
|
||||
irq_count[irq_index]++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#ifdef DEBUG_IRQ_LATENCY
|
||||
if (level) {
|
||||
irq_time[irq_index] = qemu_get_clock_ns(vm_clock);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (s->elcr & mask) {
|
||||
/* level triggered */
|
||||
if (level) {
|
||||
|
@ -156,32 +184,6 @@ static void pic_set_irq1(PicState *s, int irq, int level)
|
|||
pic_update_irq(s);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_IRQ_LATENCY
|
||||
int64_t irq_time[16];
|
||||
#endif
|
||||
|
||||
static void i8259_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
PicState *s = irq <= 7 ? isa_pic : slave_pic;
|
||||
|
||||
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
|
||||
if (level != irq_level[irq]) {
|
||||
DPRINTF("i8259_set_irq: irq=%d level=%d\n", irq, level);
|
||||
irq_level[irq] = level;
|
||||
#ifdef DEBUG_IRQ_COUNT
|
||||
if (level == 1)
|
||||
irq_count[irq]++;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#ifdef DEBUG_IRQ_LATENCY
|
||||
if (level) {
|
||||
irq_time[irq] = qemu_get_clock_ns(vm_clock);
|
||||
}
|
||||
#endif
|
||||
pic_set_irq1(s, irq & 7, level);
|
||||
}
|
||||
|
||||
/* acknowledge interrupt 'irq' */
|
||||
static void pic_intack(PicState *s, int irq)
|
||||
{
|
||||
|
@ -258,9 +260,9 @@ static void pic_init_reset(PicState *s)
|
|||
pic_update_irq(s);
|
||||
}
|
||||
|
||||
static void pic_reset(void *opaque)
|
||||
static void pic_reset(DeviceState *dev)
|
||||
{
|
||||
PicState *s = opaque;
|
||||
PicState *s = container_of(dev, PicState, dev.qdev);
|
||||
|
||||
pic_init_reset(s);
|
||||
s->elcr = 0;
|
||||
|
@ -447,23 +449,24 @@ static const MemoryRegionOps pic_elcr_ioport_ops = {
|
|||
},
|
||||
};
|
||||
|
||||
/* XXX: add generic master/slave system */
|
||||
static void pic_init(int io_addr, int elcr_addr, PicState *s, qemu_irq int_out,
|
||||
bool master)
|
||||
static int pic_initfn(ISADevice *dev)
|
||||
{
|
||||
s->int_out = int_out;
|
||||
s->master = master;
|
||||
PicState *s = DO_UPCAST(PicState, dev, dev);
|
||||
|
||||
memory_region_init_io(&s->base_io, &pic_base_ioport_ops, s, "pic", 2);
|
||||
memory_region_init_io(&s->elcr_io, &pic_elcr_ioport_ops, s, "elcr", 1);
|
||||
|
||||
isa_register_ioport(NULL, &s->base_io, io_addr);
|
||||
if (elcr_addr >= 0) {
|
||||
isa_register_ioport(NULL, &s->elcr_io, elcr_addr);
|
||||
isa_register_ioport(NULL, &s->base_io, s->iobase);
|
||||
if (s->elcr_addr != -1) {
|
||||
isa_register_ioport(NULL, &s->elcr_io, s->elcr_addr);
|
||||
}
|
||||
|
||||
vmstate_register(NULL, io_addr, &vmstate_pic, s);
|
||||
qemu_register_reset(pic_reset, s);
|
||||
qdev_init_gpio_out(&dev->qdev, s->int_out, ARRAY_SIZE(s->int_out));
|
||||
qdev_init_gpio_in(&dev->qdev, pic_set_irq, 8);
|
||||
|
||||
qdev_set_legacy_instance_id(&dev->qdev, s->iobase, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pic_info(Monitor *mon)
|
||||
|
@ -503,20 +506,60 @@ void irq_info(Monitor *mon)
|
|||
|
||||
qemu_irq *i8259_init(qemu_irq parent_irq)
|
||||
{
|
||||
qemu_irq *irqs;
|
||||
PicState *s;
|
||||
qemu_irq *irq_set;
|
||||
ISADevice *dev;
|
||||
int i;
|
||||
|
||||
irqs = qemu_allocate_irqs(i8259_set_irq, NULL, 16);
|
||||
irq_set = g_malloc(ISA_NUM_IRQS * sizeof(qemu_irq));
|
||||
|
||||
s = g_malloc0(sizeof(PicState));
|
||||
pic_init(0x20, 0x4d0, s, parent_irq, true);
|
||||
s->elcr_mask = 0xf8;
|
||||
isa_pic = s;
|
||||
dev = isa_create("isa-i8259");
|
||||
qdev_prop_set_uint32(&dev->qdev, "iobase", 0x20);
|
||||
qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d0);
|
||||
qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xf8);
|
||||
qdev_prop_set_bit(&dev->qdev, "master", true);
|
||||
qdev_init_nofail(&dev->qdev);
|
||||
|
||||
s = g_malloc0(sizeof(PicState));
|
||||
pic_init(0xa0, 0x4d1, s, irqs[2], false);
|
||||
s->elcr_mask = 0xde;
|
||||
slave_pic = s;
|
||||
qdev_connect_gpio_out(&dev->qdev, 0, parent_irq);
|
||||
for (i = 0 ; i < 8; i++) {
|
||||
irq_set[i] = qdev_get_gpio_in(&dev->qdev, i);
|
||||
}
|
||||
|
||||
return irqs;
|
||||
isa_pic = DO_UPCAST(PicState, dev, dev);
|
||||
|
||||
dev = isa_create("isa-i8259");
|
||||
qdev_prop_set_uint32(&dev->qdev, "iobase", 0xa0);
|
||||
qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d1);
|
||||
qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xde);
|
||||
qdev_init_nofail(&dev->qdev);
|
||||
|
||||
qdev_connect_gpio_out(&dev->qdev, 0, irq_set[2]);
|
||||
for (i = 0 ; i < 8; i++) {
|
||||
irq_set[i + 8] = qdev_get_gpio_in(&dev->qdev, i);
|
||||
}
|
||||
|
||||
slave_pic = DO_UPCAST(PicState, dev, dev);
|
||||
|
||||
return irq_set;
|
||||
}
|
||||
|
||||
static ISADeviceInfo i8259_info = {
|
||||
.qdev.name = "isa-i8259",
|
||||
.qdev.size = sizeof(PicState),
|
||||
.qdev.vmsd = &vmstate_pic,
|
||||
.qdev.reset = pic_reset,
|
||||
.qdev.no_user = 1,
|
||||
.init = pic_initfn,
|
||||
.qdev.props = (Property[]) {
|
||||
DEFINE_PROP_HEX32("iobase", PicState, iobase, -1),
|
||||
DEFINE_PROP_HEX32("elcr_addr", PicState, elcr_addr, -1),
|
||||
DEFINE_PROP_HEX8("elcr_mask", PicState, elcr_mask, -1),
|
||||
DEFINE_PROP_BIT("master", PicState, master, 0, false),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
},
|
||||
};
|
||||
|
||||
static void pic_register(void)
|
||||
{
|
||||
isa_qdev_register(&i8259_info);
|
||||
}
|
||||
device_init(pic_register)
|
||||
|
|
Loading…
Reference in New Issue