Re: [RFC PATCH 09/10] ppc/pnv: Implement POWER10 PC xscom registers for direct controls

2024-05-29 Thread Nicholas Piggin
On Wed May 29, 2024 at 5:00 PM AEST, Cédric Le Goater wrote:
> On 5/26/24 14:26, Nicholas Piggin wrote:
> > The PC unit in the processor core contains xscom registers that provide
> > low level status and control of the CPU.
> > 
> > This implements "direct controls" sufficient for OPAL (skiboot) firmware
> > use, which is to stop threads and send them non-maskable IPIs in the
> > form of SRESET interrupts.
> > 
> > POWER10 is sufficiently different (particularly QME and special wakeup)
> > from POWER9 that it is not trivial to implement by reusing the code.
> > 
> > Signed-off-by: Nicholas Piggin 
> > ---
> >   include/hw/core/cpu.h |  8 
> >   include/hw/ppc/pnv.h  |  2 +
> >   include/hw/ppc/pnv_core.h |  3 ++
> >   hw/ppc/pnv.c  |  7 +++-
> >   hw/ppc/pnv_core.c | 88 ---
> >   system/cpus.c | 10 +
> >   6 files changed, 112 insertions(+), 6 deletions(-)
> > 
> > diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
> > index bb398e8237..52a8fc65cb 100644
> > --- a/include/hw/core/cpu.h
> > +++ b/include/hw/core/cpu.h
> > @@ -974,6 +974,14 @@ void cpu_reset_interrupt(CPUState *cpu, int mask);
> >*/
> >   void cpu_exit(CPUState *cpu);
> >   
> > +/**
> > + * cpu_pause:
> > + * @cpu: The CPU to pause.
> > + *
> > + * Resumes CPU, i.e. puts CPU into stopped state.
> > + */
> > +void cpu_pause(CPUState *cpu);
> > +
> >   /**
> >* cpu_resume:
> >* @cpu: The CPU to resume.
> > diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> > index 93ecb062b4..bec603f1a8 100644
> > --- a/include/hw/ppc/pnv.h
> > +++ b/include/hw/ppc/pnv.h
> > @@ -111,6 +111,8 @@ PnvChip *pnv_chip_add_phb(PnvChip *chip, PnvPHB *phb);
> >   #define PNV_FDT_ADDR  0x0100
> >   #define PNV_TIMEBASE_FREQ 51200ULL
> >   
> > +void pnv_cpu_do_nmi(CPUState *cs);
> > +
> >   /*
> >* BMC helpers
> >*/
> > diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
> > index 39f8f33e6c..9599da15ea 100644
> > --- a/include/hw/ppc/pnv_core.h
> > +++ b/include/hw/ppc/pnv_core.h
> > @@ -109,6 +109,9 @@ OBJECT_DECLARE_TYPE(PnvQuad, PnvQuadClass, PNV_QUAD)
> >   struct PnvQuad {
> >   DeviceState parent_obj;
> >   
> > +bool special_wakeup_done;
> > +bool special_wakeup[4];
> > +
> >   uint32_t quad_id;
> >   MemoryRegion xscom_regs;
> >   MemoryRegion xscom_qme_regs;
> > diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> > index 5364c55bbb..765142965f 100644
> > --- a/hw/ppc/pnv.c
> > +++ b/hw/ppc/pnv.c
> > @@ -2700,12 +2700,17 @@ static void pnv_cpu_do_nmi_on_cpu(CPUState *cs, 
> > run_on_cpu_data arg)
> >   }
> >   }
> >   
> > +void pnv_cpu_do_nmi(CPUState *cs)
> > +{
> > +async_run_on_cpu(cs, pnv_cpu_do_nmi_on_cpu, RUN_ON_CPU_NULL);
> > +}
> > +
> >   static void pnv_nmi(NMIState *n, int cpu_index, Error **errp)
> >   {
> >   CPUState *cs;
> >   
> >   CPU_FOREACH(cs) {
> > -async_run_on_cpu(cs, pnv_cpu_do_nmi_on_cpu, RUN_ON_CPU_NULL);
> > +pnv_cpu_do_nmi(cs);
> >   }
> >   }
>
> What about ?
>
> https://lore.kernel.org/qemu-devel/20240424093048.180966-1-...@redhat.com/

