arm_gic.c 28.7 KB
Newer Older
1
/*
P
pbrook 已提交
2
 * ARM Generic/Distributed Interrupt Controller
P
pbrook 已提交
3
 *
P
pbrook 已提交
4
 * Copyright (c) 2006-2007 CodeSourcery.
P
pbrook 已提交
5 6
 * Written by Paul Brook
 *
M
Matthew Fernandez 已提交
7
 * This code is licensed under the GPL.
P
pbrook 已提交
8 9
 */

P
pbrook 已提交
10
/* This file contains implementation code for the RealView EB interrupt
11 12 13 14 15 16 17 18 19
 * controller, MPCore distributed interrupt controller and ARMv7-M
 * Nested Vectored Interrupt Controller.
 * It is compiled in two ways:
 *  (1) as a standalone file to produce a sysbus device which is a GIC
 *  that can be used on the realview board and as one of the builtin
 *  private peripherals for the ARM MP CPUs (11MPCore, A9, etc)
 *  (2) by being directly #included into armv7m_nvic.c to produce the
 *  armv7m_nvic device.
 */
P
pbrook 已提交
20

21 22
#include "sysbus.h"

23 24
/* Maximum number of possible interrupts, determined by the GIC architecture */
#define GIC_MAXIRQ 1020
R
Rusty Russell 已提交
25 26
/* First 32 are private to each CPU (SGIs and PPIs). */
#define GIC_INTERNAL 32
27 28 29 30 31 32 33
/* Maximum number of possible CPU interfaces, determined by GIC architecture */
#ifdef NVIC
#define NCPU 1
#else
#define NCPU 8
#endif

P
pbrook 已提交
34 35 36
//#define DEBUG_GIC

