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

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

unix.superglobalmegacorp.com

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