|
|
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.1.8 ! root 188: case 3: // set (disable; doesn't affect pending)
1.1.1.4 root 189: // Force clear unused bits
190: val &= MASTER_IRQ_MASK;
191: s->intregm_disabled |= val;
1.1.1.6 root 192: slavio_check_interrupts(s, 1);
1.1.1.5 root 193: DPRINTF("Disabled master irq mask %x, curmask %x\n", val,
194: s->intregm_disabled);
1.1.1.4 root 195: break;
1.1 root 196: case 4:
1.1.1.4 root 197: s->target_cpu = val & (MAX_CPUS - 1);
1.1.1.6 root 198: slavio_check_interrupts(s, 1);
1.1.1.4 root 199: DPRINTF("Set master irq cpu %d\n", s->target_cpu);
200: break;
1.1 root 201: default:
1.1.1.4 root 202: break;
1.1 root 203: }
204: }
205:
1.1.1.7 root 206: static CPUReadMemoryFunc * const slavio_intctlm_mem_read[3] = {
1.1.1.4 root 207: NULL,
208: NULL,
1.1 root 209: slavio_intctlm_mem_readl,
210: };
211:
1.1.1.7 root 212: static CPUWriteMemoryFunc * const slavio_intctlm_mem_write[3] = {
1.1.1.4 root 213: NULL,
214: NULL,
1.1 root 215: slavio_intctlm_mem_writel,
216: };
217:
1.1.1.7 root 218: void slavio_pic_info(Monitor *mon, DeviceState *dev)
1.1 root 219: {
1.1.1.7 root 220: SysBusDevice *sd;
221: SLAVIO_INTCTLState *s;
1.1 root 222: int i;
223:
1.1.1.7 root 224: sd = sysbus_from_qdev(dev);
225: s = FROM_SYSBUS(SLAVIO_INTCTLState, sd);
1.1 root 226: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.6 root 227: monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
228: s->slaves[i].intreg_pending);
1.1 root 229: }
1.1.1.6 root 230: monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
231: s->intregm_pending, s->intregm_disabled);
1.1 root 232: }
233:
1.1.1.7 root 234: void slavio_irq_info(Monitor *mon, DeviceState *dev)
1.1 root 235: {
236: #ifndef DEBUG_IRQ_COUNT
1.1.1.6 root 237: monitor_printf(mon, "irq statistic code not compiled.\n");
1.1 root 238: #else
1.1.1.7 root 239: SysBusDevice *sd;
240: SLAVIO_INTCTLState *s;
1.1 root 241: int i;
242: int64_t count;
243:
1.1.1.7 root 244: sd = sysbus_from_qdev(dev);
245: s = FROM_SYSBUS(SLAVIO_INTCTLState, sd);
1.1.1.6 root 246: monitor_printf(mon, "IRQ statistics:\n");
1.1 root 247: for (i = 0; i < 32; i++) {
248: count = s->irq_count[i];
249: if (count > 0)
1.1.1.6 root 250: monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
1.1 root 251: }
252: #endif
253: }
254:
1.1.1.7 root 255: static const uint32_t intbit_to_level[] = {
256: 2, 3, 5, 7, 9, 11, 13, 2, 3, 5, 7, 9, 11, 13, 12, 12,
257: 6, 13, 4, 10, 8, 9, 11, 0, 0, 0, 0, 15, 15, 15, 15, 0,
258: };
259:
1.1.1.6 root 260: static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
1.1 root 261: {
1.1.1.4 root 262: uint32_t pending = s->intregm_pending, pil_pending;
263: unsigned int i, j;
1.1 root 264:
265: pending &= ~s->intregm_disabled;
266:
1.1.1.4 root 267: DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled);
1.1.1.2 root 268: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.4 root 269: pil_pending = 0;
1.1.1.7 root 270:
271: /* If we are the current interrupt target, get hard interrupts */
1.1.1.4 root 272: if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
273: (i == s->target_cpu)) {
274: for (j = 0; j < 32; j++) {
1.1.1.7 root 275: if ((pending & (1 << j)) && intbit_to_level[j]) {
276: pil_pending |= 1 << intbit_to_level[j];
277: }
1.1.1.2 root 278: }
279: }
1.1.1.7 root 280:
281: /* Calculate current pending hard interrupts for display */
282: s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
283: CPU_IRQ_TIMER_IN;
284: if (i == s->target_cpu) {
285: for (j = 0; j < 32; j++) {
286: if ((s->intregm_pending & (1 << j)) && intbit_to_level[j]) {
287: s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
288: }
289: }
290: }
291:
1.1.1.8 ! root 292: /* Level 15 and CPU timer interrupts are only masked when
! 293: the MASTER_DISABLE bit is set */
! 294: if (!(s->intregm_disabled & MASTER_DISABLE)) {
! 295: pil_pending |= s->slaves[i].intreg_pending &
! 296: (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
! 297: }
1.1.1.7 root 298:
299: /* Add soft interrupts */
1.1.1.6 root 300: pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
1.1.1.4 root 301:
1.1.1.6 root 302: if (set_irqs) {
1.1.1.7 root 303: for (j = MAX_PILS; j > 0; j--) {
1.1.1.6 root 304: if (pil_pending & (1 << j)) {
1.1.1.7 root 305: if (!(s->slaves[i].irl_out & (1 << j))) {
1.1.1.6 root 306: qemu_irq_raise(s->cpu_irqs[i][j]);
307: }
308: } else {
1.1.1.7 root 309: if (s->slaves[i].irl_out & (1 << j)) {
1.1.1.6 root 310: qemu_irq_lower(s->cpu_irqs[i][j]);
311: }
312: }
1.1.1.2 root 313: }
314: }
1.1.1.7 root 315: s->slaves[i].irl_out = pil_pending;
1.1.1.2 root 316: }
1.1 root 317: }
318:
319: /*
320: * "irq" here is the bit number in the system interrupt register to
321: * separate serial and keyboard interrupts sharing a level.
322: */
1.1.1.4 root 323: static void slavio_set_irq(void *opaque, int irq, int level)
1.1 root 324: {
325: SLAVIO_INTCTLState *s = opaque;
1.1.1.4 root 326: uint32_t mask = 1 << irq;
1.1.1.7 root 327: uint32_t pil = intbit_to_level[irq];
328: unsigned int i;
1.1 root 329:
1.1.1.4 root 330: DPRINTF("Set cpu %d irq %d -> pil %d level %d\n", s->target_cpu, irq, pil,
331: level);
332: if (pil > 0) {
333: if (level) {
334: #ifdef DEBUG_IRQ_COUNT
335: s->irq_count[pil]++;
336: #endif
337: s->intregm_pending |= mask;
1.1.1.7 root 338: if (pil == 15) {
339: for (i = 0; i < MAX_CPUS; i++) {
340: s->slaves[i].intreg_pending |= 1 << pil;
341: }
342: }
1.1.1.4 root 343: } else {
344: s->intregm_pending &= ~mask;
1.1.1.7 root 345: if (pil == 15) {
346: for (i = 0; i < MAX_CPUS; i++) {
347: s->slaves[i].intreg_pending &= ~(1 << pil);
348: }
349: }
1.1.1.4 root 350: }
1.1.1.6 root 351: slavio_check_interrupts(s, 1);
1.1 root 352: }
353: }
354:
1.1.1.4 root 355: static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
1.1.1.2 root 356: {
357: SLAVIO_INTCTLState *s = opaque;
358:
1.1.1.4 root 359: DPRINTF("Set cpu %d local timer level %d\n", cpu, level);
360:
361: if (level) {
1.1.1.7 root 362: s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
1.1.1.4 root 363: } else {
1.1.1.7 root 364: s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
1.1.1.2 root 365: }
1.1.1.4 root 366:
1.1.1.6 root 367: slavio_check_interrupts(s, 1);
368: }
369:
370: static void slavio_set_irq_all(void *opaque, int irq, int level)
371: {
372: if (irq < 32) {
373: slavio_set_irq(opaque, irq, level);
374: } else {
375: slavio_set_timer_irq_cpu(opaque, irq - 32, level);
376: }
1.1.1.2 root 377: }
378:
1.1.1.7 root 379: static int vmstate_intctl_post_load(void *opaque, int version_id)
1.1 root 380: {
381: SLAVIO_INTCTLState *s = opaque;
1.1.1.4 root 382:
1.1.1.7 root 383: slavio_check_interrupts(s, 0);
384: return 0;
1.1 root 385: }
386:
1.1.1.7 root 387: static const VMStateDescription vmstate_intctl_cpu = {
388: .name ="slavio_intctl_cpu",
389: .version_id = 1,
390: .minimum_version_id = 1,
391: .minimum_version_id_old = 1,
392: .fields = (VMStateField []) {
393: VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
394: VMSTATE_END_OF_LIST()
395: }
396: };
1.1 root 397:
1.1.1.7 root 398: static const VMStateDescription vmstate_intctl = {
399: .name ="slavio_intctl",
400: .version_id = 1,
401: .minimum_version_id = 1,
402: .minimum_version_id_old = 1,
403: .post_load = vmstate_intctl_post_load,
404: .fields = (VMStateField []) {
405: VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
406: vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
407: VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
408: VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
409: VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
410: VMSTATE_END_OF_LIST()
1.1 root 411: }
1.1.1.7 root 412: };
1.1 root 413:
1.1.1.7 root 414: static void slavio_intctl_reset(DeviceState *d)
1.1 root 415: {
1.1.1.7 root 416: SLAVIO_INTCTLState *s = container_of(d, SLAVIO_INTCTLState, busdev.qdev);
1.1 root 417: int i;
418:
419: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.6 root 420: s->slaves[i].intreg_pending = 0;
1.1.1.7 root 421: s->slaves[i].irl_out = 0;
1.1 root 422: }
1.1.1.4 root 423: s->intregm_disabled = ~MASTER_IRQ_MASK;
1.1 root 424: s->intregm_pending = 0;
425: s->target_cpu = 0;
1.1.1.6 root 426: slavio_check_interrupts(s, 0);
1.1 root 427: }
428:
1.1.1.7 root 429: static int slavio_intctl_init1(SysBusDevice *dev)
1.1 root 430: {
1.1.1.6 root 431: SLAVIO_INTCTLState *s = FROM_SYSBUS(SLAVIO_INTCTLState, dev);
432: int io_memory;
433: unsigned int i, j;
1.1 root 434:
1.1.1.6 root 435: qdev_init_gpio_in(&dev->qdev, slavio_set_irq_all, 32 + MAX_CPUS);
436: io_memory = cpu_register_io_memory(slavio_intctlm_mem_read,
437: slavio_intctlm_mem_write, s);
438: sysbus_init_mmio(dev, INTCTLM_SIZE, io_memory);
1.1 root 439:
440: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.6 root 441: for (j = 0; j < MAX_PILS; j++) {
442: sysbus_init_irq(dev, &s->cpu_irqs[i][j]);
443: }
444: io_memory = cpu_register_io_memory(slavio_intctl_mem_read,
445: slavio_intctl_mem_write,
446: &s->slaves[i]);
447: sysbus_init_mmio(dev, INTCTL_SIZE, io_memory);
448: s->slaves[i].cpu = i;
449: s->slaves[i].master = s;
450: }
451:
1.1.1.7 root 452: return 0;
1.1.1.6 root 453: }
1.1 root 454:
1.1.1.6 root 455: static SysBusDeviceInfo slavio_intctl_info = {
456: .init = slavio_intctl_init1,
457: .qdev.name = "slavio_intctl",
458: .qdev.size = sizeof(SLAVIO_INTCTLState),
1.1.1.7 root 459: .qdev.vmsd = &vmstate_intctl,
460: .qdev.reset = slavio_intctl_reset,
1.1.1.6 root 461: };
1.1.1.4 root 462:
1.1.1.6 root 463: static void slavio_intctl_register_devices(void)
464: {
465: sysbus_register_withprop(&slavio_intctl_info);
1.1 root 466: }
1.1.1.6 root 467:
468: 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.