#ifdef DEBUG_GIC
37 38
#define DPRINTF(fmt, ...) \
do { printf("arm_gic: " fmt , ## __VA_ARGS__); } while (0)
P
pbrook 已提交
39
#else
40
#define DPRINTF(fmt, ...) do {} while(0)
P
pbrook 已提交
41 42
#endif

P
pbrook 已提交
43 44 45 46 47 48 49
#ifdef NVIC
static const uint8_t gic_id[] =
{ 0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1 };
/* The NVIC has 16 internal vectors.  However these are not exposed
   through the normal GIC interface.  */
#define GIC_BASE_IRQ    32
#else
P
pbrook 已提交
50 51
static const uint8_t gic_id[] =
{ 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
P
pbrook 已提交
52 53
#define GIC_BASE_IRQ    0
#endif
P
pbrook 已提交
54

P
Paul Brook 已提交
55 56 57
#define FROM_SYSBUSGIC(type, dev) \
    DO_UPCAST(type, gic, FROM_SYSBUS(gic_state, dev))

P
pbrook 已提交
58 59
typedef struct gic_irq_state
{
60 61
    /* The enable bits are only banked for per-cpu interrupts.  */
    unsigned enabled:NCPU;
P
pbrook 已提交
62 63
    unsigned pending:NCPU;
    unsigned active:NCPU;
64
    unsigned level:NCPU;
P
pbrook 已提交
65
    unsigned model:1; /* 0 = N:N, 1 = 1:N */
P
pbrook 已提交
66 67 68
    unsigned trigger:1; /* nonzero = edge triggered.  */
} gic_irq_state;

69
#define ALL_CPU_MASK ((unsigned)(((1 << NCPU) - 1)))
P
Paul Brook 已提交
70 71 72 73 74
#if NCPU > 1
#define NUM_CPU(s) ((s)->num_cpu)
#else
#define NUM_CPU(s) 1
#endif
P
pbrook 已提交
75

76 77 78
#define GIC_SET_ENABLED(irq, cm) s->irq_state[irq].enabled |= (cm)
#define GIC_CLEAR_ENABLED(irq, cm) s->irq_state[irq].enabled &= ~(cm)
#define GIC_TEST_ENABLED(irq, cm) ((s->irq_state[irq].enabled & (cm)) != 0)
P
pbrook 已提交
79 80 81 82 83 84
#define GIC_SET_PENDING(irq, cm) s->irq_state[irq].pending |= (cm)
#define GIC_CLEAR_PENDING(irq, cm) s->irq_state[irq].pending &= ~(cm)
#define GIC_TEST_PENDING(irq, cm) ((s->irq_state[irq].pending & (cm)) != 0)
#define GIC_SET_ACTIVE(irq, cm) s->irq_state[irq].active |= (cm)
#define GIC_CLEAR_ACTIVE(irq, cm) s->irq_state[irq].active &= ~(cm)
#define GIC_TEST_ACTIVE(irq, cm) ((s->irq_state[irq].active & (cm)) != 0)
P
pbrook 已提交
85 86 87
#define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1
#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0
#define GIC_TEST_MODEL(irq) s->irq_state[irq].model
P
pbrook 已提交
88 89
#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm)
#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm)
90
#define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0)
P
pbrook 已提交
91 92 93
#define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1
#define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0
#define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger
R
Rusty Russell 已提交
94 95 96
#define GIC_GET_PRIORITY(irq, cpu) (((irq) < GIC_INTERNAL) ?            \
                                    s->priority1[irq][cpu] :            \
                                    s->priority2[(irq) - GIC_INTERNAL])
P
pbrook 已提交
97 98 99 100 101
#ifdef NVIC
#define GIC_TARGET(irq) 1
#else
#define GIC_TARGET(irq) s->irq_target[irq]
#endif
P
pbrook 已提交
102 103 104

typedef struct gic_state
{
P
Paul Brook 已提交
105
    SysBusDevice busdev;
P
pbrook 已提交
106
    qemu_irq parent_irq[NCPU];
P
pbrook 已提交
107
    int enabled;
P
pbrook 已提交
108
    int cpu_enabled[NCPU];
P
pbrook 已提交
109

110
    gic_irq_state irq_state[GIC_MAXIRQ];
P
pbrook 已提交
111
#ifndef NVIC
112
    int irq_target[GIC_MAXIRQ];
P
pbrook 已提交
113
#endif
R
Rusty Russell 已提交
114 115
    int priority1[GIC_INTERNAL][NCPU];
    int priority2[GIC_MAXIRQ - GIC_INTERNAL];
116
    int last_active[GIC_MAXIRQ][NCPU];
P
pbrook 已提交
117 118 119 120 121 122

    int priority_mask[NCPU];
    int running_irq[NCPU];
    int running_priority[NCPU];
    int current_pending[NCPU];

P
Paul Brook 已提交
123
#if NCPU > 1
124
    uint32_t num_cpu;
P
Paul Brook 已提交
125 126
#endif

127 128 129 130 131 132 133 134
    MemoryRegion iomem; /* Distributor */
#ifndef NVIC
    /* This is just so we can have an opaque pointer which identifies
     * both this GIC and which CPU interface we should be accessing.
     */
    struct gic_state *backref[NCPU];
    MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */
#endif
135
    uint32_t num_irq;
P
pbrook 已提交
136 137
} gic_state;

138 139 140 141 142 143 144 145 146 147
static inline int gic_get_current_cpu(gic_state *s)
{
#if NCPU > 1
    if (s->num_cpu > 1) {
        return cpu_single_env->cpu_index;
    }
#endif
    return 0;
}

P
pbrook 已提交
148 149 150 151 152 153 154
/* TODO: Many places that call this routine could be optimized.  */
/* Update interrupt status after enabled or pending bits have been changed.  */
static void gic_update(gic_state *s)
{
    int best_irq;
    int best_prio;
    int irq;
P
pbrook 已提交
155 156 157 158
    int level;
    int cpu;
    int cm;

P
Paul Brook 已提交
159
    for (cpu = 0; cpu < NUM_CPU(s); cpu++) {
P
pbrook 已提交
160 161 162 163 164 165 166 167
        cm = 1 << cpu;
        s->current_pending[cpu] = 1023;
        if (!s->enabled || !s->cpu_enabled[cpu]) {
	    qemu_irq_lower(s->parent_irq[cpu]);
            return;
        }
        best_prio = 0x100;
        best_irq = 1023;
168
        for (irq = 0; irq < s->num_irq; irq++) {
169
            if (GIC_TEST_ENABLED(irq, cm) && GIC_TEST_PENDING(irq, cm)) {
P
pbrook 已提交
170 171 172 173
                if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
                    best_prio = GIC_GET_PRIORITY(irq, cpu);
                    best_irq = irq;
                }
P
pbrook 已提交
174 175
            }
        }
P
pbrook 已提交
176 177 178 179 180 181 182
        level = 0;
        if (best_prio <= s->priority_mask[cpu]) {
            s->current_pending[cpu] = best_irq;
            if (best_prio < s->running_priority[cpu]) {
                DPRINTF("Raised pending IRQ %d\n", best_irq);
                level = 1;
            }
P
pbrook 已提交
183
        }
P
pbrook 已提交
184
        qemu_set_irq(s->parent_irq[cpu], level);
P
pbrook 已提交
185 186 187
    }
}

P
pbrook 已提交
188 189 190 191 192 193 194 195 196 197 198 199 200 201
static void __attribute__((unused))
gic_set_pending_private(gic_state *s, int cpu, int irq)
{
    int cm = 1 << cpu;

    if (GIC_TEST_PENDING(irq, cm))
        return;

    DPRINTF("Set %d pending cpu %d\n", irq, cpu);
    GIC_SET_PENDING(irq, cm);
    gic_update(s);
}

/* Process a change in an external IRQ input.  */
P
pbrook 已提交
202 203
static void gic_set_irq(void *opaque, int irq, int level)
{
204 205 206 207 208 209
    /* Meaning of the 'irq' parameter:
     *  [0..N-1] : external interrupts
     *  [N..N+31] : PPI (internal) interrupts for CPU 0
     *  [N+32..N+63] : PPI (internal interrupts for CPU 1
     *  ...
     */
P
pbrook 已提交
210
    gic_state *s = (gic_state *)opaque;
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
    int cm, target;
    if (irq < (s->num_irq - GIC_INTERNAL)) {
        /* The first external input line is internal interrupt 32.  */
        cm = ALL_CPU_MASK;
        irq += GIC_INTERNAL;
        target = GIC_TARGET(irq);
    } else {
        int cpu;
        irq -= (s->num_irq - GIC_INTERNAL);
        cpu = irq / GIC_INTERNAL;
        irq %= GIC_INTERNAL;
        cm = 1 << cpu;
        target = cm;
    }

    if (level == GIC_TEST_LEVEL(irq, cm)) {
P
pbrook 已提交
227
        return;
228
    }
P
pbrook 已提交
229 230

    if (level) {
231 232 233 234
        GIC_SET_LEVEL(irq, cm);
        if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) {
            DPRINTF("Set %d pending mask %x\n", irq, target);
            GIC_SET_PENDING(irq, target);
P
pbrook 已提交
235 236
        }
    } else {
237
        GIC_CLEAR_LEVEL(irq, cm);
P
pbrook 已提交
238 239 240 241
    }
    gic_update(s);
}

