xref: /qemu/hw/intc/slavio_intctl.c (revision 06b40d250ecfa1633209c2e431a7a38acfd03a98)
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"
270b8fa32fSMarkus Armbruster #include "qemu/module.h"
2883c9f4caSPaolo Bonzini #include "hw/sysbus.h"
29148fbe95SHervé Poussineau #include "hw/intc/intc.h"
3064552b6bSMarkus Armbruster #include "hw/irq.h"
3197bf4851SBlue Swirl #include "trace.h"
32db1015e9SEduardo Habkost #include "qom/object.h"
3387ecb68bSpbrook 
34e80cfcfcSbellard //#define DEBUG_IRQ_COUNT
35e80cfcfcSbellard 
36e80cfcfcSbellard /*
37e80cfcfcSbellard  * Registers of interrupt controller in sun4m.
38e80cfcfcSbellard  *
39e80cfcfcSbellard  * This is the interrupt controller part of chip STP2001 (Slave I/O), also
40e80cfcfcSbellard  * produced as NCR89C105. See
41e80cfcfcSbellard  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
42e80cfcfcSbellard  *
43e80cfcfcSbellard  * There is a system master controller and one for each cpu.
44e80cfcfcSbellard  *
45e80cfcfcSbellard  */
46e80cfcfcSbellard 
47e80cfcfcSbellard #define MAX_CPUS 16
48b3a23197Sblueswir1 #define MAX_PILS 16
49e80cfcfcSbellard 
50a1961a4bSBlue Swirl struct SLAVIO_INTCTLState;
51a1961a4bSBlue Swirl 
52a1961a4bSBlue Swirl typedef struct SLAVIO_CPUINTCTLState {
538bb5ef33SBenoît Canet     MemoryRegion iomem;
54a1961a4bSBlue Swirl     struct SLAVIO_INTCTLState *master;
5507dd0035SBlue Swirl     uint32_t intreg_pending;
56a1961a4bSBlue Swirl     uint32_t cpu;
57462eda24SBlue Swirl     uint32_t irl_out;
58a1961a4bSBlue Swirl } SLAVIO_CPUINTCTLState;
59a8f48dccSblueswir1 
607abad863SAndreas Färber #define TYPE_SLAVIO_INTCTL "slavio_intctl"
618063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(SLAVIO_INTCTLState, SLAVIO_INTCTL)
627abad863SAndreas Färber 
63db1015e9SEduardo Habkost struct SLAVIO_INTCTLState {
647abad863SAndreas Färber     SysBusDevice parent_obj;
657abad863SAndreas Färber 
6613c89a11SBenoît Canet     MemoryRegion iomem;
67e80cfcfcSbellard #ifdef DEBUG_IRQ_COUNT
68e80cfcfcSbellard     uint64_t irq_count[32];
69e80cfcfcSbellard #endif
70a1961a4bSBlue Swirl     qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
71a1961a4bSBlue Swirl     SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
7207dd0035SBlue Swirl     uint32_t intregm_pending;
7307dd0035SBlue Swirl     uint32_t intregm_disabled;
7407dd0035SBlue Swirl     uint32_t target_cpu;
75db1015e9SEduardo Habkost };
76e80cfcfcSbellard 
77e80cfcfcSbellard #define INTCTL_MAXADDR 0xf
785aca8c3bSblueswir1 #define INTCTL_SIZE (INTCTL_MAXADDR + 1)
79a8f48dccSblueswir1 #define INTCTLM_SIZE 0x14
8080be36b8Sblueswir1 #define MASTER_IRQ_MASK ~0x0fa2007f
819a87ce9bSblueswir1 #define MASTER_DISABLE 0x80000000
826341fdcbSblueswir1 #define CPU_SOFTIRQ_MASK 0xfffe0000
83462eda24SBlue Swirl #define CPU_IRQ_INT15_IN (1 << 15)
84462eda24SBlue Swirl #define CPU_IRQ_TIMER_IN (1 << 14)
859a87ce9bSblueswir1 
860d0a7e69SBlue Swirl static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
87e80cfcfcSbellard 
88e80cfcfcSbellard // per-cpu interrupt controller
slavio_intctl_mem_readl(void * opaque,hwaddr addr,unsigned size)89a8170e5eSAvi Kivity static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr,
908bb5ef33SBenoît Canet                                         unsigned size)
91e80cfcfcSbellard {
92a8f48dccSblueswir1     SLAVIO_CPUINTCTLState *s = opaque;
93dd4131b3Sblueswir1     uint32_t saddr, ret;
94e80cfcfcSbellard 
95a8f48dccSblueswir1     saddr = addr >> 2;
96e80cfcfcSbellard     switch (saddr) {
97e80cfcfcSbellard     case 0:
98a8f48dccSblueswir1         ret = s->intreg_pending;
99dd4131b3Sblueswir1         break;
100e80cfcfcSbellard     default:
101dd4131b3Sblueswir1         ret = 0;
102e80cfcfcSbellard         break;
103e80cfcfcSbellard     }
10497bf4851SBlue Swirl     trace_slavio_intctl_mem_readl(s->cpu, addr, ret);
105dd4131b3Sblueswir1 
106dd4131b3Sblueswir1     return ret;
107e80cfcfcSbellard }
108e80cfcfcSbellard 
slavio_intctl_mem_writel(void * opaque,hwaddr addr,uint64_t val,unsigned size)109a8170e5eSAvi Kivity static void slavio_intctl_mem_writel(void *opaque, hwaddr addr,
1108bb5ef33SBenoît Canet                                      uint64_t val, unsigned size)
111e80cfcfcSbellard {
112a8f48dccSblueswir1     SLAVIO_CPUINTCTLState *s = opaque;
113e80cfcfcSbellard     uint32_t saddr;
114e80cfcfcSbellard 
115a8f48dccSblueswir1     saddr = addr >> 2;
11697bf4851SBlue Swirl     trace_slavio_intctl_mem_writel(s->cpu, addr, val);
117e80cfcfcSbellard     switch (saddr) {
118e80cfcfcSbellard     case 1: // clear pending softints
119462eda24SBlue Swirl         val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
120a8f48dccSblueswir1         s->intreg_pending &= ~val;
1210d0a7e69SBlue Swirl         slavio_check_interrupts(s->master, 1);
12297bf4851SBlue Swirl         trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending);
123e80cfcfcSbellard         break;
124e80cfcfcSbellard     case 2: // set softint
1256341fdcbSblueswir1         val &= CPU_SOFTIRQ_MASK;
126a8f48dccSblueswir1         s->intreg_pending |= val;
1270d0a7e69SBlue Swirl         slavio_check_interrupts(s->master, 1);
12897bf4851SBlue Swirl         trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending);
129e80cfcfcSbellard         break;
130e80cfcfcSbellard     default:
131e80cfcfcSbellard         break;
132e80cfcfcSbellard     }
133e80cfcfcSbellard }
134e80cfcfcSbellard 
1358bb5ef33SBenoît Canet static const MemoryRegionOps slavio_intctl_mem_ops = {
1368bb5ef33SBenoît Canet     .read = slavio_intctl_mem_readl,
1378bb5ef33SBenoît Canet     .write = slavio_intctl_mem_writel,
1388bb5ef33SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
1398bb5ef33SBenoît Canet     .valid = {
1408bb5ef33SBenoît Canet         .min_access_size = 4,
1418bb5ef33SBenoît Canet         .max_access_size = 4,
1428bb5ef33SBenoît Canet     },
143e80cfcfcSbellard };
144e80cfcfcSbellard 
145e80cfcfcSbellard // master system interrupt controller
slavio_intctlm_mem_readl(void * opaque,hwaddr addr,unsigned size)146a8170e5eSAvi Kivity static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr,
14713c89a11SBenoît Canet                                          unsigned size)
148e80cfcfcSbellard {
149e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
150dd4131b3Sblueswir1     uint32_t saddr, ret;
151e80cfcfcSbellard 
152a8f48dccSblueswir1     saddr = addr >> 2;
153e80cfcfcSbellard     switch (saddr) {
154e80cfcfcSbellard     case 0:
1559a87ce9bSblueswir1         ret = s->intregm_pending & ~MASTER_DISABLE;
156dd4131b3Sblueswir1         break;
157e80cfcfcSbellard     case 1:
15880be36b8Sblueswir1         ret = s->intregm_disabled & MASTER_IRQ_MASK;
159dd4131b3Sblueswir1         break;
160e80cfcfcSbellard     case 4:
161dd4131b3Sblueswir1         ret = s->target_cpu;
162dd4131b3Sblueswir1         break;
163e80cfcfcSbellard     default:
164dd4131b3Sblueswir1         ret = 0;
165e80cfcfcSbellard         break;
166e80cfcfcSbellard     }
16797bf4851SBlue Swirl     trace_slavio_intctlm_mem_readl(addr, ret);
168dd4131b3Sblueswir1 
169dd4131b3Sblueswir1     return ret;
170e80cfcfcSbellard }
171e80cfcfcSbellard 
slavio_intctlm_mem_writel(void * opaque,hwaddr addr,uint64_t val,unsigned size)172a8170e5eSAvi Kivity static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr,
17313c89a11SBenoît Canet                                       uint64_t val, unsigned size)
174e80cfcfcSbellard {
175e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
176e80cfcfcSbellard     uint32_t saddr;
177e80cfcfcSbellard 
178a8f48dccSblueswir1     saddr = addr >> 2;
17997bf4851SBlue Swirl     trace_slavio_intctlm_mem_writel(addr, val);
180e80cfcfcSbellard     switch (saddr) {
181e80cfcfcSbellard     case 2: // clear (enable)
1826bae7071Sbellard         // Force clear unused bits
1839a87ce9bSblueswir1         val &= MASTER_IRQ_MASK;
184e80cfcfcSbellard         s->intregm_disabled &= ~val;
18597bf4851SBlue Swirl         trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled);
1860d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
187e80cfcfcSbellard         break;
18810760f0fSArtyom Tarasenko     case 3: // set (disable; doesn't affect pending)
1896bae7071Sbellard         // Force clear unused bits
1909a87ce9bSblueswir1         val &= MASTER_IRQ_MASK;
191e80cfcfcSbellard         s->intregm_disabled |= val;
1920d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
19397bf4851SBlue Swirl         trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled);
194e80cfcfcSbellard         break;
195e80cfcfcSbellard     case 4:
196e80cfcfcSbellard         s->target_cpu = val & (MAX_CPUS - 1);
1970d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
19897bf4851SBlue Swirl         trace_slavio_intctlm_mem_writel_target(s->target_cpu);
199e80cfcfcSbellard         break;
200e80cfcfcSbellard     default:
201e80cfcfcSbellard         break;
202e80cfcfcSbellard     }
203e80cfcfcSbellard }
204e80cfcfcSbellard 
20513c89a11SBenoît Canet static const MemoryRegionOps slavio_intctlm_mem_ops = {
20613c89a11SBenoît Canet     .read = slavio_intctlm_mem_readl,
20713c89a11SBenoît Canet     .write = slavio_intctlm_mem_writel,
20813c89a11SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
20913c89a11SBenoît Canet     .valid = {
21013c89a11SBenoît Canet         .min_access_size = 4,
21113c89a11SBenoît Canet         .max_access_size = 4,
21213c89a11SBenoît Canet     },
213e80cfcfcSbellard };
214e80cfcfcSbellard 
21568556e2eSBlue Swirl static const uint32_t intbit_to_level[] = {
216462eda24SBlue Swirl     2, 3, 5, 7, 9, 11, 13, 2,   3, 5, 7, 9, 11, 13, 12, 12,
217462eda24SBlue Swirl     6, 13, 4, 10, 8, 9, 11, 0,  0, 0, 0, 15, 15, 15, 15, 0,
21868556e2eSBlue Swirl };
21968556e2eSBlue Swirl 
slavio_check_interrupts(SLAVIO_INTCTLState * s,int set_irqs)2200d0a7e69SBlue Swirl static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
22166321a11Sbellard {
222327ac2e7Sblueswir1     uint32_t pending = s->intregm_pending, pil_pending;
223327ac2e7Sblueswir1     unsigned int i, j;
22466321a11Sbellard 
22566321a11Sbellard     pending &= ~s->intregm_disabled;
22666321a11Sbellard 
22797bf4851SBlue Swirl     trace_slavio_check_interrupts(pending, s->intregm_disabled);
228ba3c64fbSbellard     for (i = 0; i < MAX_CPUS; i++) {
229327ac2e7Sblueswir1         pil_pending = 0;
230462eda24SBlue Swirl 
231462eda24SBlue Swirl         /* If we are the current interrupt target, get hard interrupts */
2329a87ce9bSblueswir1         if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
233b3a23197Sblueswir1             (i == s->target_cpu)) {
234b3a23197Sblueswir1             for (j = 0; j < 32; j++) {
235462eda24SBlue Swirl                 if ((pending & (1 << j)) && intbit_to_level[j]) {
23668556e2eSBlue Swirl                     pil_pending |= 1 << intbit_to_level[j];
237b3a23197Sblueswir1                 }
238b3a23197Sblueswir1             }
239462eda24SBlue Swirl         }
240462eda24SBlue Swirl 
241462eda24SBlue Swirl         /* Calculate current pending hard interrupts for display */
242462eda24SBlue Swirl         s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
243462eda24SBlue Swirl             CPU_IRQ_TIMER_IN;
244462eda24SBlue Swirl         if (i == s->target_cpu) {
245462eda24SBlue Swirl             for (j = 0; j < 32; j++) {
2467d45e784SPeter Maydell                 if ((s->intregm_pending & (1U << j)) && intbit_to_level[j]) {
247462eda24SBlue Swirl                     s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
248462eda24SBlue Swirl                 }
249462eda24SBlue Swirl             }
250462eda24SBlue Swirl         }
251462eda24SBlue Swirl 
25294c5f455SArtyom Tarasenko         /* Level 15 and CPU timer interrupts are only masked when
25394c5f455SArtyom Tarasenko            the MASTER_DISABLE bit is set */
25494c5f455SArtyom Tarasenko         if (!(s->intregm_disabled & MASTER_DISABLE)) {
255462eda24SBlue Swirl             pil_pending |= s->slaves[i].intreg_pending &
256462eda24SBlue Swirl                 (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
25794c5f455SArtyom Tarasenko         }
258462eda24SBlue Swirl 
259462eda24SBlue Swirl         /* Add soft interrupts */
260a1961a4bSBlue Swirl         pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
261327ac2e7Sblueswir1 
2620d0a7e69SBlue Swirl         if (set_irqs) {
263c84a88d8SPeter Maydell             /* Since there is not really an interrupt 0 (and pil_pending
264c84a88d8SPeter Maydell              * and irl_out bit zero are thus always zero) there is no need
265c84a88d8SPeter Maydell              * to do anything with cpu_irqs[i][0] and it is OK not to do
266c84a88d8SPeter Maydell              * the j=0 iteration of this loop.
267c84a88d8SPeter Maydell              */
268c84a88d8SPeter Maydell             for (j = MAX_PILS-1; j > 0; j--) {
269327ac2e7Sblueswir1                 if (pil_pending & (1 << j)) {
270462eda24SBlue Swirl                     if (!(s->slaves[i].irl_out & (1 << j))) {
271327ac2e7Sblueswir1                         qemu_irq_raise(s->cpu_irqs[i][j]);
2720d0a7e69SBlue Swirl                     }
273327ac2e7Sblueswir1                 } else {
274462eda24SBlue Swirl                     if (s->slaves[i].irl_out & (1 << j)) {
275327ac2e7Sblueswir1                         qemu_irq_lower(s->cpu_irqs[i][j]);
276ba3c64fbSbellard                     }
277ba3c64fbSbellard                 }
2780d0a7e69SBlue Swirl             }
2790d0a7e69SBlue Swirl         }
280462eda24SBlue Swirl         s->slaves[i].irl_out = pil_pending;
281ba3c64fbSbellard     }
28266321a11Sbellard }
28366321a11Sbellard 
284e80cfcfcSbellard /*
285e80cfcfcSbellard  * "irq" here is the bit number in the system interrupt register to
286e80cfcfcSbellard  * separate serial and keyboard interrupts sharing a level.
287e80cfcfcSbellard  */
slavio_set_irq(void * opaque,int irq,int level)288d7edfd27Sblueswir1 static void slavio_set_irq(void *opaque, int irq, int level)
289e80cfcfcSbellard {
290e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
291e80cfcfcSbellard     uint32_t mask = 1 << irq;
29268556e2eSBlue Swirl     uint32_t pil = intbit_to_level[irq];
293462eda24SBlue Swirl     unsigned int i;
294b3a23197Sblueswir1 
29597bf4851SBlue Swirl     trace_slavio_set_irq(s->target_cpu, irq, pil, level);
296e80cfcfcSbellard     if (pil > 0) {
297e80cfcfcSbellard         if (level) {
298327ac2e7Sblueswir1 #ifdef DEBUG_IRQ_COUNT
299327ac2e7Sblueswir1             s->irq_count[pil]++;
300327ac2e7Sblueswir1 #endif
301e80cfcfcSbellard             s->intregm_pending |= mask;
302462eda24SBlue Swirl             if (pil == 15) {
303462eda24SBlue Swirl                 for (i = 0; i < MAX_CPUS; i++) {
304462eda24SBlue Swirl                     s->slaves[i].intreg_pending |= 1 << pil;
305462eda24SBlue Swirl                 }
306462eda24SBlue Swirl             }
307b3a23197Sblueswir1         } else {
308e80cfcfcSbellard             s->intregm_pending &= ~mask;
309462eda24SBlue Swirl             if (pil == 15) {
310462eda24SBlue Swirl                 for (i = 0; i < MAX_CPUS; i++) {
311462eda24SBlue Swirl                     s->slaves[i].intreg_pending &= ~(1 << pil);
312462eda24SBlue Swirl                 }
313462eda24SBlue Swirl             }
314e80cfcfcSbellard         }
3150d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
316e80cfcfcSbellard     }
317e80cfcfcSbellard }
318e80cfcfcSbellard 
slavio_set_timer_irq_cpu(void * opaque,int cpu,int level)319d7edfd27Sblueswir1 static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
320ba3c64fbSbellard {
321ba3c64fbSbellard     SLAVIO_INTCTLState *s = opaque;
322ba3c64fbSbellard 
32397bf4851SBlue Swirl     trace_slavio_set_timer_irq_cpu(cpu, level);
324d7edfd27Sblueswir1 
325e3a79bcaSblueswir1     if (level) {
326462eda24SBlue Swirl         s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
327e3a79bcaSblueswir1     } else {
328462eda24SBlue Swirl         s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
329e3a79bcaSblueswir1     }
330d7edfd27Sblueswir1 
3310d0a7e69SBlue Swirl     slavio_check_interrupts(s, 1);
332ba3c64fbSbellard }
333ba3c64fbSbellard 
slavio_set_irq_all(void * opaque,int irq,int level)334a1961a4bSBlue Swirl static void slavio_set_irq_all(void *opaque, int irq, int level)
335a1961a4bSBlue Swirl {
336a1961a4bSBlue Swirl     if (irq < 32) {
337a1961a4bSBlue Swirl         slavio_set_irq(opaque, irq, level);
338a1961a4bSBlue Swirl     } else {
339a1961a4bSBlue Swirl         slavio_set_timer_irq_cpu(opaque, irq - 32, level);
340a1961a4bSBlue Swirl     }
341a1961a4bSBlue Swirl }
342a1961a4bSBlue Swirl 
vmstate_intctl_post_load(void * opaque,int version_id)343e59fb374SJuan Quintela static int vmstate_intctl_post_load(void *opaque, int version_id)
344e80cfcfcSbellard {
345e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
346e80cfcfcSbellard 
3470d0a7e69SBlue Swirl     slavio_check_interrupts(s, 0);
348e80cfcfcSbellard     return 0;
349e80cfcfcSbellard }
350e80cfcfcSbellard 
351c9e95029SBlue Swirl static const VMStateDescription vmstate_intctl_cpu = {
352c9e95029SBlue Swirl     .name ="slavio_intctl_cpu",
353c9e95029SBlue Swirl     .version_id = 1,
354c9e95029SBlue Swirl     .minimum_version_id = 1,
35545b1f81dSRichard Henderson     .fields = (const VMStateField[]) {
356c9e95029SBlue Swirl         VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
357c9e95029SBlue Swirl         VMSTATE_END_OF_LIST()
358c9e95029SBlue Swirl     }
359c9e95029SBlue Swirl };
360c9e95029SBlue Swirl 
361c9e95029SBlue Swirl static const VMStateDescription vmstate_intctl = {
362c9e95029SBlue Swirl     .name ="slavio_intctl",
363c9e95029SBlue Swirl     .version_id = 1,
364c9e95029SBlue Swirl     .minimum_version_id = 1,
365752ff2faSJuan Quintela     .post_load = vmstate_intctl_post_load,
36645b1f81dSRichard Henderson     .fields = (const VMStateField[]) {
367c9e95029SBlue Swirl         VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
368c9e95029SBlue Swirl                              vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
369c9e95029SBlue Swirl         VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
370c9e95029SBlue Swirl         VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
371c9e95029SBlue Swirl         VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
372c9e95029SBlue Swirl         VMSTATE_END_OF_LIST()
373c9e95029SBlue Swirl     }
374c9e95029SBlue Swirl };
375c9e95029SBlue Swirl 
slavio_intctl_reset(DeviceState * d)37678971d57SBlue Swirl static void slavio_intctl_reset(DeviceState *d)
377e80cfcfcSbellard {
3787abad863SAndreas Färber     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(d);
379e80cfcfcSbellard     int i;
380e80cfcfcSbellard 
381e80cfcfcSbellard     for (i = 0; i < MAX_CPUS; i++) {
382a1961a4bSBlue Swirl         s->slaves[i].intreg_pending = 0;
383462eda24SBlue Swirl         s->slaves[i].irl_out = 0;
384e80cfcfcSbellard     }
3859a87ce9bSblueswir1     s->intregm_disabled = ~MASTER_IRQ_MASK;
386e80cfcfcSbellard     s->intregm_pending = 0;
387e80cfcfcSbellard     s->target_cpu = 0;
3880d0a7e69SBlue Swirl     slavio_check_interrupts(s, 0);
389e80cfcfcSbellard }
390e80cfcfcSbellard 
391148fbe95SHervé Poussineau #ifdef DEBUG_IRQ_COUNT
slavio_intctl_get_statistics(InterruptStatsProvider * obj,uint64_t ** irq_counts,unsigned int * nb_irqs)392148fbe95SHervé Poussineau static bool slavio_intctl_get_statistics(InterruptStatsProvider *obj,
393148fbe95SHervé Poussineau                                          uint64_t **irq_counts,
394148fbe95SHervé Poussineau                                          unsigned int *nb_irqs)
395148fbe95SHervé Poussineau {
396148fbe95SHervé Poussineau     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
397148fbe95SHervé Poussineau     *irq_counts = s->irq_count;
398148fbe95SHervé Poussineau     *nb_irqs = ARRAY_SIZE(s->irq_count);
399148fbe95SHervé Poussineau     return true;
400148fbe95SHervé Poussineau }
401148fbe95SHervé Poussineau #endif
402148fbe95SHervé Poussineau 
slavio_intctl_print_info(InterruptStatsProvider * obj,GString * buf)403b2580720SPhilippe Mathieu-Daudé static void slavio_intctl_print_info(InterruptStatsProvider *obj, GString *buf)
404148fbe95SHervé Poussineau {
405148fbe95SHervé Poussineau     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
406148fbe95SHervé Poussineau     int i;
407148fbe95SHervé Poussineau 
408148fbe95SHervé Poussineau     for (i = 0; i < MAX_CPUS; i++) {
409b2580720SPhilippe Mathieu-Daudé         g_string_append_printf(buf, "per-cpu %d: pending 0x%08x\n", i,
410148fbe95SHervé Poussineau                                s->slaves[i].intreg_pending);
411148fbe95SHervé Poussineau     }
412b2580720SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "master: pending 0x%08x, disabled 0x%08x\n",
413148fbe95SHervé Poussineau                            s->intregm_pending, s->intregm_disabled);
414148fbe95SHervé Poussineau }
415148fbe95SHervé Poussineau 
slavio_intctl_init(Object * obj)416c09008d2Sxiaoqiang.zhao static void slavio_intctl_init(Object *obj)
417e80cfcfcSbellard {
418c09008d2Sxiaoqiang.zhao     DeviceState *dev = DEVICE(obj);
419c09008d2Sxiaoqiang.zhao     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
420c09008d2Sxiaoqiang.zhao     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
421a1961a4bSBlue Swirl     unsigned int i, j;
4228bb5ef33SBenoît Canet     char slave_name[45];
423e80cfcfcSbellard 
4247abad863SAndreas Färber     qdev_init_gpio_in(dev, slavio_set_irq_all, 32 + MAX_CPUS);
425c09008d2Sxiaoqiang.zhao     memory_region_init_io(&s->iomem, obj, &slavio_intctlm_mem_ops, s,
42613c89a11SBenoît Canet                           "master-interrupt-controller", INTCTLM_SIZE);
4277abad863SAndreas Färber     sysbus_init_mmio(sbd, &s->iomem);
428e80cfcfcSbellard 
429e80cfcfcSbellard     for (i = 0; i < MAX_CPUS; i++) {
4308bb5ef33SBenoît Canet         snprintf(slave_name, sizeof(slave_name),
4318bb5ef33SBenoît Canet                  "slave-interrupt-controller-%i", i);
432a1961a4bSBlue Swirl         for (j = 0; j < MAX_PILS; j++) {
4337abad863SAndreas Färber             sysbus_init_irq(sbd, &s->cpu_irqs[i][j]);
434e80cfcfcSbellard         }
4351437c94bSPaolo Bonzini         memory_region_init_io(&s->slaves[i].iomem, OBJECT(s),
4361437c94bSPaolo Bonzini                               &slavio_intctl_mem_ops,
4378bb5ef33SBenoît Canet                               &s->slaves[i], slave_name, INTCTL_SIZE);
4387abad863SAndreas Färber         sysbus_init_mmio(sbd, &s->slaves[i].iomem);
439a1961a4bSBlue Swirl         s->slaves[i].cpu = i;
440a1961a4bSBlue Swirl         s->slaves[i].master = s;
441a1961a4bSBlue Swirl     }
442e80cfcfcSbellard }
443a1961a4bSBlue Swirl 
slavio_intctl_class_init(ObjectClass * klass,const void * data)44412d1a768SPhilippe Mathieu-Daudé static void slavio_intctl_class_init(ObjectClass *klass, const void *data)
445999e12bbSAnthony Liguori {
44639bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
447148fbe95SHervé Poussineau     InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
448999e12bbSAnthony Liguori 
449e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, slavio_intctl_reset);
45039bffca2SAnthony Liguori     dc->vmsd = &vmstate_intctl;
451148fbe95SHervé Poussineau #ifdef DEBUG_IRQ_COUNT
452148fbe95SHervé Poussineau     ic->get_statistics = slavio_intctl_get_statistics;
453148fbe95SHervé Poussineau #endif
454148fbe95SHervé Poussineau     ic->print_info = slavio_intctl_print_info;
455999e12bbSAnthony Liguori }
456999e12bbSAnthony Liguori 
4578c43a6f0SAndreas Färber static const TypeInfo slavio_intctl_info = {
4587abad863SAndreas Färber     .name          = TYPE_SLAVIO_INTCTL,
45939bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
46039bffca2SAnthony Liguori     .instance_size = sizeof(SLAVIO_INTCTLState),
461c09008d2Sxiaoqiang.zhao     .instance_init = slavio_intctl_init,
462999e12bbSAnthony Liguori     .class_init    = slavio_intctl_class_init,
463*2cd09e47SPhilippe Mathieu-Daudé     .interfaces = (const InterfaceInfo[]) {
464148fbe95SHervé Poussineau         { TYPE_INTERRUPT_STATS_PROVIDER },
465148fbe95SHervé Poussineau         { }
466148fbe95SHervé Poussineau     },
467a1961a4bSBlue Swirl };
468a1961a4bSBlue Swirl 
slavio_intctl_register_types(void)46983f7d43aSAndreas Färber static void slavio_intctl_register_types(void)
470a1961a4bSBlue Swirl {
47139bffca2SAnthony Liguori     type_register_static(&slavio_intctl_info);
472a1961a4bSBlue Swirl }
473a1961a4bSBlue Swirl 
47483f7d43aSAndreas Färber type_init(slavio_intctl_register_types)
475