199285aaeSCédric Le Goater /* 299285aaeSCédric Le Goater * QEMU PowerPC PowerNV Interrupt Control Presenter (ICP) model 399285aaeSCédric Le Goater * 499285aaeSCédric Le Goater * Copyright (c) 2017, IBM Corporation. 599285aaeSCédric Le Goater * 699285aaeSCédric Le Goater * This library is free software; you can redistribute it and/or 799285aaeSCédric Le Goater * modify it under the terms of the GNU Lesser General Public License 899285aaeSCédric Le Goater * as published by the Free Software Foundation; either version 2 of 999285aaeSCédric Le Goater * the License, or (at your option) any later version. 1099285aaeSCédric Le Goater * 1199285aaeSCédric Le Goater * This library is distributed in the hope that it will be useful, but 1299285aaeSCédric Le Goater * WITHOUT ANY WARRANTY; without even the implied warranty of 1399285aaeSCédric Le Goater * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1499285aaeSCédric Le Goater * Lesser General Public License for more details. 1599285aaeSCédric Le Goater * 1699285aaeSCédric Le Goater * You should have received a copy of the GNU Lesser General Public 1799285aaeSCédric Le Goater * License along with this library; if not, see <http://www.gnu.org/licenses/>. 1899285aaeSCédric Le Goater */ 1999285aaeSCédric Le Goater 2099285aaeSCédric Le Goater #include "qemu/osdep.h" 21*a028dd42SCédric Le Goater #include "qapi/error.h" 2299285aaeSCédric Le Goater #include "sysemu/sysemu.h" 2399285aaeSCédric Le Goater #include "qemu/log.h" 2499285aaeSCédric Le Goater #include "hw/ppc/xics.h" 2599285aaeSCédric Le Goater 2699285aaeSCédric Le Goater #define ICP_XIRR_POLL 0 /* 1 byte (CPRR) or 4 bytes */ 2799285aaeSCédric Le Goater #define ICP_XIRR 4 /* 1 byte (CPRR) or 4 bytes */ 2899285aaeSCédric Le Goater #define ICP_MFRR 12 /* 1 byte access only */ 2999285aaeSCédric Le Goater 3099285aaeSCédric Le Goater #define ICP_LINKA 16 /* unused */ 3199285aaeSCédric Le Goater #define ICP_LINKB 20 /* unused */ 3299285aaeSCédric Le Goater #define ICP_LINKC 24 /* unused */ 3399285aaeSCédric Le Goater 3499285aaeSCédric Le Goater static uint64_t pnv_icp_read(void *opaque, hwaddr addr, unsigned width) 3599285aaeSCédric Le Goater { 3699285aaeSCédric Le Goater ICPState *icp = ICP(opaque); 3799285aaeSCédric Le Goater PnvICPState *picp = PNV_ICP(opaque); 3899285aaeSCédric Le Goater bool byte0 = (width == 1 && (addr & 0x3) == 0); 3999285aaeSCédric Le Goater uint64_t val = 0xffffffff; 4099285aaeSCédric Le Goater 4199285aaeSCédric Le Goater switch (addr & 0xffc) { 4299285aaeSCédric Le Goater case ICP_XIRR_POLL: 4399285aaeSCédric Le Goater val = icp_ipoll(icp, NULL); 4499285aaeSCédric Le Goater if (byte0) { 4599285aaeSCédric Le Goater val >>= 24; 4699285aaeSCédric Le Goater } else if (width != 4) { 4799285aaeSCédric Le Goater goto bad_access; 4899285aaeSCédric Le Goater } 4999285aaeSCédric Le Goater break; 5099285aaeSCédric Le Goater case ICP_XIRR: 5199285aaeSCédric Le Goater if (byte0) { 5299285aaeSCédric Le Goater val = icp_ipoll(icp, NULL) >> 24; 5399285aaeSCédric Le Goater } else if (width == 4) { 5499285aaeSCédric Le Goater val = icp_accept(icp); 5599285aaeSCédric Le Goater } else { 5699285aaeSCédric Le Goater goto bad_access; 5799285aaeSCédric Le Goater } 5899285aaeSCédric Le Goater break; 5999285aaeSCédric Le Goater case ICP_MFRR: 6099285aaeSCédric Le Goater if (byte0) { 6199285aaeSCédric Le Goater val = icp->mfrr; 6299285aaeSCédric Le Goater } else { 6399285aaeSCédric Le Goater goto bad_access; 6499285aaeSCédric Le Goater } 6599285aaeSCédric Le Goater break; 6699285aaeSCédric Le Goater case ICP_LINKA: 6799285aaeSCédric Le Goater if (width == 4) { 6899285aaeSCédric Le Goater val = picp->links[0]; 6999285aaeSCédric Le Goater } else { 7099285aaeSCédric Le Goater goto bad_access; 7199285aaeSCédric Le Goater } 7299285aaeSCédric Le Goater break; 7399285aaeSCédric Le Goater case ICP_LINKB: 7499285aaeSCédric Le Goater if (width == 4) { 7599285aaeSCédric Le Goater val = picp->links[1]; 7699285aaeSCédric Le Goater } else { 7799285aaeSCédric Le Goater goto bad_access; 7899285aaeSCédric Le Goater } 7999285aaeSCédric Le Goater break; 8099285aaeSCédric Le Goater case ICP_LINKC: 8199285aaeSCédric Le Goater if (width == 4) { 8299285aaeSCédric Le Goater val = picp->links[2]; 8399285aaeSCédric Le Goater } else { 8499285aaeSCédric Le Goater goto bad_access; 8599285aaeSCédric Le Goater } 8699285aaeSCédric Le Goater break; 8799285aaeSCédric Le Goater default: 8899285aaeSCédric Le Goater bad_access: 8999285aaeSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "XICS: Bad ICP access 0x%" 9099285aaeSCédric Le Goater HWADDR_PRIx"/%d\n", addr, width); 9199285aaeSCédric Le Goater } 9299285aaeSCédric Le Goater 9399285aaeSCédric Le Goater return val; 9499285aaeSCédric Le Goater } 9599285aaeSCédric Le Goater 9699285aaeSCédric Le Goater static void pnv_icp_write(void *opaque, hwaddr addr, uint64_t val, 9799285aaeSCédric Le Goater unsigned width) 9899285aaeSCédric Le Goater { 9999285aaeSCédric Le Goater ICPState *icp = ICP(opaque); 10099285aaeSCédric Le Goater PnvICPState *picp = PNV_ICP(opaque); 10199285aaeSCédric Le Goater bool byte0 = (width == 1 && (addr & 0x3) == 0); 10299285aaeSCédric Le Goater 10399285aaeSCédric Le Goater switch (addr & 0xffc) { 10499285aaeSCédric Le Goater case ICP_XIRR: 10599285aaeSCédric Le Goater if (byte0) { 10699285aaeSCédric Le Goater icp_set_cppr(icp, val); 10799285aaeSCédric Le Goater } else if (width == 4) { 10899285aaeSCédric Le Goater icp_eoi(icp, val); 10999285aaeSCédric Le Goater } else { 11099285aaeSCédric Le Goater goto bad_access; 11199285aaeSCédric Le Goater } 11299285aaeSCédric Le Goater break; 11399285aaeSCédric Le Goater case ICP_MFRR: 11499285aaeSCédric Le Goater if (byte0) { 11599285aaeSCédric Le Goater icp_set_mfrr(icp, val); 11699285aaeSCédric Le Goater } else { 11799285aaeSCédric Le Goater goto bad_access; 11899285aaeSCédric Le Goater } 11999285aaeSCédric Le Goater break; 12099285aaeSCédric Le Goater case ICP_LINKA: 12199285aaeSCédric Le Goater if (width == 4) { 12299285aaeSCédric Le Goater picp->links[0] = val; 12399285aaeSCédric Le Goater } else { 12499285aaeSCédric Le Goater goto bad_access; 12599285aaeSCédric Le Goater } 12699285aaeSCédric Le Goater break; 12799285aaeSCédric Le Goater case ICP_LINKB: 12899285aaeSCédric Le Goater if (width == 4) { 12999285aaeSCédric Le Goater picp->links[1] = val; 13099285aaeSCédric Le Goater } else { 13199285aaeSCédric Le Goater goto bad_access; 13299285aaeSCédric Le Goater } 13399285aaeSCédric Le Goater break; 13499285aaeSCédric Le Goater case ICP_LINKC: 13599285aaeSCédric Le Goater if (width == 4) { 13699285aaeSCédric Le Goater picp->links[2] = val; 13799285aaeSCédric Le Goater } else { 13899285aaeSCédric Le Goater goto bad_access; 13999285aaeSCédric Le Goater } 14099285aaeSCédric Le Goater break; 14199285aaeSCédric Le Goater default: 14299285aaeSCédric Le Goater bad_access: 14399285aaeSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "XICS: Bad ICP access 0x%" 14499285aaeSCédric Le Goater HWADDR_PRIx"/%d\n", addr, width); 14599285aaeSCédric Le Goater } 14699285aaeSCédric Le Goater } 14799285aaeSCédric Le Goater 14899285aaeSCédric Le Goater static const MemoryRegionOps pnv_icp_ops = { 14999285aaeSCédric Le Goater .read = pnv_icp_read, 15099285aaeSCédric Le Goater .write = pnv_icp_write, 15199285aaeSCédric Le Goater .endianness = DEVICE_BIG_ENDIAN, 15299285aaeSCédric Le Goater .valid = { 15399285aaeSCédric Le Goater .min_access_size = 1, 15499285aaeSCédric Le Goater .max_access_size = 4, 15599285aaeSCédric Le Goater }, 15699285aaeSCédric Le Goater .impl = { 15799285aaeSCédric Le Goater .min_access_size = 1, 15899285aaeSCédric Le Goater .max_access_size = 4, 15999285aaeSCédric Le Goater }, 16099285aaeSCédric Le Goater }; 16199285aaeSCédric Le Goater 162*a028dd42SCédric Le Goater static void pnv_icp_realize(DeviceState *dev, Error **errp) 16399285aaeSCédric Le Goater { 164*a028dd42SCédric Le Goater ICPState *icp = ICP(dev); 165100f7388SGreg Kurz PnvICPState *pnv_icp = PNV_ICP(icp); 166*a028dd42SCédric Le Goater ICPStateClass *icpc = ICP_GET_CLASS(icp); 167*a028dd42SCédric Le Goater Error *local_err = NULL; 168*a028dd42SCédric Le Goater 169*a028dd42SCédric Le Goater icpc->parent_realize(dev, &local_err); 170*a028dd42SCédric Le Goater if (local_err) { 171*a028dd42SCédric Le Goater error_propagate(errp, local_err); 172*a028dd42SCédric Le Goater return; 173*a028dd42SCédric Le Goater } 17499285aaeSCédric Le Goater 175100f7388SGreg Kurz memory_region_init_io(&pnv_icp->mmio, OBJECT(icp), &pnv_icp_ops, 17699285aaeSCédric Le Goater icp, "icp-thread", 0x1000); 17799285aaeSCédric Le Goater } 17899285aaeSCédric Le Goater 17999285aaeSCédric Le Goater static void pnv_icp_class_init(ObjectClass *klass, void *data) 18099285aaeSCédric Le Goater { 18199285aaeSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 18299285aaeSCédric Le Goater ICPStateClass *icpc = ICP_CLASS(klass); 18399285aaeSCédric Le Goater 184*a028dd42SCédric Le Goater device_class_set_parent_realize(dc, pnv_icp_realize, 185*a028dd42SCédric Le Goater &icpc->parent_realize); 18699285aaeSCédric Le Goater dc->desc = "PowerNV ICP"; 18799285aaeSCédric Le Goater } 18899285aaeSCédric Le Goater 18999285aaeSCédric Le Goater static const TypeInfo pnv_icp_info = { 19099285aaeSCédric Le Goater .name = TYPE_PNV_ICP, 19199285aaeSCédric Le Goater .parent = TYPE_ICP, 19299285aaeSCédric Le Goater .instance_size = sizeof(PnvICPState), 19399285aaeSCédric Le Goater .class_init = pnv_icp_class_init, 19499285aaeSCédric Le Goater .class_size = sizeof(ICPStateClass), 19599285aaeSCédric Le Goater }; 19699285aaeSCédric Le Goater 19799285aaeSCédric Le Goater static void pnv_icp_register_types(void) 19899285aaeSCédric Le Goater { 19999285aaeSCédric Le Goater type_register_static(&pnv_icp_info); 20099285aaeSCédric Le Goater } 20199285aaeSCédric Le Goater 20299285aaeSCédric Le Goater type_init(pnv_icp_register_types) 203