P
pbrook 已提交
242
static void gic_set_running_irq(gic_state *s, int cpu, int irq)
P
pbrook 已提交
243
{
P
pbrook 已提交
244 245 246 247 248 249
    s->running_irq[cpu] = irq;
    if (irq == 1023) {
        s->running_priority[cpu] = 0x100;
    } else {
        s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu);
    }
P
pbrook 已提交
250 251 252
    gic_update(s);
}

P
pbrook 已提交
253
static uint32_t gic_acknowledge_irq(gic_state *s, int cpu)
P
pbrook 已提交
254 255
{
    int new_irq;
P
pbrook 已提交
256 257 258 259
    int cm = 1 << cpu;
    new_irq = s->current_pending[cpu];
    if (new_irq == 1023
            || GIC_GET_PRIORITY(new_irq, cpu) >= s->running_priority[cpu]) {
P
pbrook 已提交
260 261 262
        DPRINTF("ACK no pending IRQ\n");
        return 1023;
    }
P
pbrook 已提交
263 264 265 266 267
    s->last_active[new_irq][cpu] = s->running_irq[cpu];
    /* Clear pending flags for both level and edge triggered interrupts.
       Level triggered IRQs will be reasserted once they become inactive.  */
    GIC_CLEAR_PENDING(new_irq, GIC_TEST_MODEL(new_irq) ? ALL_CPU_MASK : cm);
    gic_set_running_irq(s, cpu, new_irq);
P
pbrook 已提交
268 269 270 271
    DPRINTF("ACK %d\n", new_irq);
    return new_irq;
}

P
pbrook 已提交
272
static void gic_complete_irq(gic_state * s, int cpu, int irq)
P
pbrook 已提交
273 274
{
    int update = 0;
P
pbrook 已提交
275
    int cm = 1 << cpu;
P
pbrook 已提交
276
    DPRINTF("EOI %d\n", irq);
277
    if (irq >= s->num_irq) {
278 279 280 281 282 283 284 285 286 287
        /* This handles two cases:
         * 1. If software writes the ID of a spurious interrupt [ie 1023]
         * to the GICC_EOIR, the GIC ignores that write.
         * 2. If software writes the number of a non-existent interrupt
         * this must be a subcase of "value written does not match the last
         * valid interrupt value read from the Interrupt Acknowledge
         * register" and so this is UNPREDICTABLE. We choose to ignore it.
         */
        return;
    }
P
pbrook 已提交
288
    if (s->running_irq[cpu] == 1023)
P
pbrook 已提交
289
        return; /* No active IRQ.  */
290 291 292 293 294 295 296
    /* Mark level triggered interrupts as pending if they are still
       raised.  */
    if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm)
        && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
        DPRINTF("Set %d pending mask %x\n", irq, cm);
        GIC_SET_PENDING(irq, cm);
        update = 1;
P
pbrook 已提交
297
    }
P
pbrook 已提交
298
    if (irq != s->running_irq[cpu]) {
P
pbrook 已提交
299
        /* Complete an IRQ that is not currently running.  */
P
pbrook 已提交
300 301 302 303
        int tmp = s->running_irq[cpu];
        while (s->last_active[tmp][cpu] != 1023) {
            if (s->last_active[tmp][cpu] == irq) {
                s->last_active[tmp][cpu] = s->last_active[irq][cpu];
P
pbrook 已提交
304 305
                break;
            }
P
pbrook 已提交
306
            tmp = s->last_active[tmp][cpu];
P
pbrook 已提交
307 308 309 310 311 312
        }
        if (update) {
            gic_update(s);
        }
    } else {
        /* Complete the current running IRQ.  */
P
pbrook 已提交
313
        gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]);
P
pbrook 已提交
314 315 316
    }
}

