0.6.1-alt1
[qemu] / qemu / hw / sched.c
1 /*
2  * QEMU interrupt controller emulation
3  * 
4  * Copyright (c) 2003-2004 Fabrice Bellard
5  * 
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #include "vl.h"
25 //#define DEBUG_IRQ_COUNT
26
27 /* These registers are used for sending/receiving irqs from/to
28  * different cpu's.
29  */
30 struct sun4m_intreg_percpu {
31         unsigned int tbt;        /* Intrs pending for this cpu, by PIL. */
32         /* These next two registers are WRITE-ONLY and are only
33          * "on bit" sensitive, "off bits" written have NO affect.
34          */
35         unsigned int clear;  /* Clear this cpus irqs here. */
36         unsigned int set;    /* Set this cpus irqs here. */
37 };
38 /*
39  * djhr
40  * Actually the clear and set fields in this struct are misleading..
41  * according to the SLAVIO manual (and the same applies for the SEC)
42  * the clear field clears bits in the mask which will ENABLE that IRQ
43  * the set field sets bits in the mask to DISABLE the IRQ.
44  *
45  * Also the undirected_xx address in the SLAVIO is defined as
46  * RESERVED and write only..
47  *
48  * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
49  *             sun4m machines, for MP the layout makes more sense.
50  */
51 struct sun4m_intreg_master {
52         unsigned int tbt;        /* IRQ's that are pending, see sun4m masks. */
53         unsigned int irqs;       /* Master IRQ bits. */
54
55         /* Again, like the above, two these registers are WRITE-ONLY. */
56         unsigned int clear;      /* Clear master IRQ's by setting bits here. */
57         unsigned int set;        /* Set master IRQ's by setting bits here. */
58
59         /* This register is both READ and WRITE. */
60         unsigned int undirected_target;  /* Which cpu gets undirected irqs. */
61 };
62
63 #define SUN4M_INT_ENABLE        0x80000000
64 #define SUN4M_INT_E14           0x00000080
65 #define SUN4M_INT_E10           0x00080000
66
67 #define SUN4M_HARD_INT(x)       (0x000000001 << (x))
68 #define SUN4M_SOFT_INT(x)       (0x000010000 << (x))
69
70 #define SUN4M_INT_MASKALL       0x80000000        /* mask all interrupts */
71 #define SUN4M_INT_MODULE_ERR    0x40000000        /* module error */
72 #define SUN4M_INT_M2S_WRITE     0x20000000        /* write buffer error */
73 #define SUN4M_INT_ECC           0x10000000        /* ecc memory error */
74 #define SUN4M_INT_FLOPPY        0x00400000        /* floppy disk */
75 #define SUN4M_INT_MODULE        0x00200000        /* module interrupt */
76 #define SUN4M_INT_VIDEO         0x00100000        /* onboard video */
77 #define SUN4M_INT_REALTIME      0x00080000        /* system timer */
78 #define SUN4M_INT_SCSI          0x00040000        /* onboard scsi */
79 #define SUN4M_INT_AUDIO         0x00020000        /* audio/isdn */
80 #define SUN4M_INT_ETHERNET      0x00010000        /* onboard ethernet */
81 #define SUN4M_INT_SERIAL        0x00008000        /* serial ports */
82 #define SUN4M_INT_SBUSBITS      0x00003F80        /* sbus int bits */
83
84 #define SUN4M_INT_SBUS(x)       (1 << (x+7))
85 #define SUN4M_INT_VME(x)        (1 << (x))
86
87 typedef struct SCHEDState {
88     uint32_t addr, addrg;
89     uint32_t intreg_pending;
90     uint32_t intreg_enabled;
91     uint32_t intregm_pending;
92     uint32_t intregm_enabled;
93 } SCHEDState;
94
95 static SCHEDState *ps;
96
97 #ifdef DEBUG_IRQ_COUNT
98 static uint64_t irq_count[32];
99 #endif
100
101 static uint32_t intreg_mem_readl(void *opaque, target_phys_addr_t addr)
102 {
103     SCHEDState *s = opaque;
104     uint32_t saddr;
105
106     saddr = (addr - s->addr) >> 2;
107     switch (saddr) {
108     case 0:
109         return s->intreg_pending;
110         break;
111     default:
112         break;
113     }
114     return 0;
115 }
116
117 static void intreg_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
118 {
119     SCHEDState *s = opaque;
120     uint32_t saddr;
121
122     saddr = (addr - s->addr) >> 2;
123     switch (saddr) {
124     case 0:
125         s->intreg_pending = val;
126         break;
127     case 1: // clear
128         s->intreg_enabled &= ~val;
129         break;
130     case 2: // set
131         s->intreg_enabled |= val;
132         break;
133     default:
134         break;
135     }
136 }
137
138 static CPUReadMemoryFunc *intreg_mem_read[3] = {
139     intreg_mem_readl,
140     intreg_mem_readl,
141     intreg_mem_readl,
142 };
143
144 static CPUWriteMemoryFunc *intreg_mem_write[3] = {
145     intreg_mem_writel,
146     intreg_mem_writel,
147     intreg_mem_writel,
148 };
149
150 static uint32_t intregm_mem_readl(void *opaque, target_phys_addr_t addr)
151 {
152     SCHEDState *s = opaque;
153     uint32_t saddr;
154
155     saddr = (addr - s->addrg) >> 2;
156     switch (saddr) {
157     case 0:
158         return s->intregm_pending;
159         break;
160     case 1:
161         return s->intregm_enabled;
162         break;
163     default:
164         break;
165     }
166     return 0;
167 }
168
169 static void intregm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
170 {
171     SCHEDState *s = opaque;
172     uint32_t saddr;
173
174     saddr = (addr - s->addrg) >> 2;
175     switch (saddr) {
176     case 0:
177         s->intregm_pending = val;
178         break;
179     case 1:
180         s->intregm_enabled = val;
181         break;
182     case 2: // clear
183         s->intregm_enabled &= ~val;
184         break;
185     case 3: // set
186         s->intregm_enabled |= val;
187         break;
188     default:
189         break;
190     }
191 }
192
193 static CPUReadMemoryFunc *intregm_mem_read[3] = {
194     intregm_mem_readl,
195     intregm_mem_readl,
196     intregm_mem_readl,
197 };
198
199 static CPUWriteMemoryFunc *intregm_mem_write[3] = {
200     intregm_mem_writel,
201     intregm_mem_writel,
202     intregm_mem_writel,
203 };
204
205 void pic_info(void)
206 {
207     term_printf("per-cpu: pending 0x%08x, enabled 0x%08x\n", ps->intreg_pending, ps->intreg_enabled);
208     term_printf("master: pending 0x%08x, enabled 0x%08x\n", ps->intregm_pending, ps->intregm_enabled);
209 }
210
211 void irq_info(void)
212 {
213 #ifndef DEBUG_IRQ_COUNT
214     term_printf("irq statistic code not compiled.\n");
215 #else
216     int i;
217     int64_t count;
218
219     term_printf("IRQ statistics:\n");
220     for (i = 0; i < 32; i++) {
221         count = irq_count[i];
222         if (count > 0)
223             term_printf("%2d: %lld\n", i, count);
224     }
225 #endif
226 }
227
228 static const unsigned int intr_to_mask[16] = {
229         0,      0,      0,      0,      0,      0, SUN4M_INT_ETHERNET,  0,
230         0,      0,      0,      0,      0,      0,      0,      0,
231 };
232
233 void pic_set_irq(int irq, int level)
234 {
235     if (irq < 16) {
236         unsigned int mask = intr_to_mask[irq];
237         ps->intreg_pending |= 1 << irq;
238         if (ps->intregm_enabled & mask) {
239             cpu_single_env->interrupt_index = irq;
240             cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
241         }
242     }
243 #ifdef DEBUG_IRQ_COUNT
244     if (level == 1)
245         irq_count[irq]++;
246 #endif
247 }
248
249 void sched_init(uint32_t addr, uint32_t addrg)
250 {
251     int intreg_io_memory, intregm_io_memory;
252     SCHEDState *s;
253
254     s = qemu_mallocz(sizeof(SCHEDState));
255     if (!s)
256         return;
257     s->addr = addr;
258     s->addrg = addrg;
259
260     intreg_io_memory = cpu_register_io_memory(0, intreg_mem_read, intreg_mem_write, s);
261     cpu_register_physical_memory(addr, 3, intreg_io_memory);
262
263     intregm_io_memory = cpu_register_io_memory(0, intregm_mem_read, intregm_mem_write, s);
264     cpu_register_physical_memory(addrg, 5, intregm_io_memory);
265
266     ps = s;
267 }
268