Statistics
| Branch: | Revision:

root / hw / sched.c @ 546fa6ab

History | View | Annotate | Download (7.4 kB)

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