Statistics
| Branch: | Revision:

root / hw / openpic.c @ bc59d9c9

History | View | Annotate | Download (47.2 kB)

1 dbda808a bellard
/*
2 dbda808a bellard
 * OpenPIC emulation
3 5fafdf24 ths
 *
4 dbda808a bellard
 * Copyright (c) 2004 Jocelyn Mayer
5 704c7e5d Alexander Graf
 *               2011 Alexander Graf
6 5fafdf24 ths
 *
7 dbda808a bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 dbda808a bellard
 * of this software and associated documentation files (the "Software"), to deal
9 dbda808a bellard
 * in the Software without restriction, including without limitation the rights
10 dbda808a bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 dbda808a bellard
 * copies of the Software, and to permit persons to whom the Software is
12 dbda808a bellard
 * furnished to do so, subject to the following conditions:
13 dbda808a bellard
 *
14 dbda808a bellard
 * The above copyright notice and this permission notice shall be included in
15 dbda808a bellard
 * all copies or substantial portions of the Software.
16 dbda808a bellard
 *
17 dbda808a bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 dbda808a bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 dbda808a bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 dbda808a bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 dbda808a bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 dbda808a bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 dbda808a bellard
 * THE SOFTWARE.
24 dbda808a bellard
 */
25 dbda808a bellard
/*
26 dbda808a bellard
 *
27 dbda808a bellard
 * Based on OpenPic implementations:
28 67b55785 blueswir1
 * - Intel GW80314 I/O companion chip developer's manual
29 dbda808a bellard
 * - Motorola MPC8245 & MPC8540 user manuals.
30 dbda808a bellard
 * - Motorola MCP750 (aka Raven) programmer manual.
31 dbda808a bellard
 * - Motorola Harrier programmer manuel
32 dbda808a bellard
 *
33 dbda808a bellard
 * Serial interrupts, as implemented in Raven chipset are not supported yet.
34 5fafdf24 ths
 *
35 dbda808a bellard
 */
36 87ecb68b pbrook
#include "hw.h"
37 87ecb68b pbrook
#include "ppc_mac.h"
38 87ecb68b pbrook
#include "pci.h"
39 b7169916 aurel32
#include "openpic.h"
40 dbda808a bellard
41 611493d9 bellard
//#define DEBUG_OPENPIC
42 dbda808a bellard
43 dbda808a bellard
#ifdef DEBUG_OPENPIC
44 001faf32 Blue Swirl
#define DPRINTF(fmt, ...) do { printf(fmt , ## __VA_ARGS__); } while (0)
45 dbda808a bellard
#else
46 001faf32 Blue Swirl
#define DPRINTF(fmt, ...) do { } while (0)
47 dbda808a bellard
#endif
48 dbda808a bellard
49 dbda808a bellard
#define USE_MPCxxx /* Intel model is broken, for now */
50 dbda808a bellard
51 dbda808a bellard
#if defined (USE_INTEL_GW80314)
52 dbda808a bellard
/* Intel GW80314 I/O Companion chip */
53 dbda808a bellard
54 dbda808a bellard
#define MAX_CPU     4
55 dbda808a bellard
#define MAX_IRQ    32
56 dbda808a bellard
#define MAX_DBL     4
57 dbda808a bellard
#define MAX_MBX     4
58 dbda808a bellard
#define MAX_TMR     4
59 dbda808a bellard
#define VECTOR_BITS 8
60 dbda808a bellard
#define MAX_IPI     0
61 dbda808a bellard
62 dbda808a bellard
#define VID (0x00000000)
63 dbda808a bellard
64 dbda808a bellard
#elif defined(USE_MPCxxx)
65 dbda808a bellard
66 dbda808a bellard
#define MAX_CPU     2
67 b7169916 aurel32
#define MAX_IRQ   128
68 dbda808a bellard
#define MAX_DBL     0
69 dbda808a bellard
#define MAX_MBX     0
70 dbda808a bellard
#define MAX_TMR     4
71 dbda808a bellard
#define VECTOR_BITS 8
72 dbda808a bellard
#define MAX_IPI     4
73 dbda808a bellard
#define VID         0x03 /* MPIC version ID */
74 dbda808a bellard
#define VENI        0x00000000 /* Vendor ID */
75 dbda808a bellard
76 dbda808a bellard
enum {
77 dbda808a bellard
    IRQ_IPVP = 0,
78 dbda808a bellard
    IRQ_IDE,
79 dbda808a bellard
};
80 dbda808a bellard
81 b7169916 aurel32
/* OpenPIC */
82 b7169916 aurel32
#define OPENPIC_MAX_CPU      2
83 b7169916 aurel32
#define OPENPIC_MAX_IRQ     64
84 b7169916 aurel32
#define OPENPIC_EXT_IRQ     48
85 b7169916 aurel32
#define OPENPIC_MAX_TMR      MAX_TMR
86 b7169916 aurel32
#define OPENPIC_MAX_IPI      MAX_IPI
87 dbda808a bellard
88 b7169916 aurel32
/* Interrupt definitions */
89 b7169916 aurel32
#define OPENPIC_IRQ_FE     (OPENPIC_EXT_IRQ)     /* Internal functional IRQ */
90 b7169916 aurel32
#define OPENPIC_IRQ_ERR    (OPENPIC_EXT_IRQ + 1) /* Error IRQ */
91 b7169916 aurel32
#define OPENPIC_IRQ_TIM0   (OPENPIC_EXT_IRQ + 2) /* First timer IRQ */
92 b7169916 aurel32
#if OPENPIC_MAX_IPI > 0
93 b7169916 aurel32
#define OPENPIC_IRQ_IPI0   (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First IPI IRQ */
94 b7169916 aurel32
#define OPENPIC_IRQ_DBL0   (OPENPIC_IRQ_IPI0 + (OPENPIC_MAX_CPU * OPENPIC_MAX_IPI)) /* First doorbell IRQ */
95 dbda808a bellard
#else
96 b7169916 aurel32
#define OPENPIC_IRQ_DBL0   (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First doorbell IRQ */
97 b7169916 aurel32
#define OPENPIC_IRQ_MBX0   (OPENPIC_IRQ_DBL0 + OPENPIC_MAX_DBL) /* First mailbox IRQ */
98 dbda808a bellard
#endif
99 dbda808a bellard
100 b7169916 aurel32
/* MPIC */
101 b7169916 aurel32
#define MPIC_MAX_CPU      1
102 b7169916 aurel32
#define MPIC_MAX_EXT     12
103 b7169916 aurel32
#define MPIC_MAX_INT     64
104 b7169916 aurel32
#define MPIC_MAX_MSG      4
105 b7169916 aurel32
#define MPIC_MAX_MSI      8
106 b7169916 aurel32
#define MPIC_MAX_TMR      MAX_TMR
107 b7169916 aurel32
#define MPIC_MAX_IPI      MAX_IPI
108 b7169916 aurel32
#define MPIC_MAX_IRQ     (MPIC_MAX_EXT + MPIC_MAX_INT + MPIC_MAX_TMR + MPIC_MAX_MSG + MPIC_MAX_MSI + (MPIC_MAX_IPI * MPIC_MAX_CPU))
109 dbda808a bellard
110 dbda808a bellard
/* Interrupt definitions */
111 b7169916 aurel32
#define MPIC_EXT_IRQ      0
112 b7169916 aurel32
#define MPIC_INT_IRQ      (MPIC_EXT_IRQ + MPIC_MAX_EXT)
113 b7169916 aurel32
#define MPIC_TMR_IRQ      (MPIC_INT_IRQ + MPIC_MAX_INT)
114 b7169916 aurel32
#define MPIC_MSG_IRQ      (MPIC_TMR_IRQ + MPIC_MAX_TMR)
115 b7169916 aurel32
#define MPIC_MSI_IRQ      (MPIC_MSG_IRQ + MPIC_MAX_MSG)
116 b7169916 aurel32
#define MPIC_IPI_IRQ      (MPIC_MSI_IRQ + MPIC_MAX_MSI)
117 b7169916 aurel32
118 b7169916 aurel32
#define MPIC_GLB_REG_START        0x0
119 b7169916 aurel32
#define MPIC_GLB_REG_SIZE         0x10F0
120 b7169916 aurel32
#define MPIC_TMR_REG_START        0x10F0
121 b7169916 aurel32
#define MPIC_TMR_REG_SIZE         0x220
122 b7169916 aurel32
#define MPIC_EXT_REG_START        0x10000
123 b7169916 aurel32
#define MPIC_EXT_REG_SIZE         0x180
124 b7169916 aurel32
#define MPIC_INT_REG_START        0x10200
125 b7169916 aurel32
#define MPIC_INT_REG_SIZE         0x800
126 b7169916 aurel32
#define MPIC_MSG_REG_START        0x11600
127 b7169916 aurel32
#define MPIC_MSG_REG_SIZE         0x100
128 b7169916 aurel32
#define MPIC_MSI_REG_START        0x11C00
129 b7169916 aurel32
#define MPIC_MSI_REG_SIZE         0x100
130 b7169916 aurel32
#define MPIC_CPU_REG_START        0x20000
131 bc59d9c9 Alexander Graf
#define MPIC_CPU_REG_SIZE         0x100 + ((MAX_CPU - 1) * 0x1000)
132 b7169916 aurel32
133 b7169916 aurel32
enum mpic_ide_bits {
134 b7169916 aurel32
    IDR_EP     = 0,
135 b7169916 aurel32
    IDR_CI0     = 1,
136 b7169916 aurel32
    IDR_CI1     = 2,
137 b7169916 aurel32
    IDR_P1     = 30,
138 b7169916 aurel32
    IDR_P0     = 31,
139 b7169916 aurel32
};
140 b7169916 aurel32
141 dbda808a bellard
#else
142 b7169916 aurel32
#error "Please select which OpenPic implementation is to be emulated"
143 dbda808a bellard
#endif
144 dbda808a bellard
145 5c4532ee Blue Swirl
#define OPENPIC_PAGE_SIZE 4096
146 5c4532ee Blue Swirl
147 dbda808a bellard
#define BF_WIDTH(_bits_) \
148 dbda808a bellard
(((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8))
149 dbda808a bellard
150 dbda808a bellard
static inline void set_bit (uint32_t *field, int bit)
151 dbda808a bellard
{
152 dbda808a bellard
    field[bit >> 5] |= 1 << (bit & 0x1F);
153 dbda808a bellard
}
154 dbda808a bellard
155 dbda808a bellard
static inline void reset_bit (uint32_t *field, int bit)
156 dbda808a bellard
{
157 dbda808a bellard
    field[bit >> 5] &= ~(1 << (bit & 0x1F));
158 dbda808a bellard
}
159 dbda808a bellard
160 dbda808a bellard
static inline int test_bit (uint32_t *field, int bit)
161 dbda808a bellard
{
162 dbda808a bellard
    return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
163 dbda808a bellard
}
164 dbda808a bellard
165 704c7e5d Alexander Graf
static int get_current_cpu(void)
166 704c7e5d Alexander Graf
{
167 704c7e5d Alexander Graf
  return cpu_single_env->cpu_index;
168 704c7e5d Alexander Graf
}
169 704c7e5d Alexander Graf
170 704c7e5d Alexander Graf
static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr,
171 704c7e5d Alexander Graf
                                          int idx);
172 704c7e5d Alexander Graf
static void openpic_cpu_write_internal(void *opaque, target_phys_addr_t addr,
173 704c7e5d Alexander Graf
                                       uint32_t val, int idx);
