xref: /qemu/hw/intc/slavio_intctl.c (revision 90191d07a6c0480802dfcaee99328b1c5e520579)
1e80cfcfcSbellard /*
2e80cfcfcSbellard  * QEMU Sparc SLAVIO interrupt controller emulation
3e80cfcfcSbellard  *
466321a11Sbellard  * Copyright (c) 2003-2005 Fabrice Bellard
5e80cfcfcSbellard  *
6e80cfcfcSbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7e80cfcfcSbellard  * of this software and associated documentation files (the "Software"), to deal
8e80cfcfcSbellard  * in the Software without restriction, including without limitation the rights
9e80cfcfcSbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10e80cfcfcSbellard  * copies of the Software, and to permit persons to whom the Software is
11e80cfcfcSbellard  * furnished to do so, subject to the following conditions:
12e80cfcfcSbellard  *
13e80cfcfcSbellard  * The above copyright notice and this permission notice shall be included in
14e80cfcfcSbellard  * all copies or substantial portions of the Software.
15e80cfcfcSbellard  *
16e80cfcfcSbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17e80cfcfcSbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18e80cfcfcSbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19e80cfcfcSbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20e80cfcfcSbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21e80cfcfcSbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22e80cfcfcSbellard  * THE SOFTWARE.
23e80cfcfcSbellard  */
24a1961a4bSBlue Swirl 
25*90191d07SPeter Maydell #include "qemu/osdep.h"
260d09e41aSPaolo Bonzini #include "hw/sparc/sun4m.h"
2783c9089eSPaolo Bonzini #include "monitor/monitor.h"
2883c9f4caSPaolo Bonzini #include "hw/sysbus.h"
2997bf4851SBlue Swirl #include "trace.h"
3087ecb68bSpbrook 
31e80cfcfcSbellard //#define DEBUG_IRQ_COUNT
32e80cfcfcSbellard 
33e80cfcfcSbellard /*
34e80cfcfcSbellard  * Registers of interrupt controller in sun4m.
35e80cfcfcSbellard  *
36e80cfcfcSbellard  * This is the interrupt controller part of chip STP2001 (Slave I/O), also
37e80cfcfcSbellard  * produced as NCR89C105. See
38e80cfcfcSbellard  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
39e80cfcfcSbellard  *
40e80cfcfcSbellard  * There is a system master controller and one for each cpu.
41e80cfcfcSbellard  *
42e80cfcfcSbellard  */
43e80cfcfcSbellard 
44e80cfcfcSbellard #define MAX_CPUS 16
45b3a23197Sblueswir1 #define MAX_PILS 16
46e80cfcfcSbellard 
47a1961a4bSBlue Swirl struct SLAVIO_INTCTLState;
48a1961a4bSBlue Swirl 
49a1961a4bSBlue Swirl typedef struct SLAVIO_CPUINTCTLState {
508bb5ef33SBenoît Canet     MemoryRegion iomem;
51a1961a4bSBlue Swirl     struct SLAVIO_INTCTLState *master;
5207dd0035SBlue Swirl     uint32_t intreg_pending;
53a1961a4bSBlue Swirl     uint32_t cpu;
54462eda24SBlue Swirl     uint32_t irl_out;
55a1961a4bSBlue Swirl } SLAVIO_CPUINTCTLState;
56a8f48dccSblueswir1 
577abad863SAndreas Färber #define TYPE_SLAVIO_INTCTL "slavio_intctl"
587abad863SAndreas Färber #define SLAVIO_INTCTL(obj) \
597abad863SAndreas Färber     OBJECT_CHECK(SLAVIO_INTCTLState, (obj), TYPE_SLAVIO_INTCTL)
607abad863SAndreas Färber 
61e80cfcfcSbellard typedef struct SLAVIO_INTCTLState {
627abad863SAndreas Färber     SysBusDevice parent_obj;
637abad863SAndreas Färber 
6413c89a11SBenoît Canet     MemoryRegion iomem;
65e80cfcfcSbellard #ifdef DEBUG_IRQ_COUNT
66e80cfcfcSbellard     uint64_t irq_count[32];
67e80cfcfcSbellard #endif
68a1961a4bSBlue Swirl     qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
69a1961a4bSBlue Swirl     SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
7007dd0035SBlue Swirl     uint32_t intregm_pending;
7107dd0035SBlue Swirl     uint32_t intregm_disabled;
7207dd0035SBlue Swirl     uint32_t target_cpu;
73e80cfcfcSbellard } SLAVIO_INTCTLState;
74e80cfcfcSbellard 
75e80cfcfcSbellard #define INTCTL_MAXADDR 0xf
765aca8c3bSblueswir1 #define INTCTL_SIZE (INTCTL_MAXADDR + 1)
77a8f48dccSblueswir1 #define INTCTLM_SIZE 0x14
7880be36b8Sblueswir1 #define MASTER_IRQ_MASK ~0x0fa2007f
799a87ce9bSblueswir1 #define MASTER_DISABLE 0x80000000
806341fdcbSblueswir1 #define CPU_SOFTIRQ_MASK 0xfffe0000
81462eda24SBlue Swirl #define CPU_IRQ_INT15_IN (1 << 15)
82462eda24SBlue Swirl #define CPU_IRQ_TIMER_IN (1 << 14)
839a87ce9bSblueswir1 
840d0a7e69SBlue Swirl static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
85e80cfcfcSbellard 
86e80cfcfcSbellard // per-cpu interrupt controller
87a8170e5eSAvi Kivity static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr,
888bb5ef33SBenoît Canet                                         unsigned size)
89e80cfcfcSbellard {
90a8f48dccSblueswir1     SLAVIO_CPUINTCTLState *s = opaque;
91dd4131b3Sblueswir1     uint32_t saddr, ret;
92e80cfcfcSbellard 
93a8f48dccSblueswir1     saddr = addr >> 2;
94e80cfcfcSbellard     switch (saddr) {
95e80cfcfcSbellard     case 0:
96a8f48dccSblueswir1         ret = s->intreg_pending;
97dd4131b3Sblueswir1         break;
98e80cfcfcSbellard     default:
99dd4131b3Sblueswir1         ret = 0;
100e80cfcfcSbellard         break;
101e80cfcfcSbellard     }
10297bf4851SBlue Swirl     trace_slavio_intctl_mem_readl(s->cpu, addr, ret);
103dd4131b3Sblueswir1 
104dd4131b3Sblueswir1     return ret;
105e80cfcfcSbellard }
106e80cfcfcSbellard 
107a8170e5eSAvi Kivity static void slavio_intctl_mem_writel(void *opaque, hwaddr addr,
1088bb5ef33SBenoît Canet                                      uint64_t val, unsigned size)
109e80cfcfcSbellard {
110a8f48dccSblueswir1     SLAVIO_CPUINTCTLState *s = opaque;
111e80cfcfcSbellard     uint32_t saddr;
112e80cfcfcSbellard 
113a8f48dccSblueswir1     saddr = addr >> 2;
11497bf4851SBlue Swirl     trace_slavio_intctl_mem_writel(s->cpu, addr, val);
115e80cfcfcSbellard     switch (saddr) {
116e80cfcfcSbellard     case 1: // clear pending softints
117462eda24SBlue Swirl         val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
118a8f48dccSblueswir1         s->intreg_pending &= ~val;
1190d0a7e69SBlue Swirl         slavio_check_interrupts(s->master, 1);
12097bf4851SBlue Swirl         trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending);
121e80cfcfcSbellard         break;
122e80cfcfcSbellard     case 2: // set softint
1236341fdcbSblueswir1         val &= CPU_SOFTIRQ_MASK;
124a8f48dccSblueswir1         s->intreg_pending |= val;
1250d0a7e69SBlue Swirl         slavio_check_interrupts(s->master, 1);
12697bf4851SBlue Swirl         trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending);
127e80cfcfcSbellard         break;
128e80cfcfcSbellard     default:
129e80cfcfcSbellard         break;
130e80cfcfcSbellard     }
131e80cfcfcSbellard }
132e80cfcfcSbellard 
1338bb5ef33SBenoît Canet static const MemoryRegionOps slavio_intctl_mem_ops = {
1348bb5ef33SBenoît Canet     .read = slavio_intctl_mem_readl,
1358bb5ef33SBenoît Canet     .write = slavio_intctl_mem_writel,
1368bb5ef33SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
1378bb5ef33SBenoît Canet     .valid = {
1388bb5ef33SBenoît Canet         .min_access_size = 4,
1398bb5ef33SBenoît Canet         .max_access_size = 4,
1408bb5ef33SBenoît Canet     },
141e80cfcfcSbellard };
142e80cfcfcSbellard 
143e80cfcfcSbellard // master system interrupt controller
144a8170e5eSAvi Kivity static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr,
14513c89a11SBenoît Canet                                          unsigned size)
146e80cfcfcSbellard {
147e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
148dd4131b3Sblueswir1     uint32_t saddr, ret;
149e80cfcfcSbellard 
150a8f48dccSblueswir1     saddr = addr >> 2;
151e80cfcfcSbellard     switch (saddr) {
152e80cfcfcSbellard     case 0:
1539a87ce9bSblueswir1         ret = s->intregm_pending & ~MASTER_DISABLE;
154dd4131b3Sblueswir1         break;
155e80cfcfcSbellard     case 1:
15680be36b8Sblueswir1         ret = s->intregm_disabled & MASTER_IRQ_MASK;
157dd4131b3Sblueswir1         break;
158e80cfcfcSbellard     case 4:
159dd4131b3Sblueswir1         ret = s->target_cpu;
160dd4131b3Sblueswir1         break;
161e80cfcfcSbellard     default:
162dd4131b3Sblueswir1         ret = 0;
163e80cfcfcSbellard         break;
164e80cfcfcSbellard     }
16597bf4851SBlue Swirl     trace_slavio_intctlm_mem_readl(addr, ret);
166dd4131b3Sblueswir1 
167dd4131b3Sblueswir1     return ret;
168e80cfcfcSbellard }
169e80cfcfcSbellard 
170a8170e5eSAvi Kivity static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr,
17113c89a11SBenoît Canet                                       uint64_t val, unsigned size)
172e80cfcfcSbellard {
173e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
174e80cfcfcSbellard     uint32_t saddr;
175e80cfcfcSbellard 
176a8f48dccSblueswir1     saddr = addr >> 2;
17797bf4851SBlue Swirl     trace_slavio_intctlm_mem_writel(addr, val);
178e80cfcfcSbellard     switch (saddr) {
179e80cfcfcSbellard     case 2: // clear (enable)
1806bae7071Sbellard         // Force clear unused bits
1819a87ce9bSblueswir1         val &= MASTER_IRQ_MASK;
182e80cfcfcSbellard         s->intregm_disabled &= ~val;
18397bf4851SBlue Swirl         trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled);
1840d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
185e80cfcfcSbellard         break;
18610760f0fSArtyom Tarasenko     case 3: // set (disable; doesn't affect pending)
1876bae7071Sbellard         // Force clear unused bits
1889a87ce9bSblueswir1         val &= MASTER_IRQ_MASK;
189e80cfcfcSbellard         s->intregm_disabled |= val;
1900d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
19197bf4851SBlue Swirl         trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled);
192e80cfcfcSbellard         break;
193e80cfcfcSbellard     case 4:
194e80cfcfcSbellard         s->target_cpu = val & (MAX_CPUS - 1);
1950d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
19697bf4851SBlue Swirl         trace_slavio_intctlm_mem_writel_target(s->target_cpu);
197e80cfcfcSbellard         break;
198e80cfcfcSbellard     default:
199e80cfcfcSbellard         break;
200e80cfcfcSbellard     }
201e80cfcfcSbellard }
202e80cfcfcSbellard 
20313c89a11SBenoît Canet static const MemoryRegionOps slavio_intctlm_mem_ops = {
20413c89a11SBenoît Canet     .read = slavio_intctlm_mem_readl,
20513c89a11SBenoît Canet     .write = slavio_intctlm_mem_writel,
20613c89a11SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
20713c89a11SBenoît Canet     .valid = {
20813c89a11SBenoît Canet         .min_access_size = 4,
20913c89a11SBenoît Canet         .max_access_size = 4,
21013c89a11SBenoît Canet     },
211e80cfcfcSbellard };
212e80cfcfcSbellard 
213d453c2c3SBlue Swirl void slavio_pic_info(Monitor *mon, DeviceState *dev)
214e80cfcfcSbellard {
2157abad863SAndreas Färber     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
216e80cfcfcSbellard     int i;
217e80cfcfcSbellard 
218e80cfcfcSbellard     for (i = 0; i < MAX_CPUS; i++) {
219376253ecSaliguori         monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
220a1961a4bSBlue Swirl                        s->slaves[i].intreg_pending);
221e80cfcfcSbellard     }
222376253ecSaliguori     monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
22377f193daSblueswir1                    s->intregm_pending, s->intregm_disabled);
224e80cfcfcSbellard }
225e80cfcfcSbellard 
226d453c2c3SBlue Swirl void slavio_irq_info(Monitor *mon, DeviceState *dev)
227e80cfcfcSbellard {
228e80cfcfcSbellard #ifndef DEBUG_IRQ_COUNT
229376253ecSaliguori     monitor_printf(mon, "irq statistic code not compiled.\n");
230e80cfcfcSbellard #else
2317abad863SAndreas Färber     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
232e80cfcfcSbellard     int i;
233e80cfcfcSbellard     int64_t count;
234e80cfcfcSbellard 
2357abad863SAndreas Färber     s = SLAVIO_INTCTL(dev);
236376253ecSaliguori     monitor_printf(mon, "IRQ statistics:\n");
237e80cfcfcSbellard     for (i = 0; i < 32; i++) {
238e80cfcfcSbellard         count = s->irq_count[i];
239e80cfcfcSbellard         if (count > 0)
240376253ecSaliguori             monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
241e80cfcfcSbellard     }
242e80cfcfcSbellard #endif
243e80cfcfcSbellard }
244e80cfcfcSbellard 
24568556e2eSBlue Swirl static const uint32_t intbit_to_level[] = {
246462eda24SBlue Swirl     2, 3, 5, 7, 9, 11, 13, 2,   3, 5, 7, 9, 11, 13, 12, 12,
247462eda24SBlue Swirl     6, 13, 4, 10, 8, 9, 11, 0,  0, 0, 0, 15, 15, 15, 15, 0,
24868556e2eSBlue Swirl };
24968556e2eSBlue Swirl 
2500d0a7e69SBlue Swirl static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
25166321a11Sbellard {
252327ac2e7Sblueswir1     uint32_t pending = s->intregm_pending, pil_pending;
253327ac2e7Sblueswir1     unsigned int i, j;
25466321a11Sbellard 
25566321a11Sbellard     pending &= ~s->intregm_disabled;
25666321a11Sbellard 
25797bf4851SBlue Swirl     trace_slavio_check_interrupts(pending, s->intregm_disabled);
258ba3c64fbSbellard     for (i = 0; i < MAX_CPUS; i++) {
259327ac2e7Sblueswir1         pil_pending = 0;
260462eda24SBlue Swirl 
261462eda24SBlue Swirl         /* If we are the current interrupt target, get hard interrupts */
2629a87ce9bSblueswir1         if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
263b3a23197Sblueswir1             (i == s->target_cpu)) {
264b3a23197Sblueswir1             for (j = 0; j < 32; j++) {
265462eda24SBlue Swirl                 if ((pending & (1 << j)) && intbit_to_level[j]) {
26668556e2eSBlue Swirl                     pil_pending |= 1 << intbit_to_level[j];
267b3a23197Sblueswir1                 }
268b3a23197Sblueswir1             }
269462eda24SBlue Swirl         }
270462eda24SBlue Swirl 
271462eda24SBlue Swirl         /* Calculate current pending hard interrupts for display */
272462eda24SBlue Swirl         s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
273462eda24SBlue Swirl             CPU_IRQ_TIMER_IN;
274462eda24SBlue Swirl         if (i == s->target_cpu) {
275462eda24SBlue Swirl             for (j = 0; j < 32; j++) {
2767d45e784SPeter Maydell                 if ((s->intregm_pending & (1U << j)) && intbit_to_level[j]) {
277462eda24SBlue Swirl                     s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
278462eda24SBlue Swirl                 }
279462eda24SBlue Swirl             }
280462eda24SBlue Swirl         }
281462eda24SBlue Swirl 
28294c5f455SArtyom Tarasenko         /* Level 15 and CPU timer interrupts are only masked when
28394c5f455SArtyom Tarasenko            the MASTER_DISABLE bit is set */
28494c5f455SArtyom Tarasenko         if (!(s->intregm_disabled & MASTER_DISABLE)) {
285462eda24SBlue Swirl             pil_pending |= s->slaves[i].intreg_pending &
286462eda24SBlue Swirl                 (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
28794c5f455SArtyom Tarasenko         }
288462eda24SBlue Swirl 
289462eda24SBlue Swirl         /* Add soft interrupts */
290a1961a4bSBlue Swirl         pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
291327ac2e7Sblueswir1 
2920d0a7e69SBlue Swirl         if (set_irqs) {
293c84a88d8SPeter Maydell             /* Since there is not really an interrupt 0 (and pil_pending
294c84a88d8SPeter Maydell              * and irl_out bit zero are thus always zero) there is no need
295c84a88d8SPeter Maydell              * to do anything with cpu_irqs[i][0] and it is OK not to do
296c84a88d8SPeter Maydell              * the j=0 iteration of this loop.
297c84a88d8SPeter Maydell              */
298c84a88d8SPeter Maydell             for (j = MAX_PILS-1; j > 0; j--) {
299327ac2e7Sblueswir1                 if (pil_pending & (1 << j)) {
300462eda24SBlue Swirl                     if (!(s->slaves[i].irl_out & (1 << j))) {
301327ac2e7Sblueswir1                         qemu_irq_raise(s->cpu_irqs[i][j]);
3020d0a7e69SBlue Swirl                     }
303327ac2e7Sblueswir1                 } else {
304462eda24SBlue Swirl                     if (s->slaves[i].irl_out & (1 << j)) {
305327ac2e7Sblueswir1                         qemu_irq_lower(s->cpu_irqs[i][j]);
306ba3c64fbSbellard                     }
307ba3c64fbSbellard                 }
3080d0a7e69SBlue Swirl             }
3090d0a7e69SBlue Swirl         }
310462eda24SBlue Swirl         s->slaves[i].irl_out = pil_pending;
311ba3c64fbSbellard     }
31266321a11Sbellard }
31366321a11Sbellard 
314e80cfcfcSbellard /*
315e80cfcfcSbellard  * "irq" here is the bit number in the system interrupt register to
316e80cfcfcSbellard  * separate serial and keyboard interrupts sharing a level.
317e80cfcfcSbellard  */
318d7edfd27Sblueswir1 static void slavio_set_irq(void *opaque, int irq, int level)
319e80cfcfcSbellard {
320e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
321e80cfcfcSbellard     uint32_t mask = 1 << irq;
32268556e2eSBlue Swirl     uint32_t pil = intbit_to_level[irq];
323462eda24SBlue Swirl     unsigned int i;
324b3a23197Sblueswir1 
32597bf4851SBlue Swirl     trace_slavio_set_irq(s->target_cpu, irq, pil, level);
326e80cfcfcSbellard     if (pil > 0) {
327e80cfcfcSbellard         if (level) {
328327ac2e7Sblueswir1 #ifdef DEBUG_IRQ_COUNT
329327ac2e7Sblueswir1             s->irq_count[pil]++;
330327ac2e7Sblueswir1 #endif
331e80cfcfcSbellard             s->intregm_pending |= mask;
332462eda24SBlue Swirl             if (pil == 15) {
333462eda24SBlue Swirl                 for (i = 0; i < MAX_CPUS; i++) {
334462eda24SBlue Swirl                     s->slaves[i].intreg_pending |= 1 << pil;
335462eda24SBlue Swirl                 }
336462eda24SBlue Swirl             }
337b3a23197Sblueswir1         } else {
338e80cfcfcSbellard             s->intregm_pending &= ~mask;
339462eda24SBlue Swirl             if (pil == 15) {
340462eda24SBlue Swirl                 for (i = 0; i < MAX_CPUS; i++) {
341462eda24SBlue Swirl                     s->slaves[i].intreg_pending &= ~(1 << pil);
342462eda24SBlue Swirl                 }
343462eda24SBlue Swirl             }
344e80cfcfcSbellard         }
3450d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
346e80cfcfcSbellard     }
347e80cfcfcSbellard }
348e80cfcfcSbellard 
349d7edfd27Sblueswir1 static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
350ba3c64fbSbellard {
351ba3c64fbSbellard     SLAVIO_INTCTLState *s = opaque;
352ba3c64fbSbellard 
35397bf4851SBlue Swirl     trace_slavio_set_timer_irq_cpu(cpu, level);
354d7edfd27Sblueswir1 
355e3a79bcaSblueswir1     if (level) {
356462eda24SBlue Swirl         s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
357e3a79bcaSblueswir1     } else {
358462eda24SBlue Swirl         s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
359e3a79bcaSblueswir1     }
360d7edfd27Sblueswir1 
3610d0a7e69SBlue Swirl     slavio_check_interrupts(s, 1);
362ba3c64fbSbellard }
363ba3c64fbSbellard 
364a1961a4bSBlue Swirl static void slavio_set_irq_all(void *opaque, int irq, int level)
365a1961a4bSBlue Swirl {
366a1961a4bSBlue Swirl     if (irq < 32) {
367a1961a4bSBlue Swirl         slavio_set_irq(opaque, irq, level);
368a1961a4bSBlue Swirl     } else {
369a1961a4bSBlue Swirl         slavio_set_timer_irq_cpu(opaque, irq - 32, level);
370a1961a4bSBlue Swirl     }
371a1961a4bSBlue Swirl }
372a1961a4bSBlue Swirl 
373e59fb374SJuan Quintela static int vmstate_intctl_post_load(void *opaque, int version_id)
374e80cfcfcSbellard {
375e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
376e80cfcfcSbellard 
3770d0a7e69SBlue Swirl     slavio_check_interrupts(s, 0);
378e80cfcfcSbellard     return 0;
379e80cfcfcSbellard }
380e80cfcfcSbellard 
381c9e95029SBlue Swirl static const VMStateDescription vmstate_intctl_cpu = {
382c9e95029SBlue Swirl     .name ="slavio_intctl_cpu",
383c9e95029SBlue Swirl     .version_id = 1,
384c9e95029SBlue Swirl     .minimum_version_id = 1,
385c9e95029SBlue Swirl     .fields = (VMStateField[]) {
386c9e95029SBlue Swirl         VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
387c9e95029SBlue Swirl         VMSTATE_END_OF_LIST()
388c9e95029SBlue Swirl     }
389c9e95029SBlue Swirl };
390c9e95029SBlue Swirl 
391c9e95029SBlue Swirl static const VMStateDescription vmstate_intctl = {
392c9e95029SBlue Swirl     .name ="slavio_intctl",
393c9e95029SBlue Swirl     .version_id = 1,
394c9e95029SBlue Swirl     .minimum_version_id = 1,
395752ff2faSJuan Quintela     .post_load = vmstate_intctl_post_load,
396c9e95029SBlue Swirl     .fields = (VMStateField[]) {
397c9e95029SBlue Swirl         VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
398c9e95029SBlue Swirl                              vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
399c9e95029SBlue Swirl         VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
400c9e95029SBlue Swirl         VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
401c9e95029SBlue Swirl         VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
402c9e95029SBlue Swirl         VMSTATE_END_OF_LIST()
403c9e95029SBlue Swirl     }
404c9e95029SBlue Swirl };
405c9e95029SBlue Swirl 
40678971d57SBlue Swirl static void slavio_intctl_reset(DeviceState *d)
407e80cfcfcSbellard {
4087abad863SAndreas Färber     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(d);
409e80cfcfcSbellard     int i;
410e80cfcfcSbellard 
411e80cfcfcSbellard     for (i = 0; i < MAX_CPUS; i++) {
412a1961a4bSBlue Swirl         s->slaves[i].intreg_pending = 0;
413462eda24SBlue Swirl         s->slaves[i].irl_out = 0;
414e80cfcfcSbellard     }
4159a87ce9bSblueswir1     s->intregm_disabled = ~MASTER_IRQ_MASK;
416e80cfcfcSbellard     s->intregm_pending = 0;
417e80cfcfcSbellard     s->target_cpu = 0;
4180d0a7e69SBlue Swirl     slavio_check_interrupts(s, 0);
419e80cfcfcSbellard }
420e80cfcfcSbellard 
4217abad863SAndreas Färber static int slavio_intctl_init1(SysBusDevice *sbd)
422e80cfcfcSbellard {
4237abad863SAndreas Färber     DeviceState *dev = DEVICE(sbd);
4247abad863SAndreas Färber     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
425a1961a4bSBlue Swirl     unsigned int i, j;
4268bb5ef33SBenoît Canet     char slave_name[45];
427e80cfcfcSbellard 
4287abad863SAndreas Färber     qdev_init_gpio_in(dev, slavio_set_irq_all, 32 + MAX_CPUS);
4291437c94bSPaolo Bonzini     memory_region_init_io(&s->iomem, OBJECT(s), &slavio_intctlm_mem_ops, s,
43013c89a11SBenoît Canet                           "master-interrupt-controller", INTCTLM_SIZE);
4317abad863SAndreas Färber     sysbus_init_mmio(sbd, &s->iomem);
432e80cfcfcSbellard 
433e80cfcfcSbellard     for (i = 0; i < MAX_CPUS; i++) {
4348bb5ef33SBenoît Canet         snprintf(slave_name, sizeof(slave_name),
4358bb5ef33SBenoît Canet                  "slave-interrupt-controller-%i", i);
436a1961a4bSBlue Swirl         for (j = 0; j < MAX_PILS; j++) {
4377abad863SAndreas Färber             sysbus_init_irq(sbd, &s->cpu_irqs[i][j]);
438e80cfcfcSbellard         }
4391437c94bSPaolo Bonzini         memory_region_init_io(&s->slaves[i].iomem, OBJECT(s),
4401437c94bSPaolo Bonzini                               &slavio_intctl_mem_ops,
4418bb5ef33SBenoît Canet                               &s->slaves[i], slave_name, INTCTL_SIZE);
4427abad863SAndreas Färber         sysbus_init_mmio(sbd, &s->slaves[i].iomem);
443a1961a4bSBlue Swirl         s->slaves[i].cpu = i;
444a1961a4bSBlue Swirl         s->slaves[i].master = s;
445a1961a4bSBlue Swirl     }
44678971d57SBlue Swirl 
44781a322d4SGerd Hoffmann     return 0;
448e80cfcfcSbellard }
449a1961a4bSBlue Swirl 
450999e12bbSAnthony Liguori static void slavio_intctl_class_init(ObjectClass *klass, void *data)
451999e12bbSAnthony Liguori {
45239bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
453999e12bbSAnthony Liguori     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
454999e12bbSAnthony Liguori 
455999e12bbSAnthony Liguori     k->init = slavio_intctl_init1;
45639bffca2SAnthony Liguori     dc->reset = slavio_intctl_reset;
45739bffca2SAnthony Liguori     dc->vmsd = &vmstate_intctl;
458999e12bbSAnthony Liguori }
459999e12bbSAnthony Liguori 
4608c43a6f0SAndreas Färber static const TypeInfo slavio_intctl_info = {
4617abad863SAndreas Färber     .name          = TYPE_SLAVIO_INTCTL,
46239bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
46339bffca2SAnthony Liguori     .instance_size = sizeof(SLAVIO_INTCTLState),
464999e12bbSAnthony Liguori     .class_init    = slavio_intctl_class_init,
465a1961a4bSBlue Swirl };
466a1961a4bSBlue Swirl 
46783f7d43aSAndreas Färber static void slavio_intctl_register_types(void)
468a1961a4bSBlue Swirl {
46939bffca2SAnthony Liguori     type_register_static(&slavio_intctl_info);
470a1961a4bSBlue Swirl }
471a1961a4bSBlue Swirl 
47283f7d43aSAndreas Färber type_init(slavio_intctl_register_types)
473