aboutsummaryrefslogtreecommitdiff
path: root/hw/intc
diff options
context:
space:
mode:
Diffstat (limited to 'hw/intc')
-rw-r--r--hw/intc/Makefile.objs1
-rw-r--r--hw/intc/xics.c22
-rw-r--r--hw/intc/xics_pnv.c192
-rw-r--r--hw/intc/xics_spapr.c25
4 files changed, 208 insertions, 32 deletions
diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index adedd0d..78426a7 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -35,6 +35,7 @@ obj-$(CONFIG_SH4) += sh_intc.o
obj-$(CONFIG_XICS) += xics.o
obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o
obj-$(CONFIG_XICS_KVM) += xics_kvm.o
+obj-$(CONFIG_POWERNV) += xics_pnv.o
obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
obj-$(CONFIG_S390_FLIC) += s390_flic.o
obj-$(CONFIG_S390_FLIC_KVM) += s390_flic_kvm.o
diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index e740989..292fffe 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -38,21 +38,10 @@
#include "monitor/monitor.h"
#include "hw/intc/intc.h"
-int xics_get_cpu_index_by_dt_id(int cpu_dt_id)
-{
- PowerPCCPU *cpu = ppc_get_vcpu_by_dt_id(cpu_dt_id);
-
- if (cpu) {
- return cpu->parent_obj.cpu_index;
- }
-
- return -1;
-}
-
void xics_cpu_destroy(XICSFabric *xi, PowerPCCPU *cpu)
{
CPUState *cs = CPU(cpu);
- ICPState *icp = xics_icp_get(xi, cs->cpu_index);
+ ICPState *icp = ICP(cpu->intc);
assert(icp);
assert(cs == icp->cs);
@@ -61,15 +50,15 @@ void xics_cpu_destroy(XICSFabric *xi, PowerPCCPU *cpu)
icp->cs = NULL;
}
-void xics_cpu_setup(XICSFabric *xi, PowerPCCPU *cpu)
+void xics_cpu_setup(XICSFabric *xi, PowerPCCPU *cpu, ICPState *icp)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
- ICPState *icp = xics_icp_get(xi, cs->cpu_index);
ICPStateClass *icpc;
assert(icp);
+ cpu->intc = OBJECT(icp);
icp->cs = cs;
icpc = ICP_GET_CLASS(icp);
@@ -348,6 +337,7 @@ static void icp_reset(void *dev)
static void icp_realize(DeviceState *dev, Error **errp)
{
ICPState *icp = ICP(dev);
+ ICPStateClass *icpc = ICP_GET_CLASS(dev);
Object *obj;
Error *err = NULL;
@@ -360,6 +350,10 @@ static void icp_realize(DeviceState *dev, Error **errp)
icp->xics = XICS_FABRIC(obj);
+ if (icpc->realize) {
+ icpc->realize(dev, errp);
+ }
+
qemu_register_reset(icp_reset, dev);
}
diff --git a/hw/intc/xics_pnv.c b/hw/intc/xics_pnv.c
new file mode 100644
index 0000000..12ae605
--- /dev/null
+++ b/hw/intc/xics_pnv.c
@@ -0,0 +1,192 @@
+/*
+ * QEMU PowerPC PowerNV Interrupt Control Presenter (ICP) model
+ *
+ * Copyright (c) 2017, IBM Corporation.
+ *
+ * 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 "qemu/osdep.h"
+#include "sysemu/sysemu.h"
+#include "qapi/error.h"
+#include "qemu/log.h"
+#include "hw/ppc/xics.h"
+
+#define ICP_XIRR_POLL 0 /* 1 byte (CPRR) or 4 bytes */
+#define ICP_XIRR 4 /* 1 byte (CPRR) or 4 bytes */
+#define ICP_MFRR 12 /* 1 byte access only */
+
+#define ICP_LINKA 16 /* unused */
+#define ICP_LINKB 20 /* unused */
+#define ICP_LINKC 24 /* unused */
+
+static uint64_t pnv_icp_read(void *opaque, hwaddr addr, unsigned width)
+{
+ ICPState *icp = ICP(opaque);
+ PnvICPState *picp = PNV_ICP(opaque);
+ bool byte0 = (width == 1 && (addr & 0x3) == 0);
+ uint64_t val = 0xffffffff;
+
+ switch (addr & 0xffc) {
+ case ICP_XIRR_POLL:
+ val = icp_ipoll(icp, NULL);
+ if (byte0) {
+ val >>= 24;
+ } else if (width != 4) {
+ goto bad_access;
+ }
+ break;
+ case ICP_XIRR:
+ if (byte0) {
+ val = icp_ipoll(icp, NULL) >> 24;
+ } else if (width == 4) {
+ val = icp_accept(icp);
+ } else {
+ goto bad_access;
+ }
+ break;
+ case ICP_MFRR:
+ if (byte0) {
+ val = icp->mfrr;
+ } else {
+ goto bad_access;
+ }
+ break;
+ case ICP_LINKA:
+ if (width == 4) {
+ val = picp->links[0];
+ } else {
+ goto bad_access;
+ }
+ break;
+ case ICP_LINKB:
+ if (width == 4) {
+ val = picp->links[1];
+ } else {
+ goto bad_access;
+ }
+ break;
+ case ICP_LINKC:
+ if (width == 4) {
+ val = picp->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_icp_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned width)
+{
+ ICPState *icp = ICP(opaque);
+ PnvICPState *picp = PNV_ICP(opaque);
+ bool byte0 = (width == 1 && (addr & 0x3) == 0);
+
+ switch (addr & 0xffc) {
+ case ICP_XIRR:
+ if (byte0) {
+ icp_set_cppr(icp, val);
+ } else if (width == 4) {
+ icp_eoi(icp, val);
+ } else {
+ goto bad_access;
+ }
+ break;
+ case ICP_MFRR:
+ if (byte0) {
+ icp_set_mfrr(icp, val);
+ } else {
+ goto bad_access;
+ }
+ break;
+ case ICP_LINKA:
+ if (width == 4) {
+ picp->links[0] = val;
+ } else {
+ goto bad_access;
+ }
+ break;
+ case ICP_LINKB:
+ if (width == 4) {
+ picp->links[1] = val;
+ } else {
+ goto bad_access;
+ }
+ break;
+ case ICP_LINKC:
+ if (width == 4) {
+ picp->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_icp_ops = {
+ .read = pnv_icp_read,
+ .write = pnv_icp_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+};
+
+static void pnv_icp_realize(DeviceState *dev, Error **errp)
+{
+ PnvICPState *icp = PNV_ICP(dev);
+
+ memory_region_init_io(&icp->mmio, OBJECT(dev), &pnv_icp_ops,
+ icp, "icp-thread", 0x1000);
+}
+
+static void pnv_icp_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ICPStateClass *icpc = ICP_CLASS(klass);
+
+ icpc->realize = pnv_icp_realize;
+ dc->desc = "PowerNV ICP";
+}
+
+static const TypeInfo pnv_icp_info = {
+ .name = TYPE_PNV_ICP,
+ .parent = TYPE_ICP,
+ .instance_size = sizeof(PnvICPState),
+ .class_init = pnv_icp_class_init,
+ .class_size = sizeof(ICPStateClass),
+};
+
+static void pnv_icp_register_types(void)
+{
+ type_register_static(&pnv_icp_info);
+}
+
+type_init(pnv_icp_register_types)
diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c
index 84d24b2..f05308b8 100644
--- a/hw/intc/xics_spapr.c
+++ b/hw/intc/xics_spapr.c
@@ -43,20 +43,17 @@
static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
- CPUState *cs = CPU(cpu);
- ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), cs->cpu_index);
target_ulong cppr = args[0];
- icp_set_cppr(icp, cppr);
+ icp_set_cppr(ICP(cpu->intc), cppr);
return H_SUCCESS;
}
static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
- target_ulong server = xics_get_cpu_index_by_dt_id(args[0]);
target_ulong mfrr = args[1];
- ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), server);
+ ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), args[0]);
if (!icp) {
return H_PARAMETER;
@@ -69,9 +66,7 @@ static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
- CPUState *cs = CPU(cpu);
- ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), cs->cpu_index);
- uint32_t xirr = icp_accept(icp);
+ uint32_t xirr = icp_accept(ICP(cpu->intc));
args[0] = xirr;
return H_SUCCESS;
@@ -80,9 +75,7 @@ static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
- CPUState *cs = CPU(cpu);
- ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), cs->cpu_index);
- uint32_t xirr = icp_accept(icp);
+ uint32_t xirr = icp_accept(ICP(cpu->intc));
args[0] = xirr;
args[1] = cpu_get_host_ticks();
@@ -92,21 +85,17 @@ static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr,
static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
- CPUState *cs = CPU(cpu);
- ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), cs->cpu_index);
target_ulong xirr = args[0];
- icp_eoi(icp, xirr);
+ icp_eoi(ICP(cpu->intc), xirr);
return H_SUCCESS;
}
static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
- CPUState *cs = CPU(cpu);
- ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), cs->cpu_index);
uint32_t mfrr;
- uint32_t xirr = icp_ipoll(icp, &mfrr);
+ uint32_t xirr = icp_ipoll(ICP(cpu->intc), &mfrr);
args[0] = xirr;
args[1] = mfrr;
@@ -132,7 +121,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
}
nr = rtas_ld(args, 0);
- server = xics_get_cpu_index_by_dt_id(rtas_ld(args, 1));
+ server = rtas_ld(args, 1);
priority = rtas_ld(args, 2);
if (!ics_valid_irq(ics, nr) || !xics_icp_get(XICS_FABRIC(spapr), server)