All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform
@ 2019-03-06  8:50 Cédric Le Goater
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 01/27] ppc/xive: hardwire the Physical CAM line of the thread context Cédric Le Goater
                   ` (26 more replies)
  0 siblings, 27 replies; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

Hello,

Here is a series adding support for the POWER9 processor to the
PowerNV machine. It includes models for the baremetal POWER9 Interrupt
controller (XIVE), the PSI host bridge, the LPC controller, and a
minimalist OCC. It should bring the POWER9 PowerNV platform to the
same level as POWER8, that is without PHBs.

A new skiboot image is not provided yet because I would like first to
have a tagged version of skiboot including the recent changes removing
support for DD1. Will come later.

Thanks,

C.

Changes in v1 (since PnvXive was last sent) :

 - fixed compilation on clang (forward declarations)
 
 - simplified the hardwiring of the Physical CAM line. removed the
   'hw-cam' property. 
 - removed 'hwaddr offset' from the get_tctx() XiveRouter handler. It
   was a misunderstanding of the PC_THREAD_EN_REGx registers.
 - changed the CPU machine_data presenter type to 'Object *' to accept
   XiveTCTX
 - introduced a new dt_populate() operation to the chip model
 - introduced a new pic_print_info() operation to the chip model
 - removed 'chip_id' from PnvXive.
 - removed 'nr_irqs' and 'nr_ends' from PnvXive. Values are now
   calculated from the VST settings done by FW.   
 - removed 'type' field from the XiveVstInfo struct describing the VSTs
 - simplified pnv_xive_get_ic() grabbing a remote IC
 - introduced a pnv_xive_vst_size() helper computing the size of a VST
   table, direct or indirect. Used to computed the number of virtual
   structures entries provisioned by FW.
 - reworked pnv_xive_vst_addr_*() helpers. Fixed a bug when multiple
   pages are in use.
 - took into account the word_number when doing stores of the virtual
   structures.
 - the IPI and the END sub memory regions of the VC BAR are now
   resized and mapped when the EDT is configured, depending on how the
   VC region was segmented.
 - the XiveSource and the XiveENDSource memory regions are now resized
   and mapped when the VST are configured, depending on how much
   virtual structures entries were provisioned by FW.
 - removed PC_GCONF_CHIPID_OVR handling. Was for debug according to HW
   designers. xive->chip->chip_id is now used as the block id when
   needed.
 - reworked pic_print_info() to use the number of virtual structures
   entries provisioned by FW.

What has not changed (since PnvXive was sent) :

 - GETFIELD/SETFIELD macros. It would break the compatibility with
   skiboot in the register definitions. Still needs some thinking to
   find a common ground. P10 material for QEMU and skiboot probably.
 - The HW interface of XIVE is still bound to the register array. P10
   support will determine which is the best approach.
 
Benjamin Herrenschmidt (1):
  ppc/xive: Make XIVE generate the proper interrupt types

Cédric Le Goater (26):
  ppc/xive: hardwire the Physical CAM line of the thread context
  ppc: externalize ppc_get_vcpu_by_pir()
  ppc/xive: export the TIMA memory accessors
  ppc/pnv: export the xive_router_notify() routine
  ppc/pnv: change the CPU machine_data presenter type to Object *
  ppc/pnv: add a XIVE interrupt controller model for POWER9
  ppc/pnv: introduce a new dt_populate() operation to the chip model
  ppc/pnv: introduce a new pic_print_info() operation to the chip model
  ppc/xive: activate HV support
  ppc/pnv: fix logging primitives using Ox
  ppc/pnv: psi: add a PSIHB_REG macro
  ppc/pnv: psi: add a reset handler
  ppc/pnv: add a PSI bridge model class
  ppc/pnv: add a PSI bridge model for POWER9
  ppc/pnv: lpc: fix OPB address ranges
  ppc/pnv: add a LPC Controller model class
  ppc/pnv: add a LPC Controller model for POWER9
  ppc/pnv: add SerIRQ routing registers
  ppc/pnv: add a OCC model class
  ppc/pnv: add a OCC model for POWER9
  ppc/pnv: extend XSCOM core support for POWER9
  ppc/pnv: POWER9 XSCOM quad support
  ppc/pnv: activate XSCOM tests for POWER9
  ppc/pnv: add more dummy XSCOM addresses
  ppc/pnv: add a "ibm,opal/power-mgt" device tree node on POWER9
  target/ppc: add HV support for POWER9

 hw/intc/pnv_xive_regs.h         |  248 +++++
 include/hw/ppc/pnv.h            |   38 +
 include/hw/ppc/pnv_core.h       |   12 +-
 include/hw/ppc/pnv_lpc.h        |   28 +
 include/hw/ppc/pnv_occ.h        |   18 +
 include/hw/ppc/pnv_psi.h        |   45 +-
 include/hw/ppc/pnv_xive.h       |   93 ++
 include/hw/ppc/pnv_xscom.h      |   21 +-
 include/hw/ppc/ppc.h            |    1 +
 include/hw/ppc/xive.h           |    7 +-
 hw/intc/pnv_xive.c              | 1753 +++++++++++++++++++++++++++++++
 hw/intc/xive.c                  |  135 ++-
 hw/ppc/pnv.c                    |  236 ++++-
 hw/ppc/pnv_core.c               |  111 +-
 hw/ppc/pnv_lpc.c                |  316 +++++-
 hw/ppc/pnv_occ.c                |   63 +-
 hw/ppc/pnv_psi.c                |  414 +++++++-
 hw/ppc/pnv_xscom.c              |   33 +-
 hw/ppc/ppc.c                    |   16 +
 target/ppc/translate_init.inc.c |    3 +-
 tests/pnv-xscom-test.c          |    2 -
 hw/intc/Makefile.objs           |    2 +-
 22 files changed, 3471 insertions(+), 124 deletions(-)
 create mode 100644 hw/intc/pnv_xive_regs.h
 create mode 100644 include/hw/ppc/pnv_xive.h
 create mode 100644 hw/intc/pnv_xive.c

-- 
2.20.1

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

* [Qemu-devel] [PATCH 01/27] ppc/xive: hardwire the Physical CAM line of the thread context
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-07  1:19   ` David Gibson
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 02/27] ppc: externalize ppc_get_vcpu_by_pir() Cédric Le Goater
                   ` (25 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

By default on P9, the HW CAM line (23bits) is hardwired to :

      0x000||0b1||4Bit chip number||7Bit Thread number.

When the block group mode is enabled at the controller level (PowerNV),
the CAM line is changed for CAM compares to :

      4Bit chip number||0x001||7Bit Thread number

This will require changes in xive_presenter_tctx_match() possibly.
This is a lowlevel functionality of the HW controller and it is not
strictly needed. Leave it for later.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/intc/xive.c | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index daa7badc8492..b21759c93856 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -1112,6 +1112,30 @@ XiveTCTX *xive_router_get_tctx(XiveRouter *xrtr, CPUState *cs)
     return xrc->get_tctx(xrtr, cs);
 }
 
+/*
+ * By default on P9, the HW CAM line (23bits) is hardwired to :
+ *
+ *   0x000||0b1||4Bit chip number||7Bit Thread number.
+ *
+ * When the block grouping is enabled, the CAM line is changed to :
+ *
+ *   4Bit chip number||0x001||7Bit Thread number.
+ */
+static uint32_t hw_cam_line(uint8_t chip_id, uint8_t tid)
+{
+    return 1 << 11 | (chip_id & 0xf) << 7 | (tid & 0x7f);
+}
+
+static bool xive_presenter_tctx_match_hw(XiveTCTX *tctx,
+                                         uint8_t nvt_blk, uint32_t nvt_idx)
+{
+    CPUPPCState *env = &POWERPC_CPU(tctx->cs)->env;
+    uint32_t pir = env->spr_cb[SPR_PIR].default_value;
+
+    return hw_cam_line((pir >> 8) & 0xf, pir & 0x7f) ==
+        hw_cam_line(nvt_blk, nvt_idx);
+}
+
 /*
  * The thread context register words are in big-endian format.
  */
@@ -1120,6 +1144,7 @@ static int xive_presenter_tctx_match(XiveTCTX *tctx, uint8_t format,
                                      bool cam_ignore, uint32_t logic_serv)
 {
     uint32_t cam = xive_nvt_cam_line(nvt_blk, nvt_idx);
+    uint32_t qw3w2 = xive_tctx_word2(&tctx->regs[TM_QW3_HV_PHYS]);
     uint32_t qw2w2 = xive_tctx_word2(&tctx->regs[TM_QW2_HV_POOL]);
     uint32_t qw1w2 = xive_tctx_word2(&tctx->regs[TM_QW1_OS]);
     uint32_t qw0w2 = xive_tctx_word2(&tctx->regs[TM_QW0_USER]);
@@ -1142,7 +1167,11 @@ static int xive_presenter_tctx_match(XiveTCTX *tctx, uint8_t format,
 
         /* F=0 & i=0: Specific NVT notification */
 
-        /* TODO (PowerNV) : PHYS ring */
+        /* PHYS ring */
+        if ((be32_to_cpu(qw3w2) & TM_QW3W2_VT) &&
+            xive_presenter_tctx_match_hw(tctx, nvt_blk, nvt_idx)) {
+            return TM_QW3_HV_PHYS;
+        }
 
         /* HV POOL ring */
         if ((be32_to_cpu(qw2w2) & TM_QW2W2_VP) &&
-- 
2.20.1

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

* [Qemu-devel] [PATCH 02/27] ppc: externalize ppc_get_vcpu_by_pir()
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 01/27] ppc/xive: hardwire the Physical CAM line of the thread context Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 03/27] ppc/xive: export the TIMA memory accessors Cédric Le Goater
                   ` (24 subsequent siblings)
  26 siblings, 0 replies; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

We will use it to get the CPU interrupt presenter in XIVE when the
TIMA is accessed from the indirect page.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/ppc/ppc.h |  1 +
 hw/ppc/pnv.c         | 16 ----------------
 hw/ppc/ppc.c         | 16 ++++++++++++++++
 3 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/include/hw/ppc/ppc.h b/include/hw/ppc/ppc.h
index 746170f635c6..4bdcb8bacd4e 100644
--- a/include/hw/ppc/ppc.h
+++ b/include/hw/ppc/ppc.h
@@ -4,6 +4,7 @@
 #include "target/ppc/cpu-qom.h"
 
 void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level);
+PowerPCCPU *ppc_get_vcpu_by_pir(int pir);
 
 /* PowerPC hardware exceptions management helpers */
 typedef void (*clk_setup_cb)(void *opaque, uint32_t freq);
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 3d5dfef220e2..9aa81c7f09c2 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -1082,22 +1082,6 @@ static void pnv_ics_resend(XICSFabric *xi)
     }
 }
 
-static PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
-{
-    CPUState *cs;
-
-    CPU_FOREACH(cs) {
-        PowerPCCPU *cpu = POWERPC_CPU(cs);
-        CPUPPCState *env = &cpu->env;
-
-        if (env->spr_cb[SPR_PIR].default_value == pir) {
-            return cpu;
-        }
-    }
-
-    return NULL;
-}
-
 static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
 {
     PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir);
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 9145aeddcb29..b2ff99ec66a1 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -1487,3 +1487,19 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
         break;
     }
 }
+
+PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
+{
+    CPUState *cs;
+
+    CPU_FOREACH(cs) {
+        PowerPCCPU *cpu = POWERPC_CPU(cs);
+        CPUPPCState *env = &cpu->env;
+
+        if (env->spr_cb[SPR_PIR].default_value == pir) {
+            return cpu;
+        }
+    }
+
+    return NULL;
+}
-- 
2.20.1

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

* [Qemu-devel] [PATCH 03/27] ppc/xive: export the TIMA memory accessors
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 01/27] ppc/xive: hardwire the Physical CAM line of the thread context Cédric Le Goater
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 02/27] ppc: externalize ppc_get_vcpu_by_pir() Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 04/27] ppc/pnv: export the xive_router_notify() routine Cédric Le Goater
                   ` (23 subsequent siblings)
  26 siblings, 0 replies; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

The PowerNV machine can perform indirect loads and stores on the TIMA
on behalf of another CPU. Give the controller the possibility to call
the TIMA memory accessors with a XiveTCTX of its choice.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/ppc/xive.h |  3 +++
 hw/intc/xive.c        | 23 ++++++++++++++++++-----
 2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h
index 13a487527b11..7dd80e0f46ef 100644
--- a/include/hw/ppc/xive.h
+++ b/include/hw/ppc/xive.h
@@ -410,6 +410,9 @@ void xive_end_queue_pic_print_info(XiveEND *end, uint32_t width, Monitor *mon);
 #define XIVE_TM_USER_PAGE       0x3
 
 extern const MemoryRegionOps xive_tm_ops;
+void xive_tctx_tm_write(XiveTCTX *tctx, hwaddr offset, uint64_t value,
+                        unsigned size);
+uint64_t xive_tctx_tm_read(XiveTCTX *tctx, hwaddr offset, unsigned size);
 
 void xive_tctx_pic_print_info(XiveTCTX *tctx, Monitor *mon);
 Object *xive_tctx_create(Object *cpu, XiveRouter *xrtr, Error **errp);
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index b21759c93856..3d7de864e93f 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -317,10 +317,9 @@ static const XiveTmOp *xive_tm_find_op(hwaddr offset, unsigned size, bool write)
 /*
  * TIMA MMIO handlers
  */
-static void xive_tm_write(void *opaque, hwaddr offset,
-                          uint64_t value, unsigned size)
+void xive_tctx_tm_write(XiveTCTX *tctx, hwaddr offset, uint64_t value,
+                        unsigned size)
 {
-    XiveTCTX *tctx = xive_router_get_tctx(XIVE_ROUTER(opaque), current_cpu);
     const XiveTmOp *xto;
 
     /*
@@ -356,9 +355,8 @@ static void xive_tm_write(void *opaque, hwaddr offset,
     xive_tm_raw_write(tctx, offset, value, size);
 }
 
-static uint64_t xive_tm_read(void *opaque, hwaddr offset, unsigned size)
+uint64_t xive_tctx_tm_read(XiveTCTX *tctx, hwaddr offset, unsigned size)
 {
-    XiveTCTX *tctx = xive_router_get_tctx(XIVE_ROUTER(opaque), current_cpu);
     const XiveTmOp *xto;
 
     /*
@@ -392,6 +390,21 @@ static uint64_t xive_tm_read(void *opaque, hwaddr offset, unsigned size)
     return xive_tm_raw_read(tctx, offset, size);
 }
 
+static void xive_tm_write(void *opaque, hwaddr offset,
+                          uint64_t value, unsigned size)
+{
+    XiveTCTX *tctx = xive_router_get_tctx(XIVE_ROUTER(opaque), current_cpu);
+
+    xive_tctx_tm_write(tctx, offset, value, size);
+}
+
+static uint64_t xive_tm_read(void *opaque, hwaddr offset, unsigned size)
+{
+    XiveTCTX *tctx = xive_router_get_tctx(XIVE_ROUTER(opaque), current_cpu);
+
+    return xive_tctx_tm_read(tctx, offset, size);
+}
+
 const MemoryRegionOps xive_tm_ops = {
     .read = xive_tm_read,
     .write = xive_tm_write,
-- 
2.20.1

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

* [Qemu-devel] [PATCH 04/27] ppc/pnv: export the xive_router_notify() routine
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (2 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 03/27] ppc/xive: export the TIMA memory accessors Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 05/27] ppc/pnv: change the CPU machine_data presenter type to Object * Cédric Le Goater
                   ` (22 subsequent siblings)
  26 siblings, 0 replies; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

The PowerNV machine with need to encode the block id in the source
interrupt number before forwarding the source event notification to
the Router.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/ppc/xive.h | 1 +
 hw/intc/xive.c        | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h
index 7dd80e0f46ef..c4f27742ca09 100644
--- a/include/hw/ppc/xive.h
+++ b/include/hw/ppc/xive.h
@@ -364,6 +364,7 @@ int xive_router_get_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
 int xive_router_write_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
                           XiveNVT *nvt, uint8_t word_number);
 XiveTCTX *xive_router_get_tctx(XiveRouter *xrtr, CPUState *cs);
+void xive_router_notify(XiveNotifier *xn, uint32_t lisn);
 
 /*
  * XIVE END ESBs
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index 3d7de864e93f..7d7992c0ce3f 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -1404,7 +1404,7 @@ static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk,
     /* TODO: Auto EOI. */
 }
 
-static void xive_router_notify(XiveNotifier *xn, uint32_t lisn)
+void xive_router_notify(XiveNotifier *xn, uint32_t lisn)
 {
     XiveRouter *xrtr = XIVE_ROUTER(xn);
     uint8_t eas_blk = XIVE_SRCNO_BLOCK(lisn);
-- 
2.20.1

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

* [Qemu-devel] [PATCH 05/27] ppc/pnv: change the CPU machine_data presenter type to Object *
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (3 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 04/27] ppc/pnv: export the xive_router_notify() routine Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-07  1:36   ` David Gibson
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 06/27] ppc/pnv: add a XIVE interrupt controller model for POWER9 Cédric Le Goater
                   ` (21 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

The POWER9 PowerNV machine will use a XIVE interrupt presenter type.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/ppc/pnv_core.h | 2 +-
 hw/ppc/pnv.c              | 6 +++---
 hw/ppc/pnv_core.c         | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
index 9961ea3a92cd..6874bb847a01 100644
--- a/include/hw/ppc/pnv_core.h
+++ b/include/hw/ppc/pnv_core.h
@@ -48,7 +48,7 @@ typedef struct PnvCoreClass {
 #define PNV_CORE_TYPE_NAME(cpu_model) cpu_model PNV_CORE_TYPE_SUFFIX
 
 typedef struct PnvCPUState {
-    struct ICPState *icp;
+    Object *intc;
 } PnvCPUState;
 
 static inline PnvCPUState *pnv_cpu_state(PowerPCCPU *cpu)
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 9aa81c7f09c2..b90d03711a05 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -684,7 +684,7 @@ static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu,
         return;
     }
 
-    pnv_cpu->icp = ICP(obj);
+    pnv_cpu->intc = obj;
 }
 
 /*
@@ -1086,7 +1086,7 @@ static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
 {
     PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir);
 
-    return cpu ? pnv_cpu_state(cpu)->icp : NULL;
+    return cpu ? ICP(pnv_cpu_state(cpu)->intc) : NULL;
 }
 
 static void pnv_pic_print_info(InterruptStatsProvider *obj,
@@ -1099,7 +1099,7 @@ static void pnv_pic_print_info(InterruptStatsProvider *obj,
     CPU_FOREACH(cs) {
         PowerPCCPU *cpu = POWERPC_CPU(cs);
 
-        icp_pic_print_info(pnv_cpu_state(cpu)->icp, mon);
+        icp_pic_print_info(ICP(pnv_cpu_state(cpu)->intc), mon);
     }
 
     for (i = 0; i < pnv->num_chips; i++) {
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 7c806da720c6..38179cdc53dc 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -198,7 +198,7 @@ static void pnv_unrealize_vcpu(PowerPCCPU *cpu)
     PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
 
     qemu_unregister_reset(pnv_cpu_reset, cpu);
-    object_unparent(OBJECT(pnv_cpu_state(cpu)->icp));
+    object_unparent(OBJECT(pnv_cpu_state(cpu)->intc));
     cpu_remove_sync(CPU(cpu));
     cpu->machine_data = NULL;
     g_free(pnv_cpu);
-- 
2.20.1

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

* [Qemu-devel] [PATCH 06/27] ppc/pnv: add a XIVE interrupt controller model for POWER9
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (4 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 05/27] ppc/pnv: change the CPU machine_data presenter type to Object * Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-07  1:37   ` David Gibson
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 07/27] ppc/pnv: introduce a new dt_populate() operation to the chip model Cédric Le Goater
                   ` (20 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

This is a simple model of the POWER9 XIVE interrupt controller for the
PowerNV machine which only addresses the needs of the skiboot
firmware. The PowerNV model reuses the common XIVE framework developed
for sPAPR as the fundamentals aspects are quite the same. The
difference are outlined below.

The controller initial BAR configuration is performed using the XSCOM
bus from there, MMIO are used for further configuration.

The MMIO regions exposed are :

 - Interrupt controller registers
 - ESB pages for IPIs and ENDs
 - Presenter MMIO (Not used)
 - Thread Interrupt Management Area MMIO, direct and indirect

The virtualization controller MMIO region containing the IPI ESB pages
and END ESB pages is sub-divided into "sets" which map portions of the
VC region to the different ESB pages. These are modeled with custom
address spaces and the XiveSource and XiveENDSource objects are sized
to the maximum allowed by HW. The memory regions are resized at
run-time using the configuration of EDT set translation table provided
by the firmware.

The XIVE virtualization structure tables (EAT, ENDT, NVTT) are now in
the machine RAM and not in the hypervisor anymore. The firmware
(skiboot) configures these tables using Virtual Structure Descriptor
defining the characteristics of each table : SBE, EAS, END and
NVT. These are later used to access the virtual interrupt entries. The
internal cache of these tables in the interrupt controller is updated
and invalidated using a set of registers.

Still to address to complete the model but not fully required is the
support for block grouping. Escalation support will be necessary for
KVM guests.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/intc/pnv_xive_regs.h    |  248 +++++
 include/hw/ppc/pnv.h       |   21 +
 include/hw/ppc/pnv_xive.h  |   93 ++
 include/hw/ppc/pnv_xscom.h |    3 +
 hw/intc/pnv_xive.c         | 1753 ++++++++++++++++++++++++++++++++++++
 hw/ppc/pnv.c               |   44 +-
 hw/intc/Makefile.objs      |    2 +-
 7 files changed, 2162 insertions(+), 2 deletions(-)
 create mode 100644 hw/intc/pnv_xive_regs.h
 create mode 100644 include/hw/ppc/pnv_xive.h
 create mode 100644 hw/intc/pnv_xive.c

diff --git a/hw/intc/pnv_xive_regs.h b/hw/intc/pnv_xive_regs.h
new file mode 100644
index 000000000000..c78f030c0260
--- /dev/null
+++ b/hw/intc/pnv_xive_regs.h
@@ -0,0 +1,248 @@
+/*
+ * QEMU PowerPC XIVE interrupt controller model
+ *
+ * Copyright (c) 2017-2018, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#ifndef PPC_PNV_XIVE_REGS_H
+#define PPC_PNV_XIVE_REGS_H
+
+/* IC register offsets 0x0 - 0x400 */
+#define CQ_SWI_CMD_HIST         0x020
+#define CQ_SWI_CMD_POLL         0x028
+#define CQ_SWI_CMD_BCAST        0x030
+#define CQ_SWI_CMD_ASSIGN       0x038
+#define CQ_SWI_CMD_BLK_UPD      0x040
+#define CQ_SWI_RSP              0x048
+#define CQ_CFG_PB_GEN           0x050
+#define   CQ_INT_ADDR_OPT       PPC_BITMASK(14, 15)
+#define CQ_MSGSND               0x058
+#define CQ_CNPM_SEL             0x078
+#define CQ_IC_BAR               0x080
+#define   CQ_IC_BAR_VALID       PPC_BIT(0)
+#define   CQ_IC_BAR_64K         PPC_BIT(1)
+#define CQ_TM1_BAR              0x90
+#define CQ_TM2_BAR              0x0a0
+#define   CQ_TM_BAR_VALID       PPC_BIT(0)
+#define   CQ_TM_BAR_64K         PPC_BIT(1)
+#define CQ_PC_BAR               0x0b0
+#define  CQ_PC_BAR_VALID        PPC_BIT(0)
+#define CQ_PC_BARM              0x0b8
+#define  CQ_PC_BARM_MASK        PPC_BITMASK(26, 38)
+#define CQ_VC_BAR               0x0c0
+#define  CQ_VC_BAR_VALID        PPC_BIT(0)
+#define CQ_VC_BARM              0x0c8
+#define  CQ_VC_BARM_MASK        PPC_BITMASK(21, 37)
+#define CQ_TAR                  0x0f0
+#define  CQ_TAR_TBL_AUTOINC     PPC_BIT(0)
+#define  CQ_TAR_TSEL            PPC_BITMASK(12, 15)
+#define  CQ_TAR_TSEL_BLK        PPC_BIT(12)
+#define  CQ_TAR_TSEL_MIG        PPC_BIT(13)
+#define  CQ_TAR_TSEL_VDT        PPC_BIT(14)
+#define  CQ_TAR_TSEL_EDT        PPC_BIT(15)
+#define  CQ_TAR_TSEL_INDEX      PPC_BITMASK(26, 31)
+#define CQ_TDR                  0x0f8
+#define  CQ_TDR_VDT_VALID       PPC_BIT(0)
+#define  CQ_TDR_VDT_BLK         PPC_BITMASK(11, 15)
+#define  CQ_TDR_VDT_INDEX       PPC_BITMASK(28, 31)
+#define  CQ_TDR_EDT_TYPE        PPC_BITMASK(0, 1)
+#define  CQ_TDR_EDT_INVALID     0
+#define  CQ_TDR_EDT_IPI         1
+#define  CQ_TDR_EDT_EQ          2
+#define  CQ_TDR_EDT_BLK         PPC_BITMASK(12, 15)
+#define  CQ_TDR_EDT_INDEX       PPC_BITMASK(26, 31)
+#define CQ_PBI_CTL              0x100
+#define  CQ_PBI_PC_64K          PPC_BIT(5)
+#define  CQ_PBI_VC_64K          PPC_BIT(6)
+#define  CQ_PBI_LNX_TRIG        PPC_BIT(7)
+#define  CQ_PBI_FORCE_TM_LOCAL  PPC_BIT(22)
+#define CQ_PBO_CTL              0x108
+#define CQ_AIB_CTL              0x110
+#define CQ_RST_CTL              0x118
+#define CQ_FIRMASK              0x198
+#define CQ_FIRMASK_AND          0x1a0
+#define CQ_FIRMASK_OR           0x1a8
+
+/* PC LBS1 register offsets 0x400 - 0x800 */
+#define PC_TCTXT_CFG            0x400
+#define  PC_TCTXT_CFG_BLKGRP_EN         PPC_BIT(0)
+#define  PC_TCTXT_CFG_TARGET_EN         PPC_BIT(1)
+#define  PC_TCTXT_CFG_LGS_EN            PPC_BIT(2)
+#define  PC_TCTXT_CFG_STORE_ACK         PPC_BIT(3)
+#define  PC_TCTXT_CFG_HARD_CHIPID_BLK   PPC_BIT(8)
+#define  PC_TCTXT_CHIPID_OVERRIDE       PPC_BIT(9)
+#define  PC_TCTXT_CHIPID                PPC_BITMASK(12, 15)
+#define  PC_TCTXT_INIT_AGE              PPC_BITMASK(30, 31)
+#define PC_TCTXT_TRACK          0x408
+#define  PC_TCTXT_TRACK_EN              PPC_BIT(0)
+#define PC_TCTXT_INDIR0         0x420
+#define  PC_TCTXT_INDIR_VALID           PPC_BIT(0)
+#define  PC_TCTXT_INDIR_THRDID          PPC_BITMASK(9, 15)
+#define PC_TCTXT_INDIR1         0x428
+#define PC_TCTXT_INDIR2         0x430
+#define PC_TCTXT_INDIR3         0x438
+#define PC_THREAD_EN_REG0       0x440
+#define PC_THREAD_EN_REG0_SET   0x448
+#define PC_THREAD_EN_REG0_CLR   0x450
+#define PC_THREAD_EN_REG1       0x460
+#define PC_THREAD_EN_REG1_SET   0x468
+#define PC_THREAD_EN_REG1_CLR   0x470
+#define PC_GLOBAL_CONFIG        0x480
+#define  PC_GCONF_INDIRECT      PPC_BIT(32)
+#define  PC_GCONF_CHIPID_OVR    PPC_BIT(40)
+#define  PC_GCONF_CHIPID        PPC_BITMASK(44, 47)
+#define PC_VSD_TABLE_ADDR       0x488
+#define PC_VSD_TABLE_DATA       0x490
+#define PC_AT_KILL              0x4b0
+#define  PC_AT_KILL_VALID       PPC_BIT(0)
+#define  PC_AT_KILL_BLOCK_ID    PPC_BITMASK(27, 31)
+#define  PC_AT_KILL_OFFSET      PPC_BITMASK(48, 60)
+#define PC_AT_KILL_MASK         0x4b8
+
+/* PC LBS2 register offsets */
+#define PC_VPC_CACHE_ENABLE     0x708
+#define  PC_VPC_CACHE_EN_MASK   PPC_BITMASK(0, 31)
+#define PC_VPC_SCRUB_TRIG       0x710
+#define PC_VPC_SCRUB_MASK       0x718
+#define  PC_SCRUB_VALID         PPC_BIT(0)
+#define  PC_SCRUB_WANT_DISABLE  PPC_BIT(1)
+#define  PC_SCRUB_WANT_INVAL    PPC_BIT(2)
+#define  PC_SCRUB_BLOCK_ID      PPC_BITMASK(27, 31)
+#define  PC_SCRUB_OFFSET        PPC_BITMASK(45, 63)
+#define PC_VPC_CWATCH_SPEC      0x738
+#define  PC_VPC_CWATCH_CONFLICT PPC_BIT(0)
+#define  PC_VPC_CWATCH_FULL     PPC_BIT(8)
+#define  PC_VPC_CWATCH_BLOCKID  PPC_BITMASK(27, 31)
+#define  PC_VPC_CWATCH_OFFSET   PPC_BITMASK(45, 63)
+#define PC_VPC_CWATCH_DAT0      0x740
+#define PC_VPC_CWATCH_DAT1      0x748
+#define PC_VPC_CWATCH_DAT2      0x750
+#define PC_VPC_CWATCH_DAT3      0x758
+#define PC_VPC_CWATCH_DAT4      0x760
+#define PC_VPC_CWATCH_DAT5      0x768
+#define PC_VPC_CWATCH_DAT6      0x770
+#define PC_VPC_CWATCH_DAT7      0x778
+
+/* VC0 register offsets 0x800 - 0xFFF */
+#define VC_GLOBAL_CONFIG        0x800
+#define  VC_GCONF_INDIRECT      PPC_BIT(32)
+#define VC_VSD_TABLE_ADDR       0x808
+#define VC_VSD_TABLE_DATA       0x810
+#define VC_IVE_ISB_BLOCK_MODE   0x818
+#define VC_EQD_BLOCK_MODE       0x820
+#define VC_VPS_BLOCK_MODE       0x828
+#define VC_IRQ_CONFIG_IPI       0x840
+#define  VC_IRQ_CONFIG_MEMB_EN  PPC_BIT(45)
+#define  VC_IRQ_CONFIG_MEMB_SZ  PPC_BITMASK(46, 51)
+#define VC_IRQ_CONFIG_HW        0x848
+#define VC_IRQ_CONFIG_CASCADE1  0x850
+#define VC_IRQ_CONFIG_CASCADE2  0x858
+#define VC_IRQ_CONFIG_REDIST    0x860
+#define VC_IRQ_CONFIG_IPI_CASC  0x868
+#define  VC_AIB_TX_ORDER_TAG2_REL_TF    PPC_BIT(20)
+#define VC_AIB_TX_ORDER_TAG2    0x890
+#define VC_AT_MACRO_KILL        0x8b0
+#define VC_AT_MACRO_KILL_MASK   0x8b8
+#define  VC_KILL_VALID          PPC_BIT(0)
+#define  VC_KILL_TYPE           PPC_BITMASK(14, 15)
+#define   VC_KILL_IRQ   0
+#define   VC_KILL_IVC   1
+#define   VC_KILL_SBC   2
+#define   VC_KILL_EQD   3
+#define  VC_KILL_BLOCK_ID       PPC_BITMASK(27, 31)
+#define  VC_KILL_OFFSET         PPC_BITMASK(48, 60)
+#define VC_EQC_CACHE_ENABLE     0x908
+#define  VC_EQC_CACHE_EN_MASK   PPC_BITMASK(0, 15)
+#define VC_EQC_SCRUB_TRIG       0x910
+#define VC_EQC_SCRUB_MASK       0x918
+#define VC_EQC_CONFIG           0x920
+#define X_VC_EQC_CONFIG         0x214 /* XSCOM register */
+#define  VC_EQC_CONF_SYNC_IPI           PPC_BIT(32)
+#define  VC_EQC_CONF_SYNC_HW            PPC_BIT(33)
+#define  VC_EQC_CONF_SYNC_ESC1          PPC_BIT(34)
+#define  VC_EQC_CONF_SYNC_ESC2          PPC_BIT(35)
+#define  VC_EQC_CONF_SYNC_REDI          PPC_BIT(36)
+#define  VC_EQC_CONF_EQP_INTERLEAVE     PPC_BIT(38)
+#define  VC_EQC_CONF_ENABLE_END_s_BIT   PPC_BIT(39)
+#define  VC_EQC_CONF_ENABLE_END_u_BIT   PPC_BIT(40)
+#define  VC_EQC_CONF_ENABLE_END_c_BIT   PPC_BIT(41)
+#define  VC_EQC_CONF_ENABLE_MORE_QSZ    PPC_BIT(42)
+#define  VC_EQC_CONF_SKIP_ESCALATE      PPC_BIT(43)
+#define VC_EQC_CWATCH_SPEC      0x928
+#define  VC_EQC_CWATCH_CONFLICT PPC_BIT(0)
+#define  VC_EQC_CWATCH_FULL     PPC_BIT(8)
+#define  VC_EQC_CWATCH_BLOCKID  PPC_BITMASK(28, 31)
+#define  VC_EQC_CWATCH_OFFSET   PPC_BITMASK(40, 63)
+#define VC_EQC_CWATCH_DAT0      0x930
+#define VC_EQC_CWATCH_DAT1      0x938
+#define VC_EQC_CWATCH_DAT2      0x940
+#define VC_EQC_CWATCH_DAT3      0x948
+#define VC_IVC_SCRUB_TRIG       0x990
+#define VC_IVC_SCRUB_MASK       0x998
+#define VC_SBC_SCRUB_TRIG       0xa10
+#define VC_SBC_SCRUB_MASK       0xa18
+#define  VC_SCRUB_VALID         PPC_BIT(0)
+#define  VC_SCRUB_WANT_DISABLE  PPC_BIT(1)
+#define  VC_SCRUB_WANT_INVAL    PPC_BIT(2) /* EQC and SBC only */
+#define  VC_SCRUB_BLOCK_ID      PPC_BITMASK(28, 31)
+#define  VC_SCRUB_OFFSET        PPC_BITMASK(40, 63)
+#define VC_IVC_CACHE_ENABLE     0x988
+#define  VC_IVC_CACHE_EN_MASK   PPC_BITMASK(0, 15)
+#define VC_SBC_CACHE_ENABLE     0xa08
+#define  VC_SBC_CACHE_EN_MASK   PPC_BITMASK(0, 15)
+#define VC_IVC_CACHE_SCRUB_TRIG 0x990
+#define VC_IVC_CACHE_SCRUB_MASK 0x998
+#define VC_SBC_CACHE_ENABLE     0xa08
+#define VC_SBC_CACHE_SCRUB_TRIG 0xa10
+#define VC_SBC_CACHE_SCRUB_MASK 0xa18
+#define VC_SBC_CONFIG           0xa20
+#define  VC_SBC_CONF_CPLX_CIST  PPC_BIT(44)
+#define  VC_SBC_CONF_CIST_BOTH  PPC_BIT(45)
+#define  VC_SBC_CONF_NO_UPD_PRF PPC_BIT(59)
+
+/* VC1 register offsets */
+
+/* VSD Table address register definitions (shared) */
+#define VST_ADDR_AUTOINC        PPC_BIT(0)
+#define VST_TABLE_SELECT        PPC_BITMASK(13, 15)
+#define  VST_TSEL_IVT   0
+#define  VST_TSEL_SBE   1
+#define  VST_TSEL_EQDT  2
+#define  VST_TSEL_VPDT  3
+#define  VST_TSEL_IRQ   4       /* VC only */
+#define VST_TABLE_BLOCK        PPC_BITMASK(27, 31)
+
+/* Number of queue overflow pages */
+#define VC_QUEUE_OVF_COUNT      6
+
+/*
+ * Bits in a VSD entry.
+ *
+ * Note: the address is naturally aligned,  we don't use a PPC_BITMASK,
+ *       but just a mask to apply to the address before OR'ing it in.
+ *
+ * Note: VSD_FIRMWARE is a SW bit ! It hijacks an unused bit in the
+ *       VSD and is only meant to be used in indirect mode !
+ */
+#define VSD_MODE                PPC_BITMASK(0, 1)
+#define  VSD_MODE_SHARED        1
+#define  VSD_MODE_EXCLUSIVE     2
+#define  VSD_MODE_FORWARD       3
+#define VSD_ADDRESS_MASK        0x0ffffffffffff000ull
+#define VSD_MIGRATION_REG       PPC_BITMASK(52, 55)
+#define VSD_INDIRECT            PPC_BIT(56)
+#define VSD_TSIZE               PPC_BITMASK(59, 63)
+#define VSD_FIRMWARE            PPC_BIT(2) /* Read warning above */
+
+#define VC_EQC_SYNC_MASK         \
+        (VC_EQC_CONF_SYNC_IPI  | \
+         VC_EQC_CONF_SYNC_HW   | \
+         VC_EQC_CONF_SYNC_ESC1 | \
+         VC_EQC_CONF_SYNC_ESC2 | \
+         VC_EQC_CONF_SYNC_REDI)
+
+
+#endif /* PPC_PNV_XIVE_REGS_H */
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index 6b65397b7ebf..ebbb3d0e9aa7 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -25,6 +25,7 @@
 #include "hw/ppc/pnv_lpc.h"
 #include "hw/ppc/pnv_psi.h"
 #include "hw/ppc/pnv_occ.h"
+#include "hw/ppc/pnv_xive.h"
 
 #define TYPE_PNV_CHIP "pnv-chip"
 #define PNV_CHIP(obj) OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP)
@@ -82,6 +83,7 @@ typedef struct Pnv9Chip {
     PnvChip      parent_obj;
 
     /*< public >*/
+    PnvXive      xive;
 } Pnv9Chip;
 
 typedef struct PnvChipClass {
@@ -215,4 +217,23 @@ void pnv_bmc_powerdown(IPMIBmc *bmc);
     (0x0003ffe000000000ull + (uint64_t)PNV_CHIP_INDEX(chip) * \
      PNV_PSIHB_FSP_SIZE)
 
+/*
+ * POWER9 MMIO base addresses
+ */
+#define PNV9_CHIP_BASE(chip, base)   \
+    ((base) + ((uint64_t) (chip)->chip_id << 42))
+
+#define PNV9_XIVE_VC_SIZE            0x0000008000000000ull
+#define PNV9_XIVE_VC_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006010000000000ull)
+
+#define PNV9_XIVE_PC_SIZE            0x0000001000000000ull
+#define PNV9_XIVE_PC_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006018000000000ull)
+
+#define PNV9_XIVE_IC_SIZE            0x0000000000080000ull
+#define PNV9_XIVE_IC_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006030203100000ull)
+
+#define PNV9_XIVE_TM_SIZE            0x0000000000040000ull
+#define PNV9_XIVE_TM_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006030203180000ull)
+
+
 #endif /* _PPC_PNV_H */
diff --git a/include/hw/ppc/pnv_xive.h b/include/hw/ppc/pnv_xive.h
new file mode 100644
index 000000000000..4fdaa9247d65
--- /dev/null
+++ b/include/hw/ppc/pnv_xive.h
@@ -0,0 +1,93 @@
+/*
+ * QEMU PowerPC XIVE interrupt controller model
+ *
+ * Copyright (c) 2017-2019, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#ifndef PPC_PNV_XIVE_H
+#define PPC_PNV_XIVE_H
+
+#include "hw/ppc/xive.h"
+
+struct PnvChip;
+
+#define TYPE_PNV_XIVE "pnv-xive"
+#define PNV_XIVE(obj) OBJECT_CHECK(PnvXive, (obj), TYPE_PNV_XIVE)
+
+#define XIVE_BLOCK_MAX      16
+
+#define XIVE_TABLE_BLK_MAX  16  /* Block Scope Table (0-15) */
+#define XIVE_TABLE_MIG_MAX  16  /* Migration Register Table (1-15) */
+#define XIVE_TABLE_VDT_MAX  16  /* VDT Domain Table (0-15) */
+#define XIVE_TABLE_EDT_MAX  64  /* EDT Domain Table (0-63) */
+
+typedef struct PnvXive {
+    XiveRouter    parent_obj;
+
+    /* Owning chip */
+    struct PnvChip *chip;
+
+    /* XSCOM addresses giving access to the controller registers */
+    MemoryRegion  xscom_regs;
+
+    /* Main MMIO regions that can be configured by FW */
+    MemoryRegion  ic_mmio;
+    MemoryRegion    ic_reg_mmio;
+    MemoryRegion    ic_notify_mmio;
+    MemoryRegion    ic_lsi_mmio;
+    MemoryRegion    tm_indirect_mmio;
+    MemoryRegion  vc_mmio;
+    MemoryRegion  pc_mmio;
+    MemoryRegion  tm_mmio;
+
+    /*
+     * IPI and END address spaces modeling the EDT segmentation in the
+     * VC region
+     */
+    AddressSpace  ipi_as;
+    MemoryRegion  ipi_mmio;
+    MemoryRegion    ipi_edt_mmio;
+
+    AddressSpace  end_as;
+    MemoryRegion  end_mmio;
+    MemoryRegion    end_edt_mmio;
+
+    /* Shortcut values for the Main MMIO regions */
+    hwaddr        ic_base;
+    uint32_t      ic_shift;
+    hwaddr        vc_base;
+    uint32_t      vc_shift;
+    hwaddr        pc_base;
+    uint32_t      pc_shift;
+    hwaddr        tm_base;
+    uint32_t      tm_shift;
+
+    /* Our XIVE source objects for IPIs and ENDs */
+    XiveSource    ipi_source;
+    XiveENDSource end_source;
+
+    /* Interrupt controller registers */
+    uint64_t      regs[0x300];
+
+    /* Can be configured by FW */
+    uint32_t      tctx_chipid;
+
+    /*
+     * Virtual Structure Descriptor tables : EAT, SBE, ENDT, NVTT, IRQ
+     * These are in a SRAM protected by ECC.
+     */
+    uint64_t      vsds[5][XIVE_BLOCK_MAX];
+
+    /* Translation tables */
+    uint64_t      blk[XIVE_TABLE_BLK_MAX];
+    uint64_t      mig[XIVE_TABLE_MIG_MAX];
+    uint64_t      vdt[XIVE_TABLE_VDT_MAX];
+    uint64_t      edt[XIVE_TABLE_EDT_MAX];
+} PnvXive;
+
+void pnv_xive_pic_print_info(PnvXive *xive, Monitor *mon);
+
+#endif /* PPC_PNV_XIVE_H */
diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
index 255b26a5aaf6..6623ec54a7a8 100644
--- a/include/hw/ppc/pnv_xscom.h
+++ b/include/hw/ppc/pnv_xscom.h
@@ -73,6 +73,9 @@ typedef struct PnvXScomInterfaceClass {
 #define PNV_XSCOM_OCC_BASE        0x0066000
 #define PNV_XSCOM_OCC_SIZE        0x6000
 
+#define PNV9_XSCOM_XIVE_BASE      0x5013000
+#define PNV9_XSCOM_XIVE_SIZE      0x300
+
 extern void pnv_xscom_realize(PnvChip *chip, Error **errp);
 extern int pnv_dt_xscom(PnvChip *chip, void *fdt, int offset);
 
diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c
new file mode 100644
index 000000000000..bb0877cbdf3b
--- /dev/null
+++ b/hw/intc/pnv_xive.c
@@ -0,0 +1,1753 @@
+/*
+ * QEMU PowerPC XIVE interrupt controller model
+ *
+ * Copyright (c) 2017-2019, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "target/ppc/cpu.h"
+#include "sysemu/cpus.h"
+#include "sysemu/dma.h"
+#include "monitor/monitor.h"
+#include "hw/ppc/fdt.h"
+#include "hw/ppc/pnv.h"
+#include "hw/ppc/pnv_core.h"
+#include "hw/ppc/pnv_xscom.h"
+#include "hw/ppc/pnv_xive.h"
+#include "hw/ppc/xive_regs.h"
+#include "hw/ppc/ppc.h"
+
+#include <libfdt.h>
+
+#include "pnv_xive_regs.h"
+
+#define XIVE_DEBUG
+
+/*
+ * Virtual structures table (VST)
+ */
+#define SBE_PER_BYTE   4
+
+typedef struct XiveVstInfo {
+    const char *name;
+    uint32_t    size;
+    uint32_t    max_blocks;
+} XiveVstInfo;
+
+static const XiveVstInfo vst_infos[] = {
+    [VST_TSEL_IVT]  = { "EAT",  sizeof(XiveEAS), 16 },
+    [VST_TSEL_SBE]  = { "SBE",  1,               16 },
+    [VST_TSEL_EQDT] = { "ENDT", sizeof(XiveEND), 16 },
+    [VST_TSEL_VPDT] = { "VPDT", sizeof(XiveNVT), 32 },
+
+    /*
+     *  Interrupt fifo backing store table (not modeled) :
+     *
+     * 0 - IPI,
+     * 1 - HWD,
+     * 2 - First escalate,
+     * 3 - Second escalate,
+     * 4 - Redistribution,
+     * 5 - IPI cascaded queue ?
+     */
+    [VST_TSEL_IRQ]  = { "IRQ",  1,               6  },
+};
+
+#define xive_error(xive, fmt, ...)                                      \
+    qemu_log_mask(LOG_GUEST_ERROR, "XIVE[%x] - " fmt "\n",              \
+                  (xive)->chip->chip_id, ## __VA_ARGS__);
+
+/*
+ * QEMU version of the GETFIELD/SETFIELD macros
+ *
+ * TODO: It might be better to use the existing extract64() and
+ * deposit64() but this means that all the register definitions will
+ * change and become incompatible with the ones found in skiboot.
+ *
+ * Keep it as it is for now until we find a common ground.
+ */
+static inline uint64_t GETFIELD(uint64_t mask, uint64_t word)
+{
+    return (word & mask) >> ctz64(mask);
+}
+
+static inline uint64_t SETFIELD(uint64_t mask, uint64_t word,
+                                uint64_t value)
+{
+    return (word & ~mask) | ((value << ctz64(mask)) & mask);
+}
+
+/*
+ * Remote access to controllers. HW uses MMIOs. For now, a simple scan
+ * of the chips is good enough.
+ *
+ * TODO: Block scope support
+ */
+static PnvXive *pnv_xive_get_ic(uint8_t blk)
+{
+    PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
+    int i;
+
+    for (i = 0; i < pnv->num_chips; i++) {
+        Pnv9Chip *chip9 = PNV9_CHIP(pnv->chips[i]);
+        PnvXive *xive = &chip9->xive;
+
+        if (xive->chip->chip_id == blk) {
+            return xive;
+        }
+    }
+    return NULL;
+}
+
+/*
+ * VST accessors for SBE, EAT, ENDT, NVT
+ *
+ * Indirect VST tables are arrays of VSDs pointing to a page (of same
+ * size). Each page is a direct VST table.
+ */
+
+#define XIVE_VSD_SIZE 8
+
+/* Indirect page size can be 4K, 64K, 2M, 16M. */
+static uint64_t pnv_xive_vst_page_size_allowed(uint32_t page_shift)
+{
+     return page_shift == 12 || page_shift == 16 ||
+         page_shift == 21 || page_shift == 24;
+}
+
+static uint64_t pnv_xive_vst_size(uint64_t vsd)
+{
+    uint64_t vst_tsize = 1ull << (GETFIELD(VSD_TSIZE, vsd) + 12);
+
+    /*
+     * Read the first descriptor to get the page size of the indirect
+     * table.
+     */
+    if (VSD_INDIRECT & vsd) {
+        uint32_t nr_pages = vst_tsize / XIVE_VSD_SIZE;
+        uint32_t page_shift;
+
+        vsd = ldq_be_dma(&address_space_memory, vsd & VSD_ADDRESS_MASK);
+        page_shift = GETFIELD(VSD_TSIZE, vsd) + 12;
+
+        if (!pnv_xive_vst_page_size_allowed(page_shift)) {
+            return 0;
+        }
+
+        return nr_pages * (1ull << page_shift);
+    }
+
+    return vst_tsize;
+}
+
+static uint64_t pnv_xive_vst_addr_direct(PnvXive *xive, uint32_t type,
+                                         uint64_t vsd, uint32_t idx)
+{
+    const XiveVstInfo *info = &vst_infos[type];
+    uint64_t vst_addr = vsd & VSD_ADDRESS_MASK;
+
+    return vst_addr + idx * info->size;
+}
+
+static uint64_t pnv_xive_vst_addr_indirect(PnvXive *xive, uint32_t type,
+                                           uint64_t vsd, uint32_t idx)
+{
+    const XiveVstInfo *info = &vst_infos[type];
+    uint64_t vsd_addr;
+    uint32_t vsd_idx;
+    uint32_t page_shift;
+    uint32_t vst_per_page;
+
+    /* Get the page size of the indirect table. */
+    vsd_addr = vsd & VSD_ADDRESS_MASK;
+    vsd = ldq_be_dma(&address_space_memory, vsd_addr);
+
+    if (!(vsd & VSD_ADDRESS_MASK)) {
+        xive_error(xive, "VST: invalid %s entry %x !?", info->name, 0);
+        return 0;
+    }
+
+    page_shift = GETFIELD(VSD_TSIZE, vsd) + 12;
+
+    if (!pnv_xive_vst_page_size_allowed(page_shift)) {
+        xive_error(xive, "VST: invalid %s page shift %d", info->name,
+                   page_shift);
+        return 0;
+    }
+
+    vst_per_page = (1ull << page_shift) / info->size;
+    vsd_idx = idx / vst_per_page;
+
+    /* Load the VSD we are looking for, if not already done */
+    if (vsd_idx) {
+        vsd_addr = vsd_addr + vsd_idx * XIVE_VSD_SIZE;
+        vsd = ldq_be_dma(&address_space_memory, vsd_addr);
+
+        if (!(vsd & VSD_ADDRESS_MASK)) {
+            xive_error(xive, "VST: invalid %s entry %x !?", info->name, 0);
+            return 0;
+        }
+
+        /*
+         * Check that the pages have a consistent size across the
+         * indirect table
+         */
+        if (page_shift != GETFIELD(VSD_TSIZE, vsd) + 12) {
+            xive_error(xive, "VST: %s entry %x indirect page size differ !?",
+                       info->name, idx);
+            return 0;
+        }
+    }
+
+    return pnv_xive_vst_addr_direct(xive, type, vsd, (idx % vst_per_page));
+}
+
+static uint64_t pnv_xive_vst_addr(PnvXive *xive, uint32_t type, uint8_t blk,
+                                  uint32_t idx)
+{
+    const XiveVstInfo *info = &vst_infos[type];
+    uint64_t vsd;
+    uint32_t idx_max;
+
+    if (blk >= info->max_blocks) {
+        xive_error(xive, "VST: invalid block id %d for VST %s %d !?",
+                   blk, info->name, idx);
+        return 0;
+    }
+
+    vsd = xive->vsds[type][blk];
+
+    /* Remote VST access */
+    if (GETFIELD(VSD_MODE, vsd) == VSD_MODE_FORWARD) {
+        xive = pnv_xive_get_ic(blk);
+
+        return xive ? pnv_xive_vst_addr(xive, type, blk, idx) : 0;
+    }
+
+    idx_max = pnv_xive_vst_size(vsd) / info->size - 1;
+    if (idx > idx_max) {
+#ifdef XIVE_DEBUG
+        xive_error(xive, "VST: %s entry %x/%x out of range [ 0 .. %x ] !?",
+                   info->name, blk, idx, idx_max);
+#endif
+        return 0;
+    }
+
+    if (VSD_INDIRECT & vsd) {
+        return pnv_xive_vst_addr_indirect(xive, type, vsd, idx);
+    }
+
+    return pnv_xive_vst_addr_direct(xive, type, vsd, idx);
+}
+
+static int pnv_xive_vst_read(PnvXive *xive, uint32_t type, uint8_t blk,
+                             uint32_t idx, void *data)
+{
+    const XiveVstInfo *info = &vst_infos[type];
+    uint64_t addr = pnv_xive_vst_addr(xive, type, blk, idx);
+
+    if (!addr) {
+        return -1;
+    }
+
+    cpu_physical_memory_read(addr, data, info->size);
+    return 0;
+}
+
+#define XIVE_VST_WORD_ALL -1
+
+static int pnv_xive_vst_write(PnvXive *xive, uint32_t type, uint8_t blk,
+                              uint32_t idx, void *data, uint32_t word_number)
+{
+    const XiveVstInfo *info = &vst_infos[type];
+    uint64_t addr = pnv_xive_vst_addr(xive, type, blk, idx);
+
+    if (!addr) {
+        return -1;
+    }
+
+    if (word_number == XIVE_VST_WORD_ALL) {
+        cpu_physical_memory_write(addr, data, info->size);
+    } else {
+        cpu_physical_memory_write(addr + word_number * 4,
+                                  data + word_number * 4, 4);
+    }
+    return 0;
+}
+
+static int pnv_xive_get_end(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
+                            XiveEND *end)
+{
+    return pnv_xive_vst_read(PNV_XIVE(xrtr), VST_TSEL_EQDT, blk, idx, end);
+}
+
+static int pnv_xive_write_end(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
+                              XiveEND *end, uint8_t word_number)
+{
+    return pnv_xive_vst_write(PNV_XIVE(xrtr), VST_TSEL_EQDT, blk, idx, end,
+                              word_number);
+}
+
+static int pnv_xive_end_update(PnvXive *xive, uint8_t blk, uint32_t idx)
+{
+    int i;
+    uint64_t eqc_watch[4];
+
+    for (i = 0; i < ARRAY_SIZE(eqc_watch); i++) {
+        eqc_watch[i] = cpu_to_be64(xive->regs[(VC_EQC_CWATCH_DAT0 >> 3) + i]);
+    }
+
+    return pnv_xive_vst_write(xive, VST_TSEL_EQDT, blk, idx, eqc_watch,
+                              XIVE_VST_WORD_ALL);
+}
+
+static int pnv_xive_get_nvt(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
+                            XiveNVT *nvt)
+{
+    return pnv_xive_vst_read(PNV_XIVE(xrtr), VST_TSEL_VPDT, blk, idx, nvt);
+}
+
+static int pnv_xive_write_nvt(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
+                              XiveNVT *nvt, uint8_t word_number)
+{
+    return pnv_xive_vst_write(PNV_XIVE(xrtr), VST_TSEL_VPDT, blk, idx, nvt,
+                              word_number);
+}
+
+static int pnv_xive_nvt_update(PnvXive *xive, uint8_t blk, uint32_t idx)
+{
+    int i;
+    uint64_t vpc_watch[8];
+
+    for (i = 0; i < ARRAY_SIZE(vpc_watch); i++) {
+        vpc_watch[i] = cpu_to_be64(xive->regs[(PC_VPC_CWATCH_DAT0 >> 3) + i]);
+    }
+
+    return pnv_xive_vst_write(xive, VST_TSEL_VPDT, blk, idx, vpc_watch,
+                              XIVE_VST_WORD_ALL);
+}
+
+static int pnv_xive_get_eas(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
+                            XiveEAS *eas)
+{
+    PnvXive *xive = PNV_XIVE(xrtr);
+
+    if (pnv_xive_get_ic(blk) != xive) {
+        xive_error(xive, "VST: EAS %x is remote !?", XIVE_SRCNO(blk, idx));
+        return -1;
+    }
+
+    return pnv_xive_vst_read(xive, VST_TSEL_IVT, blk, idx, eas);
+}
+
+static int pnv_xive_eas_update(PnvXive *xive, uint8_t blk, uint32_t idx)
+{
+    /* All done. */
+    return 0;
+}
+
+static XiveTCTX *pnv_xive_get_tctx(XiveRouter *xrtr, CPUState *cs)
+{
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+    XiveTCTX *tctx = XIVE_TCTX(pnv_cpu_state(cpu)->intc);
+    PnvXive *xive = NULL;
+    CPUPPCState *env = &cpu->env;
+    int pir = env->spr_cb[SPR_PIR].default_value;
+
+    /*
+     * Perform an extra check on the HW thread enablement.
+     *
+     * The TIMA is shared among the chips and to identify the chip
+     * from which the access is being done, we extract the chip id
+     * from the PIR.
+     */
+    xive = pnv_xive_get_ic((pir >> 8) & 0xf);
+    if (!xive) {
+        return NULL;
+    }
+
+    if (!(xive->regs[PC_THREAD_EN_REG0 >> 3] & PPC_BIT(pir & 0x3f))) {
+        xive_error(PNV_XIVE(xrtr), "IC: CPU %x is not enabled", pir);
+    }
+
+    return tctx;
+}
+
+/*
+ * The internal sources (IPIs) of the interrupt controller have no
+ * knowledge of the XIVE chip on which they reside. Encode the block
+ * id in the source interrupt number before forwarding the source
+ * event notification to the Router. This is required on a multichip
+ * system.
+ */
+static void pnv_xive_notify(XiveNotifier *xn, uint32_t srcno)
+{
+    PnvXive *xive = PNV_XIVE(xn);
+    uint8_t blk = xive->chip->chip_id;
+
+    xive_router_notify(xn, XIVE_SRCNO(blk, srcno));
+}
+
+/*
+ * XIVE helpers
+ */
+
+static uint64_t pnv_xive_vc_size(PnvXive *xive)
+{
+    return (~xive->regs[CQ_VC_BARM >> 3] + 1) & CQ_VC_BARM_MASK;
+}
+
+static uint64_t pnv_xive_edt_shift(PnvXive *xive)
+{
+    return ctz64(pnv_xive_vc_size(xive) / XIVE_TABLE_EDT_MAX);
+}
+
+static uint64_t pnv_xive_pc_size(PnvXive *xive)
+{
+    return (~xive->regs[CQ_PC_BARM >> 3] + 1) & CQ_PC_BARM_MASK;
+}
+
+static uint32_t pnv_xive_nr_ipis(PnvXive *xive)
+{
+    uint8_t blk = xive->chip->chip_id;
+
+    return pnv_xive_vst_size(xive->vsds[VST_TSEL_SBE][blk]) * SBE_PER_BYTE;
+}
+
+static uint32_t pnv_xive_nr_ends(PnvXive *xive)
+{
+    uint8_t blk = xive->chip->chip_id;
+
+    return pnv_xive_vst_size(xive->vsds[VST_TSEL_EQDT][blk])
+        / vst_infos[VST_TSEL_EQDT].size;
+}
+
+/*
+ * EDT Table
+ *
+ * The Virtualization Controller MMIO region containing the IPI ESB
+ * pages and END ESB pages is sub-divided into "sets" which map
+ * portions of the VC region to the different ESB pages. It is
+ * configured at runtime through the EDT "Domain Table" to let the
+ * firmware decide how to split the VC address space between IPI ESB
+ * pages and END ESB pages.
+ */
+
+/*
+ * Computes the overall size of the IPI or the END ESB pages
+ */
+static uint64_t pnv_xive_edt_size(PnvXive *xive, uint64_t type)
+{
+    uint64_t edt_size = 1ull << pnv_xive_edt_shift(xive);
+    uint64_t size = 0;
+    int i;
+
+    for (i = 0; i < XIVE_TABLE_EDT_MAX; i++) {
+        uint64_t edt_type = GETFIELD(CQ_TDR_EDT_TYPE, xive->edt[i]);
+
+        if (edt_type == type) {
+            size += edt_size;
+        }
+    }
+
+    return size;
+}
+
+/*
+ * Maps an offset of the VC region in the IPI or END region using the
+ * layout defined by the EDT "Domaine Table"
+ */
+static uint64_t pnv_xive_edt_offset(PnvXive *xive, uint64_t vc_offset,
+                                              uint64_t type)
+{
+    int i;
+    uint64_t edt_size = 1ull << pnv_xive_edt_shift(xive);
+    uint64_t edt_offset = vc_offset;
+
+    for (i = 0; i < XIVE_TABLE_EDT_MAX && (i * edt_size) < vc_offset; i++) {
+        uint64_t edt_type = GETFIELD(CQ_TDR_EDT_TYPE, xive->edt[i]);
+
+        if (edt_type != type) {
+            edt_offset -= edt_size;
+        }
+    }
+
+    return edt_offset;
+}
+
+static void pnv_xive_edt_resize(PnvXive *xive)
+{
+    uint64_t ipi_edt_size = pnv_xive_edt_size(xive, CQ_TDR_EDT_IPI);
+    uint64_t end_edt_size = pnv_xive_edt_size(xive, CQ_TDR_EDT_EQ);
+
+    memory_region_set_size(&xive->ipi_edt_mmio, ipi_edt_size);
+    memory_region_add_subregion(&xive->ipi_mmio, 0, &xive->ipi_edt_mmio);
+
+    memory_region_set_size(&xive->end_edt_mmio, end_edt_size);
+    memory_region_add_subregion(&xive->end_mmio, 0, &xive->end_edt_mmio);
+}
+
+/*
+ * XIVE Table configuration. Only EDT is supported.
+ */
+static int pnv_xive_table_set_data(PnvXive *xive, uint64_t val)
+{
+    uint64_t tsel = xive->regs[CQ_TAR >> 3] & CQ_TAR_TSEL;
+    uint8_t tsel_index = GETFIELD(CQ_TAR_TSEL_INDEX, xive->regs[CQ_TAR >> 3]);
+    uint64_t *xive_table;
+    uint8_t max_index;
+
+    switch (tsel) {
+    case CQ_TAR_TSEL_BLK:
+        max_index = ARRAY_SIZE(xive->blk);
+        xive_table = xive->blk;
+        break;
+    case CQ_TAR_TSEL_MIG:
+        max_index = ARRAY_SIZE(xive->mig);
+        xive_table = xive->mig;
+        break;
+    case CQ_TAR_TSEL_EDT:
+        max_index = ARRAY_SIZE(xive->edt);
+        xive_table = xive->edt;
+        break;
+    case CQ_TAR_TSEL_VDT:
+        max_index = ARRAY_SIZE(xive->vdt);
+        xive_table = xive->vdt;
+        break;
+    default:
+        xive_error(xive, "IC: invalid table %d", (int) tsel);
+        return -1;
+    }
+
+    if (tsel_index >= max_index) {
+        xive_error(xive, "IC: invalid index %d", (int) tsel_index);
+        return -1;
+    }
+
+    xive_table[tsel_index] = val;
+
+    if (xive->regs[CQ_TAR >> 3] & CQ_TAR_TBL_AUTOINC) {
+        xive->regs[CQ_TAR >> 3] =
+            SETFIELD(CQ_TAR_TSEL_INDEX, xive->regs[CQ_TAR >> 3], ++tsel_index);
+    }
+
+    /*
+     * EDT configuration is complete. Resize the MMIO windows exposing
+     * the IPI and the END ESBs in the VC region.
+     */
+    if (tsel == CQ_TAR_TSEL_EDT && tsel_index == ARRAY_SIZE(xive->edt)) {
+        pnv_xive_edt_resize(xive);
+    }
+
+    return 0;
+}
+
+/*
+ * Virtual Structure Tables (VST) configuration
+ */
+static void pnv_xive_vst_set_exclusive(PnvXive *xive, uint8_t type,
+                                       uint8_t blk, uint64_t vsd)
+{
+    XiveENDSource *end_xsrc = &xive->end_source;
+    XiveSource *xsrc = &xive->ipi_source;
+    const XiveVstInfo *info = &vst_infos[type];
+    uint32_t page_shift = GETFIELD(VSD_TSIZE, vsd) + 12;
+    uint64_t vst_addr = vsd & VSD_ADDRESS_MASK;
+
+    /* Basic checks */
+
+    if (VSD_INDIRECT & vsd) {
+        if (!(xive->regs[VC_GLOBAL_CONFIG >> 3] & VC_GCONF_INDIRECT)) {
+            xive_error(xive, "VST: %s indirect tables are not enabled",
+                       info->name);
+            return;
+        }
+
+        if (!pnv_xive_vst_page_size_allowed(page_shift)) {
+            xive_error(xive, "VST: invalid %s page shift %d", info->name,
+                       page_shift);
+            return;
+        }
+    }
+
+    if (!QEMU_IS_ALIGNED(vst_addr, 1ull << page_shift)) {
+        xive_error(xive, "VST: %s table address 0x%"PRIx64" is not aligned with"
+                   " page shift %d", info->name, vst_addr, page_shift);
+        return;
+    }
+
+    /* Record the table configuration (in SRAM on HW) */
+    xive->vsds[type][blk] = vsd;
+
+    /* Now tune the models with the configuration provided by the FW */
+
+    switch (type) {
+    case VST_TSEL_IVT:  /* Nothing to be done */
+        break;
+
+    case VST_TSEL_EQDT:
+        /*
+         * Backing store pages for the END. Compute the number of ENDs
+         * provisioned by FW and resize the END ESB window accordingly.
+         */
+        memory_region_set_size(&end_xsrc->esb_mmio, pnv_xive_nr_ends(xive) *
+                               (1ull << (end_xsrc->esb_shift + 1)));
+        memory_region_add_subregion(&xive->end_edt_mmio, 0,
+                                    &end_xsrc->esb_mmio);
+        break;
+
+    case VST_TSEL_SBE:
+        /*
+         * Backing store pages for the source PQ bits. The model does
+         * not use these PQ bits backed in RAM because the XiveSource
+         * model has its own. Compute the number of IRQs provisioned
+         * by FW and resize the IPI ESB window accordingly.
+         */
+        memory_region_set_size(&xsrc->esb_mmio, pnv_xive_nr_ipis(xive) *
+                               (1ull << xsrc->esb_shift));
+        memory_region_add_subregion(&xive->ipi_edt_mmio, 0, &xsrc->esb_mmio);
+        break;
+
+    case VST_TSEL_VPDT: /* Not modeled */
+    case VST_TSEL_IRQ:  /* Not modeled */
+        /*
+         * These tables contains the backing store pages for the
+         * interrupt fifos of the VC sub-engine in case of overflow.
+         */
+        break;
+
+    default:
+        g_assert_not_reached();
+    }
+}
+
+/*
+ * Both PC and VC sub-engines are configured as each use the Virtual
+ * Structure Tables : SBE, EAS, END and NVT.
+ */
+static void pnv_xive_vst_set_data(PnvXive *xive, uint64_t vsd, bool pc_engine)
+{
+    uint8_t mode = GETFIELD(VSD_MODE, vsd);
+    uint8_t type = GETFIELD(VST_TABLE_SELECT,
+                            xive->regs[VC_VSD_TABLE_ADDR >> 3]);
+    uint8_t blk = GETFIELD(VST_TABLE_BLOCK,
+                           xive->regs[VC_VSD_TABLE_ADDR >> 3]);
+    uint64_t vst_addr = vsd & VSD_ADDRESS_MASK;
+
+    if (type > VST_TSEL_IRQ) {
+        xive_error(xive, "VST: invalid table type %d", type);
+        return;
+    }
+
+    if (blk >= vst_infos[type].max_blocks) {
+        xive_error(xive, "VST: invalid block id %d for"
+                      " %s table", blk, vst_infos[type].name);
+        return;
+    }
+
+    /*
+     * Only take the VC sub-engine configuration into account because
+     * the XiveRouter model combines both VC and PC sub-engines
+     */
+    if (pc_engine) {
+        return;
+    }
+
+    if (!vst_addr) {
+        xive_error(xive, "VST: invalid %s table address", vst_infos[type].name);
+        return;
+    }
+
+    switch (mode) {
+    case VSD_MODE_FORWARD:
+        xive->vsds[type][blk] = vsd;
+        break;
+
+    case VSD_MODE_EXCLUSIVE:
+        pnv_xive_vst_set_exclusive(xive, type, blk, vsd);
+        break;
+
+    default:
+        xive_error(xive, "VST: unsupported table mode %d", mode);
+        return;
+    }
+}
+
+/*
+ * Interrupt controller MMIO region. The layout is compatible between
+ * 4K and 64K pages :
+ *
+ * Page 0           sub-engine BARs
+ *  0x000 - 0x3FF   IC registers
+ *  0x400 - 0x7FF   PC registers
+ *  0x800 - 0xFFF   VC registers
+ *
+ * Page 1           Notify page (writes only)
+ *  0x000 - 0x7FF   HW interrupt triggers (PSI, PHB)
+ *  0x800 - 0xFFF   forwards and syncs
+ *
+ * Page 2           LSI Trigger page (writes only) (not modeled)
+ * Page 3           LSI SB EOI page (reads only) (not modeled)
+ *
+ * Page 4-7         indirect TIMA
+ */
+
+/*
+ * IC - registers MMIO
+ */
+static void pnv_xive_ic_reg_write(void *opaque, hwaddr offset,
+                                  uint64_t val, unsigned size)
+{
+    PnvXive *xive = PNV_XIVE(opaque);
+    MemoryRegion *sysmem = get_system_memory();
+    uint32_t reg = offset >> 3;
+    bool is_chip0 = xive->chip->chip_id == 0;
+
+    switch (offset) {
+
+    /*
+     * XIVE CQ (PowerBus bridge) settings
+     */
+    case CQ_MSGSND:     /* msgsnd for doorbells */
+    case CQ_FIRMASK_OR: /* FIR error reporting */
+        break;
+    case CQ_PBI_CTL:
+        if (val & CQ_PBI_PC_64K) {
+            xive->pc_shift = 16;
+        }
+        if (val & CQ_PBI_VC_64K) {
+            xive->vc_shift = 16;
+        }
+        break;
+    case CQ_CFG_PB_GEN: /* PowerBus General Configuration */
+        /*
+         * TODO: CQ_INT_ADDR_OPT for 1-block-per-chip mode
+         */
+        break;
+
+    /*
+     * XIVE Virtualization Controller settings
+     */
+    case VC_GLOBAL_CONFIG:
+        break;
+
+    /*
+     * XIVE Presenter Controller settings
+     */
+    case PC_GLOBAL_CONFIG:
+        /*
+         * PC_GCONF_CHIPID_OVR
+         *   Overrides Int command Chip ID with the Chip ID field (DEBUG)
+         */
+        break;
+    case PC_TCTXT_CFG:
+        /*
+         * TODO: block group support
+         *
+         * PC_TCTXT_CFG_BLKGRP_EN
+         * PC_TCTXT_CFG_HARD_CHIPID_BLK :
+         *   Moves the chipid into block field for hardwired CAM compares.
+         *   Block offset value is adjusted to 0b0..01 & ThrdId
+         *
+         *   Will require changes in xive_presenter_tctx_match(). I am
+         *   not sure how to handle that yet.
+         */
+
+        /* Overrides hardwired chip ID with the chip ID field */
+        if (val & PC_TCTXT_CHIPID_OVERRIDE) {
+            xive->tctx_chipid = GETFIELD(PC_TCTXT_CHIPID, val);
+        }
+        break;
+    case PC_TCTXT_TRACK:
+        /*
+         * PC_TCTXT_TRACK_EN:
+         *   enable block tracking and exchange of block ownership
+         *   information between Interrupt controllers
+         */
+        break;
+
+    /*
+     * Misc settings
+     */
+    case VC_SBC_CONFIG: /* Store EOI configuration */
+        /*
+         * Configure store EOI if required by firwmare (skiboot has removed
+         * support recently though)
+         */
+        if (val & (VC_SBC_CONF_CPLX_CIST | VC_SBC_CONF_CIST_BOTH)) {
+            object_property_set_int(OBJECT(&xive->ipi_source),
+                                    XIVE_SRC_STORE_EOI, "flags", &error_fatal);
+        }
+        break;
+
+    case VC_EQC_CONFIG: /* TODO: silent escalation */
+    case VC_AIB_TX_ORDER_TAG2: /* relax ordering */
+        break;
+
+    /*
+     * XIVE BAR settings (XSCOM only)
+     */
+    case CQ_RST_CTL:
+        /* bit4: resets all BAR registers */
+        break;
+
+    case CQ_IC_BAR: /* IC BAR. 8 pages */
+        xive->ic_shift = val & CQ_IC_BAR_64K ? 16 : 12;
+        if (!(val & CQ_IC_BAR_VALID)) {
+            xive->ic_base = 0;
+            if (xive->regs[reg] & CQ_IC_BAR_VALID) {
+                memory_region_del_subregion(&xive->ic_mmio,
+                                            &xive->ic_reg_mmio);
+                memory_region_del_subregion(&xive->ic_mmio,
+                                            &xive->ic_notify_mmio);
+                memory_region_del_subregion(&xive->ic_mmio,
+                                            &xive->ic_lsi_mmio);
+                memory_region_del_subregion(&xive->ic_mmio,
+                                            &xive->tm_indirect_mmio);
+
+                memory_region_del_subregion(sysmem, &xive->ic_mmio);
+            }
+        } else {
+            xive->ic_base = val & ~(CQ_IC_BAR_VALID | CQ_IC_BAR_64K);
+            if (!(xive->regs[reg] & CQ_IC_BAR_VALID)) {
+                memory_region_add_subregion(sysmem, xive->ic_base,
+                                            &xive->ic_mmio);
+
+                memory_region_add_subregion(&xive->ic_mmio,  0,
+                                            &xive->ic_reg_mmio);
+                memory_region_add_subregion(&xive->ic_mmio,
+                                            1ul << xive->ic_shift,
+                                            &xive->ic_notify_mmio);
+                memory_region_add_subregion(&xive->ic_mmio,
+                                            2ul << xive->ic_shift,
+                                            &xive->ic_lsi_mmio);
+                memory_region_add_subregion(&xive->ic_mmio,
+                                            4ull << xive->ic_shift,
+                                            &xive->tm_indirect_mmio);
+            }
+        }
+        break;
+
+    case CQ_TM1_BAR: /* TM BAR. 4 pages. Map only once */
+    case CQ_TM2_BAR: /* second TM BAR. for hotplug. Not modeled */
+        xive->tm_shift = val & CQ_TM_BAR_64K ? 16 : 12;
+        if (!(val & CQ_TM_BAR_VALID)) {
+            xive->tm_base = 0;
+            if (xive->regs[reg] & CQ_TM_BAR_VALID && is_chip0) {
+                memory_region_del_subregion(sysmem, &xive->tm_mmio);
+            }
+        } else {
+            xive->tm_base = val & ~(CQ_TM_BAR_VALID | CQ_TM_BAR_64K);
+            if (!(xive->regs[reg] & CQ_TM_BAR_VALID) && is_chip0) {
+                memory_region_add_subregion(sysmem, xive->tm_base,
+                                            &xive->tm_mmio);
+            }
+        }
+        break;
+
+    case CQ_PC_BARM:
+        xive->regs[reg] = val;
+        memory_region_set_size(&xive->pc_mmio, pnv_xive_pc_size(xive));
+        break;
+    case CQ_PC_BAR: /* From 32M to 512G */
+        if (!(val & CQ_PC_BAR_VALID)) {
+            xive->pc_base = 0;
+            if (xive->regs[reg] & CQ_PC_BAR_VALID) {
+                memory_region_del_subregion(sysmem, &xive->pc_mmio);
+            }
+        } else {
+            xive->pc_base = val & ~(CQ_PC_BAR_VALID);
+            if (!(xive->regs[reg] & CQ_PC_BAR_VALID)) {
+                memory_region_add_subregion(sysmem, xive->pc_base,
+                                            &xive->pc_mmio);
+            }
+        }
+        break;
+
+    case CQ_VC_BARM:
+        xive->regs[reg] = val;
+        memory_region_set_size(&xive->vc_mmio, pnv_xive_vc_size(xive));
+        break;
+    case CQ_VC_BAR: /* From 64M to 4TB */
+        if (!(val & CQ_VC_BAR_VALID)) {
+            xive->vc_base = 0;
+            if (xive->regs[reg] & CQ_VC_BAR_VALID) {
+                memory_region_del_subregion(sysmem, &xive->vc_mmio);
+            }
+        } else {
+            xive->vc_base = val & ~(CQ_VC_BAR_VALID);
+            if (!(xive->regs[reg] & CQ_VC_BAR_VALID)) {
+                memory_region_add_subregion(sysmem, xive->vc_base,
+                                            &xive->vc_mmio);
+            }
+        }
+        break;
+
+    /*
+     * XIVE Table settings.
+     */
+    case CQ_TAR: /* Table Address */
+        break;
+    case CQ_TDR: /* Table Data */
+        pnv_xive_table_set_data(xive, val);
+        break;
+
+    /*
+     * XIVE VC & PC Virtual Structure Table settings
+     */
+    case VC_VSD_TABLE_ADDR:
+    case PC_VSD_TABLE_ADDR: /* Virtual table selector */
+        break;
+    case VC_VSD_TABLE_DATA: /* Virtual table setting */
+    case PC_VSD_TABLE_DATA:
+        pnv_xive_vst_set_data(xive, val, offset == PC_VSD_TABLE_DATA);
+        break;
+
+    /*
+     * Interrupt fifo overflow in memory backing store (Not modeled)
+     */
+    case VC_IRQ_CONFIG_IPI:
+    case VC_IRQ_CONFIG_HW:
+    case VC_IRQ_CONFIG_CASCADE1:
+    case VC_IRQ_CONFIG_CASCADE2:
+    case VC_IRQ_CONFIG_REDIST:
+    case VC_IRQ_CONFIG_IPI_CASC:
+        break;
+
+    /*
+     * XIVE hardware thread enablement
+     */
+    case PC_THREAD_EN_REG0: /* Physical Thread Enable */
+    case PC_THREAD_EN_REG1: /* Physical Thread Enable (fused core) */
+        break;
+
+    case PC_THREAD_EN_REG0_SET:
+        xive->regs[PC_THREAD_EN_REG0 >> 3] |= val;
+        break;
+    case PC_THREAD_EN_REG1_SET:
+        xive->regs[PC_THREAD_EN_REG1 >> 3] |= val;
+        break;
+    case PC_THREAD_EN_REG0_CLR:
+        xive->regs[PC_THREAD_EN_REG0 >> 3] &= ~val;
+        break;
+    case PC_THREAD_EN_REG1_CLR:
+        xive->regs[PC_THREAD_EN_REG1 >> 3] &= ~val;
+        break;
+
+    /*
+     * Indirect TIMA access set up. Defines the PIR of the HW thread
+     * to use.
+     */
+    case PC_TCTXT_INDIR0 ... PC_TCTXT_INDIR3:
+        break;
+
+    /*
+     * XIVE PC & VC cache updates for EAS, NVT and END
+     */
+    case VC_IVC_SCRUB_MASK:
+        break;
+    case VC_IVC_SCRUB_TRIG:
+        pnv_xive_eas_update(xive, GETFIELD(PC_SCRUB_BLOCK_ID, val),
+                            GETFIELD(VC_SCRUB_OFFSET, val));
+        break;
+
+    case VC_EQC_SCRUB_MASK:
+    case VC_EQC_CWATCH_SPEC:
+    case VC_EQC_CWATCH_DAT0 ... VC_EQC_CWATCH_DAT3:
+        break;
+    case VC_EQC_SCRUB_TRIG:
+        pnv_xive_end_update(xive, GETFIELD(VC_SCRUB_BLOCK_ID, val),
+                            GETFIELD(VC_SCRUB_OFFSET, val));
+        break;
+
+    case PC_VPC_SCRUB_MASK:
+    case PC_VPC_CWATCH_SPEC:
+    case PC_VPC_CWATCH_DAT0 ... PC_VPC_CWATCH_DAT7:
+        break;
+    case PC_VPC_SCRUB_TRIG:
+        pnv_xive_nvt_update(xive, GETFIELD(PC_SCRUB_BLOCK_ID, val),
+                           GETFIELD(PC_SCRUB_OFFSET, val));
+        break;
+
+
+    /*
+     * XIVE PC & VC cache invalidation
+     */
+    case PC_AT_KILL:
+        break;
+    case VC_AT_MACRO_KILL:
+        break;
+    case PC_AT_KILL_MASK:
+    case VC_AT_MACRO_KILL_MASK:
+        break;
+
+    default:
+        xive_error(xive, "IC: invalid write to reg=0x%"HWADDR_PRIx, offset);
+        return;
+    }
+
+    xive->regs[reg] = val;
+}
+
+static uint64_t pnv_xive_ic_reg_read(void *opaque, hwaddr offset, unsigned size)
+{
+    PnvXive *xive = PNV_XIVE(opaque);
+    uint64_t val = 0;
+    uint32_t reg = offset >> 3;
+
+    switch (offset) {
+    case CQ_CFG_PB_GEN:
+    case CQ_IC_BAR:
+    case CQ_TM1_BAR:
+    case CQ_TM2_BAR:
+    case CQ_PC_BAR:
+    case CQ_PC_BARM:
+    case CQ_VC_BAR:
+    case CQ_VC_BARM:
+    case CQ_TAR:
+    case CQ_TDR:
+    case CQ_PBI_CTL:
+
+    case PC_TCTXT_CFG:
+    case PC_TCTXT_TRACK:
+    case PC_TCTXT_INDIR0:
+    case PC_TCTXT_INDIR1:
+    case PC_TCTXT_INDIR2:
+    case PC_TCTXT_INDIR3:
+    case PC_GLOBAL_CONFIG:
+
+    case PC_VPC_SCRUB_MASK:
+    case PC_VPC_CWATCH_SPEC:
+    case PC_VPC_CWATCH_DAT0:
+    case PC_VPC_CWATCH_DAT1:
+    case PC_VPC_CWATCH_DAT2:
+    case PC_VPC_CWATCH_DAT3:
+    case PC_VPC_CWATCH_DAT4:
+    case PC_VPC_CWATCH_DAT5:
+    case PC_VPC_CWATCH_DAT6:
+    case PC_VPC_CWATCH_DAT7:
+
+    case VC_GLOBAL_CONFIG:
+    case VC_AIB_TX_ORDER_TAG2:
+
+    case VC_IRQ_CONFIG_IPI:
+    case VC_IRQ_CONFIG_HW:
+    case VC_IRQ_CONFIG_CASCADE1:
+    case VC_IRQ_CONFIG_CASCADE2:
+    case VC_IRQ_CONFIG_REDIST:
+    case VC_IRQ_CONFIG_IPI_CASC:
+
+    case VC_EQC_SCRUB_MASK:
+    case VC_EQC_CWATCH_DAT0:
+    case VC_EQC_CWATCH_DAT1:
+    case VC_EQC_CWATCH_DAT2:
+    case VC_EQC_CWATCH_DAT3:
+
+    case VC_EQC_CWATCH_SPEC:
+    case VC_IVC_SCRUB_MASK:
+    case VC_SBC_CONFIG:
+    case VC_AT_MACRO_KILL_MASK:
+    case VC_VSD_TABLE_ADDR:
+    case PC_VSD_TABLE_ADDR:
+    case VC_VSD_TABLE_DATA:
+    case PC_VSD_TABLE_DATA:
+    case PC_THREAD_EN_REG0:
+    case PC_THREAD_EN_REG1:
+        val = xive->regs[reg];
+        break;
+
+    /*
+     * XIVE hardware thread enablement
+     */
+    case PC_THREAD_EN_REG0_SET:
+    case PC_THREAD_EN_REG0_CLR:
+        val = xive->regs[PC_THREAD_EN_REG0 >> 3];
+        break;
+    case PC_THREAD_EN_REG1_SET:
+    case PC_THREAD_EN_REG1_CLR:
+        val = xive->regs[PC_THREAD_EN_REG1 >> 3];
+        break;
+
+    case CQ_MSGSND: /* Identifies which cores have msgsnd enabled. */
+        val = 0xffffff0000000000;
+        break;
+
+    /*
+     * XIVE PC & VC cache updates for EAS, NVT and END
+     */
+    case PC_VPC_SCRUB_TRIG:
+    case VC_IVC_SCRUB_TRIG:
+    case VC_EQC_SCRUB_TRIG:
+        xive->regs[reg] &= ~VC_SCRUB_VALID;
+        val = xive->regs[reg];
+        break;
+
+    /*
+     * XIVE PC & VC cache invalidation
+     */
+    case PC_AT_KILL:
+        xive->regs[reg] &= ~PC_AT_KILL_VALID;
+        val = xive->regs[reg];
+        break;
+    case VC_AT_MACRO_KILL:
+        xive->regs[reg] &= ~VC_KILL_VALID;
+        val = xive->regs[reg];
+        break;
+
+    /*
+     * XIVE synchronisation
+     */
+    case VC_EQC_CONFIG:
+        val = VC_EQC_SYNC_MASK;
+        break;
+
+    default:
+        xive_error(xive, "IC: invalid read reg=0x%"HWADDR_PRIx, offset);
+    }
+
+    return val;
+}
+
+static const MemoryRegionOps pnv_xive_ic_reg_ops = {
+    .read = pnv_xive_ic_reg_read,
+    .write = pnv_xive_ic_reg_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .valid = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    },
+};
+
+/*
+ * IC - Notify MMIO port page (write only)
+ */
+#define PNV_XIVE_FORWARD_IPI        0x800 /* Forward IPI */
+#define PNV_XIVE_FORWARD_HW         0x880 /* Forward HW */
+#define PNV_XIVE_FORWARD_OS_ESC     0x900 /* Forward OS escalation */
+#define PNV_XIVE_FORWARD_HW_ESC     0x980 /* Forward Hyp escalation */
+#define PNV_XIVE_FORWARD_REDIS      0xa00 /* Forward Redistribution */
+#define PNV_XIVE_RESERVED5          0xa80 /* Cache line 5 PowerBUS operation */
+#define PNV_XIVE_RESERVED6          0xb00 /* Cache line 6 PowerBUS operation */
+#define PNV_XIVE_RESERVED7          0xb80 /* Cache line 7 PowerBUS operation */
+
+/* VC synchronisation */
+#define PNV_XIVE_SYNC_IPI           0xc00 /* Sync IPI */
+#define PNV_XIVE_SYNC_HW            0xc80 /* Sync HW */
+#define PNV_XIVE_SYNC_OS_ESC        0xd00 /* Sync OS escalation */
+#define PNV_XIVE_SYNC_HW_ESC        0xd80 /* Sync Hyp escalation */
+#define PNV_XIVE_SYNC_REDIS         0xe00 /* Sync Redistribution */
+
+/* PC synchronisation */
+#define PNV_XIVE_SYNC_PULL          0xe80 /* Sync pull context */
+#define PNV_XIVE_SYNC_PUSH          0xf00 /* Sync push context */
+#define PNV_XIVE_SYNC_VPC           0xf80 /* Sync remove VPC store */
+
+static void pnv_xive_ic_hw_trigger(PnvXive *xive, hwaddr addr, uint64_t val)
+{
+    /*
+     * Forward the source event notification directly to the Router.
+     * The source interrupt number should already be correctly encoded
+     * with the chip block id by the sending device (PHB, PSI).
+     */
+    xive_router_notify(XIVE_NOTIFIER(xive), val);
+}
+
+static void pnv_xive_ic_notify_write(void *opaque, hwaddr addr, uint64_t val,
+                                     unsigned size)
+{
+    PnvXive *xive = PNV_XIVE(opaque);
+
+    /* VC: HW triggers */
+    switch (addr) {
+    case 0x000 ... 0x7FF:
+        pnv_xive_ic_hw_trigger(opaque, addr, val);
+        break;
+
+    /* VC: Forwarded IRQs */
+    case PNV_XIVE_FORWARD_IPI:
+    case PNV_XIVE_FORWARD_HW:
+    case PNV_XIVE_FORWARD_OS_ESC:
+    case PNV_XIVE_FORWARD_HW_ESC:
+    case PNV_XIVE_FORWARD_REDIS:
+        /* TODO: forwarded IRQs. Should be like HW triggers */
+        xive_error(xive, "IC: forwarded at @0x%"HWADDR_PRIx" IRQ 0x%"PRIx64,
+                   addr, val);
+        break;
+
+    /* VC syncs */
+    case PNV_XIVE_SYNC_IPI:
+    case PNV_XIVE_SYNC_HW:
+    case PNV_XIVE_SYNC_OS_ESC:
+    case PNV_XIVE_SYNC_HW_ESC:
+    case PNV_XIVE_SYNC_REDIS:
+        break;
+
+    /* PC syncs */
+    case PNV_XIVE_SYNC_PULL:
+    case PNV_XIVE_SYNC_PUSH:
+    case PNV_XIVE_SYNC_VPC:
+        break;
+
+    default:
+        xive_error(xive, "IC: invalid notify write @%"HWADDR_PRIx, addr);
+    }
+}
+
+static uint64_t pnv_xive_ic_notify_read(void *opaque, hwaddr addr,
+                                        unsigned size)
+{
+    PnvXive *xive = PNV_XIVE(opaque);
+
+    /* loads are invalid */
+    xive_error(xive, "IC: invalid notify read @%"HWADDR_PRIx, addr);
+    return -1;
+}
+
+static const MemoryRegionOps pnv_xive_ic_notify_ops = {
+    .read = pnv_xive_ic_notify_read,
+    .write = pnv_xive_ic_notify_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .valid = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    },
+};
+
+/*
+ * IC - LSI MMIO handlers (not modeled)
+ */
+
+static void pnv_xive_ic_lsi_write(void *opaque, hwaddr addr,
+                              uint64_t val, unsigned size)
+{
+    PnvXive *xive = PNV_XIVE(opaque);
+
+    xive_error(xive, "IC: LSI invalid write @%"HWADDR_PRIx, addr);
+}
+
+static uint64_t pnv_xive_ic_lsi_read(void *opaque, hwaddr addr, unsigned size)
+{
+    PnvXive *xive = PNV_XIVE(opaque);
+
+    xive_error(xive, "IC: LSI invalid read @%"HWADDR_PRIx, addr);
+    return -1;
+}
+
+static const MemoryRegionOps pnv_xive_ic_lsi_ops = {
+    .read = pnv_xive_ic_lsi_read,
+    .write = pnv_xive_ic_lsi_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .valid = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    },
+};
+
+/*
+ * IC - Indirect TIMA MMIO handlers
+ */
+
+/*
+ * When the TIMA is accessed from the indirect page, the thread id
+ * (PIR) has to be configured in the IC registers before. This is used
+ * for resets and for debug purpose also.
+ */
+static XiveTCTX *pnv_xive_get_indirect_tctx(PnvXive *xive)
+{
+    uint64_t tctxt_indir = xive->regs[PC_TCTXT_INDIR0 >> 3];
+    PowerPCCPU *cpu = NULL;
+    int pir;
+
+    if (!(tctxt_indir & PC_TCTXT_INDIR_VALID)) {
+        xive_error(xive, "IC: no indirect TIMA access in progress");
+        return NULL;
+    }
+
+    pir = GETFIELD(PC_TCTXT_INDIR_THRDID, tctxt_indir) & 0xff;
+    cpu = ppc_get_vcpu_by_pir(pir);
+    if (!cpu) {
+        xive_error(xive, "IC: invalid PIR %x for indirect access", pir);
+        return NULL;
+    }
+
+    /* Check that HW thread is XIVE enabled */
+    if (!(xive->regs[PC_THREAD_EN_REG0 >> 3] & PPC_BIT(pir & 0x3f))) {
+        xive_error(xive, "IC: CPU %x is not enabled", pir);
+    }
+
+    return XIVE_TCTX(pnv_cpu_state(cpu)->intc);
+}
+
+static void xive_tm_indirect_write(void *opaque, hwaddr offset,
+                                   uint64_t value, unsigned size)
+{
+    XiveTCTX *tctx = pnv_xive_get_indirect_tctx(PNV_XIVE(opaque));
+
+    xive_tctx_tm_write(tctx, offset, value, size);
+}
+
+static uint64_t xive_tm_indirect_read(void *opaque, hwaddr offset,
+                                      unsigned size)
+{
+    XiveTCTX *tctx = pnv_xive_get_indirect_tctx(PNV_XIVE(opaque));
+
+    return xive_tctx_tm_read(tctx, offset, size);
+}
+
+static const MemoryRegionOps xive_tm_indirect_ops = {
+    .read = xive_tm_indirect_read,
+    .write = xive_tm_indirect_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 8,
+    },
+};
+
+/*
+ * Interrupt controller XSCOM region.
+ */
+static uint64_t pnv_xive_xscom_read(void *opaque, hwaddr addr, unsigned size)
+{
+    switch (addr >> 3) {
+    case X_VC_EQC_CONFIG:
+        /* FIXME (skiboot): This is the only XSCOM load. Bizarre. */
+        return VC_EQC_SYNC_MASK;
+    default:
+        return pnv_xive_ic_reg_read(opaque, addr, size);
+    }
+}
+
+static void pnv_xive_xscom_write(void *opaque, hwaddr addr,
+                                uint64_t val, unsigned size)
+{
+    pnv_xive_ic_reg_write(opaque, addr, val, size);
+}
+
+static const MemoryRegionOps pnv_xive_xscom_ops = {
+    .read = pnv_xive_xscom_read,
+    .write = pnv_xive_xscom_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .valid = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    }
+};
+
+/*
+ * Virtualization Controller MMIO region containing the IPI and END ESB pages
+ */
+static uint64_t pnv_xive_vc_read(void *opaque, hwaddr offset,
+                                 unsigned size)
+{
+    PnvXive *xive = PNV_XIVE(opaque);
+    uint64_t edt_index = offset >> pnv_xive_edt_shift(xive);
+    uint64_t edt_type = 0;
+    uint64_t edt_offset;
+    MemTxResult result;
+    AddressSpace *edt_as = NULL;
+    uint64_t ret = -1;
+
+    if (edt_index < XIVE_TABLE_EDT_MAX) {
+        edt_type = GETFIELD(CQ_TDR_EDT_TYPE, xive->edt[edt_index]);
+    }
+
+    switch (edt_type) {
+    case CQ_TDR_EDT_IPI:
+        edt_as = &xive->ipi_as;
+        break;
+    case CQ_TDR_EDT_EQ:
+        edt_as = &xive->end_as;
+        break;
+    default:
+        xive_error(xive, "VC: invalid EDT type for read @%"HWADDR_PRIx, offset);
+        return -1;
+    }
+
+    /* Remap the offset for the targeted address space */
+    edt_offset = pnv_xive_edt_offset(xive, offset, edt_type);
+
+    ret = address_space_ldq(edt_as, edt_offset, MEMTXATTRS_UNSPECIFIED,
+                            &result);
+
+    if (result != MEMTX_OK) {
+        xive_error(xive, "VC: %s read failed at @0x%"HWADDR_PRIx " -> @0x%"
+                   HWADDR_PRIx, edt_type == CQ_TDR_EDT_IPI ? "IPI" : "END",
+                   offset, edt_offset);
+        return -1;
+    }
+
+    return ret;
+}
+
+static void pnv_xive_vc_write(void *opaque, hwaddr offset,
+                              uint64_t val, unsigned size)
+{
+    PnvXive *xive = PNV_XIVE(opaque);
+    uint64_t edt_index = offset >> pnv_xive_edt_shift(xive);
+    uint64_t edt_type = 0;
+    uint64_t edt_offset;
+    MemTxResult result;
+    AddressSpace *edt_as = NULL;
+
+    if (edt_index < XIVE_TABLE_EDT_MAX) {
+        edt_type = GETFIELD(CQ_TDR_EDT_TYPE, xive->edt[edt_index]);
+    }
+
+    switch (edt_type) {
+    case CQ_TDR_EDT_IPI:
+        edt_as = &xive->ipi_as;
+        break;
+    case CQ_TDR_EDT_EQ:
+        edt_as = &xive->end_as;
+        break;
+    default:
+        xive_error(xive, "VC: invalid EDT type for write @%"HWADDR_PRIx,
+                   offset);
+        return;
+    }
+
+    /* Remap the offset for the targeted address space */
+    edt_offset = pnv_xive_edt_offset(xive, offset, edt_type);
+
+    address_space_stq(edt_as, edt_offset, val, MEMTXATTRS_UNSPECIFIED, &result);
+    if (result != MEMTX_OK) {
+        xive_error(xive, "VC: write failed at @0x%"HWADDR_PRIx, edt_offset);
+    }
+}
+
+static const MemoryRegionOps pnv_xive_vc_ops = {
+    .read = pnv_xive_vc_read,
+    .write = pnv_xive_vc_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .valid = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    },
+};
+
+/*
+ * Presenter Controller MMIO region. The Virtualization Controller
+ * updates the IPB in the NVT table when required. Not modeled.
+ */
+static uint64_t pnv_xive_pc_read(void *opaque, hwaddr addr,
+                                 unsigned size)
+{
+    PnvXive *xive = PNV_XIVE(opaque);
+
+    xive_error(xive, "PC: invalid read @%"HWADDR_PRIx, addr);
+    return -1;
+}
+
+static void pnv_xive_pc_write(void *opaque, hwaddr addr,
+                              uint64_t value, unsigned size)
+{
+    PnvXive *xive = PNV_XIVE(opaque);
+
+    xive_error(xive, "PC: invalid write to VC @%"HWADDR_PRIx, addr);
+}
+
+static const MemoryRegionOps pnv_xive_pc_ops = {
+    .read = pnv_xive_pc_read,
+    .write = pnv_xive_pc_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .valid = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    },
+};
+
+void pnv_xive_pic_print_info(PnvXive *xive, Monitor *mon)
+{
+    XiveRouter *xrtr = XIVE_ROUTER(xive);
+    uint8_t blk = xive->chip->chip_id;
+    uint32_t srcno0 = XIVE_SRCNO(blk, 0);
+    uint32_t nr_ipis = pnv_xive_nr_ipis(xive);
+    uint32_t nr_ends = pnv_xive_nr_ends(xive);
+    XiveEAS eas;
+    XiveEND end;
+    int i;
+
+    monitor_printf(mon, "XIVE[%x] Source %08x .. %08x\n", blk, srcno0,
+                   srcno0 + nr_ipis - 1);
+    xive_source_pic_print_info(&xive->ipi_source, srcno0, mon);
+
+    monitor_printf(mon, "XIVE[%x] EAT %08x .. %08x\n", blk, srcno0,
+                   srcno0 + nr_ipis - 1);
+    for (i = 0; i < nr_ipis; i++) {
+        if (xive_router_get_eas(xrtr, blk, i, &eas)) {
+            break;
+        }
+        if (!xive_eas_is_masked(&eas)) {
+            xive_eas_pic_print_info(&eas, i, mon);
+        }
+    }
+
+    monitor_printf(mon, "XIVE[%x] ENDT %08x .. %08x\n", blk, 0, nr_ends - 1);
+    for (i = 0; i < nr_ends; i++) {
+        if (xive_router_get_end(xrtr, blk, i, &end)) {
+            break;
+        }
+        xive_end_pic_print_info(&end, i, mon);
+    }
+}
+
+static void pnv_xive_reset(void *dev)
+{
+    PnvXive *xive = PNV_XIVE(dev);
+    XiveSource *xsrc = &xive->ipi_source;
+    XiveENDSource *end_xsrc = &xive->end_source;
+
+    /*
+     * Use the PnvChip id to identify the XIVE interrupt controller.
+     * It can be overriden by configuration at runtime.
+     */
+    xive->tctx_chipid = xive->chip->chip_id;
+
+    /* Default page size (Should be changed at runtime to 64k) */
+    xive->ic_shift = xive->vc_shift = xive->pc_shift = 12;
+
+    /* Clear subregions */
+    if (memory_region_is_mapped(&xsrc->esb_mmio)) {
+        memory_region_del_subregion(&xive->ipi_edt_mmio, &xsrc->esb_mmio);
+    }
+
+    if (memory_region_is_mapped(&xive->ipi_edt_mmio)) {
+        memory_region_del_subregion(&xive->ipi_mmio, &xive->ipi_edt_mmio);
+    }
+
+    if (memory_region_is_mapped(&end_xsrc->esb_mmio)) {
+        memory_region_del_subregion(&xive->end_edt_mmio, &end_xsrc->esb_mmio);
+    }
+
+    if (memory_region_is_mapped(&xive->end_edt_mmio)) {
+        memory_region_del_subregion(&xive->end_mmio, &xive->end_edt_mmio);
+    }
+}
+
+static void pnv_xive_init(Object *obj)
+{
+    PnvXive *xive = PNV_XIVE(obj);
+
+    object_initialize_child(obj, "ipi_source", &xive->ipi_source,
+                            sizeof(xive->ipi_source), TYPE_XIVE_SOURCE,
+                            &error_abort, NULL);
+    object_initialize_child(obj, "end_source", &xive->end_source,
+                            sizeof(xive->end_source), TYPE_XIVE_END_SOURCE,
+                            &error_abort, NULL);
+}
+
+/*
+ *  Maximum number of IRQs and ENDs supported by HW
+ */
+#define PNV_XIVE_NR_IRQS (PNV9_XIVE_VC_SIZE / (1ull << XIVE_ESB_64K_2PAGE))
+#define PNV_XIVE_NR_ENDS (PNV9_XIVE_VC_SIZE / (1ull << XIVE_ESB_64K_2PAGE))
+
+static void pnv_xive_realize(DeviceState *dev, Error **errp)
+{
+    PnvXive *xive = PNV_XIVE(dev);
+    XiveSource *xsrc = &xive->ipi_source;
+    XiveENDSource *end_xsrc = &xive->end_source;
+    Error *local_err = NULL;
+    Object *obj;
+
+    obj = object_property_get_link(OBJECT(dev), "chip", &local_err);
+    if (!obj) {
+        error_propagate(errp, local_err);
+        error_prepend(errp, "required link 'chip' not found: ");
+        return;
+    }
+
+    /* The PnvChip id identifies the XIVE interrupt controller. */
+    xive->chip = PNV_CHIP(obj);
+
+    /*
+     * The XiveSource and XiveENDSource objects are realized with the
+     * maximum allowed HW configuration. The ESB MMIO regions will be
+     * resized dynamically when the controller is configured by the FW
+     * to limit accesses to resources not provisioned.
+     */
+    object_property_set_int(OBJECT(xsrc), PNV_XIVE_NR_IRQS, "nr-irqs",
+                            &error_fatal);
+    object_property_add_const_link(OBJECT(xsrc), "xive", OBJECT(xive),
+                                   &error_fatal);
+    object_property_set_bool(OBJECT(xsrc), true, "realized", &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    object_property_set_int(OBJECT(end_xsrc), PNV_XIVE_NR_ENDS, "nr-ends",
+                            &error_fatal);
+    object_property_add_const_link(OBJECT(end_xsrc), "xive", OBJECT(xive),
+                                   &error_fatal);
+    object_property_set_bool(OBJECT(end_xsrc), true, "realized", &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    /* Default page size. Generally changed at runtime to 64k */
+    xive->ic_shift = xive->vc_shift = xive->pc_shift = 12;
+
+    /* XSCOM region, used for initial configuration of the BARs */
+    memory_region_init_io(&xive->xscom_regs, OBJECT(dev), &pnv_xive_xscom_ops,
+                          xive, "xscom-xive", PNV9_XSCOM_XIVE_SIZE << 3);
+
+    /* Interrupt controller MMIO regions */
+    memory_region_init(&xive->ic_mmio, OBJECT(dev), "xive-ic",
+                       PNV9_XIVE_IC_SIZE);
+
+    memory_region_init_io(&xive->ic_reg_mmio, OBJECT(dev), &pnv_xive_ic_reg_ops,
+                          xive, "xive-ic-reg", 1 << xive->ic_shift);
+    memory_region_init_io(&xive->ic_notify_mmio, OBJECT(dev),
+                          &pnv_xive_ic_notify_ops,
+                          xive, "xive-ic-notify", 1 << xive->ic_shift);
+
+    /* The Pervasive LSI trigger and EOI pages (not modeled) */
+    memory_region_init_io(&xive->ic_lsi_mmio, OBJECT(dev), &pnv_xive_ic_lsi_ops,
+                          xive, "xive-ic-lsi", 2 << xive->ic_shift);
+
+    /* Thread Interrupt Management Area (Indirect) */
+    memory_region_init_io(&xive->tm_indirect_mmio, OBJECT(dev),
+                          &xive_tm_indirect_ops,
+                          xive, "xive-tima-indirect", PNV9_XIVE_TM_SIZE);
+    /*
+     * Overall Virtualization Controller MMIO region containing the
+     * IPI ESB pages and END ESB pages. The layout is defined by the
+     * EDT "Domain table" and the accesses are dispatched using
+     * address spaces for each.
+     */
+    memory_region_init_io(&xive->vc_mmio, OBJECT(xive), &pnv_xive_vc_ops, xive,
+                          "xive-vc", PNV9_XIVE_VC_SIZE);
+
+    memory_region_init(&xive->ipi_mmio, OBJECT(xive), "xive-vc-ipi",
+                       PNV9_XIVE_VC_SIZE);
+    address_space_init(&xive->ipi_as, &xive->ipi_mmio, "xive-vc-ipi");
+    memory_region_init(&xive->end_mmio, OBJECT(xive), "xive-vc-end",
+                       PNV9_XIVE_VC_SIZE);
+    address_space_init(&xive->end_as, &xive->end_mmio, "xive-vc-end");
+
+    /*
+     * The MMIO windows exposing the IPI ESBs and the END ESBs in the
+     * VC region. Their size is configured by the FW in the EDT table.
+     */
+    memory_region_init(&xive->ipi_edt_mmio, OBJECT(xive), "xive-vc-ipi-edt", 0);
+    memory_region_init(&xive->end_edt_mmio, OBJECT(xive), "xive-vc-end-edt", 0);
+
+    /* Presenter Controller MMIO region (not modeled) */
+    memory_region_init_io(&xive->pc_mmio, OBJECT(xive), &pnv_xive_pc_ops, xive,
+                          "xive-pc", PNV9_XIVE_PC_SIZE);
+
+    /* Thread Interrupt Management Area (Direct) */
+    memory_region_init_io(&xive->tm_mmio, OBJECT(xive), &xive_tm_ops,
+                          xive, "xive-tima", PNV9_XIVE_TM_SIZE);
+
+    qemu_register_reset(pnv_xive_reset, dev);
+}
+
+static int pnv_xive_dt_xscom(PnvXScomInterface *dev, void *fdt,
+                             int xscom_offset)
+{
+    const char compat[] = "ibm,power9-xive-x";
+    char *name;
+    int offset;
+    uint32_t lpc_pcba = PNV9_XSCOM_XIVE_BASE;
+    uint32_t reg[] = {
+        cpu_to_be32(lpc_pcba),
+        cpu_to_be32(PNV9_XSCOM_XIVE_SIZE)
+    };
+
+    name = g_strdup_printf("xive@%x", lpc_pcba);
+    offset = fdt_add_subnode(fdt, xscom_offset, name);
+    _FDT(offset);
+    g_free(name);
+
+    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
+    _FDT((fdt_setprop(fdt, offset, "compatible", compat,
+                      sizeof(compat))));
+    return 0;
+}
+
+static Property pnv_xive_properties[] = {
+    DEFINE_PROP_UINT64("ic-bar", PnvXive, ic_base, 0),
+    DEFINE_PROP_UINT64("vc-bar", PnvXive, vc_base, 0),
+    DEFINE_PROP_UINT64("pc-bar", PnvXive, pc_base, 0),
+    DEFINE_PROP_UINT64("tm-bar", PnvXive, tm_base, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pnv_xive_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
+    XiveRouterClass *xrc = XIVE_ROUTER_CLASS(klass);
+    XiveNotifierClass *xnc = XIVE_NOTIFIER_CLASS(klass);
+
+    xdc->dt_xscom = pnv_xive_dt_xscom;
+
+    dc->desc = "PowerNV XIVE Interrupt Controller";
+    dc->realize = pnv_xive_realize;
+    dc->props = pnv_xive_properties;
+
+    xrc->get_eas = pnv_xive_get_eas;
+    xrc->get_end = pnv_xive_get_end;
+    xrc->write_end = pnv_xive_write_end;
+    xrc->get_nvt = pnv_xive_get_nvt;
+    xrc->write_nvt = pnv_xive_write_nvt;
+    xrc->get_tctx = pnv_xive_get_tctx;
+
+    xnc->notify = pnv_xive_notify;
+};
+
+static const TypeInfo pnv_xive_info = {
+    .name          = TYPE_PNV_XIVE,
+    .parent        = TYPE_XIVE_ROUTER,
+    .instance_init = pnv_xive_init,
+    .instance_size = sizeof(PnvXive),
+    .class_init    = pnv_xive_class_init,
+    .interfaces    = (InterfaceInfo[]) {
+        { TYPE_PNV_XSCOM_INTERFACE },
+        { }
+    }
+};
+
+static void pnv_xive_register_types(void)
+{
+    type_register_static(&pnv_xive_info);
+}
+
+type_init(pnv_xive_register_types)
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index b90d03711a05..a7ec76dbd6c7 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -705,7 +705,23 @@ static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
 static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu,
                                         Error **errp)
 {
-    return;
+    Pnv9Chip *chip9 = PNV9_CHIP(chip);
+    Error *local_err = NULL;
+    Object *obj;
+    PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
+
+    /*
+     * The core creates its interrupt presenter but the XIVE interrupt
+     * controller object is initialized afterwards. Hopefully, it's
+     * only used at runtime.
+     */
+    obj = xive_tctx_create(OBJECT(cpu), XIVE_ROUTER(&chip9->xive), errp);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    pnv_cpu->intc = obj;
 }
 
 /* Allowed core identifiers on a POWER8 Processor Chip :
@@ -887,11 +903,19 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
 
 static void pnv_chip_power9_instance_init(Object *obj)
 {
+    Pnv9Chip *chip9 = PNV9_CHIP(obj);
+
+    object_initialize_child(obj, "xive", &chip9->xive, sizeof(chip9->xive),
+                            TYPE_PNV_XIVE, &error_abort, NULL);
+    object_property_add_const_link(OBJECT(&chip9->xive), "chip", obj,
+                                   &error_abort);
 }
 
 static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
 {
     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
+    Pnv9Chip *chip9 = PNV9_CHIP(dev);
+    PnvChip *chip = PNV_CHIP(dev);
     Error *local_err = NULL;
 
     pcc->parent_realize(dev, &local_err);
@@ -899,6 +923,24 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
         error_propagate(errp, local_err);
         return;
     }
+
+    /* XIVE interrupt controller (POWER9) */
+    object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_IC_BASE(chip),
+                            "ic-bar", &error_fatal);
+    object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_VC_BASE(chip),
+                            "vc-bar", &error_fatal);
+    object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_PC_BASE(chip),
+                            "pc-bar", &error_fatal);
+    object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_TM_BASE(chip),
+                            "tm-bar", &error_fatal);
+    object_property_set_bool(OBJECT(&chip9->xive), true, "realized",
+                             &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+    pnv_xscom_add_subregion(chip, PNV9_XSCOM_XIVE_BASE,
+                            &chip9->xive.xscom_regs);
 }
 
 static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 301a8e972d91..df712c3e6c93 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -39,7 +39,7 @@ obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o
 obj-$(CONFIG_XICS_KVM) += xics_kvm.o
 obj-$(CONFIG_XIVE) += xive.o
 obj-$(CONFIG_XIVE_SPAPR) += spapr_xive.o
-obj-$(CONFIG_POWERNV) += xics_pnv.o
+obj-$(CONFIG_POWERNV) += xics_pnv.o pnv_xive.o
 obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
 obj-$(CONFIG_S390_FLIC) += s390_flic.o
 obj-$(CONFIG_S390_FLIC_KVM) += s390_flic_kvm.o
-- 
2.20.1

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

* [Qemu-devel] [PATCH 07/27] ppc/pnv: introduce a new dt_populate() operation to the chip model
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (5 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 06/27] ppc/pnv: add a XIVE interrupt controller model for POWER9 Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-07  1:44   ` David Gibson
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 08/27] ppc/pnv: introduce a new pic_print_info() " Cédric Le Goater
                   ` (19 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

The POWER9 and POWER8 processors have a different set of devices and a
different device tree layout.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/ppc/pnv.h |  1 +
 hw/ppc/pnv.c         | 27 +++++++++++++++++++++++++--
 2 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index ebbb3d0e9aa7..fa9ec50fd5be 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -102,6 +102,7 @@ typedef struct PnvChipClass {
     uint32_t (*core_pir)(PnvChip *chip, uint32_t core_id);
     void (*intc_create)(PnvChip *chip, PowerPCCPU *cpu, Error **errp);
     ISABus *(*isa_create)(PnvChip *chip, Error **errp);
+    void (*dt_populate)(PnvChip *chip, void *fdt);
 } PnvChipClass;
 
 #define PNV_CHIP_TYPE_SUFFIX "-" TYPE_PNV_CHIP
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index a7ec76dbd6c7..087541a91a72 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -267,7 +267,7 @@ static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir,
     g_free(reg);
 }
 
-static void pnv_dt_chip(PnvChip *chip, void *fdt)
+static void pnv_chip_power8_dt_populate(PnvChip *chip, void *fdt)
 {
     const char *typename = pnv_chip_core_typename(chip);
     size_t typesize = object_type_get_instance_size(typename);
@@ -289,6 +289,25 @@ static void pnv_dt_chip(PnvChip *chip, void *fdt)
     }
 }
 
+static void pnv_chip_power9_dt_populate(PnvChip *chip, void *fdt)
+{
+    const char *typename = pnv_chip_core_typename(chip);
+    size_t typesize = object_type_get_instance_size(typename);
+    int i;
+
+    pnv_dt_xscom(chip, fdt, 0);
+
+    for (i = 0; i < chip->nr_cores; i++) {
+        PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
+
+        pnv_dt_core(chip, pnv_core, fdt);
+    }
+
+    if (chip->ram_size) {
+        pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
+    }
+}
+
 static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
 {
     uint32_t io_base = d->ioport_id;
@@ -474,7 +493,7 @@ static void *pnv_dt_create(MachineState *machine)
 
     /* Populate device tree for each chip */
     for (i = 0; i < pnv->num_chips; i++) {
-        pnv_dt_chip(pnv->chips[i], fdt);
+        PNV_CHIP_GET_CLASS(pnv->chips[i])->dt_populate(pnv->chips[i], fdt);
     }
 
     /* Populate ISA devices on chip 0 */
@@ -858,6 +877,7 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
     k->core_pir = pnv_chip_core_pir_p8;
     k->intc_create = pnv_chip_power8_intc_create;
     k->isa_create = pnv_chip_power8_isa_create;
+    k->dt_populate = pnv_chip_power8_dt_populate;
     k->xscom_base = 0x003fc0000000000ull;
     dc->desc = "PowerNV Chip POWER8E";
 
@@ -876,6 +896,7 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
     k->core_pir = pnv_chip_core_pir_p8;
     k->intc_create = pnv_chip_power8_intc_create;
     k->isa_create = pnv_chip_power8_isa_create;
+    k->dt_populate = pnv_chip_power8_dt_populate;
     k->xscom_base = 0x003fc0000000000ull;
     dc->desc = "PowerNV Chip POWER8";
 
@@ -894,6 +915,7 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
     k->core_pir = pnv_chip_core_pir_p8;
     k->intc_create = pnv_chip_power8_intc_create;
     k->isa_create = pnv_chip_power8nvl_isa_create;
+    k->dt_populate = pnv_chip_power8_dt_populate;
     k->xscom_base = 0x003fc0000000000ull;
     dc->desc = "PowerNV Chip POWER8NVL";
 
@@ -954,6 +976,7 @@ static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
     k->core_pir = pnv_chip_core_pir_p9;
     k->intc_create = pnv_chip_power9_intc_create;
     k->isa_create = pnv_chip_power9_isa_create;
+    k->dt_populate = pnv_chip_power9_dt_populate;
     k->xscom_base = 0x00603fc00000000ull;
     dc->desc = "PowerNV Chip POWER9";
 
-- 
2.20.1

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

* [Qemu-devel] [PATCH 08/27] ppc/pnv: introduce a new pic_print_info() operation to the chip model
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (6 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 07/27] ppc/pnv: introduce a new dt_populate() operation to the chip model Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-07  1:46   ` David Gibson
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 09/27] ppc/xive: activate HV support Cédric Le Goater
                   ` (18 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

The POWER9 and POWER8 processors have different interrupt controllers,
and reporting their state requires calling different helper routines.

However, the interrupt presenters are still handled in the higher
level pic_print_info() routine because they are not related to the
chip.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/ppc/pnv.h |  1 +
 hw/ppc/pnv.c         | 27 ++++++++++++++++++++++++---
 2 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index fa9ec50fd5be..eb4bba25b3e9 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -103,6 +103,7 @@ typedef struct PnvChipClass {
     void (*intc_create)(PnvChip *chip, PowerPCCPU *cpu, Error **errp);
     ISABus *(*isa_create)(PnvChip *chip, Error **errp);
     void (*dt_populate)(PnvChip *chip, void *fdt);
+    void (*pic_print_info)(PnvChip *chip, Monitor *mon);
 } PnvChipClass;
 
 #define PNV_CHIP_TYPE_SUFFIX "-" TYPE_PNV_CHIP
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 087541a91a72..7660eaa22cf9 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -567,6 +567,20 @@ static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
     return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp);
 }
 
+static void pnv_chip_power8_pic_print_info(PnvChip *chip, Monitor *mon)
+{
+    Pnv8Chip *chip8 = PNV8_CHIP(chip);
+
+    ics_pic_print_info(&chip8->psi.ics, mon);
+}
+
+static void pnv_chip_power9_pic_print_info(PnvChip *chip, Monitor *mon)
+{
+    Pnv9Chip *chip9 = PNV9_CHIP(chip);
+
+    pnv_xive_pic_print_info(&chip9->xive, mon);
+}
+
 static void pnv_init(MachineState *machine)
 {
     PnvMachineState *pnv = PNV_MACHINE(machine);
@@ -878,6 +892,7 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
     k->intc_create = pnv_chip_power8_intc_create;
     k->isa_create = pnv_chip_power8_isa_create;
     k->dt_populate = pnv_chip_power8_dt_populate;
+    k->pic_print_info = pnv_chip_power8_pic_print_info;
     k->xscom_base = 0x003fc0000000000ull;
     dc->desc = "PowerNV Chip POWER8E";
 
@@ -897,6 +912,7 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
     k->intc_create = pnv_chip_power8_intc_create;
     k->isa_create = pnv_chip_power8_isa_create;
     k->dt_populate = pnv_chip_power8_dt_populate;
+    k->pic_print_info = pnv_chip_power8_pic_print_info;
     k->xscom_base = 0x003fc0000000000ull;
     dc->desc = "PowerNV Chip POWER8";
 
@@ -916,6 +932,7 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
     k->intc_create = pnv_chip_power8_intc_create;
     k->isa_create = pnv_chip_power8nvl_isa_create;
     k->dt_populate = pnv_chip_power8_dt_populate;
+    k->pic_print_info = pnv_chip_power8_pic_print_info;
     k->xscom_base = 0x003fc0000000000ull;
     dc->desc = "PowerNV Chip POWER8NVL";
 
@@ -977,6 +994,7 @@ static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
     k->intc_create = pnv_chip_power9_intc_create;
     k->isa_create = pnv_chip_power9_isa_create;
     k->dt_populate = pnv_chip_power9_dt_populate;
+    k->pic_print_info = pnv_chip_power9_pic_print_info;
     k->xscom_base = 0x00603fc00000000ull;
     dc->desc = "PowerNV Chip POWER9";
 
@@ -1164,12 +1182,15 @@ static void pnv_pic_print_info(InterruptStatsProvider *obj,
     CPU_FOREACH(cs) {
         PowerPCCPU *cpu = POWERPC_CPU(cs);
 
-        icp_pic_print_info(ICP(pnv_cpu_state(cpu)->intc), mon);
+        if (pnv_chip_is_power9(pnv->chips[0])) {
+            xive_tctx_pic_print_info(XIVE_TCTX(pnv_cpu_state(cpu)->intc), mon);
+        } else {
+            icp_pic_print_info(ICP(pnv_cpu_state(cpu)->intc), mon);
+        }
     }
 
     for (i = 0; i < pnv->num_chips; i++) {
-        Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
-        ics_pic_print_info(&chip8->psi.ics, mon);
+        PNV_CHIP_GET_CLASS(pnv->chips[i])->pic_print_info(pnv->chips[i], mon);
     }
 }
 
-- 
2.20.1

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

* [Qemu-devel] [PATCH 09/27] ppc/xive: activate HV support
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (7 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 08/27] ppc/pnv: introduce a new pic_print_info() " Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-07  1:48   ` David Gibson
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 10/27] ppc/xive: Make XIVE generate the proper interrupt types Cédric Le Goater
                   ` (17 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

The NSR register of the HV ring has a different, although similar, bit
layout. TM_QW3_NSR_HE_PHYS bit should now be raised when the
Hypervisor interrupt line is signaled. Other bits TM_QW3_NSR_HE_POOL
and TM_QW3_NSR_HE_LSI are not modeled. LSI are for special interrupts
reserved for HW bringup and the POOL bit is used when signaling a
group of VPs. This is not currently implemented in Linux but it is in
pHyp.

The most important special commands on the HV TIMA page are added to
let the core manage interrupts : acking and changing the CPU priority.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/intc/xive.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 54 insertions(+), 3 deletions(-)

diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index 7d7992c0ce3f..a0b87001da25 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -54,6 +54,8 @@ static uint8_t exception_mask(uint8_t ring)
     switch (ring) {
     case TM_QW1_OS:
         return TM_QW1_NSR_EO;
+    case TM_QW3_HV_PHYS:
+        return TM_QW3_NSR_HE;
     default:
         g_assert_not_reached();
     }
@@ -88,7 +90,16 @@ static void xive_tctx_notify(XiveTCTX *tctx, uint8_t ring)
     uint8_t *regs = &tctx->regs[ring];
 
     if (regs[TM_PIPR] < regs[TM_CPPR]) {
-        regs[TM_NSR] |= exception_mask(ring);
+        switch (ring) {
+        case TM_QW1_OS:
+            regs[TM_NSR] |= TM_QW1_NSR_EO;
+            break;
+        case TM_QW3_HV_PHYS:
+            regs[TM_NSR] |= (TM_QW3_NSR_HE_PHYS << 6);
+            break;
+        default:
+            g_assert_not_reached();
+        }
         qemu_irq_raise(tctx->output);
     }
 }
@@ -109,6 +120,38 @@ static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr)
  * XIVE Thread Interrupt Management Area (TIMA)
  */
 
+static void xive_tm_set_hv_cppr(XiveTCTX *tctx, hwaddr offset,
+                                uint64_t value, unsigned size)
+{
+    xive_tctx_set_cppr(tctx, TM_QW3_HV_PHYS, value & 0xff);
+}
+
+static uint64_t xive_tm_ack_hv_reg(XiveTCTX *tctx, hwaddr offset, unsigned size)
+{
+    return xive_tctx_accept(tctx, TM_QW3_HV_PHYS);
+}
+
+static uint64_t xive_tm_pull_pool_ctx(XiveTCTX *tctx, hwaddr offset,
+                                      unsigned size)
+{
+    uint64_t ret;
+
+    ret = tctx->regs[TM_QW2_HV_POOL + TM_WORD2] & TM_QW2W2_POOL_CAM;
+    tctx->regs[TM_QW2_HV_POOL + TM_WORD2] &= ~TM_QW2W2_POOL_CAM;
+    return ret;
+}
+
+static void xive_tm_vt_push(XiveTCTX *tctx, hwaddr offset,
+                            uint64_t value, unsigned size)
+{
+    tctx->regs[TM_QW3_HV_PHYS + TM_WORD2] = value & 0xff;
+}
+
+static uint64_t xive_tm_vt_poll(XiveTCTX *tctx, hwaddr offset, unsigned size)
+{
+    return tctx->regs[TM_QW3_HV_PHYS + TM_WORD2] & 0xff;
+}
+
 /*
  * Define an access map for each page of the TIMA that we will use in
  * the memory region ops to filter values when doing loads and stores
@@ -288,10 +331,16 @@ static const XiveTmOp xive_tm_operations[] = {
      * effects
      */
     { XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR,   1, xive_tm_set_os_cppr, NULL },
+    { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, xive_tm_set_hv_cppr, NULL },
+    { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, xive_tm_vt_push, NULL },
+    { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, NULL, xive_tm_vt_poll },
 
     /* MMIOs above 2K : special operations with side effects */
     { XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG,     2, NULL, xive_tm_ack_os_reg },
     { XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending, NULL },
+    { XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG,     2, NULL, xive_tm_ack_hv_reg },
+    { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX,  4, NULL, xive_tm_pull_pool_ctx },
+    { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX,  8, NULL, xive_tm_pull_pool_ctx },
 };
 
 static const XiveTmOp *xive_tm_find_op(hwaddr offset, unsigned size, bool write)
@@ -323,7 +372,7 @@ void xive_tctx_tm_write(XiveTCTX *tctx, hwaddr offset, uint64_t value,
     const XiveTmOp *xto;
 
     /*
-     * TODO: check V bit in Q[0-3]W2, check PTER bit associated with CPU
+     * TODO: check V bit in Q[0-3]W2
      */
 
     /*
@@ -360,7 +409,7 @@ uint64_t xive_tctx_tm_read(XiveTCTX *tctx, hwaddr offset, unsigned size)
     const XiveTmOp *xto;
 
     /*
-     * TODO: check V bit in Q[0-3]W2, check PTER bit associated with CPU
+     * TODO: check V bit in Q[0-3]W2
      */
 
     /*
@@ -472,6 +521,8 @@ static void xive_tctx_reset(void *dev)
      */
     tctx->regs[TM_QW1_OS + TM_PIPR] =
         ipb_to_pipr(tctx->regs[TM_QW1_OS + TM_IPB]);
+    tctx->regs[TM_QW3_HV_PHYS + TM_PIPR] =
+        ipb_to_pipr(tctx->regs[TM_QW3_HV_PHYS + TM_IPB]);
 }
 
 static void xive_tctx_realize(DeviceState *dev, Error **errp)
-- 
2.20.1

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

* [Qemu-devel] [PATCH 10/27] ppc/xive: Make XIVE generate the proper interrupt types
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (8 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 09/27] ppc/xive: activate HV support Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-07  3:29   ` David Gibson
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 11/27] ppc/pnv: fix logging primitives using Ox Cédric Le Goater
                   ` (16 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson
  Cc: qemu-ppc, qemu-devel, Benjamin Herrenschmidt, Cédric Le Goater

From: Benjamin Herrenschmidt <benh@kernel.crashing.org>

It should be generic Hypervisor Virtualization interrupts for HV
directed rings and traditional External Interrupts for the OS directed
ring.

Don't generate anything for the user ring as it isn't actually
supported.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/ppc/xive.h |  3 ++-
 hw/intc/xive.c        | 22 +++++++++++++++++++---
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h
index c4f27742ca09..6b89dc7679f9 100644
--- a/include/hw/ppc/xive.h
+++ b/include/hw/ppc/xive.h
@@ -313,7 +313,8 @@ typedef struct XiveTCTX {
     DeviceState parent_obj;
 
     CPUState    *cs;
-    qemu_irq    output;
+    qemu_irq    hv_output;
+    qemu_irq    os_output;
 
     uint8_t     regs[XIVE_TM_RING_COUNT * XIVE_TM_RING_SIZE];
 } XiveTCTX;
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index a0b87001da25..237e7b256dc0 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -61,13 +61,28 @@ static uint8_t exception_mask(uint8_t ring)
     }
 }
 
+static qemu_irq xive_tctx_output(XiveTCTX *tctx, uint8_t ring)
+{
+        switch (ring) {
+        case TM_QW0_USER:
+                return 0; /* Not supported */
+        case TM_QW1_OS:
+                return tctx->os_output;
+        case TM_QW2_HV_POOL:
+        case TM_QW3_HV_PHYS:
+                return tctx->hv_output;
+        default:
+                return 0;
+        }
+}
+
 static uint64_t xive_tctx_accept(XiveTCTX *tctx, uint8_t ring)
 {
     uint8_t *regs = &tctx->regs[ring];
     uint8_t nsr = regs[TM_NSR];
     uint8_t mask = exception_mask(ring);
 
-    qemu_irq_lower(tctx->output);
+    qemu_irq_lower(xive_tctx_output(tctx, ring));
 
     if (regs[TM_NSR] & mask) {
         uint8_t cppr = regs[TM_PIPR];
@@ -100,7 +115,7 @@ static void xive_tctx_notify(XiveTCTX *tctx, uint8_t ring)
         default:
             g_assert_not_reached();
         }
-        qemu_irq_raise(tctx->output);
+        qemu_irq_raise(xive_tctx_output(tctx, ring));
     }
 }
 
@@ -546,7 +561,8 @@ static void xive_tctx_realize(DeviceState *dev, Error **errp)
     env = &cpu->env;
     switch (PPC_INPUT(env)) {
     case PPC_FLAGS_INPUT_POWER9:
-        tctx->output = env->irq_inputs[POWER9_INPUT_INT];
+        tctx->hv_output = env->irq_inputs[POWER9_INPUT_HINT];
+        tctx->os_output = env->irq_inputs[POWER9_INPUT_INT];
         break;
 
     default:
-- 
2.20.1

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

* [Qemu-devel] [PATCH 11/27] ppc/pnv: fix logging primitives using Ox
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (9 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 10/27] ppc/xive: Make XIVE generate the proper interrupt types Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-07  3:30   ` David Gibson
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 12/27] ppc/pnv: psi: add a PSIHB_REG macro Cédric Le Goater
                   ` (15 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/ppc/pnv_lpc.c | 10 +++++-----
 hw/ppc/pnv_psi.c |  4 ++--
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c
index 172a915cfc55..9b18ce55e391 100644
--- a/hw/ppc/pnv_lpc.c
+++ b/hw/ppc/pnv_lpc.c
@@ -294,7 +294,7 @@ static uint64_t lpc_hc_read(void *opaque, hwaddr addr, unsigned size)
         val =  lpc->lpc_hc_error_addr;
         break;
     default:
-        qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: Ox%"
+        qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: 0x%"
                       HWADDR_PRIx "\n", addr);
     }
     return val;
@@ -332,7 +332,7 @@ static void lpc_hc_write(void *opaque, hwaddr addr, uint64_t val,
     case LPC_HC_ERROR_ADDRESS:
         break;
     default:
-        qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: Ox%"
+        qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: 0x%"
                       HWADDR_PRIx "\n", addr);
     }
 }
@@ -370,7 +370,7 @@ static uint64_t opb_master_read(void *opaque, hwaddr addr, unsigned size)
         val = lpc->opb_irq_input;
         break;
     default:
-        qemu_log_mask(LOG_UNIMP, "OPB MASTER Unimplemented register: Ox%"
+        qemu_log_mask(LOG_UNIMP, "OPBM: read on unimplemented register: 0x%"
                       HWADDR_PRIx "\n", addr);
     }
 
@@ -399,8 +399,8 @@ static void opb_master_write(void *opaque, hwaddr addr,
         /* Read only */
         break;
     default:
-        qemu_log_mask(LOG_UNIMP, "OPB MASTER Unimplemented register: Ox%"
-                      HWADDR_PRIx "\n", addr);
+        qemu_log_mask(LOG_UNIMP, "OPBM: write on unimplemented register: 0x%"
+                      HWADDR_PRIx " val=0x%08"PRIx64"\n", addr, val);
     }
 }
 
diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
index 44bc0cbf58cb..c872be0b9c0d 100644
--- a/hw/ppc/pnv_psi.c
+++ b/hw/ppc/pnv_psi.c
@@ -323,7 +323,7 @@ static uint64_t pnv_psi_reg_read(PnvPsi *psi, uint32_t offset, bool mmio)
         val = psi->regs[offset];
         break;
     default:
-        qemu_log_mask(LOG_UNIMP, "PSI: read at Ox%" PRIx32 "\n", offset);
+        qemu_log_mask(LOG_UNIMP, "PSI: read at 0x%" PRIx32 "\n", offset);
     }
     return val;
 }
@@ -382,7 +382,7 @@ static void pnv_psi_reg_write(PnvPsi *psi, uint32_t offset, uint64_t val,
         pnv_psi_set_irsn(psi, val);
         break;
     default:
-        qemu_log_mask(LOG_UNIMP, "PSI: write at Ox%" PRIx32 "\n", offset);
+        qemu_log_mask(LOG_UNIMP, "PSI: write at 0x%" PRIx32 "\n", offset);
     }
 }
 
-- 
2.20.1

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

* [Qemu-devel] [PATCH 12/27] ppc/pnv: psi: add a PSIHB_REG macro
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (10 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 11/27] ppc/pnv: fix logging primitives using Ox Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-07  3:30   ` David Gibson
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 13/27] ppc/pnv: psi: add a reset handler Cédric Le Goater
                   ` (14 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

This is a simple helper to translate XSCOM addresses to MMIO addresses

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/ppc/pnv_psi.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
index c872be0b9c0d..a2f8d0dece80 100644
--- a/hw/ppc/pnv_psi.c
+++ b/hw/ppc/pnv_psi.c
@@ -114,6 +114,8 @@
 #define PSIHB_BAR_MASK                  0x0003fffffff00000ull
 #define PSIHB_FSPBAR_MASK               0x0003ffff00000000ull
 
+#define PSIHB_REG(addr) (((addr) >> 3) + PSIHB_XSCOM_BAR)
+
 static void pnv_psi_set_bar(PnvPsi *psi, uint64_t bar)
 {
     MemoryRegion *sysmem = get_system_memory();
@@ -392,13 +394,13 @@ static void pnv_psi_reg_write(PnvPsi *psi, uint32_t offset, uint64_t val,
  */
 static uint64_t pnv_psi_mmio_read(void *opaque, hwaddr addr, unsigned size)
 {
-    return pnv_psi_reg_read(opaque, (addr >> 3) + PSIHB_XSCOM_BAR, true);
+    return pnv_psi_reg_read(opaque, PSIHB_REG(addr), true);
 }
 
 static void pnv_psi_mmio_write(void *opaque, hwaddr addr,
                               uint64_t val, unsigned size)
 {
-    pnv_psi_reg_write(opaque, (addr >> 3) + PSIHB_XSCOM_BAR, val, true);
+    pnv_psi_reg_write(opaque, PSIHB_REG(addr), val, true);
 }
 
 static const MemoryRegionOps psi_mmio_ops = {
-- 
2.20.1

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

* [Qemu-devel] [PATCH 13/27] ppc/pnv: psi: add a reset handler
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (11 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 12/27] ppc/pnv: psi: add a PSIHB_REG macro Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-07  3:32   ` David Gibson
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 14/27] ppc/pnv: add a PSI bridge model class Cédric Le Goater
                   ` (13 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

Reset all regs but keep the MMIO BAR enabled as it is at realize time.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/ppc/pnv_psi.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
index a2f8d0dece80..e61861bfd3c6 100644
--- a/hw/ppc/pnv_psi.c
+++ b/hw/ppc/pnv_psi.c
@@ -442,6 +442,15 @@ static const MemoryRegionOps pnv_psi_xscom_ops = {
     }
 };
 
+static void pnv_psi_reset(void *dev)
+{
+    PnvPsi *psi = PNV_PSI(dev);
+
+    memset(psi->regs, 0x0, sizeof(psi->regs));
+
+    psi->regs[PSIHB_XSCOM_BAR] = psi->bar | PSIHB_BAR_EN;
+}
+
 static void pnv_psi_init(Object *obj)
 {
     PnvPsi *psi = PNV_PSI(obj);
@@ -511,6 +520,8 @@ static void pnv_psi_realize(DeviceState *dev, Error **errp)
         psi->regs[xivr] = PSIHB_XIVR_PRIO_MSK |
             ((uint64_t) i << PSIHB_XIVR_SRC_SH);
     }
+
+    qemu_register_reset(pnv_psi_reset, dev);
 }
 
 static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
-- 
2.20.1

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

* [Qemu-devel] [PATCH 14/27] ppc/pnv: add a PSI bridge model class
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (12 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 13/27] ppc/pnv: psi: add a reset handler Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-07  4:05   ` David Gibson
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 15/27] ppc/pnv: add a PSI bridge model for POWER9 Cédric Le Goater
                   ` (12 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

It will ease the introduction of the PSI bridge model for POWER9.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/ppc/pnv_psi.h | 21 +++++++++++-
 hw/ppc/pnv.c             |  2 +-
 hw/ppc/pnv_psi.c         | 72 ++++++++++++++++++++++++++++------------
 3 files changed, 72 insertions(+), 23 deletions(-)

diff --git a/include/hw/ppc/pnv_psi.h b/include/hw/ppc/pnv_psi.h
index 64ac73512e81..585a41cd19b6 100644
--- a/include/hw/ppc/pnv_psi.h
+++ b/include/hw/ppc/pnv_psi.h
@@ -25,6 +25,9 @@
 #define TYPE_PNV_PSI "pnv-psi"
 #define PNV_PSI(obj) \
      OBJECT_CHECK(PnvPsi, (obj), TYPE_PNV_PSI)
+#define TYPE_PNV8_PSI TYPE_PNV_PSI "-POWER8"
+#define PNV8_PSI(obj) \
+    OBJECT_CHECK(PnvPsi, (obj), TYPE_PNV8_PSI)
 
 #define PSIHB_XSCOM_MAX         0x20
 
@@ -48,6 +51,22 @@ typedef struct PnvPsi {
     MemoryRegion xscom_regs;
 } PnvPsi;
 
+#define PNV_PSI_CLASS(klass) \
+     OBJECT_CLASS_CHECK(PnvPsiClass, (klass), TYPE_PNV_PSI)
+#define PNV_PSI_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(PnvPsiClass, (obj), TYPE_PNV_PSI)
+
+typedef struct PnvPsiClass {
+    SysBusDeviceClass parent_class;
+
+    int chip_type;
+    uint32_t xscom_pcba;
+    uint32_t xscom_size;
+    uint64_t bar_mask;
+
+    void (*irq_set)(PnvPsi *psi, int, bool state);
+} PnvPsiClass;
+
 /* The PSI and FSP interrupts are muxed on the same IRQ number */
 typedef enum PnvPsiIrq {
     PSIHB_IRQ_PSI, /* internal use only */
@@ -61,6 +80,6 @@ typedef enum PnvPsiIrq {
 
 #define PSI_NUM_INTERRUPTS 6
 
-extern void pnv_psi_irq_set(PnvPsi *psi, PnvPsiIrq irq, bool state);
+void pnv_psi_irq_set(PnvPsi *psi, int irq, bool state);
 
 #endif /* _PPC_PNV_PSI_H */
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 7660eaa22cf9..67d40dc3eebc 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -788,7 +788,7 @@ static void pnv_chip_power8_instance_init(Object *obj)
     Pnv8Chip *chip8 = PNV8_CHIP(obj);
 
     object_initialize_child(obj, "psi",  &chip8->psi, sizeof(chip8->psi),
-                            TYPE_PNV_PSI, &error_abort, NULL);
+                            TYPE_PNV8_PSI, &error_abort, NULL);
     object_property_add_const_link(OBJECT(&chip8->psi), "xics",
                                    OBJECT(qdev_get_machine()), &error_abort);
 
diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
index e61861bfd3c6..e56b455a61b1 100644
--- a/hw/ppc/pnv_psi.c
+++ b/hw/ppc/pnv_psi.c
@@ -118,10 +118,11 @@
 
 static void pnv_psi_set_bar(PnvPsi *psi, uint64_t bar)
 {
+    PnvPsiClass *ppc = PNV_PSI_GET_CLASS(psi);
     MemoryRegion *sysmem = get_system_memory();
     uint64_t old = psi->regs[PSIHB_XSCOM_BAR];
 
-    psi->regs[PSIHB_XSCOM_BAR] = bar & (PSIHB_BAR_MASK | PSIHB_BAR_EN);
+    psi->regs[PSIHB_XSCOM_BAR] = bar & (ppc->bar_mask | PSIHB_BAR_EN);
 
     /* Update MR, always remove it first */
     if (old & PSIHB_BAR_EN) {
@@ -130,7 +131,7 @@ static void pnv_psi_set_bar(PnvPsi *psi, uint64_t bar)
 
     /* Then add it back if needed */
     if (bar & PSIHB_BAR_EN) {
-        uint64_t addr = bar & PSIHB_BAR_MASK;
+        uint64_t addr = bar & ppc->bar_mask;
         memory_region_add_subregion(sysmem, addr, &psi->regs_mr);
     }
 }
@@ -207,7 +208,12 @@ static const uint64_t stat_bits[] = {
     [PSIHB_IRQ_EXTERNAL]  = PSIHB_IRQ_STAT_EXT,
 };
 
-void pnv_psi_irq_set(PnvPsi *psi, PnvPsiIrq irq, bool state)
+void pnv_psi_irq_set(PnvPsi *psi, int irq, bool state)
+{
+    PNV_PSI_GET_CLASS(psi)->irq_set(psi, irq, state);
+}
+
+static void pnv_psi_power8_irq_set(PnvPsi *psi, int irq, bool state)
 {
     uint32_t xivr_reg;
     uint32_t stat_reg;
@@ -451,9 +457,9 @@ static void pnv_psi_reset(void *dev)
     psi->regs[PSIHB_XSCOM_BAR] = psi->bar | PSIHB_BAR_EN;
 }
 
-static void pnv_psi_init(Object *obj)
+static void pnv_psi_power8_instance_init(Object *obj)
 {
-    PnvPsi *psi = PNV_PSI(obj);
+    PnvPsi *psi = PNV8_PSI(obj);
 
     object_initialize_child(obj, "ics-psi",  &psi->ics, sizeof(psi->ics),
                             TYPE_ICS_SIMPLE, &error_abort, NULL);
@@ -468,9 +474,9 @@ static const uint8_t irq_to_xivr[] = {
     PSIHB_XSCOM_XIVR_EXT,
 };
 
-static void pnv_psi_realize(DeviceState *dev, Error **errp)
+static void pnv_psi_power8_realize(DeviceState *dev, Error **errp)
 {
-    PnvPsi *psi = PNV_PSI(dev);
+    PnvPsi *psi = PNV8_PSI(dev);
     ICSState *ics = &psi->ics;
     Object *obj;
     Error *err = NULL;
@@ -524,28 +530,28 @@ static void pnv_psi_realize(DeviceState *dev, Error **errp)
     qemu_register_reset(pnv_psi_reset, dev);
 }
 
+static const char compat_p8[] = "ibm,power8-psihb-x\0ibm,psihb-x";
+
 static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
 {
-    const char compat[] = "ibm,power8-psihb-x\0ibm,psihb-x";
+    PnvPsiClass *ppc = PNV_PSI_GET_CLASS(dev);
     char *name;
     int offset;
-    uint32_t lpc_pcba = PNV_XSCOM_PSIHB_BASE;
     uint32_t reg[] = {
-        cpu_to_be32(lpc_pcba),
-        cpu_to_be32(PNV_XSCOM_PSIHB_SIZE)
+        cpu_to_be32(ppc->xscom_pcba),
+        cpu_to_be32(ppc->xscom_size)
     };
 
-    name = g_strdup_printf("psihb@%x", lpc_pcba);
+    name = g_strdup_printf("psihb@%x", ppc->xscom_pcba);
     offset = fdt_add_subnode(fdt, xscom_offset, name);
     _FDT(offset);
     g_free(name);
 
-    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
-
-    _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 2)));
-    _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 1)));
-    _FDT((fdt_setprop(fdt, offset, "compatible", compat,
-                      sizeof(compat))));
+    _FDT(fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)));
+    _FDT(fdt_setprop_cell(fdt, offset, "#address-cells", 2));
+    _FDT(fdt_setprop_cell(fdt, offset, "#size-cells", 1));
+    _FDT(fdt_setprop(fdt, offset, "compatible", compat_p8,
+                     sizeof(compat_p8)));
     return 0;
 }
 
@@ -555,6 +561,28 @@ static Property pnv_psi_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
+static void pnv_psi_power8_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PnvPsiClass *ppc = PNV_PSI_CLASS(klass);
+
+    dc->desc    = "PowerNV PSI Controller POWER8";
+    dc->realize = pnv_psi_power8_realize;
+
+    ppc->chip_type =  PNV_CHIP_POWER8;
+    ppc->xscom_pcba = PNV_XSCOM_PSIHB_BASE;
+    ppc->xscom_size = PNV_XSCOM_PSIHB_SIZE;
+    ppc->bar_mask   = PSIHB_BAR_MASK;
+    ppc->irq_set    = pnv_psi_power8_irq_set;
+}
+
+static const TypeInfo pnv_psi_power8_info = {
+    .name          = TYPE_PNV8_PSI,
+    .parent        = TYPE_PNV_PSI,
+    .instance_init = pnv_psi_power8_instance_init,
+    .class_init    = pnv_psi_power8_class_init,
+};
+
 static void pnv_psi_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -562,7 +590,7 @@ static void pnv_psi_class_init(ObjectClass *klass, void *data)
 
     xdc->dt_xscom = pnv_psi_dt_xscom;
 
-    dc->realize = pnv_psi_realize;
+    dc->desc = "PowerNV PSI Controller";
     dc->props = pnv_psi_properties;
 }
 
@@ -570,8 +598,9 @@ static const TypeInfo pnv_psi_info = {
     .name          = TYPE_PNV_PSI,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(PnvPsi),
-    .instance_init = pnv_psi_init,
     .class_init    = pnv_psi_class_init,
+    .class_size    = sizeof(PnvPsiClass),
+    .abstract      = true,
     .interfaces    = (InterfaceInfo[]) {
         { TYPE_PNV_XSCOM_INTERFACE },
         { }
@@ -581,6 +610,7 @@ static const TypeInfo pnv_psi_info = {
 static void pnv_psi_register_types(void)
 {
     type_register_static(&pnv_psi_info);
+    type_register_static(&pnv_psi_power8_info);
 }
 
-type_init(pnv_psi_register_types)
+type_init(pnv_psi_register_types);
-- 
2.20.1

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

* [Qemu-devel] [PATCH 15/27] ppc/pnv: add a PSI bridge model for POWER9
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (13 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 14/27] ppc/pnv: add a PSI bridge model class Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-07  4:10   ` David Gibson
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 16/27] ppc/pnv: lpc: fix OPB address ranges Cédric Le Goater
                   ` (11 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

The PSI bridge on POWER9 is very similar to POWER8. The BAR is still
set through XSCOM but the controls are now entirely done with MMIOs.
More interrupts are defined and the interrupt controller interface has
changed to XIVE. The POWER9 model is a first example of the usage of
the notify() handler of the XiveNotifier interface, linking the PSI
XiveSource to its owning device model.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/ppc/pnv.h       |   6 +
 include/hw/ppc/pnv_psi.h   |  24 +++
 include/hw/ppc/pnv_xscom.h |   3 +
 hw/ppc/pnv.c               |  17 ++
 hw/ppc/pnv_psi.c           | 325 ++++++++++++++++++++++++++++++++++++-
 5 files changed, 373 insertions(+), 2 deletions(-)

diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index eb4bba25b3e9..57d0337219be 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -84,6 +84,7 @@ typedef struct Pnv9Chip {
 
     /*< public >*/
     PnvXive      xive;
+    PnvPsi       psi;
 } Pnv9Chip;
 
 typedef struct PnvChipClass {
@@ -231,11 +232,16 @@ void pnv_bmc_powerdown(IPMIBmc *bmc);
 #define PNV9_XIVE_PC_SIZE            0x0000001000000000ull
 #define PNV9_XIVE_PC_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006018000000000ull)
 
+#define PNV9_PSIHB_SIZE              0x0000000000100000ull
+#define PNV9_PSIHB_BASE(chip)        PNV9_CHIP_BASE(chip, 0x0006030203000000ull)
+
 #define PNV9_XIVE_IC_SIZE            0x0000000000080000ull
 #define PNV9_XIVE_IC_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006030203100000ull)
 
 #define PNV9_XIVE_TM_SIZE            0x0000000000040000ull
 #define PNV9_XIVE_TM_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006030203180000ull)
 
+#define PNV9_PSIHB_ESB_SIZE          0x0000000000010000ull
+#define PNV9_PSIHB_ESB_BASE(chip)    PNV9_CHIP_BASE(chip, 0x00060302031c0000ull)
 
 #endif /* _PPC_PNV_H */
diff --git a/include/hw/ppc/pnv_psi.h b/include/hw/ppc/pnv_psi.h
index 585a41cd19b6..d7e1ab282cf8 100644
--- a/include/hw/ppc/pnv_psi.h
+++ b/include/hw/ppc/pnv_psi.h
@@ -21,6 +21,7 @@
 
 #include "hw/sysbus.h"
 #include "hw/ppc/xics.h"
+#include "hw/ppc/xive.h"
 
 #define TYPE_PNV_PSI "pnv-psi"
 #define PNV_PSI(obj) \
@@ -28,6 +29,9 @@
 #define TYPE_PNV8_PSI TYPE_PNV_PSI "-POWER8"
 #define PNV8_PSI(obj) \
     OBJECT_CHECK(PnvPsi, (obj), TYPE_PNV8_PSI)
+#define TYPE_PNV9_PSI TYPE_PNV_PSI "-POWER9"
+#define PNV9_PSI(obj) \
+    OBJECT_CHECK(PnvPsi, (obj), TYPE_PNV9_PSI)
 
 #define PSIHB_XSCOM_MAX         0x20
 
@@ -43,6 +47,7 @@ typedef struct PnvPsi {
 
     /* Interrupt generation */
     ICSState ics;
+    XiveSource source;
     qemu_irq *qirqs;
 
     /* Registers */
@@ -82,4 +87,23 @@ typedef enum PnvPsiIrq {
 
 void pnv_psi_irq_set(PnvPsi *psi, int irq, bool state);
 
+/* P9 PSI Interrupts */
+#define PSIHB9_IRQ_PSI          0
+#define PSIHB9_IRQ_OCC          1
+#define PSIHB9_IRQ_FSI          2
+#define PSIHB9_IRQ_LPCHC        3
+#define PSIHB9_IRQ_LOCAL_ERR    4
+#define PSIHB9_IRQ_GLOBAL_ERR   5
+#define PSIHB9_IRQ_TPM          6
+#define PSIHB9_IRQ_LPC_SIRQ0    7
+#define PSIHB9_IRQ_LPC_SIRQ1    8
+#define PSIHB9_IRQ_LPC_SIRQ2    9
+#define PSIHB9_IRQ_LPC_SIRQ3    10
+#define PSIHB9_IRQ_SBE_I2C      11
+#define PSIHB9_IRQ_DIO          12
+#define PSIHB9_IRQ_PSU          13
+#define PSIHB9_NUM_IRQS         14
+
+void pnv_psi_pic_print_info(PnvPsi *psi, Monitor *mon);
+
 #endif /* _PPC_PNV_PSI_H */
diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
index 6623ec54a7a8..403a365ed274 100644
--- a/include/hw/ppc/pnv_xscom.h
+++ b/include/hw/ppc/pnv_xscom.h
@@ -73,6 +73,9 @@ typedef struct PnvXScomInterfaceClass {
 #define PNV_XSCOM_OCC_BASE        0x0066000
 #define PNV_XSCOM_OCC_SIZE        0x6000
 
+#define PNV9_XSCOM_PSIHB_BASE     0x5012900
+#define PNV9_XSCOM_PSIHB_SIZE     0x100
+
 #define PNV9_XSCOM_XIVE_BASE      0x5013000
 #define PNV9_XSCOM_XIVE_SIZE      0x300
 
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 67d40dc3eebc..4375f97c7135 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -579,6 +579,7 @@ static void pnv_chip_power9_pic_print_info(PnvChip *chip, Monitor *mon)
     Pnv9Chip *chip9 = PNV9_CHIP(chip);
 
     pnv_xive_pic_print_info(&chip9->xive, mon);
+    pnv_psi_pic_print_info(&chip9->psi, mon);
 }
 
 static void pnv_init(MachineState *machine)
@@ -948,6 +949,11 @@ static void pnv_chip_power9_instance_init(Object *obj)
                             TYPE_PNV_XIVE, &error_abort, NULL);
     object_property_add_const_link(OBJECT(&chip9->xive), "chip", obj,
                                    &error_abort);
+
+    object_initialize_child(obj, "psi",  &chip9->psi, sizeof(chip9->psi),
+                            TYPE_PNV9_PSI, &error_abort, NULL);
+    object_property_add_const_link(OBJECT(&chip9->psi), "chip", obj,
+                                   &error_abort);
 }
 
 static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
@@ -980,6 +986,17 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
     }
     pnv_xscom_add_subregion(chip, PNV9_XSCOM_XIVE_BASE,
                             &chip9->xive.xscom_regs);
+
+    /* Processor Service Interface (PSI) Host Bridge */
+    object_property_set_int(OBJECT(&chip9->psi), PNV9_PSIHB_BASE(chip),
+                            "bar", &error_fatal);
+    object_property_set_bool(OBJECT(&chip9->psi), true, "realized", &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+    pnv_xscom_add_subregion(chip, PNV9_XSCOM_PSIHB_BASE,
+                            &chip9->psi.xscom_regs);
 }
 
 static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
index e56b455a61b1..3f995a0e0d7f 100644
--- a/hw/ppc/pnv_psi.c
+++ b/hw/ppc/pnv_psi.c
@@ -22,6 +22,7 @@
 #include "target/ppc/cpu.h"
 #include "qemu/log.h"
 #include "qapi/error.h"
+#include "monitor/monitor.h"
 
 #include "exec/address-spaces.h"
 
@@ -114,6 +115,9 @@
 #define PSIHB_BAR_MASK                  0x0003fffffff00000ull
 #define PSIHB_FSPBAR_MASK               0x0003ffff00000000ull
 
+#define PSIHB9_BAR_MASK                 0x00fffffffff00000ull
+#define PSIHB9_FSPBAR_MASK              0x00ffffff00000000ull
+
 #define PSIHB_REG(addr) (((addr) >> 3) + PSIHB_XSCOM_BAR)
 
 static void pnv_psi_set_bar(PnvPsi *psi, uint64_t bar)
@@ -531,6 +535,7 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp)
 }
 
 static const char compat_p8[] = "ibm,power8-psihb-x\0ibm,psihb-x";
+static const char compat_p9[] = "ibm,power9-psihb-x\0ibm,psihb-x";
 
 static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
 {
@@ -550,8 +555,13 @@ static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
     _FDT(fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)));
     _FDT(fdt_setprop_cell(fdt, offset, "#address-cells", 2));
     _FDT(fdt_setprop_cell(fdt, offset, "#size-cells", 1));
-    _FDT(fdt_setprop(fdt, offset, "compatible", compat_p8,
-                     sizeof(compat_p8)));
+    if (ppc->chip_type == PNV_CHIP_POWER9) {
+        _FDT(fdt_setprop(fdt, offset, "compatible", compat_p9,
+                         sizeof(compat_p9)));
+    } else {
+        _FDT(fdt_setprop(fdt, offset, "compatible", compat_p8,
+                         sizeof(compat_p8)));
+    }
     return 0;
 }
 
@@ -583,6 +593,306 @@ static const TypeInfo pnv_psi_power8_info = {
     .class_init    = pnv_psi_power8_class_init,
 };
 
+
+/* Common registers */
+
+#define PSIHB9_CR                       0x20
+#define PSIHB9_SEMR                     0x28
+
+/* P9 registers */
+
+#define PSIHB9_INTERRUPT_CONTROL        0x58
+#define   PSIHB9_IRQ_METHOD             PPC_BIT(0)
+#define   PSIHB9_IRQ_RESET              PPC_BIT(1)
+#define PSIHB9_ESB_CI_BASE              0x60
+#define   PSIHB9_ESB_CI_VALID           1
+#define PSIHB9_ESB_NOTIF_ADDR           0x68
+#define   PSIHB9_ESB_NOTIF_VALID        1
+#define PSIHB9_IVT_OFFSET               0x70
+#define   PSIHB9_IVT_OFF_SHIFT          32
+
+#define PSIHB9_IRQ_LEVEL                0x78 /* assertion */
+#define   PSIHB9_IRQ_LEVEL_PSI          PPC_BIT(0)
+#define   PSIHB9_IRQ_LEVEL_OCC          PPC_BIT(1)
+#define   PSIHB9_IRQ_LEVEL_FSI          PPC_BIT(2)
+#define   PSIHB9_IRQ_LEVEL_LPCHC        PPC_BIT(3)
+#define   PSIHB9_IRQ_LEVEL_LOCAL_ERR    PPC_BIT(4)
+#define   PSIHB9_IRQ_LEVEL_GLOBAL_ERR   PPC_BIT(5)
+#define   PSIHB9_IRQ_LEVEL_TPM          PPC_BIT(6)
+#define   PSIHB9_IRQ_LEVEL_LPC_SIRQ1    PPC_BIT(7)
+#define   PSIHB9_IRQ_LEVEL_LPC_SIRQ2    PPC_BIT(8)
+#define   PSIHB9_IRQ_LEVEL_LPC_SIRQ3    PPC_BIT(9)
+#define   PSIHB9_IRQ_LEVEL_LPC_SIRQ4    PPC_BIT(10)
+#define   PSIHB9_IRQ_LEVEL_SBE_I2C      PPC_BIT(11)
+#define   PSIHB9_IRQ_LEVEL_DIO          PPC_BIT(12)
+#define   PSIHB9_IRQ_LEVEL_PSU          PPC_BIT(13)
+#define   PSIHB9_IRQ_LEVEL_I2C_C        PPC_BIT(14)
+#define   PSIHB9_IRQ_LEVEL_I2C_D        PPC_BIT(15)
+#define   PSIHB9_IRQ_LEVEL_I2C_E        PPC_BIT(16)
+#define   PSIHB9_IRQ_LEVEL_SBE          PPC_BIT(19)
+
+#define PSIHB9_IRQ_STAT                 0x80 /* P bit */
+#define   PSIHB9_IRQ_STAT_PSI           PPC_BIT(0)
+#define   PSIHB9_IRQ_STAT_OCC           PPC_BIT(1)
+#define   PSIHB9_IRQ_STAT_FSI           PPC_BIT(2)
+#define   PSIHB9_IRQ_STAT_LPCHC         PPC_BIT(3)
+#define   PSIHB9_IRQ_STAT_LOCAL_ERR     PPC_BIT(4)
+#define   PSIHB9_IRQ_STAT_GLOBAL_ERR    PPC_BIT(5)
+#define   PSIHB9_IRQ_STAT_TPM           PPC_BIT(6)
+#define   PSIHB9_IRQ_STAT_LPC_SIRQ1     PPC_BIT(7)
+#define   PSIHB9_IRQ_STAT_LPC_SIRQ2     PPC_BIT(8)
+#define   PSIHB9_IRQ_STAT_LPC_SIRQ3     PPC_BIT(9)
+#define   PSIHB9_IRQ_STAT_LPC_SIRQ4     PPC_BIT(10)
+#define   PSIHB9_IRQ_STAT_SBE_I2C       PPC_BIT(11)
+#define   PSIHB9_IRQ_STAT_DIO           PPC_BIT(12)
+#define   PSIHB9_IRQ_STAT_PSU           PPC_BIT(13)
+
+static void pnv_psi_notify(XiveNotifier *xf, uint32_t srcno)
+{
+    PnvPsi *psi = PNV9_PSI(xf);
+    uint64_t notif_port = psi->regs[PSIHB_REG(PSIHB9_ESB_NOTIF_ADDR)];
+    bool valid = notif_port & PSIHB9_ESB_NOTIF_VALID;
+    uint64_t notify_addr = notif_port & ~PSIHB9_ESB_NOTIF_VALID;
+
+    uint32_t offset =
+        (psi->regs[PSIHB_REG(PSIHB9_IVT_OFFSET)] >> PSIHB9_IVT_OFF_SHIFT);
+    uint64_t lisn = cpu_to_be64(offset + srcno);
+
+    if (valid) {
+        cpu_physical_memory_write(notify_addr, &lisn, sizeof(lisn));
+    }
+}
+
+static uint64_t pnv_psi_p9_mmio_read(void *opaque, hwaddr addr, unsigned size)
+{
+    PnvPsi *psi = PNV9_PSI(opaque);
+    uint32_t reg = PSIHB_REG(addr);
+    uint64_t val = -1;
+
+    switch (addr) {
+    case PSIHB9_CR:
+    case PSIHB9_SEMR:
+        /* FSP stuff */
+    case PSIHB9_INTERRUPT_CONTROL:
+    case PSIHB9_ESB_CI_BASE:
+    case PSIHB9_ESB_NOTIF_ADDR:
+    case PSIHB9_IVT_OFFSET:
+        val = psi->regs[reg];
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "PSI: read at 0x%" PRIx64 "\n", addr);
+    }
+
+    return val;
+}
+
+static void pnv_psi_p9_mmio_write(void *opaque, hwaddr addr,
+                                  uint64_t val, unsigned size)
+{
+    PnvPsi *psi = PNV9_PSI(opaque);
+    uint32_t reg = PSIHB_REG(addr);
+    MemoryRegion *sysmem = get_system_memory();
+
+    switch (addr) {
+    case PSIHB9_CR:
+    case PSIHB9_SEMR:
+        /* FSP stuff */
+        break;
+    case PSIHB9_INTERRUPT_CONTROL:
+        if (val & PSIHB9_IRQ_RESET) {
+            device_reset(DEVICE(&psi->source));
+        }
+        psi->regs[reg] = val;
+        break;
+
+    case PSIHB9_ESB_CI_BASE:
+        if (!(val & PSIHB9_ESB_CI_VALID)) {
+            if (psi->regs[reg] & PSIHB9_ESB_CI_VALID) {
+                memory_region_del_subregion(sysmem, &psi->source.esb_mmio);
+            }
+        } else {
+            if (!(psi->regs[reg] & PSIHB9_ESB_CI_VALID)) {
+                memory_region_add_subregion(sysmem,
+                                        val & ~PSIHB9_ESB_CI_VALID,
+                                        &psi->source.esb_mmio);
+            }
+        }
+        psi->regs[reg] = val;
+        break;
+
+    case PSIHB9_ESB_NOTIF_ADDR:
+        psi->regs[reg] = val;
+        break;
+    case PSIHB9_IVT_OFFSET:
+        psi->regs[reg] = val;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "PSI: write at 0x%" PRIx64 "\n", addr);
+    }
+}
+
+static const MemoryRegionOps pnv_psi_p9_mmio_ops = {
+    .read = pnv_psi_p9_mmio_read,
+    .write = pnv_psi_p9_mmio_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .valid = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    },
+};
+
+static uint64_t pnv_psi_p9_xscom_read(void *opaque, hwaddr addr, unsigned size)
+{
+    /* No read are expected */
+    qemu_log_mask(LOG_GUEST_ERROR, "PSI: xscom read at 0x%" PRIx64 "\n", addr);
+    return -1;
+}
+
+static void pnv_psi_p9_xscom_write(void *opaque, hwaddr addr,
+                                uint64_t val, unsigned size)
+{
+    PnvPsi *psi = PNV9_PSI(opaque);
+
+    /* XSCOM is only used to set the PSIHB MMIO region */
+    switch (addr >> 3) {
+    case PSIHB_XSCOM_BAR:
+        pnv_psi_set_bar(psi, val);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "PSI: xscom write at 0x%" PRIx64 "\n",
+                      addr);
+    }
+}
+
+static const MemoryRegionOps pnv_psi_p9_xscom_ops = {
+    .read = pnv_psi_p9_xscom_read,
+    .write = pnv_psi_p9_xscom_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .valid = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    }
+};
+
+static void pnv_psi_power9_irq_set(PnvPsi *psi, int irq, bool state)
+{
+    uint32_t irq_method = psi->regs[PSIHB_REG(PSIHB9_INTERRUPT_CONTROL)];
+
+    if (irq > PSIHB9_NUM_IRQS) {
+        qemu_log_mask(LOG_GUEST_ERROR, "PSI: Unsupported irq %d\n", irq);
+        return;
+    }
+
+    if (irq_method & PSIHB9_IRQ_METHOD) {
+        qemu_log_mask(LOG_GUEST_ERROR, "PSI: LSI IRQ method no supported\n");
+        return;
+    }
+
+    /* Update LSI levels */
+    if (state) {
+        psi->regs[PSIHB_REG(PSIHB9_IRQ_LEVEL)] |= PPC_BIT(irq);
+    } else {
+        psi->regs[PSIHB_REG(PSIHB9_IRQ_LEVEL)] &= ~PPC_BIT(irq);
+    }
+
+    qemu_set_irq(psi->qirqs[irq], state);
+}
+
+static void pnv_psi_power9_reset(void *dev)
+{
+    PnvPsi *psi = PNV9_PSI(dev);
+
+    pnv_psi_reset(dev);
+
+    if (memory_region_is_mapped(&psi->source.esb_mmio)) {
+        memory_region_del_subregion(get_system_memory(), &psi->source.esb_mmio);
+    }
+}
+
+static void pnv_psi_power9_instance_init(Object *obj)
+{
+    PnvPsi *psi = PNV9_PSI(obj);
+
+    object_initialize_child(obj, "source", &psi->source, sizeof(psi->source),
+                            TYPE_XIVE_SOURCE, &error_abort, NULL);
+}
+
+static void pnv_psi_power9_realize(DeviceState *dev, Error **errp)
+{
+    PnvPsi *psi = PNV9_PSI(dev);
+    XiveSource *xsrc = &psi->source;
+    Error *local_err = NULL;
+    int i;
+
+    /* This is the only device with 4k ESB pages */
+    object_property_set_int(OBJECT(xsrc), XIVE_ESB_4K, "shift",
+                            &error_fatal);
+    object_property_set_int(OBJECT(xsrc), PSIHB9_NUM_IRQS, "nr-irqs",
+                            &error_fatal);
+    object_property_add_const_link(OBJECT(xsrc), "xive", OBJECT(psi),
+                                   &error_fatal);
+    object_property_set_bool(OBJECT(xsrc), true, "realized", &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    for (i = 0; i < xsrc->nr_irqs; i++) {
+        xive_source_irq_set_lsi(xsrc, i);
+    }
+
+    psi->qirqs = qemu_allocate_irqs(xive_source_set_irq, xsrc, xsrc->nr_irqs);
+
+    /* XSCOM region for PSI registers */
+    pnv_xscom_region_init(&psi->xscom_regs, OBJECT(dev), &pnv_psi_p9_xscom_ops,
+                psi, "xscom-psi", PNV9_XSCOM_PSIHB_SIZE);
+
+    /* MMIO region for PSI registers */
+    memory_region_init_io(&psi->regs_mr, OBJECT(dev), &pnv_psi_p9_mmio_ops, psi,
+                          "psihb", PNV9_PSIHB_SIZE);
+
+    pnv_psi_set_bar(psi, psi->bar | PSIHB_BAR_EN);
+
+    qemu_register_reset(pnv_psi_power9_reset, dev);
+}
+
+static void pnv_psi_power9_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PnvPsiClass *ppc = PNV_PSI_CLASS(klass);
+    XiveNotifierClass *xfc = XIVE_NOTIFIER_CLASS(klass);
+
+    dc->desc    = "PowerNV PSI Controller POWER9";
+    dc->realize = pnv_psi_power9_realize;
+
+    ppc->chip_type  = PNV_CHIP_POWER9;
+    ppc->xscom_pcba = PNV9_XSCOM_PSIHB_BASE;
+    ppc->xscom_size = PNV9_XSCOM_PSIHB_SIZE;
+    ppc->bar_mask   = PSIHB9_BAR_MASK;
+    ppc->irq_set    = pnv_psi_power9_irq_set;
+
+    xfc->notify      = pnv_psi_notify;
+}
+
+static const TypeInfo pnv_psi_power9_info = {
+    .name          = TYPE_PNV9_PSI,
+    .parent        = TYPE_PNV_PSI,
+    .instance_init = pnv_psi_power9_instance_init,
+    .class_init    = pnv_psi_power9_class_init,
+    .interfaces = (InterfaceInfo[]) {
+            { TYPE_XIVE_NOTIFIER },
+            { },
+    },
+};
+
 static void pnv_psi_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -611,6 +921,17 @@ static void pnv_psi_register_types(void)
 {
     type_register_static(&pnv_psi_info);
     type_register_static(&pnv_psi_power8_info);
+    type_register_static(&pnv_psi_power9_info);
 }
 
 type_init(pnv_psi_register_types);
+
+void pnv_psi_pic_print_info(PnvPsi *psi, Monitor *mon)
+{
+    uint32_t offset =
+        (psi->regs[PSIHB_REG(PSIHB9_IVT_OFFSET)] >> PSIHB9_IVT_OFF_SHIFT);
+
+    monitor_printf(mon, "PSIHB Source %08x .. %08x\n",
+                  offset, offset + psi->source.nr_irqs - 1);
+    xive_source_pic_print_info(&psi->source, offset, mon);
+}
-- 
2.20.1

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

* [Qemu-devel] [PATCH 16/27] ppc/pnv: lpc: fix OPB address ranges
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (14 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 15/27] ppc/pnv: add a PSI bridge model for POWER9 Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-07  4:11   ` David Gibson
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 17/27] ppc/pnv: add a LPC Controller model class Cédric Le Goater
                   ` (10 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/ppc/pnv_lpc.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c
index 9b18ce55e391..547be609cafe 100644
--- a/hw/ppc/pnv_lpc.c
+++ b/hw/ppc/pnv_lpc.c
@@ -89,10 +89,11 @@ enum {
 #define LPC_FW_OPB_SIZE         0x10000000
 
 #define LPC_OPB_REGS_OPB_ADDR   0xc0010000
-#define LPC_OPB_REGS_OPB_SIZE   0x00002000
+#define LPC_OPB_REGS_OPB_SIZE   0x00000060
+#define LPC_OPB_REGS_OPBA_ADDR  0xc0011000
+#define LPC_OPB_REGS_OPBA_SIZE  0x00000008
 #define LPC_HC_REGS_OPB_ADDR    0xc0012000
-#define LPC_HC_REGS_OPB_SIZE    0x00001000
-
+#define LPC_HC_REGS_OPB_SIZE    0x00000100
 
 static int pnv_lpc_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
 {
-- 
2.20.1

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

* [Qemu-devel] [PATCH 17/27] ppc/pnv: add a LPC Controller model class
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (15 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 16/27] ppc/pnv: lpc: fix OPB address ranges Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-07  4:12   ` David Gibson
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 18/27] ppc/pnv: add a LPC Controller model for POWER9 Cédric Le Goater
                   ` (9 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

It will ease the introduction of the LPC Controller model for POWER9.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/ppc/pnv_lpc.h | 16 ++++++++
 hw/ppc/pnv.c             |  2 +-
 hw/ppc/pnv_lpc.c         | 85 ++++++++++++++++++++++++++++------------
 3 files changed, 78 insertions(+), 25 deletions(-)

diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h
index d657489b07ce..242baecdcb93 100644
--- a/include/hw/ppc/pnv_lpc.h
+++ b/include/hw/ppc/pnv_lpc.h
@@ -24,6 +24,9 @@
 #define TYPE_PNV_LPC "pnv-lpc"
 #define PNV_LPC(obj) \
      OBJECT_CHECK(PnvLpcController, (obj), TYPE_PNV_LPC)
+#define TYPE_PNV8_LPC TYPE_PNV_LPC "-POWER8"
+#define PNV8_LPC(obj) \
+    OBJECT_CHECK(PnvLpc, (obj), TYPE_PNV8_LPC)
 
 typedef struct PnvLpcController {
     DeviceState parent;
@@ -70,6 +73,19 @@ typedef struct PnvLpcController {
     PnvPsi *psi;
 } PnvLpcController;
 
+#define PNV_LPC_CLASS(klass) \
+     OBJECT_CLASS_CHECK(PnvLpcClass, (klass), TYPE_PNV_LPC)
+#define PNV_LPC_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(PnvLpcClass, (obj), TYPE_PNV_LPC)
+
+typedef struct PnvLpcClass {
+    DeviceClass parent_class;
+
+    int psi_irq;
+
+    DeviceRealize parent_realize;
+} PnvLpcClass;
+
 ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp);
 
 #endif /* _PPC_PNV_LPC_H */
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 4375f97c7135..7176e1b68d0e 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -794,7 +794,7 @@ static void pnv_chip_power8_instance_init(Object *obj)
                                    OBJECT(qdev_get_machine()), &error_abort);
 
     object_initialize_child(obj, "lpc",  &chip8->lpc, sizeof(chip8->lpc),
-                            TYPE_PNV_LPC, &error_abort, NULL);
+                            TYPE_PNV8_LPC, &error_abort, NULL);
     object_property_add_const_link(OBJECT(&chip8->lpc), "psi",
                                    OBJECT(&chip8->psi), &error_abort);
 
diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c
index 547be609cafe..3c509a30a0af 100644
--- a/hw/ppc/pnv_lpc.c
+++ b/hw/ppc/pnv_lpc.c
@@ -245,6 +245,7 @@ static const MemoryRegionOps pnv_lpc_xscom_ops = {
 static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
 {
     bool lpc_to_opb_irq = false;
+    PnvLpcClass *plc = PNV_LPC_GET_CLASS(lpc);
 
     /* Update LPC controller to OPB line */
     if (lpc->lpc_hc_irqser_ctrl & LPC_HC_IRQSER_EN) {
@@ -267,7 +268,7 @@ static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
     lpc->opb_irq_stat |= lpc->opb_irq_input & lpc->opb_irq_mask;
 
     /* Reflect the interrupt */
-    pnv_psi_irq_set(lpc->psi, PSIHB_IRQ_LPC_I2C, lpc->opb_irq_stat != 0);
+    pnv_psi_irq_set(lpc->psi, plc->psi_irq, lpc->opb_irq_stat != 0);
 }
 
 static uint64_t lpc_hc_read(void *opaque, hwaddr addr, unsigned size)
@@ -419,11 +420,65 @@ static const MemoryRegionOps opb_master_ops = {
     },
 };
 
+static void pnv_lpc_power8_realize(DeviceState *dev, Error **errp)
+{
+    PnvLpcController *lpc = PNV_LPC(dev);
+    PnvLpcClass *plc = PNV_LPC_GET_CLASS(dev);
+    Error *local_err = NULL;
+
+    plc->parent_realize(dev, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    /* P8 uses a XSCOM region for LPC registers */
+    pnv_xscom_region_init(&lpc->xscom_regs, OBJECT(lpc),
+                          &pnv_lpc_xscom_ops, lpc, "xscom-lpc",
+                          PNV_XSCOM_LPC_SIZE);
+}
+
+static void pnv_lpc_power8_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
+    PnvLpcClass *plc = PNV_LPC_CLASS(klass);
+
+    dc->desc = "PowerNV LPC Controller POWER8";
+
+    xdc->dt_xscom = pnv_lpc_dt_xscom;
+
+    plc->psi_irq = PSIHB_IRQ_LPC_I2C;
+
+    device_class_set_parent_realize(dc, pnv_lpc_power8_realize,
+                                    &plc->parent_realize);
+}
+
+static const TypeInfo pnv_lpc_power8_info = {
+    .name          = TYPE_PNV8_LPC,
+    .parent        = TYPE_PNV_LPC,
+    .instance_size = sizeof(PnvLpcController),
+    .class_init    = pnv_lpc_power8_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_PNV_XSCOM_INTERFACE },
+        { }
+    }
+};
+
 static void pnv_lpc_realize(DeviceState *dev, Error **errp)
 {
     PnvLpcController *lpc = PNV_LPC(dev);
     Object *obj;
-    Error *error = NULL;
+    Error *local_err = NULL;
+
+    obj = object_property_get_link(OBJECT(dev), "psi", &local_err);
+    if (!obj) {
+        error_propagate(errp, local_err);
+        error_prepend(errp, "required link 'psi' not found: ");
+        return;
+    }
+    /* The LPC controller needs PSI to generate interrupts  */
+    lpc->psi = PNV_PSI(obj);
 
     /* Reg inits */
     lpc->lpc_hc_fw_rd_acc_size = LPC_HC_FW_RD_4B;
@@ -463,46 +518,28 @@ static void pnv_lpc_realize(DeviceState *dev, Error **errp)
                           "lpc-hc", LPC_HC_REGS_OPB_SIZE);
     memory_region_add_subregion(&lpc->opb_mr, LPC_HC_REGS_OPB_ADDR,
                                 &lpc->lpc_hc_regs);
-
-    /* XScom region for LPC registers */
-    pnv_xscom_region_init(&lpc->xscom_regs, OBJECT(dev),
-                          &pnv_lpc_xscom_ops, lpc, "xscom-lpc",
-                          PNV_XSCOM_LPC_SIZE);
-
-    /* get PSI object from chip */
-    obj = object_property_get_link(OBJECT(dev), "psi", &error);
-    if (!obj) {
-        error_setg(errp, "%s: required link 'psi' not found: %s",
-                   __func__, error_get_pretty(error));
-        return;
-    }
-    lpc->psi = PNV_PSI(obj);
 }
 
 static void pnv_lpc_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
-
-    xdc->dt_xscom = pnv_lpc_dt_xscom;
 
     dc->realize = pnv_lpc_realize;
+    dc->desc = "PowerNV LPC Controller";
 }
 
 static const TypeInfo pnv_lpc_info = {
     .name          = TYPE_PNV_LPC,
     .parent        = TYPE_DEVICE,
-    .instance_size = sizeof(PnvLpcController),
     .class_init    = pnv_lpc_class_init,
-    .interfaces = (InterfaceInfo[]) {
-        { TYPE_PNV_XSCOM_INTERFACE },
-        { }
-    }
+    .class_size    = sizeof(PnvLpcClass),
+    .abstract      = true,
 };
 
 static void pnv_lpc_register_types(void)
 {
     type_register_static(&pnv_lpc_info);
+    type_register_static(&pnv_lpc_power8_info);
 }
 
 type_init(pnv_lpc_register_types)
-- 
2.20.1

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

* [Qemu-devel] [PATCH 18/27] ppc/pnv: add a LPC Controller model for POWER9
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (16 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 17/27] ppc/pnv: add a LPC Controller model class Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-07  4:18   ` David Gibson
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 19/27] ppc/pnv: add SerIRQ routing registers Cédric Le Goater
                   ` (8 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

The LPC Controller on POWER9 is very similar to the one found on
POWER8 but accesses are now done via on MMIOs, without the XSCOM and
ECCB logic. The device tree is populated differently so we add a
specific POWER9 routine for the purpose.

SerIRQ routing is yet to be done.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/ppc/pnv.h     |   4 +
 include/hw/ppc/pnv_lpc.h |  10 ++
 hw/ppc/pnv.c             |  29 +++++-
 hw/ppc/pnv_lpc.c         | 200 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 240 insertions(+), 3 deletions(-)

diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index 57d0337219be..2d68aabc212f 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -85,6 +85,7 @@ typedef struct Pnv9Chip {
     /*< public >*/
     PnvXive      xive;
     PnvPsi       psi;
+    PnvLpcController lpc;
 } Pnv9Chip;
 
 typedef struct PnvChipClass {
@@ -232,6 +233,9 @@ void pnv_bmc_powerdown(IPMIBmc *bmc);
 #define PNV9_XIVE_PC_SIZE            0x0000001000000000ull
 #define PNV9_XIVE_PC_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006018000000000ull)
 
+#define PNV9_LPCM_SIZE               0x0000000100000000ull
+#define PNV9_LPCM_BASE(chip)         PNV9_CHIP_BASE(chip, 0x0006030000000000ull)
+
 #define PNV9_PSIHB_SIZE              0x0000000000100000ull
 #define PNV9_PSIHB_BASE(chip)        PNV9_CHIP_BASE(chip, 0x0006030203000000ull)
 
diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h
index 242baecdcb93..24fe23f0f63b 100644
--- a/include/hw/ppc/pnv_lpc.h
+++ b/include/hw/ppc/pnv_lpc.h
@@ -28,6 +28,10 @@
 #define PNV8_LPC(obj) \
     OBJECT_CHECK(PnvLpc, (obj), TYPE_PNV8_LPC)
 
+#define TYPE_PNV9_LPC TYPE_PNV_LPC "-POWER9"
+#define PNV9_LPC(obj) \
+    OBJECT_CHECK(PnvLpc, (obj), TYPE_PNV9_LPC)
+
 typedef struct PnvLpcController {
     DeviceState parent;
 
@@ -86,6 +90,12 @@ typedef struct PnvLpcClass {
     DeviceRealize parent_realize;
 } PnvLpcClass;
 
+/*
+ * Old compilers error on typdef forward declarations. Keep them happy.
+ */
+struct PnvChip;
+
 ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp);
+int pnv_dt_lpc(struct PnvChip *chip, void *fdt, int root_offset);
 
 #endif /* _PPC_PNV_LPC_H */
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 7176e1b68d0e..895be470af67 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -306,6 +306,8 @@ static void pnv_chip_power9_dt_populate(PnvChip *chip, void *fdt)
     if (chip->ram_size) {
         pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
     }
+
+    pnv_dt_lpc(chip, fdt, 0);
 }
 
 static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
@@ -422,8 +424,14 @@ static int pnv_chip_isa_offset(PnvChip *chip, void *fdt)
     char *name;
     int offset;
 
-    name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
-                           (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE);
+    if (pnv_chip_is_power9(chip)) {
+        name = g_strdup_printf("/lpcm-opb@%" PRIx64 "/lpc@0",
+                               (uint64_t) PNV9_LPCM_BASE(chip));
+    } else {
+        name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
+                               (uint64_t) PNV_XSCOM_BASE(chip),
+                               PNV_XSCOM_LPC_BASE);
+    }
     offset = fdt_path_offset(fdt, name);
     g_free(name);
     return offset;
@@ -559,7 +567,8 @@ static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp)
 
 static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp)
 {
-    return NULL;
+    Pnv9Chip *chip9 = PNV9_CHIP(chip);
+    return pnv_lpc_isa_create(&chip9->lpc, false, errp);
 }
 
 static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
@@ -954,6 +963,11 @@ static void pnv_chip_power9_instance_init(Object *obj)
                             TYPE_PNV9_PSI, &error_abort, NULL);
     object_property_add_const_link(OBJECT(&chip9->psi), "chip", obj,
                                    &error_abort);
+
+    object_initialize_child(obj, "lpc",  &chip9->lpc, sizeof(chip9->lpc),
+                            TYPE_PNV9_LPC, &error_abort, NULL);
+    object_property_add_const_link(OBJECT(&chip9->lpc), "psi",
+                                   OBJECT(&chip9->psi), &error_abort);
 }
 
 static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
@@ -997,6 +1011,15 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
     }
     pnv_xscom_add_subregion(chip, PNV9_XSCOM_PSIHB_BASE,
                             &chip9->psi.xscom_regs);
+
+    /* LPC */
+    object_property_set_bool(OBJECT(&chip9->lpc), true, "realized", &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+    memory_region_add_subregion(get_system_memory(), PNV9_LPCM_BASE(chip),
+                                &chip9->lpc.xscom_regs);
 }
 
 static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c
index 3c509a30a0af..6df694e0abc1 100644
--- a/hw/ppc/pnv_lpc.c
+++ b/hw/ppc/pnv_lpc.c
@@ -118,6 +118,100 @@ static int pnv_lpc_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
     return 0;
 }
 
+/* POWER9 only */
+int pnv_dt_lpc(PnvChip *chip, void *fdt, int root_offset)
+{
+    const char compat[] = "ibm,power9-lpcm-opb\0simple-bus";
+    const char lpc_compat[] = "ibm,power9-lpc\0ibm,lpc";
+    char *name;
+    int offset, lpcm_offset;
+    uint64_t lpcm_addr = PNV9_LPCM_BASE(chip);
+    uint32_t opb_ranges[8] = { 0,
+                               cpu_to_be32(lpcm_addr >> 32),
+                               cpu_to_be32((uint32_t)lpcm_addr),
+                               cpu_to_be32(PNV9_LPCM_SIZE / 2),
+                               cpu_to_be32(PNV9_LPCM_SIZE / 2),
+                               cpu_to_be32(lpcm_addr >> 32),
+                               cpu_to_be32(PNV9_LPCM_SIZE / 2),
+                               cpu_to_be32(PNV9_LPCM_SIZE / 2),
+    };
+    uint32_t opb_reg[4] = { cpu_to_be32(lpcm_addr >> 32),
+                            cpu_to_be32((uint32_t)lpcm_addr),
+                            cpu_to_be32(PNV9_LPCM_SIZE >> 32),
+                            cpu_to_be32((uint32_t)PNV9_LPCM_SIZE),
+    };
+    uint32_t reg[2];
+
+    /*
+     * OPB bus
+     */
+    name = g_strdup_printf("lpcm-opb@%"PRIx64, lpcm_addr);
+    lpcm_offset = fdt_add_subnode(fdt, root_offset, name);
+    _FDT(lpcm_offset);
+    g_free(name);
+
+    _FDT((fdt_setprop(fdt, lpcm_offset, "reg", opb_reg, sizeof(opb_reg))));
+    _FDT((fdt_setprop_cell(fdt, lpcm_offset, "#address-cells", 1)));
+    _FDT((fdt_setprop_cell(fdt, lpcm_offset, "#size-cells", 1)));
+    _FDT((fdt_setprop(fdt, lpcm_offset, "compatible", compat, sizeof(compat))));
+    _FDT((fdt_setprop_cell(fdt, lpcm_offset, "ibm,chip-id", chip->chip_id)));
+    _FDT((fdt_setprop(fdt, lpcm_offset, "ranges", opb_ranges,
+                      sizeof(opb_ranges))));
+
+    /*
+     * OPB Master registers
+     */
+    name = g_strdup_printf("opb-master@%x", LPC_OPB_REGS_OPB_ADDR);
+    offset = fdt_add_subnode(fdt, lpcm_offset, name);
+    _FDT(offset);
+    g_free(name);
+
+    reg[0] = cpu_to_be32(LPC_OPB_REGS_OPB_ADDR);
+    reg[1] = cpu_to_be32(LPC_OPB_REGS_OPB_SIZE);
+    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
+    _FDT((fdt_setprop_string(fdt, offset, "compatible",
+                             "ibm,power9-lpcm-opb-master")));
+
+    /*
+     * OPB arbitrer registers
+     */
+    name = g_strdup_printf("opb-arbitrer@%x", LPC_OPB_REGS_OPBA_ADDR);
+    offset = fdt_add_subnode(fdt, lpcm_offset, name);
+    _FDT(offset);
+    g_free(name);
+
+    reg[0] = cpu_to_be32(LPC_OPB_REGS_OPBA_ADDR);
+    reg[1] = cpu_to_be32(LPC_OPB_REGS_OPBA_SIZE);
+    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
+    _FDT((fdt_setprop_string(fdt, offset, "compatible",
+                             "ibm,power9-lpcm-opb-arbiter")));
+
+    /*
+     * LPC Host Controller registers
+     */
+    name = g_strdup_printf("lpc-controller@%x", LPC_HC_REGS_OPB_ADDR);
+    offset = fdt_add_subnode(fdt, lpcm_offset, name);
+    _FDT(offset);
+    g_free(name);
+
+    reg[0] = cpu_to_be32(LPC_HC_REGS_OPB_ADDR);
+    reg[1] = cpu_to_be32(LPC_HC_REGS_OPB_SIZE);
+    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
+    _FDT((fdt_setprop_string(fdt, offset, "compatible",
+                             "ibm,power9-lpc-controller")));
+
+    name = g_strdup_printf("lpc@0");
+    offset = fdt_add_subnode(fdt, lpcm_offset, name);
+    _FDT(offset);
+    g_free(name);
+    _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 2)));
+    _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 1)));
+    _FDT((fdt_setprop(fdt, offset, "compatible", lpc_compat,
+                      sizeof(lpc_compat))));
+
+    return 0;
+}
+
 /*
  * These read/write handlers of the OPB address space should be common
  * with the P9 LPC Controller which uses direct MMIOs.
@@ -242,6 +336,74 @@ static const MemoryRegionOps pnv_lpc_xscom_ops = {
     .endianness = DEVICE_BIG_ENDIAN,
 };
 
+static uint64_t pnv_lpc_mmio_read(void *opaque, hwaddr addr, unsigned size)
+{
+    PnvLpcController *lpc = PNV_LPC(opaque);
+    uint64_t val = 0;
+    uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK;
+    MemTxResult result;
+
+    switch (size) {
+    case 4:
+        val = address_space_ldl(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED,
+                                &result);
+        break;
+    case 1:
+        val = address_space_ldub(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED,
+                                 &result);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%"
+                      HWADDR_PRIx " invalid size %d\n", addr, size);
+        return 0;
+    }
+
+    if (result != MEMTX_OK) {
+        qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%"
+                      HWADDR_PRIx "\n", addr);
+    }
+
+    return val;
+}
+
+static void pnv_lpc_mmio_write(void *opaque, hwaddr addr,
+                                uint64_t val, unsigned size)
+{
+    PnvLpcController *lpc = PNV_LPC(opaque);
+    uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK;
+    MemTxResult result;
+
+    switch (size) {
+    case 4:
+        address_space_stl(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED,
+                          &result);
+         break;
+    case 1:
+        address_space_stb(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED,
+                          &result);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%"
+                      HWADDR_PRIx " invalid size %d\n", addr, size);
+        return;
+    }
+
+    if (result != MEMTX_OK) {
+        qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%"
+                      HWADDR_PRIx "\n", addr);
+    }
+}
+
+static const MemoryRegionOps pnv_lpc_mmio_ops = {
+    .read = pnv_lpc_mmio_read,
+    .write = pnv_lpc_mmio_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_BIG_ENDIAN,
+};
+
 static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
 {
     bool lpc_to_opb_irq = false;
@@ -465,6 +627,43 @@ static const TypeInfo pnv_lpc_power8_info = {
     }
 };
 
+static void pnv_lpc_power9_realize(DeviceState *dev, Error **errp)
+{
+    PnvLpcController *lpc = PNV_LPC(dev);
+    PnvLpcClass *plc = PNV_LPC_GET_CLASS(dev);
+    Error *local_err = NULL;
+
+    plc->parent_realize(dev, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    /* P9 uses a MMIO region */
+    memory_region_init_io(&lpc->xscom_regs, OBJECT(lpc), &pnv_lpc_mmio_ops,
+                          lpc, "lpcm", PNV9_LPCM_SIZE);
+}
+
+static void pnv_lpc_power9_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PnvLpcClass *plc = PNV_LPC_CLASS(klass);
+
+    dc->desc = "PowerNV LPC Controller POWER9";
+
+    plc->psi_irq = PSIHB9_IRQ_LPCHC;
+
+    device_class_set_parent_realize(dc, pnv_lpc_power9_realize,
+                                    &plc->parent_realize);
+}
+
+static const TypeInfo pnv_lpc_power9_info = {
+    .name          = TYPE_PNV9_LPC,
+    .parent        = TYPE_PNV_LPC,
+    .instance_size = sizeof(PnvLpcController),
+    .class_init    = pnv_lpc_power9_class_init,
+};
+
 static void pnv_lpc_realize(DeviceState *dev, Error **errp)
 {
     PnvLpcController *lpc = PNV_LPC(dev);
@@ -540,6 +739,7 @@ static void pnv_lpc_register_types(void)
 {
     type_register_static(&pnv_lpc_info);
     type_register_static(&pnv_lpc_power8_info);
+    type_register_static(&pnv_lpc_power9_info);
 }
 
 type_init(pnv_lpc_register_types)
-- 
2.20.1

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

* [Qemu-devel] [PATCH 19/27] ppc/pnv: add SerIRQ routing registers
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (17 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 18/27] ppc/pnv: add a LPC Controller model for POWER9 Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 20/27] ppc/pnv: add a OCC model class Cédric Le Goater
                   ` (7 subsequent siblings)
  26 siblings, 0 replies; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

This is just a simple reminder that SerIRQ routing should be
addressed.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/ppc/pnv_lpc.h |  2 ++
 hw/ppc/pnv_lpc.c         | 14 ++++++++++++++
 2 files changed, 16 insertions(+)

diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h
index 24fe23f0f63b..ede7802f3420 100644
--- a/include/hw/ppc/pnv_lpc.h
+++ b/include/hw/ppc/pnv_lpc.h
@@ -57,6 +57,8 @@ typedef struct PnvLpcController {
     MemoryRegion opb_master_regs;
 
     /* OPB Master LS registers */
+    uint32_t opb_irq_route0;
+    uint32_t opb_irq_route1;
     uint32_t opb_irq_stat;
     uint32_t opb_irq_mask;
     uint32_t opb_irq_pol;
diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c
index 6df694e0abc1..641e2046db92 100644
--- a/hw/ppc/pnv_lpc.c
+++ b/hw/ppc/pnv_lpc.c
@@ -39,6 +39,8 @@ enum {
 };
 
 /* OPB Master LS registers */
+#define OPB_MASTER_LS_ROUTE0    0x8
+#define OPB_MASTER_LS_ROUTE1    0xC
 #define OPB_MASTER_LS_IRQ_STAT  0x50
 #define   OPB_MASTER_IRQ_LPC            0x00000800
 #define OPB_MASTER_LS_IRQ_MASK  0x54
@@ -521,6 +523,12 @@ static uint64_t opb_master_read(void *opaque, hwaddr addr, unsigned size)
     uint64_t val = 0xfffffffffffffffful;
 
     switch (addr) {
+    case OPB_MASTER_LS_ROUTE0: /* TODO */
+        val = lpc->opb_irq_route0;
+        break;
+    case OPB_MASTER_LS_ROUTE1: /* TODO */
+        val = lpc->opb_irq_route1;
+        break;
     case OPB_MASTER_LS_IRQ_STAT:
         val = lpc->opb_irq_stat;
         break;
@@ -547,6 +555,12 @@ static void opb_master_write(void *opaque, hwaddr addr,
     PnvLpcController *lpc = opaque;
 
     switch (addr) {
+    case OPB_MASTER_LS_ROUTE0: /* TODO */
+        lpc->opb_irq_route0 = val;
+        break;
+    case OPB_MASTER_LS_ROUTE1: /* TODO */
+        lpc->opb_irq_route1 = val;
+        break;
     case OPB_MASTER_LS_IRQ_STAT:
         lpc->opb_irq_stat &= ~val;
         pnv_lpc_eval_irqs(lpc);
-- 
2.20.1

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

* [Qemu-devel] [PATCH 20/27] ppc/pnv: add a OCC model class
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (18 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 19/27] ppc/pnv: add SerIRQ routing registers Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-07  4:26   ` David Gibson
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 21/27] ppc/pnv: add a OCC model for POWER9 Cédric Le Goater
                   ` (6 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

It will ease the introduction of the OCC model for POWER9.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/ppc/pnv_occ.h | 14 ++++++++++++++
 hw/ppc/pnv.c             |  2 +-
 hw/ppc/pnv_occ.c         | 23 ++++++++++++++++++++---
 3 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/include/hw/ppc/pnv_occ.h b/include/hw/ppc/pnv_occ.h
index 82f299dc76ff..ce2631e21f5e 100644
--- a/include/hw/ppc/pnv_occ.h
+++ b/include/hw/ppc/pnv_occ.h
@@ -23,6 +23,9 @@
 
 #define TYPE_PNV_OCC "pnv-occ"
 #define PNV_OCC(obj) OBJECT_CHECK(PnvOCC, (obj), TYPE_PNV_OCC)
+#define TYPE_PNV8_OCC TYPE_PNV_OCC "-POWER8"
+#define PNV8_OCC(obj) \
+    OBJECT_CHECK(PnvOCC, (obj), TYPE_PNV8_OCC)
 
 typedef struct PnvOCC {
     DeviceState xd;
@@ -35,4 +38,15 @@ typedef struct PnvOCC {
     MemoryRegion xscom_regs;
 } PnvOCC;
 
+#define PNV_OCC_CLASS(klass) \
+     OBJECT_CLASS_CHECK(PnvOCCClass, (klass), TYPE_PNV_OCC)
+#define PNV_OCC_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(PnvOCCClass, (obj), TYPE_PNV_OCC)
+
+typedef struct PnvOCCClass {
+    DeviceClass parent_class;
+
+    int xscom_size;
+} PnvOCCClass;
+
 #endif /* _PPC_PNV_OCC_H */
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 895be470af67..81ab53899dbc 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -808,7 +808,7 @@ static void pnv_chip_power8_instance_init(Object *obj)
                                    OBJECT(&chip8->psi), &error_abort);
 
     object_initialize_child(obj, "occ",  &chip8->occ, sizeof(chip8->occ),
-                            TYPE_PNV_OCC, &error_abort, NULL);
+                            TYPE_PNV8_OCC, &error_abort, NULL);
     object_property_add_const_link(OBJECT(&chip8->occ), "psi",
                                    OBJECT(&chip8->psi), &error_abort);
 }
diff --git a/hw/ppc/pnv_occ.c b/hw/ppc/pnv_occ.c
index 04880f26d612..a210f44926aa 100644
--- a/hw/ppc/pnv_occ.c
+++ b/hw/ppc/pnv_occ.c
@@ -54,7 +54,7 @@ static uint64_t pnv_occ_xscom_read(void *opaque, hwaddr addr, unsigned size)
         break;
     default:
         qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
-                      HWADDR_PRIx "\n", addr);
+                      HWADDR_PRIx "\n", addr >> 3);
     }
     return val;
 }
@@ -77,7 +77,7 @@ static void pnv_occ_xscom_write(void *opaque, hwaddr addr,
         break;
     default:
         qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
-                      HWADDR_PRIx "\n", addr);
+                      HWADDR_PRIx "\n", addr >> 3);
     }
 }
 
@@ -95,6 +95,7 @@ static const MemoryRegionOps pnv_occ_xscom_ops = {
 static void pnv_occ_realize(DeviceState *dev, Error **errp)
 {
     PnvOCC *occ = PNV_OCC(dev);
+    PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
     Object *obj;
     Error *error = NULL;
 
@@ -111,9 +112,23 @@ static void pnv_occ_realize(DeviceState *dev, Error **errp)
 
     /* XScom region for OCC registers */
     pnv_xscom_region_init(&occ->xscom_regs, OBJECT(dev), &pnv_occ_xscom_ops,
-                  occ, "xscom-occ", PNV_XSCOM_OCC_SIZE);
+                  occ, "xscom-occ", poc->xscom_size);
 }
 
+static void pnv_occ_power8_class_init(ObjectClass *klass, void *data)
+{
+    PnvOCCClass *poc = PNV_OCC_CLASS(klass);
+
+    poc->xscom_size = PNV_XSCOM_OCC_SIZE;
+}
+
+static const TypeInfo pnv_occ_power8_type_info = {
+    .name          = TYPE_PNV8_OCC,
+    .parent        = TYPE_PNV_OCC,
+    .instance_size = sizeof(PnvOCC),
+    .class_init    = pnv_occ_power8_class_init,
+};
+
 static void pnv_occ_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -124,6 +139,7 @@ static void pnv_occ_class_init(ObjectClass *klass, void *data)
 static const TypeInfo pnv_occ_type_info = {
     .name          = TYPE_PNV_OCC,
     .parent        = TYPE_DEVICE,
+    .abstract      = true,
     .instance_size = sizeof(PnvOCC),
     .class_init    = pnv_occ_class_init,
 };
@@ -131,6 +147,7 @@ static const TypeInfo pnv_occ_type_info = {
 static void pnv_occ_register_types(void)
 {
     type_register_static(&pnv_occ_type_info);
+    type_register_static(&pnv_occ_power8_type_info);
 }
 
 type_init(pnv_occ_register_types)
-- 
2.20.1

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

* [Qemu-devel] [PATCH 21/27] ppc/pnv: add a OCC model for POWER9
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (19 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 20/27] ppc/pnv: add a OCC model class Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-07  4:27   ` David Gibson
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 22/27] ppc/pnv: extend XSCOM core support " Cédric Le Goater
                   ` (5 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

The OCC on POWER9 is very similar to the one found on POWER8. Provide
the same routines with P9 values for the registers and IRQ number.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/ppc/pnv.h       |  1 +
 include/hw/ppc/pnv_occ.h   |  4 ++++
 include/hw/ppc/pnv_xscom.h |  3 +++
 hw/ppc/pnv.c               | 13 +++++++++++++
 hw/ppc/pnv_occ.c           | 40 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 61 insertions(+)

diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index 2d68aabc212f..ad3bf0690ecf 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -86,6 +86,7 @@ typedef struct Pnv9Chip {
     PnvXive      xive;
     PnvPsi       psi;
     PnvLpcController lpc;
+    PnvOCC       occ;
 } Pnv9Chip;
 
 typedef struct PnvChipClass {
diff --git a/include/hw/ppc/pnv_occ.h b/include/hw/ppc/pnv_occ.h
index ce2631e21f5e..8951eb7ea316 100644
--- a/include/hw/ppc/pnv_occ.h
+++ b/include/hw/ppc/pnv_occ.h
@@ -27,6 +27,10 @@
 #define PNV8_OCC(obj) \
     OBJECT_CHECK(PnvOCC, (obj), TYPE_PNV8_OCC)
 
+#define TYPE_PNV9_OCC TYPE_PNV_OCC "-POWER9"
+#define PNV9_OCC(obj) \
+    OBJECT_CHECK(PnvOCC, (obj), TYPE_PNV9_OCC)
+
 typedef struct PnvOCC {
     DeviceState xd;
 
diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
index 403a365ed274..3292459fbb78 100644
--- a/include/hw/ppc/pnv_xscom.h
+++ b/include/hw/ppc/pnv_xscom.h
@@ -73,6 +73,9 @@ typedef struct PnvXScomInterfaceClass {
 #define PNV_XSCOM_OCC_BASE        0x0066000
 #define PNV_XSCOM_OCC_SIZE        0x6000
 
+#define PNV9_XSCOM_OCC_BASE       PNV_XSCOM_OCC_BASE
+#define PNV9_XSCOM_OCC_SIZE       0x8000
+
 #define PNV9_XSCOM_PSIHB_BASE     0x5012900
 #define PNV9_XSCOM_PSIHB_SIZE     0x100
 
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 81ab53899dbc..a056064c8c11 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -968,6 +968,11 @@ static void pnv_chip_power9_instance_init(Object *obj)
                             TYPE_PNV9_LPC, &error_abort, NULL);
     object_property_add_const_link(OBJECT(&chip9->lpc), "psi",
                                    OBJECT(&chip9->psi), &error_abort);
+
+    object_initialize_child(obj, "occ",  &chip9->occ, sizeof(chip9->occ),
+                            TYPE_PNV9_OCC, &error_abort, NULL);
+    object_property_add_const_link(OBJECT(&chip9->occ), "psi",
+                                   OBJECT(&chip9->psi), &error_abort);
 }
 
 static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
@@ -1020,6 +1025,14 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
     }
     memory_region_add_subregion(get_system_memory(), PNV9_LPCM_BASE(chip),
                                 &chip9->lpc.xscom_regs);
+
+    /* Create the simplified OCC model */
+    object_property_set_bool(OBJECT(&chip9->occ), true, "realized", &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+    pnv_xscom_add_subregion(chip, PNV9_XSCOM_OCC_BASE, &chip9->occ.xscom_regs);
 }
 
 static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
diff --git a/hw/ppc/pnv_occ.c b/hw/ppc/pnv_occ.c
index a210f44926aa..59b0702bc716 100644
--- a/hw/ppc/pnv_occ.c
+++ b/hw/ppc/pnv_occ.c
@@ -31,6 +31,10 @@
 #define OCB_OCI_OCCMISC_AND     0x4021
 #define OCB_OCI_OCCMISC_OR      0x4022
 
+#define P9_OCB_OCI_OCCMISC              0x6080
+#define P9_OCB_OCI_OCCMISC_CLEAR        0x6081
+#define P9_OCB_OCI_OCCMISC_OR           0x6082
+
 static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val)
 {
     bool irq_state;
@@ -42,6 +46,17 @@ static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val)
     pnv_psi_irq_set(occ->psi, PSIHB_IRQ_OCC, irq_state);
 }
 
+static void pnv_occ_p9_set_misc(PnvOCC *occ, uint64_t val)
+{
+    bool irq_state;
+
+    val &= 0xffff000000000000ull;
+
+    occ->occmisc = val;
+    irq_state = !!(val >> 63);
+    pnv_psi_irq_set(occ->psi, PSIHB9_IRQ_OCC, irq_state);
+}
+
 static uint64_t pnv_occ_xscom_read(void *opaque, hwaddr addr, unsigned size)
 {
     PnvOCC *occ = PNV_OCC(opaque);
@@ -50,6 +65,7 @@ static uint64_t pnv_occ_xscom_read(void *opaque, hwaddr addr, unsigned size)
 
     switch (offset) {
     case OCB_OCI_OCCMISC:
+    case P9_OCB_OCI_OCCMISC:
         val = occ->occmisc;
         break;
     default:
@@ -75,6 +91,15 @@ static void pnv_occ_xscom_write(void *opaque, hwaddr addr,
     case OCB_OCI_OCCMISC:
         pnv_occ_set_misc(occ, val);
         break;
+    case P9_OCB_OCI_OCCMISC_CLEAR:
+        pnv_occ_p9_set_misc(occ, 0);
+        break;
+    case P9_OCB_OCI_OCCMISC_OR:
+        pnv_occ_p9_set_misc(occ, occ->occmisc | val);
+        break;
+    case P9_OCB_OCI_OCCMISC:
+        pnv_occ_p9_set_misc(occ, val);
+       break;
     default:
         qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
                       HWADDR_PRIx "\n", addr >> 3);
@@ -115,6 +140,20 @@ static void pnv_occ_realize(DeviceState *dev, Error **errp)
                   occ, "xscom-occ", poc->xscom_size);
 }
 
+static void pnv_occ_power9_class_init(ObjectClass *klass, void *data)
+{
+    PnvOCCClass *poc = PNV_OCC_CLASS(klass);
+
+    poc->xscom_size = PNV9_XSCOM_OCC_SIZE;
+}
+
+static const TypeInfo pnv_occ_power9_type_info = {
+    .name          = TYPE_PNV9_OCC,
+    .parent        = TYPE_PNV_OCC,
+    .instance_size = sizeof(PnvOCC),
+    .class_init    = pnv_occ_power9_class_init,
+};
+
 static void pnv_occ_power8_class_init(ObjectClass *klass, void *data)
 {
     PnvOCCClass *poc = PNV_OCC_CLASS(klass);
@@ -148,6 +187,7 @@ static void pnv_occ_register_types(void)
 {
     type_register_static(&pnv_occ_type_info);
     type_register_static(&pnv_occ_power8_type_info);
+    type_register_static(&pnv_occ_power9_type_info);
 }
 
 type_init(pnv_occ_register_types)
-- 
2.20.1

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

* [Qemu-devel] [PATCH 22/27] ppc/pnv: extend XSCOM core support for POWER9
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (20 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 21/27] ppc/pnv: add a OCC model for POWER9 Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-07  4:28   ` David Gibson
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 23/27] ppc/pnv: POWER9 XSCOM quad support Cédric Le Goater
                   ` (4 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

Add a couple of XSCOM addresses controlling the power management
states of the core.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/ppc/pnv_core.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 38179cdc53dc..c3d6350dc90a 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -60,6 +60,12 @@ static void pnv_cpu_reset(void *opaque)
 #define PNV_XSCOM_EX_DTS_RESULT0     0x50000
 #define PNV_XSCOM_EX_DTS_RESULT1     0x50001
 
+/*
+ * POWER9 core controls
+ */
+#define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP 0xf010d
+#define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR 0xf010a
+
 static uint64_t pnv_core_xscom_read(void *opaque, hwaddr addr,
                                     unsigned int width)
 {
@@ -74,6 +80,10 @@ static uint64_t pnv_core_xscom_read(void *opaque, hwaddr addr,
     case PNV_XSCOM_EX_DTS_RESULT1:
         val = 0x24f000000000000ull;
         break;
+    case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP:
+    case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR:
+        val = 0x0;
+        break;
     default:
         qemu_log_mask(LOG_UNIMP, "Warning: reading reg=0x%" HWADDR_PRIx "\n",
                   addr);
@@ -85,8 +95,16 @@ static uint64_t pnv_core_xscom_read(void *opaque, hwaddr addr,
 static void pnv_core_xscom_write(void *opaque, hwaddr addr, uint64_t val,
                                  unsigned int width)
 {
-    qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx "\n",
-                  addr);
+    uint32_t offset = addr >> 3;
+
+    switch (offset) {
+    case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP:
+    case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR:
+        break;
+    default:
+        qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx "\n",
+                      addr);
+    }
 }
 
 static const MemoryRegionOps pnv_core_xscom_ops = {
-- 
2.20.1

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

* [Qemu-devel] [PATCH 23/27] ppc/pnv: POWER9 XSCOM quad support
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (21 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 22/27] ppc/pnv: extend XSCOM core support " Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 24/27] ppc/pnv: activate XSCOM tests for POWER9 Cédric Le Goater
                   ` (3 subsequent siblings)
  26 siblings, 0 replies; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

The POWER9 processor does not support per-core frequency control. The
cores are arranged in groups of four, along with their respective L2
and L3 caches, into a structure known as a Quad. The frequency must be
managed at the Quad level.

Provide a basic Quad model to fake the settings done by the firmware
on the Non-Cacheable Unit (NCU). Each core pair (EX) needs a special
BAR setting for the TIMA area of XIVE because it resides on the same
address on all chips.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 include/hw/ppc/pnv.h       |  4 ++
 include/hw/ppc/pnv_core.h  | 10 +++++
 include/hw/ppc/pnv_xscom.h | 12 ++++--
 hw/ppc/pnv.c               | 38 ++++++++++++++++-
 hw/ppc/pnv_core.c          | 87 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 146 insertions(+), 5 deletions(-)

diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index ad3bf0690ecf..04c7125a876d 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -26,6 +26,7 @@
 #include "hw/ppc/pnv_psi.h"
 #include "hw/ppc/pnv_occ.h"
 #include "hw/ppc/pnv_xive.h"
+#include "hw/ppc/pnv_core.h"
 
 #define TYPE_PNV_CHIP "pnv-chip"
 #define PNV_CHIP(obj) OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP)
@@ -87,6 +88,9 @@ typedef struct Pnv9Chip {
     PnvPsi       psi;
     PnvLpcController lpc;
     PnvOCC       occ;
+
+    uint32_t     nr_quads;
+    PnvQuad      *quads;
 } Pnv9Chip;
 
 typedef struct PnvChipClass {
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
index 6874bb847a01..4dcd63660bd1 100644
--- a/include/hw/ppc/pnv_core.h
+++ b/include/hw/ppc/pnv_core.h
@@ -56,4 +56,14 @@ static inline PnvCPUState *pnv_cpu_state(PowerPCCPU *cpu)
     return (PnvCPUState *)cpu->machine_data;
 }
 
+#define TYPE_PNV_QUAD "powernv-cpu-quad"
+#define PNV_QUAD(obj) \
+    OBJECT_CHECK(PnvQuad, (obj), TYPE_PNV_QUAD)
+
+typedef struct PnvQuad {
+    DeviceState parent_obj;
+
+    uint32_t id;
+    MemoryRegion xscom_regs;
+} PnvQuad;
 #endif /* _PPC_PNV_CORE_H */
diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
index 3292459fbb78..68dfae0dfe41 100644
--- a/include/hw/ppc/pnv_xscom.h
+++ b/include/hw/ppc/pnv_xscom.h
@@ -60,10 +60,6 @@ typedef struct PnvXScomInterfaceClass {
     (PNV_XSCOM_EX_CORE_BASE | ((uint64_t)(core) << 24))
 #define PNV_XSCOM_EX_SIZE         0x100000
 
-#define PNV_XSCOM_P9_EC_BASE(core) \
-    ((uint64_t)(((core) & 0x1F) + 0x20) << 24)
-#define PNV_XSCOM_P9_EC_SIZE      0x100000
-
 #define PNV_XSCOM_LPC_BASE        0xb0020
 #define PNV_XSCOM_LPC_SIZE        0x4
 
@@ -73,6 +69,14 @@ typedef struct PnvXScomInterfaceClass {
 #define PNV_XSCOM_OCC_BASE        0x0066000
 #define PNV_XSCOM_OCC_SIZE        0x6000
 
+#define PNV9_XSCOM_EC_BASE(core) \
+    ((uint64_t)(((core) & 0x1F) + 0x20) << 24)
+#define PNV9_XSCOM_EC_SIZE        0x100000
+
+#define PNV9_XSCOM_EQ_BASE(core) \
+    ((uint64_t)(((core) & 0x1C) + 0x40) << 22)
+#define PNV9_XSCOM_EQ_SIZE        0x100000
+
 #define PNV9_XSCOM_OCC_BASE       PNV_XSCOM_OCC_BASE
 #define PNV9_XSCOM_OCC_SIZE       0x8000
 
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index a056064c8c11..30153ad5acea 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -975,6 +975,36 @@ static void pnv_chip_power9_instance_init(Object *obj)
                                    OBJECT(&chip9->psi), &error_abort);
 }
 
+static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp)
+{
+    PnvChip *chip = PNV_CHIP(chip9);
+    const char *typename = pnv_chip_core_typename(chip);
+    size_t typesize = object_type_get_instance_size(typename);
+    int i;
+
+    chip9->nr_quads = DIV_ROUND_UP(chip->nr_cores, 4);
+    chip9->quads = g_new0(PnvQuad, chip9->nr_quads);
+
+    for (i = 0; i < chip9->nr_quads; i++) {
+        char eq_name[32];
+        PnvQuad *eq = &chip9->quads[i];
+        PnvCore *pnv_core = PNV_CORE(chip->cores + (i * 4) * typesize);
+        int core_id = CPU_CORE(pnv_core)->core_id;
+
+        object_initialize(eq, sizeof(*eq), TYPE_PNV_QUAD);
+        snprintf(eq_name, sizeof(eq_name), "eq[%d]", core_id);
+
+        object_property_add_child(OBJECT(chip), eq_name, OBJECT(eq),
+                                  &error_fatal);
+        object_property_set_int(OBJECT(eq), core_id, "id", &error_fatal);
+        object_property_set_bool(OBJECT(eq), true, "realized", &error_fatal);
+        object_unref(OBJECT(eq));
+
+        pnv_xscom_add_subregion(chip, PNV9_XSCOM_EQ_BASE(eq->id),
+                                &eq->xscom_regs);
+    }
+}
+
 static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
 {
     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
@@ -988,6 +1018,12 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
         return;
     }
 
+    pnv_chip_quad_realize(chip9, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
     /* XIVE interrupt controller (POWER9) */
     object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_IC_BASE(chip),
                             "ic-bar", &error_fatal);
@@ -1143,7 +1179,7 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
         if (!pnv_chip_is_power9(chip)) {
             xscom_core_base = PNV_XSCOM_EX_BASE(core_hwid);
         } else {
-            xscom_core_base = PNV_XSCOM_P9_EC_BASE(core_hwid);
+            xscom_core_base = PNV9_XSCOM_EC_BASE(core_hwid);
         }
 
         pnv_xscom_add_subregion(chip, xscom_core_base,
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index c3d6350dc90a..9e0d87224d5e 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -271,3 +271,90 @@ static const TypeInfo pnv_core_infos[] = {
 };
 
 DEFINE_TYPES(pnv_core_infos)
+
+/*
+ * POWER9 Quads
+ */
+
+#define P9X_EX_NCU_SPEC_BAR                     0x11010
+
+static uint64_t pnv_quad_xscom_read(void *opaque, hwaddr addr,
+                                    unsigned int width)
+{
+    uint32_t offset = addr >> 3;
+    uint64_t val = -1;
+
+    switch (offset) {
+    case P9X_EX_NCU_SPEC_BAR:
+    case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
+        val = 0;
+        break;
+    default:
+        qemu_log_mask(LOG_UNIMP, "%s: writing @0x%08x\n", __func__,
+                      offset);
+    }
+
+    return val;
+}
+
+static void pnv_quad_xscom_write(void *opaque, hwaddr addr, uint64_t val,
+                                 unsigned int width)
+{
+    uint32_t offset = addr >> 3;
+
+    switch (offset) {
+    case P9X_EX_NCU_SPEC_BAR:
+    case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
+        break;
+    default:
+        qemu_log_mask(LOG_UNIMP, "%s: writing @0x%08x\n", __func__,
+                  offset);
+    }
+}
+
+static const MemoryRegionOps pnv_quad_xscom_ops = {
+    .read = pnv_quad_xscom_read,
+    .write = pnv_quad_xscom_write,
+    .valid.min_access_size = 8,
+    .valid.max_access_size = 8,
+    .impl.min_access_size = 8,
+    .impl.max_access_size = 8,
+    .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static void pnv_quad_realize(DeviceState *dev, Error **errp)
+{
+    PnvQuad *eq = PNV_QUAD(dev);
+    char name[32];
+
+    snprintf(name, sizeof(name), "xscom-quad.%d", eq->id);
+    pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev), &pnv_quad_xscom_ops,
+                          eq, name, PNV9_XSCOM_EQ_SIZE);
+}
+
+static Property pnv_quad_properties[] = {
+    DEFINE_PROP_UINT32("id", PnvQuad, id, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pnv_quad_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = pnv_quad_realize;
+    dc->props = pnv_quad_properties;
+}
+
+static const TypeInfo pnv_quad_info = {
+    .name          = TYPE_PNV_QUAD,
+    .parent        = TYPE_DEVICE,
+    .instance_size = sizeof(PnvQuad),
+    .class_init    = pnv_quad_class_init,
+};
+
+static void pnv_core_register_types(void)
+{
+    type_register_static(&pnv_quad_info);
+}
+
+type_init(pnv_core_register_types)
-- 
2.20.1

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

* [Qemu-devel] [PATCH 24/27] ppc/pnv: activate XSCOM tests for POWER9
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (22 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 23/27] ppc/pnv: POWER9 XSCOM quad support Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 25/27] ppc/pnv: add more dummy XSCOM addresses Cédric Le Goater
                   ` (2 subsequent siblings)
  26 siblings, 0 replies; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 tests/pnv-xscom-test.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/tests/pnv-xscom-test.c b/tests/pnv-xscom-test.c
index 974f8da5b240..63d464048d53 100644
--- a/tests/pnv-xscom-test.c
+++ b/tests/pnv-xscom-test.c
@@ -39,7 +39,6 @@ static const PnvChip pnv_chips[] = {
         .cfam_id    = 0x120d304980000000ull,
         .first_core = 0x1,
     },
-#if 0 /* POWER9 support is not ready yet */
     {
         .chip_type  = PNV_CHIP_POWER9,
         .cpu_model  = "POWER9",
@@ -47,7 +46,6 @@ static const PnvChip pnv_chips[] = {
         .cfam_id    = 0x220d104900008000ull,
         .first_core = 0x0,
     },
-#endif
 };
 
 static uint64_t pnv_xscom_addr(const PnvChip *chip, uint32_t pcba)
-- 
2.20.1

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

* [Qemu-devel] [PATCH 25/27] ppc/pnv: add more dummy XSCOM addresses
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (23 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 24/27] ppc/pnv: activate XSCOM tests for POWER9 Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 26/27] ppc/pnv: add a "ibm, opal/power-mgt" device tree node on POWER9 Cédric Le Goater
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 27/27] target/ppc: add HV support for POWER9 Cédric Le Goater
  26 siblings, 0 replies; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/ppc/pnv_xscom.c | 33 +++++++++++++++++++++++++++------
 1 file changed, 27 insertions(+), 6 deletions(-)

diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c
index 46fae41f32b0..c285ef514e88 100644
--- a/hw/ppc/pnv_xscom.c
+++ b/hw/ppc/pnv_xscom.c
@@ -64,11 +64,21 @@ static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba)
     switch (pcba) {
     case 0xf000f:
         return PNV_CHIP_GET_CLASS(chip)->chip_cfam_id;
+    case 0x18002:       /* ECID2 */
+        return 0;
+
     case 0x1010c00:     /* PIBAM FIR */
     case 0x1010c03:     /* PIBAM FIR MASK */
-    case 0x2020007:     /* ADU stuff */
-    case 0x2020009:     /* ADU stuff */
-    case 0x202000f:     /* ADU stuff */
+
+        /* P9 xscom reset */
+    case 0x0090018:     /* Receive status reg */
+    case 0x0090012:     /* log register */
+    case 0x0090013:     /* error register */
+
+        /* P8 xscom reset */
+    case 0x2020007:     /* ADU stuff, log register */
+    case 0x2020009:     /* ADU stuff, error register */
+    case 0x202000f:     /* ADU stuff, receive status register*/
         return 0;
     case 0x2013f00:     /* PBA stuff */
     case 0x2013f01:     /* PBA stuff */
@@ -100,9 +110,20 @@ static bool xscom_write_default(PnvChip *chip, uint32_t pcba, uint64_t val)
     case 0x1010c03:     /* PIBAM FIR MASK */
     case 0x1010c04:     /* PIBAM FIR MASK */
     case 0x1010c05:     /* PIBAM FIR MASK */
-    case 0x2020007:     /* ADU stuff */
-    case 0x2020009:     /* ADU stuff */
-    case 0x202000f:     /* ADU stuff */
+        /* P9 xscom reset */
+    case 0x0090018:     /* Receive status reg */
+    case 0x0090012:     /* log register */
+    case 0x0090013:     /* error register */
+
+        /* P8 xscom reset */
+    case 0x2020007:     /* ADU stuff, log register */
+    case 0x2020009:     /* ADU stuff, error register */
+    case 0x202000f:     /* ADU stuff, receive status register*/
+
+    case 0x2013028:     /* CAPP stuff */
+    case 0x201302a:     /* CAPP stuff */
+    case 0x2013801:     /* CAPP stuff */
+    case 0x2013802:     /* CAPP stuff */
         return true;
     default:
         return false;
-- 
2.20.1

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

* [Qemu-devel] [PATCH 26/27] ppc/pnv: add a "ibm, opal/power-mgt" device tree node on POWER9
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (24 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 25/27] ppc/pnv: add more dummy XSCOM addresses Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 27/27] target/ppc: add HV support for POWER9 Cédric Le Goater
  26 siblings, 0 replies; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

Activate stop0 and stop1 levels.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/ppc/pnv.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 30153ad5acea..9d40b006c0af 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -456,6 +456,16 @@ static void pnv_dt_isa(PnvMachineState *pnv, void *fdt)
                        &args);
 }
 
+static void pnv_dt_power_mgt(void *fdt)
+{
+    int off;
+
+    off = fdt_add_subnode(fdt, 0, "ibm,opal");
+    off = fdt_add_subnode(fdt, off, "power-mgt");
+
+    _FDT(fdt_setprop_cell(fdt, off, "ibm,enabled-stop-levels", 0xc0000000));
+}
+
 static void *pnv_dt_create(MachineState *machine)
 {
     const char plat_compat[] = "qemu,powernv\0ibm,powernv";
@@ -511,6 +521,11 @@ static void *pnv_dt_create(MachineState *machine)
         pnv_dt_bmc_sensors(pnv->bmc, fdt);
     }
 
+    /* Create an extra node for power management on Power9 */
+    if (pnv_is_power9(pnv)) {
+        pnv_dt_power_mgt(fdt);
+    }
+
     return fdt;
 }
 
-- 
2.20.1

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

* [Qemu-devel] [PATCH 27/27] target/ppc: add HV support for POWER9
  2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
                   ` (25 preceding siblings ...)
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 26/27] ppc/pnv: add a "ibm, opal/power-mgt" device tree node on POWER9 Cédric Le Goater
@ 2019-03-06  8:50 ` Cédric Le Goater
  26 siblings, 0 replies; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-06  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, Cédric Le Goater

We now have enough support to boot a PowerNV machine with a POWER9
processor. Allow HV mode on POWER9.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 target/ppc/translate_init.inc.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c
index af70a3b78c9a..0bd555eb1913 100644
--- a/target/ppc/translate_init.inc.c
+++ b/target/ppc/translate_init.inc.c
@@ -8895,7 +8895,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
                        PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
                        PPC_MEM_SYNC | PPC_MEM_EIEIO |
                        PPC_MEM_TLBSYNC |
-                       PPC_64B | PPC_64BX | PPC_ALTIVEC |
+                       PPC_64B | PPC_64H | PPC_64BX | PPC_ALTIVEC |
                        PPC_SEGMENT_64B | PPC_SLBI |
                        PPC_POPCNTB | PPC_POPCNTWD |
                        PPC_CILDST;
@@ -8907,6 +8907,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
                         PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
                         PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL;
     pcc->msr_mask = (1ull << MSR_SF) |
+                    (1ull << MSR_SHV) |
                     (1ull << MSR_TM) |
                     (1ull << MSR_VR) |
                     (1ull << MSR_VSX) |
-- 
2.20.1

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

* Re: [Qemu-devel] [PATCH 01/27] ppc/xive: hardwire the Physical CAM line of the thread context
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 01/27] ppc/xive: hardwire the Physical CAM line of the thread context Cédric Le Goater
@ 2019-03-07  1:19   ` David Gibson
  0 siblings, 0 replies; 55+ messages in thread
From: David Gibson @ 2019-03-07  1:19 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 3159 bytes --]

On Wed, Mar 06, 2019 at 09:50:06AM +0100, Cédric Le Goater wrote:
> By default on P9, the HW CAM line (23bits) is hardwired to :
> 
>       0x000||0b1||4Bit chip number||7Bit Thread number.
> 
> When the block group mode is enabled at the controller level (PowerNV),
> the CAM line is changed for CAM compares to :
> 
>       4Bit chip number||0x001||7Bit Thread number
> 
> This will require changes in xive_presenter_tctx_match() possibly.
> This is a lowlevel functionality of the HW controller and it is not
> strictly needed. Leave it for later.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>

Applied to ppc-for-4.0, thanks.

> ---
>  hw/intc/xive.c | 31 ++++++++++++++++++++++++++++++-
>  1 file changed, 30 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/intc/xive.c b/hw/intc/xive.c
> index daa7badc8492..b21759c93856 100644
> --- a/hw/intc/xive.c
> +++ b/hw/intc/xive.c
> @@ -1112,6 +1112,30 @@ XiveTCTX *xive_router_get_tctx(XiveRouter *xrtr, CPUState *cs)
>      return xrc->get_tctx(xrtr, cs);
>  }
>  
> +/*
> + * By default on P9, the HW CAM line (23bits) is hardwired to :
> + *
> + *   0x000||0b1||4Bit chip number||7Bit Thread number.
> + *
> + * When the block grouping is enabled, the CAM line is changed to :
> + *
> + *   4Bit chip number||0x001||7Bit Thread number.
> + */
> +static uint32_t hw_cam_line(uint8_t chip_id, uint8_t tid)
> +{
> +    return 1 << 11 | (chip_id & 0xf) << 7 | (tid & 0x7f);
> +}
> +
> +static bool xive_presenter_tctx_match_hw(XiveTCTX *tctx,
> +                                         uint8_t nvt_blk, uint32_t nvt_idx)
> +{
> +    CPUPPCState *env = &POWERPC_CPU(tctx->cs)->env;
> +    uint32_t pir = env->spr_cb[SPR_PIR].default_value;
> +
> +    return hw_cam_line((pir >> 8) & 0xf, pir & 0x7f) ==
> +        hw_cam_line(nvt_blk, nvt_idx);
> +}
> +
>  /*
>   * The thread context register words are in big-endian format.
>   */
> @@ -1120,6 +1144,7 @@ static int xive_presenter_tctx_match(XiveTCTX *tctx, uint8_t format,
>                                       bool cam_ignore, uint32_t logic_serv)
>  {
>      uint32_t cam = xive_nvt_cam_line(nvt_blk, nvt_idx);
> +    uint32_t qw3w2 = xive_tctx_word2(&tctx->regs[TM_QW3_HV_PHYS]);
>      uint32_t qw2w2 = xive_tctx_word2(&tctx->regs[TM_QW2_HV_POOL]);
>      uint32_t qw1w2 = xive_tctx_word2(&tctx->regs[TM_QW1_OS]);
>      uint32_t qw0w2 = xive_tctx_word2(&tctx->regs[TM_QW0_USER]);
> @@ -1142,7 +1167,11 @@ static int xive_presenter_tctx_match(XiveTCTX *tctx, uint8_t format,
>  
>          /* F=0 & i=0: Specific NVT notification */
>  
> -        /* TODO (PowerNV) : PHYS ring */
> +        /* PHYS ring */
> +        if ((be32_to_cpu(qw3w2) & TM_QW3W2_VT) &&
> +            xive_presenter_tctx_match_hw(tctx, nvt_blk, nvt_idx)) {
> +            return TM_QW3_HV_PHYS;
> +        }
>  
>          /* HV POOL ring */
>          if ((be32_to_cpu(qw2w2) & TM_QW2W2_VP) &&

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 05/27] ppc/pnv: change the CPU machine_data presenter type to Object *
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 05/27] ppc/pnv: change the CPU machine_data presenter type to Object * Cédric Le Goater
@ 2019-03-07  1:36   ` David Gibson
  0 siblings, 0 replies; 55+ messages in thread
From: David Gibson @ 2019-03-07  1:36 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 2643 bytes --]

On Wed, Mar 06, 2019 at 09:50:10AM +0100, Cédric Le Goater wrote:
> The POWER9 PowerNV machine will use a XIVE interrupt presenter type.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>

Applied patches 2..5.

> ---
>  include/hw/ppc/pnv_core.h | 2 +-
>  hw/ppc/pnv.c              | 6 +++---
>  hw/ppc/pnv_core.c         | 2 +-
>  3 files changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
> index 9961ea3a92cd..6874bb847a01 100644
> --- a/include/hw/ppc/pnv_core.h
> +++ b/include/hw/ppc/pnv_core.h
> @@ -48,7 +48,7 @@ typedef struct PnvCoreClass {
>  #define PNV_CORE_TYPE_NAME(cpu_model) cpu_model PNV_CORE_TYPE_SUFFIX
>  
>  typedef struct PnvCPUState {
> -    struct ICPState *icp;
> +    Object *intc;
>  } PnvCPUState;
>  
>  static inline PnvCPUState *pnv_cpu_state(PowerPCCPU *cpu)
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 9aa81c7f09c2..b90d03711a05 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -684,7 +684,7 @@ static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu,
>          return;
>      }
>  
> -    pnv_cpu->icp = ICP(obj);
> +    pnv_cpu->intc = obj;
>  }
>  
>  /*
> @@ -1086,7 +1086,7 @@ static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
>  {
>      PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir);
>  
> -    return cpu ? pnv_cpu_state(cpu)->icp : NULL;
> +    return cpu ? ICP(pnv_cpu_state(cpu)->intc) : NULL;
>  }
>  
>  static void pnv_pic_print_info(InterruptStatsProvider *obj,
> @@ -1099,7 +1099,7 @@ static void pnv_pic_print_info(InterruptStatsProvider *obj,
>      CPU_FOREACH(cs) {
>          PowerPCCPU *cpu = POWERPC_CPU(cs);
>  
> -        icp_pic_print_info(pnv_cpu_state(cpu)->icp, mon);
> +        icp_pic_print_info(ICP(pnv_cpu_state(cpu)->intc), mon);
>      }
>  
>      for (i = 0; i < pnv->num_chips; i++) {
> diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
> index 7c806da720c6..38179cdc53dc 100644
> --- a/hw/ppc/pnv_core.c
> +++ b/hw/ppc/pnv_core.c
> @@ -198,7 +198,7 @@ static void pnv_unrealize_vcpu(PowerPCCPU *cpu)
>      PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
>  
>      qemu_unregister_reset(pnv_cpu_reset, cpu);
> -    object_unparent(OBJECT(pnv_cpu_state(cpu)->icp));
> +    object_unparent(OBJECT(pnv_cpu_state(cpu)->intc));
>      cpu_remove_sync(CPU(cpu));
>      cpu->machine_data = NULL;
>      g_free(pnv_cpu);

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 06/27] ppc/pnv: add a XIVE interrupt controller model for POWER9
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 06/27] ppc/pnv: add a XIVE interrupt controller model for POWER9 Cédric Le Goater
@ 2019-03-07  1:37   ` David Gibson
  0 siblings, 0 replies; 55+ messages in thread
From: David Gibson @ 2019-03-07  1:37 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 68020 bytes --]

On Wed, Mar 06, 2019 at 09:50:11AM +0100, Cédric Le Goater wrote:
> This is a simple model of the POWER9 XIVE interrupt controller for the
> PowerNV machine which only addresses the needs of the skiboot
> firmware. The PowerNV model reuses the common XIVE framework developed
> for sPAPR as the fundamentals aspects are quite the same. The
> difference are outlined below.
> 
> The controller initial BAR configuration is performed using the XSCOM
> bus from there, MMIO are used for further configuration.
> 
> The MMIO regions exposed are :
> 
>  - Interrupt controller registers
>  - ESB pages for IPIs and ENDs
>  - Presenter MMIO (Not used)
>  - Thread Interrupt Management Area MMIO, direct and indirect
> 
> The virtualization controller MMIO region containing the IPI ESB pages
> and END ESB pages is sub-divided into "sets" which map portions of the
> VC region to the different ESB pages. These are modeled with custom
> address spaces and the XiveSource and XiveENDSource objects are sized
> to the maximum allowed by HW. The memory regions are resized at
> run-time using the configuration of EDT set translation table provided
> by the firmware.
> 
> The XIVE virtualization structure tables (EAT, ENDT, NVTT) are now in
> the machine RAM and not in the hypervisor anymore. The firmware
> (skiboot) configures these tables using Virtual Structure Descriptor
> defining the characteristics of each table : SBE, EAS, END and
> NVT. These are later used to access the virtual interrupt entries. The
> internal cache of these tables in the interrupt controller is updated
> and invalidated using a set of registers.
> 
> Still to address to complete the model but not fully required is the
> support for block grouping. Escalation support will be necessary for
> KVM guests.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>

[snip]

> +typedef struct PnvXive {
> +    XiveRouter    parent_obj;
> +
> +    /* Owning chip */
> +    struct PnvChip *chip;
> +
> +    /* XSCOM addresses giving access to the controller registers */
> +    MemoryRegion  xscom_regs;
> +
> +    /* Main MMIO regions that can be configured by FW */
> +    MemoryRegion  ic_mmio;
> +    MemoryRegion    ic_reg_mmio;
> +    MemoryRegion    ic_notify_mmio;
> +    MemoryRegion    ic_lsi_mmio;
> +    MemoryRegion    tm_indirect_mmio;
> +    MemoryRegion  vc_mmio;
> +    MemoryRegion  pc_mmio;
> +    MemoryRegion  tm_mmio;
> +
> +    /*
> +     * IPI and END address spaces modeling the EDT segmentation in the
> +     * VC region
> +     */
> +    AddressSpace  ipi_as;
> +    MemoryRegion  ipi_mmio;
> +    MemoryRegion    ipi_edt_mmio;
> +
> +    AddressSpace  end_as;
> +    MemoryRegion  end_mmio;
> +    MemoryRegion    end_edt_mmio;
> +
> +    /* Shortcut values for the Main MMIO regions */
> +    hwaddr        ic_base;
> +    uint32_t      ic_shift;
> +    hwaddr        vc_base;
> +    uint32_t      vc_shift;
> +    hwaddr        pc_base;
> +    uint32_t      pc_shift;
> +    hwaddr        tm_base;
> +    uint32_t      tm_shift;
> +
> +    /* Our XIVE source objects for IPIs and ENDs */
> +    XiveSource    ipi_source;
> +    XiveENDSource end_source;
> +
> +    /* Interrupt controller registers */
> +    uint64_t      regs[0x300];

I'm still pretty dubious about whether encoding the registers this way
is a good idea.  But, the pnv model isn't migratable so it's something
we can fix later.  Therefore, applied to ppc-for-4.0.


> +
> +    /* Can be configured by FW */
> +    uint32_t      tctx_chipid;
> +
> +    /*
> +     * Virtual Structure Descriptor tables : EAT, SBE, ENDT, NVTT, IRQ
> +     * These are in a SRAM protected by ECC.
> +     */
> +    uint64_t      vsds[5][XIVE_BLOCK_MAX];
> +
> +    /* Translation tables */
> +    uint64_t      blk[XIVE_TABLE_BLK_MAX];
> +    uint64_t      mig[XIVE_TABLE_MIG_MAX];
> +    uint64_t      vdt[XIVE_TABLE_VDT_MAX];
> +    uint64_t      edt[XIVE_TABLE_EDT_MAX];
> +} PnvXive;
> +
> +void pnv_xive_pic_print_info(PnvXive *xive, Monitor *mon);
> +
> +#endif /* PPC_PNV_XIVE_H */
> diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
> index 255b26a5aaf6..6623ec54a7a8 100644
> --- a/include/hw/ppc/pnv_xscom.h
> +++ b/include/hw/ppc/pnv_xscom.h
> @@ -73,6 +73,9 @@ typedef struct PnvXScomInterfaceClass {
>  #define PNV_XSCOM_OCC_BASE        0x0066000
>  #define PNV_XSCOM_OCC_SIZE        0x6000
>  
> +#define PNV9_XSCOM_XIVE_BASE      0x5013000
> +#define PNV9_XSCOM_XIVE_SIZE      0x300
> +
>  extern void pnv_xscom_realize(PnvChip *chip, Error **errp);
>  extern int pnv_dt_xscom(PnvChip *chip, void *fdt, int offset);
>  
> diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c
> new file mode 100644
> index 000000000000..bb0877cbdf3b
> --- /dev/null
> +++ b/hw/intc/pnv_xive.c
> @@ -0,0 +1,1753 @@
> +/*
> + * QEMU PowerPC XIVE interrupt controller model
> + *
> + * Copyright (c) 2017-2019, IBM Corporation.
> + *
> + * This code is licensed under the GPL version 2 or later. See the
> + * COPYING file in the top-level directory.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "qapi/error.h"
> +#include "target/ppc/cpu.h"
> +#include "sysemu/cpus.h"
> +#include "sysemu/dma.h"
> +#include "monitor/monitor.h"
> +#include "hw/ppc/fdt.h"
> +#include "hw/ppc/pnv.h"
> +#include "hw/ppc/pnv_core.h"
> +#include "hw/ppc/pnv_xscom.h"
> +#include "hw/ppc/pnv_xive.h"
> +#include "hw/ppc/xive_regs.h"
> +#include "hw/ppc/ppc.h"
> +
> +#include <libfdt.h>
> +
> +#include "pnv_xive_regs.h"
> +
> +#define XIVE_DEBUG
> +
> +/*
> + * Virtual structures table (VST)
> + */
> +#define SBE_PER_BYTE   4
> +
> +typedef struct XiveVstInfo {
> +    const char *name;
> +    uint32_t    size;
> +    uint32_t    max_blocks;
> +} XiveVstInfo;
> +
> +static const XiveVstInfo vst_infos[] = {
> +    [VST_TSEL_IVT]  = { "EAT",  sizeof(XiveEAS), 16 },
> +    [VST_TSEL_SBE]  = { "SBE",  1,               16 },
> +    [VST_TSEL_EQDT] = { "ENDT", sizeof(XiveEND), 16 },
> +    [VST_TSEL_VPDT] = { "VPDT", sizeof(XiveNVT), 32 },
> +
> +    /*
> +     *  Interrupt fifo backing store table (not modeled) :
> +     *
> +     * 0 - IPI,
> +     * 1 - HWD,
> +     * 2 - First escalate,
> +     * 3 - Second escalate,
> +     * 4 - Redistribution,
> +     * 5 - IPI cascaded queue ?
> +     */
> +    [VST_TSEL_IRQ]  = { "IRQ",  1,               6  },
> +};
> +
> +#define xive_error(xive, fmt, ...)                                      \
> +    qemu_log_mask(LOG_GUEST_ERROR, "XIVE[%x] - " fmt "\n",              \
> +                  (xive)->chip->chip_id, ## __VA_ARGS__);
> +
> +/*
> + * QEMU version of the GETFIELD/SETFIELD macros
> + *
> + * TODO: It might be better to use the existing extract64() and
> + * deposit64() but this means that all the register definitions will
> + * change and become incompatible with the ones found in skiboot.
> + *
> + * Keep it as it is for now until we find a common ground.
> + */
> +static inline uint64_t GETFIELD(uint64_t mask, uint64_t word)
> +{
> +    return (word & mask) >> ctz64(mask);
> +}
> +
> +static inline uint64_t SETFIELD(uint64_t mask, uint64_t word,
> +                                uint64_t value)
> +{
> +    return (word & ~mask) | ((value << ctz64(mask)) & mask);
> +}
> +
> +/*
> + * Remote access to controllers. HW uses MMIOs. For now, a simple scan
> + * of the chips is good enough.
> + *
> + * TODO: Block scope support
> + */
> +static PnvXive *pnv_xive_get_ic(uint8_t blk)
> +{
> +    PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
> +    int i;
> +
> +    for (i = 0; i < pnv->num_chips; i++) {
> +        Pnv9Chip *chip9 = PNV9_CHIP(pnv->chips[i]);
> +        PnvXive *xive = &chip9->xive;
> +
> +        if (xive->chip->chip_id == blk) {
> +            return xive;
> +        }
> +    }
> +    return NULL;
> +}
> +
> +/*
> + * VST accessors for SBE, EAT, ENDT, NVT
> + *
> + * Indirect VST tables are arrays of VSDs pointing to a page (of same
> + * size). Each page is a direct VST table.
> + */
> +
> +#define XIVE_VSD_SIZE 8
> +
> +/* Indirect page size can be 4K, 64K, 2M, 16M. */
> +static uint64_t pnv_xive_vst_page_size_allowed(uint32_t page_shift)
> +{
> +     return page_shift == 12 || page_shift == 16 ||
> +         page_shift == 21 || page_shift == 24;
> +}
> +
> +static uint64_t pnv_xive_vst_size(uint64_t vsd)
> +{
> +    uint64_t vst_tsize = 1ull << (GETFIELD(VSD_TSIZE, vsd) + 12);
> +
> +    /*
> +     * Read the first descriptor to get the page size of the indirect
> +     * table.
> +     */
> +    if (VSD_INDIRECT & vsd) {
> +        uint32_t nr_pages = vst_tsize / XIVE_VSD_SIZE;
> +        uint32_t page_shift;
> +
> +        vsd = ldq_be_dma(&address_space_memory, vsd & VSD_ADDRESS_MASK);
> +        page_shift = GETFIELD(VSD_TSIZE, vsd) + 12;
> +
> +        if (!pnv_xive_vst_page_size_allowed(page_shift)) {
> +            return 0;
> +        }
> +
> +        return nr_pages * (1ull << page_shift);
> +    }
> +
> +    return vst_tsize;
> +}
> +
> +static uint64_t pnv_xive_vst_addr_direct(PnvXive *xive, uint32_t type,
> +                                         uint64_t vsd, uint32_t idx)
> +{
> +    const XiveVstInfo *info = &vst_infos[type];
> +    uint64_t vst_addr = vsd & VSD_ADDRESS_MASK;
> +
> +    return vst_addr + idx * info->size;
> +}
> +
> +static uint64_t pnv_xive_vst_addr_indirect(PnvXive *xive, uint32_t type,
> +                                           uint64_t vsd, uint32_t idx)
> +{
> +    const XiveVstInfo *info = &vst_infos[type];
> +    uint64_t vsd_addr;
> +    uint32_t vsd_idx;
> +    uint32_t page_shift;
> +    uint32_t vst_per_page;
> +
> +    /* Get the page size of the indirect table. */
> +    vsd_addr = vsd & VSD_ADDRESS_MASK;
> +    vsd = ldq_be_dma(&address_space_memory, vsd_addr);
> +
> +    if (!(vsd & VSD_ADDRESS_MASK)) {
> +        xive_error(xive, "VST: invalid %s entry %x !?", info->name, 0);
> +        return 0;
> +    }
> +
> +    page_shift = GETFIELD(VSD_TSIZE, vsd) + 12;
> +
> +    if (!pnv_xive_vst_page_size_allowed(page_shift)) {
> +        xive_error(xive, "VST: invalid %s page shift %d", info->name,
> +                   page_shift);
> +        return 0;
> +    }
> +
> +    vst_per_page = (1ull << page_shift) / info->size;
> +    vsd_idx = idx / vst_per_page;
> +
> +    /* Load the VSD we are looking for, if not already done */
> +    if (vsd_idx) {
> +        vsd_addr = vsd_addr + vsd_idx * XIVE_VSD_SIZE;
> +        vsd = ldq_be_dma(&address_space_memory, vsd_addr);
> +
> +        if (!(vsd & VSD_ADDRESS_MASK)) {
> +            xive_error(xive, "VST: invalid %s entry %x !?", info->name, 0);
> +            return 0;
> +        }
> +
> +        /*
> +         * Check that the pages have a consistent size across the
> +         * indirect table
> +         */
> +        if (page_shift != GETFIELD(VSD_TSIZE, vsd) + 12) {
> +            xive_error(xive, "VST: %s entry %x indirect page size differ !?",
> +                       info->name, idx);
> +            return 0;
> +        }
> +    }
> +
> +    return pnv_xive_vst_addr_direct(xive, type, vsd, (idx % vst_per_page));
> +}
> +
> +static uint64_t pnv_xive_vst_addr(PnvXive *xive, uint32_t type, uint8_t blk,
> +                                  uint32_t idx)
> +{
> +    const XiveVstInfo *info = &vst_infos[type];
> +    uint64_t vsd;
> +    uint32_t idx_max;
> +
> +    if (blk >= info->max_blocks) {
> +        xive_error(xive, "VST: invalid block id %d for VST %s %d !?",
> +                   blk, info->name, idx);
> +        return 0;
> +    }
> +
> +    vsd = xive->vsds[type][blk];
> +
> +    /* Remote VST access */
> +    if (GETFIELD(VSD_MODE, vsd) == VSD_MODE_FORWARD) {
> +        xive = pnv_xive_get_ic(blk);
> +
> +        return xive ? pnv_xive_vst_addr(xive, type, blk, idx) : 0;
> +    }
> +
> +    idx_max = pnv_xive_vst_size(vsd) / info->size - 1;
> +    if (idx > idx_max) {
> +#ifdef XIVE_DEBUG
> +        xive_error(xive, "VST: %s entry %x/%x out of range [ 0 .. %x ] !?",
> +                   info->name, blk, idx, idx_max);
> +#endif
> +        return 0;
> +    }
> +
> +    if (VSD_INDIRECT & vsd) {
> +        return pnv_xive_vst_addr_indirect(xive, type, vsd, idx);
> +    }
> +
> +    return pnv_xive_vst_addr_direct(xive, type, vsd, idx);
> +}
> +
> +static int pnv_xive_vst_read(PnvXive *xive, uint32_t type, uint8_t blk,
> +                             uint32_t idx, void *data)
> +{
> +    const XiveVstInfo *info = &vst_infos[type];
> +    uint64_t addr = pnv_xive_vst_addr(xive, type, blk, idx);
> +
> +    if (!addr) {
> +        return -1;
> +    }
> +
> +    cpu_physical_memory_read(addr, data, info->size);
> +    return 0;
> +}
> +
> +#define XIVE_VST_WORD_ALL -1
> +
> +static int pnv_xive_vst_write(PnvXive *xive, uint32_t type, uint8_t blk,
> +                              uint32_t idx, void *data, uint32_t word_number)
> +{
> +    const XiveVstInfo *info = &vst_infos[type];
> +    uint64_t addr = pnv_xive_vst_addr(xive, type, blk, idx);
> +
> +    if (!addr) {
> +        return -1;
> +    }
> +
> +    if (word_number == XIVE_VST_WORD_ALL) {
> +        cpu_physical_memory_write(addr, data, info->size);
> +    } else {
> +        cpu_physical_memory_write(addr + word_number * 4,
> +                                  data + word_number * 4, 4);
> +    }
> +    return 0;
> +}
> +
> +static int pnv_xive_get_end(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
> +                            XiveEND *end)
> +{
> +    return pnv_xive_vst_read(PNV_XIVE(xrtr), VST_TSEL_EQDT, blk, idx, end);
> +}
> +
> +static int pnv_xive_write_end(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
> +                              XiveEND *end, uint8_t word_number)
> +{
> +    return pnv_xive_vst_write(PNV_XIVE(xrtr), VST_TSEL_EQDT, blk, idx, end,
> +                              word_number);
> +}
> +
> +static int pnv_xive_end_update(PnvXive *xive, uint8_t blk, uint32_t idx)
> +{
> +    int i;
> +    uint64_t eqc_watch[4];
> +
> +    for (i = 0; i < ARRAY_SIZE(eqc_watch); i++) {
> +        eqc_watch[i] = cpu_to_be64(xive->regs[(VC_EQC_CWATCH_DAT0 >> 3) + i]);
> +    }
> +
> +    return pnv_xive_vst_write(xive, VST_TSEL_EQDT, blk, idx, eqc_watch,
> +                              XIVE_VST_WORD_ALL);
> +}
> +
> +static int pnv_xive_get_nvt(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
> +                            XiveNVT *nvt)
> +{
> +    return pnv_xive_vst_read(PNV_XIVE(xrtr), VST_TSEL_VPDT, blk, idx, nvt);
> +}
> +
> +static int pnv_xive_write_nvt(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
> +                              XiveNVT *nvt, uint8_t word_number)
> +{
> +    return pnv_xive_vst_write(PNV_XIVE(xrtr), VST_TSEL_VPDT, blk, idx, nvt,
> +                              word_number);
> +}
> +
> +static int pnv_xive_nvt_update(PnvXive *xive, uint8_t blk, uint32_t idx)
> +{
> +    int i;
> +    uint64_t vpc_watch[8];
> +
> +    for (i = 0; i < ARRAY_SIZE(vpc_watch); i++) {
> +        vpc_watch[i] = cpu_to_be64(xive->regs[(PC_VPC_CWATCH_DAT0 >> 3) + i]);
> +    }
> +
> +    return pnv_xive_vst_write(xive, VST_TSEL_VPDT, blk, idx, vpc_watch,
> +                              XIVE_VST_WORD_ALL);
> +}
> +
> +static int pnv_xive_get_eas(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
> +                            XiveEAS *eas)
> +{
> +    PnvXive *xive = PNV_XIVE(xrtr);
> +
> +    if (pnv_xive_get_ic(blk) != xive) {
> +        xive_error(xive, "VST: EAS %x is remote !?", XIVE_SRCNO(blk, idx));
> +        return -1;
> +    }
> +
> +    return pnv_xive_vst_read(xive, VST_TSEL_IVT, blk, idx, eas);
> +}
> +
> +static int pnv_xive_eas_update(PnvXive *xive, uint8_t blk, uint32_t idx)
> +{
> +    /* All done. */
> +    return 0;
> +}
> +
> +static XiveTCTX *pnv_xive_get_tctx(XiveRouter *xrtr, CPUState *cs)
> +{
> +    PowerPCCPU *cpu = POWERPC_CPU(cs);
> +    XiveTCTX *tctx = XIVE_TCTX(pnv_cpu_state(cpu)->intc);
> +    PnvXive *xive = NULL;
> +    CPUPPCState *env = &cpu->env;
> +    int pir = env->spr_cb[SPR_PIR].default_value;
> +
> +    /*
> +     * Perform an extra check on the HW thread enablement.
> +     *
> +     * The TIMA is shared among the chips and to identify the chip
> +     * from which the access is being done, we extract the chip id
> +     * from the PIR.
> +     */
> +    xive = pnv_xive_get_ic((pir >> 8) & 0xf);
> +    if (!xive) {
> +        return NULL;
> +    }
> +
> +    if (!(xive->regs[PC_THREAD_EN_REG0 >> 3] & PPC_BIT(pir & 0x3f))) {
> +        xive_error(PNV_XIVE(xrtr), "IC: CPU %x is not enabled", pir);
> +    }
> +
> +    return tctx;
> +}
> +
> +/*
> + * The internal sources (IPIs) of the interrupt controller have no
> + * knowledge of the XIVE chip on which they reside. Encode the block
> + * id in the source interrupt number before forwarding the source
> + * event notification to the Router. This is required on a multichip
> + * system.
> + */
> +static void pnv_xive_notify(XiveNotifier *xn, uint32_t srcno)
> +{
> +    PnvXive *xive = PNV_XIVE(xn);
> +    uint8_t blk = xive->chip->chip_id;
> +
> +    xive_router_notify(xn, XIVE_SRCNO(blk, srcno));
> +}
> +
> +/*
> + * XIVE helpers
> + */
> +
> +static uint64_t pnv_xive_vc_size(PnvXive *xive)
> +{
> +    return (~xive->regs[CQ_VC_BARM >> 3] + 1) & CQ_VC_BARM_MASK;
> +}
> +
> +static uint64_t pnv_xive_edt_shift(PnvXive *xive)
> +{
> +    return ctz64(pnv_xive_vc_size(xive) / XIVE_TABLE_EDT_MAX);
> +}
> +
> +static uint64_t pnv_xive_pc_size(PnvXive *xive)
> +{
> +    return (~xive->regs[CQ_PC_BARM >> 3] + 1) & CQ_PC_BARM_MASK;
> +}
> +
> +static uint32_t pnv_xive_nr_ipis(PnvXive *xive)
> +{
> +    uint8_t blk = xive->chip->chip_id;
> +
> +    return pnv_xive_vst_size(xive->vsds[VST_TSEL_SBE][blk]) * SBE_PER_BYTE;
> +}
> +
> +static uint32_t pnv_xive_nr_ends(PnvXive *xive)
> +{
> +    uint8_t blk = xive->chip->chip_id;
> +
> +    return pnv_xive_vst_size(xive->vsds[VST_TSEL_EQDT][blk])
> +        / vst_infos[VST_TSEL_EQDT].size;
> +}
> +
> +/*
> + * EDT Table
> + *
> + * The Virtualization Controller MMIO region containing the IPI ESB
> + * pages and END ESB pages is sub-divided into "sets" which map
> + * portions of the VC region to the different ESB pages. It is
> + * configured at runtime through the EDT "Domain Table" to let the
> + * firmware decide how to split the VC address space between IPI ESB
> + * pages and END ESB pages.
> + */
> +
> +/*
> + * Computes the overall size of the IPI or the END ESB pages
> + */
> +static uint64_t pnv_xive_edt_size(PnvXive *xive, uint64_t type)
> +{
> +    uint64_t edt_size = 1ull << pnv_xive_edt_shift(xive);
> +    uint64_t size = 0;
> +    int i;
> +
> +    for (i = 0; i < XIVE_TABLE_EDT_MAX; i++) {
> +        uint64_t edt_type = GETFIELD(CQ_TDR_EDT_TYPE, xive->edt[i]);
> +
> +        if (edt_type == type) {
> +            size += edt_size;
> +        }
> +    }
> +
> +    return size;
> +}
> +
> +/*
> + * Maps an offset of the VC region in the IPI or END region using the
> + * layout defined by the EDT "Domaine Table"
> + */
> +static uint64_t pnv_xive_edt_offset(PnvXive *xive, uint64_t vc_offset,
> +                                              uint64_t type)
> +{
> +    int i;
> +    uint64_t edt_size = 1ull << pnv_xive_edt_shift(xive);
> +    uint64_t edt_offset = vc_offset;
> +
> +    for (i = 0; i < XIVE_TABLE_EDT_MAX && (i * edt_size) < vc_offset; i++) {
> +        uint64_t edt_type = GETFIELD(CQ_TDR_EDT_TYPE, xive->edt[i]);
> +
> +        if (edt_type != type) {
> +            edt_offset -= edt_size;
> +        }
> +    }
> +
> +    return edt_offset;
> +}
> +
> +static void pnv_xive_edt_resize(PnvXive *xive)
> +{
> +    uint64_t ipi_edt_size = pnv_xive_edt_size(xive, CQ_TDR_EDT_IPI);
> +    uint64_t end_edt_size = pnv_xive_edt_size(xive, CQ_TDR_EDT_EQ);
> +
> +    memory_region_set_size(&xive->ipi_edt_mmio, ipi_edt_size);
> +    memory_region_add_subregion(&xive->ipi_mmio, 0, &xive->ipi_edt_mmio);
> +
> +    memory_region_set_size(&xive->end_edt_mmio, end_edt_size);
> +    memory_region_add_subregion(&xive->end_mmio, 0, &xive->end_edt_mmio);
> +}
> +
> +/*
> + * XIVE Table configuration. Only EDT is supported.
> + */
> +static int pnv_xive_table_set_data(PnvXive *xive, uint64_t val)
> +{
> +    uint64_t tsel = xive->regs[CQ_TAR >> 3] & CQ_TAR_TSEL;
> +    uint8_t tsel_index = GETFIELD(CQ_TAR_TSEL_INDEX, xive->regs[CQ_TAR >> 3]);
> +    uint64_t *xive_table;
> +    uint8_t max_index;
> +
> +    switch (tsel) {
> +    case CQ_TAR_TSEL_BLK:
> +        max_index = ARRAY_SIZE(xive->blk);
> +        xive_table = xive->blk;
> +        break;
> +    case CQ_TAR_TSEL_MIG:
> +        max_index = ARRAY_SIZE(xive->mig);
> +        xive_table = xive->mig;
> +        break;
> +    case CQ_TAR_TSEL_EDT:
> +        max_index = ARRAY_SIZE(xive->edt);
> +        xive_table = xive->edt;
> +        break;
> +    case CQ_TAR_TSEL_VDT:
> +        max_index = ARRAY_SIZE(xive->vdt);
> +        xive_table = xive->vdt;
> +        break;
> +    default:
> +        xive_error(xive, "IC: invalid table %d", (int) tsel);
> +        return -1;
> +    }
> +
> +    if (tsel_index >= max_index) {
> +        xive_error(xive, "IC: invalid index %d", (int) tsel_index);
> +        return -1;
> +    }
> +
> +    xive_table[tsel_index] = val;
> +
> +    if (xive->regs[CQ_TAR >> 3] & CQ_TAR_TBL_AUTOINC) {
> +        xive->regs[CQ_TAR >> 3] =
> +            SETFIELD(CQ_TAR_TSEL_INDEX, xive->regs[CQ_TAR >> 3], ++tsel_index);
> +    }
> +
> +    /*
> +     * EDT configuration is complete. Resize the MMIO windows exposing
> +     * the IPI and the END ESBs in the VC region.
> +     */
> +    if (tsel == CQ_TAR_TSEL_EDT && tsel_index == ARRAY_SIZE(xive->edt)) {
> +        pnv_xive_edt_resize(xive);
> +    }
> +
> +    return 0;
> +}
> +
> +/*
> + * Virtual Structure Tables (VST) configuration
> + */
> +static void pnv_xive_vst_set_exclusive(PnvXive *xive, uint8_t type,
> +                                       uint8_t blk, uint64_t vsd)
> +{
> +    XiveENDSource *end_xsrc = &xive->end_source;
> +    XiveSource *xsrc = &xive->ipi_source;
> +    const XiveVstInfo *info = &vst_infos[type];
> +    uint32_t page_shift = GETFIELD(VSD_TSIZE, vsd) + 12;
> +    uint64_t vst_addr = vsd & VSD_ADDRESS_MASK;
> +
> +    /* Basic checks */
> +
> +    if (VSD_INDIRECT & vsd) {
> +        if (!(xive->regs[VC_GLOBAL_CONFIG >> 3] & VC_GCONF_INDIRECT)) {
> +            xive_error(xive, "VST: %s indirect tables are not enabled",
> +                       info->name);
> +            return;
> +        }
> +
> +        if (!pnv_xive_vst_page_size_allowed(page_shift)) {
> +            xive_error(xive, "VST: invalid %s page shift %d", info->name,
> +                       page_shift);
> +            return;
> +        }
> +    }
> +
> +    if (!QEMU_IS_ALIGNED(vst_addr, 1ull << page_shift)) {
> +        xive_error(xive, "VST: %s table address 0x%"PRIx64" is not aligned with"
> +                   " page shift %d", info->name, vst_addr, page_shift);
> +        return;
> +    }
> +
> +    /* Record the table configuration (in SRAM on HW) */
> +    xive->vsds[type][blk] = vsd;
> +
> +    /* Now tune the models with the configuration provided by the FW */
> +
> +    switch (type) {
> +    case VST_TSEL_IVT:  /* Nothing to be done */
> +        break;
> +
> +    case VST_TSEL_EQDT:
> +        /*
> +         * Backing store pages for the END. Compute the number of ENDs
> +         * provisioned by FW and resize the END ESB window accordingly.
> +         */
> +        memory_region_set_size(&end_xsrc->esb_mmio, pnv_xive_nr_ends(xive) *
> +                               (1ull << (end_xsrc->esb_shift + 1)));
> +        memory_region_add_subregion(&xive->end_edt_mmio, 0,
> +                                    &end_xsrc->esb_mmio);
> +        break;
> +
> +    case VST_TSEL_SBE:
> +        /*
> +         * Backing store pages for the source PQ bits. The model does
> +         * not use these PQ bits backed in RAM because the XiveSource
> +         * model has its own. Compute the number of IRQs provisioned
> +         * by FW and resize the IPI ESB window accordingly.
> +         */
> +        memory_region_set_size(&xsrc->esb_mmio, pnv_xive_nr_ipis(xive) *
> +                               (1ull << xsrc->esb_shift));
> +        memory_region_add_subregion(&xive->ipi_edt_mmio, 0, &xsrc->esb_mmio);
> +        break;
> +
> +    case VST_TSEL_VPDT: /* Not modeled */
> +    case VST_TSEL_IRQ:  /* Not modeled */
> +        /*
> +         * These tables contains the backing store pages for the
> +         * interrupt fifos of the VC sub-engine in case of overflow.
> +         */
> +        break;
> +
> +    default:
> +        g_assert_not_reached();
> +    }
> +}
> +
> +/*
> + * Both PC and VC sub-engines are configured as each use the Virtual
> + * Structure Tables : SBE, EAS, END and NVT.
> + */
> +static void pnv_xive_vst_set_data(PnvXive *xive, uint64_t vsd, bool pc_engine)
> +{
> +    uint8_t mode = GETFIELD(VSD_MODE, vsd);
> +    uint8_t type = GETFIELD(VST_TABLE_SELECT,
> +                            xive->regs[VC_VSD_TABLE_ADDR >> 3]);
> +    uint8_t blk = GETFIELD(VST_TABLE_BLOCK,
> +                           xive->regs[VC_VSD_TABLE_ADDR >> 3]);
> +    uint64_t vst_addr = vsd & VSD_ADDRESS_MASK;
> +
> +    if (type > VST_TSEL_IRQ) {
> +        xive_error(xive, "VST: invalid table type %d", type);
> +        return;
> +    }
> +
> +    if (blk >= vst_infos[type].max_blocks) {
> +        xive_error(xive, "VST: invalid block id %d for"
> +                      " %s table", blk, vst_infos[type].name);
> +        return;
> +    }
> +
> +    /*
> +     * Only take the VC sub-engine configuration into account because
> +     * the XiveRouter model combines both VC and PC sub-engines
> +     */
> +    if (pc_engine) {
> +        return;
> +    }
> +
> +    if (!vst_addr) {
> +        xive_error(xive, "VST: invalid %s table address", vst_infos[type].name);
> +        return;
> +    }
> +
> +    switch (mode) {
> +    case VSD_MODE_FORWARD:
> +        xive->vsds[type][blk] = vsd;
> +        break;
> +
> +    case VSD_MODE_EXCLUSIVE:
> +        pnv_xive_vst_set_exclusive(xive, type, blk, vsd);
> +        break;
> +
> +    default:
> +        xive_error(xive, "VST: unsupported table mode %d", mode);
> +        return;
> +    }
> +}
> +
> +/*
> + * Interrupt controller MMIO region. The layout is compatible between
> + * 4K and 64K pages :
> + *
> + * Page 0           sub-engine BARs
> + *  0x000 - 0x3FF   IC registers
> + *  0x400 - 0x7FF   PC registers
> + *  0x800 - 0xFFF   VC registers
> + *
> + * Page 1           Notify page (writes only)
> + *  0x000 - 0x7FF   HW interrupt triggers (PSI, PHB)
> + *  0x800 - 0xFFF   forwards and syncs
> + *
> + * Page 2           LSI Trigger page (writes only) (not modeled)
> + * Page 3           LSI SB EOI page (reads only) (not modeled)
> + *
> + * Page 4-7         indirect TIMA
> + */
> +
> +/*
> + * IC - registers MMIO
> + */
> +static void pnv_xive_ic_reg_write(void *opaque, hwaddr offset,
> +                                  uint64_t val, unsigned size)
> +{
> +    PnvXive *xive = PNV_XIVE(opaque);
> +    MemoryRegion *sysmem = get_system_memory();
> +    uint32_t reg = offset >> 3;
> +    bool is_chip0 = xive->chip->chip_id == 0;
> +
> +    switch (offset) {
> +
> +    /*
> +     * XIVE CQ (PowerBus bridge) settings
> +     */
> +    case CQ_MSGSND:     /* msgsnd for doorbells */
> +    case CQ_FIRMASK_OR: /* FIR error reporting */
> +        break;
> +    case CQ_PBI_CTL:
> +        if (val & CQ_PBI_PC_64K) {
> +            xive->pc_shift = 16;
> +        }
> +        if (val & CQ_PBI_VC_64K) {
> +            xive->vc_shift = 16;
> +        }
> +        break;
> +    case CQ_CFG_PB_GEN: /* PowerBus General Configuration */
> +        /*
> +         * TODO: CQ_INT_ADDR_OPT for 1-block-per-chip mode
> +         */
> +        break;
> +
> +    /*
> +     * XIVE Virtualization Controller settings
> +     */
> +    case VC_GLOBAL_CONFIG:
> +        break;
> +
> +    /*
> +     * XIVE Presenter Controller settings
> +     */
> +    case PC_GLOBAL_CONFIG:
> +        /*
> +         * PC_GCONF_CHIPID_OVR
> +         *   Overrides Int command Chip ID with the Chip ID field (DEBUG)
> +         */
> +        break;
> +    case PC_TCTXT_CFG:
> +        /*
> +         * TODO: block group support
> +         *
> +         * PC_TCTXT_CFG_BLKGRP_EN
> +         * PC_TCTXT_CFG_HARD_CHIPID_BLK :
> +         *   Moves the chipid into block field for hardwired CAM compares.
> +         *   Block offset value is adjusted to 0b0..01 & ThrdId
> +         *
> +         *   Will require changes in xive_presenter_tctx_match(). I am
> +         *   not sure how to handle that yet.
> +         */
> +
> +        /* Overrides hardwired chip ID with the chip ID field */
> +        if (val & PC_TCTXT_CHIPID_OVERRIDE) {
> +            xive->tctx_chipid = GETFIELD(PC_TCTXT_CHIPID, val);
> +        }
> +        break;
> +    case PC_TCTXT_TRACK:
> +        /*
> +         * PC_TCTXT_TRACK_EN:
> +         *   enable block tracking and exchange of block ownership
> +         *   information between Interrupt controllers
> +         */
> +        break;
> +
> +    /*
> +     * Misc settings
> +     */
> +    case VC_SBC_CONFIG: /* Store EOI configuration */
> +        /*
> +         * Configure store EOI if required by firwmare (skiboot has removed
> +         * support recently though)
> +         */
> +        if (val & (VC_SBC_CONF_CPLX_CIST | VC_SBC_CONF_CIST_BOTH)) {
> +            object_property_set_int(OBJECT(&xive->ipi_source),
> +                                    XIVE_SRC_STORE_EOI, "flags", &error_fatal);
> +        }
> +        break;
> +
> +    case VC_EQC_CONFIG: /* TODO: silent escalation */
> +    case VC_AIB_TX_ORDER_TAG2: /* relax ordering */
> +        break;
> +
> +    /*
> +     * XIVE BAR settings (XSCOM only)
> +     */
> +    case CQ_RST_CTL:
> +        /* bit4: resets all BAR registers */
> +        break;
> +
> +    case CQ_IC_BAR: /* IC BAR. 8 pages */
> +        xive->ic_shift = val & CQ_IC_BAR_64K ? 16 : 12;
> +        if (!(val & CQ_IC_BAR_VALID)) {
> +            xive->ic_base = 0;
> +            if (xive->regs[reg] & CQ_IC_BAR_VALID) {
> +                memory_region_del_subregion(&xive->ic_mmio,
> +                                            &xive->ic_reg_mmio);
> +                memory_region_del_subregion(&xive->ic_mmio,
> +                                            &xive->ic_notify_mmio);
> +                memory_region_del_subregion(&xive->ic_mmio,
> +                                            &xive->ic_lsi_mmio);
> +                memory_region_del_subregion(&xive->ic_mmio,
> +                                            &xive->tm_indirect_mmio);
> +
> +                memory_region_del_subregion(sysmem, &xive->ic_mmio);
> +            }
> +        } else {
> +            xive->ic_base = val & ~(CQ_IC_BAR_VALID | CQ_IC_BAR_64K);
> +            if (!(xive->regs[reg] & CQ_IC_BAR_VALID)) {
> +                memory_region_add_subregion(sysmem, xive->ic_base,
> +                                            &xive->ic_mmio);
> +
> +                memory_region_add_subregion(&xive->ic_mmio,  0,
> +                                            &xive->ic_reg_mmio);
> +                memory_region_add_subregion(&xive->ic_mmio,
> +                                            1ul << xive->ic_shift,
> +                                            &xive->ic_notify_mmio);
> +                memory_region_add_subregion(&xive->ic_mmio,
> +                                            2ul << xive->ic_shift,
> +                                            &xive->ic_lsi_mmio);
> +                memory_region_add_subregion(&xive->ic_mmio,
> +                                            4ull << xive->ic_shift,
> +                                            &xive->tm_indirect_mmio);
> +            }
> +        }
> +        break;
> +
> +    case CQ_TM1_BAR: /* TM BAR. 4 pages. Map only once */
> +    case CQ_TM2_BAR: /* second TM BAR. for hotplug. Not modeled */
> +        xive->tm_shift = val & CQ_TM_BAR_64K ? 16 : 12;
> +        if (!(val & CQ_TM_BAR_VALID)) {
> +            xive->tm_base = 0;
> +            if (xive->regs[reg] & CQ_TM_BAR_VALID && is_chip0) {
> +                memory_region_del_subregion(sysmem, &xive->tm_mmio);
> +            }
> +        } else {
> +            xive->tm_base = val & ~(CQ_TM_BAR_VALID | CQ_TM_BAR_64K);
> +            if (!(xive->regs[reg] & CQ_TM_BAR_VALID) && is_chip0) {
> +                memory_region_add_subregion(sysmem, xive->tm_base,
> +                                            &xive->tm_mmio);
> +            }
> +        }
> +        break;
> +
> +    case CQ_PC_BARM:
> +        xive->regs[reg] = val;
> +        memory_region_set_size(&xive->pc_mmio, pnv_xive_pc_size(xive));
> +        break;
> +    case CQ_PC_BAR: /* From 32M to 512G */
> +        if (!(val & CQ_PC_BAR_VALID)) {
> +            xive->pc_base = 0;
> +            if (xive->regs[reg] & CQ_PC_BAR_VALID) {
> +                memory_region_del_subregion(sysmem, &xive->pc_mmio);
> +            }
> +        } else {
> +            xive->pc_base = val & ~(CQ_PC_BAR_VALID);
> +            if (!(xive->regs[reg] & CQ_PC_BAR_VALID)) {
> +                memory_region_add_subregion(sysmem, xive->pc_base,
> +                                            &xive->pc_mmio);
> +            }
> +        }
> +        break;
> +
> +    case CQ_VC_BARM:
> +        xive->regs[reg] = val;
> +        memory_region_set_size(&xive->vc_mmio, pnv_xive_vc_size(xive));
> +        break;
> +    case CQ_VC_BAR: /* From 64M to 4TB */
> +        if (!(val & CQ_VC_BAR_VALID)) {
> +            xive->vc_base = 0;
> +            if (xive->regs[reg] & CQ_VC_BAR_VALID) {
> +                memory_region_del_subregion(sysmem, &xive->vc_mmio);
> +            }
> +        } else {
> +            xive->vc_base = val & ~(CQ_VC_BAR_VALID);
> +            if (!(xive->regs[reg] & CQ_VC_BAR_VALID)) {
> +                memory_region_add_subregion(sysmem, xive->vc_base,
> +                                            &xive->vc_mmio);
> +            }
> +        }
> +        break;
> +
> +    /*
> +     * XIVE Table settings.
> +     */
> +    case CQ_TAR: /* Table Address */
> +        break;
> +    case CQ_TDR: /* Table Data */
> +        pnv_xive_table_set_data(xive, val);
> +        break;
> +
> +    /*
> +     * XIVE VC & PC Virtual Structure Table settings
> +     */
> +    case VC_VSD_TABLE_ADDR:
> +    case PC_VSD_TABLE_ADDR: /* Virtual table selector */
> +        break;
> +    case VC_VSD_TABLE_DATA: /* Virtual table setting */
> +    case PC_VSD_TABLE_DATA:
> +        pnv_xive_vst_set_data(xive, val, offset == PC_VSD_TABLE_DATA);
> +        break;
> +
> +    /*
> +     * Interrupt fifo overflow in memory backing store (Not modeled)
> +     */
> +    case VC_IRQ_CONFIG_IPI:
> +    case VC_IRQ_CONFIG_HW:
> +    case VC_IRQ_CONFIG_CASCADE1:
> +    case VC_IRQ_CONFIG_CASCADE2:
> +    case VC_IRQ_CONFIG_REDIST:
> +    case VC_IRQ_CONFIG_IPI_CASC:
> +        break;
> +
> +    /*
> +     * XIVE hardware thread enablement
> +     */
> +    case PC_THREAD_EN_REG0: /* Physical Thread Enable */
> +    case PC_THREAD_EN_REG1: /* Physical Thread Enable (fused core) */
> +        break;
> +
> +    case PC_THREAD_EN_REG0_SET:
> +        xive->regs[PC_THREAD_EN_REG0 >> 3] |= val;
> +        break;
> +    case PC_THREAD_EN_REG1_SET:
> +        xive->regs[PC_THREAD_EN_REG1 >> 3] |= val;
> +        break;
> +    case PC_THREAD_EN_REG0_CLR:
> +        xive->regs[PC_THREAD_EN_REG0 >> 3] &= ~val;
> +        break;
> +    case PC_THREAD_EN_REG1_CLR:
> +        xive->regs[PC_THREAD_EN_REG1 >> 3] &= ~val;
> +        break;
> +
> +    /*
> +     * Indirect TIMA access set up. Defines the PIR of the HW thread
> +     * to use.
> +     */
> +    case PC_TCTXT_INDIR0 ... PC_TCTXT_INDIR3:
> +        break;
> +
> +    /*
> +     * XIVE PC & VC cache updates for EAS, NVT and END
> +     */
> +    case VC_IVC_SCRUB_MASK:
> +        break;
> +    case VC_IVC_SCRUB_TRIG:
> +        pnv_xive_eas_update(xive, GETFIELD(PC_SCRUB_BLOCK_ID, val),
> +                            GETFIELD(VC_SCRUB_OFFSET, val));
> +        break;
> +
> +    case VC_EQC_SCRUB_MASK:
> +    case VC_EQC_CWATCH_SPEC:
> +    case VC_EQC_CWATCH_DAT0 ... VC_EQC_CWATCH_DAT3:
> +        break;
> +    case VC_EQC_SCRUB_TRIG:
> +        pnv_xive_end_update(xive, GETFIELD(VC_SCRUB_BLOCK_ID, val),
> +                            GETFIELD(VC_SCRUB_OFFSET, val));
> +        break;
> +
> +    case PC_VPC_SCRUB_MASK:
> +    case PC_VPC_CWATCH_SPEC:
> +    case PC_VPC_CWATCH_DAT0 ... PC_VPC_CWATCH_DAT7:
> +        break;
> +    case PC_VPC_SCRUB_TRIG:
> +        pnv_xive_nvt_update(xive, GETFIELD(PC_SCRUB_BLOCK_ID, val),
> +                           GETFIELD(PC_SCRUB_OFFSET, val));
> +        break;
> +
> +
> +    /*
> +     * XIVE PC & VC cache invalidation
> +     */
> +    case PC_AT_KILL:
> +        break;
> +    case VC_AT_MACRO_KILL:
> +        break;
> +    case PC_AT_KILL_MASK:
> +    case VC_AT_MACRO_KILL_MASK:
> +        break;
> +
> +    default:
> +        xive_error(xive, "IC: invalid write to reg=0x%"HWADDR_PRIx, offset);
> +        return;
> +    }
> +
> +    xive->regs[reg] = val;
> +}
> +
> +static uint64_t pnv_xive_ic_reg_read(void *opaque, hwaddr offset, unsigned size)
> +{
> +    PnvXive *xive = PNV_XIVE(opaque);
> +    uint64_t val = 0;
> +    uint32_t reg = offset >> 3;
> +
> +    switch (offset) {
> +    case CQ_CFG_PB_GEN:
> +    case CQ_IC_BAR:
> +    case CQ_TM1_BAR:
> +    case CQ_TM2_BAR:
> +    case CQ_PC_BAR:
> +    case CQ_PC_BARM:
> +    case CQ_VC_BAR:
> +    case CQ_VC_BARM:
> +    case CQ_TAR:
> +    case CQ_TDR:
> +    case CQ_PBI_CTL:
> +
> +    case PC_TCTXT_CFG:
> +    case PC_TCTXT_TRACK:
> +    case PC_TCTXT_INDIR0:
> +    case PC_TCTXT_INDIR1:
> +    case PC_TCTXT_INDIR2:
> +    case PC_TCTXT_INDIR3:
> +    case PC_GLOBAL_CONFIG:
> +
> +    case PC_VPC_SCRUB_MASK:
> +    case PC_VPC_CWATCH_SPEC:
> +    case PC_VPC_CWATCH_DAT0:
> +    case PC_VPC_CWATCH_DAT1:
> +    case PC_VPC_CWATCH_DAT2:
> +    case PC_VPC_CWATCH_DAT3:
> +    case PC_VPC_CWATCH_DAT4:
> +    case PC_VPC_CWATCH_DAT5:
> +    case PC_VPC_CWATCH_DAT6:
> +    case PC_VPC_CWATCH_DAT7:
> +
> +    case VC_GLOBAL_CONFIG:
> +    case VC_AIB_TX_ORDER_TAG2:
> +
> +    case VC_IRQ_CONFIG_IPI:
> +    case VC_IRQ_CONFIG_HW:
> +    case VC_IRQ_CONFIG_CASCADE1:
> +    case VC_IRQ_CONFIG_CASCADE2:
> +    case VC_IRQ_CONFIG_REDIST:
> +    case VC_IRQ_CONFIG_IPI_CASC:
> +
> +    case VC_EQC_SCRUB_MASK:
> +    case VC_EQC_CWATCH_DAT0:
> +    case VC_EQC_CWATCH_DAT1:
> +    case VC_EQC_CWATCH_DAT2:
> +    case VC_EQC_CWATCH_DAT3:
> +
> +    case VC_EQC_CWATCH_SPEC:
> +    case VC_IVC_SCRUB_MASK:
> +    case VC_SBC_CONFIG:
> +    case VC_AT_MACRO_KILL_MASK:
> +    case VC_VSD_TABLE_ADDR:
> +    case PC_VSD_TABLE_ADDR:
> +    case VC_VSD_TABLE_DATA:
> +    case PC_VSD_TABLE_DATA:
> +    case PC_THREAD_EN_REG0:
> +    case PC_THREAD_EN_REG1:
> +        val = xive->regs[reg];
> +        break;
> +
> +    /*
> +     * XIVE hardware thread enablement
> +     */
> +    case PC_THREAD_EN_REG0_SET:
> +    case PC_THREAD_EN_REG0_CLR:
> +        val = xive->regs[PC_THREAD_EN_REG0 >> 3];
> +        break;
> +    case PC_THREAD_EN_REG1_SET:
> +    case PC_THREAD_EN_REG1_CLR:
> +        val = xive->regs[PC_THREAD_EN_REG1 >> 3];
> +        break;
> +
> +    case CQ_MSGSND: /* Identifies which cores have msgsnd enabled. */
> +        val = 0xffffff0000000000;
> +        break;
> +
> +    /*
> +     * XIVE PC & VC cache updates for EAS, NVT and END
> +     */
> +    case PC_VPC_SCRUB_TRIG:
> +    case VC_IVC_SCRUB_TRIG:
> +    case VC_EQC_SCRUB_TRIG:
> +        xive->regs[reg] &= ~VC_SCRUB_VALID;
> +        val = xive->regs[reg];
> +        break;
> +
> +    /*
> +     * XIVE PC & VC cache invalidation
> +     */
> +    case PC_AT_KILL:
> +        xive->regs[reg] &= ~PC_AT_KILL_VALID;
> +        val = xive->regs[reg];
> +        break;
> +    case VC_AT_MACRO_KILL:
> +        xive->regs[reg] &= ~VC_KILL_VALID;
> +        val = xive->regs[reg];
> +        break;
> +
> +    /*
> +     * XIVE synchronisation
> +     */
> +    case VC_EQC_CONFIG:
> +        val = VC_EQC_SYNC_MASK;
> +        break;
> +
> +    default:
> +        xive_error(xive, "IC: invalid read reg=0x%"HWADDR_PRIx, offset);
> +    }
> +
> +    return val;
> +}
> +
> +static const MemoryRegionOps pnv_xive_ic_reg_ops = {
> +    .read = pnv_xive_ic_reg_read,
> +    .write = pnv_xive_ic_reg_write,
> +    .endianness = DEVICE_BIG_ENDIAN,
> +    .valid = {
> +        .min_access_size = 8,
> +        .max_access_size = 8,
> +    },
> +    .impl = {
> +        .min_access_size = 8,
> +        .max_access_size = 8,
> +    },
> +};
> +
> +/*
> + * IC - Notify MMIO port page (write only)
> + */
> +#define PNV_XIVE_FORWARD_IPI        0x800 /* Forward IPI */
> +#define PNV_XIVE_FORWARD_HW         0x880 /* Forward HW */
> +#define PNV_XIVE_FORWARD_OS_ESC     0x900 /* Forward OS escalation */
> +#define PNV_XIVE_FORWARD_HW_ESC     0x980 /* Forward Hyp escalation */
> +#define PNV_XIVE_FORWARD_REDIS      0xa00 /* Forward Redistribution */
> +#define PNV_XIVE_RESERVED5          0xa80 /* Cache line 5 PowerBUS operation */
> +#define PNV_XIVE_RESERVED6          0xb00 /* Cache line 6 PowerBUS operation */
> +#define PNV_XIVE_RESERVED7          0xb80 /* Cache line 7 PowerBUS operation */
> +
> +/* VC synchronisation */
> +#define PNV_XIVE_SYNC_IPI           0xc00 /* Sync IPI */
> +#define PNV_XIVE_SYNC_HW            0xc80 /* Sync HW */
> +#define PNV_XIVE_SYNC_OS_ESC        0xd00 /* Sync OS escalation */
> +#define PNV_XIVE_SYNC_HW_ESC        0xd80 /* Sync Hyp escalation */
> +#define PNV_XIVE_SYNC_REDIS         0xe00 /* Sync Redistribution */
> +
> +/* PC synchronisation */
> +#define PNV_XIVE_SYNC_PULL          0xe80 /* Sync pull context */
> +#define PNV_XIVE_SYNC_PUSH          0xf00 /* Sync push context */
> +#define PNV_XIVE_SYNC_VPC           0xf80 /* Sync remove VPC store */
> +
> +static void pnv_xive_ic_hw_trigger(PnvXive *xive, hwaddr addr, uint64_t val)
> +{
> +    /*
> +     * Forward the source event notification directly to the Router.
> +     * The source interrupt number should already be correctly encoded
> +     * with the chip block id by the sending device (PHB, PSI).
> +     */
> +    xive_router_notify(XIVE_NOTIFIER(xive), val);
> +}
> +
> +static void pnv_xive_ic_notify_write(void *opaque, hwaddr addr, uint64_t val,
> +                                     unsigned size)
> +{
> +    PnvXive *xive = PNV_XIVE(opaque);
> +
> +    /* VC: HW triggers */
> +    switch (addr) {
> +    case 0x000 ... 0x7FF:
> +        pnv_xive_ic_hw_trigger(opaque, addr, val);
> +        break;
> +
> +    /* VC: Forwarded IRQs */
> +    case PNV_XIVE_FORWARD_IPI:
> +    case PNV_XIVE_FORWARD_HW:
> +    case PNV_XIVE_FORWARD_OS_ESC:
> +    case PNV_XIVE_FORWARD_HW_ESC:
> +    case PNV_XIVE_FORWARD_REDIS:
> +        /* TODO: forwarded IRQs. Should be like HW triggers */
> +        xive_error(xive, "IC: forwarded at @0x%"HWADDR_PRIx" IRQ 0x%"PRIx64,
> +                   addr, val);
> +        break;
> +
> +    /* VC syncs */
> +    case PNV_XIVE_SYNC_IPI:
> +    case PNV_XIVE_SYNC_HW:
> +    case PNV_XIVE_SYNC_OS_ESC:
> +    case PNV_XIVE_SYNC_HW_ESC:
> +    case PNV_XIVE_SYNC_REDIS:
> +        break;
> +
> +    /* PC syncs */
> +    case PNV_XIVE_SYNC_PULL:
> +    case PNV_XIVE_SYNC_PUSH:
> +    case PNV_XIVE_SYNC_VPC:
> +        break;
> +
> +    default:
> +        xive_error(xive, "IC: invalid notify write @%"HWADDR_PRIx, addr);
> +    }
> +}
> +
> +static uint64_t pnv_xive_ic_notify_read(void *opaque, hwaddr addr,
> +                                        unsigned size)
> +{
> +    PnvXive *xive = PNV_XIVE(opaque);
> +
> +    /* loads are invalid */
> +    xive_error(xive, "IC: invalid notify read @%"HWADDR_PRIx, addr);
> +    return -1;
> +}
> +
> +static const MemoryRegionOps pnv_xive_ic_notify_ops = {
> +    .read = pnv_xive_ic_notify_read,
> +    .write = pnv_xive_ic_notify_write,
> +    .endianness = DEVICE_BIG_ENDIAN,
> +    .valid = {
> +        .min_access_size = 8,
> +        .max_access_size = 8,
> +    },
> +    .impl = {
> +        .min_access_size = 8,
> +        .max_access_size = 8,
> +    },
> +};
> +
> +/*
> + * IC - LSI MMIO handlers (not modeled)
> + */
> +
> +static void pnv_xive_ic_lsi_write(void *opaque, hwaddr addr,
> +                              uint64_t val, unsigned size)
> +{
> +    PnvXive *xive = PNV_XIVE(opaque);
> +
> +    xive_error(xive, "IC: LSI invalid write @%"HWADDR_PRIx, addr);
> +}
> +
> +static uint64_t pnv_xive_ic_lsi_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    PnvXive *xive = PNV_XIVE(opaque);
> +
> +    xive_error(xive, "IC: LSI invalid read @%"HWADDR_PRIx, addr);
> +    return -1;
> +}
> +
> +static const MemoryRegionOps pnv_xive_ic_lsi_ops = {
> +    .read = pnv_xive_ic_lsi_read,
> +    .write = pnv_xive_ic_lsi_write,
> +    .endianness = DEVICE_BIG_ENDIAN,
> +    .valid = {
> +        .min_access_size = 8,
> +        .max_access_size = 8,
> +    },
> +    .impl = {
> +        .min_access_size = 8,
> +        .max_access_size = 8,
> +    },
> +};
> +
> +/*
> + * IC - Indirect TIMA MMIO handlers
> + */
> +
> +/*
> + * When the TIMA is accessed from the indirect page, the thread id
> + * (PIR) has to be configured in the IC registers before. This is used
> + * for resets and for debug purpose also.
> + */
> +static XiveTCTX *pnv_xive_get_indirect_tctx(PnvXive *xive)
> +{
> +    uint64_t tctxt_indir = xive->regs[PC_TCTXT_INDIR0 >> 3];
> +    PowerPCCPU *cpu = NULL;
> +    int pir;
> +
> +    if (!(tctxt_indir & PC_TCTXT_INDIR_VALID)) {
> +        xive_error(xive, "IC: no indirect TIMA access in progress");
> +        return NULL;
> +    }
> +
> +    pir = GETFIELD(PC_TCTXT_INDIR_THRDID, tctxt_indir) & 0xff;
> +    cpu = ppc_get_vcpu_by_pir(pir);
> +    if (!cpu) {
> +        xive_error(xive, "IC: invalid PIR %x for indirect access", pir);
> +        return NULL;
> +    }
> +
> +    /* Check that HW thread is XIVE enabled */
> +    if (!(xive->regs[PC_THREAD_EN_REG0 >> 3] & PPC_BIT(pir & 0x3f))) {
> +        xive_error(xive, "IC: CPU %x is not enabled", pir);
> +    }
> +
> +    return XIVE_TCTX(pnv_cpu_state(cpu)->intc);
> +}
> +
> +static void xive_tm_indirect_write(void *opaque, hwaddr offset,
> +                                   uint64_t value, unsigned size)
> +{
> +    XiveTCTX *tctx = pnv_xive_get_indirect_tctx(PNV_XIVE(opaque));
> +
> +    xive_tctx_tm_write(tctx, offset, value, size);
> +}
> +
> +static uint64_t xive_tm_indirect_read(void *opaque, hwaddr offset,
> +                                      unsigned size)
> +{
> +    XiveTCTX *tctx = pnv_xive_get_indirect_tctx(PNV_XIVE(opaque));
> +
> +    return xive_tctx_tm_read(tctx, offset, size);
> +}
> +
> +static const MemoryRegionOps xive_tm_indirect_ops = {
> +    .read = xive_tm_indirect_read,
> +    .write = xive_tm_indirect_write,
> +    .endianness = DEVICE_BIG_ENDIAN,
> +    .valid = {
> +        .min_access_size = 1,
> +        .max_access_size = 8,
> +    },
> +    .impl = {
> +        .min_access_size = 1,
> +        .max_access_size = 8,
> +    },
> +};
> +
> +/*
> + * Interrupt controller XSCOM region.
> + */
> +static uint64_t pnv_xive_xscom_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    switch (addr >> 3) {
> +    case X_VC_EQC_CONFIG:
> +        /* FIXME (skiboot): This is the only XSCOM load. Bizarre. */
> +        return VC_EQC_SYNC_MASK;
> +    default:
> +        return pnv_xive_ic_reg_read(opaque, addr, size);
> +    }
> +}
> +
> +static void pnv_xive_xscom_write(void *opaque, hwaddr addr,
> +                                uint64_t val, unsigned size)
> +{
> +    pnv_xive_ic_reg_write(opaque, addr, val, size);
> +}
> +
> +static const MemoryRegionOps pnv_xive_xscom_ops = {
> +    .read = pnv_xive_xscom_read,
> +    .write = pnv_xive_xscom_write,
> +    .endianness = DEVICE_BIG_ENDIAN,
> +    .valid = {
> +        .min_access_size = 8,
> +        .max_access_size = 8,
> +    },
> +    .impl = {
> +        .min_access_size = 8,
> +        .max_access_size = 8,
> +    }
> +};
> +
> +/*
> + * Virtualization Controller MMIO region containing the IPI and END ESB pages
> + */
> +static uint64_t pnv_xive_vc_read(void *opaque, hwaddr offset,
> +                                 unsigned size)
> +{
> +    PnvXive *xive = PNV_XIVE(opaque);
> +    uint64_t edt_index = offset >> pnv_xive_edt_shift(xive);
> +    uint64_t edt_type = 0;
> +    uint64_t edt_offset;
> +    MemTxResult result;
> +    AddressSpace *edt_as = NULL;
> +    uint64_t ret = -1;
> +
> +    if (edt_index < XIVE_TABLE_EDT_MAX) {
> +        edt_type = GETFIELD(CQ_TDR_EDT_TYPE, xive->edt[edt_index]);
> +    }
> +
> +    switch (edt_type) {
> +    case CQ_TDR_EDT_IPI:
> +        edt_as = &xive->ipi_as;
> +        break;
> +    case CQ_TDR_EDT_EQ:
> +        edt_as = &xive->end_as;
> +        break;
> +    default:
> +        xive_error(xive, "VC: invalid EDT type for read @%"HWADDR_PRIx, offset);
> +        return -1;
> +    }
> +
> +    /* Remap the offset for the targeted address space */
> +    edt_offset = pnv_xive_edt_offset(xive, offset, edt_type);
> +
> +    ret = address_space_ldq(edt_as, edt_offset, MEMTXATTRS_UNSPECIFIED,
> +                            &result);
> +
> +    if (result != MEMTX_OK) {
> +        xive_error(xive, "VC: %s read failed at @0x%"HWADDR_PRIx " -> @0x%"
> +                   HWADDR_PRIx, edt_type == CQ_TDR_EDT_IPI ? "IPI" : "END",
> +                   offset, edt_offset);
> +        return -1;
> +    }
> +
> +    return ret;
> +}
> +
> +static void pnv_xive_vc_write(void *opaque, hwaddr offset,
> +                              uint64_t val, unsigned size)
> +{
> +    PnvXive *xive = PNV_XIVE(opaque);
> +    uint64_t edt_index = offset >> pnv_xive_edt_shift(xive);
> +    uint64_t edt_type = 0;
> +    uint64_t edt_offset;
> +    MemTxResult result;
> +    AddressSpace *edt_as = NULL;
> +
> +    if (edt_index < XIVE_TABLE_EDT_MAX) {
> +        edt_type = GETFIELD(CQ_TDR_EDT_TYPE, xive->edt[edt_index]);
> +    }
> +
> +    switch (edt_type) {
> +    case CQ_TDR_EDT_IPI:
> +        edt_as = &xive->ipi_as;
> +        break;
> +    case CQ_TDR_EDT_EQ:
> +        edt_as = &xive->end_as;
> +        break;
> +    default:
> +        xive_error(xive, "VC: invalid EDT type for write @%"HWADDR_PRIx,
> +                   offset);
> +        return;
> +    }
> +
> +    /* Remap the offset for the targeted address space */
> +    edt_offset = pnv_xive_edt_offset(xive, offset, edt_type);
> +
> +    address_space_stq(edt_as, edt_offset, val, MEMTXATTRS_UNSPECIFIED, &result);
> +    if (result != MEMTX_OK) {
> +        xive_error(xive, "VC: write failed at @0x%"HWADDR_PRIx, edt_offset);
> +    }
> +}
> +
> +static const MemoryRegionOps pnv_xive_vc_ops = {
> +    .read = pnv_xive_vc_read,
> +    .write = pnv_xive_vc_write,
> +    .endianness = DEVICE_BIG_ENDIAN,
> +    .valid = {
> +        .min_access_size = 8,
> +        .max_access_size = 8,
> +    },
> +    .impl = {
> +        .min_access_size = 8,
> +        .max_access_size = 8,
> +    },
> +};
> +
> +/*
> + * Presenter Controller MMIO region. The Virtualization Controller
> + * updates the IPB in the NVT table when required. Not modeled.
> + */
> +static uint64_t pnv_xive_pc_read(void *opaque, hwaddr addr,
> +                                 unsigned size)
> +{
> +    PnvXive *xive = PNV_XIVE(opaque);
> +
> +    xive_error(xive, "PC: invalid read @%"HWADDR_PRIx, addr);
> +    return -1;
> +}
> +
> +static void pnv_xive_pc_write(void *opaque, hwaddr addr,
> +                              uint64_t value, unsigned size)
> +{
> +    PnvXive *xive = PNV_XIVE(opaque);
> +
> +    xive_error(xive, "PC: invalid write to VC @%"HWADDR_PRIx, addr);
> +}
> +
> +static const MemoryRegionOps pnv_xive_pc_ops = {
> +    .read = pnv_xive_pc_read,
> +    .write = pnv_xive_pc_write,
> +    .endianness = DEVICE_BIG_ENDIAN,
> +    .valid = {
> +        .min_access_size = 8,
> +        .max_access_size = 8,
> +    },
> +    .impl = {
> +        .min_access_size = 8,
> +        .max_access_size = 8,
> +    },
> +};
> +
> +void pnv_xive_pic_print_info(PnvXive *xive, Monitor *mon)
> +{
> +    XiveRouter *xrtr = XIVE_ROUTER(xive);
> +    uint8_t blk = xive->chip->chip_id;
> +    uint32_t srcno0 = XIVE_SRCNO(blk, 0);
> +    uint32_t nr_ipis = pnv_xive_nr_ipis(xive);
> +    uint32_t nr_ends = pnv_xive_nr_ends(xive);
> +    XiveEAS eas;
> +    XiveEND end;
> +    int i;
> +
> +    monitor_printf(mon, "XIVE[%x] Source %08x .. %08x\n", blk, srcno0,
> +                   srcno0 + nr_ipis - 1);
> +    xive_source_pic_print_info(&xive->ipi_source, srcno0, mon);
> +
> +    monitor_printf(mon, "XIVE[%x] EAT %08x .. %08x\n", blk, srcno0,
> +                   srcno0 + nr_ipis - 1);
> +    for (i = 0; i < nr_ipis; i++) {
> +        if (xive_router_get_eas(xrtr, blk, i, &eas)) {
> +            break;
> +        }
> +        if (!xive_eas_is_masked(&eas)) {
> +            xive_eas_pic_print_info(&eas, i, mon);
> +        }
> +    }
> +
> +    monitor_printf(mon, "XIVE[%x] ENDT %08x .. %08x\n", blk, 0, nr_ends - 1);
> +    for (i = 0; i < nr_ends; i++) {
> +        if (xive_router_get_end(xrtr, blk, i, &end)) {
> +            break;
> +        }
> +        xive_end_pic_print_info(&end, i, mon);
> +    }
> +}
> +
> +static void pnv_xive_reset(void *dev)
> +{
> +    PnvXive *xive = PNV_XIVE(dev);
> +    XiveSource *xsrc = &xive->ipi_source;
> +    XiveENDSource *end_xsrc = &xive->end_source;
> +
> +    /*
> +     * Use the PnvChip id to identify the XIVE interrupt controller.
> +     * It can be overriden by configuration at runtime.
> +     */
> +    xive->tctx_chipid = xive->chip->chip_id;
> +
> +    /* Default page size (Should be changed at runtime to 64k) */
> +    xive->ic_shift = xive->vc_shift = xive->pc_shift = 12;
> +
> +    /* Clear subregions */
> +    if (memory_region_is_mapped(&xsrc->esb_mmio)) {
> +        memory_region_del_subregion(&xive->ipi_edt_mmio, &xsrc->esb_mmio);
> +    }
> +
> +    if (memory_region_is_mapped(&xive->ipi_edt_mmio)) {
> +        memory_region_del_subregion(&xive->ipi_mmio, &xive->ipi_edt_mmio);
> +    }
> +
> +    if (memory_region_is_mapped(&end_xsrc->esb_mmio)) {
> +        memory_region_del_subregion(&xive->end_edt_mmio, &end_xsrc->esb_mmio);
> +    }
> +
> +    if (memory_region_is_mapped(&xive->end_edt_mmio)) {
> +        memory_region_del_subregion(&xive->end_mmio, &xive->end_edt_mmio);
> +    }
> +}
> +
> +static void pnv_xive_init(Object *obj)
> +{
> +    PnvXive *xive = PNV_XIVE(obj);
> +
> +    object_initialize_child(obj, "ipi_source", &xive->ipi_source,
> +                            sizeof(xive->ipi_source), TYPE_XIVE_SOURCE,
> +                            &error_abort, NULL);
> +    object_initialize_child(obj, "end_source", &xive->end_source,
> +                            sizeof(xive->end_source), TYPE_XIVE_END_SOURCE,
> +                            &error_abort, NULL);
> +}
> +
> +/*
> + *  Maximum number of IRQs and ENDs supported by HW
> + */
> +#define PNV_XIVE_NR_IRQS (PNV9_XIVE_VC_SIZE / (1ull << XIVE_ESB_64K_2PAGE))
> +#define PNV_XIVE_NR_ENDS (PNV9_XIVE_VC_SIZE / (1ull << XIVE_ESB_64K_2PAGE))
> +
> +static void pnv_xive_realize(DeviceState *dev, Error **errp)
> +{
> +    PnvXive *xive = PNV_XIVE(dev);
> +    XiveSource *xsrc = &xive->ipi_source;
> +    XiveENDSource *end_xsrc = &xive->end_source;
> +    Error *local_err = NULL;
> +    Object *obj;
> +
> +    obj = object_property_get_link(OBJECT(dev), "chip", &local_err);
> +    if (!obj) {
> +        error_propagate(errp, local_err);
> +        error_prepend(errp, "required link 'chip' not found: ");
> +        return;
> +    }
> +
> +    /* The PnvChip id identifies the XIVE interrupt controller. */
> +    xive->chip = PNV_CHIP(obj);
> +
> +    /*
> +     * The XiveSource and XiveENDSource objects are realized with the
> +     * maximum allowed HW configuration. The ESB MMIO regions will be
> +     * resized dynamically when the controller is configured by the FW
> +     * to limit accesses to resources not provisioned.
> +     */
> +    object_property_set_int(OBJECT(xsrc), PNV_XIVE_NR_IRQS, "nr-irqs",
> +                            &error_fatal);
> +    object_property_add_const_link(OBJECT(xsrc), "xive", OBJECT(xive),
> +                                   &error_fatal);
> +    object_property_set_bool(OBJECT(xsrc), true, "realized", &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +
> +    object_property_set_int(OBJECT(end_xsrc), PNV_XIVE_NR_ENDS, "nr-ends",
> +                            &error_fatal);
> +    object_property_add_const_link(OBJECT(end_xsrc), "xive", OBJECT(xive),
> +                                   &error_fatal);
> +    object_property_set_bool(OBJECT(end_xsrc), true, "realized", &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +
> +    /* Default page size. Generally changed at runtime to 64k */
> +    xive->ic_shift = xive->vc_shift = xive->pc_shift = 12;
> +
> +    /* XSCOM region, used for initial configuration of the BARs */
> +    memory_region_init_io(&xive->xscom_regs, OBJECT(dev), &pnv_xive_xscom_ops,
> +                          xive, "xscom-xive", PNV9_XSCOM_XIVE_SIZE << 3);
> +
> +    /* Interrupt controller MMIO regions */
> +    memory_region_init(&xive->ic_mmio, OBJECT(dev), "xive-ic",
> +                       PNV9_XIVE_IC_SIZE);
> +
> +    memory_region_init_io(&xive->ic_reg_mmio, OBJECT(dev), &pnv_xive_ic_reg_ops,
> +                          xive, "xive-ic-reg", 1 << xive->ic_shift);
> +    memory_region_init_io(&xive->ic_notify_mmio, OBJECT(dev),
> +                          &pnv_xive_ic_notify_ops,
> +                          xive, "xive-ic-notify", 1 << xive->ic_shift);
> +
> +    /* The Pervasive LSI trigger and EOI pages (not modeled) */
> +    memory_region_init_io(&xive->ic_lsi_mmio, OBJECT(dev), &pnv_xive_ic_lsi_ops,
> +                          xive, "xive-ic-lsi", 2 << xive->ic_shift);
> +
> +    /* Thread Interrupt Management Area (Indirect) */
> +    memory_region_init_io(&xive->tm_indirect_mmio, OBJECT(dev),
> +                          &xive_tm_indirect_ops,
> +                          xive, "xive-tima-indirect", PNV9_XIVE_TM_SIZE);
> +    /*
> +     * Overall Virtualization Controller MMIO region containing the
> +     * IPI ESB pages and END ESB pages. The layout is defined by the
> +     * EDT "Domain table" and the accesses are dispatched using
> +     * address spaces for each.
> +     */
> +    memory_region_init_io(&xive->vc_mmio, OBJECT(xive), &pnv_xive_vc_ops, xive,
> +                          "xive-vc", PNV9_XIVE_VC_SIZE);
> +
> +    memory_region_init(&xive->ipi_mmio, OBJECT(xive), "xive-vc-ipi",
> +                       PNV9_XIVE_VC_SIZE);
> +    address_space_init(&xive->ipi_as, &xive->ipi_mmio, "xive-vc-ipi");
> +    memory_region_init(&xive->end_mmio, OBJECT(xive), "xive-vc-end",
> +                       PNV9_XIVE_VC_SIZE);
> +    address_space_init(&xive->end_as, &xive->end_mmio, "xive-vc-end");
> +
> +    /*
> +     * The MMIO windows exposing the IPI ESBs and the END ESBs in the
> +     * VC region. Their size is configured by the FW in the EDT table.
> +     */
> +    memory_region_init(&xive->ipi_edt_mmio, OBJECT(xive), "xive-vc-ipi-edt", 0);
> +    memory_region_init(&xive->end_edt_mmio, OBJECT(xive), "xive-vc-end-edt", 0);
> +
> +    /* Presenter Controller MMIO region (not modeled) */
> +    memory_region_init_io(&xive->pc_mmio, OBJECT(xive), &pnv_xive_pc_ops, xive,
> +                          "xive-pc", PNV9_XIVE_PC_SIZE);
> +
> +    /* Thread Interrupt Management Area (Direct) */
> +    memory_region_init_io(&xive->tm_mmio, OBJECT(xive), &xive_tm_ops,
> +                          xive, "xive-tima", PNV9_XIVE_TM_SIZE);
> +
> +    qemu_register_reset(pnv_xive_reset, dev);
> +}
> +
> +static int pnv_xive_dt_xscom(PnvXScomInterface *dev, void *fdt,
> +                             int xscom_offset)
> +{
> +    const char compat[] = "ibm,power9-xive-x";
> +    char *name;
> +    int offset;
> +    uint32_t lpc_pcba = PNV9_XSCOM_XIVE_BASE;
> +    uint32_t reg[] = {
> +        cpu_to_be32(lpc_pcba),
> +        cpu_to_be32(PNV9_XSCOM_XIVE_SIZE)
> +    };
> +
> +    name = g_strdup_printf("xive@%x", lpc_pcba);
> +    offset = fdt_add_subnode(fdt, xscom_offset, name);
> +    _FDT(offset);
> +    g_free(name);
> +
> +    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
> +    _FDT((fdt_setprop(fdt, offset, "compatible", compat,
> +                      sizeof(compat))));
> +    return 0;
> +}
> +
> +static Property pnv_xive_properties[] = {
> +    DEFINE_PROP_UINT64("ic-bar", PnvXive, ic_base, 0),
> +    DEFINE_PROP_UINT64("vc-bar", PnvXive, vc_base, 0),
> +    DEFINE_PROP_UINT64("pc-bar", PnvXive, pc_base, 0),
> +    DEFINE_PROP_UINT64("tm-bar", PnvXive, tm_base, 0),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void pnv_xive_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
> +    XiveRouterClass *xrc = XIVE_ROUTER_CLASS(klass);
> +    XiveNotifierClass *xnc = XIVE_NOTIFIER_CLASS(klass);
> +
> +    xdc->dt_xscom = pnv_xive_dt_xscom;
> +
> +    dc->desc = "PowerNV XIVE Interrupt Controller";
> +    dc->realize = pnv_xive_realize;
> +    dc->props = pnv_xive_properties;
> +
> +    xrc->get_eas = pnv_xive_get_eas;
> +    xrc->get_end = pnv_xive_get_end;
> +    xrc->write_end = pnv_xive_write_end;
> +    xrc->get_nvt = pnv_xive_get_nvt;
> +    xrc->write_nvt = pnv_xive_write_nvt;
> +    xrc->get_tctx = pnv_xive_get_tctx;
> +
> +    xnc->notify = pnv_xive_notify;
> +};
> +
> +static const TypeInfo pnv_xive_info = {
> +    .name          = TYPE_PNV_XIVE,
> +    .parent        = TYPE_XIVE_ROUTER,
> +    .instance_init = pnv_xive_init,
> +    .instance_size = sizeof(PnvXive),
> +    .class_init    = pnv_xive_class_init,
> +    .interfaces    = (InterfaceInfo[]) {
> +        { TYPE_PNV_XSCOM_INTERFACE },
> +        { }
> +    }
> +};
> +
> +static void pnv_xive_register_types(void)
> +{
> +    type_register_static(&pnv_xive_info);
> +}
> +
> +type_init(pnv_xive_register_types)
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index b90d03711a05..a7ec76dbd6c7 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -705,7 +705,23 @@ static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
>  static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu,
>                                          Error **errp)
>  {
> -    return;
> +    Pnv9Chip *chip9 = PNV9_CHIP(chip);
> +    Error *local_err = NULL;
> +    Object *obj;
> +    PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
> +
> +    /*
> +     * The core creates its interrupt presenter but the XIVE interrupt
> +     * controller object is initialized afterwards. Hopefully, it's
> +     * only used at runtime.
> +     */
> +    obj = xive_tctx_create(OBJECT(cpu), XIVE_ROUTER(&chip9->xive), errp);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +
> +    pnv_cpu->intc = obj;
>  }
>  
>  /* Allowed core identifiers on a POWER8 Processor Chip :
> @@ -887,11 +903,19 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
>  
>  static void pnv_chip_power9_instance_init(Object *obj)
>  {
> +    Pnv9Chip *chip9 = PNV9_CHIP(obj);
> +
> +    object_initialize_child(obj, "xive", &chip9->xive, sizeof(chip9->xive),
> +                            TYPE_PNV_XIVE, &error_abort, NULL);
> +    object_property_add_const_link(OBJECT(&chip9->xive), "chip", obj,
> +                                   &error_abort);
>  }
>  
>  static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
>  {
>      PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
> +    Pnv9Chip *chip9 = PNV9_CHIP(dev);
> +    PnvChip *chip = PNV_CHIP(dev);
>      Error *local_err = NULL;
>  
>      pcc->parent_realize(dev, &local_err);
> @@ -899,6 +923,24 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
>          error_propagate(errp, local_err);
>          return;
>      }
> +
> +    /* XIVE interrupt controller (POWER9) */
> +    object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_IC_BASE(chip),
> +                            "ic-bar", &error_fatal);
> +    object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_VC_BASE(chip),
> +                            "vc-bar", &error_fatal);
> +    object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_PC_BASE(chip),
> +                            "pc-bar", &error_fatal);
> +    object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_TM_BASE(chip),
> +                            "tm-bar", &error_fatal);
> +    object_property_set_bool(OBJECT(&chip9->xive), true, "realized",
> +                             &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +    pnv_xscom_add_subregion(chip, PNV9_XSCOM_XIVE_BASE,
> +                            &chip9->xive.xscom_regs);
>  }
>  
>  static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
> diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
> index 301a8e972d91..df712c3e6c93 100644
> --- a/hw/intc/Makefile.objs
> +++ b/hw/intc/Makefile.objs
> @@ -39,7 +39,7 @@ obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o
>  obj-$(CONFIG_XICS_KVM) += xics_kvm.o
>  obj-$(CONFIG_XIVE) += xive.o
>  obj-$(CONFIG_XIVE_SPAPR) += spapr_xive.o
> -obj-$(CONFIG_POWERNV) += xics_pnv.o
> +obj-$(CONFIG_POWERNV) += xics_pnv.o pnv_xive.o
>  obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
>  obj-$(CONFIG_S390_FLIC) += s390_flic.o
>  obj-$(CONFIG_S390_FLIC_KVM) += s390_flic_kvm.o

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 07/27] ppc/pnv: introduce a new dt_populate() operation to the chip model
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 07/27] ppc/pnv: introduce a new dt_populate() operation to the chip model Cédric Le Goater
@ 2019-03-07  1:44   ` David Gibson
  0 siblings, 0 replies; 55+ messages in thread
From: David Gibson @ 2019-03-07  1:44 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 4373 bytes --]

On Wed, Mar 06, 2019 at 09:50:12AM +0100, Cédric Le Goater wrote:
> The POWER9 and POWER8 processors have a different set of devices and a
> different device tree layout.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>

Applied, thanks.

> ---
>  include/hw/ppc/pnv.h |  1 +
>  hw/ppc/pnv.c         | 27 +++++++++++++++++++++++++--
>  2 files changed, 26 insertions(+), 2 deletions(-)
> 
> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> index ebbb3d0e9aa7..fa9ec50fd5be 100644
> --- a/include/hw/ppc/pnv.h
> +++ b/include/hw/ppc/pnv.h
> @@ -102,6 +102,7 @@ typedef struct PnvChipClass {
>      uint32_t (*core_pir)(PnvChip *chip, uint32_t core_id);
>      void (*intc_create)(PnvChip *chip, PowerPCCPU *cpu, Error **errp);
>      ISABus *(*isa_create)(PnvChip *chip, Error **errp);
> +    void (*dt_populate)(PnvChip *chip, void *fdt);
>  } PnvChipClass;
>  
>  #define PNV_CHIP_TYPE_SUFFIX "-" TYPE_PNV_CHIP
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index a7ec76dbd6c7..087541a91a72 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -267,7 +267,7 @@ static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir,
>      g_free(reg);
>  }
>  
> -static void pnv_dt_chip(PnvChip *chip, void *fdt)
> +static void pnv_chip_power8_dt_populate(PnvChip *chip, void *fdt)
>  {
>      const char *typename = pnv_chip_core_typename(chip);
>      size_t typesize = object_type_get_instance_size(typename);
> @@ -289,6 +289,25 @@ static void pnv_dt_chip(PnvChip *chip, void *fdt)
>      }
>  }
>  
> +static void pnv_chip_power9_dt_populate(PnvChip *chip, void *fdt)
> +{
> +    const char *typename = pnv_chip_core_typename(chip);
> +    size_t typesize = object_type_get_instance_size(typename);
> +    int i;
> +
> +    pnv_dt_xscom(chip, fdt, 0);
> +
> +    for (i = 0; i < chip->nr_cores; i++) {
> +        PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
> +
> +        pnv_dt_core(chip, pnv_core, fdt);
> +    }
> +
> +    if (chip->ram_size) {
> +        pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
> +    }
> +}
> +
>  static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
>  {
>      uint32_t io_base = d->ioport_id;
> @@ -474,7 +493,7 @@ static void *pnv_dt_create(MachineState *machine)
>  
>      /* Populate device tree for each chip */
>      for (i = 0; i < pnv->num_chips; i++) {
> -        pnv_dt_chip(pnv->chips[i], fdt);
> +        PNV_CHIP_GET_CLASS(pnv->chips[i])->dt_populate(pnv->chips[i], fdt);
>      }
>  
>      /* Populate ISA devices on chip 0 */
> @@ -858,6 +877,7 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
>      k->core_pir = pnv_chip_core_pir_p8;
>      k->intc_create = pnv_chip_power8_intc_create;
>      k->isa_create = pnv_chip_power8_isa_create;
> +    k->dt_populate = pnv_chip_power8_dt_populate;
>      k->xscom_base = 0x003fc0000000000ull;
>      dc->desc = "PowerNV Chip POWER8E";
>  
> @@ -876,6 +896,7 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
>      k->core_pir = pnv_chip_core_pir_p8;
>      k->intc_create = pnv_chip_power8_intc_create;
>      k->isa_create = pnv_chip_power8_isa_create;
> +    k->dt_populate = pnv_chip_power8_dt_populate;
>      k->xscom_base = 0x003fc0000000000ull;
>      dc->desc = "PowerNV Chip POWER8";
>  
> @@ -894,6 +915,7 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
>      k->core_pir = pnv_chip_core_pir_p8;
>      k->intc_create = pnv_chip_power8_intc_create;
>      k->isa_create = pnv_chip_power8nvl_isa_create;
> +    k->dt_populate = pnv_chip_power8_dt_populate;
>      k->xscom_base = 0x003fc0000000000ull;
>      dc->desc = "PowerNV Chip POWER8NVL";
>  
> @@ -954,6 +976,7 @@ static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
>      k->core_pir = pnv_chip_core_pir_p9;
>      k->intc_create = pnv_chip_power9_intc_create;
>      k->isa_create = pnv_chip_power9_isa_create;
> +    k->dt_populate = pnv_chip_power9_dt_populate;
>      k->xscom_base = 0x00603fc00000000ull;
>      dc->desc = "PowerNV Chip POWER9";
>  

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 08/27] ppc/pnv: introduce a new pic_print_info() operation to the chip model
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 08/27] ppc/pnv: introduce a new pic_print_info() " Cédric Le Goater
@ 2019-03-07  1:46   ` David Gibson
  0 siblings, 0 replies; 55+ messages in thread
From: David Gibson @ 2019-03-07  1:46 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 4509 bytes --]

On Wed, Mar 06, 2019 at 09:50:13AM +0100, Cédric Le Goater wrote:
> The POWER9 and POWER8 processors have different interrupt controllers,
> and reporting their state requires calling different helper routines.
> 
> However, the interrupt presenters are still handled in the higher
> level pic_print_info() routine because they are not related to the
> chip.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>

Applied, thanks.

> ---
>  include/hw/ppc/pnv.h |  1 +
>  hw/ppc/pnv.c         | 27 ++++++++++++++++++++++++---
>  2 files changed, 25 insertions(+), 3 deletions(-)
> 
> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> index fa9ec50fd5be..eb4bba25b3e9 100644
> --- a/include/hw/ppc/pnv.h
> +++ b/include/hw/ppc/pnv.h
> @@ -103,6 +103,7 @@ typedef struct PnvChipClass {
>      void (*intc_create)(PnvChip *chip, PowerPCCPU *cpu, Error **errp);
>      ISABus *(*isa_create)(PnvChip *chip, Error **errp);
>      void (*dt_populate)(PnvChip *chip, void *fdt);
> +    void (*pic_print_info)(PnvChip *chip, Monitor *mon);
>  } PnvChipClass;
>  
>  #define PNV_CHIP_TYPE_SUFFIX "-" TYPE_PNV_CHIP
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 087541a91a72..7660eaa22cf9 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -567,6 +567,20 @@ static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
>      return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp);
>  }
>  
> +static void pnv_chip_power8_pic_print_info(PnvChip *chip, Monitor *mon)
> +{
> +    Pnv8Chip *chip8 = PNV8_CHIP(chip);
> +
> +    ics_pic_print_info(&chip8->psi.ics, mon);
> +}
> +
> +static void pnv_chip_power9_pic_print_info(PnvChip *chip, Monitor *mon)
> +{
> +    Pnv9Chip *chip9 = PNV9_CHIP(chip);
> +
> +    pnv_xive_pic_print_info(&chip9->xive, mon);
> +}
> +
>  static void pnv_init(MachineState *machine)
>  {
>      PnvMachineState *pnv = PNV_MACHINE(machine);
> @@ -878,6 +892,7 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
>      k->intc_create = pnv_chip_power8_intc_create;
>      k->isa_create = pnv_chip_power8_isa_create;
>      k->dt_populate = pnv_chip_power8_dt_populate;
> +    k->pic_print_info = pnv_chip_power8_pic_print_info;
>      k->xscom_base = 0x003fc0000000000ull;
>      dc->desc = "PowerNV Chip POWER8E";
>  
> @@ -897,6 +912,7 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
>      k->intc_create = pnv_chip_power8_intc_create;
>      k->isa_create = pnv_chip_power8_isa_create;
>      k->dt_populate = pnv_chip_power8_dt_populate;
> +    k->pic_print_info = pnv_chip_power8_pic_print_info;
>      k->xscom_base = 0x003fc0000000000ull;
>      dc->desc = "PowerNV Chip POWER8";
>  
> @@ -916,6 +932,7 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
>      k->intc_create = pnv_chip_power8_intc_create;
>      k->isa_create = pnv_chip_power8nvl_isa_create;
>      k->dt_populate = pnv_chip_power8_dt_populate;
> +    k->pic_print_info = pnv_chip_power8_pic_print_info;
>      k->xscom_base = 0x003fc0000000000ull;
>      dc->desc = "PowerNV Chip POWER8NVL";
>  
> @@ -977,6 +994,7 @@ static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
>      k->intc_create = pnv_chip_power9_intc_create;
>      k->isa_create = pnv_chip_power9_isa_create;
>      k->dt_populate = pnv_chip_power9_dt_populate;
> +    k->pic_print_info = pnv_chip_power9_pic_print_info;
>      k->xscom_base = 0x00603fc00000000ull;
>      dc->desc = "PowerNV Chip POWER9";
>  
> @@ -1164,12 +1182,15 @@ static void pnv_pic_print_info(InterruptStatsProvider *obj,
>      CPU_FOREACH(cs) {
>          PowerPCCPU *cpu = POWERPC_CPU(cs);
>  
> -        icp_pic_print_info(ICP(pnv_cpu_state(cpu)->intc), mon);
> +        if (pnv_chip_is_power9(pnv->chips[0])) {
> +            xive_tctx_pic_print_info(XIVE_TCTX(pnv_cpu_state(cpu)->intc), mon);
> +        } else {
> +            icp_pic_print_info(ICP(pnv_cpu_state(cpu)->intc), mon);
> +        }
>      }
>  
>      for (i = 0; i < pnv->num_chips; i++) {
> -        Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
> -        ics_pic_print_info(&chip8->psi.ics, mon);
> +        PNV_CHIP_GET_CLASS(pnv->chips[i])->pic_print_info(pnv->chips[i], mon);
>      }
>  }
>  

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 09/27] ppc/xive: activate HV support
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 09/27] ppc/xive: activate HV support Cédric Le Goater
@ 2019-03-07  1:48   ` David Gibson
  0 siblings, 0 replies; 55+ messages in thread
From: David Gibson @ 2019-03-07  1:48 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 5584 bytes --]

On Wed, Mar 06, 2019 at 09:50:14AM +0100, Cédric Le Goater wrote:
> The NSR register of the HV ring has a different, although similar, bit
> layout. TM_QW3_NSR_HE_PHYS bit should now be raised when the
> Hypervisor interrupt line is signaled. Other bits TM_QW3_NSR_HE_POOL
> and TM_QW3_NSR_HE_LSI are not modeled. LSI are for special interrupts
> reserved for HW bringup and the POOL bit is used when signaling a
> group of VPs. This is not currently implemented in Linux but it is in
> pHyp.
> 
> The most important special commands on the HV TIMA page are added to
> let the core manage interrupts : acking and changing the CPU priority.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  hw/intc/xive.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 54 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/intc/xive.c b/hw/intc/xive.c
> index 7d7992c0ce3f..a0b87001da25 100644
> --- a/hw/intc/xive.c
> +++ b/hw/intc/xive.c
> @@ -54,6 +54,8 @@ static uint8_t exception_mask(uint8_t ring)
>      switch (ring) {
>      case TM_QW1_OS:
>          return TM_QW1_NSR_EO;
> +    case TM_QW3_HV_PHYS:
> +        return TM_QW3_NSR_HE;
>      default:
>          g_assert_not_reached();
>      }
> @@ -88,7 +90,16 @@ static void xive_tctx_notify(XiveTCTX *tctx, uint8_t ring)
>      uint8_t *regs = &tctx->regs[ring];
>  
>      if (regs[TM_PIPR] < regs[TM_CPPR]) {
> -        regs[TM_NSR] |= exception_mask(ring);

This means there's only one remaining caller to exception_mask, so it
might be better to just open code it at that site.  That can be a
later cleanup though, so applied to ppc-for-4.0.

> +        switch (ring) {
> +        case TM_QW1_OS:
> +            regs[TM_NSR] |= TM_QW1_NSR_EO;
> +            break;
> +        case TM_QW3_HV_PHYS:
> +            regs[TM_NSR] |= (TM_QW3_NSR_HE_PHYS << 6);
> +            break;
> +        default:
> +            g_assert_not_reached();
> +        }
>          qemu_irq_raise(tctx->output);
>      }
>  }
> @@ -109,6 +120,38 @@ static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr)
>   * XIVE Thread Interrupt Management Area (TIMA)
>   */
>  
> +static void xive_tm_set_hv_cppr(XiveTCTX *tctx, hwaddr offset,
> +                                uint64_t value, unsigned size)
> +{
> +    xive_tctx_set_cppr(tctx, TM_QW3_HV_PHYS, value & 0xff);
> +}
> +
> +static uint64_t xive_tm_ack_hv_reg(XiveTCTX *tctx, hwaddr offset, unsigned size)
> +{
> +    return xive_tctx_accept(tctx, TM_QW3_HV_PHYS);
> +}
> +
> +static uint64_t xive_tm_pull_pool_ctx(XiveTCTX *tctx, hwaddr offset,
> +                                      unsigned size)
> +{
> +    uint64_t ret;
> +
> +    ret = tctx->regs[TM_QW2_HV_POOL + TM_WORD2] & TM_QW2W2_POOL_CAM;
> +    tctx->regs[TM_QW2_HV_POOL + TM_WORD2] &= ~TM_QW2W2_POOL_CAM;
> +    return ret;
> +}
> +
> +static void xive_tm_vt_push(XiveTCTX *tctx, hwaddr offset,
> +                            uint64_t value, unsigned size)
> +{
> +    tctx->regs[TM_QW3_HV_PHYS + TM_WORD2] = value & 0xff;
> +}
> +
> +static uint64_t xive_tm_vt_poll(XiveTCTX *tctx, hwaddr offset, unsigned size)
> +{
> +    return tctx->regs[TM_QW3_HV_PHYS + TM_WORD2] & 0xff;
> +}
> +
>  /*
>   * Define an access map for each page of the TIMA that we will use in
>   * the memory region ops to filter values when doing loads and stores
> @@ -288,10 +331,16 @@ static const XiveTmOp xive_tm_operations[] = {
>       * effects
>       */
>      { XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR,   1, xive_tm_set_os_cppr, NULL },
> +    { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, xive_tm_set_hv_cppr, NULL },
> +    { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, xive_tm_vt_push, NULL },
> +    { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, NULL, xive_tm_vt_poll },
>  
>      /* MMIOs above 2K : special operations with side effects */
>      { XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG,     2, NULL, xive_tm_ack_os_reg },
>      { XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending, NULL },
> +    { XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG,     2, NULL, xive_tm_ack_hv_reg },
> +    { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX,  4, NULL, xive_tm_pull_pool_ctx },
> +    { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX,  8, NULL, xive_tm_pull_pool_ctx },
>  };
>  
>  static const XiveTmOp *xive_tm_find_op(hwaddr offset, unsigned size, bool write)
> @@ -323,7 +372,7 @@ void xive_tctx_tm_write(XiveTCTX *tctx, hwaddr offset, uint64_t value,
>      const XiveTmOp *xto;
>  
>      /*
> -     * TODO: check V bit in Q[0-3]W2, check PTER bit associated with CPU
> +     * TODO: check V bit in Q[0-3]W2
>       */
>  
>      /*
> @@ -360,7 +409,7 @@ uint64_t xive_tctx_tm_read(XiveTCTX *tctx, hwaddr offset, unsigned size)
>      const XiveTmOp *xto;
>  
>      /*
> -     * TODO: check V bit in Q[0-3]W2, check PTER bit associated with CPU
> +     * TODO: check V bit in Q[0-3]W2
>       */
>  
>      /*
> @@ -472,6 +521,8 @@ static void xive_tctx_reset(void *dev)
>       */
>      tctx->regs[TM_QW1_OS + TM_PIPR] =
>          ipb_to_pipr(tctx->regs[TM_QW1_OS + TM_IPB]);
> +    tctx->regs[TM_QW3_HV_PHYS + TM_PIPR] =
> +        ipb_to_pipr(tctx->regs[TM_QW3_HV_PHYS + TM_IPB]);
>  }
>  
>  static void xive_tctx_realize(DeviceState *dev, Error **errp)

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 10/27] ppc/xive: Make XIVE generate the proper interrupt types
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 10/27] ppc/xive: Make XIVE generate the proper interrupt types Cédric Le Goater
@ 2019-03-07  3:29   ` David Gibson
  0 siblings, 0 replies; 55+ messages in thread
From: David Gibson @ 2019-03-07  3:29 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel, Benjamin Herrenschmidt

[-- Attachment #1: Type: text/plain, Size: 3442 bytes --]

On Wed, Mar 06, 2019 at 09:50:15AM +0100, Cédric Le Goater wrote:
> From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> 
> It should be generic Hypervisor Virtualization interrupts for HV
> directed rings and traditional External Interrupts for the OS directed
> ring.
> 
> Don't generate anything for the user ring as it isn't actually
> supported.
> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  include/hw/ppc/xive.h |  3 ++-
>  hw/intc/xive.c        | 22 +++++++++++++++++++---
>  2 files changed, 21 insertions(+), 4 deletions(-)
> 
> diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h
> index c4f27742ca09..6b89dc7679f9 100644
> --- a/include/hw/ppc/xive.h
> +++ b/include/hw/ppc/xive.h
> @@ -313,7 +313,8 @@ typedef struct XiveTCTX {
>      DeviceState parent_obj;
>  
>      CPUState    *cs;
> -    qemu_irq    output;
> +    qemu_irq    hv_output;
> +    qemu_irq    os_output;
>  
>      uint8_t     regs[XIVE_TM_RING_COUNT * XIVE_TM_RING_SIZE];
>  } XiveTCTX;
> diff --git a/hw/intc/xive.c b/hw/intc/xive.c
> index a0b87001da25..237e7b256dc0 100644
> --- a/hw/intc/xive.c
> +++ b/hw/intc/xive.c
> @@ -61,13 +61,28 @@ static uint8_t exception_mask(uint8_t ring)
>      }
>  }
>  
> +static qemu_irq xive_tctx_output(XiveTCTX *tctx, uint8_t ring)
> +{
> +        switch (ring) {
> +        case TM_QW0_USER:
> +                return 0; /* Not supported */

IIUC hitting this case would indicate a code error, not a guest error,
in which case g_assert_not_reached() would be more appropriate that
returning 0.

Return "0" is kind of weird.  qemu_irq is actually a pointer so this
is really returning NULL.  But I don't think most things that handle
qemu_irq expect them to be NULL, so it's likely that this will just
crash further on.

Apart from that, LGTM.

> +        case TM_QW1_OS:
> +                return tctx->os_output;
> +        case TM_QW2_HV_POOL:
> +        case TM_QW3_HV_PHYS:
> +                return tctx->hv_output;
> +        default:
> +                return 0;
> +        }
> +}
> +
>  static uint64_t xive_tctx_accept(XiveTCTX *tctx, uint8_t ring)
>  {
>      uint8_t *regs = &tctx->regs[ring];
>      uint8_t nsr = regs[TM_NSR];
>      uint8_t mask = exception_mask(ring);
>  
> -    qemu_irq_lower(tctx->output);
> +    qemu_irq_lower(xive_tctx_output(tctx, ring));
>  
>      if (regs[TM_NSR] & mask) {
>          uint8_t cppr = regs[TM_PIPR];
> @@ -100,7 +115,7 @@ static void xive_tctx_notify(XiveTCTX *tctx, uint8_t ring)
>          default:
>              g_assert_not_reached();
>          }
> -        qemu_irq_raise(tctx->output);
> +        qemu_irq_raise(xive_tctx_output(tctx, ring));
>      }
>  }
>  
> @@ -546,7 +561,8 @@ static void xive_tctx_realize(DeviceState *dev, Error **errp)
>      env = &cpu->env;
>      switch (PPC_INPUT(env)) {
>      case PPC_FLAGS_INPUT_POWER9:
> -        tctx->output = env->irq_inputs[POWER9_INPUT_INT];
> +        tctx->hv_output = env->irq_inputs[POWER9_INPUT_HINT];
> +        tctx->os_output = env->irq_inputs[POWER9_INPUT_INT];
>          break;
>  
>      default:

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 11/27] ppc/pnv: fix logging primitives using Ox
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 11/27] ppc/pnv: fix logging primitives using Ox Cédric Le Goater
@ 2019-03-07  3:30   ` David Gibson
  0 siblings, 0 replies; 55+ messages in thread
From: David Gibson @ 2019-03-07  3:30 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 3132 bytes --]

On Wed, Mar 06, 2019 at 09:50:16AM +0100, Cédric Le Goater wrote:
> Signed-off-by: Cédric Le Goater <clg@kaod.org>

Wow, that's a deeply weird starting point.  Applied.

> ---
>  hw/ppc/pnv_lpc.c | 10 +++++-----
>  hw/ppc/pnv_psi.c |  4 ++--
>  2 files changed, 7 insertions(+), 7 deletions(-)
> 
> diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c
> index 172a915cfc55..9b18ce55e391 100644
> --- a/hw/ppc/pnv_lpc.c
> +++ b/hw/ppc/pnv_lpc.c
> @@ -294,7 +294,7 @@ static uint64_t lpc_hc_read(void *opaque, hwaddr addr, unsigned size)
>          val =  lpc->lpc_hc_error_addr;
>          break;
>      default:
> -        qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: Ox%"
> +        qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: 0x%"
>                        HWADDR_PRIx "\n", addr);
>      }
>      return val;
> @@ -332,7 +332,7 @@ static void lpc_hc_write(void *opaque, hwaddr addr, uint64_t val,
>      case LPC_HC_ERROR_ADDRESS:
>          break;
>      default:
> -        qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: Ox%"
> +        qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented register: 0x%"
>                        HWADDR_PRIx "\n", addr);
>      }
>  }
> @@ -370,7 +370,7 @@ static uint64_t opb_master_read(void *opaque, hwaddr addr, unsigned size)
>          val = lpc->opb_irq_input;
>          break;
>      default:
> -        qemu_log_mask(LOG_UNIMP, "OPB MASTER Unimplemented register: Ox%"
> +        qemu_log_mask(LOG_UNIMP, "OPBM: read on unimplemented register: 0x%"
>                        HWADDR_PRIx "\n", addr);
>      }
>  
> @@ -399,8 +399,8 @@ static void opb_master_write(void *opaque, hwaddr addr,
>          /* Read only */
>          break;
>      default:
> -        qemu_log_mask(LOG_UNIMP, "OPB MASTER Unimplemented register: Ox%"
> -                      HWADDR_PRIx "\n", addr);
> +        qemu_log_mask(LOG_UNIMP, "OPBM: write on unimplemented register: 0x%"
> +                      HWADDR_PRIx " val=0x%08"PRIx64"\n", addr, val);
>      }
>  }
>  
> diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
> index 44bc0cbf58cb..c872be0b9c0d 100644
> --- a/hw/ppc/pnv_psi.c
> +++ b/hw/ppc/pnv_psi.c
> @@ -323,7 +323,7 @@ static uint64_t pnv_psi_reg_read(PnvPsi *psi, uint32_t offset, bool mmio)
>          val = psi->regs[offset];
>          break;
>      default:
> -        qemu_log_mask(LOG_UNIMP, "PSI: read at Ox%" PRIx32 "\n", offset);
> +        qemu_log_mask(LOG_UNIMP, "PSI: read at 0x%" PRIx32 "\n", offset);
>      }
>      return val;
>  }
> @@ -382,7 +382,7 @@ static void pnv_psi_reg_write(PnvPsi *psi, uint32_t offset, uint64_t val,
>          pnv_psi_set_irsn(psi, val);
>          break;
>      default:
> -        qemu_log_mask(LOG_UNIMP, "PSI: write at Ox%" PRIx32 "\n", offset);
> +        qemu_log_mask(LOG_UNIMP, "PSI: write at 0x%" PRIx32 "\n", offset);
>      }
>  }
>  

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 12/27] ppc/pnv: psi: add a PSIHB_REG macro
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 12/27] ppc/pnv: psi: add a PSIHB_REG macro Cédric Le Goater
@ 2019-03-07  3:30   ` David Gibson
  0 siblings, 0 replies; 55+ messages in thread
From: David Gibson @ 2019-03-07  3:30 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1717 bytes --]

On Wed, Mar 06, 2019 at 09:50:17AM +0100, Cédric Le Goater wrote:
> This is a simple helper to translate XSCOM addresses to MMIO addresses
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>

A worthy cleanup, regardless of anything else.  Applied.

> ---
>  hw/ppc/pnv_psi.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
> index c872be0b9c0d..a2f8d0dece80 100644
> --- a/hw/ppc/pnv_psi.c
> +++ b/hw/ppc/pnv_psi.c
> @@ -114,6 +114,8 @@
>  #define PSIHB_BAR_MASK                  0x0003fffffff00000ull
>  #define PSIHB_FSPBAR_MASK               0x0003ffff00000000ull
>  
> +#define PSIHB_REG(addr) (((addr) >> 3) + PSIHB_XSCOM_BAR)
> +
>  static void pnv_psi_set_bar(PnvPsi *psi, uint64_t bar)
>  {
>      MemoryRegion *sysmem = get_system_memory();
> @@ -392,13 +394,13 @@ static void pnv_psi_reg_write(PnvPsi *psi, uint32_t offset, uint64_t val,
>   */
>  static uint64_t pnv_psi_mmio_read(void *opaque, hwaddr addr, unsigned size)
>  {
> -    return pnv_psi_reg_read(opaque, (addr >> 3) + PSIHB_XSCOM_BAR, true);
> +    return pnv_psi_reg_read(opaque, PSIHB_REG(addr), true);
>  }
>  
>  static void pnv_psi_mmio_write(void *opaque, hwaddr addr,
>                                uint64_t val, unsigned size)
>  {
> -    pnv_psi_reg_write(opaque, (addr >> 3) + PSIHB_XSCOM_BAR, val, true);
> +    pnv_psi_reg_write(opaque, PSIHB_REG(addr), val, true);
>  }
>  
>  static const MemoryRegionOps psi_mmio_ops = {

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 13/27] ppc/pnv: psi: add a reset handler
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 13/27] ppc/pnv: psi: add a reset handler Cédric Le Goater
@ 2019-03-07  3:32   ` David Gibson
  0 siblings, 0 replies; 55+ messages in thread
From: David Gibson @ 2019-03-07  3:32 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1512 bytes --]

On Wed, Mar 06, 2019 at 09:50:18AM +0100, Cédric Le Goater wrote:
> Reset all regs but keep the MMIO BAR enabled as it is at realize time.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>

Again, I don't like the duplication of information between psi->reg
and psi->bar.  But that's out of scope for this patch, so, applied.

> ---
>  hw/ppc/pnv_psi.c | 11 +++++++++++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
> index a2f8d0dece80..e61861bfd3c6 100644
> --- a/hw/ppc/pnv_psi.c
> +++ b/hw/ppc/pnv_psi.c
> @@ -442,6 +442,15 @@ static const MemoryRegionOps pnv_psi_xscom_ops = {
>      }
>  };
>  
> +static void pnv_psi_reset(void *dev)
> +{
> +    PnvPsi *psi = PNV_PSI(dev);
> +
> +    memset(psi->regs, 0x0, sizeof(psi->regs));
> +
> +    psi->regs[PSIHB_XSCOM_BAR] = psi->bar | PSIHB_BAR_EN;
> +}
> +
>  static void pnv_psi_init(Object *obj)
>  {
>      PnvPsi *psi = PNV_PSI(obj);
> @@ -511,6 +520,8 @@ static void pnv_psi_realize(DeviceState *dev, Error **errp)
>          psi->regs[xivr] = PSIHB_XIVR_PRIO_MSK |
>              ((uint64_t) i << PSIHB_XIVR_SRC_SH);
>      }
> +
> +    qemu_register_reset(pnv_psi_reset, dev);
>  }
>  
>  static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 14/27] ppc/pnv: add a PSI bridge model class
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 14/27] ppc/pnv: add a PSI bridge model class Cédric Le Goater
@ 2019-03-07  4:05   ` David Gibson
  2019-03-07  4:08     ` David Gibson
  0 siblings, 1 reply; 55+ messages in thread
From: David Gibson @ 2019-03-07  4:05 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 8652 bytes --]

On Wed, Mar 06, 2019 at 09:50:19AM +0100, Cédric Le Goater wrote:
> It will ease the introduction of the PSI bridge model for POWER9.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>

Applied, thanks.

> ---
>  include/hw/ppc/pnv_psi.h | 21 +++++++++++-
>  hw/ppc/pnv.c             |  2 +-
>  hw/ppc/pnv_psi.c         | 72 ++++++++++++++++++++++++++++------------
>  3 files changed, 72 insertions(+), 23 deletions(-)
> 
> diff --git a/include/hw/ppc/pnv_psi.h b/include/hw/ppc/pnv_psi.h
> index 64ac73512e81..585a41cd19b6 100644
> --- a/include/hw/ppc/pnv_psi.h
> +++ b/include/hw/ppc/pnv_psi.h
> @@ -25,6 +25,9 @@
>  #define TYPE_PNV_PSI "pnv-psi"
>  #define PNV_PSI(obj) \
>       OBJECT_CHECK(PnvPsi, (obj), TYPE_PNV_PSI)
> +#define TYPE_PNV8_PSI TYPE_PNV_PSI "-POWER8"
> +#define PNV8_PSI(obj) \
> +    OBJECT_CHECK(PnvPsi, (obj), TYPE_PNV8_PSI)
>  
>  #define PSIHB_XSCOM_MAX         0x20
>  
> @@ -48,6 +51,22 @@ typedef struct PnvPsi {
>      MemoryRegion xscom_regs;
>  } PnvPsi;
>  
> +#define PNV_PSI_CLASS(klass) \
> +     OBJECT_CLASS_CHECK(PnvPsiClass, (klass), TYPE_PNV_PSI)
> +#define PNV_PSI_GET_CLASS(obj) \
> +     OBJECT_GET_CLASS(PnvPsiClass, (obj), TYPE_PNV_PSI)
> +
> +typedef struct PnvPsiClass {
> +    SysBusDeviceClass parent_class;
> +
> +    int chip_type;
> +    uint32_t xscom_pcba;
> +    uint32_t xscom_size;
> +    uint64_t bar_mask;
> +
> +    void (*irq_set)(PnvPsi *psi, int, bool state);
> +} PnvPsiClass;
> +
>  /* The PSI and FSP interrupts are muxed on the same IRQ number */
>  typedef enum PnvPsiIrq {
>      PSIHB_IRQ_PSI, /* internal use only */
> @@ -61,6 +80,6 @@ typedef enum PnvPsiIrq {
>  
>  #define PSI_NUM_INTERRUPTS 6
>  
> -extern void pnv_psi_irq_set(PnvPsi *psi, PnvPsiIrq irq, bool state);
> +void pnv_psi_irq_set(PnvPsi *psi, int irq, bool state);
>  
>  #endif /* _PPC_PNV_PSI_H */
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 7660eaa22cf9..67d40dc3eebc 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -788,7 +788,7 @@ static void pnv_chip_power8_instance_init(Object *obj)
>      Pnv8Chip *chip8 = PNV8_CHIP(obj);
>  
>      object_initialize_child(obj, "psi",  &chip8->psi, sizeof(chip8->psi),
> -                            TYPE_PNV_PSI, &error_abort, NULL);
> +                            TYPE_PNV8_PSI, &error_abort, NULL);
>      object_property_add_const_link(OBJECT(&chip8->psi), "xics",
>                                     OBJECT(qdev_get_machine()), &error_abort);
>  
> diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
> index e61861bfd3c6..e56b455a61b1 100644
> --- a/hw/ppc/pnv_psi.c
> +++ b/hw/ppc/pnv_psi.c
> @@ -118,10 +118,11 @@
>  
>  static void pnv_psi_set_bar(PnvPsi *psi, uint64_t bar)
>  {
> +    PnvPsiClass *ppc = PNV_PSI_GET_CLASS(psi);
>      MemoryRegion *sysmem = get_system_memory();
>      uint64_t old = psi->regs[PSIHB_XSCOM_BAR];
>  
> -    psi->regs[PSIHB_XSCOM_BAR] = bar & (PSIHB_BAR_MASK | PSIHB_BAR_EN);
> +    psi->regs[PSIHB_XSCOM_BAR] = bar & (ppc->bar_mask | PSIHB_BAR_EN);
>  
>      /* Update MR, always remove it first */
>      if (old & PSIHB_BAR_EN) {
> @@ -130,7 +131,7 @@ static void pnv_psi_set_bar(PnvPsi *psi, uint64_t bar)
>  
>      /* Then add it back if needed */
>      if (bar & PSIHB_BAR_EN) {
> -        uint64_t addr = bar & PSIHB_BAR_MASK;
> +        uint64_t addr = bar & ppc->bar_mask;
>          memory_region_add_subregion(sysmem, addr, &psi->regs_mr);
>      }
>  }
> @@ -207,7 +208,12 @@ static const uint64_t stat_bits[] = {
>      [PSIHB_IRQ_EXTERNAL]  = PSIHB_IRQ_STAT_EXT,
>  };
>  
> -void pnv_psi_irq_set(PnvPsi *psi, PnvPsiIrq irq, bool state)
> +void pnv_psi_irq_set(PnvPsi *psi, int irq, bool state)
> +{
> +    PNV_PSI_GET_CLASS(psi)->irq_set(psi, irq, state);
> +}
> +
> +static void pnv_psi_power8_irq_set(PnvPsi *psi, int irq, bool state)
>  {
>      uint32_t xivr_reg;
>      uint32_t stat_reg;
> @@ -451,9 +457,9 @@ static void pnv_psi_reset(void *dev)
>      psi->regs[PSIHB_XSCOM_BAR] = psi->bar | PSIHB_BAR_EN;
>  }
>  
> -static void pnv_psi_init(Object *obj)
> +static void pnv_psi_power8_instance_init(Object *obj)
>  {
> -    PnvPsi *psi = PNV_PSI(obj);
> +    PnvPsi *psi = PNV8_PSI(obj);
>  
>      object_initialize_child(obj, "ics-psi",  &psi->ics, sizeof(psi->ics),
>                              TYPE_ICS_SIMPLE, &error_abort, NULL);
> @@ -468,9 +474,9 @@ static const uint8_t irq_to_xivr[] = {
>      PSIHB_XSCOM_XIVR_EXT,
>  };
>  
> -static void pnv_psi_realize(DeviceState *dev, Error **errp)
> +static void pnv_psi_power8_realize(DeviceState *dev, Error **errp)
>  {
> -    PnvPsi *psi = PNV_PSI(dev);
> +    PnvPsi *psi = PNV8_PSI(dev);
>      ICSState *ics = &psi->ics;
>      Object *obj;
>      Error *err = NULL;
> @@ -524,28 +530,28 @@ static void pnv_psi_realize(DeviceState *dev, Error **errp)
>      qemu_register_reset(pnv_psi_reset, dev);
>  }
>  
> +static const char compat_p8[] = "ibm,power8-psihb-x\0ibm,psihb-x";
> +
>  static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
>  {
> -    const char compat[] = "ibm,power8-psihb-x\0ibm,psihb-x";
> +    PnvPsiClass *ppc = PNV_PSI_GET_CLASS(dev);
>      char *name;
>      int offset;
> -    uint32_t lpc_pcba = PNV_XSCOM_PSIHB_BASE;
>      uint32_t reg[] = {
> -        cpu_to_be32(lpc_pcba),
> -        cpu_to_be32(PNV_XSCOM_PSIHB_SIZE)
> +        cpu_to_be32(ppc->xscom_pcba),
> +        cpu_to_be32(ppc->xscom_size)
>      };
>  
> -    name = g_strdup_printf("psihb@%x", lpc_pcba);
> +    name = g_strdup_printf("psihb@%x", ppc->xscom_pcba);
>      offset = fdt_add_subnode(fdt, xscom_offset, name);
>      _FDT(offset);
>      g_free(name);
>  
> -    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
> -
> -    _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 2)));
> -    _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 1)));
> -    _FDT((fdt_setprop(fdt, offset, "compatible", compat,
> -                      sizeof(compat))));
> +    _FDT(fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)));
> +    _FDT(fdt_setprop_cell(fdt, offset, "#address-cells", 2));
> +    _FDT(fdt_setprop_cell(fdt, offset, "#size-cells", 1));
> +    _FDT(fdt_setprop(fdt, offset, "compatible", compat_p8,
> +                     sizeof(compat_p8)));
>      return 0;
>  }
>  
> @@ -555,6 +561,28 @@ static Property pnv_psi_properties[] = {
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
> +static void pnv_psi_power8_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PnvPsiClass *ppc = PNV_PSI_CLASS(klass);
> +
> +    dc->desc    = "PowerNV PSI Controller POWER8";
> +    dc->realize = pnv_psi_power8_realize;
> +
> +    ppc->chip_type =  PNV_CHIP_POWER8;
> +    ppc->xscom_pcba = PNV_XSCOM_PSIHB_BASE;
> +    ppc->xscom_size = PNV_XSCOM_PSIHB_SIZE;
> +    ppc->bar_mask   = PSIHB_BAR_MASK;
> +    ppc->irq_set    = pnv_psi_power8_irq_set;
> +}
> +
> +static const TypeInfo pnv_psi_power8_info = {
> +    .name          = TYPE_PNV8_PSI,
> +    .parent        = TYPE_PNV_PSI,
> +    .instance_init = pnv_psi_power8_instance_init,
> +    .class_init    = pnv_psi_power8_class_init,
> +};
> +
>  static void pnv_psi_class_init(ObjectClass *klass, void *data)
>  {
>      DeviceClass *dc = DEVICE_CLASS(klass);
> @@ -562,7 +590,7 @@ static void pnv_psi_class_init(ObjectClass *klass, void *data)
>  
>      xdc->dt_xscom = pnv_psi_dt_xscom;
>  
> -    dc->realize = pnv_psi_realize;
> +    dc->desc = "PowerNV PSI Controller";
>      dc->props = pnv_psi_properties;
>  }
>  
> @@ -570,8 +598,9 @@ static const TypeInfo pnv_psi_info = {
>      .name          = TYPE_PNV_PSI,
>      .parent        = TYPE_SYS_BUS_DEVICE,
>      .instance_size = sizeof(PnvPsi),
> -    .instance_init = pnv_psi_init,
>      .class_init    = pnv_psi_class_init,
> +    .class_size    = sizeof(PnvPsiClass),
> +    .abstract      = true,
>      .interfaces    = (InterfaceInfo[]) {
>          { TYPE_PNV_XSCOM_INTERFACE },
>          { }
> @@ -581,6 +610,7 @@ static const TypeInfo pnv_psi_info = {
>  static void pnv_psi_register_types(void)
>  {
>      type_register_static(&pnv_psi_info);
> +    type_register_static(&pnv_psi_power8_info);
>  }
>  
> -type_init(pnv_psi_register_types)
> +type_init(pnv_psi_register_types);

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 14/27] ppc/pnv: add a PSI bridge model class
  2019-03-07  4:05   ` David Gibson
@ 2019-03-07  4:08     ` David Gibson
  0 siblings, 0 replies; 55+ messages in thread
From: David Gibson @ 2019-03-07  4:08 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 9281 bytes --]

On Thu, Mar 07, 2019 at 03:05:19PM +1100, David Gibson wrote:
> On Wed, Mar 06, 2019 at 09:50:19AM +0100, Cédric Le Goater wrote:
> > It will ease the introduction of the PSI bridge model for POWER9.
> > 
> > Signed-off-by: Cédric Le Goater <clg@kaod.org>
> 
> Applied, thanks.

And now unapplied, due to issues revealed in the next patch.  See the
comments there.

> 
> > ---
> >  include/hw/ppc/pnv_psi.h | 21 +++++++++++-
> >  hw/ppc/pnv.c             |  2 +-
> >  hw/ppc/pnv_psi.c         | 72 ++++++++++++++++++++++++++++------------
> >  3 files changed, 72 insertions(+), 23 deletions(-)
> > 
> > diff --git a/include/hw/ppc/pnv_psi.h b/include/hw/ppc/pnv_psi.h
> > index 64ac73512e81..585a41cd19b6 100644
> > --- a/include/hw/ppc/pnv_psi.h
> > +++ b/include/hw/ppc/pnv_psi.h
> > @@ -25,6 +25,9 @@
> >  #define TYPE_PNV_PSI "pnv-psi"
> >  #define PNV_PSI(obj) \
> >       OBJECT_CHECK(PnvPsi, (obj), TYPE_PNV_PSI)
> > +#define TYPE_PNV8_PSI TYPE_PNV_PSI "-POWER8"
> > +#define PNV8_PSI(obj) \
> > +    OBJECT_CHECK(PnvPsi, (obj), TYPE_PNV8_PSI)
> >  
> >  #define PSIHB_XSCOM_MAX         0x20
> >  
> > @@ -48,6 +51,22 @@ typedef struct PnvPsi {
> >      MemoryRegion xscom_regs;
> >  } PnvPsi;
> >  
> > +#define PNV_PSI_CLASS(klass) \
> > +     OBJECT_CLASS_CHECK(PnvPsiClass, (klass), TYPE_PNV_PSI)
> > +#define PNV_PSI_GET_CLASS(obj) \
> > +     OBJECT_GET_CLASS(PnvPsiClass, (obj), TYPE_PNV_PSI)
> > +
> > +typedef struct PnvPsiClass {
> > +    SysBusDeviceClass parent_class;
> > +
> > +    int chip_type;
> > +    uint32_t xscom_pcba;
> > +    uint32_t xscom_size;
> > +    uint64_t bar_mask;
> > +
> > +    void (*irq_set)(PnvPsi *psi, int, bool state);
> > +} PnvPsiClass;
> > +
> >  /* The PSI and FSP interrupts are muxed on the same IRQ number */
> >  typedef enum PnvPsiIrq {
> >      PSIHB_IRQ_PSI, /* internal use only */
> > @@ -61,6 +80,6 @@ typedef enum PnvPsiIrq {
> >  
> >  #define PSI_NUM_INTERRUPTS 6
> >  
> > -extern void pnv_psi_irq_set(PnvPsi *psi, PnvPsiIrq irq, bool state);
> > +void pnv_psi_irq_set(PnvPsi *psi, int irq, bool state);
> >  
> >  #endif /* _PPC_PNV_PSI_H */
> > diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> > index 7660eaa22cf9..67d40dc3eebc 100644
> > --- a/hw/ppc/pnv.c
> > +++ b/hw/ppc/pnv.c
> > @@ -788,7 +788,7 @@ static void pnv_chip_power8_instance_init(Object *obj)
> >      Pnv8Chip *chip8 = PNV8_CHIP(obj);
> >  
> >      object_initialize_child(obj, "psi",  &chip8->psi, sizeof(chip8->psi),
> > -                            TYPE_PNV_PSI, &error_abort, NULL);
> > +                            TYPE_PNV8_PSI, &error_abort, NULL);
> >      object_property_add_const_link(OBJECT(&chip8->psi), "xics",
> >                                     OBJECT(qdev_get_machine()), &error_abort);
> >  
> > diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
> > index e61861bfd3c6..e56b455a61b1 100644
> > --- a/hw/ppc/pnv_psi.c
> > +++ b/hw/ppc/pnv_psi.c
> > @@ -118,10 +118,11 @@
> >  
> >  static void pnv_psi_set_bar(PnvPsi *psi, uint64_t bar)
> >  {
> > +    PnvPsiClass *ppc = PNV_PSI_GET_CLASS(psi);
> >      MemoryRegion *sysmem = get_system_memory();
> >      uint64_t old = psi->regs[PSIHB_XSCOM_BAR];
> >  
> > -    psi->regs[PSIHB_XSCOM_BAR] = bar & (PSIHB_BAR_MASK | PSIHB_BAR_EN);
> > +    psi->regs[PSIHB_XSCOM_BAR] = bar & (ppc->bar_mask | PSIHB_BAR_EN);
> >  
> >      /* Update MR, always remove it first */
> >      if (old & PSIHB_BAR_EN) {
> > @@ -130,7 +131,7 @@ static void pnv_psi_set_bar(PnvPsi *psi, uint64_t bar)
> >  
> >      /* Then add it back if needed */
> >      if (bar & PSIHB_BAR_EN) {
> > -        uint64_t addr = bar & PSIHB_BAR_MASK;
> > +        uint64_t addr = bar & ppc->bar_mask;
> >          memory_region_add_subregion(sysmem, addr, &psi->regs_mr);
> >      }
> >  }
> > @@ -207,7 +208,12 @@ static const uint64_t stat_bits[] = {
> >      [PSIHB_IRQ_EXTERNAL]  = PSIHB_IRQ_STAT_EXT,
> >  };
> >  
> > -void pnv_psi_irq_set(PnvPsi *psi, PnvPsiIrq irq, bool state)
> > +void pnv_psi_irq_set(PnvPsi *psi, int irq, bool state)
> > +{
> > +    PNV_PSI_GET_CLASS(psi)->irq_set(psi, irq, state);
> > +}
> > +
> > +static void pnv_psi_power8_irq_set(PnvPsi *psi, int irq, bool state)
> >  {
> >      uint32_t xivr_reg;
> >      uint32_t stat_reg;
> > @@ -451,9 +457,9 @@ static void pnv_psi_reset(void *dev)
> >      psi->regs[PSIHB_XSCOM_BAR] = psi->bar | PSIHB_BAR_EN;
> >  }
> >  
> > -static void pnv_psi_init(Object *obj)
> > +static void pnv_psi_power8_instance_init(Object *obj)
> >  {
> > -    PnvPsi *psi = PNV_PSI(obj);
> > +    PnvPsi *psi = PNV8_PSI(obj);
> >  
> >      object_initialize_child(obj, "ics-psi",  &psi->ics, sizeof(psi->ics),
> >                              TYPE_ICS_SIMPLE, &error_abort, NULL);
> > @@ -468,9 +474,9 @@ static const uint8_t irq_to_xivr[] = {
> >      PSIHB_XSCOM_XIVR_EXT,
> >  };
> >  
> > -static void pnv_psi_realize(DeviceState *dev, Error **errp)
> > +static void pnv_psi_power8_realize(DeviceState *dev, Error **errp)
> >  {
> > -    PnvPsi *psi = PNV_PSI(dev);
> > +    PnvPsi *psi = PNV8_PSI(dev);
> >      ICSState *ics = &psi->ics;
> >      Object *obj;
> >      Error *err = NULL;
> > @@ -524,28 +530,28 @@ static void pnv_psi_realize(DeviceState *dev, Error **errp)
> >      qemu_register_reset(pnv_psi_reset, dev);
> >  }
> >  
> > +static const char compat_p8[] = "ibm,power8-psihb-x\0ibm,psihb-x";
> > +
> >  static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
> >  {
> > -    const char compat[] = "ibm,power8-psihb-x\0ibm,psihb-x";
> > +    PnvPsiClass *ppc = PNV_PSI_GET_CLASS(dev);
> >      char *name;
> >      int offset;
> > -    uint32_t lpc_pcba = PNV_XSCOM_PSIHB_BASE;
> >      uint32_t reg[] = {
> > -        cpu_to_be32(lpc_pcba),
> > -        cpu_to_be32(PNV_XSCOM_PSIHB_SIZE)
> > +        cpu_to_be32(ppc->xscom_pcba),
> > +        cpu_to_be32(ppc->xscom_size)
> >      };
> >  
> > -    name = g_strdup_printf("psihb@%x", lpc_pcba);
> > +    name = g_strdup_printf("psihb@%x", ppc->xscom_pcba);
> >      offset = fdt_add_subnode(fdt, xscom_offset, name);
> >      _FDT(offset);
> >      g_free(name);
> >  
> > -    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
> > -
> > -    _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 2)));
> > -    _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 1)));
> > -    _FDT((fdt_setprop(fdt, offset, "compatible", compat,
> > -                      sizeof(compat))));
> > +    _FDT(fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)));
> > +    _FDT(fdt_setprop_cell(fdt, offset, "#address-cells", 2));
> > +    _FDT(fdt_setprop_cell(fdt, offset, "#size-cells", 1));
> > +    _FDT(fdt_setprop(fdt, offset, "compatible", compat_p8,
> > +                     sizeof(compat_p8)));
> >      return 0;
> >  }
> >  
> > @@ -555,6 +561,28 @@ static Property pnv_psi_properties[] = {
> >      DEFINE_PROP_END_OF_LIST(),
> >  };
> >  
> > +static void pnv_psi_power8_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +    PnvPsiClass *ppc = PNV_PSI_CLASS(klass);
> > +
> > +    dc->desc    = "PowerNV PSI Controller POWER8";
> > +    dc->realize = pnv_psi_power8_realize;
> > +
> > +    ppc->chip_type =  PNV_CHIP_POWER8;
> > +    ppc->xscom_pcba = PNV_XSCOM_PSIHB_BASE;
> > +    ppc->xscom_size = PNV_XSCOM_PSIHB_SIZE;
> > +    ppc->bar_mask   = PSIHB_BAR_MASK;
> > +    ppc->irq_set    = pnv_psi_power8_irq_set;
> > +}
> > +
> > +static const TypeInfo pnv_psi_power8_info = {
> > +    .name          = TYPE_PNV8_PSI,
> > +    .parent        = TYPE_PNV_PSI,
> > +    .instance_init = pnv_psi_power8_instance_init,
> > +    .class_init    = pnv_psi_power8_class_init,
> > +};
> > +
> >  static void pnv_psi_class_init(ObjectClass *klass, void *data)
> >  {
> >      DeviceClass *dc = DEVICE_CLASS(klass);
> > @@ -562,7 +590,7 @@ static void pnv_psi_class_init(ObjectClass *klass, void *data)
> >  
> >      xdc->dt_xscom = pnv_psi_dt_xscom;
> >  
> > -    dc->realize = pnv_psi_realize;
> > +    dc->desc = "PowerNV PSI Controller";
> >      dc->props = pnv_psi_properties;
> >  }
> >  
> > @@ -570,8 +598,9 @@ static const TypeInfo pnv_psi_info = {
> >      .name          = TYPE_PNV_PSI,
> >      .parent        = TYPE_SYS_BUS_DEVICE,
> >      .instance_size = sizeof(PnvPsi),
> > -    .instance_init = pnv_psi_init,
> >      .class_init    = pnv_psi_class_init,
> > +    .class_size    = sizeof(PnvPsiClass),
> > +    .abstract      = true,
> >      .interfaces    = (InterfaceInfo[]) {
> >          { TYPE_PNV_XSCOM_INTERFACE },
> >          { }
> > @@ -581,6 +610,7 @@ static const TypeInfo pnv_psi_info = {
> >  static void pnv_psi_register_types(void)
> >  {
> >      type_register_static(&pnv_psi_info);
> > +    type_register_static(&pnv_psi_power8_info);
> >  }
> >  
> > -type_init(pnv_psi_register_types)
> > +type_init(pnv_psi_register_types);
> 



-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 15/27] ppc/pnv: add a PSI bridge model for POWER9
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 15/27] ppc/pnv: add a PSI bridge model for POWER9 Cédric Le Goater
@ 2019-03-07  4:10   ` David Gibson
  2019-03-07  6:37     ` Cédric Le Goater
  0 siblings, 1 reply; 55+ messages in thread
From: David Gibson @ 2019-03-07  4:10 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 20148 bytes --]

On Wed, Mar 06, 2019 at 09:50:20AM +0100, Cédric Le Goater wrote:
> The PSI bridge on POWER9 is very similar to POWER8. The BAR is still
> set through XSCOM but the controls are now entirely done with MMIOs.
> More interrupts are defined and the interrupt controller interface has
> changed to XIVE. The POWER9 model is a first example of the usage of
> the notify() handler of the XiveNotifier interface, linking the PSI
> XiveSource to its owning device model.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  include/hw/ppc/pnv.h       |   6 +
>  include/hw/ppc/pnv_psi.h   |  24 +++
>  include/hw/ppc/pnv_xscom.h |   3 +
>  hw/ppc/pnv.c               |  17 ++
>  hw/ppc/pnv_psi.c           | 325 ++++++++++++++++++++++++++++++++++++-
>  5 files changed, 373 insertions(+), 2 deletions(-)
> 
> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> index eb4bba25b3e9..57d0337219be 100644
> --- a/include/hw/ppc/pnv.h
> +++ b/include/hw/ppc/pnv.h
> @@ -84,6 +84,7 @@ typedef struct Pnv9Chip {
>  
>      /*< public >*/
>      PnvXive      xive;
> +    PnvPsi       psi;
>  } Pnv9Chip;
>  
>  typedef struct PnvChipClass {
> @@ -231,11 +232,16 @@ void pnv_bmc_powerdown(IPMIBmc *bmc);
>  #define PNV9_XIVE_PC_SIZE            0x0000001000000000ull
>  #define PNV9_XIVE_PC_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006018000000000ull)
>  
> +#define PNV9_PSIHB_SIZE              0x0000000000100000ull
> +#define PNV9_PSIHB_BASE(chip)        PNV9_CHIP_BASE(chip, 0x0006030203000000ull)
> +
>  #define PNV9_XIVE_IC_SIZE            0x0000000000080000ull
>  #define PNV9_XIVE_IC_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006030203100000ull)
>  
>  #define PNV9_XIVE_TM_SIZE            0x0000000000040000ull
>  #define PNV9_XIVE_TM_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006030203180000ull)
>  
> +#define PNV9_PSIHB_ESB_SIZE          0x0000000000010000ull
> +#define PNV9_PSIHB_ESB_BASE(chip)    PNV9_CHIP_BASE(chip, 0x00060302031c0000ull)
>  
>  #endif /* _PPC_PNV_H */
> diff --git a/include/hw/ppc/pnv_psi.h b/include/hw/ppc/pnv_psi.h
> index 585a41cd19b6..d7e1ab282cf8 100644
> --- a/include/hw/ppc/pnv_psi.h
> +++ b/include/hw/ppc/pnv_psi.h
> @@ -21,6 +21,7 @@
>  
>  #include "hw/sysbus.h"
>  #include "hw/ppc/xics.h"
> +#include "hw/ppc/xive.h"
>  
>  #define TYPE_PNV_PSI "pnv-psi"
>  #define PNV_PSI(obj) \
> @@ -28,6 +29,9 @@
>  #define TYPE_PNV8_PSI TYPE_PNV_PSI "-POWER8"
>  #define PNV8_PSI(obj) \
>      OBJECT_CHECK(PnvPsi, (obj), TYPE_PNV8_PSI)
> +#define TYPE_PNV9_PSI TYPE_PNV_PSI "-POWER9"
> +#define PNV9_PSI(obj) \
> +    OBJECT_CHECK(PnvPsi, (obj), TYPE_PNV9_PSI)
>  
>  #define PSIHB_XSCOM_MAX         0x20
>  
> @@ -43,6 +47,7 @@ typedef struct PnvPsi {
>  
>      /* Interrupt generation */
>      ICSState ics;
> +    XiveSource source;

Uh... surely these should move to the subtype structures, so you don't
have both of them.

>      qemu_irq *qirqs;
>  
>      /* Registers */
> @@ -82,4 +87,23 @@ typedef enum PnvPsiIrq {
>  
>  void pnv_psi_irq_set(PnvPsi *psi, int irq, bool state);
>  
> +/* P9 PSI Interrupts */
> +#define PSIHB9_IRQ_PSI          0
> +#define PSIHB9_IRQ_OCC          1
> +#define PSIHB9_IRQ_FSI          2
> +#define PSIHB9_IRQ_LPCHC        3
> +#define PSIHB9_IRQ_LOCAL_ERR    4
> +#define PSIHB9_IRQ_GLOBAL_ERR   5
> +#define PSIHB9_IRQ_TPM          6
> +#define PSIHB9_IRQ_LPC_SIRQ0    7
> +#define PSIHB9_IRQ_LPC_SIRQ1    8
> +#define PSIHB9_IRQ_LPC_SIRQ2    9
> +#define PSIHB9_IRQ_LPC_SIRQ3    10
> +#define PSIHB9_IRQ_SBE_I2C      11
> +#define PSIHB9_IRQ_DIO          12
> +#define PSIHB9_IRQ_PSU          13
> +#define PSIHB9_NUM_IRQS         14
> +
> +void pnv_psi_pic_print_info(PnvPsi *psi, Monitor *mon);
> +
>  #endif /* _PPC_PNV_PSI_H */
> diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
> index 6623ec54a7a8..403a365ed274 100644
> --- a/include/hw/ppc/pnv_xscom.h
> +++ b/include/hw/ppc/pnv_xscom.h
> @@ -73,6 +73,9 @@ typedef struct PnvXScomInterfaceClass {
>  #define PNV_XSCOM_OCC_BASE        0x0066000
>  #define PNV_XSCOM_OCC_SIZE        0x6000
>  
> +#define PNV9_XSCOM_PSIHB_BASE     0x5012900
> +#define PNV9_XSCOM_PSIHB_SIZE     0x100
> +
>  #define PNV9_XSCOM_XIVE_BASE      0x5013000
>  #define PNV9_XSCOM_XIVE_SIZE      0x300
>  
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 67d40dc3eebc..4375f97c7135 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -579,6 +579,7 @@ static void pnv_chip_power9_pic_print_info(PnvChip *chip, Monitor *mon)
>      Pnv9Chip *chip9 = PNV9_CHIP(chip);
>  
>      pnv_xive_pic_print_info(&chip9->xive, mon);
> +    pnv_psi_pic_print_info(&chip9->psi, mon);
>  }
>  
>  static void pnv_init(MachineState *machine)
> @@ -948,6 +949,11 @@ static void pnv_chip_power9_instance_init(Object *obj)
>                              TYPE_PNV_XIVE, &error_abort, NULL);
>      object_property_add_const_link(OBJECT(&chip9->xive), "chip", obj,
>                                     &error_abort);
> +
> +    object_initialize_child(obj, "psi",  &chip9->psi, sizeof(chip9->psi),
> +                            TYPE_PNV9_PSI, &error_abort, NULL);
> +    object_property_add_const_link(OBJECT(&chip9->psi), "chip", obj,
> +                                   &error_abort);
>  }
>  
>  static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
> @@ -980,6 +986,17 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
>      }
>      pnv_xscom_add_subregion(chip, PNV9_XSCOM_XIVE_BASE,
>                              &chip9->xive.xscom_regs);
> +
> +    /* Processor Service Interface (PSI) Host Bridge */
> +    object_property_set_int(OBJECT(&chip9->psi), PNV9_PSIHB_BASE(chip),
> +                            "bar", &error_fatal);
> +    object_property_set_bool(OBJECT(&chip9->psi), true, "realized", &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +    pnv_xscom_add_subregion(chip, PNV9_XSCOM_PSIHB_BASE,
> +                            &chip9->psi.xscom_regs);
>  }
>  
>  static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
> diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
> index e56b455a61b1..3f995a0e0d7f 100644
> --- a/hw/ppc/pnv_psi.c
> +++ b/hw/ppc/pnv_psi.c
> @@ -22,6 +22,7 @@
>  #include "target/ppc/cpu.h"
>  #include "qemu/log.h"
>  #include "qapi/error.h"
> +#include "monitor/monitor.h"
>  
>  #include "exec/address-spaces.h"
>  
> @@ -114,6 +115,9 @@
>  #define PSIHB_BAR_MASK                  0x0003fffffff00000ull
>  #define PSIHB_FSPBAR_MASK               0x0003ffff00000000ull
>  
> +#define PSIHB9_BAR_MASK                 0x00fffffffff00000ull
> +#define PSIHB9_FSPBAR_MASK              0x00ffffff00000000ull
> +
>  #define PSIHB_REG(addr) (((addr) >> 3) + PSIHB_XSCOM_BAR)
>  
>  static void pnv_psi_set_bar(PnvPsi *psi, uint64_t bar)
> @@ -531,6 +535,7 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp)
>  }
>  
>  static const char compat_p8[] = "ibm,power8-psihb-x\0ibm,psihb-x";
> +static const char compat_p9[] = "ibm,power9-psihb-x\0ibm,psihb-x";
>  
>  static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
>  {
> @@ -550,8 +555,13 @@ static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
>      _FDT(fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)));
>      _FDT(fdt_setprop_cell(fdt, offset, "#address-cells", 2));
>      _FDT(fdt_setprop_cell(fdt, offset, "#size-cells", 1));
> -    _FDT(fdt_setprop(fdt, offset, "compatible", compat_p8,
> -                     sizeof(compat_p8)));
> +    if (ppc->chip_type == PNV_CHIP_POWER9) {

Ew.  You already have subclasses - put the compatible in there, rather
than more explicit tests against chip type.

> +        _FDT(fdt_setprop(fdt, offset, "compatible", compat_p9,
> +                         sizeof(compat_p9)));
> +    } else {
> +        _FDT(fdt_setprop(fdt, offset, "compatible", compat_p8,
> +                         sizeof(compat_p8)));
> +    }
>      return 0;
>  }
>  
> @@ -583,6 +593,306 @@ static const TypeInfo pnv_psi_power8_info = {
>      .class_init    = pnv_psi_power8_class_init,
>  };
>  
> +
> +/* Common registers */
> +
> +#define PSIHB9_CR                       0x20
> +#define PSIHB9_SEMR                     0x28
> +
> +/* P9 registers */
> +
> +#define PSIHB9_INTERRUPT_CONTROL        0x58
> +#define   PSIHB9_IRQ_METHOD             PPC_BIT(0)
> +#define   PSIHB9_IRQ_RESET              PPC_BIT(1)
> +#define PSIHB9_ESB_CI_BASE              0x60
> +#define   PSIHB9_ESB_CI_VALID           1
> +#define PSIHB9_ESB_NOTIF_ADDR           0x68
> +#define   PSIHB9_ESB_NOTIF_VALID        1
> +#define PSIHB9_IVT_OFFSET               0x70
> +#define   PSIHB9_IVT_OFF_SHIFT          32
> +
> +#define PSIHB9_IRQ_LEVEL                0x78 /* assertion */
> +#define   PSIHB9_IRQ_LEVEL_PSI          PPC_BIT(0)
> +#define   PSIHB9_IRQ_LEVEL_OCC          PPC_BIT(1)
> +#define   PSIHB9_IRQ_LEVEL_FSI          PPC_BIT(2)
> +#define   PSIHB9_IRQ_LEVEL_LPCHC        PPC_BIT(3)
> +#define   PSIHB9_IRQ_LEVEL_LOCAL_ERR    PPC_BIT(4)
> +#define   PSIHB9_IRQ_LEVEL_GLOBAL_ERR   PPC_BIT(5)
> +#define   PSIHB9_IRQ_LEVEL_TPM          PPC_BIT(6)
> +#define   PSIHB9_IRQ_LEVEL_LPC_SIRQ1    PPC_BIT(7)
> +#define   PSIHB9_IRQ_LEVEL_LPC_SIRQ2    PPC_BIT(8)
> +#define   PSIHB9_IRQ_LEVEL_LPC_SIRQ3    PPC_BIT(9)
> +#define   PSIHB9_IRQ_LEVEL_LPC_SIRQ4    PPC_BIT(10)
> +#define   PSIHB9_IRQ_LEVEL_SBE_I2C      PPC_BIT(11)
> +#define   PSIHB9_IRQ_LEVEL_DIO          PPC_BIT(12)
> +#define   PSIHB9_IRQ_LEVEL_PSU          PPC_BIT(13)
> +#define   PSIHB9_IRQ_LEVEL_I2C_C        PPC_BIT(14)
> +#define   PSIHB9_IRQ_LEVEL_I2C_D        PPC_BIT(15)
> +#define   PSIHB9_IRQ_LEVEL_I2C_E        PPC_BIT(16)
> +#define   PSIHB9_IRQ_LEVEL_SBE          PPC_BIT(19)
> +
> +#define PSIHB9_IRQ_STAT                 0x80 /* P bit */
> +#define   PSIHB9_IRQ_STAT_PSI           PPC_BIT(0)
> +#define   PSIHB9_IRQ_STAT_OCC           PPC_BIT(1)
> +#define   PSIHB9_IRQ_STAT_FSI           PPC_BIT(2)
> +#define   PSIHB9_IRQ_STAT_LPCHC         PPC_BIT(3)
> +#define   PSIHB9_IRQ_STAT_LOCAL_ERR     PPC_BIT(4)
> +#define   PSIHB9_IRQ_STAT_GLOBAL_ERR    PPC_BIT(5)
> +#define   PSIHB9_IRQ_STAT_TPM           PPC_BIT(6)
> +#define   PSIHB9_IRQ_STAT_LPC_SIRQ1     PPC_BIT(7)
> +#define   PSIHB9_IRQ_STAT_LPC_SIRQ2     PPC_BIT(8)
> +#define   PSIHB9_IRQ_STAT_LPC_SIRQ3     PPC_BIT(9)
> +#define   PSIHB9_IRQ_STAT_LPC_SIRQ4     PPC_BIT(10)
> +#define   PSIHB9_IRQ_STAT_SBE_I2C       PPC_BIT(11)
> +#define   PSIHB9_IRQ_STAT_DIO           PPC_BIT(12)
> +#define   PSIHB9_IRQ_STAT_PSU           PPC_BIT(13)
> +
> +static void pnv_psi_notify(XiveNotifier *xf, uint32_t srcno)
> +{
> +    PnvPsi *psi = PNV9_PSI(xf);
> +    uint64_t notif_port = psi->regs[PSIHB_REG(PSIHB9_ESB_NOTIF_ADDR)];
> +    bool valid = notif_port & PSIHB9_ESB_NOTIF_VALID;
> +    uint64_t notify_addr = notif_port & ~PSIHB9_ESB_NOTIF_VALID;
> +
> +    uint32_t offset =
> +        (psi->regs[PSIHB_REG(PSIHB9_IVT_OFFSET)] >> PSIHB9_IVT_OFF_SHIFT);
> +    uint64_t lisn = cpu_to_be64(offset + srcno);
> +
> +    if (valid) {
> +        cpu_physical_memory_write(notify_addr, &lisn, sizeof(lisn));
> +    }
> +}
> +
> +static uint64_t pnv_psi_p9_mmio_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    PnvPsi *psi = PNV9_PSI(opaque);
> +    uint32_t reg = PSIHB_REG(addr);
> +    uint64_t val = -1;
> +
> +    switch (addr) {
> +    case PSIHB9_CR:
> +    case PSIHB9_SEMR:
> +        /* FSP stuff */
> +    case PSIHB9_INTERRUPT_CONTROL:
> +    case PSIHB9_ESB_CI_BASE:
> +    case PSIHB9_ESB_NOTIF_ADDR:
> +    case PSIHB9_IVT_OFFSET:
> +        val = psi->regs[reg];
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR, "PSI: read at 0x%" PRIx64 "\n", addr);
> +    }
> +
> +    return val;
> +}
> +
> +static void pnv_psi_p9_mmio_write(void *opaque, hwaddr addr,
> +                                  uint64_t val, unsigned size)
> +{
> +    PnvPsi *psi = PNV9_PSI(opaque);
> +    uint32_t reg = PSIHB_REG(addr);
> +    MemoryRegion *sysmem = get_system_memory();
> +
> +    switch (addr) {
> +    case PSIHB9_CR:
> +    case PSIHB9_SEMR:
> +        /* FSP stuff */
> +        break;
> +    case PSIHB9_INTERRUPT_CONTROL:
> +        if (val & PSIHB9_IRQ_RESET) {
> +            device_reset(DEVICE(&psi->source));
> +        }
> +        psi->regs[reg] = val;
> +        break;
> +
> +    case PSIHB9_ESB_CI_BASE:
> +        if (!(val & PSIHB9_ESB_CI_VALID)) {
> +            if (psi->regs[reg] & PSIHB9_ESB_CI_VALID) {
> +                memory_region_del_subregion(sysmem, &psi->source.esb_mmio);
> +            }
> +        } else {
> +            if (!(psi->regs[reg] & PSIHB9_ESB_CI_VALID)) {
> +                memory_region_add_subregion(sysmem,
> +                                        val & ~PSIHB9_ESB_CI_VALID,
> +                                        &psi->source.esb_mmio);
> +            }
> +        }
> +        psi->regs[reg] = val;
> +        break;
> +
> +    case PSIHB9_ESB_NOTIF_ADDR:
> +        psi->regs[reg] = val;

Again, not in scope for this patch, but not being able to put a
reg[reg] = val outside the switch is a pretty good sign that a regs[]
array mirroring the guest register interface is not the right model
for this device.

> +        break;
> +    case PSIHB9_IVT_OFFSET:
> +        psi->regs[reg] = val;
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR, "PSI: write at 0x%" PRIx64 "\n", addr);
> +    }
> +}
> +
> +static const MemoryRegionOps pnv_psi_p9_mmio_ops = {
> +    .read = pnv_psi_p9_mmio_read,
> +    .write = pnv_psi_p9_mmio_write,
> +    .endianness = DEVICE_BIG_ENDIAN,
> +    .valid = {
> +        .min_access_size = 8,
> +        .max_access_size = 8,
> +    },
> +    .impl = {
> +        .min_access_size = 8,
> +        .max_access_size = 8,
> +    },
> +};
> +
> +static uint64_t pnv_psi_p9_xscom_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    /* No read are expected */
> +    qemu_log_mask(LOG_GUEST_ERROR, "PSI: xscom read at 0x%" PRIx64 "\n", addr);
> +    return -1;
> +}
> +
> +static void pnv_psi_p9_xscom_write(void *opaque, hwaddr addr,
> +                                uint64_t val, unsigned size)
> +{
> +    PnvPsi *psi = PNV9_PSI(opaque);
> +
> +    /* XSCOM is only used to set the PSIHB MMIO region */
> +    switch (addr >> 3) {
> +    case PSIHB_XSCOM_BAR:
> +        pnv_psi_set_bar(psi, val);
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR, "PSI: xscom write at 0x%" PRIx64 "\n",
> +                      addr);
> +    }
> +}
> +
> +static const MemoryRegionOps pnv_psi_p9_xscom_ops = {
> +    .read = pnv_psi_p9_xscom_read,
> +    .write = pnv_psi_p9_xscom_write,
> +    .endianness = DEVICE_BIG_ENDIAN,
> +    .valid = {
> +        .min_access_size = 8,
> +        .max_access_size = 8,
> +    },
> +    .impl = {
> +        .min_access_size = 8,
> +        .max_access_size = 8,
> +    }
> +};
> +
> +static void pnv_psi_power9_irq_set(PnvPsi *psi, int irq, bool state)
> +{
> +    uint32_t irq_method = psi->regs[PSIHB_REG(PSIHB9_INTERRUPT_CONTROL)];
> +
> +    if (irq > PSIHB9_NUM_IRQS) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "PSI: Unsupported irq %d\n", irq);
> +        return;
> +    }
> +
> +    if (irq_method & PSIHB9_IRQ_METHOD) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "PSI: LSI IRQ method no supported\n");
> +        return;
> +    }
> +
> +    /* Update LSI levels */
> +    if (state) {
> +        psi->regs[PSIHB_REG(PSIHB9_IRQ_LEVEL)] |= PPC_BIT(irq);
> +    } else {
> +        psi->regs[PSIHB_REG(PSIHB9_IRQ_LEVEL)] &= ~PPC_BIT(irq);
> +    }
> +
> +    qemu_set_irq(psi->qirqs[irq], state);
> +}
> +
> +static void pnv_psi_power9_reset(void *dev)
> +{
> +    PnvPsi *psi = PNV9_PSI(dev);
> +
> +    pnv_psi_reset(dev);
> +
> +    if (memory_region_is_mapped(&psi->source.esb_mmio)) {
> +        memory_region_del_subregion(get_system_memory(), &psi->source.esb_mmio);
> +    }
> +}
> +
> +static void pnv_psi_power9_instance_init(Object *obj)
> +{
> +    PnvPsi *psi = PNV9_PSI(obj);
> +
> +    object_initialize_child(obj, "source", &psi->source, sizeof(psi->source),
> +                            TYPE_XIVE_SOURCE, &error_abort, NULL);
> +}
> +
> +static void pnv_psi_power9_realize(DeviceState *dev, Error **errp)
> +{
> +    PnvPsi *psi = PNV9_PSI(dev);
> +    XiveSource *xsrc = &psi->source;
> +    Error *local_err = NULL;
> +    int i;
> +
> +    /* This is the only device with 4k ESB pages */
> +    object_property_set_int(OBJECT(xsrc), XIVE_ESB_4K, "shift",
> +                            &error_fatal);
> +    object_property_set_int(OBJECT(xsrc), PSIHB9_NUM_IRQS, "nr-irqs",
> +                            &error_fatal);
> +    object_property_add_const_link(OBJECT(xsrc), "xive", OBJECT(psi),
> +                                   &error_fatal);
> +    object_property_set_bool(OBJECT(xsrc), true, "realized", &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +
> +    for (i = 0; i < xsrc->nr_irqs; i++) {
> +        xive_source_irq_set_lsi(xsrc, i);
> +    }
> +
> +    psi->qirqs = qemu_allocate_irqs(xive_source_set_irq, xsrc, xsrc->nr_irqs);
> +
> +    /* XSCOM region for PSI registers */
> +    pnv_xscom_region_init(&psi->xscom_regs, OBJECT(dev), &pnv_psi_p9_xscom_ops,
> +                psi, "xscom-psi", PNV9_XSCOM_PSIHB_SIZE);
> +
> +    /* MMIO region for PSI registers */
> +    memory_region_init_io(&psi->regs_mr, OBJECT(dev), &pnv_psi_p9_mmio_ops, psi,
> +                          "psihb", PNV9_PSIHB_SIZE);
> +
> +    pnv_psi_set_bar(psi, psi->bar | PSIHB_BAR_EN);
> +
> +    qemu_register_reset(pnv_psi_power9_reset, dev);
> +}
> +
> +static void pnv_psi_power9_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PnvPsiClass *ppc = PNV_PSI_CLASS(klass);
> +    XiveNotifierClass *xfc = XIVE_NOTIFIER_CLASS(klass);
> +
> +    dc->desc    = "PowerNV PSI Controller POWER9";
> +    dc->realize = pnv_psi_power9_realize;
> +
> +    ppc->chip_type  = PNV_CHIP_POWER9;
> +    ppc->xscom_pcba = PNV9_XSCOM_PSIHB_BASE;
> +    ppc->xscom_size = PNV9_XSCOM_PSIHB_SIZE;
> +    ppc->bar_mask   = PSIHB9_BAR_MASK;
> +    ppc->irq_set    = pnv_psi_power9_irq_set;
> +
> +    xfc->notify      = pnv_psi_notify;
> +}
> +
> +static const TypeInfo pnv_psi_power9_info = {
> +    .name          = TYPE_PNV9_PSI,
> +    .parent        = TYPE_PNV_PSI,
> +    .instance_init = pnv_psi_power9_instance_init,
> +    .class_init    = pnv_psi_power9_class_init,
> +    .interfaces = (InterfaceInfo[]) {
> +            { TYPE_XIVE_NOTIFIER },
> +            { },
> +    },
> +};
> +
>  static void pnv_psi_class_init(ObjectClass *klass, void *data)
>  {
>      DeviceClass *dc = DEVICE_CLASS(klass);
> @@ -611,6 +921,17 @@ static void pnv_psi_register_types(void)
>  {
>      type_register_static(&pnv_psi_info);
>      type_register_static(&pnv_psi_power8_info);
> +    type_register_static(&pnv_psi_power9_info);
>  }
>  
>  type_init(pnv_psi_register_types);
> +
> +void pnv_psi_pic_print_info(PnvPsi *psi, Monitor *mon)
> +{
> +    uint32_t offset =
> +        (psi->regs[PSIHB_REG(PSIHB9_IVT_OFFSET)] >> PSIHB9_IVT_OFF_SHIFT);
> +
> +    monitor_printf(mon, "PSIHB Source %08x .. %08x\n",
> +                  offset, offset + psi->source.nr_irqs - 1);
> +    xive_source_pic_print_info(&psi->source, offset, mon);
> +}

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 16/27] ppc/pnv: lpc: fix OPB address ranges
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 16/27] ppc/pnv: lpc: fix OPB address ranges Cédric Le Goater
@ 2019-03-07  4:11   ` David Gibson
  0 siblings, 0 replies; 55+ messages in thread
From: David Gibson @ 2019-03-07  4:11 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1215 bytes --]

On Wed, Mar 06, 2019 at 09:50:21AM +0100, Cédric Le Goater wrote:

This absolutely needs a commit message explaining why/how they were
wrong in the first place.

> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  hw/ppc/pnv_lpc.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c
> index 9b18ce55e391..547be609cafe 100644
> --- a/hw/ppc/pnv_lpc.c
> +++ b/hw/ppc/pnv_lpc.c
> @@ -89,10 +89,11 @@ enum {
>  #define LPC_FW_OPB_SIZE         0x10000000
>  
>  #define LPC_OPB_REGS_OPB_ADDR   0xc0010000
> -#define LPC_OPB_REGS_OPB_SIZE   0x00002000
> +#define LPC_OPB_REGS_OPB_SIZE   0x00000060
> +#define LPC_OPB_REGS_OPBA_ADDR  0xc0011000
> +#define LPC_OPB_REGS_OPBA_SIZE  0x00000008
>  #define LPC_HC_REGS_OPB_ADDR    0xc0012000
> -#define LPC_HC_REGS_OPB_SIZE    0x00001000
> -
> +#define LPC_HC_REGS_OPB_SIZE    0x00000100
>  
>  static int pnv_lpc_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
>  {

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 17/27] ppc/pnv: add a LPC Controller model class
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 17/27] ppc/pnv: add a LPC Controller model class Cédric Le Goater
@ 2019-03-07  4:12   ` David Gibson
  0 siblings, 0 replies; 55+ messages in thread
From: David Gibson @ 2019-03-07  4:12 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 7364 bytes --]

On Wed, Mar 06, 2019 at 09:50:22AM +0100, Cédric Le Goater wrote:
> It will ease the introduction of the LPC Controller model for POWER9.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>

> ---
>  include/hw/ppc/pnv_lpc.h | 16 ++++++++
>  hw/ppc/pnv.c             |  2 +-
>  hw/ppc/pnv_lpc.c         | 85 ++++++++++++++++++++++++++++------------
>  3 files changed, 78 insertions(+), 25 deletions(-)
> 
> diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h
> index d657489b07ce..242baecdcb93 100644
> --- a/include/hw/ppc/pnv_lpc.h
> +++ b/include/hw/ppc/pnv_lpc.h
> @@ -24,6 +24,9 @@
>  #define TYPE_PNV_LPC "pnv-lpc"
>  #define PNV_LPC(obj) \
>       OBJECT_CHECK(PnvLpcController, (obj), TYPE_PNV_LPC)
> +#define TYPE_PNV8_LPC TYPE_PNV_LPC "-POWER8"
> +#define PNV8_LPC(obj) \
> +    OBJECT_CHECK(PnvLpc, (obj), TYPE_PNV8_LPC)
>  
>  typedef struct PnvLpcController {
>      DeviceState parent;
> @@ -70,6 +73,19 @@ typedef struct PnvLpcController {
>      PnvPsi *psi;
>  } PnvLpcController;
>  
> +#define PNV_LPC_CLASS(klass) \
> +     OBJECT_CLASS_CHECK(PnvLpcClass, (klass), TYPE_PNV_LPC)
> +#define PNV_LPC_GET_CLASS(obj) \
> +     OBJECT_GET_CLASS(PnvLpcClass, (obj), TYPE_PNV_LPC)
> +
> +typedef struct PnvLpcClass {
> +    DeviceClass parent_class;
> +
> +    int psi_irq;
> +
> +    DeviceRealize parent_realize;
> +} PnvLpcClass;
> +
>  ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp);
>  
>  #endif /* _PPC_PNV_LPC_H */
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 4375f97c7135..7176e1b68d0e 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -794,7 +794,7 @@ static void pnv_chip_power8_instance_init(Object *obj)
>                                     OBJECT(qdev_get_machine()), &error_abort);
>  
>      object_initialize_child(obj, "lpc",  &chip8->lpc, sizeof(chip8->lpc),
> -                            TYPE_PNV_LPC, &error_abort, NULL);
> +                            TYPE_PNV8_LPC, &error_abort, NULL);
>      object_property_add_const_link(OBJECT(&chip8->lpc), "psi",
>                                     OBJECT(&chip8->psi), &error_abort);
>  
> diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c
> index 547be609cafe..3c509a30a0af 100644
> --- a/hw/ppc/pnv_lpc.c
> +++ b/hw/ppc/pnv_lpc.c
> @@ -245,6 +245,7 @@ static const MemoryRegionOps pnv_lpc_xscom_ops = {
>  static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
>  {
>      bool lpc_to_opb_irq = false;
> +    PnvLpcClass *plc = PNV_LPC_GET_CLASS(lpc);
>  
>      /* Update LPC controller to OPB line */
>      if (lpc->lpc_hc_irqser_ctrl & LPC_HC_IRQSER_EN) {
> @@ -267,7 +268,7 @@ static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
>      lpc->opb_irq_stat |= lpc->opb_irq_input & lpc->opb_irq_mask;
>  
>      /* Reflect the interrupt */
> -    pnv_psi_irq_set(lpc->psi, PSIHB_IRQ_LPC_I2C, lpc->opb_irq_stat != 0);
> +    pnv_psi_irq_set(lpc->psi, plc->psi_irq, lpc->opb_irq_stat != 0);
>  }
>  
>  static uint64_t lpc_hc_read(void *opaque, hwaddr addr, unsigned size)
> @@ -419,11 +420,65 @@ static const MemoryRegionOps opb_master_ops = {
>      },
>  };
>  
> +static void pnv_lpc_power8_realize(DeviceState *dev, Error **errp)
> +{
> +    PnvLpcController *lpc = PNV_LPC(dev);
> +    PnvLpcClass *plc = PNV_LPC_GET_CLASS(dev);
> +    Error *local_err = NULL;
> +
> +    plc->parent_realize(dev, &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +
> +    /* P8 uses a XSCOM region for LPC registers */
> +    pnv_xscom_region_init(&lpc->xscom_regs, OBJECT(lpc),
> +                          &pnv_lpc_xscom_ops, lpc, "xscom-lpc",
> +                          PNV_XSCOM_LPC_SIZE);
> +}
> +
> +static void pnv_lpc_power8_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
> +    PnvLpcClass *plc = PNV_LPC_CLASS(klass);
> +
> +    dc->desc = "PowerNV LPC Controller POWER8";
> +
> +    xdc->dt_xscom = pnv_lpc_dt_xscom;
> +
> +    plc->psi_irq = PSIHB_IRQ_LPC_I2C;
> +
> +    device_class_set_parent_realize(dc, pnv_lpc_power8_realize,
> +                                    &plc->parent_realize);
> +}
> +
> +static const TypeInfo pnv_lpc_power8_info = {
> +    .name          = TYPE_PNV8_LPC,
> +    .parent        = TYPE_PNV_LPC,
> +    .instance_size = sizeof(PnvLpcController),
> +    .class_init    = pnv_lpc_power8_class_init,
> +    .interfaces = (InterfaceInfo[]) {
> +        { TYPE_PNV_XSCOM_INTERFACE },
> +        { }
> +    }
> +};
> +
>  static void pnv_lpc_realize(DeviceState *dev, Error **errp)
>  {
>      PnvLpcController *lpc = PNV_LPC(dev);
>      Object *obj;
> -    Error *error = NULL;
> +    Error *local_err = NULL;
> +
> +    obj = object_property_get_link(OBJECT(dev), "psi", &local_err);
> +    if (!obj) {
> +        error_propagate(errp, local_err);
> +        error_prepend(errp, "required link 'psi' not found: ");
> +        return;
> +    }
> +    /* The LPC controller needs PSI to generate interrupts  */
> +    lpc->psi = PNV_PSI(obj);
>  
>      /* Reg inits */
>      lpc->lpc_hc_fw_rd_acc_size = LPC_HC_FW_RD_4B;
> @@ -463,46 +518,28 @@ static void pnv_lpc_realize(DeviceState *dev, Error **errp)
>                            "lpc-hc", LPC_HC_REGS_OPB_SIZE);
>      memory_region_add_subregion(&lpc->opb_mr, LPC_HC_REGS_OPB_ADDR,
>                                  &lpc->lpc_hc_regs);
> -
> -    /* XScom region for LPC registers */
> -    pnv_xscom_region_init(&lpc->xscom_regs, OBJECT(dev),
> -                          &pnv_lpc_xscom_ops, lpc, "xscom-lpc",
> -                          PNV_XSCOM_LPC_SIZE);
> -
> -    /* get PSI object from chip */
> -    obj = object_property_get_link(OBJECT(dev), "psi", &error);
> -    if (!obj) {
> -        error_setg(errp, "%s: required link 'psi' not found: %s",
> -                   __func__, error_get_pretty(error));
> -        return;
> -    }
> -    lpc->psi = PNV_PSI(obj);
>  }
>  
>  static void pnv_lpc_class_init(ObjectClass *klass, void *data)
>  {
>      DeviceClass *dc = DEVICE_CLASS(klass);
> -    PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
> -
> -    xdc->dt_xscom = pnv_lpc_dt_xscom;
>  
>      dc->realize = pnv_lpc_realize;
> +    dc->desc = "PowerNV LPC Controller";
>  }
>  
>  static const TypeInfo pnv_lpc_info = {
>      .name          = TYPE_PNV_LPC,
>      .parent        = TYPE_DEVICE,
> -    .instance_size = sizeof(PnvLpcController),
>      .class_init    = pnv_lpc_class_init,
> -    .interfaces = (InterfaceInfo[]) {
> -        { TYPE_PNV_XSCOM_INTERFACE },
> -        { }
> -    }
> +    .class_size    = sizeof(PnvLpcClass),
> +    .abstract      = true,
>  };
>  
>  static void pnv_lpc_register_types(void)
>  {
>      type_register_static(&pnv_lpc_info);
> +    type_register_static(&pnv_lpc_power8_info);
>  }
>  
>  type_init(pnv_lpc_register_types)

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 18/27] ppc/pnv: add a LPC Controller model for POWER9
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 18/27] ppc/pnv: add a LPC Controller model for POWER9 Cédric Le Goater
@ 2019-03-07  4:18   ` David Gibson
  2019-03-07  7:07     ` Cédric Le Goater
  0 siblings, 1 reply; 55+ messages in thread
From: David Gibson @ 2019-03-07  4:18 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 14488 bytes --]

On Wed, Mar 06, 2019 at 09:50:23AM +0100, Cédric Le Goater wrote:
> The LPC Controller on POWER9 is very similar to the one found on
> POWER8 but accesses are now done via on MMIOs, without the XSCOM and
> ECCB logic. The device tree is populated differently so we add a
> specific POWER9 routine for the purpose.
> 
> SerIRQ routing is yet to be done.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  include/hw/ppc/pnv.h     |   4 +
>  include/hw/ppc/pnv_lpc.h |  10 ++
>  hw/ppc/pnv.c             |  29 +++++-
>  hw/ppc/pnv_lpc.c         | 200 +++++++++++++++++++++++++++++++++++++++
>  4 files changed, 240 insertions(+), 3 deletions(-)
> 
> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> index 57d0337219be..2d68aabc212f 100644
> --- a/include/hw/ppc/pnv.h
> +++ b/include/hw/ppc/pnv.h
> @@ -85,6 +85,7 @@ typedef struct Pnv9Chip {
>      /*< public >*/
>      PnvXive      xive;
>      PnvPsi       psi;
> +    PnvLpcController lpc;
>  } Pnv9Chip;
>  
>  typedef struct PnvChipClass {
> @@ -232,6 +233,9 @@ void pnv_bmc_powerdown(IPMIBmc *bmc);
>  #define PNV9_XIVE_PC_SIZE            0x0000001000000000ull
>  #define PNV9_XIVE_PC_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006018000000000ull)
>  
> +#define PNV9_LPCM_SIZE               0x0000000100000000ull
> +#define PNV9_LPCM_BASE(chip)         PNV9_CHIP_BASE(chip, 0x0006030000000000ull)
> +
>  #define PNV9_PSIHB_SIZE              0x0000000000100000ull
>  #define PNV9_PSIHB_BASE(chip)        PNV9_CHIP_BASE(chip, 0x0006030203000000ull)
>  
> diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h
> index 242baecdcb93..24fe23f0f63b 100644
> --- a/include/hw/ppc/pnv_lpc.h
> +++ b/include/hw/ppc/pnv_lpc.h
> @@ -28,6 +28,10 @@
>  #define PNV8_LPC(obj) \
>      OBJECT_CHECK(PnvLpc, (obj), TYPE_PNV8_LPC)
>  
> +#define TYPE_PNV9_LPC TYPE_PNV_LPC "-POWER9"
> +#define PNV9_LPC(obj) \
> +    OBJECT_CHECK(PnvLpc, (obj), TYPE_PNV9_LPC)
> +
>  typedef struct PnvLpcController {
>      DeviceState parent;
>  
> @@ -86,6 +90,12 @@ typedef struct PnvLpcClass {
>      DeviceRealize parent_realize;
>  } PnvLpcClass;
>  
> +/*
> + * Old compilers error on typdef forward declarations. Keep them happy.
> + */
> +struct PnvChip;
> +
>  ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp);
> +int pnv_dt_lpc(struct PnvChip *chip, void *fdt, int root_offset);
>  
>  #endif /* _PPC_PNV_LPC_H */
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 7176e1b68d0e..895be470af67 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -306,6 +306,8 @@ static void pnv_chip_power9_dt_populate(PnvChip *chip, void *fdt)
>      if (chip->ram_size) {
>          pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
>      }
> +
> +    pnv_dt_lpc(chip, fdt, 0);
>  }
>  
>  static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
> @@ -422,8 +424,14 @@ static int pnv_chip_isa_offset(PnvChip *chip, void *fdt)
>      char *name;
>      int offset;
>  
> -    name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
> -                           (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE);
> +    if (pnv_chip_is_power9(chip)) {

Again explicit chip type checks aren't very pretty.  Better to
redirect through a method.  Or, better, call into the common ISA DT
code from chip specific code passing the offset, rather than calling
out again to get it.

> +        name = g_strdup_printf("/lpcm-opb@%" PRIx64 "/lpc@0",
> +                               (uint64_t) PNV9_LPCM_BASE(chip));
> +    } else {
> +        name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
> +                               (uint64_t) PNV_XSCOM_BASE(chip),
> +                               PNV_XSCOM_LPC_BASE);
> +    }
>      offset = fdt_path_offset(fdt, name);
>      g_free(name);
>      return offset;
> @@ -559,7 +567,8 @@ static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp)
>  
>  static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp)
>  {
> -    return NULL;
> +    Pnv9Chip *chip9 = PNV9_CHIP(chip);
> +    return pnv_lpc_isa_create(&chip9->lpc, false, errp);
>  }
>  
>  static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
> @@ -954,6 +963,11 @@ static void pnv_chip_power9_instance_init(Object *obj)
>                              TYPE_PNV9_PSI, &error_abort, NULL);
>      object_property_add_const_link(OBJECT(&chip9->psi), "chip", obj,
>                                     &error_abort);
> +
> +    object_initialize_child(obj, "lpc",  &chip9->lpc, sizeof(chip9->lpc),
> +                            TYPE_PNV9_LPC, &error_abort, NULL);
> +    object_property_add_const_link(OBJECT(&chip9->lpc), "psi",
> +                                   OBJECT(&chip9->psi), &error_abort);
>  }
>  
>  static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
> @@ -997,6 +1011,15 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
>      }
>      pnv_xscom_add_subregion(chip, PNV9_XSCOM_PSIHB_BASE,
>                              &chip9->psi.xscom_regs);
> +
> +    /* LPC */
> +    object_property_set_bool(OBJECT(&chip9->lpc), true, "realized", &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +    memory_region_add_subregion(get_system_memory(), PNV9_LPCM_BASE(chip),
> +                                &chip9->lpc.xscom_regs);
>  }
>  
>  static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
> diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c
> index 3c509a30a0af..6df694e0abc1 100644
> --- a/hw/ppc/pnv_lpc.c
> +++ b/hw/ppc/pnv_lpc.c
> @@ -118,6 +118,100 @@ static int pnv_lpc_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
>      return 0;
>  }
>  
> +/* POWER9 only */
> +int pnv_dt_lpc(PnvChip *chip, void *fdt, int root_offset)
> +{
> +    const char compat[] = "ibm,power9-lpcm-opb\0simple-bus";
> +    const char lpc_compat[] = "ibm,power9-lpc\0ibm,lpc";
> +    char *name;
> +    int offset, lpcm_offset;
> +    uint64_t lpcm_addr = PNV9_LPCM_BASE(chip);
> +    uint32_t opb_ranges[8] = { 0,
> +                               cpu_to_be32(lpcm_addr >> 32),
> +                               cpu_to_be32((uint32_t)lpcm_addr),
> +                               cpu_to_be32(PNV9_LPCM_SIZE / 2),
> +                               cpu_to_be32(PNV9_LPCM_SIZE / 2),
> +                               cpu_to_be32(lpcm_addr >> 32),
> +                               cpu_to_be32(PNV9_LPCM_SIZE / 2),
> +                               cpu_to_be32(PNV9_LPCM_SIZE / 2),
> +    };
> +    uint32_t opb_reg[4] = { cpu_to_be32(lpcm_addr >> 32),
> +                            cpu_to_be32((uint32_t)lpcm_addr),
> +                            cpu_to_be32(PNV9_LPCM_SIZE >> 32),
> +                            cpu_to_be32((uint32_t)PNV9_LPCM_SIZE),
> +    };
> +    uint32_t reg[2];
> +
> +    /*
> +     * OPB bus
> +     */
> +    name = g_strdup_printf("lpcm-opb@%"PRIx64, lpcm_addr);
> +    lpcm_offset = fdt_add_subnode(fdt, root_offset, name);
> +    _FDT(lpcm_offset);
> +    g_free(name);
> +
> +    _FDT((fdt_setprop(fdt, lpcm_offset, "reg", opb_reg, sizeof(opb_reg))));
> +    _FDT((fdt_setprop_cell(fdt, lpcm_offset, "#address-cells", 1)));
> +    _FDT((fdt_setprop_cell(fdt, lpcm_offset, "#size-cells", 1)));
> +    _FDT((fdt_setprop(fdt, lpcm_offset, "compatible", compat, sizeof(compat))));
> +    _FDT((fdt_setprop_cell(fdt, lpcm_offset, "ibm,chip-id", chip->chip_id)));
> +    _FDT((fdt_setprop(fdt, lpcm_offset, "ranges", opb_ranges,
> +                      sizeof(opb_ranges))));
> +
> +    /*
> +     * OPB Master registers
> +     */
> +    name = g_strdup_printf("opb-master@%x", LPC_OPB_REGS_OPB_ADDR);
> +    offset = fdt_add_subnode(fdt, lpcm_offset, name);
> +    _FDT(offset);
> +    g_free(name);
> +
> +    reg[0] = cpu_to_be32(LPC_OPB_REGS_OPB_ADDR);
> +    reg[1] = cpu_to_be32(LPC_OPB_REGS_OPB_SIZE);
> +    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
> +    _FDT((fdt_setprop_string(fdt, offset, "compatible",
> +                             "ibm,power9-lpcm-opb-master")));
> +
> +    /*
> +     * OPB arbitrer registers
> +     */
> +    name = g_strdup_printf("opb-arbitrer@%x", LPC_OPB_REGS_OPBA_ADDR);
> +    offset = fdt_add_subnode(fdt, lpcm_offset, name);
> +    _FDT(offset);
> +    g_free(name);
> +
> +    reg[0] = cpu_to_be32(LPC_OPB_REGS_OPBA_ADDR);
> +    reg[1] = cpu_to_be32(LPC_OPB_REGS_OPBA_SIZE);
> +    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
> +    _FDT((fdt_setprop_string(fdt, offset, "compatible",
> +                             "ibm,power9-lpcm-opb-arbiter")));
> +
> +    /*
> +     * LPC Host Controller registers
> +     */
> +    name = g_strdup_printf("lpc-controller@%x", LPC_HC_REGS_OPB_ADDR);
> +    offset = fdt_add_subnode(fdt, lpcm_offset, name);
> +    _FDT(offset);
> +    g_free(name);
> +
> +    reg[0] = cpu_to_be32(LPC_HC_REGS_OPB_ADDR);
> +    reg[1] = cpu_to_be32(LPC_HC_REGS_OPB_SIZE);
> +    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
> +    _FDT((fdt_setprop_string(fdt, offset, "compatible",
> +                             "ibm,power9-lpc-controller")));
> +
> +    name = g_strdup_printf("lpc@0");
> +    offset = fdt_add_subnode(fdt, lpcm_offset, name);
> +    _FDT(offset);
> +    g_free(name);
> +    _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 2)));
> +    _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 1)));
> +    _FDT((fdt_setprop(fdt, offset, "compatible", lpc_compat,
> +                      sizeof(lpc_compat))));
> +
> +    return 0;
> +}
> +
>  /*
>   * These read/write handlers of the OPB address space should be common
>   * with the P9 LPC Controller which uses direct MMIOs.
> @@ -242,6 +336,74 @@ static const MemoryRegionOps pnv_lpc_xscom_ops = {
>      .endianness = DEVICE_BIG_ENDIAN,
>  };
>  
> +static uint64_t pnv_lpc_mmio_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    PnvLpcController *lpc = PNV_LPC(opaque);
> +    uint64_t val = 0;
> +    uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK;
> +    MemTxResult result;
> +
> +    switch (size) {
> +    case 4:
> +        val = address_space_ldl(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED,
> +                                &result);
> +        break;
> +    case 1:
> +        val = address_space_ldub(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED,
> +                                 &result);
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%"
> +                      HWADDR_PRIx " invalid size %d\n", addr, size);
> +        return 0;
> +    }
> +
> +    if (result != MEMTX_OK) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%"
> +                      HWADDR_PRIx "\n", addr);
> +    }
> +
> +    return val;

Couldn't you just map the relevant portion of the OPB AS into the MMIO
AS, rather than having to forward the IOs with explicit read/write
functions?

> +}
> +
> +static void pnv_lpc_mmio_write(void *opaque, hwaddr addr,
> +                                uint64_t val, unsigned size)
> +{
> +    PnvLpcController *lpc = PNV_LPC(opaque);
> +    uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK;
> +    MemTxResult result;
> +
> +    switch (size) {
> +    case 4:
> +        address_space_stl(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED,
> +                          &result);
> +         break;
> +    case 1:
> +        address_space_stb(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED,
> +                          &result);
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%"
> +                      HWADDR_PRIx " invalid size %d\n", addr, size);
> +        return;
> +    }
> +
> +    if (result != MEMTX_OK) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%"
> +                      HWADDR_PRIx "\n", addr);
> +    }
> +}
> +
> +static const MemoryRegionOps pnv_lpc_mmio_ops = {
> +    .read = pnv_lpc_mmio_read,
> +    .write = pnv_lpc_mmio_write,
> +    .impl = {
> +        .min_access_size = 1,
> +        .max_access_size = 4,
> +    },
> +    .endianness = DEVICE_BIG_ENDIAN,
> +};
> +
>  static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
>  {
>      bool lpc_to_opb_irq = false;
> @@ -465,6 +627,43 @@ static const TypeInfo pnv_lpc_power8_info = {
>      }
>  };
>  
> +static void pnv_lpc_power9_realize(DeviceState *dev, Error **errp)
> +{
> +    PnvLpcController *lpc = PNV_LPC(dev);
> +    PnvLpcClass *plc = PNV_LPC_GET_CLASS(dev);
> +    Error *local_err = NULL;
> +
> +    plc->parent_realize(dev, &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +
> +    /* P9 uses a MMIO region */
> +    memory_region_init_io(&lpc->xscom_regs, OBJECT(lpc), &pnv_lpc_mmio_ops,
> +                          lpc, "lpcm", PNV9_LPCM_SIZE);
> +}
> +
> +static void pnv_lpc_power9_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PnvLpcClass *plc = PNV_LPC_CLASS(klass);
> +
> +    dc->desc = "PowerNV LPC Controller POWER9";
> +
> +    plc->psi_irq = PSIHB9_IRQ_LPCHC;
> +
> +    device_class_set_parent_realize(dc, pnv_lpc_power9_realize,
> +                                    &plc->parent_realize);
> +}
> +
> +static const TypeInfo pnv_lpc_power9_info = {
> +    .name          = TYPE_PNV9_LPC,
> +    .parent        = TYPE_PNV_LPC,
> +    .instance_size = sizeof(PnvLpcController),
> +    .class_init    = pnv_lpc_power9_class_init,
> +};
> +
>  static void pnv_lpc_realize(DeviceState *dev, Error **errp)
>  {
>      PnvLpcController *lpc = PNV_LPC(dev);
> @@ -540,6 +739,7 @@ static void pnv_lpc_register_types(void)
>  {
>      type_register_static(&pnv_lpc_info);
>      type_register_static(&pnv_lpc_power8_info);
> +    type_register_static(&pnv_lpc_power9_info);
>  }
>  
>  type_init(pnv_lpc_register_types)

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 20/27] ppc/pnv: add a OCC model class
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 20/27] ppc/pnv: add a OCC model class Cédric Le Goater
@ 2019-03-07  4:26   ` David Gibson
  0 siblings, 0 replies; 55+ messages in thread
From: David Gibson @ 2019-03-07  4:26 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 4840 bytes --]

On Wed, Mar 06, 2019 at 09:50:25AM +0100, Cédric Le Goater wrote:
> It will ease the introduction of the OCC model for POWER9.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>

> ---
>  include/hw/ppc/pnv_occ.h | 14 ++++++++++++++
>  hw/ppc/pnv.c             |  2 +-
>  hw/ppc/pnv_occ.c         | 23 ++++++++++++++++++++---
>  3 files changed, 35 insertions(+), 4 deletions(-)
> 
> diff --git a/include/hw/ppc/pnv_occ.h b/include/hw/ppc/pnv_occ.h
> index 82f299dc76ff..ce2631e21f5e 100644
> --- a/include/hw/ppc/pnv_occ.h
> +++ b/include/hw/ppc/pnv_occ.h
> @@ -23,6 +23,9 @@
>  
>  #define TYPE_PNV_OCC "pnv-occ"
>  #define PNV_OCC(obj) OBJECT_CHECK(PnvOCC, (obj), TYPE_PNV_OCC)
> +#define TYPE_PNV8_OCC TYPE_PNV_OCC "-POWER8"
> +#define PNV8_OCC(obj) \
> +    OBJECT_CHECK(PnvOCC, (obj), TYPE_PNV8_OCC)
>  
>  typedef struct PnvOCC {
>      DeviceState xd;
> @@ -35,4 +38,15 @@ typedef struct PnvOCC {
>      MemoryRegion xscom_regs;
>  } PnvOCC;
>  
> +#define PNV_OCC_CLASS(klass) \
> +     OBJECT_CLASS_CHECK(PnvOCCClass, (klass), TYPE_PNV_OCC)
> +#define PNV_OCC_GET_CLASS(obj) \
> +     OBJECT_GET_CLASS(PnvOCCClass, (obj), TYPE_PNV_OCC)
> +
> +typedef struct PnvOCCClass {
> +    DeviceClass parent_class;
> +
> +    int xscom_size;
> +} PnvOCCClass;
> +
>  #endif /* _PPC_PNV_OCC_H */
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 895be470af67..81ab53899dbc 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -808,7 +808,7 @@ static void pnv_chip_power8_instance_init(Object *obj)
>                                     OBJECT(&chip8->psi), &error_abort);
>  
>      object_initialize_child(obj, "occ",  &chip8->occ, sizeof(chip8->occ),
> -                            TYPE_PNV_OCC, &error_abort, NULL);
> +                            TYPE_PNV8_OCC, &error_abort, NULL);
>      object_property_add_const_link(OBJECT(&chip8->occ), "psi",
>                                     OBJECT(&chip8->psi), &error_abort);
>  }
> diff --git a/hw/ppc/pnv_occ.c b/hw/ppc/pnv_occ.c
> index 04880f26d612..a210f44926aa 100644
> --- a/hw/ppc/pnv_occ.c
> +++ b/hw/ppc/pnv_occ.c
> @@ -54,7 +54,7 @@ static uint64_t pnv_occ_xscom_read(void *opaque, hwaddr addr, unsigned size)
>          break;
>      default:
>          qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
> -                      HWADDR_PRIx "\n", addr);
> +                      HWADDR_PRIx "\n", addr >> 3);
>      }
>      return val;
>  }
> @@ -77,7 +77,7 @@ static void pnv_occ_xscom_write(void *opaque, hwaddr addr,
>          break;
>      default:
>          qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
> -                      HWADDR_PRIx "\n", addr);
> +                      HWADDR_PRIx "\n", addr >> 3);
>      }
>  }
>  
> @@ -95,6 +95,7 @@ static const MemoryRegionOps pnv_occ_xscom_ops = {
>  static void pnv_occ_realize(DeviceState *dev, Error **errp)
>  {
>      PnvOCC *occ = PNV_OCC(dev);
> +    PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
>      Object *obj;
>      Error *error = NULL;
>  
> @@ -111,9 +112,23 @@ static void pnv_occ_realize(DeviceState *dev, Error **errp)
>  
>      /* XScom region for OCC registers */
>      pnv_xscom_region_init(&occ->xscom_regs, OBJECT(dev), &pnv_occ_xscom_ops,
> -                  occ, "xscom-occ", PNV_XSCOM_OCC_SIZE);
> +                  occ, "xscom-occ", poc->xscom_size);
>  }
>  
> +static void pnv_occ_power8_class_init(ObjectClass *klass, void *data)
> +{
> +    PnvOCCClass *poc = PNV_OCC_CLASS(klass);
> +
> +    poc->xscom_size = PNV_XSCOM_OCC_SIZE;
> +}
> +
> +static const TypeInfo pnv_occ_power8_type_info = {
> +    .name          = TYPE_PNV8_OCC,
> +    .parent        = TYPE_PNV_OCC,
> +    .instance_size = sizeof(PnvOCC),
> +    .class_init    = pnv_occ_power8_class_init,
> +};
> +
>  static void pnv_occ_class_init(ObjectClass *klass, void *data)
>  {
>      DeviceClass *dc = DEVICE_CLASS(klass);
> @@ -124,6 +139,7 @@ static void pnv_occ_class_init(ObjectClass *klass, void *data)
>  static const TypeInfo pnv_occ_type_info = {
>      .name          = TYPE_PNV_OCC,
>      .parent        = TYPE_DEVICE,
> +    .abstract      = true,
>      .instance_size = sizeof(PnvOCC),
>      .class_init    = pnv_occ_class_init,
>  };
> @@ -131,6 +147,7 @@ static const TypeInfo pnv_occ_type_info = {
>  static void pnv_occ_register_types(void)
>  {
>      type_register_static(&pnv_occ_type_info);
> +    type_register_static(&pnv_occ_power8_type_info);
>  }
>  
>  type_init(pnv_occ_register_types)

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 21/27] ppc/pnv: add a OCC model for POWER9
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 21/27] ppc/pnv: add a OCC model for POWER9 Cédric Le Goater
@ 2019-03-07  4:27   ` David Gibson
  2019-03-07  7:47     ` Cédric Le Goater
  0 siblings, 1 reply; 55+ messages in thread
From: David Gibson @ 2019-03-07  4:27 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 6605 bytes --]

On Wed, Mar 06, 2019 at 09:50:26AM +0100, Cédric Le Goater wrote:
> The OCC on POWER9 is very similar to the one found on POWER8. Provide
> the same routines with P9 values for the registers and IRQ number.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  include/hw/ppc/pnv.h       |  1 +
>  include/hw/ppc/pnv_occ.h   |  4 ++++
>  include/hw/ppc/pnv_xscom.h |  3 +++
>  hw/ppc/pnv.c               | 13 +++++++++++++
>  hw/ppc/pnv_occ.c           | 40 ++++++++++++++++++++++++++++++++++++++
>  5 files changed, 61 insertions(+)
> 
> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> index 2d68aabc212f..ad3bf0690ecf 100644
> --- a/include/hw/ppc/pnv.h
> +++ b/include/hw/ppc/pnv.h
> @@ -86,6 +86,7 @@ typedef struct Pnv9Chip {
>      PnvXive      xive;
>      PnvPsi       psi;
>      PnvLpcController lpc;
> +    PnvOCC       occ;
>  } Pnv9Chip;
>  
>  typedef struct PnvChipClass {
> diff --git a/include/hw/ppc/pnv_occ.h b/include/hw/ppc/pnv_occ.h
> index ce2631e21f5e..8951eb7ea316 100644
> --- a/include/hw/ppc/pnv_occ.h
> +++ b/include/hw/ppc/pnv_occ.h
> @@ -27,6 +27,10 @@
>  #define PNV8_OCC(obj) \
>      OBJECT_CHECK(PnvOCC, (obj), TYPE_PNV8_OCC)
>  
> +#define TYPE_PNV9_OCC TYPE_PNV_OCC "-POWER9"
> +#define PNV9_OCC(obj) \
> +    OBJECT_CHECK(PnvOCC, (obj), TYPE_PNV9_OCC)
> +
>  typedef struct PnvOCC {
>      DeviceState xd;
>  
> diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
> index 403a365ed274..3292459fbb78 100644
> --- a/include/hw/ppc/pnv_xscom.h
> +++ b/include/hw/ppc/pnv_xscom.h
> @@ -73,6 +73,9 @@ typedef struct PnvXScomInterfaceClass {
>  #define PNV_XSCOM_OCC_BASE        0x0066000
>  #define PNV_XSCOM_OCC_SIZE        0x6000
>  
> +#define PNV9_XSCOM_OCC_BASE       PNV_XSCOM_OCC_BASE
> +#define PNV9_XSCOM_OCC_SIZE       0x8000
> +
>  #define PNV9_XSCOM_PSIHB_BASE     0x5012900
>  #define PNV9_XSCOM_PSIHB_SIZE     0x100
>  
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 81ab53899dbc..a056064c8c11 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -968,6 +968,11 @@ static void pnv_chip_power9_instance_init(Object *obj)
>                              TYPE_PNV9_LPC, &error_abort, NULL);
>      object_property_add_const_link(OBJECT(&chip9->lpc), "psi",
>                                     OBJECT(&chip9->psi), &error_abort);
> +
> +    object_initialize_child(obj, "occ",  &chip9->occ, sizeof(chip9->occ),
> +                            TYPE_PNV9_OCC, &error_abort, NULL);
> +    object_property_add_const_link(OBJECT(&chip9->occ), "psi",
> +                                   OBJECT(&chip9->psi), &error_abort);
>  }
>  
>  static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
> @@ -1020,6 +1025,14 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
>      }
>      memory_region_add_subregion(get_system_memory(), PNV9_LPCM_BASE(chip),
>                                  &chip9->lpc.xscom_regs);
> +
> +    /* Create the simplified OCC model */
> +    object_property_set_bool(OBJECT(&chip9->occ), true, "realized", &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +    pnv_xscom_add_subregion(chip, PNV9_XSCOM_OCC_BASE, &chip9->occ.xscom_regs);
>  }
>  
>  static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
> diff --git a/hw/ppc/pnv_occ.c b/hw/ppc/pnv_occ.c
> index a210f44926aa..59b0702bc716 100644
> --- a/hw/ppc/pnv_occ.c
> +++ b/hw/ppc/pnv_occ.c
> @@ -31,6 +31,10 @@
>  #define OCB_OCI_OCCMISC_AND     0x4021
>  #define OCB_OCI_OCCMISC_OR      0x4022
>  
> +#define P9_OCB_OCI_OCCMISC              0x6080
> +#define P9_OCB_OCI_OCCMISC_CLEAR        0x6081
> +#define P9_OCB_OCI_OCCMISC_OR           0x6082
> +
>  static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val)
>  {
>      bool irq_state;
> @@ -42,6 +46,17 @@ static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val)
>      pnv_psi_irq_set(occ->psi, PSIHB_IRQ_OCC, irq_state);
>  }
>  
> +static void pnv_occ_p9_set_misc(PnvOCC *occ, uint64_t val)
> +{
> +    bool irq_state;
> +
> +    val &= 0xffff000000000000ull;
> +
> +    occ->occmisc = val;
> +    irq_state = !!(val >> 63);
> +    pnv_psi_irq_set(occ->psi, PSIHB9_IRQ_OCC, irq_state);
> +}
> +
>  static uint64_t pnv_occ_xscom_read(void *opaque, hwaddr addr, unsigned size)
>  {
>      PnvOCC *occ = PNV_OCC(opaque);
> @@ -50,6 +65,7 @@ static uint64_t pnv_occ_xscom_read(void *opaque, hwaddr addr, unsigned size)
>  
>      switch (offset) {
>      case OCB_OCI_OCCMISC:
> +    case P9_OCB_OCI_OCCMISC:
>          val = occ->occmisc;
>          break;
>      default:
> @@ -75,6 +91,15 @@ static void pnv_occ_xscom_write(void *opaque, hwaddr addr,
>      case OCB_OCI_OCCMISC:
>          pnv_occ_set_misc(occ, val);
>          break;
> +    case P9_OCB_OCI_OCCMISC_CLEAR:
> +        pnv_occ_p9_set_misc(occ, 0);
> +        break;
> +    case P9_OCB_OCI_OCCMISC_OR:
> +        pnv_occ_p9_set_misc(occ, occ->occmisc | val);
> +        break;
> +    case P9_OCB_OCI_OCCMISC:
> +        pnv_occ_p9_set_misc(occ, val);
> +       break;

Are the P9 OCC registers a strict superset of the P8 registers?

>      default:
>          qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
>                        HWADDR_PRIx "\n", addr >> 3);
> @@ -115,6 +140,20 @@ static void pnv_occ_realize(DeviceState *dev, Error **errp)
>                    occ, "xscom-occ", poc->xscom_size);
>  }
>  
> +static void pnv_occ_power9_class_init(ObjectClass *klass, void *data)
> +{
> +    PnvOCCClass *poc = PNV_OCC_CLASS(klass);
> +
> +    poc->xscom_size = PNV9_XSCOM_OCC_SIZE;
> +}
> +
> +static const TypeInfo pnv_occ_power9_type_info = {
> +    .name          = TYPE_PNV9_OCC,
> +    .parent        = TYPE_PNV_OCC,
> +    .instance_size = sizeof(PnvOCC),
> +    .class_init    = pnv_occ_power9_class_init,
> +};
> +
>  static void pnv_occ_power8_class_init(ObjectClass *klass, void *data)
>  {
>      PnvOCCClass *poc = PNV_OCC_CLASS(klass);
> @@ -148,6 +187,7 @@ static void pnv_occ_register_types(void)
>  {
>      type_register_static(&pnv_occ_type_info);
>      type_register_static(&pnv_occ_power8_type_info);
> +    type_register_static(&pnv_occ_power9_type_info);
>  }
>  
>  type_init(pnv_occ_register_types)

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 22/27] ppc/pnv: extend XSCOM core support for POWER9
  2019-03-06  8:50 ` [Qemu-devel] [PATCH 22/27] ppc/pnv: extend XSCOM core support " Cédric Le Goater
@ 2019-03-07  4:28   ` David Gibson
  0 siblings, 0 replies; 55+ messages in thread
From: David Gibson @ 2019-03-07  4:28 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 2373 bytes --]

On Wed, Mar 06, 2019 at 09:50:27AM +0100, Cédric Le Goater wrote:
> Add a couple of XSCOM addresses controlling the power management
> states of the core.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  hw/ppc/pnv_core.c | 22 ++++++++++++++++++++--
>  1 file changed, 20 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
> index 38179cdc53dc..c3d6350dc90a 100644
> --- a/hw/ppc/pnv_core.c
> +++ b/hw/ppc/pnv_core.c
> @@ -60,6 +60,12 @@ static void pnv_cpu_reset(void *opaque)
>  #define PNV_XSCOM_EX_DTS_RESULT0     0x50000
>  #define PNV_XSCOM_EX_DTS_RESULT1     0x50001
>  
> +/*
> + * POWER9 core controls
> + */
> +#define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP 0xf010d
> +#define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR 0xf010a
> +
>  static uint64_t pnv_core_xscom_read(void *opaque, hwaddr addr,
>                                      unsigned int width)
>  {
> @@ -74,6 +80,10 @@ static uint64_t pnv_core_xscom_read(void *opaque, hwaddr addr,
>      case PNV_XSCOM_EX_DTS_RESULT1:
>          val = 0x24f000000000000ull;
>          break;

Shouldn't this be in a p9 specific read/write routine?

> +    case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP:
> +    case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR:
> +        val = 0x0;
> +        break;
>      default:
>          qemu_log_mask(LOG_UNIMP, "Warning: reading reg=0x%" HWADDR_PRIx "\n",
>                    addr);
> @@ -85,8 +95,16 @@ static uint64_t pnv_core_xscom_read(void *opaque, hwaddr addr,
>  static void pnv_core_xscom_write(void *opaque, hwaddr addr, uint64_t val,
>                                   unsigned int width)
>  {
> -    qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx "\n",
> -                  addr);
> +    uint32_t offset = addr >> 3;
> +
> +    switch (offset) {
> +    case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP:
> +    case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR:
> +        break;
> +    default:
> +        qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx "\n",
> +                      addr);
> +    }
>  }
>  
>  static const MemoryRegionOps pnv_core_xscom_ops = {

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 15/27] ppc/pnv: add a PSI bridge model for POWER9
  2019-03-07  4:10   ` David Gibson
@ 2019-03-07  6:37     ` Cédric Le Goater
  2019-03-07 22:33       ` Cédric Le Goater
  2019-03-08  0:17       ` David Gibson
  0 siblings, 2 replies; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-07  6:37 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel

On 3/7/19 5:10 AM, David Gibson wrote:
> On Wed, Mar 06, 2019 at 09:50:20AM +0100, Cédric Le Goater wrote:
>> The PSI bridge on POWER9 is very similar to POWER8. The BAR is still
>> set through XSCOM but the controls are now entirely done with MMIOs.
>> More interrupts are defined and the interrupt controller interface has
>> changed to XIVE. The POWER9 model is a first example of the usage of
>> the notify() handler of the XiveNotifier interface, linking the PSI
>> XiveSource to its owning device model.
>>
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>> ---
>>  include/hw/ppc/pnv.h       |   6 +
>>  include/hw/ppc/pnv_psi.h   |  24 +++
>>  include/hw/ppc/pnv_xscom.h |   3 +
>>  hw/ppc/pnv.c               |  17 ++
>>  hw/ppc/pnv_psi.c           | 325 ++++++++++++++++++++++++++++++++++++-
>>  5 files changed, 373 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
>> index eb4bba25b3e9..57d0337219be 100644
>> --- a/include/hw/ppc/pnv.h
>> +++ b/include/hw/ppc/pnv.h
>> @@ -84,6 +84,7 @@ typedef struct Pnv9Chip {
>>  
>>      /*< public >*/
>>      PnvXive      xive;
>> +    PnvPsi       psi;
>>  } Pnv9Chip;
>>  
>>  typedef struct PnvChipClass {
>> @@ -231,11 +232,16 @@ void pnv_bmc_powerdown(IPMIBmc *bmc);
>>  #define PNV9_XIVE_PC_SIZE            0x0000001000000000ull
>>  #define PNV9_XIVE_PC_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006018000000000ull)
>>  
>> +#define PNV9_PSIHB_SIZE              0x0000000000100000ull
>> +#define PNV9_PSIHB_BASE(chip)        PNV9_CHIP_BASE(chip, 0x0006030203000000ull)
>> +
>>  #define PNV9_XIVE_IC_SIZE            0x0000000000080000ull
>>  #define PNV9_XIVE_IC_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006030203100000ull)
>>  
>>  #define PNV9_XIVE_TM_SIZE            0x0000000000040000ull
>>  #define PNV9_XIVE_TM_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006030203180000ull)
>>  
>> +#define PNV9_PSIHB_ESB_SIZE          0x0000000000010000ull
>> +#define PNV9_PSIHB_ESB_BASE(chip)    PNV9_CHIP_BASE(chip, 0x00060302031c0000ull)
>>  
>>  #endif /* _PPC_PNV_H */
>> diff --git a/include/hw/ppc/pnv_psi.h b/include/hw/ppc/pnv_psi.h
>> index 585a41cd19b6..d7e1ab282cf8 100644
>> --- a/include/hw/ppc/pnv_psi.h
>> +++ b/include/hw/ppc/pnv_psi.h
>> @@ -21,6 +21,7 @@
>>  
>>  #include "hw/sysbus.h"
>>  #include "hw/ppc/xics.h"
>> +#include "hw/ppc/xive.h"
>>  
>>  #define TYPE_PNV_PSI "pnv-psi"
>>  #define PNV_PSI(obj) \
>> @@ -28,6 +29,9 @@
>>  #define TYPE_PNV8_PSI TYPE_PNV_PSI "-POWER8"
>>  #define PNV8_PSI(obj) \
>>      OBJECT_CHECK(PnvPsi, (obj), TYPE_PNV8_PSI)
>> +#define TYPE_PNV9_PSI TYPE_PNV_PSI "-POWER9"
>> +#define PNV9_PSI(obj) \
>> +    OBJECT_CHECK(PnvPsi, (obj), TYPE_PNV9_PSI)
>>  
>>  #define PSIHB_XSCOM_MAX         0x20
>>  
>> @@ -43,6 +47,7 @@ typedef struct PnvPsi {
>>  
>>      /* Interrupt generation */
>>      ICSState ics;
>> +    XiveSource source;
> 
> Uh... surely these should move to the subtype structures, so you don't
> have both of them.

I did not introduce a subtype, only a subclass. But we could 
possibly. It seemed overkill for one attribute.

> 
>>      qemu_irq *qirqs;
>>  
>>      /* Registers */
>> @@ -82,4 +87,23 @@ typedef enum PnvPsiIrq {
>>  
>>  void pnv_psi_irq_set(PnvPsi *psi, int irq, bool state);
>>  
>> +/* P9 PSI Interrupts */
>> +#define PSIHB9_IRQ_PSI          0
>> +#define PSIHB9_IRQ_OCC          1
>> +#define PSIHB9_IRQ_FSI          2
>> +#define PSIHB9_IRQ_LPCHC        3
>> +#define PSIHB9_IRQ_LOCAL_ERR    4
>> +#define PSIHB9_IRQ_GLOBAL_ERR   5
>> +#define PSIHB9_IRQ_TPM          6
>> +#define PSIHB9_IRQ_LPC_SIRQ0    7
>> +#define PSIHB9_IRQ_LPC_SIRQ1    8
>> +#define PSIHB9_IRQ_LPC_SIRQ2    9
>> +#define PSIHB9_IRQ_LPC_SIRQ3    10
>> +#define PSIHB9_IRQ_SBE_I2C      11
>> +#define PSIHB9_IRQ_DIO          12
>> +#define PSIHB9_IRQ_PSU          13
>> +#define PSIHB9_NUM_IRQS         14
>> +
>> +void pnv_psi_pic_print_info(PnvPsi *psi, Monitor *mon);
>> +
>>  #endif /* _PPC_PNV_PSI_H */
>> diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
>> index 6623ec54a7a8..403a365ed274 100644
>> --- a/include/hw/ppc/pnv_xscom.h
>> +++ b/include/hw/ppc/pnv_xscom.h
>> @@ -73,6 +73,9 @@ typedef struct PnvXScomInterfaceClass {
>>  #define PNV_XSCOM_OCC_BASE        0x0066000
>>  #define PNV_XSCOM_OCC_SIZE        0x6000
>>  
>> +#define PNV9_XSCOM_PSIHB_BASE     0x5012900
>> +#define PNV9_XSCOM_PSIHB_SIZE     0x100
>> +
>>  #define PNV9_XSCOM_XIVE_BASE      0x5013000
>>  #define PNV9_XSCOM_XIVE_SIZE      0x300
>>  
>> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
>> index 67d40dc3eebc..4375f97c7135 100644
>> --- a/hw/ppc/pnv.c
>> +++ b/hw/ppc/pnv.c
>> @@ -579,6 +579,7 @@ static void pnv_chip_power9_pic_print_info(PnvChip *chip, Monitor *mon)
>>      Pnv9Chip *chip9 = PNV9_CHIP(chip);
>>  
>>      pnv_xive_pic_print_info(&chip9->xive, mon);
>> +    pnv_psi_pic_print_info(&chip9->psi, mon);
>>  }
>>  
>>  static void pnv_init(MachineState *machine)
>> @@ -948,6 +949,11 @@ static void pnv_chip_power9_instance_init(Object *obj)
>>                              TYPE_PNV_XIVE, &error_abort, NULL);
>>      object_property_add_const_link(OBJECT(&chip9->xive), "chip", obj,
>>                                     &error_abort);
>> +
>> +    object_initialize_child(obj, "psi",  &chip9->psi, sizeof(chip9->psi),
>> +                            TYPE_PNV9_PSI, &error_abort, NULL);
>> +    object_property_add_const_link(OBJECT(&chip9->psi), "chip", obj,
>> +                                   &error_abort);
>>  }
>>  
>>  static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
>> @@ -980,6 +986,17 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
>>      }
>>      pnv_xscom_add_subregion(chip, PNV9_XSCOM_XIVE_BASE,
>>                              &chip9->xive.xscom_regs);
>> +
>> +    /* Processor Service Interface (PSI) Host Bridge */
>> +    object_property_set_int(OBJECT(&chip9->psi), PNV9_PSIHB_BASE(chip),
>> +                            "bar", &error_fatal);
>> +    object_property_set_bool(OBJECT(&chip9->psi), true, "realized", &local_err);
>> +    if (local_err) {
>> +        error_propagate(errp, local_err);
>> +        return;
>> +    }
>> +    pnv_xscom_add_subregion(chip, PNV9_XSCOM_PSIHB_BASE,
>> +                            &chip9->psi.xscom_regs);
>>  }
>>  
>>  static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
>> diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
>> index e56b455a61b1..3f995a0e0d7f 100644
>> --- a/hw/ppc/pnv_psi.c
>> +++ b/hw/ppc/pnv_psi.c
>> @@ -22,6 +22,7 @@
>>  #include "target/ppc/cpu.h"
>>  #include "qemu/log.h"
>>  #include "qapi/error.h"
>> +#include "monitor/monitor.h"
>>  
>>  #include "exec/address-spaces.h"
>>  
>> @@ -114,6 +115,9 @@
>>  #define PSIHB_BAR_MASK                  0x0003fffffff00000ull
>>  #define PSIHB_FSPBAR_MASK               0x0003ffff00000000ull
>>  
>> +#define PSIHB9_BAR_MASK                 0x00fffffffff00000ull
>> +#define PSIHB9_FSPBAR_MASK              0x00ffffff00000000ull
>> +
>>  #define PSIHB_REG(addr) (((addr) >> 3) + PSIHB_XSCOM_BAR)
>>  
>>  static void pnv_psi_set_bar(PnvPsi *psi, uint64_t bar)
>> @@ -531,6 +535,7 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp)
>>  }
>>  
>>  static const char compat_p8[] = "ibm,power8-psihb-x\0ibm,psihb-x";
>> +static const char compat_p9[] = "ibm,power9-psihb-x\0ibm,psihb-x";
>>  
>>  static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
>>  {
>> @@ -550,8 +555,13 @@ static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
>>      _FDT(fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)));
>>      _FDT(fdt_setprop_cell(fdt, offset, "#address-cells", 2));
>>      _FDT(fdt_setprop_cell(fdt, offset, "#size-cells", 1));
>> -    _FDT(fdt_setprop(fdt, offset, "compatible", compat_p8,
>> -                     sizeof(compat_p8)));
>> +    if (ppc->chip_type == PNV_CHIP_POWER9) {
> 
> Ew.  You already have subclasses - put the compatible in there, rather
> than more explicit tests against chip type.

I would also prefer to move the compat string to PnvPsiClass instead 
of using a chip_type field but I didn't find a clean way for it. We 
use sizeof() on the compat string below and it does not work on a 
char *.

I had the same issue in pnv_dt_xscom()

> 
>> +        _FDT(fdt_setprop(fdt, offset, "compatible", compat_p9,
>> +                         sizeof(compat_p9)));
>> +    } else {
>> +        _FDT(fdt_setprop(fdt, offset, "compatible", compat_p8,
>> +                         sizeof(compat_p8)));
>> +    }
>>      return 0;
>>  }
>>  
>> @@ -583,6 +593,306 @@ static const TypeInfo pnv_psi_power8_info = {
>>      .class_init    = pnv_psi_power8_class_init,
>>  };
>>  
>> +
>> +/* Common registers */
>> +
>> +#define PSIHB9_CR                       0x20
>> +#define PSIHB9_SEMR                     0x28
>> +
>> +/* P9 registers */
>> +
>> +#define PSIHB9_INTERRUPT_CONTROL        0x58
>> +#define   PSIHB9_IRQ_METHOD             PPC_BIT(0)
>> +#define   PSIHB9_IRQ_RESET              PPC_BIT(1)
>> +#define PSIHB9_ESB_CI_BASE              0x60
>> +#define   PSIHB9_ESB_CI_VALID           1
>> +#define PSIHB9_ESB_NOTIF_ADDR           0x68
>> +#define   PSIHB9_ESB_NOTIF_VALID        1
>> +#define PSIHB9_IVT_OFFSET               0x70
>> +#define   PSIHB9_IVT_OFF_SHIFT          32
>> +
>> +#define PSIHB9_IRQ_LEVEL                0x78 /* assertion */
>> +#define   PSIHB9_IRQ_LEVEL_PSI          PPC_BIT(0)
>> +#define   PSIHB9_IRQ_LEVEL_OCC          PPC_BIT(1)
>> +#define   PSIHB9_IRQ_LEVEL_FSI          PPC_BIT(2)
>> +#define   PSIHB9_IRQ_LEVEL_LPCHC        PPC_BIT(3)
>> +#define   PSIHB9_IRQ_LEVEL_LOCAL_ERR    PPC_BIT(4)
>> +#define   PSIHB9_IRQ_LEVEL_GLOBAL_ERR   PPC_BIT(5)
>> +#define   PSIHB9_IRQ_LEVEL_TPM          PPC_BIT(6)
>> +#define   PSIHB9_IRQ_LEVEL_LPC_SIRQ1    PPC_BIT(7)
>> +#define   PSIHB9_IRQ_LEVEL_LPC_SIRQ2    PPC_BIT(8)
>> +#define   PSIHB9_IRQ_LEVEL_LPC_SIRQ3    PPC_BIT(9)
>> +#define   PSIHB9_IRQ_LEVEL_LPC_SIRQ4    PPC_BIT(10)
>> +#define   PSIHB9_IRQ_LEVEL_SBE_I2C      PPC_BIT(11)
>> +#define   PSIHB9_IRQ_LEVEL_DIO          PPC_BIT(12)
>> +#define   PSIHB9_IRQ_LEVEL_PSU          PPC_BIT(13)
>> +#define   PSIHB9_IRQ_LEVEL_I2C_C        PPC_BIT(14)
>> +#define   PSIHB9_IRQ_LEVEL_I2C_D        PPC_BIT(15)
>> +#define   PSIHB9_IRQ_LEVEL_I2C_E        PPC_BIT(16)
>> +#define   PSIHB9_IRQ_LEVEL_SBE          PPC_BIT(19)
>> +
>> +#define PSIHB9_IRQ_STAT                 0x80 /* P bit */
>> +#define   PSIHB9_IRQ_STAT_PSI           PPC_BIT(0)
>> +#define   PSIHB9_IRQ_STAT_OCC           PPC_BIT(1)
>> +#define   PSIHB9_IRQ_STAT_FSI           PPC_BIT(2)
>> +#define   PSIHB9_IRQ_STAT_LPCHC         PPC_BIT(3)
>> +#define   PSIHB9_IRQ_STAT_LOCAL_ERR     PPC_BIT(4)
>> +#define   PSIHB9_IRQ_STAT_GLOBAL_ERR    PPC_BIT(5)
>> +#define   PSIHB9_IRQ_STAT_TPM           PPC_BIT(6)
>> +#define   PSIHB9_IRQ_STAT_LPC_SIRQ1     PPC_BIT(7)
>> +#define   PSIHB9_IRQ_STAT_LPC_SIRQ2     PPC_BIT(8)
>> +#define   PSIHB9_IRQ_STAT_LPC_SIRQ3     PPC_BIT(9)
>> +#define   PSIHB9_IRQ_STAT_LPC_SIRQ4     PPC_BIT(10)
>> +#define   PSIHB9_IRQ_STAT_SBE_I2C       PPC_BIT(11)
>> +#define   PSIHB9_IRQ_STAT_DIO           PPC_BIT(12)
>> +#define   PSIHB9_IRQ_STAT_PSU           PPC_BIT(13)
>> +
>> +static void pnv_psi_notify(XiveNotifier *xf, uint32_t srcno)
>> +{
>> +    PnvPsi *psi = PNV9_PSI(xf);
>> +    uint64_t notif_port = psi->regs[PSIHB_REG(PSIHB9_ESB_NOTIF_ADDR)];
>> +    bool valid = notif_port & PSIHB9_ESB_NOTIF_VALID;
>> +    uint64_t notify_addr = notif_port & ~PSIHB9_ESB_NOTIF_VALID;
>> +
>> +    uint32_t offset =
>> +        (psi->regs[PSIHB_REG(PSIHB9_IVT_OFFSET)] >> PSIHB9_IVT_OFF_SHIFT);
>> +    uint64_t lisn = cpu_to_be64(offset + srcno);
>> +
>> +    if (valid) {
>> +        cpu_physical_memory_write(notify_addr, &lisn, sizeof(lisn));
>> +    }
>> +}
>> +
>> +static uint64_t pnv_psi_p9_mmio_read(void *opaque, hwaddr addr, unsigned size)
>> +{
>> +    PnvPsi *psi = PNV9_PSI(opaque);
>> +    uint32_t reg = PSIHB_REG(addr);
>> +    uint64_t val = -1;
>> +
>> +    switch (addr) {
>> +    case PSIHB9_CR:
>> +    case PSIHB9_SEMR:
>> +        /* FSP stuff */
>> +    case PSIHB9_INTERRUPT_CONTROL:
>> +    case PSIHB9_ESB_CI_BASE:
>> +    case PSIHB9_ESB_NOTIF_ADDR:
>> +    case PSIHB9_IVT_OFFSET:
>> +        val = psi->regs[reg];
>> +        break;
>> +    default:
>> +        qemu_log_mask(LOG_GUEST_ERROR, "PSI: read at 0x%" PRIx64 "\n", addr);
>> +    }
>> +
>> +    return val;
>> +}
>> +
>> +static void pnv_psi_p9_mmio_write(void *opaque, hwaddr addr,
>> +                                  uint64_t val, unsigned size)
>> +{
>> +    PnvPsi *psi = PNV9_PSI(opaque);
>> +    uint32_t reg = PSIHB_REG(addr);
>> +    MemoryRegion *sysmem = get_system_memory();
>> +
>> +    switch (addr) {
>> +    case PSIHB9_CR:
>> +    case PSIHB9_SEMR:
>> +        /* FSP stuff */
>> +        break;
>> +    case PSIHB9_INTERRUPT_CONTROL:
>> +        if (val & PSIHB9_IRQ_RESET) {
>> +            device_reset(DEVICE(&psi->source));
>> +        }
>> +        psi->regs[reg] = val;
>> +        break;
>> +
>> +    case PSIHB9_ESB_CI_BASE:
>> +        if (!(val & PSIHB9_ESB_CI_VALID)) {
>> +            if (psi->regs[reg] & PSIHB9_ESB_CI_VALID) {
>> +                memory_region_del_subregion(sysmem, &psi->source.esb_mmio);
>> +            }
>> +        } else {
>> +            if (!(psi->regs[reg] & PSIHB9_ESB_CI_VALID)) {
>> +                memory_region_add_subregion(sysmem,
>> +                                        val & ~PSIHB9_ESB_CI_VALID,
>> +                                        &psi->source.esb_mmio);
>> +            }
>> +        }
>> +        psi->regs[reg] = val;
>> +        break;
>> +
>> +    case PSIHB9_ESB_NOTIF_ADDR:
>> +        psi->regs[reg] = val;
> 
> Again, not in scope for this patch, but not being able to put a
> reg[reg] = val outside the switch is a pretty good sign that a regs[]
> array mirroring the guest register interface is not the right model
> for this device.

Well, in this case, I think we could put 'psi->regs[reg] = val;'.

Thanks,

C.

>> +        break;
>> +    case PSIHB9_IVT_OFFSET:
>> +        psi->regs[reg] = val;
>> +        break;
>> +    default:
>> +        qemu_log_mask(LOG_GUEST_ERROR, "PSI: write at 0x%" PRIx64 "\n", addr);
>> +    }
>> +}
>> +
>> +static const MemoryRegionOps pnv_psi_p9_mmio_ops = {
>> +    .read = pnv_psi_p9_mmio_read,
>> +    .write = pnv_psi_p9_mmio_write,
>> +    .endianness = DEVICE_BIG_ENDIAN,
>> +    .valid = {
>> +        .min_access_size = 8,
>> +        .max_access_size = 8,
>> +    },
>> +    .impl = {
>> +        .min_access_size = 8,
>> +        .max_access_size = 8,
>> +    },
>> +};
>> +
>> +static uint64_t pnv_psi_p9_xscom_read(void *opaque, hwaddr addr, unsigned size)
>> +{
>> +    /* No read are expected */
>> +    qemu_log_mask(LOG_GUEST_ERROR, "PSI: xscom read at 0x%" PRIx64 "\n", addr);
>> +    return -1;
>> +}
>> +
>> +static void pnv_psi_p9_xscom_write(void *opaque, hwaddr addr,
>> +                                uint64_t val, unsigned size)
>> +{
>> +    PnvPsi *psi = PNV9_PSI(opaque);
>> +
>> +    /* XSCOM is only used to set the PSIHB MMIO region */
>> +    switch (addr >> 3) {
>> +    case PSIHB_XSCOM_BAR:
>> +        pnv_psi_set_bar(psi, val);
>> +        break;
>> +    default:
>> +        qemu_log_mask(LOG_GUEST_ERROR, "PSI: xscom write at 0x%" PRIx64 "\n",
>> +                      addr);
>> +    }
>> +}
>> +
>> +static const MemoryRegionOps pnv_psi_p9_xscom_ops = {
>> +    .read = pnv_psi_p9_xscom_read,
>> +    .write = pnv_psi_p9_xscom_write,
>> +    .endianness = DEVICE_BIG_ENDIAN,
>> +    .valid = {
>> +        .min_access_size = 8,
>> +        .max_access_size = 8,
>> +    },
>> +    .impl = {
>> +        .min_access_size = 8,
>> +        .max_access_size = 8,
>> +    }
>> +};
>> +
>> +static void pnv_psi_power9_irq_set(PnvPsi *psi, int irq, bool state)
>> +{
>> +    uint32_t irq_method = psi->regs[PSIHB_REG(PSIHB9_INTERRUPT_CONTROL)];
>> +
>> +    if (irq > PSIHB9_NUM_IRQS) {
>> +        qemu_log_mask(LOG_GUEST_ERROR, "PSI: Unsupported irq %d\n", irq);
>> +        return;
>> +    }
>> +
>> +    if (irq_method & PSIHB9_IRQ_METHOD) {
>> +        qemu_log_mask(LOG_GUEST_ERROR, "PSI: LSI IRQ method no supported\n");
>> +        return;
>> +    }
>> +
>> +    /* Update LSI levels */
>> +    if (state) {
>> +        psi->regs[PSIHB_REG(PSIHB9_IRQ_LEVEL)] |= PPC_BIT(irq);
>> +    } else {
>> +        psi->regs[PSIHB_REG(PSIHB9_IRQ_LEVEL)] &= ~PPC_BIT(irq);
>> +    }
>> +
>> +    qemu_set_irq(psi->qirqs[irq], state);
>> +}
>> +
>> +static void pnv_psi_power9_reset(void *dev)
>> +{
>> +    PnvPsi *psi = PNV9_PSI(dev);
>> +
>> +    pnv_psi_reset(dev);
>> +
>> +    if (memory_region_is_mapped(&psi->source.esb_mmio)) {
>> +        memory_region_del_subregion(get_system_memory(), &psi->source.esb_mmio);
>> +    }
>> +}
>> +
>> +static void pnv_psi_power9_instance_init(Object *obj)
>> +{
>> +    PnvPsi *psi = PNV9_PSI(obj);
>> +
>> +    object_initialize_child(obj, "source", &psi->source, sizeof(psi->source),
>> +                            TYPE_XIVE_SOURCE, &error_abort, NULL);
>> +}
>> +
>> +static void pnv_psi_power9_realize(DeviceState *dev, Error **errp)
>> +{
>> +    PnvPsi *psi = PNV9_PSI(dev);
>> +    XiveSource *xsrc = &psi->source;
>> +    Error *local_err = NULL;
>> +    int i;
>> +
>> +    /* This is the only device with 4k ESB pages */
>> +    object_property_set_int(OBJECT(xsrc), XIVE_ESB_4K, "shift",
>> +                            &error_fatal);
>> +    object_property_set_int(OBJECT(xsrc), PSIHB9_NUM_IRQS, "nr-irqs",
>> +                            &error_fatal);
>> +    object_property_add_const_link(OBJECT(xsrc), "xive", OBJECT(psi),
>> +                                   &error_fatal);
>> +    object_property_set_bool(OBJECT(xsrc), true, "realized", &local_err);
>> +    if (local_err) {
>> +        error_propagate(errp, local_err);
>> +        return;
>> +    }
>> +
>> +    for (i = 0; i < xsrc->nr_irqs; i++) {
>> +        xive_source_irq_set_lsi(xsrc, i);
>> +    }
>> +
>> +    psi->qirqs = qemu_allocate_irqs(xive_source_set_irq, xsrc, xsrc->nr_irqs);
>> +
>> +    /* XSCOM region for PSI registers */
>> +    pnv_xscom_region_init(&psi->xscom_regs, OBJECT(dev), &pnv_psi_p9_xscom_ops,
>> +                psi, "xscom-psi", PNV9_XSCOM_PSIHB_SIZE);
>> +
>> +    /* MMIO region for PSI registers */
>> +    memory_region_init_io(&psi->regs_mr, OBJECT(dev), &pnv_psi_p9_mmio_ops, psi,
>> +                          "psihb", PNV9_PSIHB_SIZE);
>> +
>> +    pnv_psi_set_bar(psi, psi->bar | PSIHB_BAR_EN);
>> +
>> +    qemu_register_reset(pnv_psi_power9_reset, dev);
>> +}
>> +
>> +static void pnv_psi_power9_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +    PnvPsiClass *ppc = PNV_PSI_CLASS(klass);
>> +    XiveNotifierClass *xfc = XIVE_NOTIFIER_CLASS(klass);
>> +
>> +    dc->desc    = "PowerNV PSI Controller POWER9";
>> +    dc->realize = pnv_psi_power9_realize;
>> +
>> +    ppc->chip_type  = PNV_CHIP_POWER9;
>> +    ppc->xscom_pcba = PNV9_XSCOM_PSIHB_BASE;
>> +    ppc->xscom_size = PNV9_XSCOM_PSIHB_SIZE;
>> +    ppc->bar_mask   = PSIHB9_BAR_MASK;
>> +    ppc->irq_set    = pnv_psi_power9_irq_set;
>> +
>> +    xfc->notify      = pnv_psi_notify;
>> +}
>> +
>> +static const TypeInfo pnv_psi_power9_info = {
>> +    .name          = TYPE_PNV9_PSI,
>> +    .parent        = TYPE_PNV_PSI,
>> +    .instance_init = pnv_psi_power9_instance_init,
>> +    .class_init    = pnv_psi_power9_class_init,
>> +    .interfaces = (InterfaceInfo[]) {
>> +            { TYPE_XIVE_NOTIFIER },
>> +            { },
>> +    },
>> +};
>> +
>>  static void pnv_psi_class_init(ObjectClass *klass, void *data)
>>  {
>>      DeviceClass *dc = DEVICE_CLASS(klass);
>> @@ -611,6 +921,17 @@ static void pnv_psi_register_types(void)
>>  {
>>      type_register_static(&pnv_psi_info);
>>      type_register_static(&pnv_psi_power8_info);
>> +    type_register_static(&pnv_psi_power9_info);
>>  }
>>  
>>  type_init(pnv_psi_register_types);
>> +
>> +void pnv_psi_pic_print_info(PnvPsi *psi, Monitor *mon)
>> +{
>> +    uint32_t offset =
>> +        (psi->regs[PSIHB_REG(PSIHB9_IVT_OFFSET)] >> PSIHB9_IVT_OFF_SHIFT);
>> +
>> +    monitor_printf(mon, "PSIHB Source %08x .. %08x\n",
>> +                  offset, offset + psi->source.nr_irqs - 1);
>> +    xive_source_pic_print_info(&psi->source, offset, mon);
>> +}
> 

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

* Re: [Qemu-devel] [PATCH 18/27] ppc/pnv: add a LPC Controller model for POWER9
  2019-03-07  4:18   ` David Gibson
@ 2019-03-07  7:07     ` Cédric Le Goater
  2019-03-08  0:19       ` David Gibson
  0 siblings, 1 reply; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-07  7:07 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel

On 3/7/19 5:18 AM, David Gibson wrote:
> On Wed, Mar 06, 2019 at 09:50:23AM +0100, Cédric Le Goater wrote:
>> The LPC Controller on POWER9 is very similar to the one found on
>> POWER8 but accesses are now done via on MMIOs, without the XSCOM and
>> ECCB logic. The device tree is populated differently so we add a
>> specific POWER9 routine for the purpose.
>>
>> SerIRQ routing is yet to be done.
>>
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>> ---
>>  include/hw/ppc/pnv.h     |   4 +
>>  include/hw/ppc/pnv_lpc.h |  10 ++
>>  hw/ppc/pnv.c             |  29 +++++-
>>  hw/ppc/pnv_lpc.c         | 200 +++++++++++++++++++++++++++++++++++++++
>>  4 files changed, 240 insertions(+), 3 deletions(-)
>>
>> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
>> index 57d0337219be..2d68aabc212f 100644
>> --- a/include/hw/ppc/pnv.h
>> +++ b/include/hw/ppc/pnv.h
>> @@ -85,6 +85,7 @@ typedef struct Pnv9Chip {
>>      /*< public >*/
>>      PnvXive      xive;
>>      PnvPsi       psi;
>> +    PnvLpcController lpc;
>>  } Pnv9Chip;
>>  
>>  typedef struct PnvChipClass {
>> @@ -232,6 +233,9 @@ void pnv_bmc_powerdown(IPMIBmc *bmc);
>>  #define PNV9_XIVE_PC_SIZE            0x0000001000000000ull
>>  #define PNV9_XIVE_PC_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006018000000000ull)
>>  
>> +#define PNV9_LPCM_SIZE               0x0000000100000000ull
>> +#define PNV9_LPCM_BASE(chip)         PNV9_CHIP_BASE(chip, 0x0006030000000000ull)
>> +
>>  #define PNV9_PSIHB_SIZE              0x0000000000100000ull
>>  #define PNV9_PSIHB_BASE(chip)        PNV9_CHIP_BASE(chip, 0x0006030203000000ull)
>>  
>> diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h
>> index 242baecdcb93..24fe23f0f63b 100644
>> --- a/include/hw/ppc/pnv_lpc.h
>> +++ b/include/hw/ppc/pnv_lpc.h
>> @@ -28,6 +28,10 @@
>>  #define PNV8_LPC(obj) \
>>      OBJECT_CHECK(PnvLpc, (obj), TYPE_PNV8_LPC)
>>  
>> +#define TYPE_PNV9_LPC TYPE_PNV_LPC "-POWER9"
>> +#define PNV9_LPC(obj) \
>> +    OBJECT_CHECK(PnvLpc, (obj), TYPE_PNV9_LPC)
>> +
>>  typedef struct PnvLpcController {
>>      DeviceState parent;
>>  
>> @@ -86,6 +90,12 @@ typedef struct PnvLpcClass {
>>      DeviceRealize parent_realize;
>>  } PnvLpcClass;
>>  
>> +/*
>> + * Old compilers error on typdef forward declarations. Keep them happy.
>> + */
>> +struct PnvChip;
>> +
>>  ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp);
>> +int pnv_dt_lpc(struct PnvChip *chip, void *fdt, int root_offset);
>>  
>>  #endif /* _PPC_PNV_LPC_H */
>> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
>> index 7176e1b68d0e..895be470af67 100644
>> --- a/hw/ppc/pnv.c
>> +++ b/hw/ppc/pnv.c
>> @@ -306,6 +306,8 @@ static void pnv_chip_power9_dt_populate(PnvChip *chip, void *fdt)
>>      if (chip->ram_size) {
>>          pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
>>      }
>> +
>> +    pnv_dt_lpc(chip, fdt, 0);
>>  }
>>  
>>  static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
>> @@ -422,8 +424,14 @@ static int pnv_chip_isa_offset(PnvChip *chip, void *fdt)
>>      char *name;
>>      int offset;
>>  
>> -    name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
>> -                           (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE);
>> +    if (pnv_chip_is_power9(chip)) {
> 
> Again explicit chip type checks aren't very pretty.  Better to
> redirect through a method.  Or, better, call into the common ISA DT
> code from chip specific code passing the offset, rather than calling
> out again to get it.

I will an ISA DT nodename under PnvChip. The name can be computed 
at realize time.
 
> 
>> +        name = g_strdup_printf("/lpcm-opb@%" PRIx64 "/lpc@0",
>> +                               (uint64_t) PNV9_LPCM_BASE(chip));
>> +    } else {
>> +        name = g_strdup_printf("/xscom@%" PRIx64 "/isa@%x",
>> +                               (uint64_t) PNV_XSCOM_BASE(chip),
>> +                               PNV_XSCOM_LPC_BASE);
>> +    }
>>      offset = fdt_path_offset(fdt, name);
>>      g_free(name);
>>      return offset;
>> @@ -559,7 +567,8 @@ static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp)
>>  
>>  static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp)
>>  {
>> -    return NULL;
>> +    Pnv9Chip *chip9 = PNV9_CHIP(chip);
>> +    return pnv_lpc_isa_create(&chip9->lpc, false, errp);
>>  }
>>  
>>  static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
>> @@ -954,6 +963,11 @@ static void pnv_chip_power9_instance_init(Object *obj)
>>                              TYPE_PNV9_PSI, &error_abort, NULL);
>>      object_property_add_const_link(OBJECT(&chip9->psi), "chip", obj,
>>                                     &error_abort);
>> +
>> +    object_initialize_child(obj, "lpc",  &chip9->lpc, sizeof(chip9->lpc),
>> +                            TYPE_PNV9_LPC, &error_abort, NULL);
>> +    object_property_add_const_link(OBJECT(&chip9->lpc), "psi",
>> +                                   OBJECT(&chip9->psi), &error_abort);
>>  }
>>  
>>  static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
>> @@ -997,6 +1011,15 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
>>      }
>>      pnv_xscom_add_subregion(chip, PNV9_XSCOM_PSIHB_BASE,
>>                              &chip9->psi.xscom_regs);
>> +
>> +    /* LPC */
>> +    object_property_set_bool(OBJECT(&chip9->lpc), true, "realized", &local_err);
>> +    if (local_err) {
>> +        error_propagate(errp, local_err);
>> +        return;
>> +    }
>> +    memory_region_add_subregion(get_system_memory(), PNV9_LPCM_BASE(chip),
>> +                                &chip9->lpc.xscom_regs);
>>  }
>>  
>>  static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
>> diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c
>> index 3c509a30a0af..6df694e0abc1 100644
>> --- a/hw/ppc/pnv_lpc.c
>> +++ b/hw/ppc/pnv_lpc.c
>> @@ -118,6 +118,100 @@ static int pnv_lpc_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
>>      return 0;
>>  }
>>  
>> +/* POWER9 only */
>> +int pnv_dt_lpc(PnvChip *chip, void *fdt, int root_offset)
>> +{
>> +    const char compat[] = "ibm,power9-lpcm-opb\0simple-bus";
>> +    const char lpc_compat[] = "ibm,power9-lpc\0ibm,lpc";
>> +    char *name;
>> +    int offset, lpcm_offset;
>> +    uint64_t lpcm_addr = PNV9_LPCM_BASE(chip);
>> +    uint32_t opb_ranges[8] = { 0,
>> +                               cpu_to_be32(lpcm_addr >> 32),
>> +                               cpu_to_be32((uint32_t)lpcm_addr),
>> +                               cpu_to_be32(PNV9_LPCM_SIZE / 2),
>> +                               cpu_to_be32(PNV9_LPCM_SIZE / 2),
>> +                               cpu_to_be32(lpcm_addr >> 32),
>> +                               cpu_to_be32(PNV9_LPCM_SIZE / 2),
>> +                               cpu_to_be32(PNV9_LPCM_SIZE / 2),
>> +    };
>> +    uint32_t opb_reg[4] = { cpu_to_be32(lpcm_addr >> 32),
>> +                            cpu_to_be32((uint32_t)lpcm_addr),
>> +                            cpu_to_be32(PNV9_LPCM_SIZE >> 32),
>> +                            cpu_to_be32((uint32_t)PNV9_LPCM_SIZE),
>> +    };
>> +    uint32_t reg[2];
>> +
>> +    /*
>> +     * OPB bus
>> +     */
>> +    name = g_strdup_printf("lpcm-opb@%"PRIx64, lpcm_addr);
>> +    lpcm_offset = fdt_add_subnode(fdt, root_offset, name);
>> +    _FDT(lpcm_offset);
>> +    g_free(name);
>> +
>> +    _FDT((fdt_setprop(fdt, lpcm_offset, "reg", opb_reg, sizeof(opb_reg))));
>> +    _FDT((fdt_setprop_cell(fdt, lpcm_offset, "#address-cells", 1)));
>> +    _FDT((fdt_setprop_cell(fdt, lpcm_offset, "#size-cells", 1)));
>> +    _FDT((fdt_setprop(fdt, lpcm_offset, "compatible", compat, sizeof(compat))));
>> +    _FDT((fdt_setprop_cell(fdt, lpcm_offset, "ibm,chip-id", chip->chip_id)));
>> +    _FDT((fdt_setprop(fdt, lpcm_offset, "ranges", opb_ranges,
>> +                      sizeof(opb_ranges))));
>> +
>> +    /*
>> +     * OPB Master registers
>> +     */
>> +    name = g_strdup_printf("opb-master@%x", LPC_OPB_REGS_OPB_ADDR);
>> +    offset = fdt_add_subnode(fdt, lpcm_offset, name);
>> +    _FDT(offset);
>> +    g_free(name);
>> +
>> +    reg[0] = cpu_to_be32(LPC_OPB_REGS_OPB_ADDR);
>> +    reg[1] = cpu_to_be32(LPC_OPB_REGS_OPB_SIZE);
>> +    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
>> +    _FDT((fdt_setprop_string(fdt, offset, "compatible",
>> +                             "ibm,power9-lpcm-opb-master")));
>> +
>> +    /*
>> +     * OPB arbitrer registers
>> +     */
>> +    name = g_strdup_printf("opb-arbitrer@%x", LPC_OPB_REGS_OPBA_ADDR);
>> +    offset = fdt_add_subnode(fdt, lpcm_offset, name);
>> +    _FDT(offset);
>> +    g_free(name);
>> +
>> +    reg[0] = cpu_to_be32(LPC_OPB_REGS_OPBA_ADDR);
>> +    reg[1] = cpu_to_be32(LPC_OPB_REGS_OPBA_SIZE);
>> +    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
>> +    _FDT((fdt_setprop_string(fdt, offset, "compatible",
>> +                             "ibm,power9-lpcm-opb-arbiter")));
>> +
>> +    /*
>> +     * LPC Host Controller registers
>> +     */
>> +    name = g_strdup_printf("lpc-controller@%x", LPC_HC_REGS_OPB_ADDR);
>> +    offset = fdt_add_subnode(fdt, lpcm_offset, name);
>> +    _FDT(offset);
>> +    g_free(name);
>> +
>> +    reg[0] = cpu_to_be32(LPC_HC_REGS_OPB_ADDR);
>> +    reg[1] = cpu_to_be32(LPC_HC_REGS_OPB_SIZE);
>> +    _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
>> +    _FDT((fdt_setprop_string(fdt, offset, "compatible",
>> +                             "ibm,power9-lpc-controller")));
>> +
>> +    name = g_strdup_printf("lpc@0");
>> +    offset = fdt_add_subnode(fdt, lpcm_offset, name);
>> +    _FDT(offset);
>> +    g_free(name);
>> +    _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 2)));
>> +    _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 1)));
>> +    _FDT((fdt_setprop(fdt, offset, "compatible", lpc_compat,
>> +                      sizeof(lpc_compat))));
>> +
>> +    return 0;
>> +}
>> +
>>  /*
>>   * These read/write handlers of the OPB address space should be common
>>   * with the P9 LPC Controller which uses direct MMIOs.
>> @@ -242,6 +336,74 @@ static const MemoryRegionOps pnv_lpc_xscom_ops = {
>>      .endianness = DEVICE_BIG_ENDIAN,
>>  };
>>  
>> +static uint64_t pnv_lpc_mmio_read(void *opaque, hwaddr addr, unsigned size)
>> +{
>> +    PnvLpcController *lpc = PNV_LPC(opaque);
>> +    uint64_t val = 0;
>> +    uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK;
>> +    MemTxResult result;
>> +
>> +    switch (size) {
>> +    case 4:
>> +        val = address_space_ldl(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED,
>> +                                &result);
>> +        break;
>> +    case 1:
>> +        val = address_space_ldub(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED,
>> +                                 &result);
>> +        break;
>> +    default:
>> +        qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%"
>> +                      HWADDR_PRIx " invalid size %d\n", addr, size);
>> +        return 0;
>> +    }
>> +
>> +    if (result != MEMTX_OK) {
>> +        qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%"
>> +                      HWADDR_PRIx "\n", addr);
>> +    }
>> +
>> +    return val;
> 
> Couldn't you just map the relevant portion of the OPB AS into the MMIO
> AS, rather than having to forward the IOs with explicit read/write
> functions?

The underlying memory regions (ISA space, LPC HC, OPB regs) are the
same on POWER8. So this is one way to share the overall initialization. 

What I would have liked to do is to simplified the ECCB interface 
(see pnv_lpc_do_eccb()).

Thanks,

C. 


>> +}
>> +
>> +static void pnv_lpc_mmio_write(void *opaque, hwaddr addr,
>> +                                uint64_t val, unsigned size)
>> +{
>> +    PnvLpcController *lpc = PNV_LPC(opaque);
>> +    uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK;
>> +    MemTxResult result;
>> +
>> +    switch (size) {
>> +    case 4:
>> +        address_space_stl(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED,
>> +                          &result);
>> +         break;
>> +    case 1:
>> +        address_space_stb(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED,
>> +                          &result);
>> +        break;
>> +    default:
>> +        qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%"
>> +                      HWADDR_PRIx " invalid size %d\n", addr, size);
>> +        return;
>> +    }
>> +
>> +    if (result != MEMTX_OK) {
>> +        qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%"
>> +                      HWADDR_PRIx "\n", addr);
>> +    }
>> +}
>> +
>> +static const MemoryRegionOps pnv_lpc_mmio_ops = {
>> +    .read = pnv_lpc_mmio_read,
>> +    .write = pnv_lpc_mmio_write,
>> +    .impl = {
>> +        .min_access_size = 1,
>> +        .max_access_size = 4,
>> +    },
>> +    .endianness = DEVICE_BIG_ENDIAN,
>> +};
>> +
>>  static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
>>  {
>>      bool lpc_to_opb_irq = false;
>> @@ -465,6 +627,43 @@ static const TypeInfo pnv_lpc_power8_info = {
>>      }
>>  };
>>  
>> +static void pnv_lpc_power9_realize(DeviceState *dev, Error **errp)
>> +{
>> +    PnvLpcController *lpc = PNV_LPC(dev);
>> +    PnvLpcClass *plc = PNV_LPC_GET_CLASS(dev);
>> +    Error *local_err = NULL;
>> +
>> +    plc->parent_realize(dev, &local_err);
>> +    if (local_err) {
>> +        error_propagate(errp, local_err);
>> +        return;
>> +    }
>> +
>> +    /* P9 uses a MMIO region */
>> +    memory_region_init_io(&lpc->xscom_regs, OBJECT(lpc), &pnv_lpc_mmio_ops,
>> +                          lpc, "lpcm", PNV9_LPCM_SIZE);
>> +}
>> +
>> +static void pnv_lpc_power9_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +    PnvLpcClass *plc = PNV_LPC_CLASS(klass);
>> +
>> +    dc->desc = "PowerNV LPC Controller POWER9";
>> +
>> +    plc->psi_irq = PSIHB9_IRQ_LPCHC;
>> +
>> +    device_class_set_parent_realize(dc, pnv_lpc_power9_realize,
>> +                                    &plc->parent_realize);
>> +}
>> +
>> +static const TypeInfo pnv_lpc_power9_info = {
>> +    .name          = TYPE_PNV9_LPC,
>> +    .parent        = TYPE_PNV_LPC,
>> +    .instance_size = sizeof(PnvLpcController),
>> +    .class_init    = pnv_lpc_power9_class_init,
>> +};
>> +
>>  static void pnv_lpc_realize(DeviceState *dev, Error **errp)
>>  {
>>      PnvLpcController *lpc = PNV_LPC(dev);
>> @@ -540,6 +739,7 @@ static void pnv_lpc_register_types(void)
>>  {
>>      type_register_static(&pnv_lpc_info);
>>      type_register_static(&pnv_lpc_power8_info);
>> +    type_register_static(&pnv_lpc_power9_info);
>>  }
>>  
>>  type_init(pnv_lpc_register_types)
> 

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

* Re: [Qemu-devel] [PATCH 21/27] ppc/pnv: add a OCC model for POWER9
  2019-03-07  4:27   ` David Gibson
@ 2019-03-07  7:47     ` Cédric Le Goater
  0 siblings, 0 replies; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-07  7:47 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel

On 3/7/19 5:27 AM, David Gibson wrote:
> On Wed, Mar 06, 2019 at 09:50:26AM +0100, Cédric Le Goater wrote:
>> The OCC on POWER9 is very similar to the one found on POWER8. Provide
>> the same routines with P9 values for the registers and IRQ number.
>>
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>> ---
>>  include/hw/ppc/pnv.h       |  1 +
>>  include/hw/ppc/pnv_occ.h   |  4 ++++
>>  include/hw/ppc/pnv_xscom.h |  3 +++
>>  hw/ppc/pnv.c               | 13 +++++++++++++
>>  hw/ppc/pnv_occ.c           | 40 ++++++++++++++++++++++++++++++++++++++
>>  5 files changed, 61 insertions(+)
>>
>> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
>> index 2d68aabc212f..ad3bf0690ecf 100644
>> --- a/include/hw/ppc/pnv.h
>> +++ b/include/hw/ppc/pnv.h
>> @@ -86,6 +86,7 @@ typedef struct Pnv9Chip {
>>      PnvXive      xive;
>>      PnvPsi       psi;
>>      PnvLpcController lpc;
>> +    PnvOCC       occ;
>>  } Pnv9Chip;
>>  
>>  typedef struct PnvChipClass {
>> diff --git a/include/hw/ppc/pnv_occ.h b/include/hw/ppc/pnv_occ.h
>> index ce2631e21f5e..8951eb7ea316 100644
>> --- a/include/hw/ppc/pnv_occ.h
>> +++ b/include/hw/ppc/pnv_occ.h
>> @@ -27,6 +27,10 @@
>>  #define PNV8_OCC(obj) \
>>      OBJECT_CHECK(PnvOCC, (obj), TYPE_PNV8_OCC)
>>  
>> +#define TYPE_PNV9_OCC TYPE_PNV_OCC "-POWER9"
>> +#define PNV9_OCC(obj) \
>> +    OBJECT_CHECK(PnvOCC, (obj), TYPE_PNV9_OCC)
>> +
>>  typedef struct PnvOCC {
>>      DeviceState xd;
>>  
>> diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
>> index 403a365ed274..3292459fbb78 100644
>> --- a/include/hw/ppc/pnv_xscom.h
>> +++ b/include/hw/ppc/pnv_xscom.h
>> @@ -73,6 +73,9 @@ typedef struct PnvXScomInterfaceClass {
>>  #define PNV_XSCOM_OCC_BASE        0x0066000
>>  #define PNV_XSCOM_OCC_SIZE        0x6000
>>  
>> +#define PNV9_XSCOM_OCC_BASE       PNV_XSCOM_OCC_BASE
>> +#define PNV9_XSCOM_OCC_SIZE       0x8000
>> +
>>  #define PNV9_XSCOM_PSIHB_BASE     0x5012900
>>  #define PNV9_XSCOM_PSIHB_SIZE     0x100
>>  
>> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
>> index 81ab53899dbc..a056064c8c11 100644
>> --- a/hw/ppc/pnv.c
>> +++ b/hw/ppc/pnv.c
>> @@ -968,6 +968,11 @@ static void pnv_chip_power9_instance_init(Object *obj)
>>                              TYPE_PNV9_LPC, &error_abort, NULL);
>>      object_property_add_const_link(OBJECT(&chip9->lpc), "psi",
>>                                     OBJECT(&chip9->psi), &error_abort);
>> +
>> +    object_initialize_child(obj, "occ",  &chip9->occ, sizeof(chip9->occ),
>> +                            TYPE_PNV9_OCC, &error_abort, NULL);
>> +    object_property_add_const_link(OBJECT(&chip9->occ), "psi",
>> +                                   OBJECT(&chip9->psi), &error_abort);
>>  }
>>  
>>  static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
>> @@ -1020,6 +1025,14 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
>>      }
>>      memory_region_add_subregion(get_system_memory(), PNV9_LPCM_BASE(chip),
>>                                  &chip9->lpc.xscom_regs);
>> +
>> +    /* Create the simplified OCC model */
>> +    object_property_set_bool(OBJECT(&chip9->occ), true, "realized", &local_err);
>> +    if (local_err) {
>> +        error_propagate(errp, local_err);
>> +        return;
>> +    }
>> +    pnv_xscom_add_subregion(chip, PNV9_XSCOM_OCC_BASE, &chip9->occ.xscom_regs);
>>  }
>>  
>>  static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
>> diff --git a/hw/ppc/pnv_occ.c b/hw/ppc/pnv_occ.c
>> index a210f44926aa..59b0702bc716 100644
>> --- a/hw/ppc/pnv_occ.c
>> +++ b/hw/ppc/pnv_occ.c
>> @@ -31,6 +31,10 @@
>>  #define OCB_OCI_OCCMISC_AND     0x4021
>>  #define OCB_OCI_OCCMISC_OR      0x4022
>>  
>> +#define P9_OCB_OCI_OCCMISC              0x6080
>> +#define P9_OCB_OCI_OCCMISC_CLEAR        0x6081
>> +#define P9_OCB_OCI_OCCMISC_OR           0x6082
>> +
>>  static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val)
>>  {
>>      bool irq_state;
>> @@ -42,6 +46,17 @@ static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val)
>>      pnv_psi_irq_set(occ->psi, PSIHB_IRQ_OCC, irq_state);
>>  }
>>  
>> +static void pnv_occ_p9_set_misc(PnvOCC *occ, uint64_t val)
>> +{
>> +    bool irq_state;
>> +
>> +    val &= 0xffff000000000000ull;
>> +
>> +    occ->occmisc = val;
>> +    irq_state = !!(val >> 63);
>> +    pnv_psi_irq_set(occ->psi, PSIHB9_IRQ_OCC, irq_state);
>> +}
>> +
>>  static uint64_t pnv_occ_xscom_read(void *opaque, hwaddr addr, unsigned size)
>>  {
>>      PnvOCC *occ = PNV_OCC(opaque);
>> @@ -50,6 +65,7 @@ static uint64_t pnv_occ_xscom_read(void *opaque, hwaddr addr, unsigned size)
>>  
>>      switch (offset) {
>>      case OCB_OCI_OCCMISC:
>> +    case P9_OCB_OCI_OCCMISC:
>>          val = occ->occmisc;
>>          break;
>>      default:
>> @@ -75,6 +91,15 @@ static void pnv_occ_xscom_write(void *opaque, hwaddr addr,
>>      case OCB_OCI_OCCMISC:
>>          pnv_occ_set_misc(occ, val);
>>          break;
>> +    case P9_OCB_OCI_OCCMISC_CLEAR:
>> +        pnv_occ_p9_set_misc(occ, 0);
>> +        break;
>> +    case P9_OCB_OCI_OCCMISC_OR:
>> +        pnv_occ_p9_set_misc(occ, occ->occmisc | val);
>> +        break;
>> +    case P9_OCB_OCI_OCCMISC:
>> +        pnv_occ_p9_set_misc(occ, val);
>> +       break;
> 
> Are the P9 OCC registers a strict superset of the P8 registers?

I haven't checked all OCC registers but from what skiboot uses, the answer 
is yes. But we can introduce a new ops for POWER9, it would be cleaner. 

Thanks,

C. 

> 
>>      default:
>>          qemu_log_mask(LOG_UNIMP, "OCC Unimplemented register: Ox%"
>>                        HWADDR_PRIx "\n", addr >> 3);
>> @@ -115,6 +140,20 @@ static void pnv_occ_realize(DeviceState *dev, Error **errp)
>>                    occ, "xscom-occ", poc->xscom_size);
>>  }
>>  
>> +static void pnv_occ_power9_class_init(ObjectClass *klass, void *data)
>> +{
>> +    PnvOCCClass *poc = PNV_OCC_CLASS(klass);
>> +
>> +    poc->xscom_size = PNV9_XSCOM_OCC_SIZE;
>> +}
>> +
>> +static const TypeInfo pnv_occ_power9_type_info = {
>> +    .name          = TYPE_PNV9_OCC,
>> +    .parent        = TYPE_PNV_OCC,
>> +    .instance_size = sizeof(PnvOCC),
>> +    .class_init    = pnv_occ_power9_class_init,
>> +};
>> +
>>  static void pnv_occ_power8_class_init(ObjectClass *klass, void *data)
>>  {
>>      PnvOCCClass *poc = PNV_OCC_CLASS(klass);
>> @@ -148,6 +187,7 @@ static void pnv_occ_register_types(void)
>>  {
>>      type_register_static(&pnv_occ_type_info);
>>      type_register_static(&pnv_occ_power8_type_info);
>> +    type_register_static(&pnv_occ_power9_type_info);
>>  }
>>  
>>  type_init(pnv_occ_register_types)
> 

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

* Re: [Qemu-devel] [PATCH 15/27] ppc/pnv: add a PSI bridge model for POWER9
  2019-03-07  6:37     ` Cédric Le Goater
@ 2019-03-07 22:33       ` Cédric Le Goater
  2019-03-08  0:17       ` David Gibson
  1 sibling, 0 replies; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-07 22:33 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel

On 3/7/19 7:37 AM, Cédric Le Goater wrote:
> On 3/7/19 5:10 AM, David Gibson wrote:
>> On Wed, Mar 06, 2019 at 09:50:20AM +0100, Cédric Le Goater wrote:
>>> The PSI bridge on POWER9 is very similar to POWER8. The BAR is still
>>> set through XSCOM but the controls are now entirely done with MMIOs.
>>> More interrupts are defined and the interrupt controller interface has
>>> changed to XIVE. The POWER9 model is a first example of the usage of
>>> the notify() handler of the XiveNotifier interface, linking the PSI
>>> XiveSource to its owning device model.
>>>
>>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>>> ---
>>>  include/hw/ppc/pnv.h       |   6 +
>>>  include/hw/ppc/pnv_psi.h   |  24 +++
>>>  include/hw/ppc/pnv_xscom.h |   3 +
>>>  hw/ppc/pnv.c               |  17 ++
>>>  hw/ppc/pnv_psi.c           | 325 ++++++++++++++++++++++++++++++++++++-
>>>  5 files changed, 373 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
>>> index eb4bba25b3e9..57d0337219be 100644
>>> --- a/include/hw/ppc/pnv.h
>>> +++ b/include/hw/ppc/pnv.h
>>> @@ -84,6 +84,7 @@ typedef struct Pnv9Chip {
>>>  
>>>      /*< public >*/
>>>      PnvXive      xive;
>>> +    PnvPsi       psi;
>>>  } Pnv9Chip;
>>>  
>>>  typedef struct PnvChipClass {
>>> @@ -231,11 +232,16 @@ void pnv_bmc_powerdown(IPMIBmc *bmc);
>>>  #define PNV9_XIVE_PC_SIZE            0x0000001000000000ull
>>>  #define PNV9_XIVE_PC_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006018000000000ull)
>>>  
>>> +#define PNV9_PSIHB_SIZE              0x0000000000100000ull
>>> +#define PNV9_PSIHB_BASE(chip)        PNV9_CHIP_BASE(chip, 0x0006030203000000ull)
>>> +
>>>  #define PNV9_XIVE_IC_SIZE            0x0000000000080000ull
>>>  #define PNV9_XIVE_IC_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006030203100000ull)
>>>  
>>>  #define PNV9_XIVE_TM_SIZE            0x0000000000040000ull
>>>  #define PNV9_XIVE_TM_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006030203180000ull)
>>>  
>>> +#define PNV9_PSIHB_ESB_SIZE          0x0000000000010000ull
>>> +#define PNV9_PSIHB_ESB_BASE(chip)    PNV9_CHIP_BASE(chip, 0x00060302031c0000ull)
>>>  
>>>  #endif /* _PPC_PNV_H */
>>> diff --git a/include/hw/ppc/pnv_psi.h b/include/hw/ppc/pnv_psi.h
>>> index 585a41cd19b6..d7e1ab282cf8 100644
>>> --- a/include/hw/ppc/pnv_psi.h
>>> +++ b/include/hw/ppc/pnv_psi.h
>>> @@ -21,6 +21,7 @@
>>>  
>>>  #include "hw/sysbus.h"
>>>  #include "hw/ppc/xics.h"
>>> +#include "hw/ppc/xive.h"
>>>  
>>>  #define TYPE_PNV_PSI "pnv-psi"
>>>  #define PNV_PSI(obj) \
>>> @@ -28,6 +29,9 @@
>>>  #define TYPE_PNV8_PSI TYPE_PNV_PSI "-POWER8"
>>>  #define PNV8_PSI(obj) \
>>>      OBJECT_CHECK(PnvPsi, (obj), TYPE_PNV8_PSI)
>>> +#define TYPE_PNV9_PSI TYPE_PNV_PSI "-POWER9"
>>> +#define PNV9_PSI(obj) \
>>> +    OBJECT_CHECK(PnvPsi, (obj), TYPE_PNV9_PSI)
>>>  
>>>  #define PSIHB_XSCOM_MAX         0x20
>>>  
>>> @@ -43,6 +47,7 @@ typedef struct PnvPsi {
>>>  
>>>      /* Interrupt generation */
>>>      ICSState ics;
>>> +    XiveSource source;
>>
>> Uh... surely these should move to the subtype structures, so you don't
>> have both of them.
> 
> I did not introduce a subtype, only a subclass. But we could 
> possibly. It seemed overkill for one attribute.

But it is not that complex either to add a Pnv8Psi and a Pnv9Psi
with the correct attributes. 

I will send a v2 with these changes. Hopefully these are good
enough for 4.0. 

Thanks,

C. 

> 
>>
>>>      qemu_irq *qirqs;
>>>  
>>>      /* Registers */
>>> @@ -82,4 +87,23 @@ typedef enum PnvPsiIrq {
>>>  
>>>  void pnv_psi_irq_set(PnvPsi *psi, int irq, bool state);
>>>  
>>> +/* P9 PSI Interrupts */
>>> +#define PSIHB9_IRQ_PSI          0
>>> +#define PSIHB9_IRQ_OCC          1
>>> +#define PSIHB9_IRQ_FSI          2
>>> +#define PSIHB9_IRQ_LPCHC        3
>>> +#define PSIHB9_IRQ_LOCAL_ERR    4
>>> +#define PSIHB9_IRQ_GLOBAL_ERR   5
>>> +#define PSIHB9_IRQ_TPM          6
>>> +#define PSIHB9_IRQ_LPC_SIRQ0    7
>>> +#define PSIHB9_IRQ_LPC_SIRQ1    8
>>> +#define PSIHB9_IRQ_LPC_SIRQ2    9
>>> +#define PSIHB9_IRQ_LPC_SIRQ3    10
>>> +#define PSIHB9_IRQ_SBE_I2C      11
>>> +#define PSIHB9_IRQ_DIO          12
>>> +#define PSIHB9_IRQ_PSU          13
>>> +#define PSIHB9_NUM_IRQS         14
>>> +
>>> +void pnv_psi_pic_print_info(PnvPsi *psi, Monitor *mon);
>>> +
>>>  #endif /* _PPC_PNV_PSI_H */
>>> diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
>>> index 6623ec54a7a8..403a365ed274 100644
>>> --- a/include/hw/ppc/pnv_xscom.h
>>> +++ b/include/hw/ppc/pnv_xscom.h
>>> @@ -73,6 +73,9 @@ typedef struct PnvXScomInterfaceClass {
>>>  #define PNV_XSCOM_OCC_BASE        0x0066000
>>>  #define PNV_XSCOM_OCC_SIZE        0x6000
>>>  
>>> +#define PNV9_XSCOM_PSIHB_BASE     0x5012900
>>> +#define PNV9_XSCOM_PSIHB_SIZE     0x100
>>> +
>>>  #define PNV9_XSCOM_XIVE_BASE      0x5013000
>>>  #define PNV9_XSCOM_XIVE_SIZE      0x300
>>>  
>>> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
>>> index 67d40dc3eebc..4375f97c7135 100644
>>> --- a/hw/ppc/pnv.c
>>> +++ b/hw/ppc/pnv.c
>>> @@ -579,6 +579,7 @@ static void pnv_chip_power9_pic_print_info(PnvChip *chip, Monitor *mon)
>>>      Pnv9Chip *chip9 = PNV9_CHIP(chip);
>>>  
>>>      pnv_xive_pic_print_info(&chip9->xive, mon);
>>> +    pnv_psi_pic_print_info(&chip9->psi, mon);
>>>  }
>>>  
>>>  static void pnv_init(MachineState *machine)
>>> @@ -948,6 +949,11 @@ static void pnv_chip_power9_instance_init(Object *obj)
>>>                              TYPE_PNV_XIVE, &error_abort, NULL);
>>>      object_property_add_const_link(OBJECT(&chip9->xive), "chip", obj,
>>>                                     &error_abort);
>>> +
>>> +    object_initialize_child(obj, "psi",  &chip9->psi, sizeof(chip9->psi),
>>> +                            TYPE_PNV9_PSI, &error_abort, NULL);
>>> +    object_property_add_const_link(OBJECT(&chip9->psi), "chip", obj,
>>> +                                   &error_abort);
>>>  }
>>>  
>>>  static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
>>> @@ -980,6 +986,17 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
>>>      }
>>>      pnv_xscom_add_subregion(chip, PNV9_XSCOM_XIVE_BASE,
>>>                              &chip9->xive.xscom_regs);
>>> +
>>> +    /* Processor Service Interface (PSI) Host Bridge */
>>> +    object_property_set_int(OBJECT(&chip9->psi), PNV9_PSIHB_BASE(chip),
>>> +                            "bar", &error_fatal);
>>> +    object_property_set_bool(OBJECT(&chip9->psi), true, "realized", &local_err);
>>> +    if (local_err) {
>>> +        error_propagate(errp, local_err);
>>> +        return;
>>> +    }
>>> +    pnv_xscom_add_subregion(chip, PNV9_XSCOM_PSIHB_BASE,
>>> +                            &chip9->psi.xscom_regs);
>>>  }
>>>  
>>>  static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
>>> diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
>>> index e56b455a61b1..3f995a0e0d7f 100644
>>> --- a/hw/ppc/pnv_psi.c
>>> +++ b/hw/ppc/pnv_psi.c
>>> @@ -22,6 +22,7 @@
>>>  #include "target/ppc/cpu.h"
>>>  #include "qemu/log.h"
>>>  #include "qapi/error.h"
>>> +#include "monitor/monitor.h"
>>>  
>>>  #include "exec/address-spaces.h"
>>>  
>>> @@ -114,6 +115,9 @@
>>>  #define PSIHB_BAR_MASK                  0x0003fffffff00000ull
>>>  #define PSIHB_FSPBAR_MASK               0x0003ffff00000000ull
>>>  
>>> +#define PSIHB9_BAR_MASK                 0x00fffffffff00000ull
>>> +#define PSIHB9_FSPBAR_MASK              0x00ffffff00000000ull
>>> +
>>>  #define PSIHB_REG(addr) (((addr) >> 3) + PSIHB_XSCOM_BAR)
>>>  
>>>  static void pnv_psi_set_bar(PnvPsi *psi, uint64_t bar)
>>> @@ -531,6 +535,7 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp)
>>>  }
>>>  
>>>  static const char compat_p8[] = "ibm,power8-psihb-x\0ibm,psihb-x";
>>> +static const char compat_p9[] = "ibm,power9-psihb-x\0ibm,psihb-x";
>>>  
>>>  static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
>>>  {
>>> @@ -550,8 +555,13 @@ static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
>>>      _FDT(fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)));
>>>      _FDT(fdt_setprop_cell(fdt, offset, "#address-cells", 2));
>>>      _FDT(fdt_setprop_cell(fdt, offset, "#size-cells", 1));
>>> -    _FDT(fdt_setprop(fdt, offset, "compatible", compat_p8,
>>> -                     sizeof(compat_p8)));
>>> +    if (ppc->chip_type == PNV_CHIP_POWER9) {
>>
>> Ew.  You already have subclasses - put the compatible in there, rather
>> than more explicit tests against chip type.
> 
> I would also prefer to move the compat string to PnvPsiClass instead 
> of using a chip_type field but I didn't find a clean way for it. We 
> use sizeof() on the compat string below and it does not work on a 
> char *.
> 
> I had the same issue in pnv_dt_xscom()
> 
>>
>>> +        _FDT(fdt_setprop(fdt, offset, "compatible", compat_p9,
>>> +                         sizeof(compat_p9)));
>>> +    } else {
>>> +        _FDT(fdt_setprop(fdt, offset, "compatible", compat_p8,
>>> +                         sizeof(compat_p8)));
>>> +    }
>>>      return 0;
>>>  }
>>>  
>>> @@ -583,6 +593,306 @@ static const TypeInfo pnv_psi_power8_info = {
>>>      .class_init    = pnv_psi_power8_class_init,
>>>  };
>>>  
>>> +
>>> +/* Common registers */
>>> +
>>> +#define PSIHB9_CR                       0x20
>>> +#define PSIHB9_SEMR                     0x28
>>> +
>>> +/* P9 registers */
>>> +
>>> +#define PSIHB9_INTERRUPT_CONTROL        0x58
>>> +#define   PSIHB9_IRQ_METHOD             PPC_BIT(0)
>>> +#define   PSIHB9_IRQ_RESET              PPC_BIT(1)
>>> +#define PSIHB9_ESB_CI_BASE              0x60
>>> +#define   PSIHB9_ESB_CI_VALID           1
>>> +#define PSIHB9_ESB_NOTIF_ADDR           0x68
>>> +#define   PSIHB9_ESB_NOTIF_VALID        1
>>> +#define PSIHB9_IVT_OFFSET               0x70
>>> +#define   PSIHB9_IVT_OFF_SHIFT          32
>>> +
>>> +#define PSIHB9_IRQ_LEVEL                0x78 /* assertion */
>>> +#define   PSIHB9_IRQ_LEVEL_PSI          PPC_BIT(0)
>>> +#define   PSIHB9_IRQ_LEVEL_OCC          PPC_BIT(1)
>>> +#define   PSIHB9_IRQ_LEVEL_FSI          PPC_BIT(2)
>>> +#define   PSIHB9_IRQ_LEVEL_LPCHC        PPC_BIT(3)
>>> +#define   PSIHB9_IRQ_LEVEL_LOCAL_ERR    PPC_BIT(4)
>>> +#define   PSIHB9_IRQ_LEVEL_GLOBAL_ERR   PPC_BIT(5)
>>> +#define   PSIHB9_IRQ_LEVEL_TPM          PPC_BIT(6)
>>> +#define   PSIHB9_IRQ_LEVEL_LPC_SIRQ1    PPC_BIT(7)
>>> +#define   PSIHB9_IRQ_LEVEL_LPC_SIRQ2    PPC_BIT(8)
>>> +#define   PSIHB9_IRQ_LEVEL_LPC_SIRQ3    PPC_BIT(9)
>>> +#define   PSIHB9_IRQ_LEVEL_LPC_SIRQ4    PPC_BIT(10)
>>> +#define   PSIHB9_IRQ_LEVEL_SBE_I2C      PPC_BIT(11)
>>> +#define   PSIHB9_IRQ_LEVEL_DIO          PPC_BIT(12)
>>> +#define   PSIHB9_IRQ_LEVEL_PSU          PPC_BIT(13)
>>> +#define   PSIHB9_IRQ_LEVEL_I2C_C        PPC_BIT(14)
>>> +#define   PSIHB9_IRQ_LEVEL_I2C_D        PPC_BIT(15)
>>> +#define   PSIHB9_IRQ_LEVEL_I2C_E        PPC_BIT(16)
>>> +#define   PSIHB9_IRQ_LEVEL_SBE          PPC_BIT(19)
>>> +
>>> +#define PSIHB9_IRQ_STAT                 0x80 /* P bit */
>>> +#define   PSIHB9_IRQ_STAT_PSI           PPC_BIT(0)
>>> +#define   PSIHB9_IRQ_STAT_OCC           PPC_BIT(1)
>>> +#define   PSIHB9_IRQ_STAT_FSI           PPC_BIT(2)
>>> +#define   PSIHB9_IRQ_STAT_LPCHC         PPC_BIT(3)
>>> +#define   PSIHB9_IRQ_STAT_LOCAL_ERR     PPC_BIT(4)
>>> +#define   PSIHB9_IRQ_STAT_GLOBAL_ERR    PPC_BIT(5)
>>> +#define   PSIHB9_IRQ_STAT_TPM           PPC_BIT(6)
>>> +#define   PSIHB9_IRQ_STAT_LPC_SIRQ1     PPC_BIT(7)
>>> +#define   PSIHB9_IRQ_STAT_LPC_SIRQ2     PPC_BIT(8)
>>> +#define   PSIHB9_IRQ_STAT_LPC_SIRQ3     PPC_BIT(9)
>>> +#define   PSIHB9_IRQ_STAT_LPC_SIRQ4     PPC_BIT(10)
>>> +#define   PSIHB9_IRQ_STAT_SBE_I2C       PPC_BIT(11)
>>> +#define   PSIHB9_IRQ_STAT_DIO           PPC_BIT(12)
>>> +#define   PSIHB9_IRQ_STAT_PSU           PPC_BIT(13)
>>> +
>>> +static void pnv_psi_notify(XiveNotifier *xf, uint32_t srcno)
>>> +{
>>> +    PnvPsi *psi = PNV9_PSI(xf);
>>> +    uint64_t notif_port = psi->regs[PSIHB_REG(PSIHB9_ESB_NOTIF_ADDR)];
>>> +    bool valid = notif_port & PSIHB9_ESB_NOTIF_VALID;
>>> +    uint64_t notify_addr = notif_port & ~PSIHB9_ESB_NOTIF_VALID;
>>> +
>>> +    uint32_t offset =
>>> +        (psi->regs[PSIHB_REG(PSIHB9_IVT_OFFSET)] >> PSIHB9_IVT_OFF_SHIFT);
>>> +    uint64_t lisn = cpu_to_be64(offset + srcno);
>>> +
>>> +    if (valid) {
>>> +        cpu_physical_memory_write(notify_addr, &lisn, sizeof(lisn));
>>> +    }
>>> +}
>>> +
>>> +static uint64_t pnv_psi_p9_mmio_read(void *opaque, hwaddr addr, unsigned size)
>>> +{
>>> +    PnvPsi *psi = PNV9_PSI(opaque);
>>> +    uint32_t reg = PSIHB_REG(addr);
>>> +    uint64_t val = -1;
>>> +
>>> +    switch (addr) {
>>> +    case PSIHB9_CR:
>>> +    case PSIHB9_SEMR:
>>> +        /* FSP stuff */
>>> +    case PSIHB9_INTERRUPT_CONTROL:
>>> +    case PSIHB9_ESB_CI_BASE:
>>> +    case PSIHB9_ESB_NOTIF_ADDR:
>>> +    case PSIHB9_IVT_OFFSET:
>>> +        val = psi->regs[reg];
>>> +        break;
>>> +    default:
>>> +        qemu_log_mask(LOG_GUEST_ERROR, "PSI: read at 0x%" PRIx64 "\n", addr);
>>> +    }
>>> +
>>> +    return val;
>>> +}
>>> +
>>> +static void pnv_psi_p9_mmio_write(void *opaque, hwaddr addr,
>>> +                                  uint64_t val, unsigned size)
>>> +{
>>> +    PnvPsi *psi = PNV9_PSI(opaque);
>>> +    uint32_t reg = PSIHB_REG(addr);
>>> +    MemoryRegion *sysmem = get_system_memory();
>>> +
>>> +    switch (addr) {
>>> +    case PSIHB9_CR:
>>> +    case PSIHB9_SEMR:
>>> +        /* FSP stuff */
>>> +        break;
>>> +    case PSIHB9_INTERRUPT_CONTROL:
>>> +        if (val & PSIHB9_IRQ_RESET) {
>>> +            device_reset(DEVICE(&psi->source));
>>> +        }
>>> +        psi->regs[reg] = val;
>>> +        break;
>>> +
>>> +    case PSIHB9_ESB_CI_BASE:
>>> +        if (!(val & PSIHB9_ESB_CI_VALID)) {
>>> +            if (psi->regs[reg] & PSIHB9_ESB_CI_VALID) {
>>> +                memory_region_del_subregion(sysmem, &psi->source.esb_mmio);
>>> +            }
>>> +        } else {
>>> +            if (!(psi->regs[reg] & PSIHB9_ESB_CI_VALID)) {
>>> +                memory_region_add_subregion(sysmem,
>>> +                                        val & ~PSIHB9_ESB_CI_VALID,
>>> +                                        &psi->source.esb_mmio);
>>> +            }
>>> +        }
>>> +        psi->regs[reg] = val;
>>> +        break;
>>> +
>>> +    case PSIHB9_ESB_NOTIF_ADDR:
>>> +        psi->regs[reg] = val;
>>
>> Again, not in scope for this patch, but not being able to put a
>> reg[reg] = val outside the switch is a pretty good sign that a regs[]
>> array mirroring the guest register interface is not the right model
>> for this device.
> 
> Well, in this case, I think we could put 'psi->regs[reg] = val;'.
> 
> Thanks,
> 
> C.
> 
>>> +        break;
>>> +    case PSIHB9_IVT_OFFSET:
>>> +        psi->regs[reg] = val;
>>> +        break;
>>> +    default:
>>> +        qemu_log_mask(LOG_GUEST_ERROR, "PSI: write at 0x%" PRIx64 "\n", addr);
>>> +    }
>>> +}
>>> +
>>> +static const MemoryRegionOps pnv_psi_p9_mmio_ops = {
>>> +    .read = pnv_psi_p9_mmio_read,
>>> +    .write = pnv_psi_p9_mmio_write,
>>> +    .endianness = DEVICE_BIG_ENDIAN,
>>> +    .valid = {
>>> +        .min_access_size = 8,
>>> +        .max_access_size = 8,
>>> +    },
>>> +    .impl = {
>>> +        .min_access_size = 8,
>>> +        .max_access_size = 8,
>>> +    },
>>> +};
>>> +
>>> +static uint64_t pnv_psi_p9_xscom_read(void *opaque, hwaddr addr, unsigned size)
>>> +{
>>> +    /* No read are expected */
>>> +    qemu_log_mask(LOG_GUEST_ERROR, "PSI: xscom read at 0x%" PRIx64 "\n", addr);
>>> +    return -1;
>>> +}
>>> +
>>> +static void pnv_psi_p9_xscom_write(void *opaque, hwaddr addr,
>>> +                                uint64_t val, unsigned size)
>>> +{
>>> +    PnvPsi *psi = PNV9_PSI(opaque);
>>> +
>>> +    /* XSCOM is only used to set the PSIHB MMIO region */
>>> +    switch (addr >> 3) {
>>> +    case PSIHB_XSCOM_BAR:
>>> +        pnv_psi_set_bar(psi, val);
>>> +        break;
>>> +    default:
>>> +        qemu_log_mask(LOG_GUEST_ERROR, "PSI: xscom write at 0x%" PRIx64 "\n",
>>> +                      addr);
>>> +    }
>>> +}
>>> +
>>> +static const MemoryRegionOps pnv_psi_p9_xscom_ops = {
>>> +    .read = pnv_psi_p9_xscom_read,
>>> +    .write = pnv_psi_p9_xscom_write,
>>> +    .endianness = DEVICE_BIG_ENDIAN,
>>> +    .valid = {
>>> +        .min_access_size = 8,
>>> +        .max_access_size = 8,
>>> +    },
>>> +    .impl = {
>>> +        .min_access_size = 8,
>>> +        .max_access_size = 8,
>>> +    }
>>> +};
>>> +
>>> +static void pnv_psi_power9_irq_set(PnvPsi *psi, int irq, bool state)
>>> +{
>>> +    uint32_t irq_method = psi->regs[PSIHB_REG(PSIHB9_INTERRUPT_CONTROL)];
>>> +
>>> +    if (irq > PSIHB9_NUM_IRQS) {
>>> +        qemu_log_mask(LOG_GUEST_ERROR, "PSI: Unsupported irq %d\n", irq);
>>> +        return;
>>> +    }
>>> +
>>> +    if (irq_method & PSIHB9_IRQ_METHOD) {
>>> +        qemu_log_mask(LOG_GUEST_ERROR, "PSI: LSI IRQ method no supported\n");
>>> +        return;
>>> +    }
>>> +
>>> +    /* Update LSI levels */
>>> +    if (state) {
>>> +        psi->regs[PSIHB_REG(PSIHB9_IRQ_LEVEL)] |= PPC_BIT(irq);
>>> +    } else {
>>> +        psi->regs[PSIHB_REG(PSIHB9_IRQ_LEVEL)] &= ~PPC_BIT(irq);
>>> +    }
>>> +
>>> +    qemu_set_irq(psi->qirqs[irq], state);
>>> +}
>>> +
>>> +static void pnv_psi_power9_reset(void *dev)
>>> +{
>>> +    PnvPsi *psi = PNV9_PSI(dev);
>>> +
>>> +    pnv_psi_reset(dev);
>>> +
>>> +    if (memory_region_is_mapped(&psi->source.esb_mmio)) {
>>> +        memory_region_del_subregion(get_system_memory(), &psi->source.esb_mmio);
>>> +    }
>>> +}
>>> +
>>> +static void pnv_psi_power9_instance_init(Object *obj)
>>> +{
>>> +    PnvPsi *psi = PNV9_PSI(obj);
>>> +
>>> +    object_initialize_child(obj, "source", &psi->source, sizeof(psi->source),
>>> +                            TYPE_XIVE_SOURCE, &error_abort, NULL);
>>> +}
>>> +
>>> +static void pnv_psi_power9_realize(DeviceState *dev, Error **errp)
>>> +{
>>> +    PnvPsi *psi = PNV9_PSI(dev);
>>> +    XiveSource *xsrc = &psi->source;
>>> +    Error *local_err = NULL;
>>> +    int i;
>>> +
>>> +    /* This is the only device with 4k ESB pages */
>>> +    object_property_set_int(OBJECT(xsrc), XIVE_ESB_4K, "shift",
>>> +                            &error_fatal);
>>> +    object_property_set_int(OBJECT(xsrc), PSIHB9_NUM_IRQS, "nr-irqs",
>>> +                            &error_fatal);
>>> +    object_property_add_const_link(OBJECT(xsrc), "xive", OBJECT(psi),
>>> +                                   &error_fatal);
>>> +    object_property_set_bool(OBJECT(xsrc), true, "realized", &local_err);
>>> +    if (local_err) {
>>> +        error_propagate(errp, local_err);
>>> +        return;
>>> +    }
>>> +
>>> +    for (i = 0; i < xsrc->nr_irqs; i++) {
>>> +        xive_source_irq_set_lsi(xsrc, i);
>>> +    }
>>> +
>>> +    psi->qirqs = qemu_allocate_irqs(xive_source_set_irq, xsrc, xsrc->nr_irqs);
>>> +
>>> +    /* XSCOM region for PSI registers */
>>> +    pnv_xscom_region_init(&psi->xscom_regs, OBJECT(dev), &pnv_psi_p9_xscom_ops,
>>> +                psi, "xscom-psi", PNV9_XSCOM_PSIHB_SIZE);
>>> +
>>> +    /* MMIO region for PSI registers */
>>> +    memory_region_init_io(&psi->regs_mr, OBJECT(dev), &pnv_psi_p9_mmio_ops, psi,
>>> +                          "psihb", PNV9_PSIHB_SIZE);
>>> +
>>> +    pnv_psi_set_bar(psi, psi->bar | PSIHB_BAR_EN);
>>> +
>>> +    qemu_register_reset(pnv_psi_power9_reset, dev);
>>> +}
>>> +
>>> +static void pnv_psi_power9_class_init(ObjectClass *klass, void *data)
>>> +{
>>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>>> +    PnvPsiClass *ppc = PNV_PSI_CLASS(klass);
>>> +    XiveNotifierClass *xfc = XIVE_NOTIFIER_CLASS(klass);
>>> +
>>> +    dc->desc    = "PowerNV PSI Controller POWER9";
>>> +    dc->realize = pnv_psi_power9_realize;
>>> +
>>> +    ppc->chip_type  = PNV_CHIP_POWER9;
>>> +    ppc->xscom_pcba = PNV9_XSCOM_PSIHB_BASE;
>>> +    ppc->xscom_size = PNV9_XSCOM_PSIHB_SIZE;
>>> +    ppc->bar_mask   = PSIHB9_BAR_MASK;
>>> +    ppc->irq_set    = pnv_psi_power9_irq_set;
>>> +
>>> +    xfc->notify      = pnv_psi_notify;
>>> +}
>>> +
>>> +static const TypeInfo pnv_psi_power9_info = {
>>> +    .name          = TYPE_PNV9_PSI,
>>> +    .parent        = TYPE_PNV_PSI,
>>> +    .instance_init = pnv_psi_power9_instance_init,
>>> +    .class_init    = pnv_psi_power9_class_init,
>>> +    .interfaces = (InterfaceInfo[]) {
>>> +            { TYPE_XIVE_NOTIFIER },
>>> +            { },
>>> +    },
>>> +};
>>> +
>>>  static void pnv_psi_class_init(ObjectClass *klass, void *data)
>>>  {
>>>      DeviceClass *dc = DEVICE_CLASS(klass);
>>> @@ -611,6 +921,17 @@ static void pnv_psi_register_types(void)
>>>  {
>>>      type_register_static(&pnv_psi_info);
>>>      type_register_static(&pnv_psi_power8_info);
>>> +    type_register_static(&pnv_psi_power9_info);
>>>  }
>>>  
>>>  type_init(pnv_psi_register_types);
>>> +
>>> +void pnv_psi_pic_print_info(PnvPsi *psi, Monitor *mon)
>>> +{
>>> +    uint32_t offset =
>>> +        (psi->regs[PSIHB_REG(PSIHB9_IVT_OFFSET)] >> PSIHB9_IVT_OFF_SHIFT);
>>> +
>>> +    monitor_printf(mon, "PSIHB Source %08x .. %08x\n",
>>> +                  offset, offset + psi->source.nr_irqs - 1);
>>> +    xive_source_pic_print_info(&psi->source, offset, mon);
>>> +}
>>
> 

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

* Re: [Qemu-devel] [PATCH 15/27] ppc/pnv: add a PSI bridge model for POWER9
  2019-03-07  6:37     ` Cédric Le Goater
  2019-03-07 22:33       ` Cédric Le Goater
@ 2019-03-08  0:17       ` David Gibson
  2019-03-08  6:45         ` Cédric Le Goater
  1 sibling, 1 reply; 55+ messages in thread
From: David Gibson @ 2019-03-08  0:17 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 9730 bytes --]

On Thu, Mar 07, 2019 at 07:37:51AM +0100, Cédric Le Goater wrote:
> On 3/7/19 5:10 AM, David Gibson wrote:
> > On Wed, Mar 06, 2019 at 09:50:20AM +0100, Cédric Le Goater wrote:
> >> The PSI bridge on POWER9 is very similar to POWER8. The BAR is still
> >> set through XSCOM but the controls are now entirely done with MMIOs.
> >> More interrupts are defined and the interrupt controller interface has
> >> changed to XIVE. The POWER9 model is a first example of the usage of
> >> the notify() handler of the XiveNotifier interface, linking the PSI
> >> XiveSource to its owning device model.
> >>
> >> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> >> ---
> >>  include/hw/ppc/pnv.h       |   6 +
> >>  include/hw/ppc/pnv_psi.h   |  24 +++
> >>  include/hw/ppc/pnv_xscom.h |   3 +
> >>  hw/ppc/pnv.c               |  17 ++
> >>  hw/ppc/pnv_psi.c           | 325 ++++++++++++++++++++++++++++++++++++-
> >>  5 files changed, 373 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
> >> index eb4bba25b3e9..57d0337219be 100644
> >> --- a/include/hw/ppc/pnv.h
> >> +++ b/include/hw/ppc/pnv.h
> >> @@ -84,6 +84,7 @@ typedef struct Pnv9Chip {
> >>  
> >>      /*< public >*/
> >>      PnvXive      xive;
> >> +    PnvPsi       psi;
> >>  } Pnv9Chip;
> >>  
> >>  typedef struct PnvChipClass {
> >> @@ -231,11 +232,16 @@ void pnv_bmc_powerdown(IPMIBmc *bmc);
> >>  #define PNV9_XIVE_PC_SIZE            0x0000001000000000ull
> >>  #define PNV9_XIVE_PC_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006018000000000ull)
> >>  
> >> +#define PNV9_PSIHB_SIZE              0x0000000000100000ull
> >> +#define PNV9_PSIHB_BASE(chip)        PNV9_CHIP_BASE(chip, 0x0006030203000000ull)
> >> +
> >>  #define PNV9_XIVE_IC_SIZE            0x0000000000080000ull
> >>  #define PNV9_XIVE_IC_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006030203100000ull)
> >>  
> >>  #define PNV9_XIVE_TM_SIZE            0x0000000000040000ull
> >>  #define PNV9_XIVE_TM_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006030203180000ull)
> >>  
> >> +#define PNV9_PSIHB_ESB_SIZE          0x0000000000010000ull
> >> +#define PNV9_PSIHB_ESB_BASE(chip)    PNV9_CHIP_BASE(chip, 0x00060302031c0000ull)
> >>  
> >>  #endif /* _PPC_PNV_H */
> >> diff --git a/include/hw/ppc/pnv_psi.h b/include/hw/ppc/pnv_psi.h
> >> index 585a41cd19b6..d7e1ab282cf8 100644
> >> --- a/include/hw/ppc/pnv_psi.h
> >> +++ b/include/hw/ppc/pnv_psi.h
> >> @@ -21,6 +21,7 @@
> >>  
> >>  #include "hw/sysbus.h"
> >>  #include "hw/ppc/xics.h"
> >> +#include "hw/ppc/xive.h"
> >>  
> >>  #define TYPE_PNV_PSI "pnv-psi"
> >>  #define PNV_PSI(obj) \
> >> @@ -28,6 +29,9 @@
> >>  #define TYPE_PNV8_PSI TYPE_PNV_PSI "-POWER8"
> >>  #define PNV8_PSI(obj) \
> >>      OBJECT_CHECK(PnvPsi, (obj), TYPE_PNV8_PSI)
> >> +#define TYPE_PNV9_PSI TYPE_PNV_PSI "-POWER9"
> >> +#define PNV9_PSI(obj) \
> >> +    OBJECT_CHECK(PnvPsi, (obj), TYPE_PNV9_PSI)
> >>  
> >>  #define PSIHB_XSCOM_MAX         0x20
> >>  
> >> @@ -43,6 +47,7 @@ typedef struct PnvPsi {
> >>  
> >>      /* Interrupt generation */
> >>      ICSState ics;
> >> +    XiveSource source;
> > 
> > Uh... surely these should move to the subtype structures, so you don't
> > have both of them.
> 
> I did not introduce a subtype, only a subclass. But we could 
> possibly. It seemed overkill for one attribute.
> 
> > 
> >>      qemu_irq *qirqs;
> >>  
> >>      /* Registers */
> >> @@ -82,4 +87,23 @@ typedef enum PnvPsiIrq {
> >>  
> >>  void pnv_psi_irq_set(PnvPsi *psi, int irq, bool state);
> >>  
> >> +/* P9 PSI Interrupts */
> >> +#define PSIHB9_IRQ_PSI          0
> >> +#define PSIHB9_IRQ_OCC          1
> >> +#define PSIHB9_IRQ_FSI          2
> >> +#define PSIHB9_IRQ_LPCHC        3
> >> +#define PSIHB9_IRQ_LOCAL_ERR    4
> >> +#define PSIHB9_IRQ_GLOBAL_ERR   5
> >> +#define PSIHB9_IRQ_TPM          6
> >> +#define PSIHB9_IRQ_LPC_SIRQ0    7
> >> +#define PSIHB9_IRQ_LPC_SIRQ1    8
> >> +#define PSIHB9_IRQ_LPC_SIRQ2    9
> >> +#define PSIHB9_IRQ_LPC_SIRQ3    10
> >> +#define PSIHB9_IRQ_SBE_I2C      11
> >> +#define PSIHB9_IRQ_DIO          12
> >> +#define PSIHB9_IRQ_PSU          13
> >> +#define PSIHB9_NUM_IRQS         14
> >> +
> >> +void pnv_psi_pic_print_info(PnvPsi *psi, Monitor *mon);
> >> +
> >>  #endif /* _PPC_PNV_PSI_H */
> >> diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
> >> index 6623ec54a7a8..403a365ed274 100644
> >> --- a/include/hw/ppc/pnv_xscom.h
> >> +++ b/include/hw/ppc/pnv_xscom.h
> >> @@ -73,6 +73,9 @@ typedef struct PnvXScomInterfaceClass {
> >>  #define PNV_XSCOM_OCC_BASE        0x0066000
> >>  #define PNV_XSCOM_OCC_SIZE        0x6000
> >>  
> >> +#define PNV9_XSCOM_PSIHB_BASE     0x5012900
> >> +#define PNV9_XSCOM_PSIHB_SIZE     0x100
> >> +
> >>  #define PNV9_XSCOM_XIVE_BASE      0x5013000
> >>  #define PNV9_XSCOM_XIVE_SIZE      0x300
> >>  
> >> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> >> index 67d40dc3eebc..4375f97c7135 100644
> >> --- a/hw/ppc/pnv.c
> >> +++ b/hw/ppc/pnv.c
> >> @@ -579,6 +579,7 @@ static void pnv_chip_power9_pic_print_info(PnvChip *chip, Monitor *mon)
> >>      Pnv9Chip *chip9 = PNV9_CHIP(chip);
> >>  
> >>      pnv_xive_pic_print_info(&chip9->xive, mon);
> >> +    pnv_psi_pic_print_info(&chip9->psi, mon);
> >>  }
> >>  
> >>  static void pnv_init(MachineState *machine)
> >> @@ -948,6 +949,11 @@ static void pnv_chip_power9_instance_init(Object *obj)
> >>                              TYPE_PNV_XIVE, &error_abort, NULL);
> >>      object_property_add_const_link(OBJECT(&chip9->xive), "chip", obj,
> >>                                     &error_abort);
> >> +
> >> +    object_initialize_child(obj, "psi",  &chip9->psi, sizeof(chip9->psi),
> >> +                            TYPE_PNV9_PSI, &error_abort, NULL);
> >> +    object_property_add_const_link(OBJECT(&chip9->psi), "chip", obj,
> >> +                                   &error_abort);
> >>  }
> >>  
> >>  static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
> >> @@ -980,6 +986,17 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
> >>      }
> >>      pnv_xscom_add_subregion(chip, PNV9_XSCOM_XIVE_BASE,
> >>                              &chip9->xive.xscom_regs);
> >> +
> >> +    /* Processor Service Interface (PSI) Host Bridge */
> >> +    object_property_set_int(OBJECT(&chip9->psi), PNV9_PSIHB_BASE(chip),
> >> +                            "bar", &error_fatal);
> >> +    object_property_set_bool(OBJECT(&chip9->psi), true, "realized", &local_err);
> >> +    if (local_err) {
> >> +        error_propagate(errp, local_err);
> >> +        return;
> >> +    }
> >> +    pnv_xscom_add_subregion(chip, PNV9_XSCOM_PSIHB_BASE,
> >> +                            &chip9->psi.xscom_regs);
> >>  }
> >>  
> >>  static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
> >> diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
> >> index e56b455a61b1..3f995a0e0d7f 100644
> >> --- a/hw/ppc/pnv_psi.c
> >> +++ b/hw/ppc/pnv_psi.c
> >> @@ -22,6 +22,7 @@
> >>  #include "target/ppc/cpu.h"
> >>  #include "qemu/log.h"
> >>  #include "qapi/error.h"
> >> +#include "monitor/monitor.h"
> >>  
> >>  #include "exec/address-spaces.h"
> >>  
> >> @@ -114,6 +115,9 @@
> >>  #define PSIHB_BAR_MASK                  0x0003fffffff00000ull
> >>  #define PSIHB_FSPBAR_MASK               0x0003ffff00000000ull
> >>  
> >> +#define PSIHB9_BAR_MASK                 0x00fffffffff00000ull
> >> +#define PSIHB9_FSPBAR_MASK              0x00ffffff00000000ull
> >> +
> >>  #define PSIHB_REG(addr) (((addr) >> 3) + PSIHB_XSCOM_BAR)
> >>  
> >>  static void pnv_psi_set_bar(PnvPsi *psi, uint64_t bar)
> >> @@ -531,6 +535,7 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp)
> >>  }
> >>  
> >>  static const char compat_p8[] = "ibm,power8-psihb-x\0ibm,psihb-x";
> >> +static const char compat_p9[] = "ibm,power9-psihb-x\0ibm,psihb-x";
> >>  
> >>  static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
> >>  {
> >> @@ -550,8 +555,13 @@ static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
> >>      _FDT(fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)));
> >>      _FDT(fdt_setprop_cell(fdt, offset, "#address-cells", 2));
> >>      _FDT(fdt_setprop_cell(fdt, offset, "#size-cells", 1));
> >> -    _FDT(fdt_setprop(fdt, offset, "compatible", compat_p8,
> >> -                     sizeof(compat_p8)));
> >> +    if (ppc->chip_type == PNV_CHIP_POWER9) {
> > 
> > Ew.  You already have subclasses - put the compatible in there, rather
> > than more explicit tests against chip type.
> 
> I would also prefer to move the compat string to PnvPsiClass instead 
> of using a chip_type field but I didn't find a clean way for it. We 
> use sizeof() on the compat string below and it does not work on a 
> char *.

Ah, right.  There are ways to do that, but they're also ugly in their
own different ways.  Ok, well let's leave it as is for now, and
consider cleaning that up something for another day.

[snip]
> > Again, not in scope for this patch, but not being able to put a
> > reg[reg] = val outside the switch is a pretty good sign that a regs[]
> > array mirroring the guest register interface is not the right model
> > for this device.
> 
> Well, in this case, I think we could put 'psi->regs[reg] = val;'.

It feels like that sentence is unfinished.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 18/27] ppc/pnv: add a LPC Controller model for POWER9
  2019-03-07  7:07     ` Cédric Le Goater
@ 2019-03-08  0:19       ` David Gibson
  2019-03-08  6:49         ` Cédric Le Goater
  0 siblings, 1 reply; 55+ messages in thread
From: David Gibson @ 2019-03-08  0:19 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 5513 bytes --]

On Thu, Mar 07, 2019 at 08:07:41AM +0100, Cédric Le Goater wrote:
> On 3/7/19 5:18 AM, David Gibson wrote:
> > On Wed, Mar 06, 2019 at 09:50:23AM +0100, Cédric Le Goater wrote:
[snip]
> >> +static uint64_t pnv_lpc_mmio_read(void *opaque, hwaddr addr, unsigned size)
> >> +{
> >> +    PnvLpcController *lpc = PNV_LPC(opaque);
> >> +    uint64_t val = 0;
> >> +    uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK;
> >> +    MemTxResult result;
> >> +
> >> +    switch (size) {
> >> +    case 4:
> >> +        val = address_space_ldl(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED,
> >> +                                &result);
> >> +        break;
> >> +    case 1:
> >> +        val = address_space_ldub(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED,
> >> +                                 &result);
> >> +        break;
> >> +    default:
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%"
> >> +                      HWADDR_PRIx " invalid size %d\n", addr, size);
> >> +        return 0;
> >> +    }
> >> +
> >> +    if (result != MEMTX_OK) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%"
> >> +                      HWADDR_PRIx "\n", addr);
> >> +    }
> >> +
> >> +    return val;
> > 
> > Couldn't you just map the relevant portion of the OPB AS into the MMIO
> > AS, rather than having to forward the IOs with explicit read/write
> > functions?
> 
> The underlying memory regions (ISA space, LPC HC, OPB regs) are the
> same on POWER8. So this is one way to share the overall initialization. 

I don't understand how that relates to my question.  If anything that
sounds like it makes even more sense to map the common MR with the
actual registers into the MMIO AS as a subregion, rather than having a
redirect via the OPB AS.

> What I would have liked to do is to simplified the ECCB interface 
> (see pnv_lpc_do_eccb()).
> 
> Thanks,
> 
> C. 
> 
> 
> >> +}
> >> +
> >> +static void pnv_lpc_mmio_write(void *opaque, hwaddr addr,
> >> +                                uint64_t val, unsigned size)
> >> +{
> >> +    PnvLpcController *lpc = PNV_LPC(opaque);
> >> +    uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK;
> >> +    MemTxResult result;
> >> +
> >> +    switch (size) {
> >> +    case 4:
> >> +        address_space_stl(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED,
> >> +                          &result);
> >> +         break;
> >> +    case 1:
> >> +        address_space_stb(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED,
> >> +                          &result);
> >> +        break;
> >> +    default:
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%"
> >> +                      HWADDR_PRIx " invalid size %d\n", addr, size);
> >> +        return;
> >> +    }
> >> +
> >> +    if (result != MEMTX_OK) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%"
> >> +                      HWADDR_PRIx "\n", addr);
> >> +    }
> >> +}
> >> +
> >> +static const MemoryRegionOps pnv_lpc_mmio_ops = {
> >> +    .read = pnv_lpc_mmio_read,
> >> +    .write = pnv_lpc_mmio_write,
> >> +    .impl = {
> >> +        .min_access_size = 1,
> >> +        .max_access_size = 4,
> >> +    },
> >> +    .endianness = DEVICE_BIG_ENDIAN,
> >> +};
> >> +
> >>  static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
> >>  {
> >>      bool lpc_to_opb_irq = false;
> >> @@ -465,6 +627,43 @@ static const TypeInfo pnv_lpc_power8_info = {
> >>      }
> >>  };
> >>  
> >> +static void pnv_lpc_power9_realize(DeviceState *dev, Error **errp)
> >> +{
> >> +    PnvLpcController *lpc = PNV_LPC(dev);
> >> +    PnvLpcClass *plc = PNV_LPC_GET_CLASS(dev);
> >> +    Error *local_err = NULL;
> >> +
> >> +    plc->parent_realize(dev, &local_err);
> >> +    if (local_err) {
> >> +        error_propagate(errp, local_err);
> >> +        return;
> >> +    }
> >> +
> >> +    /* P9 uses a MMIO region */
> >> +    memory_region_init_io(&lpc->xscom_regs, OBJECT(lpc), &pnv_lpc_mmio_ops,
> >> +                          lpc, "lpcm", PNV9_LPCM_SIZE);
> >> +}
> >> +
> >> +static void pnv_lpc_power9_class_init(ObjectClass *klass, void *data)
> >> +{
> >> +    DeviceClass *dc = DEVICE_CLASS(klass);
> >> +    PnvLpcClass *plc = PNV_LPC_CLASS(klass);
> >> +
> >> +    dc->desc = "PowerNV LPC Controller POWER9";
> >> +
> >> +    plc->psi_irq = PSIHB9_IRQ_LPCHC;
> >> +
> >> +    device_class_set_parent_realize(dc, pnv_lpc_power9_realize,
> >> +                                    &plc->parent_realize);
> >> +}
> >> +
> >> +static const TypeInfo pnv_lpc_power9_info = {
> >> +    .name          = TYPE_PNV9_LPC,
> >> +    .parent        = TYPE_PNV_LPC,
> >> +    .instance_size = sizeof(PnvLpcController),
> >> +    .class_init    = pnv_lpc_power9_class_init,
> >> +};
> >> +
> >>  static void pnv_lpc_realize(DeviceState *dev, Error **errp)
> >>  {
> >>      PnvLpcController *lpc = PNV_LPC(dev);
> >> @@ -540,6 +739,7 @@ static void pnv_lpc_register_types(void)
> >>  {
> >>      type_register_static(&pnv_lpc_info);
> >>      type_register_static(&pnv_lpc_power8_info);
> >> +    type_register_static(&pnv_lpc_power9_info);
> >>  }
> >>  
> >>  type_init(pnv_lpc_register_types)
> > 
> 

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [Qemu-devel] [PATCH 15/27] ppc/pnv: add a PSI bridge model for POWER9
  2019-03-08  0:17       ` David Gibson
@ 2019-03-08  6:45         ` Cédric Le Goater
  0 siblings, 0 replies; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-08  6:45 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel

On 3/8/19 1:17 AM, David Gibson wrote:
> On Thu, Mar 07, 2019 at 07:37:51AM +0100, Cédric Le Goater wrote:
>> On 3/7/19 5:10 AM, David Gibson wrote:
>>> On Wed, Mar 06, 2019 at 09:50:20AM +0100, Cédric Le Goater wrote:
>>>> The PSI bridge on POWER9 is very similar to POWER8. The BAR is still
>>>> set through XSCOM but the controls are now entirely done with MMIOs.
>>>> More interrupts are defined and the interrupt controller interface has
>>>> changed to XIVE. The POWER9 model is a first example of the usage of
>>>> the notify() handler of the XiveNotifier interface, linking the PSI
>>>> XiveSource to its owning device model.
>>>>
>>>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>>>> ---
>>>>  include/hw/ppc/pnv.h       |   6 +
>>>>  include/hw/ppc/pnv_psi.h   |  24 +++
>>>>  include/hw/ppc/pnv_xscom.h |   3 +
>>>>  hw/ppc/pnv.c               |  17 ++
>>>>  hw/ppc/pnv_psi.c           | 325 ++++++++++++++++++++++++++++++++++++-
>>>>  5 files changed, 373 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
>>>> index eb4bba25b3e9..57d0337219be 100644
>>>> --- a/include/hw/ppc/pnv.h
>>>> +++ b/include/hw/ppc/pnv.h
>>>> @@ -84,6 +84,7 @@ typedef struct Pnv9Chip {
>>>>  
>>>>      /*< public >*/
>>>>      PnvXive      xive;
>>>> +    PnvPsi       psi;
>>>>  } Pnv9Chip;
>>>>  
>>>>  typedef struct PnvChipClass {
>>>> @@ -231,11 +232,16 @@ void pnv_bmc_powerdown(IPMIBmc *bmc);
>>>>  #define PNV9_XIVE_PC_SIZE            0x0000001000000000ull
>>>>  #define PNV9_XIVE_PC_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006018000000000ull)
>>>>  
>>>> +#define PNV9_PSIHB_SIZE              0x0000000000100000ull
>>>> +#define PNV9_PSIHB_BASE(chip)        PNV9_CHIP_BASE(chip, 0x0006030203000000ull)
>>>> +
>>>>  #define PNV9_XIVE_IC_SIZE            0x0000000000080000ull
>>>>  #define PNV9_XIVE_IC_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006030203100000ull)
>>>>  
>>>>  #define PNV9_XIVE_TM_SIZE            0x0000000000040000ull
>>>>  #define PNV9_XIVE_TM_BASE(chip)      PNV9_CHIP_BASE(chip, 0x0006030203180000ull)
>>>>  
>>>> +#define PNV9_PSIHB_ESB_SIZE          0x0000000000010000ull
>>>> +#define PNV9_PSIHB_ESB_BASE(chip)    PNV9_CHIP_BASE(chip, 0x00060302031c0000ull)
>>>>  
>>>>  #endif /* _PPC_PNV_H */
>>>> diff --git a/include/hw/ppc/pnv_psi.h b/include/hw/ppc/pnv_psi.h
>>>> index 585a41cd19b6..d7e1ab282cf8 100644
>>>> --- a/include/hw/ppc/pnv_psi.h
>>>> +++ b/include/hw/ppc/pnv_psi.h
>>>> @@ -21,6 +21,7 @@
>>>>  
>>>>  #include "hw/sysbus.h"
>>>>  #include "hw/ppc/xics.h"
>>>> +#include "hw/ppc/xive.h"
>>>>  
>>>>  #define TYPE_PNV_PSI "pnv-psi"
>>>>  #define PNV_PSI(obj) \
>>>> @@ -28,6 +29,9 @@
>>>>  #define TYPE_PNV8_PSI TYPE_PNV_PSI "-POWER8"
>>>>  #define PNV8_PSI(obj) \
>>>>      OBJECT_CHECK(PnvPsi, (obj), TYPE_PNV8_PSI)
>>>> +#define TYPE_PNV9_PSI TYPE_PNV_PSI "-POWER9"
>>>> +#define PNV9_PSI(obj) \
>>>> +    OBJECT_CHECK(PnvPsi, (obj), TYPE_PNV9_PSI)
>>>>  
>>>>  #define PSIHB_XSCOM_MAX         0x20
>>>>  
>>>> @@ -43,6 +47,7 @@ typedef struct PnvPsi {
>>>>  
>>>>      /* Interrupt generation */
>>>>      ICSState ics;
>>>> +    XiveSource source;
>>>
>>> Uh... surely these should move to the subtype structures, so you don't
>>> have both of them.
>>
>> I did not introduce a subtype, only a subclass. But we could 
>> possibly. It seemed overkill for one attribute.
>>
>>>
>>>>      qemu_irq *qirqs;
>>>>  
>>>>      /* Registers */
>>>> @@ -82,4 +87,23 @@ typedef enum PnvPsiIrq {
>>>>  
>>>>  void pnv_psi_irq_set(PnvPsi *psi, int irq, bool state);
>>>>  
>>>> +/* P9 PSI Interrupts */
>>>> +#define PSIHB9_IRQ_PSI          0
>>>> +#define PSIHB9_IRQ_OCC          1
>>>> +#define PSIHB9_IRQ_FSI          2
>>>> +#define PSIHB9_IRQ_LPCHC        3
>>>> +#define PSIHB9_IRQ_LOCAL_ERR    4
>>>> +#define PSIHB9_IRQ_GLOBAL_ERR   5
>>>> +#define PSIHB9_IRQ_TPM          6
>>>> +#define PSIHB9_IRQ_LPC_SIRQ0    7
>>>> +#define PSIHB9_IRQ_LPC_SIRQ1    8
>>>> +#define PSIHB9_IRQ_LPC_SIRQ2    9
>>>> +#define PSIHB9_IRQ_LPC_SIRQ3    10
>>>> +#define PSIHB9_IRQ_SBE_I2C      11
>>>> +#define PSIHB9_IRQ_DIO          12
>>>> +#define PSIHB9_IRQ_PSU          13
>>>> +#define PSIHB9_NUM_IRQS         14
>>>> +
>>>> +void pnv_psi_pic_print_info(PnvPsi *psi, Monitor *mon);
>>>> +
>>>>  #endif /* _PPC_PNV_PSI_H */
>>>> diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
>>>> index 6623ec54a7a8..403a365ed274 100644
>>>> --- a/include/hw/ppc/pnv_xscom.h
>>>> +++ b/include/hw/ppc/pnv_xscom.h
>>>> @@ -73,6 +73,9 @@ typedef struct PnvXScomInterfaceClass {
>>>>  #define PNV_XSCOM_OCC_BASE        0x0066000
>>>>  #define PNV_XSCOM_OCC_SIZE        0x6000
>>>>  
>>>> +#define PNV9_XSCOM_PSIHB_BASE     0x5012900
>>>> +#define PNV9_XSCOM_PSIHB_SIZE     0x100
>>>> +
>>>>  #define PNV9_XSCOM_XIVE_BASE      0x5013000
>>>>  #define PNV9_XSCOM_XIVE_SIZE      0x300
>>>>  
>>>> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
>>>> index 67d40dc3eebc..4375f97c7135 100644
>>>> --- a/hw/ppc/pnv.c
>>>> +++ b/hw/ppc/pnv.c
>>>> @@ -579,6 +579,7 @@ static void pnv_chip_power9_pic_print_info(PnvChip *chip, Monitor *mon)
>>>>      Pnv9Chip *chip9 = PNV9_CHIP(chip);
>>>>  
>>>>      pnv_xive_pic_print_info(&chip9->xive, mon);
>>>> +    pnv_psi_pic_print_info(&chip9->psi, mon);
>>>>  }
>>>>  
>>>>  static void pnv_init(MachineState *machine)
>>>> @@ -948,6 +949,11 @@ static void pnv_chip_power9_instance_init(Object *obj)
>>>>                              TYPE_PNV_XIVE, &error_abort, NULL);
>>>>      object_property_add_const_link(OBJECT(&chip9->xive), "chip", obj,
>>>>                                     &error_abort);
>>>> +
>>>> +    object_initialize_child(obj, "psi",  &chip9->psi, sizeof(chip9->psi),
>>>> +                            TYPE_PNV9_PSI, &error_abort, NULL);
>>>> +    object_property_add_const_link(OBJECT(&chip9->psi), "chip", obj,
>>>> +                                   &error_abort);
>>>>  }
>>>>  
>>>>  static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
>>>> @@ -980,6 +986,17 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
>>>>      }
>>>>      pnv_xscom_add_subregion(chip, PNV9_XSCOM_XIVE_BASE,
>>>>                              &chip9->xive.xscom_regs);
>>>> +
>>>> +    /* Processor Service Interface (PSI) Host Bridge */
>>>> +    object_property_set_int(OBJECT(&chip9->psi), PNV9_PSIHB_BASE(chip),
>>>> +                            "bar", &error_fatal);
>>>> +    object_property_set_bool(OBJECT(&chip9->psi), true, "realized", &local_err);
>>>> +    if (local_err) {
>>>> +        error_propagate(errp, local_err);
>>>> +        return;
>>>> +    }
>>>> +    pnv_xscom_add_subregion(chip, PNV9_XSCOM_PSIHB_BASE,
>>>> +                            &chip9->psi.xscom_regs);
>>>>  }
>>>>  
>>>>  static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
>>>> diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
>>>> index e56b455a61b1..3f995a0e0d7f 100644
>>>> --- a/hw/ppc/pnv_psi.c
>>>> +++ b/hw/ppc/pnv_psi.c
>>>> @@ -22,6 +22,7 @@
>>>>  #include "target/ppc/cpu.h"
>>>>  #include "qemu/log.h"
>>>>  #include "qapi/error.h"
>>>> +#include "monitor/monitor.h"
>>>>  
>>>>  #include "exec/address-spaces.h"
>>>>  
>>>> @@ -114,6 +115,9 @@
>>>>  #define PSIHB_BAR_MASK                  0x0003fffffff00000ull
>>>>  #define PSIHB_FSPBAR_MASK               0x0003ffff00000000ull
>>>>  
>>>> +#define PSIHB9_BAR_MASK                 0x00fffffffff00000ull
>>>> +#define PSIHB9_FSPBAR_MASK              0x00ffffff00000000ull
>>>> +
>>>>  #define PSIHB_REG(addr) (((addr) >> 3) + PSIHB_XSCOM_BAR)
>>>>  
>>>>  static void pnv_psi_set_bar(PnvPsi *psi, uint64_t bar)
>>>> @@ -531,6 +535,7 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp)
>>>>  }
>>>>  
>>>>  static const char compat_p8[] = "ibm,power8-psihb-x\0ibm,psihb-x";
>>>> +static const char compat_p9[] = "ibm,power9-psihb-x\0ibm,psihb-x";
>>>>  
>>>>  static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
>>>>  {
>>>> @@ -550,8 +555,13 @@ static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
>>>>      _FDT(fdt_setprop(fdt, offset, "reg", reg, sizeof(reg)));
>>>>      _FDT(fdt_setprop_cell(fdt, offset, "#address-cells", 2));
>>>>      _FDT(fdt_setprop_cell(fdt, offset, "#size-cells", 1));
>>>> -    _FDT(fdt_setprop(fdt, offset, "compatible", compat_p8,
>>>> -                     sizeof(compat_p8)));
>>>> +    if (ppc->chip_type == PNV_CHIP_POWER9) {
>>>
>>> Ew.  You already have subclasses - put the compatible in there, rather
>>> than more explicit tests against chip type.
>>
>> I would also prefer to move the compat string to PnvPsiClass instead 
>> of using a chip_type field but I didn't find a clean way for it. We 
>> use sizeof() on the compat string below and it does not work on a 
>> char *.
> 
> Ah, right.  There are ways to do that, but they're also ugly in their
> own different ways.  Ok, well let's leave it as is for now, and
> consider cleaning that up something for another day.
> 
> [snip]
>>> Again, not in scope for this patch, but not being able to put a
>>> reg[reg] = val outside the switch is a pretty good sign that a regs[]
>>> array mirroring the guest register interface is not the right model
>>> for this device.
>>
>> Well, in this case, I think we could put 'psi->regs[reg] = val;'.
> 
> It feels like that sentence is unfinished.

... at the end of the switch case. 

I will add it to my list of fixes for QEMU4.0

Thanks, 

C. 

 

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

* Re: [Qemu-devel] [PATCH 18/27] ppc/pnv: add a LPC Controller model for POWER9
  2019-03-08  0:19       ` David Gibson
@ 2019-03-08  6:49         ` Cédric Le Goater
  0 siblings, 0 replies; 55+ messages in thread
From: Cédric Le Goater @ 2019-03-08  6:49 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel

On 3/8/19 1:19 AM, David Gibson wrote:
> On Thu, Mar 07, 2019 at 08:07:41AM +0100, Cédric Le Goater wrote:
>> On 3/7/19 5:18 AM, David Gibson wrote:
>>> On Wed, Mar 06, 2019 at 09:50:23AM +0100, Cédric Le Goater wrote:
> [snip]
>>>> +static uint64_t pnv_lpc_mmio_read(void *opaque, hwaddr addr, unsigned size)
>>>> +{
>>>> +    PnvLpcController *lpc = PNV_LPC(opaque);
>>>> +    uint64_t val = 0;
>>>> +    uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK;
>>>> +    MemTxResult result;
>>>> +
>>>> +    switch (size) {
>>>> +    case 4:
>>>> +        val = address_space_ldl(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED,
>>>> +                                &result);
>>>> +        break;
>>>> +    case 1:
>>>> +        val = address_space_ldub(&lpc->opb_as, opb_addr, MEMTXATTRS_UNSPECIFIED,
>>>> +                                 &result);
>>>> +        break;
>>>> +    default:
>>>> +        qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%"
>>>> +                      HWADDR_PRIx " invalid size %d\n", addr, size);
>>>> +        return 0;
>>>> +    }
>>>> +
>>>> +    if (result != MEMTX_OK) {
>>>> +        qemu_log_mask(LOG_GUEST_ERROR, "OPB read failed at @0x%"
>>>> +                      HWADDR_PRIx "\n", addr);
>>>> +    }
>>>> +
>>>> +    return val;
>>>
>>> Couldn't you just map the relevant portion of the OPB AS into the MMIO
>>> AS, rather than having to forward the IOs with explicit read/write
>>> functions?
>>
>> The underlying memory regions (ISA space, LPC HC, OPB regs) are the
>> same on POWER8. So this is one way to share the overall initialization. 
> 
> I don't understand how that relates to my question.  If anything that
> sounds like it makes even more sense to map the common MR with the
> actual registers into the MMIO AS as a subregion, rather than having a
> redirect via the OPB AS.

ok. I will try that.

Thanks,

C.   

> 
>> What I would have liked to do is to simplified the ECCB interface 
>> (see pnv_lpc_do_eccb()).
>>
>> Thanks,
>>
>> C. 
>>
>>
>>>> +}
>>>> +
>>>> +static void pnv_lpc_mmio_write(void *opaque, hwaddr addr,
>>>> +                                uint64_t val, unsigned size)
>>>> +{
>>>> +    PnvLpcController *lpc = PNV_LPC(opaque);
>>>> +    uint32_t opb_addr = addr & ECCB_CTL_ADDR_MASK;
>>>> +    MemTxResult result;
>>>> +
>>>> +    switch (size) {
>>>> +    case 4:
>>>> +        address_space_stl(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED,
>>>> +                          &result);
>>>> +         break;
>>>> +    case 1:
>>>> +        address_space_stb(&lpc->opb_as, opb_addr, val, MEMTXATTRS_UNSPECIFIED,
>>>> +                          &result);
>>>> +        break;
>>>> +    default:
>>>> +        qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%"
>>>> +                      HWADDR_PRIx " invalid size %d\n", addr, size);
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    if (result != MEMTX_OK) {
>>>> +        qemu_log_mask(LOG_GUEST_ERROR, "OPB write failed at @0x%"
>>>> +                      HWADDR_PRIx "\n", addr);
>>>> +    }
>>>> +}
>>>> +
>>>> +static const MemoryRegionOps pnv_lpc_mmio_ops = {
>>>> +    .read = pnv_lpc_mmio_read,
>>>> +    .write = pnv_lpc_mmio_write,
>>>> +    .impl = {
>>>> +        .min_access_size = 1,
>>>> +        .max_access_size = 4,
>>>> +    },
>>>> +    .endianness = DEVICE_BIG_ENDIAN,
>>>> +};
>>>> +
>>>>  static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
>>>>  {
>>>>      bool lpc_to_opb_irq = false;
>>>> @@ -465,6 +627,43 @@ static const TypeInfo pnv_lpc_power8_info = {
>>>>      }
>>>>  };
>>>>  
>>>> +static void pnv_lpc_power9_realize(DeviceState *dev, Error **errp)
>>>> +{
>>>> +    PnvLpcController *lpc = PNV_LPC(dev);
>>>> +    PnvLpcClass *plc = PNV_LPC_GET_CLASS(dev);
>>>> +    Error *local_err = NULL;
>>>> +
>>>> +    plc->parent_realize(dev, &local_err);
>>>> +    if (local_err) {
>>>> +        error_propagate(errp, local_err);
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    /* P9 uses a MMIO region */
>>>> +    memory_region_init_io(&lpc->xscom_regs, OBJECT(lpc), &pnv_lpc_mmio_ops,
>>>> +                          lpc, "lpcm", PNV9_LPCM_SIZE);
>>>> +}
>>>> +
>>>> +static void pnv_lpc_power9_class_init(ObjectClass *klass, void *data)
>>>> +{
>>>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>>>> +    PnvLpcClass *plc = PNV_LPC_CLASS(klass);
>>>> +
>>>> +    dc->desc = "PowerNV LPC Controller POWER9";
>>>> +
>>>> +    plc->psi_irq = PSIHB9_IRQ_LPCHC;
>>>> +
>>>> +    device_class_set_parent_realize(dc, pnv_lpc_power9_realize,
>>>> +                                    &plc->parent_realize);
>>>> +}
>>>> +
>>>> +static const TypeInfo pnv_lpc_power9_info = {
>>>> +    .name          = TYPE_PNV9_LPC,
>>>> +    .parent        = TYPE_PNV_LPC,
>>>> +    .instance_size = sizeof(PnvLpcController),
>>>> +    .class_init    = pnv_lpc_power9_class_init,
>>>> +};
>>>> +
>>>>  static void pnv_lpc_realize(DeviceState *dev, Error **errp)
>>>>  {
>>>>      PnvLpcController *lpc = PNV_LPC(dev);
>>>> @@ -540,6 +739,7 @@ static void pnv_lpc_register_types(void)
>>>>  {
>>>>      type_register_static(&pnv_lpc_info);
>>>>      type_register_static(&pnv_lpc_power8_info);
>>>> +    type_register_static(&pnv_lpc_power9_info);
>>>>  }
>>>>  
>>>>  type_init(pnv_lpc_register_types)
>>>
>>
> 

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

end of thread, other threads:[~2019-03-08  6:49 UTC | newest]

Thread overview: 55+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-06  8:50 [Qemu-devel] [PATCH 00/27] ppc: add POWER9 support to the PowerNV platform Cédric Le Goater
2019-03-06  8:50 ` [Qemu-devel] [PATCH 01/27] ppc/xive: hardwire the Physical CAM line of the thread context Cédric Le Goater
2019-03-07  1:19   ` David Gibson
2019-03-06  8:50 ` [Qemu-devel] [PATCH 02/27] ppc: externalize ppc_get_vcpu_by_pir() Cédric Le Goater
2019-03-06  8:50 ` [Qemu-devel] [PATCH 03/27] ppc/xive: export the TIMA memory accessors Cédric Le Goater
2019-03-06  8:50 ` [Qemu-devel] [PATCH 04/27] ppc/pnv: export the xive_router_notify() routine Cédric Le Goater
2019-03-06  8:50 ` [Qemu-devel] [PATCH 05/27] ppc/pnv: change the CPU machine_data presenter type to Object * Cédric Le Goater
2019-03-07  1:36   ` David Gibson
2019-03-06  8:50 ` [Qemu-devel] [PATCH 06/27] ppc/pnv: add a XIVE interrupt controller model for POWER9 Cédric Le Goater
2019-03-07  1:37   ` David Gibson
2019-03-06  8:50 ` [Qemu-devel] [PATCH 07/27] ppc/pnv: introduce a new dt_populate() operation to the chip model Cédric Le Goater
2019-03-07  1:44   ` David Gibson
2019-03-06  8:50 ` [Qemu-devel] [PATCH 08/27] ppc/pnv: introduce a new pic_print_info() " Cédric Le Goater
2019-03-07  1:46   ` David Gibson
2019-03-06  8:50 ` [Qemu-devel] [PATCH 09/27] ppc/xive: activate HV support Cédric Le Goater
2019-03-07  1:48   ` David Gibson
2019-03-06  8:50 ` [Qemu-devel] [PATCH 10/27] ppc/xive: Make XIVE generate the proper interrupt types Cédric Le Goater
2019-03-07  3:29   ` David Gibson
2019-03-06  8:50 ` [Qemu-devel] [PATCH 11/27] ppc/pnv: fix logging primitives using Ox Cédric Le Goater
2019-03-07  3:30   ` David Gibson
2019-03-06  8:50 ` [Qemu-devel] [PATCH 12/27] ppc/pnv: psi: add a PSIHB_REG macro Cédric Le Goater
2019-03-07  3:30   ` David Gibson
2019-03-06  8:50 ` [Qemu-devel] [PATCH 13/27] ppc/pnv: psi: add a reset handler Cédric Le Goater
2019-03-07  3:32   ` David Gibson
2019-03-06  8:50 ` [Qemu-devel] [PATCH 14/27] ppc/pnv: add a PSI bridge model class Cédric Le Goater
2019-03-07  4:05   ` David Gibson
2019-03-07  4:08     ` David Gibson
2019-03-06  8:50 ` [Qemu-devel] [PATCH 15/27] ppc/pnv: add a PSI bridge model for POWER9 Cédric Le Goater
2019-03-07  4:10   ` David Gibson
2019-03-07  6:37     ` Cédric Le Goater
2019-03-07 22:33       ` Cédric Le Goater
2019-03-08  0:17       ` David Gibson
2019-03-08  6:45         ` Cédric Le Goater
2019-03-06  8:50 ` [Qemu-devel] [PATCH 16/27] ppc/pnv: lpc: fix OPB address ranges Cédric Le Goater
2019-03-07  4:11   ` David Gibson
2019-03-06  8:50 ` [Qemu-devel] [PATCH 17/27] ppc/pnv: add a LPC Controller model class Cédric Le Goater
2019-03-07  4:12   ` David Gibson
2019-03-06  8:50 ` [Qemu-devel] [PATCH 18/27] ppc/pnv: add a LPC Controller model for POWER9 Cédric Le Goater
2019-03-07  4:18   ` David Gibson
2019-03-07  7:07     ` Cédric Le Goater
2019-03-08  0:19       ` David Gibson
2019-03-08  6:49         ` Cédric Le Goater
2019-03-06  8:50 ` [Qemu-devel] [PATCH 19/27] ppc/pnv: add SerIRQ routing registers Cédric Le Goater
2019-03-06  8:50 ` [Qemu-devel] [PATCH 20/27] ppc/pnv: add a OCC model class Cédric Le Goater
2019-03-07  4:26   ` David Gibson
2019-03-06  8:50 ` [Qemu-devel] [PATCH 21/27] ppc/pnv: add a OCC model for POWER9 Cédric Le Goater
2019-03-07  4:27   ` David Gibson
2019-03-07  7:47     ` Cédric Le Goater
2019-03-06  8:50 ` [Qemu-devel] [PATCH 22/27] ppc/pnv: extend XSCOM core support " Cédric Le Goater
2019-03-07  4:28   ` David Gibson
2019-03-06  8:50 ` [Qemu-devel] [PATCH 23/27] ppc/pnv: POWER9 XSCOM quad support Cédric Le Goater
2019-03-06  8:50 ` [Qemu-devel] [PATCH 24/27] ppc/pnv: activate XSCOM tests for POWER9 Cédric Le Goater
2019-03-06  8:50 ` [Qemu-devel] [PATCH 25/27] ppc/pnv: add more dummy XSCOM addresses Cédric Le Goater
2019-03-06  8:50 ` [Qemu-devel] [PATCH 26/27] ppc/pnv: add a "ibm, opal/power-mgt" device tree node on POWER9 Cédric Le Goater
2019-03-06  8:50 ` [Qemu-devel] [PATCH 27/27] target/ppc: add HV support for POWER9 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.