A
Anthony Liguori 已提交
317
static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
P
pbrook 已提交
318 319 320 321 322
{
    gic_state *s = (gic_state *)opaque;
    uint32_t res;
    int irq;
    int i;
P
pbrook 已提交
323 324 325
    int cpu;
    int cm;
    int mask;
P
pbrook 已提交
326

327
    cpu = gic_get_current_cpu(s);
P
pbrook 已提交
328
    cm = 1 << cpu;
P
pbrook 已提交
329
    if (offset < 0x100) {
P
pbrook 已提交
330
#ifndef NVIC
P
pbrook 已提交
331 332 333
        if (offset == 0)
            return s->enabled;
        if (offset == 4)
334
            return ((s->num_irq / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
P
pbrook 已提交
335 336
        if (offset < 0x08)
            return 0;
337 338 339 340
        if (offset >= 0x80) {
            /* Interrupt Security , RAZ/WI */
            return 0;
        }
P
pbrook 已提交
341
#endif
P
pbrook 已提交
342 343 344 345 346 347 348
        goto bad_reg;
    } else if (offset < 0x200) {
        /* Interrupt Set/Clear Enable.  */
        if (offset < 0x180)
            irq = (offset - 0x100) * 8;
        else
            irq = (offset - 0x180) * 8;
P
pbrook 已提交
349
        irq += GIC_BASE_IRQ;
350
        if (irq >= s->num_irq)
P
pbrook 已提交
351 352 353
            goto bad_reg;
        res = 0;
        for (i = 0; i < 8; i++) {
354
            if (GIC_TEST_ENABLED(irq + i, cm)) {
P
pbrook 已提交
355 356 357 358 359 360 361 362 363
                res |= (1 << i);
            }
        }
    } else if (offset < 0x300) {
        /* Interrupt Set/Clear Pending.  */
        if (offset < 0x280)
            irq = (offset - 0x200) * 8;
        else
            irq = (offset - 0x280) * 8;
P
pbrook 已提交
364
        irq += GIC_BASE_IRQ;
365
        if (irq >= s->num_irq)
P
pbrook 已提交
366 367
            goto bad_reg;
        res = 0;
R
Rusty Russell 已提交
368
        mask = (irq < GIC_INTERNAL) ?  cm : ALL_CPU_MASK;
P
pbrook 已提交
369
        for (i = 0; i < 8; i++) {
P
pbrook 已提交
370
            if (GIC_TEST_PENDING(irq + i, mask)) {
P
pbrook 已提交
371 372 373 374 375
                res |= (1 << i);
            }
        }
    } else if (offset < 0x400) {
        /* Interrupt Active.  */
P
pbrook 已提交
376
        irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
377
        if (irq >= s->num_irq)
P
pbrook 已提交
378 379
            goto bad_reg;
        res = 0;
R
Rusty Russell 已提交
380
        mask = (irq < GIC_INTERNAL) ?  cm : ALL_CPU_MASK;
P
pbrook 已提交
381
        for (i = 0; i < 8; i++) {
P
pbrook 已提交
382
            if (GIC_TEST_ACTIVE(irq + i, mask)) {
P
pbrook 已提交
383 384 385 386 387
                res |= (1 << i);
            }
        }
    } else if (offset < 0x800) {
        /* Interrupt Priority.  */
P
pbrook 已提交
388
        irq = (offset - 0x400) + GIC_BASE_IRQ;
389
        if (irq >= s->num_irq)
P
pbrook 已提交
390
            goto bad_reg;
P
pbrook 已提交
391 392
        res = GIC_GET_PRIORITY(irq, cpu);
#ifndef NVIC
P
pbrook 已提交
393 394
    } else if (offset < 0xc00) {
        /* Interrupt CPU Target.  */
P
pbrook 已提交
395
        irq = (offset - 0x800) + GIC_BASE_IRQ;
396
        if (irq >= s->num_irq)
P
pbrook 已提交
397
            goto bad_reg;
P
pbrook 已提交
398 399 400 401 402
        if (irq >= 29 && irq <= 31) {
            res = cm;
        } else {
            res = GIC_TARGET(irq);
        }
P
pbrook 已提交
403 404
    } else if (offset < 0xf00) {
        /* Interrupt Configuration.  */
P
pbrook 已提交
405
        irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ;
406
        if (irq >= s->num_irq)
P
pbrook 已提交
407 408 409 410 411 412 413 414
            goto bad_reg;
        res = 0;
        for (i = 0; i < 4; i++) {
            if (GIC_TEST_MODEL(irq + i))
                res |= (1 << (i * 2));
            if (GIC_TEST_TRIGGER(irq + i))
                res |= (2 << (i * 2));
        }
P
pbrook 已提交
415
#endif
P
pbrook 已提交
416 417 418 419 420 421 422 423 424 425 426
    } else if (offset < 0xfe0) {
        goto bad_reg;
    } else /* offset >= 0xfe0 */ {
        if (offset & 3) {
            res = 0;
        } else {
            res = gic_id[(offset - 0xfe0) >> 2];
        }
    }
    return res;
bad_reg:
P
Paul Brook 已提交
427
    hw_error("gic_dist_readb: Bad offset %x\n", (int)offset);
P
pbrook 已提交
428 429 430
    return 0;
}

A
Anthony Liguori 已提交
431
static uint32_t gic_dist_readw(void *opaque, target_phys_addr_t offset)
P
pbrook 已提交
432 433 434 435 436 437 438
{
    uint32_t val;
    val = gic_dist_readb(opaque, offset);
    val |= gic_dist_readb(opaque, offset + 1) << 8;
    return val;
}

A
Anthony Liguori 已提交
439
static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset)
P
pbrook 已提交
440 441
{
    uint32_t val;
P
pbrook 已提交
442 443 444
#ifdef NVIC
    gic_state *s = (gic_state *)opaque;
    uint32_t addr;
445
    addr = offset;
P
pbrook 已提交
446
    if (addr < 0x100 || addr > 0xd00)
P
Paul Brook 已提交
447
        return nvic_readl(s, addr);
P
pbrook 已提交
448
#endif
P
pbrook 已提交
449 450 451 452 453
    val = gic_dist_readw(opaque, offset);
    val |= gic_dist_readw(opaque, offset + 2) << 16;
    return val;
}

A
Anthony Liguori 已提交
454
static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
P
pbrook 已提交
455 456 457 458 459
                            uint32_t value)
{
    gic_state *s = (gic_state *)opaque;
    int irq;
    int i;
P
pbrook 已提交
460
    int cpu;
P
pbrook 已提交
461

462
    cpu = gic_get_current_cpu(s);
P
pbrook 已提交
463
    if (offset < 0x100) {
P
pbrook 已提交
464 465 466
#ifdef NVIC
        goto bad_reg;
#else
P
pbrook 已提交
467 468 469 470 471
        if (offset == 0) {
            s->enabled = (value & 1);
            DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
        } else if (offset < 4) {
            /* ignored.  */
472 473
        } else if (offset >= 0x80) {
            /* Interrupt Security Registers, RAZ/WI */
P
pbrook 已提交
474 475 476
        } else {
            goto bad_reg;
        }
P
pbrook 已提交
477
#endif
P
pbrook 已提交
478 479
    } else if (offset < 0x180) {
        /* Interrupt Set Enable.  */
P
pbrook 已提交
480
        irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
481
        if (irq >= s->num_irq)
P
pbrook 已提交
482
            goto bad_reg;
P
pbrook 已提交
483 484
        if (irq < 16)
          value = 0xff;
P
pbrook 已提交
485 486
        for (i = 0; i < 8; i++) {
            if (value & (1 << i)) {
R
Rusty Russell 已提交
487 488
                int mask = (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq);
                int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
489 490

                if (!GIC_TEST_ENABLED(irq + i, cm)) {
P
pbrook 已提交
491
                    DPRINTF("Enabled IRQ %d\n", irq + i);
492 493
                }
                GIC_SET_ENABLED(irq + i, cm);
P
pbrook 已提交
494 495
                /* If a raised level triggered IRQ enabled then mark
                   is as pending.  */
P
pbrook 已提交
496 497 498 499 500
                if (GIC_TEST_LEVEL(irq + i, mask)
                        && !GIC_TEST_TRIGGER(irq + i)) {
                    DPRINTF("Set %d pending mask %x\n", irq + i, mask);
                    GIC_SET_PENDING(irq + i, mask);
                }
P
pbrook 已提交
501 502 503 504
            }
        }
    } else if (offset < 0x200) {
        /* Interrupt Clear Enable.  */
P
pbrook 已提交
505
        irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
506
        if (irq >= s->num_irq)
P
pbrook 已提交
507
            goto bad_reg;
P
pbrook 已提交
508 509
        if (irq < 16)
          value = 0;
P
pbrook 已提交
510 511
        for (i = 0; i < 8; i++) {
            if (value & (1 << i)) {
R
Rusty Russell 已提交
512
                int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
513 514

                if (GIC_TEST_ENABLED(irq + i, cm)) {
P
pbrook 已提交
515
                    DPRINTF("Disabled IRQ %d\n", irq + i);
516 517
                }
                GIC_CLEAR_ENABLED(irq + i, cm);
P
pbrook 已提交
518 519 520 521
            }
        }
    } else if (offset < 0x280) {
        /* Interrupt Set Pending.  */
P
pbrook 已提交
522
        irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
523
        if (irq >= s->num_irq)
P
pbrook 已提交
524
            goto bad_reg;
P
pbrook 已提交
525 526 527
        if (irq < 16)
          irq = 0;

P
pbrook 已提交
528 529
        for (i = 0; i < 8; i++) {
            if (value & (1 << i)) {
P
pbrook 已提交
530
                GIC_SET_PENDING(irq + i, GIC_TARGET(irq));
P
pbrook 已提交
531 532 533 534
            }
        }
    } else if (offset < 0x300) {
        /* Interrupt Clear Pending.  */
P
pbrook 已提交
535
        irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
536
        if (irq >= s->num_irq)
P
pbrook 已提交
537 538
            goto bad_reg;
        for (i = 0; i < 8; i++) {
P
pbrook 已提交
539 540 541
            /* ??? This currently clears the pending bit for all CPUs, even
               for per-CPU interrupts.  It's unclear whether this is the
               corect behavior.  */
P
pbrook 已提交
542
            if (value & (1 << i)) {
P
pbrook 已提交
543
                GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK);
P
pbrook 已提交
544 545 546 547 548 549 550
            }
        }
    } else if (offset < 0x400) {
        /* Interrupt Active.  */
        goto bad_reg;
    } else if (offset < 0x800) {
        /* Interrupt Priority.  */
P
pbrook 已提交
551
        irq = (offset - 0x400) + GIC_BASE_IRQ;
552
        if (irq >= s->num_irq)
P
pbrook 已提交
553
            goto bad_reg;
R
Rusty Russell 已提交
554
        if (irq < GIC_INTERNAL) {
P
pbrook 已提交
555 556
            s->priority1[irq][cpu] = value;
        } else {
R
Rusty Russell 已提交
557
            s->priority2[irq - GIC_INTERNAL] = value;
P
pbrook 已提交
558 559
        }
#ifndef NVIC
P
pbrook 已提交
560 561
    } else if (offset < 0xc00) {
        /* Interrupt CPU Target.  */
P
pbrook 已提交
562
        irq = (offset - 0x800) + GIC_BASE_IRQ;
563
        if (irq >= s->num_irq)
P
pbrook 已提交
564
            goto bad_reg;
P
pbrook 已提交
565 566
        if (irq < 29)
            value = 0;
R
Rusty Russell 已提交
567
        else if (irq < GIC_INTERNAL)
P
pbrook 已提交
568 569
            value = ALL_CPU_MASK;
        s->irq_target[irq] = value & ALL_CPU_MASK;
P
pbrook 已提交
570 571
    } else if (offset < 0xf00) {
        /* Interrupt Configuration.  */
P
pbrook 已提交
572
        irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
573
        if (irq >= s->num_irq)
P
pbrook 已提交
574
            goto bad_reg;
R
Rusty Russell 已提交
575
        if (irq < GIC_INTERNAL)
P
pbrook 已提交
576
            value |= 0xaa;
P
pbrook 已提交
577 578 579 580 581 582 583 584 585 586 587 588
        for (i = 0; i < 4; i++) {
            if (value & (1 << (i * 2))) {
                GIC_SET_MODEL(irq + i);
            } else {
                GIC_CLEAR_MODEL(irq + i);
            }
            if (value & (2 << (i * 2))) {
                GIC_SET_TRIGGER(irq + i);
            } else {
                GIC_CLEAR_TRIGGER(irq + i);
            }
        }
P
pbrook 已提交
589
#endif
P
pbrook 已提交
590
    } else {
P
pbrook 已提交
591
        /* 0xf00 is only handled for 32-bit writes.  */
P
pbrook 已提交
592 593 594 595 596
        goto bad_reg;
    }
    gic_update(s);
    return;
