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

Reply via email to