[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v6 06/10] ppc/pnv: add MMIO regions for ICPs
From: |
Cédric Le Goater |
Subject: |
[Qemu-devel] [PATCH v6 06/10] ppc/pnv: add MMIO regions for ICPs |
Date: |
Tue, 8 Nov 2016 09:08:06 +0100 |
This provides access to the MMIO based Interrupt Presentation
Controllers (ICP) as found on a POWER8 system.
Each chip of a PowerNV machine has a global container MMIO region for
all ICPs. Each thread of the chip has its own ICP MMIO subregion,
indexed by its PIR number, holding a XIVE (External Interrupt Vector
Entry).
The regions also provide a mean to link with the ICPState to a CPU.
Signed-off-by: Cédric Le Goater <address@hidden>
---
Changes since v5:
- moved the ICP container region to PnvChip
- moved the ICP subregions to PnvCore
- removed XICSNative
- renamed patch
Changes since v4:
- replaced the pir_table by memory subregions using an ICP.
- removed the find_icp() and cpu_setup() handlers which became
useless with the memory regions.
- removed the superfluous inits done in xics_native_initfn. This is
covered in the parent class init.
- took ownership of the patch.
hw/ppc/pnv.c | 16 ++++++
hw/ppc/pnv_core.c | 140 +++++++++++++++++++++++++++++++++++++++++++++-
include/hw/ppc/pnv.h | 20 +++++++
include/hw/ppc/pnv_core.h | 2 +
include/hw/ppc/xics.h | 5 ++
5 files changed, 182 insertions(+), 1 deletion(-)
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 435af7cf4e48..474e791bbe50 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -645,6 +645,15 @@ static void pnv_chip_init(Object *obj)
object_property_add_child(obj, "lpc", OBJECT(&chip->lpc), NULL);
}
+static void pnv_chip_icp_realize(PnvChip *chip, Error **errp)
+{
+ char *name;
+
+ name = g_strdup_printf("icp-%x", chip->chip_id);
+ memory_region_init(&chip->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE);
+ sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip->icp_mmio);
+}
+
static void pnv_chip_realize(DeviceState *dev, Error **errp)
{
PnvChip *chip = PNV_CHIP(dev);
@@ -667,6 +676,13 @@ static void pnv_chip_realize(DeviceState *dev, Error
**errp)
}
sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
+ /* Interrupt Controller */
+ pnv_chip_icp_realize(chip, &error);
+ if (error) {
+ error_propagate(errp, error);
+ return;
+ }
+
/* Cores */
pnv_chip_core_sanitize(chip, &error);
if (error) {
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 76ce854b0c40..426b18b59ed8 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -26,6 +26,128 @@
#include "hw/ppc/pnv_core.h"
#include "hw/ppc/pnv_xscom.h"
+static uint64_t pnv_core_icp_read(void *opaque, hwaddr addr, unsigned width)
+{
+ ICPState *icp = opaque;
+ bool byte0 = (width == 1 && (addr & 0x3) == 0);
+ uint64_t val = 0xffffffff;
+
+ switch (addr & 0xffc) {
+ case 0: /* poll */
+ val = icp_ipoll(icp, NULL);
+ if (byte0) {
+ val >>= 24;
+ } else if (width != 4) {
+ goto bad_access;
+ }
+ break;
+ case 4: /* xirr */
+ if (byte0) {
+ val = icp_ipoll(icp, NULL) >> 24;
+ } else if (width == 4) {
+ val = icp_accept(icp);
+ } else {
+ goto bad_access;
+ }
+ break;
+ case 12:
+ if (byte0) {
+ val = icp->mfrr;
+ } else {
+ goto bad_access;
+ }
+ break;
+ case 16:
+ if (width == 4) {
+ val = icp->links[0];
+ } else {
+ goto bad_access;
+ }
+ break;
+ case 20:
+ if (width == 4) {
+ val = icp->links[1];
+ } else {
+ goto bad_access;
+ }
+ break;
+ case 24:
+ if (width == 4) {
+ val = icp->links[2];
+ } else {
+ goto bad_access;
+ }
+ break;
+ default:
+bad_access:
+ qemu_log_mask(LOG_GUEST_ERROR, "XICS: Bad ICP access 0x%"
+ HWADDR_PRIx"/%d\n", addr, width);
+ }
+
+ return val;
+}
+
+static void pnv_core_icp_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned width)
+{
+ ICPState *icp = opaque;
+ bool byte0 = (width == 1 && (addr & 0x3) == 0);
+
+ switch (addr & 0xffc) {
+ case 4: /* xirr */
+ if (byte0) {
+ icp_set_cppr(icp, val);
+ } else if (width == 4) {
+ icp_eoi(icp, val);
+ } else {
+ goto bad_access;
+ }
+ break;
+ case 12:
+ if (byte0) {
+ icp_set_mfrr(icp, val);
+ } else {
+ goto bad_access;
+ }
+ break;
+ case 16:
+ if (width == 4) {
+ icp->links[0] = val;
+ } else {
+ goto bad_access;
+ }
+ break;
+ case 20:
+ if (width == 4) {
+ icp->links[1] = val;
+ } else {
+ goto bad_access;
+ }
+ break;
+ case 24:
+ if (width == 4) {
+ icp->links[2] = val;
+ } else {
+ goto bad_access;
+ }
+ break;
+ default:
+bad_access:
+ qemu_log_mask(LOG_GUEST_ERROR, "XICS: Bad ICP access 0x%"
+ HWADDR_PRIx"/%d\n", addr, width);
+ }
+}
+
+static const MemoryRegionOps pnv_core_icp_ops = {
+ .read = pnv_core_icp_read,
+ .write = pnv_core_icp_write,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+ .impl.min_access_size = 1,
+ .impl.max_access_size = 4,
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
static void powernv_cpu_reset(void *opaque)
{
PowerPCCPU *cpu = opaque;
@@ -129,6 +251,14 @@ static void pnv_core_realize_child(Object *child, Error
**errp)
}
}
+static ICPState *xics_get_icp_per_pir(XICSState* xics, int pir)
+{
+ int index = xics_get_cpu_index_by_pir(pir);
+ assert(index != -1);
+
+ return &xics->ss[index];
+}
+
static void pnv_core_realize(DeviceState *dev, Error **errp)
{
PnvCore *pc = PNV_CORE(OBJECT(dev));
@@ -140,6 +270,7 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
void *obj;
int i, j;
char name[32];
+ PnvMachineState *pnv = POWERNV_MACHINE(qdev_get_machine());
pc->threads = g_malloc0(size * cc->nr_threads);
for (i = 0; i < cc->nr_threads; i++) {
@@ -169,8 +300,15 @@ static void pnv_core_realize(DeviceState *dev, Error
**errp)
snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id);
pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), &pnv_core_xscom_ops,
pc, name, PNV_XSCOM_EX_CORE_SIZE);
- return;
+ pc->icp_mmios = g_new0(MemoryRegion, cc->nr_threads);
+ for (i = 0; i < cc->nr_threads; i++) {
+ ICPState *icp = xics_get_icp_per_pir(&pnv->xics, pc->pir + i);
+ snprintf(name, sizeof(name), "icp-core.%d", cc->core_id);
+ memory_region_init_io(&pc->icp_mmios[i], OBJECT(dev),
+ &pnv_core_icp_ops, icp, name, 0x1000);
+ }
+ return;
err:
while (--i >= 0) {
obj = pc->threads + i * size;
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index cb9499728fda..2b1cb04b4792 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -55,6 +55,7 @@ typedef struct PnvChip {
MemoryRegion xscom_mmio;
MemoryRegion xscom;
AddressSpace xscom_as;
+ MemoryRegion icp_mmio;
PnvLpcController lpc;
} PnvChip;
@@ -128,4 +129,23 @@ typedef struct PnvMachineState {
#define PNV_XSCOM_BASE(chip) \
(chip->xscom_base + ((uint64_t)(chip)->chip_id) * PNV_XSCOM_SIZE)
+/*
+ * XSCOM 0x20109CA defines the ICP BAR:
+ *
+ * 0:29 : bits 14 to 43 of address to define 1 MB region.
+ * 30 : 1 to enable ICP to receive loads/stores against its BAR region
+ * 31:63 : Constant 0
+ *
+ * Usually defined as :
+ *
+ * 0xffffe00200000000 -> 0x0003ffff80000000
+ * 0xffffe00600000000 -> 0x0003ffff80100000
+ * 0xffffe02200000000 -> 0x0003ffff80800000
+ * 0xffffe02600000000 -> 0x0003ffff80900000
+ *
+ * TODO: make a macro using the chip hw id
+ */
+#define PNV_ICP_BASE(chip) 0x0003ffff80000000ull
+#define PNV_ICP_SIZE 0x0000000000100000ull
+
#endif /* _PPC_PNV_H */
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
index 2955a41c901f..5521b07b3b1f 100644
--- a/include/hw/ppc/pnv_core.h
+++ b/include/hw/ppc/pnv_core.h
@@ -38,6 +38,8 @@ typedef struct PnvCore {
uint32_t pir;
MemoryRegion xscom_regs;
+
+ MemoryRegion *icp_mmios;
} PnvCore;
typedef struct PnvCoreClass {
diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h
index c58a09916f37..3b5e976f8a1a 100644
--- a/include/hw/ppc/xics.h
+++ b/include/hw/ppc/xics.h
@@ -120,6 +120,11 @@ struct ICPState {
bool cap_irq_xics_enabled;
XICSState *xics;
+
+ /*
+ * for XICSNative (not used by Linux).
+ */
+ uint32_t links[3];
};
#define TYPE_ICS_BASE "ics-base"
--
2.7.4
- [Qemu-devel] [PATCH v6 00/10] ppc/pnv: reworking the interrupt controller, Cédric Le Goater, 2016/11/08
- [Qemu-devel] [PATCH v6 01/10] ppc/xics: introduce a helper to insert a new ics, Cédric Le Goater, 2016/11/08
- [Qemu-devel] [PATCH v6 02/10] ppc/xics: add a xics_get_cpu_index_by_pir helper, Cédric Le Goater, 2016/11/08
- [Qemu-devel] [PATCH v6 03/10] ppc/xics: add a 'realize' handler to the xics_common class, Cédric Le Goater, 2016/11/08
- [Qemu-devel] [PATCH v6 04/10] ppc/xics: add a 'set_nr_servers' handler to the xics_common class, Cédric Le Goater, 2016/11/08
- [Qemu-devel] [PATCH v6 05/10] ppc/pnv: add a XICS object to the PowerNV machine, Cédric Le Goater, 2016/11/08
- [Qemu-devel] [PATCH v6 06/10] ppc/pnv: add MMIO regions for ICPs,
Cédric Le Goater <=
- [Qemu-devel] [PATCH v6 07/10] ppc/pnv: link the CPUs to the machine XICS, Cédric Le Goater, 2016/11/08
- [Qemu-devel] [PATCH v6 08/10] ppc/pnv: Add cut down PSI bridge model and hookup external interrupt, Cédric Le Goater, 2016/11/08
- [Qemu-devel] [PATCH v6 09/10] ppc/pnv: Add OCC model stub with interrupt support, Cédric Le Goater, 2016/11/08
- [Qemu-devel] [PATCH v6 10/10] ppc/pnv: Add Naples chip support for LPC interrupts, Cédric Le Goater, 2016/11/08