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