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" 21a028dd42SCédric Le Goater #include "qapi/error.h" 2299285aaeSCédric Le Goater #include "sysemu/sysemu.h" 2399285aaeSCédric Le Goater #include "qemu/log.h" 24*0b8fa32fSMarkus Armbruster #include "qemu/module.h" 2599285aaeSCédric Le Goater #include "hw/ppc/xics.h" 2699285aaeSCédric Le Goater 2799285aaeSCédric Le Goater #define ICP_XIRR_POLL 0 /* 1 byte (CPRR) or 4 bytes */ 2899285aaeSCédric Le Goater #define ICP_XIRR 4 /* 1 byte (CPRR) or 4 bytes */ 2999285aaeSCédric Le Goater #define ICP_MFRR 12 /* 1 byte access only */ 3099285aaeSCédric Le Goater 3199285aaeSCédric Le Goater #define ICP_LINKA 16 /* unused */ 3299285aaeSCédric Le Goater #define ICP_LINKB 20 /* unused */ 3399285aaeSCédric Le Goater #define ICP_LINKC 24 /* unused */ 3499285aaeSCédric Le Goater 3599285aaeSCédric Le Goater static uint64_t pnv_icp_read(void *opaque, hwaddr addr, unsigned width) 3699285aaeSCédric Le Goater { 3799285aaeSCédric Le Goater ICPState *icp = ICP(opaque); 3899285aaeSCédric Le Goater PnvICPState *picp = PNV_ICP(opaque); 3999285aaeSCédric Le Goater bool byte0 = (width == 1 && (addr & 0x3) == 0); 4099285aaeSCédric Le Goater uint64_t val = 0xffffffff; 4199285aaeSCédric Le Goater 4299285aaeSCédric Le Goater switch (addr & 0xffc) { 4399285aaeSCédric Le Goater case ICP_XIRR_POLL: 4499285aaeSCédric Le Goater val = icp_ipoll(icp, NULL); 4599285aaeSCédric Le Goater if (byte0) { 4699285aaeSCédric Le Goater val >>= 24; 4799285aaeSCédric Le Goater } else if (width != 4) { 4899285aaeSCédric Le Goater goto bad_access; 4999285aaeSCédric Le Goater } 5099285aaeSCédric Le Goater break; 5199285aaeSCédric Le Goater case ICP_XIRR: 5299285aaeSCédric Le Goater if (byte0) { 5399285aaeSCédric Le Goater val = icp_ipoll(icp, NULL) >> 24; 5499285aaeSCédric Le Goater } else if (width == 4) { 5599285aaeSCédric Le Goater val = icp_accept(icp); 5699285aaeSCédric Le Goater } else { 5799285aaeSCédric Le Goater goto bad_access; 5899285aaeSCédric Le Goater } 5999285aaeSCédric Le Goater break; 6099285aaeSCédric Le Goater case ICP_MFRR: 6199285aaeSCédric Le Goater if (byte0) { 6299285aaeSCédric Le Goater val = icp->mfrr; 6399285aaeSCédric Le Goater } else { 6499285aaeSCédric Le Goater goto bad_access; 6599285aaeSCédric Le Goater } 6699285aaeSCédric Le Goater break; 6799285aaeSCédric Le Goater case ICP_LINKA: 6899285aaeSCédric Le Goater if (width == 4) { 6999285aaeSCédric Le Goater val = picp->links[0]; 7099285aaeSCédric Le Goater } else { 7199285aaeSCédric Le Goater goto bad_access; 7299285aaeSCédric Le Goater } 7399285aaeSCédric Le Goater break; 7499285aaeSCédric Le Goater case ICP_LINKB: 7599285aaeSCédric Le Goater if (width == 4) { 7699285aaeSCédric Le Goater val = picp->links[1]; 7799285aaeSCédric Le Goater } else { 7899285aaeSCédric Le Goater goto bad_access; 7999285aaeSCédric Le Goater } 8099285aaeSCédric Le Goater break; 8199285aaeSCédric Le Goater case ICP_LINKC: 8299285aaeSCédric Le Goater if (width == 4) { 8399285aaeSCédric Le Goater val = picp->links[2]; 8499285aaeSCédric Le Goater } else { 8599285aaeSCédric Le Goater goto bad_access; 8699285aaeSCédric Le Goater } 8799285aaeSCédric Le Goater break; 8899285aaeSCédric Le Goater default: 8999285aaeSCédric Le Goater bad_access: 9099285aaeSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "XICS: Bad ICP access 0x%" 9199285aaeSCédric Le Goater HWADDR_PRIx"/%d\n", addr, width); 9299285aaeSCédric Le Goater } 9399285aaeSCédric Le Goater 9499285aaeSCédric Le Goater return val; 9599285aaeSCédric Le Goater } 9699285aaeSCédric Le Goater 9799285aaeSCédric Le Goater static void pnv_icp_write(void *opaque, hwaddr addr, uint64_t val, 9899285aaeSCédric Le Goater unsigned width) 9999285aaeSCédric Le Goater { 10099285aaeSCédric Le Goater ICPState *icp = ICP(opaque); 10199285aaeSCédric Le Goater PnvICPState *picp = PNV_ICP(opaque); 10299285aaeSCédric Le Goater bool byte0 = (width == 1 && (addr & 0x3) == 0); 10399285aaeSCédric Le Goater 10499285aaeSCédric Le Goater switch (addr & 0xffc) { 10599285aaeSCédric Le Goater case ICP_XIRR: 10699285aaeSCédric Le Goater if (byte0) { 10799285aaeSCédric Le Goater icp_set_cppr(icp, val); 10899285aaeSCédric Le Goater } else if (width == 4) { 10999285aaeSCédric Le Goater icp_eoi(icp, val); 11099285aaeSCédric Le Goater } else { 11199285aaeSCédric Le Goater goto bad_access; 11299285aaeSCédric Le Goater } 11399285aaeSCédric Le Goater break; 11499285aaeSCédric Le Goater case ICP_MFRR: 11599285aaeSCédric Le Goater if (byte0) { 11699285aaeSCédric Le Goater icp_set_mfrr(icp, val); 11799285aaeSCédric Le Goater } else { 11899285aaeSCédric Le Goater goto bad_access; 11999285aaeSCédric Le Goater } 12099285aaeSCédric Le Goater break; 12199285aaeSCédric Le Goater case ICP_LINKA: 12299285aaeSCédric Le Goater if (width == 4) { 12399285aaeSCédric Le Goater picp->links[0] = val; 12499285aaeSCédric Le Goater } else { 12599285aaeSCédric Le Goater goto bad_access; 12699285aaeSCédric Le Goater } 12799285aaeSCédric Le Goater break; 12899285aaeSCédric Le Goater case ICP_LINKB: 12999285aaeSCédric Le Goater if (width == 4) { 13099285aaeSCédric Le Goater picp->links[1] = val; 13199285aaeSCédric Le Goater } else { 13299285aaeSCédric Le Goater goto bad_access; 13399285aaeSCédric Le Goater } 13499285aaeSCédric Le Goater break; 13599285aaeSCédric Le Goater case ICP_LINKC: 13699285aaeSCédric Le Goater if (width == 4) { 13799285aaeSCédric Le Goater picp->links[2] = val; 13899285aaeSCédric Le Goater } else { 13999285aaeSCédric Le Goater goto bad_access; 14099285aaeSCédric Le Goater } 14199285aaeSCédric Le Goater break; 14299285aaeSCédric Le Goater default: 14399285aaeSCédric Le Goater bad_access: 14499285aaeSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "XICS: Bad ICP access 0x%" 14599285aaeSCédric Le Goater HWADDR_PRIx"/%d\n", addr, width); 14699285aaeSCédric Le Goater } 14799285aaeSCédric Le Goater } 14899285aaeSCédric Le Goater 14999285aaeSCédric Le Goater static const MemoryRegionOps pnv_icp_ops = { 15099285aaeSCédric Le Goater .read = pnv_icp_read, 15199285aaeSCédric Le Goater .write = pnv_icp_write, 15299285aaeSCédric Le Goater .endianness = DEVICE_BIG_ENDIAN, 15399285aaeSCédric Le Goater .valid = { 15499285aaeSCédric Le Goater .min_access_size = 1, 15599285aaeSCédric Le Goater .max_access_size = 4, 15699285aaeSCédric Le Goater }, 15799285aaeSCédric Le Goater .impl = { 15899285aaeSCédric Le Goater .min_access_size = 1, 15999285aaeSCédric Le Goater .max_access_size = 4, 16099285aaeSCédric Le Goater }, 16199285aaeSCédric Le Goater }; 16299285aaeSCédric Le Goater 163a028dd42SCédric Le Goater static void pnv_icp_realize(DeviceState *dev, Error **errp) 16499285aaeSCédric Le Goater { 165a028dd42SCédric Le Goater ICPState *icp = ICP(dev); 166100f7388SGreg Kurz PnvICPState *pnv_icp = PNV_ICP(icp); 167a028dd42SCédric Le Goater ICPStateClass *icpc = ICP_GET_CLASS(icp); 168a028dd42SCédric Le Goater Error *local_err = NULL; 169a028dd42SCédric Le Goater 170a028dd42SCédric Le Goater icpc->parent_realize(dev, &local_err); 171a028dd42SCédric Le Goater if (local_err) { 172a028dd42SCédric Le Goater error_propagate(errp, local_err); 173a028dd42SCédric Le Goater return; 174a028dd42SCédric Le Goater } 17599285aaeSCédric Le Goater 176100f7388SGreg Kurz memory_region_init_io(&pnv_icp->mmio, OBJECT(icp), &pnv_icp_ops, 17799285aaeSCédric Le Goater icp, "icp-thread", 0x1000); 17899285aaeSCédric Le Goater } 17999285aaeSCédric Le Goater 18099285aaeSCédric Le Goater static void pnv_icp_class_init(ObjectClass *klass, void *data) 18199285aaeSCédric Le Goater { 18299285aaeSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 18399285aaeSCédric Le Goater ICPStateClass *icpc = ICP_CLASS(klass); 18499285aaeSCédric Le Goater 185a028dd42SCédric Le Goater device_class_set_parent_realize(dc, pnv_icp_realize, 186a028dd42SCédric Le Goater &icpc->parent_realize); 18799285aaeSCédric Le Goater dc->desc = "PowerNV ICP"; 18899285aaeSCédric Le Goater } 18999285aaeSCédric Le Goater 19099285aaeSCédric Le Goater static const TypeInfo pnv_icp_info = { 19199285aaeSCédric Le Goater .name = TYPE_PNV_ICP, 19299285aaeSCédric Le Goater .parent = TYPE_ICP, 19399285aaeSCédric Le Goater .instance_size = sizeof(PnvICPState), 19499285aaeSCédric Le Goater .class_init = pnv_icp_class_init, 19599285aaeSCédric Le Goater .class_size = sizeof(ICPStateClass), 19699285aaeSCédric Le Goater }; 19799285aaeSCédric Le Goater 19899285aaeSCédric Le Goater static void pnv_icp_register_types(void) 19999285aaeSCédric Le Goater { 20099285aaeSCédric Le Goater type_register_static(&pnv_icp_info); 20199285aaeSCédric Le Goater } 20299285aaeSCédric Le Goater 20399285aaeSCédric Le Goater type_init(pnv_icp_register_types) 204