All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH v2 00/29] PowerPC interrupt rework
@ 2022-09-27 20:15 Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 01/29] target/ppc: define PPC_INTERRUPT_* values directly Matheus Ferst
                   ` (29 more replies)
  0 siblings, 30 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

Link to v1: https://lists.gnu.org/archive/html/qemu-ppc/2022-08/msg00370.html
This series is also available as a git branch: https://github.com/PPC64/qemu/tree/ferst-interrupt-fix-v2

This version addresses Fabiano's feedback and fixes some issues found
with the tests suggested by Cédric. While working on it, I found two
intermittent problems on master:

 i) ~10% of boots with pSeries and 970/970mp/POWER5+ hard lockup after
    either SCSI or network initialization when using -smp 4. With
    -smp 2, the problem is harder to reproduce but still happens, and I
    couldn't reproduce with thread=single.
ii) ~52% of KVM guest initializations on PowerNV hang in different parts
    of the boot process when using more than one CPU.

With the complete series applied, I couldn't reproduce (i) anymore, and
(ii) became a little more frequent (~58%).

I've tested each patch of this series with [1], modified to use -smp for
machines that support more than one CPU. The machines I can currently
boot with FreeBSD (970/970,p/POWER5+/POWER7/POWER8/POWER9 pSeries,
POWER8/POWER9 PowerNV, and mpc8544ds) were tested with the images from
[2] and still boot after applying the patch series. Booting nested
guests inside a TCG pSeries machine also seems to be working fine.

Using command lines like:

./qemu-system-ppc64 -M powernv9 -cpu POWER9 -accel tcg,thread=multi \
                -m 8G -smp $SMP -vga none -nographic -kernel zImage \
                -append 'console=hvc0' -initrdootfs.cpio.xz \
                -serial pipe:pipe -monitor unix:mon,server,nowait

and

./qemu-system-ppc64 -M pseries -cpu POWER9 -accel tcg,thread=multi \
                -m 8G -smp $SMP -vga none -nographic -kernel zImage \
                -append 'console=hvc0' -initrd rootfs.cpio.xz \
                -serial pipe:pipe -monitor unix:mon,server,nowait

to measure the time to boot, login, and shut down a compressed kernel
with a buildroot initramfs, with 100 iteration we get:

+-----+------------------------------+-----------------------------+
|     |            PowerNV           |           pSeries           |
|-smp |------------------------------+-----------------------------+
|     |     master    | patch series |    master    | patch series |
+-----+------------------------------+-----------------------------+
|  1  |  45,84 ± 0,92 | 38,08 ± 0,66 | 23,56 ± 1,16 | 23,76 ± 1,04 |
|  2  |  80,21 ± 8,03 | 40,81 ± 0,45 | 26,59 ± 0,92 | 26,88 ± 0,99 |
|  4  | 115,98 ± 9,85 | 38,80 ± 0,44 | 28,83 ± 0,84 | 28,46 ± 0,94 |
|  6  | 199,14 ± 6,36 | 39,32 ± 0,50 | 29,22 ± 0,78 | 29,45 ± 0,86 |
|  8  | 47,85 ± 27,50 | 38,98 ± 0,49 | 29,63 ± 0,80 | 29,60 ± 0,78 |
+-----+------------------------------+-----------------------------+

This results shows that the problem reported in [3] is solved, while
pSeries boot time is essentially unchanged.

With a non-compressed kernel, the difference with PowerNV is smaller,
and pSeries stills the same:

+-----+------------------------------+-----------------------------+
|     |            PowerNV           |           pSeries           |
|-smp |------------------------------+-----------------------------+
|     |     master    | patch series |    master    | patch series |
+-----+------------------------------+-----------------------------+
|  1  |  42,17 ± 0,92 | 38,13 ± 0,59 | 23,15 ± 1,02 | 23,46 ± 1,02 |
|  2  |  55,72 ± 3,54 | 40,30 ± 0,56 | 26,26 ± 0,82 | 26,38 ± 0,80 |
|  4  |  67,09 ± 3,02 | 38,26 ± 0,47 | 28,36 ± 0,77 | 28,19 ± 0,78 |
|  6  |  98,96 ± 2,49 | 39,01 ± 0,38 | 28,68 ± 0,75 | 29,02 ± 0,88 |
|  8  |  39,68 ± 0,42 | 38,44 ± 0,41 | 29,24 ± 0,81 | 29,44 ± 0,75 |
+-----+------------------------------+-----------------------------+

Finally, using command lines like

./qemu-system-ppc64 -M powernv9 -cpu POWER9 -accel tcg,thread=multi \
    -m 8G -smp 4 -device virtio-scsi-pci -boot c -vga none -nographic \
    -device nvme,bus=pcie.2,addr=0x0,drive=drive0,serial=1234 \
    -drive file=rootfs.ext2,if=none,id=drive0,format=raw,cache=none \
    -snapshot -serial pipe:pipe -monitor unix:mon,server,nowait \
    -kernel zImage -append 'console=hvc0 rootwait root=/dev/nvme0n1' \
    -device virtio-net-pci,netdev=br0,mac=52:54:00:12:34:57,bus=pcie.0 \
    -netdev bridge,id=br0

and

./qemu-system-ppc64 -M pseries -cpu POWER9 -accel tcg,thread=multi \
    -m 8G -smp 4 -device virtio-scsi-pci -boot c -vga none -nographic \
    -drive file=rootfs.ext2,if=scsi,index=0,format=raw -snapshot \
    -kernel zImage -append 'console=hvc0 rootwait root=/dev/sda' \
    -serial pipe:pipe -monitor unix:mon,server,nowait \
    -device virtio-net-pci,netdev=br0,mac=52:54:00:12:34:57 \
    -netdev bridge,id=br0

to tests IO performance, with iperf to test network and a 4Gb scp
transfer to test disk+network, in 100 iterations we saw:

+---------------------+---------------+-----------------+
|                     |    scp (s)    |   iperf (MB/s)  |
+---------------------+---------------+-----------------+
|PowerNV master       | 166,91 ± 8,37 | 918,06 ± 114,78 |
|PowerNV patch series | 166,25 ± 8,85 | 916,91 ± 107,56 |
|pSeries master       | 175,70 ± 8,22 | 958,73 ± 115,09 |
|pSeries patch series | 173,62 ± 8,13 | 893,42 ±  87,77 |
+---------------------+---------------+-----------------+

The scp data shows little difference, while testing just network shows
that it's a bit slower with the patch series applied (although, with
this variation, we'd probably need to repeat this test more times to
have a more robust result...)

[1] https://github.com/legoater/qemu-ppc-boot
[2] https://artifact.ci.freebsd.org/snapshot/14.0-CURRENT/latest_vm/powerpc
[3] https://lists.gnu.org/archive/html/qemu-ppc/2022-06/msg00336.html

Matheus Ferst (29):
  target/ppc: define PPC_INTERRUPT_* values directly
  target/ppc: always use ppc_set_irq to set env->pending_interrupts
  target/ppc: split interrupt masking and delivery from ppc_hw_interrupt
  target/ppc: prepare to split interrupt masking and delivery by excp_model
  target/ppc: create an interrupt masking method for POWER9/POWER10
  target/ppc: remove unused interrupts from p9_pending_interrupt
  target/ppc: create an interrupt deliver method for POWER9/POWER10
  target/ppc: remove unused interrupts from p9_deliver_interrupt
  target/ppc: remove generic architecture checks from p9_deliver_interrupt
  target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER9
  target/ppc: add power-saving interrupt masking logic to p9_next_unmasked_interrupt
  target/ppc: create an interrupt masking method for POWER8
  target/ppc: remove unused interrupts from p8_pending_interrupt
  target/ppc: create an interrupt deliver method for POWER8
  target/ppc: remove unused interrupts from p8_deliver_interrupt
  target/ppc: remove generic architecture checks from p8_deliver_interrupt
  target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER8
  target/ppc: add power-saving interrupt masking logic to p8_next_unmasked_interrupt
  target/ppc: create an interrupt masking method for POWER7
  target/ppc: remove unused interrupts from p7_pending_interrupt
  target/ppc: create an interrupt deliver method for POWER7
  target/ppc: remove unused interrupts from p7_deliver_interrupt
  target/ppc: remove generic architecture checks from p7_deliver_interrupt
  target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER7
  target/ppc: add power-saving interrupt masking logic to p7_next_unmasked_interrupt
  target/ppc: remove ppc_store_lpcr from CONFIG_USER_ONLY builds
  target/ppc: introduce ppc_maybe_interrupt
  target/ppc: unify cpu->has_work based on cs->interrupt_request
  target/ppc: move the p*_interrupt_powersave methods to excp_helper.c

 hw/ppc/pnv_core.c        |   1 +
 hw/ppc/ppc.c             |  17 +-
 hw/ppc/spapr_hcall.c     |   6 +
 hw/ppc/spapr_rtas.c      |   2 +-
 hw/ppc/trace-events      |   2 +-
 target/ppc/cpu.c         |   4 +
 target/ppc/cpu.h         |  43 +-
 target/ppc/cpu_init.c    | 212 +---------
 target/ppc/excp_helper.c | 857 ++++++++++++++++++++++++++++++++++-----
 target/ppc/helper.h      |   1 +
 target/ppc/helper_regs.c |   2 +
 target/ppc/misc_helper.c |  11 +-
 target/ppc/translate.c   |   2 +
 13 files changed, 803 insertions(+), 357 deletions(-)

-- 
2.25.1



^ permalink raw reply	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 01/29] target/ppc: define PPC_INTERRUPT_* values directly
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 02/29] target/ppc: always use ppc_set_irq to set env->pending_interrupts Matheus Ferst
                   ` (28 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

This enum defines the bit positions in env->pending_interrupts for each
interrupt. However, except for the comparison in kvmppc_set_interrupt,
the values are always used as (1 << PPC_INTERRUPT_*). Define them
directly like that to save some clutter. No functional change intended.

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
 hw/ppc/ppc.c             | 10 +++---
 hw/ppc/trace-events      |  2 +-
 target/ppc/cpu.h         | 40 +++++++++++-----------
 target/ppc/cpu_init.c    | 56 +++++++++++++++---------------
 target/ppc/excp_helper.c | 74 ++++++++++++++++++++--------------------
 target/ppc/misc_helper.c |  6 ++--
 6 files changed, 94 insertions(+), 94 deletions(-)

diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 690f448cb9..77e611e81c 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -40,7 +40,7 @@
 static void cpu_ppc_tb_stop (CPUPPCState *env);
 static void cpu_ppc_tb_start (CPUPPCState *env);
 
-void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level)
+void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
 {
     CPUState *cs = CPU(cpu);
     CPUPPCState *env = &cpu->env;
@@ -56,21 +56,21 @@ void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level)
     old_pending = env->pending_interrupts;
 
     if (level) {
-        env->pending_interrupts |= 1 << n_IRQ;
+        env->pending_interrupts |= irq;
         cpu_interrupt(cs, CPU_INTERRUPT_HARD);
     } else {
-        env->pending_interrupts &= ~(1 << n_IRQ);
+        env->pending_interrupts &= ~irq;
         if (env->pending_interrupts == 0) {
             cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
         }
     }
 
     if (old_pending != env->pending_interrupts) {
-        kvmppc_set_interrupt(cpu, n_IRQ, level);
+        kvmppc_set_interrupt(cpu, irq, level);
     }
 
 
-    trace_ppc_irq_set_exit(env, n_IRQ, level, env->pending_interrupts,
+    trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts,
                            CPU(cpu)->interrupt_request);
 
     if (locked) {
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index a07d5aca0f..956938ebcd 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -127,7 +127,7 @@ ppc40x_set_tb_clk(uint32_t value) "new frequency %" PRIu32
 ppc40x_timers_init(uint32_t value) "frequency %" PRIu32
 
 ppc_irq_set(void *env, uint32_t pin, uint32_t level) "env [%p] pin %d level %d"
-ppc_irq_set_exit(void *env, uint32_t n_IRQ, uint32_t level, uint32_t pending, uint32_t request) "env [%p] n_IRQ %d level %d => pending 0x%08" PRIx32 " req 0x%08" PRIx32
+ppc_irq_set_exit(void *env, uint32_t irq, uint32_t level, uint32_t pending, uint32_t request) "env [%p] irq 0x%05" PRIx32 " level %d => pending 0x%08" PRIx32 " req 0x%08" PRIx32
 ppc_irq_set_state(const char *name, uint32_t level) "\"%s\" level %d"
 ppc_irq_reset(const char *name) "%s"
 ppc_irq_cpu(const char *action) "%s"
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 7f73e2ac81..9ccd23db04 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -2416,27 +2416,27 @@ enum {
 /* Hardware exceptions definitions */
 enum {
     /* External hardware exception sources */
-    PPC_INTERRUPT_RESET     = 0,  /* Reset exception                      */
-    PPC_INTERRUPT_WAKEUP,         /* Wakeup exception                     */
-    PPC_INTERRUPT_MCK,            /* Machine check exception              */
-    PPC_INTERRUPT_EXT,            /* External interrupt                   */
-    PPC_INTERRUPT_SMI,            /* System management interrupt          */
-    PPC_INTERRUPT_CEXT,           /* Critical external interrupt          */
-    PPC_INTERRUPT_DEBUG,          /* External debug exception             */
-    PPC_INTERRUPT_THERM,          /* Thermal exception                    */
+    PPC_INTERRUPT_RESET     = 0x00001,  /* Reset exception                    */
+    PPC_INTERRUPT_WAKEUP    = 0x00002,  /* Wakeup exception                   */
+    PPC_INTERRUPT_MCK       = 0x00004,  /* Machine check exception            */
+    PPC_INTERRUPT_EXT       = 0x00008,  /* External interrupt                 */
+    PPC_INTERRUPT_SMI       = 0x00010,  /* System management interrupt        */
+    PPC_INTERRUPT_CEXT      = 0x00020,  /* Critical external interrupt        */
+    PPC_INTERRUPT_DEBUG     = 0x00040,  /* External debug exception           */
+    PPC_INTERRUPT_THERM     = 0x00080,  /* Thermal exception                  */
     /* Internal hardware exception sources */
-    PPC_INTERRUPT_DECR,           /* Decrementer exception                */
-    PPC_INTERRUPT_HDECR,          /* Hypervisor decrementer exception     */
-    PPC_INTERRUPT_PIT,            /* Programmable interval timer interrupt */
-    PPC_INTERRUPT_FIT,            /* Fixed interval timer interrupt       */
-    PPC_INTERRUPT_WDT,            /* Watchdog timer interrupt             */
-    PPC_INTERRUPT_CDOORBELL,      /* Critical doorbell interrupt          */
-    PPC_INTERRUPT_DOORBELL,       /* Doorbell interrupt                   */
-    PPC_INTERRUPT_PERFM,          /* Performance monitor interrupt        */
-    PPC_INTERRUPT_HMI,            /* Hypervisor Maintenance interrupt    */
-    PPC_INTERRUPT_HDOORBELL,      /* Hypervisor Doorbell interrupt        */
-    PPC_INTERRUPT_HVIRT,          /* Hypervisor virtualization interrupt  */
-    PPC_INTERRUPT_EBB,            /* Event-based Branch exception         */
+    PPC_INTERRUPT_DECR      = 0x00100, /* Decrementer exception               */
+    PPC_INTERRUPT_HDECR     = 0x00200, /* Hypervisor decrementer exception    */
+    PPC_INTERRUPT_PIT       = 0x00400, /* Programmable interval timer int.    */
+    PPC_INTERRUPT_FIT       = 0x00800, /* Fixed interval timer interrupt      */
+    PPC_INTERRUPT_WDT       = 0x01000, /* Watchdog timer interrupt            */
+    PPC_INTERRUPT_CDOORBELL = 0x02000, /* Critical doorbell interrupt         */
+    PPC_INTERRUPT_DOORBELL  = 0x04000, /* Doorbell interrupt                  */
+    PPC_INTERRUPT_PERFM     = 0x08000, /* Performance monitor interrupt       */
+    PPC_INTERRUPT_HMI       = 0x10000, /* Hypervisor Maintenance interrupt    */
+    PPC_INTERRUPT_HDOORBELL = 0x20000, /* Hypervisor Doorbell interrupt       */
+    PPC_INTERRUPT_HVIRT     = 0x40000, /* Hypervisor virtualization interrupt */
+    PPC_INTERRUPT_EBB       = 0x80000, /* Event-based Branch exception        */
 };
 
 /* Processor Compatibility mask (PCR) */
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 6e080ebda0..4b4b3feac9 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -5969,23 +5969,23 @@ static bool cpu_has_work_POWER7(CPUState *cs)
         if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
             return false;
         }
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
             (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
             return true;
         }
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DECR)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
             (env->spr[SPR_LPCR] & LPCR_P7_PECE1)) {
             return true;
         }
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_MCK)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
             (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
             return true;
         }
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HMI)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
             (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
             return true;
         }
-        if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) {
+        if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
             return true;
         }
         return false;
@@ -6142,31 +6142,31 @@ static bool cpu_has_work_POWER8(CPUState *cs)
         if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
             return false;
         }
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
             (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
             return true;
         }
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DECR)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
             (env->spr[SPR_LPCR] & LPCR_P8_PECE3)) {
             return true;
         }
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_MCK)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
             (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
             return true;
         }
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HMI)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
             (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
             return true;
         }
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DOORBELL)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
             (env->spr[SPR_LPCR] & LPCR_P8_PECE0)) {
             return true;
         }
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HDOORBELL)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
             (env->spr[SPR_LPCR] & LPCR_P8_PECE1)) {
             return true;
         }
-        if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) {
+        if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
             return true;
         }
         return false;
@@ -6368,7 +6368,7 @@ static bool cpu_has_work_POWER9(CPUState *cs)
             return true;
         }
         /* External Exception */
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
             (env->spr[SPR_LPCR] & LPCR_EEE)) {
             bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
             if (!heic || !FIELD_EX64_HV(env->msr) ||
@@ -6377,31 +6377,31 @@ static bool cpu_has_work_POWER9(CPUState *cs)
             }
         }
         /* Decrementer Exception */
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DECR)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
             (env->spr[SPR_LPCR] & LPCR_DEE)) {
             return true;
         }
         /* Machine Check or Hypervisor Maintenance Exception */
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_MCK |
-            1u << PPC_INTERRUPT_HMI)) && (env->spr[SPR_LPCR] & LPCR_OEE)) {
+        if ((env->pending_interrupts & (PPC_INTERRUPT_MCK | PPC_INTERRUPT_HMI))
+            && (env->spr[SPR_LPCR] & LPCR_OEE)) {
             return true;
         }
         /* Privileged Doorbell Exception */
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DOORBELL)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
             (env->spr[SPR_LPCR] & LPCR_PDEE)) {
             return true;
         }
         /* Hypervisor Doorbell Exception */
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HDOORBELL)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
             (env->spr[SPR_LPCR] & LPCR_HDEE)) {
             return true;
         }
         /* Hypervisor virtualization exception */
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HVIRT)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) &&
             (env->spr[SPR_LPCR] & LPCR_HVEE)) {
             return true;
         }
-        if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) {
+        if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
             return true;
         }
         return false;
@@ -6601,7 +6601,7 @@ static bool cpu_has_work_POWER10(CPUState *cs)
             return true;
         }
         /* External Exception */
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
             (env->spr[SPR_LPCR] & LPCR_EEE)) {
             bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
             if (!heic || !FIELD_EX64_HV(env->msr) ||
@@ -6610,31 +6610,31 @@ static bool cpu_has_work_POWER10(CPUState *cs)
             }
         }
         /* Decrementer Exception */
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DECR)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
             (env->spr[SPR_LPCR] & LPCR_DEE)) {
             return true;
         }
         /* Machine Check or Hypervisor Maintenance Exception */
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_MCK |
-            1u << PPC_INTERRUPT_HMI)) && (env->spr[SPR_LPCR] & LPCR_OEE)) {
+        if ((env->pending_interrupts & (PPC_INTERRUPT_MCK | PPC_INTERRUPT_HMI))
+            && (env->spr[SPR_LPCR] & LPCR_OEE)) {
             return true;
         }
         /* Privileged Doorbell Exception */
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DOORBELL)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
             (env->spr[SPR_LPCR] & LPCR_PDEE)) {
             return true;
         }
         /* Hypervisor Doorbell Exception */
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HDOORBELL)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
             (env->spr[SPR_LPCR] & LPCR_HDEE)) {
             return true;
         }
         /* Hypervisor virtualization exception */
-        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HVIRT)) &&
+        if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) &&
             (env->spr[SPR_LPCR] & LPCR_HVEE)) {
             return true;
         }
-        if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) {
+        if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
             return true;
         }
         return false;
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 214acf5ac4..3f8ff9bcf3 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1683,21 +1683,21 @@ static void ppc_hw_interrupt(CPUPPCState *env)
     bool async_deliver;
 
     /* External reset */
-    if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
-        env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
+    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+        env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
         powerpc_excp(cpu, POWERPC_EXCP_RESET);
         return;
     }
     /* Machine check exception */
-    if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
-        env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
+    if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+        env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
         powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
         return;
     }
 #if 0 /* TODO */
     /* External debug exception */
-    if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
-        env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
+    if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
+        env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
         powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
         return;
     }
@@ -1712,19 +1712,19 @@ static void ppc_hw_interrupt(CPUPPCState *env)
     async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
 
     /* Hypervisor decrementer exception */
-    if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
+    if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
         /* LPCR will be clear when not supported so this will work */
         bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
         if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
             /* HDEC clears on delivery */
-            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
+            env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
             powerpc_excp(cpu, POWERPC_EXCP_HDECR);
             return;
         }
     }
 
     /* Hypervisor virtualization interrupt */
-    if (env->pending_interrupts & (1 << PPC_INTERRUPT_HVIRT)) {
+    if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
         /* LPCR will be clear when not supported so this will work */
         bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
         if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
@@ -1734,7 +1734,7 @@ static void ppc_hw_interrupt(CPUPPCState *env)
     }
 
     /* External interrupt can ignore MSR:EE under some circumstances */
-    if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
+    if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
         bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
         bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
         /* HEIC blocks delivery to the hypervisor */
@@ -1751,45 +1751,45 @@ static void ppc_hw_interrupt(CPUPPCState *env)
     }
     if (FIELD_EX64(env->msr, MSR, CE)) {
         /* External critical interrupt */
-        if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
+        if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
             powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
             return;
         }
     }
     if (async_deliver != 0) {
         /* Watchdog timer on embedded PowerPC */
-        if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
-            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
+        if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
+            env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
             powerpc_excp(cpu, POWERPC_EXCP_WDT);
             return;
         }
-        if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
-            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
+        if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
+            env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
             powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
             return;
         }
         /* Fixed interval timer on embedded PowerPC */
-        if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
-            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
+        if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
+            env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
             powerpc_excp(cpu, POWERPC_EXCP_FIT);
             return;
         }
         /* Programmable interval timer on embedded PowerPC */
-        if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
-            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
+        if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
+            env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
             powerpc_excp(cpu, POWERPC_EXCP_PIT);
             return;
         }
         /* Decrementer exception */
-        if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
+        if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
             if (ppc_decr_clear_on_delivery(env)) {
-                env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
+                env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
             }
             powerpc_excp(cpu, POWERPC_EXCP_DECR);
             return;
         }
-        if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
-            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
+        if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
+            env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
             if (is_book3s_arch2x(env)) {
                 powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
             } else {
@@ -1797,31 +1797,31 @@ static void ppc_hw_interrupt(CPUPPCState *env)
             }
             return;
         }
-        if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) {
-            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL);
+        if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
+            env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
             powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
             return;
         }
-        if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
-            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
+        if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
+            env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
             powerpc_excp(cpu, POWERPC_EXCP_PERFM);
             return;
         }
         /* Thermal interrupt */
-        if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
-            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
+        if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
+            env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
             powerpc_excp(cpu, POWERPC_EXCP_THERM);
             return;
         }
         /* EBB exception */
-        if (env->pending_interrupts & (1 << PPC_INTERRUPT_EBB)) {
+        if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
             /*
              * EBB exception must be taken in problem state and
              * with BESCR_GE set.
              */
             if (FIELD_EX64(env->msr, MSR, PR) &&
                 (env->spr[SPR_BESCR] & BESCR_GE)) {
-                env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EBB);
+                env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
 
                 if (env->spr[SPR_BESCR] & BESCR_PMEO) {
                     powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
@@ -2098,7 +2098,7 @@ static void do_ebb(CPUPPCState *env, int ebb_excp)
     if (FIELD_EX64(env->msr, MSR, PR)) {
         powerpc_excp(cpu, ebb_excp);
     } else {
-        env->pending_interrupts |= 1 << PPC_INTERRUPT_EBB;
+        env->pending_interrupts |= PPC_INTERRUPT_EBB;
         cpu_interrupt(cs, CPU_INTERRUPT_HARD);
     }
 }
@@ -2292,7 +2292,7 @@ void helper_msgclr(CPUPPCState *env, target_ulong rb)
         return;
     }
 
-    env->pending_interrupts &= ~(1 << irq);
+    env->pending_interrupts &= ~irq;
 }
 
 void helper_msgsnd(target_ulong rb)
@@ -2311,7 +2311,7 @@ void helper_msgsnd(target_ulong rb)
         CPUPPCState *cenv = &cpu->env;
 
         if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
-            cenv->pending_interrupts |= 1 << irq;
+            cenv->pending_interrupts |= irq;
             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
         }
     }
@@ -2336,7 +2336,7 @@ void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb)
         return;
     }
 
-    env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL);
+    env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
 }
 
 static void book3s_msgsnd_common(int pir, int irq)
@@ -2350,7 +2350,7 @@ static void book3s_msgsnd_common(int pir, int irq)
 
         /* TODO: broadcast message to all threads of the same  processor */
         if (cenv->spr_cb[SPR_PIR].default_value == pir) {
-            cenv->pending_interrupts |= 1 << irq;
+            cenv->pending_interrupts |= irq;
             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
         }
     }
@@ -2377,7 +2377,7 @@ void helper_book3s_msgclrp(CPUPPCState *env, target_ulong rb)
         return;
     }
 
-    env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
+    env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
 }
 
 /*
diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c
index b0a5e7ce76..05e35572bc 100644
--- a/target/ppc/misc_helper.c
+++ b/target/ppc/misc_helper.c
@@ -163,7 +163,7 @@ target_ulong helper_load_dpdes(CPUPPCState *env)
     helper_hfscr_facility_check(env, HFSCR_MSGP, "load DPDES", HFSCR_IC_MSGP);
 
     /* TODO: TCG supports only one thread */
-    if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
+    if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
         dpdes = 1;
     }
 
@@ -185,10 +185,10 @@ void helper_store_dpdes(CPUPPCState *env, target_ulong val)
     }
 
     if (val & 0x1) {
-        env->pending_interrupts |= 1 << PPC_INTERRUPT_DOORBELL;
+        env->pending_interrupts |= PPC_INTERRUPT_DOORBELL;
         cpu_interrupt(cs, CPU_INTERRUPT_HARD);
     } else {
-        env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
+        env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
     }
 }
 #endif /* defined(TARGET_PPC64) */
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 02/29] target/ppc: always use ppc_set_irq to set env->pending_interrupts
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 01/29] target/ppc: define PPC_INTERRUPT_* values directly Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-30 14:32   ` Fabiano Rosas
  2022-09-27 20:15 ` [RFC PATCH v2 03/29] target/ppc: split interrupt masking and delivery from ppc_hw_interrupt Matheus Ferst
                   ` (27 subsequent siblings)
  29 siblings, 1 reply; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

Use ppc_set_irq to raise/clear interrupts to ensure CPU_INTERRUPT_HARD
will be set/reset accordingly.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
 target/ppc/excp_helper.c | 17 +++++++----------
 target/ppc/misc_helper.c |  9 ++-------
 2 files changed, 9 insertions(+), 17 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 3f8ff9bcf3..c3c30c5d1b 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -23,6 +23,7 @@
 #include "exec/exec-all.h"
 #include "internal.h"
 #include "helper_regs.h"
+#include "hw/ppc/ppc.h"
 
 #include "trace.h"
 
@@ -2080,7 +2081,6 @@ void helper_rfebb(CPUPPCState *env, target_ulong s)
 static void do_ebb(CPUPPCState *env, int ebb_excp)
 {
     PowerPCCPU *cpu = env_archcpu(env);
-    CPUState *cs = CPU(cpu);
 
     /*
      * FSCR_EBB and FSCR_IC_EBB are the same bits used with
@@ -2098,8 +2098,7 @@ static void do_ebb(CPUPPCState *env, int ebb_excp)
     if (FIELD_EX64(env->msr, MSR, PR)) {
         powerpc_excp(cpu, ebb_excp);
     } else {
-        env->pending_interrupts |= PPC_INTERRUPT_EBB;
-        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+        ppc_set_irq(cpu, PPC_INTERRUPT_EBB, 1);
     }
 }
 
@@ -2292,7 +2291,7 @@ void helper_msgclr(CPUPPCState *env, target_ulong rb)
         return;
     }
 
-    env->pending_interrupts &= ~irq;
+    ppc_set_irq(env_archcpu(env), irq, 0);
 }
 
 void helper_msgsnd(target_ulong rb)
@@ -2311,8 +2310,7 @@ void helper_msgsnd(target_ulong rb)
         CPUPPCState *cenv = &cpu->env;
 
         if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
-            cenv->pending_interrupts |= irq;
-            cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+            ppc_set_irq(cpu, irq, 1);
         }
     }
     qemu_mutex_unlock_iothread();
@@ -2336,7 +2334,7 @@ void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb)
         return;
     }
 
-    env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
+    ppc_set_irq(env_archcpu(env), PPC_INTERRUPT_HDOORBELL, 0);
 }
 
 static void book3s_msgsnd_common(int pir, int irq)
@@ -2350,8 +2348,7 @@ static void book3s_msgsnd_common(int pir, int irq)
 
         /* TODO: broadcast message to all threads of the same  processor */
         if (cenv->spr_cb[SPR_PIR].default_value == pir) {
-            cenv->pending_interrupts |= irq;
-            cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+            ppc_set_irq(cpu, irq, 1);
         }
     }
     qemu_mutex_unlock_iothread();
@@ -2377,7 +2374,7 @@ void helper_book3s_msgclrp(CPUPPCState *env, target_ulong rb)
         return;
     }
 
-    env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
+    ppc_set_irq(env_archcpu(env), PPC_INTERRUPT_HDOORBELL, 0);
 }
 
 /*
diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c
index 05e35572bc..a9bc1522e2 100644
--- a/target/ppc/misc_helper.c
+++ b/target/ppc/misc_helper.c
@@ -25,6 +25,7 @@
 #include "qemu/error-report.h"
 #include "qemu/main-loop.h"
 #include "mmu-book3s-v3.h"
+#include "hw/ppc/ppc.h"
 
 #include "helper_regs.h"
 
@@ -173,7 +174,6 @@ target_ulong helper_load_dpdes(CPUPPCState *env)
 void helper_store_dpdes(CPUPPCState *env, target_ulong val)
 {
     PowerPCCPU *cpu = env_archcpu(env);
-    CPUState *cs = CPU(cpu);
 
     helper_hfscr_facility_check(env, HFSCR_MSGP, "store DPDES", HFSCR_IC_MSGP);
 
@@ -184,12 +184,7 @@ void helper_store_dpdes(CPUPPCState *env, target_ulong val)
         return;
     }
 
-    if (val & 0x1) {
-        env->pending_interrupts |= PPC_INTERRUPT_DOORBELL;
-        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
-    } else {
-        env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
-    }
+    ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, val & 0x1);
 }
 #endif /* defined(TARGET_PPC64) */
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 03/29] target/ppc: split interrupt masking and delivery from ppc_hw_interrupt
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 01/29] target/ppc: define PPC_INTERRUPT_* values directly Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 02/29] target/ppc: always use ppc_set_irq to set env->pending_interrupts Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-30 15:55   ` Fabiano Rosas
  2022-09-27 20:15 ` [RFC PATCH v2 04/29] target/ppc: prepare to split interrupt masking and delivery by excp_model Matheus Ferst
                   ` (26 subsequent siblings)
  29 siblings, 1 reply; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

