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