xref: /qemu/hw/intc/slavio_intctl.c (revision 7d45e784015971e70239e33256fd606638107a3e)
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 
250d09e41aSPaolo Bonzini #include "hw/sparc/sun4m.h"
2683c9089eSPaolo Bonzini #include "monitor/monitor.h"
2783c9f4caSPaolo Bonzini #include "hw/sysbus.h"
2897bf4851SBlue Swirl #include "trace.h"
2987ecb68bSpbrook 
30e80cfcfcSbellard //#define DEBUG_IRQ_COUNT
31e80cfcfcSbellard 
32e80cfcfcSbellard /*
33e80cfcfcSbellard  * Registers of interrupt controller in sun4m.
34e80cfcfcSbellard  *
35e80cfcfcSbellard  * This is the interrupt controller part of chip STP2001 (Slave I/O), also
36e80cfcfcSbellard  * produced as NCR89C105. See
37e80cfcfcSbellard  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
38e80cfcfcSbellard  *
39e80cfcfcSbellard  * There is a system master controller and one for each cpu.
40e80cfcfcSbellard  *
41e80cfcfcSbellard  */
42e80cfcfcSbellard 
43e80cfcfcSbellard #define MAX_CPUS 16
44b3a23197Sblueswir1 #define MAX_PILS 16
45e80cfcfcSbellard 
46a1961a4bSBlue Swirl struct SLAVIO_INTCTLState;
47a1961a4bSBlue Swirl 
48a1961a4bSBlue Swirl typedef struct SLAVIO_CPUINTCTLState {
498bb5ef33SBenoît Canet     MemoryRegion iomem;
50a1961a4bSBlue Swirl     struct SLAVIO_INTCTLState *master;
5107dd0035SBlue Swirl     uint32_t intreg_pending;
52a1961a4bSBlue Swirl     uint32_t cpu;
53462eda24SBlue Swirl     uint32_t irl_out;
54a1961a4bSBlue Swirl } SLAVIO_CPUINTCTLState;
55a8f48dccSblueswir1 
567abad863SAndreas Färber #define TYPE_SLAVIO_INTCTL "slavio_intctl"
577abad863SAndreas Färber #define SLAVIO_INTCTL(obj) \
587abad863SAndreas Färber     OBJECT_CHECK(SLAVIO_INTCTLState, (obj), TYPE_SLAVIO_INTCTL)
597abad863SAndreas Färber 
60e80cfcfcSbellard typedef struct SLAVIO_INTCTLState {
617abad863SAndreas Färber     SysBusDevice parent_obj;
627abad863SAndreas Färber 
6313c89a11SBenoît Canet     MemoryRegion iomem;
64e80cfcfcSbellard #ifdef DEBUG_IRQ_COUNT
65e80cfcfcSbellard     uint64_t irq_count[32];
66e80cfcfcSbellard #endif
67a1961a4bSBlue Swirl     qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
68a1961a4bSBlue Swirl     SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
6907dd0035SBlue Swirl     uint32_t intregm_pending;
7007dd0035SBlue Swirl     uint32_t intregm_disabled;
7107dd0035SBlue Swirl     uint32_t target_cpu;
72e80cfcfcSbellard } SLAVIO_INTCTLState;
73e80cfcfcSbellard 
74e80cfcfcSbellard #define INTCTL_MAXADDR 0xf
755aca8c3bSblueswir1 #define INTCTL_SIZE (INTCTL_MAXADDR + 1)
76a8f48dccSblueswir1 #define INTCTLM_SIZE 0x14
7780be36b8Sblueswir1 #define MASTER_IRQ_MASK ~0x0fa2007f
789a87ce9bSblueswir1 #define MASTER_DISABLE 0x80000000
796341fdcbSblueswir1 #define CPU_SOFTIRQ_MASK 0xfffe0000
80462eda24SBlue Swirl #define CPU_IRQ_INT15_IN (1 << 15)
81462eda24SBlue Swirl #define CPU_IRQ_TIMER_IN (1 << 14)
829a87ce9bSblueswir1 
830d0a7e69SBlue Swirl static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
84e80cfcfcSbellard 
85e80cfcfcSbellard // per-cpu interrupt controller
86a8170e5eSAvi Kivity static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr,
878bb5ef33SBenoît Canet                                         unsigned size)
88e80cfcfcSbellard {
89a8f48dccSblueswir1     SLAVIO_CPUINTCTLState *s = opaque;
90dd4131b3Sblueswir1     uint32_t saddr, ret;
91e80cfcfcSbellard 
92a8f48dccSblueswir1     saddr = addr >> 2;
93e80cfcfcSbellard     switch (saddr) {
94e80cfcfcSbellard     case 0:
95a8f48dccSblueswir1         ret = s->intreg_pending;
96dd4131b3Sblueswir1         break;
97e80cfcfcSbellard     default:
98dd4131b3Sblueswir1         ret = 0;
99e80cfcfcSbellard         break;
100e80cfcfcSbellard     }
10197bf4851SBlue Swirl     trace_slavio_intctl_mem_readl(s->cpu, addr, ret);
102dd4131b3Sblueswir1 
103dd4131b3Sblueswir1     return ret;
104e80cfcfcSbellard }
105e80cfcfcSbellard 
106a8170e5eSAvi Kivity static void slavio_intctl_mem_writel(void *opaque, hwaddr addr,
1078bb5ef33SBenoît Canet                                      uint64_t val, unsigned size)
108e80cfcfcSbellard {
109a8f48dccSblueswir1     SLAVIO_CPUINTCTLState *s = opaque;
110e80cfcfcSbellard     uint32_t saddr;
111e80cfcfcSbellard 
112a8f48dccSblueswir1     saddr = addr >> 2;
11397bf4851SBlue Swirl     trace_slavio_intctl_mem_writel(s->cpu, addr, val);
114e80cfcfcSbellard     switch (saddr) {
115e80cfcfcSbellard     case 1: // clear pending softints
116462eda24SBlue Swirl         val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
117a8f48dccSblueswir1         s->intreg_pending &= ~val;
1180d0a7e69SBlue Swirl         slavio_check_interrupts(s->master, 1);
11997bf4851SBlue Swirl         trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending);
120e80cfcfcSbellard         break;
121e80cfcfcSbellard     case 2: // set softint
1226341fdcbSblueswir1         val &= CPU_SOFTIRQ_MASK;
123a8f48dccSblueswir1         s->intreg_pending |= val;
1240d0a7e69SBlue Swirl         slavio_check_interrupts(s->master, 1);
12597bf4851SBlue Swirl         trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending);
126e80cfcfcSbellard         break;
127e80cfcfcSbellard     default:
128e80cfcfcSbellard         break;
129e80cfcfcSbellard     }
130e80cfcfcSbellard }
131e80cfcfcSbellard 
1328bb5ef33SBenoît Canet static const MemoryRegionOps slavio_intctl_mem_ops = {
1338bb5ef33SBenoît Canet     .read = slavio_intctl_mem_readl,
1348bb5ef33SBenoît Canet     .write = slavio_intctl_mem_writel,
1358bb5ef33SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
1368bb5ef33SBenoît Canet     .valid = {
1378bb5ef33SBenoît Canet         .min_access_size = 4,
1388bb5ef33SBenoît Canet         .max_access_size = 4,
1398bb5ef33SBenoît Canet     },
140e80cfcfcSbellard };
141e80cfcfcSbellard 
142e80cfcfcSbellard // master system interrupt controller
143a8170e5eSAvi Kivity static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr,
14413c89a11SBenoît Canet                                          unsigned size)
145e80cfcfcSbellard {
146e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
147dd4131b3Sblueswir1     uint32_t saddr, ret;
148e80cfcfcSbellard 
149a8f48dccSblueswir1     saddr = addr >> 2;
150e80cfcfcSbellard     switch (saddr) {
151e80cfcfcSbellard     case 0:
1529a87ce9bSblueswir1         ret = s->intregm_pending & ~MASTER_DISABLE;
153dd4131b3Sblueswir1         break;
154e80cfcfcSbellard     case 1:
15580be36b8Sblueswir1         ret = s->intregm_disabled & MASTER_IRQ_MASK;
156dd4131b3Sblueswir1         break;
157e80cfcfcSbellard     case 4:
158dd4131b3Sblueswir1         ret = s->target_cpu;
159dd4131b3Sblueswir1         break;
160e80cfcfcSbellard     default:
161dd4131b3Sblueswir1         ret = 0;
162e80cfcfcSbellard         break;
163e80cfcfcSbellard     }
16497bf4851SBlue Swirl     trace_slavio_intctlm_mem_readl(addr, ret);
165dd4131b3Sblueswir1 
166dd4131b3Sblueswir1     return ret;
167e80cfcfcSbellard }
168e80cfcfcSbellard 
169a8170e5eSAvi Kivity static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr,
17013c89a11SBenoît Canet                                       uint64_t val, unsigned size)
171e80cfcfcSbellard {
172e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
173e80cfcfcSbellard     uint32_t saddr;
174e80cfcfcSbellard 
175a8f48dccSblueswir1     saddr = addr >> 2;
17697bf4851SBlue Swirl     trace_slavio_intctlm_mem_writel(addr, val);
177e80cfcfcSbellard     switch (saddr) {
178e80cfcfcSbellard     case 2: // clear (enable)
1796bae7071Sbellard         // Force clear unused bits
1809a87ce9bSblueswir1         val &= MASTER_IRQ_MASK;
181e80cfcfcSbellard         s->intregm_disabled &= ~val;
18297bf4851SBlue Swirl         trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled);
1830d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
184e80cfcfcSbellard         break;
18510760f0fSArtyom Tarasenko     case 3: // set (disable; doesn't affect pending)
1866bae7071Sbellard         // Force clear unused bits
1879a87ce9bSblueswir1         val &= MASTER_IRQ_MASK;
188e80cfcfcSbellard         s->intregm_disabled |= val;
1890d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
19097bf4851SBlue Swirl         trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled);
191e80cfcfcSbellard         break;
192e80cfcfcSbellard     case 4:
193e80cfcfcSbellard         s->target_cpu = val & (MAX_CPUS - 1);
1940d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
19597bf4851SBlue Swirl         trace_slavio_intctlm_mem_writel_target(s->target_cpu);
196e80cfcfcSbellard         break;
197e80cfcfcSbellard     default:
198e80cfcfcSbellard         break;
199e80cfcfcSbellard     }
200e80cfcfcSbellard }
201e80cfcfcSbellard 
20213c89a11SBenoît Canet static const MemoryRegionOps slavio_intctlm_mem_ops = {
20313c89a11SBenoît Canet     .read = slavio_intctlm_mem_readl,
20413c89a11SBenoît Canet     .write = slavio_intctlm_mem_writel,
20513c89a11SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
20613c89a11SBenoît Canet     .valid = {
20713c89a11SBenoît Canet         .min_access_size = 4,
20813c89a11SBenoît Canet         .max_access_size = 4,
20913c89a11SBenoît Canet     },
210e80cfcfcSbellard };
211e80cfcfcSbellard 
212d453c2c3SBlue Swirl void slavio_pic_info(Monitor *mon, DeviceState *dev)
213e80cfcfcSbellard {
2147abad863SAndreas Färber     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
215e80cfcfcSbellard     int i;
216e80cfcfcSbellard 
217e80cfcfcSbellard     for (i = 0; i < MAX_CPUS; i++) {
218376253ecSaliguori         monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
219a1961a4bSBlue Swirl                        s->slaves[i].intreg_pending);
220e80cfcfcSbellard     }
221376253ecSaliguori     monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
22277f193daSblueswir1                    s->intregm_pending, s->intregm_disabled);
223e80cfcfcSbellard }
224e80cfcfcSbellard 
225d453c2c3SBlue Swirl void slavio_irq_info(Monitor *mon, DeviceState *dev)
226e80cfcfcSbellard {
227e80cfcfcSbellard #ifndef DEBUG_IRQ_COUNT
228376253ecSaliguori     monitor_printf(mon, "irq statistic code not compiled.\n");
229e80cfcfcSbellard #else
2307abad863SAndreas Färber     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
231e80cfcfcSbellard     int i;
232e80cfcfcSbellard     int64_t count;
233e80cfcfcSbellard 
2347abad863SAndreas Färber     s = SLAVIO_INTCTL(dev);
235376253ecSaliguori     monitor_printf(mon, "IRQ statistics:\n");
236e80cfcfcSbellard     for (i = 0; i < 32; i++) {
237e80cfcfcSbellard         count = s->irq_count[i];
238e80cfcfcSbellard         if (count > 0)
239376253ecSaliguori             monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
240e80cfcfcSbellard     }
241e80cfcfcSbellard #endif
242e80cfcfcSbellard }
243e80cfcfcSbellard 
24468556e2eSBlue Swirl static const uint32_t intbit_to_level[] = {
245462eda24SBlue Swirl     2, 3, 5, 7, 9, 11, 13, 2,   3, 5, 7, 9, 11, 13, 12, 12,
246462eda24SBlue Swirl     6, 13, 4, 10, 8, 9, 11, 0,  0, 0, 0, 15, 15, 15, 15, 0,
24768556e2eSBlue Swirl };
24868556e2eSBlue Swirl 
2490d0a7e69SBlue Swirl static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
25066321a11Sbellard {
251327ac2e7Sblueswir1     uint32_t pending = s->intregm_pending, pil_pending;
252327ac2e7Sblueswir1     unsigned int i, j;
25366321a11Sbellard 
25466321a11Sbellard     pending &= ~s->intregm_disabled;
25566321a11Sbellard 
25697bf4851SBlue Swirl     trace_slavio_check_interrupts(pending, s->intregm_disabled);
257ba3c64fbSbellard     for (i = 0; i < MAX_CPUS; i++) {
258327ac2e7Sblueswir1         pil_pending = 0;
259462eda24SBlue Swirl 
260462eda24SBlue Swirl         /* If we are the current interrupt target, get hard interrupts */
2619a87ce9bSblueswir1         if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
262b3a23197Sblueswir1             (i == s->target_cpu)) {
263b3a23197Sblueswir1             for (j = 0; j < 32; j++) {
264462eda24SBlue Swirl                 if ((pending & (1 << j)) && intbit_to_level[j]) {
26568556e2eSBlue Swirl                     pil_pending |= 1 << intbit_to_level[j];
266b3a23197Sblueswir1                 }
267b3a23197Sblueswir1             }
268462eda24SBlue Swirl         }
269462eda24SBlue Swirl 
270462eda24SBlue Swirl         /* Calculate current pending hard interrupts for display */
271462eda24SBlue Swirl         s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
272462eda24SBlue Swirl             CPU_IRQ_TIMER_IN;
273462eda24SBlue Swirl         if (i == s->target_cpu) {
274462eda24SBlue Swirl             for (j = 0; j < 32; j++) {
275*7d45e784SPeter Maydell                 if ((s->intregm_pending & (1U << j)) && intbit_to_level[j]) {
276462eda24SBlue Swirl                     s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
277462eda24SBlue Swirl                 }
278462eda24SBlue Swirl             }
279462eda24SBlue Swirl         }
280462eda24SBlue Swirl 
28194c5f455SArtyom Tarasenko         /* Level 15 and CPU timer interrupts are only masked when
28294c5f455SArtyom Tarasenko            the MASTER_DISABLE bit is set */
28394c5f455SArtyom Tarasenko         if (!(s->intregm_disabled & MASTER_DISABLE)) {
284462eda24SBlue Swirl             pil_pending |= s->slaves[i].intreg_pending &
285462eda24SBlue Swirl                 (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
28694c5f455SArtyom Tarasenko         }
287462eda24SBlue Swirl 
288462eda24SBlue Swirl         /* Add soft interrupts */
289a1961a4bSBlue Swirl         pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
290327ac2e7Sblueswir1 
2910d0a7e69SBlue Swirl         if (set_irqs) {
292c84a88d8SPeter Maydell             /* Since there is not really an interrupt 0 (and pil_pending
293c84a88d8SPeter Maydell              * and irl_out bit zero are thus always zero) there is no need
294c84a88d8SPeter Maydell              * to do anything with cpu_irqs[i][0] and it is OK not to do
295c84a88d8SPeter Maydell              * the j=0 iteration of this loop.
296c84a88d8SPeter Maydell              */
297c84a88d8SPeter Maydell             for (j = MAX_PILS-1; j > 0; j--) {
298327ac2e7Sblueswir1                 if (pil_pending & (1 << j)) {
299462eda24SBlue Swirl                     if (!(s->slaves[i].irl_out & (1 << j))) {
300327ac2e7Sblueswir1                         qemu_irq_raise(s->cpu_irqs[i][j]);
3010d0a7e69SBlue Swirl                     }
302327ac2e7Sblueswir1                 } else {
303462eda24SBlue Swirl                     if (s->slaves[i].irl_out & (1 << j)) {
304327ac2e7Sblueswir1                         qemu_irq_lower(s->cpu_irqs[i][j]);
305ba3c64fbSbellard                     }
306ba3c64fbSbellard                 }
3070d0a7e69SBlue Swirl             }
3080d0a7e69SBlue Swirl         }
309462eda24SBlue Swirl         s->slaves[i].irl_out = pil_pending;
310ba3c64fbSbellard     }
31166321a11Sbellard }
31266321a11Sbellard 
313e80cfcfcSbellard /*
314e80cfcfcSbellard  * "irq" here is the bit number in the system interrupt register to
315e80cfcfcSbellard  * separate serial and keyboard interrupts sharing a level.
316e80cfcfcSbellard  */
317d7edfd27Sblueswir1 static void slavio_set_irq(void *opaque, int irq, int level)
318e80cfcfcSbellard {
319e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
320e80cfcfcSbellard     uint32_t mask = 1 << irq;
32168556e2eSBlue Swirl     uint32_t pil = intbit_to_level[irq];
322462eda24SBlue Swirl     unsigned int i;
323b3a23197Sblueswir1 
32497bf4851SBlue Swirl     trace_slavio_set_irq(s->target_cpu, irq, pil, level);
325e80cfcfcSbellard     if (pil > 0) {
326e80cfcfcSbellard         if (level) {
327327ac2e7Sblueswir1 #ifdef DEBUG_IRQ_COUNT
328327ac2e7Sblueswir1             s->irq_count[pil]++;
329327ac2e7Sblueswir1 #endif
330e80cfcfcSbellard             s->intregm_pending |= mask;
331462eda24SBlue Swirl             if (pil == 15) {
332462eda24SBlue Swirl                 for (i = 0; i < MAX_CPUS; i++) {
333462eda24SBlue Swirl                     s->slaves[i].intreg_pending |= 1 << pil;
334462eda24SBlue Swirl                 }
335462eda24SBlue Swirl             }
336b3a23197Sblueswir1         } else {
337e80cfcfcSbellard             s->intregm_pending &= ~mask;
338462eda24SBlue Swirl             if (pil == 15) {
339462eda24SBlue Swirl                 for (i = 0; i < MAX_CPUS; i++) {
340462eda24SBlue Swirl                     s->slaves[i].intreg_pending &= ~(1 << pil);
341462eda24SBlue Swirl                 }
342462eda24SBlue Swirl             }
343e80cfcfcSbellard         }
3440d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
345e80cfcfcSbellard     }
346e80cfcfcSbellard }
347e80cfcfcSbellard 
348d7edfd27Sblueswir1 static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
349ba3c64fbSbellard {
350ba3c64fbSbellard     SLAVIO_INTCTLState *s = opaque;
351ba3c64fbSbellard 
35297bf4851SBlue Swirl     trace_slavio_set_timer_irq_cpu(cpu, level);
353d7edfd27Sblueswir1 
354e3a79bcaSblueswir1     if (level) {
355462eda24SBlue Swirl         s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
356e3a79bcaSblueswir1     } else {
357462eda24SBlue Swirl         s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
358e3a79bcaSblueswir1     }
359d7edfd27Sblueswir1 
3600d0a7e69SBlue Swirl     slavio_check_interrupts(s, 1);
361ba3c64fbSbellard }
362ba3c64fbSbellard 
363a1961a4bSBlue Swirl static void slavio_set_irq_all(void *opaque, int irq, int level)
364a1961a4bSBlue Swirl {
365a1961a4bSBlue Swirl     if (irq < 32) {
366a1961a4bSBlue Swirl         slavio_set_irq(opaque, irq, level);
367a1961a4bSBlue Swirl     } else {
368a1961a4bSBlue Swirl         slavio_set_timer_irq_cpu(opaque, irq - 32, level);
369a1961a4bSBlue Swirl     }
370a1961a4bSBlue Swirl }
371a1961a4bSBlue Swirl 
372e59fb374SJuan Quintela static int vmstate_intctl_post_load(void *opaque, int version_id)
373e80cfcfcSbellard {
374e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
375e80cfcfcSbellard 
3760d0a7e69SBlue Swirl     slavio_check_interrupts(s, 0);
377e80cfcfcSbellard     return 0;
378e80cfcfcSbellard }
379e80cfcfcSbellard 
380c9e95029SBlue Swirl static const VMStateDescription vmstate_intctl_cpu = {
381c9e95029SBlue Swirl     .name ="slavio_intctl_cpu",
382c9e95029SBlue Swirl     .version_id = 1,
383c9e95029SBlue Swirl     .minimum_version_id = 1,
384c9e95029SBlue Swirl     .minimum_version_id_old = 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,
395c9e95029SBlue Swirl     .minimum_version_id_old = 1,
396752ff2faSJuan Quintela     .post_load = vmstate_intctl_post_load,
397c9e95029SBlue Swirl     .fields      = (VMStateField []) {
398c9e95029SBlue Swirl         VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
399c9e95029SBlue Swirl                              vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
400c9e95029SBlue Swirl         VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
401c9e95029SBlue Swirl         VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
402c9e95029SBlue Swirl         VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
403c9e95029SBlue Swirl         VMSTATE_END_OF_LIST()
404c9e95029SBlue Swirl     }
405c9e95029SBlue Swirl };
406c9e95029SBlue Swirl 
40778971d57SBlue Swirl static void slavio_intctl_reset(DeviceState *d)
408e80cfcfcSbellard {
4097abad863SAndreas Färber     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(d);
410e80cfcfcSbellard     int i;
411e80cfcfcSbellard 
412e80cfcfcSbellard     for (i = 0; i < MAX_CPUS; i++) {
413a1961a4bSBlue Swirl         s->slaves[i].intreg_pending = 0;
414462eda24SBlue Swirl         s->slaves[i].irl_out = 0;
415e80cfcfcSbellard     }
4169a87ce9bSblueswir1     s->intregm_disabled = ~MASTER_IRQ_MASK;
417e80cfcfcSbellard     s->intregm_pending = 0;
418e80cfcfcSbellard     s->target_cpu = 0;
4190d0a7e69SBlue Swirl     slavio_check_interrupts(s, 0);
420e80cfcfcSbellard }
421e80cfcfcSbellard 
4227abad863SAndreas Färber static int slavio_intctl_init1(SysBusDevice *sbd)
423e80cfcfcSbellard {
4247abad863SAndreas Färber     DeviceState *dev = DEVICE(sbd);
4257abad863SAndreas Färber     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
426a1961a4bSBlue Swirl     unsigned int i, j;
4278bb5ef33SBenoît Canet     char slave_name[45];
428e80cfcfcSbellard 
4297abad863SAndreas Färber     qdev_init_gpio_in(dev, slavio_set_irq_all, 32 + MAX_CPUS);
4301437c94bSPaolo Bonzini     memory_region_init_io(&s->iomem, OBJECT(s), &slavio_intctlm_mem_ops, s,
43113c89a11SBenoît Canet                           "master-interrupt-controller", INTCTLM_SIZE);
4327abad863SAndreas Färber     sysbus_init_mmio(sbd, &s->iomem);
433e80cfcfcSbellard 
434e80cfcfcSbellard     for (i = 0; i < MAX_CPUS; i++) {
4358bb5ef33SBenoît Canet         snprintf(slave_name, sizeof(slave_name),
4368bb5ef33SBenoît Canet                  "slave-interrupt-controller-%i", i);
437a1961a4bSBlue Swirl         for (j = 0; j < MAX_PILS; j++) {
4387abad863SAndreas Färber             sysbus_init_irq(sbd, &s->cpu_irqs[i][j]);
439e80cfcfcSbellard         }
4401437c94bSPaolo Bonzini         memory_region_init_io(&s->slaves[i].iomem, OBJECT(s),
4411437c94bSPaolo Bonzini                               &slavio_intctl_mem_ops,
4428bb5ef33SBenoît Canet                               &s->slaves[i], slave_name, INTCTL_SIZE);
4437abad863SAndreas Färber         sysbus_init_mmio(sbd, &s->slaves[i].iomem);
444a1961a4bSBlue Swirl         s->slaves[i].cpu = i;
445a1961a4bSBlue Swirl         s->slaves[i].master = s;
446a1961a4bSBlue Swirl     }
44778971d57SBlue Swirl 
44881a322d4SGerd Hoffmann     return 0;
449e80cfcfcSbellard }
450a1961a4bSBlue Swirl 
451999e12bbSAnthony Liguori static void slavio_intctl_class_init(ObjectClass *klass, void *data)
452999e12bbSAnthony Liguori {
45339bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
454999e12bbSAnthony Liguori     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
455999e12bbSAnthony Liguori 
456999e12bbSAnthony Liguori     k->init = slavio_intctl_init1;
45739bffca2SAnthony Liguori     dc->reset = slavio_intctl_reset;
45839bffca2SAnthony Liguori     dc->vmsd = &vmstate_intctl;
459999e12bbSAnthony Liguori }
460999e12bbSAnthony Liguori 
4618c43a6f0SAndreas Färber static const TypeInfo slavio_intctl_info = {
4627abad863SAndreas Färber     .name          = TYPE_SLAVIO_INTCTL,
46339bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
46439bffca2SAnthony Liguori     .instance_size = sizeof(SLAVIO_INTCTLState),
465999e12bbSAnthony Liguori     .class_init    = slavio_intctl_class_init,
466a1961a4bSBlue Swirl };
467a1961a4bSBlue Swirl 
46883f7d43aSAndreas Färber static void slavio_intctl_register_types(void)
469a1961a4bSBlue Swirl {
47039bffca2SAnthony Liguori     type_register_static(&slavio_intctl_info);
471a1961a4bSBlue Swirl }
472a1961a4bSBlue Swirl 
47383f7d43aSAndreas Färber type_init(slavio_intctl_register_types)
474