Split ppc_hw_interrupt into an interrupt masking method,
ppc_next_unmasked_interrupt, and an interrupt processing method,
ppc_deliver_interrupt.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
v2:
  - ppc_hw_interrupt renamed as ppc_deliver_interrupt (farosas);
  - Handle the "Wakeup from PM state but interrupt Undelivered" case
    as an assert in ppc_deliver_interrupt (farosas).
---
 target/ppc/excp_helper.c | 207 +++++++++++++++++++++++++--------------
 1 file changed, 131 insertions(+), 76 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index c3c30c5d1b..c6381489b6 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1678,29 +1678,22 @@ void ppc_cpu_do_interrupt(CPUState *cs)
     powerpc_excp(cpu, cs->exception_index);
 }
 
-static void ppc_hw_interrupt(CPUPPCState *env)
+static int ppc_next_unmasked_interrupt(CPUPPCState *env)
 {
-    PowerPCCPU *cpu = env_archcpu(env);
     bool async_deliver;
 
     /* External reset */
     if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-        env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
-        powerpc_excp(cpu, POWERPC_EXCP_RESET);
-        return;
+        return PPC_INTERRUPT_RESET;
     }
     /* Machine check exception */
     if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
-        env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
-        powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
-        return;
+        return PPC_INTERRUPT_MCK;
     }
 #if 0 /* TODO */
     /* External debug exception */
     if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
-        env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
-        powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
-        return;
+        return PPC_INTERRUPT_DEBUG;
     }
 #endif
 
@@ -1718,9 +1711,7 @@ static void ppc_hw_interrupt(CPUPPCState *env)
         bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
         if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
             /* HDEC clears on delivery */
-            env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
-            powerpc_excp(cpu, POWERPC_EXCP_HDECR);
-            return;
+            return PPC_INTERRUPT_HDECR;
         }
     }
 
@@ -1729,8 +1720,7 @@ static void ppc_hw_interrupt(CPUPPCState *env)
         /* LPCR will be clear when not supported so this will work */
         bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
         if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
-            powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
-            return;
+            return PPC_INTERRUPT_HVIRT;
         }
     }
 
@@ -1742,77 +1732,47 @@ static void ppc_hw_interrupt(CPUPPCState *env)
         if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
             !FIELD_EX64(env->msr, MSR, PR))) ||
             (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
-            if (books_vhyp_promotes_external_to_hvirt(cpu)) {
-                powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
-            } else {
-                powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
-            }
-            return;
+            return PPC_INTERRUPT_EXT;
         }
     }
     if (FIELD_EX64(env->msr, MSR, CE)) {
         /* External critical interrupt */
         if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
-            powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
-            return;
+            return PPC_INTERRUPT_CEXT;
         }
     }
     if (async_deliver != 0) {
         /* Watchdog timer on embedded PowerPC */
         if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
-            env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
-            powerpc_excp(cpu, POWERPC_EXCP_WDT);
-            return;
+            return PPC_INTERRUPT_WDT;
         }
         if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
-            env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
-            powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
-            return;
+            return PPC_INTERRUPT_CDOORBELL;
         }
         /* Fixed interval timer on embedded PowerPC */
         if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
-            env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
-            powerpc_excp(cpu, POWERPC_EXCP_FIT);
-            return;
+            return PPC_INTERRUPT_FIT;
         }
         /* Programmable interval timer on embedded PowerPC */
         if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
-            env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
-            powerpc_excp(cpu, POWERPC_EXCP_PIT);
-            return;
+            return PPC_INTERRUPT_PIT;
         }
         /* Decrementer exception */
         if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
-            if (ppc_decr_clear_on_delivery(env)) {
-                env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
-            }
-            powerpc_excp(cpu, POWERPC_EXCP_DECR);
-            return;
+            return PPC_INTERRUPT_DECR;
         }
         if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
-            env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
-            if (is_book3s_arch2x(env)) {
-                powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
-            } else {
-                powerpc_excp(cpu, POWERPC_EXCP_DOORI);
-            }
-            return;
+            return PPC_INTERRUPT_DOORBELL;
         }
         if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
-            env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
-            powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
-            return;
+            return PPC_INTERRUPT_HDOORBELL;
         }
         if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
-            env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
-            powerpc_excp(cpu, POWERPC_EXCP_PERFM);
-            return;
+            return PPC_INTERRUPT_PERFM;
         }
         /* Thermal interrupt */
         if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
-            env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
-            powerpc_excp(cpu, POWERPC_EXCP_THERM);
-            return;
+            return PPC_INTERRUPT_THERM;
         }
         /* EBB exception */
         if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
@@ -1822,20 +1782,106 @@ static void ppc_hw_interrupt(CPUPPCState *env)
              */
             if (FIELD_EX64(env->msr, MSR, PR) &&
                 (env->spr[SPR_BESCR] & BESCR_GE)) {
-                env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
-
-                if (env->spr[SPR_BESCR] & BESCR_PMEO) {
-                    powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
-                } else if (env->spr[SPR_BESCR] & BESCR_EEO) {
-                    powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB);
-                }
-
-                return;
+                return PPC_INTERRUPT_EBB;
             }
         }
     }
 
-    if (env->resume_as_sreset) {
+    return 0;
+}
+
+static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt)
+{
+    PowerPCCPU *cpu = env_archcpu(env);
+    CPUState *cs = env_cpu(env);
+
+    switch (interrupt) {
+    case PPC_INTERRUPT_RESET: /* External reset */
+        env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
+        powerpc_excp(cpu, POWERPC_EXCP_RESET);
+        break;
+    case PPC_INTERRUPT_MCK: /* Machine check exception */
+        env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
+        powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
+        break;
+#if 0 /* TODO */
+    case PPC_INTERRUPT_DEBUG: /* External debug exception */
+        env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
+        powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
+        break;
+#endif
+
+    case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */
+        /* HDEC clears on delivery */
+        env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
+        powerpc_excp(cpu, POWERPC_EXCP_HDECR);
+        break;
+    case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */
+        powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+        break;
+
+    case PPC_INTERRUPT_EXT:
+        if (books_vhyp_promotes_external_to_hvirt(cpu)) {
+            powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+        } else {
+            powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
+        }
+        break;
+    case PPC_INTERRUPT_CEXT: /* External critical interrupt */
+        powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
+        break;
+
+    case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
+        env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
+        powerpc_excp(cpu, POWERPC_EXCP_WDT);
+        break;
+    case PPC_INTERRUPT_CDOORBELL:
+        env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
+        powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
+        break;
+    case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
+        env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
+        powerpc_excp(cpu, POWERPC_EXCP_FIT);
+        break;
+    case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC */
+        env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
+        powerpc_excp(cpu, POWERPC_EXCP_PIT);
+        break;
+    case PPC_INTERRUPT_DECR: /* Decrementer exception */
+        if (ppc_decr_clear_on_delivery(env)) {
+            env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
+        }
+        powerpc_excp(cpu, POWERPC_EXCP_DECR);
+        break;
+    case PPC_INTERRUPT_DOORBELL:
+        env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
+        if (is_book3s_arch2x(env)) {
+            powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
+        } else {
+            powerpc_excp(cpu, POWERPC_EXCP_DOORI);
+        }
+        break;
+    case PPC_INTERRUPT_HDOORBELL:
+        env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
+        powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
+        break;
+    case PPC_INTERRUPT_PERFM:
+        env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
+        powerpc_excp(cpu, POWERPC_EXCP_PERFM);
+        break;
+    case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
+        env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
+        powerpc_excp(cpu, POWERPC_EXCP_THERM);
+        break;
+    case PPC_INTERRUPT_EBB: /* EBB exception */
+        env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
+        if (env->spr[SPR_BESCR] & BESCR_PMEO) {
+            powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
+        } else if (env->spr[SPR_BESCR] & BESCR_EEO) {
+            powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB);
+        }
+        break;
+    case 0:
         /*
          * This is a bug ! It means that has_work took us out of halt without
          * anything to deliver while in a PM state that requires getting
@@ -1847,8 +1893,10 @@ static void ppc_hw_interrupt(CPUPPCState *env)
          * It generally means a discrepancy between the wakeup conditions in the
          * processor has_work implementation and the logic in this function.
          */
-        cpu_abort(env_cpu(env),
-                  "Wakeup from PM state but interrupt Undelivered");
+        assert(env->resume_as_sreset != 0);
+        break;
+    default:
+        cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt);
     }
 }
 
@@ -1884,15 +1932,22 @@ bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
     CPUPPCState *env = &cpu->env;
+    int interrupt;
 
-    if (interrupt_request & CPU_INTERRUPT_HARD) {
-        ppc_hw_interrupt(env);
-        if (env->pending_interrupts == 0) {
-            cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
-        }
-        return true;
+    if ((interrupt_request & CPU_INTERRUPT_HARD) == 0) {
+        return false;
     }
-    return false;
+
+    interrupt = ppc_next_unmasked_interrupt(env);
+    if (interrupt == 0) {
+        return false;
+    }
+
+    ppc_deliver_interrupt(env, interrupt);
+    if (env->pending_interrupts == 0) {
+        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+    }
+    return true;
 }
 
 #endif /* !CONFIG_USER_ONLY */
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 04/29] target/ppc: prepare to split interrupt masking and delivery by excp_model
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (2 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 03/29] target/ppc: split interrupt masking and delivery from ppc_hw_interrupt Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 05/29] target/ppc: create an interrupt masking method for POWER9/POWER10 Matheus Ferst
                   ` (25 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

No functional change intended.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
v2:
  - Use "generic" instead of "legacy" to name the original methods (farosas).
---
 target/ppc/excp_helper.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index c6381489b6..6da4dba616 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1678,7 +1678,7 @@ void ppc_cpu_do_interrupt(CPUState *cs)
     powerpc_excp(cpu, cs->exception_index);
 }
 
-static int ppc_next_unmasked_interrupt(CPUPPCState *env)
+static int ppc_next_unmasked_interrupt_generic(CPUPPCState *env)
 {
     bool async_deliver;
 
@@ -1790,7 +1790,15 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
     return 0;
 }
 
-static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt)
+static int ppc_next_unmasked_interrupt(CPUPPCState *env)
+{
+    switch (env->excp_model) {
+    default:
+        return ppc_next_unmasked_interrupt_generic(env);
+    }
+}
+
+static void ppc_deliver_interrupt_generic(CPUPPCState *env, int interrupt)
 {
     PowerPCCPU *cpu = env_archcpu(env);
     CPUState *cs = env_cpu(env);
@@ -1900,6 +1908,14 @@ static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt)
     }
 }
 
+static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt)
+{
+    switch (env->excp_model) {
+    default:
+        ppc_deliver_interrupt_generic(env, interrupt);
+    }
+}
+
 void ppc_cpu_do_system_reset(CPUState *cs)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 05/29] target/ppc: create an interrupt masking method for POWER9/POWER10
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (3 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 04/29] target/ppc: prepare to split interrupt masking and delivery by excp_model Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 06/29] target/ppc: remove unused interrupts from p9_pending_interrupt Matheus Ferst
                   ` (24 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

The new method is identical to ppc_next_unmasked_interrupt_generic,
processor-specific code will be added/removed in the following patches.
No functional change intended.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
v2:
  - Renamed the method from ppc_pending_interrupt_p9 to
    p9_next_unmasked_interrupt
  - Processor-specific stuff were moved to the following patches to ease
    review.
---
 target/ppc/excp_helper.c | 119 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 6da4dba616..f2b0845735 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1678,6 +1678,120 @@ void ppc_cpu_do_interrupt(CPUState *cs)
     powerpc_excp(cpu, cs->exception_index);
 }
 
+#if defined(TARGET_PPC64)
+static int p9_next_unmasked_interrupt(CPUPPCState *env)
+{
+    bool async_deliver;
+
+    /* External reset */
+    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+        return PPC_INTERRUPT_RESET;
+    }
+    /* Machine check exception */
+    if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+        return PPC_INTERRUPT_MCK;
+    }
+#if 0 /* TODO */
+    /* External debug exception */
+    if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
+        return PPC_INTERRUPT_DEBUG;
+    }
+#endif
+
+    /*
+     * For interrupts that gate on MSR:EE, we need to do something a
+     * bit more subtle, as we need to let them through even when EE is
+     * clear when coming out of some power management states (in order
+     * for them to become a 0x100).
+     */
+    async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
+
+    /* Hypervisor decrementer exception */
+    if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
+        /* LPCR will be clear when not supported so this will work */
+        bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
+        if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+            /* HDEC clears on delivery */
+            return PPC_INTERRUPT_HDECR;
+        }
+    }
+
+    /* Hypervisor virtualization interrupt */
+    if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
+        /* LPCR will be clear when not supported so this will work */
+        bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
+        if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
+            return PPC_INTERRUPT_HVIRT;
+        }
+    }
+
+    /* External interrupt can ignore MSR:EE under some circumstances */
+    if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
+        bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
+        bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+        /* HEIC blocks delivery to the hypervisor */
+        if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+            !FIELD_EX64(env->msr, MSR, PR))) ||
+            (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
+            return PPC_INTERRUPT_EXT;
+        }
+    }
+    if (FIELD_EX64(env->msr, MSR, CE)) {
+        /* External critical interrupt */
+        if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
+            return PPC_INTERRUPT_CEXT;
+        }
+    }
+    if (async_deliver != 0) {
+        /* Watchdog timer on embedded PowerPC */
+        if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
+            return PPC_INTERRUPT_WDT;
+        }
+        if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
+            return PPC_INTERRUPT_CDOORBELL;
+        }
+        /* Fixed interval timer on embedded PowerPC */
+        if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
+            return PPC_INTERRUPT_FIT;
+        }
+        /* Programmable interval timer on embedded PowerPC */
+        if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
+            return PPC_INTERRUPT_PIT;
+        }
+        /* Decrementer exception */
+        if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
+            return PPC_INTERRUPT_DECR;
+        }
+        if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
+            return PPC_INTERRUPT_DOORBELL;
+        }
+        if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
+            return PPC_INTERRUPT_HDOORBELL;
+        }
+        if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
+            return PPC_INTERRUPT_PERFM;
+        }
+        /* Thermal interrupt */
+        if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
+            return PPC_INTERRUPT_THERM;
+        }
+        /* EBB exception */
+        if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
+            /*
+             * EBB exception must be taken in problem state and
+             * with BESCR_GE set.
+             */
+            if (FIELD_EX64(env->msr, MSR, PR) &&
+                (env->spr[SPR_BESCR] & BESCR_GE)) {
+                return PPC_INTERRUPT_EBB;
+            }
+        }
+    }
+
+    return 0;
+}
+#endif
+
 static int ppc_next_unmasked_interrupt_generic(CPUPPCState *env)
 {
     bool async_deliver;
@@ -1793,6 +1907,11 @@ static int ppc_next_unmasked_interrupt_generic(CPUPPCState *env)
 static int ppc_next_unmasked_interrupt(CPUPPCState *env)
 {
     switch (env->excp_model) {
+#if defined(TARGET_PPC64)
+    case POWERPC_EXCP_POWER9:
+    case POWERPC_EXCP_POWER10:
+        return p9_next_unmasked_interrupt(env);
+#endif
     default:
         return ppc_next_unmasked_interrupt_generic(env);
     }
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 06/29] target/ppc: remove unused interrupts from p9_pending_interrupt
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (4 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 05/29] target/ppc: create an interrupt masking method for POWER9/POWER10 Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 07/29] target/ppc: create an interrupt delivery method for POWER9/POWER10 Matheus Ferst
                   ` (23 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

Remove the following unused interrupts from the POWER9 interrupt masking
method:
- PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970, and POWER5p;
- Debug Interrupt: removed in Power ISA v2.07;
- Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
  for embedded CPUs;
- Critical Doorbell Interrupt: removed in Power ISA v3.0;
- Programmable Interval Timer: 40x-only.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
v2:
  - Remove CDOORBELL and THERM (farosas);
  - Also remove RESET and DEBUG, interrupts;
  - Assert for the removed interrupts.
---
 target/ppc/excp_helper.c | 42 +++++++---------------------------------
 1 file changed, 7 insertions(+), 35 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index f2b0845735..af2cab01a7 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1679,24 +1679,21 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 }
 
 #if defined(TARGET_PPC64)
+#define P9_UNUSED_INTERRUPTS \
+    (PPC_INTERRUPT_RESET | PPC_INTERRUPT_DEBUG | PPC_INTERRUPT_CEXT |   \
+     PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | PPC_INTERRUPT_FIT |  \
+     PPC_INTERRUPT_PIT | PPC_INTERRUPT_THERM)
+
 static int p9_next_unmasked_interrupt(CPUPPCState *env)
 {
     bool async_deliver;
 
-    /* External reset */
-    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-        return PPC_INTERRUPT_RESET;
-    }
+    assert((env->pending_interrupts & P9_UNUSED_INTERRUPTS) == 0);
+
     /* Machine check exception */
     if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
         return PPC_INTERRUPT_MCK;
     }
-#if 0 /* TODO */
-    /* External debug exception */
-    if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
-        return PPC_INTERRUPT_DEBUG;
-    }
-#endif
 
     /*
      * For interrupts that gate on MSR:EE, we need to do something a
@@ -1736,28 +1733,7 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
             return PPC_INTERRUPT_EXT;
         }
     }
-    if (FIELD_EX64(env->msr, MSR, CE)) {
-        /* External critical interrupt */
-        if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
-            return PPC_INTERRUPT_CEXT;
-        }
-    }
     if (async_deliver != 0) {
-        /* Watchdog timer on embedded PowerPC */
-        if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
-            return PPC_INTERRUPT_WDT;
-        }
-        if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
-            return PPC_INTERRUPT_CDOORBELL;
-        }
-        /* Fixed interval timer on embedded PowerPC */
-        if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
-            return PPC_INTERRUPT_FIT;
-        }
-        /* Programmable interval timer on embedded PowerPC */
-        if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
-            return PPC_INTERRUPT_PIT;
-        }
         /* Decrementer exception */
         if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
             return PPC_INTERRUPT_DECR;
@@ -1771,10 +1747,6 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
         if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
             return PPC_INTERRUPT_PERFM;
         }
-        /* Thermal interrupt */
-        if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
-            return PPC_INTERRUPT_THERM;
-        }
         /* EBB exception */
         if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
             /*
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 07/29] target/ppc: create an interrupt delivery method for POWER9/POWER10
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (5 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 06/29] target/ppc: remove unused interrupts from p9_pending_interrupt Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 08/29] target/ppc: remove unused interrupts from p9_deliver_interrupt Matheus Ferst
                   ` (22 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

The new method is identical to ppc_deliver_interrupt, processor-specific
code will be added/removed in the following patches. No functional
change intended.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
 target/ppc/excp_helper.c | 118 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 118 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index af2cab01a7..8a32acbc7f 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1889,6 +1889,118 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
     }
 }
 
+#if defined(TARGET_PPC64)
+static void p9_deliver_interrupt(CPUPPCState *env, int interrupt)
+{
+    PowerPCCPU *cpu = env_archcpu(env);
+    CPUState *cs = env_cpu(env);
+
+    switch (interrupt) {
+    case PPC_INTERRUPT_RESET: /* External reset */
+        env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
+        powerpc_excp(cpu, POWERPC_EXCP_RESET);
+        break;
+    case PPC_INTERRUPT_MCK: /* Machine check exception */
+        env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
+        powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
+        break;
+#if 0 /* TODO */
+    case PPC_INTERRUPT_DEBUG: /* External debug exception */
+        env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
+        powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
+        break;
+#endif
+
+    case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */
+        /* HDEC clears on delivery */
+        env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
+        powerpc_excp(cpu, POWERPC_EXCP_HDECR);
+        break;
+    case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */
+        powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+        break;
+
+    case PPC_INTERRUPT_EXT:
+        if (books_vhyp_promotes_external_to_hvirt(cpu)) {
+            powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+        } else {
+            powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
+        }
+        break;
+    case PPC_INTERRUPT_CEXT: /* External critical interrupt */
+        powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
+        break;
+
+    case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
+        env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
+        powerpc_excp(cpu, POWERPC_EXCP_WDT);
+        break;
+    case PPC_INTERRUPT_CDOORBELL:
+        env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
+        powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
+        break;
+    case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
+        env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
+        powerpc_excp(cpu, POWERPC_EXCP_FIT);
+        break;
+    case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC */
+        env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
+        powerpc_excp(cpu, POWERPC_EXCP_PIT);
+        break;
+    case PPC_INTERRUPT_DECR: /* Decrementer exception */
+        if (ppc_decr_clear_on_delivery(env)) {
+            env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
+        }
+        powerpc_excp(cpu, POWERPC_EXCP_DECR);
+        break;
+    case PPC_INTERRUPT_DOORBELL:
+        env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
+        if (is_book3s_arch2x(env)) {
+            powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
+        } else {
+            powerpc_excp(cpu, POWERPC_EXCP_DOORI);
+        }
+        break;
+    case PPC_INTERRUPT_HDOORBELL:
+        env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
+        powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
+        break;
+    case PPC_INTERRUPT_PERFM:
+        env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
+        powerpc_excp(cpu, POWERPC_EXCP_PERFM);
+        break;
+    case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
+        env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
+        powerpc_excp(cpu, POWERPC_EXCP_THERM);
+        break;
+    case PPC_INTERRUPT_EBB: /* EBB exception */
+        env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
+        if (env->spr[SPR_BESCR] & BESCR_PMEO) {
+            powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
+        } else if (env->spr[SPR_BESCR] & BESCR_EEO) {
+            powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB);
+        }
+        break;
+    case 0:
+        /*
+         * This is a bug ! It means that has_work took us out of halt without
+         * anything to deliver while in a PM state that requires getting
+         * out via a 0x100
+         *
+         * This means we will incorrectly execute past the power management
+         * instruction instead of triggering a reset.
+         *
+         * It generally means a discrepancy between the wakeup conditions in the
+         * processor has_work implementation and the logic in this function.
+         */
+        assert(env->resume_as_sreset != 0);
+        break;
+    default:
+        cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt);
+    }
+}
+#endif
+
 static void ppc_deliver_interrupt_generic(CPUPPCState *env, int interrupt)
 {
     PowerPCCPU *cpu = env_archcpu(env);
@@ -2002,6 +2114,12 @@ static void ppc_deliver_interrupt_generic(CPUPPCState *env, int interrupt)
 static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt)
 {
     switch (env->excp_model) {
+#if defined(TARGET_PPC64)
+    case POWERPC_EXCP_POWER9:
+    case POWERPC_EXCP_POWER10:
+        p9_deliver_interrupt(env, interrupt);
+        break;
+#endif
     default:
         ppc_deliver_interrupt_generic(env, interrupt);
     }
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 08/29] target/ppc: remove unused interrupts from p9_deliver_interrupt
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (6 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 07/29] target/ppc: create an interrupt delivery method for POWER9/POWER10 Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 09/29] target/ppc: remove generic architecture checks " Matheus Ferst
                   ` (21 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

Remove the following unused interrupts from the POWER9 interrupt
processing method:
- PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970 and POWER5p;
- Debug Interrupt: removed in Power ISA v2.07;
- Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
  for embedded CPUs;
- Critical Doorbell Interrupt: removed in Power ISA v3.0;
- Programmable Interval Timer: 40x-only.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
 target/ppc/excp_helper.c | 33 ---------------------------------
 1 file changed, 33 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 8a32acbc7f..603c956588 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1896,20 +1896,10 @@ static void p9_deliver_interrupt(CPUPPCState *env, int interrupt)
     CPUState *cs = env_cpu(env);
 
     switch (interrupt) {
-    case PPC_INTERRUPT_RESET: /* External reset */
-        env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
-        powerpc_excp(cpu, POWERPC_EXCP_RESET);
-        break;
     case PPC_INTERRUPT_MCK: /* Machine check exception */
         env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
         powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
         break;
-#if 0 /* TODO */
-    case PPC_INTERRUPT_DEBUG: /* External debug exception */
-        env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
-        powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
-        break;
-#endif
 
     case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */
         /* HDEC clears on delivery */
@@ -1927,26 +1917,7 @@ static void p9_deliver_interrupt(CPUPPCState *env, int interrupt)
             powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
         }
         break;
-    case PPC_INTERRUPT_CEXT: /* External critical interrupt */
-        powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
-        break;
 
-    case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
-        env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
-        powerpc_excp(cpu, POWERPC_EXCP_WDT);
-        break;
-    case PPC_INTERRUPT_CDOORBELL:
-        env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
-        powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
-        break;
-    case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
-        env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
-        powerpc_excp(cpu, POWERPC_EXCP_FIT);
-        break;
-    case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC */
-        env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
-        powerpc_excp(cpu, POWERPC_EXCP_PIT);
-        break;
     case PPC_INTERRUPT_DECR: /* Decrementer exception */
         if (ppc_decr_clear_on_delivery(env)) {
             env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
@@ -1969,10 +1940,6 @@ static void p9_deliver_interrupt(CPUPPCState *env, int interrupt)
         env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
         powerpc_excp(cpu, POWERPC_EXCP_PERFM);
         break;
-    case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
-        env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
-        powerpc_excp(cpu, POWERPC_EXCP_THERM);
-        break;
     case PPC_INTERRUPT_EBB: /* EBB exception */
         env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
         if (env->spr[SPR_BESCR] & BESCR_PMEO) {
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 09/29] target/ppc: remove generic architecture checks from p9_deliver_interrupt
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (7 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 08/29] target/ppc: remove unused interrupts from p9_deliver_interrupt Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-30 18:13   ` Fabiano Rosas
  2022-09-27 20:15 ` [RFC PATCH v2 10/29] target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER9 Matheus Ferst
                   ` (20 subsequent siblings)
  29 siblings, 1 reply; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

No functional change intended.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
 target/ppc/excp_helper.c | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 603c956588..67e73f30ab 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1919,18 +1919,11 @@ static void p9_deliver_interrupt(CPUPPCState *env, int interrupt)
         break;
 
     case PPC_INTERRUPT_DECR: /* Decrementer exception */
-        if (ppc_decr_clear_on_delivery(env)) {
-            env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
-        }
         powerpc_excp(cpu, POWERPC_EXCP_DECR);
         break;
     case PPC_INTERRUPT_DOORBELL:
         env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
