xref: /qemu/hw/intc/slavio_intctl.c (revision 148fbe950454a7faf9ffae1763a3a185fcc7233e)
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"
260d09e41aSPaolo Bonzini #include "hw/sparc/sun4m.h"
2783c9089eSPaolo Bonzini #include "monitor/monitor.h"
2883c9f4caSPaolo Bonzini #include "hw/sysbus.h"
29*148fbe95SHervé Poussineau #include "hw/intc/intc.h"
3097bf4851SBlue Swirl #include "trace.h"
3187ecb68bSpbrook 
32e80cfcfcSbellard //#define DEBUG_IRQ_COUNT
33e80cfcfcSbellard 
34e80cfcfcSbellard /*
35e80cfcfcSbellard  * Registers of interrupt controller in sun4m.
36e80cfcfcSbellard  *
37e80cfcfcSbellard  * This is the interrupt controller part of chip STP2001 (Slave I/O), also
38e80cfcfcSbellard  * produced as NCR89C105. See
39e80cfcfcSbellard  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
40e80cfcfcSbellard  *
41e80cfcfcSbellard  * There is a system master controller and one for each cpu.
42e80cfcfcSbellard  *
43e80cfcfcSbellard  */
44e80cfcfcSbellard 
45e80cfcfcSbellard #define MAX_CPUS 16
46b3a23197Sblueswir1 #define MAX_PILS 16
47e80cfcfcSbellard 
48a1961a4bSBlue Swirl struct SLAVIO_INTCTLState;
49a1961a4bSBlue Swirl 
50a1961a4bSBlue Swirl typedef struct SLAVIO_CPUINTCTLState {
518bb5ef33SBenoît Canet     MemoryRegion iomem;
52a1961a4bSBlue Swirl     struct SLAVIO_INTCTLState *master;
5307dd0035SBlue Swirl     uint32_t intreg_pending;
54a1961a4bSBlue Swirl     uint32_t cpu;
55462eda24SBlue Swirl     uint32_t irl_out;
56a1961a4bSBlue Swirl } SLAVIO_CPUINTCTLState;
57a8f48dccSblueswir1 
587abad863SAndreas Färber #define TYPE_SLAVIO_INTCTL "slavio_intctl"
597abad863SAndreas Färber #define SLAVIO_INTCTL(obj) \
607abad863SAndreas Färber     OBJECT_CHECK(SLAVIO_INTCTLState, (obj), TYPE_SLAVIO_INTCTL)
617abad863SAndreas Färber 
62e80cfcfcSbellard typedef struct SLAVIO_INTCTLState {
637abad863SAndreas Färber     SysBusDevice parent_obj;
647abad863SAndreas Färber 
6513c89a11SBenoît Canet     MemoryRegion iomem;
66e80cfcfcSbellard #ifdef DEBUG_IRQ_COUNT
67e80cfcfcSbellard     uint64_t irq_count[32];
68e80cfcfcSbellard #endif
69a1961a4bSBlue Swirl     qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
70a1961a4bSBlue Swirl     SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
7107dd0035SBlue Swirl     uint32_t intregm_pending;
7207dd0035SBlue Swirl     uint32_t intregm_disabled;
7307dd0035SBlue Swirl     uint32_t target_cpu;
74e80cfcfcSbellard } SLAVIO_INTCTLState;
75e80cfcfcSbellard 
76e80cfcfcSbellard #define INTCTL_MAXADDR 0xf
775aca8c3bSblueswir1 #define INTCTL_SIZE (INTCTL_MAXADDR + 1)
78a8f48dccSblueswir1 #define INTCTLM_SIZE 0x14
7980be36b8Sblueswir1 #define MASTER_IRQ_MASK ~0x0fa2007f
809a87ce9bSblueswir1 #define MASTER_DISABLE 0x80000000
816341fdcbSblueswir1 #define CPU_SOFTIRQ_MASK 0xfffe0000
82462eda24SBlue Swirl #define CPU_IRQ_INT15_IN (1 << 15)
83462eda24SBlue Swirl #define CPU_IRQ_TIMER_IN (1 << 14)
849a87ce9bSblueswir1 
850d0a7e69SBlue Swirl static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
86e80cfcfcSbellard 
87e80cfcfcSbellard // per-cpu interrupt controller
88a8170e5eSAvi Kivity static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr,
898bb5ef33SBenoît Canet                                         unsigned size)
90e80cfcfcSbellard {
91a8f48dccSblueswir1     SLAVIO_CPUINTCTLState *s = opaque;
92dd4131b3Sblueswir1     uint32_t saddr, ret;
93e80cfcfcSbellard 
94a8f48dccSblueswir1     saddr = addr >> 2;
95e80cfcfcSbellard     switch (saddr) {
96e80cfcfcSbellard     case 0:
97a8f48dccSblueswir1         ret = s->intreg_pending;
98dd4131b3Sblueswir1         break;
99e80cfcfcSbellard     default:
100dd4131b3Sblueswir1         ret = 0;
101e80cfcfcSbellard         break;
102e80cfcfcSbellard     }
10397bf4851SBlue Swirl     trace_slavio_intctl_mem_readl(s->cpu, addr, ret);
104dd4131b3Sblueswir1 
105dd4131b3Sblueswir1     return ret;
106e80cfcfcSbellard }
107e80cfcfcSbellard 
108a8170e5eSAvi Kivity static void slavio_intctl_mem_writel(void *opaque, hwaddr addr,
1098bb5ef33SBenoît Canet                                      uint64_t val, unsigned size)
110e80cfcfcSbellard {
111a8f48dccSblueswir1     SLAVIO_CPUINTCTLState *s = opaque;
112e80cfcfcSbellard     uint32_t saddr;
113e80cfcfcSbellard 
114a8f48dccSblueswir1     saddr = addr >> 2;
11597bf4851SBlue Swirl     trace_slavio_intctl_mem_writel(s->cpu, addr, val);
116e80cfcfcSbellard     switch (saddr) {
117e80cfcfcSbellard     case 1: // clear pending softints
118462eda24SBlue Swirl         val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
119a8f48dccSblueswir1         s->intreg_pending &= ~val;
1200d0a7e69SBlue Swirl         slavio_check_interrupts(s->master, 1);
12197bf4851SBlue Swirl         trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending);
122e80cfcfcSbellard         break;
123e80cfcfcSbellard     case 2: // set softint
1246341fdcbSblueswir1         val &= CPU_SOFTIRQ_MASK;
125a8f48dccSblueswir1         s->intreg_pending |= val;
1260d0a7e69SBlue Swirl         slavio_check_interrupts(s->master, 1);
12797bf4851SBlue Swirl         trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending);
128e80cfcfcSbellard         break;
129e80cfcfcSbellard     default:
130e80cfcfcSbellard         break;
131e80cfcfcSbellard     }
132e80cfcfcSbellard }
133e80cfcfcSbellard 
1348bb5ef33SBenoît Canet static const MemoryRegionOps slavio_intctl_mem_ops = {
1358bb5ef33SBenoît Canet     .read = slavio_intctl_mem_readl,
1368bb5ef33SBenoît Canet     .write = slavio_intctl_mem_writel,
1378bb5ef33SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
1388bb5ef33SBenoît Canet     .valid = {
1398bb5ef33SBenoît Canet         .min_access_size = 4,
1408bb5ef33SBenoît Canet         .max_access_size = 4,
1418bb5ef33SBenoît Canet     },
142e80cfcfcSbellard };
143e80cfcfcSbellard 
144e80cfcfcSbellard // master system interrupt controller
145a8170e5eSAvi Kivity static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr,
14613c89a11SBenoît Canet                                          unsigned size)
147e80cfcfcSbellard {
148e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
149dd4131b3Sblueswir1     uint32_t saddr, ret;
150e80cfcfcSbellard 
151a8f48dccSblueswir1     saddr = addr >> 2;
152e80cfcfcSbellard     switch (saddr) {
153e80cfcfcSbellard     case 0:
1549a87ce9bSblueswir1         ret = s->intregm_pending & ~MASTER_DISABLE;
155dd4131b3Sblueswir1         break;
156e80cfcfcSbellard     case 1:
15780be36b8Sblueswir1         ret = s->intregm_disabled & MASTER_IRQ_MASK;
158dd4131b3Sblueswir1         break;
159e80cfcfcSbellard     case 4:
160dd4131b3Sblueswir1         ret = s->target_cpu;
161dd4131b3Sblueswir1         break;
162e80cfcfcSbellard     default:
163dd4131b3Sblueswir1         ret = 0;
164e80cfcfcSbellard         break;
165e80cfcfcSbellard     }
16697bf4851SBlue Swirl     trace_slavio_intctlm_mem_readl(addr, ret);
167dd4131b3Sblueswir1 
168dd4131b3Sblueswir1     return ret;
169e80cfcfcSbellard }
170e80cfcfcSbellard 
171a8170e5eSAvi Kivity static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr,
17213c89a11SBenoît Canet                                       uint64_t val, unsigned size)
173e80cfcfcSbellard {
174e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
175e80cfcfcSbellard     uint32_t saddr;
176e80cfcfcSbellard 
177a8f48dccSblueswir1     saddr = addr >> 2;
17897bf4851SBlue Swirl     trace_slavio_intctlm_mem_writel(addr, val);
179e80cfcfcSbellard     switch (saddr) {
180e80cfcfcSbellard     case 2: // clear (enable)
1816bae7071Sbellard         // Force clear unused bits
1829a87ce9bSblueswir1         val &= MASTER_IRQ_MASK;
183e80cfcfcSbellard         s->intregm_disabled &= ~val;
18497bf4851SBlue Swirl         trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled);
1850d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
186e80cfcfcSbellard         break;
18710760f0fSArtyom Tarasenko     case 3: // set (disable; doesn't affect pending)
1886bae7071Sbellard         // Force clear unused bits
1899a87ce9bSblueswir1         val &= MASTER_IRQ_MASK;
190e80cfcfcSbellard         s->intregm_disabled |= val;
1910d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
19297bf4851SBlue Swirl         trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled);
193e80cfcfcSbellard         break;
194e80cfcfcSbellard     case 4:
195e80cfcfcSbellard         s->target_cpu = val & (MAX_CPUS - 1);
1960d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
19797bf4851SBlue Swirl         trace_slavio_intctlm_mem_writel_target(s->target_cpu);
198e80cfcfcSbellard         break;
199e80cfcfcSbellard     default:
200e80cfcfcSbellard         break;
201e80cfcfcSbellard     }
202e80cfcfcSbellard }
203e80cfcfcSbellard 
20413c89a11SBenoît Canet static const MemoryRegionOps slavio_intctlm_mem_ops = {
20513c89a11SBenoît Canet     .read = slavio_intctlm_mem_readl,
20613c89a11SBenoît Canet     .write = slavio_intctlm_mem_writel,
20713c89a11SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
20813c89a11SBenoît Canet     .valid = {
20913c89a11SBenoît Canet         .min_access_size = 4,
21013c89a11SBenoît Canet         .max_access_size = 4,
21113c89a11SBenoît Canet     },
212e80cfcfcSbellard };
213e80cfcfcSbellard 
214d453c2c3SBlue Swirl void slavio_pic_info(Monitor *mon, DeviceState *dev)
215e80cfcfcSbellard {
2167abad863SAndreas Färber     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
217e80cfcfcSbellard     int i;
218e80cfcfcSbellard 
219e80cfcfcSbellard     for (i = 0; i < MAX_CPUS; i++) {
220376253ecSaliguori         monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
221a1961a4bSBlue Swirl                        s->slaves[i].intreg_pending);
222e80cfcfcSbellard     }
223376253ecSaliguori     monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
22477f193daSblueswir1                    s->intregm_pending, s->intregm_disabled);
225e80cfcfcSbellard }
226e80cfcfcSbellard 
227d453c2c3SBlue Swirl void slavio_irq_info(Monitor *mon, DeviceState *dev)
228e80cfcfcSbellard {
229e80cfcfcSbellard #ifndef DEBUG_IRQ_COUNT
230376253ecSaliguori     monitor_printf(mon, "irq statistic code not compiled.\n");
231e80cfcfcSbellard #else
2327abad863SAndreas Färber     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
233e80cfcfcSbellard     int i;
234e80cfcfcSbellard     int64_t count;
235e80cfcfcSbellard 
2367abad863SAndreas Färber     s = SLAVIO_INTCTL(dev);
237376253ecSaliguori     monitor_printf(mon, "IRQ statistics:\n");
238e80cfcfcSbellard     for (i = 0; i < 32; i++) {
239e80cfcfcSbellard         count = s->irq_count[i];
240e80cfcfcSbellard         if (count > 0)
241376253ecSaliguori             monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
242e80cfcfcSbellard     }
243e80cfcfcSbellard #endif
244e80cfcfcSbellard }
245e80cfcfcSbellard 
24668556e2eSBlue Swirl static const uint32_t intbit_to_level[] = {
247462eda24SBlue Swirl     2, 3, 5, 7, 9, 11, 13, 2,   3, 5, 7, 9, 11, 13, 12, 12,
248462eda24SBlue Swirl     6, 13, 4, 10, 8, 9, 11, 0,  0, 0, 0, 15, 15, 15, 15, 0,
24968556e2eSBlue Swirl };
25068556e2eSBlue Swirl 
2510d0a7e69SBlue Swirl static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
25266321a11Sbellard {
253327ac2e7Sblueswir1     uint32_t pending = s->intregm_pending, pil_pending;
254327ac2e7Sblueswir1     unsigned int i, j;
25566321a11Sbellard 
25666321a11Sbellard     pending &= ~s->intregm_disabled;
25766321a11Sbellard 
25897bf4851SBlue Swirl     trace_slavio_check_interrupts(pending, s->intregm_disabled);
259ba3c64fbSbellard     for (i = 0; i < MAX_CPUS; i++) {
260327ac2e7Sblueswir1         pil_pending = 0;
261462eda24SBlue Swirl 
262462eda24SBlue Swirl         /* If we are the current interrupt target, get hard interrupts */
2639a87ce9bSblueswir1         if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
264b3a23197Sblueswir1             (i == s->target_cpu)) {
265b3a23197Sblueswir1             for (j = 0; j < 32; j++) {
266462eda24SBlue Swirl                 if ((pending & (1 << j)) && intbit_to_level[j]) {
26768556e2eSBlue Swirl                     pil_pending |= 1 << intbit_to_level[j];
268b3a23197Sblueswir1                 }
269b3a23197Sblueswir1             }
270462eda24SBlue Swirl         }
271462eda24SBlue Swirl 
272462eda24SBlue Swirl         /* Calculate current pending hard interrupts for display */
273462eda24SBlue Swirl         s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
274462eda24SBlue Swirl             CPU_IRQ_TIMER_IN;
275462eda24SBlue Swirl         if (i == s->target_cpu) {
276462eda24SBlue Swirl             for (j = 0; j < 32; j++) {
2777d45e784SPeter Maydell                 if ((s->intregm_pending & (1U << j)) && intbit_to_level[j]) {
278462eda24SBlue Swirl                     s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
279462eda24SBlue Swirl                 }
280462eda24SBlue Swirl             }
281462eda24SBlue Swirl         }
282462eda24SBlue Swirl 
28394c5f455SArtyom Tarasenko         /* Level 15 and CPU timer interrupts are only masked when
28494c5f455SArtyom Tarasenko            the MASTER_DISABLE bit is set */
28594c5f455SArtyom Tarasenko         if (!(s->intregm_disabled & MASTER_DISABLE)) {
286462eda24SBlue Swirl             pil_pending |= s->slaves[i].intreg_pending &
287462eda24SBlue Swirl                 (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
28894c5f455SArtyom Tarasenko         }
289462eda24SBlue Swirl 
290462eda24SBlue Swirl         /* Add soft interrupts */
291a1961a4bSBlue Swirl         pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
292327ac2e7Sblueswir1 
2930d0a7e69SBlue Swirl         if (set_irqs) {
294c84a88d8SPeter Maydell             /* Since there is not really an interrupt 0 (and pil_pending
295c84a88d8SPeter Maydell              * and irl_out bit zero are thus always zero) there is no need
296c84a88d8SPeter Maydell              * to do anything with cpu_irqs[i][0] and it is OK not to do
297c84a88d8SPeter Maydell              * the j=0 iteration of this loop.
298c84a88d8SPeter Maydell              */
299c84a88d8SPeter Maydell             for (j = MAX_PILS-1; j > 0; j--) {
300327ac2e7Sblueswir1                 if (pil_pending & (1 << j)) {
301462eda24SBlue Swirl                     if (!(s->slaves[i].irl_out & (1 << j))) {
302327ac2e7Sblueswir1                         qemu_irq_raise(s->cpu_irqs[i][j]);
3030d0a7e69SBlue Swirl                     }
304327ac2e7Sblueswir1                 } else {
305462eda24SBlue Swirl                     if (s->slaves[i].irl_out & (1 << j)) {
306327ac2e7Sblueswir1                         qemu_irq_lower(s->cpu_irqs[i][j]);
307ba3c64fbSbellard                     }
308ba3c64fbSbellard                 }
3090d0a7e69SBlue Swirl             }
3100d0a7e69SBlue Swirl         }
311462eda24SBlue Swirl         s->slaves[i].irl_out = pil_pending;
312ba3c64fbSbellard     }
31366321a11Sbellard }
31466321a11Sbellard 
315e80cfcfcSbellard /*
316e80cfcfcSbellard  * "irq" here is the bit number in the system interrupt register to
317e80cfcfcSbellard  * separate serial and keyboard interrupts sharing a level.
318e80cfcfcSbellard  */
319d7edfd27Sblueswir1 static void slavio_set_irq(void *opaque, int irq, int level)
320e80cfcfcSbellard {
321e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
322e80cfcfcSbellard     uint32_t mask = 1 << irq;
32368556e2eSBlue Swirl     uint32_t pil = intbit_to_level[irq];
324462eda24SBlue Swirl     unsigned int i;
325b3a23197Sblueswir1 
32697bf4851SBlue Swirl     trace_slavio_set_irq(s->target_cpu, irq, pil, level);
327e80cfcfcSbellard     if (pil > 0) {
328e80cfcfcSbellard         if (level) {
329327ac2e7Sblueswir1 #ifdef DEBUG_IRQ_COUNT
330327ac2e7Sblueswir1             s->irq_count[pil]++;
331327ac2e7Sblueswir1 #endif
332e80cfcfcSbellard             s->intregm_pending |= mask;
333462eda24SBlue Swirl             if (pil == 15) {
334462eda24SBlue Swirl                 for (i = 0; i < MAX_CPUS; i++) {
335462eda24SBlue Swirl                     s->slaves[i].intreg_pending |= 1 << pil;
336462eda24SBlue Swirl                 }
337462eda24SBlue Swirl             }
338b3a23197Sblueswir1         } else {
339e80cfcfcSbellard             s->intregm_pending &= ~mask;
340462eda24SBlue Swirl             if (pil == 15) {
341462eda24SBlue Swirl                 for (i = 0; i < MAX_CPUS; i++) {
342462eda24SBlue Swirl                     s->slaves[i].intreg_pending &= ~(1 << pil);
343462eda24SBlue Swirl                 }
344462eda24SBlue Swirl             }
345e80cfcfcSbellard         }
3460d0a7e69SBlue Swirl         slavio_check_interrupts(s, 1);
347e80cfcfcSbellard     }
348e80cfcfcSbellard }
349e80cfcfcSbellard 
350d7edfd27Sblueswir1 static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
351ba3c64fbSbellard {
352ba3c64fbSbellard     SLAVIO_INTCTLState *s = opaque;
353ba3c64fbSbellard 
35497bf4851SBlue Swirl     trace_slavio_set_timer_irq_cpu(cpu, level);
355d7edfd27Sblueswir1 
356e3a79bcaSblueswir1     if (level) {
357462eda24SBlue Swirl         s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
358e3a79bcaSblueswir1     } else {
359462eda24SBlue Swirl         s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
360e3a79bcaSblueswir1     }
361d7edfd27Sblueswir1 
3620d0a7e69SBlue Swirl     slavio_check_interrupts(s, 1);
363ba3c64fbSbellard }
364ba3c64fbSbellard 
365a1961a4bSBlue Swirl static void slavio_set_irq_all(void *opaque, int irq, int level)
366a1961a4bSBlue Swirl {
367a1961a4bSBlue Swirl     if (irq < 32) {
368a1961a4bSBlue Swirl         slavio_set_irq(opaque, irq, level);
369a1961a4bSBlue Swirl     } else {
370a1961a4bSBlue Swirl         slavio_set_timer_irq_cpu(opaque, irq - 32, level);
371a1961a4bSBlue Swirl     }
372a1961a4bSBlue Swirl }
373a1961a4bSBlue Swirl 
374e59fb374SJuan Quintela static int vmstate_intctl_post_load(void *opaque, int version_id)
375e80cfcfcSbellard {
376e80cfcfcSbellard     SLAVIO_INTCTLState *s = opaque;
377e80cfcfcSbellard 
3780d0a7e69SBlue Swirl     slavio_check_interrupts(s, 0);
379e80cfcfcSbellard     return 0;
380e80cfcfcSbellard }
381e80cfcfcSbellard 
382c9e95029SBlue Swirl static const VMStateDescription vmstate_intctl_cpu = {
383c9e95029SBlue Swirl     .name ="slavio_intctl_cpu",
384c9e95029SBlue Swirl     .version_id = 1,
385c9e95029SBlue Swirl     .minimum_version_id = 1,
386c9e95029SBlue Swirl     .fields = (VMStateField[]) {
387c9e95029SBlue Swirl         VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
388c9e95029SBlue Swirl         VMSTATE_END_OF_LIST()
389c9e95029SBlue Swirl     }
390c9e95029SBlue Swirl };
391c9e95029SBlue Swirl 
392c9e95029SBlue Swirl static const VMStateDescription vmstate_intctl = {
393c9e95029SBlue Swirl     .name ="slavio_intctl",
394c9e95029SBlue Swirl     .version_id = 1,
395c9e95029SBlue Swirl     .minimum_version_id = 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 
422*148fbe95SHervé Poussineau #ifdef DEBUG_IRQ_COUNT
423*148fbe95SHervé Poussineau static bool slavio_intctl_get_statistics(InterruptStatsProvider *obj,
424*148fbe95SHervé Poussineau                                          uint64_t **irq_counts,
425*148fbe95SHervé Poussineau                                          unsigned int *nb_irqs)
426*148fbe95SHervé Poussineau {
427*148fbe95SHervé Poussineau     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
428*148fbe95SHervé Poussineau     *irq_counts = s->irq_count;
429*148fbe95SHervé Poussineau     *nb_irqs = ARRAY_SIZE(s->irq_count);
430*148fbe95SHervé Poussineau     return true;
431*148fbe95SHervé Poussineau }
432*148fbe95SHervé Poussineau #endif
433*148fbe95SHervé Poussineau 
434*148fbe95SHervé Poussineau static void slavio_intctl_print_info(InterruptStatsProvider *obj, Monitor *mon)
435*148fbe95SHervé Poussineau {
436*148fbe95SHervé Poussineau     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
437*148fbe95SHervé Poussineau     int i;
438*148fbe95SHervé Poussineau 
439*148fbe95SHervé Poussineau     for (i = 0; i < MAX_CPUS; i++) {
440*148fbe95SHervé Poussineau         monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
441*148fbe95SHervé Poussineau                        s->slaves[i].intreg_pending);
442*148fbe95SHervé Poussineau     }
443*148fbe95SHervé Poussineau     monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
444*148fbe95SHervé Poussineau                    s->intregm_pending, s->intregm_disabled);
445*148fbe95SHervé Poussineau }
446*148fbe95SHervé Poussineau 
447c09008d2Sxiaoqiang.zhao static void slavio_intctl_init(Object *obj)
448e80cfcfcSbellard {
449c09008d2Sxiaoqiang.zhao     DeviceState *dev = DEVICE(obj);
450c09008d2Sxiaoqiang.zhao     SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
451c09008d2Sxiaoqiang.zhao     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
452a1961a4bSBlue Swirl     unsigned int i, j;
4538bb5ef33SBenoît Canet     char slave_name[45];
454e80cfcfcSbellard 
4557abad863SAndreas Färber     qdev_init_gpio_in(dev, slavio_set_irq_all, 32 + MAX_CPUS);
456c09008d2Sxiaoqiang.zhao     memory_region_init_io(&s->iomem, obj, &slavio_intctlm_mem_ops, s,
45713c89a11SBenoît Canet                           "master-interrupt-controller", INTCTLM_SIZE);
4587abad863SAndreas Färber     sysbus_init_mmio(sbd, &s->iomem);
459e80cfcfcSbellard 
460e80cfcfcSbellard     for (i = 0; i < MAX_CPUS; i++) {
4618bb5ef33SBenoît Canet         snprintf(slave_name, sizeof(slave_name),
4628bb5ef33SBenoît Canet                  "slave-interrupt-controller-%i", i);
463a1961a4bSBlue Swirl         for (j = 0; j < MAX_PILS; j++) {
4647abad863SAndreas Färber             sysbus_init_irq(sbd, &s->cpu_irqs[i][j]);
465e80cfcfcSbellard         }
4661437c94bSPaolo Bonzini         memory_region_init_io(&s->slaves[i].iomem, OBJECT(s),
4671437c94bSPaolo Bonzini                               &slavio_intctl_mem_ops,
4688bb5ef33SBenoît Canet                               &s->slaves[i], slave_name, INTCTL_SIZE);
4697abad863SAndreas Färber         sysbus_init_mmio(sbd, &s->slaves[i].iomem);
470a1961a4bSBlue Swirl         s->slaves[i].cpu = i;
471a1961a4bSBlue Swirl         s->slaves[i].master = s;
472a1961a4bSBlue Swirl     }
473e80cfcfcSbellard }
474a1961a4bSBlue Swirl 
475999e12bbSAnthony Liguori static void slavio_intctl_class_init(ObjectClass *klass, void *data)
476999e12bbSAnthony Liguori {
47739bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
478*148fbe95SHervé Poussineau     InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
479999e12bbSAnthony Liguori 
48039bffca2SAnthony Liguori     dc->reset = slavio_intctl_reset;
48139bffca2SAnthony Liguori     dc->vmsd = &vmstate_intctl;
482*148fbe95SHervé Poussineau #ifdef DEBUG_IRQ_COUNT
483*148fbe95SHervé Poussineau     ic->get_statistics = slavio_intctl_get_statistics;
484*148fbe95SHervé Poussineau #endif
485*148fbe95SHervé Poussineau     ic->print_info = slavio_intctl_print_info;
486999e12bbSAnthony Liguori }
487999e12bbSAnthony Liguori 
4888c43a6f0SAndreas Färber static const TypeInfo slavio_intctl_info = {
4897abad863SAndreas Färber     .name          = TYPE_SLAVIO_INTCTL,
49039bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
49139bffca2SAnthony Liguori     .instance_size = sizeof(SLAVIO_INTCTLState),
492c09008d2Sxiaoqiang.zhao     .instance_init = slavio_intctl_init,
493999e12bbSAnthony Liguori     .class_init    = slavio_intctl_class_init,
494*148fbe95SHervé Poussineau     .interfaces = (InterfaceInfo[]) {
495*148fbe95SHervé Poussineau         { TYPE_INTERRUPT_STATS_PROVIDER },
496*148fbe95SHervé Poussineau         { }
497*148fbe95SHervé Poussineau     },
498a1961a4bSBlue Swirl };
499a1961a4bSBlue Swirl 
50083f7d43aSAndreas Färber static void slavio_intctl_register_types(void)
501a1961a4bSBlue Swirl {
50239bffca2SAnthony Liguori     type_register_static(&slavio_intctl_info);
503a1961a4bSBlue Swirl }
504a1961a4bSBlue Swirl 
50583f7d43aSAndreas Färber type_init(slavio_intctl_register_types)
506