All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618
@ 2018-06-18  3:52 David Gibson
  2018-06-18  3:52 ` [Qemu-devel] [PULL 01/28] target/ppc: Don't require private l1d cache on POWER8 for cap_ppc_safe_cache David Gibson
                   ` (28 more replies)
  0 siblings, 29 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:52 UTC (permalink / raw)
  To: peter.maydell; +Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, David Gibson

The following changes since commit 2ef2f16781af9dee6ba6517755e9073ba5799fa2:

  Merge remote-tracking branch 'remotes/dgilbert/tags/pull-migration-20180615a' into staging (2018-06-15 18:13:35 +0100)

are available in the Git repository at:

  git://github.com/dgibson/qemu.git tags/ppc-for-3.0-20180618

for you to fetch changes up to 844afc54ae229515a37f63519855661ad2d01d19:

  spapr: fix xics_system_init() error path (2018-06-18 09:43:19 +1000)

----------------------------------------------------------------
ppc patch queue 2018-06-18

Next batch of ppc and spapr related patches for the 3.0 release.
    * Improved handling of Spectre/Meltdown mitigations for POWER8
    * Numerous Mac machine type cleanups and improvements
    * Cleanup to cpu realize/unrealize path for spapr
    * Create a place for machine-specific per-cpu information, and
      start moving some things to it
    * Assorted bugfixes

----------------------------------------------------------------
BALATON Zoltan (1):
      sm501: Do not clear read only bits when writing registers

Cédric Le Goater (2):
      xics_kvm: fix a build break
      ppc/pnv: introduce a pnv_chip_core_realize() routine

David Gibson (6):
      spapr: Clean up cpu realize/unrealize paths
      pnv: Fix some error handling cpu realize()
      pnv_core: Allocate cpu thread objects individually
      pnv: Clean up cpu realize path
      pnv: Add cpu unrealize path
      target/ppc, spapr: Move VPA information to machine_data

Greg Kurz (7):
      target/ppc: drop empty #if/#endif block
      spapr: fix leak in h_client_architecture_support()
      spapr_cpu_core: convert last snprintf() to g_strdup_printf()
      spapr_cpu_core: fix potential leak in spapr_cpu_core_realize()
      spapr_cpu_core: add missing rollback on realization path
      spapr_cpu_core: introduce spapr_create_vcpu()
      spapr: fix xics_system_init() error path

Mark Cave-Ayland (10):
      ppc: introduce Core99MachinesState for the mac99 machine
      mac_newworld: add via machine option to control mac99 VIA/ADB configuration
      mac_newworld: add gpios to macio devices with PMU enabled
      mac_newworld: wire up programmer switch to NMI handler
      adb: fix read reg 3 byte ordering
      adb: add property to disable direct reg 3 writes
      mac_newworld: add PMU device
      mos6522: only clear the shift register interrupt upon write
      mos6522: remove additional interrupt flag filter from mos6522_update_irq()
      mos6522: expose mos6522_update_irq() through MOS6522DeviceClass

Suraj Jitindar Singh (2):
      target/ppc: Don't require private l1d cache on POWER8 for cap_ppc_safe_cache
      ppc/spapr_caps: Don't disable cap_cfpc on POWER8 by default

 default-configs/ppc-softmmu.mak |   2 +
 hw/display/sm501.c              |  15 +-
 hw/input/adb-kbd.c              |  29 +-
 hw/input/adb-mouse.c            |  41 +-
 hw/input/adb.c                  |   7 +
 hw/intc/xics_kvm.c              |  10 +-
 hw/misc/macio/Makefile.objs     |   2 +
 hw/misc/macio/gpio.c            | 231 +++++++++++
 hw/misc/macio/macio.c           |  89 +++-
 hw/misc/macio/pmu.c             | 871 ++++++++++++++++++++++++++++++++++++++++
 hw/misc/macio/trace-events      |  28 ++
 hw/misc/mos6522.c               |   5 +-
 hw/ppc/mac.h                    |  20 +
 hw/ppc/mac_newworld.c           |  84 +++-
 hw/ppc/pnv.c                    |  36 +-
 hw/ppc/pnv_core.c               |  93 ++---
 hw/ppc/spapr.c                  |  22 +-
 hw/ppc/spapr_caps.c             |   6 +-
 hw/ppc/spapr_cpu_core.c         | 163 ++++----
 hw/ppc/spapr_hcall.c            |  78 ++--
 include/hw/input/adb.h          |   1 +
 include/hw/misc/macio/gpio.h    |  47 +++
 include/hw/misc/macio/macio.h   |   7 +
 include/hw/misc/macio/pmu.h     | 237 +++++++++++
 include/hw/misc/mos6522.h       |   1 +
 include/hw/ppc/pnv_core.h       |   2 +-
 include/hw/ppc/ppc.h            |   1 +
 include/hw/ppc/spapr_cpu_core.h |  11 +
 target/ppc/cpu.h                |   9 +-
 target/ppc/kvm.c                |  58 ++-
 target/ppc/translate_init.inc.c |   8 -
 31 files changed, 1930 insertions(+), 284 deletions(-)
 create mode 100644 hw/misc/macio/gpio.c
 create mode 100644 hw/misc/macio/pmu.c
 create mode 100644 include/hw/misc/macio/gpio.h
 create mode 100644 include/hw/misc/macio/pmu.h

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

* [Qemu-devel] [PULL 01/28] target/ppc: Don't require private l1d cache on POWER8 for cap_ppc_safe_cache
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
@ 2018-06-18  3:52 ` David Gibson
  2018-06-18  3:52 ` [Qemu-devel] [PULL 02/28] ppc/spapr_caps: Don't disable cap_cfpc on POWER8 by default David Gibson
                   ` (27 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:52 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik,
	Suraj Jitindar Singh, David Gibson

From: Suraj Jitindar Singh <sjitindarsingh@gmail.com>

For cap_ppc_safe_cache to be set to workaround, we require both a l1d
cache flush instruction and private l1d cache.

On POWER8 don't require private l1d cache. This means a guest on a
POWER8 machine can make use of the cache flush workarounds.

Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 target/ppc/kvm.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 2c0c34e125..7fe9d0126b 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -2412,11 +2412,28 @@ bool kvmppc_has_cap_mmu_hash_v3(void)
     return cap_mmu_hash_v3;
 }
 
+static bool kvmppc_power8_host(void)
+{
+    bool ret = false;
+#ifdef TARGET_PPC64
+    {
+        uint32_t base_pvr = CPU_POWERPC_POWER_SERVER_MASK & mfpvr();
+        ret = (base_pvr == CPU_POWERPC_POWER8E_BASE) ||
+              (base_pvr == CPU_POWERPC_POWER8NVL_BASE) ||
+              (base_pvr == CPU_POWERPC_POWER8_BASE);
+    }
+#endif /* TARGET_PPC64 */
+    return ret;
+}
+
 static int parse_cap_ppc_safe_cache(struct kvm_ppc_cpu_char c)
 {
+    bool l1d_thread_priv_req = !kvmppc_power8_host();
+
     if (~c.behaviour & c.behaviour_mask & H_CPU_BEHAV_L1D_FLUSH_PR) {
         return 2;
-    } else if ((c.character & c.character_mask & H_CPU_CHAR_L1D_THREAD_PRIV) &&
+    } else if ((!l1d_thread_priv_req ||
+                c.character & c.character_mask & H_CPU_CHAR_L1D_THREAD_PRIV) &&
                (c.character & c.character_mask
                 & (H_CPU_CHAR_L1D_FLUSH_ORI30 | H_CPU_CHAR_L1D_FLUSH_TRIG2))) {
         return 1;
-- 
2.17.1

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

* [Qemu-devel] [PULL 02/28] ppc/spapr_caps: Don't disable cap_cfpc on POWER8 by default
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
  2018-06-18  3:52 ` [Qemu-devel] [PULL 01/28] target/ppc: Don't require private l1d cache on POWER8 for cap_ppc_safe_cache David Gibson
@ 2018-06-18  3:52 ` David Gibson
  2018-06-18  3:52 ` [Qemu-devel] [PULL 03/28] target/ppc: drop empty #if/#endif block David Gibson
                   ` (26 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:52 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik,
	Suraj Jitindar Singh, David Gibson

From: Suraj Jitindar Singh <sjitindarsingh@gmail.com>

In default_caps_with_cpu() we set spapr_cap_cfpc to broken for POWER8
processors and before.

Since we no longer require private l1d cache on POWER8 for this cap to
be set to workaround change this to default to broken for POWER7
processors and before.

Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_caps.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
index 531e145114..00e43a9ba7 100644
--- a/hw/ppc/spapr_caps.c
+++ b/hw/ppc/spapr_caps.c
@@ -335,14 +335,10 @@ static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr,
 
     caps = smc->default_caps;
 
-    if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00,
-                          0, spapr->max_compat_pvr)) {
-        caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
-    }
-
     if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07,
                           0, spapr->max_compat_pvr)) {
         caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
+        caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
     }
 
     if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06_PLUS,
-- 
2.17.1

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

* [Qemu-devel] [PULL 03/28] target/ppc: drop empty #if/#endif block
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
  2018-06-18  3:52 ` [Qemu-devel] [PULL 01/28] target/ppc: Don't require private l1d cache on POWER8 for cap_ppc_safe_cache David Gibson
  2018-06-18  3:52 ` [Qemu-devel] [PULL 02/28] ppc/spapr_caps: Don't disable cap_cfpc on POWER8 by default David Gibson
@ 2018-06-18  3:52 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 04/28] spapr: fix leak in h_client_architecture_support() David Gibson
                   ` (25 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:52 UTC (permalink / raw)
  To: peter.maydell; +Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, David Gibson

From: Greg Kurz <groug@kaod.org>

Commit 9d6f106552fa moved the last line in this block to somewhere else,
but it forgot to remove the now useless #if/#endif.

Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 target/ppc/cpu.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 0247c1f04c..a91f1a8777 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1300,8 +1300,6 @@ void ppc_store_ptcr(CPUPPCState *env, target_ulong value);
 void ppc_store_msr (CPUPPCState *env, target_ulong value);
 
 void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf);
-#if defined(TARGET_PPC64)
-#endif
 
 /* Time-base and decrementer management */
 #ifndef NO_CPU_IO_DEFS
-- 
2.17.1

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

* [Qemu-devel] [PULL 04/28] spapr: fix leak in h_client_architecture_support()
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (2 preceding siblings ...)
  2018-06-18  3:52 ` [Qemu-devel] [PULL 03/28] target/ppc: drop empty #if/#endif block David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 05/28] ppc: introduce Core99MachinesState for the mac99 machine David Gibson
                   ` (24 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell; +Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, David Gibson

From: Greg Kurz <groug@kaod.org>

If the negotiated compat mode can't be set, but raw mode is supported,
we decide to ignore the error. An so, we should free it to prevent a
memory leak.

Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_hcall.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 022f6d8101..8b9a4b577f 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -1547,6 +1547,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
                 error_report_err(local_err);
                 return H_HARDWARE;
             }
+            error_free(local_err);
             local_err = NULL;
         }
     }
-- 
2.17.1

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

* [Qemu-devel] [PULL 05/28] ppc: introduce Core99MachinesState for the mac99 machine
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (3 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 04/28] spapr: fix leak in h_client_architecture_support() David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 06/28] mac_newworld: add via machine option to control mac99 VIA/ADB configuration David Gibson
                   ` (23 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, Mark Cave-Ayland,
	David Gibson

From: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>

This is in preparation for adding configuration controlled via machine
options.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/mac.h          | 11 +++++++++++
 hw/ppc/mac_newworld.c |  7 +++++++
 2 files changed, 18 insertions(+)

diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h
index 89fa8bbed7..8046cd8a2f 100644
--- a/hw/ppc/mac.h
+++ b/hw/ppc/mac.h
@@ -27,6 +27,7 @@
 #define PPC_MAC_H
 
 #include "exec/memory.h"
+#include "hw/boards.h"
 #include "hw/sysbus.h"
 #include "hw/ide/internal.h"
 #include "hw/input/adb.h"
@@ -65,6 +66,16 @@
 #define NEWWORLD_IDE1_IRQ      0xe
 #define NEWWORLD_IDE1_DMA_IRQ  0x3
 
+/* Core99 machine */
+#define TYPE_CORE99_MACHINE MACHINE_TYPE_NAME("mac99")
+#define CORE99_MACHINE(obj) OBJECT_CHECK(Core99MachineState, (obj), \
+                                         TYPE_CORE99_MACHINE)
+
+typedef struct Core99MachineState {
+    /*< private >*/
+    MachineState parent;
+} Core99MachineState;
+
 /* MacIO */
 #define TYPE_MACIO_IDE "macio-ide"
 #define MACIO_IDE(obj) OBJECT_CHECK(MACIOIDEState, (obj), TYPE_MACIO_IDE)
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index 744acdfd2e..5331aa002c 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -515,10 +515,17 @@ static void core99_machine_class_init(ObjectClass *oc, void *data)
 #endif
 }
 
+static void core99_instance_init(Object *obj)
+{
+    return;
+}
+
 static const TypeInfo core99_machine_info = {
     .name          = MACHINE_TYPE_NAME("mac99"),
     .parent        = TYPE_MACHINE,
     .class_init    = core99_machine_class_init,
+    .instance_init = core99_instance_init,
+    .instance_size = sizeof(Core99MachineState)
 };
 
 static void mac_machine_register_types(void)
-- 
2.17.1

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

* [Qemu-devel] [PULL 06/28] mac_newworld: add via machine option to control mac99 VIA/ADB configuration
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (4 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 05/28] ppc: introduce Core99MachinesState for the mac99 machine David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 07/28] mac_newworld: add gpios to macio devices with PMU enabled David Gibson
                   ` (22 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, Mark Cave-Ayland,
	David Gibson

From: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>

This option allows the VIA configuration to be controlled between 3
different possible setups: cuda, pmu-adb and pmu with USB rather than ADB
keyboard/mouse.

For the moment we don't do anything with the configuration except to pass
it to the macio device (the via-cuda parent) and also to the firmware via
the fw_cfg interface so that it can present the correct device tree.

The default is cuda which is the current default and so will have no
change in behaviour.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/misc/macio/macio.c         |  7 ++++
 hw/ppc/mac.h                  |  6 +++
 hw/ppc/mac_newworld.c         | 69 +++++++++++++++++++++++++++++++----
 include/hw/misc/macio/macio.h |  2 +
 include/hw/ppc/ppc.h          |  1 +
 5 files changed, 78 insertions(+), 7 deletions(-)

diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c
index f9a40eea81..dddf743bcb 100644
--- a/hw/misc/macio/macio.c
+++ b/hw/misc/macio/macio.c
@@ -399,6 +399,12 @@ static const VMStateDescription vmstate_macio_newworld = {
     }
 };
 
+static Property macio_newworld_properties[] = {
+    DEFINE_PROP_BOOL("has-pmu", NewWorldMacIOState, has_pmu, false),
+    DEFINE_PROP_BOOL("has-adb", NewWorldMacIOState, has_adb, false),
+    DEFINE_PROP_END_OF_LIST()
+};
+
 static void macio_newworld_class_init(ObjectClass *oc, void *data)
 {
     PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
@@ -407,6 +413,7 @@ static void macio_newworld_class_init(ObjectClass *oc, void *data)
     pdc->realize = macio_newworld_realize;
     pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL;
     dc->vmsd = &vmstate_macio_newworld;
+    dc->props = macio_newworld_properties;
 }
 
 static Property macio_properties[] = {
diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h
index 8046cd8a2f..4c08f52b87 100644
--- a/hw/ppc/mac.h
+++ b/hw/ppc/mac.h
@@ -71,9 +71,15 @@
 #define CORE99_MACHINE(obj) OBJECT_CHECK(Core99MachineState, (obj), \
                                          TYPE_CORE99_MACHINE)
 
+#define CORE99_VIA_CONFIG_CUDA     0x0
+#define CORE99_VIA_CONFIG_PMU      0x1
+#define CORE99_VIA_CONFIG_PMU_ADB  0x2
+
 typedef struct Core99MachineState {
     /*< private >*/
     MachineState parent;
+
+    uint8_t via_config;
 } Core99MachineState;
 
 /* MacIO */
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index 5331aa002c..ca21d47234 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -111,6 +111,7 @@ static void ppc_core99_init(MachineState *machine)
     const char *kernel_cmdline = machine->kernel_cmdline;
     const char *initrd_filename = machine->initrd_filename;
     const char *boot_device = machine->boot_order;
+    Core99MachineState *core99_machine = CORE99_MACHINE(machine);
     PowerPCCPU *cpu = NULL;
     CPUPPCState *env = NULL;
     char *filename;
@@ -122,6 +123,7 @@ static void ppc_core99_init(MachineState *machine)
     UNINHostState *uninorth_pci;
     PCIBus *pci_bus;
     NewWorldMacIOState *macio;
+    bool has_pmu, has_adb;
     MACIOIDEState *macio_ide;
     BusState *adb_bus;
     MacIONVRAMState *nvr;
@@ -361,6 +363,9 @@ static void ppc_core99_init(MachineState *machine)
     }
 
     machine->usb |= defaults_enabled() && !machine->usb_disabled;
+    has_pmu = (core99_machine->via_config != CORE99_VIA_CONFIG_CUDA);
+    has_adb = (core99_machine->via_config == CORE99_VIA_CONFIG_CUDA ||
+               core99_machine->via_config == CORE99_VIA_CONFIG_PMU_ADB);
 
     /* Timebase Frequency */
     if (kvm_enabled()) {
@@ -376,6 +381,8 @@ static void ppc_core99_init(MachineState *machine)
     macio = NEWWORLD_MACIO(pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO));
     dev = DEVICE(macio);
     qdev_prop_set_uint64(dev, "frequency", tbfreq);
+    qdev_prop_set_bit(dev, "has-pmu", has_pmu);
+    qdev_prop_set_bit(dev, "has-adb", has_adb);
     object_property_set_link(OBJECT(macio), OBJECT(pic_dev), "pic",
                              &error_abort);
     qdev_init_nofail(dev);
@@ -391,19 +398,21 @@ static void ppc_core99_init(MachineState *machine)
                                                         "ide[1]"));
     macio_ide_init_drives(macio_ide, &hd[MAX_IDE_DEVS]);
 
-    dev = DEVICE(object_resolve_path_component(OBJECT(macio), "cuda"));
-    adb_bus = qdev_get_child_bus(dev, "adb.0");
-    dev = qdev_create(adb_bus, TYPE_ADB_KEYBOARD);
-    qdev_init_nofail(dev);
-    dev = qdev_create(adb_bus, TYPE_ADB_MOUSE);
-    qdev_init_nofail(dev);
+    if (has_adb) {
+        dev = DEVICE(object_resolve_path_component(OBJECT(macio), "cuda"));
+        adb_bus = qdev_get_child_bus(dev, "adb.0");
+        dev = qdev_create(adb_bus, TYPE_ADB_KEYBOARD);
+        qdev_init_nofail(dev);
+        dev = qdev_create(adb_bus, TYPE_ADB_MOUSE);
+        qdev_init_nofail(dev);
+    }
 
     if (machine->usb) {
         pci_create_simple(pci_bus, -1, "pci-ohci");
 
         /* U3 needs to use USB for input because Linux doesn't support via-cuda
         on PPC64 */
-        if (machine_arch == ARCH_MAC99_U3) {
+        if (!has_adb || machine_arch == ARCH_MAC99_U3) {
             USBBus *usb_bus = usb_bus_find(-1);
 
             usb_create_simple(usb_bus, "usb-kbd");
@@ -459,6 +468,8 @@ static void ppc_core99_init(MachineState *machine)
     fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);
     fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);
 
+    fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_VIACONFIG, core99_machine->via_config);
+
     fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled());
     if (kvm_enabled()) {
 #ifdef CONFIG_KVM
@@ -515,8 +526,52 @@ static void core99_machine_class_init(ObjectClass *oc, void *data)
 #endif
 }
 