-        if (is_book3s_arch2x(env)) {
-            powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
-        } else {
-            powerpc_excp(cpu, POWERPC_EXCP_DOORI);
-        }
+        powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
         break;
     case PPC_INTERRUPT_HDOORBELL:
         env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 10/29] target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER9
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (8 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 09/29] target/ppc: remove generic architecture checks " Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 11/29] target/ppc: add power-saving interrupt masking logic to p9_next_unmasked_interrupt Matheus Ferst
                   ` (19 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

Move the interrupt masking logic out of cpu_has_work_POWER9 in a new
method, p9_interrupt_powersave, that only returns an interrupt if it can
wake the processor from power-saving mode. No functional change
intended.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
 target/ppc/cpu_init.c | 126 +++++++++++++++++-------------------------
 1 file changed, 50 insertions(+), 76 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 4b4b3feac9..1f8f6c6ef2 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6351,6 +6351,52 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
     return false;
 }
 
+static int p9_interrupt_powersave(CPUPPCState *env)
+{
+    /* External Exception */
+    if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
+        (env->spr[SPR_LPCR] & LPCR_EEE)) {
+        bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+        if (!heic || !FIELD_EX64_HV(env->msr) ||
+            FIELD_EX64(env->msr, MSR, PR)) {
+            return PPC_INTERRUPT_EXT;
+        }
+    }
+    /* Decrementer Exception */
+    if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
+        (env->spr[SPR_LPCR] & LPCR_DEE)) {
+        return PPC_INTERRUPT_DECR;
+    }
+    /* Machine Check or Hypervisor Maintenance Exception */
+    if (env->spr[SPR_LPCR] & LPCR_OEE) {
+        if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+            return PPC_INTERRUPT_MCK;
+        }
+        if (env->pending_interrupts & PPC_INTERRUPT_HMI) {
+            return PPC_INTERRUPT_HMI;
+        }
+    }
+    /* Privileged Doorbell Exception */
+    if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
+        (env->spr[SPR_LPCR] & LPCR_PDEE)) {
+        return PPC_INTERRUPT_DOORBELL;
+    }
+    /* Hypervisor Doorbell Exception */
+    if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
+        (env->spr[SPR_LPCR] & LPCR_HDEE)) {
+        return PPC_INTERRUPT_HDOORBELL;
+    }
+    /* Hypervisor virtualization exception */
+    if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) &&
+        (env->spr[SPR_LPCR] & LPCR_HVEE)) {
+        return PPC_INTERRUPT_HVIRT;
+    }
+    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+        return PPC_INTERRUPT_RESET;
+    }
+    return 0;
+}
+
 static bool cpu_has_work_POWER9(CPUState *cs)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -6367,44 +6413,8 @@ static bool cpu_has_work_POWER9(CPUState *cs)
         if (!(psscr & PSSCR_EC)) {
             return true;
         }
-        /* External Exception */
-        if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-            (env->spr[SPR_LPCR] & LPCR_EEE)) {
-            bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
-            if (!heic || !FIELD_EX64_HV(env->msr) ||
-                FIELD_EX64(env->msr, MSR, PR)) {
-                return true;
-            }
-        }
-        /* Decrementer Exception */
-        if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-            (env->spr[SPR_LPCR] & LPCR_DEE)) {
-            return true;
-        }
-        /* Machine Check or Hypervisor Maintenance Exception */
-        if ((env->pending_interrupts & (PPC_INTERRUPT_MCK | PPC_INTERRUPT_HMI))
-            && (env->spr[SPR_LPCR] & LPCR_OEE)) {
-            return true;
-        }
-        /* Privileged Doorbell Exception */
-        if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
-            (env->spr[SPR_LPCR] & LPCR_PDEE)) {
-            return true;
-        }
-        /* Hypervisor Doorbell Exception */
-        if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
-            (env->spr[SPR_LPCR] & LPCR_HDEE)) {
-            return true;
-        }
-        /* Hypervisor virtualization exception */
-        if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) &&
-            (env->spr[SPR_LPCR] & LPCR_HVEE)) {
-            return true;
-        }
-        if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-            return true;
-        }
-        return false;
+
+        return p9_interrupt_powersave(env) != 0;
     } else {
         return FIELD_EX64(env->msr, MSR, EE) &&
                (cs->interrupt_request & CPU_INTERRUPT_HARD);
@@ -6600,44 +6610,8 @@ static bool cpu_has_work_POWER10(CPUState *cs)
         if (!(psscr & PSSCR_EC)) {
             return true;
         }
-        /* External Exception */
-        if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-            (env->spr[SPR_LPCR] & LPCR_EEE)) {
-            bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
-            if (!heic || !FIELD_EX64_HV(env->msr) ||
-                FIELD_EX64(env->msr, MSR, PR)) {
-                return true;
-            }
-        }
-        /* Decrementer Exception */
-        if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-            (env->spr[SPR_LPCR] & LPCR_DEE)) {
-            return true;
-        }
-        /* Machine Check or Hypervisor Maintenance Exception */
-        if ((env->pending_interrupts & (PPC_INTERRUPT_MCK | PPC_INTERRUPT_HMI))
-            && (env->spr[SPR_LPCR] & LPCR_OEE)) {
-            return true;
-        }
-        /* Privileged Doorbell Exception */
-        if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
-            (env->spr[SPR_LPCR] & LPCR_PDEE)) {
-            return true;
-        }
-        /* Hypervisor Doorbell Exception */
-        if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
-            (env->spr[SPR_LPCR] & LPCR_HDEE)) {
-            return true;
-        }
-        /* Hypervisor virtualization exception */
-        if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) &&
-            (env->spr[SPR_LPCR] & LPCR_HVEE)) {
-            return true;
-        }
-        if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-            return true;
-        }
-        return false;
+
+        return p9_interrupt_powersave(env) != 0;
     } else {
         return FIELD_EX64(env->msr, MSR, EE) &&
                (cs->interrupt_request & CPU_INTERRUPT_HARD);
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 11/29] target/ppc: add power-saving interrupt masking logic to p9_next_unmasked_interrupt
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (9 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 10/29] target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER9 Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-30 18:38   ` Fabiano Rosas
  2022-09-27 20:15 ` [RFC PATCH v2 12/29] target/ppc: create an interrupt masking method for POWER8 Matheus Ferst
                   ` (18 subsequent siblings)
  29 siblings, 1 reply; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

Export p9_interrupt_powersave and use it in p9_next_unmasked_interrupt.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
Temporarily putting the prototype in internal.h for lack of a better place,
we will un-export p9_interrupt_powersave in future patches.
---
 target/ppc/cpu_init.c    |  2 +-
 target/ppc/excp_helper.c | 46 ++++++++++++++++++++++++++++------------
 target/ppc/internal.h    |  4 ++++
 3 files changed, 38 insertions(+), 14 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 1f8f6c6ef2..7889158c52 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6351,7 +6351,7 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
     return false;
 }
 
-static int p9_interrupt_powersave(CPUPPCState *env)
+int p9_interrupt_powersave(CPUPPCState *env)
 {
     /* External Exception */
     if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 67e73f30ab..5a0d2c11a2 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1686,28 +1686,39 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 
 static int p9_next_unmasked_interrupt(CPUPPCState *env)
 {
-    bool async_deliver;
+    PowerPCCPU *cpu = env_archcpu(env);
+    CPUState *cs = CPU(cpu);
+    /* Ignore MSR[EE] when coming out of some power management states */
+    bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
 
     assert((env->pending_interrupts & P9_UNUSED_INTERRUPTS) == 0);
 
+    if (cs->halted) {
+        if (env->spr[SPR_PSSCR] & PSSCR_EC) {
+            /*
+             * When PSSCR[EC] is set, LPCR[PECE] controls which interrupts can
+             * wakeup the processor
+             */
+            return p9_interrupt_powersave(env);
+        } else {
+            /*
+             * When it's clear, any system-caused exception exits power-saving
+             * mode, even the ones that gate on MSR[EE].
+             */
+            msr_ee = true;
+        }
+    }
+
     /* Machine check exception */
     if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
         return PPC_INTERRUPT_MCK;
     }
 
-    /*
-     * For interrupts that gate on MSR:EE, we need to do something a
-     * bit more subtle, as we need to let them through even when EE is
-     * clear when coming out of some power management states (in order
-     * for them to become a 0x100).
-     */
-    async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
-
     /* Hypervisor decrementer exception */
     if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
         /* LPCR will be clear when not supported so this will work */
         bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
-        if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+        if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) {
             /* HDEC clears on delivery */
             return PPC_INTERRUPT_HDECR;
         }
@@ -1717,7 +1728,7 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
     if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
         /* LPCR will be clear when not supported so this will work */
         bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
-        if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
+        if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hvice) {
             return PPC_INTERRUPT_HVIRT;
         }
     }
@@ -1727,13 +1738,13 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
         bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
         bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
         /* HEIC blocks delivery to the hypervisor */
-        if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+        if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) &&
             !FIELD_EX64(env->msr, MSR, PR))) ||
             (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
             return PPC_INTERRUPT_EXT;
         }
     }
-    if (async_deliver != 0) {
+    if (msr_ee != 0) {
         /* Decrementer exception */
         if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
             return PPC_INTERRUPT_DECR;
@@ -1895,6 +1906,15 @@ static void p9_deliver_interrupt(CPUPPCState *env, int interrupt)
     PowerPCCPU *cpu = env_archcpu(env);
     CPUState *cs = env_cpu(env);
 
+    if (cs->halted && !(env->spr[SPR_PSSCR] & PSSCR_EC) &&
+        !FIELD_EX64(env->msr, MSR, EE)) {
+        /*
+         * A pending interrupt took us out of power-saving, but MSR[EE] says
+         * that we should return to NIP+4 instead of delivering it.
+         */
+        return;
+    }
+
     switch (interrupt) {
     case PPC_INTERRUPT_MCK: /* Machine check exception */
         env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index 337a362205..41e79adfdb 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -306,4 +306,8 @@ static inline int ger_pack_masks(int pmsk, int ymsk, int xmsk)
     return msk;
 }
 
+#if defined(TARGET_PPC64)
+int p9_interrupt_powersave(CPUPPCState *env);
+#endif
+
 #endif /* PPC_INTERNAL_H */
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 12/29] target/ppc: create an interrupt masking method for POWER8
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (10 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 11/29] target/ppc: add power-saving interrupt masking logic to p9_next_unmasked_interrupt Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 13/29] target/ppc: remove unused interrupts from p8_pending_interrupt Matheus Ferst
                   ` (17 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

The new method is identical to ppc_next_unmasked_interrupt_generic,
processor-specific code will be added/removed in the following patches.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
v2:
  - Renamed the method from ppc_pending_interrupt_p8 to
    p8_next_unmasked_interrupt
  - Processor-specific stuff were moved to the following patches to ease
    review.
---
 target/ppc/excp_helper.c | 114 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 114 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 5a0d2c11a2..f60d9826d8 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1679,6 +1679,118 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 }
 
 #if defined(TARGET_PPC64)
+static int p8_next_unmasked_interrupt(CPUPPCState *env)
+{
+    bool async_deliver;
+
+    /* External reset */
+    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+        return PPC_INTERRUPT_RESET;
+    }
+    /* Machine check exception */
+    if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+        return PPC_INTERRUPT_MCK;
+    }
+#if 0 /* TODO */
+    /* External debug exception */
+    if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
+        return PPC_INTERRUPT_DEBUG;
+    }
+#endif
+
+    /*
+     * For interrupts that gate on MSR:EE, we need to do something a
+     * bit more subtle, as we need to let them through even when EE is
+     * clear when coming out of some power management states (in order
+     * for them to become a 0x100).
+     */
+    async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
+
+    /* Hypervisor decrementer exception */
+    if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
+        /* LPCR will be clear when not supported so this will work */
+        bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
+        if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+            /* HDEC clears on delivery */
+            return PPC_INTERRUPT_HDECR;
+        }
+    }
+
+    /* Hypervisor virtualization interrupt */
+    if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
+        /* LPCR will be clear when not supported so this will work */
+        bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
+        if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
+            return PPC_INTERRUPT_HVIRT;
+        }
+    }
+
+    /* External interrupt can ignore MSR:EE under some circumstances */
+    if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
+        bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
+        bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+        /* HEIC blocks delivery to the hypervisor */
+        if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+            !FIELD_EX64(env->msr, MSR, PR))) ||
+            (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
+            return PPC_INTERRUPT_EXT;
+        }
+    }
+    if (FIELD_EX64(env->msr, MSR, CE)) {
+        /* External critical interrupt */
+        if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
+            return PPC_INTERRUPT_CEXT;
+        }
+    }
+    if (async_deliver != 0) {
+        /* Watchdog timer on embedded PowerPC */
+        if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
+            return PPC_INTERRUPT_WDT;
+        }
+        if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
+            return PPC_INTERRUPT_CDOORBELL;
+        }
+        /* Fixed interval timer on embedded PowerPC */
+        if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
+            return PPC_INTERRUPT_FIT;
+        }
+        /* Programmable interval timer on embedded PowerPC */
+        if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
+            return PPC_INTERRUPT_PIT;
+        }
+        /* Decrementer exception */
+        if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
+            return PPC_INTERRUPT_DECR;
+        }
+        if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
+            return PPC_INTERRUPT_DOORBELL;
+        }
+        if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
+            return PPC_INTERRUPT_HDOORBELL;
+        }
+        if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
+            return PPC_INTERRUPT_PERFM;
+        }
+        /* Thermal interrupt */
+        if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
+            return PPC_INTERRUPT_THERM;
+        }
+        /* EBB exception */
+        if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
+            /*
+             * EBB exception must be taken in problem state and
+             * with BESCR_GE set.
+             */
+            if (FIELD_EX64(env->msr, MSR, PR) &&
+                (env->spr[SPR_BESCR] & BESCR_GE)) {
+                return PPC_INTERRUPT_EBB;
+            }
+        }
+    }
+
+    return 0;
+}
+
 #define P9_UNUSED_INTERRUPTS \
     (PPC_INTERRUPT_RESET | PPC_INTERRUPT_DEBUG | PPC_INTERRUPT_CEXT |   \
      PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | PPC_INTERRUPT_FIT |  \
@@ -1891,6 +2003,8 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
 {
     switch (env->excp_model) {
 #if defined(TARGET_PPC64)
+    case POWERPC_EXCP_POWER8:
+        return p8_next_unmasked_interrupt(env);
     case POWERPC_EXCP_POWER9:
     case POWERPC_EXCP_POWER10:
         return p9_next_unmasked_interrupt(env);
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 13/29] target/ppc: remove unused interrupts from p8_pending_interrupt
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (11 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 12/29] target/ppc: create an interrupt masking method for POWER8 Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 22:14   ` Fabiano Rosas
  2022-09-27 20:15 ` [RFC PATCH v2 14/29] target/ppc: create an interrupt delivery method for POWER8 Matheus Ferst
                   ` (16 subsequent siblings)
  29 siblings, 1 reply; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

Remove the following unused interrupts from the POWER8 interrupt masking
method:
- PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970, and POWER5p;
- Debug Interrupt: removed in Power ISA v2.07;
- Hypervisor Virtualization: introduced in Power ISA v3.0;
- Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
  for embedded CPUs;
- Hypervisor Doorbell, Doorbell, and Critical Doorbell: processor does
  not implement the "Embedded.Processor Control" category;
- Programmable Interval Timer: 40x-only;
- PPC_INTERRUPT_THERM: only raised for 970 and POWER5p;

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
v2:
  - Remove CDOORBELL and THERM interrupts (farosas);
  - Also remove RESET, DEBUG, DOORBELL, and HDOORBELL interrupts;
  - Assert for the removed interrupts.
---
 target/ppc/excp_helper.c | 58 ++++++----------------------------------
 1 file changed, 8 insertions(+), 50 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index f60d9826d8..6ab03b2e12 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1679,24 +1679,22 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 }
 
 #if defined(TARGET_PPC64)
+#define P8_UNUSED_INTERRUPTS \
+    (PPC_INTERRUPT_RESET | PPC_INTERRUPT_DEBUG | PPC_INTERRUPT_HVIRT |  \
+    PPC_INTERRUPT_CEXT | PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL |  \
+    PPC_INTERRUPT_FIT | PPC_INTERRUPT_PIT | PPC_INTERRUPT_DOORBELL |    \
+    PPC_INTERRUPT_HDOORBELL | PPC_INTERRUPT_THERM)
+
 static int p8_next_unmasked_interrupt(CPUPPCState *env)
 {
     bool async_deliver;
 
-    /* External reset */
-    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-        return PPC_INTERRUPT_RESET;
-    }
+    assert((env->pending_interrupts & P8_UNUSED_INTERRUPTS) == 0);
+
     /* Machine check exception */
     if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
         return PPC_INTERRUPT_MCK;
     }
-#if 0 /* TODO */
-    /* External debug exception */
-    if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
-        return PPC_INTERRUPT_DEBUG;
-    }
-#endif
 
     /*
      * For interrupts that gate on MSR:EE, we need to do something a
@@ -1716,15 +1714,6 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env)
         }
     }
 
-    /* Hypervisor virtualization interrupt */
-    if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
-        /* LPCR will be clear when not supported so this will work */
-        bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
-        if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
-            return PPC_INTERRUPT_HVIRT;
-        }
-    }
-
     /* External interrupt can ignore MSR:EE under some circumstances */
     if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
         bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
@@ -1736,45 +1725,14 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env)
             return PPC_INTERRUPT_EXT;
         }
     }
-    if (FIELD_EX64(env->msr, MSR, CE)) {
-        /* External critical interrupt */
-        if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
-            return PPC_INTERRUPT_CEXT;
-        }
-    }
     if (async_deliver != 0) {
-        /* Watchdog timer on embedded PowerPC */
-        if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
-            return PPC_INTERRUPT_WDT;
-        }
-        if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
-            return PPC_INTERRUPT_CDOORBELL;
-        }
-        /* Fixed interval timer on embedded PowerPC */
-        if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
-            return PPC_INTERRUPT_FIT;
-        }
-        /* Programmable interval timer on embedded PowerPC */
-        if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
-            return PPC_INTERRUPT_PIT;
-        }
         /* Decrementer exception */
         if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
             return PPC_INTERRUPT_DECR;
         }
-        if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
-            return PPC_INTERRUPT_DOORBELL;
-        }
-        if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
-            return PPC_INTERRUPT_HDOORBELL;
-        }
         if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
             return PPC_INTERRUPT_PERFM;
         }
-        /* Thermal interrupt */
-        if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
-            return PPC_INTERRUPT_THERM;
-        }
         /* EBB exception */
         if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
             /*
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 14/29] target/ppc: create an interrupt delivery method for POWER8
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (12 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 13/29] target/ppc: remove unused interrupts from p8_pending_interrupt Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 15/29] target/ppc: remove unused interrupts from p8_deliver_interrupt Matheus Ferst
                   ` (15 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

The new method is identical to ppc_deliver_interrupt, processor-specific
code will be added/removed in the following patches. No functional
change intended.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
 target/ppc/excp_helper.c | 113 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 6ab03b2e12..0405fc8eee 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1973,6 +1973,116 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
 }
 
 #if defined(TARGET_PPC64)
+static void p8_deliver_interrupt(CPUPPCState *env, int interrupt)
+{
+    PowerPCCPU *cpu = env_archcpu(env);
+    CPUState *cs = env_cpu(env);
+
+    switch (interrupt) {
+    case PPC_INTERRUPT_RESET: /* External reset */
+        env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
+        powerpc_excp(cpu, POWERPC_EXCP_RESET);
+        break;
+    case PPC_INTERRUPT_MCK: /* Machine check exception */
+        env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
+        powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
+        break;
+#if 0 /* TODO */
+    case PPC_INTERRUPT_DEBUG: /* External debug exception */
+        env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
+        powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
+        break;
+#endif
+
+    case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */
+        /* HDEC clears on delivery */
+        env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
+        powerpc_excp(cpu, POWERPC_EXCP_HDECR);
+        break;
+    case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */
+        powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+        break;
+
+    case PPC_INTERRUPT_EXT:
+        if (books_vhyp_promotes_external_to_hvirt(cpu)) {
+            powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+        } else {
+            powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
+        }
+        break;
+    case PPC_INTERRUPT_CEXT: /* External critical interrupt */
+        powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
+        break;
+
+    case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
+        env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
+        powerpc_excp(cpu, POWERPC_EXCP_WDT);
+        break;
+    case PPC_INTERRUPT_CDOORBELL:
+        env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
+        powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
+        break;
+    case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
+        env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
+        powerpc_excp(cpu, POWERPC_EXCP_FIT);
+        break;
+    case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC */
+        env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
+        powerpc_excp(cpu, POWERPC_EXCP_PIT);
+        break;
+    case PPC_INTERRUPT_DECR: /* Decrementer exception */
+        if (ppc_decr_clear_on_delivery(env)) {
+            env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
+        }
+        powerpc_excp(cpu, POWERPC_EXCP_DECR);
+        break;
+    case PPC_INTERRUPT_DOORBELL:
+        env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
+        if (is_book3s_arch2x(env)) {
+            powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
+        } else {
+            powerpc_excp(cpu, POWERPC_EXCP_DOORI);
+        }
+        break;
+    case PPC_INTERRUPT_HDOORBELL:
+        env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
+        powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
+        break;
+    case PPC_INTERRUPT_PERFM:
+        env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
+        powerpc_excp(cpu, POWERPC_EXCP_PERFM);
+        break;
+    case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
+        env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
+        powerpc_excp(cpu, POWERPC_EXCP_THERM);
+        break;
+    case PPC_INTERRUPT_EBB: /* EBB exception */
+        env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
+        if (env->spr[SPR_BESCR] & BESCR_PMEO) {
+            powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
+        } else if (env->spr[SPR_BESCR] & BESCR_EEO) {
+            powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB);
+        }
+        break;
+    case 0:
+        /*
+         * This is a bug ! It means that has_work took us out of halt without
+         * anything to deliver while in a PM state that requires getting
+         * out via a 0x100
+         *
+         * This means we will incorrectly execute past the power management
+         * instruction instead of triggering a reset.
+         *
+         * It generally means a discrepancy between the wakeup conditions in the
+         * processor has_work implementation and the logic in this function.
+         */
+        assert(env->resume_as_sreset != 0);
+        break;
+    default:
+        cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt);
+    }
+}
+
 static void p9_deliver_interrupt(CPUPPCState *env, int interrupt)
 {
     PowerPCCPU *cpu = env_archcpu(env);
@@ -2167,6 +2277,9 @@ static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt)
 {
     switch (env->excp_model) {
 #if defined(TARGET_PPC64)
+    case POWERPC_EXCP_POWER8:
+        p8_deliver_interrupt(env, interrupt);
+        break;
     case POWERPC_EXCP_POWER9:
     case POWERPC_EXCP_POWER10:
         p9_deliver_interrupt(env, interrupt);
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 15/29] target/ppc: remove unused interrupts from p8_deliver_interrupt
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (13 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 14/29] target/ppc: create an interrupt delivery method for POWER8 Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 16/29] target/ppc: remove generic architecture checks " Matheus Ferst
                   ` (14 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

Remove the following unused interrupts from the POWER8 interrupt
processing method:
- PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970, and POWER5p;
- Debug Interrupt: removed in Power ISA v2.07;
- Hypervisor Virtualization: introduced in Power ISA v3.0;
- Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
  for embedded CPUs;
- Hypervisor Doorbell, Doorbell, and Critical Doorbell: processor does
  not implement the "Embedded.Processor Control" category;
- Programmable Interval Timer: 40x-only;
- PPC_INTERRUPT_THERM: only raised for 970 and POWER5p;

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
 target/ppc/excp_helper.c | 48 ----------------------------------------
 1 file changed, 48 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 0405fc8eee..4cbf6b29fc 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1979,29 +1979,16 @@ static void p8_deliver_interrupt(CPUPPCState *env, int interrupt)
     CPUState *cs = env_cpu(env);
 
     switch (interrupt) {
-    case PPC_INTERRUPT_RESET: /* External reset */
-        env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
-        powerpc_excp(cpu, POWERPC_EXCP_RESET);
-        break;
     case PPC_INTERRUPT_MCK: /* Machine check exception */
         env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
         powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
         break;
-#if 0 /* TODO */
-    case PPC_INTERRUPT_DEBUG: /* External debug exception */
-        env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
-        powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
-        break;
-#endif
 
     case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */
         /* HDEC clears on delivery */
         env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
         powerpc_excp(cpu, POWERPC_EXCP_HDECR);
         break;
-    case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */
-        powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
-        break;
 
     case PPC_INTERRUPT_EXT:
         if (books_vhyp_promotes_external_to_hvirt(cpu)) {
@@ -2010,52 +1997,17 @@ static void p8_deliver_interrupt(CPUPPCState *env, int interrupt)
             powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
         }
         break;
-    case PPC_INTERRUPT_CEXT: /* External critical interrupt */
-        powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
-        break;
 
-    case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
-        env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
-        powerpc_excp(cpu, POWERPC_EXCP_WDT);
-        break;
-    case PPC_INTERRUPT_CDOORBELL:
-        env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
-        powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
-        break;
-    case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
-        env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
-        powerpc_excp(cpu, POWERPC_EXCP_FIT);
-        break;
-    case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC */
-        env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
-        powerpc_excp(cpu, POWERPC_EXCP_PIT);
-        break;
     case PPC_INTERRUPT_DECR: /* Decrementer exception */
         if (ppc_decr_clear_on_delivery(env)) {
             env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
         }
         powerpc_excp(cpu, POWERPC_EXCP_DECR);
         break;
-    case PPC_INTERRUPT_DOORBELL:
-        env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
-        if (is_book3s_arch2x(env)) {
-            powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
-        } else {
-            powerpc_excp(cpu, POWERPC_EXCP_DOORI);
-        }
-        break;
-    case PPC_INTERRUPT_HDOORBELL:
-        env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
-        powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
-        break;
     case PPC_INTERRUPT_PERFM:
         env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
         powerpc_excp(cpu, POWERPC_EXCP_PERFM);
         break;
-    case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
-        env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
-        powerpc_excp(cpu, POWERPC_EXCP_THERM);
-        break;
     case PPC_INTERRUPT_EBB: /* EBB exception */
         env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
         if (env->spr[SPR_BESCR] & BESCR_PMEO) {
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 16/29] target/ppc: remove generic architecture checks from p8_deliver_interrupt
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (14 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 15/29] target/ppc: remove unused interrupts from p8_deliver_interrupt Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 17/29] target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER8 Matheus Ferst
                   ` (13 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

No functional change intended.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
 target/ppc/excp_helper.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 4cbf6b29fc..2e8d4699a9 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1999,9 +1999,6 @@ static void p8_deliver_interrupt(CPUPPCState *env, int interrupt)
         break;
 
     case PPC_INTERRUPT_DECR: /* Decrementer exception */
-        if (ppc_decr_clear_on_delivery(env)) {
-            env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
-        }
         powerpc_excp(cpu, POWERPC_EXCP_DECR);
         break;
     case PPC_INTERRUPT_PERFM:
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 17/29] target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER8
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (15 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 16/29] target/ppc: remove generic architecture checks " Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 18/29] target/ppc: add power-saving interrupt masking logic to p8_next_unmasked_interrupt Matheus Ferst
                   ` (12 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

Move the interrupt masking logic out of cpu_has_work_POWER8 in a new
method, p8_interrupt_powersave, that only returns an interrupt if it can
wake the processor from power-saving mode. No functional change
intended.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
 target/ppc/cpu_init.c | 61 +++++++++++++++++++++++--------------------
 1 file changed, 33 insertions(+), 28 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 7889158c52..59e4c325c5 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6133,6 +6133,38 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
     return true;
 }
 
+static int p8_interrupt_powersave(CPUPPCState *env)
+{
+    if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
+        (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
+        return PPC_INTERRUPT_EXT;
+    }
+    if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
+        (env->spr[SPR_LPCR] & LPCR_P8_PECE3)) {
+        return PPC_INTERRUPT_DECR;
+    }
+    if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
+        (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
+        return PPC_INTERRUPT_MCK;
+    }
+    if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
+        (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
+        return PPC_INTERRUPT_HMI;
+    }
+    if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
+        (env->spr[SPR_LPCR] & LPCR_P8_PECE0)) {
+        return PPC_INTERRUPT_DOORBELL;
+    }
+    if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
+        (env->spr[SPR_LPCR] & LPCR_P8_PECE1)) {
+        return PPC_INTERRUPT_HDOORBELL;
+    }
+    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+        return PPC_INTERRUPT_RESET;
+    }
+    return 0;
+}
+
 static bool cpu_has_work_POWER8(CPUState *cs)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -6142,34 +6174,7 @@ static bool cpu_has_work_POWER8(CPUState *cs)
         if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
             return false;
         }
-        if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-            (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
-            return true;
-        }
-        if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-            (env->spr[SPR_LPCR] & LPCR_P8_PECE3)) {
-            return true;
-        }
-        if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
-            (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
-            return true;
-        }
-        if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
-            (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
-            return true;
-        }
-        if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
-            (env->spr[SPR_LPCR] & LPCR_P8_PECE0)) {
-            return true;
-        }
-        if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
-            (env->spr[SPR_LPCR] & LPCR_P8_PECE1)) {
-            return true;
-        }
-        if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-            return true;
-        }
-        return false;
+        return p8_interrupt_powersave(env) != 0;
     } else {
         return FIELD_EX64(env->msr, MSR, EE) &&
                (cs->interrupt_request & CPU_INTERRUPT_HARD);
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 18/29] target/ppc: add power-saving interrupt masking logic to p8_next_unmasked_interrupt
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (16 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 17/29] target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER8 Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 19/29] target/ppc: create an interrupt masking method for POWER7 Matheus Ferst
                   ` (11 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

Export p8_interrupt_powersave and use it in p8_next_unmasked_interrupt.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
 target/ppc/cpu_init.c    |  2 +-
 target/ppc/excp_helper.c | 24 ++++++++++++------------
 target/ppc/internal.h    |  1 +
 3 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 59e4c325c5..319d2355ec 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6133,7 +6133,7 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
     return true;
 }
 
-static int p8_interrupt_powersave(CPUPPCState *env)
+int p8_interrupt_powersave(CPUPPCState *env)
 {
     if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
         (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 2e8d4699a9..609579f45f 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1687,28 +1687,28 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 
 static int p8_next_unmasked_interrupt(CPUPPCState *env)
 {
-    bool async_deliver;
+    PowerPCCPU *cpu = env_archcpu(env);
+    CPUState *cs = CPU(cpu);
+    /* Ignore MSR[EE] when coming out of some power management states */
+    bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
 
     assert((env->pending_interrupts & P8_UNUSED_INTERRUPTS) == 0);
 
+    if (cs->halted) {
+        /* LPCR[PECE] controls which interrupts can exit power-saving mode */
+        return p8_interrupt_powersave(env);
+    }
+
     /* Machine check exception */
     if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
         return PPC_INTERRUPT_MCK;
     }
 
-    /*
-     * For interrupts that gate on MSR:EE, we need to do something a
-     * bit more subtle, as we need to let them through even when EE is
-     * clear when coming out of some power management states (in order
-     * for them to become a 0x100).
-     */
-    async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
-
     /* Hypervisor decrementer exception */
     if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
         /* LPCR will be clear when not supported so this will work */
         bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
-        if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+        if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) {
             /* HDEC clears on delivery */
             return PPC_INTERRUPT_HDECR;
         }
@@ -1719,13 +1719,13 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env)
         bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
         bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
         /* HEIC blocks delivery to the hypervisor */
-        if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+        if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) &&
             !FIELD_EX64(env->msr, MSR, PR))) ||
             (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
             return PPC_INTERRUPT_EXT;
         }
     }
