1 /* 2 * QEMU GRLIB IRQMP Emulator 3 * 4 * (Multiprocessor and extended interrupt not supported) 5 * 6 * Copyright (c) 2010-2019 AdaCore 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a copy 9 * of this software and associated documentation files (the "Software"), to deal 10 * in the Software without restriction, including without limitation the rights 11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 * copies of the Software, and to permit persons to whom the Software is 13 * furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included in 16 * all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 * THE SOFTWARE. 25 */ 26 27 #include "qemu/osdep.h" 28 #include "hw/sysbus.h" 29 #include "cpu.h" 30 31 #include "hw/qdev-properties.h" 32 #include "hw/sparc/grlib.h" 33 34 #include "trace.h" 35 #include "qapi/error.h" 36 #include "qemu/module.h" 37 38 #define IRQMP_MAX_CPU 16 39 #define IRQMP_REG_SIZE 256 /* Size of memory mapped registers */ 40 41 /* Memory mapped register offsets */ 42 #define LEVEL_OFFSET 0x00 43 #define PENDING_OFFSET 0x04 44 #define FORCE0_OFFSET 0x08 45 #define CLEAR_OFFSET 0x0C 46 #define MP_STATUS_OFFSET 0x10 47 #define BROADCAST_OFFSET 0x14 48 #define MASK_OFFSET 0x40 49 #define FORCE_OFFSET 0x80 50 #define EXTENDED_OFFSET 0xC0 51 52 #define GRLIB_IRQMP(obj) OBJECT_CHECK(IRQMP, (obj), TYPE_GRLIB_IRQMP) 53 54 typedef struct IRQMPState IRQMPState; 55 56 typedef struct IRQMP { 57 SysBusDevice parent_obj; 58 59 MemoryRegion iomem; 60 61 void *set_pil_in; 62 void *set_pil_in_opaque; 63 64 IRQMPState *state; 65 } IRQMP; 66 67 struct IRQMPState { 68 uint32_t level; 69 uint32_t pending; 70 uint32_t clear; 71 uint32_t broadcast; 72 73 uint32_t mask[IRQMP_MAX_CPU]; 74 uint32_t force[IRQMP_MAX_CPU]; 75 uint32_t extended[IRQMP_MAX_CPU]; 76 77 IRQMP *parent; 78 }; 79 80 static void grlib_irqmp_check_irqs(IRQMPState *state) 81 { 82 uint32_t pend = 0; 83 uint32_t level0 = 0; 84 uint32_t level1 = 0; 85 set_pil_in_fn set_pil_in; 86 87 assert(state != NULL); 88 assert(state->parent != NULL); 89 90 /* IRQ for CPU 0 (no SMP support) */ 91 pend = (state->pending | state->force[0]) 92 & state->mask[0]; 93 94 level0 = pend & ~state->level; 95 level1 = pend & state->level; 96 97 trace_grlib_irqmp_check_irqs(state->pending, state->force[0], 98 state->mask[0], level1, level0); 99 100 set_pil_in = (set_pil_in_fn)state->parent->set_pil_in; 101 102 /* Trigger level1 interrupt first and level0 if there is no level1 */ 103 if (level1 != 0) { 104 set_pil_in(state->parent->set_pil_in_opaque, level1); 105 } else { 106 set_pil_in(state->parent->set_pil_in_opaque, level0); 107 } 108 } 109 110 static void grlib_irqmp_ack_mask(IRQMPState *state, uint32_t mask) 111 { 112 /* Clear registers */ 113 state->pending &= ~mask; 114 state->force[0] &= ~mask; /* Only CPU 0 (No SMP support) */ 115 116 grlib_irqmp_check_irqs(state); 117 } 118 119 void grlib_irqmp_ack(DeviceState *dev, int intno) 120 { 121 IRQMP *irqmp = GRLIB_IRQMP(dev); 122 IRQMPState *state; 123 uint32_t mask; 124 125 state = irqmp->state; 126 assert(state != NULL); 127 128 intno &= 15; 129 mask = 1 << intno; 130 131 trace_grlib_irqmp_ack(intno); 132 133 grlib_irqmp_ack_mask(state, mask); 134 } 135 136 void grlib_irqmp_set_irq(void *opaque, int irq, int level) 137 { 138 IRQMP *irqmp = GRLIB_IRQMP(opaque); 139 IRQMPState *s; 140 int i = 0; 141 142 s = irqmp->state; 143 assert(s != NULL); 144 assert(s->parent != NULL); 145 146 147 if (level) { 148 trace_grlib_irqmp_set_irq(irq); 149 150 if (s->broadcast & 1 << irq) { 151 /* Broadcasted IRQ */ 152 for (i = 0; i < IRQMP_MAX_CPU; i++) { 153 s->force[i] |= 1 << irq; 154 } 155 } else { 156 s->pending |= 1 << irq; 157 } 158 grlib_irqmp_check_irqs(s); 159 160 } 161 } 162 163 static uint64_t grlib_irqmp_read(void *opaque, hwaddr addr, 164 unsigned size) 165 { 166 IRQMP *irqmp = opaque; 167 IRQMPState *state; 168 169 assert(irqmp != NULL); 170 state = irqmp->state; 171 assert(state != NULL); 172 173 addr &= 0xff; 174 175 /* global registers */ 176 switch (addr) { 177 case LEVEL_OFFSET: 178 return state->level; 179 180 case PENDING_OFFSET: 181 return state->pending; 182 183 case FORCE0_OFFSET: 184 /* This register is an "alias" for the force register of CPU 0 */ 185 return state->force[0]; 186 187 case CLEAR_OFFSET: 188 case MP_STATUS_OFFSET: 189 /* Always read as 0 */ 190 return 0; 191 192 case BROADCAST_OFFSET: 193 return state->broadcast; 194 195 default: 196 break; 197 } 198 199 /* mask registers */ 200 if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) { 201 int cpu = (addr - MASK_OFFSET) / 4; 202 assert(cpu >= 0 && cpu < IRQMP_MAX_CPU); 203 204 return state->mask[cpu]; 205 } 206 207 /* force registers */ 208 if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) { 209 int cpu = (addr - FORCE_OFFSET) / 4; 210 assert(cpu >= 0 && cpu < IRQMP_MAX_CPU); 211 212 return state->force[cpu]; 213 } 214 215 /* extended (not supported) */ 216 if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) { 217 int cpu = (addr - EXTENDED_OFFSET) / 4; 218 assert(cpu >= 0 && cpu < IRQMP_MAX_CPU); 219 220 return state->extended[cpu]; 221 } 222 223 trace_grlib_irqmp_readl_unknown(addr); 224 return 0; 225 } 226 227 static void grlib_irqmp_write(void *opaque, hwaddr addr, 228 uint64_t value, unsigned size) 229 { 230 IRQMP *irqmp = opaque; 231 IRQMPState *state; 232 233 assert(irqmp != NULL); 234 state = irqmp->state; 235 assert(state != NULL); 236 237 addr &= 0xff; 238 239 /* global registers */ 240 switch (addr) { 241 case LEVEL_OFFSET: 242 value &= 0xFFFF << 1; /* clean up the value */ 243 state->level = value; 244 return; 245 246 case PENDING_OFFSET: 247 /* Read Only */ 248 return; 249 250 case FORCE0_OFFSET: 251 /* This register is an "alias" for the force register of CPU 0 */ 252 253 value &= 0xFFFE; /* clean up the value */ 254 state->force[0] = value; 255 grlib_irqmp_check_irqs(irqmp->state); 256 return; 257 258 case CLEAR_OFFSET: 259 value &= ~1; /* clean up the value */ 260 grlib_irqmp_ack_mask(state, value); 261 return; 262 263 case MP_STATUS_OFFSET: 264 /* Read Only (no SMP support) */ 265 return; 266 267 case BROADCAST_OFFSET: 268 value &= 0xFFFE; /* clean up the value */ 269 state->broadcast = value; 270 return; 271 272 default: 273 break; 274 } 275 276 /* mask registers */ 277 if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) { 278 int cpu = (addr - MASK_OFFSET) / 4; 279 assert(cpu >= 0 && cpu < IRQMP_MAX_CPU); 280 281 value &= ~1; /* clean up the value */ 282 state->mask[cpu] = value; 283 grlib_irqmp_check_irqs(irqmp->state); 284 return; 285 } 286 287 /* force registers */ 288 if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) { 289 int cpu = (addr - FORCE_OFFSET) / 4; 290 assert(cpu >= 0 && cpu < IRQMP_MAX_CPU); 291 292 uint32_t force = value & 0xFFFE; 293 uint32_t clear = (value >> 16) & 0xFFFE; 294 uint32_t old = state->force[cpu]; 295 296 state->force[cpu] = (old | force) & ~clear; 297 grlib_irqmp_check_irqs(irqmp->state); 298 return; 299 } 300 301 /* extended (not supported) */ 302 if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) { 303 int cpu = (addr - EXTENDED_OFFSET) / 4; 304 assert(cpu >= 0 && cpu < IRQMP_MAX_CPU); 305 306 value &= 0xF; /* clean up the value */ 307 state->extended[cpu] = value; 308 return; 309 } 310 311 trace_grlib_irqmp_writel_unknown(addr, value); 312 } 313 314 static const MemoryRegionOps grlib_irqmp_ops = { 315 .read = grlib_irqmp_read, 316 .write = grlib_irqmp_write, 317 .endianness = DEVICE_NATIVE_ENDIAN, 318 .valid = { 319 .min_access_size = 4, 320 .max_access_size = 4, 321 }, 322 }; 323 324 static void grlib_irqmp_reset(DeviceState *d) 325 { 326 IRQMP *irqmp = GRLIB_IRQMP(d); 327 assert(irqmp->state != NULL); 328 329 memset(irqmp->state, 0, sizeof *irqmp->state); 330 irqmp->state->parent = irqmp; 331 } 332 333 static void grlib_irqmp_init(Object *obj) 334 { 335 IRQMP *irqmp = GRLIB_IRQMP(obj); 336 SysBusDevice *dev = SYS_BUS_DEVICE(obj); 337 338 memory_region_init_io(&irqmp->iomem, obj, &grlib_irqmp_ops, irqmp, 339 "irqmp", IRQMP_REG_SIZE); 340 341 irqmp->state = g_malloc0(sizeof *irqmp->state); 342 343 sysbus_init_mmio(dev, &irqmp->iomem); 344 } 345 346 static void grlib_irqmp_realize(DeviceState *dev, Error **errp) 347 { 348 IRQMP *irqmp = GRLIB_IRQMP(dev); 349 350 /* Check parameters */ 351 if (irqmp->set_pil_in == NULL) { 352 error_setg(errp, "set_pil_in cannot be NULL."); 353 } 354 } 355 356 static Property grlib_irqmp_properties[] = { 357 DEFINE_PROP_PTR("set_pil_in", IRQMP, set_pil_in), 358 DEFINE_PROP_PTR("set_pil_in_opaque", IRQMP, set_pil_in_opaque), 359 DEFINE_PROP_END_OF_LIST(), 360 }; 361 362 static void grlib_irqmp_class_init(ObjectClass *klass, void *data) 363 { 364 DeviceClass *dc = DEVICE_CLASS(klass); 365 366 dc->reset = grlib_irqmp_reset; 367 dc->props = grlib_irqmp_properties; 368 /* Reason: pointer properties "set_pil_in", "set_pil_in_opaque" */ 369 dc->user_creatable = false; 370 dc->realize = grlib_irqmp_realize; 371 } 372 373 static const TypeInfo grlib_irqmp_info = { 374 .name = TYPE_GRLIB_IRQMP, 375 .parent = TYPE_SYS_BUS_DEVICE, 376 .instance_size = sizeof(IRQMP), 377 .instance_init = grlib_irqmp_init, 378 .class_init = grlib_irqmp_class_init, 379 }; 380 381 static void grlib_irqmp_register_types(void) 382 { 383 type_register_static(&grlib_irqmp_info); 384 } 385 386 type_init(grlib_irqmp_register_types) 387