+static char *core99_get_via_config(Object *obj, Error **errp)
+{
+    Core99MachineState *cms = CORE99_MACHINE(obj);
+
+    switch (cms->via_config) {
+    default:
+    case CORE99_VIA_CONFIG_CUDA:
+        return g_strdup("cuda");
+
+    case CORE99_VIA_CONFIG_PMU:
+        return g_strdup("pmu");
+
+    case CORE99_VIA_CONFIG_PMU_ADB:
+        return g_strdup("pmu-adb");
+    }
+}
+
+static void core99_set_via_config(Object *obj, const char *value, Error **errp)
+{
+    Core99MachineState *cms = CORE99_MACHINE(obj);
+
+    if (!strcmp(value, "cuda")) {
+        cms->via_config = CORE99_VIA_CONFIG_CUDA;
+    } else if (!strcmp(value, "pmu")) {
+        cms->via_config = CORE99_VIA_CONFIG_PMU;
+    } else if (!strcmp(value, "pmu-adb")) {
+        cms->via_config = CORE99_VIA_CONFIG_PMU_ADB;
+    } else {
+        error_setg(errp, "Invalid via value");
+        error_append_hint(errp, "Valid values are cuda, pmu, pmu-adb.\n");
+    }
+}
+
 static void core99_instance_init(Object *obj)
 {
+    Core99MachineState *cms = CORE99_MACHINE(obj);
+
+    /* Default via_config is CORE99_VIA_CONFIG_CUDA */
+    cms->via_config = CORE99_VIA_CONFIG_CUDA;
+    object_property_add_str(obj, "via", core99_get_via_config,
+                            core99_set_via_config, NULL);
+    object_property_set_description(obj, "via",
+                                    "Set VIA configuration. "
+                                    "Valid values are cuda, pmu and pmu-adb",
+                                    NULL);
+
     return;
 }
 
diff --git a/include/hw/misc/macio/macio.h b/include/hw/misc/macio/macio.h
index 838eaf1db0..9529073ba8 100644
--- a/include/hw/misc/macio/macio.h
+++ b/include/hw/misc/macio/macio.h
@@ -70,6 +70,8 @@ typedef struct NewWorldMacIOState {
     MacIOState parent_obj;
     /*< public >*/
 
+    bool has_pmu;
+    bool has_adb;
     OpenPICState *pic;
     MACIOIDEState ide[2];
 } NewWorldMacIOState;
diff --git a/include/hw/ppc/ppc.h b/include/hw/ppc/ppc.h
index b18ef3eefb..298ec354a8 100644
--- a/include/hw/ppc/ppc.h
+++ b/include/hw/ppc/ppc.h
@@ -101,6 +101,7 @@ enum {
 #define FW_CFG_PPC_NVRAM_ADDR   (FW_CFG_ARCH_LOCAL + 0x08)
 #define FW_CFG_PPC_BUSFREQ      (FW_CFG_ARCH_LOCAL + 0x09)
 #define FW_CFG_PPC_NVRAM_FLAT   (FW_CFG_ARCH_LOCAL + 0x0a)
+#define FW_CFG_PPC_VIACONFIG    (FW_CFG_ARCH_LOCAL + 0x0b)
 
 #define PPC_SERIAL_MM_BAUDBASE 399193
 
-- 
2.17.1

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

* [Qemu-devel] [PULL 07/28] mac_newworld: add gpios to macio devices with PMU enabled
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (5 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 06/28] mac_newworld: add via machine option to control mac99 VIA/ADB configuration David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 08/28] mac_newworld: wire up programmer switch to NMI handler David Gibson
                   ` (21 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, Mark Cave-Ayland,
	David Gibson

From: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>

PMU-enabled New World Macs expose their GPIOs via a separate memory region
within the macio device.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 default-configs/ppc-softmmu.mak |   1 +
 hw/misc/macio/Makefile.objs     |   1 +
 hw/misc/macio/gpio.c            | 218 ++++++++++++++++++++++++++++++++
 hw/misc/macio/macio.c           |  13 ++
 hw/misc/macio/trace-events      |   7 +
 hw/ppc/mac.h                    |   2 +
 include/hw/misc/macio/gpio.h    |  47 +++++++
 include/hw/misc/macio/macio.h   |   3 +
 8 files changed, 292 insertions(+)
 create mode 100644 hw/misc/macio/gpio.c
 create mode 100644 include/hw/misc/macio/gpio.h

diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index 4d7be45ac5..38197e39eb 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -31,6 +31,7 @@ CONFIG_I2C=y
 CONFIG_MAC=y
 CONFIG_ESCC=y
 CONFIG_MACIO=y
+CONFIG_MACIO_GPIO=y
 CONFIG_SUNGEM=y
 CONFIG_MOS6522=y
 CONFIG_CUDA=y
diff --git a/hw/misc/macio/Makefile.objs b/hw/misc/macio/Makefile.objs
index ef7ac249ec..fb9dbf91b5 100644
--- a/hw/misc/macio/Makefile.objs
+++ b/hw/misc/macio/Makefile.objs
@@ -1,3 +1,4 @@
 common-obj-y += macio.o
 common-obj-$(CONFIG_CUDA) += cuda.o
 common-obj-$(CONFIG_MAC_DBDMA) += mac_dbdma.o
+common-obj-$(CONFIG_MACIO_GPIO) += gpio.o
diff --git a/hw/misc/macio/gpio.c b/hw/misc/macio/gpio.c
new file mode 100644
index 0000000000..5630afdf18
--- /dev/null
+++ b/hw/misc/macio/gpio.c
@@ -0,0 +1,218 @@
+/*
+ * PowerMac NewWorld MacIO GPIO emulation
+ *
+ * Copyright (c) 2016 Benjamin Herrenschmidt
+ * Copyright (c) 2018 Mark Cave-Ayland
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/hw.h"
+#include "hw/ppc/mac.h"
+#include "hw/misc/macio/macio.h"
+#include "hw/misc/macio/gpio.h"
+#include "qemu/log.h"
+#include "trace.h"
+
+
+void macio_set_gpio(MacIOGPIOState *s, uint32_t gpio, bool state)
+{
+    uint8_t new_reg;
+
+    trace_macio_set_gpio(gpio, state);
+
+    if (s->gpio_regs[gpio] & 4) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "GPIO: Setting GPIO %d while it's an output\n", gpio);
+    }
+
+    new_reg = s->gpio_regs[gpio] & ~2;
+    if (state) {
+        new_reg |= 2;
+    }
+
+    if (new_reg == s->gpio_regs[gpio]) {
+        return;
+    }
+
+    s->gpio_regs[gpio] = new_reg;
+
+    /* This is will work until we fix the binding between MacIO and
+     * the MPIC properly so we can route all GPIOs and avoid going
+     * via the top level platform code.
+     *
+     * Note that we probably need to get access to the MPIC config to
+     * decode polarity since qemu always use "raise" regardless.
+     *
+     * For now, we hard wire known GPIOs
+     */
+
+    switch (gpio) {
+    case 1:
+        /* Level low */
+        if (!state) {
+            trace_macio_gpio_irq_assert(gpio);
+            qemu_irq_raise(s->gpio_extirqs[gpio]);
+        } else {
+            trace_macio_gpio_irq_deassert(gpio);
+            qemu_irq_lower(s->gpio_extirqs[gpio]);
+        }
+        break;
+
+    case 9:
+        /* Edge, triggered by NMI below */
+        if (state) {
+            trace_macio_gpio_irq_assert(gpio);
+            qemu_irq_raise(s->gpio_extirqs[gpio]);
+        } else {
+            trace_macio_gpio_irq_deassert(gpio);
+            qemu_irq_lower(s->gpio_extirqs[gpio]);
+        }
+        break;
+
+    default:
+        qemu_log_mask(LOG_UNIMP, "GPIO: setting unimplemented GPIO %d", gpio);
+    }
+}
+
+static void macio_gpio_write(void *opaque, hwaddr addr, uint64_t value,
+                             unsigned size)
+{
+    MacIOGPIOState *s = opaque;
+    uint8_t ibit;
+
+    trace_macio_gpio_write(addr, value);
+
+    /* Levels regs are read-only */
+    if (addr < 8) {
+        return;
+    }
+
+    addr -= 8;
+    if (addr < 36) {
+        value &= ~2;
+
+        if (value & 4) {
+            ibit = (value & 1) << 1;
+        } else {
+            ibit = s->gpio_regs[addr] & 2;
+        }
+
+        s->gpio_regs[addr] = value | ibit;
+    }
+}
+
+static uint64_t macio_gpio_read(void *opaque, hwaddr addr, unsigned size)
+{
+    MacIOGPIOState *s = opaque;
+    uint64_t val = 0;
+
+    /* Levels regs */
+    if (addr < 8) {
+        val = s->gpio_levels[addr];
+    } else {
+        addr -= 8;
+
+        if (addr < 36) {
+            val = s->gpio_regs[addr];
+        }
+    }
+
+    trace_macio_gpio_write(addr, val);
+    return val;
+}
+
+static const MemoryRegionOps macio_gpio_ops = {
+    .read = macio_gpio_read,
+    .write = macio_gpio_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static void macio_gpio_realize(DeviceState *dev, Error **errp)
+{
+    MacIOGPIOState *s = MACIO_GPIO(dev);
+
+    s->gpio_extirqs[1] = qdev_get_gpio_in(DEVICE(s->pic),
+                                          NEWWORLD_EXTING_GPIO1);
+    s->gpio_extirqs[9] = qdev_get_gpio_in(DEVICE(s->pic),
+                                          NEWWORLD_EXTING_GPIO9);
+}
+
+static void macio_gpio_init(Object *obj)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    MacIOGPIOState *s = MACIO_GPIO(obj);
+
+    object_property_add_link(obj, "pic", TYPE_OPENPIC,
+                             (Object **) &s->pic,
+                             qdev_prop_allow_set_link_before_realize,
+                             0, NULL);
+
+    memory_region_init_io(&s->gpiomem, OBJECT(s), &macio_gpio_ops, obj,
+                          "gpio", 0x30);
+    sysbus_init_mmio(sbd, &s->gpiomem);
+}
+
+static const VMStateDescription vmstate_macio_gpio = {
+    .name = "macio_gpio",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8_ARRAY(gpio_levels, MacIOGPIOState, 8),
+        VMSTATE_UINT8_ARRAY(gpio_regs, MacIOGPIOState, 36),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void macio_gpio_reset(DeviceState *dev)
+{
+    MacIOGPIOState *s = MACIO_GPIO(dev);
+
+    /* GPIO 1 is up by default */
+    macio_set_gpio(s, 1, true);
+}
+
+static void macio_gpio_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = macio_gpio_realize;
+    dc->reset = macio_gpio_reset;
+    dc->vmsd = &vmstate_macio_gpio;
+}
+
+static const TypeInfo macio_gpio_init_info = {
+    .name          = TYPE_MACIO_GPIO,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MacIOGPIOState),
+    .instance_init = macio_gpio_init,
+    .class_init    = macio_gpio_class_init,
+};
+
+static void macio_gpio_register_types(void)
+{
+    type_register_static(&macio_gpio_init_info);
+}
+
+type_init(macio_gpio_register_types)
diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c
index dddf743bcb..8dfcbc3d9b 100644
--- a/hw/misc/macio/macio.c
+++ b/hw/misc/macio/macio.c
@@ -332,6 +332,16 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp)
     memory_region_init_io(timer_memory, OBJECT(s), &timer_ops, NULL, "timer",
                           0x1000);
     memory_region_add_subregion(&s->bar, 0x15000, timer_memory);
+
+    if (ns->has_pmu) {
+        /* GPIOs */
+        sysbus_dev = SYS_BUS_DEVICE(&ns->gpio);
+        object_property_set_link(OBJECT(&ns->gpio), OBJECT(pic_dev), "pic",
+                                 &error_abort);
+        memory_region_add_subregion(&s->bar, 0x50,
+                                    sysbus_mmio_get_region(sysbus_dev, 0));
+        object_property_set_bool(OBJECT(&ns->gpio), true, "realized", &err);
+    }
 }
 
 static void macio_newworld_init(Object *obj)
@@ -345,6 +355,9 @@ static void macio_newworld_init(Object *obj)
                              qdev_prop_allow_set_link_before_realize,
                              0, NULL);
 
+    object_initialize(&ns->gpio, sizeof(ns->gpio), TYPE_MACIO_GPIO);
+    qdev_set_parent_bus(DEVICE(&ns->gpio), sysbus_get_default());
+
     for (i = 0; i < 2; i++) {
         macio_init_ide(s, &ns->ide[i], sizeof(ns->ide[i]), i);
     }
diff --git a/hw/misc/macio/trace-events b/hw/misc/macio/trace-events
index d499d78c99..71c47520eb 100644
--- a/hw/misc/macio/trace-events
+++ b/hw/misc/macio/trace-events
@@ -13,3 +13,10 @@ cuda_packet_send_data(int i, const uint8_t data) "[%d] 0x%02x"
 # hw/misc/macio/macio.c
 macio_timer_write(uint64_t addr, unsigned len, uint64_t val) "write addr 0x%"PRIx64 " len %d val 0x%"PRIx64
 macio_timer_read(uint64_t addr, unsigned len, uint32_t val) "read addr 0x%"PRIx64 " len %d val 0x%"PRIx32
+
+# hw/misc/macio/gpio.c
+macio_set_gpio(int gpio, bool state) "setting GPIO %d to %d"
+macio_gpio_irq_assert(int gpio) "asserting GPIO %d"
+macio_gpio_irq_deassert(int gpio) "deasserting GPIO %d"
+macio_gpio_write(uint64_t addr, uint64_t val) "addr: 0x%"PRIx64" value: 0x%"PRIx64
+macio_gpio_read(uint64_t addr, uint64_t val) "addr: 0x%"PRIx64" value: 0x%"PRIx64
diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h
index 4c08f52b87..b3b7f9d8ae 100644
--- a/hw/ppc/mac.h
+++ b/hw/ppc/mac.h
@@ -65,6 +65,8 @@
 #define NEWWORLD_IDE0_DMA_IRQ  0x2
 #define NEWWORLD_IDE1_IRQ      0xe
 #define NEWWORLD_IDE1_DMA_IRQ  0x3
+#define NEWWORLD_EXTING_GPIO1  0x2f
+#define NEWWORLD_EXTING_GPIO9  0x37
 
 /* Core99 machine */
 #define TYPE_CORE99_MACHINE MACHINE_TYPE_NAME("mac99")
diff --git a/include/hw/misc/macio/gpio.h b/include/hw/misc/macio/gpio.h
new file mode 100644
index 0000000000..2838ae5fde
--- /dev/null
+++ b/include/hw/misc/macio/gpio.h
@@ -0,0 +1,47 @@
+/*
+ * PowerMac NewWorld MacIO GPIO emulation
+ *
+ * Copyright (c) 2016 Benjamin Herrenschmidt
+ * Copyright (c) 2018 Mark Cave-Ayland
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MACIO_GPIO_H
+#define MACIO_GPIO_H
+
+#define TYPE_MACIO_GPIO "macio-gpio"
+#define MACIO_GPIO(obj) OBJECT_CHECK(MacIOGPIOState, (obj), TYPE_MACIO_GPIO)
+
+typedef struct MacIOGPIOState {
+    /*< private >*/
+    SysBusDevice parent;
+    /*< public >*/
+
+    OpenPICState *pic;
+
+    MemoryRegion gpiomem;
+    qemu_irq gpio_extirqs[10];
+    uint8_t gpio_levels[8];
+    uint8_t gpio_regs[36]; /* XXX Check count */
+} MacIOGPIOState;
+
+void macio_set_gpio(MacIOGPIOState *s, uint32_t gpio, bool state);
+
+#endif
diff --git a/include/hw/misc/macio/macio.h b/include/hw/misc/macio/macio.h
index 9529073ba8..d43883a893 100644
--- a/include/hw/misc/macio/macio.h
+++ b/include/hw/misc/macio/macio.h
@@ -26,8 +26,10 @@
 #ifndef MACIO_H
 #define MACIO_H
 
+#include "hw/char/escc.h"
 #include "hw/intc/heathrow_pic.h"
 #include "hw/misc/macio/cuda.h"
+#include "hw/misc/macio/gpio.h"
 #include "hw/ppc/mac_dbdma.h"
 #include "hw/ppc/openpic.h"
 
@@ -74,6 +76,7 @@ typedef struct NewWorldMacIOState {
     bool has_adb;
     OpenPICState *pic;
     MACIOIDEState ide[2];
+    MacIOGPIOState gpio;
 } NewWorldMacIOState;
 
 #endif /* MACIO_H */
-- 
2.17.1

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

* [Qemu-devel] [PULL 08/28] mac_newworld: wire up programmer switch to NMI handler
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (6 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 07/28] mac_newworld: add gpios to macio devices with PMU enabled David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 09/28] adb: fix read reg 3 byte ordering David Gibson
                   ` (20 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, Mark Cave-Ayland,
	David Gibson

From: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>

The programmer switch is wired up via an external GPIO pin and can be used
to aid debugging Mac guests.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/misc/macio/gpio.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/hw/misc/macio/gpio.c b/hw/misc/macio/gpio.c
index 5630afdf18..9317df759c 100644
--- a/hw/misc/macio/gpio.c
+++ b/hw/misc/macio/gpio.c
@@ -28,6 +28,7 @@
 #include "hw/ppc/mac.h"
 #include "hw/misc/macio/macio.h"
 #include "hw/misc/macio/gpio.h"
+#include "hw/nmi.h"
 #include "qemu/log.h"
 #include "trace.h"
 
@@ -193,13 +194,21 @@ static void macio_gpio_reset(DeviceState *dev)
     macio_set_gpio(s, 1, true);
 }
 
+static void macio_gpio_nmi(NMIState *n, int cpu_index, Error **errp)
+{
+    macio_set_gpio(MACIO_GPIO(n), 9, true);
+    macio_set_gpio(MACIO_GPIO(n), 9, false);
+}
+
 static void macio_gpio_class_init(ObjectClass *oc, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
+    NMIClass *nc = NMI_CLASS(oc);
 
     dc->realize = macio_gpio_realize;
     dc->reset = macio_gpio_reset;
     dc->vmsd = &vmstate_macio_gpio;
+    nc->nmi_monitor_handler = macio_gpio_nmi;
 }
 
 static const TypeInfo macio_gpio_init_info = {
@@ -208,6 +217,10 @@ static const TypeInfo macio_gpio_init_info = {
     .instance_size = sizeof(MacIOGPIOState),
     .instance_init = macio_gpio_init,
     .class_init    = macio_gpio_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_NMI },
+        { }
+    },
 };
 
 static void macio_gpio_register_types(void)
-- 
2.17.1

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