-    if (async_deliver != 0) {
+    if (msr_ee != 0) {
         /* Decrementer exception */
         if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
             return PPC_INTERRUPT_DECR;
diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index 41e79adfdb..9069874adb 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -308,6 +308,7 @@ static inline int ger_pack_masks(int pmsk, int ymsk, int xmsk)
 
 #if defined(TARGET_PPC64)
 int p9_interrupt_powersave(CPUPPCState *env);
+int p8_interrupt_powersave(CPUPPCState *env);
 #endif
 
 #endif /* PPC_INTERNAL_H */
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 19/29] target/ppc: create an interrupt masking method for POWER7
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (17 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 18/29] target/ppc: add power-saving interrupt masking logic to p8_next_unmasked_interrupt Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 20/29] target/ppc: remove unused interrupts from p7_pending_interrupt Matheus Ferst
                   ` (10 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

The new method is identical to ppc_next_unmasked_interrupt_generic,
processor-specific code will be added/removed in the following patches.
No functional change intended.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
v2:
  - Renamed the method from ppc_pending_interrupt_p7 to
    p7_next_unmasked_interrupt;
  - Processor-specific stuff moved to the following patches to ease
    review.
---
 target/ppc/excp_helper.c | 114 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 114 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 609579f45f..8e1e18317d 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1679,6 +1679,118 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 }
 
 #if defined(TARGET_PPC64)
+static int p7_next_unmasked_interrupt(CPUPPCState *env)
+{
+    bool async_deliver;
+
+    /* External reset */
+    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+        return PPC_INTERRUPT_RESET;
+    }
+    /* Machine check exception */
+    if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+        return PPC_INTERRUPT_MCK;
+    }
+#if 0 /* TODO */
+    /* External debug exception */
+    if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
+        return PPC_INTERRUPT_DEBUG;
+    }
+#endif
+
+    /*
+     * For interrupts that gate on MSR:EE, we need to do something a
+     * bit more subtle, as we need to let them through even when EE is
+     * clear when coming out of some power management states (in order
+     * for them to become a 0x100).
+     */
+    async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
+
+    /* Hypervisor decrementer exception */
+    if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
+        /* LPCR will be clear when not supported so this will work */
+        bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
+        if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+            /* HDEC clears on delivery */
+            return PPC_INTERRUPT_HDECR;
+        }
+    }
+
+    /* Hypervisor virtualization interrupt */
+    if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
+        /* LPCR will be clear when not supported so this will work */
+        bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
+        if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
+            return PPC_INTERRUPT_HVIRT;
+        }
+    }
+
+    /* External interrupt can ignore MSR:EE under some circumstances */
+    if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
+        bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
+        bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+        /* HEIC blocks delivery to the hypervisor */
+        if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+            !FIELD_EX64(env->msr, MSR, PR))) ||
+            (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
+            return PPC_INTERRUPT_EXT;
+        }
+    }
+    if (FIELD_EX64(env->msr, MSR, CE)) {
+        /* External critical interrupt */
+        if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
+            return PPC_INTERRUPT_CEXT;
+        }
+    }
+    if (async_deliver != 0) {
+        /* Watchdog timer on embedded PowerPC */
+        if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
+            return PPC_INTERRUPT_WDT;
+        }
+        if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
+            return PPC_INTERRUPT_CDOORBELL;
+        }
+        /* Fixed interval timer on embedded PowerPC */
+        if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
+            return PPC_INTERRUPT_FIT;
+        }
+        /* Programmable interval timer on embedded PowerPC */
+        if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
+            return PPC_INTERRUPT_PIT;
+        }
+        /* Decrementer exception */
+        if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
+            return PPC_INTERRUPT_DECR;
+        }
+        if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
+            return PPC_INTERRUPT_DOORBELL;
+        }
+        if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
+            return PPC_INTERRUPT_HDOORBELL;
+        }
+        if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
+            return PPC_INTERRUPT_PERFM;
+        }
+        /* Thermal interrupt */
+        if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
+            return PPC_INTERRUPT_THERM;
+        }
+        /* EBB exception */
+        if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
+            /*
+             * EBB exception must be taken in problem state and
+             * with BESCR_GE set.
+             */
+            if (FIELD_EX64(env->msr, MSR, PR) &&
+                (env->spr[SPR_BESCR] & BESCR_GE)) {
+                return PPC_INTERRUPT_EBB;
+            }
+        }
+    }
+
+    return 0;
+}
+
 #define P8_UNUSED_INTERRUPTS \
     (PPC_INTERRUPT_RESET | PPC_INTERRUPT_DEBUG | PPC_INTERRUPT_HVIRT |  \
     PPC_INTERRUPT_CEXT | PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL |  \
@@ -1961,6 +2073,8 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
 {
     switch (env->excp_model) {
 #if defined(TARGET_PPC64)
+    case POWERPC_EXCP_POWER7:
+        return p7_next_unmasked_interrupt(env);
     case POWERPC_EXCP_POWER8:
         return p8_next_unmasked_interrupt(env);
     case POWERPC_EXCP_POWER9:
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 20/29] target/ppc: remove unused interrupts from p7_pending_interrupt
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (18 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 19/29] target/ppc: create an interrupt masking method for POWER7 Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 21/29] target/ppc: create an interrupt delivery method for POWER7 Matheus Ferst
                   ` (9 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

Remove the following unused interrupts from the POWER7 interrupt masking
method:
- PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970, and POWER5p;
- Hypervisor Virtualization: introduced in Power ISA v3.0;
- Hypervisor Doorbell and Event-Based Branch: introduced in
  Power ISA v2.07;
- Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
  for embedded CPUs;
- Doorbell and Critical Doorbell Interrupt: processor does not implement
  the "Embedded.Processor Control" category;
- Programmable Interval Timer: 40x-only;
- PPC_INTERRUPT_THERM: only raised for 970 and POWER5p;

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
v2:
  - Remove CDOORBELL and THERM interrupts (farosas);
  - Also remove RESET, DOORBELL, and HDOORBELL interrupts;
  - Assert for the removed interrupts.
---
 target/ppc/excp_helper.c | 63 +++++-----------------------------------
 1 file changed, 8 insertions(+), 55 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 8e1e18317d..d8522d0b17 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1679,14 +1679,18 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 }
 
 #if defined(TARGET_PPC64)
+#define P7_UNUSED_INTERRUPTS \
+    (PPC_INTERRUPT_RESET | PPC_INTERRUPT_HVIRT | PPC_INTERRUPT_CEXT |       \
+     PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | PPC_INTERRUPT_FIT |      \
+     PPC_INTERRUPT_PIT | PPC_INTERRUPT_DOORBELL | PPC_INTERRUPT_HDOORBELL | \
+     PPC_INTERRUPT_THERM | PPC_INTERRUPT_EBB)
+
 static int p7_next_unmasked_interrupt(CPUPPCState *env)
 {
     bool async_deliver;
 
-    /* External reset */
-    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-        return PPC_INTERRUPT_RESET;
-    }
+    assert((env->pending_interrupts & P7_UNUSED_INTERRUPTS) == 0);
+
     /* Machine check exception */
     if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
         return PPC_INTERRUPT_MCK;
@@ -1716,15 +1720,6 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env)
         }
     }
 
-    /* Hypervisor virtualization interrupt */
-    if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
-        /* LPCR will be clear when not supported so this will work */
-        bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
-        if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
-            return PPC_INTERRUPT_HVIRT;
-        }
-    }
-
     /* External interrupt can ignore MSR:EE under some circumstances */
     if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
         bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
@@ -1736,56 +1731,14 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env)
             return PPC_INTERRUPT_EXT;
         }
     }
-    if (FIELD_EX64(env->msr, MSR, CE)) {
-        /* External critical interrupt */
-        if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
-            return PPC_INTERRUPT_CEXT;
-        }
-    }
     if (async_deliver != 0) {
-        /* Watchdog timer on embedded PowerPC */
-        if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
-            return PPC_INTERRUPT_WDT;
-        }
-        if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
-            return PPC_INTERRUPT_CDOORBELL;
-        }
-        /* Fixed interval timer on embedded PowerPC */
-        if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
-            return PPC_INTERRUPT_FIT;
-        }
-        /* Programmable interval timer on embedded PowerPC */
-        if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
-            return PPC_INTERRUPT_PIT;
-        }
         /* Decrementer exception */
         if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
             return PPC_INTERRUPT_DECR;
         }
-        if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
-            return PPC_INTERRUPT_DOORBELL;
-        }
-        if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
-            return PPC_INTERRUPT_HDOORBELL;
-        }
         if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
             return PPC_INTERRUPT_PERFM;
         }
-        /* Thermal interrupt */
-        if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
-            return PPC_INTERRUPT_THERM;
-        }
-        /* EBB exception */
-        if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
-            /*
-             * EBB exception must be taken in problem state and
-             * with BESCR_GE set.
-             */
-            if (FIELD_EX64(env->msr, MSR, PR) &&
-                (env->spr[SPR_BESCR] & BESCR_GE)) {
-                return PPC_INTERRUPT_EBB;
-            }
-        }
     }
 
     return 0;
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 21/29] target/ppc: create an interrupt delivery method for POWER7
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (19 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 20/29] target/ppc: remove unused interrupts from p7_pending_interrupt Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 22/29] target/ppc: remove unused interrupts from p7_deliver_interrupt Matheus Ferst
                   ` (8 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

The new method is identical to ppc_deliver_interrupt, processor-specific
code will be added/removed in the following patches. No functional
change intended.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
 target/ppc/excp_helper.c | 113 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index d8522d0b17..f32472fb43 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -2040,6 +2040,116 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
 }
 
 #if defined(TARGET_PPC64)
+static void p7_deliver_interrupt(CPUPPCState *env, int interrupt)
+{
+    PowerPCCPU *cpu = env_archcpu(env);
+    CPUState *cs = env_cpu(env);
+
+    switch (interrupt) {
+    case PPC_INTERRUPT_RESET: /* External reset */
+        env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
+        powerpc_excp(cpu, POWERPC_EXCP_RESET);
+        break;
+    case PPC_INTERRUPT_MCK: /* Machine check exception */
+        env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
+        powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
+        break;
+#if 0 /* TODO */
+    case PPC_INTERRUPT_DEBUG: /* External debug exception */
+        env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
+        powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
+        break;
+#endif
+
+    case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */
+        /* HDEC clears on delivery */
+        env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
+        powerpc_excp(cpu, POWERPC_EXCP_HDECR);
+        break;
+    case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */
+        powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+        break;
+
+    case PPC_INTERRUPT_EXT:
+        if (books_vhyp_promotes_external_to_hvirt(cpu)) {
+            powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+        } else {
+            powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
+        }
+        break;
+    case PPC_INTERRUPT_CEXT: /* External critical interrupt */
+        powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
+        break;
+
+    case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
+        env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
+        powerpc_excp(cpu, POWERPC_EXCP_WDT);
+        break;
+    case PPC_INTERRUPT_CDOORBELL:
+        env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
+        powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
+        break;
+    case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
+        env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
+        powerpc_excp(cpu, POWERPC_EXCP_FIT);
+        break;
+    case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC */
+        env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
+        powerpc_excp(cpu, POWERPC_EXCP_PIT);
+        break;
+    case PPC_INTERRUPT_DECR: /* Decrementer exception */
+        if (ppc_decr_clear_on_delivery(env)) {
+            env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
+        }
+        powerpc_excp(cpu, POWERPC_EXCP_DECR);
+        break;
+    case PPC_INTERRUPT_DOORBELL:
+        env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
+        if (is_book3s_arch2x(env)) {
+            powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
+        } else {
+            powerpc_excp(cpu, POWERPC_EXCP_DOORI);
+        }
+        break;
+    case PPC_INTERRUPT_HDOORBELL:
+        env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
+        powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
+        break;
+    case PPC_INTERRUPT_PERFM:
+        env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
+        powerpc_excp(cpu, POWERPC_EXCP_PERFM);
+        break;
+    case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
+        env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
+        powerpc_excp(cpu, POWERPC_EXCP_THERM);
+        break;
+    case PPC_INTERRUPT_EBB: /* EBB exception */
+        env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
+        if (env->spr[SPR_BESCR] & BESCR_PMEO) {
+            powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
+        } else if (env->spr[SPR_BESCR] & BESCR_EEO) {
+            powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB);
+        }
+        break;
+    case 0:
+        /*
+         * This is a bug ! It means that has_work took us out of halt without
+         * anything to deliver while in a PM state that requires getting
+         * out via a 0x100
+         *
+         * This means we will incorrectly execute past the power management
+         * instruction instead of triggering a reset.
+         *
+         * It generally means a discrepancy between the wakeup conditions in the
+         * processor has_work implementation and the logic in this function.
+         */
+        assert(env->resume_as_sreset != 0);
+        break;
+    default:
+        cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt);
+    }
+}
+
 static void p8_deliver_interrupt(CPUPPCState *env, int interrupt)
 {
     PowerPCCPU *cpu = env_archcpu(env);
@@ -2293,6 +2403,9 @@ static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt)
 {
     switch (env->excp_model) {
 #if defined(TARGET_PPC64)
+    case POWERPC_EXCP_POWER7:
+        p7_deliver_interrupt(env, interrupt);
+        break;
     case POWERPC_EXCP_POWER8:
         p8_deliver_interrupt(env, interrupt);
         break;
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 22/29] target/ppc: remove unused interrupts from p7_deliver_interrupt
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (20 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 21/29] target/ppc: create an interrupt delivery method for POWER7 Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 23/29] target/ppc: remove generic architecture checks " Matheus Ferst
                   ` (7 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

Remove the following unused interrupts from the POWER7 interrupt
processing method:
- PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970, and POWER5p;
- Hypervisor Virtualization: introduced in Power ISA v3.0;
- Hypervisor Doorbell and Event-Based Branch: introduced in
  Power ISA v2.07;
- Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
  for embedded CPUs;
- Doorbell and Critical Doorbell Interrupt: processor does not implement
  the "Embedded.Processor Control" category;
- Programmable Interval Timer: 40x-only;
- PPC_INTERRUPT_THERM: only raised for 970 and POWER5p;

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
 target/ppc/excp_helper.c | 50 ----------------------------------------
 1 file changed, 50 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index f32472fb43..de6972d002 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -2046,10 +2046,6 @@ static void p7_deliver_interrupt(CPUPPCState *env, int interrupt)
     CPUState *cs = env_cpu(env);
 
     switch (interrupt) {
-    case PPC_INTERRUPT_RESET: /* External reset */
-        env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
-        powerpc_excp(cpu, POWERPC_EXCP_RESET);
-        break;
     case PPC_INTERRUPT_MCK: /* Machine check exception */
         env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
         powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
@@ -2066,9 +2062,6 @@ static void p7_deliver_interrupt(CPUPPCState *env, int interrupt)
         env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
         powerpc_excp(cpu, POWERPC_EXCP_HDECR);
         break;
-    case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */
-        powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
-        break;
 
     case PPC_INTERRUPT_EXT:
         if (books_vhyp_promotes_external_to_hvirt(cpu)) {
@@ -2077,60 +2070,17 @@ static void p7_deliver_interrupt(CPUPPCState *env, int interrupt)
             powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
         }
         break;
-    case PPC_INTERRUPT_CEXT: /* External critical interrupt */
-        powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
-        break;
 
-    case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
-        env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
-        powerpc_excp(cpu, POWERPC_EXCP_WDT);
-        break;
-    case PPC_INTERRUPT_CDOORBELL:
-        env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
-        powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
-        break;
-    case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
-        env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
-        powerpc_excp(cpu, POWERPC_EXCP_FIT);
-        break;
-    case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC */
-        env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
-        powerpc_excp(cpu, POWERPC_EXCP_PIT);
-        break;
     case PPC_INTERRUPT_DECR: /* Decrementer exception */
         if (ppc_decr_clear_on_delivery(env)) {
             env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
         }
         powerpc_excp(cpu, POWERPC_EXCP_DECR);
         break;
-    case PPC_INTERRUPT_DOORBELL:
-        env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
-        if (is_book3s_arch2x(env)) {
-            powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
-        } else {
-            powerpc_excp(cpu, POWERPC_EXCP_DOORI);
-        }
-        break;
-    case PPC_INTERRUPT_HDOORBELL:
-        env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
-        powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
-        break;
     case PPC_INTERRUPT_PERFM:
         env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
         powerpc_excp(cpu, POWERPC_EXCP_PERFM);
         break;
-    case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
-        env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
-        powerpc_excp(cpu, POWERPC_EXCP_THERM);
-        break;
-    case PPC_INTERRUPT_EBB: /* EBB exception */
-        env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
-        if (env->spr[SPR_BESCR] & BESCR_PMEO) {
-            powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
-        } else if (env->spr[SPR_BESCR] & BESCR_EEO) {
-            powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB);
-        }
-        break;
     case 0:
         /*
          * This is a bug ! It means that has_work took us out of halt without
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 23/29] target/ppc: remove generic architecture checks from p7_deliver_interrupt
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (21 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 22/29] target/ppc: remove unused interrupts from p7_deliver_interrupt Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 24/29] target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER7 Matheus Ferst
                   ` (6 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

No functional change intended.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
 target/ppc/excp_helper.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index de6972d002..ca594c3b9e 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -2072,9 +2072,6 @@ static void p7_deliver_interrupt(CPUPPCState *env, int interrupt)
         break;
 
     case PPC_INTERRUPT_DECR: /* Decrementer exception */
-        if (ppc_decr_clear_on_delivery(env)) {
-            env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
-        }
         powerpc_excp(cpu, POWERPC_EXCP_DECR);
         break;
     case PPC_INTERRUPT_PERFM:
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 24/29] target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER7
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (22 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 23/29] target/ppc: remove generic architecture checks " Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 25/29] target/ppc: add power-saving interrupt masking logic to p7_next_unmasked_interrupt Matheus Ferst
                   ` (5 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

Move the interrupt masking logic out of cpu_has_work_POWER7 in a new
method, p7_interrupt_powersave, that only returns an interrupt if it can
wake the processor from power-saving mode. No functional change
intended.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
 target/ppc/cpu_init.c | 45 ++++++++++++++++++++++++-------------------
 1 file changed, 25 insertions(+), 20 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 319d2355ec..dd127cbeea 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -5960,6 +5960,30 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
     return true;
 }
 
+static int p7_interrupt_powersave(CPUPPCState *env)
+{
+    if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
+        (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
+        return PPC_INTERRUPT_EXT;
+    }
+    if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
+        (env->spr[SPR_LPCR] & LPCR_P7_PECE1)) {
+        return PPC_INTERRUPT_DECR;
+    }
+    if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
+        (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
+        return PPC_INTERRUPT_MCK;
+    }
+    if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
+        (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
+        return PPC_INTERRUPT_HMI;
+    }
+    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+        return PPC_INTERRUPT_RESET;
+    }
+    return 0;
+}
+
 static bool cpu_has_work_POWER7(CPUState *cs)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -5969,26 +5993,7 @@ static bool cpu_has_work_POWER7(CPUState *cs)
         if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
             return false;
         }
-        if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-            (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
-            return true;
-        }
-        if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-            (env->spr[SPR_LPCR] & LPCR_P7_PECE1)) {
-            return true;
-        }
-        if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
-            (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
-            return true;
-        }
-        if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
-            (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
-            return true;
-        }
-        if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-            return true;
-        }
-        return false;
+        return p7_interrupt_powersave(env) != 0;
     } else {
         return FIELD_EX64(env->msr, MSR, EE) &&
                (cs->interrupt_request & CPU_INTERRUPT_HARD);
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 25/29] target/ppc: add power-saving interrupt masking logic to p7_next_unmasked_interrupt
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (23 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 24/29] target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER7 Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 26/29] target/ppc: remove ppc_store_lpcr from CONFIG_USER_ONLY builds Matheus Ferst
                   ` (4 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

Export p7_interrupt_powersave and use it in p7_next_unmasked_interrupt.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
 target/ppc/cpu_init.c    |  2 +-
 target/ppc/excp_helper.c | 24 ++++++++++++------------
 target/ppc/internal.h    |  1 +
 3 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index dd127cbeea..26686d1557 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -5960,7 +5960,7 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
     return true;
 }
 
-static int p7_interrupt_powersave(CPUPPCState *env)
+int p7_interrupt_powersave(CPUPPCState *env)
 {
     if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
         (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index ca594c3b9e..497a9889d1 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1687,10 +1687,18 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 
 static int p7_next_unmasked_interrupt(CPUPPCState *env)
 {
-    bool async_deliver;
+    PowerPCCPU *cpu = env_archcpu(env);
+    CPUState *cs = CPU(cpu);
+    /* Ignore MSR[EE] when coming out of some power management states */
+    bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
 
     assert((env->pending_interrupts & P7_UNUSED_INTERRUPTS) == 0);
 
+    if (cs->halted) {
+        /* LPCR[PECE] controls which interrupts can exit power-saving mode */
+        return p7_interrupt_powersave(env);
+    }
+
     /* Machine check exception */
     if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
         return PPC_INTERRUPT_MCK;
@@ -1702,19 +1710,11 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env)
     }
 #endif
 
-    /*
-     * For interrupts that gate on MSR:EE, we need to do something a
-     * bit more subtle, as we need to let them through even when EE is
-     * clear when coming out of some power management states (in order
-     * for them to become a 0x100).
-     */
-    async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
-
     /* Hypervisor decrementer exception */
     if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
         /* LPCR will be clear when not supported so this will work */
         bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
-        if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+        if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) {
             /* HDEC clears on delivery */
             return PPC_INTERRUPT_HDECR;
         }
@@ -1725,13 +1725,13 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env)
         bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
         bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
         /* HEIC blocks delivery to the hypervisor */
-        if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+        if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) &&
             !FIELD_EX64(env->msr, MSR, PR))) ||
             (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
             return PPC_INTERRUPT_EXT;
         }
     }
-    if (async_deliver != 0) {
+    if (msr_ee != 0) {
         /* Decrementer exception */
         if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
             return PPC_INTERRUPT_DECR;
diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index 9069874adb..25827ebf6f 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -309,6 +309,7 @@ static inline int ger_pack_masks(int pmsk, int ymsk, int xmsk)
 #if defined(TARGET_PPC64)
 int p9_interrupt_powersave(CPUPPCState *env);
 int p8_interrupt_powersave(CPUPPCState *env);
+int p7_interrupt_powersave(CPUPPCState *env);
 #endif
 
 #endif /* PPC_INTERNAL_H */
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 26/29] target/ppc: remove ppc_store_lpcr from CONFIG_USER_ONLY builds
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (24 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 25/29] target/ppc: add power-saving interrupt masking logic to p7_next_unmasked_interrupt Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-09-27 20:15 ` [RFC PATCH v2 27/29] target/ppc: introduce ppc_maybe_interrupt Matheus Ferst
                   ` (3 subsequent siblings)
  29 siblings, 0 replies; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

Writes to LPCR are hypervisor privileged.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
The method introduced in the next patch, ppc_maybe_interrupt, will be
called in ppc_store_lpcr and only available in !CONFIG_USER_ONLY builds.
---
 target/ppc/cpu.c | 2 ++
 target/ppc/cpu.h | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c
index 0ebac04bc4..e95b4c5ee1 100644
--- a/target/ppc/cpu.c
+++ b/target/ppc/cpu.c
@@ -73,6 +73,7 @@ void ppc_store_msr(CPUPPCState *env, target_ulong value)
     hreg_store_msr(env, value, 0);
 }
 
+#if !defined(CONFIG_USER_ONLY)
 void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
 {
     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
@@ -82,6 +83,7 @@ void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
     /* The gtse bit affects hflags */
     hreg_compute_hflags(env);
 }
+#endif
 
 static inline void fpscr_set_rounding_mode(CPUPPCState *env)
 {
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 9ccd23db04..7b13d4cf86 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1370,9 +1370,9 @@ void ppc_translate_init(void);
 
 #if !defined(CONFIG_USER_ONLY)
 void ppc_store_sdr1(CPUPPCState *env, target_ulong value);
+void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val);
 #endif /* !defined(CONFIG_USER_ONLY) */
 void ppc_store_msr(CPUPPCState *env, target_ulong value);
-void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val);
 
 void ppc_cpu_list(void);
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 27/29] target/ppc: introduce ppc_maybe_interrupt
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (25 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 26/29] target/ppc: remove ppc_store_lpcr from CONFIG_USER_ONLY builds Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-10-03 14:11   ` Fabiano Rosas
  2022-09-27 20:15 ` [RFC PATCH v2 28/29] target/ppc: unify cpu->has_work based on cs->interrupt_request Matheus Ferst
                   ` (2 subsequent siblings)
  29 siblings, 1 reply; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

The method checks if any pending interrupt is unmasked and calls
cpu_interrupt/cpu_reset_interrupt accordingly. Code that raises/lowers
or masks/unmasks interrupts should call this method to keep
CPU_INTERRUPT_HARD coherent with env->pending_interrupts.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
v2:
  - Found many other places where ppc_maybe_interrupt had to be called
    with the IO and kvm-nested tests that Cédric suggested.
  - Create a helper to call ppc_maybe_interrupt to avoid using
    helper_store_msr in WRTEE[I].

I couldn't find a better name for this method, so I used "maybe
interrupt" just like we have "maybe bswap" for gdbstub registers.
---
 hw/ppc/pnv_core.c        |  1 +
 hw/ppc/ppc.c             |  7 +------
 hw/ppc/spapr_hcall.c     |  6 ++++++
 hw/ppc/spapr_rtas.c      |  2 +-
 target/ppc/cpu.c         |  2 ++
 target/ppc/cpu.h         |  1 +
 target/ppc/excp_helper.c | 29 +++++++++++++++++++++++++++++
 target/ppc/helper.h      |  1 +
 target/ppc/helper_regs.c |  2 ++
 target/ppc/translate.c   |  2 ++
 10 files changed, 46 insertions(+), 7 deletions(-)

diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 19e8eb885f..9ee79192dd 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -58,6 +58,7 @@ static void pnv_core_cpu_reset(PnvCore *pc, PowerPCCPU *cpu)
     env->msr |= MSR_HVB; /* Hypervisor mode */
     env->spr[SPR_HRMOR] = pc->hrmor;
     hreg_compute_hflags(env);
+    ppc_maybe_interrupt(env);
 
     pcc->intc_reset(pc->chip, cpu);
 }
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 77e611e81c..dc86c1c7db 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -42,7 +42,6 @@ static void cpu_ppc_tb_start (CPUPPCState *env);
 
 void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
 {
-    CPUState *cs = CPU(cpu);
     CPUPPCState *env = &cpu->env;
     unsigned int old_pending;
     bool locked = false;
@@ -57,19 +56,15 @@ void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
 
     if (level) {
         env->pending_interrupts |= irq;
-        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
     } else {
         env->pending_interrupts &= ~irq;
-        if (env->pending_interrupts == 0) {
-            cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
-        }
     }
 
     if (old_pending != env->pending_interrupts) {
+        ppc_maybe_interrupt(env);
         kvmppc_set_interrupt(cpu, irq, level);
     }
 
-
     trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts,
                            CPU(cpu)->interrupt_request);
 
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index a8d4a6bcf0..23aa41c879 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -490,6 +490,7 @@ static target_ulong h_cede(PowerPCCPU *cpu, SpaprMachineState *spapr,
 
     env->msr |= (1ULL << MSR_EE);
     hreg_compute_hflags(env);
+    ppc_maybe_interrupt(env);
 
     if (spapr_cpu->prod) {
         spapr_cpu->prod = false;
@@ -500,6 +501,7 @@ static target_ulong h_cede(PowerPCCPU *cpu, SpaprMachineState *spapr,
         cs->halted = 1;
         cs->exception_index = EXCP_HLT;
         cs->exit_request = 1;
+        ppc_maybe_interrupt(env);
     }
 
     return H_SUCCESS;
@@ -521,6 +523,7 @@ static target_ulong h_confer_self(PowerPCCPU *cpu)
     cs->halted = 1;
     cs->exception_index = EXCP_HALTED;
     cs->exit_request = 1;
+    ppc_maybe_interrupt(&cpu->env);
 
     return H_SUCCESS;
 }
@@ -633,6 +636,7 @@ static target_ulong h_prod(PowerPCCPU *cpu, SpaprMachineState *spapr,
     spapr_cpu = spapr_cpu_state(tcpu);
     spapr_cpu->prod = true;
     cs->halted = 0;
+    ppc_maybe_interrupt(&cpu->env);
     qemu_cpu_kick(cs);
 
     return H_SUCCESS;
@@ -1661,6 +1665,7 @@ static target_ulong h_enter_nested(PowerPCCPU *cpu,
     spapr_cpu->in_nested = true;
 
     hreg_compute_hflags(env);
+    ppc_maybe_interrupt(env);
     tlb_flush(cs);
     env->reserve_addr = -1; /* Reset the reservation */
 
@@ -1802,6 +1807,7 @@ out_restore_l1:
     spapr_cpu->in_nested = false;
 
     hreg_compute_hflags(env);
+    ppc_maybe_interrupt(env);
     tlb_flush(cs);
     env->reserve_addr = -1; /* Reset the reservation */
 
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index d58b65e88f..3f664ea02c 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -214,9 +214,9 @@ static void rtas_stop_self(PowerPCCPU *cpu, SpaprMachineState *spapr,
      * guest.
      * For the same reason, set PSSCR_EC.
      */
-    ppc_store_lpcr(cpu, env->spr[SPR_LPCR] & ~pcc->lpcr_pm);
     env->spr[SPR_PSSCR] |= PSSCR_EC;
     cs->halted = 1;
+    ppc_store_lpcr(cpu, env->spr[SPR_LPCR] & ~pcc->lpcr_pm);
     kvmppc_set_reg_ppc_online(cpu, 0);
     qemu_cpu_kick(cs);
 }
diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c
index e95b4c5ee1..1a97b41c6b 100644
--- a/target/ppc/cpu.c
+++ b/target/ppc/cpu.c
@@ -82,6 +82,8 @@ void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
     env->spr[SPR_LPCR] = val & pcc->lpcr_mask;
     /* The gtse bit affects hflags */
     hreg_compute_hflags(env);
+
+    ppc_maybe_interrupt(env);
 }
 #endif
 
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 7b13d4cf86..89c065521f 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1358,6 +1358,7 @@ int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
 int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
                                int cpuid, void *opaque);
 #ifndef CONFIG_USER_ONLY
+void ppc_maybe_interrupt(CPUPPCState *env);
 void ppc_cpu_do_interrupt(CPUState *cpu);
 bool ppc_cpu_exec_interrupt(CPUState *cpu, int int_req);
 void ppc_cpu_do_system_reset(CPUState *cs);
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 497a9889d1..9708f82b30 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -390,6 +390,7 @@ static void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong vector,
     env->nip = vector;
     env->msr = msr;
     hreg_compute_hflags(env);
+    ppc_maybe_interrupt(env);
 
     powerpc_reset_excp_state(cpu);
 
@@ -2039,6 +2040,27 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
     }
 }
 
+void ppc_maybe_interrupt(CPUPPCState *env)
+{
+    CPUState *cs = env_cpu(env);
+    bool locked = false;
+
+    if (!qemu_mutex_iothread_locked()) {
+        locked = true;
+        qemu_mutex_lock_iothread();
+    }
+
+    if (ppc_next_unmasked_interrupt(env)) {
+        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+    } else {
+        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+    }
+
+    if (locked) {
+        qemu_mutex_unlock_iothread();
+    }
+}
+
 #if defined(TARGET_PPC64)
 static void p7_deliver_interrupt(CPUPPCState *env, int interrupt)
 {
@@ -2474,6 +2496,11 @@ void helper_store_msr(CPUPPCState *env, target_ulong val)
     }
 }
 
+void helper_ppc_maybe_interrupt(CPUPPCState *env)
+{
+    ppc_maybe_interrupt(env);
+}
+
 #if defined(TARGET_PPC64)
 void helper_scv(CPUPPCState *env, uint32_t lev)
 {
@@ -2494,6 +2521,8 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
     /* Condition for waking up at 0x100 */
     env->resume_as_sreset = (insn != PPC_PM_STOP) ||
         (env->spr[SPR_PSSCR] & PSSCR_EC);
+
+    ppc_maybe_interrupt(env);
 }
 #endif /* defined(TARGET_PPC64) */
 
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 57eee07256..3d09aae5fc 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -10,6 +10,7 @@ DEF_HELPER_4(HASHSTP, void, env, tl, tl, tl)
 DEF_HELPER_4(HASHCHKP, void, env, tl, tl, tl)
 #if !defined(CONFIG_USER_ONLY)
 DEF_HELPER_2(store_msr, void, env, tl)
+DEF_HELPER_1(ppc_maybe_interrupt, void, env)
 DEF_HELPER_1(rfi, void, env)
 DEF_HELPER_1(40x_rfci, void, env)
 DEF_HELPER_1(rfci, void, env)
diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c
index 12235ea2e9..2e85e124ab 100644
--- a/target/ppc/helper_regs.c
+++ b/target/ppc/helper_regs.c
@@ -260,6 +260,8 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv)
     env->msr = value;
     hreg_compute_hflags(env);
 #if !defined(CONFIG_USER_ONLY)
+    ppc_maybe_interrupt(env);
+
     if (unlikely(FIELD_EX64(env->msr, MSR, POW))) {
         if (!env->pending_interrupts && (*env->check_pow)(env)) {
             cs->halted = 1;
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index e810842925..e8336452c4 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -6175,6 +6175,7 @@ static void gen_wrtee(DisasContext *ctx)
     tcg_gen_andi_tl(t0, cpu_gpr[rD(ctx->opcode)], (1 << MSR_EE));
     tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(1 << MSR_EE));
     tcg_gen_or_tl(cpu_msr, cpu_msr, t0);
+    gen_helper_ppc_maybe_interrupt(cpu_env);
     tcg_temp_free(t0);
     /*
      * Stop translation to have a chance to raise an exception if we
@@ -6193,6 +6194,7 @@ static void gen_wrteei(DisasContext *ctx)
     CHK_SV(ctx);
     if (ctx->opcode & 0x00008000) {
         tcg_gen_ori_tl(cpu_msr, cpu_msr, (1 << MSR_EE));
+        gen_helper_ppc_maybe_interrupt(cpu_env);
         /* Stop translation to have a chance to raise an exception */
         ctx->base.is_jmp = DISAS_EXIT_UPDATE;
     } else {
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 28/29] target/ppc: unify cpu->has_work based on cs->interrupt_request
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (26 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 27/29] target/ppc: introduce ppc_maybe_interrupt Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-10-03 14:12   ` Fabiano Rosas
  2022-09-27 20:15 ` [RFC PATCH v2 29/29] target/ppc: move the p*_interrupt_powersave methods to excp_helper.c Matheus Ferst
  2022-09-28 17:31 ` [RFC PATCH v2 00/29] PowerPC interrupt rework Cédric Le Goater
  29 siblings, 1 reply; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

