Statistics
| Branch: | Revision:

root / hw / slavio_intctl.c @ 0633879f

History | View | Annotate | Download (10.9 kB)

1
/*
2
 * QEMU Sparc SLAVIO interrupt controller emulation
3
 * 
4
 * Copyright (c) 2003-2005 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
//#define DEBUG_IRQ
27

    
28
#ifdef DEBUG_IRQ
29
#define DPRINTF(fmt, args...) \
30
do { printf("IRQ: " fmt , ##args); } while (0)
31
#else
32
#define DPRINTF(fmt, args...)
33
#endif
34

    
35
/*
36
 * Registers of interrupt controller in sun4m.
37
 *
38
 * This is the interrupt controller part of chip STP2001 (Slave I/O), also
39
 * produced as NCR89C105. See
40
 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
41
 *
42
 * There is a system master controller and one for each cpu.
43
 * 
44
 */
45

    
46
#define MAX_CPUS 16
47

    
48
typedef struct SLAVIO_INTCTLState {
49
    uint32_t intreg_pending[MAX_CPUS];
50
    uint32_t intregm_pending;
51
    uint32_t intregm_disabled;
52
    uint32_t target_cpu;
53
#ifdef DEBUG_IRQ_COUNT
54
    uint64_t irq_count[32];
55
#endif
56
    CPUState *cpu_envs[MAX_CPUS];
57
    const uint32_t *intbit_to_level;
58
} SLAVIO_INTCTLState;
59

    
60
#define INTCTL_MAXADDR 0xf
61
#define INTCTLM_MAXADDR 0x13
62
#define INTCTLM_MASK 0x1f
63
static void slavio_check_interrupts(void *opaque);
64

    
65
// per-cpu interrupt controller
66
static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
67
{
68
    SLAVIO_INTCTLState *s = opaque;
69
    uint32_t saddr;
70
    int cpu;
71

    
72
    cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
73
    saddr = (addr & INTCTL_MAXADDR) >> 2;
74
    switch (saddr) {
75
    case 0:
76
        return s->intreg_pending[cpu];
77
    default:
78
        break;
79
    }
80
    return 0;
81
}
82

    
83
static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
84
{
85
    SLAVIO_INTCTLState *s = opaque;
86
    uint32_t saddr;
87
    int cpu;
88

    
89
    cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
90
    saddr = (addr & INTCTL_MAXADDR) >> 2;
91
    switch (saddr) {
92
    case 1: // clear pending softints
93
        if (val & 0x4000)
94
            val |= 80000000;
95
        val &= 0xfffe0000;
96
        s->intreg_pending[cpu] &= ~val;
97
        DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
98
        break;
99
    case 2: // set softint
100
        val &= 0xfffe0000;
101
        s->intreg_pending[cpu] |= val;
102
        slavio_check_interrupts(s);
103
        DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
104
        break;
105
    default:
106
        break;
107
    }
108
}
109

    
110
static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = {
111
    slavio_intctl_mem_readl,
112
    slavio_intctl_mem_readl,
113
    slavio_intctl_mem_readl,
114
};
115

    
116
static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = {
117
    slavio_intctl_mem_writel,
118
    slavio_intctl_mem_writel,
119
    slavio_intctl_mem_writel,
120
};
121

    
122
// master system interrupt controller
123
static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
124
{
125
    SLAVIO_INTCTLState *s = opaque;
126
    uint32_t saddr;
127

    
128
    saddr = (addr & INTCTLM_MAXADDR) >> 2;
129
    switch (saddr) {
130
    case 0:
131
        return s->intregm_pending & 0x7fffffff;
132
    case 1:
133
        return s->intregm_disabled;
134
    case 4:
135
        return s->target_cpu;
136
    default:
137
        break;
138
    }
139
    return 0;
140
}
141

    
142
static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
143
{
144
    SLAVIO_INTCTLState *s = opaque;
145
    uint32_t saddr;
146

    
147
    saddr = (addr & INTCTLM_MASK) >> 2;
148
    switch (saddr) {
149
    case 2: // clear (enable)
150
        // Force clear unused bits
151
        val &= ~0x4fb2007f;
152
        s->intregm_disabled &= ~val;
153
        DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
154
        slavio_check_interrupts(s);
155
        break;
156
    case 3: // set (disable, clear pending)
157
        // Force clear unused bits
158
        val &= ~0x4fb2007f;
159
        s->intregm_disabled |= val;
160
        s->intregm_pending &= ~val;
161
        DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
162
        break;
163
    case 4:
164
        s->target_cpu = val & (MAX_CPUS - 1);
165
        DPRINTF("Set master irq cpu %d\n", s->target_cpu);
166
        break;
167
    default:
168
        break;
169
    }
170
}
171

    
172
static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = {
173
    slavio_intctlm_mem_readl,
174
    slavio_intctlm_mem_readl,
175
    slavio_intctlm_mem_readl,
176
};
177

    
178
static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = {
179
    slavio_intctlm_mem_writel,
180
    slavio_intctlm_mem_writel,
181
    slavio_intctlm_mem_writel,
182
};
183

    
184
void slavio_pic_info(void *opaque)
185
{
186
    SLAVIO_INTCTLState *s = opaque;
187
    int i;
188

    
189
    for (i = 0; i < MAX_CPUS; i++) {
190
        term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]);