* [Qemu-devel] [PULL 09/28] adb: fix read reg 3 byte ordering
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (7 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 08/28] mac_newworld: wire up programmer switch to NMI handler David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 10/28] adb: add property to disable direct reg 3 writes David Gibson
                   ` (19 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, Mark Cave-Ayland,
	David Gibson

From: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>

According to the Apple ADB documentation, register 3 is a 2-byte register
with the device address in the first byte, and the handler ID in the second
byte.

This is currently the opposite away to which QEMU returns them so switch the
order around.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/input/adb-kbd.c   | 4 ++--
 hw/input/adb-mouse.c | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c
index 50b62712c8..0ad384dc89 100644
--- a/hw/input/adb-kbd.c
+++ b/hw/input/adb-kbd.c
@@ -290,8 +290,8 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
             olen = 2;
             break;
         case 3:
-            obuf[0] = d->handler;
-            obuf[1] = d->devaddr;
+            obuf[0] = d->devaddr;
+            obuf[1] = d->handler;
             olen = 2;
             break;
         }
diff --git a/hw/input/adb-mouse.c b/hw/input/adb-mouse.c
index 3ba6027d33..473045fbac 100644
--- a/hw/input/adb-mouse.c
+++ b/hw/input/adb-mouse.c
@@ -172,8 +172,8 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
         case 1:
             break;
         case 3:
-            obuf[0] = d->handler;
-            obuf[1] = d->devaddr;
+            obuf[0] = d->devaddr;
+            obuf[1] = d->handler;
             olen = 2;
             break;
         }
-- 
2.17.1

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

* [Qemu-devel] [PULL 10/28] adb: add property to disable direct reg 3 writes
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (8 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 09/28] adb: fix read reg 3 byte ordering David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 11/28] mac_newworld: add PMU device David Gibson
                   ` (18 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, Mark Cave-Ayland,
	David Gibson

From: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>

MacOS 9 has a bug in its PMU driver whereby after configuring the ADB bus
devices it sends another write to reg 3 on both devices resetting them
both back to the same address.

Add a new disable_direct_reg3_writes property to ADBDevice to disable these
direct writes which can enabled just for the upcoming pmu-adb support.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/input/adb-kbd.c     | 25 ++++++++++++++-----------
 hw/input/adb-mouse.c   | 37 ++++++++++++++++++++-----------------
 hw/input/adb.c         |  7 +++++++
 include/hw/input/adb.h |  1 +
 4 files changed, 42 insertions(+), 28 deletions(-)

diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c
index 0ad384dc89..b026e9d49f 100644
--- a/hw/input/adb-kbd.c
+++ b/hw/input/adb-kbd.c
@@ -261,18 +261,21 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
                 trace_adb_kbd_request_change_addr(d->devaddr);
                 break;
             default:
-                d->devaddr = buf[1] & 0xf;
-                /* we support handlers:
-                 * 1: Apple Standard Keyboard
-                 * 2: Apple Extended Keyboard (LShift = RShift)
-                 * 3: Apple Extended Keyboard (LShift != RShift)
-                 */
-                if (buf[2] == 1 || buf[2] == 2 || buf[2] == 3) {
-                    d->handler = buf[2];
+                if (!d->disable_direct_reg3_writes) {
+                    d->devaddr = buf[1] & 0xf;
+
+                    /* we support handlers:
+                     * 1: Apple Standard Keyboard
+                     * 2: Apple Extended Keyboard (LShift = RShift)
+                     * 3: Apple Extended Keyboard (LShift != RShift)
+                     */
+                    if (buf[2] == 1 || buf[2] == 2 || buf[2] == 3) {
+                        d->handler = buf[2];
+                    }
+
+                    trace_adb_kbd_request_change_addr_and_handler(d->devaddr,
+                                                                  d->handler);
                 }
-
-                trace_adb_kbd_request_change_addr_and_handler(d->devaddr,
-                                                              d->handler);
                 break;
             }
         }
diff --git a/hw/input/adb-mouse.c b/hw/input/adb-mouse.c
index 473045fbac..83833b0035 100644
--- a/hw/input/adb-mouse.c
+++ b/hw/input/adb-mouse.c
@@ -142,24 +142,27 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
                 trace_adb_mouse_request_change_addr(d->devaddr);
                 break;
             default:
-                d->devaddr = buf[1] & 0xf;
-                /* we support handlers:
-                 * 0x01: Classic Apple Mouse Protocol / 100 cpi operations
-                 * 0x02: Classic Apple Mouse Protocol / 200 cpi operations
-                 * we don't support handlers (at least):
-                 * 0x03: Mouse systems A3 trackball
-                 * 0x04: Extended Apple Mouse Protocol
-                 * 0x2f: Microspeed mouse
-                 * 0x42: Macally
-                 * 0x5f: Microspeed mouse
-                 * 0x66: Microspeed mouse
-                 */
-                if (buf[2] == 1 || buf[2] == 2) {
-                    d->handler = buf[2];
+                if (!d->disable_direct_reg3_writes) {
+                    d->devaddr = buf[1] & 0xf;
+
+                    /* we support handlers:
+                     * 0x01: Classic Apple Mouse Protocol / 100 cpi operations
+                     * 0x02: Classic Apple Mouse Protocol / 200 cpi operations
+                     * we don't support handlers (at least):
+                     * 0x03: Mouse systems A3 trackball
+                     * 0x04: Extended Apple Mouse Protocol
+                     * 0x2f: Microspeed mouse
+                     * 0x42: Macally
+                     * 0x5f: Microspeed mouse
+                     * 0x66: Microspeed mouse
+                     */
+                    if (buf[2] == 1 || buf[2] == 2) {
+                        d->handler = buf[2];
+                    }
+
+                    trace_adb_mouse_request_change_addr_and_handler(
+                        d->devaddr, d->handler);
                 }
-
-                trace_adb_mouse_request_change_addr_and_handler(d->devaddr,
-                                                                d->handler);
                 break;
             }
         }
diff --git a/hw/input/adb.c b/hw/input/adb.c
index 23ae6f0d75..bbb40aeef1 100644
--- a/hw/input/adb.c
+++ b/hw/input/adb.c
@@ -113,11 +113,18 @@ static void adb_device_realizefn(DeviceState *dev, Error **errp)
     bus->devices[bus->nb_devices++] = d;
 }
 