Now that cs->interrupt_request indicates if there is any unmasked
interrupt, checking if the CPU has work to do can be simplified to a
single check that works for all CPU models.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
 target/ppc/cpu_init.c | 94 +------------------------------------------
 1 file changed, 1 insertion(+), 93 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 26686d1557..4d0064c7a5 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -5984,27 +5984,10 @@ int p7_interrupt_powersave(CPUPPCState *env)
     return 0;
 }
 
-static bool cpu_has_work_POWER7(CPUState *cs)
-{
-    PowerPCCPU *cpu = POWERPC_CPU(cs);
-    CPUPPCState *env = &cpu->env;
-
-    if (cs->halted) {
-        if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
-            return false;
-        }
-        return p7_interrupt_powersave(env) != 0;
-    } else {
-        return FIELD_EX64(env->msr, MSR, EE) &&
-               (cs->interrupt_request & CPU_INTERRUPT_HARD);
-    }
-}
-
 POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
     PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-    CPUClass *cc = CPU_CLASS(oc);
 
     dc->fw_name = "PowerPC,POWER7";
     dc->desc = "POWER7";
@@ -6013,7 +5996,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
     pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
     pcc->init_proc = init_proc_POWER7;
     pcc->check_pow = check_pow_nocheck;
-    cc->has_work = cpu_has_work_POWER7;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -6170,27 +6152,10 @@ int p8_interrupt_powersave(CPUPPCState *env)
     return 0;
 }
 
-static bool cpu_has_work_POWER8(CPUState *cs)
-{
-    PowerPCCPU *cpu = POWERPC_CPU(cs);
-    CPUPPCState *env = &cpu->env;
-
-    if (cs->halted) {
-        if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
-            return false;
-        }
-        return p8_interrupt_powersave(env) != 0;
-    } else {
-        return FIELD_EX64(env->msr, MSR, EE) &&
-               (cs->interrupt_request & CPU_INTERRUPT_HARD);
-    }
-}
-
 POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
     PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-    CPUClass *cc = CPU_CLASS(oc);
 
     dc->fw_name = "PowerPC,POWER8";
     dc->desc = "POWER8";
@@ -6199,7 +6164,6 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
     pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
     pcc->init_proc = init_proc_POWER8;
     pcc->check_pow = check_pow_nocheck;
-    cc->has_work = cpu_has_work_POWER8;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -6407,35 +6371,10 @@ int p9_interrupt_powersave(CPUPPCState *env)
     return 0;
 }
 
-static bool cpu_has_work_POWER9(CPUState *cs)
-{
-    PowerPCCPU *cpu = POWERPC_CPU(cs);
-    CPUPPCState *env = &cpu->env;
-
-    if (cs->halted) {
-        uint64_t psscr = env->spr[SPR_PSSCR];
-
-        if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
-            return false;
-        }
-
-        /* If EC is clear, just return true on any pending interrupt */
-        if (!(psscr & PSSCR_EC)) {
-            return true;
-        }
-
-        return p9_interrupt_powersave(env) != 0;
-    } else {
-        return FIELD_EX64(env->msr, MSR, EE) &&
-               (cs->interrupt_request & CPU_INTERRUPT_HARD);
-    }
-}
-
 POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
     PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-    CPUClass *cc = CPU_CLASS(oc);
 
     dc->fw_name = "PowerPC,POWER9";
     dc->desc = "POWER9";
@@ -6445,7 +6384,6 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
                          PCR_COMPAT_2_05;
     pcc->init_proc = init_proc_POWER9;
     pcc->check_pow = check_pow_nocheck;
-    cc->has_work = cpu_has_work_POWER9;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -6604,35 +6542,10 @@ static bool ppc_pvr_match_power10(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
     return false;
 }
 
-static bool cpu_has_work_POWER10(CPUState *cs)
-{
-    PowerPCCPU *cpu = POWERPC_CPU(cs);
-    CPUPPCState *env = &cpu->env;
-
-    if (cs->halted) {
-        uint64_t psscr = env->spr[SPR_PSSCR];
-
-        if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
-            return false;
-        }
-
-        /* If EC is clear, just return true on any pending interrupt */
-        if (!(psscr & PSSCR_EC)) {
-            return true;
-        }
-
-        return p9_interrupt_powersave(env) != 0;
-    } else {
-        return FIELD_EX64(env->msr, MSR, EE) &&
-               (cs->interrupt_request & CPU_INTERRUPT_HARD);
-    }
-}
-
 POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
     PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-    CPUClass *cc = CPU_CLASS(oc);
 
     dc->fw_name = "PowerPC,POWER10";
     dc->desc = "POWER10";
@@ -6643,7 +6556,6 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
                          PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
     pcc->init_proc = init_proc_POWER10;
     pcc->check_pow = check_pow_nocheck;
-    cc->has_work = cpu_has_work_POWER10;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -7200,11 +7112,7 @@ static void ppc_cpu_set_pc(CPUState *cs, vaddr value)
 
 static bool ppc_cpu_has_work(CPUState *cs)
 {
-    PowerPCCPU *cpu = POWERPC_CPU(cs);
-    CPUPPCState *env = &cpu->env;
-
-    return FIELD_EX64(env->msr, MSR, EE) &&
-           (cs->interrupt_request & CPU_INTERRUPT_HARD);
+    return cs->interrupt_request & CPU_INTERRUPT_HARD;
 }
 
 static void ppc_cpu_reset(DeviceState *dev)
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [RFC PATCH v2 29/29] target/ppc: move the p*_interrupt_powersave methods to excp_helper.c
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (27 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 28/29] target/ppc: unify cpu->has_work based on cs->interrupt_request Matheus Ferst
@ 2022-09-27 20:15 ` Matheus Ferst
  2022-10-03 14:13   ` Fabiano Rosas
  2022-09-28 17:31 ` [RFC PATCH v2 00/29] PowerPC interrupt rework Cédric Le Goater
  29 siblings, 1 reply; 46+ messages in thread
From: Matheus Ferst @ 2022-09-27 20:15 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, farosas,
	Matheus Ferst

Move the methods to excp_helper.c and make them static.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
---
 target/ppc/cpu_init.c    | 102 ---------------------------------------
 target/ppc/excp_helper.c | 102 +++++++++++++++++++++++++++++++++++++++
 target/ppc/internal.h    |   6 ---
 3 files changed, 102 insertions(+), 108 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 4d0064c7a5..a9c2726d51 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -5960,30 +5960,6 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
     return true;
 }
 
-int p7_interrupt_powersave(CPUPPCState *env)
-{
-    if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-        (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
-        return PPC_INTERRUPT_EXT;
-    }
-    if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-        (env->spr[SPR_LPCR] & LPCR_P7_PECE1)) {
-        return PPC_INTERRUPT_DECR;
-    }
-    if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
-        (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
-        return PPC_INTERRUPT_MCK;
-    }
-    if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
-        (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
-        return PPC_INTERRUPT_HMI;
-    }
-    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-        return PPC_INTERRUPT_RESET;
-    }
-    return 0;
-}
-
 POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
@@ -6120,38 +6096,6 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
     return true;
 }
 
-int p8_interrupt_powersave(CPUPPCState *env)
-{
-    if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-        (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
-        return PPC_INTERRUPT_EXT;
-    }
-    if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-        (env->spr[SPR_LPCR] & LPCR_P8_PECE3)) {
-        return PPC_INTERRUPT_DECR;
-    }
-    if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
-        (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
-        return PPC_INTERRUPT_MCK;
-    }
-    if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
-        (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
-        return PPC_INTERRUPT_HMI;
-    }
-    if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
-        (env->spr[SPR_LPCR] & LPCR_P8_PECE0)) {
-        return PPC_INTERRUPT_DOORBELL;
-    }
-    if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
-        (env->spr[SPR_LPCR] & LPCR_P8_PECE1)) {
-        return PPC_INTERRUPT_HDOORBELL;
-    }
-    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-        return PPC_INTERRUPT_RESET;
-    }
-    return 0;
-}
-
 POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
@@ -6325,52 +6269,6 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
     return false;
 }
 
-int p9_interrupt_powersave(CPUPPCState *env)
-{
-    /* External Exception */
-    if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-        (env->spr[SPR_LPCR] & LPCR_EEE)) {
-        bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
-        if (!heic || !FIELD_EX64_HV(env->msr) ||
-            FIELD_EX64(env->msr, MSR, PR)) {
-            return PPC_INTERRUPT_EXT;
-        }
-    }
-    /* Decrementer Exception */
-    if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-        (env->spr[SPR_LPCR] & LPCR_DEE)) {
-        return PPC_INTERRUPT_DECR;
-    }
-    /* Machine Check or Hypervisor Maintenance Exception */
-    if (env->spr[SPR_LPCR] & LPCR_OEE) {
-        if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
-            return PPC_INTERRUPT_MCK;
-        }
-        if (env->pending_interrupts & PPC_INTERRUPT_HMI) {
-            return PPC_INTERRUPT_HMI;
-        }
-    }
-    /* Privileged Doorbell Exception */
-    if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
-        (env->spr[SPR_LPCR] & LPCR_PDEE)) {
-        return PPC_INTERRUPT_DOORBELL;
-    }
-    /* Hypervisor Doorbell Exception */
-    if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
-        (env->spr[SPR_LPCR] & LPCR_HDEE)) {
-        return PPC_INTERRUPT_HDOORBELL;
-    }
-    /* Hypervisor virtualization exception */
-    if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) &&
-        (env->spr[SPR_LPCR] & LPCR_HVEE)) {
-        return PPC_INTERRUPT_HVIRT;
-    }
-    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-        return PPC_INTERRUPT_RESET;
-    }
-    return 0;
-}
-
 POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 9708f82b30..57937956e4 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1686,6 +1686,30 @@ void ppc_cpu_do_interrupt(CPUState *cs)
      PPC_INTERRUPT_PIT | PPC_INTERRUPT_DOORBELL | PPC_INTERRUPT_HDOORBELL | \
      PPC_INTERRUPT_THERM | PPC_INTERRUPT_EBB)
 
+static int p7_interrupt_powersave(CPUPPCState *env)
+{
+    if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
+        (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
+        return PPC_INTERRUPT_EXT;
+    }
+    if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
+        (env->spr[SPR_LPCR] & LPCR_P7_PECE1)) {
+        return PPC_INTERRUPT_DECR;
+    }
+    if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
+        (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
+        return PPC_INTERRUPT_MCK;
+    }
+    if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
+        (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
+        return PPC_INTERRUPT_HMI;
+    }
+    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+        return PPC_INTERRUPT_RESET;
+    }
+    return 0;
+}
+
 static int p7_next_unmasked_interrupt(CPUPPCState *env)
 {
     PowerPCCPU *cpu = env_archcpu(env);
@@ -1751,6 +1775,38 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env)
     PPC_INTERRUPT_FIT | PPC_INTERRUPT_PIT | PPC_INTERRUPT_DOORBELL |    \
     PPC_INTERRUPT_HDOORBELL | PPC_INTERRUPT_THERM)
 
+static int p8_interrupt_powersave(CPUPPCState *env)
+{
+    if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
+        (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
+        return PPC_INTERRUPT_EXT;
+    }
+    if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
+        (env->spr[SPR_LPCR] & LPCR_P8_PECE3)) {
+        return PPC_INTERRUPT_DECR;
+    }
+    if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
+        (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
+        return PPC_INTERRUPT_MCK;
+    }
+    if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
+        (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
+        return PPC_INTERRUPT_HMI;
+    }
+    if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
+        (env->spr[SPR_LPCR] & LPCR_P8_PECE0)) {
+        return PPC_INTERRUPT_DOORBELL;
+    }
+    if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
+        (env->spr[SPR_LPCR] & LPCR_P8_PECE1)) {
+        return PPC_INTERRUPT_HDOORBELL;
+    }
+    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+        return PPC_INTERRUPT_RESET;
+    }
+    return 0;
+}
+
 static int p8_next_unmasked_interrupt(CPUPPCState *env)
 {
     PowerPCCPU *cpu = env_archcpu(env);
@@ -1820,6 +1876,52 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env)
      PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | PPC_INTERRUPT_FIT |  \
      PPC_INTERRUPT_PIT | PPC_INTERRUPT_THERM)
 
+static int p9_interrupt_powersave(CPUPPCState *env)
+{
+    /* External Exception */
+    if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
+        (env->spr[SPR_LPCR] & LPCR_EEE)) {
+        bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+        if (!heic || !FIELD_EX64_HV(env->msr) ||
+            FIELD_EX64(env->msr, MSR, PR)) {
+            return PPC_INTERRUPT_EXT;
+        }
+    }
+    /* Decrementer Exception */
+    if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
+        (env->spr[SPR_LPCR] & LPCR_DEE)) {
+        return PPC_INTERRUPT_DECR;
+    }
+    /* Machine Check or Hypervisor Maintenance Exception */
+    if (env->spr[SPR_LPCR] & LPCR_OEE) {
+        if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+            return PPC_INTERRUPT_MCK;
+        }
+        if (env->pending_interrupts & PPC_INTERRUPT_HMI) {
+            return PPC_INTERRUPT_HMI;
+        }
+    }
+    /* Privileged Doorbell Exception */
+    if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
+        (env->spr[SPR_LPCR] & LPCR_PDEE)) {
+        return PPC_INTERRUPT_DOORBELL;
+    }
+    /* Hypervisor Doorbell Exception */
+    if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
+        (env->spr[SPR_LPCR] & LPCR_HDEE)) {
+        return PPC_INTERRUPT_HDOORBELL;
+    }
+    /* Hypervisor virtualization exception */
+    if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) &&
+        (env->spr[SPR_LPCR] & LPCR_HVEE)) {
+        return PPC_INTERRUPT_HVIRT;
+    }
+    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+        return PPC_INTERRUPT_RESET;
+    }
+    return 0;
+}
+
 static int p9_next_unmasked_interrupt(CPUPPCState *env)
 {
     PowerPCCPU *cpu = env_archcpu(env);
diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index 25827ebf6f..337a362205 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -306,10 +306,4 @@ static inline int ger_pack_masks(int pmsk, int ymsk, int xmsk)
     return msk;
 }
 
-#if defined(TARGET_PPC64)
-int p9_interrupt_powersave(CPUPPCState *env);
-int p8_interrupt_powersave(CPUPPCState *env);
-int p7_interrupt_powersave(CPUPPCState *env);
-#endif
-
 #endif /* PPC_INTERNAL_H */
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 46+ messages in thread

* Re: [RFC PATCH v2 13/29] target/ppc: remove unused interrupts from p8_pending_interrupt
  2022-09-27 20:15 ` [RFC PATCH v2 13/29] target/ppc: remove unused interrupts from p8_pending_interrupt Matheus Ferst
@ 2022-09-27 22:14   ` Fabiano Rosas
  2022-10-03 15:45     ` Matheus K. Ferst
  0 siblings, 1 reply; 46+ messages in thread
From: Fabiano Rosas @ 2022-09-27 22:14 UTC (permalink / raw)
  To: Matheus Ferst, qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, Matheus Ferst

Matheus Ferst <matheus.ferst@eldorado.org.br> writes:

> Remove the following unused interrupts from the POWER8 interrupt masking
> method:
> - PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970, and POWER5p;
> - Debug Interrupt: removed in Power ISA v2.07;
> - Hypervisor Virtualization: introduced in Power ISA v3.0;
> - Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
>   for embedded CPUs;
> - Hypervisor Doorbell, Doorbell, and Critical Doorbell: processor does

We still need the first two.
0xe80 - Directed hypervisor doorbell
0xa00 - Directed privileged doorbell

>   not implement the "Embedded.Processor Control" category;
> - Programmable Interval Timer: 40x-only;
> - PPC_INTERRUPT_THERM: only raised for 970 and POWER5p;
>


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFC PATCH v2 00/29] PowerPC interrupt rework
  2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
                   ` (28 preceding siblings ...)
  2022-09-27 20:15 ` [RFC PATCH v2 29/29] target/ppc: move the p*_interrupt_powersave methods to excp_helper.c Matheus Ferst
@ 2022-09-28 17:31 ` Cédric Le Goater
  2022-10-03 15:45   ` Matheus K. Ferst
  29 siblings, 1 reply; 46+ messages in thread
From: Cédric Le Goater @ 2022-09-28 17:31 UTC (permalink / raw)
  To: Matheus Ferst, qemu-devel, qemu-ppc
  Cc: danielhb413, david, groug, fbarrat, alex.bennee, farosas

Hello Matheus,

On 9/27/22 22:15, Matheus Ferst wrote:
> Link to v1: https://lists.gnu.org/archive/html/qemu-ppc/2022-08/msg00370.html
> This series is also available as a git branch: https://github.com/PPC64/qemu/tree/ferst-interrupt-fix-v2

This is impressive work on QEMU PPC.

> This version addresses Fabiano's feedback and fixes some issues found
> with the tests suggested by Cédric. While working on it, I found two
> intermittent problems on master:
> 
>   i) ~10% of boots with pSeries and 970/970mp/POWER5+ hard lockup after

These CPUs never got real attention with KVM. The FW was even broken
before 7.0.

>      either SCSI or network initialization when using -smp 4. With
>      -smp 2, the problem is harder to reproduce but still happens, and I
>      couldn't reproduce with thread=single.
> ii) ~52% of KVM guest initializations on PowerNV hang in different parts
>      of the boot process when using more than one CPU.

Do you mean when the guest is SMP or the host ?

> With the complete series applied, I couldn't reproduce (i) anymore, 

Super ! Models are getting better. This is nice for the 970.

> and (ii) became a little more frequent (~58%).

Have you checked 'info pic' ? XIVE is in charge of vCPU scheduling.
Could you please check with powersave=off in the host kernel also ?

> I've tested each patch of this series with [1], modified to use -smp for
> machines that support more than one CPU. The machines I can currently
> boot with FreeBSD (970/970,p/POWER5+/POWER7/POWER8/POWER9 pSeries,
> POWER8/POWER9 PowerNV, and mpc8544ds) were tested with the images from
> [2] and still boot after applying the patch series. Booting nested
> guests inside a TCG pSeries machine also seems to be working fine.
> 
> Using command lines like:
> 
> ./qemu-system-ppc64 -M powernv9 -cpu POWER9 -accel tcg,thread=multi \
>                  -m 8G -smp $SMP -vga none -nographic -kernel zImage \
>                  -append 'console=hvc0' -initrdootfs.cpio.xz \
>                  -serial pipe:pipe -monitor unix:mon,server,nowait
> 
> and
> 
> ./qemu-system-ppc64 -M pseries -cpu POWER9 -accel tcg,thread=multi \
>                  -m 8G -smp $SMP -vga none -nographic -kernel zImage \
>                  -append 'console=hvc0' -initrd rootfs.cpio.xz \
>                  -serial pipe:pipe -monitor unix:mon,server,nowait
> 
> to measure the time to boot, login, and shut down a compressed kernel
> with a buildroot initramfs, with 100 iteration we get:
> 
> +-----+------------------------------+-----------------------------+
> |     |            PowerNV           |           pSeries           |
> |-smp |------------------------------+-----------------------------+
> |     |     master    | patch series |    master    | patch series |
> +-----+------------------------------+-----------------------------+
> |  1  |  45,84 ± 0,92 | 38,08 ± 0,66 | 23,56 ± 1,16 | 23,76 ± 1,04 |
> |  2  |  80,21 ± 8,03 | 40,81 ± 0,45 | 26,59 ± 0,92 | 26,88 ± 0,99 |
> |  4  | 115,98 ± 9,85 | 38,80 ± 0,44 | 28,83 ± 0,84 | 28,46 ± 0,94 |
> |  6  | 199,14 ± 6,36 | 39,32 ± 0,50 | 29,22 ± 0,78 | 29,45 ± 0,86 |
> |  8  | 47,85 ± 27,50 | 38,98 ± 0,49 | 29,63 ± 0,80 | 29,60 ± 0,78 |
> +-----+------------------------------+-----------------------------+
> 
> This results shows that the problem reported in [3] is solved, while

Yes. Nice work ! The PowerNV results with -smp 8 on master are unexpected.
Did you do some profiling also ?
  
> pSeries boot time is essentially unchanged.
>
> 
> With a non-compressed kernel, the difference with PowerNV is smaller,
> and pSeries stills the same:
> 
> +-----+------------------------------+-----------------------------+
> |     |            PowerNV           |           pSeries           |
> |-smp |------------------------------+-----------------------------+
> |     |     master    | patch series |    master    | patch series |
> +-----+------------------------------+-----------------------------+
> |  1  |  42,17 ± 0,92 | 38,13 ± 0,59 | 23,15 ± 1,02 | 23,46 ± 1,02 |
> |  2  |  55,72 ± 3,54 | 40,30 ± 0,56 | 26,26 ± 0,82 | 26,38 ± 0,80 |
> |  4  |  67,09 ± 3,02 | 38,26 ± 0,47 | 28,36 ± 0,77 | 28,19 ± 0,78 |
> |  6  |  98,96 ± 2,49 | 39,01 ± 0,38 | 28,68 ± 0,75 | 29,02 ± 0,88 |
> |  8  |  39,68 ± 0,42 | 38,44 ± 0,41 | 29,24 ± 0,81 | 29,44 ± 0,75 |
> +-----+------------------------------+-----------------------------+
> 
> Finally, using command lines like
> 
> ./qemu-system-ppc64 -M powernv9 -cpu POWER9 -accel tcg,thread=multi \
>      -m 8G -smp 4 -device virtio-scsi-pci -boot c -vga none -nographic \
>      -device nvme,bus=pcie.2,addr=0x0,drive=drive0,serial=1234 \
>      -drive file=rootfs.ext2,if=none,id=drive0,format=raw,cache=none \
>      -snapshot -serial pipe:pipe -monitor unix:mon,server,nowait \
>      -kernel zImage -append 'console=hvc0 rootwait root=/dev/nvme0n1' \
>      -device virtio-net-pci,netdev=br0,mac=52:54:00:12:34:57,bus=pcie.0 \
>      -netdev bridge,id=br0
> 
> and
> 
> ./qemu-system-ppc64 -M pseries -cpu POWER9 -accel tcg,thread=multi \
>      -m 8G -smp 4 -device virtio-scsi-pci -boot c -vga none -nographic \
>      -drive file=rootfs.ext2,if=scsi,index=0,format=raw -snapshot \
>      -kernel zImage -append 'console=hvc0 rootwait root=/dev/sda' \
>      -serial pipe:pipe -monitor unix:mon,server,nowait \
>      -device virtio-net-pci,netdev=br0,mac=52:54:00:12:34:57 \
>      -netdev bridge,id=br0
> 
> to tests IO performance, with iperf to test network and a 4Gb scp
> transfer to test disk+network, in 100 iterations we saw:
> 
> +---------------------+---------------+-----------------+
> |                     |    scp (s)    |   iperf (MB/s)  |
> +---------------------+---------------+-----------------+
> |PowerNV master       | 166,91 ± 8,37 | 918,06 ± 114,78 |
> |PowerNV patch series | 166,25 ± 8,85 | 916,91 ± 107,56 |
> |pSeries master       | 175,70 ± 8,22 | 958,73 ± 115,09 |
> |pSeries patch series | 173,62 ± 8,13 | 893,42 ±  87,77 |
> +---------------------+---------------+-----------------+

These are SMP machines under high IO load using MTTCG. It means
that the models are quite robust now.

> The scp data shows little difference, while testing just network shows
> that it's a bit slower with the patch series applied (although, with
> this variation, we'd probably need to repeat this test more times to
> have a more robust result...)

You could try with powersave=off.

Thanks,

C.



> [1] https://github.com/legoater/qemu-ppc-boot
> [2] https://artifact.ci.freebsd.org/snapshot/14.0-CURRENT/latest_vm/powerpc
> [3] https://lists.gnu.org/archive/html/qemu-ppc/2022-06/msg00336.html
> 
> Matheus Ferst (29):
>    target/ppc: define PPC_INTERRUPT_* values directly
>    target/ppc: always use ppc_set_irq to set env->pending_interrupts
>    target/ppc: split interrupt masking and delivery from ppc_hw_interrupt
>    target/ppc: prepare to split interrupt masking and delivery by excp_model
>    target/ppc: create an interrupt masking method for POWER9/POWER10
>    target/ppc: remove unused interrupts from p9_pending_interrupt
>    target/ppc: create an interrupt deliver method for POWER9/POWER10
>    target/ppc: remove unused interrupts from p9_deliver_interrupt
>    target/ppc: remove generic architecture checks from p9_deliver_interrupt
>    target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER9
>    target/ppc: add power-saving interrupt masking logic to p9_next_unmasked_interrupt
>    target/ppc: create an interrupt masking method for POWER8
>    target/ppc: remove unused interrupts from p8_pending_interrupt
>    target/ppc: create an interrupt deliver method for POWER8
>    target/ppc: remove unused interrupts from p8_deliver_interrupt
>    target/ppc: remove generic architecture checks from p8_deliver_interrupt
>    target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER8
>    target/ppc: add power-saving interrupt masking logic to p8_next_unmasked_interrupt
>    target/ppc: create an interrupt masking method for POWER7
>    target/ppc: remove unused interrupts from p7_pending_interrupt
>    target/ppc: create an interrupt deliver method for POWER7
>    target/ppc: remove unused interrupts from p7_deliver_interrupt
>    target/ppc: remove generic architecture checks from p7_deliver_interrupt
>    target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER7
>    target/ppc: add power-saving interrupt masking logic to p7_next_unmasked_interrupt
>    target/ppc: remove ppc_store_lpcr from CONFIG_USER_ONLY builds
>    target/ppc: introduce ppc_maybe_interrupt
>    target/ppc: unify cpu->has_work based on cs->interrupt_request
>    target/ppc: move the p*_interrupt_powersave methods to excp_helper.c
> 
>   hw/ppc/pnv_core.c        |   1 +
>   hw/ppc/ppc.c             |  17 +-
>   hw/ppc/spapr_hcall.c     |   6 +
>   hw/ppc/spapr_rtas.c      |   2 +-
>   hw/ppc/trace-events      |   2 +-
>   target/ppc/cpu.c         |   4 +
>   target/ppc/cpu.h         |  43 +-
>   target/ppc/cpu_init.c    | 212 +---------
>   target/ppc/excp_helper.c | 857 ++++++++++++++++++++++++++++++++++-----
>   target/ppc/helper.h      |   1 +
>   target/ppc/helper_regs.c |   2 +
>   target/ppc/misc_helper.c |  11 +-
>   target/ppc/translate.c   |   2 +
>   13 files changed, 803 insertions(+), 357 deletions(-)
> 



^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFC PATCH v2 02/29] target/ppc: always use ppc_set_irq to set env->pending_interrupts
  2022-09-27 20:15 ` [RFC PATCH v2 02/29] target/ppc: always use ppc_set_irq to set env->pending_interrupts Matheus Ferst
@ 2022-09-30 14:32   ` Fabiano Rosas
  0 siblings, 0 replies; 46+ messages in thread
From: Fabiano Rosas @ 2022-09-30 14:32 UTC (permalink / raw)
  To: Matheus Ferst, qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, Matheus Ferst

Matheus Ferst <matheus.ferst@eldorado.org.br> writes:

> Use ppc_set_irq to raise/clear interrupts to ensure CPU_INTERRUPT_HARD
> will be set/reset accordingly.
>
> Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>

Reviewed-by: Fabiano Rosas <farosas@linux.ibm.com>


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFC PATCH v2 03/29] target/ppc: split interrupt masking and delivery from ppc_hw_interrupt
  2022-09-27 20:15 ` [RFC PATCH v2 03/29] target/ppc: split interrupt masking and delivery from ppc_hw_interrupt Matheus Ferst
@ 2022-09-30 15:55   ` Fabiano Rosas
  0 siblings, 0 replies; 46+ messages in thread
From: Fabiano Rosas @ 2022-09-30 15:55 UTC (permalink / raw)
  To: Matheus Ferst, qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, Matheus Ferst

Matheus Ferst <matheus.ferst@eldorado.org.br> writes:

> Split ppc_hw_interrupt into an interrupt masking method,
> ppc_next_unmasked_interrupt, and an interrupt processing method,
> ppc_deliver_interrupt.
>

<snip>

