]> git.proxmox.com Git - qemu.git/commitdiff
ppc: move files referencing CPU to hw/ppc/
authorPaolo Bonzini <pbonzini@redhat.com>
Tue, 5 Feb 2013 14:22:56 +0000 (15:22 +0100)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 1 Mar 2013 14:01:19 +0000 (15:01 +0100)
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
hw/mpc8544_guts.c [deleted file]
hw/ppc/Makefile.objs
hw/ppc/mpc8544_guts.c [new file with mode: 0644]
hw/ppc/ppc4xx_devs.c [new file with mode: 0644]
hw/ppc/ppce500_spin.c [new file with mode: 0644]
hw/ppc/spapr_vio.c [new file with mode: 0644]
hw/ppc/xics.c [new file with mode: 0644]
hw/ppc4xx_devs.c [deleted file]
hw/ppce500_spin.c [deleted file]
hw/spapr_vio.c [deleted file]
hw/xics.c [deleted file]

diff --git a/hw/mpc8544_guts.c b/hw/mpc8544_guts.c
deleted file mode 100644 (file)
index 193beab..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * QEMU PowerPC MPC8544 global util pseudo-device
- *
- * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
- *
- * Author: Alexander Graf, <alex@csgraf.de>
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of  the GNU General  Public License as published by
- * the Free Software Foundation;  either version 2 of the  License, or
- * (at your option) any later version.
- *
- * *****************************************************************
- *
- * The documentation for this device is noted in the MPC8544 documentation,
- * file name "MPC8544ERM.pdf". You can easily find it on the web.
- *
- */
-
-#include "hw/hw.h"
-#include "sysemu/sysemu.h"
-#include "hw/sysbus.h"
-
-#define MPC8544_GUTS_MMIO_SIZE        0x1000
-#define MPC8544_GUTS_RSTCR_RESET      0x02
-
-#define MPC8544_GUTS_ADDR_PORPLLSR    0x00
-#define MPC8544_GUTS_ADDR_PORBMSR     0x04
-#define MPC8544_GUTS_ADDR_PORIMPSCR   0x08
-#define MPC8544_GUTS_ADDR_PORDEVSR    0x0C
-#define MPC8544_GUTS_ADDR_PORDBGMSR   0x10
-#define MPC8544_GUTS_ADDR_PORDEVSR2   0x14
-#define MPC8544_GUTS_ADDR_GPPORCR     0x20
-#define MPC8544_GUTS_ADDR_GPIOCR      0x30
-#define MPC8544_GUTS_ADDR_GPOUTDR     0x40
-#define MPC8544_GUTS_ADDR_GPINDR      0x50
-#define MPC8544_GUTS_ADDR_PMUXCR      0x60
-#define MPC8544_GUTS_ADDR_DEVDISR     0x70
-#define MPC8544_GUTS_ADDR_POWMGTCSR   0x80
-#define MPC8544_GUTS_ADDR_MCPSUMR     0x90
-#define MPC8544_GUTS_ADDR_RSTRSCR     0x94
-#define MPC8544_GUTS_ADDR_PVR         0xA0
-#define MPC8544_GUTS_ADDR_SVR         0xA4
-#define MPC8544_GUTS_ADDR_RSTCR       0xB0
-#define MPC8544_GUTS_ADDR_IOVSELSR    0xC0
-#define MPC8544_GUTS_ADDR_DDRCSR      0xB20
-#define MPC8544_GUTS_ADDR_DDRCDR      0xB24
-#define MPC8544_GUTS_ADDR_DDRCLKDR    0xB28
-#define MPC8544_GUTS_ADDR_CLKOCR      0xE00
-#define MPC8544_GUTS_ADDR_SRDS1CR1    0xF04
-#define MPC8544_GUTS_ADDR_SRDS2CR1    0xF10
-#define MPC8544_GUTS_ADDR_SRDS2CR3    0xF18
-
-struct GutsState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-};
-
-typedef struct GutsState GutsState;
-
-static uint64_t mpc8544_guts_read(void *opaque, hwaddr addr,
-                                  unsigned size)
-{
-    uint32_t value = 0;
-    CPUPPCState *env = cpu_single_env;
-
-    addr &= MPC8544_GUTS_MMIO_SIZE - 1;
-    switch (addr) {
-    case MPC8544_GUTS_ADDR_PVR:
-        value = env->spr[SPR_PVR];
-        break;
-    case MPC8544_GUTS_ADDR_SVR:
-        value = env->spr[SPR_E500_SVR];
-        break;
-    default:
-        fprintf(stderr, "guts: Unknown register read: %x\n", (int)addr);
-        break;
-    }
-
-    return value;
-}
-
-static void mpc8544_guts_write(void *opaque, hwaddr addr,
-                               uint64_t value, unsigned size)
-{
-    addr &= MPC8544_GUTS_MMIO_SIZE - 1;
-
-    switch (addr) {
-    case MPC8544_GUTS_ADDR_RSTCR:
-        if (value & MPC8544_GUTS_RSTCR_RESET) {
-            qemu_system_reset_request();
-        }
-        break;
-    default:
-        fprintf(stderr, "guts: Unknown register write: %x = %x\n",
-                (int)addr, (unsigned)value);
-        break;
-    }
-}
-
-static const MemoryRegionOps mpc8544_guts_ops = {
-    .read = mpc8544_guts_read,
-    .write = mpc8544_guts_write,
-    .endianness = DEVICE_BIG_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static int mpc8544_guts_initfn(SysBusDevice *dev)
-{
-    GutsState *s;
-
-    s = FROM_SYSBUS(GutsState, SYS_BUS_DEVICE(dev));
-
-    memory_region_init_io(&s->iomem, &mpc8544_guts_ops, s,
-                          "mpc6544.guts", MPC8544_GUTS_MMIO_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static void mpc8544_guts_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = mpc8544_guts_initfn;
-}
-
-static const TypeInfo mpc8544_guts_info = {
-    .name          = "mpc8544-guts",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(GutsState),
-    .class_init    = mpc8544_guts_class_init,
-};
-
-static void mpc8544_guts_register_types(void)
-{
-    type_register_static(&mpc8544_guts_info);
-}
-
-type_init(mpc8544_guts_register_types)
index 294d0de2119c3c4341acf5213ecdee4782e9d1f9..acc9961ab00240b62f2689e2ca68706c549e4be1 100644 (file)
@@ -1,14 +1,12 @@
 # PREP target
 obj-y += mc146818rtc.o
 # IBM pSeries (sPAPR)
-obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_rtas.o spapr_vio.o
-obj-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o
+obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_rtas.o
+obj-$(CONFIG_PSERIES) += spapr_vty.o spapr_llan.o spapr_vscsi.o
 obj-$(CONFIG_PSERIES) += spapr_pci.o pci/pci-hotplug.o spapr_iommu.o
 obj-$(CONFIG_PSERIES) += spapr_events.o spapr_nvram.o
 # PowerPC 4xx boards
-obj-y += ppc4xx_devs.o ppc4xx_pci.o
-# PowerPC E500 boards
-obj-$(CONFIG_E500) += mpc8544_guts.o ppce500_spin.o
+obj-y += ppc4xx_pci.o
 # PowerPC OpenPIC
 obj-y += openpic.o
 
@@ -20,9 +18,9 @@ obj-y := $(addprefix ../,$(obj-y))
 # shared objects
 obj-y += ppc.o ppc_booke.o
 # IBM pSeries (sPAPR)
-obj-$(CONFIG_PSERIES) += spapr.o
+obj-$(CONFIG_PSERIES) += spapr.o xics.o spapr_vio.o
 # PowerPC 4xx boards
-obj-y += ppc405_boards.o ppc405_uc.o ppc440_bamboo.o
+obj-y += ppc405_boards.o ppc4xx_devs.o ppc405_uc.o ppc440_bamboo.o
 # PReP
 obj-y += prep.o
 # OldWorld PowerMac
@@ -31,5 +29,6 @@ obj-y += mac_oldworld.o
 obj-y += mac_newworld.o
 # e500
 obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o
+obj-$(CONFIG_E500) += mpc8544_guts.o ppce500_spin.o
 # PowerPC 440 Xilinx ML507 reference board.
 obj-y += virtex_ml507.o
diff --git a/hw/ppc/mpc8544_guts.c b/hw/ppc/mpc8544_guts.c
new file mode 100644 (file)
index 0000000..193beab
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * QEMU PowerPC MPC8544 global util pseudo-device
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Alexander Graf, <alex@csgraf.de>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of  the GNU General  Public License as published by
+ * the Free Software Foundation;  either version 2 of the  License, or
+ * (at your option) any later version.
+ *
+ * *****************************************************************
+ *
+ * The documentation for this device is noted in the MPC8544 documentation,
+ * file name "MPC8544ERM.pdf". You can easily find it on the web.
+ *
+ */
+
+#include "hw/hw.h"
+#include "sysemu/sysemu.h"
+#include "hw/sysbus.h"
+
+#define MPC8544_GUTS_MMIO_SIZE        0x1000
+#define MPC8544_GUTS_RSTCR_RESET      0x02
+
+#define MPC8544_GUTS_ADDR_PORPLLSR    0x00
+#define MPC8544_GUTS_ADDR_PORBMSR     0x04
+#define MPC8544_GUTS_ADDR_PORIMPSCR   0x08
+#define MPC8544_GUTS_ADDR_PORDEVSR    0x0C
+#define MPC8544_GUTS_ADDR_PORDBGMSR   0x10
+#define MPC8544_GUTS_ADDR_PORDEVSR2   0x14
+#define MPC8544_GUTS_ADDR_GPPORCR     0x20
+#define MPC8544_GUTS_ADDR_GPIOCR      0x30
+#define MPC8544_GUTS_ADDR_GPOUTDR     0x40
+#define MPC8544_GUTS_ADDR_GPINDR      0x50
+#define MPC8544_GUTS_ADDR_PMUXCR      0x60
+#define MPC8544_GUTS_ADDR_DEVDISR     0x70
+#define MPC8544_GUTS_ADDR_POWMGTCSR   0x80
+#define MPC8544_GUTS_ADDR_MCPSUMR     0x90
+#define MPC8544_GUTS_ADDR_RSTRSCR     0x94
+#define MPC8544_GUTS_ADDR_PVR         0xA0
+#define MPC8544_GUTS_ADDR_SVR         0xA4
+#define MPC8544_GUTS_ADDR_RSTCR       0xB0
+#define MPC8544_GUTS_ADDR_IOVSELSR    0xC0
+#define MPC8544_GUTS_ADDR_DDRCSR      0xB20
+#define MPC8544_GUTS_ADDR_DDRCDR      0xB24
+#define MPC8544_GUTS_ADDR_DDRCLKDR    0xB28
+#define MPC8544_GUTS_ADDR_CLKOCR      0xE00
+#define MPC8544_GUTS_ADDR_SRDS1CR1    0xF04
+#define MPC8544_GUTS_ADDR_SRDS2CR1    0xF10
+#define MPC8544_GUTS_ADDR_SRDS2CR3    0xF18
+
+struct GutsState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+};
+
+typedef struct GutsState GutsState;
+
+static uint64_t mpc8544_guts_read(void *opaque, hwaddr addr,
+                                  unsigned size)
+{
+    uint32_t value = 0;
+    CPUPPCState *env = cpu_single_env;
+
+    addr &= MPC8544_GUTS_MMIO_SIZE - 1;
+    switch (addr) {
+    case MPC8544_GUTS_ADDR_PVR:
+        value = env->spr[SPR_PVR];
+        break;
+    case MPC8544_GUTS_ADDR_SVR:
+        value = env->spr[SPR_E500_SVR];
+        break;
+    default:
+        fprintf(stderr, "guts: Unknown register read: %x\n", (int)addr);
+        break;
+    }
+
+    return value;
+}
+
+static void mpc8544_guts_write(void *opaque, hwaddr addr,
+                               uint64_t value, unsigned size)
+{
+    addr &= MPC8544_GUTS_MMIO_SIZE - 1;
+
+    switch (addr) {
+    case MPC8544_GUTS_ADDR_RSTCR:
+        if (value & MPC8544_GUTS_RSTCR_RESET) {
+            qemu_system_reset_request();
+        }
+        break;
+    default:
+        fprintf(stderr, "guts: Unknown register write: %x = %x\n",
+                (int)addr, (unsigned)value);
+        break;
+    }
+}
+
+static const MemoryRegionOps mpc8544_guts_ops = {
+    .read = mpc8544_guts_read,
+    .write = mpc8544_guts_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static int mpc8544_guts_initfn(SysBusDevice *dev)
+{
+    GutsState *s;
+
+    s = FROM_SYSBUS(GutsState, SYS_BUS_DEVICE(dev));
+
+    memory_region_init_io(&s->iomem, &mpc8544_guts_ops, s,
+                          "mpc6544.guts", MPC8544_GUTS_MMIO_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void mpc8544_guts_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mpc8544_guts_initfn;
+}
+
+static const TypeInfo mpc8544_guts_info = {
+    .name          = "mpc8544-guts",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(GutsState),
+    .class_init    = mpc8544_guts_class_init,
+};
+
+static void mpc8544_guts_register_types(void)
+{
+    type_register_static(&mpc8544_guts_info);
+}
+
+type_init(mpc8544_guts_register_types)
diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
new file mode 100644 (file)
index 0000000..49ec728
--- /dev/null
@@ -0,0 +1,721 @@
+/*
+ * QEMU PowerPC 4xx embedded processors shared devices emulation
+ *
+ * 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 "hw/hw.h"
+#include "hw/ppc.h"
+#include "hw/ppc4xx.h"
+#include "qemu/log.h"
+#include "exec/address-spaces.h"
+
+//#define DEBUG_MMIO
+//#define DEBUG_UNASSIGNED
+#define DEBUG_UIC
+
+
+#ifdef DEBUG_UIC
+#  define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
+#else
+#  define LOG_UIC(...) do { } while (0)
+#endif
+
+static void ppc4xx_reset(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+
+    cpu_reset(CPU(cpu));
+}
+
+/*****************************************************************************/
+/* Generic PowerPC 4xx processor instantiation */
+PowerPCCPU *ppc4xx_init(const char *cpu_model,
+                        clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
+                        uint32_t sysclk)
+{
+    PowerPCCPU *cpu;
+    CPUPPCState *env;
+
+    /* init CPUs */
+    cpu = cpu_ppc_init(cpu_model);
+    if (cpu == NULL) {
+        fprintf(stderr, "Unable to find PowerPC %s CPU definition\n",
+                cpu_model);
+        exit(1);
+    }
+    env = &cpu->env;
+
+    cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
+    cpu_clk->opaque = env;
+    /* Set time-base frequency to sysclk */
+    tb_clk->cb = ppc_40x_timers_init(env, sysclk, PPC_INTERRUPT_PIT);
+    tb_clk->opaque = env;
+    ppc_dcr_init(env, NULL, NULL);
+    /* Register qemu callbacks */
+    qemu_register_reset(ppc4xx_reset, cpu);
+
+    return cpu;
+}
+
+/*****************************************************************************/
+/* "Universal" Interrupt controller */
+enum {
+    DCR_UICSR  = 0x000,
+    DCR_UICSRS = 0x001,
+    DCR_UICER  = 0x002,
+    DCR_UICCR  = 0x003,
+    DCR_UICPR  = 0x004,
+    DCR_UICTR  = 0x005,
+    DCR_UICMSR = 0x006,
+    DCR_UICVR  = 0x007,
+    DCR_UICVCR = 0x008,
+    DCR_UICMAX = 0x009,
+};
+
+#define UIC_MAX_IRQ 32
+typedef struct ppcuic_t ppcuic_t;
+struct ppcuic_t {
+    uint32_t dcr_base;
+    int use_vectors;
+    uint32_t level;  /* Remembers the state of level-triggered interrupts. */
+    uint32_t uicsr;  /* Status register */
+    uint32_t uicer;  /* Enable register */
+    uint32_t uiccr;  /* Critical register */
+    uint32_t uicpr;  /* Polarity register */
+    uint32_t uictr;  /* Triggering register */
+    uint32_t uicvcr; /* Vector configuration register */
+    uint32_t uicvr;
+    qemu_irq *irqs;
+};
+
+static void ppcuic_trigger_irq (ppcuic_t *uic)
+{
+    uint32_t ir, cr;
+    int start, end, inc, i;
+
+    /* Trigger interrupt if any is pending */
+    ir = uic->uicsr & uic->uicer & (~uic->uiccr);
+    cr = uic->uicsr & uic->uicer & uic->uiccr;
+    LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32
+                " uiccr %08" PRIx32 "\n"
+                "   %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
+                __func__, uic->uicsr, uic->uicer, uic->uiccr,
+                uic->uicsr & uic->uicer, ir, cr);
+    if (ir != 0x0000000) {
+        LOG_UIC("Raise UIC interrupt\n");
+        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]);
+    } else {
+        LOG_UIC("Lower UIC interrupt\n");
+        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]);
+    }
+    /* Trigger critical interrupt if any is pending and update vector */
+    if (cr != 0x0000000) {
+        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]);
+        if (uic->use_vectors) {
+            /* Compute critical IRQ vector */
+            if (uic->uicvcr & 1) {
+                start = 31;
+                end = 0;
+                inc = -1;
+            } else {
+                start = 0;
+                end = 31;
+                inc = 1;
+            }
+            uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
+            for (i = start; i <= end; i += inc) {
+                if (cr & (1 << i)) {
+                    uic->uicvr += (i - start) * 512 * inc;
+                    break;
+                }
+            }
+        }
+        LOG_UIC("Raise UIC critical interrupt - "
+                    "vector %08" PRIx32 "\n", uic->uicvr);
+    } else {
+        LOG_UIC("Lower UIC critical interrupt\n");
+        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]);
+        uic->uicvr = 0x00000000;
+    }
+}
+
+static void ppcuic_set_irq (void *opaque, int irq_num, int level)
+{
+    ppcuic_t *uic;
+    uint32_t mask, sr;
+
+    uic = opaque;
+    mask = 1 << (31-irq_num);
+    LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
+                " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
+                __func__, irq_num, level,
+                uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
+    if (irq_num < 0 || irq_num > 31)
+        return;
+    sr = uic->uicsr;
+
+    /* Update status register */
+    if (uic->uictr & mask) {
+        /* Edge sensitive interrupt */
+        if (level == 1)
+            uic->uicsr |= mask;
+    } else {
+        /* Level sensitive interrupt */
+        if (level == 1) {
+            uic->uicsr |= mask;
+            uic->level |= mask;
+        } else {
+            uic->uicsr &= ~mask;
+            uic->level &= ~mask;
+        }
+    }
+    LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
+                "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
+    if (sr != uic->uicsr)
+        ppcuic_trigger_irq(uic);
+}
+
+static uint32_t dcr_read_uic (void *opaque, int dcrn)
+{
+    ppcuic_t *uic;
+    uint32_t ret;
+
+    uic = opaque;
+    dcrn -= uic->dcr_base;
+    switch (dcrn) {
+    case DCR_UICSR:
+    case DCR_UICSRS:
+        ret = uic->uicsr;
+        break;
+    case DCR_UICER:
+        ret = uic->uicer;
+        break;
+    case DCR_UICCR:
+        ret = uic->uiccr;
+        break;
+    case DCR_UICPR:
+        ret = uic->uicpr;
+        break;
+    case DCR_UICTR:
+        ret = uic->uictr;
+        break;
+    case DCR_UICMSR:
+        ret = uic->uicsr & uic->uicer;
+        break;
+    case DCR_UICVR:
+        if (!uic->use_vectors)
+            goto no_read;
+        ret = uic->uicvr;
+        break;
+    case DCR_UICVCR:
+        if (!uic->use_vectors)
+            goto no_read;
+        ret = uic->uicvcr;
+        break;
+    default:
+    no_read:
+        ret = 0x00000000;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_uic (void *opaque, int dcrn, uint32_t val)
+{
+    ppcuic_t *uic;
+
+    uic = opaque;
+    dcrn -= uic->dcr_base;
+    LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val);
+    switch (dcrn) {
+    case DCR_UICSR:
+        uic->uicsr &= ~val;
+        uic->uicsr |= uic->level;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICSRS:
+        uic->uicsr |= val;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICER:
+        uic->uicer = val;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICCR:
+        uic->uiccr = val;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICPR:
+        uic->uicpr = val;
+        break;
+    case DCR_UICTR:
+        uic->uictr = val;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICMSR:
+        break;
+    case DCR_UICVR:
+        break;
+    case DCR_UICVCR:
+        uic->uicvcr = val & 0xFFFFFFFD;
+        ppcuic_trigger_irq(uic);
+        break;
+    }
+}
+
+static void ppcuic_reset (void *opaque)
+{
+    ppcuic_t *uic;
+
+    uic = opaque;
+    uic->uiccr = 0x00000000;
+    uic->uicer = 0x00000000;
+    uic->uicpr = 0x00000000;
+    uic->uicsr = 0x00000000;
+    uic->uictr = 0x00000000;
+    if (uic->use_vectors) {
+        uic->uicvcr = 0x00000000;
+        uic->uicvr = 0x0000000;
+    }
+}
+
+qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs,
+                       uint32_t dcr_base, int has_ssr, int has_vr)
+{
+    ppcuic_t *uic;
+    int i;
+
+    uic = g_malloc0(sizeof(ppcuic_t));
+    uic->dcr_base = dcr_base;
+    uic->irqs = irqs;
+    if (has_vr)
+        uic->use_vectors = 1;
+    for (i = 0; i < DCR_UICMAX; i++) {
+        ppc_dcr_register(env, dcr_base + i, uic,
+                         &dcr_read_uic, &dcr_write_uic);
+    }
+    qemu_register_reset(ppcuic_reset, uic);
+
+    return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ);
+}
+
+/*****************************************************************************/
+/* SDRAM controller */
+typedef struct ppc4xx_sdram_t ppc4xx_sdram_t;
+struct ppc4xx_sdram_t {
+    uint32_t addr;
+    int nbanks;
+    MemoryRegion containers[4]; /* used for clipping */
+    MemoryRegion *ram_memories;
+    hwaddr ram_bases[4];
+    hwaddr ram_sizes[4];
+    uint32_t besr0;
+    uint32_t besr1;
+    uint32_t bear;
+    uint32_t cfg;
+    uint32_t status;
+    uint32_t rtr;
+    uint32_t pmit;
+    uint32_t bcr[4];
+    uint32_t tr;
+    uint32_t ecccfg;
+    uint32_t eccesr;
+    qemu_irq irq;
+};
+
+enum {
+    SDRAM0_CFGADDR = 0x010,
+    SDRAM0_CFGDATA = 0x011,
+};
+
+/* XXX: TOFIX: some patches have made this code become inconsistent:
+ *      there are type inconsistencies, mixing hwaddr, target_ulong
+ *      and uint32_t
+ */
+static uint32_t sdram_bcr (hwaddr ram_base,
+                           hwaddr ram_size)
+{
+    uint32_t bcr;
+
+    switch (ram_size) {
+    case (4 * 1024 * 1024):
+        bcr = 0x00000000;
+        break;
+    case (8 * 1024 * 1024):
+        bcr = 0x00020000;
+        break;
+    case (16 * 1024 * 1024):
+        bcr = 0x00040000;
+        break;
+    case (32 * 1024 * 1024):
+        bcr = 0x00060000;
+        break;
+    case (64 * 1024 * 1024):
+        bcr = 0x00080000;
+        break;
+    case (128 * 1024 * 1024):
+        bcr = 0x000A0000;
+        break;
+    case (256 * 1024 * 1024):
+        bcr = 0x000C0000;
+        break;
+    default:
+        printf("%s: invalid RAM size " TARGET_FMT_plx "\n", __func__,
+               ram_size);
+        return 0x00000000;
+    }
+    bcr |= ram_base & 0xFF800000;
+    bcr |= 1;
+
+    return bcr;
+}
+
+static inline hwaddr sdram_base(uint32_t bcr)
+{
+    return bcr & 0xFF800000;
+}
+
+static target_ulong sdram_size (uint32_t bcr)
+{
+    target_ulong size;
+    int sh;
+
+    sh = (bcr >> 17) & 0x7;
+    if (sh == 7)
+        size = -1;
+    else
+        size = (4 * 1024 * 1024) << sh;
+
+    return size;
+}
+
+static void sdram_set_bcr(ppc4xx_sdram_t *sdram,
+                          uint32_t *bcrp, uint32_t bcr, int enabled)
+{
+    unsigned n = bcrp - sdram->bcr;
+
+    if (*bcrp & 0x00000001) {
+        /* Unmap RAM */
+#ifdef DEBUG_SDRAM
+        printf("%s: unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
+               __func__, sdram_base(*bcrp), sdram_size(*bcrp));
+#endif
+        memory_region_del_subregion(get_system_memory(),
+                                    &sdram->containers[n]);
+        memory_region_del_subregion(&sdram->containers[n],
+                                    &sdram->ram_memories[n]);
+        memory_region_destroy(&sdram->containers[n]);
+    }
+    *bcrp = bcr & 0xFFDEE001;
+    if (enabled && (bcr & 0x00000001)) {
+#ifdef DEBUG_SDRAM
+        printf("%s: Map RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
+               __func__, sdram_base(bcr), sdram_size(bcr));
+#endif
+        memory_region_init(&sdram->containers[n], "sdram-containers",
+                           sdram_size(bcr));
+        memory_region_add_subregion(&sdram->containers[n], 0,
+                                    &sdram->ram_memories[n]);
+        memory_region_add_subregion(get_system_memory(),
+                                    sdram_base(bcr),
+                                    &sdram->containers[n]);
+    }
+}
+
+static void sdram_map_bcr (ppc4xx_sdram_t *sdram)
+{
+    int i;
+
+    for (i = 0; i < sdram->nbanks; i++) {
+        if (sdram->ram_sizes[i] != 0) {
+            sdram_set_bcr(sdram,
+                          &sdram->bcr[i],
+                          sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]),
+                          1);
+        } else {
+            sdram_set_bcr(sdram, &sdram->bcr[i], 0x00000000, 0);
+        }
+    }
+}
+
+static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram)
+{
+    int i;
+
+    for (i = 0; i < sdram->nbanks; i++) {
+#ifdef DEBUG_SDRAM
+        printf("%s: Unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
+               __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i]));
+#endif
+        memory_region_del_subregion(get_system_memory(),
+                                    &sdram->ram_memories[i]);
+    }
+}
+
+static uint32_t dcr_read_sdram (void *opaque, int dcrn)
+{
+    ppc4xx_sdram_t *sdram;
+    uint32_t ret;
+
+    sdram = opaque;
+    switch (dcrn) {
+    case SDRAM0_CFGADDR:
+        ret = sdram->addr;
+        break;
+    case SDRAM0_CFGDATA:
+        switch (sdram->addr) {
+        case 0x00: /* SDRAM_BESR0 */
+            ret = sdram->besr0;
+            break;
+        case 0x08: /* SDRAM_BESR1 */
+            ret = sdram->besr1;
+            break;
+        case 0x10: /* SDRAM_BEAR */
+            ret = sdram->bear;
+            break;
+        case 0x20: /* SDRAM_CFG */
+            ret = sdram->cfg;
+            break;
+        case 0x24: /* SDRAM_STATUS */
+            ret = sdram->status;
+            break;
+        case 0x30: /* SDRAM_RTR */
+            ret = sdram->rtr;
+            break;
+        case 0x34: /* SDRAM_PMIT */
+            ret = sdram->pmit;
+            break;
+        case 0x40: /* SDRAM_B0CR */
+            ret = sdram->bcr[0];
+            break;
+        case 0x44: /* SDRAM_B1CR */
+            ret = sdram->bcr[1];
+            break;
+        case 0x48: /* SDRAM_B2CR */
+            ret = sdram->bcr[2];
+            break;
+        case 0x4C: /* SDRAM_B3CR */
+            ret = sdram->bcr[3];
+            break;
+        case 0x80: /* SDRAM_TR */
+            ret = -1; /* ? */
+            break;
+        case 0x94: /* SDRAM_ECCCFG */
+            ret = sdram->ecccfg;
+            break;
+        case 0x98: /* SDRAM_ECCESR */
+            ret = sdram->eccesr;
+            break;
+        default: /* Error */
+            ret = -1;
+            break;
+        }
+        break;
+    default:
+        /* Avoid gcc warning */
+        ret = 0x00000000;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val)
+{
+    ppc4xx_sdram_t *sdram;
+
+    sdram = opaque;
+    switch (dcrn) {
+    case SDRAM0_CFGADDR:
+        sdram->addr = val;
+        break;
+    case SDRAM0_CFGDATA:
+        switch (sdram->addr) {
+        case 0x00: /* SDRAM_BESR0 */
+            sdram->besr0 &= ~val;
+            break;
+        case 0x08: /* SDRAM_BESR1 */
+            sdram->besr1 &= ~val;
+            break;
+        case 0x10: /* SDRAM_BEAR */
+            sdram->bear = val;
+            break;
+        case 0x20: /* SDRAM_CFG */
+            val &= 0xFFE00000;
+            if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) {
+#ifdef DEBUG_SDRAM
+                printf("%s: enable SDRAM controller\n", __func__);
+#endif
+                /* validate all RAM mappings */
+                sdram_map_bcr(sdram);
+                sdram->status &= ~0x80000000;
+            } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) {
+#ifdef DEBUG_SDRAM
+                printf("%s: disable SDRAM controller\n", __func__);
+#endif
+                /* invalidate all RAM mappings */
+                sdram_unmap_bcr(sdram);
+                sdram->status |= 0x80000000;
+            }
+            if (!(sdram->cfg & 0x40000000) && (val & 0x40000000))
+                sdram->status |= 0x40000000;
+            else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000))
+                sdram->status &= ~0x40000000;
+            sdram->cfg = val;
+            break;
+        case 0x24: /* SDRAM_STATUS */
+            /* Read-only register */
+            break;
+        case 0x30: /* SDRAM_RTR */
+            sdram->rtr = val & 0x3FF80000;
+            break;
+        case 0x34: /* SDRAM_PMIT */
+            sdram->pmit = (val & 0xF8000000) | 0x07C00000;
+            break;
+        case 0x40: /* SDRAM_B0CR */
+            sdram_set_bcr(sdram, &sdram->bcr[0], val, sdram->cfg & 0x80000000);
+            break;
+        case 0x44: /* SDRAM_B1CR */
+            sdram_set_bcr(sdram, &sdram->bcr[1], val, sdram->cfg & 0x80000000);
+            break;
+        case 0x48: /* SDRAM_B2CR */
+            sdram_set_bcr(sdram, &sdram->bcr[2], val, sdram->cfg & 0x80000000);
+            break;
+        case 0x4C: /* SDRAM_B3CR */
+            sdram_set_bcr(sdram, &sdram->bcr[3], val, sdram->cfg & 0x80000000);
+            break;
+        case 0x80: /* SDRAM_TR */
+            sdram->tr = val & 0x018FC01F;
+            break;
+        case 0x94: /* SDRAM_ECCCFG */
+            sdram->ecccfg = val & 0x00F00000;
+            break;
+        case 0x98: /* SDRAM_ECCESR */
+            val &= 0xFFF0F000;
+            if (sdram->eccesr == 0 && val != 0)
+                qemu_irq_raise(sdram->irq);
+            else if (sdram->eccesr != 0 && val == 0)
+                qemu_irq_lower(sdram->irq);
+            sdram->eccesr = val;
+            break;
+        default: /* Error */
+            break;
+        }
+        break;
+    }
+}
+
+static void sdram_reset (void *opaque)
+{
+    ppc4xx_sdram_t *sdram;
+
+    sdram = opaque;
+    sdram->addr = 0x00000000;
+    sdram->bear = 0x00000000;
+    sdram->besr0 = 0x00000000; /* No error */
+    sdram->besr1 = 0x00000000; /* No error */
+    sdram->cfg = 0x00000000;
+    sdram->ecccfg = 0x00000000; /* No ECC */
+    sdram->eccesr = 0x00000000; /* No error */
+    sdram->pmit = 0x07C00000;
+    sdram->rtr = 0x05F00000;
+    sdram->tr = 0x00854009;
+    /* We pre-initialize RAM banks */
+    sdram->status = 0x00000000;
+    sdram->cfg = 0x00800000;
+}
+
+void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks,
+                        MemoryRegion *ram_memories,
+                        hwaddr *ram_bases,
+                        hwaddr *ram_sizes,
+                        int do_init)
+{
+    ppc4xx_sdram_t *sdram;
+
+    sdram = g_malloc0(sizeof(ppc4xx_sdram_t));
+    sdram->irq = irq;
+    sdram->nbanks = nbanks;
+    sdram->ram_memories = ram_memories;
+    memset(sdram->ram_bases, 0, 4 * sizeof(hwaddr));
+    memcpy(sdram->ram_bases, ram_bases,
+           nbanks * sizeof(hwaddr));
+    memset(sdram->ram_sizes, 0, 4 * sizeof(hwaddr));
+    memcpy(sdram->ram_sizes, ram_sizes,
+           nbanks * sizeof(hwaddr));
+    qemu_register_reset(&sdram_reset, sdram);
+    ppc_dcr_register(env, SDRAM0_CFGADDR,
+                     sdram, &dcr_read_sdram, &dcr_write_sdram);
+    ppc_dcr_register(env, SDRAM0_CFGDATA,
+                     sdram, &dcr_read_sdram, &dcr_write_sdram);
+    if (do_init)
+        sdram_map_bcr(sdram);
+}
+
+/* Fill in consecutive SDRAM banks with 'ram_size' bytes of memory.
+ *
+ * sdram_bank_sizes[] must be 0-terminated.
+ *
+ * The 4xx SDRAM controller supports a small number of banks, and each bank
+ * must be one of a small set of sizes. The number of banks and the supported
+ * sizes varies by SoC. */
+ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
+                               MemoryRegion ram_memories[],
+                               hwaddr ram_bases[],
+                               hwaddr ram_sizes[],
+                               const unsigned int sdram_bank_sizes[])
+{
+    ram_addr_t size_left = ram_size;
+    ram_addr_t base = 0;
+    int i;
+    int j;
+
+    for (i = 0; i < nr_banks; i++) {
+        for (j = 0; sdram_bank_sizes[j] != 0; j++) {
+            unsigned int bank_size = sdram_bank_sizes[j];
+
+            if (bank_size <= size_left) {
+                char name[32];
+                snprintf(name, sizeof(name), "ppc4xx.sdram%d", i);
+                memory_region_init_ram(&ram_memories[i], name, bank_size);
+                vmstate_register_ram_global(&ram_memories[i]);
+                ram_bases[i] = base;
+                ram_sizes[i] = bank_size;
+                base += bank_size;
+                size_left -= bank_size;
+                break;
+            }
+        }
+
+        if (!size_left) {
+            /* No need to use the remaining banks. */
+            break;
+        }
+    }
+
+    ram_size -= size_left;
+    if (size_left)
+        printf("Truncating memory to %d MiB to fit SDRAM controller limits.\n",
+               (int)(ram_size >> 20));
+
+    return ram_size;
+}
diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c
new file mode 100644 (file)
index 0000000..d904fbe
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * QEMU PowerPC e500v2 ePAPR spinning code
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Alexander Graf, <agraf@suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * This code is not really a device, but models an interface that usually
+ * firmware takes care of. It's used when QEMU plays the role of firmware.
+ *
+ * Specification:
+ *
+ * https://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.1.pdf
+ *
+ */
+
+#include "hw/hw.h"
+#include "sysemu/sysemu.h"
+#include "hw/sysbus.h"
+#include "sysemu/kvm.h"
+
+#define MAX_CPUS 32
+
+typedef struct spin_info {
+    uint64_t addr;
+    uint64_t r3;
+    uint32_t resv;
+    uint32_t pir;
+    uint64_t reserved;
+} QEMU_PACKED SpinInfo;
+
+typedef struct spin_state {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    SpinInfo spin[MAX_CPUS];
+} SpinState;
+
+typedef struct spin_kick {
+    PowerPCCPU *cpu;
+    SpinInfo *spin;
+} SpinKick;
+
+static void spin_reset(void *opaque)
+{
+    SpinState *s = opaque;
+    int i;
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        SpinInfo *info = &s->spin[i];
+
+        info->pir = i;
+        info->r3 = i;
+        info->addr = 1;
+    }
+}
+
+/* Create -kernel TLB entries for BookE, linearly spanning 256MB.  */
+static inline hwaddr booke206_page_size_to_tlb(uint64_t size)
+{
+    return (ffs(size >> 10) - 1) >> 1;
+}
+
+static void mmubooke_create_initial_mapping(CPUPPCState *env,
+                                     target_ulong va,
+                                     hwaddr pa,
+                                     hwaddr len)
+{
+    ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1);
+    hwaddr size;
+
+    size = (booke206_page_size_to_tlb(len) << MAS1_TSIZE_SHIFT);
+    tlb->mas1 = MAS1_VALID | size;
+    tlb->mas2 = (va & TARGET_PAGE_MASK) | MAS2_M;
+    tlb->mas7_3 = pa & TARGET_PAGE_MASK;
+    tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
+    env->tlb_dirty = true;
+}
+
+static void spin_kick(void *data)
+{
+    SpinKick *kick = data;
+    CPUState *cpu = CPU(kick->cpu);
+    CPUPPCState *env = &kick->cpu->env;
+    SpinInfo *curspin = kick->spin;
+    hwaddr map_size = 64 * 1024 * 1024;
+    hwaddr map_start;
+
+    cpu_synchronize_state(env);
+    stl_p(&curspin->pir, env->spr[SPR_PIR]);
+    env->nip = ldq_p(&curspin->addr) & (map_size - 1);
+    env->gpr[3] = ldq_p(&curspin->r3);
+    env->gpr[4] = 0;
+    env->gpr[5] = 0;
+    env->gpr[6] = 0;
+    env->gpr[7] = map_size;
+    env->gpr[8] = 0;
+    env->gpr[9] = 0;
+
+    map_start = ldq_p(&curspin->addr) & ~(map_size - 1);
+    mmubooke_create_initial_mapping(env, 0, map_start, map_size);
+
+    env->halted = 0;
+    env->exception_index = -1;
+    cpu->stopped = false;
+    qemu_cpu_kick(cpu);
+}
+
+static void spin_write(void *opaque, hwaddr addr, uint64_t value,
+                       unsigned len)
+{
+    SpinState *s = opaque;
+    int env_idx = addr / sizeof(SpinInfo);
+    CPUState *cpu;
+    SpinInfo *curspin = &s->spin[env_idx];
+    uint8_t *curspin_p = (uint8_t*)curspin;
+
+    cpu = qemu_get_cpu(env_idx);
+    if (cpu == NULL) {
+        /* Unknown CPU */
+        return;
+    }
+
+    if (cpu->cpu_index == 0) {
+        /* primary CPU doesn't spin */
+        return;
+    }
+
+    curspin_p = &curspin_p[addr % sizeof(SpinInfo)];
+    switch (len) {
+    case 1:
+        stb_p(curspin_p, value);
+        break;
+    case 2:
+        stw_p(curspin_p, value);
+        break;
+    case 4:
+        stl_p(curspin_p, value);
+        break;
+    }
+
+    if (!(ldq_p(&curspin->addr) & 1)) {
+        /* run CPU */
+        SpinKick kick = {
+            .cpu = POWERPC_CPU(cpu),
+            .spin = curspin,
+        };
+
+        run_on_cpu(cpu, spin_kick, &kick);
+    }
+}
+
+static uint64_t spin_read(void *opaque, hwaddr addr, unsigned len)
+{
+    SpinState *s = opaque;
+    uint8_t *spin_p = &((uint8_t*)s->spin)[addr];
+
+    switch (len) {
+    case 1:
+        return ldub_p(spin_p);
+    case 2:
+        return lduw_p(spin_p);
+    case 4:
+        return ldl_p(spin_p);
+    default:
+        hw_error("ppce500: unexpected %s with len = %u", __func__, len);
+    }
+}
+
+static const MemoryRegionOps spin_rw_ops = {
+    .read = spin_read,
+    .write = spin_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static int ppce500_spin_initfn(SysBusDevice *dev)
+{
+    SpinState *s;
+
+    s = FROM_SYSBUS(SpinState, SYS_BUS_DEVICE(dev));
+
+    memory_region_init_io(&s->iomem, &spin_rw_ops, s, "e500 spin pv device",
+                          sizeof(SpinInfo) * MAX_CPUS);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    qemu_register_reset(spin_reset, s);
+
+    return 0;
+}
+
+static void ppce500_spin_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = ppce500_spin_initfn;
+}
+
+static const TypeInfo ppce500_spin_info = {
+    .name          = "e500-spin",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SpinState),
+    .class_init    = ppce500_spin_class_init,
+};
+
+static void ppce500_spin_register_types(void)
+{
+    type_register_static(&ppce500_spin_info);
+}
+
+type_init(ppce500_spin_register_types)
diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c
new file mode 100644 (file)
index 0000000..6eb3ab5
--- /dev/null
@@ -0,0 +1,649 @@
+/*
+ * QEMU sPAPR VIO code
+ *
+ * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com>
+ * Based on the s390 virtio bus code:
+ * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/hw.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "monitor/monitor.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "hw/sysbus.h"
+#include "sysemu/kvm.h"
+#include "sysemu/device_tree.h"
+#include "kvm_ppc.h"
+
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+#include "hw/xics.h"
+
+#ifdef CONFIG_FDT
+#include <libfdt.h>
+#endif /* CONFIG_FDT */
+
+/* #define DEBUG_SPAPR */
+
+#ifdef DEBUG_SPAPR
+#define dprintf(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+static Property spapr_vio_props[] = {
+    DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, irq, 0), \
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static const TypeInfo spapr_vio_bus_info = {
+    .name = TYPE_SPAPR_VIO_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(VIOsPAPRBus),
+};
+
+VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
+{
+    BusChild *kid;
+    VIOsPAPRDevice *dev = NULL;
+
+    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
+        dev = (VIOsPAPRDevice *)kid->child;
+        if (dev->reg == reg) {
+            return dev;
+        }
+    }
+
+    return NULL;
+}
+
+static char *vio_format_dev_name(VIOsPAPRDevice *dev)
+{
+    VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
+    char *name;
+
+    /* Device tree style name device@reg */
+    name = g_strdup_printf("%s@%x", pc->dt_name, dev->reg);
+
+    return name;
+}
+
+#ifdef CONFIG_FDT
+static int vio_make_devnode(VIOsPAPRDevice *dev,
+                            void *fdt)
+{
+    VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
+    int vdevice_off, node_off, ret;
+    char *dt_name;
+
+    vdevice_off = fdt_path_offset(fdt, "/vdevice");
+    if (vdevice_off < 0) {
+        return vdevice_off;
+    }
+
+    dt_name = vio_format_dev_name(dev);
+    node_off = fdt_add_subnode(fdt, vdevice_off, dt_name);
+    g_free(dt_name);
+    if (node_off < 0) {
+        return node_off;
+    }
+
+    ret = fdt_setprop_cell(fdt, node_off, "reg", dev->reg);
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (pc->dt_type) {
+        ret = fdt_setprop_string(fdt, node_off, "device_type",
+                                 pc->dt_type);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    if (pc->dt_compatible) {
+        ret = fdt_setprop_string(fdt, node_off, "compatible",
+                                 pc->dt_compatible);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    if (dev->irq) {
+        uint32_t ints_prop[] = {cpu_to_be32(dev->irq), 0};
+
+        ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop,
+                          sizeof(ints_prop));
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    ret = spapr_tcet_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->dma);
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (pc->devnode) {
+        ret = (pc->devnode)(dev, fdt, node_off);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    return node_off;
+}
+#endif /* CONFIG_FDT */
+
+/*
+ * CRQ handling
+ */
+static target_ulong h_reg_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                              target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong queue_addr = args[1];
+    target_ulong queue_len = args[2];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+
+    if (!dev) {
+        hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
+        return H_PARAMETER;
+    }
+
+    /* We can't grok a queue size bigger than 256M for now */
+    if (queue_len < 0x1000 || queue_len > 0x10000000) {
+        hcall_dprintf("Queue size too small or too big (0x" TARGET_FMT_lx
+                      ")\n", queue_len);
+        return H_PARAMETER;
+    }
+
+    /* Check queue alignment */
+    if (queue_addr & 0xfff) {
+        hcall_dprintf("Queue not aligned (0x" TARGET_FMT_lx ")\n", queue_addr);
+        return H_PARAMETER;
+    }
+
+    /* Check if device supports CRQs */
+    if (!dev->crq.SendFunc) {
+        hcall_dprintf("Device does not support CRQ\n");
+        return H_NOT_FOUND;
+    }
+
+    /* Already a queue ? */
+    if (dev->crq.qsize) {
+        hcall_dprintf("CRQ already registered\n");
+        return H_RESOURCE;
+    }
+    dev->crq.qladdr = queue_addr;
+    dev->crq.qsize = queue_len;
+    dev->crq.qnext = 0;
+
+    dprintf("CRQ for dev 0x" TARGET_FMT_lx " registered at 0x"
+            TARGET_FMT_lx "/0x" TARGET_FMT_lx "\n",
+            reg, queue_addr, queue_len);
+    return H_SUCCESS;
+}
+
+static target_ulong free_crq(VIOsPAPRDevice *dev)
+{
+    dev->crq.qladdr = 0;
+    dev->crq.qsize = 0;
+    dev->crq.qnext = 0;
+
+    dprintf("CRQ for dev 0x%" PRIx32 " freed\n", dev->reg);
+
+    return H_SUCCESS;
+}
+
+static target_ulong h_free_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                               target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+
+    if (!dev) {
+        hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
+        return H_PARAMETER;
+    }
+
+    return free_crq(dev);
+}
+
+static target_ulong h_send_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                               target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong msg_hi = args[1];
+    target_ulong msg_lo = args[2];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    uint64_t crq_mangle[2];
+
+    if (!dev) {
+        hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
+        return H_PARAMETER;
+    }
+    crq_mangle[0] = cpu_to_be64(msg_hi);
+    crq_mangle[1] = cpu_to_be64(msg_lo);
+
+    if (dev->crq.SendFunc) {
+        return dev->crq.SendFunc(dev, (uint8_t *)crq_mangle);
+    }
+
+    return H_HARDWARE;
+}
+
+static target_ulong h_enable_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                                 target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+
+    if (!dev) {
+        hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
+        return H_PARAMETER;
+    }
+
+    return 0;
+}
+
+/* Returns negative error, 0 success, or positive: queue full */
+int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq)
+{
+    int rc;
+    uint8_t byte;
+
+    if (!dev->crq.qsize) {
+        fprintf(stderr, "spapr_vio_send_creq on uninitialized queue\n");
+        return -1;
+    }
+
+    /* Maybe do a fast path for KVM just writing to the pages */
+    rc = spapr_vio_dma_read(dev, dev->crq.qladdr + dev->crq.qnext, &byte, 1);
+    if (rc) {
+        return rc;
+    }
+    if (byte != 0) {
+        return 1;
+    }
+
+    rc = spapr_vio_dma_write(dev, dev->crq.qladdr + dev->crq.qnext + 8,
+                             &crq[8], 8);
+    if (rc) {
+        return rc;
+    }
+
+    kvmppc_eieio();
+
+    rc = spapr_vio_dma_write(dev, dev->crq.qladdr + dev->crq.qnext, crq, 8);
+    if (rc) {
+        return rc;
+    }
+
+    dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize;
+
+    if (dev->signal_state & 1) {
+        qemu_irq_pulse(spapr_vio_qirq(dev));
+    }
+
+    return 0;
+}
+
+/* "quiesce" handling */
+
+static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev)
+{
+    if (dev->dma) {
+        spapr_tce_reset(dev->dma);
+    }
+    free_crq(dev);
+}
+
+static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token,
+                                uint32_t nargs, target_ulong args,
+                                uint32_t nret, target_ulong rets)
+{
+    VIOsPAPRBus *bus = spapr->vio_bus;
+    VIOsPAPRDevice *dev;
+    uint32_t unit, enable;
+
+    if (nargs != 2) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+    unit = rtas_ld(args, 0);
+    enable = rtas_ld(args, 1);
+    dev = spapr_vio_find_by_reg(bus, unit);
+    if (!dev) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    if (!dev->dma) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    spapr_tce_set_bypass(dev->dma, !!enable);
+
+    rtas_st(rets, 0, 0);
+}
+
+static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
+                         uint32_t nargs, target_ulong args,
+                         uint32_t nret, target_ulong rets)
+{
+    VIOsPAPRBus *bus = spapr->vio_bus;
+    BusChild *kid;
+    VIOsPAPRDevice *dev = NULL;
+
+    if (nargs != 0) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
+        dev = (VIOsPAPRDevice *)kid->child;
+        spapr_vio_quiesce_one(dev);
+    }
+
+    rtas_st(rets, 0, 0);
+}
+
+static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev)
+{
+    VIOsPAPRBus *bus = DO_UPCAST(VIOsPAPRBus, bus, dev->qdev.parent_bus);
+    BusChild *kid;
+    VIOsPAPRDevice *other;
+
+    /*
+     * Check for a device other than the given one which is already
+     * using the requested address. We have to open code this because
+     * the given dev might already be in the list.
+     */
+    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
+        other = DO_UPCAST(VIOsPAPRDevice, qdev, kid->child);
+
+        if (other != dev && other->reg == dev->reg) {
+            return other;
+        }
+    }
+
+    return 0;
+}
+
+static void spapr_vio_busdev_reset(DeviceState *qdev)
+{
+    VIOsPAPRDevice *dev = DO_UPCAST(VIOsPAPRDevice, qdev, qdev);
+    VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
+
+    /* Shut down the request queue and TCEs if necessary */
+    spapr_vio_quiesce_one(dev);
+
+    dev->signal_state = 0;
+
+    if (pc->reset) {
+        pc->reset(dev);
+    }
+}
+
+static int spapr_vio_busdev_init(DeviceState *qdev)
+{
+    VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
+    VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
+    char *id;
+
+    if (dev->reg != -1) {
+        /*
+         * Explicitly assigned address, just verify that no-one else
+         * is using it.  other mechanism). We have to open code this
+         * rather than using spapr_vio_find_by_reg() because sdev
+         * itself is already in the list.
+         */
+        VIOsPAPRDevice *other = reg_conflict(dev);
+
+        if (other) {
+            fprintf(stderr, "vio: %s and %s devices conflict at address %#x\n",
+                    object_get_typename(OBJECT(qdev)),
+                    object_get_typename(OBJECT(&other->qdev)),
+                    dev->reg);
+            return -1;
+        }
+    } else {
+        /* Need to assign an address */
+        VIOsPAPRBus *bus = DO_UPCAST(VIOsPAPRBus, bus, dev->qdev.parent_bus);
+
+        do {
+            dev->reg = bus->next_reg++;
+        } while (reg_conflict(dev));
+    }
+
+    /* Don't overwrite ids assigned on the command line */
+    if (!dev->qdev.id) {
+        id = vio_format_dev_name(dev);
+        dev->qdev.id = id;
+    }
+
+    dev->irq = spapr_allocate_msi(dev->irq);
+    if (!dev->irq) {
+        return -1;
+    }
+
+    if (pc->rtce_window_size) {
+        uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg;
+        dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size);
+    }
+
+    return pc->init(dev);
+}
+
+static target_ulong h_vio_signal(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                                 target_ulong opcode,
+                                 target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong mode = args[1];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRDeviceClass *pc;
+
+    if (!dev) {
+        return H_PARAMETER;
+    }
+
+    pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
+
+    if (mode & ~pc->signal_mask) {
+        return H_PARAMETER;
+    }
+
+    dev->signal_state = mode;
+
+    return H_SUCCESS;
+}
+
+VIOsPAPRBus *spapr_vio_bus_init(void)
+{
+    VIOsPAPRBus *bus;
+    BusState *qbus;
+    DeviceState *dev;
+
+    /* Create bridge device */
+    dev = qdev_create(NULL, "spapr-vio-bridge");
+    qdev_init_nofail(dev);
+
+    /* Create bus on bridge device */
+
+    qbus = qbus_create(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio");
+    bus = DO_UPCAST(VIOsPAPRBus, bus, qbus);
+    bus->next_reg = 0x71000000;
+
+    /* hcall-vio */
+    spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal);
+
+    /* hcall-crq */
+    spapr_register_hypercall(H_REG_CRQ, h_reg_crq);
+    spapr_register_hypercall(H_FREE_CRQ, h_free_crq);
+    spapr_register_hypercall(H_SEND_CRQ, h_send_crq);
+    spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq);
+
+    /* RTAS calls */
+    spapr_rtas_register("ibm,set-tce-bypass", rtas_set_tce_bypass);
+    spapr_rtas_register("quiesce", rtas_quiesce);
+
+    return bus;
+}
+
+/* Represents sPAPR hcall VIO devices */
+
+static int spapr_vio_bridge_init(SysBusDevice *dev)
+{
+    /* nothing */
+    return 0;
+}
+
+static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = spapr_vio_bridge_init;
+    dc->no_user = 1;
+}
+
+static const TypeInfo spapr_vio_bridge_info = {
+    .name          = "spapr-vio-bridge",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SysBusDevice),
+    .class_init    = spapr_vio_bridge_class_init,
+};
+
+static void vio_spapr_device_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *k = DEVICE_CLASS(klass);
+    k->init = spapr_vio_busdev_init;
+    k->reset = spapr_vio_busdev_reset;
+    k->bus_type = TYPE_SPAPR_VIO_BUS;
+    k->props = spapr_vio_props;
+}
+
+static const TypeInfo spapr_vio_type_info = {
+    .name = TYPE_VIO_SPAPR_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(VIOsPAPRDevice),
+    .abstract = true,
+    .class_size = sizeof(VIOsPAPRDeviceClass),
+    .class_init = vio_spapr_device_class_init,
+};
+
+static void spapr_vio_register_types(void)
+{
+    type_register_static(&spapr_vio_bus_info);
+    type_register_static(&spapr_vio_bridge_info);
+    type_register_static(&spapr_vio_type_info);
+}
+
+type_init(spapr_vio_register_types)
+
+#ifdef CONFIG_FDT
+static int compare_reg(const void *p1, const void *p2)
+{
+    VIOsPAPRDevice const *dev1, *dev2;
+
+    dev1 = (VIOsPAPRDevice *)*(DeviceState **)p1;
+    dev2 = (VIOsPAPRDevice *)*(DeviceState **)p2;
+
+    if (dev1->reg < dev2->reg) {
+        return -1;
+    }
+    if (dev1->reg == dev2->reg) {
+        return 0;
+    }
+
+    /* dev1->reg > dev2->reg */
+    return 1;
+}
+
+int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
+{
+    DeviceState *qdev, **qdevs;
+    BusChild *kid;
+    int i, num, ret = 0;
+
+    /* Count qdevs on the bus list */
+    num = 0;
+    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
+        num++;
+    }
+
+    /* Copy out into an array of pointers */
+    qdevs = g_malloc(sizeof(qdev) * num);
+    num = 0;
+    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
+        qdevs[num++] = kid->child;
+    }
+
+    /* Sort the array */
+    qsort(qdevs, num, sizeof(qdev), compare_reg);
+
+    /* Hack alert. Give the devices to libfdt in reverse order, we happen
+     * to know that will mean they are in forward order in the tree. */
+    for (i = num - 1; i >= 0; i--) {
+        VIOsPAPRDevice *dev = (VIOsPAPRDevice *)(qdevs[i]);
+
+        ret = vio_make_devnode(dev, fdt);
+
+        if (ret < 0) {
+            goto out;
+        }
+    }
+
+    ret = 0;
+out:
+    free(qdevs);
+
+    return ret;
+}
+
+int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus)
+{
+    VIOsPAPRDevice *dev;
+    char *name, *path;
+    int ret, offset;
+
+    dev = spapr_vty_get_default(bus);
+    if (!dev)
+        return 0;
+
+    offset = fdt_path_offset(fdt, "/chosen");
+    if (offset < 0) {
+        return offset;
+    }
+
+    name = vio_format_dev_name(dev);
+    path = g_strdup_printf("/vdevice/%s", name);
+
+    ret = fdt_setprop_string(fdt, offset, "linux,stdout-path", path);
+
+    g_free(name);
+    g_free(path);
+
+    return ret;
+}
+#endif /* CONFIG_FDT */
diff --git a/hw/ppc/xics.c b/hw/ppc/xics.c
new file mode 100644 (file)
index 0000000..c3ef12f
--- /dev/null
@@ -0,0 +1,588 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
+ *
+ * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
+ *
+ * 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 "hw/hw.h"
+#include "trace.h"
+#include "hw/spapr.h"
+#include "hw/xics.h"
+
+/*
+ * ICP: Presentation layer
+ */
+
+struct icp_server_state {
+    uint32_t xirr;
+    uint8_t pending_priority;
+    uint8_t mfrr;
+    qemu_irq output;
+};
+
+#define XISR_MASK  0x00ffffff
+#define CPPR_MASK  0xff000000
+
+#define XISR(ss)   (((ss)->xirr) & XISR_MASK)
+#define CPPR(ss)   (((ss)->xirr) >> 24)
+
+struct ics_state;
+
+struct icp_state {
+    long nr_servers;
+    struct icp_server_state *ss;
+    struct ics_state *ics;
+};
+
+static void ics_reject(struct ics_state *ics, int nr);
+static void ics_resend(struct ics_state *ics);
+static void ics_eoi(struct ics_state *ics, int nr);
+
+static void icp_check_ipi(struct icp_state *icp, int server)
+{
+    struct icp_server_state *ss = icp->ss + server;
+
+    if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
+        return;
+    }
+
+    trace_xics_icp_check_ipi(server, ss->mfrr);
+
+    if (XISR(ss)) {
+        ics_reject(icp->ics, XISR(ss));
+    }
+
+    ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
+    ss->pending_priority = ss->mfrr;
+    qemu_irq_raise(ss->output);
+}
+
+static void icp_resend(struct icp_state *icp, int server)
+{
+    struct icp_server_state *ss = icp->ss + server;
+
+    if (ss->mfrr < CPPR(ss)) {
+        icp_check_ipi(icp, server);
+    }
+    ics_resend(icp->ics);
+}
+
+static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr)
+{
+    struct icp_server_state *ss = icp->ss + server;
+    uint8_t old_cppr;
+    uint32_t old_xisr;
+
+    old_cppr = CPPR(ss);
+    ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
+
+    if (cppr < old_cppr) {
+        if (XISR(ss) && (cppr <= ss->pending_priority)) {
+            old_xisr = XISR(ss);
+            ss->xirr &= ~XISR_MASK; /* Clear XISR */
+            qemu_irq_lower(ss->output);
+            ics_reject(icp->ics, old_xisr);
+        }
+    } else {
+        if (!XISR(ss)) {
+            icp_resend(icp, server);
+        }
+    }
+}
+
+static void icp_set_mfrr(struct icp_state *icp, int server, uint8_t mfrr)
+{
+    struct icp_server_state *ss = icp->ss + server;
+
+    ss->mfrr = mfrr;
+    if (mfrr < CPPR(ss)) {
+        icp_check_ipi(icp, server);
+    }
+}
+
+static uint32_t icp_accept(struct icp_server_state *ss)
+{
+    uint32_t xirr = ss->xirr;
+
+    qemu_irq_lower(ss->output);
+    ss->xirr = ss->pending_priority << 24;
+
+    trace_xics_icp_accept(xirr, ss->xirr);
+
+    return xirr;
+}
+
+static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr)
+{
+    struct icp_server_state *ss = icp->ss + server;
+
+    /* Send EOI -> ICS */
+    ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
+    trace_xics_icp_eoi(server, xirr, ss->xirr);
+    ics_eoi(icp->ics, xirr & XISR_MASK);
+    if (!XISR(ss)) {
+        icp_resend(icp, server);
+    }
+}
+
+static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority)
+{
+    struct icp_server_state *ss = icp->ss + server;
+
+    trace_xics_icp_irq(server, nr, priority);
+
+    if ((priority >= CPPR(ss))
+        || (XISR(ss) && (ss->pending_priority <= priority))) {
+        ics_reject(icp->ics, nr);
+    } else {
+        if (XISR(ss)) {
+            ics_reject(icp->ics, XISR(ss));
+        }
+        ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
+        ss->pending_priority = priority;
+        trace_xics_icp_raise(ss->xirr, ss->pending_priority);
+        qemu_irq_raise(ss->output);
+    }
+}
+
+/*
+ * ICS: Source layer
+ */
+
+struct ics_irq_state {
+    int server;
+    uint8_t priority;
+    uint8_t saved_priority;
+#define XICS_STATUS_ASSERTED           0x1
+#define XICS_STATUS_SENT               0x2
+#define XICS_STATUS_REJECTED           0x4
+#define XICS_STATUS_MASKED_PENDING     0x8
+    uint8_t status;
+};
+
+struct ics_state {
+    int nr_irqs;
+    int offset;
+    qemu_irq *qirqs;
+    bool *islsi;
+    struct ics_irq_state *irqs;
+    struct icp_state *icp;
+};
+
+static int ics_valid_irq(struct ics_state *ics, uint32_t nr)
+{
+    return (nr >= ics->offset)
+        && (nr < (ics->offset + ics->nr_irqs));
+}
+
+static void resend_msi(struct ics_state *ics, int srcno)
+{
+    struct ics_irq_state *irq = ics->irqs + srcno;
+
+    /* FIXME: filter by server#? */
+    if (irq->status & XICS_STATUS_REJECTED) {
+        irq->status &= ~XICS_STATUS_REJECTED;
+        if (irq->priority != 0xff) {
+            icp_irq(ics->icp, irq->server, srcno + ics->offset,
+                    irq->priority);
+        }
+    }
+}
+
+static void resend_lsi(struct ics_state *ics, int srcno)
+{
+    struct ics_irq_state *irq = ics->irqs + srcno;
+
+    if ((irq->priority != 0xff)
+        && (irq->status & XICS_STATUS_ASSERTED)
+        && !(irq->status & XICS_STATUS_SENT)) {
+        irq->status |= XICS_STATUS_SENT;
+        icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
+    }
+}
+
+static void set_irq_msi(struct ics_state *ics, int srcno, int val)
+{
+    struct ics_irq_state *irq = ics->irqs + srcno;
+
+    trace_xics_set_irq_msi(srcno, srcno + ics->offset);
+
+    if (val) {
+        if (irq->priority == 0xff) {
+            irq->status |= XICS_STATUS_MASKED_PENDING;
+            trace_xics_masked_pending();
+        } else  {
+            icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
+        }
+    }
+}
+
+static void set_irq_lsi(struct ics_state *ics, int srcno, int val)
+{
+    struct ics_irq_state *irq = ics->irqs + srcno;
+
+    trace_xics_set_irq_lsi(srcno, srcno + ics->offset);
+    if (val) {
+        irq->status |= XICS_STATUS_ASSERTED;
+    } else {
+        irq->status &= ~XICS_STATUS_ASSERTED;
+    }
+    resend_lsi(ics, srcno);
+}
+
+static void ics_set_irq(void *opaque, int srcno, int val)
+{
+    struct ics_state *ics = (struct ics_state *)opaque;
+
+    if (ics->islsi[srcno]) {
+        set_irq_lsi(ics, srcno, val);
+    } else {
+        set_irq_msi(ics, srcno, val);
+    }
+}
+
+static void write_xive_msi(struct ics_state *ics, int srcno)
+{
+    struct ics_irq_state *irq = ics->irqs + srcno;
+
+    if (!(irq->status & XICS_STATUS_MASKED_PENDING)
+        || (irq->priority == 0xff)) {
+        return;
+    }
+
+    irq->status &= ~XICS_STATUS_MASKED_PENDING;
+    icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
+}
+
+static void write_xive_lsi(struct ics_state *ics, int srcno)
+{
+    resend_lsi(ics, srcno);
+}
+
+static void ics_write_xive(struct ics_state *ics, int nr, int server,
+                           uint8_t priority, uint8_t saved_priority)
+{
+    int srcno = nr - ics->offset;
+    struct ics_irq_state *irq = ics->irqs + srcno;
+
+    irq->server = server;
+    irq->priority = priority;
+    irq->saved_priority = saved_priority;
+
+    trace_xics_ics_write_xive(nr, srcno, server, priority);
+
+    if (ics->islsi[srcno]) {
+        write_xive_lsi(ics, srcno);
+    } else {
+        write_xive_msi(ics, srcno);
+    }
+}
+
+static void ics_reject(struct ics_state *ics, int nr)
+{
+    struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
+
+    trace_xics_ics_reject(nr, nr - ics->offset);
+    irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */
+    irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */
+}
+
+static void ics_resend(struct ics_state *ics)
+{
+    int i;
+
+    for (i = 0; i < ics->nr_irqs; i++) {
+        /* FIXME: filter by server#? */
+        if (ics->islsi[i]) {
+            resend_lsi(ics, i);
+        } else {
+            resend_msi(ics, i);
+        }
+    }
+}
+
+static void ics_eoi(struct ics_state *ics, int nr)
+{
+    int srcno = nr - ics->offset;
+    struct ics_irq_state *irq = ics->irqs + srcno;
+
+    trace_xics_ics_eoi(nr);
+
+    if (ics->islsi[srcno]) {
+        irq->status &= ~XICS_STATUS_SENT;
+    }
+}
+
+/*
+ * Exported functions
+ */
+
+qemu_irq xics_get_qirq(struct icp_state *icp, int irq)
+{
+    if (!ics_valid_irq(icp->ics, irq)) {
+        return NULL;
+    }
+
+    return icp->ics->qirqs[irq - icp->ics->offset];
+}
+
+void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi)
+{
+    assert(ics_valid_irq(icp->ics, irq));
+
+    icp->ics->islsi[irq - icp->ics->offset] = lsi;
+}
+
+static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                           target_ulong opcode, target_ulong *args)
+{
+    CPUState *cs = CPU(cpu);
+    target_ulong cppr = args[0];
+
+    icp_set_cppr(spapr->icp, cs->cpu_index, cppr);
+    return H_SUCCESS;
+}
+
+static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                          target_ulong opcode, target_ulong *args)
+{
+    target_ulong server = args[0];
+    target_ulong mfrr = args[1];
+
+    if (server >= spapr->icp->nr_servers) {
+        return H_PARAMETER;
+    }
+
+    icp_set_mfrr(spapr->icp, server, mfrr);
+    return H_SUCCESS;
+}
+
+static target_ulong h_xirr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                           target_ulong opcode, target_ulong *args)
+{
+    CPUState *cs = CPU(cpu);
+    uint32_t xirr = icp_accept(spapr->icp->ss + cs->cpu_index);
+
+    args[0] = xirr;
+    return H_SUCCESS;
+}
+
+static target_ulong h_eoi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                          target_ulong opcode, target_ulong *args)
+{
+    CPUState *cs = CPU(cpu);
+    target_ulong xirr = args[0];
+
+    icp_eoi(spapr->icp, cs->cpu_index, xirr);
+    return H_SUCCESS;
+}
+
+static void rtas_set_xive(sPAPREnvironment *spapr, uint32_t token,
+                          uint32_t nargs, target_ulong args,
+                          uint32_t nret, target_ulong rets)
+{
+    struct ics_state *ics = spapr->icp->ics;
+    uint32_t nr, server, priority;
+
+    if ((nargs != 3) || (nret != 1)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    nr = rtas_ld(args, 0);
+    server = rtas_ld(args, 1);
+    priority = rtas_ld(args, 2);
+
+    if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
+        || (priority > 0xff)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    ics_write_xive(ics, nr, server, priority, priority);
+
+    rtas_st(rets, 0, 0); /* Success */
+}
+
+static void rtas_get_xive(sPAPREnvironment *spapr, uint32_t token,
+                          uint32_t nargs, target_ulong args,
+                          uint32_t nret, target_ulong rets)
+{
+    struct ics_state *ics = spapr->icp->ics;
+    uint32_t nr;
+
+    if ((nargs != 1) || (nret != 3)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    nr = rtas_ld(args, 0);
+
+    if (!ics_valid_irq(ics, nr)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    rtas_st(rets, 0, 0); /* Success */
+    rtas_st(rets, 1, ics->irqs[nr - ics->offset].server);
+    rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
+}
+
+static void rtas_int_off(sPAPREnvironment *spapr, uint32_t token,
+                         uint32_t nargs, target_ulong args,
+                         uint32_t nret, target_ulong rets)
+{
+    struct ics_state *ics = spapr->icp->ics;
+    uint32_t nr;
+
+    if ((nargs != 1) || (nret != 1)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    nr = rtas_ld(args, 0);
+
+    if (!ics_valid_irq(ics, nr)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff,
+                   ics->irqs[nr - ics->offset].priority);
+
+    rtas_st(rets, 0, 0); /* Success */
+}
+
+static void rtas_int_on(sPAPREnvironment *spapr, uint32_t token,
+                        uint32_t nargs, target_ulong args,
+                        uint32_t nret, target_ulong rets)
+{
+    struct ics_state *ics = spapr->icp->ics;
+    uint32_t nr;
+
+    if ((nargs != 1) || (nret != 1)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    nr = rtas_ld(args, 0);
+
+    if (!ics_valid_irq(ics, nr)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server,
+                   ics->irqs[nr - ics->offset].saved_priority,
+                   ics->irqs[nr - ics->offset].saved_priority);
+
+    rtas_st(rets, 0, 0); /* Success */
+}
+
+static void xics_reset(void *opaque)
+{
+    struct icp_state *icp = (struct icp_state *)opaque;
+    struct ics_state *ics = icp->ics;
+    int i;
+
+    for (i = 0; i < icp->nr_servers; i++) {
+        icp->ss[i].xirr = 0;
+        icp->ss[i].pending_priority = 0xff;
+        icp->ss[i].mfrr = 0xff;
+        /* Make all outputs are deasserted */
+        qemu_set_irq(icp->ss[i].output, 0);
+    }
+
+    memset(ics->irqs, 0, sizeof(struct ics_irq_state) * ics->nr_irqs);
+    for (i = 0; i < ics->nr_irqs; i++) {
+        ics->irqs[i].priority = 0xff;
+        ics->irqs[i].saved_priority = 0xff;
+    }
+}
+
+struct icp_state *xics_system_init(int nr_irqs)
+{
+    CPUPPCState *env;
+    CPUState *cpu;
+    int max_server_num;
+    struct icp_state *icp;
+    struct ics_state *ics;
+
+    max_server_num = -1;
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        cpu = CPU(ppc_env_get_cpu(env));
+        if (cpu->cpu_index > max_server_num) {
+            max_server_num = cpu->cpu_index;
+        }
+    }
+
+    icp = g_malloc0(sizeof(*icp));
+    icp->nr_servers = max_server_num + 1;
+    icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state));
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        cpu = CPU(ppc_env_get_cpu(env));
+        struct icp_server_state *ss = &icp->ss[cpu->cpu_index];
+
+        switch (PPC_INPUT(env)) {
+        case PPC_FLAGS_INPUT_POWER7:
+            ss->output = env->irq_inputs[POWER7_INPUT_INT];
+            break;
+
+        case PPC_FLAGS_INPUT_970:
+            ss->output = env->irq_inputs[PPC970_INPUT_INT];
+            break;
+
+        default:
+            hw_error("XICS interrupt model does not support this CPU bus "
+                     "model\n");
+            exit(1);
+        }
+    }
+
+    ics = g_malloc0(sizeof(*ics));
+    ics->nr_irqs = nr_irqs;
+    ics->offset = XICS_IRQ_BASE;
+    ics->irqs = g_malloc0(nr_irqs * sizeof(struct ics_irq_state));
+    ics->islsi = g_malloc0(nr_irqs * sizeof(bool));
+
+    icp->ics = ics;
+    ics->icp = icp;
+
+    ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, nr_irqs);
+
+    spapr_register_hypercall(H_CPPR, h_cppr);
+    spapr_register_hypercall(H_IPI, h_ipi);
+    spapr_register_hypercall(H_XIRR, h_xirr);
+    spapr_register_hypercall(H_EOI, h_eoi);
+
+    spapr_rtas_register("ibm,set-xive", rtas_set_xive);
+    spapr_rtas_register("ibm,get-xive", rtas_get_xive);
+    spapr_rtas_register("ibm,int-off", rtas_int_off);
+    spapr_rtas_register("ibm,int-on", rtas_int_on);
+
+    qemu_register_reset(xics_reset, icp);
+
+    return icp;
+}
diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c
deleted file mode 100644 (file)
index 49ec728..0000000
+++ /dev/null
@@ -1,721 +0,0 @@
-/*
- * QEMU PowerPC 4xx embedded processors shared devices emulation
- *
- * 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 "hw/hw.h"
-#include "hw/ppc.h"
-#include "hw/ppc4xx.h"
-#include "qemu/log.h"
-#include "exec/address-spaces.h"
-
-//#define DEBUG_MMIO
-//#define DEBUG_UNASSIGNED
-#define DEBUG_UIC
-
-
-#ifdef DEBUG_UIC
-#  define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
-#else
-#  define LOG_UIC(...) do { } while (0)
-#endif
-
-static void ppc4xx_reset(void *opaque)
-{
-    PowerPCCPU *cpu = opaque;
-
-    cpu_reset(CPU(cpu));
-}
-
-/*****************************************************************************/
-/* Generic PowerPC 4xx processor instantiation */
-PowerPCCPU *ppc4xx_init(const char *cpu_model,
-                        clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
-                        uint32_t sysclk)
-{
-    PowerPCCPU *cpu;
-    CPUPPCState *env;
-
-    /* init CPUs */
-    cpu = cpu_ppc_init(cpu_model);
-    if (cpu == NULL) {
-        fprintf(stderr, "Unable to find PowerPC %s CPU definition\n",
-                cpu_model);
-        exit(1);
-    }
-    env = &cpu->env;
-
-    cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
-    cpu_clk->opaque = env;
-    /* Set time-base frequency to sysclk */
-    tb_clk->cb = ppc_40x_timers_init(env, sysclk, PPC_INTERRUPT_PIT);
-    tb_clk->opaque = env;
-    ppc_dcr_init(env, NULL, NULL);
-    /* Register qemu callbacks */
-    qemu_register_reset(ppc4xx_reset, cpu);
-
-    return cpu;
-}
-
-/*****************************************************************************/
-/* "Universal" Interrupt controller */
-enum {
-    DCR_UICSR  = 0x000,
-    DCR_UICSRS = 0x001,
-    DCR_UICER  = 0x002,
-    DCR_UICCR  = 0x003,
-    DCR_UICPR  = 0x004,
-    DCR_UICTR  = 0x005,
-    DCR_UICMSR = 0x006,
-    DCR_UICVR  = 0x007,
-    DCR_UICVCR = 0x008,
-    DCR_UICMAX = 0x009,
-};
-
-#define UIC_MAX_IRQ 32
-typedef struct ppcuic_t ppcuic_t;
-struct ppcuic_t {
-    uint32_t dcr_base;
-    int use_vectors;
-    uint32_t level;  /* Remembers the state of level-triggered interrupts. */
-    uint32_t uicsr;  /* Status register */
-    uint32_t uicer;  /* Enable register */
-    uint32_t uiccr;  /* Critical register */
-    uint32_t uicpr;  /* Polarity register */
-    uint32_t uictr;  /* Triggering register */
-    uint32_t uicvcr; /* Vector configuration register */
-    uint32_t uicvr;
-    qemu_irq *irqs;
-};
-
-static void ppcuic_trigger_irq (ppcuic_t *uic)
-{
-    uint32_t ir, cr;
-    int start, end, inc, i;
-
-    /* Trigger interrupt if any is pending */
-    ir = uic->uicsr & uic->uicer & (~uic->uiccr);
-    cr = uic->uicsr & uic->uicer & uic->uiccr;
-    LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32
-                " uiccr %08" PRIx32 "\n"
-                "   %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
-                __func__, uic->uicsr, uic->uicer, uic->uiccr,
-                uic->uicsr & uic->uicer, ir, cr);
-    if (ir != 0x0000000) {
-        LOG_UIC("Raise UIC interrupt\n");
-        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]);
-    } else {
-        LOG_UIC("Lower UIC interrupt\n");
-        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]);
-    }
-    /* Trigger critical interrupt if any is pending and update vector */
-    if (cr != 0x0000000) {
-        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]);
-        if (uic->use_vectors) {
-            /* Compute critical IRQ vector */
-            if (uic->uicvcr & 1) {
-                start = 31;
-                end = 0;
-                inc = -1;
-            } else {
-                start = 0;
-                end = 31;
-                inc = 1;
-            }
-            uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
-            for (i = start; i <= end; i += inc) {
-                if (cr & (1 << i)) {
-                    uic->uicvr += (i - start) * 512 * inc;
-                    break;
-                }
-            }
-        }
-        LOG_UIC("Raise UIC critical interrupt - "
-                    "vector %08" PRIx32 "\n", uic->uicvr);
-    } else {
-        LOG_UIC("Lower UIC critical interrupt\n");
-        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]);
-        uic->uicvr = 0x00000000;
-    }
-}
-
-static void ppcuic_set_irq (void *opaque, int irq_num, int level)
-{
-    ppcuic_t *uic;
-    uint32_t mask, sr;
-
-    uic = opaque;
-    mask = 1 << (31-irq_num);
-    LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
-                " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
-                __func__, irq_num, level,
-                uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
-    if (irq_num < 0 || irq_num > 31)
-        return;
-    sr = uic->uicsr;
-
-    /* Update status register */
-    if (uic->uictr & mask) {
-        /* Edge sensitive interrupt */
-        if (level == 1)
-            uic->uicsr |= mask;
-    } else {
-        /* Level sensitive interrupt */
-        if (level == 1) {
-            uic->uicsr |= mask;
-            uic->level |= mask;
-        } else {
-            uic->uicsr &= ~mask;
-            uic->level &= ~mask;
-        }
-    }
-    LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
-                "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
-    if (sr != uic->uicsr)
-        ppcuic_trigger_irq(uic);
-}
-
-static uint32_t dcr_read_uic (void *opaque, int dcrn)
-{
-    ppcuic_t *uic;
-    uint32_t ret;
-
-    uic = opaque;
-    dcrn -= uic->dcr_base;
-    switch (dcrn) {
-    case DCR_UICSR:
-    case DCR_UICSRS:
-        ret = uic->uicsr;
-        break;
-    case DCR_UICER:
-        ret = uic->uicer;
-        break;
-    case DCR_UICCR:
-        ret = uic->uiccr;
-        break;
-    case DCR_UICPR:
-        ret = uic->uicpr;
-        break;
-    case DCR_UICTR:
-        ret = uic->uictr;
-        break;
-    case DCR_UICMSR:
-        ret = uic->uicsr & uic->uicer;
-        break;
-    case DCR_UICVR:
-        if (!uic->use_vectors)
-            goto no_read;
-        ret = uic->uicvr;
-        break;
-    case DCR_UICVCR:
-        if (!uic->use_vectors)
-            goto no_read;
-        ret = uic->uicvcr;
-        break;
-    default:
-    no_read:
-        ret = 0x00000000;
-        break;
-    }
-
-    return ret;
-}
-
-static void dcr_write_uic (void *opaque, int dcrn, uint32_t val)
-{
-    ppcuic_t *uic;
-
-    uic = opaque;
-    dcrn -= uic->dcr_base;
-    LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val);
-    switch (dcrn) {
-    case DCR_UICSR:
-        uic->uicsr &= ~val;
-        uic->uicsr |= uic->level;
-        ppcuic_trigger_irq(uic);
-        break;
-    case DCR_UICSRS:
-        uic->uicsr |= val;
-        ppcuic_trigger_irq(uic);
-        break;
-    case DCR_UICER:
-        uic->uicer = val;
-        ppcuic_trigger_irq(uic);
-        break;
-    case DCR_UICCR:
-        uic->uiccr = val;
-        ppcuic_trigger_irq(uic);
-        break;
-    case DCR_UICPR:
-        uic->uicpr = val;
-        break;
-    case DCR_UICTR:
-        uic->uictr = val;
-        ppcuic_trigger_irq(uic);
-        break;
-    case DCR_UICMSR:
-        break;
-    case DCR_UICVR:
-        break;
-    case DCR_UICVCR:
-        uic->uicvcr = val & 0xFFFFFFFD;
-        ppcuic_trigger_irq(uic);
-        break;
-    }
-}
-
-static void ppcuic_reset (void *opaque)
-{
-    ppcuic_t *uic;
-
-    uic = opaque;
-    uic->uiccr = 0x00000000;
-    uic->uicer = 0x00000000;
-    uic->uicpr = 0x00000000;
-    uic->uicsr = 0x00000000;
-    uic->uictr = 0x00000000;
-    if (uic->use_vectors) {
-        uic->uicvcr = 0x00000000;
-        uic->uicvr = 0x0000000;
-    }
-}
-
-qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs,
-                       uint32_t dcr_base, int has_ssr, int has_vr)
-{
-    ppcuic_t *uic;
-    int i;
-
-    uic = g_malloc0(sizeof(ppcuic_t));
-    uic->dcr_base = dcr_base;
-    uic->irqs = irqs;
-    if (has_vr)
-        uic->use_vectors = 1;
-    for (i = 0; i < DCR_UICMAX; i++) {
-        ppc_dcr_register(env, dcr_base + i, uic,
-                         &dcr_read_uic, &dcr_write_uic);
-    }
-    qemu_register_reset(ppcuic_reset, uic);
-
-    return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ);
-}
-
-/*****************************************************************************/
-/* SDRAM controller */
-typedef struct ppc4xx_sdram_t ppc4xx_sdram_t;
-struct ppc4xx_sdram_t {
-    uint32_t addr;
-    int nbanks;
-    MemoryRegion containers[4]; /* used for clipping */
-    MemoryRegion *ram_memories;
-    hwaddr ram_bases[4];
-    hwaddr ram_sizes[4];
-    uint32_t besr0;
-    uint32_t besr1;
-    uint32_t bear;
-    uint32_t cfg;
-    uint32_t status;
-    uint32_t rtr;
-    uint32_t pmit;
-    uint32_t bcr[4];
-    uint32_t tr;
-    uint32_t ecccfg;
-    uint32_t eccesr;
-    qemu_irq irq;
-};
-
-enum {
-    SDRAM0_CFGADDR = 0x010,
-    SDRAM0_CFGDATA = 0x011,
-};
-
-/* XXX: TOFIX: some patches have made this code become inconsistent:
- *      there are type inconsistencies, mixing hwaddr, target_ulong
- *      and uint32_t
- */
-static uint32_t sdram_bcr (hwaddr ram_base,
-                           hwaddr ram_size)
-{
-    uint32_t bcr;
-
-    switch (ram_size) {
-    case (4 * 1024 * 1024):
-        bcr = 0x00000000;
-        break;
-    case (8 * 1024 * 1024):
-        bcr = 0x00020000;
-        break;
-    case (16 * 1024 * 1024):
-        bcr = 0x00040000;
-        break;
-    case (32 * 1024 * 1024):
-        bcr = 0x00060000;
-        break;
-    case (64 * 1024 * 1024):
-        bcr = 0x00080000;
-        break;
-    case (128 * 1024 * 1024):
-        bcr = 0x000A0000;
-        break;
-    case (256 * 1024 * 1024):
-        bcr = 0x000C0000;
-        break;
-    default:
-        printf("%s: invalid RAM size " TARGET_FMT_plx "\n", __func__,
-               ram_size);
-        return 0x00000000;
-    }
-    bcr |= ram_base & 0xFF800000;
-    bcr |= 1;
-
-    return bcr;
-}
-
-static inline hwaddr sdram_base(uint32_t bcr)
-{
-    return bcr & 0xFF800000;
-}
-
-static target_ulong sdram_size (uint32_t bcr)
-{
-    target_ulong size;
-    int sh;
-
-    sh = (bcr >> 17) & 0x7;
-    if (sh == 7)
-        size = -1;
-    else
-        size = (4 * 1024 * 1024) << sh;
-
-    return size;
-}
-
-static void sdram_set_bcr(ppc4xx_sdram_t *sdram,
-                          uint32_t *bcrp, uint32_t bcr, int enabled)
-{
-    unsigned n = bcrp - sdram->bcr;
-
-    if (*bcrp & 0x00000001) {
-        /* Unmap RAM */
-#ifdef DEBUG_SDRAM
-        printf("%s: unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
-               __func__, sdram_base(*bcrp), sdram_size(*bcrp));
-#endif
-        memory_region_del_subregion(get_system_memory(),
-                                    &sdram->containers[n]);
-        memory_region_del_subregion(&sdram->containers[n],
-                                    &sdram->ram_memories[n]);
-        memory_region_destroy(&sdram->containers[n]);
-    }
-    *bcrp = bcr & 0xFFDEE001;
-    if (enabled && (bcr & 0x00000001)) {
-#ifdef DEBUG_SDRAM
-        printf("%s: Map RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
-               __func__, sdram_base(bcr), sdram_size(bcr));
-#endif
-        memory_region_init(&sdram->containers[n], "sdram-containers",
-                           sdram_size(bcr));
-        memory_region_add_subregion(&sdram->containers[n], 0,
-                                    &sdram->ram_memories[n]);
-        memory_region_add_subregion(get_system_memory(),
-                                    sdram_base(bcr),
-                                    &sdram->containers[n]);
-    }
-}
-
-static void sdram_map_bcr (ppc4xx_sdram_t *sdram)
-{
-    int i;
-
-    for (i = 0; i < sdram->nbanks; i++) {
-        if (sdram->ram_sizes[i] != 0) {
-            sdram_set_bcr(sdram,
-                          &sdram->bcr[i],
-                          sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]),
-                          1);
-        } else {
-            sdram_set_bcr(sdram, &sdram->bcr[i], 0x00000000, 0);
-        }
-    }
-}
-
-static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram)
-{
-    int i;
-
-    for (i = 0; i < sdram->nbanks; i++) {
-#ifdef DEBUG_SDRAM
-        printf("%s: Unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
-               __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i]));
-#endif
-        memory_region_del_subregion(get_system_memory(),
-                                    &sdram->ram_memories[i]);
-    }
-}
-
-static uint32_t dcr_read_sdram (void *opaque, int dcrn)
-{
-    ppc4xx_sdram_t *sdram;
-    uint32_t ret;
-
-    sdram = opaque;
-    switch (dcrn) {
-    case SDRAM0_CFGADDR:
-        ret = sdram->addr;
-        break;
-    case SDRAM0_CFGDATA:
-        switch (sdram->addr) {
-        case 0x00: /* SDRAM_BESR0 */
-            ret = sdram->besr0;
-            break;
-        case 0x08: /* SDRAM_BESR1 */
-            ret = sdram->besr1;
-            break;
-        case 0x10: /* SDRAM_BEAR */
-            ret = sdram->bear;
-            break;
-        case 0x20: /* SDRAM_CFG */
-            ret = sdram->cfg;
-            break;
-        case 0x24: /* SDRAM_STATUS */
-            ret = sdram->status;
-            break;
-        case 0x30: /* SDRAM_RTR */
-            ret = sdram->rtr;
-            break;
-        case 0x34: /* SDRAM_PMIT */
-            ret = sdram->pmit;
-            break;
-        case 0x40: /* SDRAM_B0CR */
-            ret = sdram->bcr[0];
-            break;
-        case 0x44: /* SDRAM_B1CR */
-            ret = sdram->bcr[1];
-            break;
-        case 0x48: /* SDRAM_B2CR */
-            ret = sdram->bcr[2];
-            break;
-        case 0x4C: /* SDRAM_B3CR */
-            ret = sdram->bcr[3];
-            break;
-        case 0x80: /* SDRAM_TR */
-            ret = -1; /* ? */
-            break;
-        case 0x94: /* SDRAM_ECCCFG */
-            ret = sdram->ecccfg;
-            break;
-        case 0x98: /* SDRAM_ECCESR */
-            ret = sdram->eccesr;
-            break;
-        default: /* Error */
-            ret = -1;
-            break;
-        }
-        break;
-    default:
-        /* Avoid gcc warning */
-        ret = 0x00000000;
-        break;
-    }
-
-    return ret;
-}
-
-static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val)
-{
-    ppc4xx_sdram_t *sdram;
-
-    sdram = opaque;
-    switch (dcrn) {
-    case SDRAM0_CFGADDR:
-        sdram->addr = val;
-        break;
-    case SDRAM0_CFGDATA:
-        switch (sdram->addr) {
-        case 0x00: /* SDRAM_BESR0 */
-            sdram->besr0 &= ~val;
-            break;
-        case 0x08: /* SDRAM_BESR1 */
-            sdram->besr1 &= ~val;
-            break;
-        case 0x10: /* SDRAM_BEAR */
-            sdram->bear = val;
-            break;
-        case 0x20: /* SDRAM_CFG */
-            val &= 0xFFE00000;
-            if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) {
-#ifdef DEBUG_SDRAM
-                printf("%s: enable SDRAM controller\n", __func__);
-#endif
-                /* validate all RAM mappings */
-                sdram_map_bcr(sdram);
-                sdram->status &= ~0x80000000;
-            } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) {
-#ifdef DEBUG_SDRAM
-                printf("%s: disable SDRAM controller\n", __func__);
-#endif
-                /* invalidate all RAM mappings */
-                sdram_unmap_bcr(sdram);
-                sdram->status |= 0x80000000;
-            }
-            if (!(sdram->cfg & 0x40000000) && (val & 0x40000000))
-                sdram->status |= 0x40000000;
-            else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000))
-                sdram->status &= ~0x40000000;
-            sdram->cfg = val;
-            break;
-        case 0x24: /* SDRAM_STATUS */
-            /* Read-only register */
-            break;
-        case 0x30: /* SDRAM_RTR */
-            sdram->rtr = val & 0x3FF80000;
-            break;
-        case 0x34: /* SDRAM_PMIT */
-            sdram->pmit = (val & 0xF8000000) | 0x07C00000;
-            break;
-        case 0x40: /* SDRAM_B0CR */
-            sdram_set_bcr(sdram, &sdram->bcr[0], val, sdram->cfg & 0x80000000);
-            break;
-        case 0x44: /* SDRAM_B1CR */
-            sdram_set_bcr(sdram, &sdram->bcr[1], val, sdram->cfg & 0x80000000);
-            break;
-        case 0x48: /* SDRAM_B2CR */
-            sdram_set_bcr(sdram, &sdram->bcr[2], val, sdram->cfg & 0x80000000);
-            break;
-        case 0x4C: /* SDRAM_B3CR */
-            sdram_set_bcr(sdram, &sdram->bcr[3], val, sdram->cfg & 0x80000000);
-            break;
-        case 0x80: /* SDRAM_TR */
-            sdram->tr = val & 0x018FC01F;
-            break;
-        case 0x94: /* SDRAM_ECCCFG */
-            sdram->ecccfg = val & 0x00F00000;
-            break;
-        case 0x98: /* SDRAM_ECCESR */
-            val &= 0xFFF0F000;
-            if (sdram->eccesr == 0 && val != 0)
-                qemu_irq_raise(sdram->irq);
-            else if (sdram->eccesr != 0 && val == 0)
-                qemu_irq_lower(sdram->irq);
-            sdram->eccesr = val;
-            break;
-        default: /* Error */
-            break;
-        }
-        break;
-    }
-}
-
-static void sdram_reset (void *opaque)
-{
-    ppc4xx_sdram_t *sdram;
-
-    sdram = opaque;
-    sdram->addr = 0x00000000;
-    sdram->bear = 0x00000000;
-    sdram->besr0 = 0x00000000; /* No error */
-    sdram->besr1 = 0x00000000; /* No error */
-    sdram->cfg = 0x00000000;
-    sdram->ecccfg = 0x00000000; /* No ECC */
-    sdram->eccesr = 0x00000000; /* No error */
-    sdram->pmit = 0x07C00000;
-    sdram->rtr = 0x05F00000;
-    sdram->tr = 0x00854009;
-    /* We pre-initialize RAM banks */
-    sdram->status = 0x00000000;
-    sdram->cfg = 0x00800000;
-}
-
-void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks,
-                        MemoryRegion *ram_memories,
-                        hwaddr *ram_bases,
-                        hwaddr *ram_sizes,
-                        int do_init)
-{
-    ppc4xx_sdram_t *sdram;
-
-    sdram = g_malloc0(sizeof(ppc4xx_sdram_t));
-    sdram->irq = irq;
-    sdram->nbanks = nbanks;
-    sdram->ram_memories = ram_memories;
-    memset(sdram->ram_bases, 0, 4 * sizeof(hwaddr));
-    memcpy(sdram->ram_bases, ram_bases,
-           nbanks * sizeof(hwaddr));
-    memset(sdram->ram_sizes, 0, 4 * sizeof(hwaddr));
-    memcpy(sdram->ram_sizes, ram_sizes,
-           nbanks * sizeof(hwaddr));
-    qemu_register_reset(&sdram_reset, sdram);
-    ppc_dcr_register(env, SDRAM0_CFGADDR,
-                     sdram, &dcr_read_sdram, &dcr_write_sdram);
-    ppc_dcr_register(env, SDRAM0_CFGDATA,
-                     sdram, &dcr_read_sdram, &dcr_write_sdram);
-    if (do_init)
-        sdram_map_bcr(sdram);
-}
-
-/* Fill in consecutive SDRAM banks with 'ram_size' bytes of memory.
- *
- * sdram_bank_sizes[] must be 0-terminated.
- *
- * The 4xx SDRAM controller supports a small number of banks, and each bank
- * must be one of a small set of sizes. The number of banks and the supported
- * sizes varies by SoC. */
-ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
-                               MemoryRegion ram_memories[],
-                               hwaddr ram_bases[],
-                               hwaddr ram_sizes[],
-                               const unsigned int sdram_bank_sizes[])
-{
-    ram_addr_t size_left = ram_size;
-    ram_addr_t base = 0;
-    int i;
-    int j;
-
-    for (i = 0; i < nr_banks; i++) {
-        for (j = 0; sdram_bank_sizes[j] != 0; j++) {
-            unsigned int bank_size = sdram_bank_sizes[j];
-
-            if (bank_size <= size_left) {
-                char name[32];
-                snprintf(name, sizeof(name), "ppc4xx.sdram%d", i);
-                memory_region_init_ram(&ram_memories[i], name, bank_size);
-                vmstate_register_ram_global(&ram_memories[i]);
-                ram_bases[i] = base;
-                ram_sizes[i] = bank_size;
-                base += bank_size;
-                size_left -= bank_size;
-                break;
-            }
-        }
-
-        if (!size_left) {
-            /* No need to use the remaining banks. */
-            break;
-        }
-    }
-
-    ram_size -= size_left;
-    if (size_left)
-        printf("Truncating memory to %d MiB to fit SDRAM controller limits.\n",
-               (int)(ram_size >> 20));
-
-    return ram_size;
-}
diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c
deleted file mode 100644 (file)
index d904fbe..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * QEMU PowerPC e500v2 ePAPR spinning code
- *
- * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
- *
- * Author: Alexander Graf, <agraf@suse.de>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- * This code is not really a device, but models an interface that usually
- * firmware takes care of. It's used when QEMU plays the role of firmware.
- *
- * Specification:
- *
- * https://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.1.pdf
- *
- */
-
-#include "hw/hw.h"
-#include "sysemu/sysemu.h"
-#include "hw/sysbus.h"
-#include "sysemu/kvm.h"
-
-#define MAX_CPUS 32
-
-typedef struct spin_info {
-    uint64_t addr;
-    uint64_t r3;
-    uint32_t resv;
-    uint32_t pir;
-    uint64_t reserved;
-} QEMU_PACKED SpinInfo;
-
-typedef struct spin_state {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    SpinInfo spin[MAX_CPUS];
-} SpinState;
-
-typedef struct spin_kick {
-    PowerPCCPU *cpu;
-    SpinInfo *spin;
-} SpinKick;
-
-static void spin_reset(void *opaque)
-{
-    SpinState *s = opaque;
-    int i;
-
-    for (i = 0; i < MAX_CPUS; i++) {
-        SpinInfo *info = &s->spin[i];
-
-        info->pir = i;
-        info->r3 = i;
-        info->addr = 1;
-    }
-}
-
-/* Create -kernel TLB entries for BookE, linearly spanning 256MB.  */
-static inline hwaddr booke206_page_size_to_tlb(uint64_t size)
-{
-    return (ffs(size >> 10) - 1) >> 1;
-}
-
-static void mmubooke_create_initial_mapping(CPUPPCState *env,
-                                     target_ulong va,
-                                     hwaddr pa,
-                                     hwaddr len)
-{
-    ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1);
-    hwaddr size;
-
-    size = (booke206_page_size_to_tlb(len) << MAS1_TSIZE_SHIFT);
-    tlb->mas1 = MAS1_VALID | size;
-    tlb->mas2 = (va & TARGET_PAGE_MASK) | MAS2_M;
-    tlb->mas7_3 = pa & TARGET_PAGE_MASK;
-    tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
-    env->tlb_dirty = true;
-}
-
-static void spin_kick(void *data)
-{
-    SpinKick *kick = data;
-    CPUState *cpu = CPU(kick->cpu);
-    CPUPPCState *env = &kick->cpu->env;
-    SpinInfo *curspin = kick->spin;
-    hwaddr map_size = 64 * 1024 * 1024;
-    hwaddr map_start;
-
-    cpu_synchronize_state(env);
-    stl_p(&curspin->pir, env->spr[SPR_PIR]);
-    env->nip = ldq_p(&curspin->addr) & (map_size - 1);
-    env->gpr[3] = ldq_p(&curspin->r3);
-    env->gpr[4] = 0;
-    env->gpr[5] = 0;
-    env->gpr[6] = 0;
-    env->gpr[7] = map_size;
-    env->gpr[8] = 0;
-    env->gpr[9] = 0;
-
-    map_start = ldq_p(&curspin->addr) & ~(map_size - 1);
-    mmubooke_create_initial_mapping(env, 0, map_start, map_size);
-
-    env->halted = 0;
-    env->exception_index = -1;
-    cpu->stopped = false;
-    qemu_cpu_kick(cpu);
-}
-
-static void spin_write(void *opaque, hwaddr addr, uint64_t value,
-                       unsigned len)
-{
-    SpinState *s = opaque;
-    int env_idx = addr / sizeof(SpinInfo);
-    CPUState *cpu;
-    SpinInfo *curspin = &s->spin[env_idx];
-    uint8_t *curspin_p = (uint8_t*)curspin;
-
-    cpu = qemu_get_cpu(env_idx);
-    if (cpu == NULL) {
-        /* Unknown CPU */
-        return;
-    }
-
-    if (cpu->cpu_index == 0) {
-        /* primary CPU doesn't spin */
-        return;
-    }
-
-    curspin_p = &curspin_p[addr % sizeof(SpinInfo)];
-    switch (len) {
-    case 1:
-        stb_p(curspin_p, value);
-        break;
-    case 2:
-        stw_p(curspin_p, value);
-        break;
-    case 4:
-        stl_p(curspin_p, value);
-        break;
-    }
-
-    if (!(ldq_p(&curspin->addr) & 1)) {
-        /* run CPU */
-        SpinKick kick = {
-            .cpu = POWERPC_CPU(cpu),
-            .spin = curspin,
-        };
-
-        run_on_cpu(cpu, spin_kick, &kick);
-    }
-}
-
-static uint64_t spin_read(void *opaque, hwaddr addr, unsigned len)
-{
-    SpinState *s = opaque;
-    uint8_t *spin_p = &((uint8_t*)s->spin)[addr];
-
-    switch (len) {
-    case 1:
-        return ldub_p(spin_p);
-    case 2:
-        return lduw_p(spin_p);
-    case 4:
-        return ldl_p(spin_p);
-    default:
-        hw_error("ppce500: unexpected %s with len = %u", __func__, len);
-    }
-}
-
-static const MemoryRegionOps spin_rw_ops = {
-    .read = spin_read,
-    .write = spin_write,
-    .endianness = DEVICE_BIG_ENDIAN,
-};
-
-static int ppce500_spin_initfn(SysBusDevice *dev)
-{
-    SpinState *s;
-
-    s = FROM_SYSBUS(SpinState, SYS_BUS_DEVICE(dev));
-
-    memory_region_init_io(&s->iomem, &spin_rw_ops, s, "e500 spin pv device",
-                          sizeof(SpinInfo) * MAX_CPUS);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    qemu_register_reset(spin_reset, s);
-
-    return 0;
-}
-
-static void ppce500_spin_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = ppce500_spin_initfn;
-}
-
-static const TypeInfo ppce500_spin_info = {
-    .name          = "e500-spin",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SpinState),
-    .class_init    = ppce500_spin_class_init,
-};
-
-static void ppce500_spin_register_types(void)
-{
-    type_register_static(&ppce500_spin_info);
-}
-
-type_init(ppce500_spin_register_types)
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
deleted file mode 100644 (file)
index 6eb3ab5..0000000
+++ /dev/null
@@ -1,649 +0,0 @@
-/*
- * QEMU sPAPR VIO code
- *
- * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com>
- * Based on the s390 virtio bus code:
- * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "hw/hw.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "monitor/monitor.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "hw/sysbus.h"
-#include "sysemu/kvm.h"
-#include "sysemu/device_tree.h"
-#include "kvm_ppc.h"
-
-#include "hw/spapr.h"
-#include "hw/spapr_vio.h"
-#include "hw/xics.h"
-
-#ifdef CONFIG_FDT
-#include <libfdt.h>
-#endif /* CONFIG_FDT */
-
-/* #define DEBUG_SPAPR */
-
-#ifdef DEBUG_SPAPR
-#define dprintf(fmt, ...) \
-    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
-#else
-#define dprintf(fmt, ...) \
-    do { } while (0)
-#endif
-
-static Property spapr_vio_props[] = {
-    DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, irq, 0), \
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static const TypeInfo spapr_vio_bus_info = {
-    .name = TYPE_SPAPR_VIO_BUS,
-    .parent = TYPE_BUS,
-    .instance_size = sizeof(VIOsPAPRBus),
-};
-
-VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
-{
-    BusChild *kid;
-    VIOsPAPRDevice *dev = NULL;
-
-    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
-        dev = (VIOsPAPRDevice *)kid->child;
-        if (dev->reg == reg) {
-            return dev;
-        }
-    }
-
-    return NULL;
-}
-
-static char *vio_format_dev_name(VIOsPAPRDevice *dev)
-{
-    VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
-    char *name;
-
-    /* Device tree style name device@reg */
-    name = g_strdup_printf("%s@%x", pc->dt_name, dev->reg);
-
-    return name;
-}
-
-#ifdef CONFIG_FDT
-static int vio_make_devnode(VIOsPAPRDevice *dev,
-                            void *fdt)
-{
-    VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
-    int vdevice_off, node_off, ret;
-    char *dt_name;
-
-    vdevice_off = fdt_path_offset(fdt, "/vdevice");
-    if (vdevice_off < 0) {
-        return vdevice_off;
-    }
-
-    dt_name = vio_format_dev_name(dev);
-    node_off = fdt_add_subnode(fdt, vdevice_off, dt_name);
-    g_free(dt_name);
-    if (node_off < 0) {
-        return node_off;
-    }
-
-    ret = fdt_setprop_cell(fdt, node_off, "reg", dev->reg);
-    if (ret < 0) {
-        return ret;
-    }
-
-    if (pc->dt_type) {
-        ret = fdt_setprop_string(fdt, node_off, "device_type",
-                                 pc->dt_type);
-        if (ret < 0) {
-            return ret;
-        }
-    }
-
-    if (pc->dt_compatible) {
-        ret = fdt_setprop_string(fdt, node_off, "compatible",
-                                 pc->dt_compatible);
-        if (ret < 0) {
-            return ret;
-        }
-    }
-
-    if (dev->irq) {
-        uint32_t ints_prop[] = {cpu_to_be32(dev->irq), 0};
-
-        ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop,
-                          sizeof(ints_prop));
-        if (ret < 0) {
-            return ret;
-        }
-    }
-
-    ret = spapr_tcet_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->dma);
-    if (ret < 0) {
-        return ret;
-    }
-
-    if (pc->devnode) {
-        ret = (pc->devnode)(dev, fdt, node_off);
-        if (ret < 0) {
-            return ret;
-        }
-    }
-
-    return node_off;
-}
-#endif /* CONFIG_FDT */
-
-/*
- * CRQ handling
- */
-static target_ulong h_reg_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr,
-                              target_ulong opcode, target_ulong *args)
-{
-    target_ulong reg = args[0];
-    target_ulong queue_addr = args[1];
-    target_ulong queue_len = args[2];
-    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-
-    if (!dev) {
-        hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
-        return H_PARAMETER;
-    }
-
-    /* We can't grok a queue size bigger than 256M for now */
-    if (queue_len < 0x1000 || queue_len > 0x10000000) {
-        hcall_dprintf("Queue size too small or too big (0x" TARGET_FMT_lx
-                      ")\n", queue_len);
-        return H_PARAMETER;
-    }
-
-    /* Check queue alignment */
-    if (queue_addr & 0xfff) {
-        hcall_dprintf("Queue not aligned (0x" TARGET_FMT_lx ")\n", queue_addr);
-        return H_PARAMETER;
-    }
-
-    /* Check if device supports CRQs */
-    if (!dev->crq.SendFunc) {
-        hcall_dprintf("Device does not support CRQ\n");
-        return H_NOT_FOUND;
-    }
-
-    /* Already a queue ? */
-    if (dev->crq.qsize) {
-        hcall_dprintf("CRQ already registered\n");
-        return H_RESOURCE;
-    }
-    dev->crq.qladdr = queue_addr;
-    dev->crq.qsize = queue_len;
-    dev->crq.qnext = 0;
-
-    dprintf("CRQ for dev 0x" TARGET_FMT_lx " registered at 0x"
-            TARGET_FMT_lx "/0x" TARGET_FMT_lx "\n",
-            reg, queue_addr, queue_len);
-    return H_SUCCESS;
-}
-
-static target_ulong free_crq(VIOsPAPRDevice *dev)
-{
-    dev->crq.qladdr = 0;
-    dev->crq.qsize = 0;
-    dev->crq.qnext = 0;
-
-    dprintf("CRQ for dev 0x%" PRIx32 " freed\n", dev->reg);
-
-    return H_SUCCESS;
-}
-
-static target_ulong h_free_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr,
-                               target_ulong opcode, target_ulong *args)
-{
-    target_ulong reg = args[0];
-    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-
-    if (!dev) {
-        hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
-        return H_PARAMETER;
-    }
-
-    return free_crq(dev);
-}
-
-static target_ulong h_send_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr,
-                               target_ulong opcode, target_ulong *args)
-{
-    target_ulong reg = args[0];
-    target_ulong msg_hi = args[1];
-    target_ulong msg_lo = args[2];
-    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-    uint64_t crq_mangle[2];
-
-    if (!dev) {
-        hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
-        return H_PARAMETER;
-    }
-    crq_mangle[0] = cpu_to_be64(msg_hi);
-    crq_mangle[1] = cpu_to_be64(msg_lo);
-
-    if (dev->crq.SendFunc) {
-        return dev->crq.SendFunc(dev, (uint8_t *)crq_mangle);
-    }
-
-    return H_HARDWARE;
-}
-
-static target_ulong h_enable_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr,
-                                 target_ulong opcode, target_ulong *args)
-{
-    target_ulong reg = args[0];
-    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-
-    if (!dev) {
-        hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
-        return H_PARAMETER;
-    }
-
-    return 0;
-}
-
-/* Returns negative error, 0 success, or positive: queue full */
-int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq)
-{
-    int rc;
-    uint8_t byte;
-
-    if (!dev->crq.qsize) {
-        fprintf(stderr, "spapr_vio_send_creq on uninitialized queue\n");
-        return -1;
-    }
-
-    /* Maybe do a fast path for KVM just writing to the pages */
-    rc = spapr_vio_dma_read(dev, dev->crq.qladdr + dev->crq.qnext, &byte, 1);
-    if (rc) {
-        return rc;
-    }
-    if (byte != 0) {
-        return 1;
-    }
-
-    rc = spapr_vio_dma_write(dev, dev->crq.qladdr + dev->crq.qnext + 8,
-                             &crq[8], 8);
-    if (rc) {
-        return rc;
-    }
-
-    kvmppc_eieio();
-
-    rc = spapr_vio_dma_write(dev, dev->crq.qladdr + dev->crq.qnext, crq, 8);
-    if (rc) {
-        return rc;
-    }
-
-    dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize;
-
-    if (dev->signal_state & 1) {
-        qemu_irq_pulse(spapr_vio_qirq(dev));
-    }
-
-    return 0;
-}
-
-/* "quiesce" handling */
-
-static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev)
-{
-    if (dev->dma) {
-        spapr_tce_reset(dev->dma);
-    }
-    free_crq(dev);
-}
-
-static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token,
-                                uint32_t nargs, target_ulong args,
-                                uint32_t nret, target_ulong rets)
-{
-    VIOsPAPRBus *bus = spapr->vio_bus;
-    VIOsPAPRDevice *dev;
-    uint32_t unit, enable;
-
-    if (nargs != 2) {
-        rtas_st(rets, 0, -3);
-        return;
-    }
-    unit = rtas_ld(args, 0);
-    enable = rtas_ld(args, 1);
-    dev = spapr_vio_find_by_reg(bus, unit);
-    if (!dev) {
-        rtas_st(rets, 0, -3);
-        return;
-    }
-
-    if (!dev->dma) {
-        rtas_st(rets, 0, -3);
-        return;
-    }
-
-    spapr_tce_set_bypass(dev->dma, !!enable);
-
-    rtas_st(rets, 0, 0);
-}
-
-static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
-                         uint32_t nargs, target_ulong args,
-                         uint32_t nret, target_ulong rets)
-{
-    VIOsPAPRBus *bus = spapr->vio_bus;
-    BusChild *kid;
-    VIOsPAPRDevice *dev = NULL;
-
-    if (nargs != 0) {
-        rtas_st(rets, 0, -3);
-        return;
-    }
-
-    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
-        dev = (VIOsPAPRDevice *)kid->child;
-        spapr_vio_quiesce_one(dev);
-    }
-
-    rtas_st(rets, 0, 0);
-}
-
-static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev)
-{
-    VIOsPAPRBus *bus = DO_UPCAST(VIOsPAPRBus, bus, dev->qdev.parent_bus);
-    BusChild *kid;
-    VIOsPAPRDevice *other;
-
-    /*
-     * Check for a device other than the given one which is already
-     * using the requested address. We have to open code this because
-     * the given dev might already be in the list.
-     */
-    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
-        other = DO_UPCAST(VIOsPAPRDevice, qdev, kid->child);
-
-        if (other != dev && other->reg == dev->reg) {
-            return other;
-        }
-    }
-
-    return 0;
-}
-
-static void spapr_vio_busdev_reset(DeviceState *qdev)
-{
-    VIOsPAPRDevice *dev = DO_UPCAST(VIOsPAPRDevice, qdev, qdev);
-    VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
-
-    /* Shut down the request queue and TCEs if necessary */
-    spapr_vio_quiesce_one(dev);
-
-    dev->signal_state = 0;
-
-    if (pc->reset) {
-        pc->reset(dev);
-    }
-}
-
-static int spapr_vio_busdev_init(DeviceState *qdev)
-{
-    VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
-    VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
-    char *id;
-
-    if (dev->reg != -1) {
-        /*
-         * Explicitly assigned address, just verify that no-one else
-         * is using it.  other mechanism). We have to open code this
-         * rather than using spapr_vio_find_by_reg() because sdev
-         * itself is already in the list.
-         */
-        VIOsPAPRDevice *other = reg_conflict(dev);
-
-        if (other) {
-            fprintf(stderr, "vio: %s and %s devices conflict at address %#x\n",
-                    object_get_typename(OBJECT(qdev)),
-                    object_get_typename(OBJECT(&other->qdev)),
-                    dev->reg);
-            return -1;
-        }
-    } else {
-        /* Need to assign an address */
-        VIOsPAPRBus *bus = DO_UPCAST(VIOsPAPRBus, bus, dev->qdev.parent_bus);
-
-        do {
-            dev->reg = bus->next_reg++;
-        } while (reg_conflict(dev));
-    }
-
-    /* Don't overwrite ids assigned on the command line */
-    if (!dev->qdev.id) {
-        id = vio_format_dev_name(dev);
-        dev->qdev.id = id;
-    }
-
-    dev->irq = spapr_allocate_msi(dev->irq);
-    if (!dev->irq) {
-        return -1;
-    }
-
-    if (pc->rtce_window_size) {
-        uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg;
-        dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size);
-    }
-
-    return pc->init(dev);
-}
-
-static target_ulong h_vio_signal(PowerPCCPU *cpu, sPAPREnvironment *spapr,
-                                 target_ulong opcode,
-                                 target_ulong *args)
-{
-    target_ulong reg = args[0];
-    target_ulong mode = args[1];
-    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-    VIOsPAPRDeviceClass *pc;
-
-    if (!dev) {
-        return H_PARAMETER;
-    }
-
-    pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
-
-    if (mode & ~pc->signal_mask) {
-        return H_PARAMETER;
-    }
-
-    dev->signal_state = mode;
-
-    return H_SUCCESS;
-}
-
-VIOsPAPRBus *spapr_vio_bus_init(void)
-{
-    VIOsPAPRBus *bus;
-    BusState *qbus;
-    DeviceState *dev;
-
-    /* Create bridge device */
-    dev = qdev_create(NULL, "spapr-vio-bridge");
-    qdev_init_nofail(dev);
-
-    /* Create bus on bridge device */
-
-    qbus = qbus_create(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio");
-    bus = DO_UPCAST(VIOsPAPRBus, bus, qbus);
-    bus->next_reg = 0x71000000;
-
-    /* hcall-vio */
-    spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal);
-
-    /* hcall-crq */
-    spapr_register_hypercall(H_REG_CRQ, h_reg_crq);
-    spapr_register_hypercall(H_FREE_CRQ, h_free_crq);
-    spapr_register_hypercall(H_SEND_CRQ, h_send_crq);
-    spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq);
-
-    /* RTAS calls */
-    spapr_rtas_register("ibm,set-tce-bypass", rtas_set_tce_bypass);
-    spapr_rtas_register("quiesce", rtas_quiesce);
-
-    return bus;
-}
-
-/* Represents sPAPR hcall VIO devices */
-
-static int spapr_vio_bridge_init(SysBusDevice *dev)
-{
-    /* nothing */
-    return 0;
-}
-
-static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = spapr_vio_bridge_init;
-    dc->no_user = 1;
-}
-
-static const TypeInfo spapr_vio_bridge_info = {
-    .name          = "spapr-vio-bridge",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SysBusDevice),
-    .class_init    = spapr_vio_bridge_class_init,
-};
-
-static void vio_spapr_device_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *k = DEVICE_CLASS(klass);
-    k->init = spapr_vio_busdev_init;
-    k->reset = spapr_vio_busdev_reset;
-    k->bus_type = TYPE_SPAPR_VIO_BUS;
-    k->props = spapr_vio_props;
-}
-
-static const TypeInfo spapr_vio_type_info = {
-    .name = TYPE_VIO_SPAPR_DEVICE,
-    .parent = TYPE_DEVICE,
-    .instance_size = sizeof(VIOsPAPRDevice),
-    .abstract = true,
-    .class_size = sizeof(VIOsPAPRDeviceClass),
-    .class_init = vio_spapr_device_class_init,
-};
-
-static void spapr_vio_register_types(void)
-{
-    type_register_static(&spapr_vio_bus_info);
-    type_register_static(&spapr_vio_bridge_info);
-    type_register_static(&spapr_vio_type_info);
-}
-
-type_init(spapr_vio_register_types)
-
-#ifdef CONFIG_FDT
-static int compare_reg(const void *p1, const void *p2)
-{
-    VIOsPAPRDevice const *dev1, *dev2;
-
-    dev1 = (VIOsPAPRDevice *)*(DeviceState **)p1;
-    dev2 = (VIOsPAPRDevice *)*(DeviceState **)p2;
-
-    if (dev1->reg < dev2->reg) {
-        return -1;
-    }
-    if (dev1->reg == dev2->reg) {
-        return 0;
-    }
-
-    /* dev1->reg > dev2->reg */
-    return 1;
-}
-
-int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
-{
-    DeviceState *qdev, **qdevs;
-    BusChild *kid;
-    int i, num, ret = 0;
-
-    /* Count qdevs on the bus list */
-    num = 0;
-    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
-        num++;
-    }
-
-    /* Copy out into an array of pointers */
-    qdevs = g_malloc(sizeof(qdev) * num);
-    num = 0;
-    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
-        qdevs[num++] = kid->child;
-    }
-
-    /* Sort the array */
-    qsort(qdevs, num, sizeof(qdev), compare_reg);
-
-    /* Hack alert. Give the devices to libfdt in reverse order, we happen
-     * to know that will mean they are in forward order in the tree. */
-    for (i = num - 1; i >= 0; i--) {
-        VIOsPAPRDevice *dev = (VIOsPAPRDevice *)(qdevs[i]);
-
-        ret = vio_make_devnode(dev, fdt);
-
-        if (ret < 0) {
-            goto out;
-        }
-    }
-
-    ret = 0;
-out:
-    free(qdevs);
-
-    return ret;
-}
-
-int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus)
-{
-    VIOsPAPRDevice *dev;
-    char *name, *path;
-    int ret, offset;
-
-    dev = spapr_vty_get_default(bus);
-    if (!dev)
-        return 0;
-
-    offset = fdt_path_offset(fdt, "/chosen");
-    if (offset < 0) {
-        return offset;
-    }
-
-    name = vio_format_dev_name(dev);
-    path = g_strdup_printf("/vdevice/%s", name);
-
-    ret = fdt_setprop_string(fdt, offset, "linux,stdout-path", path);
-
-    g_free(name);
-    g_free(path);
-
-    return ret;
-}
-#endif /* CONFIG_FDT */
diff --git a/hw/xics.c b/hw/xics.c
deleted file mode 100644 (file)
index c3ef12f..0000000
--- a/hw/xics.c
+++ /dev/null
@@ -1,588 +0,0 @@
-/*
- * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
- *
- * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
- *
- * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
- *
- * 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 "hw/hw.h"
-#include "trace.h"
-#include "hw/spapr.h"
-#include "hw/xics.h"
-
-/*
- * ICP: Presentation layer
- */
-
-struct icp_server_state {
-    uint32_t xirr;
-    uint8_t pending_priority;
-    uint8_t mfrr;
-    qemu_irq output;
-};
-
-#define XISR_MASK  0x00ffffff
-#define CPPR_MASK  0xff000000
-
-#define XISR(ss)   (((ss)->xirr) & XISR_MASK)
-#define CPPR(ss)   (((ss)->xirr) >> 24)
-
-struct ics_state;
-
-struct icp_state {
-    long nr_servers;
-    struct icp_server_state *ss;
-    struct ics_state *ics;
-};
-
-static void ics_reject(struct ics_state *ics, int nr);
-static void ics_resend(struct ics_state *ics);
-static void ics_eoi(struct ics_state *ics, int nr);
-
-static void icp_check_ipi(struct icp_state *icp, int server)
-{
-    struct icp_server_state *ss = icp->ss + server;
-
-    if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
-        return;
-    }
-
-    trace_xics_icp_check_ipi(server, ss->mfrr);
-
-    if (XISR(ss)) {
-        ics_reject(icp->ics, XISR(ss));
-    }
-
-    ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
-    ss->pending_priority = ss->mfrr;
-    qemu_irq_raise(ss->output);
-}
-
-static void icp_resend(struct icp_state *icp, int server)
-{
-    struct icp_server_state *ss = icp->ss + server;
-
-    if (ss->mfrr < CPPR(ss)) {
-        icp_check_ipi(icp, server);
-    }
-    ics_resend(icp->ics);
-}
-
-static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr)
-{
-    struct icp_server_state *ss = icp->ss + server;
-    uint8_t old_cppr;
-    uint32_t old_xisr;
-
-    old_cppr = CPPR(ss);
-    ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
-
-    if (cppr < old_cppr) {
-        if (XISR(ss) && (cppr <= ss->pending_priority)) {
-            old_xisr = XISR(ss);
-            ss->xirr &= ~XISR_MASK; /* Clear XISR */
-            qemu_irq_lower(ss->output);
-            ics_reject(icp->ics, old_xisr);
-        }
-    } else {
-        if (!XISR(ss)) {
-            icp_resend(icp, server);
-        }
-    }
-}
-
-static void icp_set_mfrr(struct icp_state *icp, int server, uint8_t mfrr)
-{
-    struct icp_server_state *ss = icp->ss + server;
-
-    ss->mfrr = mfrr;
-    if (mfrr < CPPR(ss)) {
-        icp_check_ipi(icp, server);
-    }
-}
-
-static uint32_t icp_accept(struct icp_server_state *ss)
-{
-    uint32_t xirr = ss->xirr;
-
-    qemu_irq_lower(ss->output);
-    ss->xirr = ss->pending_priority << 24;
-
-    trace_xics_icp_accept(xirr, ss->xirr);
-
-    return xirr;
-}
-
-static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr)
-{
-    struct icp_server_state *ss = icp->ss + server;
-
-    /* Send EOI -> ICS */
-    ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
-    trace_xics_icp_eoi(server, xirr, ss->xirr);
-    ics_eoi(icp->ics, xirr & XISR_MASK);
-    if (!XISR(ss)) {
-        icp_resend(icp, server);
-    }
-}
-
-static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority)
-{
-    struct icp_server_state *ss = icp->ss + server;
-
-    trace_xics_icp_irq(server, nr, priority);
-
-    if ((priority >= CPPR(ss))
-        || (XISR(ss) && (ss->pending_priority <= priority))) {
-        ics_reject(icp->ics, nr);
-    } else {
-        if (XISR(ss)) {
-            ics_reject(icp->ics, XISR(ss));
-        }
-        ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
-        ss->pending_priority = priority;
-        trace_xics_icp_raise(ss->xirr, ss->pending_priority);
-        qemu_irq_raise(ss->output);
-    }
-}
-
-/*
- * ICS: Source layer
- */
-
-struct ics_irq_state {
-    int server;
-    uint8_t priority;
-    uint8_t saved_priority;
-#define XICS_STATUS_ASSERTED           0x1
-#define XICS_STATUS_SENT               0x2
-#define XICS_STATUS_REJECTED           0x4
-#define XICS_STATUS_MASKED_PENDING     0x8
-    uint8_t status;
-};
-
-struct ics_state {
-    int nr_irqs;
-    int offset;
-    qemu_irq *qirqs;
-    bool *islsi;
-    struct ics_irq_state *irqs;
-    struct icp_state *icp;
-};
-
-static int ics_valid_irq(struct ics_state *ics, uint32_t nr)
-{
-    return (nr >= ics->offset)
-        && (nr < (ics->offset + ics->nr_irqs));
-}
-
-static void resend_msi(struct ics_state *ics, int srcno)
-{
-    struct ics_irq_state *irq = ics->irqs + srcno;
-
-    /* FIXME: filter by server#? */
-    if (irq->status & XICS_STATUS_REJECTED) {
-        irq->status &= ~XICS_STATUS_REJECTED;
-        if (irq->priority != 0xff) {
-            icp_irq(ics->icp, irq->server, srcno + ics->offset,
-                    irq->priority);
-        }
-    }
-}
-
-static void resend_lsi(struct ics_state *ics, int srcno)
-{
-    struct ics_irq_state *irq = ics->irqs + srcno;
-
-    if ((irq->priority != 0xff)
-        && (irq->status & XICS_STATUS_ASSERTED)
-        && !(irq->status & XICS_STATUS_SENT)) {
-        irq->status |= XICS_STATUS_SENT;
-        icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
-    }
-}
-
-static void set_irq_msi(struct ics_state *ics, int srcno, int val)
-{
-    struct ics_irq_state *irq = ics->irqs + srcno;
-
-    trace_xics_set_irq_msi(srcno, srcno + ics->offset);
-
-    if (val) {
-        if (irq->priority == 0xff) {
-            irq->status |= XICS_STATUS_MASKED_PENDING;
-            trace_xics_masked_pending();
-        } else  {
-            icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
-        }
-    }
-}
-
-static void set_irq_lsi(struct ics_state *ics, int srcno, int val)
-{
-    struct ics_irq_state *irq = ics->irqs + srcno;
-
-    trace_xics_set_irq_lsi(srcno, srcno + ics->offset);
-    if (val) {
-        irq->status |= XICS_STATUS_ASSERTED;
-    } else {
-        irq->status &= ~XICS_STATUS_ASSERTED;
-    }
-    resend_lsi(ics, srcno);
-}
-
-static void ics_set_irq(void *opaque, int srcno, int val)
-{
-    struct ics_state *ics = (struct ics_state *)opaque;
-
-    if (ics->islsi[srcno]) {
-        set_irq_lsi(ics, srcno, val);
-    } else {
-        set_irq_msi(ics, srcno, val);
-    }
-}
-
-static void write_xive_msi(struct ics_state *ics, int srcno)
-{
-    struct ics_irq_state *irq = ics->irqs + srcno;
-
-    if (!(irq->status & XICS_STATUS_MASKED_PENDING)
-        || (irq->priority == 0xff)) {
-        return;
-    }
-
-    irq->status &= ~XICS_STATUS_MASKED_PENDING;
-    icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
-}
-
-static void write_xive_lsi(struct ics_state *ics, int srcno)
-{
-    resend_lsi(ics, srcno);
-}
-
-static void ics_write_xive(struct ics_state *ics, int nr, int server,
-                           uint8_t priority, uint8_t saved_priority)
-{
-    int srcno = nr - ics->offset;
-    struct ics_irq_state *irq = ics->irqs + srcno;
-
-    irq->server = server;
-    irq->priority = priority;
-    irq->saved_priority = saved_priority;
-
-    trace_xics_ics_write_xive(nr, srcno, server, priority);
-
-    if (ics->islsi[srcno]) {
-        write_xive_lsi(ics, srcno);
-    } else {
-        write_xive_msi(ics, srcno);
-    }
-}
-
-static void ics_reject(struct ics_state *ics, int nr)
-{
-    struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
-
-    trace_xics_ics_reject(nr, nr - ics->offset);
-    irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */
-    irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */
-}
-
-static void ics_resend(struct ics_state *ics)
-{
-    int i;
-
-    for (i = 0; i < ics->nr_irqs; i++) {
-        /* FIXME: filter by server#? */
-        if (ics->islsi[i]) {
-            resend_lsi(ics, i);
-        } else {
-            resend_msi(ics, i);
-        }
-    }
-}
-
-static void ics_eoi(struct ics_state *ics, int nr)
-{
-    int srcno = nr - ics->offset;
-    struct ics_irq_state *irq = ics->irqs + srcno;
-
-    trace_xics_ics_eoi(nr);
-
-    if (ics->islsi[srcno]) {
-        irq->status &= ~XICS_STATUS_SENT;
-    }
-}
-
-/*
- * Exported functions
- */
-
-qemu_irq xics_get_qirq(struct icp_state *icp, int irq)
-{
-    if (!ics_valid_irq(icp->ics, irq)) {
-        return NULL;
-    }
-
-    return icp->ics->qirqs[irq - icp->ics->offset];
-}
-
-void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi)
-{
-    assert(ics_valid_irq(icp->ics, irq));
-
-    icp->ics->islsi[irq - icp->ics->offset] = lsi;
-}
-
-static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
-                           target_ulong opcode, target_ulong *args)
-{
-    CPUState *cs = CPU(cpu);
-    target_ulong cppr = args[0];
-
-    icp_set_cppr(spapr->icp, cs->cpu_index, cppr);
-    return H_SUCCESS;
-}
-
-static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
-                          target_ulong opcode, target_ulong *args)
-{
-    target_ulong server = args[0];
-    target_ulong mfrr = args[1];
-
-    if (server >= spapr->icp->nr_servers) {
-        return H_PARAMETER;
-    }
-
-    icp_set_mfrr(spapr->icp, server, mfrr);
-    return H_SUCCESS;
-}
-
-static target_ulong h_xirr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
-                           target_ulong opcode, target_ulong *args)
-{
-    CPUState *cs = CPU(cpu);
-    uint32_t xirr = icp_accept(spapr->icp->ss + cs->cpu_index);
-
-    args[0] = xirr;
-    return H_SUCCESS;
-}
-
-static target_ulong h_eoi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
-                          target_ulong opcode, target_ulong *args)
-{
-    CPUState *cs = CPU(cpu);
-    target_ulong xirr = args[0];
-
-    icp_eoi(spapr->icp, cs->cpu_index, xirr);
-    return H_SUCCESS;
-}
-
-static void rtas_set_xive(sPAPREnvironment *spapr, uint32_t token,
-                          uint32_t nargs, target_ulong args,
-                          uint32_t nret, target_ulong rets)
-{
-    struct ics_state *ics = spapr->icp->ics;
-    uint32_t nr, server, priority;
-
-    if ((nargs != 3) || (nret != 1)) {
-        rtas_st(rets, 0, -3);
-        return;
-    }
-
-    nr = rtas_ld(args, 0);
-    server = rtas_ld(args, 1);
-    priority = rtas_ld(args, 2);
-
-    if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
-        || (priority > 0xff)) {
-        rtas_st(rets, 0, -3);
-        return;
-    }
-
-    ics_write_xive(ics, nr, server, priority, priority);
-
-    rtas_st(rets, 0, 0); /* Success */
-}
-
-static void rtas_get_xive(sPAPREnvironment *spapr, uint32_t token,
-                          uint32_t nargs, target_ulong args,
-                          uint32_t nret, target_ulong rets)
-{
-    struct ics_state *ics = spapr->icp->ics;
-    uint32_t nr;
-
-    if ((nargs != 1) || (nret != 3)) {
-        rtas_st(rets, 0, -3);
-        return;
-    }
-
-    nr = rtas_ld(args, 0);
-
-    if (!ics_valid_irq(ics, nr)) {
-        rtas_st(rets, 0, -3);
-        return;
-    }
-
-    rtas_st(rets, 0, 0); /* Success */
-    rtas_st(rets, 1, ics->irqs[nr - ics->offset].server);
-    rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
-}
-
-static void rtas_int_off(sPAPREnvironment *spapr, uint32_t token,
-                         uint32_t nargs, target_ulong args,
-                         uint32_t nret, target_ulong rets)
-{
-    struct ics_state *ics = spapr->icp->ics;
-    uint32_t nr;
-
-    if ((nargs != 1) || (nret != 1)) {
-        rtas_st(rets, 0, -3);
-        return;
-    }
-
-    nr = rtas_ld(args, 0);
-
-    if (!ics_valid_irq(ics, nr)) {
-        rtas_st(rets, 0, -3);
-        return;
-    }
-
-    ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff,
-                   ics->irqs[nr - ics->offset].priority);
-
-    rtas_st(rets, 0, 0); /* Success */
-}
-
-static void rtas_int_on(sPAPREnvironment *spapr, uint32_t token,
-                        uint32_t nargs, target_ulong args,
-                        uint32_t nret, target_ulong rets)
-{
-    struct ics_state *ics = spapr->icp->ics;
-    uint32_t nr;
-
-    if ((nargs != 1) || (nret != 1)) {
-        rtas_st(rets, 0, -3);
-        return;
-    }
-
-    nr = rtas_ld(args, 0);
-
-    if (!ics_valid_irq(ics, nr)) {
-        rtas_st(rets, 0, -3);
-        return;
-    }
-
-    ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server,
-                   ics->irqs[nr - ics->offset].saved_priority,
-                   ics->irqs[nr - ics->offset].saved_priority);
-
-    rtas_st(rets, 0, 0); /* Success */
-}
-
-static void xics_reset(void *opaque)
-{
-    struct icp_state *icp = (struct icp_state *)opaque;
-    struct ics_state *ics = icp->ics;
-    int i;
-
-    for (i = 0; i < icp->nr_servers; i++) {
-        icp->ss[i].xirr = 0;
-        icp->ss[i].pending_priority = 0xff;
-        icp->ss[i].mfrr = 0xff;
-        /* Make all outputs are deasserted */
-        qemu_set_irq(icp->ss[i].output, 0);
-    }
-
-    memset(ics->irqs, 0, sizeof(struct ics_irq_state) * ics->nr_irqs);
-    for (i = 0; i < ics->nr_irqs; i++) {
-        ics->irqs[i].priority = 0xff;
-        ics->irqs[i].saved_priority = 0xff;
-    }
-}
-
-struct icp_state *xics_system_init(int nr_irqs)
-{
-    CPUPPCState *env;
-    CPUState *cpu;
-    int max_server_num;
-    struct icp_state *icp;
-    struct ics_state *ics;
-
-    max_server_num = -1;
-    for (env = first_cpu; env != NULL; env = env->next_cpu) {
-        cpu = CPU(ppc_env_get_cpu(env));
-        if (cpu->cpu_index > max_server_num) {
-            max_server_num = cpu->cpu_index;
-        }
-    }
-
-    icp = g_malloc0(sizeof(*icp));
-    icp->nr_servers = max_server_num + 1;
-    icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state));
-
-    for (env = first_cpu; env != NULL; env = env->next_cpu) {
-        cpu = CPU(ppc_env_get_cpu(env));
-        struct icp_server_state *ss = &icp->ss[cpu->cpu_index];
-
-        switch (PPC_INPUT(env)) {
-        case PPC_FLAGS_INPUT_POWER7:
-            ss->output = env->irq_inputs[POWER7_INPUT_INT];
-            break;
-
-        case PPC_FLAGS_INPUT_970:
-            ss->output = env->irq_inputs[PPC970_INPUT_INT];
-            break;
-
-        default:
-            hw_error("XICS interrupt model does not support this CPU bus "
-                     "model\n");
-            exit(1);
-        }
-    }
-
-    ics = g_malloc0(sizeof(*ics));
-    ics->nr_irqs = nr_irqs;
-    ics->offset = XICS_IRQ_BASE;
-    ics->irqs = g_malloc0(nr_irqs * sizeof(struct ics_irq_state));
-    ics->islsi = g_malloc0(nr_irqs * sizeof(bool));
-
-    icp->ics = ics;
-    ics->icp = icp;
-
-    ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, nr_irqs);
-
-    spapr_register_hypercall(H_CPPR, h_cppr);
-    spapr_register_hypercall(H_IPI, h_ipi);
-    spapr_register_hypercall(H_XIRR, h_xirr);
-    spapr_register_hypercall(H_EOI, h_eoi);
-
-    spapr_rtas_register("ibm,set-xive", rtas_set_xive);
-    spapr_rtas_register("ibm,get-xive", rtas_get_xive);
-    spapr_rtas_register("ibm,int-off", rtas_int_off);
-    spapr_rtas_register("ibm,int-on", rtas_int_on);
-
-    qemu_register_reset(xics_reset, icp);
-
-    return icp;
-}