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