> @@ -1822,20 +1782,106 @@ static void ppc_hw_interrupt(CPUPPCState *env)
>               */
>              if (FIELD_EX64(env->msr, MSR, PR) &&
>                  (env->spr[SPR_BESCR] & BESCR_GE)) {
> -                env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
> -
> -                if (env->spr[SPR_BESCR] & BESCR_PMEO) {
> -                    powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
> -                } else if (env->spr[SPR_BESCR] & BESCR_EEO) {
> -                    powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB);
> -                }
> -
> -                return;
> +                return PPC_INTERRUPT_EBB;
>              }
>          }
>      }
>  
> -    if (env->resume_as_sreset) {
> +    return 0;
> +}
> +
> +static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt)
> +{
> +    PowerPCCPU *cpu = env_archcpu(env);
> +    CPUState *cs = env_cpu(env);
> +
> +    switch (interrupt) {
> +    case PPC_INTERRUPT_RESET: /* External reset */
> +        env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
> +        powerpc_excp(cpu, POWERPC_EXCP_RESET);
> +        break;
> +    case PPC_INTERRUPT_MCK: /* Machine check exception */
> +        env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
> +        powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
> +        break;
> +#if 0 /* TODO */
> +    case PPC_INTERRUPT_DEBUG: /* External debug exception */
> +        env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
> +        powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
> +        break;
> +#endif
> +
> +    case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */
> +        /* HDEC clears on delivery */
> +        env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
> +        powerpc_excp(cpu, POWERPC_EXCP_HDECR);
> +        break;
> +    case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */
> +        powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
> +        break;
> +
> +    case PPC_INTERRUPT_EXT:
> +        if (books_vhyp_promotes_external_to_hvirt(cpu)) {
> +            powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
> +        } else {
> +            powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
> +        }
> +        break;
> +    case PPC_INTERRUPT_CEXT: /* External critical interrupt */
> +        powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
> +        break;
> +
> +    case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
> +        env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
> +        powerpc_excp(cpu, POWERPC_EXCP_WDT);
> +        break;
> +    case PPC_INTERRUPT_CDOORBELL:
> +        env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
> +        powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
> +        break;
> +    case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
> +        env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
> +        powerpc_excp(cpu, POWERPC_EXCP_FIT);
> +        break;
> +    case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC */
> +        env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
> +        powerpc_excp(cpu, POWERPC_EXCP_PIT);
> +        break;
> +    case PPC_INTERRUPT_DECR: /* Decrementer exception */
> +        if (ppc_decr_clear_on_delivery(env)) {
> +            env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
> +        }
> +        powerpc_excp(cpu, POWERPC_EXCP_DECR);
> +        break;
> +    case PPC_INTERRUPT_DOORBELL:
> +        env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
> +        if (is_book3s_arch2x(env)) {
> +            powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
> +        } else {
> +            powerpc_excp(cpu, POWERPC_EXCP_DOORI);
> +        }
> +        break;
> +    case PPC_INTERRUPT_HDOORBELL:
> +        env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
> +        powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
> +        break;
> +    case PPC_INTERRUPT_PERFM:
> +        env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
> +        powerpc_excp(cpu, POWERPC_EXCP_PERFM);
> +        break;
> +    case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
> +        env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
> +        powerpc_excp(cpu, POWERPC_EXCP_THERM);
> +        break;
> +    case PPC_INTERRUPT_EBB: /* EBB exception */
> +        env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
> +        if (env->spr[SPR_BESCR] & BESCR_PMEO) {
> +            powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
> +        } else if (env->spr[SPR_BESCR] & BESCR_EEO) {
> +            powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB);
> +        }
> +        break;
> +    case 0:
>          /*
>           * This is a bug ! It means that has_work took us out of halt without
>           * anything to deliver while in a PM state that requires getting
> @@ -1847,8 +1893,10 @@ static void ppc_hw_interrupt(CPUPPCState *env)
>           * It generally means a discrepancy between the wakeup conditions in the
>           * processor has_work implementation and the logic in this function.
>           */
> -        cpu_abort(env_cpu(env),
> -                  "Wakeup from PM state but interrupt Undelivered");
> +        assert(env->resume_as_sreset != 0);

This should be: assert(!env->resume_as_sreset);

> +        break;
> +    default:
> +        cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt);
>      }
>  }
>  
> @@ -1884,15 +1932,22 @@ bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
>  {
>      PowerPCCPU *cpu = POWERPC_CPU(cs);
>      CPUPPCState *env = &cpu->env;
> +    int interrupt;
>  
> -    if (interrupt_request & CPU_INTERRUPT_HARD) {
> -        ppc_hw_interrupt(env);
> -        if (env->pending_interrupts == 0) {
> -            cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
> -        }
> -        return true;
> +    if ((interrupt_request & CPU_INTERRUPT_HARD) == 0) {
> +        return false;
>      }
> -    return false;
> +
> +    interrupt = ppc_next_unmasked_interrupt(env);
> +    if (interrupt == 0) {
> +        return false;
> +    }
> +
> +    ppc_deliver_interrupt(env, interrupt);
> +    if (env->pending_interrupts == 0) {
> +        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
> +    }
> +    return true;
>  }
>  
>  #endif /* !CONFIG_USER_ONLY */


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFC PATCH v2 09/29] target/ppc: remove generic architecture checks from p9_deliver_interrupt
  2022-09-27 20:15 ` [RFC PATCH v2 09/29] target/ppc: remove generic architecture checks " Matheus Ferst
@ 2022-09-30 18:13   ` Fabiano Rosas
  2022-10-03 15:45     ` Matheus K. Ferst
  0 siblings, 1 reply; 46+ messages in thread
From: Fabiano Rosas @ 2022-09-30 18:13 UTC (permalink / raw)
  To: Matheus Ferst, qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, Matheus Ferst

Matheus Ferst <matheus.ferst@eldorado.org.br> writes:

> No functional change intended.
>
> Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
> ---
>  target/ppc/excp_helper.c | 9 +--------
>  1 file changed, 1 insertion(+), 8 deletions(-)
>
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 603c956588..67e73f30ab 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -1919,18 +1919,11 @@ static void p9_deliver_interrupt(CPUPPCState *env, int interrupt)
>          break;
>  
>      case PPC_INTERRUPT_DECR: /* Decrementer exception */
> -        if (ppc_decr_clear_on_delivery(env)) {
> -            env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
> -        }

Maybe I'm missing something, but this should continue to clear the bit,
no? Same comment for P8.

>          powerpc_excp(cpu, POWERPC_EXCP_DECR);
>          break;
>      case PPC_INTERRUPT_DOORBELL:
>          env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
> -        if (is_book3s_arch2x(env)) {
> -            powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
> -        } else {
> -            powerpc_excp(cpu, POWERPC_EXCP_DOORI);
> -        }
> +        powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
>          break;
>      case PPC_INTERRUPT_HDOORBELL:
>          env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFC PATCH v2 11/29] target/ppc: add power-saving interrupt masking logic to p9_next_unmasked_interrupt
  2022-09-27 20:15 ` [RFC PATCH v2 11/29] target/ppc: add power-saving interrupt masking logic to p9_next_unmasked_interrupt Matheus Ferst
@ 2022-09-30 18:38   ` Fabiano Rosas
  2022-10-03 15:46     ` Matheus K. Ferst
  0 siblings, 1 reply; 46+ messages in thread
From: Fabiano Rosas @ 2022-09-30 18:38 UTC (permalink / raw)
  To: Matheus Ferst, qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, Matheus Ferst

Matheus Ferst <matheus.ferst@eldorado.org.br> writes:

> Export p9_interrupt_powersave and use it in p9_next_unmasked_interrupt.
>
> Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
> ---
> Temporarily putting the prototype in internal.h for lack of a better place,
> we will un-export p9_interrupt_powersave in future patches.
> ---
>  target/ppc/cpu_init.c    |  2 +-
>  target/ppc/excp_helper.c | 46 ++++++++++++++++++++++++++++------------
>  target/ppc/internal.h    |  4 ++++
>  3 files changed, 38 insertions(+), 14 deletions(-)
>
> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> index 1f8f6c6ef2..7889158c52 100644
> --- a/target/ppc/cpu_init.c
> +++ b/target/ppc/cpu_init.c
> @@ -6351,7 +6351,7 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
>      return false;
>  }
>  
> -static int p9_interrupt_powersave(CPUPPCState *env)
> +int p9_interrupt_powersave(CPUPPCState *env)
>  {
>      /* External Exception */
>      if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 67e73f30ab..5a0d2c11a2 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -1686,28 +1686,39 @@ void ppc_cpu_do_interrupt(CPUState *cs)
>  
>  static int p9_next_unmasked_interrupt(CPUPPCState *env)
>  {
> -    bool async_deliver;
> +    PowerPCCPU *cpu = env_archcpu(env);
> +    CPUState *cs = CPU(cpu);
> +    /* Ignore MSR[EE] when coming out of some power management states */
> +    bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
>  
>      assert((env->pending_interrupts & P9_UNUSED_INTERRUPTS) == 0);
>  
> +    if (cs->halted) {
> +        if (env->spr[SPR_PSSCR] & PSSCR_EC) {
> +            /*
> +             * When PSSCR[EC] is set, LPCR[PECE] controls which interrupts can
> +             * wakeup the processor
> +             */
> +            return p9_interrupt_powersave(env);
> +        } else {
> +            /*
> +             * When it's clear, any system-caused exception exits power-saving
> +             * mode, even the ones that gate on MSR[EE].
> +             */
> +            msr_ee = true;
> +        }
> +    }
> +
>      /* Machine check exception */
>      if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
>          return PPC_INTERRUPT_MCK;
>      }
>  
> -    /*
> -     * For interrupts that gate on MSR:EE, we need to do something a
> -     * bit more subtle, as we need to let them through even when EE is
> -     * clear when coming out of some power management states (in order
> -     * for them to become a 0x100).
> -     */
> -    async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
> -

You could simplify the code below if you bail early here when !msr_ee.

>      /* Hypervisor decrementer exception */
>      if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
>          /* LPCR will be clear when not supported so this will work */
>          bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
> -        if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
> +        if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) {
>              /* HDEC clears on delivery */
>              return PPC_INTERRUPT_HDECR;
>          }
> @@ -1717,7 +1728,7 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
>      if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
>          /* LPCR will be clear when not supported so this will work */
>          bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
> -        if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
> +        if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hvice) {
>              return PPC_INTERRUPT_HVIRT;
>          }
>      }
> @@ -1727,13 +1738,13 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
>          bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
>          bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
>          /* HEIC blocks delivery to the hypervisor */
> -        if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
> +        if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) &&
>              !FIELD_EX64(env->msr, MSR, PR))) ||
>              (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
>              return PPC_INTERRUPT_EXT;
>          }
>      }
> -    if (async_deliver != 0) {
> +    if (msr_ee != 0) {
>          /* Decrementer exception */
>          if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
>              return PPC_INTERRUPT_DECR;
> @@ -1895,6 +1906,15 @@ static void p9_deliver_interrupt(CPUPPCState *env, int interrupt)
>      PowerPCCPU *cpu = env_archcpu(env);
>      CPUState *cs = env_cpu(env);
>  
> +    if (cs->halted && !(env->spr[SPR_PSSCR] & PSSCR_EC) &&
> +        !FIELD_EX64(env->msr, MSR, EE)) {
> +        /*
> +         * A pending interrupt took us out of power-saving, but MSR[EE] says
> +         * that we should return to NIP+4 instead of delivering it.
> +         */
> +        return;

How will the NIP be advanced in this case?

> +    }
> +
>      switch (interrupt) {
>      case PPC_INTERRUPT_MCK: /* Machine check exception */
>          env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
> diff --git a/target/ppc/internal.h b/target/ppc/internal.h
> index 337a362205..41e79adfdb 100644
> --- a/target/ppc/internal.h
> +++ b/target/ppc/internal.h
> @@ -306,4 +306,8 @@ static inline int ger_pack_masks(int pmsk, int ymsk, int xmsk)
>      return msk;
>  }
>  
> +#if defined(TARGET_PPC64)
> +int p9_interrupt_powersave(CPUPPCState *env);
> +#endif
> +
>  #endif /* PPC_INTERNAL_H */


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFC PATCH v2 27/29] target/ppc: introduce ppc_maybe_interrupt
  2022-09-27 20:15 ` [RFC PATCH v2 27/29] target/ppc: introduce ppc_maybe_interrupt Matheus Ferst
@ 2022-10-03 14:11   ` Fabiano Rosas
  0 siblings, 0 replies; 46+ messages in thread
From: Fabiano Rosas @ 2022-10-03 14:11 UTC (permalink / raw)
  To: Matheus Ferst, qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, Matheus Ferst

Matheus Ferst <matheus.ferst@eldorado.org.br> writes:

> The method checks if any pending interrupt is unmasked and calls
> cpu_interrupt/cpu_reset_interrupt accordingly. Code that raises/lowers
> or masks/unmasks interrupts should call this method to keep
> CPU_INTERRUPT_HARD coherent with env->pending_interrupts.
>
> Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
> ---
> v2:
>   - Found many other places where ppc_maybe_interrupt had to be called
>     with the IO and kvm-nested tests that Cédric suggested.

We might need some words describing the situations in which this
function should be used to avoid new code missing it.

>   - Create a helper to call ppc_maybe_interrupt to avoid using
>     helper_store_msr in WRTEE[I].
>
> I couldn't find a better name for this method, so I used "maybe
> interrupt" just like we have "maybe bswap" for gdbstub registers.
> ---
>  hw/ppc/pnv_core.c        |  1 +
>  hw/ppc/ppc.c             |  7 +------
>  hw/ppc/spapr_hcall.c     |  6 ++++++
>  hw/ppc/spapr_rtas.c      |  2 +-
>  target/ppc/cpu.c         |  2 ++
>  target/ppc/cpu.h         |  1 +
>  target/ppc/excp_helper.c | 29 +++++++++++++++++++++++++++++
>  target/ppc/helper.h      |  1 +
>  target/ppc/helper_regs.c |  2 ++
>  target/ppc/translate.c   |  2 ++
>  10 files changed, 46 insertions(+), 7 deletions(-)
>
> diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
> index 19e8eb885f..9ee79192dd 100644
> --- a/hw/ppc/pnv_core.c
> +++ b/hw/ppc/pnv_core.c
> @@ -58,6 +58,7 @@ static void pnv_core_cpu_reset(PnvCore *pc, PowerPCCPU *cpu)
>      env->msr |= MSR_HVB; /* Hypervisor mode */
>      env->spr[SPR_HRMOR] = pc->hrmor;
>      hreg_compute_hflags(env);
> +    ppc_maybe_interrupt(env);
>  
>      pcc->intc_reset(pc->chip, cpu);
>  }
> diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
> index 77e611e81c..dc86c1c7db 100644
> --- a/hw/ppc/ppc.c
> +++ b/hw/ppc/ppc.c
> @@ -42,7 +42,6 @@ static void cpu_ppc_tb_start (CPUPPCState *env);
>  
>  void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
>  {
> -    CPUState *cs = CPU(cpu);
>      CPUPPCState *env = &cpu->env;
>      unsigned int old_pending;
>      bool locked = false;
> @@ -57,19 +56,15 @@ void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
>  
>      if (level) {
>          env->pending_interrupts |= irq;
> -        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
>      } else {
>          env->pending_interrupts &= ~irq;
> -        if (env->pending_interrupts == 0) {
> -            cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
> -        }
>      }
>  
>      if (old_pending != env->pending_interrupts) {
> +        ppc_maybe_interrupt(env);
>          kvmppc_set_interrupt(cpu, irq, level);
>      }
>  
> -
>      trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts,
>                             CPU(cpu)->interrupt_request);
>  
> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> index a8d4a6bcf0..23aa41c879 100644
> --- a/hw/ppc/spapr_hcall.c
> +++ b/hw/ppc/spapr_hcall.c
> @@ -490,6 +490,7 @@ static target_ulong h_cede(PowerPCCPU *cpu, SpaprMachineState *spapr,
>  
>      env->msr |= (1ULL << MSR_EE);
>      hreg_compute_hflags(env);
> +    ppc_maybe_interrupt(env);
>  
>      if (spapr_cpu->prod) {
>          spapr_cpu->prod = false;
> @@ -500,6 +501,7 @@ static target_ulong h_cede(PowerPCCPU *cpu, SpaprMachineState *spapr,
>          cs->halted = 1;
>          cs->exception_index = EXCP_HLT;
>          cs->exit_request = 1;
> +        ppc_maybe_interrupt(env);
>      }
>  
>      return H_SUCCESS;
> @@ -521,6 +523,7 @@ static target_ulong h_confer_self(PowerPCCPU *cpu)
>      cs->halted = 1;
>      cs->exception_index = EXCP_HALTED;
>      cs->exit_request = 1;
> +    ppc_maybe_interrupt(&cpu->env);
>  
>      return H_SUCCESS;
>  }
> @@ -633,6 +636,7 @@ static target_ulong h_prod(PowerPCCPU *cpu, SpaprMachineState *spapr,
>      spapr_cpu = spapr_cpu_state(tcpu);
>      spapr_cpu->prod = true;
>      cs->halted = 0;
> +    ppc_maybe_interrupt(&cpu->env);
>      qemu_cpu_kick(cs);
>  
>      return H_SUCCESS;
> @@ -1661,6 +1665,7 @@ static target_ulong h_enter_nested(PowerPCCPU *cpu,
>      spapr_cpu->in_nested = true;
>  
>      hreg_compute_hflags(env);
> +    ppc_maybe_interrupt(env);
>      tlb_flush(cs);
>      env->reserve_addr = -1; /* Reset the reservation */
>  
> @@ -1802,6 +1807,7 @@ out_restore_l1:
>      spapr_cpu->in_nested = false;
>  
>      hreg_compute_hflags(env);
> +    ppc_maybe_interrupt(env);
>      tlb_flush(cs);
>      env->reserve_addr = -1; /* Reset the reservation */
>  
> diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
> index d58b65e88f..3f664ea02c 100644
> --- a/hw/ppc/spapr_rtas.c
> +++ b/hw/ppc/spapr_rtas.c
> @@ -214,9 +214,9 @@ static void rtas_stop_self(PowerPCCPU *cpu, SpaprMachineState *spapr,
>       * guest.
>       * For the same reason, set PSSCR_EC.
>       */
> -    ppc_store_lpcr(cpu, env->spr[SPR_LPCR] & ~pcc->lpcr_pm);
>      env->spr[SPR_PSSCR] |= PSSCR_EC;
>      cs->halted = 1;
> +    ppc_store_lpcr(cpu, env->spr[SPR_LPCR] & ~pcc->lpcr_pm);
>      kvmppc_set_reg_ppc_online(cpu, 0);
>      qemu_cpu_kick(cs);
>  }
> diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c
> index e95b4c5ee1..1a97b41c6b 100644
> --- a/target/ppc/cpu.c
> +++ b/target/ppc/cpu.c
> @@ -82,6 +82,8 @@ void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
>      env->spr[SPR_LPCR] = val & pcc->lpcr_mask;
>      /* The gtse bit affects hflags */
>      hreg_compute_hflags(env);
> +
> +    ppc_maybe_interrupt(env);
>  }
>  #endif
>  
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index 7b13d4cf86..89c065521f 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -1358,6 +1358,7 @@ int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
>  int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
>                                 int cpuid, void *opaque);
>  #ifndef CONFIG_USER_ONLY
> +void ppc_maybe_interrupt(CPUPPCState *env);
>  void ppc_cpu_do_interrupt(CPUState *cpu);
>  bool ppc_cpu_exec_interrupt(CPUState *cpu, int int_req);
>  void ppc_cpu_do_system_reset(CPUState *cs);
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 497a9889d1..9708f82b30 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -390,6 +390,7 @@ static void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong vector,
>      env->nip = vector;
>      env->msr = msr;
>      hreg_compute_hflags(env);
> +    ppc_maybe_interrupt(env);
>  
>      powerpc_reset_excp_state(cpu);
>  
> @@ -2039,6 +2040,27 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
>      }
>  }
>  
> +void ppc_maybe_interrupt(CPUPPCState *env)
> +{
> +    CPUState *cs = env_cpu(env);
> +    bool locked = false;
> +
> +    if (!qemu_mutex_iothread_locked()) {
> +        locked = true;
> +        qemu_mutex_lock_iothread();
> +    }
> +
> +    if (ppc_next_unmasked_interrupt(env)) {
> +        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
> +    } else {
> +        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
> +    }
> +
> +    if (locked) {
> +        qemu_mutex_unlock_iothread();
> +    }
> +}
> +
>  #if defined(TARGET_PPC64)
>  static void p7_deliver_interrupt(CPUPPCState *env, int interrupt)
>  {
> @@ -2474,6 +2496,11 @@ void helper_store_msr(CPUPPCState *env, target_ulong val)
>      }
>  }
>  
> +void helper_ppc_maybe_interrupt(CPUPPCState *env)
> +{
> +    ppc_maybe_interrupt(env);
> +}
> +
>  #if defined(TARGET_PPC64)
>  void helper_scv(CPUPPCState *env, uint32_t lev)
>  {
> @@ -2494,6 +2521,8 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
>      /* Condition for waking up at 0x100 */
>      env->resume_as_sreset = (insn != PPC_PM_STOP) ||
>          (env->spr[SPR_PSSCR] & PSSCR_EC);
> +
> +    ppc_maybe_interrupt(env);
>  }
>  #endif /* defined(TARGET_PPC64) */
>  
> diff --git a/target/ppc/helper.h b/target/ppc/helper.h
> index 57eee07256..3d09aae5fc 100644
> --- a/target/ppc/helper.h
> +++ b/target/ppc/helper.h
> @@ -10,6 +10,7 @@ DEF_HELPER_4(HASHSTP, void, env, tl, tl, tl)
>  DEF_HELPER_4(HASHCHKP, void, env, tl, tl, tl)
>  #if !defined(CONFIG_USER_ONLY)
>  DEF_HELPER_2(store_msr, void, env, tl)
> +DEF_HELPER_1(ppc_maybe_interrupt, void, env)
>  DEF_HELPER_1(rfi, void, env)
>  DEF_HELPER_1(40x_rfci, void, env)
>  DEF_HELPER_1(rfci, void, env)
> diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c
> index 12235ea2e9..2e85e124ab 100644
> --- a/target/ppc/helper_regs.c
> +++ b/target/ppc/helper_regs.c
> @@ -260,6 +260,8 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv)
>      env->msr = value;
>      hreg_compute_hflags(env);
>  #if !defined(CONFIG_USER_ONLY)
> +    ppc_maybe_interrupt(env);
> +
>      if (unlikely(FIELD_EX64(env->msr, MSR, POW))) {
>          if (!env->pending_interrupts && (*env->check_pow)(env)) {
>              cs->halted = 1;
> diff --git a/target/ppc/translate.c b/target/ppc/translate.c
> index e810842925..e8336452c4 100644
> --- a/target/ppc/translate.c
> +++ b/target/ppc/translate.c
> @@ -6175,6 +6175,7 @@ static void gen_wrtee(DisasContext *ctx)
>      tcg_gen_andi_tl(t0, cpu_gpr[rD(ctx->opcode)], (1 << MSR_EE));
>      tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(1 << MSR_EE));
>      tcg_gen_or_tl(cpu_msr, cpu_msr, t0);
> +    gen_helper_ppc_maybe_interrupt(cpu_env);
>      tcg_temp_free(t0);
>      /*
>       * Stop translation to have a chance to raise an exception if we
> @@ -6193,6 +6194,7 @@ static void gen_wrteei(DisasContext *ctx)
>      CHK_SV(ctx);
>      if (ctx->opcode & 0x00008000) {
>          tcg_gen_ori_tl(cpu_msr, cpu_msr, (1 << MSR_EE));
> +        gen_helper_ppc_maybe_interrupt(cpu_env);
>          /* Stop translation to have a chance to raise an exception */
>          ctx->base.is_jmp = DISAS_EXIT_UPDATE;
>      } else {


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFC PATCH v2 28/29] target/ppc: unify cpu->has_work based on cs->interrupt_request
  2022-09-27 20:15 ` [RFC PATCH v2 28/29] target/ppc: unify cpu->has_work based on cs->interrupt_request Matheus Ferst
@ 2022-10-03 14:12   ` Fabiano Rosas
  0 siblings, 0 replies; 46+ messages in thread
From: Fabiano Rosas @ 2022-10-03 14:12 UTC (permalink / raw)
  To: Matheus Ferst, qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, Matheus Ferst

Matheus Ferst <matheus.ferst@eldorado.org.br> writes:

> Now that cs->interrupt_request indicates if there is any unmasked
> interrupt, checking if the CPU has work to do can be simplified to a
> single check that works for all CPU models.
>
> Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>

Reviewed-by: Fabiano Rosas <farosas@linux.ibm.com>

> ---
>  target/ppc/cpu_init.c | 94 +------------------------------------------
>  1 file changed, 1 insertion(+), 93 deletions(-)
>
> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> index 26686d1557..4d0064c7a5 100644
> --- a/target/ppc/cpu_init.c
> +++ b/target/ppc/cpu_init.c
> @@ -5984,27 +5984,10 @@ int p7_interrupt_powersave(CPUPPCState *env)
>      return 0;
>  }
>  
> -static bool cpu_has_work_POWER7(CPUState *cs)
> -{
> -    PowerPCCPU *cpu = POWERPC_CPU(cs);
> -    CPUPPCState *env = &cpu->env;
> -
> -    if (cs->halted) {
> -        if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
> -            return false;
> -        }
> -        return p7_interrupt_powersave(env) != 0;
> -    } else {
> -        return FIELD_EX64(env->msr, MSR, EE) &&
> -               (cs->interrupt_request & CPU_INTERRUPT_HARD);
> -    }
> -}
> -
>  POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
>  {
>      DeviceClass *dc = DEVICE_CLASS(oc);
>      PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
> -    CPUClass *cc = CPU_CLASS(oc);
>  
>      dc->fw_name = "PowerPC,POWER7";
>      dc->desc = "POWER7";
> @@ -6013,7 +5996,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
>      pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
>      pcc->init_proc = init_proc_POWER7;
>      pcc->check_pow = check_pow_nocheck;
> -    cc->has_work = cpu_has_work_POWER7;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -6170,27 +6152,10 @@ int p8_interrupt_powersave(CPUPPCState *env)
>      return 0;
>  }
>  
> -static bool cpu_has_work_POWER8(CPUState *cs)
> -{
> -    PowerPCCPU *cpu = POWERPC_CPU(cs);
> -    CPUPPCState *env = &cpu->env;
> -
> -    if (cs->halted) {
> -        if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
> -            return false;
> -        }
> -        return p8_interrupt_powersave(env) != 0;
> -    } else {
> -        return FIELD_EX64(env->msr, MSR, EE) &&
> -               (cs->interrupt_request & CPU_INTERRUPT_HARD);
> -    }
> -}
> -
>  POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
>  {
>      DeviceClass *dc = DEVICE_CLASS(oc);
>      PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
> -    CPUClass *cc = CPU_CLASS(oc);
>  
>      dc->fw_name = "PowerPC,POWER8";
>      dc->desc = "POWER8";
> @@ -6199,7 +6164,6 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
>      pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
>      pcc->init_proc = init_proc_POWER8;
>      pcc->check_pow = check_pow_nocheck;
> -    cc->has_work = cpu_has_work_POWER8;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -6407,35 +6371,10 @@ int p9_interrupt_powersave(CPUPPCState *env)
>      return 0;
>  }
>  
> -static bool cpu_has_work_POWER9(CPUState *cs)
> -{
> -    PowerPCCPU *cpu = POWERPC_CPU(cs);
> -    CPUPPCState *env = &cpu->env;
> -
> -    if (cs->halted) {
> -        uint64_t psscr = env->spr[SPR_PSSCR];
> -
> -        if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
> -            return false;
> -        }
> -
> -        /* If EC is clear, just return true on any pending interrupt */
> -        if (!(psscr & PSSCR_EC)) {
> -            return true;
> -        }
> -
> -        return p9_interrupt_powersave(env) != 0;
> -    } else {
> -        return FIELD_EX64(env->msr, MSR, EE) &&
> -               (cs->interrupt_request & CPU_INTERRUPT_HARD);
> -    }
> -}
> -
>  POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
>  {
>      DeviceClass *dc = DEVICE_CLASS(oc);
>      PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
> -    CPUClass *cc = CPU_CLASS(oc);
>  
>      dc->fw_name = "PowerPC,POWER9";
>      dc->desc = "POWER9";
> @@ -6445,7 +6384,6 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
>                           PCR_COMPAT_2_05;
>      pcc->init_proc = init_proc_POWER9;
>      pcc->check_pow = check_pow_nocheck;
> -    cc->has_work = cpu_has_work_POWER9;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -6604,35 +6542,10 @@ static bool ppc_pvr_match_power10(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
>      return false;
>  }
>  
> -static bool cpu_has_work_POWER10(CPUState *cs)
> -{
> -    PowerPCCPU *cpu = POWERPC_CPU(cs);
> -    CPUPPCState *env = &cpu->env;
> -
> -    if (cs->halted) {
> -        uint64_t psscr = env->spr[SPR_PSSCR];
> -
> -        if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
> -            return false;
> -        }
> -
> -        /* If EC is clear, just return true on any pending interrupt */
> -        if (!(psscr & PSSCR_EC)) {
> -            return true;
> -        }
> -
> -        return p9_interrupt_powersave(env) != 0;
> -    } else {
> -        return FIELD_EX64(env->msr, MSR, EE) &&
> -               (cs->interrupt_request & CPU_INTERRUPT_HARD);
> -    }
> -}
> -
>  POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
>  {
>      DeviceClass *dc = DEVICE_CLASS(oc);
>      PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
> -    CPUClass *cc = CPU_CLASS(oc);
>  
>      dc->fw_name = "PowerPC,POWER10";
>      dc->desc = "POWER10";
> @@ -6643,7 +6556,6 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
>                           PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
>      pcc->init_proc = init_proc_POWER10;
>      pcc->check_pow = check_pow_nocheck;
> -    cc->has_work = cpu_has_work_POWER10;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -7200,11 +7112,7 @@ static void ppc_cpu_set_pc(CPUState *cs, vaddr value)
>  
>  static bool ppc_cpu_has_work(CPUState *cs)
>  {
> -    PowerPCCPU *cpu = POWERPC_CPU(cs);
> -    CPUPPCState *env = &cpu->env;
> -
> -    return FIELD_EX64(env->msr, MSR, EE) &&
> -           (cs->interrupt_request & CPU_INTERRUPT_HARD);
> +    return cs->interrupt_request & CPU_INTERRUPT_HARD;
>  }
>  
>  static void ppc_cpu_reset(DeviceState *dev)


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFC PATCH v2 29/29] target/ppc: move the p*_interrupt_powersave methods to excp_helper.c
  2022-09-27 20:15 ` [RFC PATCH v2 29/29] target/ppc: move the p*_interrupt_powersave methods to excp_helper.c Matheus Ferst
@ 2022-10-03 14:13   ` Fabiano Rosas
  0 siblings, 0 replies; 46+ messages in thread
From: Fabiano Rosas @ 2022-10-03 14:13 UTC (permalink / raw)
  To: Matheus Ferst, qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee, Matheus Ferst