+static Property adb_device_properties[] = {
+    DEFINE_PROP_BOOL("disable-direct-reg3-writes", ADBDevice,
+                     disable_direct_reg3_writes, false),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
 static void adb_device_class_init(ObjectClass *oc, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
 
     dc->realize = adb_device_realizefn;
+    dc->props = adb_device_properties;
     dc->bus_type = TYPE_ADB_BUS;
 }
 
diff --git a/include/hw/input/adb.h b/include/hw/input/adb.h
index 3ae8445e95..f99d478252 100644
--- a/include/hw/input/adb.h
+++ b/include/hw/input/adb.h
@@ -49,6 +49,7 @@ struct ADBDevice {
 
     int devaddr;
     int handler;
+    bool disable_direct_reg3_writes;
 };
 
 #define ADB_DEVICE_CLASS(cls) \
-- 
2.17.1

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

* [Qemu-devel] [PULL 11/28] mac_newworld: add PMU device
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (9 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 10/28] adb: add property to disable direct reg 3 writes David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 12/28] xics_kvm: fix a build break David Gibson
                   ` (17 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, Mark Cave-Ayland,
	David Gibson

From: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>

The PMU device supercedes the CUDA device found on older New World Macs and
is supported by a larger number of guest OSs from OS 9 to OS X 10.5.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 default-configs/ppc-softmmu.mak |   1 +
 hw/misc/macio/Makefile.objs     |   1 +
 hw/misc/macio/macio.c           |  69 ++-
 hw/misc/macio/pmu.c             | 871 ++++++++++++++++++++++++++++++++
 hw/misc/macio/trace-events      |  21 +
 hw/ppc/mac.h                    |   1 +
 hw/ppc/mac_newworld.c           |  10 +-
 include/hw/misc/macio/macio.h   |   2 +
 include/hw/misc/macio/pmu.h     | 237 +++++++++
 9 files changed, 1193 insertions(+), 20 deletions(-)
 create mode 100644 hw/misc/macio/pmu.c
 create mode 100644 include/hw/misc/macio/pmu.h

diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index 38197e39eb..abeeb0418a 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -38,6 +38,7 @@ CONFIG_CUDA=y
 CONFIG_ADB=y
 CONFIG_MAC_NVRAM=y
 CONFIG_MAC_DBDMA=y
+CONFIG_MAC_PMU=y
 CONFIG_HEATHROW_PIC=y
 CONFIG_GRACKLE_PCI=y
 CONFIG_UNIN_PCI=y
diff --git a/hw/misc/macio/Makefile.objs b/hw/misc/macio/Makefile.objs
index fb9dbf91b5..07fdb320d4 100644
--- a/hw/misc/macio/Makefile.objs
+++ b/hw/misc/macio/Makefile.objs
@@ -1,4 +1,5 @@
 common-obj-y += macio.o
 common-obj-$(CONFIG_CUDA) += cuda.o
+common-obj-$(CONFIG_MAC_PMU) += pmu.o
 common-obj-$(CONFIG_MAC_DBDMA) += mac_dbdma.o
 common-obj-$(CONFIG_MACIO_GPIO) += gpio.o
diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c
index 8dfcbc3d9b..d135e3bc2b 100644
--- a/hw/misc/macio/macio.c
+++ b/hw/misc/macio/macio.c
@@ -105,17 +105,6 @@ static void macio_common_realize(PCIDevice *d, Error **errp)
     memory_region_add_subregion(&s->bar, 0x08000,
                                 sysbus_mmio_get_region(sysbus_dev, 0));
 
-    qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency",
-                         s->frequency);
-    object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err);
-    if (err) {
-        error_propagate(errp, err);
-        return;
-    }
-    sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
-    memory_region_add_subregion(&s->bar, 0x16000,
-                                sysbus_mmio_get_region(sysbus_dev, 0));
-
     qdev_prop_set_uint32(DEVICE(&s->escc), "disabled", 0);
     qdev_prop_set_uint32(DEVICE(&s->escc), "frequency", ESCC_CLOCK);
     qdev_prop_set_uint32(DEVICE(&s->escc), "it_shift", 4);
@@ -163,7 +152,16 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp)
         return;
     }
 
+    qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency",
+                         s->frequency);
+    object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
     sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
+    memory_region_add_subregion(&s->bar, 0x16000,
+                                sysbus_mmio_get_region(sysbus_dev, 0));
     sysbus_connect_irq(sysbus_dev, 0, qdev_get_gpio_in(pic_dev,
                                                        OLDWORLD_CUDA_IRQ));
 
@@ -234,6 +232,10 @@ static void macio_oldworld_init(Object *obj)
                              qdev_prop_allow_set_link_before_realize,
                              0, NULL);
 
+    object_initialize(&s->cuda, sizeof(s->cuda), TYPE_CUDA);
+    qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default());
+    object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL);
+
     object_initialize(&os->nvram, sizeof(os->nvram), TYPE_MACIO_NVRAM);
     dev = DEVICE(&os->nvram);
     qdev_prop_set_uint32(dev, "size", 0x2000);
@@ -293,10 +295,6 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp)
         return;
     }
 
-    sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
-    sysbus_connect_irq(sysbus_dev, 0, qdev_get_gpio_in(pic_dev,
-                                                       NEWWORLD_CUDA_IRQ));
-
     sysbus_dev = SYS_BUS_DEVICE(&s->escc);
     sysbus_connect_irq(sysbus_dev, 0, qdev_get_gpio_in(pic_dev,
                                                        NEWWORLD_ESCCB_IRQ));
@@ -341,6 +339,43 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp)
         memory_region_add_subregion(&s->bar, 0x50,
                                     sysbus_mmio_get_region(sysbus_dev, 0));
         object_property_set_bool(OBJECT(&ns->gpio), true, "realized", &err);
+
+        /* PMU */
+        object_initialize(&s->pmu, sizeof(s->pmu), TYPE_VIA_PMU);
+        object_property_set_link(OBJECT(&s->pmu), OBJECT(sysbus_dev), "gpio",
+                                 &error_abort);
+        qdev_prop_set_bit(DEVICE(&s->pmu), "has-adb", ns->has_adb);
+        qdev_set_parent_bus(DEVICE(&s->pmu), sysbus_get_default());
+        object_property_add_child(OBJECT(s), "pmu", OBJECT(&s->pmu), NULL);
+
+        object_property_set_bool(OBJECT(&s->pmu), true, "realized", &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+        sysbus_dev = SYS_BUS_DEVICE(&s->pmu);
+        sysbus_connect_irq(sysbus_dev, 0, qdev_get_gpio_in(pic_dev,
+                                                           NEWWORLD_PMU_IRQ));
+        memory_region_add_subregion(&s->bar, 0x16000,
+                                    sysbus_mmio_get_region(sysbus_dev, 0));
+    } else {
+        /* CUDA */
+        object_initialize(&s->cuda, sizeof(s->cuda), TYPE_CUDA);
+        qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default());
+        object_property_add_child(OBJECT(s), "cuda", OBJECT(&s->cuda), NULL);
+        qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency",
+                             s->frequency);
+
+        object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+        sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
+        sysbus_connect_irq(sysbus_dev, 0, qdev_get_gpio_in(pic_dev,
+                                                           NEWWORLD_CUDA_IRQ));
+        memory_region_add_subregion(&s->bar, 0x16000,
+                                    sysbus_mmio_get_region(sysbus_dev, 0));
     }
 }
 
@@ -369,10 +404,6 @@ static void macio_instance_init(Object *obj)
 
     memory_region_init(&s->bar, obj, "macio", 0x80000);
 
-    object_initialize(&s->cuda, sizeof(s->cuda), TYPE_CUDA);
-    qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default());
-    object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL);
-
     object_initialize(&s->dbdma, sizeof(s->dbdma), TYPE_MAC_DBDMA);
     qdev_set_parent_bus(DEVICE(&s->dbdma), sysbus_get_default());
     object_property_add_child(obj, "dbdma", OBJECT(&s->dbdma), NULL);
diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c
new file mode 100644
index 0000000000..e246b0fd41
--- /dev/null
+++ b/hw/misc/macio/pmu.c
@@ -0,0 +1,871 @@
+/*
+ * QEMU PowerMac PMU device support
+ *
+ * Copyright (c) 2016 Benjamin Herrenschmidt, IBM Corp.
+ * Copyright (c) 2018 Mark Cave-Ayland
+ *
+ * Based on the CUDA device by:
+ *
+ * Copyright (c) 2004-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/hw.h"
+#include "hw/ppc/mac.h"
+#include "hw/input/adb.h"
+#include "hw/misc/mos6522.h"
+#include "hw/misc/macio/gpio.h"
+#include "hw/misc/macio/pmu.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+#include "qemu/cutils.h"
+#include "qemu/log.h"
+#include "trace.h"
+
+
+/* Bits in B data register: all active low */
+#define TACK    0x08    /* Transfer request (input) */
+#define TREQ    0x10    /* Transfer acknowledge (output) */
+
+/* PMU returns time_t's offset from Jan 1, 1904, not 1970 */
+#define RTC_OFFSET                      2082844800
+
+#define VIA_TIMER_FREQ (4700000 / 6)
+
+static void via_update_irq(PMUState *s)
+{
+    MOS6522PMUState *mps = MOS6522_PMU(&s->mos6522_pmu);
+    MOS6522State *ms = MOS6522(mps);
+
+    bool new_state = !!(ms->ifr & ms->ier & (SR_INT | T1_INT | T2_INT));
+
+    if (new_state != s->via_irq_state) {
+        s->via_irq_state = new_state;
+        qemu_set_irq(s->via_irq, new_state);
+    }
+}
+
+static void via_set_sr_int(void *opaque)
+{
+    PMUState *s = opaque;
+    MOS6522PMUState *mps = MOS6522_PMU(&s->mos6522_pmu);
+    MOS6522State *ms = MOS6522(mps);
+    MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(ms);
+
+    mdc->set_sr_int(ms);
+}
+
+static void pmu_update_extirq(PMUState *s)
+{
+    if ((s->intbits & s->intmask) != 0) {
+        macio_set_gpio(s->gpio, 1, false);
+    } else {
+        macio_set_gpio(s->gpio, 1, true);
+    }
+}
+
+static void pmu_adb_poll(void *opaque)
+{
+    PMUState *s = opaque;
+    int olen;
+
+    if (!(s->intbits & PMU_INT_ADB)) {
+        olen = adb_poll(&s->adb_bus, s->adb_reply, s->adb_poll_mask);
+        trace_pmu_adb_poll(olen);
+
+        if (olen > 0) {
+            s->adb_reply_size = olen;
+            s->intbits |= PMU_INT_ADB | PMU_INT_ADB_AUTO;
+            pmu_update_extirq(s);
+        }
+    }
+
+    timer_mod(s->adb_poll_timer,
+              qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 30);
+}
+
+static void pmu_one_sec_timer(void *opaque)
+{
+    PMUState *s = opaque;
+
+    trace_pmu_one_sec_timer();
+
+    s->intbits |= PMU_INT_TICK;
+    pmu_update_extirq(s);
+    s->one_sec_target += 1000;
+
+    timer_mod(s->one_sec_timer, s->one_sec_target);
+}
+
+static void pmu_cmd_int_ack(PMUState *s,
+                            const uint8_t *in_data, uint8_t in_len,
+                            uint8_t *out_data, uint8_t *out_len)
+{
+    if (in_len != 0) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "PMU: INT_ACK command, invalid len: %d want: 0\n",
+                      in_len);
+        return;
+    }
+
+    /* Make appropriate reply packet */
+    if (s->intbits & PMU_INT_ADB) {
+        if (!s->adb_reply_size) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "Odd, PMU_INT_ADB set with no reply in buffer\n");
+        }
+
+        memcpy(out_data + 1, s->adb_reply, s->adb_reply_size);
+        out_data[0] = s->intbits & (PMU_INT_ADB | PMU_INT_ADB_AUTO);
+        *out_len = s->adb_reply_size + 1;
+        s->intbits &= ~(PMU_INT_ADB | PMU_INT_ADB_AUTO);
+        s->adb_reply_size = 0;
+    } else {
+        out_data[0] = s->intbits;
+        s->intbits = 0;
+        *out_len = 1;
+    }
+
+    pmu_update_extirq(s);
+}
+
+static void pmu_cmd_set_int_mask(PMUState *s,
+                                 const uint8_t *in_data, uint8_t in_len,
+                                 uint8_t *out_data, uint8_t *out_len)
+{
+    if (in_len != 1) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "PMU: SET_INT_MASK command, invalid len: %d want: 1\n",
+                      in_len);
+        return;
+    }
+
+    trace_pmu_cmd_set_int_mask(s->intmask);
+    s->intmask = in_data[0];
+
+    pmu_update_extirq(s);
+}
+
+static void pmu_cmd_set_adb_autopoll(PMUState *s, uint16_t mask)
+{
+    trace_pmu_cmd_set_adb_autopoll(mask);
+
+    if (s->autopoll_mask == mask) {
+        return;
+    }
+
+    s->autopoll_mask = mask;
+    if (mask) {
+        timer_mod(s->adb_poll_timer,
+                  qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 30);
+    } else {
+        timer_del(s->adb_poll_timer);
+    }
+}
+
+static void pmu_cmd_adb(PMUState *s,
+                        const uint8_t *in_data, uint8_t in_len,
+                        uint8_t *out_data, uint8_t *out_len)
+{
+    int len, adblen;
+    uint8_t adb_cmd[255];
+
+    if (in_len < 2) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "PMU: ADB PACKET, invalid len: %d want at least 2\n",
+                      in_len);
+        return;
+    }
+
+    *out_len = 0;
+
+    if (!s->has_adb) {
+        trace_pmu_cmd_adb_nobus();
+        return;
+    }
+
+    /* Set autopoll is a special form of the command */
+    if (in_data[0] == 0 && in_data[1] == 0x86) {
+        uint16_t mask = in_data[2];
+        mask = (mask << 8) | in_data[3];
+        if (in_len != 4) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "PMU: ADB Autopoll requires 4 bytes, got %d\n",
+                          in_len);
+            return;
+        }
+
+        pmu_cmd_set_adb_autopoll(s, mask);
+        return;
+    }
+
+    trace_pmu_cmd_adb_request(in_len, in_data[0], in_data[1], in_data[2],
+                              in_data[3], in_data[4]);
+
+    *out_len = 0;
+
+    /* Check ADB len */
+    adblen = in_data[2];
+    if (adblen > (in_len - 3)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "PMU: ADB len is %d > %d (in_len -3)...erroring\n",
+                      adblen, in_len - 3);
+        len = -1;
+    } else if (adblen > 252) {
+        qemu_log_mask(LOG_GUEST_ERROR, "PMU: ADB command too big!\n");
+        len = -1;
+    } else {
+        /* Format command */
+        adb_cmd[0] = in_data[0];
+        memcpy(&adb_cmd[1], &in_data[3], in_len - 3);
+        len = adb_request(&s->adb_bus, s->adb_reply + 2, adb_cmd, in_len - 2);
+
+        trace_pmu_cmd_adb_reply(len);
+    }
+
+    if (len > 0) {
+        /* XXX Check this */
+        s->adb_reply_size = len + 2;
+        s->adb_reply[0] = 0x01;
+        s->adb_reply[1] = len;
+    } else {
+        /* XXX Check this */
+        s->adb_reply_size = 1;
+        s->adb_reply[0] = 0x00;
+    }
+
+    s->intbits |= PMU_INT_ADB;
+    pmu_update_extirq(s);
+}
+
+static void pmu_cmd_adb_poll_off(PMUState *s,
+                                 const uint8_t *in_data, uint8_t in_len,
+                                 uint8_t *out_data, uint8_t *out_len)
+{
+    if (in_len != 0) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "PMU: ADB POLL OFF command, invalid len: %d want: 0\n",
+                      in_len);
+        return;
+    }
+
+    if (s->has_adb && s->autopoll_mask) {
+        timer_del(s->adb_poll_timer);
+        s->autopoll_mask = false;
+    }
+}
+
+static void pmu_cmd_shutdown(PMUState *s,
+                             const uint8_t *in_data, uint8_t in_len,
+                             uint8_t *out_data, uint8_t *out_len)
+{
+    if (in_len != 4) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "PMU: SHUTDOWN command, invalid len: %d want: 4\n",
+                      in_len);
+        return;
+    }
+
+    *out_len = 1;
+    out_data[0] = 0;
+
+    if (in_data[0] != 'M' || in_data[1] != 'A' || in_data[2] != 'T' ||
+        in_data[3] != 'T') {
+
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "PMU: SHUTDOWN command, Bad MATT signature\n");
+        return;
+    }
+
+    qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
+}
+
+static void pmu_cmd_reset(PMUState *s,
+                          const uint8_t *in_data, uint8_t in_len,
+                          uint8_t *out_data, uint8_t *out_len)
+{
+    if (in_len != 0) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "PMU: RESET command, invalid len: %d want: 0\n",
+                      in_len);
+        return;
+    }
+
+    qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+}
+
+static void pmu_cmd_get_rtc(PMUState *s,
+                            const uint8_t *in_data, uint8_t in_len,
+                            uint8_t *out_data, uint8_t *out_len)
+{
+    uint32_t ti;
+
+    if (in_len != 0) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "PMU: GET_RTC command, invalid len: %d want: 0\n",
+                      in_len);
+        return;
+    }
+
+    ti = s->tick_offset + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
+                           / NANOSECONDS_PER_SECOND);
+    out_data[0] = ti >> 24;
+    out_data[1] = ti >> 16;
+    out_data[2] = ti >> 8;
+    out_data[3] = ti;
+    *out_len = 4;
+}
+
+static void pmu_cmd_set_rtc(PMUState *s,
+                            const uint8_t *in_data, uint8_t in_len,
+                            uint8_t *out_data, uint8_t *out_len)
+{
+    uint32_t ti;
+
+    if (in_len != 4) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "PMU: SET_RTC command, invalid len: %d want: 4\n",
+                      in_len);
+        return;
+    }
+
+    ti = (((uint32_t)in_data[0]) << 24) + (((uint32_t)in_data[1]) << 16)
+         + (((uint32_t)in_data[2]) << 8) + in_data[3];
+
+    s->tick_offset = ti - (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
+                           / NANOSECONDS_PER_SECOND);
+}
+
+static void pmu_cmd_system_ready(PMUState *s,
+                                 const uint8_t *in_data, uint8_t in_len,
+                                 uint8_t *out_data, uint8_t *out_len)
+{
+    /* Do nothing */
+}
+
+static void pmu_cmd_get_version(PMUState *s,
+                                const uint8_t *in_data, uint8_t in_len,
+                                uint8_t *out_data, uint8_t *out_len)
+{
+    *out_len = 1;
+    *out_data = 1; /* ??? Check what Apple does */
+}
+
+static void pmu_cmd_power_events(PMUState *s,
+                                 const uint8_t *in_data, uint8_t in_len,
+                                 uint8_t *out_data, uint8_t *out_len)
+{
+    if (in_len < 1) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "PMU: POWER EVENTS command, invalid len %d, want at least 1\n",
+                      in_len);
+        return;
+    }
+
+    switch (in_data[0]) {
+    /* Dummies for now */
+    case PMU_PWR_GET_POWERUP_EVENTS:
+        *out_len = 2;
+        out_data[0] = 0;
+        out_data[1] = 0;
+        break;
+    case PMU_PWR_SET_POWERUP_EVENTS:
+    case PMU_PWR_CLR_POWERUP_EVENTS:
+        break;
+    case PMU_PWR_GET_WAKEUP_EVENTS:
+        *out_len = 2;
+        out_data[0] = 0;
+        out_data[1] = 0;
+        break;
+    case PMU_PWR_SET_WAKEUP_EVENTS:
+    case PMU_PWR_CLR_WAKEUP_EVENTS:
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "PMU: POWER EVENTS unknown subcommand 0x%02x\n",
+                      in_data[0]);
+    }
+}
+
+static void pmu_cmd_get_cover(PMUState *s,
+                              const uint8_t *in_data, uint8_t in_len,
+                              uint8_t *out_data, uint8_t *out_len)
+{
+    /* Not 100% sure here, will have to check what a real Mac
+     * returns other than byte 0 bit 0 is LID closed on laptops
+     */
+    *out_len = 1;
+    *out_data = 0x00;
+}
+
+static void pmu_cmd_download_status(PMUState *s,
+                                    const uint8_t *in_data, uint8_t in_len,
+                                    uint8_t *out_data, uint8_t *out_len)
+{
+    /* This has to do with PMU firmware updates as far as I can tell.
+     *
+     * We return 0x62 which is what OpenPMU expects
+     */
+    *out_len = 1;
+    *out_data = 0x62;
+}
+
+static void pmu_cmd_read_pmu_ram(PMUState *s,
+                                 const uint8_t *in_data, uint8_t in_len,
+                                 uint8_t *out_data, uint8_t *out_len)
+{
+    if (in_len < 3) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "PMU: READ_PMU_RAM command, invalid len %d, expected 3\n",
+                      in_len);
+        return;
+    }
+
+    qemu_log_mask(LOG_GUEST_ERROR,
+                  "PMU: Unsupported READ_PMU_RAM, args: %02x %02x %02x\n",
+                  in_data[0], in_data[1], in_data[2]);
+
+    *out_len = 0;
+}
+
+/* description of commands */
+typedef struct PMUCmdHandler {
+    uint8_t command;
+    const char *name;
+    void (*handler)(PMUState *s,
+                    const uint8_t *in_args, uint8_t in_len,
+                    uint8_t *out_args, uint8_t *out_len);
+} PMUCmdHandler;
+
+static const PMUCmdHandler PMUCmdHandlers[] = {
+    { PMU_INT_ACK, "INT ACK", pmu_cmd_int_ack },
+    { PMU_SET_INTR_MASK, "SET INT MASK", pmu_cmd_set_int_mask },
+    { PMU_ADB_CMD, "ADB COMMAND", pmu_cmd_adb },
+    { PMU_ADB_POLL_OFF, "ADB POLL OFF", pmu_cmd_adb_poll_off },
+    { PMU_RESET, "REBOOT", pmu_cmd_reset },
+    { PMU_SHUTDOWN, "SHUTDOWN", pmu_cmd_shutdown },
+    { PMU_READ_RTC, "GET RTC", pmu_cmd_get_rtc },
+    { PMU_SET_RTC, "SET RTC", pmu_cmd_set_rtc },
+    { PMU_SYSTEM_READY, "SYSTEM READY", pmu_cmd_system_ready },
+    { PMU_GET_VERSION, "GET VERSION", pmu_cmd_get_version },
+    { PMU_POWER_EVENTS, "POWER EVENTS", pmu_cmd_power_events },
+    { PMU_GET_COVER, "GET_COVER", pmu_cmd_get_cover },
+    { PMU_DOWNLOAD_STATUS, "DOWNLOAD STATUS", pmu_cmd_download_status },
+    { PMU_READ_PMU_RAM, "READ PMGR RAM", pmu_cmd_read_pmu_ram },
+};
+
+static void pmu_dispatch_cmd(PMUState *s)
+{
+    unsigned int i;
+
+    /* No response by default */
+    s->cmd_rsp_sz = 0;
+
+    for (i = 0; i < ARRAY_SIZE(PMUCmdHandlers); i++) {
+        const PMUCmdHandler *desc = &PMUCmdHandlers[i];
+
+        if (desc->command != s->cmd) {
+            continue;
+        }
+
+        trace_pmu_dispatch_cmd(desc->name);
+        desc->handler(s, s->cmd_buf, s->cmd_buf_pos,
+                      s->cmd_rsp, &s->cmd_rsp_sz);
+
+        if (s->rsplen != -1 && s->rsplen != s->cmd_rsp_sz) {
+            trace_pmu_debug_protocol_string("QEMU internal cmd resp mismatch!");
+        } else {
+            trace_pmu_debug_protocol_resp_size(s->cmd_rsp_sz);
+        }
+
+        return;
+    }
+
+    trace_pmu_dispatch_unknown_cmd(s->cmd);
+
+    /* Manufacture fake response with 0's */
+    if (s->rsplen == -1) {
+        s->cmd_rsp_sz = 0;
+    } else {
+        s->cmd_rsp_sz = s->rsplen;
+        memset(s->cmd_rsp, 0, s->rsplen);
+    }
+}
+
+static void pmu_update(PMUState *s)
+{
+    MOS6522PMUState *mps = &s->mos6522_pmu;
+    MOS6522State *ms = MOS6522(mps);
+
+    /* Only react to changes in reg B */
+    if (ms->b == s->last_b) {
+        return;
+    }
+    s->last_b = ms->b;
+
+    /* Check the TREQ / TACK state */
+    switch (ms->b & (TREQ | TACK)) {
+    case TREQ:
+        /* This is an ack release, handle it and bail out */
+        ms->b |= TACK;
+        s->last_b = ms->b;
+
+        trace_pmu_debug_protocol_string("handshake: TREQ high, setting TACK");
+        return;
+    case TACK:
+        /* This is a valid request, handle below */
+        break;
+    case TREQ | TACK:
+        /* This is an idle state */
+        return;
+    default:
+        /* Invalid state, log and ignore */
+        trace_pmu_debug_protocol_error(ms->b);
+        return;
+    }
+
+    /* If we wanted to handle commands asynchronously, this is where
+     * we would delay the clearing of TACK until we are ready to send
+     * the response
+     */
+
+    /* We have a request, handshake TACK so we don't stay in
+     * an invalid state. If we were concurrent with the OS we
+     * should only do this after we grabbed the SR but that isn't
+     * a problem here.
+     */
+
+    trace_pmu_debug_protocol_clear_treq(s->cmd_state);
+
+    ms->b &= ~TACK;
+    s->last_b = ms->b;
+
+    /* Act according to state */
+    switch (s->cmd_state) {
+    case pmu_state_idle:
+        if (!(ms->acr & SR_OUT)) {
+            trace_pmu_debug_protocol_string("protocol error! "
+                                            "state idle, ACR reading");
+            break;
+        }
+
+        s->cmd = ms->sr;
+        via_set_sr_int(s);
+        s->cmdlen = pmu_data_len[s->cmd][0];
+        s->rsplen = pmu_data_len[s->cmd][1];
+        s->cmd_buf_pos = 0;
+        s->cmd_rsp_pos = 0;
+        s->cmd_state = pmu_state_cmd;
+
+        trace_pmu_debug_protocol_cmd(s->cmd, s->cmdlen, s->rsplen);
+        break;
+
+    case pmu_state_cmd:
+        if (!(ms->acr & SR_OUT)) {
+            trace_pmu_debug_protocol_string("protocol error! "
+                                            "state cmd, ACR reading");
+            break;
+        }
+
+        if (s->cmdlen == -1) {
+            trace_pmu_debug_protocol_cmdlen(ms->sr);
+
+            s->cmdlen = ms->sr;
+            if (s->cmdlen > sizeof(s->cmd_buf)) {
+                trace_pmu_debug_protocol_cmd_toobig(s->cmdlen);
+            }
+        } else if (s->cmd_buf_pos < sizeof(s->cmd_buf)) {
+            s->cmd_buf[s->cmd_buf_pos++] = ms->sr;
+        }
+
+        via_set_sr_int(s);
+        break;
+
+    case pmu_state_rsp:
+        if (ms->acr & SR_OUT) {
+            trace_pmu_debug_protocol_string("protocol error! "
+                                            "state resp, ACR writing");
+            break;
+        }
+
+        if (s->rsplen == -1) {
+            trace_pmu_debug_protocol_cmd_send_resp_size(s->cmd_rsp_sz);
+
+            ms->sr = s->cmd_rsp_sz;
+            s->rsplen = s->cmd_rsp_sz;
+        } else if (s->cmd_rsp_pos < s->cmd_rsp_sz) {
+            trace_pmu_debug_protocol_cmd_send_resp(s->cmd_rsp_pos, s->rsplen);
+
+            ms->sr = s->cmd_rsp[s->cmd_rsp_pos++];
+        }
+
+        via_set_sr_int(s);
+        break;
+    }
+
+    /* Check for state completion */
+    if (s->cmd_state == pmu_state_cmd && s->cmdlen == s->cmd_buf_pos) {
+        trace_pmu_debug_protocol_string("Command reception complete, "
+                                        "dispatching...");
+
+        pmu_dispatch_cmd(s);
+        s->cmd_state = pmu_state_rsp;
+    }
+
+    if (s->cmd_state == pmu_state_rsp && s->rsplen == s->cmd_rsp_pos) {
+        trace_pmu_debug_protocol_cmd_resp_complete(ms->ier);
+
+        s->cmd_state = pmu_state_idle;
+    }
+}
+
+static uint64_t mos6522_pmu_read(void *opaque, hwaddr addr, unsigned size)
+{
+    PMUState *s = opaque;
+    MOS6522PMUState *mps = &s->mos6522_pmu;
+    MOS6522State *ms = MOS6522(mps);
+
+    addr = (addr >> 9) & 0xf;
+    return mos6522_read(ms, addr, size);
+}
+
+static void mos6522_pmu_write(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned size)
+{
+    PMUState *s = opaque;
+    MOS6522PMUState *mps = &s->mos6522_pmu;
+    MOS6522State *ms = MOS6522(mps);
+
+    addr = (addr >> 9) & 0xf;
+    mos6522_write(ms, addr, val, size);
+}
+
+static const MemoryRegionOps mos6522_pmu_ops = {
+    .read = mos6522_pmu_read,
+    .write = mos6522_pmu_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static bool pmu_adb_state_needed(void *opaque)
+{
+    PMUState *s = opaque;
+
+    return s->has_adb;
+}
+
+static const VMStateDescription vmstate_pmu_adb = {
+    .name = "pmu/adb",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .needed = pmu_adb_state_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT16(adb_poll_mask, PMUState),
+        VMSTATE_TIMER_PTR(adb_poll_timer, PMUState),
+        VMSTATE_UINT8(adb_reply_size, PMUState),
+        VMSTATE_BUFFER(adb_reply, PMUState),
+    }
+};
+
+static const VMStateDescription vmstate_pmu = {
+    .name = "pmu",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(mos6522_pmu.parent_obj, PMUState, 0, vmstate_mos6522,
+                       MOS6522State),
+        VMSTATE_UINT8(last_b, PMUState),
+        VMSTATE_UINT8(cmd, PMUState),
+        VMSTATE_UINT32(cmdlen, PMUState),
+        VMSTATE_UINT32(rsplen, PMUState),
+        VMSTATE_UINT8(cmd_buf_pos, PMUState),
+        VMSTATE_BUFFER(cmd_buf, PMUState),
+        VMSTATE_UINT8(cmd_rsp_pos, PMUState),
+        VMSTATE_UINT8(cmd_rsp_sz, PMUState),
+        VMSTATE_BUFFER(cmd_rsp, PMUState),
+        VMSTATE_UINT8(intbits, PMUState),
+        VMSTATE_UINT8(intmask, PMUState),
+        VMSTATE_UINT8(autopoll_rate_ms, PMUState),
+        VMSTATE_UINT8(autopoll_mask, PMUState),
+        VMSTATE_UINT32(tick_offset, PMUState),
+        VMSTATE_TIMER_PTR(one_sec_timer, PMUState),
+        VMSTATE_INT64(one_sec_target, PMUState),
+        VMSTATE_END_OF_LIST()
+    },
+    .subsections = (const VMStateDescription * []) {
+        &vmstate_pmu_adb,
+    }
+};
+
+static void pmu_reset(DeviceState *dev)
+{
+    PMUState *s = VIA_PMU(dev);
+
+    /* OpenBIOS needs to do this? MacOS 9 needs it */
+    s->intmask = PMU_INT_ADB | PMU_INT_TICK;
+    s->intbits = 0;
+
+    s->cmd_state = pmu_state_idle;
+    s->autopoll_mask = 0;
+}
+
+static void pmu_realize(DeviceState *dev, Error **errp)
+{
+    PMUState *s = VIA_PMU(dev);
+    SysBusDevice *sbd;
+    MOS6522State *ms;
+    DeviceState *d;
+    struct tm tm;
+
+    /* Pass IRQ from 6522 */
+    d = DEVICE(&s->mos6522_pmu);
+    ms = MOS6522(d);
+    sbd = SYS_BUS_DEVICE(s);
+    sysbus_pass_irq(sbd, SYS_BUS_DEVICE(ms));
+
+    qemu_get_timedate(&tm, 0);
+    s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
+    s->one_sec_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, pmu_one_sec_timer, s);
+    s->one_sec_target = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000;
+    timer_mod(s->one_sec_timer, s->one_sec_target);
+
+    if (s->has_adb) {
+        qbus_create_inplace(&s->adb_bus, sizeof(s->adb_bus), TYPE_ADB_BUS,
+                            DEVICE(dev), "adb.0");
+        s->adb_poll_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, pmu_adb_poll, s);
+        s->adb_poll_mask = 0xffff;
+        s->autopoll_rate_ms = 20;
+    }
+}
+
+static void pmu_init(Object *obj)
+{
+    SysBusDevice *d = SYS_BUS_DEVICE(obj);
+    PMUState *s = VIA_PMU(obj);
+
+    object_property_add_link(obj, "gpio", TYPE_MACIO_GPIO,
+                             (Object **) &s->gpio,
+                             qdev_prop_allow_set_link_before_realize,
+                             0, NULL);
+
+    object_initialize(&s->mos6522_pmu, sizeof(s->mos6522_pmu),
+                      TYPE_MOS6522_PMU);
+    qdev_set_parent_bus(DEVICE(&s->mos6522_pmu), sysbus_get_default());
+
+    memory_region_init_io(&s->mem, obj, &mos6522_pmu_ops, s, "via-pmu",
+                          0x2000);
+    sysbus_init_mmio(d, &s->mem);
+}
+
+static Property pmu_properties[] = {
+    DEFINE_PROP_BOOL("has-adb", PMUState, has_adb, true),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void pmu_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = pmu_realize;
+    dc->reset = pmu_reset;
+    dc->vmsd = &vmstate_pmu;
+    dc->props = pmu_properties;
+    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+}
+
+static const TypeInfo pmu_type_info = {
+    .name = TYPE_VIA_PMU,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PMUState),
+    .instance_init = pmu_init,
+    .class_init = pmu_class_init,
+};
+
+static void mos6522_pmu_portB_write(MOS6522State *s)
+{
+    MOS6522PMUState *mps = container_of(s, MOS6522PMUState, parent_obj);
+    PMUState *ps = container_of(mps, PMUState, mos6522_pmu);
+
+    if ((s->pcr & 0xe0) == 0x20 || (s->pcr & 0xe0) == 0x60) {
+        s->ifr &= ~CB2_INT;
+    }
+    s->ifr &= ~CB1_INT;
+
+    via_update_irq(ps);
+    pmu_update(ps);
+}
+
+static void mos6522_pmu_portA_write(MOS6522State *s)
+{
+    MOS6522PMUState *mps = container_of(s, MOS6522PMUState, parent_obj);
+    PMUState *ps = container_of(mps, PMUState, mos6522_pmu);
+
+    if ((s->pcr & 0x0e) == 0x02 || (s->pcr & 0x0e) == 0x06) {
+        s->ifr &= ~CA2_INT;
+    }
+    s->ifr &= ~CA1_INT;
+
+    via_update_irq(ps);
+}
+
+static void mos6522_pmu_reset(DeviceState *dev)
+{
+    MOS6522State *ms = MOS6522(dev);
+    MOS6522PMUState *mps = container_of(ms, MOS6522PMUState, parent_obj);
+    PMUState *s = container_of(mps, PMUState, mos6522_pmu);
+    MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(ms);
+
+    mdc->parent_reset(dev);
+
+    ms->timers[0].frequency = VIA_TIMER_FREQ;
+    ms->timers[1].frequency = (SCALE_US * 6000) / 4700;
+
+    s->last_b = ms->b = TACK | TREQ;
+}
+
+static void mos6522_pmu_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    MOS6522DeviceClass *mdc = MOS6522_DEVICE_CLASS(oc);
+
+    dc->reset = mos6522_pmu_reset;
+    mdc->portB_write = mos6522_pmu_portB_write;
+    mdc->portA_write = mos6522_pmu_portA_write;
+}
+
+static const TypeInfo mos6522_pmu_type_info = {
+    .name = TYPE_MOS6522_PMU,
+    .parent = TYPE_MOS6522,
+    .instance_size = sizeof(MOS6522PMUState),
+    .class_init = mos6522_pmu_class_init,
+};
+
+static void pmu_register_types(void)
+{
+    type_register_static(&pmu_type_info);
+    type_register_static(&mos6522_pmu_type_info);
+}
+
+type_init(pmu_register_types)
diff --git a/hw/misc/macio/trace-events b/hw/misc/macio/trace-events
index 71c47520eb..05019262fa 100644
--- a/hw/misc/macio/trace-events
+++ b/hw/misc/macio/trace-events
@@ -20,3 +20,24 @@ macio_gpio_irq_assert(int gpio) "asserting GPIO %d"
 macio_gpio_irq_deassert(int gpio) "deasserting GPIO %d"
 macio_gpio_write(uint64_t addr, uint64_t val) "addr: 0x%"PRIx64" value: 0x%"PRIx64
 macio_gpio_read(uint64_t addr, uint64_t val) "addr: 0x%"PRIx64" value: 0x%"PRIx64
+
+# hw/misc/macio/pmu.c
+pmu_adb_poll(int olen) "ADB autopoll, olen=%d"
+pmu_one_sec_timer(void) "PMU one sec..."
+pmu_cmd_set_int_mask(int intmask) "Setting PMU int mask to 0x%02x"
+pmu_cmd_set_adb_autopoll(int mask) "ADB set autopoll, mask=0x%04x"
+pmu_cmd_adb_nobus(void) "ADB PACKET with no ADB bus!"
+pmu_cmd_adb_request(int inlen, int indata0, int indata1, int indata2, int indata3, int indata4) "ADB request: len=%d, cmd=0x%02x, pflags=0x%02x, adblen=%d: 0x%02x 0x%02x..."
+pmu_cmd_adb_reply(int len) "ADB reply is %d bytes"
+pmu_dispatch_cmd(const char *name) "handling command %s"
+pmu_dispatch_unknown_cmd(int cmd) "Unknown PMU command 0x%02x"
+pmu_debug_protocol_string(const char *str) "%s"
+pmu_debug_protocol_resp_size(int size) "sending %d resp bytes"
+pmu_debug_protocol_error(int portB) "protocol error! portB=0x%02x"
+pmu_debug_protocol_clear_treq(int state) "TREQ cleared, clearing TACK, state: %d"
+pmu_debug_protocol_cmd(int cmd, int cmdlen, int rsplen) "Got command byte 0x%02x, clen=%d, rlen=%d"
+pmu_debug_protocol_cmdlen(int len) "got cmd length byte: %d"
+pmu_debug_protocol_cmd_toobig(int len) "command too big (%d bytes)"
+pmu_debug_protocol_cmd_send_resp_size(int len) "sending length byte: %d"
+pmu_debug_protocol_cmd_send_resp(int pos, int len) "sending byte: %d/%d"
+pmu_debug_protocol_cmd_resp_complete(int ier) "Response send complete. IER=0x%02x"
diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h
index b3b7f9d8ae..c0217e66f2 100644
--- a/hw/ppc/mac.h
+++ b/hw/ppc/mac.h
@@ -59,6 +59,7 @@
 
 /* New World IRQs */
 #define NEWWORLD_CUDA_IRQ      0x19
+#define NEWWORLD_PMU_IRQ       0x19
 #define NEWWORLD_ESCCB_IRQ     0x24
 #define NEWWORLD_ESCCA_IRQ     0x25
 #define NEWWORLD_IDE0_IRQ      0xd
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index ca21d47234..ff715ffffd 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -399,11 +399,19 @@ static void ppc_core99_init(MachineState *machine)
     macio_ide_init_drives(macio_ide, &hd[MAX_IDE_DEVS]);
 
     if (has_adb) {
-        dev = DEVICE(object_resolve_path_component(OBJECT(macio), "cuda"));
+        if (has_pmu) {
+            dev = DEVICE(object_resolve_path_component(OBJECT(macio), "pmu"));
+        } else {
+            dev = DEVICE(object_resolve_path_component(OBJECT(macio), "cuda"));
+        }
+
         adb_bus = qdev_get_child_bus(dev, "adb.0");
         dev = qdev_create(adb_bus, TYPE_ADB_KEYBOARD);
+        qdev_prop_set_bit(dev, "disable-direct-reg3-writes", has_pmu);
         qdev_init_nofail(dev);
+
         dev = qdev_create(adb_bus, TYPE_ADB_MOUSE);
+        qdev_prop_set_bit(dev, "disable-direct-reg3-writes", has_pmu);
         qdev_init_nofail(dev);
     }
 
diff --git a/include/hw/misc/macio/macio.h b/include/hw/misc/macio/macio.h
index d43883a893..cfaa145500 100644
--- a/include/hw/misc/macio/macio.h
+++ b/include/hw/misc/macio/macio.h
@@ -30,6 +30,7 @@
 #include "hw/intc/heathrow_pic.h"
 #include "hw/misc/macio/cuda.h"
 #include "hw/misc/macio/gpio.h"
+#include "hw/misc/macio/pmu.h"
 #include "hw/ppc/mac_dbdma.h"
 #include "hw/ppc/openpic.h"
 
@@ -43,6 +44,7 @@ typedef struct MacIOState {
 
     MemoryRegion bar;
     CUDAState cuda;
+    PMUState pmu;
     DBDMAState dbdma;
     ESCCState escc;
     uint64_t frequency;
diff --git a/include/hw/misc/macio/pmu.h b/include/hw/misc/macio/pmu.h
new file mode 100644
index 0000000000..d10895ba5f
--- /dev/null
+++ b/include/hw/misc/macio/pmu.h
@@ -0,0 +1,237 @@
+/*
+ * Definitions for talking to the PMU.  The PMU is a microcontroller
+ * which controls battery charging and system power on PowerBook 3400
+ * and 2400 models as well as the RTC and various other things.
+ *
+ * Copyright (C) 1998 Paul Mackerras.
+ * Copyright (C) 2016 Ben Herrenschmidt
+ */
+
+#ifndef PMU_H
+#define PMU_H
+
+/*
+ * PMU commands
+ */
+
+#define PMU_POWER_CTRL0            0x10  /* control power of some devices */
+#define PMU_POWER_CTRL             0x11  /* control power of some devices */
+#define PMU_ADB_CMD                0x20  /* send ADB packet */
+#define PMU_ADB_POLL_OFF           0x21  /* disable ADB auto-poll */
+#define PMU_WRITE_NVRAM            0x33  /* write non-volatile RAM */
+#define PMU_READ_NVRAM             0x3b  /* read non-volatile RAM */
+#define PMU_SET_RTC                0x30  /* set real-time clock */
+#define PMU_READ_RTC               0x38  /* read real-time clock */
+#define PMU_SET_VOLBUTTON          0x40  /* set volume up/down position */
+#define PMU_BACKLIGHT_BRIGHT       0x41  /* set backlight brightness */
+#define PMU_GET_VOLBUTTON          0x48  /* get volume up/down position */
+#define PMU_PCEJECT                0x4c  /* eject PC-card from slot */
+#define PMU_BATTERY_STATE          0x6b  /* report battery state etc. */
+#define PMU_SMART_BATTERY_STATE    0x6f  /* report battery state (new way) */
+#define PMU_SET_INTR_MASK          0x70  /* set PMU interrupt mask */
+#define PMU_INT_ACK                0x78  /* read interrupt bits */
+#define PMU_SHUTDOWN               0x7e  /* turn power off */
+#define PMU_CPU_SPEED              0x7d  /* control CPU speed on some models */
+#define PMU_SLEEP                  0x7f  /* put CPU to sleep */
+#define PMU_POWER_EVENTS           0x8f  /* Send power-event commands to PMU */
+#define PMU_I2C_CMD                0x9a  /* I2C operations */
+#define PMU_RESET                  0xd0  /* reset CPU */
+#define PMU_GET_BRIGHTBUTTON       0xd9  /* report brightness up/down pos */
+#define PMU_GET_COVER              0xdc  /* report cover open/closed */
+#define PMU_SYSTEM_READY           0xdf  /* tell PMU we are awake */
+#define PMU_DOWNLOAD_STATUS        0xe2  /* Called by MacOS during boot... */
+#define PMU_READ_PMU_RAM           0xe8  /* read the PMU RAM... ??? */
+#define PMU_GET_VERSION            0xea  /* read the PMU version */
+
+/* Bits to use with the PMU_POWER_CTRL0 command */
+#define PMU_POW0_ON            0x80    /* OR this to power ON the device */
+#define PMU_POW0_OFF           0x00    /* leave bit 7 to 0 to power it OFF */
+#define PMU_POW0_HARD_DRIVE    0x04    /* Hard drive power
+                                        * (on wallstreet/lombard ?) */
+
+/* Bits to use with the PMU_POWER_CTRL command */
+#define PMU_POW_ON             0x80    /* OR this to power ON the device */
+#define PMU_POW_OFF            0x00    /* leave bit 7 to 0 to power it OFF */
+#define PMU_POW_BACKLIGHT      0x01    /* backlight power */
+#define PMU_POW_CHARGER        0x02    /* battery charger power */
+#define PMU_POW_IRLED          0x04    /* IR led power (on wallstreet) */
+#define PMU_POW_MEDIABAY       0x08    /* media bay power
+                                        * (wallstreet/lombard ?) */
+
+/* Bits in PMU interrupt and interrupt mask bytes */
+#define PMU_INT_PCEJECT        0x04    /* PC-card eject buttons */
+#define PMU_INT_SNDBRT         0x08    /* sound/brightness up/down buttons */
+#define PMU_INT_ADB            0x10    /* ADB autopoll or reply data */
+#define PMU_INT_BATTERY        0x20    /* Battery state change */
+#define PMU_INT_ENVIRONMENT    0x40    /* Environment interrupts */
+#define PMU_INT_TICK           0x80    /* 1-second tick interrupt */
+
+/* Other bits in PMU interrupt valid when PMU_INT_ADB is set */
+#define PMU_INT_ADB_AUTO           0x04    /* ADB autopoll, when PMU_INT_ADB */
+#define PMU_INT_WAITING_CHARGER    0x01    /* ??? */
+#define PMU_INT_AUTO_SRQ_POLL      0x02    /* ??? */
+
+/* Bits in the environement message (either obtained via PMU_GET_COVER,
+ * or via PMU_INT_ENVIRONMENT on core99 */
+#define PMU_ENV_LID_CLOSED     0x01    /* The lid is closed */
+
+/* I2C related definitions */
+#define PMU_I2C_MODE_SIMPLE    0
+#define PMU_I2C_MODE_STDSUB    1
+#define PMU_I2C_MODE_COMBINED  2
+
+#define PMU_I2C_BUS_STATUS     0
+#define PMU_I2C_BUS_SYSCLK     1
+#define PMU_I2C_BUS_POWER      2
+
+#define PMU_I2C_STATUS_OK          0
+#define PMU_I2C_STATUS_DATAREAD    1
+#define PMU_I2C_STATUS_BUSY        0xfe
+
+/* Kind of PMU (model) */
+enum {
+    PMU_UNKNOWN,
+    PMU_OHARE_BASED,        /* 2400, 3400, 3500 (old G3 powerbook) */
+    PMU_HEATHROW_BASED,     /* PowerBook G3 series */
+    PMU_PADDINGTON_BASED,   /* 1999 PowerBook G3 */
+    PMU_KEYLARGO_BASED,     /* Core99 motherboard (PMU99) */
+    PMU_68K_V1,             /* 68K PMU, version 1 */
+    PMU_68K_V2,             /* 68K PMU, version 2 */
+};
+
+/* PMU PMU_POWER_EVENTS commands */
+enum {
+    PMU_PWR_GET_POWERUP_EVENTS = 0x00,
+    PMU_PWR_SET_POWERUP_EVENTS = 0x01,
+    PMU_PWR_CLR_POWERUP_EVENTS = 0x02,
+    PMU_PWR_GET_WAKEUP_EVENTS = 0x03,
+    PMU_PWR_SET_WAKEUP_EVENTS = 0x04,
+    PMU_PWR_CLR_WAKEUP_EVENTS = 0x05,
+};
+
+/* Power events wakeup bits */
+enum {
+    PMU_PWR_WAKEUP_KEY = 0x01,           /* Wake on key press */
+    PMU_PWR_WAKEUP_AC_INSERT = 0x02,     /* Wake on AC adapter plug */
+    PMU_PWR_WAKEUP_AC_CHANGE = 0x04,
+    PMU_PWR_WAKEUP_LID_OPEN = 0x08,
+    PMU_PWR_WAKEUP_RING = 0x10,
+};
+
+/*
+ * This table indicates for each PMU opcode:
+ * - the number of data bytes to be sent with the command, or -1
+ *   if a length byte should be sent,
+ * - the number of response bytes which the PMU will return, or
+ *   -1 if it will send a length byte.
+ */
+
+static const int8_t pmu_data_len[256][2] = {
+/*  0        1        2        3        4        5        6        7  */
+    {-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},
+    {-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},
+    { 1,  0},{ 1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},
+    { 0,  1},{ 0,  1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{ 0,  0},
+    {-1,  0},{ 0,  0},{ 2,  0},{ 1,  0},{ 1,  0},{-1,  0},{-1,  0},{-1,  0},
+    { 0, -1},{ 0, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{ 0, -1},
+    { 4,  0},{20,  0},{-1,  0},{ 3,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},
+    { 0,  4},{ 0, 20},{ 2, -1},{ 2,  1},{ 3, -1},{-1, -1},{-1, -1},{ 4,  0},
+    { 1,  0},{ 1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},
+    { 0,  1},{ 0,  1},{-1, -1},{ 1,  0},{ 1,  0},{-1, -1},{-1, -1},{-1, -1},
+    { 1,  0},{ 0,  0},{ 2,  0},{ 2,  0},{-1,  0},{ 1,  0},{ 3,  0},{ 1,  0},
+    { 0,  1},{ 1,  0},{ 0,  2},{ 0,  2},{ 0, -1},{-1, -1},{-1, -1},{-1, -1},
+    { 2,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},
+    { 0,  3},{ 0,  3},{ 0,  2},{ 0,  8},{ 0, -1},{ 0, -1},{-1, -1},{-1, -1},
+    { 1,  0},{ 1,  0},{ 1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},
+    { 0, -1},{ 0, -1},{-1, -1},{-1, -1},{-1, -1},{ 5,  1},{ 4,  1},{ 4,  1},
+    { 4,  0},{-1,  0},{ 0,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},
+    { 0,  5},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},
+    { 1,  0},{ 2,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},
+    { 0,  1},{ 0,  1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},
+    { 2,  0},{ 2,  0},{ 2,  0},{ 4,  0},{-1,  0},{ 0,  0},{-1,  0},{-1,  0},
+    { 1,  1},{ 1,  0},{ 3,  0},{ 2,  0},{-1, -1},{-1, -1},{-1, -1},{-1, -1},
+    {-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},
+    {-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},
+    {-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},
+    {-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},
+    { 0,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},
+    { 1,  1},{ 1,  1},{-1, -1},{-1, -1},{ 0,  1},{ 0, -1},{-1, -1},{-1, -1},
+    {-1,  0},{ 4,  0},{ 0,  1},{-1,  0},{-1,  0},{ 4,  0},{-1,  0},{-1,  0},
+    { 3, -1},{-1, -1},{ 0,  1},{-1, -1},{ 0, -1},{-1, -1},{-1, -1},{ 0,  0},
+    {-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},{-1,  0},
+    {-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1},
+};
+
+/* Command protocol state machine */
+typedef enum {
+    pmu_state_idle, /* Waiting for command */
+    pmu_state_cmd,  /* Receiving command */
+    pmu_state_rsp,  /* Responding to command */
+} PMUCmdState;
+
+/* MOS6522 PMU */
+typedef struct MOS6522PMUState {
+    /*< private >*/
+    MOS6522State parent_obj;
+} MOS6522PMUState;
+
+#define TYPE_MOS6522_PMU "mos6522-pmu"
+#define MOS6522_PMU(obj) OBJECT_CHECK(MOS6522PMUState, (obj), \
+                                      TYPE_MOS6522_PMU)
+/**
+ * PMUState:
+ * @last_b: last value of B register
+ */
+
+typedef struct PMUState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+    /*< public >*/
+
+    MemoryRegion mem;
+    uint64_t frequency;
+    qemu_irq via_irq;
+    bool via_irq_state;
+
+    /* PMU state */
+    MOS6522PMUState mos6522_pmu;
+
+    /* PMU low level protocol state */
+    PMUCmdState cmd_state;
+    uint8_t last_b;
+    uint8_t cmd;
+    uint32_t cmdlen;
+    uint32_t rsplen;
+    uint8_t cmd_buf_pos;
+    uint8_t cmd_buf[128];
+    uint8_t cmd_rsp_pos;
+    uint8_t cmd_rsp_sz;
+    uint8_t cmd_rsp[128];
+
+    /* PMU events/interrupts */
+    uint8_t intbits;
+    uint8_t intmask;
+
+    /* ADB */
+    bool has_adb;
+    ADBBusState adb_bus;
+    uint16_t adb_poll_mask;
+    uint8_t autopoll_rate_ms;
+    uint8_t autopoll_mask;
+    QEMUTimer *adb_poll_timer;
+    uint8_t adb_reply_size;
+    uint8_t adb_reply[ADB_MAX_OUT_LEN];
+
+    /* RTC */
+    uint32_t tick_offset;
+    QEMUTimer *one_sec_timer;
+    int64_t one_sec_target;
+
+    /* GPIO */
+    MacIOGPIOState *gpio;
+} PMUState;
+
+#define TYPE_VIA_PMU "via-pmu"
+#define VIA_PMU(obj) OBJECT_CHECK(PMUState, (obj), TYPE_VIA_PMU)
+
+#endif /* PMU_H */
-- 
2.17.1

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

* [Qemu-devel] [PULL 12/28] xics_kvm: fix a build break
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (10 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 11/28] mac_newworld: add PMU device David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 13/28] mos6522: only clear the shift register interrupt upon write David Gibson
                   ` (16 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell; +Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, David Gibson

From: Cédric Le Goater <clg@kaod.org>

On CentOS 7.5, gcc-4.8.5-28.el7_5.1.ppc64le fails to build QEMU due to :

  hw/intc/xics_kvm.c: In function ‘ics_set_kvm_state’:
  hw/intc/xics_kvm.c:281:13: error: ‘ret’ may be used uninitialized in this
    function [-Werror=maybe-uninitialized]
             return ret;

Fix the breakage and also remove the extra error reporting as
kvm_device_access() already provides a substantial error message.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/intc/xics_kvm.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c
index 8bdf6afe82..8dba2f84e7 100644
--- a/hw/intc/xics_kvm.c
+++ b/hw/intc/xics_kvm.c
@@ -186,8 +186,7 @@ static void ics_get_kvm_state(ICSState *ics)
         kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES,
                           i + ics->offset, &state, false, &local_err);
         if (local_err) {
-            error_report("Unable to retrieve KVM interrupt controller state"
-                    " for IRQ %d: %s", i + ics->offset, strerror(errno));
+            error_report_err(local_err);
             exit(1);
         }
 
