]> git.proxmox.com Git - qemu.git/blame - hw/slavio_intctl.c
virtio-blk: Avoid zeroing every request structure
[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 */
a1961a4b 24
87ecb68b 25#include "sun4m.h"
376253ec 26#include "monitor.h"
a1961a4b 27#include "sysbus.h"
87ecb68b 28
e80cfcfc 29//#define DEBUG_IRQ_COUNT
66321a11
FB
30//#define DEBUG_IRQ
31
32#ifdef DEBUG_IRQ
001faf32
BS
33#define DPRINTF(fmt, ...) \
34 do { printf("IRQ: " fmt , ## __VA_ARGS__); } while (0)
66321a11 35#else
001faf32 36#define DPRINTF(fmt, ...)
66321a11 37#endif
e80cfcfc
FB
38
39/*
40 * Registers of interrupt controller in sun4m.
41 *
42 * This is the interrupt controller part of chip STP2001 (Slave I/O), also
43 * produced as NCR89C105. See
44 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
45 *
46 * There is a system master controller and one for each cpu.
5fafdf24 47 *
e80cfcfc
FB
48 */
49
50#define MAX_CPUS 16
b3a23197 51#define MAX_PILS 16
e80cfcfc 52
a1961a4b
BS
53struct SLAVIO_INTCTLState;
54
55typedef struct SLAVIO_CPUINTCTLState {
56 uint32_t intreg_pending;
57 struct SLAVIO_INTCTLState *master;
58 uint32_t cpu;
462eda24 59 uint32_t irl_out;
a1961a4b 60} SLAVIO_CPUINTCTLState;
a8f48dcc 61
e80cfcfc 62typedef struct SLAVIO_INTCTLState {
a1961a4b 63 SysBusDevice busdev;
e80cfcfc
FB
64 uint32_t intregm_pending;
65 uint32_t intregm_disabled;
66 uint32_t target_cpu;
67#ifdef DEBUG_IRQ_COUNT
68 uint64_t irq_count[32];
69#endif
a1961a4b 70 qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
a1961a4b 71 SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
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
c227f099 86static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
e80cfcfc 87{
a8f48dcc 88 SLAVIO_CPUINTCTLState *s = opaque;
dd4131b3 89 uint32_t saddr, ret;
e80cfcfc 90
a8f48dcc 91 saddr = addr >> 2;
e80cfcfc
FB
92 switch (saddr) {
93 case 0:
a8f48dcc 94 ret = s->intreg_pending;
dd4131b3 95 break;
e80cfcfc 96 default:
dd4131b3
BS
97 ret = 0;
98 break;
e80cfcfc 99 }
3c4cf535 100 DPRINTF("read cpu %d reg 0x" TARGET_FMT_plx " = %x\n", s->cpu, addr, ret);
dd4131b3
BS
101
102 return ret;
e80cfcfc
FB
103}
104
c227f099 105static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr,
77f193da 106 uint32_t val)
e80cfcfc 107{
a8f48dcc 108 SLAVIO_CPUINTCTLState *s = opaque;
e80cfcfc 109 uint32_t saddr;
e80cfcfc 110
a8f48dcc 111 saddr = addr >> 2;
3c4cf535 112 DPRINTF("write cpu %d reg 0x" TARGET_FMT_plx " = %x\n", s->cpu, addr, val);
e80cfcfc
FB
113 switch (saddr) {
114 case 1: // clear pending softints
462eda24 115 val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
a8f48dcc 116 s->intreg_pending &= ~val;
0d0a7e69 117 slavio_check_interrupts(s->master, 1);
a8f48dcc
BS
118 DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", s->cpu, val,
119 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);
a8f48dcc
BS
125 DPRINTF("Set cpu %d irq mask %x, curmask %x\n", s->cpu, val,
126 s->intreg_pending);
f930d07e 127 break;
e80cfcfc 128 default:
f930d07e 129 break;
e80cfcfc
FB
130 }
131}
132
d60efc6b 133static CPUReadMemoryFunc * const slavio_intctl_mem_read[3] = {
7c560456
BS
134 NULL,
135 NULL,
e80cfcfc
FB
136 slavio_intctl_mem_readl,
137};
138
d60efc6b 139static CPUWriteMemoryFunc * const slavio_intctl_mem_write[3] = {
7c560456
BS
140 NULL,
141 NULL,
e80cfcfc
FB
142 slavio_intctl_mem_writel,
143};
144
145// master system interrupt controller
c227f099 146static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
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 }
1569fc29 166 DPRINTF("read system reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
dd4131b3
BS
167
168 return ret;
e80cfcfc
FB
169}
170
c227f099 171static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr,
77f193da 172 uint32_t val)
e80cfcfc
FB
173{
174 SLAVIO_INTCTLState *s = opaque;
175 uint32_t saddr;
176
a8f48dcc 177 saddr = addr >> 2;
1569fc29 178 DPRINTF("write system reg 0x" TARGET_FMT_plx " = %x\n", 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;
77f193da
BS
184 DPRINTF("Enabled master irq mask %x, curmask %x\n", val,
185 s->intregm_disabled);
0d0a7e69 186 slavio_check_interrupts(s, 1);
f930d07e 187 break;
10760f0f 188 case 3: // set (disable; doesn't affect pending)
f930d07e 189 // Force clear unused bits
9a87ce9b 190 val &= MASTER_IRQ_MASK;
f930d07e 191 s->intregm_disabled |= val;
0d0a7e69 192 slavio_check_interrupts(s, 1);
77f193da
BS
193 DPRINTF("Disabled master irq mask %x, curmask %x\n", val,
194 s->intregm_disabled);
f930d07e 195 break;
e80cfcfc 196 case 4:
f930d07e 197 s->target_cpu = val & (MAX_CPUS - 1);
0d0a7e69 198 slavio_check_interrupts(s, 1);
f930d07e
BS
199 DPRINTF("Set master irq cpu %d\n", s->target_cpu);
200 break;
e80cfcfc 201 default:
f930d07e 202 break;
e80cfcfc
FB
203 }
204}
205
d60efc6b 206static CPUReadMemoryFunc * const slavio_intctlm_mem_read[3] = {
7c560456
BS
207 NULL,
208 NULL,
e80cfcfc
FB
209 slavio_intctlm_mem_readl,
210};
211
d60efc6b 212static CPUWriteMemoryFunc * const slavio_intctlm_mem_write[3] = {
7c560456
BS
213 NULL,
214 NULL,
e80cfcfc
FB
215 slavio_intctlm_mem_writel,
216};
217
d453c2c3 218void slavio_pic_info(Monitor *mon, DeviceState *dev)
e80cfcfc 219{
d453c2c3
BS
220 SysBusDevice *sd;
221 SLAVIO_INTCTLState *s;
e80cfcfc
FB
222 int i;
223
d453c2c3
BS
224 sd = sysbus_from_qdev(dev);
225 s = FROM_SYSBUS(SLAVIO_INTCTLState, sd);
e80cfcfc 226 for (i = 0; i < MAX_CPUS; i++) {
376253ec 227 monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
a1961a4b 228 s->slaves[i].intreg_pending);
e80cfcfc 229 }
376253ec
AL
230 monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
231 s->intregm_pending, s->intregm_disabled);
e80cfcfc
FB
232}
233
d453c2c3 234void slavio_irq_info(Monitor *mon, DeviceState *dev)
e80cfcfc
FB
235{
236#ifndef DEBUG_IRQ_COUNT
376253ec 237 monitor_printf(mon, "irq statistic code not compiled.\n");
e80cfcfc 238#else
d453c2c3
BS
239 SysBusDevice *sd;
240 SLAVIO_INTCTLState *s;
e80cfcfc
FB
241 int i;
242 int64_t count;
243
d453c2c3
BS
244 sd = sysbus_from_qdev(dev);
245 s = FROM_SYSBUS(SLAVIO_INTCTLState, sd);
376253ec 246 monitor_printf(mon, "IRQ statistics:\n");
e80cfcfc
FB
247 for (i = 0; i < 32; i++) {
248 count = s->irq_count[i];
249 if (count > 0)
376253ec 250 monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
e80cfcfc
FB
251 }
252#endif
253}
254
68556e2e 255static const uint32_t intbit_to_level[] = {
462eda24
BS
256 2, 3, 5, 7, 9, 11, 13, 2, 3, 5, 7, 9, 11, 13, 12, 12,
257 6, 13, 4, 10, 8, 9, 11, 0, 0, 0, 0, 15, 15, 15, 15, 0,
68556e2e
BS
258};
259
0d0a7e69 260static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
66321a11 261{
327ac2e7
BS
262 uint32_t pending = s->intregm_pending, pil_pending;
263 unsigned int i, j;
66321a11
FB
264
265 pending &= ~s->intregm_disabled;
266
b3a23197 267 DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled);
ba3c64fb 268 for (i = 0; i < MAX_CPUS; i++) {
327ac2e7 269 pil_pending = 0;
462eda24
BS
270
271 /* If we are the current interrupt target, get hard interrupts */
9a87ce9b 272 if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
b3a23197
BS
273 (i == s->target_cpu)) {
274 for (j = 0; j < 32; j++) {
462eda24 275 if ((pending & (1 << j)) && intbit_to_level[j]) {
68556e2e 276 pil_pending |= 1 << intbit_to_level[j];
462eda24
BS
277 }
278 }
279 }
280
281 /* Calculate current pending hard interrupts for display */
282 s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
283 CPU_IRQ_TIMER_IN;
284 if (i == s->target_cpu) {
285 for (j = 0; j < 32; j++) {
286 if ((s->intregm_pending & (1 << j)) && intbit_to_level[j]) {
287 s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
288 }
b3a23197
BS
289 }
290 }
462eda24
BS
291
292 /* Level 15 and CPU timer interrupts are not maskable */
293 pil_pending |= s->slaves[i].intreg_pending &
294 (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
295
296 /* Add soft interrupts */
a1961a4b 297 pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
327ac2e7 298
0d0a7e69 299 if (set_irqs) {
462eda24 300 for (j = MAX_PILS; j > 0; j--) {
0d0a7e69 301 if (pil_pending & (1 << j)) {
462eda24 302 if (!(s->slaves[i].irl_out & (1 << j))) {
0d0a7e69
BS
303 qemu_irq_raise(s->cpu_irqs[i][j]);
304 }
305 } else {
462eda24 306 if (s->slaves[i].irl_out & (1 << j)) {
0d0a7e69
BS
307 qemu_irq_lower(s->cpu_irqs[i][j]);
308 }
309 }
ba3c64fb
FB
310 }
311 }
462eda24 312 s->slaves[i].irl_out = pil_pending;
ba3c64fb 313 }
66321a11
FB
314}
315
e80cfcfc
FB
316/*
317 * "irq" here is the bit number in the system interrupt register to
318 * separate serial and keyboard interrupts sharing a level.
319 */
d7edfd27 320static void slavio_set_irq(void *opaque, int irq, int level)
e80cfcfc
FB
321{
322 SLAVIO_INTCTLState *s = opaque;
b3a23197 323 uint32_t mask = 1 << irq;
68556e2e 324 uint32_t pil = intbit_to_level[irq];
462eda24 325 unsigned int i;
b3a23197
BS
326
327 DPRINTF("Set cpu %d irq %d -> pil %d level %d\n", s->target_cpu, irq, pil,
328 level);
329 if (pil > 0) {
330 if (level) {
327ac2e7
BS
331#ifdef DEBUG_IRQ_COUNT
332 s->irq_count[pil]++;
333#endif
b3a23197 334 s->intregm_pending |= mask;
462eda24
BS
335 if (pil == 15) {
336 for (i = 0; i < MAX_CPUS; i++) {
337 s->slaves[i].intreg_pending |= 1 << pil;
338 }
339 }
b3a23197
BS
340 } else {
341 s->intregm_pending &= ~mask;
462eda24
BS
342 if (pil == 15) {
343 for (i = 0; i < MAX_CPUS; i++) {
344 s->slaves[i].intreg_pending &= ~(1 << pil);
345 }
346 }
b3a23197 347 }
0d0a7e69 348 slavio_check_interrupts(s, 1);
e80cfcfc
FB
349 }
350}
351
d7edfd27 352static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
ba3c64fb
FB
353{
354 SLAVIO_INTCTLState *s = opaque;
355
b3a23197 356 DPRINTF("Set cpu %d local timer level %d\n", cpu, level);
d7edfd27 357
e3a79bca 358 if (level) {
462eda24 359 s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
e3a79bca 360 } else {
462eda24 361 s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
e3a79bca 362 }
d7edfd27 363
0d0a7e69 364 slavio_check_interrupts(s, 1);
ba3c64fb
FB
365}
366
a1961a4b
BS
367static void slavio_set_irq_all(void *opaque, int irq, int level)
368{
369 if (irq < 32) {
370 slavio_set_irq(opaque, irq, level);
371 } else {
372 slavio_set_timer_irq_cpu(opaque, irq - 32, level);
373 }
374}
375
e59fb374 376static int vmstate_intctl_post_load(void *opaque, int version_id)
e80cfcfc
FB
377{
378 SLAVIO_INTCTLState *s = opaque;
3b46e624 379
c9e95029
BS
380 slavio_check_interrupts(s, 0);
381 return 0;
e80cfcfc
FB
382}
383
c9e95029
BS
384static const VMStateDescription vmstate_intctl_cpu = {
385 .name ="slavio_intctl_cpu",
386 .version_id = 1,
387 .minimum_version_id = 1,
388 .minimum_version_id_old = 1,
389 .fields = (VMStateField []) {
390 VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
391 VMSTATE_END_OF_LIST()
392 }
393};
e80cfcfc 394
c9e95029
BS
395static const VMStateDescription vmstate_intctl = {
396 .name ="slavio_intctl",
397 .version_id = 1,
398 .minimum_version_id = 1,
399 .minimum_version_id_old = 1,
752ff2fa 400 .post_load = vmstate_intctl_post_load,
c9e95029
BS
401 .fields = (VMStateField []) {
402 VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
403 vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
404 VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
405 VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
406 VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
407 VMSTATE_END_OF_LIST()
e80cfcfc 408 }
c9e95029 409};
e80cfcfc 410
78971d57 411static void slavio_intctl_reset(DeviceState *d)
e80cfcfc 412{
78971d57 413 SLAVIO_INTCTLState *s = container_of(d, SLAVIO_INTCTLState, busdev.qdev);
e80cfcfc
FB
414 int i;
415
416 for (i = 0; i < MAX_CPUS; i++) {
a1961a4b 417 s->slaves[i].intreg_pending = 0;
462eda24 418 s->slaves[i].irl_out = 0;
e80cfcfc 419 }
9a87ce9b 420 s->intregm_disabled = ~MASTER_IRQ_MASK;
e80cfcfc
FB
421 s->intregm_pending = 0;
422 s->target_cpu = 0;
0d0a7e69 423 slavio_check_interrupts(s, 0);
e80cfcfc
FB
424}
425
81a322d4 426static int slavio_intctl_init1(SysBusDevice *dev)
e80cfcfc 427{
a1961a4b 428 SLAVIO_INTCTLState *s = FROM_SYSBUS(SLAVIO_INTCTLState, dev);
ee6847d1 429 int io_memory;
a1961a4b 430 unsigned int i, j;
e80cfcfc 431
a1961a4b
BS
432 qdev_init_gpio_in(&dev->qdev, slavio_set_irq_all, 32 + MAX_CPUS);
433 io_memory = cpu_register_io_memory(slavio_intctlm_mem_read,
434 slavio_intctlm_mem_write, s);
435 sysbus_init_mmio(dev, INTCTLM_SIZE, io_memory);
e80cfcfc
FB
436
437 for (i = 0; i < MAX_CPUS; i++) {
a1961a4b
BS
438 for (j = 0; j < MAX_PILS; j++) {
439 sysbus_init_irq(dev, &s->cpu_irqs[i][j]);
440 }
441 io_memory = cpu_register_io_memory(slavio_intctl_mem_read,
442 slavio_intctl_mem_write,
443 &s->slaves[i]);
444 sysbus_init_mmio(dev, INTCTL_SIZE, io_memory);
445 s->slaves[i].cpu = i;
446 s->slaves[i].master = s;
447 }
78971d57 448
81a322d4 449 return 0;
a1961a4b
BS
450}
451
a1961a4b
BS
452static SysBusDeviceInfo slavio_intctl_info = {
453 .init = slavio_intctl_init1,
454 .qdev.name = "slavio_intctl",
455 .qdev.size = sizeof(SLAVIO_INTCTLState),
78971d57
BS
456 .qdev.vmsd = &vmstate_intctl,
457 .qdev.reset = slavio_intctl_reset,
a1961a4b 458};
d7edfd27 459
a1961a4b
BS
460static void slavio_intctl_register_devices(void)
461{
462 sysbus_register_withprop(&slavio_intctl_info);
e80cfcfc 463}
a1961a4b
BS
464
465device_init(slavio_intctl_register_devices)