Statistics
| Branch: | Revision:

root / hw / slavio_intctl.c @ 5fafdf24

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
#define MAX_PILS 16
48

    
49
typedef struct SLAVIO_INTCTLState {
50
    uint32_t intreg_pending[MAX_CPUS];
51
    uint32_t intregm_pending;
52
    uint32_t intregm_disabled;
53
    uint32_t target_cpu;
54
#ifdef DEBUG_IRQ_COUNT
55
    uint64_t irq_count[32];
56
#endif
57
    qemu_irq *cpu_irqs[MAX_CPUS];
58
    const uint32_t *intbit_to_level;
59
    uint32_t cputimer_bit;
60
    uint32_t pil_out[MAX_CPUS];
61
} SLAVIO_INTCTLState;
62

    
63
#define INTCTL_MAXADDR 0xf
64
#define INTCTL_SIZE (INTCTL_MAXADDR + 1)
65
#define INTCTLM_MAXADDR 0x13
66
#define INTCTLM_SIZE (INTCTLM_MAXADDR + 1)
67
#define INTCTLM_MASK 0x1f
68
static void slavio_check_interrupts(void *opaque);
69

    
70
// per-cpu interrupt controller
71
static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
72
{
73
    SLAVIO_INTCTLState *s = opaque;
74
    uint32_t saddr, ret;
75
    int cpu;
76

    
77
    cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
78
    saddr = (addr & INTCTL_MAXADDR) >> 2;
79
    switch (saddr) {
80
    case 0:
81
        ret = s->intreg_pending[cpu];
82
        break;
83
    default:
84
        ret = 0;
85
        break;
86
    }
87
    DPRINTF("read cpu %d reg 0x" TARGET_FMT_plx " = %x\n", cpu, addr, ret);
88

    
89
    return ret;
90
}
91

    
92
static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
93
{
94
    SLAVIO_INTCTLState *s = opaque;
95
    uint32_t saddr;
96
    int cpu;
97

    
98
    cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
99
    saddr = (addr & INTCTL_MAXADDR) >> 2;
100
    DPRINTF("write cpu %d reg 0x" TARGET_FMT_plx " = %x\n", cpu, addr, val);
101
    switch (saddr) {
102
    case 1: // clear pending softints
103
        if (val & 0x4000)
104
            val |= 80000000;
105
        val &= 0xfffe0000;
106
        s->intreg_pending[cpu] &= ~val;
107
        slavio_check_interrupts(s);
108
        DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
109
        break;
110
    case 2: // set softint
111
        val &= 0xfffe0000;
112
        s->intreg_pending[cpu] |= val;
113
        slavio_check_interrupts(s);
114
        DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
115
        break;
116
    default:
117
        break;
118
    }
119
}
120

    
121
static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = {
122
    slavio_intctl_mem_readl,
123
    slavio_intctl_mem_readl,
124
    slavio_intctl_mem_readl,
125
};
126

    
127
static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = {
128
    slavio_intctl_mem_writel,
129
    slavio_intctl_mem_writel,
130
    slavio_intctl_mem_writel,
131
};
132

    
133
// master system interrupt controller
134
static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
135
{
136
    SLAVIO_INTCTLState *s = opaque;
137
    uint32_t saddr, ret;
138

    
139
    saddr = (addr & INTCTLM_MAXADDR) >> 2;
140
    switch (saddr) {
141
    case 0:
142
        ret = s->intregm_pending & 0x7fffffff;
143
        break;
144
    case 1:
145
        ret = s->intregm_disabled;
146
        break;
147
    case 4:
148
        ret = s->target_cpu;
149
        break;
150
    default:
151
        ret = 0;
152
        break;
153
    }
154
    DPRINTF("read system reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
155

    
156
    return ret;
157
}
158

    
159
static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
160
{
161
    SLAVIO_INTCTLState *s = opaque;
162
    uint32_t saddr;
163

    
164
    saddr = (addr & INTCTLM_MASK) >> 2;
165
    DPRINTF("write system reg 0x" TARGET_FMT_plx " = %x\n", addr, val);
166
    switch (saddr) {
167
    case 2: // clear (enable)
168
        // Force clear unused bits
169
        val &= ~0x4fb2007f;
170
        s->intregm_disabled &= ~val;
171
        DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
172
        slavio_check_interrupts(s);
173
        break;
174
    case 3: // set (disable, clear pending)
175
        // Force clear unused bits
176
        val &= ~0x4fb2007f;
177
        s->intregm_disabled |= val;
178
        s->intregm_pending &= ~val;
179
        slavio_check_interrupts(s);
180
        DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
181
        break;
182
    case 4:
183
        s->target_cpu = val & (MAX_CPUS - 1);
184
        slavio_check_interrupts(s);
185
        DPRINTF("Set master irq cpu %d\n", s->target_cpu);
186
        break;
187
    default:
188
        break;
189
    }
190
}
191

    
192
static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = {
193
    slavio_intctlm_mem_readl,
194
    slavio_intctlm_mem_readl,
195
    slavio_intctlm_mem_readl,
196
};
197

    
198
static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = {
199
    slavio_intctlm_mem_writel,
200
    slavio_intctlm_mem_writel,
201
    slavio_intctlm_mem_writel,
202
};
203

    
204
void slavio_pic_info(void *opaque)
205
{
206
    SLAVIO_INTCTLState *s = opaque;
207
    int i;
208

    
209
    for (i = 0; i < MAX_CPUS; i++) {
210
        term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]);
211
    }
