Annotation of qemu/hw/arm_gic.c, revision 1.1.1.9

1.1.1.2   root        1: /*
                      2:  * ARM Generic/Distributed Interrupt Controller
1.1       root        3:  *
1.1.1.2   root        4:  * Copyright (c) 2006-2007 CodeSourcery.
1.1       root        5:  * Written by Paul Brook
                      6:  *
1.1.1.8   root        7:  * This code is licensed under the GPL.
1.1       root        8:  */
                      9: 
1.1.1.2   root       10: /* This file contains implementation code for the RealView EB interrupt
                     11:    controller, MPCore distributed interrupt controller and ARMv7-M
                     12:    Nested Vectored Interrupt Controller.  */
1.1       root       13: 
                     14: //#define DEBUG_GIC
                     15: 
                     16: #ifdef DEBUG_GIC
1.1.1.4   root       17: #define DPRINTF(fmt, ...) \
                     18: do { printf("arm_gic: " fmt , ## __VA_ARGS__); } while (0)
1.1       root       19: #else
1.1.1.4   root       20: #define DPRINTF(fmt, ...) do {} while(0)
1.1       root       21: #endif
                     22: 
1.1.1.2   root       23: #ifdef NVIC
                     24: static const uint8_t gic_id[] =
                     25: { 0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1 };
                     26: /* The NVIC has 16 internal vectors.  However these are not exposed
                     27:    through the normal GIC interface.  */
                     28: #define GIC_BASE_IRQ    32
                     29: #else
1.1       root       30: static const uint8_t gic_id[] =
                     31: { 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
1.1.1.2   root       32: #define GIC_BASE_IRQ    0
                     33: #endif
1.1       root       34: 
1.1.1.4   root       35: #define FROM_SYSBUSGIC(type, dev) \
                     36:     DO_UPCAST(type, gic, FROM_SYSBUS(gic_state, dev))
                     37: 
1.1       root       38: typedef struct gic_irq_state
                     39: {
1.1.1.9 ! root       40:     /* The enable bits are only banked for per-cpu interrupts.  */
        !            41:     unsigned enabled:NCPU;
1.1.1.2   root       42:     unsigned pending:NCPU;
                     43:     unsigned active:NCPU;
1.1.1.4   root       44:     unsigned level:NCPU;
1.1.1.2   root       45:     unsigned model:1; /* 0 = N:N, 1 = 1:N */
1.1       root       46:     unsigned trigger:1; /* nonzero = edge triggered.  */
                     47: } gic_irq_state;
                     48: 
1.1.1.2   root       49: #define ALL_CPU_MASK ((1 << NCPU) - 1)
1.1.1.5   root       50: #if NCPU > 1
                     51: #define NUM_CPU(s) ((s)->num_cpu)
                     52: #else
                     53: #define NUM_CPU(s) 1
                     54: #endif
1.1.1.2   root       55: 
1.1.1.9 ! root       56: #define GIC_SET_ENABLED(irq, cm) s->irq_state[irq].enabled |= (cm)
        !            57: #define GIC_CLEAR_ENABLED(irq, cm) s->irq_state[irq].enabled &= ~(cm)
        !            58: #define GIC_TEST_ENABLED(irq, cm) ((s->irq_state[irq].enabled & (cm)) != 0)
1.1.1.2   root       59: #define GIC_SET_PENDING(irq, cm) s->irq_state[irq].pending |= (cm)
                     60: #define GIC_CLEAR_PENDING(irq, cm) s->irq_state[irq].pending &= ~(cm)
                     61: #define GIC_TEST_PENDING(irq, cm) ((s->irq_state[irq].pending & (cm)) != 0)
                     62: #define GIC_SET_ACTIVE(irq, cm) s->irq_state[irq].active |= (cm)
                     63: #define GIC_CLEAR_ACTIVE(irq, cm) s->irq_state[irq].active &= ~(cm)
                     64: #define GIC_TEST_ACTIVE(irq, cm) ((s->irq_state[irq].active & (cm)) != 0)
1.1       root       65: #define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1
                     66: #define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0
                     67: #define GIC_TEST_MODEL(irq) s->irq_state[irq].model
1.1.1.2   root       68: #define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm)
                     69: #define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm)
1.1.1.3   root       70: #define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0)
1.1       root       71: #define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1
                     72: #define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0
                     73: #define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger
1.1.1.2   root       74: #define GIC_GET_PRIORITY(irq, cpu) \
                     75:   (((irq) < 32) ? s->priority1[irq][cpu] : s->priority2[(irq) - 32])
                     76: #ifdef NVIC
                     77: #define GIC_TARGET(irq) 1
                     78: #else
                     79: #define GIC_TARGET(irq) s->irq_target[irq]
                     80: #endif
1.1       root       81: 
                     82: typedef struct gic_state
                     83: {
1.1.1.4   root       84:     SysBusDevice busdev;
1.1.1.2   root       85:     qemu_irq parent_irq[NCPU];
1.1       root       86:     int enabled;
1.1.1.2   root       87:     int cpu_enabled[NCPU];
1.1       root       88: 
                     89:     gic_irq_state irq_state[GIC_NIRQ];
1.1.1.2   root       90: #ifndef NVIC
1.1       root       91:     int irq_target[GIC_NIRQ];
1.1.1.2   root       92: #endif
                     93:     int priority1[32][NCPU];
                     94:     int priority2[GIC_NIRQ - 32];
                     95:     int last_active[GIC_NIRQ][NCPU];
                     96: 
                     97:     int priority_mask[NCPU];
                     98:     int running_irq[NCPU];
                     99:     int running_priority[NCPU];
                    100:     int current_pending[NCPU];
                    101: 
1.1.1.5   root      102: #if NCPU > 1
                    103:     int num_cpu;
                    104: #endif
                    105: 
1.1.1.9 ! root      106:     MemoryRegion iomem;
1.1       root      107: } gic_state;
                    108: 
                    109: /* TODO: Many places that call this routine could be optimized.  */
                    110: /* Update interrupt status after enabled or pending bits have been changed.  */
                    111: static void gic_update(gic_state *s)
                    112: {
                    113:     int best_irq;
                    114:     int best_prio;
                    115:     int irq;
1.1.1.2   root      116:     int level;
                    117:     int cpu;
                    118:     int cm;
1.1       root      119: 
1.1.1.5   root      120:     for (cpu = 0; cpu < NUM_CPU(s); cpu++) {
1.1.1.2   root      121:         cm = 1 << cpu;
                    122:         s->current_pending[cpu] = 1023;
                    123:         if (!s->enabled || !s->cpu_enabled[cpu]) {
                    124:            qemu_irq_lower(s->parent_irq[cpu]);
                    125:             return;
                    126:         }
                    127:         best_prio = 0x100;
                    128:         best_irq = 1023;
                    129:         for (irq = 0; irq < GIC_NIRQ; irq++) {
1.1.1.9 ! root      130:             if (GIC_TEST_ENABLED(irq, cm) && GIC_TEST_PENDING(irq, cm)) {
1.1.1.2   root      131:                 if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
                    132:                     best_prio = GIC_GET_PRIORITY(irq, cpu);
                    133:                     best_irq = irq;
                    134:                 }
1.1       root      135:             }
                    136:         }
1.1.1.2   root      137:         level = 0;
                    138:         if (best_prio <= s->priority_mask[cpu]) {
                    139:             s->current_pending[cpu] = best_irq;
                    140:             if (best_prio < s->running_priority[cpu]) {
                    141:                 DPRINTF("Raised pending IRQ %d\n", best_irq);
                    142:                 level = 1;
                    143:             }
1.1       root      144:         }
1.1.1.2   root      145:         qemu_set_irq(s->parent_irq[cpu], level);
1.1       root      146:     }
                    147: }
                    148: 
1.1.1.2   root      149: static void __attribute__((unused))
                    150: gic_set_pending_private(gic_state *s, int cpu, int irq)
                    151: {
                    152:     int cm = 1 << cpu;
                    153: 
                    154:     if (GIC_TEST_PENDING(irq, cm))
                    155:         return;
                    156: 
                    157:     DPRINTF("Set %d pending cpu %d\n", irq, cpu);
                    158:     GIC_SET_PENDING(irq, cm);
                    159:     gic_update(s);
                    160: }
                    161: 
                    162: /* Process a change in an external IRQ input.  */
1.1       root      163: static void gic_set_irq(void *opaque, int irq, int level)
                    164: {
                    165:     gic_state *s = (gic_state *)opaque;
                    166:     /* The first external input line is internal interrupt 32.  */
                    167:     irq += 32;
1.1.1.2   root      168:     if (level == GIC_TEST_LEVEL(irq, ALL_CPU_MASK))
1.1       root      169:         return;
                    170: 
                    171:     if (level) {
1.1.1.2   root      172:         GIC_SET_LEVEL(irq, ALL_CPU_MASK);
1.1.1.9 ! root      173:         if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq, ALL_CPU_MASK)) {
1.1.1.2   root      174:             DPRINTF("Set %d pending mask %x\n", irq, GIC_TARGET(irq));
                    175:             GIC_SET_PENDING(irq, GIC_TARGET(irq));
1.1       root      176:         }
                    177:     } else {
1.1.1.2   root      178:         GIC_CLEAR_LEVEL(irq, ALL_CPU_MASK);
1.1       root      179:     }
                    180:     gic_update(s);
                    181: }
                    182: 
