blob: 259e45ee85ae37fad5e911d40c2dfc0b52b7935c [file] [log] [blame]
bellarde80cfcf2004-12-19 23:18:01 +00001/*
2 * QEMU Sparc SLAVIO interrupt controller emulation
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard66321a12005-04-06 20:47:48 +00004 * Copyright (c) 2003-2005 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
bellarde80cfcf2004-12-19 23:18:01 +00006 * 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 */
Blue Swirla1961a42009-07-16 14:15:34 +000024
pbrook87ecb682007-11-17 17:14:51 +000025#include "sun4m.h"
aliguori376253e2009-03-05 23:01:23 +000026#include "monitor.h"
Blue Swirla1961a42009-07-16 14:15:34 +000027#include "sysbus.h"
pbrook87ecb682007-11-17 17:14:51 +000028
bellarde80cfcf2004-12-19 23:18:01 +000029//#define DEBUG_IRQ_COUNT
bellard66321a12005-04-06 20:47:48 +000030//#define DEBUG_IRQ
31
32#ifdef DEBUG_IRQ
Blue Swirl001faf32009-05-13 17:53:17 +000033#define DPRINTF(fmt, ...) \
34 do { printf("IRQ: " fmt , ## __VA_ARGS__); } while (0)
bellard66321a12005-04-06 20:47:48 +000035#else
Blue Swirl001faf32009-05-13 17:53:17 +000036#define DPRINTF(fmt, ...)
bellard66321a12005-04-06 20:47:48 +000037#endif
bellarde80cfcf2004-12-19 23:18:01 +000038
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.
ths5fafdf22007-09-16 21:08:06 +000047 *
bellarde80cfcf2004-12-19 23:18:01 +000048 */
49
50#define MAX_CPUS 16
blueswir1b3a23192007-05-27 16:42:29 +000051#define MAX_PILS 16
bellarde80cfcf2004-12-19 23:18:01 +000052
Blue Swirla1961a42009-07-16 14:15:34 +000053struct SLAVIO_INTCTLState;
54
55typedef struct SLAVIO_CPUINTCTLState {
56 uint32_t intreg_pending;
57 struct SLAVIO_INTCTLState *master;
58 uint32_t cpu;
Blue Swirl462eda22009-08-25 18:29:36 +000059 uint32_t irl_out;
Blue Swirla1961a42009-07-16 14:15:34 +000060} SLAVIO_CPUINTCTLState;
blueswir1a8f48dc2008-12-02 17:51:19 +000061
bellarde80cfcf2004-12-19 23:18:01 +000062typedef struct SLAVIO_INTCTLState {
Blue Swirla1961a42009-07-16 14:15:34 +000063 SysBusDevice busdev;
bellarde80cfcf2004-12-19 23:18:01 +000064 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
Blue Swirla1961a42009-07-16 14:15:34 +000070 qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
Blue Swirla1961a42009-07-16 14:15:34 +000071 SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
bellarde80cfcf2004-12-19 23:18:01 +000072} SLAVIO_INTCTLState;
73
74#define INTCTL_MAXADDR 0xf
blueswir15aca8c32007-05-26 17:39:43 +000075#define INTCTL_SIZE (INTCTL_MAXADDR + 1)
blueswir1a8f48dc2008-12-02 17:51:19 +000076#define INTCTLM_SIZE 0x14
blueswir180be36b2007-12-28 18:48:39 +000077#define MASTER_IRQ_MASK ~0x0fa2007f
blueswir19a87ce92007-11-17 21:01:04 +000078#define MASTER_DISABLE 0x80000000
blueswir16341fdc2007-12-29 20:09:57 +000079#define CPU_SOFTIRQ_MASK 0xfffe0000
Blue Swirl462eda22009-08-25 18:29:36 +000080#define CPU_IRQ_INT15_IN (1 << 15)
81#define CPU_IRQ_TIMER_IN (1 << 14)
blueswir19a87ce92007-11-17 21:01:04 +000082
Blue Swirl0d0a7e62009-06-17 17:20:01 +000083static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
bellarde80cfcf2004-12-19 23:18:01 +000084
85// per-cpu interrupt controller
86static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
87{
blueswir1a8f48dc2008-12-02 17:51:19 +000088 SLAVIO_CPUINTCTLState *s = opaque;
blueswir1dd4131b2007-05-27 19:42:35 +000089 uint32_t saddr, ret;
bellarde80cfcf2004-12-19 23:18:01 +000090
blueswir1a8f48dc2008-12-02 17:51:19 +000091 saddr = addr >> 2;
bellarde80cfcf2004-12-19 23:18:01 +000092 switch (saddr) {
93 case 0:
blueswir1a8f48dc2008-12-02 17:51:19 +000094 ret = s->intreg_pending;
blueswir1dd4131b2007-05-27 19:42:35 +000095 break;
bellarde80cfcf2004-12-19 23:18:01 +000096 default:
blueswir1dd4131b2007-05-27 19:42:35 +000097 ret = 0;
98 break;
bellarde80cfcf2004-12-19 23:18:01 +000099 }
blueswir13c4cf532009-03-03 20:11:43 +0000100 DPRINTF("read cpu %d reg 0x" TARGET_FMT_plx " = %x\n", s->cpu, addr, ret);
blueswir1dd4131b2007-05-27 19:42:35 +0000101
102 return ret;
bellarde80cfcf2004-12-19 23:18:01 +0000103}
104
blueswir177f193d2008-05-12 16:13:33 +0000105static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr,
106 uint32_t val)
bellarde80cfcf2004-12-19 23:18:01 +0000107{
blueswir1a8f48dc2008-12-02 17:51:19 +0000108 SLAVIO_CPUINTCTLState *s = opaque;
bellarde80cfcf2004-12-19 23:18:01 +0000109 uint32_t saddr;
bellarde80cfcf2004-12-19 23:18:01 +0000110
blueswir1a8f48dc2008-12-02 17:51:19 +0000111 saddr = addr >> 2;
blueswir13c4cf532009-03-03 20:11:43 +0000112 DPRINTF("write cpu %d reg 0x" TARGET_FMT_plx " = %x\n", s->cpu, addr, val);
bellarde80cfcf2004-12-19 23:18:01 +0000113 switch (saddr) {
114 case 1: // clear pending softints
Blue Swirl462eda22009-08-25 18:29:36 +0000115 val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
blueswir1a8f48dc2008-12-02 17:51:19 +0000116 s->intreg_pending &= ~val;
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000117 slavio_check_interrupts(s->master, 1);
blueswir1a8f48dc2008-12-02 17:51:19 +0000118 DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", s->cpu, val,
119 s->intreg_pending);
blueswir1f930d072007-10-06 11:28:21 +0000120 break;
bellarde80cfcf2004-12-19 23:18:01 +0000121 case 2: // set softint
blueswir16341fdc2007-12-29 20:09:57 +0000122 val &= CPU_SOFTIRQ_MASK;
blueswir1a8f48dc2008-12-02 17:51:19 +0000123 s->intreg_pending |= val;
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000124 slavio_check_interrupts(s->master, 1);
blueswir1a8f48dc2008-12-02 17:51:19 +0000125 DPRINTF("Set cpu %d irq mask %x, curmask %x\n", s->cpu, val,
126 s->intreg_pending);
blueswir1f930d072007-10-06 11:28:21 +0000127 break;
bellarde80cfcf2004-12-19 23:18:01 +0000128 default:
blueswir1f930d072007-10-06 11:28:21 +0000129 break;
bellarde80cfcf2004-12-19 23:18:01 +0000130 }
131}
132
Blue Swirld60efc62009-08-25 18:29:31 +0000133static CPUReadMemoryFunc * const slavio_intctl_mem_read[3] = {
blueswir17c560452008-01-01 17:06:38 +0000134 NULL,
135 NULL,
bellarde80cfcf2004-12-19 23:18:01 +0000136 slavio_intctl_mem_readl,
137};
138
Blue Swirld60efc62009-08-25 18:29:31 +0000139static CPUWriteMemoryFunc * const slavio_intctl_mem_write[3] = {
blueswir17c560452008-01-01 17:06:38 +0000140 NULL,
141 NULL,
bellarde80cfcf2004-12-19 23:18:01 +0000142 slavio_intctl_mem_writel,
143};
144
145// master system interrupt controller
146static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
147{
148 SLAVIO_INTCTLState *s = opaque;
blueswir1dd4131b2007-05-27 19:42:35 +0000149 uint32_t saddr, ret;
bellarde80cfcf2004-12-19 23:18:01 +0000150
blueswir1a8f48dc2008-12-02 17:51:19 +0000151 saddr = addr >> 2;
bellarde80cfcf2004-12-19 23:18:01 +0000152 switch (saddr) {
153 case 0:
blueswir19a87ce92007-11-17 21:01:04 +0000154 ret = s->intregm_pending & ~MASTER_DISABLE;
blueswir1dd4131b2007-05-27 19:42:35 +0000155 break;
bellarde80cfcf2004-12-19 23:18:01 +0000156 case 1:
blueswir180be36b2007-12-28 18:48:39 +0000157 ret = s->intregm_disabled & MASTER_IRQ_MASK;
blueswir1dd4131b2007-05-27 19:42:35 +0000158 break;
bellarde80cfcf2004-12-19 23:18:01 +0000159 case 4:
blueswir1dd4131b2007-05-27 19:42:35 +0000160 ret = s->target_cpu;
161 break;
bellarde80cfcf2004-12-19 23:18:01 +0000162 default:
blueswir1dd4131b2007-05-27 19:42:35 +0000163 ret = 0;
164 break;
bellarde80cfcf2004-12-19 23:18:01 +0000165 }
blueswir11569fc22007-08-05 17:47:16 +0000166 DPRINTF("read system reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
blueswir1dd4131b2007-05-27 19:42:35 +0000167
168 return ret;
bellarde80cfcf2004-12-19 23:18:01 +0000169}
170
blueswir177f193d2008-05-12 16:13:33 +0000171static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr,
172 uint32_t val)
bellarde80cfcf2004-12-19 23:18:01 +0000173{
174 SLAVIO_INTCTLState *s = opaque;
175 uint32_t saddr;
176
blueswir1a8f48dc2008-12-02 17:51:19 +0000177 saddr = addr >> 2;
blueswir11569fc22007-08-05 17:47:16 +0000178 DPRINTF("write system reg 0x" TARGET_FMT_plx " = %x\n", addr, val);
bellarde80cfcf2004-12-19 23:18:01 +0000179 switch (saddr) {
180 case 2: // clear (enable)
blueswir1f930d072007-10-06 11:28:21 +0000181 // Force clear unused bits
blueswir19a87ce92007-11-17 21:01:04 +0000182 val &= MASTER_IRQ_MASK;
blueswir1f930d072007-10-06 11:28:21 +0000183 s->intregm_disabled &= ~val;
blueswir177f193d2008-05-12 16:13:33 +0000184 DPRINTF("Enabled master irq mask %x, curmask %x\n", val,
185 s->intregm_disabled);
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000186 slavio_check_interrupts(s, 1);
blueswir1f930d072007-10-06 11:28:21 +0000187 break;
bellarde80cfcf2004-12-19 23:18:01 +0000188 case 3: // set (disable, clear pending)
blueswir1f930d072007-10-06 11:28:21 +0000189 // Force clear unused bits
blueswir19a87ce92007-11-17 21:01:04 +0000190 val &= MASTER_IRQ_MASK;
blueswir1f930d072007-10-06 11:28:21 +0000191 s->intregm_disabled |= val;
192 s->intregm_pending &= ~val;
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000193 slavio_check_interrupts(s, 1);
blueswir177f193d2008-05-12 16:13:33 +0000194 DPRINTF("Disabled master irq mask %x, curmask %x\n", val,
195 s->intregm_disabled);
blueswir1f930d072007-10-06 11:28:21 +0000196 break;
bellarde80cfcf2004-12-19 23:18:01 +0000197 case 4:
blueswir1f930d072007-10-06 11:28:21 +0000198 s->target_cpu = val & (MAX_CPUS - 1);
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000199 slavio_check_interrupts(s, 1);
blueswir1f930d072007-10-06 11:28:21 +0000200 DPRINTF("Set master irq cpu %d\n", s->target_cpu);
201 break;
bellarde80cfcf2004-12-19 23:18:01 +0000202 default:
blueswir1f930d072007-10-06 11:28:21 +0000203 break;
bellarde80cfcf2004-12-19 23:18:01 +0000204 }
205}
206
Blue Swirld60efc62009-08-25 18:29:31 +0000207static CPUReadMemoryFunc * const slavio_intctlm_mem_read[3] = {
blueswir17c560452008-01-01 17:06:38 +0000208 NULL,
209 NULL,
bellarde80cfcf2004-12-19 23:18:01 +0000210 slavio_intctlm_mem_readl,
211};
212
Blue Swirld60efc62009-08-25 18:29:31 +0000213static CPUWriteMemoryFunc * const slavio_intctlm_mem_write[3] = {
blueswir17c560452008-01-01 17:06:38 +0000214 NULL,
215 NULL,
bellarde80cfcf2004-12-19 23:18:01 +0000216 slavio_intctlm_mem_writel,
217};
218
Blue Swirld453c2c2009-08-23 12:23:30 +0000219void slavio_pic_info(Monitor *mon, DeviceState *dev)
bellarde80cfcf2004-12-19 23:18:01 +0000220{
Blue Swirld453c2c2009-08-23 12:23:30 +0000221 SysBusDevice *sd;
222 SLAVIO_INTCTLState *s;
bellarde80cfcf2004-12-19 23:18:01 +0000223 int i;
224
Blue Swirld453c2c2009-08-23 12:23:30 +0000225 sd = sysbus_from_qdev(dev);
226 s = FROM_SYSBUS(SLAVIO_INTCTLState, sd);
bellarde80cfcf2004-12-19 23:18:01 +0000227 for (i = 0; i < MAX_CPUS; i++) {
aliguori376253e2009-03-05 23:01:23 +0000228 monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
Blue Swirla1961a42009-07-16 14:15:34 +0000229 s->slaves[i].intreg_pending);
bellarde80cfcf2004-12-19 23:18:01 +0000230 }
aliguori376253e2009-03-05 23:01:23 +0000231 monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
232 s->intregm_pending, s->intregm_disabled);
bellarde80cfcf2004-12-19 23:18:01 +0000233}
234
Blue Swirld453c2c2009-08-23 12:23:30 +0000235void slavio_irq_info(Monitor *mon, DeviceState *dev)
bellarde80cfcf2004-12-19 23:18:01 +0000236{
237#ifndef DEBUG_IRQ_COUNT
aliguori376253e2009-03-05 23:01:23 +0000238 monitor_printf(mon, "irq statistic code not compiled.\n");
bellarde80cfcf2004-12-19 23:18:01 +0000239#else
Blue Swirld453c2c2009-08-23 12:23:30 +0000240 SysBusDevice *sd;
241 SLAVIO_INTCTLState *s;
bellarde80cfcf2004-12-19 23:18:01 +0000242 int i;
243 int64_t count;
244
Blue Swirld453c2c2009-08-23 12:23:30 +0000245 sd = sysbus_from_qdev(dev);
246 s = FROM_SYSBUS(SLAVIO_INTCTLState, sd);
aliguori376253e2009-03-05 23:01:23 +0000247 monitor_printf(mon, "IRQ statistics:\n");
bellarde80cfcf2004-12-19 23:18:01 +0000248 for (i = 0; i < 32; i++) {
249 count = s->irq_count[i];
250 if (count > 0)
aliguori376253e2009-03-05 23:01:23 +0000251 monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
bellarde80cfcf2004-12-19 23:18:01 +0000252 }
253#endif
254}
255
Blue Swirl68556e22009-08-08 20:36:08 +0000256static const uint32_t intbit_to_level[] = {
Blue Swirl462eda22009-08-25 18:29:36 +0000257 2, 3, 5, 7, 9, 11, 13, 2, 3, 5, 7, 9, 11, 13, 12, 12,
258 6, 13, 4, 10, 8, 9, 11, 0, 0, 0, 0, 15, 15, 15, 15, 0,
Blue Swirl68556e22009-08-08 20:36:08 +0000259};
260
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000261static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
bellard66321a12005-04-06 20:47:48 +0000262{
blueswir1327ac2e2007-08-04 10:50:30 +0000263 uint32_t pending = s->intregm_pending, pil_pending;
264 unsigned int i, j;
bellard66321a12005-04-06 20:47:48 +0000265
266 pending &= ~s->intregm_disabled;
267
blueswir1b3a23192007-05-27 16:42:29 +0000268 DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled);
bellardba3c64f2005-12-05 20:31:52 +0000269 for (i = 0; i < MAX_CPUS; i++) {
blueswir1327ac2e2007-08-04 10:50:30 +0000270 pil_pending = 0;
Blue Swirl462eda22009-08-25 18:29:36 +0000271
272 /* If we are the current interrupt target, get hard interrupts */
blueswir19a87ce92007-11-17 21:01:04 +0000273 if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
blueswir1b3a23192007-05-27 16:42:29 +0000274 (i == s->target_cpu)) {
275 for (j = 0; j < 32; j++) {
Blue Swirl462eda22009-08-25 18:29:36 +0000276 if ((pending & (1 << j)) && intbit_to_level[j]) {
Blue Swirl68556e22009-08-08 20:36:08 +0000277 pil_pending |= 1 << intbit_to_level[j];
Blue Swirl462eda22009-08-25 18:29:36 +0000278 }
blueswir1b3a23192007-05-27 16:42:29 +0000279 }
280 }
Blue Swirl462eda22009-08-25 18:29:36 +0000281
282 /* Calculate current pending hard interrupts for display */
283 s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
284 CPU_IRQ_TIMER_IN;
285 if (i == s->target_cpu) {
286 for (j = 0; j < 32; j++) {
287 if ((s->intregm_pending & (1 << j)) && intbit_to_level[j]) {
288 s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
289 }
290 }
291 }
292
293 /* Level 15 and CPU timer interrupts are not maskable */
294 pil_pending |= s->slaves[i].intreg_pending &
295 (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
296
297 /* Add soft interrupts */
Blue Swirla1961a42009-07-16 14:15:34 +0000298 pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
blueswir1327ac2e2007-08-04 10:50:30 +0000299
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000300 if (set_irqs) {
Blue Swirl462eda22009-08-25 18:29:36 +0000301 for (j = MAX_PILS; j > 0; j--) {
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000302 if (pil_pending & (1 << j)) {
Blue Swirl462eda22009-08-25 18:29:36 +0000303 if (!(s->slaves[i].irl_out & (1 << j))) {
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000304 qemu_irq_raise(s->cpu_irqs[i][j]);
305 }
306 } else {
Blue Swirl462eda22009-08-25 18:29:36 +0000307 if (s->slaves[i].irl_out & (1 << j)) {
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000308 qemu_irq_lower(s->cpu_irqs[i][j]);
309 }
310 }
bellardba3c64f2005-12-05 20:31:52 +0000311 }
312 }
Blue Swirl462eda22009-08-25 18:29:36 +0000313 s->slaves[i].irl_out = pil_pending;
bellardba3c64f2005-12-05 20:31:52 +0000314 }
bellard66321a12005-04-06 20:47:48 +0000315}
316
bellarde80cfcf2004-12-19 23:18:01 +0000317/*
318 * "irq" here is the bit number in the system interrupt register to
319 * separate serial and keyboard interrupts sharing a level.
320 */
blueswir1d7edfd22007-05-27 16:37:49 +0000321static void slavio_set_irq(void *opaque, int irq, int level)
bellarde80cfcf2004-12-19 23:18:01 +0000322{
323 SLAVIO_INTCTLState *s = opaque;
blueswir1b3a23192007-05-27 16:42:29 +0000324 uint32_t mask = 1 << irq;
Blue Swirl68556e22009-08-08 20:36:08 +0000325 uint32_t pil = intbit_to_level[irq];
Blue Swirl462eda22009-08-25 18:29:36 +0000326 unsigned int i;
bellarde80cfcf2004-12-19 23:18:01 +0000327
blueswir1b3a23192007-05-27 16:42:29 +0000328 DPRINTF("Set cpu %d irq %d -> pil %d level %d\n", s->target_cpu, irq, pil,
329 level);
330 if (pil > 0) {
331 if (level) {
blueswir1327ac2e2007-08-04 10:50:30 +0000332#ifdef DEBUG_IRQ_COUNT
333 s->irq_count[pil]++;
334#endif
blueswir1b3a23192007-05-27 16:42:29 +0000335 s->intregm_pending |= mask;
Blue Swirl462eda22009-08-25 18:29:36 +0000336 if (pil == 15) {
337 for (i = 0; i < MAX_CPUS; i++) {
338 s->slaves[i].intreg_pending |= 1 << pil;
339 }
340 }
blueswir1b3a23192007-05-27 16:42:29 +0000341 } else {
342 s->intregm_pending &= ~mask;
Blue Swirl462eda22009-08-25 18:29:36 +0000343 if (pil == 15) {
344 for (i = 0; i < MAX_CPUS; i++) {
345 s->slaves[i].intreg_pending &= ~(1 << pil);
346 }
347 }
blueswir1b3a23192007-05-27 16:42:29 +0000348 }
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000349 slavio_check_interrupts(s, 1);
bellarde80cfcf2004-12-19 23:18:01 +0000350 }
351}
352
blueswir1d7edfd22007-05-27 16:37:49 +0000353static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
bellardba3c64f2005-12-05 20:31:52 +0000354{
355 SLAVIO_INTCTLState *s = opaque;
356
blueswir1b3a23192007-05-27 16:42:29 +0000357 DPRINTF("Set cpu %d local timer level %d\n", cpu, level);
blueswir1d7edfd22007-05-27 16:37:49 +0000358
blueswir1e3a79bc2008-01-01 20:57:25 +0000359 if (level) {
Blue Swirl462eda22009-08-25 18:29:36 +0000360 s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
blueswir1e3a79bc2008-01-01 20:57:25 +0000361 } else {
Blue Swirl462eda22009-08-25 18:29:36 +0000362 s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
blueswir1e3a79bc2008-01-01 20:57:25 +0000363 }
blueswir1d7edfd22007-05-27 16:37:49 +0000364
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000365 slavio_check_interrupts(s, 1);
bellardba3c64f2005-12-05 20:31:52 +0000366}
367
Blue Swirla1961a42009-07-16 14:15:34 +0000368static void slavio_set_irq_all(void *opaque, int irq, int level)
369{
370 if (irq < 32) {
371 slavio_set_irq(opaque, irq, level);
372 } else {
373 slavio_set_timer_irq_cpu(opaque, irq - 32, level);
374 }
375}
376
Blue Swirlc9e95022009-08-28 20:22:52 +0000377static int vmstate_intctl_after_load(void *opaque)
bellarde80cfcf2004-12-19 23:18:01 +0000378{
379 SLAVIO_INTCTLState *s = opaque;
ths3b46e622007-09-17 08:09:54 +0000380
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000381 slavio_check_interrupts(s, 0);
bellarde80cfcf2004-12-19 23:18:01 +0000382 return 0;
383}
384
Blue Swirlc9e95022009-08-28 20:22:52 +0000385static const VMStateDescription vmstate_intctl_cpu = {
386 .name ="slavio_intctl_cpu",
387 .version_id = 1,
388 .minimum_version_id = 1,
389 .minimum_version_id_old = 1,
390 .fields = (VMStateField []) {
391 VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
392 VMSTATE_END_OF_LIST()
393 }
394};
395
396static const VMStateDescription vmstate_intctl = {
397 .name ="slavio_intctl",
398 .version_id = 1,
399 .minimum_version_id = 1,
400 .minimum_version_id_old = 1,
401 .run_after_load = vmstate_intctl_after_load,
402 .fields = (VMStateField []) {
403 VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
404 vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
405 VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
406 VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
407 VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
408 VMSTATE_END_OF_LIST()
409 }
410};
411
bellarde80cfcf2004-12-19 23:18:01 +0000412static void slavio_intctl_reset(void *opaque)
413{
414 SLAVIO_INTCTLState *s = opaque;
415 int i;
416
417 for (i = 0; i < MAX_CPUS; i++) {
Blue Swirla1961a42009-07-16 14:15:34 +0000418 s->slaves[i].intreg_pending = 0;
Blue Swirl462eda22009-08-25 18:29:36 +0000419 s->slaves[i].irl_out = 0;
bellarde80cfcf2004-12-19 23:18:01 +0000420 }
blueswir19a87ce92007-11-17 21:01:04 +0000421 s->intregm_disabled = ~MASTER_IRQ_MASK;
bellarde80cfcf2004-12-19 23:18:01 +0000422 s->intregm_pending = 0;
423 s->target_cpu = 0;
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000424 slavio_check_interrupts(s, 0);
bellarde80cfcf2004-12-19 23:18:01 +0000425}
426
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200427static int slavio_intctl_init1(SysBusDevice *dev)
bellarde80cfcf2004-12-19 23:18:01 +0000428{
Blue Swirla1961a42009-07-16 14:15:34 +0000429 SLAVIO_INTCTLState *s = FROM_SYSBUS(SLAVIO_INTCTLState, dev);
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200430 int io_memory;
Blue Swirla1961a42009-07-16 14:15:34 +0000431 unsigned int i, j;
bellarde80cfcf2004-12-19 23:18:01 +0000432
Blue Swirla1961a42009-07-16 14:15:34 +0000433 qdev_init_gpio_in(&dev->qdev, slavio_set_irq_all, 32 + MAX_CPUS);
434 io_memory = cpu_register_io_memory(slavio_intctlm_mem_read,
435 slavio_intctlm_mem_write, s);
436 sysbus_init_mmio(dev, INTCTLM_SIZE, io_memory);
bellarde80cfcf2004-12-19 23:18:01 +0000437
bellarde80cfcf2004-12-19 23:18:01 +0000438 for (i = 0; i < MAX_CPUS; i++) {
Blue Swirla1961a42009-07-16 14:15:34 +0000439 for (j = 0; j < MAX_PILS; j++) {
440 sysbus_init_irq(dev, &s->cpu_irqs[i][j]);
441 }
442 io_memory = cpu_register_io_memory(slavio_intctl_mem_read,
443 slavio_intctl_mem_write,
444 &s->slaves[i]);
445 sysbus_init_mmio(dev, INTCTL_SIZE, io_memory);
446 s->slaves[i].cpu = i;
447 s->slaves[i].master = s;
bellarde80cfcf2004-12-19 23:18:01 +0000448 }
Blue Swirlc9e95022009-08-28 20:22:52 +0000449 vmstate_register(-1, &vmstate_intctl, s);
Jan Kiszkaa08d4362009-06-27 09:25:07 +0200450 qemu_register_reset(slavio_intctl_reset, s);
bellarde80cfcf2004-12-19 23:18:01 +0000451 slavio_intctl_reset(s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200452 return 0;
bellarde80cfcf2004-12-19 23:18:01 +0000453}
Blue Swirla1961a42009-07-16 14:15:34 +0000454
Blue Swirla1961a42009-07-16 14:15:34 +0000455static SysBusDeviceInfo slavio_intctl_info = {
456 .init = slavio_intctl_init1,
457 .qdev.name = "slavio_intctl",
458 .qdev.size = sizeof(SLAVIO_INTCTLState),
Blue Swirla1961a42009-07-16 14:15:34 +0000459};
460
461static void slavio_intctl_register_devices(void)
462{
463 sysbus_register_withprop(&slavio_intctl_info);
464}
465
466device_init(slavio_intctl_register_devices)