1*99285aaeSCédric Le Goater /* 2*99285aaeSCédric Le Goater * QEMU PowerPC PowerNV Interrupt Control Presenter (ICP) model 3*99285aaeSCédric Le Goater * 4*99285aaeSCédric Le Goater * Copyright (c) 2017, IBM Corporation. 5*99285aaeSCédric Le Goater * 6*99285aaeSCédric Le Goater * This library is free software; you can redistribute it and/or 7*99285aaeSCédric Le Goater * modify it under the terms of the GNU Lesser General Public License 8*99285aaeSCédric Le Goater * as published by the Free Software Foundation; either version 2 of 9*99285aaeSCédric Le Goater * the License, or (at your option) any later version. 10*99285aaeSCédric Le Goater * 11*99285aaeSCédric Le Goater * This library is distributed in the hope that it will be useful, but 12*99285aaeSCédric Le Goater * WITHOUT ANY WARRANTY; without even the implied warranty of 13*99285aaeSCédric Le Goater * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14*99285aaeSCédric Le Goater * Lesser General Public License for more details. 15*99285aaeSCédric Le Goater * 16*99285aaeSCédric Le Goater * You should have received a copy of the GNU Lesser General Public 17*99285aaeSCédric Le Goater * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18*99285aaeSCédric Le Goater */ 19*99285aaeSCédric Le Goater 20*99285aaeSCédric Le Goater #include "qemu/osdep.h" 21*99285aaeSCédric Le Goater #include "sysemu/sysemu.h" 22*99285aaeSCédric Le Goater #include "qapi/error.h" 23*99285aaeSCédric Le Goater #include "qemu/log.h" 24*99285aaeSCédric Le Goater #include "hw/ppc/xics.h" 25*99285aaeSCédric Le Goater 26*99285aaeSCédric Le Goater #define ICP_XIRR_POLL 0 /* 1 byte (CPRR) or 4 bytes */ 27*99285aaeSCédric Le Goater #define ICP_XIRR 4 /* 1 byte (CPRR) or 4 bytes */ 28*99285aaeSCédric Le Goater #define ICP_MFRR 12 /* 1 byte access only */ 29*99285aaeSCédric Le Goater 30*99285aaeSCédric Le Goater #define ICP_LINKA 16 /* unused */ 31*99285aaeSCédric Le Goater #define ICP_LINKB 20 /* unused */ 32*99285aaeSCédric Le Goater #define ICP_LINKC 24 /* unused */ 33*99285aaeSCédric Le Goater 34*99285aaeSCédric Le Goater static uint64_t pnv_icp_read(void *opaque, hwaddr addr, unsigned width) 35*99285aaeSCédric Le Goater { 36*99285aaeSCédric Le Goater ICPState *icp = ICP(opaque); 37*99285aaeSCédric Le Goater PnvICPState *picp = PNV_ICP(opaque); 38*99285aaeSCédric Le Goater bool byte0 = (width == 1 && (addr & 0x3) == 0); 39*99285aaeSCédric Le Goater uint64_t val = 0xffffffff; 40*99285aaeSCédric Le Goater 41*99285aaeSCédric Le Goater switch (addr & 0xffc) { 42*99285aaeSCédric Le Goater case ICP_XIRR_POLL: 43*99285aaeSCédric Le Goater val = icp_ipoll(icp, NULL); 44*99285aaeSCédric Le Goater if (byte0) { 45*99285aaeSCédric Le Goater val >>= 24; 46*99285aaeSCédric Le Goater } else if (width != 4) { 47*99285aaeSCédric Le Goater goto bad_access; 48*99285aaeSCédric Le Goater } 49*99285aaeSCédric Le Goater break; 50*99285aaeSCédric Le Goater case ICP_XIRR: 51*99285aaeSCédric Le Goater if (byte0) { 52*99285aaeSCédric Le Goater val = icp_ipoll(icp, NULL) >> 24; 53*99285aaeSCédric Le Goater } else if (width == 4) { 54*99285aaeSCédric Le Goater val = icp_accept(icp); 55*99285aaeSCédric Le Goater } else { 56*99285aaeSCédric Le Goater goto bad_access; 57*99285aaeSCédric Le Goater } 58*99285aaeSCédric Le Goater break; 59*99285aaeSCédric Le Goater case ICP_MFRR: 60*99285aaeSCédric Le Goater if (byte0) { 61*99285aaeSCédric Le Goater val = icp->mfrr; 62*99285aaeSCédric Le Goater } else { 63*99285aaeSCédric Le Goater goto bad_access; 64*99285aaeSCédric Le Goater } 65*99285aaeSCédric Le Goater break; 66*99285aaeSCédric Le Goater case ICP_LINKA: 67*99285aaeSCédric Le Goater if (width == 4) { 68*99285aaeSCédric Le Goater val = picp->links[0]; 69*99285aaeSCédric Le Goater } else { 70*99285aaeSCédric Le Goater goto bad_access; 71*99285aaeSCédric Le Goater } 72*99285aaeSCédric Le Goater break; 73*99285aaeSCédric Le Goater case ICP_LINKB: 74*99285aaeSCédric Le Goater if (width == 4) { 75*99285aaeSCédric Le Goater val = picp->links[1]; 76*99285aaeSCédric Le Goater } else { 77*99285aaeSCédric Le Goater goto bad_access; 78*99285aaeSCédric Le Goater } 79*99285aaeSCédric Le Goater break; 80*99285aaeSCédric Le Goater case ICP_LINKC: 81*99285aaeSCédric Le Goater if (width == 4) { 82*99285aaeSCédric Le Goater val = picp->links[2]; 83*99285aaeSCédric Le Goater } else { 84*99285aaeSCédric Le Goater goto bad_access; 85*99285aaeSCédric Le Goater } 86*99285aaeSCédric Le Goater break; 87*99285aaeSCédric Le Goater default: 88*99285aaeSCédric Le Goater bad_access: 89*99285aaeSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "XICS: Bad ICP access 0x%" 90*99285aaeSCédric Le Goater HWADDR_PRIx"/%d\n", addr, width); 91*99285aaeSCédric Le Goater } 92*99285aaeSCédric Le Goater 93*99285aaeSCédric Le Goater return val; 94*99285aaeSCédric Le Goater } 95*99285aaeSCédric Le Goater 96*99285aaeSCédric Le Goater static void pnv_icp_write(void *opaque, hwaddr addr, uint64_t val, 97*99285aaeSCédric Le Goater unsigned width) 98*99285aaeSCédric Le Goater { 99*99285aaeSCédric Le Goater ICPState *icp = ICP(opaque); 100*99285aaeSCédric Le Goater PnvICPState *picp = PNV_ICP(opaque); 101*99285aaeSCédric Le Goater bool byte0 = (width == 1 && (addr & 0x3) == 0); 102*99285aaeSCédric Le Goater 103*99285aaeSCédric Le Goater switch (addr & 0xffc) { 104*99285aaeSCédric Le Goater case ICP_XIRR: 105*99285aaeSCédric Le Goater if (byte0) { 106*99285aaeSCédric Le Goater icp_set_cppr(icp, val); 107*99285aaeSCédric Le Goater } else if (width == 4) { 108*99285aaeSCédric Le Goater icp_eoi(icp, val); 109*99285aaeSCédric Le Goater } else { 110*99285aaeSCédric Le Goater goto bad_access; 111*99285aaeSCédric Le Goater } 112*99285aaeSCédric Le Goater break; 113*99285aaeSCédric Le Goater case ICP_MFRR: 114*99285aaeSCédric Le Goater if (byte0) { 115*99285aaeSCédric Le Goater icp_set_mfrr(icp, val); 116*99285aaeSCédric Le Goater } else { 117*99285aaeSCédric Le Goater goto bad_access; 118*99285aaeSCédric Le Goater } 119*99285aaeSCédric Le Goater break; 120*99285aaeSCédric Le Goater case ICP_LINKA: 121*99285aaeSCédric Le Goater if (width == 4) { 122*99285aaeSCédric Le Goater picp->links[0] = val; 123*99285aaeSCédric Le Goater } else { 124*99285aaeSCédric Le Goater goto bad_access; 125*99285aaeSCédric Le Goater } 126*99285aaeSCédric Le Goater break; 127*99285aaeSCédric Le Goater case ICP_LINKB: 128*99285aaeSCédric Le Goater if (width == 4) { 129*99285aaeSCédric Le Goater picp->links[1] = val; 130*99285aaeSCédric Le Goater } else { 131*99285aaeSCédric Le Goater goto bad_access; 132*99285aaeSCédric Le Goater } 133*99285aaeSCédric Le Goater break; 134*99285aaeSCédric Le Goater case ICP_LINKC: 135*99285aaeSCédric Le Goater if (width == 4) { 136*99285aaeSCédric Le Goater picp->links[2] = val; 137*99285aaeSCédric Le Goater } else { 138*99285aaeSCédric Le Goater goto bad_access; 139*99285aaeSCédric Le Goater } 140*99285aaeSCédric Le Goater break; 141*99285aaeSCédric Le Goater default: 142*99285aaeSCédric Le Goater bad_access: 143*99285aaeSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "XICS: Bad ICP access 0x%" 144*99285aaeSCédric Le Goater HWADDR_PRIx"/%d\n", addr, width); 145*99285aaeSCédric Le Goater } 146*99285aaeSCédric Le Goater } 147*99285aaeSCédric Le Goater 148*99285aaeSCédric Le Goater static const MemoryRegionOps pnv_icp_ops = { 149*99285aaeSCédric Le Goater .read = pnv_icp_read, 150*99285aaeSCédric Le Goater .write = pnv_icp_write, 151*99285aaeSCédric Le Goater .endianness = DEVICE_BIG_ENDIAN, 152*99285aaeSCédric Le Goater .valid = { 153*99285aaeSCédric Le Goater .min_access_size = 1, 154*99285aaeSCédric Le Goater .max_access_size = 4, 155*99285aaeSCédric Le Goater }, 156*99285aaeSCédric Le Goater .impl = { 157*99285aaeSCédric Le Goater .min_access_size = 1, 158*99285aaeSCédric Le Goater .max_access_size = 4, 159*99285aaeSCédric Le Goater }, 160*99285aaeSCédric Le Goater }; 161*99285aaeSCédric Le Goater 162*99285aaeSCédric Le Goater static void pnv_icp_realize(DeviceState *dev, Error **errp) 163*99285aaeSCédric Le Goater { 164*99285aaeSCédric Le Goater PnvICPState *icp = PNV_ICP(dev); 165*99285aaeSCédric Le Goater 166*99285aaeSCédric Le Goater memory_region_init_io(&icp->mmio, OBJECT(dev), &pnv_icp_ops, 167*99285aaeSCédric Le Goater icp, "icp-thread", 0x1000); 168*99285aaeSCédric Le Goater } 169*99285aaeSCédric Le Goater 170*99285aaeSCédric Le Goater static void pnv_icp_class_init(ObjectClass *klass, void *data) 171*99285aaeSCédric Le Goater { 172*99285aaeSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 173*99285aaeSCédric Le Goater ICPStateClass *icpc = ICP_CLASS(klass); 174*99285aaeSCédric Le Goater 175*99285aaeSCédric Le Goater icpc->realize = pnv_icp_realize; 176*99285aaeSCédric Le Goater dc->desc = "PowerNV ICP"; 177*99285aaeSCédric Le Goater } 178*99285aaeSCédric Le Goater 179*99285aaeSCédric Le Goater static const TypeInfo pnv_icp_info = { 180*99285aaeSCédric Le Goater .name = TYPE_PNV_ICP, 181*99285aaeSCédric Le Goater .parent = TYPE_ICP, 182*99285aaeSCédric Le Goater .instance_size = sizeof(PnvICPState), 183*99285aaeSCédric Le Goater .class_init = pnv_icp_class_init, 184*99285aaeSCédric Le Goater .class_size = sizeof(ICPStateClass), 185*99285aaeSCédric Le Goater }; 186*99285aaeSCédric Le Goater 187*99285aaeSCédric Le Goater static void pnv_icp_register_types(void) 188*99285aaeSCédric Le Goater { 189*99285aaeSCédric Le Goater type_register_static(&pnv_icp_info); 190*99285aaeSCédric Le Goater } 191*99285aaeSCédric Le Goater 192*99285aaeSCédric Le Goater type_init(pnv_icp_register_types) 193