I haven't forgotten it. I just didn't put it in the first PR since
there was quite a lot of pnv patches to do so I thought I will collect
most of them for another PR.

Thanks,
Nick



Re: [RFC PATCH 09/10] ppc/pnv: Implement POWER10 PC xscom registers for direct controls

2024-05-29 Thread Cédric Le Goater

On 5/26/24 14:26, Nicholas Piggin wrote:

The PC unit in the processor core contains xscom registers that provide
low level status and control of the CPU.

This implements "direct controls" sufficient for OPAL (skiboot) firmware
use, which is to stop threads and send them non-maskable IPIs in the
form of SRESET interrupts.

POWER10 is sufficiently different (particularly QME and special wakeup)
from POWER9 that it is not trivial to implement by reusing the code.

Signed-off-by: Nicholas Piggin 
---
  include/hw/core/cpu.h |  8 
  include/hw/ppc/pnv.h  |  2 +
  include/hw/ppc/pnv_core.h |  3 ++
  hw/ppc/pnv.c  |  7 +++-
  hw/ppc/pnv_core.c | 88 ---
  system/cpus.c | 10 +
  6 files changed, 112 insertions(+), 6 deletions(-)

diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index bb398e8237..52a8fc65cb 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -974,6 +974,14 @@ void cpu_reset_interrupt(CPUState *cpu, int mask);
   */
  void cpu_exit(CPUState *cpu);
  
+/**

+ * cpu_pause:
+ * @cpu: The CPU to pause.
+ *
+ * Resumes CPU, i.e. puts CPU into stopped state.
+ */
+void cpu_pause(CPUState *cpu);
+
  /**
   * cpu_resume:
   * @cpu: The CPU to resume.
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index 93ecb062b4..bec603f1a8 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -111,6 +111,8 @@ PnvChip *pnv_chip_add_phb(PnvChip *chip, PnvPHB *phb);
  #define PNV_FDT_ADDR  0x0100
  #define PNV_TIMEBASE_FREQ 51200ULL
  
+void pnv_cpu_do_nmi(CPUState *cs);

+
  /*
   * BMC helpers
   */
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
index 39f8f33e6c..9599da15ea 100644
--- a/include/hw/ppc/pnv_core.h
+++ b/include/hw/ppc/pnv_core.h
@@ -109,6 +109,9 @@ OBJECT_DECLARE_TYPE(PnvQuad, PnvQuadClass, PNV_QUAD)
  struct PnvQuad {
  DeviceState parent_obj;
  
+bool special_wakeup_done;

+bool special_wakeup[4];
+
  uint32_t quad_id;
  MemoryRegion xscom_regs;
  MemoryRegion xscom_qme_regs;
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 5364c55bbb..765142965f 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -2700,12 +2700,17 @@ static void pnv_cpu_do_nmi_on_cpu(CPUState *cs, 
run_on_cpu_data arg)
  }
  }
  
+void pnv_cpu_do_nmi(CPUState *cs)

+{
+async_run_on_cpu(cs, pnv_cpu_do_nmi_on_cpu, RUN_ON_CPU_NULL);
+}
+
  static void pnv_nmi(NMIState *n, int cpu_index, Error **errp)
  {
  CPUState *cs;
  
  CPU_FOREACH(cs) {

-async_run_on_cpu(cs, pnv_cpu_do_nmi_on_cpu, RUN_ON_CPU_NULL);
+pnv_cpu_do_nmi(cs);
  }
  }


What about ?

https://lore.kernel.org/qemu-devel/20240424093048.180966-1-...@redhat.com/


Thanks,

C.




diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 10417d92ae..835c35d90b 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -184,16 +184,40 @@ static const MemoryRegionOps pnv_core_power9_xscom_ops = {
   */
  
  #define PNV10_XSCOM_EC_CORE_THREAD_STATE0x412

+#define PNV10_XSCOM_EC_CORE_THREAD_INFO 0x413
+#define PNV10_XSCOM_EC_CORE_DIRECT_CONTROLS 0x449
+#define PNV10_XSCOM_EC_CORE_RAS_STATUS  0x454
  
  static uint64_t pnv_core_power10_xscom_read(void *opaque, hwaddr addr,

 unsigned int width)
  {
+PnvCore *pc = PNV_CORE(opaque);
+int nr_threads = CPU_CORE(pc)->nr_threads;
+int i;
  uint32_t offset = addr >> 3;
  uint64_t val = 0;
  
  switch (offset) {

  case PNV10_XSCOM_EC_CORE_THREAD_STATE:
-val = 0;
+for (i = 0; i < nr_threads; i++) {
+PowerPCCPU *cpu = pc->threads[i];
+CPUState *cs = CPU(cpu);
+
+if (cs->halted) {
+val |= PPC_BIT(56 + i);
+}
+}
+break;
+case PNV10_XSCOM_EC_CORE_THREAD_INFO:
+break;
+case PNV10_XSCOM_EC_CORE_RAS_STATUS:
+for (i = 0; i < nr_threads; i++) {
+PowerPCCPU *cpu = pc->threads[i];
+CPUState *cs = CPU(cpu);
+if (cs->stopped) {
+val |= PPC_BIT(0 + 8*i) | PPC_BIT(1 + 8*i);
+}
+}
  break;
  default:
  qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
@@ -206,9 +230,45 @@ static uint64_t pnv_core_power10_xscom_read(void *opaque, 
hwaddr addr,
  static void pnv_core_power10_xscom_write(void *opaque, hwaddr addr,
   uint64_t val, unsigned int width)
  {
+PnvCore *pc = PNV_CORE(opaque);
+int nr_threads = CPU_CORE(pc)->nr_threads;
+int i;
  uint32_t offset = addr >> 3;
  
  switch (offset) {

+case PNV10_XSCOM_EC_CORE_DIRECT_CONTROLS:
+for (i = 0; i < nr_threads; i++) {
+PowerPCCPU *cpu = pc->threads[i];
+CPUState *cs = CPU(cpu);
+
+if (val & PPC_BIT(7 + 8*i)) { /* stop */
+val &= ~PPC_BIT(7 + 8*i);
+cpu_pa

[RFC PATCH 09/10] ppc/pnv: Implement POWER10 PC xscom registers for direct controls

2024-05-26 Thread Nicholas Piggin
The PC unit in the processor core contains xscom registers that provide
low level status and control of the CPU.

This implements "direct controls" sufficient for OPAL (skiboot) firmware
use, which is to stop threads and send them non-maskable IPIs in the
form of SRESET interrupts.

POWER10 is sufficiently different (particularly QME and special wakeup)
from POWER9 that it is not trivial to implement by reusing the code.

Signed-off-by: Nicholas Piggin 
---
 include/hw/core/cpu.h |  8 
 include/hw/ppc/pnv.h  |  2 +
 include/hw/ppc/pnv_core.h |  3 ++
 hw/ppc/pnv.c  |  7 +++-
 hw/ppc/pnv_core.c | 88 ---
 system/cpus.c | 10 +
 6 files changed, 112 insertions(+), 6 deletions(-)

diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index bb398e8237..52a8fc65cb 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -974,6 +974,14 @@ void cpu_reset_interrupt(CPUState *cpu, int mask);
  */
 void cpu_exit(CPUState *cpu);
 
+/**
+ * cpu_pause:
+ * @cpu: The CPU to pause.
+ *
+ * Resumes CPU, i.e. puts CPU into stopped state.
+ */
+void cpu_pause(CPUState *cpu);
+
 /**
  * cpu_resume:
  * @cpu: The CPU to resume.
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index 93ecb062b4..bec603f1a8 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -111,6 +111,8 @@ PnvChip *pnv_chip_add_phb(PnvChip *chip, PnvPHB *phb);
 #define PNV_FDT_ADDR  0x0100
 #define PNV_TIMEBASE_FREQ 51200ULL
 
+void pnv_cpu_do_nmi(CPUState *cs);
+
 /*
  * BMC helpers
  */
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
index 39f8f33e6c..9599da15ea 100644
--- a/include/hw/ppc/pnv_core.h
+++ b/include/hw/ppc/pnv_core.h
@@ -109,6 +109,9 @@ OBJECT_DECLARE_TYPE(PnvQuad, PnvQuadClass, PNV_QUAD)
 struct PnvQuad {
 DeviceState parent_obj;
 
+bool special_wakeup_done;
+bool special_wakeup[4];
+
 uint32_t quad_id;
 MemoryRegion xscom_regs;
 MemoryRegion xscom_qme_regs;
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 5364c55bbb..765142965f 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -2700,12 +2700,17 @@ static void pnv_cpu_do_nmi_on_cpu(CPUState *cs, 
run_on_cpu_data arg)
 }
 }
 
+void pnv_cpu_do_nmi(CPUState *cs)
+{
+async_run_on_cpu(cs, pnv_cpu_do_nmi_on_cpu, RUN_ON_CPU_NULL);
+}
+
 static void pnv_nmi(NMIState *n, int cpu_index, Error **errp)
 {
 CPUState *cs;
 
 CPU_FOREACH(cs) {
-async_run_on_cpu(cs, pnv_cpu_do_nmi_on_cpu, RUN_ON_CPU_NULL);
+pnv_cpu_do_nmi(cs);
 }
 }
 
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 10417d92ae..835c35d90b 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -184,16 +184,40 @@ static const MemoryRegionOps pnv_core_power9_xscom_ops = {
  */
 
 #define PNV10_XSCOM_EC_CORE_THREAD_STATE0x412
+#define PNV10_XSCOM_EC_CORE_THREAD_INFO 0x413
+#define PNV10_XSCOM_EC_CORE_DIRECT_CONTROLS 0x449
+#define PNV10_XSCOM_EC_CORE_RAS_STATUS  0x454
 
 static uint64_t pnv_core_power10_xscom_read(void *opaque, hwaddr addr,
unsigned int width)
 {
+PnvCore *pc = PNV_CORE(opaque);
+int nr_threads = CPU_CORE(pc)->nr_threads;
+int i;
 uint32_t offset = addr >> 3;
 uint64_t val = 0;
 
 switch (offset) {
 case PNV10_XSCOM_EC_CORE_THREAD_STATE:
-val = 0;
+for (i = 0; i < nr_threads; i++) {
+PowerPCCPU *cpu = pc->threads[i];
+CPUState *cs = CPU(cpu);
+
+if (cs->halted) {
+val |= PPC_BIT(56 + i);
+}
+}
+break;
+case PNV10_XSCOM_EC_CORE_THREAD_INFO:
+break;
+case PNV10_XSCOM_EC_CORE_RAS_STATUS:
+for (i = 0; i < nr_threads; i++) {
+PowerPCCPU *cpu = pc->threads[i];
+CPUState *cs = CPU(cpu);
+if (cs->stopped) {
+val |= PPC_BIT(0 + 8*i) | PPC_BIT(1 + 8*i);
+}
+}
 break;
 default:
 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
@@ -206,9 +230,45 @@ static uint64_t pnv_core_power10_xscom_read(void *opaque, 
hwaddr addr,
 static void pnv_core_power10_xscom_write(void *opaque, hwaddr addr,
  uint64_t val, unsigned int width)
 {
+PnvCore *pc = PNV_CORE(opaque);
+int nr_threads = CPU_CORE(pc)->nr_threads;
+int i;
 uint32_t offset = addr >> 3;
 
 switch (offset) {
+case PNV10_XSCOM_EC_CORE_DIRECT_CONTROLS:
+for (i = 0; i < nr_threads; i++) {
+PowerPCCPU *cpu = pc->threads[i];
+CPUState *cs = CPU(cpu);
+
+if (val & PPC_BIT(7 + 8*i)) { /* stop */
+val &= ~PPC_BIT(7 + 8*i);
+cpu_pause(cs);
+}
+if (val & PPC_BIT(6 + 8*i)) { /* start */
+val &= ~PPC_BIT(6 + 8*i);
+cpu_resume(cs);
+}
+if (val & PPC_BIT(4 + 8*i)) { /*