174 704c7e5d Alexander Graf
175 dbda808a bellard
enum {
176 dbda808a bellard
    IRQ_EXTERNAL = 0x01,
177 dbda808a bellard
    IRQ_INTERNAL = 0x02,
178 dbda808a bellard
    IRQ_TIMER    = 0x04,
179 dbda808a bellard
    IRQ_SPECIAL  = 0x08,
180 b1d8e52e blueswir1
};
181 dbda808a bellard
182 c227f099 Anthony Liguori
typedef struct IRQ_queue_t {
183 dbda808a bellard
    uint32_t queue[BF_WIDTH(MAX_IRQ)];
184 dbda808a bellard
    int next;
185 dbda808a bellard
    int priority;
186 c227f099 Anthony Liguori
} IRQ_queue_t;
187 dbda808a bellard
188 c227f099 Anthony Liguori
typedef struct IRQ_src_t {
189 dbda808a bellard
    uint32_t ipvp;  /* IRQ vector/priority register */
190 dbda808a bellard
    uint32_t ide;   /* IRQ destination register */
191 dbda808a bellard
    int type;
192 dbda808a bellard
    int last_cpu;
193 611493d9 bellard
    int pending;    /* TRUE if IRQ is pending */
194 c227f099 Anthony Liguori
} IRQ_src_t;
195 dbda808a bellard
196 dbda808a bellard
enum IPVP_bits {
197 dbda808a bellard
    IPVP_MASK     = 31,
198 dbda808a bellard
    IPVP_ACTIVITY = 30,
199 dbda808a bellard
    IPVP_MODE     = 29,
200 dbda808a bellard
    IPVP_POLARITY = 23,
201 dbda808a bellard
    IPVP_SENSE    = 22,
202 dbda808a bellard
};
203 dbda808a bellard
#define IPVP_PRIORITY_MASK     (0x1F << 16)
204 611493d9 bellard
#define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16))
205 dbda808a bellard
#define IPVP_VECTOR_MASK       ((1 << VECTOR_BITS) - 1)
206 dbda808a bellard
#define IPVP_VECTOR(_ipvpr_)   ((_ipvpr_) & IPVP_VECTOR_MASK)
207 dbda808a bellard
208 c227f099 Anthony Liguori
typedef struct IRQ_dst_t {
209 b7169916 aurel32
    uint32_t tfrr;
210 dbda808a bellard
    uint32_t pctp; /* CPU current task priority */
211 dbda808a bellard
    uint32_t pcsr; /* CPU sensitivity register */
212 c227f099 Anthony Liguori
    IRQ_queue_t raised;
213 c227f099 Anthony Liguori
    IRQ_queue_t servicing;
214 e9df014c j_mayer
    qemu_irq *irqs;
215 c227f099 Anthony Liguori
} IRQ_dst_t;
216 dbda808a bellard
217 c227f099 Anthony Liguori
typedef struct openpic_t {
218 dbda808a bellard
    PCIDevice pci_dev;
219 23c5e4ca Avi Kivity
    MemoryRegion mem;
220 dbda808a bellard
    /* Global registers */
221 dbda808a bellard
    uint32_t frep; /* Feature reporting register */
222 dbda808a bellard
    uint32_t glbc; /* Global configuration register  */
223 dbda808a bellard
    uint32_t micr; /* MPIC interrupt configuration register */
224 dbda808a bellard
    uint32_t veni; /* Vendor identification register */
225 e9df014c j_mayer
    uint32_t pint; /* Processor initialization register */
226 dbda808a bellard
    uint32_t spve; /* Spurious vector register */
227 dbda808a bellard
    uint32_t tifr; /* Timer frequency reporting register */
228 dbda808a bellard
    /* Source registers */
229 c227f099 Anthony Liguori
    IRQ_src_t src[MAX_IRQ];
230 dbda808a bellard
    /* Local registers per output pin */
231 c227f099 Anthony Liguori
    IRQ_dst_t dst[MAX_CPU];
232 dbda808a bellard
    int nb_cpus;
233 dbda808a bellard
    /* Timer registers */
234 dbda808a bellard
    struct {
235 060fbfe1 Aurelien Jarno
        uint32_t ticc;  /* Global timer current count register */
236 060fbfe1 Aurelien Jarno
        uint32_t tibc;  /* Global timer base count register */
237 dbda808a bellard
    } timers[MAX_TMR];
238 dbda808a bellard
#if MAX_DBL > 0
239 dbda808a bellard
    /* Doorbell registers */
240 dbda808a bellard
    uint32_t dar;        /* Doorbell activate register */
241 dbda808a bellard
    struct {
242 060fbfe1 Aurelien Jarno
        uint32_t dmr;    /* Doorbell messaging register */
243 dbda808a bellard
    } doorbells[MAX_DBL];
244 dbda808a bellard
#endif
245 dbda808a bellard
#if MAX_MBX > 0
246 dbda808a bellard
    /* Mailbox registers */
247 dbda808a bellard
    struct {
248 060fbfe1 Aurelien Jarno
        uint32_t mbr;    /* Mailbox register */
249 dbda808a bellard
    } mailboxes[MAX_MAILBOXES];
250 dbda808a bellard
#endif
251 e9df014c j_mayer
    /* IRQ out is used when in bypass mode (not implemented) */
252 e9df014c j_mayer
    qemu_irq irq_out;
253 b7169916 aurel32
    int max_irq;
254 b7169916 aurel32
    int irq_ipi0;
255 b7169916 aurel32
    int irq_tim0;
256 b7169916 aurel32
    void (*reset) (void *);
257 c227f099 Anthony Liguori
    void (*irq_raise) (struct openpic_t *, int, IRQ_src_t *);
258 c227f099 Anthony Liguori
} openpic_t;
259 dbda808a bellard
260 c227f099 Anthony Liguori
static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
261 dbda808a bellard
{
262 dbda808a bellard
    set_bit(q->queue, n_IRQ);
263 dbda808a bellard
}
264 dbda808a bellard
265 c227f099 Anthony Liguori
static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ)
266 dbda808a bellard
{
267 dbda808a bellard
    reset_bit(q->queue, n_IRQ);
268 dbda808a bellard
}
269 dbda808a bellard
270 c227f099 Anthony Liguori
static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ)
271 dbda808a bellard
{
272 dbda808a bellard
    return test_bit(q->queue, n_IRQ);
273 dbda808a bellard
}
274 dbda808a bellard
275 c227f099 Anthony Liguori
static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
276 dbda808a bellard
{
277 dbda808a bellard
    int next, i;
278 dbda808a bellard
    int priority;
279 dbda808a bellard
280 dbda808a bellard
    next = -1;
281 dbda808a bellard
    priority = -1;
282 b7169916 aurel32
    for (i = 0; i < opp->max_irq; i++) {
283 060fbfe1 Aurelien Jarno
        if (IRQ_testbit(q, i)) {
284 5fafdf24 ths
            DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n",
285 611493d9 bellard
                    i, IPVP_PRIORITY(opp->src[i].ipvp), priority);
286 060fbfe1 Aurelien Jarno
            if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {
287 060fbfe1 Aurelien Jarno
                next = i;
288 060fbfe1 Aurelien Jarno
                priority = IPVP_PRIORITY(opp->src[i].ipvp);
289 060fbfe1 Aurelien Jarno
            }
290 060fbfe1 Aurelien Jarno
        }
291 dbda808a bellard
    }
292 dbda808a bellard
    q->next = next;
293 dbda808a bellard
    q->priority = priority;
294 dbda808a bellard
}
295 dbda808a bellard
296 c227f099 Anthony Liguori
static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q)
297 dbda808a bellard
{
298 dbda808a bellard
    if (q->next == -1) {
299 611493d9 bellard
        /* XXX: optimize */
300 060fbfe1 Aurelien Jarno
        IRQ_check(opp, q);
301 dbda808a bellard
    }
302 dbda808a bellard
303 dbda808a bellard
    return q->next;
304 dbda808a bellard
}
305 dbda808a bellard
306 c227f099 Anthony Liguori
static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
307 dbda808a bellard
{
308 c227f099 Anthony Liguori
    IRQ_dst_t *dst;
309 c227f099 Anthony Liguori
    IRQ_src_t *src;
310 dbda808a bellard
    int priority;
311 dbda808a bellard
312 dbda808a bellard
    dst = &opp->dst[n_CPU];
313 dbda808a bellard
    src = &opp->src[n_IRQ];
314 dbda808a bellard
    priority = IPVP_PRIORITY(src->ipvp);
315 dbda808a bellard
    if (priority <= dst->pctp) {
316 060fbfe1 Aurelien Jarno
        /* Too low priority */
317 e9df014c j_mayer
        DPRINTF("%s: IRQ %d has too low priority on CPU %d\n",
318 e9df014c j_mayer
                __func__, n_IRQ, n_CPU);
319 060fbfe1 Aurelien Jarno
        return;
320 dbda808a bellard
    }
321 dbda808a bellard
    if (IRQ_testbit(&dst->raised, n_IRQ)) {
322 060fbfe1 Aurelien Jarno
        /* Interrupt miss */
323 e9df014c j_mayer
        DPRINTF("%s: IRQ %d was missed on CPU %d\n",
324 e9df014c j_mayer
                __func__, n_IRQ, n_CPU);
325 060fbfe1 Aurelien Jarno
        return;
326 dbda808a bellard
    }
327 dbda808a bellard
    set_bit(&src->ipvp, IPVP_ACTIVITY);
328 dbda808a bellard
    IRQ_setbit(&dst->raised, n_IRQ);
329 e9df014c j_mayer
    if (priority < dst->raised.priority) {
330 e9df014c j_mayer
        /* An higher priority IRQ is already raised */
331 e9df014c j_mayer
        DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n",
332 e9df014c j_mayer
                __func__, n_IRQ, dst->raised.next, n_CPU);
333 e9df014c j_mayer
        return;
334 e9df014c j_mayer
    }
335 e9df014c j_mayer
    IRQ_get_next(opp, &dst->raised);
336 e9df014c j_mayer
    if (IRQ_get_next(opp, &dst->servicing) != -1 &&
337 24865167 aliguori
        priority <= dst->servicing.priority) {
338 e9df014c j_mayer
        DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
339 e9df014c j_mayer
                __func__, n_IRQ, dst->servicing.next, n_CPU);
340 e9df014c j_mayer
        /* Already servicing a higher priority IRQ */
341 e9df014c j_mayer
        return;
342 dbda808a bellard
    }
343 e9df014c j_mayer
    DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ);
344 b7169916 aurel32
    opp->irq_raise(opp, n_CPU, src);
345 dbda808a bellard
}
346 dbda808a bellard
347 611493d9 bellard
/* update pic state because registers for n_IRQ have changed value */
348 c227f099 Anthony Liguori
static void openpic_update_irq(openpic_t *opp, int n_IRQ)
349 dbda808a bellard
{
350 c227f099 Anthony Liguori
    IRQ_src_t *src;
351 dbda808a bellard
    int i;
352 dbda808a bellard
353 dbda808a bellard
    src = &opp->src[n_IRQ];
354 611493d9 bellard
355 611493d9 bellard
    if (!src->pending) {
356 611493d9 bellard
        /* no irq pending */
357 e9df014c j_mayer
        DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ);
358 611493d9 bellard
        return;
359 611493d9 bellard
    }
360 611493d9 bellard
    if (test_bit(&src->ipvp, IPVP_MASK)) {
361 060fbfe1 Aurelien Jarno
        /* Interrupt source is disabled */
362 e9df014c j_mayer
        DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
363 060fbfe1 Aurelien Jarno
        return;
364 dbda808a bellard
    }
365 dbda808a bellard
    if (IPVP_PRIORITY(src->ipvp) == 0) {
366 060fbfe1 Aurelien Jarno
        /* Priority set to zero */
367 e9df014c j_mayer
        DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ);
368 060fbfe1 Aurelien Jarno
        return;
369 dbda808a bellard
    }
370 611493d9 bellard
    if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
371 611493d9 bellard
        /* IRQ already active */
372 e9df014c j_mayer
        DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ);
373 611493d9 bellard
        return;
374 611493d9 bellard
    }
375 dbda808a bellard
    if (src->ide == 0x00000000) {
376 060fbfe1 Aurelien Jarno
        /* No target */
377 e9df014c j_mayer
        DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
378 060fbfe1 Aurelien Jarno
        return;
379 dbda808a bellard
    }
380 611493d9 bellard
381 e9df014c j_mayer
    if (src->ide == (1 << src->last_cpu)) {
382 e9df014c j_mayer
        /* Only one CPU is allowed to receive this IRQ */
383 e9df014c j_mayer
        IRQ_local_pipe(opp, src->last_cpu, n_IRQ);
384 e9df014c j_mayer
    } else if (!test_bit(&src->ipvp, IPVP_MODE)) {
385 611493d9 bellard
        /* Directed delivery mode */
386 611493d9 bellard
        for (i = 0; i < opp->nb_cpus; i++) {
387 611493d9 bellard
            if (test_bit(&src->ide, i))
388 611493d9 bellard
                IRQ_local_pipe(opp, i, n_IRQ);
389 611493d9 bellard
        }
390 dbda808a bellard
    } else {
391 611493d9 bellard
        /* Distributed delivery mode */
392 e9df014c j_mayer
        for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
393 e9df014c j_mayer
            if (i == opp->nb_cpus)
394 611493d9 bellard
                i = 0;
395 611493d9 bellard
            if (test_bit(&src->ide, i)) {
396 611493d9 bellard
                IRQ_local_pipe(opp, i, n_IRQ);
397 611493d9 bellard
                src->last_cpu = i;
398 611493d9 bellard
                break;
399 611493d9 bellard
            }
400 611493d9 bellard
        }
401 611493d9 bellard
    }