212
    term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled);
213
}
214

    
215
void slavio_irq_info(void *opaque)
216
{
217
#ifndef DEBUG_IRQ_COUNT
218
    term_printf("irq statistic code not compiled.\n");
219
#else
220
    SLAVIO_INTCTLState *s = opaque;
221
    int i;
222
    int64_t count;
223

    
224
    term_printf("IRQ statistics:\n");
225
    for (i = 0; i < 32; i++) {
226
        count = s->irq_count[i];
227
        if (count > 0)
228
            term_printf("%2d: %" PRId64 "\n", i, count);
229
    }
230
#endif
231
}
232

    
233
static void slavio_check_interrupts(void *opaque)
234
{
235
    SLAVIO_INTCTLState *s = opaque;
236
    uint32_t pending = s->intregm_pending, pil_pending;
237
    unsigned int i, j;
238

    
239
    pending &= ~s->intregm_disabled;
240

    
241
    DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled);
242
    for (i = 0; i < MAX_CPUS; i++) {
243
        pil_pending = 0;
244
        if (pending && !(s->intregm_disabled & 0x80000000) &&
245
            (i == s->target_cpu)) {
246
            for (j = 0; j < 32; j++) {
247
                if (pending & (1 << j))
248
                    pil_pending |= 1 << s->intbit_to_level[j];
249
            }
250
        }
251
        pil_pending |= (s->intreg_pending[i] >> 16) & 0xfffe;
252

    
253
        for (j = 0; j < MAX_PILS; j++) {
254
            if (pil_pending & (1 << j)) {
255
                if (!(s->pil_out[i] & (1 << j)))
256
                    qemu_irq_raise(s->cpu_irqs[i][j]);
257
            } else {
258
                if (s->pil_out[i] & (1 << j))
259
                    qemu_irq_lower(s->cpu_irqs[i][j]);
260
            }
261
        }
262
        s->pil_out[i] = pil_pending;
263
    }
264
}
265

    
266
/*
267
 * "irq" here is the bit number in the system interrupt register to
268
 * separate serial and keyboard interrupts sharing a level.
269
 */
