|
|
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;
! 59: } SLAVIO_CPUINTCTLState;
1.1.1.5 root 60:
1.1 root 61: typedef struct SLAVIO_INTCTLState {
1.1.1.6 ! root 62: SysBusDevice busdev;
1.1 root 63: uint32_t intregm_pending;
64: uint32_t intregm_disabled;
65: uint32_t target_cpu;
66: #ifdef DEBUG_IRQ_COUNT
67: uint64_t irq_count[32];
68: #endif
1.1.1.6 ! root 69: qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
1.1.1.4 root 70: const uint32_t *intbit_to_level;
71: uint32_t cputimer_lbit, cputimer_mbit;
1.1.1.6 ! root 72: uint32_t cputimer_bit;
1.1.1.4 root 73: uint32_t pil_out[MAX_CPUS];
1.1.1.6 ! root 74: SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
1.1 root 75: } SLAVIO_INTCTLState;
76:
77: #define INTCTL_MAXADDR 0xf
1.1.1.4 root 78: #define INTCTL_SIZE (INTCTL_MAXADDR + 1)
1.1.1.5 root 79: #define INTCTLM_SIZE 0x14
1.1.1.4 root 80: #define MASTER_IRQ_MASK ~0x0fa2007f
81: #define MASTER_DISABLE 0x80000000
82: #define CPU_SOFTIRQ_MASK 0xfffe0000
83: #define CPU_IRQ_INT15_IN 0x0004000
84: #define CPU_IRQ_INT15_MASK 0x80000000
85:
1.1.1.6 ! root 86: static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
1.1 root 87:
88: // per-cpu interrupt controller
89: static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
90: {
1.1.1.5 root 91: SLAVIO_CPUINTCTLState *s = opaque;
1.1.1.4 root 92: uint32_t saddr, ret;
1.1 root 93:
1.1.1.5 root 94: saddr = addr >> 2;
1.1 root 95: switch (saddr) {
96: case 0:
1.1.1.5 root 97: ret = s->intreg_pending;
1.1.1.4 root 98: break;
1.1 root 99: default:
1.1.1.4 root 100: ret = 0;
101: break;
1.1 root 102: }
1.1.1.5 root 103: DPRINTF("read cpu %d reg 0x" TARGET_FMT_plx " = %x\n", s->cpu, addr, ret);
1.1.1.4 root 104:
105: return ret;
1.1 root 106: }
107:
1.1.1.5 root 108: static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr,
109: uint32_t val)
1.1 root 110: {
1.1.1.5 root 111: SLAVIO_CPUINTCTLState *s = opaque;
1.1 root 112: uint32_t saddr;
113:
1.1.1.5 root 114: saddr = addr >> 2;
115: DPRINTF("write cpu %d reg 0x" TARGET_FMT_plx " = %x\n", s->cpu, addr, val);
1.1 root 116: switch (saddr) {
117: case 1: // clear pending softints
1.1.1.4 root 118: if (val & CPU_IRQ_INT15_IN)
119: val |= CPU_IRQ_INT15_MASK;
120: val &= CPU_SOFTIRQ_MASK;
1.1.1.5 root 121: s->intreg_pending &= ~val;
1.1.1.6 ! root 122: slavio_check_interrupts(s->master, 1);
1.1.1.5 root 123: DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", s->cpu, val,
124: s->intreg_pending);
1.1.1.4 root 125: break;
1.1 root 126: case 2: // set softint
1.1.1.4 root 127: val &= CPU_SOFTIRQ_MASK;
1.1.1.5 root 128: s->intreg_pending |= val;
1.1.1.6 ! root 129: slavio_check_interrupts(s->master, 1);
1.1.1.5 root 130: DPRINTF("Set cpu %d irq mask %x, curmask %x\n", s->cpu, val,
131: s->intreg_pending);
1.1.1.4 root 132: break;
1.1 root 133: default:
1.1.1.4 root 134: break;
1.1 root 135: }
136: }
137:
138: static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = {
1.1.1.4 root 139: NULL,
140: NULL,
1.1 root 141: slavio_intctl_mem_readl,
142: };
143:
144: static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = {
1.1.1.4 root 145: NULL,
146: NULL,
1.1 root 147: slavio_intctl_mem_writel,
148: };
149:
150: // master system interrupt controller
151: static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
152: {
153: SLAVIO_INTCTLState *s = opaque;
1.1.1.4 root 154: uint32_t saddr, ret;
1.1 root 155:
1.1.1.5 root 156: saddr = addr >> 2;
1.1 root 157: switch (saddr) {
158: case 0:
1.1.1.4 root 159: ret = s->intregm_pending & ~MASTER_DISABLE;
160: break;
1.1 root 161: case 1:
1.1.1.4 root 162: ret = s->intregm_disabled & MASTER_IRQ_MASK;
163: break;
1.1 root 164: case 4:
1.1.1.4 root 165: ret = s->target_cpu;
166: break;
1.1 root 167: default:
1.1.1.4 root 168: ret = 0;
169: break;
1.1 root 170: }
1.1.1.4 root 171: DPRINTF("read system reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
172:
173: return ret;
1.1 root 174: }
175:
1.1.1.5 root 176: static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr,
177: uint32_t val)
1.1 root 178: {
179: SLAVIO_INTCTLState *s = opaque;
180: uint32_t saddr;
181:
1.1.1.5 root 182: saddr = addr >> 2;
1.1.1.4 root 183: DPRINTF("write system reg 0x" TARGET_FMT_plx " = %x\n", addr, val);
1.1 root 184: switch (saddr) {
185: case 2: // clear (enable)
1.1.1.4 root 186: // Force clear unused bits
187: val &= MASTER_IRQ_MASK;
188: s->intregm_disabled &= ~val;
1.1.1.5 root 189: DPRINTF("Enabled master irq mask %x, curmask %x\n", val,
190: s->intregm_disabled);
1.1.1.6 ! root 191: slavio_check_interrupts(s, 1);
1.1.1.4 root 192: break;
1.1 root 193: case 3: // set (disable, clear pending)
1.1.1.4 root 194: // Force clear unused bits
195: val &= MASTER_IRQ_MASK;
196: s->intregm_disabled |= val;
197: s->intregm_pending &= ~val;
1.1.1.6 ! root 198: slavio_check_interrupts(s, 1);
1.1.1.5 root 199: DPRINTF("Disabled master irq mask %x, curmask %x\n", val,
200: s->intregm_disabled);
1.1.1.4 root 201: break;
1.1 root 202: case 4:
1.1.1.4 root 203: s->target_cpu = val & (MAX_CPUS - 1);
1.1.1.6 ! root 204: slavio_check_interrupts(s, 1);
1.1.1.4 root 205: DPRINTF("Set master irq cpu %d\n", s->target_cpu);
206: break;
1.1 root 207: default:
1.1.1.4 root 208: break;
1.1 root 209: }
210: }
211:
212: static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = {
1.1.1.4 root 213: NULL,
214: NULL,
1.1 root 215: slavio_intctlm_mem_readl,
216: };
217:
218: static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = {
1.1.1.4 root 219: NULL,
220: NULL,
1.1 root 221: slavio_intctlm_mem_writel,
222: };
223:
1.1.1.6 ! root 224: void slavio_pic_info(Monitor *mon, void *opaque)
1.1 root 225: {
226: SLAVIO_INTCTLState *s = opaque;
227: int i;
228:
229: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.6 ! root 230: monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
! 231: s->slaves[i].intreg_pending);
1.1 root 232: }
1.1.1.6 ! root 233: monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
! 234: s->intregm_pending, s->intregm_disabled);
1.1 root 235: }
236:
1.1.1.6 ! root 237: void slavio_irq_info(Monitor *mon, void *opaque)
1.1 root 238: {
239: #ifndef DEBUG_IRQ_COUNT
1.1.1.6 ! root 240: monitor_printf(mon, "irq statistic code not compiled.\n");
1.1 root 241: #else
242: SLAVIO_INTCTLState *s = opaque;
243: int i;
244: int64_t count;
245:
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.6 ! root 255: static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
1.1 root 256: {
1.1.1.4 root 257: uint32_t pending = s->intregm_pending, pil_pending;
258: unsigned int i, j;
1.1 root 259:
260: pending &= ~s->intregm_disabled;
261:
1.1.1.4 root 262: DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled);
1.1.1.2 root 263: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.4 root 264: pil_pending = 0;
265: if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
266: (i == s->target_cpu)) {
267: for (j = 0; j < 32; j++) {
268: if (pending & (1 << j))
269: pil_pending |= 1 << s->intbit_to_level[j];
1.1.1.2 root 270: }
271: }
1.1.1.6 ! root 272: pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
1.1.1.4 root 273:
1.1.1.6 ! root 274: if (set_irqs) {
! 275: for (j = 0; j < MAX_PILS; j++) {
! 276: if (pil_pending & (1 << j)) {
! 277: if (!(s->pil_out[i] & (1 << j))) {
! 278: qemu_irq_raise(s->cpu_irqs[i][j]);
! 279: }
! 280: } else {
! 281: if (s->pil_out[i] & (1 << j)) {
! 282: qemu_irq_lower(s->cpu_irqs[i][j]);
! 283: }
! 284: }
1.1.1.2 root 285: }
286: }
1.1.1.4 root 287: s->pil_out[i] = pil_pending;
1.1.1.2 root 288: }
1.1 root 289: }
290:
291: /*
292: * "irq" here is the bit number in the system interrupt register to
293: * separate serial and keyboard interrupts sharing a level.
294: */
1.1.1.4 root 295: static void slavio_set_irq(void *opaque, int irq, int level)
1.1 root 296: {
297: SLAVIO_INTCTLState *s = opaque;
1.1.1.4 root 298: uint32_t mask = 1 << irq;
299: uint32_t pil = s->intbit_to_level[irq];
1.1 root 300:
1.1.1.4 root 301: DPRINTF("Set cpu %d irq %d -> pil %d level %d\n", s->target_cpu, irq, pil,
302: level);
303: if (pil > 0) {
304: if (level) {
305: #ifdef DEBUG_IRQ_COUNT
306: s->irq_count[pil]++;
307: #endif
308: s->intregm_pending |= mask;
1.1.1.6 ! root 309: s->slaves[s->target_cpu].intreg_pending |= 1 << pil;
1.1.1.4 root 310: } else {
311: s->intregm_pending &= ~mask;
1.1.1.6 ! root 312: s->slaves[s->target_cpu].intreg_pending &= ~(1 << pil);
1.1.1.4 root 313: }
1.1.1.6 ! root 314: slavio_check_interrupts(s, 1);
1.1 root 315: }
316: }
317:
1.1.1.4 root 318: static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
1.1.1.2 root 319: {
320: SLAVIO_INTCTLState *s = opaque;
321:
1.1.1.4 root 322: DPRINTF("Set cpu %d local timer level %d\n", cpu, level);
323:
324: if (level) {
325: s->intregm_pending |= s->cputimer_mbit;
1.1.1.6 ! root 326: s->slaves[cpu].intreg_pending |= s->cputimer_lbit;
1.1.1.4 root 327: } else {
328: s->intregm_pending &= ~s->cputimer_mbit;
1.1.1.6 ! root 329: s->slaves[cpu].intreg_pending &= ~s->cputimer_lbit;
1.1.1.2 root 330: }
1.1.1.4 root 331:
1.1.1.6 ! root 332: slavio_check_interrupts(s, 1);
! 333: }
! 334:
! 335: static void slavio_set_irq_all(void *opaque, int irq, int level)
! 336: {
! 337: if (irq < 32) {
! 338: slavio_set_irq(opaque, irq, level);
! 339: } else {
! 340: slavio_set_timer_irq_cpu(opaque, irq - 32, level);
! 341: }
1.1.1.2 root 342: }
343:
1.1 root 344: static void slavio_intctl_save(QEMUFile *f, void *opaque)
345: {
346: SLAVIO_INTCTLState *s = opaque;
347: int i;
1.1.1.4 root 348:
1.1 root 349: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.6 ! root 350: qemu_put_be32s(f, &s->slaves[i].intreg_pending);
1.1 root 351: }
352: qemu_put_be32s(f, &s->intregm_pending);
353: qemu_put_be32s(f, &s->intregm_disabled);
354: qemu_put_be32s(f, &s->target_cpu);
355: }
356:
357: static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id)
358: {
359: SLAVIO_INTCTLState *s = opaque;
360: int i;
361:
362: if (version_id != 1)
363: return -EINVAL;
364:
365: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.6 ! root 366: qemu_get_be32s(f, &s->slaves[i].intreg_pending);
1.1 root 367: }
368: qemu_get_be32s(f, &s->intregm_pending);
369: qemu_get_be32s(f, &s->intregm_disabled);
370: qemu_get_be32s(f, &s->target_cpu);
1.1.1.6 ! root 371: slavio_check_interrupts(s, 0);
1.1 root 372: return 0;
373: }
374:
375: static void slavio_intctl_reset(void *opaque)
376: {
377: SLAVIO_INTCTLState *s = opaque;
378: int i;
379:
380: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.6 ! root 381: s->slaves[i].intreg_pending = 0;
1.1 root 382: }
1.1.1.4 root 383: s->intregm_disabled = ~MASTER_IRQ_MASK;
1.1 root 384: s->intregm_pending = 0;
385: s->target_cpu = 0;
1.1.1.6 ! root 386: slavio_check_interrupts(s, 0);
1.1 root 387: }
388:
1.1.1.6 ! root 389: static void slavio_intctl_init1(SysBusDevice *dev)
1.1 root 390: {
1.1.1.6 ! root 391: SLAVIO_INTCTLState *s = FROM_SYSBUS(SLAVIO_INTCTLState, dev);
! 392: int io_memory;
! 393: unsigned int i, j;
1.1 root 394:
1.1.1.6 ! root 395: qdev_init_gpio_in(&dev->qdev, slavio_set_irq_all, 32 + MAX_CPUS);
! 396: io_memory = cpu_register_io_memory(slavio_intctlm_mem_read,
! 397: slavio_intctlm_mem_write, s);
! 398: sysbus_init_mmio(dev, INTCTLM_SIZE, io_memory);
! 399: s->cputimer_mbit = 1 << s->cputimer_bit;
! 400: s->cputimer_lbit = 1 << s->intbit_to_level[s->cputimer_bit];
1.1 root 401:
402: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.6 ! root 403: for (j = 0; j < MAX_PILS; j++) {
! 404: sysbus_init_irq(dev, &s->cpu_irqs[i][j]);
! 405: }
! 406: io_memory = cpu_register_io_memory(slavio_intctl_mem_read,
! 407: slavio_intctl_mem_write,
! 408: &s->slaves[i]);
! 409: sysbus_init_mmio(dev, INTCTL_SIZE, io_memory);
! 410: s->slaves[i].cpu = i;
! 411: s->slaves[i].master = s;
! 412: }
! 413: register_savevm("slavio_intctl", -1, 1, slavio_intctl_save,
! 414: slavio_intctl_load, s);
! 415: qemu_register_reset(slavio_intctl_reset, s);
! 416: slavio_intctl_reset(s);
! 417: }
! 418:
! 419: DeviceState *slavio_intctl_init(target_phys_addr_t addr,
! 420: target_phys_addr_t addrg,
! 421: const uint32_t *intbit_to_level,
! 422: qemu_irq **parent_irq, unsigned int cputimer)
! 423: {
! 424: DeviceState *dev;
! 425: SysBusDevice *s;
! 426: unsigned int i, j;
1.1.1.5 root 427:
1.1.1.6 ! root 428: dev = qdev_create(NULL, "slavio_intctl");
! 429: qdev_prop_set_ptr(dev, "intbit_to_level", (void *)intbit_to_level);
! 430: qdev_prop_set_uint32(dev, "cputimer_bit", cputimer);
! 431: qdev_init(dev);
1.1.1.5 root 432:
1.1.1.6 ! root 433: s = sysbus_from_qdev(dev);
1.1.1.5 root 434:
1.1.1.6 ! root 435: for (i = 0; i < MAX_CPUS; i++) {
! 436: for (j = 0; j < MAX_PILS; j++) {
! 437: sysbus_connect_irq(s, i * MAX_PILS + j, parent_irq[i][j]);
! 438: }
! 439: }
! 440: sysbus_mmio_map(s, 0, addrg);
! 441: for (i = 0; i < MAX_CPUS; i++) {
! 442: sysbus_mmio_map(s, i + 1, addr + i * TARGET_PAGE_SIZE);
1.1 root 443: }
444:
1.1.1.6 ! root 445: return dev;
! 446: }
1.1 root 447:
1.1.1.6 ! root 448: static SysBusDeviceInfo slavio_intctl_info = {
! 449: .init = slavio_intctl_init1,
! 450: .qdev.name = "slavio_intctl",
! 451: .qdev.size = sizeof(SLAVIO_INTCTLState),
! 452: .qdev.props = (Property[]) {
! 453: {
! 454: .name = "intbit_to_level",
! 455: .info = &qdev_prop_ptr,
! 456: .offset = offsetof(SLAVIO_INTCTLState, intbit_to_level),
! 457: },
! 458: {
! 459: .name = "cputimer_bit",
! 460: .info = &qdev_prop_uint32,
! 461: .offset = offsetof(SLAVIO_INTCTLState, cputimer_bit),
! 462: },
! 463: {/* end of property list */}
! 464: }
! 465: };
1.1.1.4 root 466:
1.1.1.6 ! root 467: static void slavio_intctl_register_devices(void)
! 468: {
! 469: sysbus_register_withprop(&slavio_intctl_info);
1.1 root 470: }
1.1.1.6 ! root 471:
! 472: 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.