402 611493d9 bellard
}
403 611493d9 bellard
404 d537cf6c pbrook
static void openpic_set_irq(void *opaque, int n_IRQ, int level)
405 611493d9 bellard
{
406 c227f099 Anthony Liguori
    openpic_t *opp = opaque;
407 c227f099 Anthony Liguori
    IRQ_src_t *src;
408 611493d9 bellard
409 611493d9 bellard
    src = &opp->src[n_IRQ];
410 5fafdf24 ths
    DPRINTF("openpic: set irq %d = %d ipvp=%08x\n",
411 611493d9 bellard
            n_IRQ, level, src->ipvp);
412 611493d9 bellard
    if (test_bit(&src->ipvp, IPVP_SENSE)) {
413 611493d9 bellard
        /* level-sensitive irq */
414 611493d9 bellard
        src->pending = level;
415 611493d9 bellard
        if (!level)
416 611493d9 bellard
            reset_bit(&src->ipvp, IPVP_ACTIVITY);
417 611493d9 bellard
    } else {
418 611493d9 bellard
        /* edge-sensitive irq */
419 611493d9 bellard
        if (level)
420 611493d9 bellard
            src->pending = 1;
421 dbda808a bellard
    }
422 611493d9 bellard
    openpic_update_irq(opp, n_IRQ);
423 dbda808a bellard
}
424 dbda808a bellard
425 67b55785 blueswir1
static void openpic_reset (void *opaque)
426 dbda808a bellard
{
427 c227f099 Anthony Liguori
    openpic_t *opp = (openpic_t *)opaque;
428 dbda808a bellard
    int i;
429 dbda808a bellard
430 dbda808a bellard
    opp->glbc = 0x80000000;
431 f8407028 bellard
    /* Initialise controller registers */
432 b7169916 aurel32
    opp->frep = ((OPENPIC_EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
433 dbda808a bellard
    opp->veni = VENI;
434 e9df014c j_mayer
    opp->pint = 0x00000000;
435 dbda808a bellard
    opp->spve = 0x000000FF;
436 dbda808a bellard
    opp->tifr = 0x003F7A00;
437 dbda808a bellard
    /* ? */
438 dbda808a bellard
    opp->micr = 0x00000000;
439 dbda808a bellard
    /* Initialise IRQ sources */
440 b7169916 aurel32
    for (i = 0; i < opp->max_irq; i++) {
441 060fbfe1 Aurelien Jarno
        opp->src[i].ipvp = 0xA0000000;
442 060fbfe1 Aurelien Jarno
        opp->src[i].ide  = 0x00000000;
443 dbda808a bellard
    }
444 dbda808a bellard
    /* Initialise IRQ destinations */
445 e9df014c j_mayer
    for (i = 0; i < MAX_CPU; i++) {
446 060fbfe1 Aurelien Jarno
        opp->dst[i].pctp      = 0x0000000F;
447 060fbfe1 Aurelien Jarno
        opp->dst[i].pcsr      = 0x00000000;
448 060fbfe1 Aurelien Jarno
        memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
449 d14ed254 Alexander Graf
        opp->dst[i].raised.next = -1;
450 060fbfe1 Aurelien Jarno
        memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
451 d14ed254 Alexander Graf
        opp->dst[i].servicing.next = -1;
452 dbda808a bellard
    }
453 dbda808a bellard
    /* Initialise timers */
454 dbda808a bellard
    for (i = 0; i < MAX_TMR; i++) {
455 060fbfe1 Aurelien Jarno
        opp->timers[i].ticc = 0x00000000;
456 060fbfe1 Aurelien Jarno
        opp->timers[i].tibc = 0x80000000;
457 dbda808a bellard
    }
458 dbda808a bellard
    /* Initialise doorbells */
459 dbda808a bellard
#if MAX_DBL > 0
460 dbda808a bellard
    opp->dar = 0x00000000;
461 dbda808a bellard
    for (i = 0; i < MAX_DBL; i++) {
462 060fbfe1 Aurelien Jarno
        opp->doorbells[i].dmr  = 0x00000000;
463 dbda808a bellard
    }
464 dbda808a bellard
#endif
465 dbda808a bellard
    /* Initialise mailboxes */
466 dbda808a bellard
#if MAX_MBX > 0
467 dbda808a bellard
    for (i = 0; i < MAX_MBX; i++) { /* ? */
468 060fbfe1 Aurelien Jarno
        opp->mailboxes[i].mbr   = 0x00000000;
469 dbda808a bellard
    }
470 dbda808a bellard
#endif
471 dbda808a bellard
    /* Go out of RESET state */
472 dbda808a bellard
    opp->glbc = 0x00000000;
473 dbda808a bellard
}
474 dbda808a bellard
475 c227f099 Anthony Liguori
static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg)
476 dbda808a bellard
{
477 dbda808a bellard
    uint32_t retval;
478 dbda808a bellard
479 dbda808a bellard
    switch (reg) {
480 dbda808a bellard
    case IRQ_IPVP:
481 060fbfe1 Aurelien Jarno
        retval = opp->src[n_IRQ].ipvp;
482 060fbfe1 Aurelien Jarno
        break;
483 dbda808a bellard
    case IRQ_IDE:
484 060fbfe1 Aurelien Jarno
        retval = opp->src[n_IRQ].ide;
485 060fbfe1 Aurelien Jarno
        break;
486 dbda808a bellard
    }
487 dbda808a bellard
488 dbda808a bellard
    return retval;
489 dbda808a bellard
}
490 dbda808a bellard
491 c227f099 Anthony Liguori
static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
492 dbda808a bellard
                                 uint32_t reg, uint32_t val)
493 dbda808a bellard
{
494 dbda808a bellard
    uint32_t tmp;
495 dbda808a bellard
496 dbda808a bellard
    switch (reg) {
497 dbda808a bellard
    case IRQ_IPVP:
498 611493d9 bellard
        /* NOTE: not fully accurate for special IRQs, but simple and
499 611493d9 bellard
           sufficient */
500 611493d9 bellard
        /* ACTIVITY bit is read-only */
501 060fbfe1 Aurelien Jarno
        opp->src[n_IRQ].ipvp =
502 611493d9 bellard
            (opp->src[n_IRQ].ipvp & 0x40000000) |
503 611493d9 bellard
            (val & 0x800F00FF);
504 611493d9 bellard
        openpic_update_irq(opp, n_IRQ);
505 5fafdf24 ths
        DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n",
506 611493d9 bellard
                n_IRQ, val, opp->src[n_IRQ].ipvp);
507 060fbfe1 Aurelien Jarno
        break;
508 dbda808a bellard
    case IRQ_IDE:
509 060fbfe1 Aurelien Jarno
        tmp = val & 0xC0000000;
510 dbda808a bellard
        tmp |= val & ((1 << MAX_CPU) - 1);
511 060fbfe1 Aurelien Jarno
        opp->src[n_IRQ].ide = tmp;
512 dbda808a bellard
        DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
513 060fbfe1 Aurelien Jarno
        break;
514 dbda808a bellard
    }
515 dbda808a bellard
}
516 dbda808a bellard
517 dbda808a bellard
#if 0 // Code provision for Intel model
518 dbda808a bellard
#if MAX_DBL > 0
519 c227f099 Anthony Liguori
static uint32_t read_doorbell_register (openpic_t *opp,
520 060fbfe1 Aurelien Jarno
                                        int n_dbl, uint32_t offset)
521 dbda808a bellard
{
522 dbda808a bellard
    uint32_t retval;
523 dbda808a bellard

524 dbda808a bellard
    switch (offset) {
525 dbda808a bellard
    case DBL_IPVP_OFFSET:
526 060fbfe1 Aurelien Jarno
        retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP);
527 060fbfe1 Aurelien Jarno
        break;
528 dbda808a bellard
    case DBL_IDE_OFFSET:
529 060fbfe1 Aurelien Jarno
        retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE);
530 060fbfe1 Aurelien Jarno
        break;
531 dbda808a bellard
    case DBL_DMR_OFFSET:
532 060fbfe1 Aurelien Jarno
        retval = opp->doorbells[n_dbl].dmr;
533 060fbfe1 Aurelien Jarno
        break;
534 dbda808a bellard
    }
535 dbda808a bellard

536 dbda808a bellard
    return retval;
537 dbda808a bellard
}
538 3b46e624 ths

539 dbda808a bellard
static void write_doorbell_register (penpic_t *opp, int n_dbl,
540 060fbfe1 Aurelien Jarno
                                     uint32_t offset, uint32_t value)
541 dbda808a bellard
{
542 dbda808a bellard
    switch (offset) {
543 dbda808a bellard
    case DBL_IVPR_OFFSET:
544 060fbfe1 Aurelien Jarno
        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value);
545 060fbfe1 Aurelien Jarno
        break;
546 dbda808a bellard
    case DBL_IDE_OFFSET:
547 060fbfe1 Aurelien Jarno
        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value);
548 060fbfe1 Aurelien Jarno
        break;
549 dbda808a bellard
    case DBL_DMR_OFFSET:
550 060fbfe1 Aurelien Jarno
        opp->doorbells[n_dbl].dmr = value;
551 060fbfe1 Aurelien Jarno
        break;
552 dbda808a bellard
    }
553 dbda808a bellard
}
554 dbda808a bellard
#endif
555 dbda808a bellard
556 dbda808a bellard
#if MAX_MBX > 0
557 c227f099 Anthony Liguori
static uint32_t read_mailbox_register (openpic_t *opp,
558 060fbfe1 Aurelien Jarno
                                       int n_mbx, uint32_t offset)
559 dbda808a bellard
{
560 dbda808a bellard
    uint32_t retval;
561 dbda808a bellard
562 dbda808a bellard
    switch (offset) {
563 dbda808a bellard
    case MBX_MBR_OFFSET:
564 060fbfe1 Aurelien Jarno
        retval = opp->mailboxes[n_mbx].mbr;
565 060fbfe1 Aurelien Jarno
        break;
566 dbda808a bellard
    case MBX_IVPR_OFFSET:
567 060fbfe1 Aurelien Jarno
        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP);
568 060fbfe1 Aurelien Jarno
        break;
569 dbda808a bellard
    case MBX_DMR_OFFSET:
570 060fbfe1 Aurelien Jarno
        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE);
571 060fbfe1 Aurelien Jarno
        break;
572 dbda808a bellard
    }
573 dbda808a bellard
574 dbda808a bellard
    return retval;
575 dbda808a bellard
}
576 dbda808a bellard
577 c227f099 Anthony Liguori
static void write_mailbox_register (openpic_t *opp, int n_mbx,
578 060fbfe1 Aurelien Jarno
                                    uint32_t address, uint32_t value)
579 dbda808a bellard
{
580 dbda808a bellard
    switch (offset) {
581 dbda808a bellard
    case MBX_MBR_OFFSET:
582 060fbfe1 Aurelien Jarno
        opp->mailboxes[n_mbx].mbr = value;
583 060fbfe1 Aurelien Jarno
        break;
584 dbda808a bellard
    case MBX_IVPR_OFFSET:
585 060fbfe1 Aurelien Jarno
        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value);
586 060fbfe1 Aurelien Jarno
        break;
587 dbda808a bellard
    case MBX_DMR_OFFSET:
588 060fbfe1 Aurelien Jarno
        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value);
589 060fbfe1 Aurelien Jarno
        break;
590 dbda808a bellard
    }
591 dbda808a bellard
}
592 dbda808a bellard
#endif
593 dbda808a bellard
#endif /* 0 : Code provision for Intel model */
594 dbda808a bellard
595 c227f099 Anthony Liguori
static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t val)
596 dbda808a bellard
{
597 c227f099 Anthony Liguori
    openpic_t *opp = opaque;
598 c227f099 Anthony Liguori
    IRQ_dst_t *dst;
599 e9df014c j_mayer
    int idx;
600 dbda808a bellard
601 0bf9e31a Blue Swirl
    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
602 dbda808a bellard
    if (addr & 0xF)
603 dbda808a bellard
        return;
604 dbda808a bellard
    switch (addr) {
605 704c7e5d Alexander Graf
    case 0x40:
606 704c7e5d Alexander Graf
    case 0x50:
607 704c7e5d Alexander Graf
    case 0x60:
608 704c7e5d Alexander Graf
    case 0x70:
609 704c7e5d Alexander Graf
    case 0x80:
610 704c7e5d Alexander Graf
    case 0x90:
611 704c7e5d Alexander Graf
    case 0xA0:
612 704c7e5d Alexander Graf
    case 0xB0:
613 704c7e5d Alexander Graf
        openpic_cpu_write_internal(opp, addr, val, get_current_cpu());
614 704c7e5d Alexander Graf
        break;
615 704c7e5d Alexander Graf
    case 0x1000: /* FREP */
616 dbda808a bellard
        break;
617 704c7e5d Alexander Graf
    case 0x1020: /* GLBC */
618 b7169916 aurel32
        if (val & 0x80000000 && opp->reset)
619 b7169916 aurel32
            opp->reset(opp);
620 dbda808a bellard
        opp->glbc = val & ~0x80000000;
621 060fbfe1 Aurelien Jarno
        break;
622 704c7e5d Alexander Graf
    case 0x1080: /* VENI */
623 060fbfe1 Aurelien Jarno
        break;
624 704c7e5d Alexander Graf
    case 0x1090: /* PINT */
625 e9df014c j_mayer
        for (idx = 0; idx < opp->nb_cpus; idx++) {
626 e9df014c j_mayer
            if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) {
627 e9df014c j_mayer
                DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
628 e9df014c j_mayer
                dst = &opp->dst[idx];
629 e9df014c j_mayer
                qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
630 e9df014c j_mayer
            } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) {
631 e9df014c j_mayer
                DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
632 e9df014c j_mayer
                dst = &opp->dst[idx];
633 e9df014c j_mayer
                qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
634 e9df014c j_mayer
            }
635 dbda808a bellard
        }
636 e9df014c j_mayer
        opp->pint = val;
637 060fbfe1 Aurelien Jarno
        break;
638 704c7e5d Alexander Graf
    case 0x10A0: /* IPI_IPVP */
639 704c7e5d Alexander Graf
    case 0x10B0:
640 704c7e5d Alexander Graf
    case 0x10C0:
641 704c7e5d Alexander Graf
    case 0x10D0:
642 dbda808a bellard
        {
643 dbda808a bellard
            int idx;
644 704c7e5d Alexander Graf
            idx = (addr - 0x10A0) >> 4;
645 b7169916 aurel32
            write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP, val);
646 dbda808a bellard
        }
647 dbda808a bellard
        break;
648 704c7e5d Alexander Graf
    case 0x10E0: /* SPVE */
649 dbda808a bellard
        opp->spve = val & 0x000000FF;
650 dbda808a bellard
        break;
651 704c7e5d Alexander Graf
    case 0x10F0: /* TIFR */
652 dbda808a bellard
        opp->tifr = val;
653 060fbfe1 Aurelien Jarno
        break;
654 dbda808a bellard
    default:
655 dbda808a bellard
        break;
656 dbda808a bellard
    }