@@ -273,11 +272,10 @@ static int ics_set_kvm_state(ICSState *ics, int version_id)
                 state |= KVM_XICS_QUEUED;
         }
 
-        kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES,
-                          i + ics->offset, &state, true, &local_err);
+        ret = kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES,
+                                i + ics->offset, &state, true, &local_err);
         if (local_err) {
-            error_report("Unable to restore KVM interrupt controller state"
-                    " for IRQs %d: %s", i + ics->offset, strerror(errno));
+            error_report_err(local_err);
             return ret;
         }
     }
-- 
2.17.1

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

* [Qemu-devel] [PULL 13/28] mos6522: only clear the shift register interrupt upon write
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (11 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 12/28] xics_kvm: fix a build break David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 14/28] mos6522: remove additional interrupt flag filter from mos6522_update_irq() David Gibson
                   ` (15 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, Mark Cave-Ayland,
	David Gibson

From: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>

According to the 6522 datasheet the shift register (SR) interrupt flag is
cleared upon write with no mention of any other interrupt flags.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/misc/mos6522.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/misc/mos6522.c b/hw/misc/mos6522.c
index 44eb306cf1..ad5041d8c0 100644
--- a/hw/misc/mos6522.c
+++ b/hw/misc/mos6522.c
@@ -241,7 +241,7 @@ uint64_t mos6522_read(void *opaque, hwaddr addr, unsigned size)
         break;
     case VIA_REG_SR:
         val = s->sr;
-        s->ifr &= ~(SR_INT | CB1_INT | CB2_INT);
+        s->ifr &= ~SR_INT;
         mos6522_update_irq(s);
         break;
     case VIA_REG_ACR:
-- 
2.17.1

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

* [Qemu-devel] [PULL 14/28] mos6522: remove additional interrupt flag filter from mos6522_update_irq()
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (12 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 13/28] mos6522: only clear the shift register interrupt upon write David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 15/28] mos6522: expose mos6522_update_irq() through MOS6522DeviceClass David Gibson
                   ` (14 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, Mark Cave-Ayland,
	David Gibson

From: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>

The datasheet indicates that the interrupt is generated by ANDing the
interrupt flags register (IFR) with the interrupt enable register (IER)
but currently there is an extra filter for the SR and timer interrupts.

Remove this extra filter to allow interrupts to be generated by external
inputs on bits 1 and 2 of ports A and B.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/misc/mos6522.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/misc/mos6522.c b/hw/misc/mos6522.c
index ad5041d8c0..8d5b419825 100644
--- a/hw/misc/mos6522.c
+++ b/hw/misc/mos6522.c
@@ -40,7 +40,7 @@ static void mos6522_timer_update(MOS6522State *s, MOS6522Timer *ti,
 
 static void mos6522_update_irq(MOS6522State *s)
 {
-    if (s->ifr & s->ier & (SR_INT | T1_INT | T2_INT)) {
+    if (s->ifr & s->ier) {
         qemu_irq_raise(s->irq);
     } else {
         qemu_irq_lower(s->irq);
-- 
2.17.1

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

* [Qemu-devel] [PULL 15/28] mos6522: expose mos6522_update_irq() through MOS6522DeviceClass
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (13 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 14/28] mos6522: remove additional interrupt flag filter from mos6522_update_irq() David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 16/28] sm501: Do not clear read only bits when writing registers David Gibson
                   ` (13 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, Mark Cave-Ayland,
	David Gibson

From: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>

In the case where we have an interrupt generated externally from inputs to
bits 1 and 2 of port A and/or port B, it is necessary to expose
mos6522_update_irq() so it can be called by the interrupt source.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/misc/mos6522.c         | 1 +
 include/hw/misc/mos6522.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/hw/misc/mos6522.c b/hw/misc/mos6522.c
index 8d5b419825..14cff26c61 100644
--- a/hw/misc/mos6522.c
+++ b/hw/misc/mos6522.c
@@ -463,6 +463,7 @@ static void mos6522_class_init(ObjectClass *oc, void *data)
     mdc->set_sr_int = mos6522_set_sr_int;
     mdc->portB_write = mos6522_portB_write;
     mdc->portA_write = mos6522_portA_write;
+    mdc->update_irq = mos6522_update_irq;
     mdc->get_timer1_counter_value = mos6522_get_counter_value;
     mdc->get_timer2_counter_value = mos6522_get_counter_value;
     mdc->get_timer1_load_time = mos6522_get_load_time;
diff --git a/include/hw/misc/mos6522.h b/include/hw/misc/mos6522.h
index f52b41920b..03d9f0c059 100644
--- a/include/hw/misc/mos6522.h
+++ b/include/hw/misc/mos6522.h
@@ -134,6 +134,7 @@ typedef struct MOS6522DeviceClass {
     void (*set_sr_int)(MOS6522State *dev);
     void (*portB_write)(MOS6522State *dev);
     void (*portA_write)(MOS6522State *dev);
+    void (*update_irq)(MOS6522State *dev);
     /* These are used to influence the CUDA MacOS timebase calibration */
     uint64_t (*get_timer1_counter_value)(MOS6522State *dev, MOS6522Timer *ti);
     uint64_t (*get_timer2_counter_value)(MOS6522State *dev, MOS6522Timer *ti);
-- 
2.17.1

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

* [Qemu-devel] [PULL 16/28] sm501: Do not clear read only bits when writing registers
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (14 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 15/28] mos6522: expose mos6522_update_irq() through MOS6522DeviceClass David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 17/28] spapr: Clean up cpu realize/unrealize paths David Gibson
                   ` (12 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell
  Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, BALATON Zoltan,
	David Gibson

From: BALATON Zoltan <balaton@eik.bme.hu>

When writing registers that have read only bits we have to avoid
changing these bits as they may have non zero values. Make sure we use
the correct masks to mask out read only and reserved bits when
changing registers.

Also remove extra spaces from dram_control and arbitration_control
assignments.

Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/display/sm501.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index e47be99451..ca0840f6fa 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -836,27 +836,30 @@ static void sm501_system_config_write(void *opaque, hwaddr addr,
 
     switch (addr) {
     case SM501_SYSTEM_CONTROL:
-        s->system_control = value & 0xE300B8F7;
+        s->system_control &= 0x10DB0000;
+        s->system_control |= value & 0xEF00B8F7;
         break;
     case SM501_MISC_CONTROL:
-        s->misc_control = value & 0xFF7FFF20;
+        s->misc_control &= 0xEF;
+        s->misc_control |= value & 0xFF7FFF10;
         break;
     case SM501_GPIO31_0_CONTROL:
         s->gpio_31_0_control = value;
         break;
     case SM501_GPIO63_32_CONTROL:
-        s->gpio_63_32_control = value;
+        s->gpio_63_32_control = value & 0xFF80FFFF;
         break;
     case SM501_DRAM_CONTROL:
         s->local_mem_size_index = (value >> 13) & 0x7;
         /* TODO : check validity of size change */
-        s->dram_control |=  value & 0x7FFFFFC3;
+        s->dram_control &= 0x80000000;
+        s->dram_control |= value & 0x7FFFFFC3;
         break;
     case SM501_ARBTRTN_CONTROL:
-        s->arbitration_control =  value & 0x37777777;
+        s->arbitration_control = value & 0x37777777;
         break;
     case SM501_IRQ_MASK:
-        s->irq_mask = value;
+        s->irq_mask = value & 0xFFDF3F5F;
         break;
     case SM501_MISC_TIMING:
         s->misc_timing = value & 0xF31F1FFF;
-- 
2.17.1

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

* [Qemu-devel] [PULL 17/28] spapr: Clean up cpu realize/unrealize paths
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (15 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 16/28] sm501: Do not clear read only bits when writing registers David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 18/28] pnv: Fix some error handling cpu realize() David Gibson
                   ` (11 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell; +Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, David Gibson

spapr_cpu_init() and spapr_cpu_destroy() are only called from the spapr
cpu core realize/unrealize paths, and really can only be called from there.

Those are all short functions, so fold the pairs together for simplicity.
While we're there rename some functions and change some parameter types
for brevity and clarity.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: Greg Kurz <groug@kaod.org>
---
 hw/ppc/spapr_cpu_core.c | 69 +++++++++++++++--------------------------
 1 file changed, 25 insertions(+), 44 deletions(-)

diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index f3e9b879b2..7fdb3b6667 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -83,26 +83,6 @@ void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r
     ppc_store_lpcr(cpu, env->spr[SPR_LPCR] | pcc->lpcr_pm);
 }
 
-static void spapr_cpu_destroy(PowerPCCPU *cpu)
-{
-    qemu_unregister_reset(spapr_cpu_reset, cpu);
-}
-
-static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu,
-                           Error **errp)
-{
-    CPUPPCState *env = &cpu->env;
-
-    /* Set time-base frequency to 512 MHz */
-    cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ);
-
-    cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr));
-    kvmppc_set_papr(cpu);
-
-    qemu_register_reset(spapr_cpu_reset, cpu);
-    spapr_cpu_reset(cpu);
-}
-
 /*
  * Return the sPAPR CPU core type for @model which essentially is the CPU
  * model specified with -cpu cmdline option.
@@ -122,44 +102,47 @@ const char *spapr_get_cpu_core_type(const char *cpu_type)
     return object_class_get_name(oc);
 }
 
-static void spapr_cpu_core_unrealizefn(DeviceState *dev, Error **errp)
+static void spapr_unrealize_vcpu(PowerPCCPU *cpu)
+{
+    qemu_unregister_reset(spapr_cpu_reset, cpu);
+    object_unparent(cpu->intc);
+    cpu_remove_sync(CPU(cpu));
+    object_unparent(OBJECT(cpu));
+}
+
+static void spapr_cpu_core_unrealize(DeviceState *dev, Error **errp)
 {
     sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
     CPUCore *cc = CPU_CORE(dev);
     int i;
 
     for (i = 0; i < cc->nr_threads; i++) {
-        Object *obj = OBJECT(sc->threads[i]);
-        DeviceState *dev = DEVICE(obj);
-        CPUState *cs = CPU(dev);
-        PowerPCCPU *cpu = POWERPC_CPU(cs);
-
-        spapr_cpu_destroy(cpu);
-        object_unparent(cpu->intc);
-        cpu_remove_sync(cs);
-        object_unparent(obj);
+        spapr_unrealize_vcpu(sc->threads[i]);
     }
     g_free(sc->threads);
 }
 
-static void spapr_cpu_core_realize_child(Object *child,
-                                         sPAPRMachineState *spapr, Error **errp)
+static void spapr_realize_vcpu(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+                               Error **errp)
 {
+    CPUPPCState *env = &cpu->env;
     Error *local_err = NULL;
-    CPUState *cs = CPU(child);
-    PowerPCCPU *cpu = POWERPC_CPU(cs);
 
-    object_property_set_bool(child, true, "realized", &local_err);
+    object_property_set_bool(OBJECT(cpu), true, "realized", &local_err);
     if (local_err) {
         goto error;
     }
 
-    spapr_cpu_init(spapr, cpu, &local_err);
-    if (local_err) {
-        goto error;
-    }
+    /* Set time-base frequency to 512 MHz */
+    cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ);
+
+    cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr));
+    kvmppc_set_papr(cpu);
 
-    cpu->intc = icp_create(child, spapr->icp_type, XICS_FABRIC(spapr),
+    qemu_register_reset(spapr_cpu_reset, cpu);
+    spapr_cpu_reset(cpu);
+
+    cpu->intc = icp_create(OBJECT(cpu), spapr->icp_type, XICS_FABRIC(spapr),
                            &local_err);
     if (local_err) {
         goto error;
@@ -220,9 +203,7 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
     }
 
     for (j = 0; j < cc->nr_threads; j++) {
-        obj = OBJECT(sc->threads[j]);
-
-        spapr_cpu_core_realize_child(obj, spapr, &local_err);
+        spapr_realize_vcpu(sc->threads[j], spapr, &local_err);
         if (local_err) {
             goto err;
         }
@@ -249,7 +230,7 @@ static void spapr_cpu_core_class_init(ObjectClass *oc, void *data)
     sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_CLASS(oc);
 
     dc->realize = spapr_cpu_core_realize;
-    dc->unrealize = spapr_cpu_core_unrealizefn;
+    dc->unrealize = spapr_cpu_core_unrealize;
     dc->props = spapr_cpu_core_properties;
     scc->cpu_type = data;
 }
-- 
2.17.1

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

* [Qemu-devel] [PULL 18/28] pnv: Fix some error handling cpu realize()
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (16 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 17/28] spapr: Clean up cpu realize/unrealize paths David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 19/28] pnv_core: Allocate cpu thread objects individually David Gibson
                   ` (10 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell; +Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, David Gibson

In pnv_core_realize() we call two functions with an Error * parameter in
succession, which will go badly if they both cause errors.  In fact, a
failure in either of them indicates a qemu internal error, so we can just
use &error_abort in both cases.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: Greg Kurz <groug@kaod.org>
---
 hw/ppc/pnv_core.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 13ad7d9e04..01f47c8037 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -172,12 +172,9 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
         object_initialize(obj, size, typename);
 
         snprintf(name, sizeof(name), "thread[%d]", i);
-        object_property_add_child(OBJECT(pc), name, obj, &local_err);
+        object_property_add_child(OBJECT(pc), name, obj, &error_abort);
         object_property_add_alias(obj, "core-pir", OBJECT(pc),
-                                  "pir", &local_err);
-        if (local_err) {
-            goto err;
-        }
+                                  "pir", &error_abort);
         object_unref(obj);
     }
 
-- 
2.17.1

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

* [Qemu-devel] [PULL 19/28] pnv_core: Allocate cpu thread objects individually
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (17 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 18/28] pnv: Fix some error handling cpu realize() David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 20/28] pnv: Clean up cpu realize path David Gibson
                   ` (9 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell; +Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, David Gibson

Currently, we allocate space for all the cpu objects within a single core
in one big block.  This was copied from an older version of the spapr code
and requires some ugly pointer manipulation to extract the individual
objects.

This design was due to a misunderstanding of qemu lifetime conventions and
has already been changed in spapr (in 94ad93bd "spapr_cpu_core: instantiate
CPUs separately".

Make an equivalent change in pnv_core to get rid of the nasty pointer
arithmetic.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: Greg Kurz <groug@kaod.org>
---
 hw/ppc/pnv.c              |  4 ++--
 hw/ppc/pnv_core.c         | 11 +++++------
 include/hw/ppc/pnv_core.h |  2 +-
 3 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 0314881316..0b9508d94d 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -121,9 +121,9 @@ static int get_cpus_node(void *fdt)
  */
 static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
 {
-    CPUState *cs = CPU(DEVICE(pc->threads));
+    PowerPCCPU *cpu = pc->threads[0];
+    CPUState *cs = CPU(cpu);
     DeviceClass *dc = DEVICE_GET_CLASS(cs);
-    PowerPCCPU *cpu = POWERPC_CPU(cs);
     int smt_threads = CPU_CORE(pc)->nr_threads;
     CPUPPCState *env = &cpu->env;
     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 01f47c8037..1e40f01e98 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -151,7 +151,6 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
     PnvCore *pc = PNV_CORE(OBJECT(dev));
     CPUCore *cc = CPU_CORE(OBJECT(dev));
     const char *typename = pnv_core_cpu_typename(pc);
-    size_t size = object_type_get_instance_size(typename);
     Error *local_err = NULL;
     void *obj;
     int i, j;
@@ -165,11 +164,11 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
         return;
     }
 
-    pc->threads = g_malloc0(size * cc->nr_threads);
+    pc->threads = g_new(PowerPCCPU *, cc->nr_threads);
     for (i = 0; i < cc->nr_threads; i++) {
-        obj = pc->threads + i * size;
+        obj = object_new(typename);
 
-        object_initialize(obj, size, typename);
+        pc->threads[i] = POWERPC_CPU(obj);
 
         snprintf(name, sizeof(name), "thread[%d]", i);
         object_property_add_child(OBJECT(pc), name, obj, &error_abort);
@@ -179,7 +178,7 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
     }
 
     for (j = 0; j < cc->nr_threads; j++) {
-        obj = pc->threads + j * size;
+        obj = OBJECT(pc->threads[j]);
 
         pnv_core_realize_child(obj, XICS_FABRIC(xi), &local_err);
         if (local_err) {
@@ -194,7 +193,7 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
 
 err:
     while (--i >= 0) {
-        obj = pc->threads + i * size;
+        obj = OBJECT(pc->threads[i]);
         object_unparent(obj);
     }
     g_free(pc->threads);
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
index e337af7a3a..447ae761f7 100644
--- a/include/hw/ppc/pnv_core.h
+++ b/include/hw/ppc/pnv_core.h
@@ -34,7 +34,7 @@ typedef struct PnvCore {
     CPUCore parent_obj;
 
     /*< public >*/
-    void *threads;
+    PowerPCCPU **threads;
     uint32_t pir;
 
     MemoryRegion xscom_regs;
-- 
2.17.1

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

* [Qemu-devel] [PULL 20/28] pnv: Clean up cpu realize path
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (18 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 19/28] pnv_core: Allocate cpu thread objects individually David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 21/28] pnv: Add cpu unrealize path David Gibson
                   ` (8 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell; +Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, David Gibson

pnv_cpu_init() is only called from the the pnv cpu core realize path, and
really only can be called from there.  So fold it into its caller, which
we also rename for brevity.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: Greg Kurz <groug@kaod.org>
---
 hw/ppc/pnv_core.c | 56 ++++++++++++++++++-----------------------------
 1 file changed, 21 insertions(+), 35 deletions(-)

diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 1e40f01e98..f4c41d89d6 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -54,28 +54,6 @@ static void pnv_cpu_reset(void *opaque)
     env->msr |= MSR_HVB; /* Hypervisor mode */
 }
 
-static void pnv_cpu_init(PowerPCCPU *cpu, Error **errp)
-{
-    CPUPPCState *env = &cpu->env;
-    int core_pir;
-    int thread_index = 0; /* TODO: TCG supports only one thread */
-    ppc_spr_t *pir = &env->spr_cb[SPR_PIR];
-
-    core_pir = object_property_get_uint(OBJECT(cpu), "core-pir", &error_abort);
-
-    /*
-     * The PIR of a thread is the core PIR + the thread index. We will
-     * need to find a way to get the thread index when TCG supports
-     * more than 1. We could use the object name ?
-     */
-    pir->default_value = core_pir + thread_index;
-
-    /* Set time-base frequency to 512 MHz */
-    cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
-
-    qemu_register_reset(pnv_cpu_reset, cpu);
-}
-
 /*
  * These values are read by the PowerNV HW monitors under Linux
  */
@@ -121,29 +99,39 @@ static const MemoryRegionOps pnv_core_xscom_ops = {
     .endianness = DEVICE_BIG_ENDIAN,
 };
 
-static void pnv_core_realize_child(Object *child, XICSFabric *xi, Error **errp)
+static void pnv_realize_vcpu(PowerPCCPU *cpu, XICSFabric *xi, Error **errp)
 {
+    CPUPPCState *env = &cpu->env;
+    int core_pir;
+    int thread_index = 0; /* TODO: TCG supports only one thread */
+    ppc_spr_t *pir = &env->spr_cb[SPR_PIR];
     Error *local_err = NULL;
-    CPUState *cs = CPU(child);
-    PowerPCCPU *cpu = POWERPC_CPU(cs);
 
-    object_property_set_bool(child, true, "realized", &local_err);
+    object_property_set_bool(OBJECT(cpu), true, "realized", &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         return;
     }
 
-    cpu->intc = icp_create(child, TYPE_PNV_ICP, xi, &local_err);
+    cpu->intc = icp_create(OBJECT(cpu), TYPE_PNV_ICP, xi, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         return;
     }
 
-    pnv_cpu_init(cpu, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        return;
-    }
+    core_pir = object_property_get_uint(OBJECT(cpu), "core-pir", &error_abort);
+
+    /*
+     * The PIR of a thread is the core PIR + the thread index. We will
+     * need to find a way to get the thread index when TCG supports
+     * more than 1. We could use the object name ?
+     */
+    pir->default_value = core_pir + thread_index;
+
+    /* Set time-base frequency to 512 MHz */
+    cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
+
+    qemu_register_reset(pnv_cpu_reset, cpu);
 }
 
 static void pnv_core_realize(DeviceState *dev, Error **errp)
@@ -178,9 +166,7 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
     }
 
     for (j = 0; j < cc->nr_threads; j++) {
-        obj = OBJECT(pc->threads[j]);
-
-        pnv_core_realize_child(obj, XICS_FABRIC(xi), &local_err);
+        pnv_realize_vcpu(pc->threads[j], XICS_FABRIC(xi), &local_err);
         if (local_err) {
             goto err;
         }
-- 
2.17.1

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

* [Qemu-devel] [PULL 21/28] pnv: Add cpu unrealize path
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (19 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 20/28] pnv: Clean up cpu realize path David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 22/28] spapr_cpu_core: convert last snprintf() to g_strdup_printf() David Gibson
                   ` (7 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell; +Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, David Gibson

Currently we don't have any unrealize path for pnv cpu cores.  We get away
with this because we don't yet support cpu hotplug for pnv.

However, we're going to want it eventually, and in the meantime, it makes
it non-obvious why there are a bunch of allocations on the realize() path
that don't have matching frees.

So, implement the missing unrealize path.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: Greg Kurz <groug@kaod.org>
---
 hw/ppc/pnv_core.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index f4c41d89d6..f7cf33f547 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -186,6 +186,26 @@ err:
     error_propagate(errp, local_err);
 }
 
+static void pnv_unrealize_vcpu(PowerPCCPU *cpu)
+{
+    qemu_unregister_reset(pnv_cpu_reset, cpu);
+    object_unparent(cpu->intc);
+    cpu_remove_sync(CPU(cpu));
+    object_unparent(OBJECT(cpu));
+}
+
+static void pnv_core_unrealize(DeviceState *dev, Error **errp)
+{
+    PnvCore *pc = PNV_CORE(dev);
+    CPUCore *cc = CPU_CORE(dev);
+    int i;
+
+    for (i = 0; i < cc->nr_threads; i++) {
+        pnv_unrealize_vcpu(pc->threads[i]);
+    }
+    g_free(pc->threads);
+}
+
 static Property pnv_core_properties[] = {
     DEFINE_PROP_UINT32("pir", PnvCore, pir, 0),
     DEFINE_PROP_END_OF_LIST(),
@@ -196,6 +216,7 @@ static void pnv_core_class_init(ObjectClass *oc, void *data)
     DeviceClass *dc = DEVICE_CLASS(oc);
 
     dc->realize = pnv_core_realize;
+    dc->unrealize = pnv_core_unrealize;
     dc->props = pnv_core_properties;
 }
 
-- 
2.17.1

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

* [Qemu-devel] [PULL 22/28] spapr_cpu_core: convert last snprintf() to g_strdup_printf()
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (20 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 21/28] pnv: Add cpu unrealize path David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 23/28] spapr_cpu_core: fix potential leak in spapr_cpu_core_realize() David Gibson
                   ` (6 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell; +Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, David Gibson

From: Greg Kurz <groug@kaod.org>

Because this is the preferred practice in QEMU.

Signed-off-by: Greg Kurz <groug@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_cpu_core.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 7fdb3b6667..ad404d13ec 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -176,7 +176,7 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
 
     sc->threads = g_new(PowerPCCPU *, cc->nr_threads);
     for (i = 0; i < cc->nr_threads; i++) {
-        char id[32];
+        char *id;
         CPUState *cs;
         PowerPCCPU *cpu;
 
@@ -194,8 +194,9 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
         /* Set NUMA node for the threads belonged to core  */
         cpu->node_id = sc->node_id;
 
-        snprintf(id, sizeof(id), "thread[%d]", i);
+        id = g_strdup_printf("thread[%d]", i);
         object_property_add_child(OBJECT(sc), id, obj, &local_err);
+        g_free(id);
         if (local_err) {
             goto err;
         }
-- 
2.17.1

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

* [Qemu-devel] [PULL 23/28] spapr_cpu_core: fix potential leak in spapr_cpu_core_realize()
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (21 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 22/28] spapr_cpu_core: convert last snprintf() to g_strdup_printf() David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 24/28] spapr_cpu_core: add missing rollback on realization path David Gibson
                   ` (5 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell; +Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, David Gibson

From: Greg Kurz <groug@kaod.org>

Commit 94ad93bd97684 (QEMU 2.12) switched to instantiate CPUs separately
but it missed to adapt the error path accordingly. If something fails in
the CPU creation loop, then the CPU object that was just created is leaked.

The error paths in this function are a bit obfuscated, and adding
yet another label to free this CPU object makes it worse. We should
move the block of the loop to a separate function, with a proper
rollback path, but this is a bigger cleanup.

For now, let's just fix the bug by adding the missing calls to
object_unref(). This will allow easier backport to older QEMU
versions.

Signed-off-by: Greg Kurz <groug@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_cpu_core.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index ad404d13ec..a9bb2d61e8 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -187,6 +187,7 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
         cs->cpu_index = cc->core_id + i;
         spapr_set_vcpu_id(cpu, cs->cpu_index, &local_err);
         if (local_err) {
+            object_unref(obj);
             goto err;
         }
 
@@ -198,6 +199,7 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
         object_property_add_child(OBJECT(sc), id, obj, &local_err);
         g_free(id);
         if (local_err) {
+            object_unref(obj);
             goto err;
         }
         object_unref(obj);
-- 
2.17.1

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

* [Qemu-devel] [PULL 24/28] spapr_cpu_core: add missing rollback on realization path
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (22 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 23/28] spapr_cpu_core: fix potential leak in spapr_cpu_core_realize() David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 25/28] spapr_cpu_core: introduce spapr_create_vcpu() David Gibson
                   ` (4 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell; +Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, David Gibson

From: Greg Kurz <groug@kaod.org>

The spapr_realize_vcpu() function doesn't rollback in case of error.
This isn't a problem with coldplugged CPUs because the machine won't
start and QEMU will exit. Hotplug is a different story though: the
CPU thread is started under object_property_set_bool() and it assumes
it can access the CPU object.

If icp_create() fails, we return an error without unregistering the
reset handler for this CPU, and we let the underlying QEMU thread for
this CPU alive. Since spapr_cpu_core_realize() doesn't care to unrealize
already realized CPUs either, but happily frees all of them anyway, the
CPU thread crashes instantly:

(qemu) device_add host-spapr-cpu-core,core-id=1,id=gku
GKU: failing icp_create (cpu 0x11497fd0)
                             ^^^^^^^^^^
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffee3feaa0 (LWP 24725)]
0x00000000104c8374 in object_dynamic_cast_assert (obj=0x11497fd0,
                                                  ^^^^^^^^^^^^^^
                                             pointer to the CPU object
623         trace_object_dynamic_cast_assert(obj ? obj->class->type->name
(gdb) p obj->class->type
$1 = (Type) 0x0
(gdb) p * obj
$2 = {class = 0x10ea9c10, free = 0x11244620,
                                 ^^^^^^^^^^
                              should be g_free
(gdb) p g_free
$3 = {<text variable, no debug info>} 0x7ffff282bef0 <g_free>

obj is a dangling pointer to the CPU that was just destroyed in
spapr_cpu_core_realize().

This patch adds proper rollback to both spapr_realize_vcpu() and
spapr_cpu_core_realize().

Signed-off-by: Greg Kurz <groug@kaod.org>
[dwg: Fixed a conflict due to a change in my tree]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_cpu_core.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index a9bb2d61e8..30a7cf9e03 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -145,11 +145,14 @@ static void spapr_realize_vcpu(PowerPCCPU *cpu, sPAPRMachineState *spapr,
     cpu->intc = icp_create(OBJECT(cpu), spapr->icp_type, XICS_FABRIC(spapr),
                            &local_err);
     if (local_err) {
-        goto error;
+        goto error_unregister;
     }
 
     return;
 
+error_unregister:
+    qemu_unregister_reset(spapr_cpu_reset, cpu);
+    cpu_remove_sync(CPU(cpu));
 error:
     error_propagate(errp, local_err);
 }
@@ -208,11 +211,15 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
     for (j = 0; j < cc->nr_threads; j++) {
         spapr_realize_vcpu(sc->threads[j], spapr, &local_err);
         if (local_err) {
-            goto err;
+            goto err_unrealize;
         }
     }
     return;
 
+err_unrealize:
+    while (--j >= 0) {
+        spapr_unrealize_vcpu(sc->threads[j]);
+    }
 err:
     while (--i >= 0) {
         obj = OBJECT(sc->threads[i]);
-- 
2.17.1

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

* [Qemu-devel] [PULL 25/28] spapr_cpu_core: introduce spapr_create_vcpu()
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (23 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 24/28] spapr_cpu_core: add missing rollback on realization path David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 26/28] ppc/pnv: introduce a pnv_chip_core_realize() routine David Gibson
                   ` (3 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell; +Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, David Gibson

From: Greg Kurz <groug@kaod.org>

This moves some code out from spapr_cpu_core_realize() for clarity. No
functional change.

Signed-off-by: Greg Kurz <groug@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_cpu_core.c | 73 +++++++++++++++++++++++++----------------
 1 file changed, 45 insertions(+), 28 deletions(-)

diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 30a7cf9e03..98a018c8d0 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -157,6 +157,49 @@ error:
     error_propagate(errp, local_err);
 }
 
+static PowerPCCPU *spapr_create_vcpu(sPAPRCPUCore *sc, int i, Error **errp)
+{
+    sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(sc);
+    CPUCore *cc = CPU_CORE(sc);
+    Object *obj;
+    char *id;
+    CPUState *cs;
+    PowerPCCPU *cpu;
+    Error *local_err = NULL;
+
+    obj = object_new(scc->cpu_type);
+
+    cs = CPU(obj);
+    cpu = POWERPC_CPU(obj);
+    cs->cpu_index = cc->core_id + i;
+    spapr_set_vcpu_id(cpu, cs->cpu_index, &local_err);
+    if (local_err) {
+        goto err;
+    }
+
+    cpu->node_id = sc->node_id;
+
+    id = g_strdup_printf("thread[%d]", i);
+    object_property_add_child(OBJECT(sc), id, obj, &local_err);
+    g_free(id);
+    if (local_err) {
+        goto err;
+    }
+
+    object_unref(obj);
+    return cpu;
+
+err:
+    object_unref(obj);
+    error_propagate(errp, local_err);
+    return NULL;
+}
+
+static void spapr_delete_vcpu(PowerPCCPU *cpu)
+{
+    object_unparent(OBJECT(cpu));
+}
+
 static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
 {
     /* We don't use SPAPR_MACHINE() in order to exit gracefully if the user
@@ -166,10 +209,8 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
         (sPAPRMachineState *) object_dynamic_cast(qdev_get_machine(),
                                                   TYPE_SPAPR_MACHINE);
     sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
-    sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev));
     CPUCore *cc = CPU_CORE(OBJECT(dev));
     Error *local_err = NULL;
-    Object *obj;
     int i, j;
 
     if (!spapr) {
@@ -179,33 +220,10 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
 
     sc->threads = g_new(PowerPCCPU *, cc->nr_threads);
     for (i = 0; i < cc->nr_threads; i++) {
-        char *id;
-        CPUState *cs;
-        PowerPCCPU *cpu;
-
-        obj = object_new(scc->cpu_type);
-
-        cs = CPU(obj);
-        cpu = sc->threads[i] = POWERPC_CPU(obj);
-        cs->cpu_index = cc->core_id + i;
-        spapr_set_vcpu_id(cpu, cs->cpu_index, &local_err);
-        if (local_err) {
-            object_unref(obj);
-            goto err;
-        }
-
-
-        /* Set NUMA node for the threads belonged to core  */
-        cpu->node_id = sc->node_id;
-
-        id = g_strdup_printf("thread[%d]", i);
-        object_property_add_child(OBJECT(sc), id, obj, &local_err);
-        g_free(id);
+        sc->threads[i] = spapr_create_vcpu(sc, i, &local_err);
         if (local_err) {
-            object_unref(obj);
             goto err;
         }
-        object_unref(obj);
     }
 
     for (j = 0; j < cc->nr_threads; j++) {
@@ -222,8 +240,7 @@ err_unrealize:
     }
 err:
     while (--i >= 0) {
-        obj = OBJECT(sc->threads[i]);
-        object_unparent(obj);
+        spapr_delete_vcpu(sc->threads[i]);
     }
     g_free(sc->threads);
     error_propagate(errp, local_err);
-- 
2.17.1

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

* [Qemu-devel] [PULL 26/28] ppc/pnv: introduce a pnv_chip_core_realize() routine
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (24 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 25/28] spapr_cpu_core: introduce spapr_create_vcpu() David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 27/28] target/ppc, spapr: Move VPA information to machine_data David Gibson
                   ` (2 subsequent siblings)
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell; +Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, David Gibson

From: Cédric Le Goater <clg@kaod.org>

This extracts from the PvChip realize routine the part creating the
cores. On Power9, we will need to create the cores after the Xive
interrupt controller is created.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/pnv.c | 32 ++++++++++++++++++++++----------
 1 file changed, 22 insertions(+), 10 deletions(-)

diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 0b9508d94d..0d2b79f798 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -849,9 +849,8 @@ static void pnv_chip_icp_realize(PnvChip *chip, Error **errp)
     }
 }
 
-static void pnv_chip_realize(DeviceState *dev, Error **errp)
+static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
 {
-    PnvChip *chip = PNV_CHIP(dev);
     Error *error = NULL;
     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
     const char *typename = pnv_chip_core_typename(chip);
@@ -863,14 +862,6 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
         return;
     }
 
-    /* XSCOM bridge */
-    pnv_xscom_realize(chip, &error);
-    if (error) {
-        error_propagate(errp, error);
-        return;
-    }
-    sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
-
     /* Cores */
     pnv_chip_core_sanitize(chip, &error);
     if (error) {
@@ -918,6 +909,27 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp)
                                 &PNV_CORE(pnv_core)->xscom_regs);
         i++;
     }
+}
+
+static void pnv_chip_realize(DeviceState *dev, Error **errp)
+{
+    PnvChip *chip = PNV_CHIP(dev);
+    Error *error = NULL;
+
+    /* XSCOM bridge */
+    pnv_xscom_realize(chip, &error);
+    if (error) {
+        error_propagate(errp, error);
+        return;
+    }
+    sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
+
+    /* Cores */
+    pnv_chip_core_realize(chip, &error);
+    if (error) {
+        error_propagate(errp, error);
+        return;
+    }
 
     /* Create LPC controller */
     object_property_set_bool(OBJECT(&chip->lpc), true, "realized",
-- 
2.17.1

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

* [Qemu-devel] [PULL 27/28] target/ppc, spapr: Move VPA information to machine_data
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (25 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 26/28] ppc/pnv: introduce a pnv_chip_core_realize() routine David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-18  3:53 ` [Qemu-devel] [PULL 28/28] spapr: fix xics_system_init() error path David Gibson
  2018-06-19 11:57 ` [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 Peter Maydell
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell; +Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, David Gibson

CPUPPCState currently contains a number of fields containing the state of
the VPA.  The VPA is a PAPR specific concept covering several guest/host
shared memory areas used to communicate some information with the
hypervisor.

As a PAPR concept this is really machine specific information, although it
is per-cpu, so it doesn't really belong in the core CPU state structure.

There's also other information that's per-cpu, but platform/machine
specific.  So create a (void *)machine_data in PowerPCCPU which can be
used by the machine to locate per-cpu data.  Intialization, lifetime and
cleanup of machine_data is entirely up to the machine type.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Greg Kurz <groug@kaod.org>
Tested-by: Greg Kurz <groug@kaod.org>
---
 hw/ppc/spapr_cpu_core.c         | 13 ++++++
 hw/ppc/spapr_hcall.c            | 77 ++++++++++++++++++---------------
 include/hw/ppc/spapr_cpu_core.h | 11 +++++
 target/ppc/cpu.h                |  7 +--
 target/ppc/kvm.c                | 39 +++++++++--------
 target/ppc/translate_init.inc.c |  8 ----
 6 files changed, 88 insertions(+), 67 deletions(-)

diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 98a018c8d0..aef3be33a3 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -28,6 +28,7 @@ static void spapr_cpu_reset(void *opaque)
     CPUState *cs = CPU(cpu);
     CPUPPCState *env = &cpu->env;
     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+    sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
     target_ulong lpcr;
 
     cpu_reset(cs);
@@ -69,6 +70,12 @@ static void spapr_cpu_reset(void *opaque)
 
     /* Set a full AMOR so guest can use the AMR as it sees fit */
     env->spr[SPR_AMOR] = 0xffffffffffffffffull;
+
+    spapr_cpu->vpa_addr = 0;
+    spapr_cpu->slb_shadow_addr = 0;
+    spapr_cpu->slb_shadow_size = 0;
+    spapr_cpu->dtl_addr = 0;
+    spapr_cpu->dtl_size = 0;
 }
 
 void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r3)
@@ -186,6 +193,8 @@ static PowerPCCPU *spapr_create_vcpu(sPAPRCPUCore *sc, int i, Error **errp)
         goto err;
     }
 
+    cpu->machine_data = g_new0(sPAPRCPUState, 1);
+
     object_unref(obj);
     return cpu;
 
@@ -197,6 +206,10 @@ err:
 
 static void spapr_delete_vcpu(PowerPCCPU *cpu)
 {
+    sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
+
+    cpu->machine_data = NULL;
+    g_free(spapr_cpu);
     object_unparent(OBJECT(cpu));
 }
 
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 8b9a4b577f..ae913d070f 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -8,6 +8,7 @@
 #include "exec/exec-all.h"
 #include "helper_regs.h"
 #include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_cpu_core.h"
 #include "mmu-hash64.h"
 #include "cpu-models.h"
 #include "trace.h"
@@ -908,9 +909,11 @@ unmap_out:
 #define VPA_SHARED_PROC_OFFSET 0x9
 #define VPA_SHARED_PROC_VAL    0x2
 
-static target_ulong register_vpa(CPUPPCState *env, target_ulong vpa)
+static target_ulong register_vpa(PowerPCCPU *cpu, target_ulong vpa)
 {
-    CPUState *cs = CPU(ppc_env_get_cpu(env));
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+    sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
     uint16_t size;
     uint8_t tmp;
 
@@ -935,32 +938,34 @@ static target_ulong register_vpa(CPUPPCState *env, target_ulong vpa)
         return H_PARAMETER;
     }
 
-    env->vpa_addr = vpa;
+    spapr_cpu->vpa_addr = vpa;
 
-    tmp = ldub_phys(cs->as, env->vpa_addr + VPA_SHARED_PROC_OFFSET);
+    tmp = ldub_phys(cs->as, spapr_cpu->vpa_addr + VPA_SHARED_PROC_OFFSET);
     tmp |= VPA_SHARED_PROC_VAL;
-    stb_phys(cs->as, env->vpa_addr + VPA_SHARED_PROC_OFFSET, tmp);
+    stb_phys(cs->as, spapr_cpu->vpa_addr + VPA_SHARED_PROC_OFFSET, tmp);
 
     return H_SUCCESS;
 }
 
-static target_ulong deregister_vpa(CPUPPCState *env, target_ulong vpa)
+static target_ulong deregister_vpa(PowerPCCPU *cpu, target_ulong vpa)
 {
-    if (env->slb_shadow_addr) {
+    sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
+
+    if (spapr_cpu->slb_shadow_addr) {
         return H_RESOURCE;
     }
 
-    if (env->dtl_addr) {
+    if (spapr_cpu->dtl_addr) {
         return H_RESOURCE;
     }
 
-    env->vpa_addr = 0;
+    spapr_cpu->vpa_addr = 0;
     return H_SUCCESS;
 }
 
-static target_ulong register_slb_shadow(CPUPPCState *env, target_ulong addr)
+static target_ulong register_slb_shadow(PowerPCCPU *cpu, target_ulong addr)
 {
-    CPUState *cs = CPU(ppc_env_get_cpu(env));
+    sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
     uint32_t size;
 
     if (addr == 0) {
@@ -968,7 +973,7 @@ static target_ulong register_slb_shadow(CPUPPCState *env, target_ulong addr)
         return H_HARDWARE;
     }
 
-    size = ldl_be_phys(cs->as, addr + 0x4);
+    size = ldl_be_phys(CPU(cpu)->as, addr + 0x4);
     if (size < 0x8) {
         return H_PARAMETER;
     }
@@ -977,26 +982,28 @@ static target_ulong register_slb_shadow(CPUPPCState *env, target_ulong addr)
         return H_PARAMETER;
     }
 
-    if (!env->vpa_addr) {
+    if (!spapr_cpu->vpa_addr) {
         return H_RESOURCE;
     }
 
-    env->slb_shadow_addr = addr;
-    env->slb_shadow_size = size;
+    spapr_cpu->slb_shadow_addr = addr;
+    spapr_cpu->slb_shadow_size = size;
 
     return H_SUCCESS;
 }
 
-static target_ulong deregister_slb_shadow(CPUPPCState *env, target_ulong addr)
+static target_ulong deregister_slb_shadow(PowerPCCPU *cpu, target_ulong addr)
 {
-    env->slb_shadow_addr = 0;
-    env->slb_shadow_size = 0;
+    sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
+
+    spapr_cpu->slb_shadow_addr = 0;
+    spapr_cpu->slb_shadow_size = 0;
     return H_SUCCESS;
 }
 
-static target_ulong register_dtl(CPUPPCState *env, target_ulong addr)
+static target_ulong register_dtl(PowerPCCPU *cpu, target_ulong addr)
 {
-    CPUState *cs = CPU(ppc_env_get_cpu(env));
+    sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
     uint32_t size;
 
     if (addr == 0) {
@@ -1004,26 +1011,28 @@ static target_ulong register_dtl(CPUPPCState *env, target_ulong addr)
         return H_HARDWARE;
     }
 
-    size = ldl_be_phys(cs->as, addr + 0x4);
+    size = ldl_be_phys(CPU(cpu)->as, addr + 0x4);
 
     if (size < 48) {
         return H_PARAMETER;
     }
 
-    if (!env->vpa_addr) {
+    if (!spapr_cpu->vpa_addr) {
         return H_RESOURCE;
     }
 
-    env->dtl_addr = addr;
-    env->dtl_size = size;
+    spapr_cpu->dtl_addr = addr;
+    spapr_cpu->dtl_size = size;
 
     return H_SUCCESS;
 }
 
-static target_ulong deregister_dtl(CPUPPCState *env, target_ulong addr)
+static target_ulong deregister_dtl(PowerPCCPU *cpu, target_ulong addr)
 {
-    env->dtl_addr = 0;
-    env->dtl_size = 0;
+    sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
+
+    spapr_cpu->dtl_addr = 0;
+    spapr_cpu->dtl_size = 0;
 
     return H_SUCCESS;
 }
@@ -1035,38 +1044,36 @@ static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPRMachineState *spapr,
     target_ulong procno = args[1];
     target_ulong vpa = args[2];
     target_ulong ret = H_PARAMETER;
-    CPUPPCState *tenv;
     PowerPCCPU *tcpu;
 
     tcpu = spapr_find_cpu(procno);
     if (!tcpu) {
         return H_PARAMETER;
     }
-    tenv = &tcpu->env;
 
     switch (flags) {
     case FLAGS_REGISTER_VPA:
-        ret = register_vpa(tenv, vpa);
+        ret = register_vpa(tcpu, vpa);
         break;
 
     case FLAGS_DEREGISTER_VPA:
-        ret = deregister_vpa(tenv, vpa);
+        ret = deregister_vpa(tcpu, vpa);
         break;
 
     case FLAGS_REGISTER_SLBSHADOW:
-        ret = register_slb_shadow(tenv, vpa);
+        ret = register_slb_shadow(tcpu, vpa);
         break;
 
     case FLAGS_DEREGISTER_SLBSHADOW:
-        ret = deregister_slb_shadow(tenv, vpa);
+        ret = deregister_slb_shadow(tcpu, vpa);
         break;
 
     case FLAGS_REGISTER_DTL:
-        ret = register_dtl(tenv, vpa);
+        ret = register_dtl(tcpu, vpa);
         break;
 
     case FLAGS_DEREGISTER_DTL:
-        ret = deregister_dtl(tenv, vpa);
+        ret = deregister_dtl(tcpu, vpa);
         break;
     }
 
diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h
index 47dcfda12b..8ceea2973a 100644
--- a/include/hw/ppc/spapr_cpu_core.h
+++ b/include/hw/ppc/spapr_cpu_core.h
@@ -41,4 +41,15 @@ typedef struct sPAPRCPUCoreClass {
 const char *spapr_get_cpu_core_type(const char *cpu_type);
 void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r3);
 
+typedef struct sPAPRCPUState {
+    uint64_t vpa_addr;
+    uint64_t slb_shadow_addr, slb_shadow_size;
+    uint64_t dtl_addr, dtl_size;
+} sPAPRCPUState;
+
+static inline sPAPRCPUState *spapr_cpu_state(PowerPCCPU *cpu)
+{
+    return (sPAPRCPUState *)cpu->machine_data;
+}
+
 #endif
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index a91f1a8777..874da6efbc 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1091,12 +1091,6 @@ struct CPUPPCState {
     target_ulong rmls;
 #endif
 
-#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
-    uint64_t vpa_addr;
-    uint64_t slb_shadow_addr, slb_shadow_size;
-    uint64_t dtl_addr, dtl_size;
-#endif /* TARGET_PPC64 */
-
     int error_code;
     uint32_t pending_interrupts;
 #if !defined(CONFIG_USER_ONLY)
@@ -1205,6 +1199,7 @@ struct PowerPCCPU {
     uint32_t compat_pvr;
     PPCVirtualHypervisor *vhyp;
     Object *intc;
+    void *machine_data;
     int32_t node_id; /* NUMA node this CPU belongs to */
     PPCHash64Options *hash64_opts;
 
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 7fe9d0126b..5c0e313ca6 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -829,22 +829,22 @@ static int kvm_get_fp(CPUState *cs)
 static int kvm_get_vpa(CPUState *cs)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
-    CPUPPCState *env = &cpu->env;
+    sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
     struct kvm_one_reg reg;
     int ret;
 
     reg.id = KVM_REG_PPC_VPA_ADDR;
-    reg.addr = (uintptr_t)&env->vpa_addr;
+    reg.addr = (uintptr_t)&spapr_cpu->vpa_addr;
     ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
     if (ret < 0) {
         DPRINTF("Unable to get VPA address from KVM: %s\n", strerror(errno));
         return ret;
     }
 
-    assert((uintptr_t)&env->slb_shadow_size
-           == ((uintptr_t)&env->slb_shadow_addr + 8));
+    assert((uintptr_t)&spapr_cpu->slb_shadow_size
+           == ((uintptr_t)&spapr_cpu->slb_shadow_addr + 8));
     reg.id = KVM_REG_PPC_VPA_SLB;
-    reg.addr = (uintptr_t)&env->slb_shadow_addr;
+    reg.addr = (uintptr_t)&spapr_cpu->slb_shadow_addr;
     ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
     if (ret < 0) {
         DPRINTF("Unable to get SLB shadow state from KVM: %s\n",
@@ -852,9 +852,10 @@ static int kvm_get_vpa(CPUState *cs)
         return ret;
     }
 
-    assert((uintptr_t)&env->dtl_size == ((uintptr_t)&env->dtl_addr + 8));
+    assert((uintptr_t)&spapr_cpu->dtl_size
+           == ((uintptr_t)&spapr_cpu->dtl_addr + 8));
     reg.id = KVM_REG_PPC_VPA_DTL;
-    reg.addr = (uintptr_t)&env->dtl_addr;
+    reg.addr = (uintptr_t)&spapr_cpu->dtl_addr;
     ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
     if (ret < 0) {
         DPRINTF("Unable to get dispatch trace log state from KVM: %s\n",
@@ -868,7 +869,7 @@ static int kvm_get_vpa(CPUState *cs)
 static int kvm_put_vpa(CPUState *cs)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
-    CPUPPCState *env = &cpu->env;
+    sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
     struct kvm_one_reg reg;
     int ret;
 
@@ -876,11 +877,12 @@ static int kvm_put_vpa(CPUState *cs)
      * registered.  That means when restoring state, if a VPA *is*
      * registered, we need to set that up first.  If not, we need to
      * deregister the others before deregistering the master VPA */
-    assert(env->vpa_addr || !(env->slb_shadow_addr || env->dtl_addr));
+    assert(spapr_cpu->vpa_addr
+           || !(spapr_cpu->slb_shadow_addr || spapr_cpu->dtl_addr));
 
-    if (env->vpa_addr) {
+    if (spapr_cpu->vpa_addr) {
         reg.id = KVM_REG_PPC_VPA_ADDR;
-        reg.addr = (uintptr_t)&env->vpa_addr;
+        reg.addr = (uintptr_t)&spapr_cpu->vpa_addr;
         ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
         if (ret < 0) {
             DPRINTF("Unable to set VPA address to KVM: %s\n", strerror(errno));
@@ -888,19 +890,20 @@ static int kvm_put_vpa(CPUState *cs)
         }
     }
 
-    assert((uintptr_t)&env->slb_shadow_size
-           == ((uintptr_t)&env->slb_shadow_addr + 8));
+    assert((uintptr_t)&spapr_cpu->slb_shadow_size
+           == ((uintptr_t)&spapr_cpu->slb_shadow_addr + 8));
     reg.id = KVM_REG_PPC_VPA_SLB;
-    reg.addr = (uintptr_t)&env->slb_shadow_addr;
+    reg.addr = (uintptr_t)&spapr_cpu->slb_shadow_addr;
     ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
     if (ret < 0) {
         DPRINTF("Unable to set SLB shadow state to KVM: %s\n", strerror(errno));
         return ret;
     }
 
-    assert((uintptr_t)&env->dtl_size == ((uintptr_t)&env->dtl_addr + 8));
+    assert((uintptr_t)&spapr_cpu->dtl_size
+           == ((uintptr_t)&spapr_cpu->dtl_addr + 8));
     reg.id = KVM_REG_PPC_VPA_DTL;
-    reg.addr = (uintptr_t)&env->dtl_addr;
+    reg.addr = (uintptr_t)&spapr_cpu->dtl_addr;
     ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
     if (ret < 0) {
         DPRINTF("Unable to set dispatch trace log state to KVM: %s\n",
@@ -908,9 +911,9 @@ static int kvm_put_vpa(CPUState *cs)
         return ret;
     }
 
-    if (!env->vpa_addr) {
+    if (!spapr_cpu->vpa_addr) {
         reg.id = KVM_REG_PPC_VPA_ADDR;
-        reg.addr = (uintptr_t)&env->vpa_addr;
+        reg.addr = (uintptr_t)&spapr_cpu->vpa_addr;
         ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
         if (ret < 0) {
             DPRINTF("Unable to set VPA address to KVM: %s\n", strerror(errno));
diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c
index bb9296f5a3..76d6f3fd5e 100644
--- a/target/ppc/translate_init.inc.c
+++ b/target/ppc/translate_init.inc.c
@@ -10316,14 +10316,6 @@ static void ppc_cpu_reset(CPUState *s)
     s->exception_index = POWERPC_EXCP_NONE;
     env->error_code = 0;
 
-#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
-    env->vpa_addr = 0;
-    env->slb_shadow_addr = 0;
-    env->slb_shadow_size = 0;
-    env->dtl_addr = 0;
-    env->dtl_size = 0;
-#endif /* TARGET_PPC64 */
-
     for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) {
         ppc_spr_t *spr = &env->spr_cb[i];
 
-- 
2.17.1

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

* [Qemu-devel] [PULL 28/28] spapr: fix xics_system_init() error path
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (26 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 27/28] target/ppc, spapr: Move VPA information to machine_data David Gibson
@ 2018-06-18  3:53 ` David Gibson
  2018-06-19 11:57 ` [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 Peter Maydell
  28 siblings, 0 replies; 30+ messages in thread
From: David Gibson @ 2018-06-18  3:53 UTC (permalink / raw)
  To: peter.maydell; +Cc: qemu-ppc, qemu-devel, groug, clg, agraf, aik, David Gibson

From: Greg Kurz <groug@kaod.org>

Commit 3d85885a1b1f3 tried to fix error handling, but it actually
went into the wrong direction by dropping the local Error *.

In the default KVM case, the rationale is to try the in-kernel XICS first,
and if not possible, to fallback to userland XICS. Passing errp everywhere
makes this fallback impossible if errp is &error_fatal (which happens to
be the case). And anyway, if the caller would pass a regular &local_err,
things would be worse: we could possibly pass an already set *errp to
error_setg() and crash, or return an error even in case of success.

So we definitely need a local Error * and only propagate it when we're
done with the fallback logic. This is what this patch does.

Signed-off-by: Greg Kurz <groug@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr.c | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index f59999daac..db0fb385d4 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -186,27 +186,33 @@ static int xics_max_server_number(sPAPRMachineState *spapr)
 static void xics_system_init(MachineState *machine, int nr_irqs, Error **errp)
 {
     sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
+    Error *local_err = NULL;
 
     if (kvm_enabled()) {
         if (machine_kernel_irqchip_allowed(machine) &&
-            !xics_kvm_init(spapr, errp)) {
+            !xics_kvm_init(spapr, &local_err)) {
             spapr->icp_type = TYPE_KVM_ICP;
-            spapr->ics = spapr_ics_create(spapr, TYPE_ICS_KVM, nr_irqs, errp);
+            spapr->ics = spapr_ics_create(spapr, TYPE_ICS_KVM, nr_irqs,
+                                          &local_err);
         }
         if (machine_kernel_irqchip_required(machine) && !spapr->ics) {
-            error_prepend(errp, "kernel_irqchip requested but unavailable: ");
-            return;
+            error_prepend(&local_err,
+                          "kernel_irqchip requested but unavailable: ");
+            goto error;
         }
+        error_free(local_err);
+        local_err = NULL;
     }
 
     if (!spapr->ics) {
         xics_spapr_init(spapr);
         spapr->icp_type = TYPE_ICP;
-        spapr->ics = spapr_ics_create(spapr, TYPE_ICS_SIMPLE, nr_irqs, errp);
-        if (!spapr->ics) {
-            return;
-        }
+        spapr->ics = spapr_ics_create(spapr, TYPE_ICS_SIMPLE, nr_irqs,
+                                      &local_err);
     }
+
+error:
+    error_propagate(errp, local_err);
 }
 
 static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
-- 
2.17.1

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

* Re: [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618
  2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
                   ` (27 preceding siblings ...)
  2018-06-18  3:53 ` [Qemu-devel] [PULL 28/28] spapr: fix xics_system_init() error path David Gibson
@ 2018-06-19 11:57 ` Peter Maydell
  28 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2018-06-19 11:57 UTC (permalink / raw)
  To: David Gibson
  Cc: qemu-ppc, QEMU Developers, Greg Kurz, Cédric Le Goater,
	Alexander Graf, Alexey Kardashevskiy

On 18 June 2018 at 04:52, David Gibson <david@gibson.dropbear.id.au> wrote:
> The following changes since commit 2ef2f16781af9dee6ba6517755e9073ba5799fa2:
>
>   Merge remote-tracking branch 'remotes/dgilbert/tags/pull-migration-20180615a' into staging (2018-06-15 18:13:35 +0100)
>
> are available in the Git repository at:
>
>   git://github.com/dgibson/qemu.git tags/ppc-for-3.0-20180618
>
> for you to fetch changes up to 844afc54ae229515a37f63519855661ad2d01d19:
>
>   spapr: fix xics_system_init() error path (2018-06-18 09:43:19 +1000)
>
> ----------------------------------------------------------------
> ppc patch queue 2018-06-18
>
> Next batch of ppc and spapr related patches for the 3.0 release.
>     * Improved handling of Spectre/Meltdown mitigations for POWER8
>     * Numerous Mac machine type cleanups and improvements
>     * Cleanup to cpu realize/unrealize path for spapr
>     * Create a place for machine-specific per-cpu information, and
>       start moving some things to it
>     * Assorted bugfixes
>

Applied, thanks.

-- PMM

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

end of thread, other threads:[~2018-06-19 11:58 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-18  3:52 [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 David Gibson
2018-06-18  3:52 ` [Qemu-devel] [PULL 01/28] target/ppc: Don't require private l1d cache on POWER8 for cap_ppc_safe_cache David Gibson
2018-06-18  3:52 ` [Qemu-devel] [PULL 02/28] ppc/spapr_caps: Don't disable cap_cfpc on POWER8 by default David Gibson
2018-06-18  3:52 ` [Qemu-devel] [PULL 03/28] target/ppc: drop empty #if/#endif block David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 04/28] spapr: fix leak in h_client_architecture_support() David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 05/28] ppc: introduce Core99MachinesState for the mac99 machine David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 06/28] mac_newworld: add via machine option to control mac99 VIA/ADB configuration David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 07/28] mac_newworld: add gpios to macio devices with PMU enabled David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 08/28] mac_newworld: wire up programmer switch to NMI handler David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 09/28] adb: fix read reg 3 byte ordering David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 10/28] adb: add property to disable direct reg 3 writes David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 11/28] mac_newworld: add PMU device David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 12/28] xics_kvm: fix a build break David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 13/28] mos6522: only clear the shift register interrupt upon write David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 14/28] mos6522: remove additional interrupt flag filter from mos6522_update_irq() David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 15/28] mos6522: expose mos6522_update_irq() through MOS6522DeviceClass David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 16/28] sm501: Do not clear read only bits when writing registers David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 17/28] spapr: Clean up cpu realize/unrealize paths David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 18/28] pnv: Fix some error handling cpu realize() David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 19/28] pnv_core: Allocate cpu thread objects individually David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 20/28] pnv: Clean up cpu realize path David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 21/28] pnv: Add cpu unrealize path David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 22/28] spapr_cpu_core: convert last snprintf() to g_strdup_printf() David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 23/28] spapr_cpu_core: fix potential leak in spapr_cpu_core_realize() David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 24/28] spapr_cpu_core: add missing rollback on realization path David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 25/28] spapr_cpu_core: introduce spapr_create_vcpu() David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 26/28] ppc/pnv: introduce a pnv_chip_core_realize() routine David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 27/28] target/ppc, spapr: Move VPA information to machine_data David Gibson
2018-06-18  3:53 ` [Qemu-devel] [PULL 28/28] spapr: fix xics_system_init() error path David Gibson
2018-06-19 11:57 ` [Qemu-devel] [PULL 00/28] ppc-for-3.0 queue 20180618 Peter Maydell

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.