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