657 dbda808a bellard
}
658 dbda808a bellard
659 c227f099 Anthony Liguori
static uint32_t openpic_gbl_read (void *opaque, target_phys_addr_t addr)
660 dbda808a bellard
{
661 c227f099 Anthony Liguori
    openpic_t *opp = opaque;
662 dbda808a bellard
    uint32_t retval;
663 dbda808a bellard
664 0bf9e31a Blue Swirl
    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
665 dbda808a bellard
    retval = 0xFFFFFFFF;
666 dbda808a bellard
    if (addr & 0xF)
667 dbda808a bellard
        return retval;
668 dbda808a bellard
    switch (addr) {
669 704c7e5d Alexander Graf
    case 0x1000: /* FREP */
670 dbda808a bellard
        retval = opp->frep;
671 dbda808a bellard
        break;
672 704c7e5d Alexander Graf
    case 0x1020: /* GLBC */
673 dbda808a bellard
        retval = opp->glbc;
674 060fbfe1 Aurelien Jarno
        break;
675 704c7e5d Alexander Graf
    case 0x1080: /* VENI */
676 dbda808a bellard
        retval = opp->veni;
677 060fbfe1 Aurelien Jarno
        break;
678 704c7e5d Alexander Graf
    case 0x1090: /* PINT */
679 dbda808a bellard
        retval = 0x00000000;
680 060fbfe1 Aurelien Jarno
        break;
681 704c7e5d Alexander Graf
    case 0x40:
682 704c7e5d Alexander Graf
    case 0x50:
683 704c7e5d Alexander Graf
    case 0x60:
684 704c7e5d Alexander Graf
    case 0x70:
685 704c7e5d Alexander Graf
    case 0x80:
686 704c7e5d Alexander Graf
    case 0x90:
687 704c7e5d Alexander Graf
    case 0xA0:
688 dbda808a bellard
    case 0xB0:
689 704c7e5d Alexander Graf
        retval = openpic_cpu_read_internal(opp, addr, get_current_cpu());
690 704c7e5d Alexander Graf
        break;
691 704c7e5d Alexander Graf
    case 0x10A0: /* IPI_IPVP */
692 704c7e5d Alexander Graf
    case 0x10B0:
693 704c7e5d Alexander Graf
    case 0x10C0:
694 704c7e5d Alexander Graf
    case 0x10D0:
695 dbda808a bellard
        {
696 dbda808a bellard
            int idx;
697 704c7e5d Alexander Graf
            idx = (addr - 0x10A0) >> 4;
698 b7169916 aurel32
            retval = read_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP);
699 dbda808a bellard
        }
700 060fbfe1 Aurelien Jarno
        break;
701 704c7e5d Alexander Graf
    case 0x10E0: /* SPVE */
702 dbda808a bellard
        retval = opp->spve;
703 dbda808a bellard
        break;
704 704c7e5d Alexander Graf
    case 0x10F0: /* TIFR */
705 dbda808a bellard
        retval = opp->tifr;
706 060fbfe1 Aurelien Jarno
        break;
707 dbda808a bellard
    default:
708 dbda808a bellard
        break;
709 dbda808a bellard
    }
710 dbda808a bellard
    DPRINTF("%s: => %08x\n", __func__, retval);
711 dbda808a bellard
712 dbda808a bellard
    return retval;
713 dbda808a bellard
}
714 dbda808a bellard
715 dbda808a bellard
static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
716 dbda808a bellard
{
717 c227f099 Anthony Liguori
    openpic_t *opp = opaque;
718 dbda808a bellard
    int idx;
719 dbda808a bellard
720 dbda808a bellard
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
721 dbda808a bellard
    if (addr & 0xF)
722 dbda808a bellard
        return;
723 dbda808a bellard
    addr -= 0x1100;
724 dbda808a bellard
    addr &= 0xFFFF;
725 dbda808a bellard
    idx = (addr & 0xFFF0) >> 6;
726 dbda808a bellard
    addr = addr & 0x30;
727 dbda808a bellard
    switch (addr) {
728 dbda808a bellard
    case 0x00: /* TICC */
729 dbda808a bellard
        break;
730 dbda808a bellard
    case 0x10: /* TIBC */
731 060fbfe1 Aurelien Jarno
        if ((opp->timers[idx].ticc & 0x80000000) != 0 &&
732 060fbfe1 Aurelien Jarno
            (val & 0x80000000) == 0 &&
733 dbda808a bellard
            (opp->timers[idx].tibc & 0x80000000) != 0)
734 060fbfe1 Aurelien Jarno
            opp->timers[idx].ticc &= ~0x80000000;
735 060fbfe1 Aurelien Jarno
        opp->timers[idx].tibc = val;
736 060fbfe1 Aurelien Jarno
        break;
737 dbda808a bellard
    case 0x20: /* TIVP */
738 b7169916 aurel32
        write_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IPVP, val);
739 060fbfe1 Aurelien Jarno
        break;
740 dbda808a bellard
    case 0x30: /* TIDE */
741 b7169916 aurel32
        write_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IDE, val);
742 060fbfe1 Aurelien Jarno
        break;
743 dbda808a bellard
    }
744 dbda808a bellard
}
745 dbda808a bellard
746 dbda808a bellard
static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
747 dbda808a bellard
{
748 c227f099 Anthony Liguori
    openpic_t *opp = opaque;
749 dbda808a bellard
    uint32_t retval;
750 dbda808a bellard
    int idx;
751 dbda808a bellard
752 dbda808a bellard
    DPRINTF("%s: addr %08x\n", __func__, addr);
753 dbda808a bellard
    retval = 0xFFFFFFFF;
754 dbda808a bellard
    if (addr & 0xF)
755 dbda808a bellard
        return retval;
756 dbda808a bellard
    addr -= 0x1100;
757 dbda808a bellard
    addr &= 0xFFFF;
758 dbda808a bellard
    idx = (addr & 0xFFF0) >> 6;
759 dbda808a bellard
    addr = addr & 0x30;
760 dbda808a bellard
    switch (addr) {
761 dbda808a bellard
    case 0x00: /* TICC */
762 060fbfe1 Aurelien Jarno
        retval = opp->timers[idx].ticc;
763 dbda808a bellard
        break;
764 dbda808a bellard
    case 0x10: /* TIBC */
765 060fbfe1 Aurelien Jarno
        retval = opp->timers[idx].tibc;
766 060fbfe1 Aurelien Jarno
        break;
767 dbda808a bellard
    case 0x20: /* TIPV */
768 b7169916 aurel32
        retval = read_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IPVP);
769 060fbfe1 Aurelien Jarno
        break;
770 dbda808a bellard
    case 0x30: /* TIDE */
771 b7169916 aurel32
        retval = read_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IDE);
772 060fbfe1 Aurelien Jarno
        break;
773 dbda808a bellard
    }
774 dbda808a bellard
    DPRINTF("%s: => %08x\n", __func__, retval);
775 dbda808a bellard
776 dbda808a bellard
    return retval;
777 dbda808a bellard
}
778 dbda808a bellard
779 dbda808a bellard
static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
780 dbda808a bellard
{
781 c227f099 Anthony Liguori
    openpic_t *opp = opaque;
782 dbda808a bellard
    int idx;
783 dbda808a bellard
784 dbda808a bellard
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
785 dbda808a bellard
    if (addr & 0xF)
786 dbda808a bellard
        return;
787 dbda808a bellard
    addr = addr & 0xFFF0;
788 dbda808a bellard
    idx = addr >> 5;
789 dbda808a bellard
    if (addr & 0x10) {
790 dbda808a bellard
        /* EXDE / IFEDE / IEEDE */
791 dbda808a bellard
        write_IRQreg(opp, idx, IRQ_IDE, val);
792 dbda808a bellard
    } else {
793 dbda808a bellard
        /* EXVP / IFEVP / IEEVP */
794 dbda808a bellard
        write_IRQreg(opp, idx, IRQ_IPVP, val);
795 dbda808a bellard
    }
796 dbda808a bellard
}
797 dbda808a bellard
798 dbda808a bellard
static uint32_t openpic_src_read (void *opaque, uint32_t addr)
799 dbda808a bellard
{
800 c227f099 Anthony Liguori
    openpic_t *opp = opaque;
801 dbda808a bellard
    uint32_t retval;
802 dbda808a bellard
    int idx;
803 dbda808a bellard
804 dbda808a bellard
    DPRINTF("%s: addr %08x\n", __func__, addr);
805 dbda808a bellard
    retval = 0xFFFFFFFF;
806 dbda808a bellard
    if (addr & 0xF)
807 dbda808a bellard
        return retval;
808 dbda808a bellard
    addr = addr & 0xFFF0;
809 dbda808a bellard
    idx = addr >> 5;
810 dbda808a bellard
    if (addr & 0x10) {
811 dbda808a bellard
        /* EXDE / IFEDE / IEEDE */
812 dbda808a bellard
        retval = read_IRQreg(opp, idx, IRQ_IDE);
813 dbda808a bellard
    } else {
814 dbda808a bellard
        /* EXVP / IFEVP / IEEVP */
815 dbda808a bellard
        retval = read_IRQreg(opp, idx, IRQ_IPVP);
816 dbda808a bellard
    }
817 dbda808a bellard
    DPRINTF("%s: => %08x\n", __func__, retval);
818 dbda808a bellard
819 dbda808a bellard
    return retval;
820 dbda808a bellard
}
821 dbda808a bellard
822 704c7e5d Alexander Graf
static void openpic_cpu_write_internal(void *opaque, target_phys_addr_t addr,
823 704c7e5d Alexander Graf
                                       uint32_t val, int idx)
824 dbda808a bellard
{
825 c227f099 Anthony Liguori
    openpic_t *opp = opaque;
826 c227f099 Anthony Liguori
    IRQ_src_t *src;
827 c227f099 Anthony Liguori
    IRQ_dst_t *dst;
828 704c7e5d Alexander Graf
    int s_IRQ, n_IRQ;
829 dbda808a bellard
830 704c7e5d Alexander Graf
    DPRINTF("%s: cpu %d addr " TARGET_FMT_plx " <= %08x\n", __func__, idx,
831 704c7e5d Alexander Graf
            addr, val);
832 dbda808a bellard
    if (addr & 0xF)
833 dbda808a bellard
        return;
834 dbda808a bellard
    dst = &opp->dst[idx];
835 dbda808a bellard
    addr &= 0xFF0;
836 dbda808a bellard
    switch (addr) {
837 dbda808a bellard
#if MAX_IPI > 0
838 704c7e5d Alexander Graf
    case 0x40: /* IPIDR */
839 dbda808a bellard
    case 0x50:
840 dbda808a bellard
    case 0x60:
841 dbda808a bellard
    case 0x70:
842 dbda808a bellard
        idx = (addr - 0x40) >> 4;
843 b7169916 aurel32
        write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE, val);
844 b7169916 aurel32
        openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);
845 b7169916 aurel32
        openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);
846 dbda808a bellard
        break;
847 dbda808a bellard
#endif
848 dbda808a bellard
    case 0x80: /* PCTP */
849 060fbfe1 Aurelien Jarno
        dst->pctp = val & 0x0000000F;
850 060fbfe1 Aurelien Jarno
        break;
851 dbda808a bellard
    case 0x90: /* WHOAMI */
852 060fbfe1 Aurelien Jarno
        /* Read-only register */
853 060fbfe1 Aurelien Jarno
        break;
854 dbda808a bellard
    case 0xA0: /* PIAC */
855 060fbfe1 Aurelien Jarno
        /* Read-only register */
856 060fbfe1 Aurelien Jarno
        break;
857 dbda808a bellard
    case 0xB0: /* PEOI */
858 dbda808a bellard
        DPRINTF("PEOI\n");
859 060fbfe1 Aurelien Jarno
        s_IRQ = IRQ_get_next(opp, &dst->servicing);
860 060fbfe1 Aurelien Jarno
        IRQ_resetbit(&dst->servicing, s_IRQ);
861 060fbfe1 Aurelien Jarno
        dst->servicing.next = -1;
862 060fbfe1 Aurelien Jarno
        /* Set up next servicing IRQ */
863 060fbfe1 Aurelien Jarno
        s_IRQ = IRQ_get_next(opp, &dst->servicing);
864 e9df014c j_mayer
        /* Check queued interrupts. */
865 e9df014c j_mayer
        n_IRQ = IRQ_get_next(opp, &dst->raised);
866 e9df014c j_mayer
        src = &opp->src[n_IRQ];
867 e9df014c j_mayer
        if (n_IRQ != -1 &&
868 e9df014c j_mayer
            (s_IRQ == -1 ||
869 e9df014c j_mayer
             IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) {
870 e9df014c j_mayer
            DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
871 e9df014c j_mayer
                    idx, n_IRQ);
872 b7169916 aurel32
            opp->irq_raise(opp, idx, src);
873 e9df014c j_mayer
        }
874 060fbfe1 Aurelien Jarno
        break;
875 dbda808a bellard
    default:
876 dbda808a bellard
        break;
877 dbda808a bellard
    }
878 dbda808a bellard
}
879 dbda808a bellard
880 704c7e5d Alexander Graf
static void openpic_cpu_write(void *opaque, target_phys_addr_t addr, uint32_t val)
881 704c7e5d Alexander Graf
{
882 704c7e5d Alexander Graf
    openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12);
883 704c7e5d Alexander Graf
}
884 704c7e5d Alexander Graf
885 704c7e5d Alexander Graf
static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr,
886 704c7e5d Alexander Graf
                                          int idx)