191
    }
192
    term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled);
193
}
194

    
195
void slavio_irq_info(void *opaque)
196
{
197
#ifndef DEBUG_IRQ_COUNT
198
    term_printf("irq statistic code not compiled.\n");
199
#else
200
    SLAVIO_INTCTLState *s = opaque;
201
    int i;
202
    int64_t count;
203

    
204
    term_printf("IRQ statistics:\n");
205
    for (i = 0; i < 32; i++) {
206
        count = s->irq_count[i];
207
        if (count > 0)
208
            term_printf("%2d: %" PRId64 "\n", i, count);
209
    }
210
#endif
211
}
212

    
213
static void slavio_check_interrupts(void *opaque)
214
{
215
    CPUState *env;
216
    SLAVIO_INTCTLState *s = opaque;
217
    uint32_t pending = s->intregm_pending;
218
    unsigned int i, j, max = 0;
219

    
220
    pending &= ~s->intregm_disabled;
221

    
222
    if (pending && !(s->intregm_disabled & 0x80000000)) {
223
        for (i = 0; i < 32; i++) {
224
            if (pending & (1 << i)) {
225
                if (max < s->intbit_to_level[i])
226
                    max = s->intbit_to_level[i];
227
            }
228
        }
229
        env = s->cpu_envs[s->target_cpu];
230
        if (!env) {
231
            DPRINTF("No CPU %d, not triggered (pending %x)\n", s->target_cpu, pending);
232
        }
233
        else {
234
            if (env->halted)
235
                env->halted = 0;
236
            if (env->interrupt_index == 0) {
237
                DPRINTF("Triggered CPU %d pil %d\n", s->target_cpu, max);
238
#ifdef DEBUG_IRQ_COUNT
239
                s->irq_count[max]++;
240
#endif
241
                env->interrupt_index = TT_EXTINT | max;
242
                cpu_interrupt(env, CPU_INTERRUPT_HARD);
243
            }
244
            else
245
                DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, env->interrupt_index);
246
        }
247
    }
248
    else
249
        DPRINTF("Not triggered (pending %x), disabled %x\n", pending, s->intregm_disabled);
250
    
251
    for (i = 0; i < MAX_CPUS; i++) {
252
        max = 0;
253
        env = s->cpu_envs[i];
254
        if (!env)
255
            continue;
256
        for (j = 17; j < 32; j++) {
257
            if (s->intreg_pending[i] & (1 << j)) {
258
                if (max < j - 16)
259
                    max = j - 16;
260
            }
261
        }
262
        if (max > 0) {
263
            if (env->halted)
264
                env->halted = 0;
265
            if (env->interrupt_index == 0) {
266
                DPRINTF("Triggered softint %d for cpu %d (pending %x)\n", max, i, pending);
267
#ifdef DEBUG_IRQ_COUNT
268
                s->irq_count[max]++;
269
#endif
270
                env->interrupt_index = TT_EXTINT | max;
271
                cpu_interrupt(env, CPU_INTERRUPT_HARD);
272
            }
273
        }
274
    }
275
}
276

    
277
/*
278
 * "irq" here is the bit number in the system interrupt register to
279
 * separate serial and keyboard interrupts sharing a level.
280
 */
