l2vic_update_all() called l2vic_update() for each of the 1024 irqs, and every call rescanned all of int_status for an active vid. ciad runs it on each interrupt return, so this was a hot function for an OS boot.
Check once whether a vid is active, then deliver the lowest irq that is both pending and enabled by scanning int_pending & int_enable a word at a time. The delivered irq is unchanged. Reviewed-by: Pierrick Bouvier <[email protected]> Signed-off-by: Brian Cain <[email protected]> --- hw/intc/hex-l2vic.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/hw/intc/hex-l2vic.c b/hw/intc/hex-l2vic.c index b73ecb821e4..2335236f837 100644 --- a/hw/intc/hex-l2vic.c +++ b/hw/intc/hex-l2vic.c @@ -290,9 +290,20 @@ static bool l2vic_update(HexL2VICState *s, int irq) static void l2vic_update_all(HexL2VICState *s) { - for (int i = 0; i < L2VIC_INTERRUPT_MAX; i++) { - if (l2vic_update(s, i)) { - /* once vid is active, no-one else can set it until ciad */ + /* once vid is active, no-one else can set it until ciad */ + if (vid_active(s)) { + return; + } + + /* + * Quickly find lowest-numbered irq ready by scanning their statuses + * range by range instead of one by one. + */ + for (int slice = 0; slice < SLICE_MAX; slice++) { + uint32_t ready = s->int_pending[slice] & s->int_enable[slice]; + + if (ready) { + l2vic_update(s, slice * 32 + ctz32(ready)); return; } } -- 2.34.1
