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