bad_reg:
P
Paul Brook 已提交
597
    hw_error("gic_dist_writeb: Bad offset %x\n", (int)offset);
P
pbrook 已提交
598 599
}

A
Anthony Liguori 已提交
600
static void gic_dist_writew(void *opaque, target_phys_addr_t offset,
P
pbrook 已提交
601 602 603 604 605 606
                            uint32_t value)
{
    gic_dist_writeb(opaque, offset, value & 0xff);
    gic_dist_writeb(opaque, offset + 1, value >> 8);
}

A
Anthony Liguori 已提交
607
static void gic_dist_writel(void *opaque, target_phys_addr_t offset,
P
pbrook 已提交
608 609
                            uint32_t value)
{
P
pbrook 已提交
610 611 612
    gic_state *s = (gic_state *)opaque;
#ifdef NVIC
    uint32_t addr;
613
    addr = offset;
P
pbrook 已提交
614
    if (addr < 0x100 || (addr > 0xd00 && addr != 0xf00)) {
P
Paul Brook 已提交
615
        nvic_writel(s, addr, value);
P
pbrook 已提交
616 617 618
        return;
    }
#endif
619
    if (offset == 0xf00) {
P
pbrook 已提交
620 621 622 623
        int cpu;
        int irq;
        int mask;

624
        cpu = gic_get_current_cpu(s);
P
pbrook 已提交
625 626 627 628 629 630
        irq = value & 0x3ff;
        switch ((value >> 24) & 3) {
        case 0:
            mask = (value >> 16) & ALL_CPU_MASK;
            break;
        case 1:
631
            mask = ALL_CPU_MASK ^ (1 << cpu);
P
pbrook 已提交
632 633
            break;
        case 2:
634
            mask = 1 << cpu;
P
pbrook 已提交
635 636 637 638 639 640 641 642 643 644
            break;
        default:
            DPRINTF("Bad Soft Int target filter\n");
            mask = ALL_CPU_MASK;
            break;
        }
        GIC_SET_PENDING(irq, mask);
        gic_update(s);
        return;
    }
P
pbrook 已提交
645 646 647 648
    gic_dist_writew(opaque, offset, value & 0xffff);
    gic_dist_writew(opaque, offset + 2, value >> 16);
}