1.1.1.2   root      183: static void gic_set_running_irq(gic_state *s, int cpu, int irq)
1.1       root      184: {
1.1.1.2   root      185:     s->running_irq[cpu] = irq;
                    186:     if (irq == 1023) {
                    187:         s->running_priority[cpu] = 0x100;
                    188:     } else {
                    189:         s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu);
                    190:     }
1.1       root      191:     gic_update(s);
                    192: }
                    193: 
1.1.1.2   root      194: static uint32_t gic_acknowledge_irq(gic_state *s, int cpu)
1.1       root      195: {
                    196:     int new_irq;
1.1.1.2   root      197:     int cm = 1 << cpu;
                    198:     new_irq = s->current_pending[cpu];
                    199:     if (new_irq == 1023
                    200:             || GIC_GET_PRIORITY(new_irq, cpu) >= s->running_priority[cpu]) {
1.1       root      201:         DPRINTF("ACK no pending IRQ\n");
                    202:         return 1023;
                    203:     }
1.1.1.2   root      204:     s->last_active[new_irq][cpu] = s->running_irq[cpu];
                    205:     /* Clear pending flags for both level and edge triggered interrupts.
                    206:        Level triggered IRQs will be reasserted once they become inactive.  */
                    207:     GIC_CLEAR_PENDING(new_irq, GIC_TEST_MODEL(new_irq) ? ALL_CPU_MASK : cm);
                    208:     gic_set_running_irq(s, cpu, new_irq);
1.1       root      209:     DPRINTF("ACK %d\n", new_irq);
                    210:     return new_irq;
                    211: }
                    212: 