887 dbda808a bellard
{
888 c227f099 Anthony Liguori
    openpic_t *opp = opaque;
889 c227f099 Anthony Liguori
    IRQ_src_t *src;
890 c227f099 Anthony Liguori
    IRQ_dst_t *dst;
891 dbda808a bellard
    uint32_t retval;
892 704c7e5d Alexander Graf
    int n_IRQ;
893 3b46e624 ths
894 704c7e5d Alexander Graf
    DPRINTF("%s: cpu %d addr " TARGET_FMT_plx "\n", __func__, idx, addr);
895 dbda808a bellard
    retval = 0xFFFFFFFF;
896 dbda808a bellard
    if (addr & 0xF)
897 dbda808a bellard
        return retval;
898 dbda808a bellard
    dst = &opp->dst[idx];
899 dbda808a bellard
    addr &= 0xFF0;
900 dbda808a bellard
    switch (addr) {
901 dbda808a bellard
    case 0x80: /* PCTP */
902 060fbfe1 Aurelien Jarno
        retval = dst->pctp;
903 060fbfe1 Aurelien Jarno
        break;
904 dbda808a bellard
    case 0x90: /* WHOAMI */
905 060fbfe1 Aurelien Jarno
        retval = idx;
906 060fbfe1 Aurelien Jarno
        break;
907 dbda808a bellard
    case 0xA0: /* PIAC */
908 e9df014c j_mayer
        DPRINTF("Lower OpenPIC INT output\n");
909 e9df014c j_mayer
        qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
910 060fbfe1 Aurelien Jarno
        n_IRQ = IRQ_get_next(opp, &dst->raised);
911 dbda808a bellard
        DPRINTF("PIAC: irq=%d\n", n_IRQ);
912 060fbfe1 Aurelien Jarno
        if (n_IRQ == -1) {
913 060fbfe1 Aurelien Jarno
            /* No more interrupt pending */
914 e9df014c j_mayer
            retval = IPVP_VECTOR(opp->spve);
915 060fbfe1 Aurelien Jarno
        } else {
916 060fbfe1 Aurelien Jarno
            src = &opp->src[n_IRQ];
917 060fbfe1 Aurelien Jarno
            if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
918 060fbfe1 Aurelien Jarno
                !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) {
919 060fbfe1 Aurelien Jarno
                /* - Spurious level-sensitive IRQ
920 060fbfe1 Aurelien Jarno
                 * - Priorities has been changed
921 060fbfe1 Aurelien Jarno
                 *   and the pending IRQ isn't allowed anymore
922 060fbfe1 Aurelien Jarno
                 */
923 060fbfe1 Aurelien Jarno
                reset_bit(&src->ipvp, IPVP_ACTIVITY);
924 060fbfe1 Aurelien Jarno
                retval = IPVP_VECTOR(opp->spve);
925 060fbfe1 Aurelien Jarno
            } else {
926 060fbfe1 Aurelien Jarno
                /* IRQ enter servicing state */
927 060fbfe1 Aurelien Jarno
                IRQ_setbit(&dst->servicing, n_IRQ);
928 060fbfe1 Aurelien Jarno
                retval = IPVP_VECTOR(src->ipvp);
929 060fbfe1 Aurelien Jarno
            }
930 060fbfe1 Aurelien Jarno
            IRQ_resetbit(&dst->raised, n_IRQ);
931 060fbfe1 Aurelien Jarno
            dst->raised.next = -1;
932 060fbfe1 Aurelien Jarno
            if (!test_bit(&src->ipvp, IPVP_SENSE)) {
933 611493d9 bellard
                /* edge-sensitive IRQ */
934 060fbfe1 Aurelien Jarno
                reset_bit(&src->ipvp, IPVP_ACTIVITY);
935 611493d9 bellard
                src->pending = 0;
936 611493d9 bellard
            }
937 060fbfe1 Aurelien Jarno
        }
938 060fbfe1 Aurelien Jarno
        break;
939 dbda808a bellard
    case 0xB0: /* PEOI */
940 060fbfe1 Aurelien Jarno
        retval = 0;
941 060fbfe1 Aurelien Jarno
        break;
942 dbda808a bellard
#if MAX_IPI > 0
943 dbda808a bellard
    case 0x40: /* IDE */
944 dbda808a bellard
    case 0x50:
945 dbda808a bellard
        idx = (addr - 0x40) >> 4;
946 b7169916 aurel32
        retval = read_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE);
947 dbda808a bellard
        break;
948 dbda808a bellard
#endif
949 dbda808a bellard
    default:
950 dbda808a bellard
        break;
951 dbda808a bellard
    }
952 dbda808a bellard
    DPRINTF("%s: => %08x\n", __func__, retval);
953 dbda808a bellard
954 dbda808a bellard
    return retval;
955 dbda808a bellard
}
956 dbda808a bellard
957 704c7e5d Alexander Graf
static uint32_t openpic_cpu_read(void *opaque, target_phys_addr_t addr)
958 704c7e5d Alexander Graf
{
959 704c7e5d Alexander Graf
    return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12);
960 704c7e5d Alexander Graf
}
961 704c7e5d Alexander Graf
962 dbda808a bellard
static void openpic_buggy_write (void *opaque,
963 c227f099 Anthony Liguori
                                 target_phys_addr_t addr, uint32_t val)
964 dbda808a bellard
{
965 dbda808a bellard
    printf("Invalid OPENPIC write access !\n");
966 dbda808a bellard
}
967 dbda808a bellard
968 c227f099 Anthony Liguori
static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr)
969 dbda808a bellard
{
970 dbda808a bellard
    printf("Invalid OPENPIC read access !\n");
971 dbda808a bellard
972 dbda808a bellard
    return -1;
973 dbda808a bellard
}
974 dbda808a bellard
975 dbda808a bellard
static void openpic_writel (void *opaque,
976 c227f099 Anthony Liguori
                            target_phys_addr_t addr, uint32_t val)
977 dbda808a bellard
{
978 c227f099 Anthony Liguori
    openpic_t *opp = opaque;
979 dbda808a bellard
980 dbda808a bellard
    addr &= 0x3FFFF;
981 611493d9 bellard
    DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val);
982 dbda808a bellard
    if (addr < 0x1100) {
983 dbda808a bellard
        /* Global registers */
984 dbda808a bellard
        openpic_gbl_write(opp, addr, val);
985 dbda808a bellard
    } else if (addr < 0x10000) {
986 dbda808a bellard
        /* Timers registers */
987 dbda808a bellard
        openpic_timer_write(opp, addr, val);
988 dbda808a bellard
    } else if (addr < 0x20000) {
989 dbda808a bellard
        /* Source registers */
990 dbda808a bellard
        openpic_src_write(opp, addr, val);
991 dbda808a bellard
    } else {
992 dbda808a bellard
        /* CPU registers */
993 dbda808a bellard
        openpic_cpu_write(opp, addr, val);
994 dbda808a bellard
    }
995 dbda808a bellard
}
996 dbda808a bellard
997 c227f099 Anthony Liguori
static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr)
998 dbda808a bellard
{
999 c227f099 Anthony Liguori
    openpic_t *opp = opaque;
1000 dbda808a bellard
    uint32_t retval;
1001 dbda808a bellard
1002 dbda808a bellard
    addr &= 0x3FFFF;
1003 611493d9 bellard
    DPRINTF("%s: offset %08x\n", __func__, (int)addr);
1004 dbda808a bellard
    if (addr < 0x1100) {
1005 dbda808a bellard
        /* Global registers */
1006 dbda808a bellard
        retval = openpic_gbl_read(opp, addr);
1007 dbda808a bellard
    } else if (addr < 0x10000) {
1008 dbda808a bellard
        /* Timers registers */
1009 dbda808a bellard
        retval = openpic_timer_read(opp, addr);
1010 dbda808a bellard
    } else if (addr < 0x20000) {
1011 dbda808a bellard
        /* Source registers */
1012 dbda808a bellard
        retval = openpic_src_read(opp, addr);
1013 dbda808a bellard
    } else {
1014 dbda808a bellard
        /* CPU registers */
1015 dbda808a bellard
        retval = openpic_cpu_read(opp, addr);
1016 dbda808a bellard
    }
1017 dbda808a bellard
1018 dbda808a bellard
    return retval;
1019 dbda808a bellard
}
1020 dbda808a bellard
1021 23c5e4ca Avi Kivity
static uint64_t openpic_read(void *opaque, target_phys_addr_t addr,
1022 23c5e4ca Avi Kivity
                             unsigned size)
1023 23c5e4ca Avi Kivity
{
1024 23c5e4ca Avi Kivity
    openpic_t *opp = opaque;
1025 dbda808a bellard
1026 23c5e4ca Avi Kivity
    switch (size) {
1027 23c5e4ca Avi Kivity
    case 4: return openpic_readl(opp, addr);
1028 23c5e4ca Avi Kivity
    default: return openpic_buggy_read(opp, addr);
1029 23c5e4ca Avi Kivity
    }
1030 23c5e4ca Avi Kivity
}
1031 dbda808a bellard
1032 23c5e4ca Avi Kivity
static void openpic_write(void *opaque, target_phys_addr_t addr,
1033 23c5e4ca Avi Kivity
                          uint64_t data, unsigned size)