A
Avi Kivity 已提交
649 650 651 652 653 654
static const MemoryRegionOps gic_dist_ops = {
    .old_mmio = {
        .read = { gic_dist_readb, gic_dist_readw, gic_dist_readl, },
        .write = { gic_dist_writeb, gic_dist_writew, gic_dist_writel, },
    },
    .endianness = DEVICE_NATIVE_ENDIAN,
P
pbrook 已提交
655 656
};

P
pbrook 已提交
657 658
#ifndef NVIC
static uint32_t gic_cpu_read(gic_state *s, int cpu, int offset)
P
pbrook 已提交
659 660 661
{
    switch (offset) {
    case 0x00: /* Control */
P
pbrook 已提交
662
        return s->cpu_enabled[cpu];
P
pbrook 已提交
663
    case 0x04: /* Priority mask */
P
pbrook 已提交
664
        return s->priority_mask[cpu];
P
pbrook 已提交
665 666 667 668
    case 0x08: /* Binary Point */
        /* ??? Not implemented.  */
        return 0;
    case 0x0c: /* Acknowledge */
P
pbrook 已提交
669
        return gic_acknowledge_irq(s, cpu);
D
Dong Xu Wang 已提交
670
    case 0x14: /* Running Priority */
P
pbrook 已提交
671
        return s->running_priority[cpu];
P
pbrook 已提交
672
    case 0x18: /* Highest Pending Interrupt */
P
pbrook 已提交
673
        return s->current_pending[cpu];
P
pbrook 已提交
674
    default:
P
Paul Brook 已提交
675
        hw_error("gic_cpu_read: Bad offset %x\n", (int)offset);
P
pbrook 已提交
676 677 678 679
        return 0;
    }
}

P
pbrook 已提交
680
static void gic_cpu_write(gic_state *s, int cpu, int offset, uint32_t value)
P
pbrook 已提交
681 682 683
{
    switch (offset) {
    case 0x00: /* Control */
P
pbrook 已提交
684
        s->cpu_enabled[cpu] = (value & 1);
P
Paul Brook 已提交
685
        DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled ? "En" : "Dis");
P
pbrook 已提交
686 687
        break;
    case 0x04: /* Priority mask */
P
pbrook 已提交
688
        s->priority_mask[cpu] = (value & 0xff);
P
pbrook 已提交
689 690 691 692 693
        break;
    case 0x08: /* Binary Point */
        /* ??? Not implemented.  */
        break;
    case 0x10: /* End Of Interrupt */
P
pbrook 已提交
694
        return gic_complete_irq(s, cpu, value & 0x3ff);
P
pbrook 已提交
695
    default:
P
Paul Brook 已提交
696
        hw_error("gic_cpu_write: Bad offset %x\n", (int)offset);
P
pbrook 已提交
697 698 699 700
        return;
    }
    gic_update(s);
}
701 702 703 704 705 706

/* Wrappers to read/write the GIC CPU interface for the current CPU */
static uint64_t gic_thiscpu_read(void *opaque, target_phys_addr_t addr,
                                 unsigned size)
{
    gic_state *s = (gic_state *)opaque;
707
    return gic_cpu_read(s, gic_get_current_cpu(s), addr);
708 709 710 711 712 713
}

