]> git.proxmox.com Git - qemu.git/blame - hw/intc/slavio_intctl.c
mips jazz: do not raise data bus exception when accessing invalid addresses
[qemu.git] / hw / intc / 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 */
a1961a4b 24
0d09e41a 25#include "hw/sparc/sun4m.h"
83c9089e 26#include "monitor/monitor.h"
83c9f4ca 27#include "hw/sysbus.h"
97bf4851 28#include "trace.h"
87ecb68b 29
e80cfcfc
FB
30//#define DEBUG_IRQ_COUNT
31
32/*
33 * Registers of interrupt controller in sun4m.
34 *
35 * This is the interrupt controller part of chip STP2001 (Slave I/O), also
36 * produced as NCR89C105. See
37 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
38 *
39 * There is a system master controller and one for each cpu.
5fafdf24 40 *
e80cfcfc
FB
41 */
42
43#define MAX_CPUS 16
b3a23197 44#define MAX_PILS 16
e80cfcfc 45
a1961a4b
BS
46struct SLAVIO_INTCTLState;
47
48typedef struct SLAVIO_CPUINTCTLState {
8bb5ef33 49 MemoryRegion iomem;
a1961a4b 50 struct SLAVIO_INTCTLState *master;
07dd0035 51 uint32_t intreg_pending;
a1961a4b 52 uint32_t cpu;
462eda24 53 uint32_t irl_out;
a1961a4b 54} SLAVIO_CPUINTCTLState;
a8f48dcc 55
7abad863
AF
56#define TYPE_SLAVIO_INTCTL "slavio_intctl"
57#define SLAVIO_INTCTL(obj) \
58 OBJECT_CHECK(SLAVIO_INTCTLState, (obj), TYPE_SLAVIO_INTCTL)
59
e80cfcfc 60typedef struct SLAVIO_INTCTLState {
7abad863
AF
61 SysBusDevice parent_obj;
62
13c89a11 63 MemoryRegion iomem;
e80cfcfc
FB
64#ifdef DEBUG_IRQ_COUNT
65 uint64_t irq_count[32];
66#endif
a1961a4b 67 qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
a1961a4b 68 SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
07dd0035
BS
69 uint32_t intregm_pending;
70 uint32_t intregm_disabled;
71 uint32_t target_cpu;
e80cfcfc
FB
72} SLAVIO_INTCTLState;
73
74#define INTCTL_MAXADDR 0xf
5aca8c3b 75#define INTCTL_SIZE (INTCTL_MAXADDR + 1)
a8f48dcc 76#define INTCTLM_SIZE 0x14
80be36b8 77#define MASTER_IRQ_MASK ~0x0fa2007f
9a87ce9b 78#define MASTER_DISABLE 0x80000000
6341fdcb 79#define CPU_SOFTIRQ_MASK 0xfffe0000
462eda24
BS
80#define CPU_IRQ_INT15_IN (1 << 15)
81#define CPU_IRQ_TIMER_IN (1 << 14)
9a87ce9b 82
0d0a7e69 83static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
e80cfcfc
FB
84
85// per-cpu interrupt controller
a8170e5e 86static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr,
8bb5ef33 87 unsigned size)
e80cfcfc 88{
a8f48dcc 89 SLAVIO_CPUINTCTLState *s = opaque;
dd4131b3 90 uint32_t saddr, ret;
e80cfcfc 91
a8f48dcc 92 saddr = addr >> 2;
e80cfcfc
FB
93 switch (saddr) {
94 case 0:
a8f48dcc 95 ret = s->intreg_pending;
dd4131b3 96 break;
e80cfcfc 97 default:
dd4131b3
BS
98 ret = 0;
99 break;
e80cfcfc 100 }
97bf4851 101 trace_slavio_intctl_mem_readl(s->cpu, addr, ret);
dd4131b3
BS
102
103 return ret;
e80cfcfc
FB
104}
105
a8170e5e 106static void slavio_intctl_mem_writel(void *opaque, hwaddr addr,
8bb5ef33 107 uint64_t val, unsigned size)
e80cfcfc 108{
a8f48dcc 109 SLAVIO_CPUINTCTLState *s = opaque;
e80cfcfc 110 uint32_t saddr;
e80cfcfc 111
a8f48dcc 112 saddr = addr >> 2;
97bf4851 113 trace_slavio_intctl_mem_writel(s->cpu, addr, val);
e80cfcfc
FB
114 switch (saddr) {
115 case 1: // clear pending softints
462eda24 116 val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
a8f48dcc 117 s->intreg_pending &= ~val;
0d0a7e69 118 slavio_check_interrupts(s->master, 1);
97bf4851 119 trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending);
f930d07e 120 break;
e80cfcfc 121 case 2: // set softint
6341fdcb 122 val &= CPU_SOFTIRQ_MASK;
a8f48dcc 123 s->intreg_pending |= val;
0d0a7e69 124 slavio_check_interrupts(s->master, 1);
97bf4851 125 trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending);
f930d07e 126 break;
e80cfcfc 127 default:
f930d07e 128 break;
e80cfcfc
FB
129 }
130}
131
8bb5ef33
BC
132static const MemoryRegionOps slavio_intctl_mem_ops = {
133 .read = slavio_intctl_mem_readl,
134 .write = slavio_intctl_mem_writel,
135 .endianness = DEVICE_NATIVE_ENDIAN,
136 .valid = {
137 .min_access_size = 4,
138 .max_access_size = 4,
139 },
e80cfcfc
FB
140};
141
142// master system interrupt controller
a8170e5e 143static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr,
13c89a11 144 unsigned size)
e80cfcfc
FB
145{
146 SLAVIO_INTCTLState *s = opaque;
dd4131b3 147 uint32_t saddr, ret;
e80cfcfc 148
a8f48dcc 149 saddr = addr >> 2;
e80cfcfc
FB
150 switch (saddr) {
151 case 0:
9a87ce9b 152 ret = s->intregm_pending & ~MASTER_DISABLE;
dd4131b3 153 break;
e80cfcfc 154 case 1:
80be36b8 155 ret = s->intregm_disabled & MASTER_IRQ_MASK;
dd4131b3 156 break;
e80cfcfc 157 case 4:
dd4131b3
BS
158 ret = s->target_cpu;
159 break;
e80cfcfc 160 default:
dd4131b3
BS
161 ret = 0;
162 break;
e80cfcfc 163 }
97bf4851 164 trace_slavio_intctlm_mem_readl(addr, ret);
dd4131b3
BS
165
166 return ret;
e80cfcfc
FB
167}
168
a8170e5e 169static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr,
13c89a11 170 uint64_t val, unsigned size)
e80cfcfc
FB
171{
172 SLAVIO_INTCTLState *s = opaque;
173 uint32_t saddr;
174
a8f48dcc 175 saddr = addr >> 2;
97bf4851 176 trace_slavio_intctlm_mem_writel(addr, val);
e80cfcfc
FB
177 switch (saddr) {
178 case 2: // clear (enable)
f930d07e 179 // Force clear unused bits
9a87ce9b 180 val &= MASTER_IRQ_MASK;
f930d07e 181 s->intregm_disabled &= ~val;
97bf4851 182 trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled);
0d0a7e69 183 slavio_check_interrupts(s, 1);
f930d07e 184 break;
10760f0f 185 case 3: // set (disable; doesn't affect pending)
f930d07e 186 // Force clear unused bits
9a87ce9b 187 val &= MASTER_IRQ_MASK;
f930d07e 188 s->intregm_disabled |= val;
0d0a7e69 189 slavio_check_interrupts(s, 1);
97bf4851 190 trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled);
f930d07e 191 break;
e80cfcfc 192 case 4:
f930d07e 193 s->target_cpu = val & (MAX_CPUS - 1);
0d0a7e69 194 slavio_check_interrupts(s, 1);
97bf4851 195 trace_slavio_intctlm_mem_writel_target(s->target_cpu);
f930d07e 196 break;
e80cfcfc 197 default:
f930d07e 198 break;
e80cfcfc
FB
199 }
200}
201
13c89a11
BC
202static const MemoryRegionOps slavio_intctlm_mem_ops = {
203 .read = slavio_intctlm_mem_readl,
204 .write = slavio_intctlm_mem_writel,
205 .endianness = DEVICE_NATIVE_ENDIAN,
206 .valid = {
207 .min_access_size = 4,
208 .max_access_size = 4,
209 },
e80cfcfc
FB
210};
211
d453c2c3 212void slavio_pic_info(Monitor *mon, DeviceState *dev)
e80cfcfc 213{
7abad863 214 SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
e80cfcfc
FB
215 int i;
216
217 for (i = 0; i < MAX_CPUS; i++) {
376253ec 218 monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
a1961a4b 219 s->slaves[i].intreg_pending);
e80cfcfc 220 }
376253ec
AL
221 monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
222 s->intregm_pending, s->intregm_disabled);
e80cfcfc
FB
223}
224
d453c2c3 225void slavio_irq_info(Monitor *mon, DeviceState *dev)
e80cfcfc
FB
226{
227#ifndef DEBUG_IRQ_COUNT
376253ec 228 monitor_printf(mon, "irq statistic code not compiled.\n");
e80cfcfc 229#else
7abad863 230 SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
e80cfcfc
FB
231 int i;
232 int64_t count;
233
7abad863 234 s = SLAVIO_INTCTL(dev);
376253ec 235 monitor_printf(mon, "IRQ statistics:\n");
e80cfcfc
FB
236 for (i = 0; i < 32; i++) {
237 count = s->irq_count[i];
238 if (count > 0)
376253ec 239 monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
e80cfcfc
FB
240 }
241#endif
242}
243
68556e2e 244static const uint32_t intbit_to_level[] = {
462eda24
BS
245 2, 3, 5, 7, 9, 11, 13, 2, 3, 5, 7, 9, 11, 13, 12, 12,
246 6, 13, 4, 10, 8, 9, 11, 0, 0, 0, 0, 15, 15, 15, 15, 0,
68556e2e
BS
247};
248
0d0a7e69 249static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
66321a11 250{
327ac2e7
BS
251 uint32_t pending = s->intregm_pending, pil_pending;
252 unsigned int i, j;
66321a11
FB
253
254 pending &= ~s->intregm_disabled;
255
97bf4851 256 trace_slavio_check_interrupts(pending, s->intregm_disabled);
ba3c64fb 257 for (i = 0; i < MAX_CPUS; i++) {
327ac2e7 258 pil_pending = 0;
462eda24
BS
259
260 /* If we are the current interrupt target, get hard interrupts */
9a87ce9b 261 if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
b3a23197
BS
262 (i == s->target_cpu)) {
263 for (j = 0; j < 32; j++) {
462eda24 264 if ((pending & (1 << j)) && intbit_to_level[j]) {
68556e2e 265 pil_pending |= 1 << intbit_to_level[j];
462eda24
BS
266 }
267 }
268 }
269
270 /* Calculate current pending hard interrupts for display */
271 s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
272 CPU_IRQ_TIMER_IN;
273 if (i == s->target_cpu) {
274 for (j = 0; j < 32; j++) {
275 if ((s->intregm_pending & (1 << j)) && intbit_to_level[j]) {
276 s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
277 }
b3a23197
BS
278 }
279 }
462eda24 280
94c5f455
AT
281 /* Level 15 and CPU timer interrupts are only masked when
282 the MASTER_DISABLE bit is set */
283 if (!(s->intregm_disabled & MASTER_DISABLE)) {
284 pil_pending |= s->slaves[i].intreg_pending &
285 (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
286 }
462eda24
BS
287
288 /* Add soft interrupts */
a1961a4b 289 pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
327ac2e7 290
0d0a7e69 291 if (set_irqs) {
c84a88d8
PM
292 /* Since there is not really an interrupt 0 (and pil_pending
293 * and irl_out bit zero are thus always zero) there is no need
294 * to do anything with cpu_irqs[i][0] and it is OK not to do
295 * the j=0 iteration of this loop.
296 */
297 for (j = MAX_PILS-1; j > 0; j--) {
0d0a7e69 298 if (pil_pending & (1 << j)) {
462eda24 299 if (!(s->slaves[i].irl_out & (1 << j))) {
0d0a7e69
BS
300 qemu_irq_raise(s->cpu_irqs[i][j]);
301 }
302 } else {
462eda24 303 if (s->slaves[i].irl_out & (1 << j)) {
0d0a7e69
BS
304 qemu_irq_lower(s->cpu_irqs[i][j]);
305 }
306 }
ba3c64fb
FB
307 }
308 }
462eda24 309 s->slaves[i].irl_out = pil_pending;
ba3c64fb 310 }
66321a11
FB
311}
312
e80cfcfc
FB
313/*
314 * "irq" here is the bit number in the system interrupt register to
315 * separate serial and keyboard interrupts sharing a level.
316 */
d7edfd27 317static void slavio_set_irq(void *opaque, int irq, int level)
e80cfcfc
FB
318{
319 SLAVIO_INTCTLState *s = opaque;
b3a23197 320 uint32_t mask = 1 << irq;
68556e2e 321 uint32_t pil = intbit_to_level[irq];
462eda24 322 unsigned int i;
b3a23197 323
97bf4851 324 trace_slavio_set_irq(s->target_cpu, irq, pil, level);
b3a23197
BS
325 if (pil > 0) {
326 if (level) {
327ac2e7
BS
327#ifdef DEBUG_IRQ_COUNT
328 s->irq_count[pil]++;
329#endif
b3a23197 330 s->intregm_pending |= mask;
462eda24
BS
331 if (pil == 15) {
332 for (i = 0; i < MAX_CPUS; i++) {
333 s->slaves[i].intreg_pending |= 1 << pil;
334 }
335 }
b3a23197
BS
336 } else {
337 s->intregm_pending &= ~mask;
462eda24
BS
338 if (pil == 15) {
339 for (i = 0; i < MAX_CPUS; i++) {
340 s->slaves[i].intreg_pending &= ~(1 << pil);
341 }
342 }
b3a23197 343 }
0d0a7e69 344 slavio_check_interrupts(s, 1);
e80cfcfc
FB
345 }
346}
347
d7edfd27 348static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
ba3c64fb
FB
349{
350 SLAVIO_INTCTLState *s = opaque;
351
97bf4851 352 trace_slavio_set_timer_irq_cpu(cpu, level);
d7edfd27 353
e3a79bca 354 if (level) {
462eda24 355 s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
e3a79bca 356 } else {
462eda24 357 s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
e3a79bca 358 }
d7edfd27 359
0d0a7e69 360 slavio_check_interrupts(s, 1);
ba3c64fb
FB
361}
362
a1961a4b
BS
363static void slavio_set_irq_all(void *opaque, int irq, int level)
364{
365 if (irq < 32) {
366 slavio_set_irq(opaque, irq, level);
367 } else {
368 slavio_set_timer_irq_cpu(opaque, irq - 32, level);
369 }
370}
371
e59fb374 372static int vmstate_intctl_post_load(void *opaque, int version_id)
e80cfcfc
FB
373{
374 SLAVIO_INTCTLState *s = opaque;
3b46e624 375
c9e95029
BS
376 slavio_check_interrupts(s, 0);
377 return 0;
e80cfcfc
FB
378}
379
c9e95029
BS
380static const VMStateDescription vmstate_intctl_cpu = {
381 .name ="slavio_intctl_cpu",
382 .version_id = 1,
383 .minimum_version_id = 1,
384 .minimum_version_id_old = 1,
385 .fields = (VMStateField []) {
386 VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
387 VMSTATE_END_OF_LIST()
388 }
389};
e80cfcfc 390
c9e95029
BS
391static const VMStateDescription vmstate_intctl = {
392 .name ="slavio_intctl",
393 .version_id = 1,
394 .minimum_version_id = 1,
395 .minimum_version_id_old = 1,
752ff2fa 396 .post_load = vmstate_intctl_post_load,
c9e95029
BS
397 .fields = (VMStateField []) {
398 VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
399 vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
400 VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
401 VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
402 VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
403 VMSTATE_END_OF_LIST()
e80cfcfc 404 }
c9e95029 405};
e80cfcfc 406
78971d57 407static void slavio_intctl_reset(DeviceState *d)
e80cfcfc 408{
7abad863 409 SLAVIO_INTCTLState *s = SLAVIO_INTCTL(d);
e80cfcfc
FB
410 int i;
411
412 for (i = 0; i < MAX_CPUS; i++) {
a1961a4b 413 s->slaves[i].intreg_pending = 0;
462eda24 414 s->slaves[i].irl_out = 0;
e80cfcfc 415 }
9a87ce9b 416 s->intregm_disabled = ~MASTER_IRQ_MASK;
e80cfcfc
FB
417 s->intregm_pending = 0;
418 s->target_cpu = 0;
0d0a7e69 419 slavio_check_interrupts(s, 0);
e80cfcfc
FB
420}
421
7abad863 422static int slavio_intctl_init1(SysBusDevice *sbd)
e80cfcfc 423{
7abad863
AF
424 DeviceState *dev = DEVICE(sbd);
425 SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
a1961a4b 426 unsigned int i, j;
8bb5ef33 427 char slave_name[45];
e80cfcfc 428
7abad863 429 qdev_init_gpio_in(dev, slavio_set_irq_all, 32 + MAX_CPUS);
1437c94b 430 memory_region_init_io(&s->iomem, OBJECT(s), &slavio_intctlm_mem_ops, s,
13c89a11 431 "master-interrupt-controller", INTCTLM_SIZE);
7abad863 432 sysbus_init_mmio(sbd, &s->iomem);
e80cfcfc
FB
433
434 for (i = 0; i < MAX_CPUS; i++) {
8bb5ef33
BC
435 snprintf(slave_name, sizeof(slave_name),
436 "slave-interrupt-controller-%i", i);
a1961a4b 437 for (j = 0; j < MAX_PILS; j++) {
7abad863 438 sysbus_init_irq(sbd, &s->cpu_irqs[i][j]);
a1961a4b 439 }
1437c94b
PB
440 memory_region_init_io(&s->slaves[i].iomem, OBJECT(s),
441 &slavio_intctl_mem_ops,
8bb5ef33 442 &s->slaves[i], slave_name, INTCTL_SIZE);
7abad863 443 sysbus_init_mmio(sbd, &s->slaves[i].iomem);
a1961a4b
BS
444 s->slaves[i].cpu = i;
445 s->slaves[i].master = s;
446 }
78971d57 447
81a322d4 448 return 0;
a1961a4b
BS
449}
450
999e12bb
AL
451static void slavio_intctl_class_init(ObjectClass *klass, void *data)
452{
39bffca2 453 DeviceClass *dc = DEVICE_CLASS(klass);
999e12bb
AL
454 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
455
456 k->init = slavio_intctl_init1;
39bffca2
AL
457 dc->reset = slavio_intctl_reset;
458 dc->vmsd = &vmstate_intctl;
999e12bb
AL
459}
460
8c43a6f0 461static const TypeInfo slavio_intctl_info = {
7abad863 462 .name = TYPE_SLAVIO_INTCTL,
39bffca2
AL
463 .parent = TYPE_SYS_BUS_DEVICE,
464 .instance_size = sizeof(SLAVIO_INTCTLState),
465 .class_init = slavio_intctl_class_init,
a1961a4b 466};
d7edfd27 467
83f7d43a 468static void slavio_intctl_register_types(void)
a1961a4b 469{
39bffca2 470 type_register_static(&slavio_intctl_info);
e80cfcfc 471}
a1961a4b 472
83f7d43a 473type_init(slavio_intctl_register_types)