Matheus Ferst <matheus.ferst@eldorado.org.br> writes:

> Move the methods to excp_helper.c and make them static.
>
> Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>

Reviewed-by: Fabiano Rosas <farosas@linux.ibm.com>

> ---
>  target/ppc/cpu_init.c    | 102 ---------------------------------------
>  target/ppc/excp_helper.c | 102 +++++++++++++++++++++++++++++++++++++++
>  target/ppc/internal.h    |   6 ---
>  3 files changed, 102 insertions(+), 108 deletions(-)
>
> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> index 4d0064c7a5..a9c2726d51 100644
> --- a/target/ppc/cpu_init.c
> +++ b/target/ppc/cpu_init.c
> @@ -5960,30 +5960,6 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
>      return true;
>  }
>  
> -int p7_interrupt_powersave(CPUPPCState *env)
> -{
> -    if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
> -        (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
> -        return PPC_INTERRUPT_EXT;
> -    }
> -    if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
> -        (env->spr[SPR_LPCR] & LPCR_P7_PECE1)) {
> -        return PPC_INTERRUPT_DECR;
> -    }
> -    if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
> -        (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
> -        return PPC_INTERRUPT_MCK;
> -    }
> -    if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
> -        (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
> -        return PPC_INTERRUPT_HMI;
> -    }
> -    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
> -        return PPC_INTERRUPT_RESET;
> -    }
> -    return 0;
> -}
> -
>  POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
>  {
>      DeviceClass *dc = DEVICE_CLASS(oc);
> @@ -6120,38 +6096,6 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
>      return true;
>  }
>  
> -int p8_interrupt_powersave(CPUPPCState *env)
> -{
> -    if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
> -        (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
> -        return PPC_INTERRUPT_EXT;
> -    }
> -    if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
> -        (env->spr[SPR_LPCR] & LPCR_P8_PECE3)) {
> -        return PPC_INTERRUPT_DECR;
> -    }
> -    if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
> -        (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
> -        return PPC_INTERRUPT_MCK;
> -    }
> -    if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
> -        (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
> -        return PPC_INTERRUPT_HMI;
> -    }
> -    if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
> -        (env->spr[SPR_LPCR] & LPCR_P8_PECE0)) {
> -        return PPC_INTERRUPT_DOORBELL;
> -    }
> -    if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
> -        (env->spr[SPR_LPCR] & LPCR_P8_PECE1)) {
> -        return PPC_INTERRUPT_HDOORBELL;
> -    }
> -    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
> -        return PPC_INTERRUPT_RESET;
> -    }
> -    return 0;
> -}
> -
>  POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
>  {
>      DeviceClass *dc = DEVICE_CLASS(oc);
> @@ -6325,52 +6269,6 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
>      return false;
>  }
>  
> -int p9_interrupt_powersave(CPUPPCState *env)
> -{
> -    /* External Exception */
> -    if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
> -        (env->spr[SPR_LPCR] & LPCR_EEE)) {
> -        bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
> -        if (!heic || !FIELD_EX64_HV(env->msr) ||
> -            FIELD_EX64(env->msr, MSR, PR)) {
> -            return PPC_INTERRUPT_EXT;
> -        }
> -    }
> -    /* Decrementer Exception */
> -    if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
> -        (env->spr[SPR_LPCR] & LPCR_DEE)) {
> -        return PPC_INTERRUPT_DECR;
> -    }
> -    /* Machine Check or Hypervisor Maintenance Exception */
> -    if (env->spr[SPR_LPCR] & LPCR_OEE) {
> -        if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
> -            return PPC_INTERRUPT_MCK;
> -        }
> -        if (env->pending_interrupts & PPC_INTERRUPT_HMI) {
> -            return PPC_INTERRUPT_HMI;
> -        }
> -    }
> -    /* Privileged Doorbell Exception */
> -    if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
> -        (env->spr[SPR_LPCR] & LPCR_PDEE)) {
> -        return PPC_INTERRUPT_DOORBELL;
> -    }
> -    /* Hypervisor Doorbell Exception */
> -    if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
> -        (env->spr[SPR_LPCR] & LPCR_HDEE)) {
> -        return PPC_INTERRUPT_HDOORBELL;
> -    }
> -    /* Hypervisor virtualization exception */
> -    if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) &&
> -        (env->spr[SPR_LPCR] & LPCR_HVEE)) {
> -        return PPC_INTERRUPT_HVIRT;
> -    }
> -    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
> -        return PPC_INTERRUPT_RESET;
> -    }
> -    return 0;
> -}
> -
>  POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
>  {
>      DeviceClass *dc = DEVICE_CLASS(oc);
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 9708f82b30..57937956e4 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -1686,6 +1686,30 @@ void ppc_cpu_do_interrupt(CPUState *cs)
>       PPC_INTERRUPT_PIT | PPC_INTERRUPT_DOORBELL | PPC_INTERRUPT_HDOORBELL | \
>       PPC_INTERRUPT_THERM | PPC_INTERRUPT_EBB)
>  
> +static int p7_interrupt_powersave(CPUPPCState *env)
> +{
> +    if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
> +        (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
> +        return PPC_INTERRUPT_EXT;
> +    }
> +    if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
> +        (env->spr[SPR_LPCR] & LPCR_P7_PECE1)) {
> +        return PPC_INTERRUPT_DECR;
> +    }
> +    if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
> +        (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
> +        return PPC_INTERRUPT_MCK;
> +    }
> +    if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
> +        (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
> +        return PPC_INTERRUPT_HMI;
> +    }
> +    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
> +        return PPC_INTERRUPT_RESET;
> +    }
> +    return 0;
> +}
> +
>  static int p7_next_unmasked_interrupt(CPUPPCState *env)
>  {
>      PowerPCCPU *cpu = env_archcpu(env);
> @@ -1751,6 +1775,38 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env)
>      PPC_INTERRUPT_FIT | PPC_INTERRUPT_PIT | PPC_INTERRUPT_DOORBELL |    \
>      PPC_INTERRUPT_HDOORBELL | PPC_INTERRUPT_THERM)
>  
> +static int p8_interrupt_powersave(CPUPPCState *env)
> +{
> +    if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
> +        (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
> +        return PPC_INTERRUPT_EXT;
> +    }
> +    if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
> +        (env->spr[SPR_LPCR] & LPCR_P8_PECE3)) {
> +        return PPC_INTERRUPT_DECR;
> +    }
> +    if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
> +        (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
> +        return PPC_INTERRUPT_MCK;
> +    }
> +    if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
> +        (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
> +        return PPC_INTERRUPT_HMI;
> +    }
> +    if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
> +        (env->spr[SPR_LPCR] & LPCR_P8_PECE0)) {
> +        return PPC_INTERRUPT_DOORBELL;
> +    }
> +    if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
> +        (env->spr[SPR_LPCR] & LPCR_P8_PECE1)) {
> +        return PPC_INTERRUPT_HDOORBELL;
> +    }
> +    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
> +        return PPC_INTERRUPT_RESET;
> +    }
> +    return 0;
> +}
> +
>  static int p8_next_unmasked_interrupt(CPUPPCState *env)
>  {
>      PowerPCCPU *cpu = env_archcpu(env);
> @@ -1820,6 +1876,52 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env)
>       PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | PPC_INTERRUPT_FIT |  \
>       PPC_INTERRUPT_PIT | PPC_INTERRUPT_THERM)
>  
> +static int p9_interrupt_powersave(CPUPPCState *env)
> +{
> +    /* External Exception */
> +    if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
> +        (env->spr[SPR_LPCR] & LPCR_EEE)) {
> +        bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
> +        if (!heic || !FIELD_EX64_HV(env->msr) ||
> +            FIELD_EX64(env->msr, MSR, PR)) {
> +            return PPC_INTERRUPT_EXT;
> +        }
> +    }
> +    /* Decrementer Exception */
> +    if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
> +        (env->spr[SPR_LPCR] & LPCR_DEE)) {
> +        return PPC_INTERRUPT_DECR;
> +    }
> +    /* Machine Check or Hypervisor Maintenance Exception */
> +    if (env->spr[SPR_LPCR] & LPCR_OEE) {
> +        if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
> +            return PPC_INTERRUPT_MCK;
> +        }
> +        if (env->pending_interrupts & PPC_INTERRUPT_HMI) {
> +            return PPC_INTERRUPT_HMI;
> +        }
> +    }
> +    /* Privileged Doorbell Exception */
> +    if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
> +        (env->spr[SPR_LPCR] & LPCR_PDEE)) {
> +        return PPC_INTERRUPT_DOORBELL;
> +    }
> +    /* Hypervisor Doorbell Exception */
> +    if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
> +        (env->spr[SPR_LPCR] & LPCR_HDEE)) {
> +        return PPC_INTERRUPT_HDOORBELL;
> +    }
> +    /* Hypervisor virtualization exception */
> +    if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) &&
> +        (env->spr[SPR_LPCR] & LPCR_HVEE)) {
> +        return PPC_INTERRUPT_HVIRT;
> +    }
> +    if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
> +        return PPC_INTERRUPT_RESET;
> +    }
> +    return 0;
> +}
> +
>  static int p9_next_unmasked_interrupt(CPUPPCState *env)
>  {
>      PowerPCCPU *cpu = env_archcpu(env);
> diff --git a/target/ppc/internal.h b/target/ppc/internal.h
> index 25827ebf6f..337a362205 100644
> --- a/target/ppc/internal.h
> +++ b/target/ppc/internal.h
> @@ -306,10 +306,4 @@ static inline int ger_pack_masks(int pmsk, int ymsk, int xmsk)
>      return msk;
>  }
>  
> -#if defined(TARGET_PPC64)
> -int p9_interrupt_powersave(CPUPPCState *env);
> -int p8_interrupt_powersave(CPUPPCState *env);
> -int p7_interrupt_powersave(CPUPPCState *env);
> -#endif
> -
>  #endif /* PPC_INTERNAL_H */


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFC PATCH v2 00/29] PowerPC interrupt rework
  2022-09-28 17:31 ` [RFC PATCH v2 00/29] PowerPC interrupt rework Cédric Le Goater
@ 2022-10-03 15:45   ` Matheus K. Ferst
  2022-10-03 20:58     ` Cédric Le Goater
  0 siblings, 1 reply; 46+ messages in thread
From: Matheus K. Ferst @ 2022-10-03 15:45 UTC (permalink / raw)
  To: Cédric Le Goater, qemu-devel, qemu-ppc
  Cc: danielhb413, david, groug, fbarrat, alex.bennee, farosas

On 28/09/2022 14:31, Cédric Le Goater wrote:
> Hello Matheus,
> 
> On 9/27/22 22:15, Matheus Ferst wrote:
>> Link to v1: 
>> https://lists.gnu.org/archive/html/qemu-ppc/2022-08/msg00370.html
>> This series is also available as a git branch: 
>> https://github.com/PPC64/qemu/tree/ferst-interrupt-fix-v2
> 
> This is impressive work on QEMU PPC.
> 
>> This version addresses Fabiano's feedback and fixes some issues found
>> with the tests suggested by Cédric. While working on it, I found two
>> intermittent problems on master:
>>
>>   i) ~10% of boots with pSeries and 970/970mp/POWER5+ hard lockup after
> 
> These CPUs never got real attention with KVM. The FW was even broken
> before 7.0.
> 
>>      either SCSI or network initialization when using -smp 4. With
>>      -smp 2, the problem is harder to reproduce but still happens, and I
>>      couldn't reproduce with thread=single.
>> ii) ~52% of KVM guest initializations on PowerNV hang in different parts
>>      of the boot process when using more than one CPU.
> 
> Do you mean when the guest is SMP or the host ?

I should've added more details, this percentage was testing powernv9 
with "-smp 4" and a pSeries-POWER9 guest with "-smp 4", but I can also 
reproduce with a multithread L0 and single thread L1. The firmware is 
printing messages like:

Could not set special wakeup on 0:1: timeout waiting for SPECIAL_WKUP_DONE.

when it hangs, but I also have this message on some successful boots.

> 
>> With the complete series applied, I couldn't reproduce (i) anymore,
> 
> Super ! Models are getting better. This is nice for the 970.
> 
>> and (ii) became a little more frequent (~58%).
> 
> Have you checked 'info pic' ? XIVE is in charge of vCPU scheduling.

I don't have much knowledge in this area yet, so I don't know what to 
look for, but if it's useful, here is the output of the command when the 
problem occurs with a 4 core L0 and a single core L1:

(qemu) info pic
info pic
CPU[0000]:   QW   NSR CPPR IPB LSMFB ACK# INC AGE PIPR  W2
CPU[0000]: USER    00   00  00    00   00  00  00   00  00000000
CPU[0000]:   OS    00   00  00    ff   ff  00  ff   ff  00000000
CPU[0000]: POOL    00   00  00    ff   00  00  00   00  00000000
CPU[0000]: PHYS    00   ff  00    00   00  00  00   ff  80000000
CPU[0001]:   QW   NSR CPPR IPB LSMFB ACK# INC AGE PIPR  W2
CPU[0001]: USER    00   00  00    00   00  00  00   00  00000000
CPU[0001]:   OS    00   00  00    ff   ff  00  ff   ff  00000000
CPU[0001]: POOL    00   00  00    ff   00  00  00   00  00000001
CPU[0001]: PHYS    00   ff  00    00   00  00  00   ff  80000000
CPU[0002]:   QW   NSR CPPR IPB LSMFB ACK# INC AGE PIPR  W2
CPU[0002]: USER    00   00  00    00   00  00  00   00  00000000
CPU[0002]:   OS    00   00  00    ff   ff  00  ff   ff  00000000
CPU[0002]: POOL    00   00  00    ff   00  00  00   00  00000002
CPU[0002]: PHYS    00   ff  00    00   00  00  00   ff  80000000
CPU[0003]:   QW   NSR CPPR IPB LSMFB ACK# INC AGE PIPR  W2
CPU[0003]: USER    00   00  00    00   00  00  00   00  00000000
CPU[0003]:   OS    00   ff  00    00   ff  00  ff   ff  00000004
CPU[0003]: POOL    00   00  00    ff   00  00  00   00  00000003
CPU[0003]: PHYS    00   ff  00    00   00  00  00   ff  80000000
XIVE[0] #0 Source 00000000 .. 000fffff
   00000014 MSI --
   00000015 MSI --
   00000016 MSI --
   00000017 MSI --
   00000018 MSI --
   00000019 MSI --
   0000001a MSI --
   0000001b MSI --
   0000001e MSI P-
   00000023 MSI --
   00000024 MSI --
   00000025 MSI --
   00000026 MSI --
XIVE[0] #0 EAT 00000000 .. 000fffff
   00000014   end:00/000f data:00000010
   00000015   end:00/0017 data:00000010
   00000016   end:00/001f data:00000010
   00000017   end:00/0027 data:00000010
   00000018   end:00/004e data:00000010
   00000019   end:00/004e data:00000012
   0000001a   end:00/004e data:0000001b
   0000001b   end:00/004e data:00000013
   0000001e   end:00/004e data:00000016
   00000023   end:00/004e data:00000017
   00000024   end:00/004e data:00000018
   00000025   end:00/004e data:00000019
   00000026   end:00/004e data:0000001a
   000fb000   end:00/001f data:00000030
   000fb001   end:00/0027 data:00000031
   000fb002   end:00/000f data:00000032
   000fb003   end:00/000f data:00000033
   000fb004   end:00/0017 data:00000034
   000fb005   end:00/001f data:00000035
   000fb006   end:00/0027 data:00000036
   000fb7fe   end:00/000f data:00000029
   000fb7ff   end:00/0017 data:0000002a
   000fbffe   end:00/001f data:00000027
   000fbfff   end:00/0027 data:00000028
   000fcffe   end:00/000f data:00000025
   000fcfff   end:00/0017 data:00000026
   000fd000   end:00/001f data:00000037
   000fd001   end:00/000f data:00000038
   000fd002   end:00/0017 data:00000039
   000fd003   end:00/001f data:0000003a
   000fd004   end:00/0027 data:0000003b
   000fd7fe   end:00/001f data:00000023
   000fd7ff   end:00/0027 data:00000024
   000fdffe   end:00/000f data:00000021
   000fdfff   end:00/0017 data:00000022
   000feffe   end:00/001f data:0000001f
   000fefff   end:00/0027 data:00000020
   000ffff0   end:00/000f data:00000011
   000ffff1   end:00/0017 data:00000012
   000ffff2   end:00/001f data:00000013
   000ffff3   end:00/0027 data:00000014
   000ffff4   end:00/000f data:00000015
   000ffff5   end:00/0017 data:00000016
   000ffff6   end:00/001f data:00000017
   000ffff7   end:00/0027 data:00000018
   000ffff8   end:00/000f data:00000019
   000ffff9   end:00/0017 data:0000001a
   000ffffa   end:00/001f data:0000001b
   000ffffb   end:00/0027 data:0000001c
   000ffffc   end:00/000f data:0000001d
   000ffffd   end:00/0017 data:0000001e
XIVE[0] #0 ENDT
   0000000f -Q vqnb---f prio:7 nvt:00/0080 eq:@03400000   825/16384 ^1 [ 
8000004f 8000004f 80000
04f 8000004f 8000004f ^00000000 ]
   00000017 -Q vqnb---f prio:7 nvt:00/0084 eq:@03750000  1048/16384 ^1 [ 
8000001e 8000001e 80000
01e 8000001e 8000001e ^00000000 ]
   0000001f -Q vqnb---f prio:7 nvt:00/0088 eq:@037f0000   154/16384 ^1 [ 
8000003a 8000003a 80000
03a 8000003a 8000003a ^00000000 ]
   00000027 -Q vqnb---f prio:7 nvt:00/008c eq:@038a0000   340/16384 ^1 [ 
80000014 80000014 80000
014 80000014 8000003b ^00000000 ]
   0000004e -Q vqnbeu-- prio:6 nvt:00/0004 eq:@1d170000  1104/16384 ^1 [ 
80000016 80000016 80000
016 80000016 80000016 ^00000000 ]
   0000004f -Q v--be-s- prio:0 nvt:00/0000
XIVE[0] #0 END Escalation EAT
   0000004e -Q    end:00/004f data:00000000
   0000004f P-    end:00/000f data:0000004f
XIVE[0] #0 NVTT 00000000 .. 0007ffff
   00000000 end:00/0028 IPB:00
   00000001 end:00/0030 IPB:00
   00000002 end:00/0038 IPB:00
00000003 end:00/0040 IPB:00
   00000004 end:00/0048 IPB:02
   00000080 end:00/0008 IPB:00
   00000084 end:00/0010 IPB:00
   00000088 end:00/0018 IPB:00
   0000008c end:00/0020 IPB:00
PSIHB Source 000ffff0 .. 000ffffd
   000ffff0 LSI --
   000ffff1 LSI --
   000ffff2 LSI --
   000ffff3 LSI --
   000ffff4 LSI --
   000ffff5 LSI --
   000ffff6 LSI --
   000ffff7 LSI --
   000ffff8 LSI --
   000ffff9 LSI --
   000ffffa LSI --
   000ffffb LSI --
   000ffffc LSI --
   000ffffd LSI --
PHB4[0:0] Source 000fe000 .. 000fefff  @6030203110100
   00000ffe LSI --
   00000fff LSI --
PHB4[0:5] Source 000fb000 .. 000fb7ff  @6030203110228
   00000000 MSI --
   00000001 MSI --
   00000002 MSI --
   00000003 MSI --
   00000004 MSI --
   00000005 MSI --
   00000006 MSI --
   000007fe LSI --
   000007ff LSI --
PHB4[0:4] Source 000fb800 .. 000fbfff  @6030203110220
   000007fe LSI --
   000007ff LSI --
PHB4[0:3] Source 000fc000 .. 000fcfff  @6030203110218
   00000ffe LSI --
   00000fff LSI --
PHB4[0:2] Source 000fd000 .. 000fd7ff  @6030203110210
   00000000 MSI --
   00000001 MSI --
   00000002 MSI --
   00000003 MSI --
   00000004 MSI --
   000007fe LSI --
   000007ff LSI --
PHB4[0:1] Source 000fd800 .. 000fdfff  @6030203110208
   000007fe LSI --
   000007ff LSI --

> Could you please check with powersave=off in the host kernel also ?
> 

It still hangs with this option.

>> I've tested each patch of this series with [1], modified to use -smp for
>> machines that support more than one CPU. The machines I can currently
>> boot with FreeBSD (970/970,p/POWER5+/POWER7/POWER8/POWER9 pSeries,
>> POWER8/POWER9 PowerNV, and mpc8544ds) were tested with the images from
>> [2] and still boot after applying the patch series. Booting nested
>> guests inside a TCG pSeries machine also seems to be working fine.
>>
>> Using command lines like:
>>
>> ./qemu-system-ppc64 -M powernv9 -cpu POWER9 -accel tcg,thread=multi \
>>                  -m 8G -smp $SMP -vga none -nographic -kernel zImage \
>>                  -append 'console=hvc0' -initrdootfs.cpio.xz \
>>                  -serial pipe:pipe -monitor unix:mon,server,nowait
>>
>> and
>>
>> ./qemu-system-ppc64 -M pseries -cpu POWER9 -accel tcg,thread=multi \
>>                  -m 8G -smp $SMP -vga none -nographic -kernel zImage \
>>                  -append 'console=hvc0' -initrd rootfs.cpio.xz \
>>                  -serial pipe:pipe -monitor unix:mon,server,nowait
>>
>> to measure the time to boot, login, and shut down a compressed kernel
>> with a buildroot initramfs, with 100 iteration we get:
>>
>> +-----+------------------------------+-----------------------------+
>> |     |            PowerNV           |           pSeries           |
>> |-smp |------------------------------+-----------------------------+
>> |     |     master    | patch series |    master    | patch series |
>> +-----+------------------------------+-----------------------------+
>> |  1  |  45,84 ± 0,92 | 38,08 ± 0,66 | 23,56 ± 1,16 | 23,76 ± 1,04 |
>> |  2  |  80,21 ± 8,03 | 40,81 ± 0,45 | 26,59 ± 0,92 | 26,88 ± 0,99 |
>> |  4  | 115,98 ± 9,85 | 38,80 ± 0,44 | 28,83 ± 0,84 | 28,46 ± 0,94 |
>> |  6  | 199,14 ± 6,36 | 39,32 ± 0,50 | 29,22 ± 0,78 | 29,45 ± 0,86 |
>> |  8  | 47,85 ± 27,50 | 38,98 ± 0,49 | 29,63 ± 0,80 | 29,60 ± 0,78 |
>> +-----+------------------------------+-----------------------------+
>>
>> This results shows that the problem reported in [3] is solved, while
> 
> Yes. Nice work ! The PowerNV results with -smp 8 on master are unexpected.
> Did you do some profiling also ?
> 

We've noticed that in the original thread when Frederic reported the 
issue, this happens when the -smp >= $(nproc), but I haven't looked too 
deep in this case. Maybe some magic optimization on Linux mutex 
implementation that helps on the higher contention case?

>> pSeries boot time is essentially unchanged.
>>
>>
>> With a non-compressed kernel, the difference with PowerNV is smaller,
>> and pSeries stills the same:
>>
>> +-----+------------------------------+-----------------------------+
>> |     |            PowerNV           |           pSeries           |
>> |-smp |------------------------------+-----------------------------+
>> |     |     master    | patch series |    master    | patch series |
>> +-----+------------------------------+-----------------------------+
>> |  1  |  42,17 ± 0,92 | 38,13 ± 0,59 | 23,15 ± 1,02 | 23,46 ± 1,02 |
>> |  2  |  55,72 ± 3,54 | 40,30 ± 0,56 | 26,26 ± 0,82 | 26,38 ± 0,80 |
>> |  4  |  67,09 ± 3,02 | 38,26 ± 0,47 | 28,36 ± 0,77 | 28,19 ± 0,78 |
>> |  6  |  98,96 ± 2,49 | 39,01 ± 0,38 | 28,68 ± 0,75 | 29,02 ± 0,88 |
>> |  8  |  39,68 ± 0,42 | 38,44 ± 0,41 | 29,24 ± 0,81 | 29,44 ± 0,75 |
>> +-----+------------------------------+-----------------------------+
>>
>> Finally, using command lines like
>>
>> ./qemu-system-ppc64 -M powernv9 -cpu POWER9 -accel tcg,thread=multi \
>>      -m 8G -smp 4 -device virtio-scsi-pci -boot c -vga none -nographic \
>>      -device nvme,bus=pcie.2,addr=0x0,drive=drive0,serial=1234 \
>>      -drive file=rootfs.ext2,if=none,id=drive0,format=raw,cache=none \
>>      -snapshot -serial pipe:pipe -monitor unix:mon,server,nowait \
>>      -kernel zImage -append 'console=hvc0 rootwait root=/dev/nvme0n1' \
>>      -device virtio-net-pci,netdev=br0,mac=52:54:00:12:34:57,bus=pcie.0 \
>>      -netdev bridge,id=br0
>>
>> and
>>
>> ./qemu-system-ppc64 -M pseries -cpu POWER9 -accel tcg,thread=multi \
>>      -m 8G -smp 4 -device virtio-scsi-pci -boot c -vga none -nographic \
>>      -drive file=rootfs.ext2,if=scsi,index=0,format=raw -snapshot \
>>      -kernel zImage -append 'console=hvc0 rootwait root=/dev/sda' \
>>      -serial pipe:pipe -monitor unix:mon,server,nowait \
>>      -device virtio-net-pci,netdev=br0,mac=52:54:00:12:34:57 \
>>      -netdev bridge,id=br0
>>
>> to tests IO performance, with iperf to test network and a 4Gb scp
>> transfer to test disk+network, in 100 iterations we saw:
>>
>> +---------------------+---------------+-----------------+
>> |                     |    scp (s)    |   iperf (MB/s)  |
>> +---------------------+---------------+-----------------+
>> |PowerNV master       | 166,91 ± 8,37 | 918,06 ± 114,78 |
>> |PowerNV patch series | 166,25 ± 8,85 | 916,91 ± 107,56 |
>> |pSeries master       | 175,70 ± 8,22 | 958,73 ± 115,09 |
>> |pSeries patch series | 173,62 ± 8,13 | 893,42 ±  87,77 |
>> +---------------------+---------------+-----------------+
> 
> These are SMP machines under high IO load using MTTCG. It means
> that the models are quite robust now.
> 
>> The scp data shows little difference, while testing just network shows
>> that it's a bit slower with the patch series applied (although, with
>> this variation, we'd probably need to repeat this test more times to
>> have a more robust result...)
> 
> You could try with powersave=off.
> 

Not a big difference, with 50 iterations:

+---------------------+---------------+-----------------+
|                     |    scp (s)    |   iperf (MB/s)  |
+---------------------+---------------+-----------------+
|PowerNV master       | 142.73 ± 8.38 | 924.34 ± 353.93 |
|PowerNV patch series | 145.75 ± 9.18 | 874.52 ± 286.21 |
+---------------------+---------------+-----------------+

Thanks,
Matheus K. Ferst
Instituto de Pesquisas ELDORADO <http://www.eldorado.org.br/>
Analista de Software
Aviso Legal - Disclaimer <https://www.eldorado.org.br/disclaimer.html>


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFC PATCH v2 09/29] target/ppc: remove generic architecture checks from p9_deliver_interrupt
  2022-09-30 18:13   ` Fabiano Rosas
@ 2022-10-03 15:45     ` Matheus K. Ferst
  2022-10-03 16:59       ` Fabiano Rosas
  0 siblings, 1 reply; 46+ messages in thread
From: Matheus K. Ferst @ 2022-10-03 15:45 UTC (permalink / raw)
  To: Fabiano Rosas, qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee

On 30/09/2022 15:13, Fabiano Rosas wrote:
> Matheus Ferst <matheus.ferst@eldorado.org.br> writes:
> 
>> No functional change intended.
>>
>> Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
>> ---
>>   target/ppc/excp_helper.c | 9 +--------
>>   1 file changed, 1 insertion(+), 8 deletions(-)
>>
>> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
>> index 603c956588..67e73f30ab 100644
>> --- a/target/ppc/excp_helper.c
>> +++ b/target/ppc/excp_helper.c
>> @@ -1919,18 +1919,11 @@ static void p9_deliver_interrupt(CPUPPCState *env, int interrupt)
>>           break;
>>
>>       case PPC_INTERRUPT_DECR: /* Decrementer exception */
>> -        if (ppc_decr_clear_on_delivery(env)) {
>> -            env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
>> -        }
> 
> Maybe I'm missing something, but this should continue to clear the bit,
> no? Same comment for P8.
> 

ppc_decr_clear_on_delivery returns true if (env->tb_env->flags & 
(PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL)) ==
PPC_DECR_UNDERFLOW_TRIGGERED, i.e., PPC_DECR_UNDERFLOW_TRIGGERED is set 
and PPC_DECR_UNDERFLOW_LEVEL is clear. All Book3S CPU have a level 
triggered interrupt, so the method return false.

Thanks,
Matheus K. Ferst
Instituto de Pesquisas ELDORADO <http://www.eldorado.org.br/>
Analista de Software
Aviso Legal - Disclaimer <https://www.eldorado.org.br/disclaimer.html>


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFC PATCH v2 13/29] target/ppc: remove unused interrupts from p8_pending_interrupt
  2022-09-27 22:14   ` Fabiano Rosas
@ 2022-10-03 15:45     ` Matheus K. Ferst
  0 siblings, 0 replies; 46+ messages in thread
From: Matheus K. Ferst @ 2022-10-03 15:45 UTC (permalink / raw)
  To: Fabiano Rosas, qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee

On 27/09/2022 19:14, Fabiano Rosas wrote:
> Matheus Ferst <matheus.ferst@eldorado.org.br> writes:
> 
>> Remove the following unused interrupts from the POWER8 interrupt masking
>> method:
>> - PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970, and POWER5p;
>> - Debug Interrupt: removed in Power ISA v2.07;
>> - Hypervisor Virtualization: introduced in Power ISA v3.0;
>> - Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
>>    for embedded CPUs;
>> - Hypervisor Doorbell, Doorbell, and Critical Doorbell: processor does
> 
> We still need the first two.
> 0xe80 - Directed hypervisor doorbell
> 0xa00 - Directed privileged doorbell
> 

It seems that on PowerISA v2.07, the category for msgsnd and msgclr 
became "Embedded Processor Control" or "Book S." That's certainly not 
what we are doing in code, both instructions are behind the PPC2_PRCNTL 
flag, so they are not available for -cpu POWER8. Also, we're not 
checking for ISA 3.00 on msgsync... I'll keep these interrupts in v3 and 
send a separate patch fixing the instruction flags.