1034 dbda808a bellard
{
1035 23c5e4ca Avi Kivity
    openpic_t *opp = opaque;
1036 dbda808a bellard
1037 23c5e4ca Avi Kivity
    switch (size) {
1038 23c5e4ca Avi Kivity
    case 4: return openpic_writel(opp, addr, data);
1039 23c5e4ca Avi Kivity
    default: return openpic_buggy_write(opp, addr, data);
1040 23c5e4ca Avi Kivity
    }
1041 dbda808a bellard
}
1042 dbda808a bellard
1043 23c5e4ca Avi Kivity
static const MemoryRegionOps openpic_ops = {
1044 23c5e4ca Avi Kivity
    .read = openpic_read,
1045 23c5e4ca Avi Kivity
    .write = openpic_write,
1046 23c5e4ca Avi Kivity
    .endianness = DEVICE_LITTLE_ENDIAN,
1047 23c5e4ca Avi Kivity
};
1048 23c5e4ca Avi Kivity
1049 c227f099 Anthony Liguori
static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
1050 67b55785 blueswir1
{
1051 67b55785 blueswir1
    unsigned int i;
1052 67b55785 blueswir1
1053 67b55785 blueswir1
    for (i = 0; i < BF_WIDTH(MAX_IRQ); i++)
1054 67b55785 blueswir1
        qemu_put_be32s(f, &q->queue[i]);
1055 67b55785 blueswir1
1056 67b55785 blueswir1
    qemu_put_sbe32s(f, &q->next);
1057 67b55785 blueswir1
    qemu_put_sbe32s(f, &q->priority);
1058 67b55785 blueswir1
}
1059 67b55785 blueswir1
1060 67b55785 blueswir1
static void openpic_save(QEMUFile* f, void *opaque)
1061 67b55785 blueswir1
{
1062 c227f099 Anthony Liguori
    openpic_t *opp = (openpic_t *)opaque;
1063 67b55785 blueswir1
    unsigned int i;
1064 67b55785 blueswir1
1065 67b55785 blueswir1
    qemu_put_be32s(f, &opp->frep);
1066 67b55785 blueswir1
    qemu_put_be32s(f, &opp->glbc);
1067 67b55785 blueswir1
    qemu_put_be32s(f, &opp->micr);
1068 67b55785 blueswir1
    qemu_put_be32s(f, &opp->veni);
1069 67b55785 blueswir1
    qemu_put_be32s(f, &opp->pint);
1070 67b55785 blueswir1
    qemu_put_be32s(f, &opp->spve);
1071 67b55785 blueswir1
    qemu_put_be32s(f, &opp->tifr);
1072 67b55785 blueswir1
1073 b7169916 aurel32
    for (i = 0; i < opp->max_irq; i++) {
1074 67b55785 blueswir1
        qemu_put_be32s(f, &opp->src[i].ipvp);
1075 67b55785 blueswir1
        qemu_put_be32s(f, &opp->src[i].ide);
1076 67b55785 blueswir1
        qemu_put_sbe32s(f, &opp->src[i].type);
1077 67b55785 blueswir1
        qemu_put_sbe32s(f, &opp->src[i].last_cpu);
1078 67b55785 blueswir1
        qemu_put_sbe32s(f, &opp->src[i].pending);
1079 67b55785 blueswir1
    }
1080 67b55785 blueswir1
1081 b7169916 aurel32
    qemu_put_sbe32s(f, &opp->nb_cpus);
1082 b7169916 aurel32
1083 b7169916 aurel32
    for (i = 0; i < opp->nb_cpus; i++) {
1084 b7169916 aurel32
        qemu_put_be32s(f, &opp->dst[i].tfrr);
1085 67b55785 blueswir1
        qemu_put_be32s(f, &opp->dst[i].pctp);
1086 67b55785 blueswir1
        qemu_put_be32s(f, &opp->dst[i].pcsr);
1087 67b55785 blueswir1
        openpic_save_IRQ_queue(f, &opp->dst[i].raised);
1088 67b55785 blueswir1
        openpic_save_IRQ_queue(f, &opp->dst[i].servicing);
1089 67b55785 blueswir1
    }
1090 67b55785 blueswir1
1091 67b55785 blueswir1
    for (i = 0; i < MAX_TMR; i++) {
1092 67b55785 blueswir1
        qemu_put_be32s(f, &opp->timers[i].ticc);
1093 67b55785 blueswir1
        qemu_put_be32s(f, &opp->timers[i].tibc);
1094 67b55785 blueswir1
    }
1095 67b55785 blueswir1
1096 67b55785 blueswir1
#if MAX_DBL > 0
1097 67b55785 blueswir1
    qemu_put_be32s(f, &opp->dar);
1098 67b55785 blueswir1
1099 67b55785 blueswir1
    for (i = 0; i < MAX_DBL; i++) {
1100 67b55785 blueswir1
        qemu_put_be32s(f, &opp->doorbells[i].dmr);
1101 67b55785 blueswir1
    }
1102 67b55785 blueswir1
#endif
1103 67b55785 blueswir1
1104 67b55785 blueswir1
#if MAX_MBX > 0
1105 67b55785 blueswir1
    for (i = 0; i < MAX_MAILBOXES; i++) {
1106 67b55785 blueswir1
        qemu_put_be32s(f, &opp->mailboxes[i].mbr);
1107 67b55785 blueswir1
    }
1108 67b55785 blueswir1
#endif
1109 67b55785 blueswir1
1110 67b55785 blueswir1
    pci_device_save(&opp->pci_dev, f);
1111 67b55785 blueswir1
}
1112 67b55785 blueswir1
1113 c227f099 Anthony Liguori
static void openpic_load_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
1114 67b55785 blueswir1
{
1115 67b55785 blueswir1
    unsigned int i;
1116 67b55785 blueswir1
1117 67b55785 blueswir1
    for (i = 0; i < BF_WIDTH(MAX_IRQ); i++)
1118 67b55785 blueswir1
        qemu_get_be32s(f, &q->queue[i]);
1119 67b55785 blueswir1
1120 67b55785 blueswir1
    qemu_get_sbe32s(f, &q->next);
1121 67b55785 blueswir1
    qemu_get_sbe32s(f, &q->priority);
1122 67b55785 blueswir1
}
1123 67b55785 blueswir1
1124 67b55785 blueswir1
static int openpic_load(QEMUFile* f, void *opaque, int version_id)
1125 67b55785 blueswir1
{
1126 c227f099 Anthony Liguori
    openpic_t *opp = (openpic_t *)opaque;
1127 67b55785 blueswir1
    unsigned int i;
1128 67b55785 blueswir1
1129 67b55785 blueswir1
    if (version_id != 1)
1130 67b55785 blueswir1
        return -EINVAL;
1131 67b55785 blueswir1
1132 67b55785 blueswir1
    qemu_get_be32s(f, &opp->frep);
1133 67b55785 blueswir1
    qemu_get_be32s(f, &opp->glbc);
1134 67b55785 blueswir1
    qemu_get_be32s(f, &opp->micr);
1135 67b55785 blueswir1
    qemu_get_be32s(f, &opp->veni);
1136 67b55785 blueswir1
    qemu_get_be32s(f, &opp->pint);
1137 67b55785 blueswir1
    qemu_get_be32s(f, &opp->spve);
1138 67b55785 blueswir1
    qemu_get_be32s(f, &opp->tifr);
1139 67b55785 blueswir1
1140 b7169916 aurel32
    for (i = 0; i < opp->max_irq; i++) {
1141 67b55785 blueswir1
        qemu_get_be32s(f, &opp->src[i].ipvp);
1142 67b55785 blueswir1
        qemu_get_be32s(f, &opp->src[i].ide);
1143 67b55785 blueswir1
        qemu_get_sbe32s(f, &opp->src[i].type);
1144 67b55785 blueswir1
        qemu_get_sbe32s(f, &opp->src[i].last_cpu);
1145 67b55785 blueswir1
        qemu_get_sbe32s(f, &opp->src[i].pending);
1146 67b55785 blueswir1
    }
1147 67b55785 blueswir1
1148 b7169916 aurel32
    qemu_get_sbe32s(f, &opp->nb_cpus);
1149 b7169916 aurel32
1150 b7169916 aurel32
    for (i = 0; i < opp->nb_cpus; i++) {
1151 b7169916 aurel32
        qemu_get_be32s(f, &opp->dst[i].tfrr);
1152 67b55785 blueswir1
        qemu_get_be32s(f, &opp->dst[i].pctp);
1153 67b55785 blueswir1
        qemu_get_be32s(f, &opp->dst[i].pcsr);
1154 67b55785 blueswir1
        openpic_load_IRQ_queue(f, &opp->dst[i].raised);
1155 67b55785 blueswir1
        openpic_load_IRQ_queue(f, &opp->dst[i].servicing);
1156 67b55785 blueswir1
    }
1157 67b55785 blueswir1
1158 67b55785 blueswir1
    for (i = 0; i < MAX_TMR; i++) {
1159 67b55785 blueswir1
        qemu_get_be32s(f, &opp->timers[i].ticc);
1160 67b55785 blueswir1
        qemu_get_be32s(f, &opp->timers[i].tibc);
1161 67b55785 blueswir1
    }
1162 67b55785 blueswir1
1163 67b55785 blueswir1
#if MAX_DBL > 0
1164 67b55785 blueswir1
    qemu_get_be32s(f, &opp->dar);
1165 67b55785 blueswir1
1166 67b55785 blueswir1
    for (i = 0; i < MAX_DBL; i++) {
1167 67b55785 blueswir1
        qemu_get_be32s(f, &opp->doorbells[i].dmr);
1168 67b55785 blueswir1
    }
1169 67b55785 blueswir1
#endif
1170 67b55785 blueswir1
1171 67b55785 blueswir1
#if MAX_MBX > 0
1172 67b55785 blueswir1
    for (i = 0; i < MAX_MAILBOXES; i++) {
1173 67b55785 blueswir1
        qemu_get_be32s(f, &opp->mailboxes[i].mbr);
1174 67b55785 blueswir1
    }
1175 67b55785 blueswir1
#endif
1176 67b55785 blueswir1
1177 67b55785 blueswir1
    return pci_device_load(&opp->pci_dev, f);
1178 67b55785 blueswir1
}
1179 67b55785 blueswir1
1180 c227f099 Anthony Liguori
static void openpic_irq_raise(openpic_t *opp, int n_CPU, IRQ_src_t *src)
1181 b7169916 aurel32
{
1182 b7169916 aurel32
    qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
1183 b7169916 aurel32
}
1184 b7169916 aurel32
1185 23c5e4ca Avi Kivity
qemu_irq *openpic_init (PCIBus *bus, MemoryRegion **pmem, int nb_cpus,
1186 e9df014c j_mayer
                        qemu_irq **irqs, qemu_irq irq_out)
1187 dbda808a bellard
{
1188 c227f099 Anthony Liguori
    openpic_t *opp;
1189 dbda808a bellard
    uint8_t *pci_conf;
1190 dbda808a bellard
    int i, m;
1191 3b46e624 ths
1192 dbda808a bellard
    /* XXX: for now, only one CPU is supported */
1193 dbda808a bellard
    if (nb_cpus != 1)
1194 dbda808a bellard
        return NULL;
1195 91d848eb bellard
    if (bus) {
1196 c227f099 Anthony Liguori
        opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t),
1197 91d848eb bellard
                                               -1, NULL, NULL);
1198 91d848eb bellard
        pci_conf = opp->pci_dev.config;
1199 deb54399 aliguori
        pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM);
1200 4ebcf884 blueswir1
        pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_OPENPIC2);
1201 173a543b blueswir1
        pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER); // FIXME?
1202 91d848eb bellard
        pci_conf[0x3d] = 0x00; // no interrupt pin
1203 3b46e624 ths
1204 23c5e4ca Avi Kivity
        memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
1205 23c5e4ca Avi Kivity
#if 0 // Don't implement ISU for now
1206 23c5e4ca Avi Kivity
        opp_io_memory = cpu_register_io_memory(openpic_src_read,
1207 23c5e4ca Avi Kivity
                                               openpic_src_write, NULL
1208 23c5e4ca Avi Kivity
                                               DEVICE_NATIVE_ENDIAN);
1209 23c5e4ca Avi Kivity
        cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
1210 23c5e4ca Avi Kivity
                                     opp_io_memory);
1211 23c5e4ca Avi Kivity
#endif
1212 23c5e4ca Avi Kivity
1213 91d848eb bellard
        /* Register I/O spaces */
1214 e824b2cc Avi Kivity
        pci_register_bar(&opp->pci_dev, 0,
1215 e824b2cc Avi Kivity
                         PCI_BASE_ADDRESS_SPACE_MEMORY, &opp->mem);
1216 91d848eb bellard
    } else {
1217 7267c094 Anthony Liguori
        opp = g_malloc0(sizeof(openpic_t));
1218 23c5e4ca Avi Kivity
        memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
1219 91d848eb bellard
    }
1220 3b46e624 ths
1221 91d848eb bellard
    //    isu_base &= 0xFFFC0000;
1222 dbda808a bellard
    opp->nb_cpus = nb_cpus;
1223 b7169916 aurel32
    opp->max_irq = OPENPIC_MAX_IRQ;
1224 b7169916 aurel32
    opp->irq_ipi0 = OPENPIC_IRQ_IPI0;
1225 b7169916 aurel32
    opp->irq_tim0 = OPENPIC_IRQ_TIM0;
1226 dbda808a bellard
    /* Set IRQ types */
1227 b7169916 aurel32
    for (i = 0; i < OPENPIC_EXT_IRQ; i++) {
1228 dbda808a bellard
        opp->src[i].type = IRQ_EXTERNAL;
1229 dbda808a bellard
    }
1230 b7169916 aurel32
    for (; i < OPENPIC_IRQ_TIM0; i++) {
1231 dbda808a bellard
        opp->src[i].type = IRQ_SPECIAL;
1232 dbda808a bellard
    }
1233 dbda808a bellard
#if MAX_IPI > 0
1234 b7169916 aurel32
    m = OPENPIC_IRQ_IPI0;
1235 dbda808a bellard
#else
1236 b7169916 aurel32
    m = OPENPIC_IRQ_DBL0;
1237 dbda808a bellard
#endif
1238 dbda808a bellard
    for (; i < m; i++) {
1239 dbda808a bellard
        opp->src[i].type = IRQ_TIMER;
1240 dbda808a bellard
    }
1241 b7169916 aurel32
    for (; i < OPENPIC_MAX_IRQ; i++) {
1242 dbda808a bellard
        opp->src[i].type = IRQ_INTERNAL;
1243 dbda808a bellard
    }
1244 7668a27f bellard
    for (i = 0; i < nb_cpus; i++)
1245 e9df014c j_mayer
        opp->dst[i].irqs = irqs[i];
1246 e9df014c j_mayer
    opp->irq_out = irq_out;
1247 67b55785 blueswir1
1248 0be71e32 Alex Williamson
    register_savevm(&opp->pci_dev.qdev, "openpic", 0, 2,
1249 0be71e32 Alex Williamson
                    openpic_save, openpic_load, opp);
1250 a08d4367 Jan Kiszka
    qemu_register_reset(openpic_reset, opp);
1251 b7169916 aurel32
1252 b7169916 aurel32
    opp->irq_raise = openpic_irq_raise;
1253 b7169916 aurel32
    opp->reset = openpic_reset;
1254 b7169916 aurel32
1255 23c5e4ca Avi Kivity
    if (pmem)
1256 23c5e4ca Avi Kivity
        *pmem = &opp->mem;
1257 e9df014c j_mayer
1258 b7169916 aurel32
    return qemu_allocate_irqs(openpic_set_irq, opp, opp->max_irq);
1259 b7169916 aurel32
}
1260 b7169916 aurel32
1261 c227f099 Anthony Liguori
static void mpic_irq_raise(openpic_t *mpp, int n_CPU, IRQ_src_t *src)
1262 b7169916 aurel32
{
1263 b7169916 aurel32
    int n_ci = IDR_CI0 - n_CPU;
1264 0bf9e31a Blue Swirl
1265 b7169916 aurel32
    if(test_bit(&src->ide, n_ci)) {
1266 b7169916 aurel32
        qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_CINT]);
1267 b7169916 aurel32
    }
1268 b7169916 aurel32
    else {
1269 b7169916 aurel32
        qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
1270 b7169916 aurel32
    }