static void gic_thiscpu_write(void *opaque, target_phys_addr_t addr,
                              uint64_t value, unsigned size)
{
    gic_state *s = (gic_state *)opaque;
714
    gic_cpu_write(s, gic_get_current_cpu(s), addr, value);
715 716 717 718 719 720 721 722 723 724 725
}

/* Wrappers to read/write the GIC CPU interface for a specific CPU.
 * These just decode the opaque pointer into gic_state* + cpu id.
 */
static uint64_t gic_do_cpu_read(void *opaque, target_phys_addr_t addr,
                                unsigned size)
{
    gic_state **backref = (gic_state **)opaque;
    gic_state *s = *backref;
    int id = (backref - s->backref);
726
    return gic_cpu_read(s, id, addr);
727 728 729 730 731 732 733 734
}

static void gic_do_cpu_write(void *opaque, target_phys_addr_t addr,
                             uint64_t value, unsigned size)
{
    gic_state **backref = (gic_state **)opaque;
    gic_state *s = *backref;
    int id = (backref - s->backref);
735
    gic_cpu_write(s, id, addr, value);
736 737 738 739 740 741 742 743 744 745 746 747 748
}

static const MemoryRegionOps gic_thiscpu_ops = {
    .read = gic_thiscpu_read,
    .write = gic_thiscpu_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
};

static const MemoryRegionOps gic_cpu_ops = {
    .read = gic_do_cpu_read,
    .write = gic_do_cpu_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
};
P
pbrook 已提交
749
#endif
P
pbrook 已提交
750

751
static void gic_reset(DeviceState *dev)
P
pbrook 已提交
752
{
753
    gic_state *s = FROM_SYSBUS(gic_state, sysbus_from_qdev(dev));
P
pbrook 已提交
754
    int i;
755
    memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
P
Paul Brook 已提交
756
    for (i = 0 ; i < NUM_CPU(s); i++) {
P
pbrook 已提交
757 758 759 760 761 762 763 764 765 766 767
        s->priority_mask[i] = 0xf0;
        s->current_pending[i] = 1023;
        s->running_irq[i] = 1023;
        s->running_priority[i] = 0x100;
#ifdef NVIC
        /* The NVIC doesn't have per-cpu interfaces, so enable by default.  */
        s->cpu_enabled[i] = 1;
#else
        s->cpu_enabled[i] = 0;
#endif
    }
P
pbrook 已提交
768
    for (i = 0; i < 16; i++) {
769
        GIC_SET_ENABLED(i, ALL_CPU_MASK);
P
pbrook 已提交
770 771
        GIC_SET_TRIGGER(i);
    }
P
pbrook 已提交
772 773 774 775
#ifdef NVIC
    /* The NVIC is always enabled.  */
    s->enabled = 1;
#else
P
pbrook 已提交
776
    s->enabled = 0;
P
pbrook 已提交
777
#endif
P
pbrook 已提交
778 779
}

P
pbrook 已提交
780 781 782 783 784 785 786
static void gic_save(QEMUFile *f, void *opaque)
{
    gic_state *s = (gic_state *)opaque;
    int i;
    int j;

    qemu_put_be32(f, s->enabled);
P
Paul Brook 已提交
787
    for (i = 0; i < NUM_CPU(s); i++) {
P
pbrook 已提交
788
        qemu_put_be32(f, s->cpu_enabled[i]);
R
Rusty Russell 已提交
789
        for (j = 0; j < GIC_INTERNAL; j++)
P
pbrook 已提交
790
            qemu_put_be32(f, s->priority1[j][i]);
791
        for (j = 0; j < s->num_irq; j++)
P
pbrook 已提交
792 793 794 795 796 797
            qemu_put_be32(f, s->last_active[j][i]);
        qemu_put_be32(f, s->priority_mask[i]);
        qemu_put_be32(f, s->running_irq[i]);
        qemu_put_be32(f, s->running_priority[i]);
        qemu_put_be32(f, s->current_pending[i]);
    }
R
Rusty Russell 已提交
798
    for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) {
P
pbrook 已提交
799 800
        qemu_put_be32(f, s->priority2[i]);
    }
801
    for (i = 0; i < s->num_irq; i++) {
802 803 804
#ifndef NVIC
        qemu_put_be32(f, s->irq_target[i]);
#endif
P
pbrook 已提交
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819
        qemu_put_byte(f, s->irq_state[i].enabled);
        qemu_put_byte(f, s->irq_state[i].pending);
        qemu_put_byte(f, s->irq_state[i].active);
        qemu_put_byte(f, s->irq_state[i].level);
        qemu_put_byte(f, s->irq_state[i].model);
        qemu_put_byte(f, s->irq_state[i].trigger);
    }
}

static int gic_load(QEMUFile *f, void *opaque, int version_id)
{
    gic_state *s = (gic_state *)opaque;
    int i;
    int j;

820
    if (version_id != 2)
P
pbrook 已提交
821 822 823
        return -EINVAL;

    s->enabled = qemu_get_be32(f);
P
Paul Brook 已提交
824
    for (i = 0; i < NUM_CPU(s); i++) {
P
pbrook 已提交
825
        s->cpu_enabled[i] = qemu_get_be32(f);
R
Rusty Russell 已提交
826
        for (j = 0; j < GIC_INTERNAL; j++)
P
pbrook 已提交
827
            s->priority1[j][i] = qemu_get_be32(f);
828
        for (j = 0; j < s->num_irq; j++)
P
pbrook 已提交
829 830 831 832 833 834
            s->last_active[j][i] = qemu_get_be32(f);
        s->priority_mask[i] = qemu_get_be32(f);
        s->running_irq[i] = qemu_get_be32(f);
        s->running_priority[i] = qemu_get_be32(f);
        s->current_pending[i] = qemu_get_be32(f);
    }
R
Rusty Russell 已提交
835
    for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) {
P
pbrook 已提交
836 837
        s->priority2[i] = qemu_get_be32(f);
    }
