blob: e82e89362863636bc31d7a34147688edee698a84 [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
Peter Maydell90191d02016-01-26 18:17:19 +000025#include "qemu/osdep.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010026#include "hw/sparc/sun4m.h"
Paolo Bonzini83c90892012-12-17 18:19:49 +010027#include "monitor/monitor.h"
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010028#include "hw/sysbus.h"
Blue Swirl97bf4852010-10-31 09:24:14 +000029#include "trace.h"
pbrook87ecb682007-11-17 17:14:51 +000030
bellarde80cfcf2004-12-19 23:18:01 +000031//#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.
ths5fafdf22007-09-16 21:08:06 +000041 *
bellarde80cfcf2004-12-19 23:18:01 +000042 */
43
44#define MAX_CPUS 16
blueswir1b3a23192007-05-27 16:42:29 +000045#define MAX_PILS 16
bellarde80cfcf2004-12-19 23:18:01 +000046
Blue Swirla1961a42009-07-16 14:15:34 +000047struct SLAVIO_INTCTLState;
48
49typedef struct SLAVIO_CPUINTCTLState {
Benoît Canet8bb5ef32011-11-15 12:14:00 +010050 MemoryRegion iomem;
Blue Swirla1961a42009-07-16 14:15:34 +000051 struct SLAVIO_INTCTLState *master;
Blue Swirl07dd0032011-08-07 19:06:26 +000052 uint32_t intreg_pending;
Blue Swirla1961a42009-07-16 14:15:34 +000053 uint32_t cpu;
Blue Swirl462eda22009-08-25 18:29:36 +000054 uint32_t irl_out;
Blue Swirla1961a42009-07-16 14:15:34 +000055} SLAVIO_CPUINTCTLState;
blueswir1a8f48dc2008-12-02 17:51:19 +000056
Andreas Färber7abad862013-07-26 20:40:40 +020057#define TYPE_SLAVIO_INTCTL "slavio_intctl"
58#define SLAVIO_INTCTL(obj) \
59 OBJECT_CHECK(SLAVIO_INTCTLState, (obj), TYPE_SLAVIO_INTCTL)
60
bellarde80cfcf2004-12-19 23:18:01 +000061typedef struct SLAVIO_INTCTLState {
Andreas Färber7abad862013-07-26 20:40:40 +020062 SysBusDevice parent_obj;
63
Benoît Canet13c89a12011-11-15 12:13:59 +010064 MemoryRegion iomem;
bellarde80cfcf2004-12-19 23:18:01 +000065#ifdef DEBUG_IRQ_COUNT
66 uint64_t irq_count[32];
67#endif
Blue Swirla1961a42009-07-16 14:15:34 +000068 qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
Blue Swirla1961a42009-07-16 14:15:34 +000069 SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
Blue Swirl07dd0032011-08-07 19:06:26 +000070 uint32_t intregm_pending;
71 uint32_t intregm_disabled;
72 uint32_t target_cpu;
bellarde80cfcf2004-12-19 23:18:01 +000073} SLAVIO_INTCTLState;
74
75#define INTCTL_MAXADDR 0xf
blueswir15aca8c32007-05-26 17:39:43 +000076#define INTCTL_SIZE (INTCTL_MAXADDR + 1)
blueswir1a8f48dc2008-12-02 17:51:19 +000077#define INTCTLM_SIZE 0x14
blueswir180be36b2007-12-28 18:48:39 +000078#define MASTER_IRQ_MASK ~0x0fa2007f
blueswir19a87ce92007-11-17 21:01:04 +000079#define MASTER_DISABLE 0x80000000
blueswir16341fdc2007-12-29 20:09:57 +000080#define CPU_SOFTIRQ_MASK 0xfffe0000
Blue Swirl462eda22009-08-25 18:29:36 +000081#define CPU_IRQ_INT15_IN (1 << 15)
82#define CPU_IRQ_TIMER_IN (1 << 14)
blueswir19a87ce92007-11-17 21:01:04 +000083
Blue Swirl0d0a7e62009-06-17 17:20:01 +000084static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
bellarde80cfcf2004-12-19 23:18:01 +000085
86// per-cpu interrupt controller
Avi Kivitya8170e52012-10-23 12:30:10 +020087static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr,
Benoît Canet8bb5ef32011-11-15 12:14:00 +010088 unsigned size)
bellarde80cfcf2004-12-19 23:18:01 +000089{
blueswir1a8f48dc2008-12-02 17:51:19 +000090 SLAVIO_CPUINTCTLState *s = opaque;
blueswir1dd4131b2007-05-27 19:42:35 +000091 uint32_t saddr, ret;
bellarde80cfcf2004-12-19 23:18:01 +000092
blueswir1a8f48dc2008-12-02 17:51:19 +000093 saddr = addr >> 2;
bellarde80cfcf2004-12-19 23:18:01 +000094 switch (saddr) {
95 case 0:
blueswir1a8f48dc2008-12-02 17:51:19 +000096 ret = s->intreg_pending;
blueswir1dd4131b2007-05-27 19:42:35 +000097 break;
bellarde80cfcf2004-12-19 23:18:01 +000098 default:
blueswir1dd4131b2007-05-27 19:42:35 +000099 ret = 0;
100 break;
bellarde80cfcf2004-12-19 23:18:01 +0000101 }
Blue Swirl97bf4852010-10-31 09:24:14 +0000102 trace_slavio_intctl_mem_readl(s->cpu, addr, ret);
blueswir1dd4131b2007-05-27 19:42:35 +0000103
104 return ret;
bellarde80cfcf2004-12-19 23:18:01 +0000105}
106
Avi Kivitya8170e52012-10-23 12:30:10 +0200107static void slavio_intctl_mem_writel(void *opaque, hwaddr addr,
Benoît Canet8bb5ef32011-11-15 12:14:00 +0100108 uint64_t val, unsigned size)
bellarde80cfcf2004-12-19 23:18:01 +0000109{
blueswir1a8f48dc2008-12-02 17:51:19 +0000110 SLAVIO_CPUINTCTLState *s = opaque;
bellarde80cfcf2004-12-19 23:18:01 +0000111 uint32_t saddr;
bellarde80cfcf2004-12-19 23:18:01 +0000112
blueswir1a8f48dc2008-12-02 17:51:19 +0000113 saddr = addr >> 2;
Blue Swirl97bf4852010-10-31 09:24:14 +0000114 trace_slavio_intctl_mem_writel(s->cpu, addr, val);
bellarde80cfcf2004-12-19 23:18:01 +0000115 switch (saddr) {
116 case 1: // clear pending softints
Blue Swirl462eda22009-08-25 18:29:36 +0000117 val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
blueswir1a8f48dc2008-12-02 17:51:19 +0000118 s->intreg_pending &= ~val;
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000119 slavio_check_interrupts(s->master, 1);
Blue Swirl97bf4852010-10-31 09:24:14 +0000120 trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending);
blueswir1f930d072007-10-06 11:28:21 +0000121 break;
bellarde80cfcf2004-12-19 23:18:01 +0000122 case 2: // set softint
blueswir16341fdc2007-12-29 20:09:57 +0000123 val &= CPU_SOFTIRQ_MASK;
blueswir1a8f48dc2008-12-02 17:51:19 +0000124 s->intreg_pending |= val;
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000125 slavio_check_interrupts(s->master, 1);
Blue Swirl97bf4852010-10-31 09:24:14 +0000126 trace_slavio_intctl_mem_writel_set(s->cpu, val, 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
Benoît Canet8bb5ef32011-11-15 12:14:00 +0100133static 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 },
bellarde80cfcf2004-12-19 23:18:01 +0000141};
142
143// master system interrupt controller
Avi Kivitya8170e52012-10-23 12:30:10 +0200144static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr,
Benoît Canet13c89a12011-11-15 12:13:59 +0100145 unsigned size)
bellarde80cfcf2004-12-19 23:18:01 +0000146{
147 SLAVIO_INTCTLState *s = opaque;
blueswir1dd4131b2007-05-27 19:42:35 +0000148 uint32_t saddr, ret;
bellarde80cfcf2004-12-19 23:18:01 +0000149
blueswir1a8f48dc2008-12-02 17:51:19 +0000150 saddr = addr >> 2;
bellarde80cfcf2004-12-19 23:18:01 +0000151 switch (saddr) {
152 case 0:
blueswir19a87ce92007-11-17 21:01:04 +0000153 ret = s->intregm_pending & ~MASTER_DISABLE;
blueswir1dd4131b2007-05-27 19:42:35 +0000154 break;
bellarde80cfcf2004-12-19 23:18:01 +0000155 case 1:
blueswir180be36b2007-12-28 18:48:39 +0000156 ret = s->intregm_disabled & MASTER_IRQ_MASK;
blueswir1dd4131b2007-05-27 19:42:35 +0000157 break;
bellarde80cfcf2004-12-19 23:18:01 +0000158 case 4:
blueswir1dd4131b2007-05-27 19:42:35 +0000159 ret = s->target_cpu;
160 break;
bellarde80cfcf2004-12-19 23:18:01 +0000161 default:
blueswir1dd4131b2007-05-27 19:42:35 +0000162 ret = 0;
163 break;
bellarde80cfcf2004-12-19 23:18:01 +0000164 }
Blue Swirl97bf4852010-10-31 09:24:14 +0000165 trace_slavio_intctlm_mem_readl(addr, ret);
blueswir1dd4131b2007-05-27 19:42:35 +0000166
167 return ret;
bellarde80cfcf2004-12-19 23:18:01 +0000168}
169
Avi Kivitya8170e52012-10-23 12:30:10 +0200170static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr,
Benoît Canet13c89a12011-11-15 12:13:59 +0100171 uint64_t val, unsigned size)
bellarde80cfcf2004-12-19 23:18:01 +0000172{
173 SLAVIO_INTCTLState *s = opaque;
174 uint32_t saddr;
175
blueswir1a8f48dc2008-12-02 17:51:19 +0000176 saddr = addr >> 2;
Blue Swirl97bf4852010-10-31 09:24:14 +0000177 trace_slavio_intctlm_mem_writel(addr, val);
bellarde80cfcf2004-12-19 23:18:01 +0000178 switch (saddr) {
179 case 2: // clear (enable)
blueswir1f930d072007-10-06 11:28:21 +0000180 // Force clear unused bits
blueswir19a87ce92007-11-17 21:01:04 +0000181 val &= MASTER_IRQ_MASK;
blueswir1f930d072007-10-06 11:28:21 +0000182 s->intregm_disabled &= ~val;
Blue Swirl97bf4852010-10-31 09:24:14 +0000183 trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled);
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000184 slavio_check_interrupts(s, 1);
blueswir1f930d072007-10-06 11:28:21 +0000185 break;
Artyom Tarasenko10760f02010-01-16 09:06:32 +0000186 case 3: // set (disable; doesn't affect pending)
blueswir1f930d072007-10-06 11:28:21 +0000187 // Force clear unused bits
blueswir19a87ce92007-11-17 21:01:04 +0000188 val &= MASTER_IRQ_MASK;
blueswir1f930d072007-10-06 11:28:21 +0000189 s->intregm_disabled |= val;
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000190 slavio_check_interrupts(s, 1);
Blue Swirl97bf4852010-10-31 09:24:14 +0000191 trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled);
blueswir1f930d072007-10-06 11:28:21 +0000192 break;
bellarde80cfcf2004-12-19 23:18:01 +0000193 case 4:
blueswir1f930d072007-10-06 11:28:21 +0000194 s->target_cpu = val & (MAX_CPUS - 1);
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000195 slavio_check_interrupts(s, 1);
Blue Swirl97bf4852010-10-31 09:24:14 +0000196 trace_slavio_intctlm_mem_writel_target(s->target_cpu);
blueswir1f930d072007-10-06 11:28:21 +0000197 break;
bellarde80cfcf2004-12-19 23:18:01 +0000198 default:
blueswir1f930d072007-10-06 11:28:21 +0000199 break;
bellarde80cfcf2004-12-19 23:18:01 +0000200 }
201}
202
Benoît Canet13c89a12011-11-15 12:13:59 +0100203static 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 },
bellarde80cfcf2004-12-19 23:18:01 +0000211};
212
Blue Swirld453c2c2009-08-23 12:23:30 +0000213void slavio_pic_info(Monitor *mon, DeviceState *dev)
bellarde80cfcf2004-12-19 23:18:01 +0000214{
Andreas Färber7abad862013-07-26 20:40:40 +0200215 SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
bellarde80cfcf2004-12-19 23:18:01 +0000216 int i;
217
218 for (i = 0; i < MAX_CPUS; i++) {
aliguori376253e2009-03-05 23:01:23 +0000219 monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
Blue Swirla1961a42009-07-16 14:15:34 +0000220 s->slaves[i].intreg_pending);
bellarde80cfcf2004-12-19 23:18:01 +0000221 }
aliguori376253e2009-03-05 23:01:23 +0000222 monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
223 s->intregm_pending, s->intregm_disabled);
bellarde80cfcf2004-12-19 23:18:01 +0000224}
225
Blue Swirld453c2c2009-08-23 12:23:30 +0000226void slavio_irq_info(Monitor *mon, DeviceState *dev)
bellarde80cfcf2004-12-19 23:18:01 +0000227{
228#ifndef DEBUG_IRQ_COUNT
aliguori376253e2009-03-05 23:01:23 +0000229 monitor_printf(mon, "irq statistic code not compiled.\n");
bellarde80cfcf2004-12-19 23:18:01 +0000230#else
Andreas Färber7abad862013-07-26 20:40:40 +0200231 SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
bellarde80cfcf2004-12-19 23:18:01 +0000232 int i;
233 int64_t count;
234
Andreas Färber7abad862013-07-26 20:40:40 +0200235 s = SLAVIO_INTCTL(dev);
aliguori376253e2009-03-05 23:01:23 +0000236 monitor_printf(mon, "IRQ statistics:\n");
bellarde80cfcf2004-12-19 23:18:01 +0000237 for (i = 0; i < 32; i++) {
238 count = s->irq_count[i];
239 if (count > 0)
aliguori376253e2009-03-05 23:01:23 +0000240 monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
bellarde80cfcf2004-12-19 23:18:01 +0000241 }
242#endif
243}
244
Blue Swirl68556e22009-08-08 20:36:08 +0000245static const uint32_t intbit_to_level[] = {
Blue Swirl462eda22009-08-25 18:29:36 +0000246 2, 3, 5, 7, 9, 11, 13, 2, 3, 5, 7, 9, 11, 13, 12, 12,
247 6, 13, 4, 10, 8, 9, 11, 0, 0, 0, 0, 15, 15, 15, 15, 0,
Blue Swirl68556e22009-08-08 20:36:08 +0000248};
249
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000250static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
bellard66321a12005-04-06 20:47:48 +0000251{
blueswir1327ac2e2007-08-04 10:50:30 +0000252 uint32_t pending = s->intregm_pending, pil_pending;
253 unsigned int i, j;
bellard66321a12005-04-06 20:47:48 +0000254
255 pending &= ~s->intregm_disabled;
256
Blue Swirl97bf4852010-10-31 09:24:14 +0000257 trace_slavio_check_interrupts(pending, s->intregm_disabled);
bellardba3c64f2005-12-05 20:31:52 +0000258 for (i = 0; i < MAX_CPUS; i++) {
blueswir1327ac2e2007-08-04 10:50:30 +0000259 pil_pending = 0;
Blue Swirl462eda22009-08-25 18:29:36 +0000260
261 /* If we are the current interrupt target, get hard interrupts */
blueswir19a87ce92007-11-17 21:01:04 +0000262 if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
blueswir1b3a23192007-05-27 16:42:29 +0000263 (i == s->target_cpu)) {
264 for (j = 0; j < 32; j++) {
Blue Swirl462eda22009-08-25 18:29:36 +0000265 if ((pending & (1 << j)) && intbit_to_level[j]) {
Blue Swirl68556e22009-08-08 20:36:08 +0000266 pil_pending |= 1 << intbit_to_level[j];
Blue Swirl462eda22009-08-25 18:29:36 +0000267 }
blueswir1b3a23192007-05-27 16:42:29 +0000268 }
269 }
Blue Swirl462eda22009-08-25 18:29:36 +0000270
271 /* Calculate current pending hard interrupts for display */
272 s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
273 CPU_IRQ_TIMER_IN;
274 if (i == s->target_cpu) {
275 for (j = 0; j < 32; j++) {
Peter Maydell7d45e782014-03-17 16:00:39 +0000276 if ((s->intregm_pending & (1U << j)) && intbit_to_level[j]) {
Blue Swirl462eda22009-08-25 18:29:36 +0000277 s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
278 }
279 }
280 }
281
Artyom Tarasenko94c5f452010-06-21 20:23:21 +0200282 /* Level 15 and CPU timer interrupts are only masked when
283 the MASTER_DISABLE bit is set */
284 if (!(s->intregm_disabled & MASTER_DISABLE)) {
285 pil_pending |= s->slaves[i].intreg_pending &
286 (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
287 }
Blue Swirl462eda22009-08-25 18:29:36 +0000288
289 /* Add soft interrupts */
Blue Swirla1961a42009-07-16 14:15:34 +0000290 pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
blueswir1327ac2e2007-08-04 10:50:30 +0000291
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000292 if (set_irqs) {
Peter Maydellc84a88d2011-01-31 10:42:26 +0000293 /* Since there is not really an interrupt 0 (and pil_pending
294 * and irl_out bit zero are thus always zero) there is no need
295 * to do anything with cpu_irqs[i][0] and it is OK not to do
296 * the j=0 iteration of this loop.
297 */
298 for (j = MAX_PILS-1; j > 0; j--) {
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000299 if (pil_pending & (1 << j)) {
Blue Swirl462eda22009-08-25 18:29:36 +0000300 if (!(s->slaves[i].irl_out & (1 << j))) {
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000301 qemu_irq_raise(s->cpu_irqs[i][j]);
302 }
303 } else {
Blue Swirl462eda22009-08-25 18:29:36 +0000304 if (s->slaves[i].irl_out & (1 << j)) {
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000305 qemu_irq_lower(s->cpu_irqs[i][j]);
306 }
307 }
bellardba3c64f2005-12-05 20:31:52 +0000308 }
309 }
Blue Swirl462eda22009-08-25 18:29:36 +0000310 s->slaves[i].irl_out = pil_pending;
bellardba3c64f2005-12-05 20:31:52 +0000311 }
bellard66321a12005-04-06 20:47:48 +0000312}
313
bellarde80cfcf2004-12-19 23:18:01 +0000314/*
315 * "irq" here is the bit number in the system interrupt register to
316 * separate serial and keyboard interrupts sharing a level.
317 */
blueswir1d7edfd22007-05-27 16:37:49 +0000318static void slavio_set_irq(void *opaque, int irq, int level)
bellarde80cfcf2004-12-19 23:18:01 +0000319{
320 SLAVIO_INTCTLState *s = opaque;
blueswir1b3a23192007-05-27 16:42:29 +0000321 uint32_t mask = 1 << irq;
Blue Swirl68556e22009-08-08 20:36:08 +0000322 uint32_t pil = intbit_to_level[irq];
Blue Swirl462eda22009-08-25 18:29:36 +0000323 unsigned int i;
bellarde80cfcf2004-12-19 23:18:01 +0000324
Blue Swirl97bf4852010-10-31 09:24:14 +0000325 trace_slavio_set_irq(s->target_cpu, irq, pil, level);
blueswir1b3a23192007-05-27 16:42:29 +0000326 if (pil > 0) {
327 if (level) {
blueswir1327ac2e2007-08-04 10:50:30 +0000328#ifdef DEBUG_IRQ_COUNT
329 s->irq_count[pil]++;
330#endif
blueswir1b3a23192007-05-27 16:42:29 +0000331 s->intregm_pending |= mask;
Blue Swirl462eda22009-08-25 18:29:36 +0000332 if (pil == 15) {
333 for (i = 0; i < MAX_CPUS; i++) {
334 s->slaves[i].intreg_pending |= 1 << pil;
335 }
336 }
blueswir1b3a23192007-05-27 16:42:29 +0000337 } else {
338 s->intregm_pending &= ~mask;
Blue Swirl462eda22009-08-25 18:29:36 +0000339 if (pil == 15) {
340 for (i = 0; i < MAX_CPUS; i++) {
341 s->slaves[i].intreg_pending &= ~(1 << pil);
342 }
343 }
blueswir1b3a23192007-05-27 16:42:29 +0000344 }
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000345 slavio_check_interrupts(s, 1);
bellarde80cfcf2004-12-19 23:18:01 +0000346 }
347}
348
blueswir1d7edfd22007-05-27 16:37:49 +0000349static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
bellardba3c64f2005-12-05 20:31:52 +0000350{
351 SLAVIO_INTCTLState *s = opaque;
352
Blue Swirl97bf4852010-10-31 09:24:14 +0000353 trace_slavio_set_timer_irq_cpu(cpu, level);
blueswir1d7edfd22007-05-27 16:37:49 +0000354
blueswir1e3a79bc2008-01-01 20:57:25 +0000355 if (level) {
Blue Swirl462eda22009-08-25 18:29:36 +0000356 s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
blueswir1e3a79bc2008-01-01 20:57:25 +0000357 } else {
Blue Swirl462eda22009-08-25 18:29:36 +0000358 s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
blueswir1e3a79bc2008-01-01 20:57:25 +0000359 }
blueswir1d7edfd22007-05-27 16:37:49 +0000360
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000361 slavio_check_interrupts(s, 1);
bellardba3c64f2005-12-05 20:31:52 +0000362}
363
Blue Swirla1961a42009-07-16 14:15:34 +0000364static void slavio_set_irq_all(void *opaque, int irq, int level)
365{
366 if (irq < 32) {
367 slavio_set_irq(opaque, irq, level);
368 } else {
369 slavio_set_timer_irq_cpu(opaque, irq - 32, level);
370 }
371}
372
Juan Quintelae59fb372009-09-29 22:48:21 +0200373static int vmstate_intctl_post_load(void *opaque, int version_id)
bellarde80cfcf2004-12-19 23:18:01 +0000374{
375 SLAVIO_INTCTLState *s = opaque;
ths3b46e622007-09-17 08:09:54 +0000376
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000377 slavio_check_interrupts(s, 0);
bellarde80cfcf2004-12-19 23:18:01 +0000378 return 0;
379}
380
Blue Swirlc9e95022009-08-28 20:22:52 +0000381static const VMStateDescription vmstate_intctl_cpu = {
382 .name ="slavio_intctl_cpu",
383 .version_id = 1,
384 .minimum_version_id = 1,
Juan Quintela35d08452014-04-16 16:01:33 +0200385 .fields = (VMStateField[]) {
Blue Swirlc9e95022009-08-28 20:22:52 +0000386 VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
387 VMSTATE_END_OF_LIST()
388 }
389};
390
391static const VMStateDescription vmstate_intctl = {
392 .name ="slavio_intctl",
393 .version_id = 1,
394 .minimum_version_id = 1,
Juan Quintela752ff2f2009-09-10 03:04:30 +0200395 .post_load = vmstate_intctl_post_load,
Juan Quintela35d08452014-04-16 16:01:33 +0200396 .fields = (VMStateField[]) {
Blue Swirlc9e95022009-08-28 20:22:52 +0000397 VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
398 vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
399 VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
400 VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
401 VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
402 VMSTATE_END_OF_LIST()
403 }
404};
405
Blue Swirl78971d52009-10-24 19:44:37 +0000406static void slavio_intctl_reset(DeviceState *d)
bellarde80cfcf2004-12-19 23:18:01 +0000407{
Andreas Färber7abad862013-07-26 20:40:40 +0200408 SLAVIO_INTCTLState *s = SLAVIO_INTCTL(d);
bellarde80cfcf2004-12-19 23:18:01 +0000409 int i;
410
411 for (i = 0; i < MAX_CPUS; i++) {
Blue Swirla1961a42009-07-16 14:15:34 +0000412 s->slaves[i].intreg_pending = 0;
Blue Swirl462eda22009-08-25 18:29:36 +0000413 s->slaves[i].irl_out = 0;
bellarde80cfcf2004-12-19 23:18:01 +0000414 }
blueswir19a87ce92007-11-17 21:01:04 +0000415 s->intregm_disabled = ~MASTER_IRQ_MASK;
bellarde80cfcf2004-12-19 23:18:01 +0000416 s->intregm_pending = 0;
417 s->target_cpu = 0;
Blue Swirl0d0a7e62009-06-17 17:20:01 +0000418 slavio_check_interrupts(s, 0);
bellarde80cfcf2004-12-19 23:18:01 +0000419}
420
xiaoqiang.zhaoc09008d2016-05-12 13:22:25 +0100421static void slavio_intctl_init(Object *obj)
bellarde80cfcf2004-12-19 23:18:01 +0000422{
xiaoqiang.zhaoc09008d2016-05-12 13:22:25 +0100423 DeviceState *dev = DEVICE(obj);
424 SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
425 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
Blue Swirla1961a42009-07-16 14:15:34 +0000426 unsigned int i, j;
Benoît Canet8bb5ef32011-11-15 12:14:00 +0100427 char slave_name[45];
bellarde80cfcf2004-12-19 23:18:01 +0000428
Andreas Färber7abad862013-07-26 20:40:40 +0200429 qdev_init_gpio_in(dev, slavio_set_irq_all, 32 + MAX_CPUS);
xiaoqiang.zhaoc09008d2016-05-12 13:22:25 +0100430 memory_region_init_io(&s->iomem, obj, &slavio_intctlm_mem_ops, s,
Benoît Canet13c89a12011-11-15 12:13:59 +0100431 "master-interrupt-controller", INTCTLM_SIZE);
Andreas Färber7abad862013-07-26 20:40:40 +0200432 sysbus_init_mmio(sbd, &s->iomem);
bellarde80cfcf2004-12-19 23:18:01 +0000433
bellarde80cfcf2004-12-19 23:18:01 +0000434 for (i = 0; i < MAX_CPUS; i++) {
Benoît Canet8bb5ef32011-11-15 12:14:00 +0100435 snprintf(slave_name, sizeof(slave_name),
436 "slave-interrupt-controller-%i", i);
Blue Swirla1961a42009-07-16 14:15:34 +0000437 for (j = 0; j < MAX_PILS; j++) {
Andreas Färber7abad862013-07-26 20:40:40 +0200438 sysbus_init_irq(sbd, &s->cpu_irqs[i][j]);
Blue Swirla1961a42009-07-16 14:15:34 +0000439 }
Paolo Bonzini1437c942013-06-06 21:25:08 -0400440 memory_region_init_io(&s->slaves[i].iomem, OBJECT(s),
441 &slavio_intctl_mem_ops,
Benoît Canet8bb5ef32011-11-15 12:14:00 +0100442 &s->slaves[i], slave_name, INTCTL_SIZE);
Andreas Färber7abad862013-07-26 20:40:40 +0200443 sysbus_init_mmio(sbd, &s->slaves[i].iomem);
Blue Swirla1961a42009-07-16 14:15:34 +0000444 s->slaves[i].cpu = i;
445 s->slaves[i].master = s;
bellarde80cfcf2004-12-19 23:18:01 +0000446 }
bellarde80cfcf2004-12-19 23:18:01 +0000447}
Blue Swirla1961a42009-07-16 14:15:34 +0000448
Anthony Liguori999e12b2012-01-24 13:12:29 -0600449static void slavio_intctl_class_init(ObjectClass *klass, void *data)
450{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600451 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori999e12b2012-01-24 13:12:29 -0600452
Anthony Liguori39bffca2011-12-07 21:34:16 -0600453 dc->reset = slavio_intctl_reset;
454 dc->vmsd = &vmstate_intctl;
Anthony Liguori999e12b2012-01-24 13:12:29 -0600455}
456
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100457static const TypeInfo slavio_intctl_info = {
Andreas Färber7abad862013-07-26 20:40:40 +0200458 .name = TYPE_SLAVIO_INTCTL,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600459 .parent = TYPE_SYS_BUS_DEVICE,
460 .instance_size = sizeof(SLAVIO_INTCTLState),
xiaoqiang.zhaoc09008d2016-05-12 13:22:25 +0100461 .instance_init = slavio_intctl_init,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600462 .class_init = slavio_intctl_class_init,
Blue Swirla1961a42009-07-16 14:15:34 +0000463};
464
Andreas Färber83f7d432012-02-09 15:20:55 +0100465static void slavio_intctl_register_types(void)
Blue Swirla1961a42009-07-16 14:15:34 +0000466{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600467 type_register_static(&slavio_intctl_info);
Blue Swirla1961a42009-07-16 14:15:34 +0000468}
469
Andreas Färber83f7d432012-02-09 15:20:55 +0100470type_init(slavio_intctl_register_types)