1.1.1.2   root      213: static void gic_complete_irq(gic_state * s, int cpu, int irq)
1.1       root      214: {
                    215:     int update = 0;
1.1.1.2   root      216:     int cm = 1 << cpu;
1.1       root      217:     DPRINTF("EOI %d\n", irq);
1.1.1.2   root      218:     if (s->running_irq[cpu] == 1023)
1.1       root      219:         return; /* No active IRQ.  */
                    220:     if (irq != 1023) {
                    221:         /* Mark level triggered interrupts as pending if they are still
                    222:            raised.  */
1.1.1.9 ! root      223:         if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm)
1.1.1.2   root      224:                 && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
                    225:             DPRINTF("Set %d pending mask %x\n", irq, cm);
                    226:             GIC_SET_PENDING(irq, cm);
1.1       root      227:             update = 1;
                    228:         }
                    229:     }
1.1.1.2   root      230:     if (irq != s->running_irq[cpu]) {
1.1       root      231:         /* Complete an IRQ that is not currently running.  */
1.1.1.2   root      232:         int tmp = s->running_irq[cpu];
                    233:         while (s->last_active[tmp][cpu] != 1023) {
                    234:             if (s->last_active[tmp][cpu] == irq) {
                    235:                 s->last_active[tmp][cpu] = s->last_active[irq][cpu];
1.1       root      236:                 break;
                    237:             }
1.1.1.2   root      238:             tmp = s->last_active[tmp][cpu];
1.1       root      239:         }
                    240:         if (update) {
                    241:             gic_update(s);
                    242:         }
                    243:     } else {
                    244:         /* Complete the current running IRQ.  */
1.1.1.2   root      245:         gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]);
1.1       root      246:     }
                    247: }
                    248: 
                    249: static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
                    250: {
                    251:     gic_state *s = (gic_state *)opaque;
                    252:     uint32_t res;
                    253:     int irq;
                    254:     int i;
1.1.1.2   root      255:     int cpu;
                    256:     int cm;
                    257:     int mask;
                    258: 
                    259:     cpu = gic_get_current_cpu();
                    260:     cm = 1 << cpu;
1.1       root      261:     if (offset < 0x100) {
1.1.1.2   root      262: #ifndef NVIC
1.1       root      263:         if (offset == 0)
                    264:             return s->enabled;
                    265:         if (offset == 4)
1.1.1.5   root      266:             return ((GIC_NIRQ / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
1.1       root      267:         if (offset < 0x08)
                    268:             return 0;
1.1.1.2   root      269: #endif
1.1       root      270:         goto bad_reg;
                    271:     } else if (offset < 0x200) {
                    272:         /* Interrupt Set/Clear Enable.  */
                    273:         if (offset < 0x180)
                    274:             irq = (offset - 0x100) * 8;
                    275:         else
                    276:             irq = (offset - 0x180) * 8;
1.1.1.2   root      277:         irq += GIC_BASE_IRQ;
1.1       root      278:         if (irq >= GIC_NIRQ)
                    279:             goto bad_reg;
                    280:         res = 0;
                    281:         for (i = 0; i < 8; i++) {
1.1.1.9 ! root      282:             if (GIC_TEST_ENABLED(irq + i, cm)) {
1.1       root      283:                 res |= (1 << i);
                    284:             }
                    285:         }
                    286:     } else if (offset < 0x300) {
                    287:         /* Interrupt Set/Clear Pending.  */
                    288:         if (offset < 0x280)
                    289:             irq = (offset - 0x200) * 8;
                    290:         else
                    291:             irq = (offset - 0x280) * 8;
1.1.1.2   root      292:         irq += GIC_BASE_IRQ;
1.1       root      293:         if (irq >= GIC_NIRQ)
                    294:             goto bad_reg;
                    295:         res = 0;
1.1.1.2   root      296:         mask = (irq < 32) ?  cm : ALL_CPU_MASK;
1.1       root      297:         for (i = 0; i < 8; i++) {
1.1.1.2   root      298:             if (GIC_TEST_PENDING(irq + i, mask)) {
1.1       root      299:                 res |= (1 << i);
                    300:             }
                    301:         }
                    302:     } else if (offset < 0x400) {
                    303:         /* Interrupt Active.  */
1.1.1.2   root      304:         irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
1.1       root      305:         if (irq >= GIC_NIRQ)
                    306:             goto bad_reg;
                    307:         res = 0;
1.1.1.2   root      308:         mask = (irq < 32) ?  cm : ALL_CPU_MASK;
1.1       root      309:         for (i = 0; i < 8; i++) {
1.1.1.2   root      310:             if (GIC_TEST_ACTIVE(irq + i, mask)) {
1.1       root      311:                 res |= (1 << i);
                    312:             }
                    313:         }
                    314:     } else if (offset < 0x800) {
                    315:         /* Interrupt Priority.  */
1.1.1.2   root      316:         irq = (offset - 0x400) + GIC_BASE_IRQ;
1.1       root      317:         if (irq >= GIC_NIRQ)
                    318:             goto bad_reg;
1.1.1.2   root      319:         res = GIC_GET_PRIORITY(irq, cpu);
                    320: #ifndef NVIC
1.1       root      321:     } else if (offset < 0xc00) {
                    322:         /* Interrupt CPU Target.  */
1.1.1.2   root      323:         irq = (offset - 0x800) + GIC_BASE_IRQ;
1.1       root      324:         if (irq >= GIC_NIRQ)
                    325:             goto bad_reg;
1.1.1.2   root      326:         if (irq >= 29 && irq <= 31) {
                    327:             res = cm;
                    328:         } else {
                    329:             res = GIC_TARGET(irq);
                    330:         }
1.1       root      331:     } else if (offset < 0xf00) {
                    332:         /* Interrupt Configuration.  */
1.1.1.2   root      333:         irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ;
1.1       root      334:         if (irq >= GIC_NIRQ)
                    335:             goto bad_reg;
                    336:         res = 0;
                    337:         for (i = 0; i < 4; i++) {
                    338:             if (GIC_TEST_MODEL(irq + i))
                    339:                 res |= (1 << (i * 2));
                    340:             if (GIC_TEST_TRIGGER(irq + i))
                    341:                 res |= (2 << (i * 2));
                    342:         }
1.1.1.2   root      343: #endif
1.1       root      344:     } else if (offset < 0xfe0) {
                    345:         goto bad_reg;
                    346:     } else /* offset >= 0xfe0 */ {
                    347:         if (offset & 3) {
                    348:             res = 0;
                    349:         } else {
                    350:             res = gic_id[(offset - 0xfe0) >> 2];
                    351:         }
                    352:     }
                    353:     return res;
                    354: bad_reg:
1.1.1.4   root      355:     hw_error("gic_dist_readb: Bad offset %x\n", (int)offset);
1.1       root      356:     return 0;
                    357: }
                    358: 
                    359: static uint32_t gic_dist_readw(void *opaque, target_phys_addr_t offset)
                    360: {
                    361:     uint32_t val;
                    362:     val = gic_dist_readb(opaque, offset);
                    363:     val |= gic_dist_readb(opaque, offset + 1) << 8;
                    364:     return val;
                    365: }
                    366: 
                    367: static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset)
                    368: {
                    369:     uint32_t val;
1.1.1.2   root      370: #ifdef NVIC
                    371:     gic_state *s = (gic_state *)opaque;
                    372:     uint32_t addr;
1.1.1.3   root      373:     addr = offset;
1.1.1.2   root      374:     if (addr < 0x100 || addr > 0xd00)
1.1.1.4   root      375:         return nvic_readl(s, addr);
1.1.1.2   root      376: #endif
1.1       root      377:     val = gic_dist_readw(opaque, offset);
                    378:     val |= gic_dist_readw(opaque, offset + 2) << 16;
                    379:     return val;
                    380: }
                    381: 
                    382: static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
                    383:                             uint32_t value)
                    384: {
                    385:     gic_state *s = (gic_state *)opaque;
                    386:     int irq;
                    387:     int i;
1.1.1.2   root      388:     int cpu;
1.1       root      389: 
1.1.1.2   root      390:     cpu = gic_get_current_cpu();
1.1       root      391:     if (offset < 0x100) {
1.1.1.2   root      392: #ifdef NVIC
                    393:         goto bad_reg;
                    394: #else
1.1       root      395:         if (offset == 0) {
                    396:             s->enabled = (value & 1);
                    397:             DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
                    398:         } else if (offset < 4) {
                    399:             /* ignored.  */
                    400:         } else {
                    401:             goto bad_reg;
                    402:         }
1.1.1.2   root      403: #endif
1.1       root      404:     } else if (offset < 0x180) {
                    405:         /* Interrupt Set Enable.  */
1.1.1.2   root      406:         irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
1.1       root      407:         if (irq >= GIC_NIRQ)
                    408:             goto bad_reg;
1.1.1.2   root      409:         if (irq < 16)
                    410:           value = 0xff;
1.1       root      411:         for (i = 0; i < 8; i++) {
                    412:             if (value & (1 << i)) {
1.1.1.2   root      413:                 int mask = (irq < 32) ? (1 << cpu) : GIC_TARGET(irq);
1.1.1.9 ! root      414:                 int cm = (irq < 32) ? (1 << cpu) : ALL_CPU_MASK;
        !           415: 
        !           416:                 if (!GIC_TEST_ENABLED(irq + i, cm)) {
1.1       root      417:                     DPRINTF("Enabled IRQ %d\n", irq + i);
1.1.1.9 ! root      418:                 }
        !           419:                 GIC_SET_ENABLED(irq + i, cm);
1.1       root      420:                 /* If a raised level triggered IRQ enabled then mark
                    421:                    is as pending.  */
1.1.1.2   root      422:                 if (GIC_TEST_LEVEL(irq + i, mask)
                    423:                         && !GIC_TEST_TRIGGER(irq + i)) {
                    424:                     DPRINTF("Set %d pending mask %x\n", irq + i, mask);
                    425:                     GIC_SET_PENDING(irq + i, mask);
                    426:                 }
1.1       root      427:             }
                    428:         }
                    429:     } else if (offset < 0x200) {
                    430:         /* Interrupt Clear Enable.  */
1.1.1.2   root      431:         irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
1.1       root      432:         if (irq >= GIC_NIRQ)
                    433:             goto bad_reg;
1.1.1.2   root      434:         if (irq < 16)
                    435:           value = 0;
1.1       root      436:         for (i = 0; i < 8; i++) {
                    437:             if (value & (1 << i)) {
1.1.1.9 ! root      438:                 int cm = (irq < 32) ? (1 << cpu) : ALL_CPU_MASK;
        !           439: 
        !           440:                 if (GIC_TEST_ENABLED(irq + i, cm)) {
1.1       root      441:                     DPRINTF("Disabled IRQ %d\n", irq + i);
1.1.1.9 ! root      442:                 }
        !           443:                 GIC_CLEAR_ENABLED(irq + i, cm);
1.1       root      444:             }
                    445:         }
                    446:     } else if (offset < 0x280) {
                    447:         /* Interrupt Set Pending.  */
1.1.1.2   root      448:         irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
1.1       root      449:         if (irq >= GIC_NIRQ)
                    450:             goto bad_reg;
1.1.1.2   root      451:         if (irq < 16)
                    452:           irq = 0;
                    453: 
1.1       root      454:         for (i = 0; i < 8; i++) {
                    455:             if (value & (1 << i)) {
1.1.1.2   root      456:                 GIC_SET_PENDING(irq + i, GIC_TARGET(irq));
1.1       root      457:             }
                    458:         }
                    459:     } else if (offset < 0x300) {
                    460:         /* Interrupt Clear Pending.  */
1.1.1.2   root      461:         irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
1.1       root      462:         if (irq >= GIC_NIRQ)
                    463:             goto bad_reg;
                    464:         for (i = 0; i < 8; i++) {
1.1.1.2   root      465:             /* ??? This currently clears the pending bit for all CPUs, even
                    466:                for per-CPU interrupts.  It's unclear whether this is the
                    467:                corect behavior.  */
1.1       root      468:             if (value & (1 << i)) {
1.1.1.2   root      469:                 GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK);
1.1       root      470:             }
                    471:         }
                    472:     } else if (offset < 0x400) {
                    473:         /* Interrupt Active.  */
                    474:         goto bad_reg;
                    475:     } else if (offset < 0x800) {
                    476:         /* Interrupt Priority.  */
1.1.1.2   root      477:         irq = (offset - 0x400) + GIC_BASE_IRQ;
1.1       root      478:         if (irq >= GIC_NIRQ)
                    479:             goto bad_reg;
1.1.1.2   root      480:         if (irq < 32) {
                    481:             s->priority1[irq][cpu] = value;
                    482:         } else {
                    483:             s->priority2[irq - 32] = value;
                    484:         }
                    485: #ifndef NVIC
1.1       root      486:     } else if (offset < 0xc00) {
                    487:         /* Interrupt CPU Target.  */
1.1.1.2   root      488:         irq = (offset - 0x800) + GIC_BASE_IRQ;
1.1       root      489:         if (irq >= GIC_NIRQ)
                    490:             goto bad_reg;
1.1.1.2   root      491:         if (irq < 29)
                    492:             value = 0;
                    493:         else if (irq < 32)
                    494:             value = ALL_CPU_MASK;
                    495:         s->irq_target[irq] = value & ALL_CPU_MASK;
1.1       root      496:     } else if (offset < 0xf00) {
                    497:         /* Interrupt Configuration.  */
1.1.1.2   root      498:         irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
1.1       root      499:         if (irq >= GIC_NIRQ)
                    500:             goto bad_reg;
1.1.1.2   root      501:         if (irq < 32)
                    502:             value |= 0xaa;
1.1       root      503:         for (i = 0; i < 4; i++) {
                    504:             if (value & (1 << (i * 2))) {
                    505:                 GIC_SET_MODEL(irq + i);
                    506:             } else {
                    507:                 GIC_CLEAR_MODEL(irq + i);
                    508:             }
                    509:             if (value & (2 << (i * 2))) {
                    510:                 GIC_SET_TRIGGER(irq + i);
                    511:             } else {
                    512:                 GIC_CLEAR_TRIGGER(irq + i);
                    513:             }
                    514:         }
1.1.1.2   root      515: #endif
1.1       root      516:     } else {
1.1.1.2   root      517:         /* 0xf00 is only handled for 32-bit writes.  */
1.1       root      518:         goto bad_reg;
                    519:     }
                    520:     gic_update(s);
                    521:     return;
                    522: bad_reg:
1.1.1.4   root      523:     hw_error("gic_dist_writeb: Bad offset %x\n", (int)offset);
1.1       root      524: }
                    525: 
                    526: static void gic_dist_writew(void *opaque, target_phys_addr_t offset,
                    527:                             uint32_t value)
                    528: {
                    529:     gic_dist_writeb(opaque, offset, value & 0xff);
                    530:     gic_dist_writeb(opaque, offset + 1, value >> 8);
                    531: }
                    532: 
                    533: static void gic_dist_writel(void *opaque, target_phys_addr_t offset,
                    534:                             uint32_t value)
                    535: {
1.1.1.2   root      536:     gic_state *s = (gic_state *)opaque;
                    537: #ifdef NVIC
                    538:     uint32_t addr;
1.1.1.3   root      539:     addr = offset;
1.1.1.2   root      540:     if (addr < 0x100 || (addr > 0xd00 && addr != 0xf00)) {
1.1.1.4   root      541:         nvic_writel(s, addr, value);
1.1.1.2   root      542:         return;
                    543:     }
                    544: #endif
1.1.1.3   root      545:     if (offset == 0xf00) {
1.1.1.2   root      546:         int cpu;
                    547:         int irq;
                    548:         int mask;
                    549: 
                    550:         cpu = gic_get_current_cpu();
                    551:         irq = value & 0x3ff;
                    552:         switch ((value >> 24) & 3) {
                    553:         case 0:
                    554:             mask = (value >> 16) & ALL_CPU_MASK;
                    555:             break;
                    556:         case 1:
1.1.1.8   root      557:             mask = ALL_CPU_MASK ^ (1 << cpu);
1.1.1.2   root      558:             break;
                    559:         case 2:
1.1.1.8   root      560:             mask = 1 << cpu;
1.1.1.2   root      561:             break;
                    562:         default:
                    563:             DPRINTF("Bad Soft Int target filter\n");
                    564:             mask = ALL_CPU_MASK;
                    565:             break;
                    566:         }
                    567:         GIC_SET_PENDING(irq, mask);
                    568:         gic_update(s);
                    569:         return;
                    570:     }
1.1       root      571:     gic_dist_writew(opaque, offset, value & 0xffff);
                    572:     gic_dist_writew(opaque, offset + 2, value >> 16);
                    573: }
                    574: 
