xref: /qemu/hw/intc/slavio_intctl.c (revision 8063396bf3459a810d24e3efd6110b8480f0de5b)
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 
2590191d07SPeter Maydell #include "qemu/osdep.h"
26d6454270SMarkus Armbruster #include "migration/vmstate.h"
2783c9089eSPaolo Bonzini #include "monitor/monitor.h"
280b8fa32fSMarkus Armbruster #include "qemu/module.h"
2983c9f4caSPaolo Bonzini #include "hw/sysbus.h"
30148fbe95SHervé Poussineau #include "hw/intc/intc.h"
3164552b6bSMarkus Armbruster #include "hw/irq.h"
3297bf4851SBlue Swirl #include "trace.h"
33db1015e9SEduardo Habkost #include "qom/object.h"
3487ecb68bSpbrook 
35e80cfcfcSbellard //#define DEBUG_IRQ_COUNT
36e80cfcfcSbellard 
37e80cfcfcSbellard /*
38e80cfcfcSbellard  * Registers of interrupt controller in sun4m.
39e80cfcfcSbellard  *
40e80cfcfcSbellard  * This is the interrupt controller part of chip STP2001 (Slave I/O), also
41e80cfcfcSbellard  * produced as NCR89C105. See
42e80cfcfcSbellard  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
43e80cfcfcSbellard  *
44e80cfcfcSbellard  * There is a system master controller and one for each cpu.
45e80cfcfcSbellard  *
46e80cfcfcSbellard  */
47e80cfcfcSbellard 
48e80cfcfcSbellard #define MAX_CPUS 16
49b3a23197Sblueswir1 #define MAX_PILS 16
50e80cfcfcSbellard 
51a1961a4bSBlue Swirl struct SLAVIO_INTCTLState;
52a1961a4bSBlue Swirl 
53a1961a4bSBlue Swirl typedef struct SLAVIO_CPUINTCTLState {
548bb5ef33SBenoît Canet     MemoryRegion iomem;
55a1961a4bSBlue Swirl     struct SLAVIO_INTCTLState *master;
5607dd0035SBlue Swirl     uint32_t intreg_pending;
57a1961a4bSBlue Swirl     uint32_t cpu;
58462eda24SBlue Swirl     uint32_t irl_out;
59a1961a4bSBlue Swirl } SLAVIO_CPUINTCTLState;
60a8f48dccSblueswir1 
617abad863SAndreas Färber #define TYPE_SLAVIO_INTCTL "slavio_intctl"
62*8063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(SLAVIO_INTCTLState, SLAVIO_INTCTL)
637abad863SAndreas Färber 
64db1015e9SEduardo Habkost struct SLAVIO_INTCTLState {
657abad863SAndreas Färber     SysBusDevice parent_obj;
667abad863SAndreas Färber 
6713c89a11SBenoît Canet     MemoryRegion iomem;
68e80cfcfcSbellard #ifdef DEBUG_IRQ_COUNT
69e80cfcfcSbellard     uint64_t irq_count[32];
70e80cfcfcSbellard #endif
71a1961a4bSBlue Swirl     qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
72a1961a4bSBlue Swirl     SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
7307dd0035SBlue Swirl     uint32_t intregm_pending;
7407dd0035SBlue Swirl     uint32_t intregm_disabled;
7507dd0035SBlue Swirl     uint32_t target_cpu;
76db1015e9SEduardo Habkost };
77e80cfcfcSbellard 
78e80cfcfcSbellard #define INTCTL_MAXADDR 0xf
795aca8c3bSblueswir1 #define INTCTL_SIZE (INTCTL_MAXADDR + 1)
80a8f48dccSblueswir1 #define INTCTLM_SIZE 0x14
8180be36b8Sblueswir1 #define MASTER_IRQ_MASK ~0x0fa2007f
829a87ce9bSblueswir1 #define MASTER_DISABLE 0x80000000
836341fdcbSblueswir1 #define CPU_SOFTIRQ_MASK 0xfffe0000
84462eda24SBlue Swirl #define CPU_IRQ_INT15_IN (1 << 15)
85462eda24SBlue Swirl #define CPU_IRQ_TIMER_IN (1 << 14)
869a87ce9bSblueswir1 
870d0a7e69SBlue Swirl static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
88e80cfcfcSbellard 
89e80cfcfcSbellard // per-cpu interrupt controller
90a8170e5eSAvi Kivity static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr,
918bb5ef33SBenoît Canet                                         unsigned size)
92e80cfcfcSbellard {
93a8f48dccSblueswir1     SLAVIO_CPUINTCTLState *s = opaque;
94dd4131b3Sblueswir1     uint32_t saddr, ret;
95e80cfcfcSbellard 
96a8f48dccSblueswir1     saddr = addr >> 2;
97e80cfcfcSbellard     switch (saddr) {
98e80cfcfcSbellard     case 0:
99a8f48dccSblueswir1         ret = s->intreg_pending;
100dd4131b3Sblueswir1         break;
101e80cfcfcSbellard     default:
102dd4131b3Sblueswir1         ret = 0;
103e80cfcfcSbellard         break;
104e80cfcfcSbellard     }
10597bf4851SBlue Swirl     trace_slavio_intctl_mem_readl(s->cpu, addr, ret);
106dd4131b3Sblueswir1 
107dd4131b3Sblueswir1     return ret;
108e80cfcfcSbellard }
109e80cfcfcSbellard 
110a8170e5eSAvi Kivity static void slavio_intctl_mem_writel(void *opaque, hwaddr addr,
1118bb5ef33SBenoît Canet                                      uint64_t val, unsigned size)
112e80cfcfcSbellard {
113a8f48dccSblueswir1     SLAVIO_CPUINTCTLState *s = opaque;
114e80cfcfcSbellard     uint32_t saddr;
115e80cfcfcSbellard 
116a8f48dccSblueswir1     saddr = addr >> 2;
11797bf4851SBlue Swirl     trace_slavio_intctl_mem_writel(s->cpu, addr, val);
118e80cfcfcSbellard     switch (saddr) {
119e80cfcfcSbellard     case 1: // clear pending softints
120462eda24SBlue Swirl         val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
121a8f48dccSblueswir1         s->intreg_pending &= ~val;
1220d0a7e69SBlue Swirl         slavio_check_interrupts(s->master, 1);
12397bf4851SBlue Swirl         trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending);
124e80cfcfcSbellard         break;
125e80cfcfcSbellard     case 2: // set softint
1266341fdcbSblueswir1         val &= CPU_SOFTIRQ_MASK;
127a8f48dccSblueswir1         s->intreg_pending |= val;
1280d0a7e69SBlue Swirl         slavio_check_interrupts(s->master, 1);
12997bf4851SBlue Swirl         trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending);
130e80cfcfcSbellard         break;
131e80cfcfcSbellard     default:
132e80cfcfcSbellard         break;
133e80cfcfcSbellard     }
134e80cfcfcSbellard }
135e80cfcfcSbellard 
1368bb5ef33SBenoît Canet static const MemoryRegionOps slavio_intctl_mem_ops = {
1378bb5ef33SBenoît Canet     .read = slavio_intctl_mem_readl,
1388bb5ef33SBenoît Canet     .write = slavio_intctl_mem_writel,
1398bb5ef33SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
1408bb5ef33SBenoît Canet     .valid = {
1418bb5ef33SBenoît Canet         .min_access_size = 4,
1428bb5ef33SBenoît Canet         .max_access_size = 4,
1438bb5ef33SBenoît Canet     },
144e80cfcfcSbellard };
145e80cfcfcSbellard 
146e80cfcfcSbellard // master system interrupt controller
147a8170e5eSAvi Kivity static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr,
14813c89a11SBenoît Canet                                          unsigned size)
149e80cfcfcSbellard {
150e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
151dd4131b3Sblueswir1     uint32_t saddr, ret;
152e80cfcfcSbellard 
153a8f48dccSblueswir1     saddr = addr >> 2;
154e80cfcfcSbellard     switch (saddr) {
155e80cfcfcSbellard     case 0:
1569a87ce9bSblueswir1         ret = s->intregm_pending & ~MASTER_DISABLE;
157dd4131b3Sblueswir1         break;
158e80cfcfcSbellard     case 1:
15980be36b8Sblueswir1         ret = s->intregm_disabled & MASTER_IRQ_MASK;
160dd4131b3Sblueswir1         break;
161e80cfcfcSbellard     case 4:
162dd4131b3Sblueswir1         ret = s->target_cpu;
163dd4131b3Sblueswir1         break;
164e80cfcfcSbellard     default:
165dd4131b3Sblueswir1         ret = 0;
166e80cfcfcSbellard         break;
167e80cfcfcSbellard     }
16897bf4851SBlue Swirl     trace_slavio_intctlm_mem_readl(addr, ret);
169dd4131b3Sblueswir1 
170dd4131b3Sblueswir1     return ret;
171e80cfcfcSbellard }
172e80cfcfcSbellard 
173a8170e5eSAvi Kivity static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr,
17413c89a11SBenoît Canet                                       uint64_t val, unsigned size)
175e80cfcfcSbellard {
176e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
177e80cfcfcSbellard     uint32_t saddr;
178e80cfcfcSbellard 
179a8f48dccSblueswir1     saddr = addr >> 2;
18097bf4851SBlue Swirl     trace_slavio_intctlm_mem_writel(addr, val);
181e80cfcfcSbellard     switch (saddr) {
182e80cfcfcSbellard     case 2: // clear (enable)
1836bae7071Sbellard         // Force clear unused bits
1849a87ce9bSblueswir1         val &= MASTER_IRQ_MASK;
185e80cfcfcSbellard         s->intregm_disabled &= ~val;
18697bf4851SBlue Swirl         trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled);
1870d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
188e80cfcfcSbellard         break;
18910760f0fSArtyom Tarasenko     case 3: // set (disable; doesn't affect pending)
1906bae7071Sbellard         // Force clear unused bits
1919a87ce9bSblueswir1         val &= MASTER_IRQ_MASK;
192e80cfcfcSbellard         s->intregm_disabled |= val;
1930d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
19497bf4851SBlue Swirl         trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled);
195e80cfcfcSbellard         break;
196e80cfcfcSbellard     case 4:
197e80cfcfcSbellard         s->target_cpu = val & (MAX_CPUS - 1);
1980d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
19997bf4851SBlue Swirl         trace_slavio_intctlm_mem_writel_target(s->target_cpu);
200e80cfcfcSbellard         break;
201e80cfcfcSbellard     default:
202e80cfcfcSbellard         break;
203e80cfcfcSbellard     }
204e80cfcfcSbellard }
205e80cfcfcSbellard 
20613c89a11SBenoît Canet static const MemoryRegionOps slavio_intctlm_mem_ops = {
20713c89a11SBenoît Canet     .read = slavio_intctlm_mem_readl,
20813c89a11SBenoît Canet     .write = slavio_intctlm_mem_writel,
20913c89a11SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
21013c89a11SBenoît Canet     .valid = {
21113c89a11SBenoît Canet         .min_access_size = 4,
21213c89a11SBenoît Canet         .max_access_size = 4,
21313c89a11SBenoît Canet     },
214e80cfcfcSbellard };
215e80cfcfcSbellard 
21668556e2eSBlue Swirl static const uint32_t intbit_to_level[] = {
217462eda24SBlue Swirl     2, 3, 5, 7, 9, 11, 13, 2,   3, 5, 7, 9, 11, 13, 12, 12,
218462eda24SBlue Swirl     6, 13, 4, 10, 8, 9, 11, 0,  0, 0, 0, 15, 15, 15, 15, 0,
21968556e2eSBlue Swirl };
22068556e2eSBlue Swirl 
2210d0a7e69SBlue Swirl static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
22266321a11Sbellard {
223327ac2e7Sblueswir1     uint32_t pending = s->intregm_pending, pil_pending;
224327ac2e7Sblueswir1     unsigned int i, j;
22566321a11Sbellard 
22666321a11Sbellard     pending &= ~s->intregm_disabled;
22766321a11Sbellard 
22897bf4851SBlue Swirl     trace_slavio_check_interrupts(pending, s->intregm_disabled);
229ba3c64fbSbellard     for (i = 0; i < MAX_CPUS; i++) {
230327ac2e7Sblueswir1         pil_pending = 0;
231462eda24SBlue Swirl 
232462eda24SBlue Swirl         /* If we are the current interrupt target, get hard interrupts */
2339a87ce9bSblueswir1         if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
234b3a23197Sblueswir1             (i == s->target_cpu)) {
235b3a23197Sblueswir1             for (j = 0; j < 32; j++) {
236462eda24SBlue Swirl                 if ((pending & (1 << j)) && intbit_to_level[j]) {
23768556e2eSBlue Swirl                     pil_pending |= 1 << intbit_to_level[j];
238b3a23197Sblueswir1                 }
239b3a23197Sblueswir1             }
240462eda24SBlue Swirl         }
241462eda24SBlue Swirl 
242462eda24SBlue Swirl         /* Calculate current pending hard interrupts for display */
243462eda24SBlue Swirl         s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
244462eda24SBlue Swirl             CPU_IRQ_TIMER_IN;
245462eda24SBlue Swirl         if (i == s->target_cpu) {
246462eda24SBlue Swirl             for (j = 0; j < 32; j++) {
2477d45e784SPeter Maydell                 if ((s->intregm_pending & (1U << j)) && intbit_to_level[j]) {
248462eda24SBlue Swirl                     s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
249462eda24SBlue Swirl                 }
250462eda24SBlue Swirl             }
251462eda24SBlue Swirl         }
252462eda24SBlue Swirl 
25394c5f455SArtyom Tarasenko         /* Level 15 and CPU timer interrupts are only masked when
25494c5f455SArtyom Tarasenko            the MASTER_DISABLE bit is set */
25594c5f455SArtyom Tarasenko         if (!(s->intregm_disabled & MASTER_DISABLE)) {
256462eda24SBlue Swirl             pil_pending |= s->slaves[i].intreg_pending &
257462eda24SBlue Swirl                 (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
25894c5f455SArtyom Tarasenko         }
259462eda24SBlue Swirl 
260462eda24SBlue Swirl         /* Add soft interrupts */
261a1961a4bSBlue Swirl         pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
262327ac2e7Sblueswir1 
2630d0a7e69SBlue Swirl         if (set_irqs) {
264c84a88d8SPeter Maydell             /* Since there is not really an interrupt 0 (and pil_pending
265c84a88d8SPeter Maydell              * and irl_out bit zero are thus always zero) there is no need
266c84a88d8SPeter Maydell              * to do anything with cpu_irqs[i][0] and it is OK not to do
267c84a88d8SPeter Maydell              * the j=0 iteration of this loop.
268c84a88d8SPeter Maydell              */
269c84a88d8SPeter Maydell             for (j = MAX_PILS-1; j > 0; j--) {
270327ac2e7Sblueswir1                 if (pil_pending & (1 << j)) {
271462eda24SBlue Swirl                     if (!(s->slaves[i].irl_out & (1 << j))) {
272327ac2e7Sblueswir1                         qemu_irq_raise(s->cpu_irqs[i][j]);
2730d0a7e69SBlue Swirl                     }
274327ac2e7Sblueswir1                 } else {
275462eda24SBlue Swirl                     if (s->slaves[i].irl_out & (1 << j)) {
276327ac2e7Sblueswir1                         qemu_irq_lower(s->cpu_irqs[i][j]);
277ba3c64fbSbellard                     }
278ba3c64fbSbellard                 }
2790d0a7e69SBlue Swirl             }
2800d0a7e69SBlue Swirl         }
281462eda24SBlue Swirl         s->slaves[i].irl_out = pil_pending;
282ba3c64fbSbellard     }
28366321a11Sbellard }
28466321a11Sbellard 
285e80cfcfcSbellard /*
286e80cfcfcSbellard  * "irq" here is the bit number in the system interrupt register to
287e80cfcfcSbellard  * separate serial and keyboard interrupts sharing a level.
288e80cfcfcSbellard  */
289d7edfd27Sblueswir1 static void slavio_set_irq(void *opaque, int irq, int level)
290e80cfcfcSbellard {
291e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
292e80cfcfcSbellard     uint32_t mask = 1 << irq;
29368556e2eSBlue Swirl     uint32_t pil = intbit_to_level[irq];
294462eda24SBlue Swirl     unsigned int i;
295b3a23197Sblueswir1 
29697bf4851SBlue Swirl     trace_slavio_set_irq(s->target_cpu, irq, pil, level);
297e80cfcfcSbellard     if (pil > 0) {
298e80cfcfcSbellard         if (level) {
299327ac2e7Sblueswir1 #ifdef DEBUG_IRQ_COUNT
300327ac2e7Sblueswir1             s->irq_count[pil]++;
301327ac2e7Sblueswir1 #endif
302e80cfcfcSbellard             s->intregm_pending |= mask;
303462eda24SBlue Swirl             if (pil == 15) {
304462eda24SBlue Swirl                 for (i = 0; i < MAX_CPUS; i++) {
305462eda24SBlue Swirl                     s->slaves[i].intreg_pending |= 1 << pil;
306462eda24SBlue Swirl                 }
307462eda24SBlue Swirl             }
308b3a23197Sblueswir1         } else {
309e80cfcfcSbellard             s->intregm_pending &= ~mask;
310462eda24SBlue Swirl             if (pil == 15) {
311462eda24SBlue Swirl                 for (i = 0; i < MAX_CPUS; i++) {
312462eda24SBlue Swirl                     s->slaves[i].intreg_pending &= ~(1 << pil);
313462eda24SBlue Swirl                 }
314462eda24SBlue Swirl             }
315e80cfcfcSbellard         }
3160d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
317e80cfcfcSbellard     }
318e80cfcfcSbellard }
319e80cfcfcSbellard 
320d7edfd27Sblueswir1 static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
321ba3c64fbSbellard {
322ba3c64fbSbellard     SLAVIO_INTCTLState *s = opaque;
323ba3c64fbSbellard 
32497bf4851SBlue Swirl     trace_slavio_set_timer_irq_cpu(cpu, level);
325d7edfd27Sblueswir1 
326e3a79bcaSblueswir1     if (level) {
327462eda24SBlue Swirl         s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
328e3a79bcaSblueswir1     } else {
329462eda24SBlue Swirl         s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
330e3a79bcaSblueswir1     }
331d7edfd27Sblueswir1 
3320d0a7e69SBlue Swirl     slavio_check_interrupts(s, 1);
333ba3c64fbSbellard }
334ba3c64fbSbellard 
335a1961a4bSBlue Swirl static void slavio_set_irq_all(void *opaque, int irq, int level)
336a1961a4bSBlue Swirl {
337a1961a4bSBlue Swirl     if (irq < 32) {
338a1961a4bSBlue Swirl         slavio_set_irq(opaque, irq, level);
339a1961a4bSBlue Swirl     } else {
340a1961a4bSBlue Swirl         slavio_set_timer_irq_cpu(opaque, irq - 32, level);
341a1961a4bSBlue Swirl     }
342a1961a4bSBlue Swirl }
343a1961a4bSBlue Swirl 
344e59fb374SJuan Quintela static int vmstate_intctl_post_load(void *opaque, int version_id)
345e80cfcfcSbellard {
346e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
347e80cfcfcSbellard 
3480d0a7e69SBlue Swirl     slavio_check_interrupts(s, 0);
349e80cfcfcSbellard     return 0;
350e80cfcfcSbellard }
351e80cfcfcSbellard 
352c9e95029SBlue Swirl static const VMStateDescription vmstate_intctl_cpu = {
353c9e95029SBlue Swirl     .name ="slavio_intctl_cpu",
354c9e95029SBlue Swirl     .version_id = 1,
355c9e95029SBlue Swirl     .minimum_version_id = 1,
356c9e95029SBlue Swirl     .fields = (VMStateField[]) {
357c9e95029SBlue Swirl         VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
358c9e95029SBlue Swirl         VMSTATE_END_OF_LIST()
359c9e95029SBlue Swirl     }
360c9e95029SBlue Swirl };
361c9e95029SBlue Swirl 
362c9e95029SBlue Swirl static const VMStateDescription vmstate_intctl = {
363c9e95029SBlue Swirl     .name ="slavio_intctl",
364c9e95029SBlue Swirl     .version_id = 1,
365c9e95029SBlue Swirl     .minimum_version_id = 1,
366752ff2faSJuan Quintela     .post_load = vmstate_intctl_post_load,
367c9e95029SBlue Swirl     .fields = (VMStateField[]) {
368c9e95029SBlue Swirl         VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
369c9e95029SBlue Swirl                              vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
370c9e95029SBlue Swirl         VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
371c9e95029SBlue Swirl         VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
372c9e95029SBlue Swirl         VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
373c9e95029SBlue Swirl         VMSTATE_END_OF_LIST()
374c9e95029SBlue Swirl     }
375c9e95029SBlue Swirl };
376c9e95029SBlue Swirl 
37778971d57SBlue Swirl static void slavio_intctl_reset(DeviceState *d)
378e80cfcfcSbellard {
3797abad863SAndreas Färber     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(d);
380e80cfcfcSbellard     int i;
381e80cfcfcSbellard 
382e80cfcfcSbellard     for (i = 0; i < MAX_CPUS; i++) {
383a1961a4bSBlue Swirl         s->slaves[i].intreg_pending = 0;
384462eda24SBlue Swirl         s->slaves[i].irl_out = 0;
385e80cfcfcSbellard     }
3869a87ce9bSblueswir1     s->intregm_disabled = ~MASTER_IRQ_MASK;
387e80cfcfcSbellard     s->intregm_pending = 0;
388e80cfcfcSbellard     s->target_cpu = 0;
3890d0a7e69SBlue Swirl     slavio_check_interrupts(s, 0);
390e80cfcfcSbellard }
391e80cfcfcSbellard 
392148fbe95SHervé Poussineau #ifdef DEBUG_IRQ_COUNT
393148fbe95SHervé Poussineau static bool slavio_intctl_get_statistics(InterruptStatsProvider *obj,
394148fbe95SHervé Poussineau                                          uint64_t **irq_counts,
395148fbe95SHervé Poussineau                                          unsigned int *nb_irqs)
396148fbe95SHervé Poussineau {
397148fbe95SHervé Poussineau     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
398148fbe95SHervé Poussineau     *irq_counts = s->irq_count;
399148fbe95SHervé Poussineau     *nb_irqs = ARRAY_SIZE(s->irq_count);
400148fbe95SHervé Poussineau     return true;
401148fbe95SHervé Poussineau }
402148fbe95SHervé Poussineau #endif
403148fbe95SHervé Poussineau 
404148fbe95SHervé Poussineau static void slavio_intctl_print_info(InterruptStatsProvider *obj, Monitor *mon)
405148fbe95SHervé Poussineau {
406148fbe95SHervé Poussineau     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
407148fbe95SHervé Poussineau     int i;
408148fbe95SHervé Poussineau 
409148fbe95SHervé Poussineau     for (i = 0; i < MAX_CPUS; i++) {
410148fbe95SHervé Poussineau         monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
411148fbe95SHervé Poussineau                        s->slaves[i].intreg_pending);
412148fbe95SHervé Poussineau     }
413148fbe95SHervé Poussineau     monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
414148fbe95SHervé Poussineau                    s->intregm_pending, s->intregm_disabled);
415148fbe95SHervé Poussineau }
416148fbe95SHervé Poussineau 
417c09008d2Sxiaoqiang.zhao static void slavio_intctl_init(Object *obj)
418e80cfcfcSbellard {
419c09008d2Sxiaoqiang.zhao     DeviceState *dev = DEVICE(obj);
420c09008d2Sxiaoqiang.zhao     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
421c09008d2Sxiaoqiang.zhao     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
422a1961a4bSBlue Swirl     unsigned int i, j;
4238bb5ef33SBenoît Canet     char slave_name[45];
424e80cfcfcSbellard 
4257abad863SAndreas Färber     qdev_init_gpio_in(dev, slavio_set_irq_all, 32 + MAX_CPUS);
426c09008d2Sxiaoqiang.zhao     memory_region_init_io(&s->iomem, obj, &slavio_intctlm_mem_ops, s,
42713c89a11SBenoît Canet                           "master-interrupt-controller", INTCTLM_SIZE);
4287abad863SAndreas Färber     sysbus_init_mmio(sbd, &s->iomem);
429e80cfcfcSbellard 
430e80cfcfcSbellard     for (i = 0; i < MAX_CPUS; i++) {
4318bb5ef33SBenoît Canet         snprintf(slave_name, sizeof(slave_name),
4328bb5ef33SBenoît Canet                  "slave-interrupt-controller-%i", i);
433a1961a4bSBlue Swirl         for (j = 0; j < MAX_PILS; j++) {
4347abad863SAndreas Färber             sysbus_init_irq(sbd, &s->cpu_irqs[i][j]);
435e80cfcfcSbellard         }
4361437c94bSPaolo Bonzini         memory_region_init_io(&s->slaves[i].iomem, OBJECT(s),
4371437c94bSPaolo Bonzini                               &slavio_intctl_mem_ops,
4388bb5ef33SBenoît Canet                               &s->slaves[i], slave_name, INTCTL_SIZE);
4397abad863SAndreas Färber         sysbus_init_mmio(sbd, &s->slaves[i].iomem);
440a1961a4bSBlue Swirl         s->slaves[i].cpu = i;
441a1961a4bSBlue Swirl         s->slaves[i].master = s;
442a1961a4bSBlue Swirl     }
443e80cfcfcSbellard }
444a1961a4bSBlue Swirl 
445999e12bbSAnthony Liguori static void slavio_intctl_class_init(ObjectClass *klass, void *data)
446999e12bbSAnthony Liguori {
44739bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
448148fbe95SHervé Poussineau     InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
449999e12bbSAnthony Liguori 
45039bffca2SAnthony Liguori     dc->reset = slavio_intctl_reset;
45139bffca2SAnthony Liguori     dc->vmsd = &vmstate_intctl;
452148fbe95SHervé Poussineau #ifdef DEBUG_IRQ_COUNT
453148fbe95SHervé Poussineau     ic->get_statistics = slavio_intctl_get_statistics;
454148fbe95SHervé Poussineau #endif
455148fbe95SHervé Poussineau     ic->print_info = slavio_intctl_print_info;
456999e12bbSAnthony Liguori }
457999e12bbSAnthony Liguori 
4588c43a6f0SAndreas Färber static const TypeInfo slavio_intctl_info = {
4597abad863SAndreas Färber     .name          = TYPE_SLAVIO_INTCTL,
46039bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
46139bffca2SAnthony Liguori     .instance_size = sizeof(SLAVIO_INTCTLState),
462c09008d2Sxiaoqiang.zhao     .instance_init = slavio_intctl_init,
463999e12bbSAnthony Liguori     .class_init    = slavio_intctl_class_init,
464148fbe95SHervé Poussineau     .interfaces = (InterfaceInfo[]) {
465148fbe95SHervé Poussineau         { TYPE_INTERRUPT_STATS_PROVIDER },
466148fbe95SHervé Poussineau         { }
467148fbe95SHervé Poussineau     },
468a1961a4bSBlue Swirl };
469a1961a4bSBlue Swirl 
47083f7d43aSAndreas Färber static void slavio_intctl_register_types(void)
471a1961a4bSBlue Swirl {
47239bffca2SAnthony Liguori     type_register_static(&slavio_intctl_info);
473a1961a4bSBlue Swirl }
474a1961a4bSBlue Swirl 
47583f7d43aSAndreas Färber type_init(slavio_intctl_register_types)
476