[PATCH v2 3/6] hw/char: pl011 don't keep setting the IRQ if nothing changed
Peter Maydell
peter.maydell at linaro.org
Thu Mar 12 08:51:50 PDT 2015
On 4 March 2015 at 14:35, Alex Bennée <alex.bennee at linaro.org> wrote:
> While observing KVM traces I can see additional IRQ calls on pretty much
> every MMIO access which is just plain inefficient. Only update the QEMU
> IRQ level if something has actually changed from last time. Otherwise we
> may be papering over other failure modes.
>
> Signed-off-by: Alex Bennée <alex.bennee at linaro.org>
>
> diff --git a/hw/char/pl011.c b/hw/char/pl011.c
> index 0a45115..bb554bc 100644
> --- a/hw/char/pl011.c
> +++ b/hw/char/pl011.c
> @@ -36,6 +36,9 @@ typedef struct PL011State {
> CharDriverState *chr;
> qemu_irq irq;
> const unsigned char *id;
> +
> + /* not serialised, prevents pl011_update doing extra set_irqs */
> + uint32_t current_irq;
> } PL011State;
>
> #define PL011_INT_TX 0x20
> @@ -53,10 +56,11 @@ static const unsigned char pl011_id_luminary[8] =
>
> static void pl011_update(PL011State *s)
> {
> - uint32_t flags;
> -
> - flags = s->int_level & s->int_enabled;
> - qemu_set_irq(s->irq, flags != 0);
> + uint32_t flags = s->int_level & s->int_enabled;
> + if (flags != s->current_irq) {
> + s->current_irq = flags;
> + qemu_set_irq(s->irq, s->current_irq != 0);
> + }
> }
Consider this sequence of events:
* the guest does something causing the interrupt to
be asserted; int_level and int_enabled are 1, and
current_irq is also now 1. We call qemu_set_irq()
to raise the interrupt with the GIC
* we migrate the guest to another host
* on the receiving end, QEMU is in a cleanly reset
state, and so current_irq, int_level and int_enabled
are all zero before incoming data arrives
* int_level and int_enabled are both set to 1 from
the incoming data stream
* the GIC itself is set to the "interrupt is
asserted" state by its own incoming data
* current_irq remains zero, because it's not migrated
* the guest is resumed, and does something to deassert
the interrupt. the new 'flags' value is zero
* because flags == s->current_irq, we don't call
qemu_set_irq, and so we've just dropped the deassert
of this interrupt on the floor.
-- PMM
More information about the linux-arm-kernel
mailing list