1.1.1.9 ! root      575: static const MemoryRegionOps gic_dist_ops = {
        !           576:     .old_mmio = {
        !           577:         .read = { gic_dist_readb, gic_dist_readw, gic_dist_readl, },
        !           578:         .write = { gic_dist_writeb, gic_dist_writew, gic_dist_writel, },
        !           579:     },
        !           580:     .endianness = DEVICE_NATIVE_ENDIAN,
1.1       root      581: };
                    582: 
1.1.1.2   root      583: #ifndef NVIC
                    584: static uint32_t gic_cpu_read(gic_state *s, int cpu, int offset)
1.1       root      585: {
                    586:     switch (offset) {
                    587:     case 0x00: /* Control */
1.1.1.2   root      588:         return s->cpu_enabled[cpu];
1.1       root      589:     case 0x04: /* Priority mask */
1.1.1.2   root      590:         return s->priority_mask[cpu];
1.1       root      591:     case 0x08: /* Binary Point */
                    592:         /* ??? Not implemented.  */
                    593:         return 0;
                    594:     case 0x0c: /* Acknowledge */
1.1.1.2   root      595:         return gic_acknowledge_irq(s, cpu);
1.1       root      596:     case 0x14: /* Runing Priority */
1.1.1.2   root      597:         return s->running_priority[cpu];
1.1       root      598:     case 0x18: /* Highest Pending Interrupt */
1.1.1.2   root      599:         return s->current_pending[cpu];
1.1       root      600:     default:
1.1.1.4   root      601:         hw_error("gic_cpu_read: Bad offset %x\n", (int)offset);
1.1       root      602:         return 0;
                    603:     }
                    604: }
                    605: 
