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