281
void slavio_set_irq(void *opaque, int irq, int level)
282
{
283
    SLAVIO_INTCTLState *s = opaque;
284

    
285
    DPRINTF("Set cpu %d irq %d level %d\n", s->target_cpu, irq, level);
286
    if (irq < 32) {
287
        uint32_t mask = 1 << irq;
288
        uint32_t pil = s->intbit_to_level[irq];
289
        if (pil > 0) {
290
            if (level) {
291
                s->intregm_pending |= mask;
292
                s->intreg_pending[s->target_cpu] |= 1 << pil;
293
                slavio_check_interrupts(s);
294
            }
295
            else {
296
                s->intregm_pending &= ~mask;
297
                s->intreg_pending[s->target_cpu] &= ~(1 << pil);
298
            }
299
        }
300
    }
301
}
302

    
303
void pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu)
304
{
305
    SLAVIO_INTCTLState *s = opaque;
306

    
307
    DPRINTF("Set cpu %d local irq %d level %d\n", cpu, irq, level);
308
    if (cpu == (unsigned int)-1) {
309
        slavio_set_irq(opaque, irq, level);
310
        return;
311
    }
312
    if (irq < 32) {
313
        uint32_t pil = s->intbit_to_level[irq];
314
            if (pil > 0) {
315
            if (level) {
316
                s->intreg_pending[cpu] |= 1 << pil;
317
            }
318
            else {
319
                s->intreg_pending[cpu] &= ~(1 << pil);
320
            }
321
        }
322
    }
323
    slavio_check_interrupts(s);
324
}
325

    
326
static void slavio_intctl_save(QEMUFile *f, void *opaque)
327
{
328
    SLAVIO_INTCTLState *s = opaque;
329
    int i;
330
    
331
    for (i = 0; i < MAX_CPUS; i++) {
332
        qemu_put_be32s(f, &s->intreg_pending[i]);
333
    }
334
    qemu_put_be32s(f, &s->intregm_pending);
335
    qemu_put_be32s(f, &s->intregm_disabled);
336
    qemu_put_be32s(f, &s->target_cpu);
337
}
338

    
339
static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id)
340
{
341
    SLAVIO_INTCTLState *s = opaque;
342
    int i;
343

    
344
    if (version_id != 1)
345
        return -EINVAL;
346

    
347
    for (i = 0; i < MAX_CPUS; i++) {
348
        qemu_get_be32s(f, &s->intreg_pending[i]);
349
    }
350
    qemu_get_be32s(f, &s->intregm_pending);
351
    qemu_get_be32s(f, &s->intregm_disabled);
352
    qemu_get_be32s(f, &s->target_cpu);
353
    return 0;
354
}
355

    
356
static void slavio_intctl_reset(void *opaque)
357
{
358
    SLAVIO_INTCTLState *s = opaque;
359
    int i;
360

    
361
    for (i = 0; i < MAX_CPUS; i++) {
362
        s->intreg_pending[i] = 0;
363
    }
364
    s->intregm_disabled = ~0xffb2007f;
365
    s->intregm_pending = 0;
366
    s->target_cpu = 0;
367
}
368

    
369
void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env)
370
{
371
    SLAVIO_INTCTLState *s = opaque;
372
    s->cpu_envs[cpu] = env;
373
}
374

    
375
void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg,
376
                         const uint32_t *intbit_to_level,
377
                         qemu_irq **irq)
378
{
379
    int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;
380
    SLAVIO_INTCTLState *s;
381

    
382
    s = qemu_mallocz(sizeof(SLAVIO_INTCTLState));
383
    if (!s)
384
        return NULL;
385

    
386
    s->intbit_to_level = intbit_to_level;
387
    for (i = 0; i < MAX_CPUS; i++) {
388
        slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s);
389
        cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory);
390
    }
391

    
392
    slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s);
393
    cpu_register_physical_memory(addrg, INTCTLM_MAXADDR, slavio_intctlm_io_memory);
394

    
395
    register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s);
396
    qemu_register_reset(slavio_intctl_reset, s);
397
    *irq = qemu_allocate_irqs(slavio_set_irq, s, 32);
398
    slavio_intctl_reset(s);
399
    return s;
400
}
401