838
    for (i = 0; i < s->num_irq; i++) {
839 840 841
#ifndef NVIC
        s->irq_target[i] = qemu_get_be32(f);
#endif
P
pbrook 已提交
842 843 844 845 846 847 848 849 850 851 852
        s->irq_state[i].enabled = qemu_get_byte(f);
        s->irq_state[i].pending = qemu_get_byte(f);
        s->irq_state[i].active = qemu_get_byte(f);
        s->irq_state[i].level = qemu_get_byte(f);
        s->irq_state[i].model = qemu_get_byte(f);
        s->irq_state[i].trigger = qemu_get_byte(f);
    }

    return 0;
}

P
Paul Brook 已提交
853
#if NCPU > 1
854
static void gic_init(gic_state *s, int num_cpu, int num_irq)
P
Paul Brook 已提交
855
#else
856
static void gic_init(gic_state *s, int num_irq)
P
Paul Brook 已提交
857
#endif
P
pbrook 已提交
858
{
P
pbrook 已提交
859
    int i;
P
pbrook 已提交
860

P
Paul Brook 已提交
861 862
#if NCPU > 1
    s->num_cpu = num_cpu;
863 864 865 866
    if (s->num_cpu > NCPU) {
        hw_error("requested %u CPUs exceeds GIC maximum %d\n",
                 num_cpu, NCPU);
    }
P
Paul Brook 已提交
867
#endif
868 869 870 871 872
    s->num_irq = num_irq + GIC_BASE_IRQ;
    if (s->num_irq > GIC_MAXIRQ) {
        hw_error("requested %u interrupt lines exceeds GIC maximum %d\n",
                 num_irq, GIC_MAXIRQ);
    }
873 874 875 876 877 878 879 880 881
    /* ITLinesNumber is represented as (N / 32) - 1 (see
     * gic_dist_readb) so this is an implementation imposed
     * restriction, not an architectural one:
     */
    if (s->num_irq < 32 || (s->num_irq % 32)) {
        hw_error("%d interrupt lines unsupported: not divisible by 32\n",
                 num_irq);
    }

882 883 884 885 886 887 888 889 890 891 892 893
    i = s->num_irq - GIC_INTERNAL;
#ifndef NVIC
    /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
     * GPIO array layout is thus:
     *  [0..N-1] SPIs
     *  [N..N+31] PPIs for CPU 0
     *  [N+32..N+63] PPIs for CPU 1
     *   ...
     */
    i += (GIC_INTERNAL * num_cpu);
#endif
    qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, i);
P
Paul Brook 已提交
894
    for (i = 0; i < NUM_CPU(s); i++) {
P
Paul Brook 已提交
895
        sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
P
pbrook 已提交
896
    }
A
Avi Kivity 已提交
897
    memory_region_init_io(&s->iomem, &gic_dist_ops, s, "gic_dist", 0x1000);
898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915
#ifndef NVIC
    /* Memory regions for the CPU interfaces (NVIC doesn't have these):
     * a region for "CPU interface for this core", then a region for
     * "CPU interface for core 0", "for core 1", ...
     * NB that the memory region size of 0x100 applies for the 11MPCore
     * and also cores following the GIC v1 spec (ie A9).
     * GIC v2 defines a larger memory region (0x1000) so this will need
     * to be extended when we implement A15.
     */
    memory_region_init_io(&s->cpuiomem[0], &gic_thiscpu_ops, s,
                          "gic_cpu", 0x100);
    for (i = 0; i < NUM_CPU(s); i++) {
        s->backref[i] = s;
        memory_region_init_io(&s->cpuiomem[i+1], &gic_cpu_ops, &s->backref[i],
                              "gic_cpu", 0x100);
    }
#endif

916
    register_savevm(NULL, "arm_gic", -1, 2, gic_save, gic_load, s);
P
pbrook 已提交
917
}
918

919
#ifndef NVIC
920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947

static int arm_gic_init(SysBusDevice *dev)
{
    /* Device instance init function for the GIC sysbus device */
    int i;
    gic_state *s = FROM_SYSBUS(gic_state, dev);
    gic_init(s, s->num_cpu, s->num_irq);
    /* Distributor */
    sysbus_init_mmio(dev, &s->iomem);
    /* cpu interfaces (one for "current cpu" plus one per cpu) */
    for (i = 0; i <= NUM_CPU(s); i++) {
        sysbus_init_mmio(dev, &s->cpuiomem[i]);
    }
    return 0;
}

static Property arm_gic_properties[] = {
    DEFINE_PROP_UINT32("num-cpu", gic_state, num_cpu, 1),
    DEFINE_PROP_UINT32("num-irq", gic_state, num_irq, 32),
    DEFINE_PROP_END_OF_LIST(),
};

static void arm_gic_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
    sbc->init = arm_gic_init;
    dc->props = arm_gic_properties;
948
    dc->reset = gic_reset;
949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966
    dc->no_user = 1;
}

static TypeInfo arm_gic_info = {
    .name = "arm_gic",
    .parent = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(gic_state),
    .class_init = arm_gic_class_init,
};

static void arm_gic_register_types(void)
{
    type_register_static(&arm_gic_info);
}

type_init(arm_gic_register_types)

#endif