On Thu, Mar 16, 2017 at 03:35:08PM +0100, Cédric Le Goater wrote: > This provides a new ICPState object for the PowerNV machine (POWER8). > Access to the Interrupt Management area is done though a memory > region. It contains the registers of the Interrupt Control Presenters > of each thread which are used to accept, return, forward interrupts in > the system. > > Signed-off-by: Cédric Le Goater Revieed-by: David Gibson > --- > > Changes since v1: > > - moved the memory region from PnvCore to a specific PnvICPState object > > hw/intc/Makefile.objs | 1 + > hw/intc/xics_pnv.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++ > include/hw/ppc/xics.h | 12 ++++ > 3 files changed, 193 insertions(+) > create mode 100644 hw/intc/xics_pnv.c > > diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs > index adedd0da5fd8..78426a7dafcd 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_pnv.c b/hw/intc/xics_pnv.c > new file mode 100644 > index 000000000000..68a3ef6097a6 > --- /dev/null > +++ b/hw/intc/xics_pnv.c > @@ -0,0 +1,180 @@ > +/* > + * QEMU PowerPC PowerNV ICP model > + * > + * Copyright (c) 2016, 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 . > + */ > + > +#include "qemu/osdep.h" > +#include "sysemu/sysemu.h" > +#include "qapi/error.h" > +#include "qemu/log.h" > +#include "hw/ppc/xics.h" > + > +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 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 = picp->links[0]; > + } else { > + goto bad_access; > + } > + break; > + case 20: > + if (width == 4) { > + val = picp->links[1]; > + } else { > + goto bad_access; > + } > + break; > + case 24: > + 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 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) { > + picp->links[0] = val; > + } else { > + goto bad_access; > + } > + break; > + case 20: > + if (width == 4) { > + picp->links[1] = val; > + } else { > + goto bad_access; > + } > + break; > + case 24: > + 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, > + .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 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/include/hw/ppc/xics.h b/include/hw/ppc/xics.h > index 0863e3a079f5..cfcf7ecece69 100644 > --- a/include/hw/ppc/xics.h > +++ b/include/hw/ppc/xics.h > @@ -41,10 +41,12 @@ > */ > typedef struct ICPStateClass ICPStateClass; > typedef struct ICPState ICPState; > +typedef struct PnvICPState PnvICPState; > typedef struct ICSStateClass ICSStateClass; > typedef struct ICSState ICSState; > typedef struct ICSIRQState ICSIRQState; > typedef struct XICSFabric XICSFabric; > +typedef struct PowerPCCPU PowerPCCPU; > > #define TYPE_ICP "icp" > #define ICP(obj) OBJECT_CHECK(ICPState, (obj), TYPE_ICP) > @@ -52,6 +54,9 @@ typedef struct XICSFabric XICSFabric; > #define TYPE_KVM_ICP "icp-kvm" > #define KVM_ICP(obj) OBJECT_CHECK(ICPState, (obj), TYPE_KVM_ICP) > > +#define TYPE_PNV_ICP "pnv-icp" > +#define PNV_ICP(obj) OBJECT_CHECK(PnvICPState, (obj), TYPE_PNV_ICP) > + > #define ICP_CLASS(klass) \ > OBJECT_CLASS_CHECK(ICPStateClass, (klass), TYPE_ICP) > #define ICP_GET_CLASS(obj) \ > @@ -81,6 +86,13 @@ struct ICPState { > XICSFabric *xics; > }; > > +struct PnvICPState { > + ICPState parent_obj; > + > + MemoryRegion mmio; > + uint32_t links[3]; > +}; > + > #define TYPE_ICS_BASE "ics-base" > #define ICS_BASE(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS_BASE) > -- David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson