qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 43/77] ppc/pnv: Add OCC model stub with interrupt su


From: Benjamin Herrenschmidt
Subject: [Qemu-devel] [PATCH 43/77] ppc/pnv: Add OCC model stub with interrupt support
Date: Wed, 11 Nov 2015 11:27:56 +1100

The OCC is an on-chip microcontroller based on a ppc405 core used
for various power management tasks. It comes with a pile of additional
hardware sitting on the PIB (aka XSCOM bus). At this point we don't
emulate it (nor plan to do so). However there is one facility which
is provided by the surrounding hardware that we do need, which is the
interrupt generation facility. OPAL uses it to send itself interrupts
under some circumstances and there are other uses around the corner.

So this implement just enough to support this.

Signed-off-by: Benjamin Herrenschmidt <address@hidden>
---
 hw/ppc/Makefile.objs |   2 +-
 hw/ppc/pnv.c         |   3 ++
 hw/ppc/pnv_occ.c     | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/ppc/pnv.h |   3 ++
 4 files changed, 132 insertions(+), 1 deletion(-)
 create mode 100644 hw/ppc/pnv_occ.c

diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index a5b3ce6..a795b1c 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -5,7 +5,7 @@ obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o
 obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o
 obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o
 # IBM PowerNV
-obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_lpc.o pnv_psi.o
+obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_lpc.o pnv_psi.o pnv_occ.o
 ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
 obj-y += spapr_pci_vfio.o
 endif
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index a10fa60..ae6efbd 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -542,6 +542,9 @@ static void pnv_create_chip(PnvSystem *sys, unsigned int 
chip_no,
                                             chip->psi, 16));
         }
     }
+
+    /* Create the simplified OCC model */
+    pnv_occ_create(chip);
 }
 
 static void ppc_powernv_init(MachineState *machine)
diff --git a/hw/ppc/pnv_occ.c b/hw/ppc/pnv_occ.c
new file mode 100644
index 0000000..a759c6d
--- /dev/null
+++ b/hw/ppc/pnv_occ.c
@@ -0,0 +1,125 @@
+/*
+ * Emulation of a few OCC related registers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright IBM Corp. 2014
+ */
+#include "hw/hw.h"
+#include "hw/ppc/pnv.h"
+#include "hw/ppc/pnv_xscom.h"
+
+struct PnvOCCState {
+    XScomDevice xd;
+    PnvPsiController *psi;
+
+    /* OCC Misc interrupt */
+    uint64_t occmisc;
+};
+
+#define TYPE_PNV_OCC "pnv-occ"
+#define PNV_OCC(obj) OBJECT_CHECK(PnvOCCState, (obj), TYPE_PNV_OCC)
+
+static void pnv_occ_set_misc(PnvOCCState *occ, uint64_t val)
+{
+    bool irq_state;
+
+    val &= 0xffff000000000000ull;
+
+    occ->occmisc = val;
+    irq_state = !!(val >> 63);
+    pnv_psi_irq_set(occ->psi, PSIHB_IRQ_OCC, irq_state);
+}
+
+static bool pnv_occ_xscom_read(XScomDevice *dev, uint32_t range,
+                               uint32_t offset, uint64_t *out_val)
+{
+    PnvOCCState *occ = PNV_OCC(dev);
+    uint32_t pcb_addr = dev->ranges[range].addr + offset;
+
+    switch(pcb_addr) {
+    case 0x6a020:
+        *out_val = occ->occmisc;
+        return true;
+    }
+    return false;
+}
+
+static bool pnv_occ_xscom_write(XScomDevice *dev, uint32_t range,
+                                uint32_t offset, uint64_t val)
+{
+    PnvOCCState *occ = PNV_OCC(dev);
+    uint32_t pcb_addr = dev->ranges[range].addr + offset;
+
+    switch(pcb_addr) {
+    default:
+    case 0x6a020:
+        pnv_occ_set_misc(occ, val);
+        return true;
+    case 0x6a021:
+        pnv_occ_set_misc(occ, occ->occmisc & val);
+        return true;
+    case 0x6a022:
+        pnv_occ_set_misc(occ, occ->occmisc | val);
+        return true;
+   }
+    return false;
+}
+
+static void pnv_occ_realize(DeviceState *dev, Error **errp)
+{
+    PnvOCCState *occ = PNV_OCC(dev);
+    XScomDevice *xd = XSCOM_DEVICE(dev);
+
+    xd->ranges[0].addr = 0x66000;
+    xd->ranges[0].size = 0x6000;
+
+    occ->occmisc = 0;
+}
+
+static void pnv_occ_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    XScomDeviceClass *k = XSCOM_DEVICE_CLASS(klass);
+
+    k->read = pnv_occ_xscom_read;
+    k->write = pnv_occ_xscom_write;
+
+    dc->realize = pnv_occ_realize;
+}
+
+static const TypeInfo pnv_occ_type_info = {
+    .name          = TYPE_PNV_OCC,
+    .parent        = TYPE_XSCOM_DEVICE,
+    .instance_size = sizeof(PnvOCCState),
+    .class_init    = pnv_occ_class_init,
+};
+
+static void pnv_occ_register_types(void)
+{
+    type_register_static(&pnv_occ_type_info);
+}
+
+type_init(pnv_occ_register_types)
+
+void pnv_occ_create(PnvChip *chip)
+{
+    struct DeviceState *dev;
+    PnvOCCState *occ;
+
+    dev = qdev_create(&chip->xscom->bus, TYPE_PNV_OCC);
+    occ = PNV_OCC(dev);
+    occ->psi = chip->psi;
+    qdev_init_nofail(dev);
+    chip->occ = occ;
+}
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index 73bbef9..c488f12 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -25,6 +25,7 @@ typedef struct ISABus ISABus;
 typedef struct PnvLpcController PnvLpcController;
 typedef struct PnvPsiController PnvPsiController;
 typedef struct XICSState XICSState;
+typedef struct PnvOCCState PnvOCCState;
 
 /* Should we turn that into a QOjb of some sort ? */
 typedef struct PnvChip {
@@ -33,6 +34,7 @@ typedef struct PnvChip {
     PnvLpcController *lpc;
     ISABus           *lpc_bus;
     PnvPsiController *psi;
+    PnvOCCState      *occ;
 } PnvChip;
 
 typedef struct PnvSystem {
@@ -44,6 +46,7 @@ typedef struct PnvSystem {
 
 extern void pnv_lpc_create(PnvChip *chip, bool has_serirq);
 extern void pnv_psi_create(PnvChip *chip, XICSState *xics);
+extern void pnv_occ_create(PnvChip *chip);
 
 typedef enum PnvPsiIrq {
     PSIHB_IRQ_PSI, /* internal use only */
-- 
2.5.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]