1.1.1.2   root      606: static void gic_cpu_write(gic_state *s, int cpu, int offset, uint32_t value)
1.1       root      607: {
                    608:     switch (offset) {
                    609:     case 0x00: /* Control */
1.1.1.2   root      610:         s->cpu_enabled[cpu] = (value & 1);
1.1.1.5   root      611:         DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled ? "En" : "Dis");
1.1       root      612:         break;
                    613:     case 0x04: /* Priority mask */
1.1.1.2   root      614:         s->priority_mask[cpu] = (value & 0xff);
1.1       root      615:         break;
                    616:     case 0x08: /* Binary Point */
                    617:         /* ??? Not implemented.  */
                    618:         break;
                    619:     case 0x10: /* End Of Interrupt */
1.1.1.2   root      620:         return gic_complete_irq(s, cpu, value & 0x3ff);
1.1       root      621:     default:
1.1.1.4   root      622:         hw_error("gic_cpu_write: Bad offset %x\n", (int)offset);
1.1       root      623:         return;
                    624:     }
                    625:     gic_update(s);
                    626: }
1.1.1.2   root      627: #endif
1.1       root      628: 
                    629: static void gic_reset(gic_state *s)
                    630: {
                    631:     int i;
                    632:     memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state));
1.1.1.5   root      633:     for (i = 0 ; i < NUM_CPU(s); i++) {
1.1.1.2   root      634:         s->priority_mask[i] = 0xf0;
                    635:         s->current_pending[i] = 1023;
                    636:         s->running_irq[i] = 1023;
                    637:         s->running_priority[i] = 0x100;
                    638: #ifdef NVIC
                    639:         /* The NVIC doesn't have per-cpu interfaces, so enable by default.  */
                    640:         s->cpu_enabled[i] = 1;
                    641: #else
                    642:         s->cpu_enabled[i] = 0;
                    643: #endif
                    644:     }
                    645:     for (i = 0; i < 16; i++) {
1.1.1.9 ! root      646:         GIC_SET_ENABLED(i, ALL_CPU_MASK);
1.1       root      647:         GIC_SET_TRIGGER(i);
                    648:     }