1271 b7169916 aurel32
}
1272 b7169916 aurel32
1273 b7169916 aurel32
static void mpic_reset (void *opaque)
1274 b7169916 aurel32
{
1275 c227f099 Anthony Liguori
    openpic_t *mpp = (openpic_t *)opaque;
1276 b7169916 aurel32
    int i;
1277 b7169916 aurel32
1278 b7169916 aurel32
    mpp->glbc = 0x80000000;
1279 b7169916 aurel32
    /* Initialise controller registers */
1280 b7169916 aurel32
    mpp->frep = 0x004f0002;
1281 b7169916 aurel32
    mpp->veni = VENI;
1282 b7169916 aurel32
    mpp->pint = 0x00000000;
1283 b7169916 aurel32
    mpp->spve = 0x0000FFFF;
1284 b7169916 aurel32
    /* Initialise IRQ sources */
1285 b7169916 aurel32
    for (i = 0; i < mpp->max_irq; i++) {
1286 b7169916 aurel32
        mpp->src[i].ipvp = 0x80800000;
1287 b7169916 aurel32
        mpp->src[i].ide  = 0x00000001;
1288 b7169916 aurel32
    }
1289 b7169916 aurel32
    /* Initialise IRQ destinations */
1290 b7169916 aurel32
    for (i = 0; i < MAX_CPU; i++) {
1291 b7169916 aurel32
        mpp->dst[i].pctp      = 0x0000000F;
1292 b7169916 aurel32
        mpp->dst[i].tfrr      = 0x00000000;
1293 c227f099 Anthony Liguori
        memset(&mpp->dst[i].raised, 0, sizeof(IRQ_queue_t));
1294 b7169916 aurel32
        mpp->dst[i].raised.next = -1;
1295 c227f099 Anthony Liguori
        memset(&mpp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
1296 b7169916 aurel32
        mpp->dst[i].servicing.next = -1;
1297 b7169916 aurel32
    }
1298 b7169916 aurel32
    /* Initialise timers */
1299 b7169916 aurel32
    for (i = 0; i < MAX_TMR; i++) {
1300 b7169916 aurel32
        mpp->timers[i].ticc = 0x00000000;
1301 b7169916 aurel32
        mpp->timers[i].tibc = 0x80000000;
1302 b7169916 aurel32
    }
1303 b7169916 aurel32
    /* Go out of RESET state */
1304 b7169916 aurel32
    mpp->glbc = 0x00000000;
1305 b7169916 aurel32
}
1306 b7169916 aurel32
1307 c227f099 Anthony Liguori
static void mpic_timer_write (void *opaque, target_phys_addr_t addr, uint32_t val)
1308 b7169916 aurel32
{
1309 c227f099 Anthony Liguori
    openpic_t *mpp = opaque;
1310 b7169916 aurel32
    int idx, cpu;
1311 b7169916 aurel32
1312 0bf9e31a Blue Swirl
    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1313 b7169916 aurel32
    if (addr & 0xF)
1314 b7169916 aurel32
        return;
1315 b7169916 aurel32
    addr &= 0xFFFF;
1316 b7169916 aurel32
    cpu = addr >> 12;
1317 b7169916 aurel32
    idx = (addr >> 6) & 0x3;
1318 b7169916 aurel32
    switch (addr & 0x30) {
1319 b7169916 aurel32
    case 0x00: /* gtccr */
1320 b7169916 aurel32
        break;
1321 b7169916 aurel32
    case 0x10: /* gtbcr */
1322 b7169916 aurel32
        if ((mpp->timers[idx].ticc & 0x80000000) != 0 &&
1323 b7169916 aurel32
            (val & 0x80000000) == 0 &&
1324 b7169916 aurel32
            (mpp->timers[idx].tibc & 0x80000000) != 0)
1325 b7169916 aurel32
            mpp->timers[idx].ticc &= ~0x80000000;
1326 b7169916 aurel32
        mpp->timers[idx].tibc = val;
1327 b7169916 aurel32
        break;
1328 b7169916 aurel32
    case 0x20: /* GTIVPR */
1329 b7169916 aurel32
        write_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IPVP, val);
1330 b7169916 aurel32
        break;
1331 b7169916 aurel32
    case 0x30: /* GTIDR & TFRR */
1332 b7169916 aurel32
        if ((addr & 0xF0) == 0xF0)
1333 b7169916 aurel32
            mpp->dst[cpu].tfrr = val;
1334 b7169916 aurel32
        else
1335 b7169916 aurel32
            write_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IDE, val);
1336 b7169916 aurel32
        break;
1337 b7169916 aurel32
    }
1338 b7169916 aurel32
}
1339 b7169916 aurel32
1340 c227f099 Anthony Liguori
static uint32_t mpic_timer_read (void *opaque, target_phys_addr_t addr)
1341 b7169916 aurel32
{
1342 c227f099 Anthony Liguori
    openpic_t *mpp = opaque;
1343 b7169916 aurel32
    uint32_t retval;
1344 b7169916 aurel32
    int idx, cpu;
1345 b7169916 aurel32
1346 0bf9e31a Blue Swirl
    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1347 b7169916 aurel32
    retval = 0xFFFFFFFF;
1348 b7169916 aurel32
    if (addr & 0xF)
1349 b7169916 aurel32
        return retval;
1350 b7169916 aurel32
    addr &= 0xFFFF;
1351 b7169916 aurel32
    cpu = addr >> 12;
1352 b7169916 aurel32
    idx = (addr >> 6) & 0x3;
1353 b7169916 aurel32
    switch (addr & 0x30) {
1354 b7169916 aurel32
    case 0x00: /* gtccr */
1355 b7169916 aurel32
        retval = mpp->timers[idx].ticc;
1356 b7169916 aurel32
        break;
1357 b7169916 aurel32
    case 0x10: /* gtbcr */
1358 b7169916 aurel32
        retval = mpp->timers[idx].tibc;
1359 b7169916 aurel32
        break;
1360 b7169916 aurel32
    case 0x20: /* TIPV */
1361 b7169916 aurel32
        retval = read_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IPVP);
1362 b7169916 aurel32
        break;
1363 b7169916 aurel32
    case 0x30: /* TIDR */
1364 b7169916 aurel32
        if ((addr &0xF0) == 0XF0)
1365 b7169916 aurel32
            retval = mpp->dst[cpu].tfrr;
1366 b7169916 aurel32
        else
1367 b7169916 aurel32
            retval = read_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IDE);
1368 b7169916 aurel32
        break;
1369 b7169916 aurel32
    }
1370 b7169916 aurel32
    DPRINTF("%s: => %08x\n", __func__, retval);
1371 b7169916 aurel32
1372 b7169916 aurel32
    return retval;
1373 b7169916 aurel32
}
1374 b7169916 aurel32
1375 c227f099 Anthony Liguori
static void mpic_src_ext_write (void *opaque, target_phys_addr_t addr,
1376 b7169916 aurel32
                                uint32_t val)
1377 b7169916 aurel32
{
1378 c227f099 Anthony Liguori
    openpic_t *mpp = opaque;
1379 b7169916 aurel32
    int idx = MPIC_EXT_IRQ;
1380 b7169916 aurel32
1381 0bf9e31a Blue Swirl
    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1382 b7169916 aurel32
    if (addr & 0xF)
1383 b7169916 aurel32
        return;
1384 b7169916 aurel32
1385 5c4532ee Blue Swirl
    addr -= MPIC_EXT_REG_START & (OPENPIC_PAGE_SIZE - 1);
1386 b7169916 aurel32
    if (addr < MPIC_EXT_REG_SIZE) {
1387 b7169916 aurel32
        idx += (addr & 0xFFF0) >> 5;
1388 b7169916 aurel32
        if (addr & 0x10) {
1389 b7169916 aurel32
            /* EXDE / IFEDE / IEEDE */
1390 b7169916 aurel32
            write_IRQreg(mpp, idx, IRQ_IDE, val);
1391 b7169916 aurel32
        } else {
1392 b7169916 aurel32
            /* EXVP / IFEVP / IEEVP */
1393 b7169916 aurel32
            write_IRQreg(mpp, idx, IRQ_IPVP, val);
1394 b7169916 aurel32
        }
1395 b7169916 aurel32
    }
1396 b7169916 aurel32
}
1397 b7169916 aurel32
1398 c227f099 Anthony Liguori
static uint32_t mpic_src_ext_read (void *opaque, target_phys_addr_t addr)
1399 b7169916 aurel32
{
1400 c227f099 Anthony Liguori
    openpic_t *mpp = opaque;
1401 b7169916 aurel32
    uint32_t retval;
1402 b7169916 aurel32
    int idx = MPIC_EXT_IRQ;
1403 b7169916 aurel32
1404 0bf9e31a Blue Swirl
    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1405 b7169916 aurel32
    retval = 0xFFFFFFFF;
1406 b7169916 aurel32
    if (addr & 0xF)
1407 b7169916 aurel32
        return retval;
1408 b7169916 aurel32
1409 5c4532ee Blue Swirl
    addr -= MPIC_EXT_REG_START & (OPENPIC_PAGE_SIZE - 1);
1410 b7169916 aurel32
    if (addr < MPIC_EXT_REG_SIZE) {
1411 b7169916 aurel32
        idx += (addr & 0xFFF0) >> 5;
1412 b7169916 aurel32
        if (addr & 0x10) {
1413 b7169916 aurel32
            /* EXDE / IFEDE / IEEDE */
1414 b7169916 aurel32
            retval = read_IRQreg(mpp, idx, IRQ_IDE);
1415 b7169916 aurel32
        } else {
1416 b7169916 aurel32
            /* EXVP / IFEVP / IEEVP */
1417 b7169916 aurel32
            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
1418 b7169916 aurel32
        }
1419 b7169916 aurel32
        DPRINTF("%s: => %08x\n", __func__, retval);
1420 b7169916 aurel32
    }
1421 b7169916 aurel32
1422 b7169916 aurel32
    return retval;
1423 b7169916 aurel32
}
1424 b7169916 aurel32
1425 c227f099 Anthony Liguori
static void mpic_src_int_write (void *opaque, target_phys_addr_t addr,
1426 b7169916 aurel32
                                uint32_t val)
1427 b7169916 aurel32
{
1428 c227f099 Anthony Liguori
    openpic_t *mpp = opaque;
1429 b7169916 aurel32
    int idx = MPIC_INT_IRQ;
1430 b7169916 aurel32
1431 0bf9e31a Blue Swirl
    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1432 b7169916 aurel32
    if (addr & 0xF)
1433 b7169916 aurel32
        return;
1434 b7169916 aurel32
1435 5c4532ee Blue Swirl
    addr -= MPIC_INT_REG_START & (OPENPIC_PAGE_SIZE - 1);
1436 b7169916 aurel32
    if (addr < MPIC_INT_REG_SIZE) {
1437 b7169916 aurel32
        idx += (addr & 0xFFF0) >> 5;
1438 b7169916 aurel32
        if (addr & 0x10) {
1439 b7169916 aurel32
            /* EXDE / IFEDE / IEEDE */
1440 b7169916 aurel32
            write_IRQreg(mpp, idx, IRQ_IDE, val);
1441 b7169916 aurel32
        } else {
1442 b7169916 aurel32
            /* EXVP / IFEVP / IEEVP */
1443 b7169916 aurel32
            write_IRQreg(mpp, idx, IRQ_IPVP, val);
1444 b7169916 aurel32
        }
1445 b7169916 aurel32
    }
1446 b7169916 aurel32
}
1447 b7169916 aurel32
1448 c227f099 Anthony Liguori
static uint32_t mpic_src_int_read (void *opaque, target_phys_addr_t addr)
1449 b7169916 aurel32
{
1450 c227f099 Anthony Liguori
    openpic_t *mpp = opaque;
1451 b7169916 aurel32
    uint32_t retval;
1452 b7169916 aurel32
    int idx = MPIC_INT_IRQ;
1453 b7169916 aurel32
1454 0bf9e31a Blue Swirl
    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1455 b7169916 aurel32
    retval = 0xFFFFFFFF;
1456 b7169916 aurel32
    if (addr & 0xF)
1457 b7169916 aurel32
        return retval;
1458 b7169916 aurel32
1459 5c4532ee Blue Swirl
    addr -= MPIC_INT_REG_START & (OPENPIC_PAGE_SIZE - 1);
1460 b7169916 aurel32
    if (addr < MPIC_INT_REG_SIZE) {
1461 b7169916 aurel32
        idx += (addr & 0xFFF0) >> 5;
1462 b7169916 aurel32
        if (addr & 0x10) {
1463 b7169916 aurel32
            /* EXDE / IFEDE / IEEDE */
1464 b7169916 aurel32
            retval = read_IRQreg(mpp, idx, IRQ_IDE);
1465 b7169916 aurel32
        } else {
1466 b7169916 aurel32
            /* EXVP / IFEVP / IEEVP */
1467 b7169916 aurel32
            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
1468 b7169916 aurel32
        }
1469 b7169916 aurel32
        DPRINTF("%s: => %08x\n", __func__, retval);
1470 b7169916 aurel32
    }
1471 b7169916 aurel32
1472 b7169916 aurel32
    return retval;
1473 b7169916 aurel32
}
1474 b7169916 aurel32
1475 c227f099 Anthony Liguori
static void mpic_src_msg_write (void *opaque, target_phys_addr_t addr,
1476 b7169916 aurel32
                                uint32_t val)
1477 b7169916 aurel32
{
1478 c227f099 Anthony Liguori
    openpic_t *mpp = opaque;
1479 b7169916 aurel32
    int idx = MPIC_MSG_IRQ;
1480 b7169916 aurel32
1481 0bf9e31a Blue Swirl
    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1482 b7169916 aurel32
    if (addr & 0xF)
1483 b7169916 aurel32
        return;
1484 b7169916 aurel32
1485 5c4532ee Blue Swirl
    addr -= MPIC_MSG_REG_START & (OPENPIC_PAGE_SIZE - 1);
1486 b7169916 aurel32
    if (addr < MPIC_MSG_REG_SIZE) {
1487 b7169916 aurel32
        idx += (addr & 0xFFF0) >> 5;
1488 b7169916 aurel32
        if (addr & 0x10) {
1489 b7169916 aurel32
            /* EXDE / IFEDE / IEEDE */
1490 b7169916 aurel32
            write_IRQreg(mpp, idx, IRQ_IDE, val);
1491 b7169916 aurel32
        } else {
1492 b7169916 aurel32
            /* EXVP / IFEVP / IEEVP */
1493 b7169916 aurel32
            write_IRQreg(mpp, idx, IRQ_IPVP, val);
1494 b7169916 aurel32
        }
1495 b7169916 aurel32
    }
1496 b7169916 aurel32
}
1497 b7169916 aurel32
1498 c227f099 Anthony Liguori
static uint32_t mpic_src_msg_read (void *opaque, target_phys_addr_t addr)
1499 b7169916 aurel32
{
1500 c227f099 Anthony Liguori
    openpic_t *mpp = opaque;
1501 b7169916 aurel32
    uint32_t retval;
1502 b7169916 aurel32
    int idx = MPIC_MSG_IRQ;
1503 b7169916 aurel32
1504 0bf9e31a Blue Swirl
    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1505 b7169916 aurel32
    retval = 0xFFFFFFFF;
1506 b7169916 aurel32
    if (addr & 0xF)
1507 b7169916 aurel32
        return retval;
1508 b7169916 aurel32
1509 5c4532ee Blue Swirl
    addr -= MPIC_MSG_REG_START & (OPENPIC_PAGE_SIZE - 1);
1510 b7169916 aurel32
    if (addr < MPIC_MSG_REG_SIZE) {
1511 b7169916 aurel32
        idx += (addr & 0xFFF0) >> 5;
1512 b7169916 aurel32
        if (addr & 0x10) {
1513 b7169916 aurel32
            /* EXDE / IFEDE / IEEDE */
1514 b7169916 aurel32
            retval = read_IRQreg(mpp, idx, IRQ_IDE);
1515 b7169916 aurel32
        } else {
1516 b7169916 aurel32
            /* EXVP / IFEVP / IEEVP */
1517 b7169916 aurel32
            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
1518 b7169916 aurel32
        }
1519 b7169916 aurel32
        DPRINTF("%s: => %08x\n", __func__, retval);
1520 b7169916 aurel32
    }
1521 b7169916 aurel32
1522 b7169916 aurel32
    return retval;
1523 b7169916 aurel32
}
1524 b7169916 aurel32
1525 c227f099 Anthony Liguori
static void mpic_src_msi_write (void *opaque, target_phys_addr_t addr,
1526 b7169916 aurel32
                                uint32_t val)