270
static void slavio_set_irq(void *opaque, int irq, int level)
271
{
272
    SLAVIO_INTCTLState *s = opaque;
273
    uint32_t mask = 1 << irq;
274
    uint32_t pil = s->intbit_to_level[irq];
275

    
276
    DPRINTF("Set cpu %d irq %d -> pil %d level %d\n", s->target_cpu, irq, pil,
277
            level);
278
    if (pil > 0) {
279
        if (level) {
280
#ifdef DEBUG_IRQ_COUNT
281
            s->irq_count[pil]++;
282
#endif
283
            s->intregm_pending |= mask;
284
            s->intreg_pending[s->target_cpu] |= 1 << pil;
285
        } else {
286
            s->intregm_pending &= ~mask;
287
            s->intreg_pending[s->target_cpu] &= ~(1 << pil);
288
        }
289
        slavio_check_interrupts(s);
290
    }
291
}
292

    
293
static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
294
{
295
    SLAVIO_INTCTLState *s = opaque;
296

    
297
    DPRINTF("Set cpu %d local timer level %d\n", cpu, level);
298

    
299
    if (level)
300
        s->intreg_pending[cpu] |= s->cputimer_bit;
301
    else
302
        s->intreg_pending[cpu] &= ~s->cputimer_bit;
303

    
304
    slavio_check_interrupts(s);
305
}
306

    
307
static void slavio_intctl_save(QEMUFile *f, void *opaque)
308
{
309
    SLAVIO_INTCTLState *s = opaque;
310
    int i;
311
   
312
    for (i = 0; i < MAX_CPUS; i++) {
313
        qemu_put_be32s(f, &s->intreg_pending[i]);
314
    }
315
    qemu_put_be32s(f, &s->intregm_pending);
316
    qemu_put_be32s(f, &s->intregm_disabled);
317
    qemu_put_be32s(f, &s->target_cpu);
318
}
319

    
320
static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id)
321
{
322
    SLAVIO_INTCTLState *s = opaque;
323
    int i;
324

    
325
    if (version_id != 1)
326
        return -EINVAL;
327

    
328
    for (i = 0; i < MAX_CPUS; i++) {
329
        qemu_get_be32s(f, &s->intreg_pending[i]);
330
    }
331
    qemu_get_be32s(f, &s->intregm_pending);
332
    qemu_get_be32s(f, &s->intregm_disabled);
333
    qemu_get_be32s(f, &s->target_cpu);
334
    slavio_check_interrupts(s);
335
    return 0;
336
}
337

    
338
static void slavio_intctl_reset(void *opaque)
339
{
340
    SLAVIO_INTCTLState *s = opaque;
341
    int i;
342

    
343
    for (i = 0; i < MAX_CPUS; i++) {
344
        s->intreg_pending[i] = 0;
345
    }
346
    s->intregm_disabled = ~0xffb2007f;
347
    s->intregm_pending = 0;
348
    s->target_cpu = 0;
349
    slavio_check_interrupts(s);
350
}
351

    
352
void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg,
353
                         const uint32_t *intbit_to_level,
354
                         qemu_irq **irq, qemu_irq **cpu_irq,
355
                         qemu_irq **parent_irq, unsigned int cputimer)
356
{
357
    int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;
358
    SLAVIO_INTCTLState *s;
359

    
360
    s = qemu_mallocz(sizeof(SLAVIO_INTCTLState));
361
    if (!s)
362
        return NULL;
363

    
364
    s->intbit_to_level = intbit_to_level;
365
    for (i = 0; i < MAX_CPUS; i++) {
366
        slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s);
367
        cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_SIZE,
368
                                     slavio_intctl_io_memory);
369
        s->cpu_irqs[i] = parent_irq[i];
370
    }
371

    
372
    slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s);
373
    cpu_register_physical_memory(addrg, INTCTLM_SIZE, slavio_intctlm_io_memory);
374

    
375
    register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s);
376
    qemu_register_reset(slavio_intctl_reset, s);
377
    *irq = qemu_allocate_irqs(slavio_set_irq, s, 32);
378

    
379
    *cpu_irq = qemu_allocate_irqs(slavio_set_timer_irq_cpu, s, MAX_CPUS);
380
    s->cputimer_bit = 1 << s->intbit_to_level[cputimer];
381
    slavio_intctl_reset(s);
382
    return s;
383
}
384