1.1.1.2   root      649: #ifdef NVIC
                    650:     /* The NVIC is always enabled.  */
                    651:     s->enabled = 1;
                    652: #else
1.1       root      653:     s->enabled = 0;
1.1.1.2   root      654: #endif
1.1       root      655: }
                    656: 
1.1.1.3   root      657: static void gic_save(QEMUFile *f, void *opaque)
                    658: {
                    659:     gic_state *s = (gic_state *)opaque;
                    660:     int i;
                    661:     int j;
                    662: 
                    663:     qemu_put_be32(f, s->enabled);
1.1.1.5   root      664:     for (i = 0; i < NUM_CPU(s); i++) {
1.1.1.3   root      665:         qemu_put_be32(f, s->cpu_enabled[i]);
                    666:         for (j = 0; j < 32; j++)
                    667:             qemu_put_be32(f, s->priority1[j][i]);
                    668:         for (j = 0; j < GIC_NIRQ; j++)
                    669:             qemu_put_be32(f, s->last_active[j][i]);
                    670:         qemu_put_be32(f, s->priority_mask[i]);
                    671:         qemu_put_be32(f, s->running_irq[i]);
                    672:         qemu_put_be32(f, s->running_priority[i]);
                    673:         qemu_put_be32(f, s->current_pending[i]);
                    674:     }
                    675:     for (i = 0; i < GIC_NIRQ - 32; i++) {
                    676:         qemu_put_be32(f, s->priority2[i]);
                    677:     }
                    678:     for (i = 0; i < GIC_NIRQ; i++) {
1.1.1.9 ! root      679: #ifndef NVIC
        !           680:         qemu_put_be32(f, s->irq_target[i]);
        !           681: #endif
1.1.1.3   root      682:         qemu_put_byte(f, s->irq_state[i].enabled);
                    683:         qemu_put_byte(f, s->irq_state[i].pending);
                    684:         qemu_put_byte(f, s->irq_state[i].active);
                    685:         qemu_put_byte(f, s->irq_state[i].level);
                    686:         qemu_put_byte(f, s->irq_state[i].model);
                    687:         qemu_put_byte(f, s->irq_state[i].trigger);
                    688:     }
                    689: }
                    690: 
                    691: static int gic_load(QEMUFile *f, void *opaque, int version_id)
                    692: {
                    693:     gic_state *s = (gic_state *)opaque;
                    694:     int i;
                    695:     int j;
                    696: 
1.1.1.9 ! root      697:     if (version_id != 2)
1.1.1.3   root      698:         return -EINVAL;
                    699: 
                    700:     s->enabled = qemu_get_be32(f);
1.1.1.5   root      701:     for (i = 0; i < NUM_CPU(s); i++) {
1.1.1.3   root      702:         s->cpu_enabled[i] = qemu_get_be32(f);
                    703:         for (j = 0; j < 32; j++)
                    704:             s->priority1[j][i] = qemu_get_be32(f);
                    705:         for (j = 0; j < GIC_NIRQ; j++)
                    706:             s->last_active[j][i] = qemu_get_be32(f);
                    707:         s->priority_mask[i] = qemu_get_be32(f);
                    708:         s->running_irq[i] = qemu_get_be32(f);
                    709:         s->running_priority[i] = qemu_get_be32(f);
                    710:         s->current_pending[i] = qemu_get_be32(f);
                    711:     }
                    712:     for (i = 0; i < GIC_NIRQ - 32; i++) {
                    713:         s->priority2[i] = qemu_get_be32(f);
                    714:     }
                    715:     for (i = 0; i < GIC_NIRQ; i++) {
1.1.1.9 ! root      716: #ifndef NVIC
        !           717:         s->irq_target[i] = qemu_get_be32(f);
        !           718: #endif
1.1.1.3   root      719:         s->irq_state[i].enabled = qemu_get_byte(f);
                    720:         s->irq_state[i].pending = qemu_get_byte(f);
                    721:         s->irq_state[i].active = qemu_get_byte(f);
                    722:         s->irq_state[i].level = qemu_get_byte(f);
                    723:         s->irq_state[i].model = qemu_get_byte(f);
                    724:         s->irq_state[i].trigger = qemu_get_byte(f);
                    725:     }
                    726: 
                    727:     return 0;
                    728: }
                    729: 
1.1.1.5   root      730: #if NCPU > 1
                    731: static void gic_init(gic_state *s, int num_cpu)
                    732: #else
1.1.1.4   root      733: static void gic_init(gic_state *s)
1.1.1.5   root      734: #endif
1.1       root      735: {
1.1.1.2   root      736:     int i;
1.1       root      737: 
1.1.1.5   root      738: #if NCPU > 1
                    739:     s->num_cpu = num_cpu;
                    740: #endif
1.1.1.4   root      741:     qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32);
1.1.1.5   root      742:     for (i = 0; i < NUM_CPU(s); i++) {
1.1.1.4   root      743:         sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
1.1.1.2   root      744:     }
1.1.1.9 ! root      745:     memory_region_init_io(&s->iomem, &gic_dist_ops, s, "gic_dist", 0x1000);
1.1       root      746:     gic_reset(s);
1.1.1.9 ! root      747:     register_savevm(NULL, "arm_gic", -1, 2, gic_save, gic_load, s);
1.1       root      748: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.