|
|
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.4 ! root 24: #include "hw.h"
! 25: #include "sun4m.h"
! 26: #include "console.h"
! 27:
1.1 root 28: //#define DEBUG_IRQ_COUNT
29: //#define DEBUG_IRQ
30:
31: #ifdef DEBUG_IRQ
32: #define DPRINTF(fmt, args...) \
33: do { printf("IRQ: " fmt , ##args); } while (0)
34: #else
35: #define DPRINTF(fmt, args...)
36: #endif
37:
38: /*
39: * Registers of interrupt controller in sun4m.
40: *
41: * This is the interrupt controller part of chip STP2001 (Slave I/O), also
42: * produced as NCR89C105. See
43: * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
44: *
45: * There is a system master controller and one for each cpu.
1.1.1.4 ! root 46: *
1.1 root 47: */
48:
49: #define MAX_CPUS 16
1.1.1.4 ! root 50: #define MAX_PILS 16
1.1 root 51:
52: typedef struct SLAVIO_INTCTLState {
53: uint32_t intreg_pending[MAX_CPUS];
54: uint32_t intregm_pending;
55: uint32_t intregm_disabled;
56: uint32_t target_cpu;
57: #ifdef DEBUG_IRQ_COUNT
58: uint64_t irq_count[32];
59: #endif
1.1.1.4 ! root 60: qemu_irq *cpu_irqs[MAX_CPUS];
! 61: const uint32_t *intbit_to_level;
! 62: uint32_t cputimer_lbit, cputimer_mbit;
! 63: uint32_t pil_out[MAX_CPUS];
1.1 root 64: } SLAVIO_INTCTLState;
65:
66: #define INTCTL_MAXADDR 0xf
1.1.1.4 ! root 67: #define INTCTL_SIZE (INTCTL_MAXADDR + 1)
! 68: #define INTCTLM_MAXADDR 0x13
! 69: #define INTCTLM_SIZE (INTCTLM_MAXADDR + 1)
! 70: #define INTCTLM_MASK 0x1f
! 71: #define MASTER_IRQ_MASK ~0x0fa2007f
! 72: #define MASTER_DISABLE 0x80000000
! 73: #define CPU_SOFTIRQ_MASK 0xfffe0000
! 74: #define CPU_HARDIRQ_MASK 0x0000fffe
! 75: #define CPU_IRQ_INT15_IN 0x0004000
! 76: #define CPU_IRQ_INT15_MASK 0x80000000
! 77:
1.1 root 78: static void slavio_check_interrupts(void *opaque);
79:
80: // per-cpu interrupt controller
81: static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
82: {
83: SLAVIO_INTCTLState *s = opaque;
1.1.1.4 ! root 84: uint32_t saddr, ret;
1.1 root 85: int cpu;
86:
87: cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
88: saddr = (addr & INTCTL_MAXADDR) >> 2;
89: switch (saddr) {
90: case 0:
1.1.1.4 ! root 91: ret = s->intreg_pending[cpu];
! 92: break;
1.1 root 93: default:
1.1.1.4 ! root 94: ret = 0;
! 95: break;
1.1 root 96: }
1.1.1.4 ! root 97: DPRINTF("read cpu %d reg 0x" TARGET_FMT_plx " = %x\n", cpu, addr, ret);
! 98:
! 99: return ret;
1.1 root 100: }
101:
102: static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
103: {
104: SLAVIO_INTCTLState *s = opaque;
105: uint32_t saddr;
106: int cpu;
107:
108: cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
109: saddr = (addr & INTCTL_MAXADDR) >> 2;
1.1.1.4 ! root 110: DPRINTF("write cpu %d reg 0x" TARGET_FMT_plx " = %x\n", cpu, addr, val);
1.1 root 111: switch (saddr) {
112: case 1: // clear pending softints
1.1.1.4 ! root 113: if (val & CPU_IRQ_INT15_IN)
! 114: val |= CPU_IRQ_INT15_MASK;
! 115: val &= CPU_SOFTIRQ_MASK;
! 116: s->intreg_pending[cpu] &= ~val;
! 117: slavio_check_interrupts(s);
! 118: DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
! 119: break;
1.1 root 120: case 2: // set softint
1.1.1.4 ! root 121: val &= CPU_SOFTIRQ_MASK;
! 122: s->intreg_pending[cpu] |= val;
1.1.1.2 root 123: slavio_check_interrupts(s);
1.1.1.4 ! root 124: DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
! 125: break;
1.1 root 126: default:
1.1.1.4 ! root 127: break;
1.1 root 128: }
129: }
130:
131: static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = {
1.1.1.4 ! root 132: NULL,
! 133: NULL,
1.1 root 134: slavio_intctl_mem_readl,
135: };
136:
137: static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = {
1.1.1.4 ! root 138: NULL,
! 139: NULL,
1.1 root 140: slavio_intctl_mem_writel,
141: };
142:
143: // master system interrupt controller
144: static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
145: {
146: SLAVIO_INTCTLState *s = opaque;
1.1.1.4 ! root 147: uint32_t saddr, ret;
1.1 root 148:
1.1.1.4 ! root 149: saddr = (addr & INTCTLM_MASK) >> 2;
1.1 root 150: switch (saddr) {
151: case 0:
1.1.1.4 ! root 152: ret = s->intregm_pending & ~MASTER_DISABLE;
! 153: break;
1.1 root 154: case 1:
1.1.1.4 ! root 155: ret = s->intregm_disabled & MASTER_IRQ_MASK;
! 156: break;
1.1 root 157: case 4:
1.1.1.4 ! root 158: ret = s->target_cpu;
! 159: break;
1.1 root 160: default:
1.1.1.4 ! root 161: ret = 0;
! 162: break;
1.1 root 163: }
1.1.1.4 ! root 164: DPRINTF("read system reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
! 165:
! 166: return ret;
1.1 root 167: }
168:
169: static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
170: {
171: SLAVIO_INTCTLState *s = opaque;
172: uint32_t saddr;
173:
1.1.1.4 ! root 174: saddr = (addr & INTCTLM_MASK) >> 2;
! 175: DPRINTF("write system reg 0x" TARGET_FMT_plx " = %x\n", addr, val);
1.1 root 176: switch (saddr) {
177: case 2: // clear (enable)
1.1.1.4 ! root 178: // Force clear unused bits
! 179: val &= MASTER_IRQ_MASK;
! 180: s->intregm_disabled &= ~val;
! 181: DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
! 182: slavio_check_interrupts(s);
! 183: break;
1.1 root 184: case 3: // set (disable, clear pending)
1.1.1.4 ! root 185: // Force clear unused bits
! 186: val &= MASTER_IRQ_MASK;
! 187: s->intregm_disabled |= val;
! 188: s->intregm_pending &= ~val;
! 189: slavio_check_interrupts(s);
! 190: DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
! 191: break;
1.1 root 192: case 4:
1.1.1.4 ! root 193: s->target_cpu = val & (MAX_CPUS - 1);
! 194: slavio_check_interrupts(s);
! 195: DPRINTF("Set master irq cpu %d\n", s->target_cpu);
! 196: break;
1.1 root 197: default:
1.1.1.4 ! root 198: break;
1.1 root 199: }
200: }
201:
202: static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = {
1.1.1.4 ! root 203: NULL,
! 204: NULL,
1.1 root 205: slavio_intctlm_mem_readl,
206: };
207:
208: static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = {
1.1.1.4 ! root 209: NULL,
! 210: NULL,
1.1 root 211: slavio_intctlm_mem_writel,
212: };
213:
214: void slavio_pic_info(void *opaque)
215: {
216: SLAVIO_INTCTLState *s = opaque;
217: int i;
218:
219: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.4 ! root 220: term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]);
1.1 root 221: }
222: term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled);
223: }
224:
225: void slavio_irq_info(void *opaque)
226: {
227: #ifndef DEBUG_IRQ_COUNT
228: term_printf("irq statistic code not compiled.\n");
229: #else
230: SLAVIO_INTCTLState *s = opaque;
231: int i;
232: int64_t count;
233:
234: term_printf("IRQ statistics:\n");
235: for (i = 0; i < 32; i++) {
236: count = s->irq_count[i];
237: if (count > 0)
1.1.1.3 root 238: term_printf("%2d: %" PRId64 "\n", i, count);
1.1 root 239: }
240: #endif
241: }
242:
243: static void slavio_check_interrupts(void *opaque)
244: {
245: SLAVIO_INTCTLState *s = opaque;
1.1.1.4 ! root 246: uint32_t pending = s->intregm_pending, pil_pending;
! 247: unsigned int i, j;
1.1 root 248:
249: pending &= ~s->intregm_disabled;
250:
1.1.1.4 ! root 251: DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled);
1.1.1.2 root 252: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.4 ! root 253: pil_pending = 0;
! 254: if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
! 255: (i == s->target_cpu)) {
! 256: for (j = 0; j < 32; j++) {
! 257: if (pending & (1 << j))
! 258: pil_pending |= 1 << s->intbit_to_level[j];
1.1.1.2 root 259: }
260: }
1.1.1.4 ! root 261: pil_pending |= (s->intreg_pending[i] & CPU_SOFTIRQ_MASK) >> 16;
! 262:
! 263: for (j = 0; j < MAX_PILS; j++) {
! 264: if (pil_pending & (1 << j)) {
! 265: if (!(s->pil_out[i] & (1 << j)))
! 266: qemu_irq_raise(s->cpu_irqs[i][j]);
! 267: } else {
! 268: if (s->pil_out[i] & (1 << j))
! 269: qemu_irq_lower(s->cpu_irqs[i][j]);
1.1.1.2 root 270: }
271: }
1.1.1.4 ! root 272: s->pil_out[i] = pil_pending;
1.1.1.2 root 273: }
1.1 root 274: }
275:
276: /*
277: * "irq" here is the bit number in the system interrupt register to
278: * separate serial and keyboard interrupts sharing a level.
279: */
1.1.1.4 ! root 280: static void slavio_set_irq(void *opaque, int irq, int level)
1.1 root 281: {
282: SLAVIO_INTCTLState *s = opaque;
1.1.1.4 ! root 283: uint32_t mask = 1 << irq;
! 284: uint32_t pil = s->intbit_to_level[irq];
1.1 root 285:
1.1.1.4 ! root 286: DPRINTF("Set cpu %d irq %d -> pil %d level %d\n", s->target_cpu, irq, pil,
! 287: level);
! 288: if (pil > 0) {
! 289: if (level) {
! 290: #ifdef DEBUG_IRQ_COUNT
! 291: s->irq_count[pil]++;
! 292: #endif
! 293: s->intregm_pending |= mask;
! 294: s->intreg_pending[s->target_cpu] |= 1 << pil;
! 295: } else {
! 296: s->intregm_pending &= ~mask;
! 297: s->intreg_pending[s->target_cpu] &= ~(1 << pil);
! 298: }
! 299: slavio_check_interrupts(s);
1.1 root 300: }
301: }
302:
1.1.1.4 ! root 303: static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
1.1.1.2 root 304: {
305: SLAVIO_INTCTLState *s = opaque;
306:
1.1.1.4 ! root 307: DPRINTF("Set cpu %d local timer level %d\n", cpu, level);
! 308:
! 309: if (level) {
! 310: s->intregm_pending |= s->cputimer_mbit;
! 311: s->intreg_pending[cpu] |= s->cputimer_lbit;
! 312: } else {
! 313: s->intregm_pending &= ~s->cputimer_mbit;
! 314: s->intreg_pending[cpu] &= ~s->cputimer_lbit;
1.1.1.2 root 315: }
1.1.1.4 ! root 316:
1.1.1.2 root 317: slavio_check_interrupts(s);
318: }
319:
1.1 root 320: static void slavio_intctl_save(QEMUFile *f, void *opaque)
321: {
322: SLAVIO_INTCTLState *s = opaque;
323: int i;
1.1.1.4 ! root 324:
1.1 root 325: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.4 ! root 326: qemu_put_be32s(f, &s->intreg_pending[i]);
1.1 root 327: }
328: qemu_put_be32s(f, &s->intregm_pending);
329: qemu_put_be32s(f, &s->intregm_disabled);
330: qemu_put_be32s(f, &s->target_cpu);
331: }
332:
333: static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id)
334: {
335: SLAVIO_INTCTLState *s = opaque;
336: int i;
337:
338: if (version_id != 1)
339: return -EINVAL;
340:
341: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.4 ! root 342: qemu_get_be32s(f, &s->intreg_pending[i]);
1.1 root 343: }
344: qemu_get_be32s(f, &s->intregm_pending);
345: qemu_get_be32s(f, &s->intregm_disabled);
346: qemu_get_be32s(f, &s->target_cpu);
1.1.1.4 ! root 347: slavio_check_interrupts(s);
1.1 root 348: return 0;
349: }
350:
351: static void slavio_intctl_reset(void *opaque)
352: {
353: SLAVIO_INTCTLState *s = opaque;
354: int i;
355:
356: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.4 ! root 357: s->intreg_pending[i] = 0;
1.1 root 358: }
1.1.1.4 ! root 359: s->intregm_disabled = ~MASTER_IRQ_MASK;
1.1 root 360: s->intregm_pending = 0;
361: s->target_cpu = 0;
1.1.1.4 ! root 362: slavio_check_interrupts(s);
1.1 root 363: }
364:
1.1.1.4 ! root 365: void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg,
! 366: const uint32_t *intbit_to_level,
! 367: qemu_irq **irq, qemu_irq **cpu_irq,
! 368: qemu_irq **parent_irq, unsigned int cputimer)
1.1 root 369: {
370: int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;
371: SLAVIO_INTCTLState *s;
372:
373: s = qemu_mallocz(sizeof(SLAVIO_INTCTLState));
374: if (!s)
375: return NULL;
376:
1.1.1.4 ! root 377: s->intbit_to_level = intbit_to_level;
1.1 root 378: for (i = 0; i < MAX_CPUS; i++) {
1.1.1.4 ! root 379: slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s);
! 380: cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_SIZE,
! 381: slavio_intctl_io_memory);
! 382: s->cpu_irqs[i] = parent_irq[i];
1.1 root 383: }
384:
385: slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s);
1.1.1.4 ! root 386: cpu_register_physical_memory(addrg, INTCTLM_SIZE, slavio_intctlm_io_memory);
1.1 root 387:
388: register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s);
389: qemu_register_reset(slavio_intctl_reset, s);
1.1.1.4 ! root 390: *irq = qemu_allocate_irqs(slavio_set_irq, s, 32);
! 391:
! 392: *cpu_irq = qemu_allocate_irqs(slavio_set_timer_irq_cpu, s, MAX_CPUS);
! 393: s->cputimer_mbit = 1 << cputimer;
! 394: s->cputimer_lbit = 1 << intbit_to_level[cputimer];
1.1 root 395: slavio_intctl_reset(s);
396: return s;
397: }
398:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.