Thanks,
Matheus K. Ferst
Instituto de Pesquisas ELDORADO <http://www.eldorado.org.br/>
Analista de Software
Aviso Legal - Disclaimer <https://www.eldorado.org.br/disclaimer.html>


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFC PATCH v2 11/29] target/ppc: add power-saving interrupt masking logic to p9_next_unmasked_interrupt
  2022-09-30 18:38   ` Fabiano Rosas
@ 2022-10-03 15:46     ` Matheus K. Ferst
  2022-10-03 17:01       ` Fabiano Rosas
  0 siblings, 1 reply; 46+ messages in thread
From: Matheus K. Ferst @ 2022-10-03 15:46 UTC (permalink / raw)
  To: Fabiano Rosas, qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee

On 30/09/2022 15:38, Fabiano Rosas wrote:
> Matheus Ferst <matheus.ferst@eldorado.org.br> writes:
> 
>> Export p9_interrupt_powersave and use it in p9_next_unmasked_interrupt.
>>
>> Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
>> ---
>> Temporarily putting the prototype in internal.h for lack of a better place,
>> we will un-export p9_interrupt_powersave in future patches.
>> ---
>>   target/ppc/cpu_init.c    |  2 +-
>>   target/ppc/excp_helper.c | 46 ++++++++++++++++++++++++++++------------
>>   target/ppc/internal.h    |  4 ++++
>>   3 files changed, 38 insertions(+), 14 deletions(-)
>>
>> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
>> index 1f8f6c6ef2..7889158c52 100644
>> --- a/target/ppc/cpu_init.c
>> +++ b/target/ppc/cpu_init.c
>> @@ -6351,7 +6351,7 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
>>       return false;
>>   }
>>
>> -static int p9_interrupt_powersave(CPUPPCState *env)
>> +int p9_interrupt_powersave(CPUPPCState *env)
>>   {
>>       /* External Exception */
>>       if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
>> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
>> index 67e73f30ab..5a0d2c11a2 100644
>> --- a/target/ppc/excp_helper.c
>> +++ b/target/ppc/excp_helper.c
>> @@ -1686,28 +1686,39 @@ void ppc_cpu_do_interrupt(CPUState *cs)
>>
>>   static int p9_next_unmasked_interrupt(CPUPPCState *env)
>>   {
>> -    bool async_deliver;
>> +    PowerPCCPU *cpu = env_archcpu(env);
>> +    CPUState *cs = CPU(cpu);
>> +    /* Ignore MSR[EE] when coming out of some power management states */
>> +    bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
>>
>>       assert((env->pending_interrupts & P9_UNUSED_INTERRUPTS) == 0);
>>
>> +    if (cs->halted) {
>> +        if (env->spr[SPR_PSSCR] & PSSCR_EC) {
>> +            /*
>> +             * When PSSCR[EC] is set, LPCR[PECE] controls which interrupts can
>> +             * wakeup the processor
>> +             */
>> +            return p9_interrupt_powersave(env);
>> +        } else {
>> +            /*
>> +             * When it's clear, any system-caused exception exits power-saving
>> +             * mode, even the ones that gate on MSR[EE].
>> +             */
>> +            msr_ee = true;
>> +        }
>> +    }
>> +
>>       /* Machine check exception */
>>       if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
>>           return PPC_INTERRUPT_MCK;
>>       }
>>
>> -    /*
>> -     * For interrupts that gate on MSR:EE, we need to do something a
>> -     * bit more subtle, as we need to let them through even when EE is
>> -     * clear when coming out of some power management states (in order
>> -     * for them to become a 0x100).
>> -     */
>> -    async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
>> -
> 
> You could simplify the code below if you bail early here when !msr_ee.
> 

The next interrupts have checks in the form

if (MSR[EE] && some_condition) || (!MSR[HV] && some_other_condition)

so we cannot return yet. We could check twice for these interrupts, e.g.

if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
     (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
     return PPC_INTERRUPT_EXT;
}

/* ... */

if (!msr_ee) {
     return 0;
}

/* ... */

if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
     !(heic && FIELD_EX64_HV(env->msr) && !FIELD_EX64(env->msr, MSR, PR))) {
     return PPC_INTERRUPT_EXT;
}

But I'm not sure if it'd be better.

>>       /* Hypervisor decrementer exception */
>>       if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
>>           /* LPCR will be clear when not supported so this will work */
>>           bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
>> -        if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
>> +        if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) {
>>               /* HDEC clears on delivery */
>>               return PPC_INTERRUPT_HDECR;
>>           }
>> @@ -1717,7 +1728,7 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
>>       if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
>>           /* LPCR will be clear when not supported so this will work */
>>           bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
>> -        if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
>> +        if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hvice) {
>>               return PPC_INTERRUPT_HVIRT;
>>           }
>>       }
>> @@ -1727,13 +1738,13 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
>>           bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
>>           bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
>>           /* HEIC blocks delivery to the hypervisor */
>> -        if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
>> +        if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) &&
>>               !FIELD_EX64(env->msr, MSR, PR))) ||
>>               (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
>>               return PPC_INTERRUPT_EXT;
>>           }
>>       }
>> -    if (async_deliver != 0) {
>> +    if (msr_ee != 0) {
>>           /* Decrementer exception */
>>           if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
>>               return PPC_INTERRUPT_DECR;
>> @@ -1895,6 +1906,15 @@ static void p9_deliver_interrupt(CPUPPCState *env, int interrupt)
>>       PowerPCCPU *cpu = env_archcpu(env);
>>       CPUState *cs = env_cpu(env);
>>
>> +    if (cs->halted && !(env->spr[SPR_PSSCR] & PSSCR_EC) &&
>> +        !FIELD_EX64(env->msr, MSR, EE)) {
>> +        /*
>> +         * A pending interrupt took us out of power-saving, but MSR[EE] says
>> +         * that we should return to NIP+4 instead of delivering it.
>> +         */
>> +        return;
> 
> How will the NIP be advanced in this case?
> 

It's already incremented by the translation code. ppc_tr_translate_insn 
increments ctx->base.pc_next before calling decode_{insn{32,64},legacy}, 
and methods that put the CPU to sleep will use gen_exception_nip with 
this value as the last argument.

>> +    }
>> +
>>       switch (interrupt) {
>>       case PPC_INTERRUPT_MCK: /* Machine check exception */
>>           env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
>> diff --git a/target/ppc/internal.h b/target/ppc/internal.h
>> index 337a362205..41e79adfdb 100644
>> --- a/target/ppc/internal.h
>> +++ b/target/ppc/internal.h
>> @@ -306,4 +306,8 @@ static inline int ger_pack_masks(int pmsk, int ymsk, int xmsk)
>>       return msk;
>>   }
>>
>> +#if defined(TARGET_PPC64)
>> +int p9_interrupt_powersave(CPUPPCState *env);
>> +#endif
>> +
>>   #endif /* PPC_INTERNAL_H */

Thanks,
Matheus K. Ferst
Instituto de Pesquisas ELDORADO <http://www.eldorado.org.br/>
Analista de Software
Aviso Legal - Disclaimer <https://www.eldorado.org.br/disclaimer.html>


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFC PATCH v2 09/29] target/ppc: remove generic architecture checks from p9_deliver_interrupt
  2022-10-03 15:45     ` Matheus K. Ferst
@ 2022-10-03 16:59       ` Fabiano Rosas
  0 siblings, 0 replies; 46+ messages in thread
From: Fabiano Rosas @ 2022-10-03 16:59 UTC (permalink / raw)
  To: Matheus K. Ferst, qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee

"Matheus K. Ferst" <matheus.ferst@eldorado.org.br> writes:

> On 30/09/2022 15:13, Fabiano Rosas wrote:
>> Matheus Ferst <matheus.ferst@eldorado.org.br> writes:
>> 
>>> No functional change intended.
>>>
>>> Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
>>> ---
>>>   target/ppc/excp_helper.c | 9 +--------
>>>   1 file changed, 1 insertion(+), 8 deletions(-)
>>>
>>> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
>>> index 603c956588..67e73f30ab 100644
>>> --- a/target/ppc/excp_helper.c
>>> +++ b/target/ppc/excp_helper.c
>>> @@ -1919,18 +1919,11 @@ static void p9_deliver_interrupt(CPUPPCState *env, int interrupt)
>>>           break;
>>>
>>>       case PPC_INTERRUPT_DECR: /* Decrementer exception */
>>> -        if (ppc_decr_clear_on_delivery(env)) {
>>> -            env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
>>> -        }
>> 
>> Maybe I'm missing something, but this should continue to clear the bit,
>> no? Same comment for P8.
>> 
>
> ppc_decr_clear_on_delivery returns true if (env->tb_env->flags & 
> (PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL)) ==
> PPC_DECR_UNDERFLOW_TRIGGERED, i.e., PPC_DECR_UNDERFLOW_TRIGGERED is set 
> and PPC_DECR_UNDERFLOW_LEVEL is clear. All Book3S CPU have a level 
> triggered interrupt, so the method return false.

You're right, I misread the code.

>
> Thanks,
> Matheus K. Ferst
> Instituto de Pesquisas ELDORADO <http://www.eldorado.org.br/>
> Analista de Software
> Aviso Legal - Disclaimer <https://www.eldorado.org.br/disclaimer.html>








^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFC PATCH v2 11/29] target/ppc: add power-saving interrupt masking logic to p9_next_unmasked_interrupt
  2022-10-03 15:46     ` Matheus K. Ferst
@ 2022-10-03 17:01       ` Fabiano Rosas
  0 siblings, 0 replies; 46+ messages in thread
From: Fabiano Rosas @ 2022-10-03 17:01 UTC (permalink / raw)
  To: Matheus K. Ferst, qemu-devel, qemu-ppc
  Cc: clg, danielhb413, david, groug, fbarrat, alex.bennee

"Matheus K. Ferst" <matheus.ferst@eldorado.org.br> writes:

> On 30/09/2022 15:38, Fabiano Rosas wrote:
>> Matheus Ferst <matheus.ferst@eldorado.org.br> writes:
>> 
>>> Export p9_interrupt_powersave and use it in p9_next_unmasked_interrupt.
>>>
>>> Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
>>> ---
>>> Temporarily putting the prototype in internal.h for lack of a better place,
>>> we will un-export p9_interrupt_powersave in future patches.
>>> ---
>>>   target/ppc/cpu_init.c    |  2 +-
>>>   target/ppc/excp_helper.c | 46 ++++++++++++++++++++++++++++------------
>>>   target/ppc/internal.h    |  4 ++++
>>>   3 files changed, 38 insertions(+), 14 deletions(-)
>>>
>>> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
>>> index 1f8f6c6ef2..7889158c52 100644
>>> --- a/target/ppc/cpu_init.c
>>> +++ b/target/ppc/cpu_init.c
>>> @@ -6351,7 +6351,7 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr, bool best)
>>>       return false;
>>>   }
>>>
>>> -static int p9_interrupt_powersave(CPUPPCState *env)
>>> +int p9_interrupt_powersave(CPUPPCState *env)
>>>   {
>>>       /* External Exception */
>>>       if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
>>> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
>>> index 67e73f30ab..5a0d2c11a2 100644
>>> --- a/target/ppc/excp_helper.c
>>> +++ b/target/ppc/excp_helper.c
>>> @@ -1686,28 +1686,39 @@ void ppc_cpu_do_interrupt(CPUState *cs)
>>>
>>>   static int p9_next_unmasked_interrupt(CPUPPCState *env)
>>>   {
>>> -    bool async_deliver;
>>> +    PowerPCCPU *cpu = env_archcpu(env);
>>> +    CPUState *cs = CPU(cpu);
>>> +    /* Ignore MSR[EE] when coming out of some power management states */
>>> +    bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
>>>
>>>       assert((env->pending_interrupts & P9_UNUSED_INTERRUPTS) == 0);
>>>
>>> +    if (cs->halted) {
>>> +        if (env->spr[SPR_PSSCR] & PSSCR_EC) {
>>> +            /*
>>> +             * When PSSCR[EC] is set, LPCR[PECE] controls which interrupts can
>>> +             * wakeup the processor
>>> +             */
>>> +            return p9_interrupt_powersave(env);
>>> +        } else {
>>> +            /*
>>> +             * When it's clear, any system-caused exception exits power-saving
>>> +             * mode, even the ones that gate on MSR[EE].
>>> +             */
>>> +            msr_ee = true;
>>> +        }
>>> +    }
>>> +
>>>       /* Machine check exception */
>>>       if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
>>>           return PPC_INTERRUPT_MCK;
>>>       }
>>>
>>> -    /*
>>> -     * For interrupts that gate on MSR:EE, we need to do something a
>>> -     * bit more subtle, as we need to let them through even when EE is
>>> -     * clear when coming out of some power management states (in order
>>> -     * for them to become a 0x100).
>>> -     */
>>> -    async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
>>> -
>> 
>> You could simplify the code below if you bail early here when !msr_ee.
>> 
>
> The next interrupts have checks in the form
>
> if (MSR[EE] && some_condition) || (!MSR[HV] && some_other_condition)
>
> so we cannot return yet. We could check twice for these interrupts, e.g.

Ah, ok. Let's leave like it is then.

>
> if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
>      (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
>      return PPC_INTERRUPT_EXT;
> }
>
> /* ... */
>
> if (!msr_ee) {
>      return 0;
> }
>
> /* ... */
>
> if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
>      !(heic && FIELD_EX64_HV(env->msr) && !FIELD_EX64(env->msr, MSR, PR))) {
>      return PPC_INTERRUPT_EXT;
> }
>
> But I'm not sure if it'd be better.
>
>>>       /* Hypervisor decrementer exception */
>>>       if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
>>>           /* LPCR will be clear when not supported so this will work */
>>>           bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
>>> -        if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
>>> +        if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) {
>>>               /* HDEC clears on delivery */
>>>               return PPC_INTERRUPT_HDECR;
>>>           }
>>> @@ -1717,7 +1728,7 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
>>>       if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
>>>           /* LPCR will be clear when not supported so this will work */
>>>           bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
>>> -        if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
>>> +        if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hvice) {
>>>               return PPC_INTERRUPT_HVIRT;
>>>           }
>>>       }
>>> @@ -1727,13 +1738,13 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
>>>           bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
>>>           bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
>>>           /* HEIC blocks delivery to the hypervisor */
>>> -        if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
>>> +        if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) &&
>>>               !FIELD_EX64(env->msr, MSR, PR))) ||
>>>               (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
>>>               return PPC_INTERRUPT_EXT;
>>>           }
>>>       }
>>> -    if (async_deliver != 0) {
>>> +    if (msr_ee != 0) {
>>>           /* Decrementer exception */
>>>           if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
>>>               return PPC_INTERRUPT_DECR;
>>> @@ -1895,6 +1906,15 @@ static void p9_deliver_interrupt(CPUPPCState *env, int interrupt)
>>>       PowerPCCPU *cpu = env_archcpu(env);
>>>       CPUState *cs = env_cpu(env);
>>>
>>> +    if (cs->halted && !(env->spr[SPR_PSSCR] & PSSCR_EC) &&
>>> +        !FIELD_EX64(env->msr, MSR, EE)) {
>>> +        /*
>>> +         * A pending interrupt took us out of power-saving, but MSR[EE] says
>>> +         * that we should return to NIP+4 instead of delivering it.
>>> +         */
>>> +        return;
>> 
>> How will the NIP be advanced in this case?
>> 
>
> It's already incremented by the translation code. ppc_tr_translate_insn 
> increments ctx->base.pc_next before calling decode_{insn{32,64},legacy}, 
> and methods that put the CPU to sleep will use gen_exception_nip with 
> this value as the last argument.
>
>>> +    }
>>> +
>>>       switch (interrupt) {
>>>       case PPC_INTERRUPT_MCK: /* Machine check exception */
>>>           env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
>>> diff --git a/target/ppc/internal.h b/target/ppc/internal.h
>>> index 337a362205..41e79adfdb 100644
>>> --- a/target/ppc/internal.h
>>> +++ b/target/ppc/internal.h
>>> @@ -306,4 +306,8 @@ static inline int ger_pack_masks(int pmsk, int ymsk, int xmsk)
>>>       return msk;
>>>   }
>>>
>>> +#if defined(TARGET_PPC64)
>>> +int p9_interrupt_powersave(CPUPPCState *env);
>>> +#endif
>>> +
>>>   #endif /* PPC_INTERNAL_H */
>
> Thanks,
> Matheus K. Ferst
> Instituto de Pesquisas ELDORADO <http://www.eldorado.org.br/>
> Analista de Software
> Aviso Legal - Disclaimer <https://www.eldorado.org.br/disclaimer.html>


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [RFC PATCH v2 00/29] PowerPC interrupt rework
  2022-10-03 15:45   ` Matheus K. Ferst
@ 2022-10-03 20:58     ` Cédric Le Goater
  0 siblings, 0 replies; 46+ messages in thread
From: Cédric Le Goater @ 2022-10-03 20:58 UTC (permalink / raw)
  To: Matheus K. Ferst, qemu-devel, qemu-ppc
  Cc: danielhb413, david, groug, fbarrat, alex.bennee, farosas

> (qemu) info pic
> info pic
> CPU[0000]:   QW   NSR CPPR IPB LSMFB ACK# INC AGE PIPR  W2
> CPU[0000]: USER    00   00  00    00   00  00  00   00  00000000
> CPU[0000]:   OS    00   00  00    ff   ff  00  ff   ff  00000000
> CPU[0000]: POOL    00   00  00    ff   00  00  00   00  00000000
> CPU[0000]: PHYS    00   ff  00    00   00  00  00   ff  80000000
> CPU[0001]:   QW   NSR CPPR IPB LSMFB ACK# INC AGE PIPR  W2
> CPU[0001]: USER    00   00  00    00   00  00  00   00  00000000
> CPU[0001]:   OS    00   00  00    ff   ff  00  ff   ff  00000000
> CPU[0001]: POOL    00   00  00    ff   00  00  00   00  00000001
> CPU[0001]: PHYS    00   ff  00    00   00  00  00   ff  80000000
> CPU[0002]:   QW   NSR CPPR IPB LSMFB ACK# INC AGE PIPR  W2
> CPU[0002]: USER    00   00  00    00   00  00  00   00  00000000
> CPU[0002]:   OS    00   00  00    ff   ff  00  ff   ff  00000000
> CPU[0002]: POOL    00   00  00    ff   00  00  00   00  00000002
> CPU[0002]: PHYS    00   ff  00    00   00  00  00   ff  80000000
> CPU[0003]:   QW   NSR CPPR IPB LSMFB ACK# INC AGE PIPR  W2
> CPU[0003]: USER    00   00  00    00   00  00  00   00  00000000
> CPU[0003]:   OS    00   ff  00    00   ff  00  ff   ff  00000004

vCPU 4 was scheduled to run on this CPU at some point, but it is not
anymore : no VALID bit.

> CPU[0003]: POOL    00   00  00    ff   00  00  00   00  00000003
> CPU[0003]: PHYS    00   ff  00    00   00  00  00   ff  80000000
> XIVE[0] #0 Source 00000000 .. 000fffff
>    00000014 MSI --
>    00000015 MSI --
>    00000016 MSI --
>    00000017 MSI --
>    00000018 MSI --
>    00000019 MSI --
>    0000001a MSI --
>    0000001b MSI --
>    0000001e MSI P-

The 0x1E HW interrupt (virtual device) is pending. And not queued.

>    00000023 MSI --
>    00000024 MSI --
>    00000025 MSI --
>    00000026 MSI --
> XIVE[0] #0 EAT 00000000 .. 000fffff
>    00000014   end:00/000f data:00000010
>    00000015   end:00/0017 data:00000010
>    00000016   end:00/001f data:00000010
>    00000017   end:00/0027 data:00000010 -> 0x10 == CPU IPI 
>    00000018   end:00/004e data:00000010 -> This is the vCPU IPI 
>    00000019   end:00/004e data:00000012
>    0000001a   end:00/004e data:0000001b
>    0000001b   end:00/004e data:00000013
>    0000001e   end:00/004e data:00000016

notificationd of 0x1E HW interrupts will be pushed on vCPU 0 queue 0x4e,
with (Linux) effective interrupt number 0x16, the console may be.

>    00000023   end:00/004e data:00000017
>    00000024   end:00/004e data:00000018
>    00000025   end:00/004e data:00000019
>    00000026   end:00/004e data:0000001a

Follow the PHB interrupts, MSI and LSIs.

>    000fb000   end:00/001f data:00000030
>    000fb001   end:00/0027 data:00000031
>    000fb002   end:00/000f data:00000032
>    000fb003   end:00/000f data:00000033
>    000fb004   end:00/0017 data:00000034
>    000fb005   end:00/001f data:00000035
>    000fb006   end:00/0027 data:00000036
>    000fb7fe   end:00/000f data:00000029
>    000fb7ff   end:00/0017 data:0000002a
>    000fbffe   end:00/001f data:00000027
>    000fbfff   end:00/0027 data:00000028
>    000fcffe   end:00/000f data:00000025
>    000fcfff   end:00/0017 data:00000026
>    000fd000   end:00/001f data:00000037
>    000fd001   end:00/000f data:00000038
>    000fd002   end:00/0017 data:00000039
>    000fd003   end:00/001f data:0000003a
>    000fd004   end:00/0027 data:0000003b
>    000fd7fe   end:00/001f data:00000023
>    000fd7ff   end:00/0027 data:00000024
>    000fdffe   end:00/000f data:00000021
>    000fdfff   end:00/0017 data:00000022
>    000feffe   end:00/001f data:0000001f
>    000fefff   end:00/0027 data:00000020

opal events are after

>    000ffff0   end:00/000f data:00000011 
>    000ffff1   end:00/0017 data:00000012
>    000ffff2   end:00/001f data:00000013 
>    000ffff3   end:00/0027 data:00000014 # opal-psi#0:lpchc
>    000ffff4   end:00/000f data:00000015
>    000ffff5   end:00/0017 data:00000016
>    000ffff6   end:00/001f data:00000017
>    000ffff7   end:00/0027 data:00000018
>    000ffff8   end:00/000f data:00000019
>    000ffff9   end:00/0017 data:0000001a
>    000ffffa   end:00/001f data:0000001b
>    000ffffb   end:00/0027 data:0000001c
>    000ffffc   end:00/000f data:0000001d
>    000ffffd   end:00/0017 data:0000001e # opal-psi#0:psu ? 
> XIVE[0] #0 ENDT
>    0000000f -Q vqnb---f prio:7 nvt:00/0080 eq:@03400000   825/16384 ^1 [ 8000004f 8000004f 8000004f 8000004f 8000004f ^00000000 ]

event queue of host CPU 0 is filling up with escalation interrupt
numbers, 0x4f.

host CPU 0 (queue 0xf) is serving its own IPI, some MSIs, some EEH PCI
interrupts, and some OPAL events.

>    00000017 -Q vqnb---f prio:7 nvt:00/0084 eq:@03750000  1048/16384 ^1 [ 8000001e 8000001e 8000001e 8000001e 8000001e ^00000000 ]

hmm, host CPU 1 is serving 0xffffd = opal-psi#0:psu. May be too much.

>    0000001f -Q vqnb---f prio:7 nvt:00/0088 eq:@037f0000   154/16384 ^1 [ 8000003a 8000003a 8000003a 8000003a 8000003a ^00000000 ]

0x3a is an MSI.

>    00000027 -Q vqnb---f prio:7 nvt:00/008c eq:@038a0000   340/16384 ^1 [ 80000014 80000014 80000014 80000014 8000003b ^00000000 ]

This is the console 0x14 and 0x3b is an MSI

>    0000004e -Q vqnbeu-- prio:6 nvt:00/0004 eq:@1d170000  1104/16384 ^1 [ 80000016 80000016 80000016 80000016 80000016 ^00000000 ]

0x4e (0x48 + 6) is the event queue number of guest's vCPU 0 prio 6.
0x16 is the Linux interrupt number in the guest of HW interrupt 0x1e,
the one pending.

>    0000004f -Q v--be-s- prio:0 nvt:00/0000

0x4f is the escalation queue of vCPU 0 (when vCPU is not dispatched on any
HW threads) 0x4f is also a source interrupt number for escalations.

> XIVE[0] #0 END Escalation EAT
>    0000004e -Q    end:00/004f data:00000000
>    0000004f P-    end:00/000f data:0000004f

0x4f interrupt number is pending. vPCU 0 should be dispatched but the
escalation interrupt has not being served by the hypervisor at this
point in time. Since it is not queued, we may have reached some deadlock ?

> XIVE[0] #0 NVTT 00000000 .. 0007ffff
>    00000000 end:00/0028 IPB:00
>    00000001 end:00/0030 IPB:00
>    00000002 end:00/0038 IPB:00
>    00000003 end:00/0040 IPB:00
>    00000004 end:00/0048 IPB:02

         ^

0x4 is the vCPU0 notification virtual target number and an interrupt is
pending on prio 6. vCPU 0 did not acknowledge it yet, because vCPU 0 (NVT=4)
has not been dispatched on any HW thread because the escalation interrupt
was not handled on the host (CPU 0 should). Question is what is CPU 0 up to?


>    00000080 end:00/0008 IPB:00
>    00000084 end:00/0010 IPB:00
>    00000088 end:00/0018 IPB:00
>    0000008c end:00/0020 IPB:00
> PSIHB Source 000ffff0 .. 000ffffd
>    000ffff0 LSI --
>    000ffff1 LSI --
>    000ffff2 LSI --
>    000ffff3 LSI --
>    000ffff4 LSI --
>    000ffff5 LSI --
>    000ffff6 LSI --
>    000ffff7 LSI --
>    000ffff8 LSI --
>    000ffff9 LSI --
>    000ffffa LSI --
>    000ffffb LSI --
>    000ffffc LSI --
>    000ffffd LSI --
> PHB4[0:0] Source 000fe000 .. 000fefff  @6030203110100
>    00000ffe LSI --
>    00000fff LSI --
> PHB4[0:5] Source 000fb000 .. 000fb7ff  @6030203110228
>    00000000 MSI --
>    00000001 MSI --
>    00000002 MSI --
>    00000003 MSI --
>    00000004 MSI --
>    00000005 MSI --
>    00000006 MSI --
>    000007fe LSI --
>    000007ff LSI --
> PHB4[0:4] Source 000fb800 .. 000fbfff  @6030203110220
>    000007fe LSI --
>    000007ff LSI --
> PHB4[0:3] Source 000fc000 .. 000fcfff  @6030203110218
>    00000ffe LSI --
>    00000fff LSI --
> PHB4[0:2] Source 000fd000 .. 000fd7ff  @6030203110210
>    00000000 MSI --
>    00000001 MSI --
>    00000002 MSI --
>    00000003 MSI --
>    00000004 MSI --
>    000007fe LSI --
>    000007ff LSI --
> PHB4[0:1] Source 000fd800 .. 000fdfff  @6030203110208
>    000007fe LSI --
>    000007ff LSI --
> 
>> Could you please check with powersave=off in the host kernel also ?
>>
> 
> It still hangs with this option.

This is going to need some serious digging to solve. It might not be worse
the time :/

C.


^ permalink raw reply	[flat|nested] 46+ messages in thread

end of thread, other threads:[~2022-10-03 22:13 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-27 20:15 [RFC PATCH v2 00/29] PowerPC interrupt rework Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 01/29] target/ppc: define PPC_INTERRUPT_* values directly Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 02/29] target/ppc: always use ppc_set_irq to set env->pending_interrupts Matheus Ferst
2022-09-30 14:32   ` Fabiano Rosas
2022-09-27 20:15 ` [RFC PATCH v2 03/29] target/ppc: split interrupt masking and delivery from ppc_hw_interrupt Matheus Ferst
2022-09-30 15:55   ` Fabiano Rosas
2022-09-27 20:15 ` [RFC PATCH v2 04/29] target/ppc: prepare to split interrupt masking and delivery by excp_model Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 05/29] target/ppc: create an interrupt masking method for POWER9/POWER10 Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 06/29] target/ppc: remove unused interrupts from p9_pending_interrupt Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 07/29] target/ppc: create an interrupt delivery method for POWER9/POWER10 Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 08/29] target/ppc: remove unused interrupts from p9_deliver_interrupt Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 09/29] target/ppc: remove generic architecture checks " Matheus Ferst
2022-09-30 18:13   ` Fabiano Rosas
2022-10-03 15:45     ` Matheus K. Ferst
2022-10-03 16:59       ` Fabiano Rosas
2022-09-27 20:15 ` [RFC PATCH v2 10/29] target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER9 Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 11/29] target/ppc: add power-saving interrupt masking logic to p9_next_unmasked_interrupt Matheus Ferst
2022-09-30 18:38   ` Fabiano Rosas
2022-10-03 15:46     ` Matheus K. Ferst
2022-10-03 17:01       ` Fabiano Rosas
2022-09-27 20:15 ` [RFC PATCH v2 12/29] target/ppc: create an interrupt masking method for POWER8 Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 13/29] target/ppc: remove unused interrupts from p8_pending_interrupt Matheus Ferst
2022-09-27 22:14   ` Fabiano Rosas
2022-10-03 15:45     ` Matheus K. Ferst
2022-09-27 20:15 ` [RFC PATCH v2 14/29] target/ppc: create an interrupt delivery method for POWER8 Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 15/29] target/ppc: remove unused interrupts from p8_deliver_interrupt Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 16/29] target/ppc: remove generic architecture checks " Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 17/29] target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER8 Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 18/29] target/ppc: add power-saving interrupt masking logic to p8_next_unmasked_interrupt Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 19/29] target/ppc: create an interrupt masking method for POWER7 Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 20/29] target/ppc: remove unused interrupts from p7_pending_interrupt Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 21/29] target/ppc: create an interrupt delivery method for POWER7 Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 22/29] target/ppc: remove unused interrupts from p7_deliver_interrupt Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 23/29] target/ppc: remove generic architecture checks " Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 24/29] target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER7 Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 25/29] target/ppc: add power-saving interrupt masking logic to p7_next_unmasked_interrupt Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 26/29] target/ppc: remove ppc_store_lpcr from CONFIG_USER_ONLY builds Matheus Ferst
2022-09-27 20:15 ` [RFC PATCH v2 27/29] target/ppc: introduce ppc_maybe_interrupt Matheus Ferst
2022-10-03 14:11   ` Fabiano Rosas
2022-09-27 20:15 ` [RFC PATCH v2 28/29] target/ppc: unify cpu->has_work based on cs->interrupt_request Matheus Ferst
2022-10-03 14:12   ` Fabiano Rosas
2022-09-27 20:15 ` [RFC PATCH v2 29/29] target/ppc: move the p*_interrupt_powersave methods to excp_helper.c Matheus Ferst
2022-10-03 14:13   ` Fabiano Rosas
2022-09-28 17:31 ` [RFC PATCH v2 00/29] PowerPC interrupt rework Cédric Le Goater
2022-10-03 15:45   ` Matheus K. Ferst
2022-10-03 20:58     ` Cédric Le Goater

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.