summary refs log tree commit diff stats
path: root/hw/intc
diff options
context:
space:
mode:
authorDavid Hildenbrand <david@redhat.com>2018-01-29 13:56:16 +0100
committerCornelia Huck <cohuck@redhat.com>2018-02-09 09:37:13 +0100
commit631b59664c9d8472d64c9c9c14b709dd40f07b16 (patch)
tree96023ad9d280f23c125266bb30bb5c48d7d0091f /hw/intc
parent6e0d8175d63afba248f7da09047d0fcedd1e953d (diff)
downloadfocaccia-qemu-631b59664c9d8472d64c9c9c14b709dd40f07b16.tar.gz
focaccia-qemu-631b59664c9d8472d64c9c9c14b709dd40f07b16.zip
s390x/flic: optimize CPU wakeup for TCG
Kicking all CPUs on every floating interrupt is far from efficient.
Let's optimize it at least a little bit.

Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20180129125623.21729-12-david@redhat.com>
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
Diffstat (limited to 'hw/intc')
-rw-r--r--hw/intc/s390_flic.c31
1 files changed, 29 insertions, 2 deletions
diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c
index cb216de9ba..5febde2d65 100644
--- a/hw/intc/s390_flic.c
+++ b/hw/intc/s390_flic.c
@@ -161,10 +161,37 @@ static void qemu_s390_flic_notify(uint32_t type)
 
     /*
      * We have to make all CPUs see CPU_INTERRUPT_HARD, so they might
-     * consider it. TODO: don't kick/wakeup all VCPUs but try to be
-     * smarter (using the interrupt type).
+     * consider it. We will kick all running CPUs and only relevant
+     * sleeping ones.
      */
     CPU_FOREACH(cs) {
+        S390CPU *cpu = S390_CPU(cs);
+
+        cs->interrupt_request |= CPU_INTERRUPT_HARD;
+
+        /* ignore CPUs that are not sleeping */
+        if (s390_cpu_get_state(cpu) != CPU_STATE_OPERATING &&
+            s390_cpu_get_state(cpu) != CPU_STATE_LOAD) {
+            continue;
+        }
+
+        /* we always kick running CPUs for now, this is tricky */
+        if (cs->halted) {
+            /* don't check for subclasses, CPUs double check when waking up */
+            if (type & FLIC_PENDING_SERVICE) {
+                if (!(cpu->env.psw.mask & PSW_MASK_EXT)) {
+                    continue;
+                }
+            } else if (type & FLIC_PENDING_IO) {
+                if (!(cpu->env.psw.mask & PSW_MASK_IO)) {
+                    continue;
+                }
+            } else if (type & FLIC_PENDING_MCHK_CR) {
+                if (!(cpu->env.psw.mask & PSW_MASK_MCHECK)) {
+                    continue;
+                }
+            }
+        }
         cpu_interrupt(cs, CPU_INTERRUPT_HARD);
     }
 }