1527 b7169916 aurel32
{
1528 c227f099 Anthony Liguori
    openpic_t *mpp = opaque;
1529 b7169916 aurel32
    int idx = MPIC_MSI_IRQ;
1530 b7169916 aurel32
1531 0bf9e31a Blue Swirl
    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1532 b7169916 aurel32
    if (addr & 0xF)
1533 b7169916 aurel32
        return;
1534 b7169916 aurel32
1535 5c4532ee Blue Swirl
    addr -= MPIC_MSI_REG_START & (OPENPIC_PAGE_SIZE - 1);
1536 b7169916 aurel32
    if (addr < MPIC_MSI_REG_SIZE) {
1537 b7169916 aurel32
        idx += (addr & 0xFFF0) >> 5;
1538 b7169916 aurel32
        if (addr & 0x10) {
1539 b7169916 aurel32
            /* EXDE / IFEDE / IEEDE */
1540 b7169916 aurel32
            write_IRQreg(mpp, idx, IRQ_IDE, val);
1541 b7169916 aurel32
        } else {
1542 b7169916 aurel32
            /* EXVP / IFEVP / IEEVP */
1543 b7169916 aurel32
            write_IRQreg(mpp, idx, IRQ_IPVP, val);
1544 b7169916 aurel32
        }
1545 b7169916 aurel32
    }
1546 b7169916 aurel32
}
1547 c227f099 Anthony Liguori
static uint32_t mpic_src_msi_read (void *opaque, target_phys_addr_t addr)
1548 b7169916 aurel32
{
1549 c227f099 Anthony Liguori
    openpic_t *mpp = opaque;
1550 b7169916 aurel32
    uint32_t retval;
1551 b7169916 aurel32
    int idx = MPIC_MSI_IRQ;
1552 b7169916 aurel32
1553 0bf9e31a Blue Swirl
    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1554 b7169916 aurel32
    retval = 0xFFFFFFFF;
1555 b7169916 aurel32
    if (addr & 0xF)
1556 b7169916 aurel32
        return retval;
1557 b7169916 aurel32
1558 5c4532ee Blue Swirl
    addr -= MPIC_MSI_REG_START & (OPENPIC_PAGE_SIZE - 1);
1559 b7169916 aurel32
    if (addr < MPIC_MSI_REG_SIZE) {
1560 b7169916 aurel32
        idx += (addr & 0xFFF0) >> 5;
1561 b7169916 aurel32
        if (addr & 0x10) {
1562 b7169916 aurel32
            /* EXDE / IFEDE / IEEDE */
1563 b7169916 aurel32
            retval = read_IRQreg(mpp, idx, IRQ_IDE);
1564 b7169916 aurel32
        } else {
1565 b7169916 aurel32
            /* EXVP / IFEVP / IEEVP */
1566 b7169916 aurel32
            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
1567 b7169916 aurel32
        }
1568 b7169916 aurel32
        DPRINTF("%s: => %08x\n", __func__, retval);
1569 b7169916 aurel32
    }
1570 b7169916 aurel32
1571 b7169916 aurel32
    return retval;
1572 b7169916 aurel32
}
1573 b7169916 aurel32
1574 d60efc6b Blue Swirl
static CPUWriteMemoryFunc * const mpic_glb_write[] = {
1575 b7169916 aurel32
    &openpic_buggy_write,
1576 b7169916 aurel32
    &openpic_buggy_write,
1577 b7169916 aurel32
    &openpic_gbl_write,
1578 b7169916 aurel32
};
1579 b7169916 aurel32
1580 d60efc6b Blue Swirl
static CPUReadMemoryFunc * const mpic_glb_read[] = {
1581 b7169916 aurel32
    &openpic_buggy_read,
1582 b7169916 aurel32
    &openpic_buggy_read,
1583 b7169916 aurel32
    &openpic_gbl_read,
1584 b7169916 aurel32
};
1585 b7169916 aurel32
1586 d60efc6b Blue Swirl
static CPUWriteMemoryFunc * const mpic_tmr_write[] = {
1587 b7169916 aurel32
    &openpic_buggy_write,
1588 b7169916 aurel32
    &openpic_buggy_write,
1589 b7169916 aurel32
    &mpic_timer_write,
1590 b7169916 aurel32
};
1591 b7169916 aurel32
1592 d60efc6b Blue Swirl
static CPUReadMemoryFunc * const mpic_tmr_read[] = {
1593 b7169916 aurel32
    &openpic_buggy_read,
1594 b7169916 aurel32
    &openpic_buggy_read,
1595 b7169916 aurel32
    &mpic_timer_read,
1596 b7169916 aurel32
};
1597 b7169916 aurel32
1598 d60efc6b Blue Swirl
static CPUWriteMemoryFunc * const mpic_cpu_write[] = {
1599 b7169916 aurel32
    &openpic_buggy_write,
1600 b7169916 aurel32
    &openpic_buggy_write,
1601 b7169916 aurel32
    &openpic_cpu_write,
1602 b7169916 aurel32
};
1603 b7169916 aurel32
1604 d60efc6b Blue Swirl
static CPUReadMemoryFunc * const mpic_cpu_read[] = {
1605 b7169916 aurel32
    &openpic_buggy_read,
1606 b7169916 aurel32
    &openpic_buggy_read,
1607 b7169916 aurel32
    &openpic_cpu_read,
1608 b7169916 aurel32
};
1609 b7169916 aurel32
1610 d60efc6b Blue Swirl
static CPUWriteMemoryFunc * const mpic_ext_write[] = {
1611 b7169916 aurel32
    &openpic_buggy_write,
1612 b7169916 aurel32
    &openpic_buggy_write,
1613 b7169916 aurel32
    &mpic_src_ext_write,
1614 b7169916 aurel32
};
1615 b7169916 aurel32
1616 d60efc6b Blue Swirl
static CPUReadMemoryFunc * const mpic_ext_read[] = {
1617 b7169916 aurel32
    &openpic_buggy_read,
1618 b7169916 aurel32
    &openpic_buggy_read,
1619 b7169916 aurel32
    &mpic_src_ext_read,
1620 b7169916 aurel32
};
1621 b7169916 aurel32
1622 d60efc6b Blue Swirl
static CPUWriteMemoryFunc * const mpic_int_write[] = {
1623 b7169916 aurel32
    &openpic_buggy_write,
1624 b7169916 aurel32
    &openpic_buggy_write,
1625 b7169916 aurel32
    &mpic_src_int_write,
1626 b7169916 aurel32
};
1627 b7169916 aurel32
1628 d60efc6b Blue Swirl
static CPUReadMemoryFunc * const mpic_int_read[] = {
1629 b7169916 aurel32
    &openpic_buggy_read,
1630 b7169916 aurel32
    &openpic_buggy_read,
1631 b7169916 aurel32
    &mpic_src_int_read,
1632 b7169916 aurel32
};
1633 b7169916 aurel32
1634 d60efc6b Blue Swirl
static CPUWriteMemoryFunc * const mpic_msg_write[] = {
1635 b7169916 aurel32
    &openpic_buggy_write,
1636 b7169916 aurel32
    &openpic_buggy_write,
1637 b7169916 aurel32
    &mpic_src_msg_write,
1638 b7169916 aurel32
};
1639 b7169916 aurel32
1640 d60efc6b Blue Swirl
static CPUReadMemoryFunc * const mpic_msg_read[] = {
1641 b7169916 aurel32
    &openpic_buggy_read,
1642 b7169916 aurel32
    &openpic_buggy_read,
1643 b7169916 aurel32
    &mpic_src_msg_read,
1644 b7169916 aurel32
};
1645 d60efc6b Blue Swirl
static CPUWriteMemoryFunc * const mpic_msi_write[] = {
1646 b7169916 aurel32
    &openpic_buggy_write,
1647 b7169916 aurel32
    &openpic_buggy_write,
1648 b7169916 aurel32
    &mpic_src_msi_write,
1649 b7169916 aurel32
};
1650 b7169916 aurel32
1651 d60efc6b Blue Swirl
static CPUReadMemoryFunc * const mpic_msi_read[] = {
1652 b7169916 aurel32
    &openpic_buggy_read,
1653 b7169916 aurel32
    &openpic_buggy_read,
1654 b7169916 aurel32
    &mpic_src_msi_read,
1655 b7169916 aurel32
};
1656 b7169916 aurel32
1657 c227f099 Anthony Liguori
qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,
1658 b7169916 aurel32
                        qemu_irq **irqs, qemu_irq irq_out)
1659 b7169916 aurel32
{
1660 c227f099 Anthony Liguori
    openpic_t *mpp;
1661 b7169916 aurel32
    int i;
1662 b7169916 aurel32
    struct {
1663 d60efc6b Blue Swirl
        CPUReadMemoryFunc * const *read;
1664 d60efc6b Blue Swirl
        CPUWriteMemoryFunc * const *write;
1665 c227f099 Anthony Liguori
        target_phys_addr_t start_addr;
1666 c227f099 Anthony Liguori
        ram_addr_t size;
1667 dfebf62b aurel32
    } const list[] = {
1668 b7169916 aurel32
        {mpic_glb_read, mpic_glb_write, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE},
1669 b7169916 aurel32
        {mpic_tmr_read, mpic_tmr_write, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE},
1670 b7169916 aurel32
        {mpic_ext_read, mpic_ext_write, MPIC_EXT_REG_START, MPIC_EXT_REG_SIZE},
1671 b7169916 aurel32
        {mpic_int_read, mpic_int_write, MPIC_INT_REG_START, MPIC_INT_REG_SIZE},
1672 b7169916 aurel32
        {mpic_msg_read, mpic_msg_write, MPIC_MSG_REG_START, MPIC_MSG_REG_SIZE},
1673 b7169916 aurel32
        {mpic_msi_read, mpic_msi_write, MPIC_MSI_REG_START, MPIC_MSI_REG_SIZE},
1674 b7169916 aurel32
        {mpic_cpu_read, mpic_cpu_write, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE},
1675 b7169916 aurel32
    };
1676 b7169916 aurel32
1677 b7169916 aurel32
    /* XXX: for now, only one CPU is supported */
1678 b7169916 aurel32
    if (nb_cpus != 1)
1679 b7169916 aurel32
        return NULL;
1680 b7169916 aurel32
1681 7267c094 Anthony Liguori
    mpp = g_malloc0(sizeof(openpic_t));
1682 b7169916 aurel32
1683 b7169916 aurel32
    for (i = 0; i < sizeof(list)/sizeof(list[0]); i++) {
1684 b7169916 aurel32
        int mem_index;
1685 b7169916 aurel32
1686 2507c12a Alexander Graf
        mem_index = cpu_register_io_memory(list[i].read, list[i].write, mpp,
1687 82600641 Alexander Graf
                                           DEVICE_BIG_ENDIAN);
1688 b7169916 aurel32
        if (mem_index < 0) {
1689 b7169916 aurel32
            goto free;
1690 b7169916 aurel32
        }
1691 b7169916 aurel32
        cpu_register_physical_memory(base + list[i].start_addr,
1692 b7169916 aurel32
                                     list[i].size, mem_index);
1693 b7169916 aurel32
    }
1694 b7169916 aurel32
1695 b7169916 aurel32
    mpp->nb_cpus = nb_cpus;
1696 b7169916 aurel32
    mpp->max_irq = MPIC_MAX_IRQ;
1697 b7169916 aurel32
    mpp->irq_ipi0 = MPIC_IPI_IRQ;
1698 b7169916 aurel32
    mpp->irq_tim0 = MPIC_TMR_IRQ;
1699 b7169916 aurel32
1700 b7169916 aurel32
    for (i = 0; i < nb_cpus; i++)
1701 b7169916 aurel32
        mpp->dst[i].irqs = irqs[i];
1702 b7169916 aurel32
    mpp->irq_out = irq_out;
1703 b7169916 aurel32
1704 b7169916 aurel32
    mpp->irq_raise = mpic_irq_raise;
1705 b7169916 aurel32
    mpp->reset = mpic_reset;
1706 b7169916 aurel32
1707 0be71e32 Alex Williamson
    register_savevm(NULL, "mpic", 0, 2, openpic_save, openpic_load, mpp);
1708 a08d4367 Jan Kiszka
    qemu_register_reset(mpic_reset, mpp);
1709 b7169916 aurel32
1710 b7169916 aurel32
    return qemu_allocate_irqs(openpic_set_irq, mpp, mpp->max_irq);
1711 b7169916 aurel32
1712 b7169916 aurel32
free:
1713 7267c094 Anthony Liguori
    g_free(mpp);
1714 b7169916 aurel32
    return NULL;
1715 dbda808a bellard
}