|
|
1.1 root 1: /*
2: * QEMU Sparc SLAVIO interrupt controller emulation
1.1.1.4 root 3: *
1.1 root 4: * Copyright (c) 2003-2005 Fabrice Bellard
1.1.1.4 root 5: *
1.1 root 6: * Permission is hereby granted, free of charge, to any person obtaining a copy
7: * of this software and associated documentation files (the "Software"), to deal
8: * in the Software without restriction, including without limitation the rights
9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10: * copies of the Software, and to permit persons to whom the Software is
11: * furnished to do so, subject to the following conditions:
12: *
13: * The above copyright notice and this permission notice shall be included in
14: * all copies or substantial portions of the Software.
15: *
16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22: * THE SOFTWARE.
23: */
1.1.1.6 root 24:
1.1.1.4 root 25: #include "sun4m.h"
1.1.1.6 root 26: #include "monitor.h"
27: #include "sysbus.h"
1.1.1.4 root 28:
1.1 root 29: //#define DEBUG_IRQ_COUNT
30: //#define DEBUG_IRQ
31:
32: #ifdef DEBUG_IRQ
1.1.1.6 root 33: #define DPRINTF(fmt, ...) \
34: do { printf("IRQ: " fmt , ## __VA_ARGS__); } while (0)
1.1 root 35: #else
1.1.1.6 root 36: #define DPRINTF(fmt, ...)
1.1 root 37: #endif
38:
39: /*
40: * Registers of interrupt controller in sun4m.
41: *
42: * This is the interrupt controller part of chip STP2001 (Slave I/O), also
43: * produced as NCR89C105. See
44: * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
45: *
46: * There is a system master controller and one for each cpu.
1.1.1.4 root 47: *
1.1 root 48: */
49:
50: #define MAX_CPUS 16
1.1.1.4 root 51: #define MAX_PILS 16
1.1 root 52:
1.1.1.6 root 53: struct SLAVIO_INTCTLState;
54:
55: typedef struct SLAVIO_CPUINTCTLState {
56: uint32_t intreg_pending;
57: struct SLAVIO_INTCTLState *master;
58: uint32_t cpu;
1.1.1.7 ! root 59: uint32_t irl_out;
1.1.1.6 root 60: } SLAVIO_CPUINTCTLState;
1.1.1.5 root 61:
1.1 root 62: typedef struct SLAVIO_INTCTLState {
1.1.1.6 root 63: SysBusDevice busdev;
1.1 root 64: uint32_t intregm_pending;
65: uint32_t intregm_disabled;
66: uint32_t target_cpu;
67: #ifdef DEBUG_IRQ_COUNT
68: uint64_t irq_count[32];
69: #endif
1.1.1.6 root 70: qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
71: SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
1.1 root 72: } SLAVIO_INTCTLState;
73:
74: #define INTCTL_MAXADDR 0xf
1.1.1.4 root 75: #define INTCTL_SIZE (INTCTL_MAXADDR + 1)
1.1.1.5 root 76: #define INTCTLM_SIZE 0x14
1.1.1.4 root 77: #define MASTER_IRQ_MASK ~0x0fa2007f
78: #define MASTER_DISABLE 0x80000000
79: #define CPU_SOFTIRQ_MASK 0xfffe0000
1.1.1.7 ! root 80: #define CPU_IRQ_INT15_IN (1 << 15)
! 81: #define CPU_IRQ_TIMER_IN (1 << 14)
1.1.1.4 root 82:
1.1.1.6 root 83: static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
1.1 root 84:
85: // per-cpu interrupt controller
86: static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
87: {
1.1.1.5 root 88: SLAVIO_CPUINTCTLState *s = opaque;
1.1.1.4 root 89: uint32_t saddr, ret;
1.1 root 90:
1.1.1.5 root 91: saddr = addr >> 2;
1.1 root 92: switch (saddr) {
93: case 0:
1.1.1.5 root 94: ret = s->intreg_pending;
1.1.1.4 root 95: break;
1.1 root 96: default:
1.1.1.4 root 97: ret = 0;
98: break;
1.1 root 99: }
1.1.1.5 root 100: DPRINTF("read cpu %d reg 0x" TARGET_FMT_plx " = %x\n", s->cpu, addr, ret);
1.1.1.4 root 101:
102: return ret;
1.1 root 103: }
104:
1.1.1.5 root 105: static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr,
106: uint32_t val)
1.1 root 107: {
1.1.1.5 root 108: SLAVIO_CPUINTCTLState *s = opaque;
1.1 root 109: uint32_t saddr;
110:
1.1.1.5 root 111: saddr = addr >> 2;
112: DPRINTF("write cpu %d reg 0x" TARGET_FMT_plx " = %x\n", s->cpu, addr, val);
1.1 root 113: switch (saddr) {
114: case 1: // clear pending softints
1.1.1.7 ! root 115: val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
1.1.1.5 root 116: s->intreg_pending &= ~val;
1.1.1.6 root 117: slavio_check_interrupts(s->master, 1);
1.1.1.5 root 118: DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", s->cpu, val,
119: s->intreg_pending);
1.1.1.4 root 120: break;
1.1 root 121: case 2: // set softint
1.1.1.4 root 122: val &= CPU_SOFTIRQ_MASK;
1.1.1.5 root 123: s->intreg_pending |= val;
1.1.1.6 root 124: slavio_check_interrupts(s->master, 1);
1.1.1.5 root 125: DPRINTF("Set cpu %d irq mask %x, curmask %x\n", s->cpu, val,
126: s->intreg_pending);
1.1.1.4 root 127: break;
1.1 root 128: default:
1.1.1.4 root 129: break;
1.1 root 130: }
131: }
132:
1.1.1.7 ! root 133: static CPUReadMemoryFunc * const slavio_intctl_mem_read[3] = {
1.1.1.4 root 134: NULL,
135: NULL,
1.1 root 136: slavio_intctl_mem_readl,
137: };
138:
1.1.1.7 ! root 139: static CPUWriteMemoryFunc * const slavio_intctl_mem_write[3] = {
1.1.1.4 root 140: NULL,
141: NULL,
1.1 root 142: slavio_intctl_mem_writel,
143: };
144:
145: // master system interrupt controller
146: static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
147: {
148: SLAVIO_INTCTLState *s = opaque;
1.1.1.4 root 149: uint32_t saddr, ret;
1.1 root 150:
1.1.1.5 root 151: saddr = addr >> 2;
1.1 root 152: switch (saddr) {
153: case 0:
1.1.1.4 root 154: ret = s->intregm_pending & ~MASTER_DISABLE;
155: break;
1.1 root 156: case 1:
1.1.1.4 root 157: ret = s->intregm_disabled & MASTER_IRQ_MASK;
158: break;
1.1 root 159: case 4:
1.1.1.4 root 160: ret = s->target_cpu;
161: break;
1.1 root 162: default:
1.1.1.4 root 163: ret = 0;
164: break;
1.1 root 165: }
1.1.1.4 root 166: DPRINTF("read system reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
167:
168: return ret;
1.1 root 169: }
170:
1.1.1.5 root 171: static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr,
172: uint32_t val)
1.1 root 173: {
174: SLAVIO_INTCTLState *s = opaque;
175: uint32_t saddr;
176:
1.1.1.5 root 177: saddr = addr >> 2;
1.1.1.4 root 178: DPRINTF("write system reg 0x" TARGET_FMT_plx " = %x\n", addr, val);
1.1 root 179: switch (saddr) {
180: case 2: // clear (enable)
1.1.1.4 root 181: // Force clear unused bits
182: val &= MASTER_IRQ_MASK;
183: s->intregm_disabled &= ~val;
1.1.1.5 root 184: DPRINTF("Enabled master irq mask %x, curmask %x\n", val,
185: s->intregm_disabled);
1.1.1.6 root 186: slavio_check_interrupts(s, 1);
1.1.1.4 root 187: break;
1.1 root 188: case 3: // set (disable, clear pending)
1.1.1.4 root 189: // Force clear unused bits
190: val &= MASTER_IRQ_MASK;
191: s->intregm_disabled |= val;
192: s->intregm_pending &= ~val;
1.1.1.6 root 193: slavio_check_interrupts(s, 1);
1.1.1.5 root 194: DPRINTF("Disabled master irq mask %x, curmask %x\n", val,
195: s->intregm_disabled);
1.1.1.4 root 196: break;
1.1 root 197: case 4:
1.1.1.4 root 198: s->target_cpu = val & (MAX_CPUS - 1);
1.1.1.6 root 199: slavio_check_interrupts(s, 1);
1.1.1.4 root 200: DPRINTF("Set master irq cpu %d\n", s->target_cpu);
201: break;
1.1 root 202: default:
1.1.1.4 root 203: break;
1.1 root 204: }
205: }
206:
1.1.1.7 ! root 207: static CPUReadMemoryFunc * const slavio_intctlm_mem_read[3] = {
1.1.1.4 root 208: NULL,
209: NULL,
1.1 root 210: slavio_intctlm_mem_readl,
211: };
212:
1.1.1.7 ! root 213: static CPUWriteMemoryFunc * const slavio_intctlm_mem_write[3] = {
1.1.1.4 root 214: NULL,
215: NULL,
1.1 root 216: slavio_intctlm_mem_writel,
217: };
218:
1.1.1.7 ! root 219: void slavio_pic_info(Monitor *mon, DeviceState *dev)
1.1 root 220: {
1.1.1.7 ! root 221: SysBusDevice *sd;
! 222: SLAVIO_INTCTLState *s;
1.1 root 223: int i;
224:
1.1.1.7 ! root 225: sd = sysbus_from_qdev(dev);
! 226: s = FROM_SYSBUS(SLAVIO_INTCTLState, sd);
1.1 root 227: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.6 root 228: monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
229: s->slaves[i].intreg_pending);
1.1 root 230: }
1.1.1.6 root 231: monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
232: s->intregm_pending, s->intregm_disabled);
1.1 root 233: }
234:
1.1.1.7 ! root 235: void slavio_irq_info(Monitor *mon, DeviceState *dev)
1.1 root 236: {
237: #ifndef DEBUG_IRQ_COUNT
1.1.1.6 root 238: monitor_printf(mon, "irq statistic code not compiled.\n");
1.1 root 239: #else
1.1.1.7 ! root 240: SysBusDevice *sd;
! 241: SLAVIO_INTCTLState *s;
1.1 root 242: int i;
243: int64_t count;
244:
1.1.1.7 ! root 245: sd = sysbus_from_qdev(dev);
! 246: s = FROM_SYSBUS(SLAVIO_INTCTLState, sd);
1.1.1.6 root 247: monitor_printf(mon, "IRQ statistics:\n");
1.1 root 248: for (i = 0; i < 32; i++) {
249: count = s->irq_count[i];
250: if (count > 0)
1.1.1.6 root 251: monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
1.1 root 252: }
253: #endif
254: }
255:
1.1.1.7 ! root 256: static const uint32_t intbit_to_level[] = {
! 257: 2, 3, 5, 7, 9, 11, 13, 2, 3, 5, 7, 9, 11, 13, 12, 12,
! 258: 6, 13, 4, 10, 8, 9, 11, 0, 0, 0, 0, 15, 15, 15, 15, 0,
! 259: };
! 260:
1.1.1.6 root 261: static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
1.1 root 262: {
1.1.1.4 root 263: uint32_t pending = s->intregm_pending, pil_pending;
264: unsigned int i, j;
1.1 root 265:
266: pending &= ~s->intregm_disabled;
267:
1.1.1.4 root 268: DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled);
1.1.1.2 root 269: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.4 root 270: pil_pending = 0;
1.1.1.7 ! root 271:
! 272: /* If we are the current interrupt target, get hard interrupts */
1.1.1.4 root 273: if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
274: (i == s->target_cpu)) {
275: for (j = 0; j < 32; j++) {
1.1.1.7 ! root 276: if ((pending & (1 << j)) && intbit_to_level[j]) {
! 277: pil_pending |= 1 << intbit_to_level[j];
! 278: }
1.1.1.2 root 279: }
280: }
1.1.1.7 ! root 281:
! 282: /* Calculate current pending hard interrupts for display */
! 283: s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
! 284: CPU_IRQ_TIMER_IN;
! 285: if (i == s->target_cpu) {
! 286: for (j = 0; j < 32; j++) {
! 287: if ((s->intregm_pending & (1 << j)) && intbit_to_level[j]) {
! 288: s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
! 289: }
! 290: }
! 291: }
! 292:
! 293: /* Level 15 and CPU timer interrupts are not maskable */
! 294: pil_pending |= s->slaves[i].intreg_pending &
! 295: (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
! 296:
! 297: /* Add soft interrupts */
1.1.1.6 root 298: pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
1.1.1.4 root 299:
1.1.1.6 root 300: if (set_irqs) {
1.1.1.7 ! root 301: for (j = MAX_PILS; j > 0; j--) {
1.1.1.6 root 302: if (pil_pending & (1 << j)) {
1.1.1.7 ! root 303: if (!(s->slaves[i].irl_out & (1 << j))) {
1.1.1.6 root 304: qemu_irq_raise(s->cpu_irqs[i][j]);
305: }
306: } else {
1.1.1.7 ! root 307: if (s->slaves[i].irl_out & (1 << j)) {
1.1.1.6 root 308: qemu_irq_lower(s->cpu_irqs[i][j]);
309: }
310: }
1.1.1.2 root 311: }
312: }
1.1.1.7 ! root 313: s->slaves[i].irl_out = pil_pending;
1.1.1.2 root 314: }
1.1 root 315: }
316:
317: /*
318: * "irq" here is the bit number in the system interrupt register to
319: * separate serial and keyboard interrupts sharing a level.
320: */
1.1.1.4 root 321: static void slavio_set_irq(void *opaque, int irq, int level)
1.1 root 322: {
323: SLAVIO_INTCTLState *s = opaque;
1.1.1.4 root 324: uint32_t mask = 1 << irq;
1.1.1.7 ! root 325: uint32_t pil = intbit_to_level[irq];
! 326: unsigned int i;
1.1 root 327:
1.1.1.4 root 328: DPRINTF("Set cpu %d irq %d -> pil %d level %d\n", s->target_cpu, irq, pil,
329: level);
330: if (pil > 0) {
331: if (level) {
332: #ifdef DEBUG_IRQ_COUNT
333: s->irq_count[pil]++;
334: #endif
335: s->intregm_pending |= mask;
1.1.1.7 ! root 336: if (pil == 15) {
! 337: for (i = 0; i < MAX_CPUS; i++) {
! 338: s->slaves[i].intreg_pending |= 1 << pil;
! 339: }
! 340: }
1.1.1.4 root 341: } else {
342: s->intregm_pending &= ~mask;
1.1.1.7 ! root 343: if (pil == 15) {
! 344: for (i = 0; i < MAX_CPUS; i++) {
! 345: s->slaves[i].intreg_pending &= ~(1 << pil);
! 346: }
! 347: }
1.1.1.4 root 348: }
1.1.1.6 root 349: slavio_check_interrupts(s, 1);
1.1 root 350: }
351: }
352:
1.1.1.4 root 353: static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
1.1.1.2 root 354: {
355: SLAVIO_INTCTLState *s = opaque;
356:
1.1.1.4 root 357: DPRINTF("Set cpu %d local timer level %d\n", cpu, level);
358:
359: if (level) {
1.1.1.7 ! root 360: s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
1.1.1.4 root 361: } else {
1.1.1.7 ! root 362: s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
1.1.1.2 root 363: }
1.1.1.4 root 364:
1.1.1.6 root 365: slavio_check_interrupts(s, 1);
366: }
367:
368: static void slavio_set_irq_all(void *opaque, int irq, int level)
369: {
370: if (irq < 32) {
371: slavio_set_irq(opaque, irq, level);
372: } else {
373: slavio_set_timer_irq_cpu(opaque, irq - 32, level);
374: }
1.1.1.2 root 375: }
376:
1.1.1.7 ! root 377: static int vmstate_intctl_post_load(void *opaque, int version_id)
1.1 root 378: {
379: SLAVIO_INTCTLState *s = opaque;
1.1.1.4 root 380:
1.1.1.7 ! root 381: slavio_check_interrupts(s, 0);
! 382: return 0;
1.1 root 383: }
384:
1.1.1.7 ! root 385: static const VMStateDescription vmstate_intctl_cpu = {
! 386: .name ="slavio_intctl_cpu",
! 387: .version_id = 1,
! 388: .minimum_version_id = 1,
! 389: .minimum_version_id_old = 1,
! 390: .fields = (VMStateField []) {
! 391: VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
! 392: VMSTATE_END_OF_LIST()
! 393: }
! 394: };
1.1 root 395:
1.1.1.7 ! root 396: static const VMStateDescription vmstate_intctl = {
! 397: .name ="slavio_intctl",
! 398: .version_id = 1,
! 399: .minimum_version_id = 1,
! 400: .minimum_version_id_old = 1,
! 401: .post_load = vmstate_intctl_post_load,
! 402: .fields = (VMStateField []) {
! 403: VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
! 404: vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
! 405: VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
! 406: VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
! 407: VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
! 408: VMSTATE_END_OF_LIST()
1.1 root 409: }
1.1.1.7 ! root 410: };
1.1 root 411:
1.1.1.7 ! root 412: static void slavio_intctl_reset(DeviceState *d)
1.1 root 413: {
1.1.1.7 ! root 414: SLAVIO_INTCTLState *s = container_of(d, SLAVIO_INTCTLState, busdev.qdev);
1.1 root 415: int i;
416:
417: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.6 root 418: s->slaves[i].intreg_pending = 0;
1.1.1.7 ! root 419: s->slaves[i].irl_out = 0;
1.1 root 420: }
1.1.1.4 root 421: s->intregm_disabled = ~MASTER_IRQ_MASK;
1.1 root 422: s->intregm_pending = 0;
423: s->target_cpu = 0;
1.1.1.6 root 424: slavio_check_interrupts(s, 0);
1.1 root 425: }
426:
1.1.1.7 ! root 427: static int slavio_intctl_init1(SysBusDevice *dev)
1.1 root 428: {
1.1.1.6 root 429: SLAVIO_INTCTLState *s = FROM_SYSBUS(SLAVIO_INTCTLState, dev);
430: int io_memory;
431: unsigned int i, j;
1.1 root 432:
1.1.1.6 root 433: qdev_init_gpio_in(&dev->qdev, slavio_set_irq_all, 32 + MAX_CPUS);
434: io_memory = cpu_register_io_memory(slavio_intctlm_mem_read,
435: slavio_intctlm_mem_write, s);
436: sysbus_init_mmio(dev, INTCTLM_SIZE, io_memory);
1.1 root 437:
438: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.6 root 439: for (j = 0; j < MAX_PILS; j++) {
440: sysbus_init_irq(dev, &s->cpu_irqs[i][j]);
441: }
442: io_memory = cpu_register_io_memory(slavio_intctl_mem_read,
443: slavio_intctl_mem_write,
444: &s->slaves[i]);
445: sysbus_init_mmio(dev, INTCTL_SIZE, io_memory);
446: s->slaves[i].cpu = i;
447: s->slaves[i].master = s;
448: }
449:
1.1.1.7 ! root 450: return 0;
1.1.1.6 root 451: }
1.1 root 452:
1.1.1.6 root 453: static SysBusDeviceInfo slavio_intctl_info = {
454: .init = slavio_intctl_init1,
455: .qdev.name = "slavio_intctl",
456: .qdev.size = sizeof(SLAVIO_INTCTLState),
1.1.1.7 ! root 457: .qdev.vmsd = &vmstate_intctl,
! 458: .qdev.reset = slavio_intctl_reset,
1.1.1.6 root 459: };
1.1.1.4 root 460:
1.1.1.6 root 461: static void slavio_intctl_register_devices(void)
462: {
463: sysbus_register_withprop(&slavio_intctl_info);
1.1 root 464: }
1.1.1.6 root 465:
466: device_init(slavio_intctl_register_devices)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.