xref: /qemu/hw/intc/slavio_intctl.c (revision db1015e92e04835c9eb50c29625fe566d1202dbd)
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"
33*db1015e9SEduardo 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*db1015e9SEduardo Habkost typedef struct SLAVIO_INTCTLState SLAVIO_INTCTLState;
637abad863SAndreas Färber #define SLAVIO_INTCTL(obj) \
647abad863SAndreas Färber     OBJECT_CHECK(SLAVIO_INTCTLState, (obj), TYPE_SLAVIO_INTCTL)
657abad863SAndreas Färber 
66*db1015e9SEduardo Habkost struct SLAVIO_INTCTLState {
677abad863SAndreas Färber     SysBusDevice parent_obj;
687abad863SAndreas Färber 
6913c89a11SBenoît Canet     MemoryRegion iomem;
70e80cfcfcSbellard #ifdef DEBUG_IRQ_COUNT
71e80cfcfcSbellard     uint64_t irq_count[32];
72e80cfcfcSbellard #endif
73a1961a4bSBlue Swirl     qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
74a1961a4bSBlue Swirl     SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
7507dd0035SBlue Swirl     uint32_t intregm_pending;
7607dd0035SBlue Swirl     uint32_t intregm_disabled;
7707dd0035SBlue Swirl     uint32_t target_cpu;
78*db1015e9SEduardo Habkost };
79e80cfcfcSbellard 
80e80cfcfcSbellard #define INTCTL_MAXADDR 0xf
815aca8c3bSblueswir1 #define INTCTL_SIZE (INTCTL_MAXADDR + 1)
82a8f48dccSblueswir1 #define INTCTLM_SIZE 0x14
8380be36b8Sblueswir1 #define MASTER_IRQ_MASK ~0x0fa2007f
849a87ce9bSblueswir1 #define MASTER_DISABLE 0x80000000
856341fdcbSblueswir1 #define CPU_SOFTIRQ_MASK 0xfffe0000
86462eda24SBlue Swirl #define CPU_IRQ_INT15_IN (1 << 15)
87462eda24SBlue Swirl #define CPU_IRQ_TIMER_IN (1 << 14)
889a87ce9bSblueswir1 
890d0a7e69SBlue Swirl static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
90e80cfcfcSbellard 
91e80cfcfcSbellard // per-cpu interrupt controller
92a8170e5eSAvi Kivity static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr,
938bb5ef33SBenoît Canet                                         unsigned size)
94e80cfcfcSbellard {
95a8f48dccSblueswir1     SLAVIO_CPUINTCTLState *s = opaque;
96dd4131b3Sblueswir1     uint32_t saddr, ret;
97e80cfcfcSbellard 
98a8f48dccSblueswir1     saddr = addr >> 2;
99e80cfcfcSbellard     switch (saddr) {
100e80cfcfcSbellard     case 0:
101a8f48dccSblueswir1         ret = s->intreg_pending;
102dd4131b3Sblueswir1         break;
103e80cfcfcSbellard     default:
104dd4131b3Sblueswir1         ret = 0;
105e80cfcfcSbellard         break;
106e80cfcfcSbellard     }
10797bf4851SBlue Swirl     trace_slavio_intctl_mem_readl(s->cpu, addr, ret);
108dd4131b3Sblueswir1 
109dd4131b3Sblueswir1     return ret;
110e80cfcfcSbellard }
111e80cfcfcSbellard 
112a8170e5eSAvi Kivity static void slavio_intctl_mem_writel(void *opaque, hwaddr addr,
1138bb5ef33SBenoît Canet                                      uint64_t val, unsigned size)
114e80cfcfcSbellard {
115a8f48dccSblueswir1     SLAVIO_CPUINTCTLState *s = opaque;
116e80cfcfcSbellard     uint32_t saddr;
117e80cfcfcSbellard 
118a8f48dccSblueswir1     saddr = addr >> 2;
11997bf4851SBlue Swirl     trace_slavio_intctl_mem_writel(s->cpu, addr, val);
120e80cfcfcSbellard     switch (saddr) {
121e80cfcfcSbellard     case 1: // clear pending softints
122462eda24SBlue Swirl         val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
123a8f48dccSblueswir1         s->intreg_pending &= ~val;
1240d0a7e69SBlue Swirl         slavio_check_interrupts(s->master, 1);
12597bf4851SBlue Swirl         trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending);
126e80cfcfcSbellard         break;
127e80cfcfcSbellard     case 2: // set softint
1286341fdcbSblueswir1         val &= CPU_SOFTIRQ_MASK;
129a8f48dccSblueswir1         s->intreg_pending |= val;
1300d0a7e69SBlue Swirl         slavio_check_interrupts(s->master, 1);
13197bf4851SBlue Swirl         trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending);
132e80cfcfcSbellard         break;
133e80cfcfcSbellard     default:
134e80cfcfcSbellard         break;
135e80cfcfcSbellard     }
136e80cfcfcSbellard }
137e80cfcfcSbellard 
1388bb5ef33SBenoît Canet static const MemoryRegionOps slavio_intctl_mem_ops = {
1398bb5ef33SBenoît Canet     .read = slavio_intctl_mem_readl,
1408bb5ef33SBenoît Canet     .write = slavio_intctl_mem_writel,
1418bb5ef33SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
1428bb5ef33SBenoît Canet     .valid = {
1438bb5ef33SBenoît Canet         .min_access_size = 4,
1448bb5ef33SBenoît Canet         .max_access_size = 4,
1458bb5ef33SBenoît Canet     },
146e80cfcfcSbellard };
147e80cfcfcSbellard 
148e80cfcfcSbellard // master system interrupt controller
149a8170e5eSAvi Kivity static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr,
15013c89a11SBenoît Canet                                          unsigned size)
151e80cfcfcSbellard {
152e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
153dd4131b3Sblueswir1     uint32_t saddr, ret;
154e80cfcfcSbellard 
155a8f48dccSblueswir1     saddr = addr >> 2;
156e80cfcfcSbellard     switch (saddr) {
157e80cfcfcSbellard     case 0:
1589a87ce9bSblueswir1         ret = s->intregm_pending & ~MASTER_DISABLE;
159dd4131b3Sblueswir1         break;
160e80cfcfcSbellard     case 1:
16180be36b8Sblueswir1         ret = s->intregm_disabled & MASTER_IRQ_MASK;
162dd4131b3Sblueswir1         break;
163e80cfcfcSbellard     case 4:
164dd4131b3Sblueswir1         ret = s->target_cpu;
165dd4131b3Sblueswir1         break;
166e80cfcfcSbellard     default:
167dd4131b3Sblueswir1         ret = 0;
168e80cfcfcSbellard         break;
169e80cfcfcSbellard     }
17097bf4851SBlue Swirl     trace_slavio_intctlm_mem_readl(addr, ret);
171dd4131b3Sblueswir1 
172dd4131b3Sblueswir1     return ret;
173e80cfcfcSbellard }
174e80cfcfcSbellard 
175a8170e5eSAvi Kivity static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr,
17613c89a11SBenoît Canet                                       uint64_t val, unsigned size)
177e80cfcfcSbellard {
178e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
179e80cfcfcSbellard     uint32_t saddr;
180e80cfcfcSbellard 
181a8f48dccSblueswir1     saddr = addr >> 2;
18297bf4851SBlue Swirl     trace_slavio_intctlm_mem_writel(addr, val);
183e80cfcfcSbellard     switch (saddr) {
184e80cfcfcSbellard     case 2: // clear (enable)
1856bae7071Sbellard         // Force clear unused bits
1869a87ce9bSblueswir1         val &= MASTER_IRQ_MASK;
187e80cfcfcSbellard         s->intregm_disabled &= ~val;
18897bf4851SBlue Swirl         trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled);
1890d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
190e80cfcfcSbellard         break;
19110760f0fSArtyom Tarasenko     case 3: // set (disable; doesn't affect pending)
1926bae7071Sbellard         // Force clear unused bits
1939a87ce9bSblueswir1         val &= MASTER_IRQ_MASK;
194e80cfcfcSbellard         s->intregm_disabled |= val;
1950d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
19697bf4851SBlue Swirl         trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled);
197e80cfcfcSbellard         break;
198e80cfcfcSbellard     case 4:
199e80cfcfcSbellard         s->target_cpu = val & (MAX_CPUS - 1);
2000d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
20197bf4851SBlue Swirl         trace_slavio_intctlm_mem_writel_target(s->target_cpu);
202e80cfcfcSbellard         break;
203e80cfcfcSbellard     default:
204e80cfcfcSbellard         break;
205e80cfcfcSbellard     }
206e80cfcfcSbellard }
207e80cfcfcSbellard 
20813c89a11SBenoît Canet static const MemoryRegionOps slavio_intctlm_mem_ops = {
20913c89a11SBenoît Canet     .read = slavio_intctlm_mem_readl,
21013c89a11SBenoît Canet     .write = slavio_intctlm_mem_writel,
21113c89a11SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
21213c89a11SBenoît Canet     .valid = {
21313c89a11SBenoît Canet         .min_access_size = 4,
21413c89a11SBenoît Canet         .max_access_size = 4,
21513c89a11SBenoît Canet     },
216e80cfcfcSbellard };
217e80cfcfcSbellard 
21868556e2eSBlue Swirl static const uint32_t intbit_to_level[] = {
219462eda24SBlue Swirl     2, 3, 5, 7, 9, 11, 13, 2,   3, 5, 7, 9, 11, 13, 12, 12,
220462eda24SBlue Swirl     6, 13, 4, 10, 8, 9, 11, 0,  0, 0, 0, 15, 15, 15, 15, 0,
22168556e2eSBlue Swirl };
22268556e2eSBlue Swirl 
2230d0a7e69SBlue Swirl static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
22466321a11Sbellard {
225327ac2e7Sblueswir1     uint32_t pending = s->intregm_pending, pil_pending;
226327ac2e7Sblueswir1     unsigned int i, j;
22766321a11Sbellard 
22866321a11Sbellard     pending &= ~s->intregm_disabled;
22966321a11Sbellard 
23097bf4851SBlue Swirl     trace_slavio_check_interrupts(pending, s->intregm_disabled);
231ba3c64fbSbellard     for (i = 0; i < MAX_CPUS; i++) {
232327ac2e7Sblueswir1         pil_pending = 0;
233462eda24SBlue Swirl 
234462eda24SBlue Swirl         /* If we are the current interrupt target, get hard interrupts */
2359a87ce9bSblueswir1         if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
236b3a23197Sblueswir1             (i == s->target_cpu)) {
237b3a23197Sblueswir1             for (j = 0; j < 32; j++) {
238462eda24SBlue Swirl                 if ((pending & (1 << j)) && intbit_to_level[j]) {
23968556e2eSBlue Swirl                     pil_pending |= 1 << intbit_to_level[j];
240b3a23197Sblueswir1                 }
241b3a23197Sblueswir1             }
242462eda24SBlue Swirl         }
243462eda24SBlue Swirl 
244462eda24SBlue Swirl         /* Calculate current pending hard interrupts for display */
245462eda24SBlue Swirl         s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
246462eda24SBlue Swirl             CPU_IRQ_TIMER_IN;
247462eda24SBlue Swirl         if (i == s->target_cpu) {
248462eda24SBlue Swirl             for (j = 0; j < 32; j++) {
2497d45e784SPeter Maydell                 if ((s->intregm_pending & (1U << j)) && intbit_to_level[j]) {
250462eda24SBlue Swirl                     s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
251462eda24SBlue Swirl                 }
252462eda24SBlue Swirl             }
253462eda24SBlue Swirl         }
254462eda24SBlue Swirl 
25594c5f455SArtyom Tarasenko         /* Level 15 and CPU timer interrupts are only masked when
25694c5f455SArtyom Tarasenko            the MASTER_DISABLE bit is set */
25794c5f455SArtyom Tarasenko         if (!(s->intregm_disabled & MASTER_DISABLE)) {
258462eda24SBlue Swirl             pil_pending |= s->slaves[i].intreg_pending &
259462eda24SBlue Swirl                 (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
26094c5f455SArtyom Tarasenko         }
261462eda24SBlue Swirl 
262462eda24SBlue Swirl         /* Add soft interrupts */
263a1961a4bSBlue Swirl         pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
264327ac2e7Sblueswir1 
2650d0a7e69SBlue Swirl         if (set_irqs) {
266c84a88d8SPeter Maydell             /* Since there is not really an interrupt 0 (and pil_pending
267c84a88d8SPeter Maydell              * and irl_out bit zero are thus always zero) there is no need
268c84a88d8SPeter Maydell              * to do anything with cpu_irqs[i][0] and it is OK not to do
269c84a88d8SPeter Maydell              * the j=0 iteration of this loop.
270c84a88d8SPeter Maydell              */
271c84a88d8SPeter Maydell             for (j = MAX_PILS-1; j > 0; j--) {
272327ac2e7Sblueswir1                 if (pil_pending & (1 << j)) {
273462eda24SBlue Swirl                     if (!(s->slaves[i].irl_out & (1 << j))) {
274327ac2e7Sblueswir1                         qemu_irq_raise(s->cpu_irqs[i][j]);
2750d0a7e69SBlue Swirl                     }
276327ac2e7Sblueswir1                 } else {
277462eda24SBlue Swirl                     if (s->slaves[i].irl_out & (1 << j)) {
278327ac2e7Sblueswir1                         qemu_irq_lower(s->cpu_irqs[i][j]);
279ba3c64fbSbellard                     }
280ba3c64fbSbellard                 }
2810d0a7e69SBlue Swirl             }
2820d0a7e69SBlue Swirl         }
283462eda24SBlue Swirl         s->slaves[i].irl_out = pil_pending;
284ba3c64fbSbellard     }
28566321a11Sbellard }
28666321a11Sbellard 
287e80cfcfcSbellard /*
288e80cfcfcSbellard  * "irq" here is the bit number in the system interrupt register to
289e80cfcfcSbellard  * separate serial and keyboard interrupts sharing a level.
290e80cfcfcSbellard  */
291d7edfd27Sblueswir1 static void slavio_set_irq(void *opaque, int irq, int level)
292e80cfcfcSbellard {
293e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
294e80cfcfcSbellard     uint32_t mask = 1 << irq;
29568556e2eSBlue Swirl     uint32_t pil = intbit_to_level[irq];
296462eda24SBlue Swirl     unsigned int i;
297b3a23197Sblueswir1 
29897bf4851SBlue Swirl     trace_slavio_set_irq(s->target_cpu, irq, pil, level);
299e80cfcfcSbellard     if (pil > 0) {
300e80cfcfcSbellard         if (level) {
301327ac2e7Sblueswir1 #ifdef DEBUG_IRQ_COUNT
302327ac2e7Sblueswir1             s->irq_count[pil]++;
303327ac2e7Sblueswir1 #endif
304e80cfcfcSbellard             s->intregm_pending |= mask;
305462eda24SBlue Swirl             if (pil == 15) {
306462eda24SBlue Swirl                 for (i = 0; i < MAX_CPUS; i++) {
307462eda24SBlue Swirl                     s->slaves[i].intreg_pending |= 1 << pil;
308462eda24SBlue Swirl                 }
309462eda24SBlue Swirl             }
310b3a23197Sblueswir1         } else {
311e80cfcfcSbellard             s->intregm_pending &= ~mask;
312462eda24SBlue Swirl             if (pil == 15) {
313462eda24SBlue Swirl                 for (i = 0; i < MAX_CPUS; i++) {
314462eda24SBlue Swirl                     s->slaves[i].intreg_pending &= ~(1 << pil);
315462eda24SBlue Swirl                 }
316462eda24SBlue Swirl             }
317e80cfcfcSbellard         }
3180d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
319e80cfcfcSbellard     }
320e80cfcfcSbellard }
321e80cfcfcSbellard 
322d7edfd27Sblueswir1 static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
323ba3c64fbSbellard {
324ba3c64fbSbellard     SLAVIO_INTCTLState *s = opaque;
325ba3c64fbSbellard 
32697bf4851SBlue Swirl     trace_slavio_set_timer_irq_cpu(cpu, level);
327d7edfd27Sblueswir1 
328e3a79bcaSblueswir1     if (level) {
329462eda24SBlue Swirl         s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
330e3a79bcaSblueswir1     } else {
331462eda24SBlue Swirl         s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
332e3a79bcaSblueswir1     }
333d7edfd27Sblueswir1 
3340d0a7e69SBlue Swirl     slavio_check_interrupts(s, 1);
335ba3c64fbSbellard }
336ba3c64fbSbellard 
337a1961a4bSBlue Swirl static void slavio_set_irq_all(void *opaque, int irq, int level)
338a1961a4bSBlue Swirl {
339a1961a4bSBlue Swirl     if (irq < 32) {
340a1961a4bSBlue Swirl         slavio_set_irq(opaque, irq, level);
341a1961a4bSBlue Swirl     } else {
342a1961a4bSBlue Swirl         slavio_set_timer_irq_cpu(opaque, irq - 32, level);
343a1961a4bSBlue Swirl     }
344a1961a4bSBlue Swirl }
345a1961a4bSBlue Swirl 
346e59fb374SJuan Quintela static int vmstate_intctl_post_load(void *opaque, int version_id)
347e80cfcfcSbellard {
348e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
349e80cfcfcSbellard 
3500d0a7e69SBlue Swirl     slavio_check_interrupts(s, 0);
351e80cfcfcSbellard     return 0;
352e80cfcfcSbellard }
353e80cfcfcSbellard 
354c9e95029SBlue Swirl static const VMStateDescription vmstate_intctl_cpu = {
355c9e95029SBlue Swirl     .name ="slavio_intctl_cpu",
356c9e95029SBlue Swirl     .version_id = 1,
357c9e95029SBlue Swirl     .minimum_version_id = 1,
358c9e95029SBlue Swirl     .fields = (VMStateField[]) {
359c9e95029SBlue Swirl         VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
360c9e95029SBlue Swirl         VMSTATE_END_OF_LIST()
361c9e95029SBlue Swirl     }
362c9e95029SBlue Swirl };
363c9e95029SBlue Swirl 
364c9e95029SBlue Swirl static const VMStateDescription vmstate_intctl = {
365c9e95029SBlue Swirl     .name ="slavio_intctl",
366c9e95029SBlue Swirl     .version_id = 1,
367c9e95029SBlue Swirl     .minimum_version_id = 1,
368752ff2faSJuan Quintela     .post_load = vmstate_intctl_post_load,
369c9e95029SBlue Swirl     .fields = (VMStateField[]) {
370c9e95029SBlue Swirl         VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
371c9e95029SBlue Swirl                              vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
372c9e95029SBlue Swirl         VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
373c9e95029SBlue Swirl         VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
374c9e95029SBlue Swirl         VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
375c9e95029SBlue Swirl         VMSTATE_END_OF_LIST()
376c9e95029SBlue Swirl     }
377c9e95029SBlue Swirl };
378c9e95029SBlue Swirl 
37978971d57SBlue Swirl static void slavio_intctl_reset(DeviceState *d)
380e80cfcfcSbellard {
3817abad863SAndreas Färber     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(d);
382e80cfcfcSbellard     int i;
383e80cfcfcSbellard 
384e80cfcfcSbellard     for (i = 0; i < MAX_CPUS; i++) {
385a1961a4bSBlue Swirl         s->slaves[i].intreg_pending = 0;
386462eda24SBlue Swirl         s->slaves[i].irl_out = 0;
387e80cfcfcSbellard     }
3889a87ce9bSblueswir1     s->intregm_disabled = ~MASTER_IRQ_MASK;
389e80cfcfcSbellard     s->intregm_pending = 0;
390e80cfcfcSbellard     s->target_cpu = 0;
3910d0a7e69SBlue Swirl     slavio_check_interrupts(s, 0);
392e80cfcfcSbellard }
393e80cfcfcSbellard 
394148fbe95SHervé Poussineau #ifdef DEBUG_IRQ_COUNT
395148fbe95SHervé Poussineau static bool slavio_intctl_get_statistics(InterruptStatsProvider *obj,
396148fbe95SHervé Poussineau                                          uint64_t **irq_counts,
397148fbe95SHervé Poussineau                                          unsigned int *nb_irqs)
398148fbe95SHervé Poussineau {
399148fbe95SHervé Poussineau     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
400148fbe95SHervé Poussineau     *irq_counts = s->irq_count;
401148fbe95SHervé Poussineau     *nb_irqs = ARRAY_SIZE(s->irq_count);
402148fbe95SHervé Poussineau     return true;
403148fbe95SHervé Poussineau }
404148fbe95SHervé Poussineau #endif
405148fbe95SHervé Poussineau 
406148fbe95SHervé Poussineau static void slavio_intctl_print_info(InterruptStatsProvider *obj, Monitor *mon)
407148fbe95SHervé Poussineau {
408148fbe95SHervé Poussineau     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
409148fbe95SHervé Poussineau     int i;
410148fbe95SHervé Poussineau 
411148fbe95SHervé Poussineau     for (i = 0; i < MAX_CPUS; i++) {
412148fbe95SHervé Poussineau         monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
413148fbe95SHervé Poussineau                        s->slaves[i].intreg_pending);
414148fbe95SHervé Poussineau     }
415148fbe95SHervé Poussineau     monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
416148fbe95SHervé Poussineau                    s->intregm_pending, s->intregm_disabled);
417148fbe95SHervé Poussineau }
418148fbe95SHervé Poussineau 
419c09008d2Sxiaoqiang.zhao static void slavio_intctl_init(Object *obj)
420e80cfcfcSbellard {
421c09008d2Sxiaoqiang.zhao     DeviceState *dev = DEVICE(obj);
422c09008d2Sxiaoqiang.zhao     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
423c09008d2Sxiaoqiang.zhao     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
424a1961a4bSBlue Swirl     unsigned int i, j;
4258bb5ef33SBenoît Canet     char slave_name[45];
426e80cfcfcSbellard 
4277abad863SAndreas Färber     qdev_init_gpio_in(dev, slavio_set_irq_all, 32 + MAX_CPUS);
428c09008d2Sxiaoqiang.zhao     memory_region_init_io(&s->iomem, obj, &slavio_intctlm_mem_ops, s,
42913c89a11SBenoît Canet                           "master-interrupt-controller", INTCTLM_SIZE);
4307abad863SAndreas Färber     sysbus_init_mmio(sbd, &s->iomem);
431e80cfcfcSbellard 
432e80cfcfcSbellard     for (i = 0; i < MAX_CPUS; i++) {
4338bb5ef33SBenoît Canet         snprintf(slave_name, sizeof(slave_name),
4348bb5ef33SBenoît Canet                  "slave-interrupt-controller-%i", i);
435a1961a4bSBlue Swirl         for (j = 0; j < MAX_PILS; j++) {
4367abad863SAndreas Färber             sysbus_init_irq(sbd, &s->cpu_irqs[i][j]);
437e80cfcfcSbellard         }
4381437c94bSPaolo Bonzini         memory_region_init_io(&s->slaves[i].iomem, OBJECT(s),
4391437c94bSPaolo Bonzini                               &slavio_intctl_mem_ops,
4408bb5ef33SBenoît Canet                               &s->slaves[i], slave_name, INTCTL_SIZE);
4417abad863SAndreas Färber         sysbus_init_mmio(sbd, &s->slaves[i].iomem);
442a1961a4bSBlue Swirl         s->slaves[i].cpu = i;
443a1961a4bSBlue Swirl         s->slaves[i].master = s;
444a1961a4bSBlue Swirl     }
445e80cfcfcSbellard }
446a1961a4bSBlue Swirl 
447999e12bbSAnthony Liguori static void slavio_intctl_class_init(ObjectClass *klass, void *data)
448999e12bbSAnthony Liguori {
44939bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
450148fbe95SHervé Poussineau     InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
451999e12bbSAnthony Liguori 
45239bffca2SAnthony Liguori     dc->reset = slavio_intctl_reset;
45339bffca2SAnthony Liguori     dc->vmsd = &vmstate_intctl;
454148fbe95SHervé Poussineau #ifdef DEBUG_IRQ_COUNT
455148fbe95SHervé Poussineau     ic->get_statistics = slavio_intctl_get_statistics;
456148fbe95SHervé Poussineau #endif
457148fbe95SHervé Poussineau     ic->print_info = slavio_intctl_print_info;
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),
464c09008d2Sxiaoqiang.zhao     .instance_init = slavio_intctl_init,
465999e12bbSAnthony Liguori     .class_init    = slavio_intctl_class_init,
466148fbe95SHervé Poussineau     .interfaces = (InterfaceInfo[]) {
467148fbe95SHervé Poussineau         { TYPE_INTERRUPT_STATS_PROVIDER },
468148fbe95SHervé Poussineau         { }
469148fbe95SHervé Poussineau     },
470a1961a4bSBlue Swirl };
471a1961a4bSBlue Swirl 
47283f7d43aSAndreas Färber static void slavio_intctl_register_types(void)
473a1961a4bSBlue Swirl {
47439bffca2SAnthony Liguori     type_register_static(&slavio_intctl_info);
475a1961a4bSBlue Swirl }
476a1961a4bSBlue Swirl 
47783f7d43aSAndreas Färber type_init(slavio_intctl_register_types)
478