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

1.1       root        1: /* 
                      2:  * ARM AMBA Generic/Distributed Interrupt Controller
                      3:  *
                      4:  * Copyright (c) 2006 CodeSourcery.
                      5:  * Written by Paul Brook
                      6:  *
                      7:  * This code is licenced under the GPL.
                      8:  */
                      9: 
                     10: /* TODO: Some variants of this controller can handle multiple CPUs.
                     11:    Currently only single CPU operation is implemented.  */
                     12: 
                     13: #include "vl.h"
                     14: #include "arm_pic.h"
                     15: 
                     16: //#define DEBUG_GIC
                     17: 
                     18: #ifdef DEBUG_GIC
                     19: #define DPRINTF(fmt, args...) \
                     20: do { printf("arm_gic: " fmt , ##args); } while (0)
                     21: #else
                     22: #define DPRINTF(fmt, args...) do {} while(0)
                     23: #endif
                     24: 
                     25: /* Distributed interrupt controller.  */
                     26: 
                     27: static const uint8_t gic_id[] =
                     28: { 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
                     29: 
                     30: #define GIC_NIRQ 96
                     31: 
                     32: typedef struct gic_irq_state
                     33: {
                     34:     unsigned enabled:1;
                     35:     unsigned pending:1;
                     36:     unsigned active:1;
                     37:     unsigned level:1;
                     38:     unsigned model:1; /* 0 = 1:N, 1 = N:N */
                     39:     unsigned trigger:1; /* nonzero = edge triggered.  */
                     40: } gic_irq_state;
                     41: 
                     42: #define GIC_SET_ENABLED(irq) s->irq_state[irq].enabled = 1
                     43: #define GIC_CLEAR_ENABLED(irq) s->irq_state[irq].enabled = 0
                     44: #define GIC_TEST_ENABLED(irq) s->irq_state[irq].enabled
                     45: #define GIC_SET_PENDING(irq) s->irq_state[irq].pending = 1
                     46: #define GIC_CLEAR_PENDING(irq) s->irq_state[irq].pending = 0
                     47: #define GIC_TEST_PENDING(irq) s->irq_state[irq].pending
                     48: #define GIC_SET_ACTIVE(irq) s->irq_state[irq].active = 1
                     49: #define GIC_CLEAR_ACTIVE(irq) s->irq_state[irq].active = 0
                     50: #define GIC_TEST_ACTIVE(irq) s->irq_state[irq].active
                     51: #define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1
                     52: #define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0
                     53: #define GIC_TEST_MODEL(irq) s->irq_state[irq].model
                     54: #define GIC_SET_LEVEL(irq) s->irq_state[irq].level = 1
                     55: #define GIC_CLEAR_LEVEL(irq) s->irq_state[irq].level = 0
                     56: #define GIC_TEST_LEVEL(irq) s->irq_state[irq].level
                     57: #define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1
                     58: #define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0
                     59: #define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger
                     60: 
                     61: typedef struct gic_state
                     62: {
                     63:     arm_pic_handler handler;
                     64:     uint32_t base;
                     65:     void *parent;
                     66:     int parent_irq;
                     67:     int enabled;
                     68:     int cpu_enabled;
                     69: 
                     70:     gic_irq_state irq_state[GIC_NIRQ];
                     71:     int irq_target[GIC_NIRQ];
                     72:     int priority[GIC_NIRQ];
                     73:     int last_active[GIC_NIRQ];
                     74: 
                     75:     int priority_mask;
                     76:     int running_irq;
                     77:     int running_priority;
                     78:     int current_pending;
                     79: } gic_state;
                     80: 
                     81: /* TODO: Many places that call this routine could be optimized.  */
                     82: /* Update interrupt status after enabled or pending bits have been changed.  */
                     83: static void gic_update(gic_state *s)
                     84: {
                     85:     int best_irq;
                     86:     int best_prio;
                     87:     int irq;
                     88: 
                     89:     s->current_pending = 1023;
                     90:     if (!s->enabled || !s->cpu_enabled) {
                     91:         pic_set_irq_new(s->parent, s->parent_irq, 0);
                     92:         return;
                     93:     }
                     94:     best_prio = 0x100;
                     95:     best_irq = 1023;
                     96:     for (irq = 0; irq < 96; irq++) {
                     97:         if (GIC_TEST_ENABLED(irq) && GIC_TEST_PENDING(irq)) {
                     98:             if (s->priority[irq] < best_prio) {
                     99:                 best_prio = s->priority[irq];
                    100:                 best_irq = irq;
                    101:             }
                    102:         }
                    103:     }
                    104:     if (best_prio > s->priority_mask) {
                    105:         pic_set_irq_new(s->parent, s->parent_irq, 0);
                    106:     } else {
                    107:         s->current_pending = best_irq;
                    108:         if (best_prio < s->running_priority) {
                    109:             DPRINTF("Raised pending IRQ %d\n", best_irq);
                    110:             pic_set_irq_new(s->parent, s->parent_irq, 1);
                    111:         }
                    112:     }
                    113: }
                    114: 
                    115: static void gic_set_irq(void *opaque, int irq, int level)
                    116: {
                    117:     gic_state *s = (gic_state *)opaque;
                    118:     /* The first external input line is internal interrupt 32.  */
                    119:     irq += 32;
                    120:     if (level == GIC_TEST_LEVEL(irq)) 
                    121:         return;
                    122: 
                    123:     if (level) {
                    124:         GIC_SET_LEVEL(irq);
                    125:         if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq)) {
                    126:             DPRINTF("Set %d pending\n", irq);
                    127:             GIC_SET_PENDING(irq);
                    128:         }
                    129:     } else {
                    130:         GIC_CLEAR_LEVEL(irq);
                    131:     }
                    132:     gic_update(s);
                    133: }
                    134: 
                    135: static void gic_set_running_irq(gic_state *s, int irq)
                    136: {
                    137:     s->running_irq = irq;
                    138:     if (irq == 1023)
                    139:         s->running_priority = 0x100;
                    140:     else
                    141:         s->running_priority = s->priority[irq];
                    142:     gic_update(s);
                    143: }
                    144: 
                    145: static uint32_t gic_acknowledge_irq(gic_state *s)
                    146: {
                    147:     int new_irq;
                    148:     new_irq = s->current_pending;
                    149:     if (new_irq == 1023 || s->priority[new_irq] >= s->running_priority) {
                    150:         DPRINTF("ACK no pending IRQ\n");
                    151:         return 1023;
                    152:     }
                    153:     pic_set_irq_new(s->parent, s->parent_irq, 0);
                    154:     s->last_active[new_irq] = s->running_irq;
                    155:     /* For level triggered interrupts we clear the pending bit while
                    156:        the interrupt is active.  */
                    157:     GIC_CLEAR_PENDING(new_irq);
                    158:     gic_set_running_irq(s, new_irq);
                    159:     DPRINTF("ACK %d\n", new_irq);
                    160:     return new_irq;
                    161: }
                    162: 
                    163: static void gic_complete_irq(gic_state * s, int irq)
                    164: {
                    165:     int update = 0;
                    166:     DPRINTF("EOI %d\n", irq);
                    167:     if (s->running_irq == 1023)
                    168:         return; /* No active IRQ.  */
                    169:     if (irq != 1023) {
                    170:         /* Mark level triggered interrupts as pending if they are still
                    171:            raised.  */
                    172:         if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq)
                    173:                 && GIC_TEST_LEVEL(irq)) {
                    174:             GIC_SET_PENDING(irq);
                    175:             update = 1;
                    176:         }
                    177:     }
                    178:     if (irq != s->running_irq) {
                    179:         /* Complete an IRQ that is not currently running.  */
                    180:         int tmp = s->running_irq;
                    181:         while (s->last_active[tmp] != 1023) {
                    182:             if (s->last_active[tmp] == irq) {
                    183:                 s->last_active[tmp] = s->last_active[irq];
                    184:                 break;
                    185:             }
                    186:             tmp = s->last_active[tmp];
                    187:         }
                    188:         if (update) {
                    189:             gic_update(s);
                    190:         }
                    191:     } else {
                    192:         /* Complete the current running IRQ.  */
                    193:         gic_set_running_irq(s, s->last_active[s->running_irq]);
                    194:     }
                    195: }
                    196: 
                    197: static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
                    198: {
                    199:     gic_state *s = (gic_state *)opaque;
                    200:     uint32_t res;
                    201:     int irq;
                    202:     int i;
                    203: 
                    204:     offset -= s->base + 0x1000;
                    205:     if (offset < 0x100) {
                    206:         if (offset == 0)
                    207:             return s->enabled;
                    208:         if (offset == 4)
                    209:             return (GIC_NIRQ / 32) - 1;
                    210:         if (offset < 0x08)
                    211:             return 0;
                    212:         goto bad_reg;
                    213:     } else if (offset < 0x200) {
                    214:         /* Interrupt Set/Clear Enable.  */
                    215:         if (offset < 0x180)
                    216:             irq = (offset - 0x100) * 8;
                    217:         else
                    218:             irq = (offset - 0x180) * 8;
                    219:         if (irq >= GIC_NIRQ)
                    220:             goto bad_reg;
                    221:         res = 0;
                    222:         for (i = 0; i < 8; i++) {
                    223:             if (GIC_TEST_ENABLED(irq + i)) {
                    224:                 res |= (1 << i);
                    225:             }
                    226:         }
                    227:     } else if (offset < 0x300) {
                    228:         /* Interrupt Set/Clear Pending.  */
                    229:         if (offset < 0x280)
                    230:             irq = (offset - 0x200) * 8;
                    231:         else
                    232:             irq = (offset - 0x280) * 8;
                    233:         if (irq >= GIC_NIRQ)
                    234:             goto bad_reg;
                    235:         res = 0;
                    236:         for (i = 0; i < 8; i++) {
                    237:             if (GIC_TEST_PENDING(irq + i)) {
                    238:                 res |= (1 << i);
                    239:             }
                    240:         }
                    241:     } else if (offset < 0x400) {
                    242:         /* Interrupt Active.  */
                    243:         irq = (offset - 0x300) * 8;
                    244:         if (irq >= GIC_NIRQ)
                    245:             goto bad_reg;
                    246:         res = 0;
                    247:         for (i = 0; i < 8; i++) {
                    248:             if (GIC_TEST_ACTIVE(irq + i)) {
                    249:                 res |= (1 << i);
                    250:             }
                    251:         }
                    252:     } else if (offset < 0x800) {
                    253:         /* Interrupt Priority.  */
                    254:         irq = offset - 0x400;
                    255:         if (irq >= GIC_NIRQ)
                    256:             goto bad_reg;
                    257:         res = s->priority[irq];
                    258:     } else if (offset < 0xc00) {
                    259:         /* Interrupt CPU Target.  */
                    260:         irq = offset - 0x800;
                    261:         if (irq >= GIC_NIRQ)
                    262:             goto bad_reg;
                    263:         res = s->irq_target[irq];
                    264:     } else if (offset < 0xf00) {
                    265:         /* Interrupt Configuration.  */
                    266:         irq = (offset - 0xc00) * 2;
                    267:         if (irq >= GIC_NIRQ)
                    268:             goto bad_reg;
                    269:         res = 0;
                    270:         for (i = 0; i < 4; i++) {
                    271:             if (GIC_TEST_MODEL(irq + i))
                    272:                 res |= (1 << (i * 2));
                    273:             if (GIC_TEST_TRIGGER(irq + i))
                    274:                 res |= (2 << (i * 2));
                    275:         }
                    276:     } else if (offset < 0xfe0) {
                    277:         goto bad_reg;
                    278:     } else /* offset >= 0xfe0 */ {
                    279:         if (offset & 3) {
                    280:             res = 0;
                    281:         } else {
                    282:             res = gic_id[(offset - 0xfe0) >> 2];
                    283:         }
                    284:     }
                    285:     return res;
                    286: bad_reg:
                    287:     cpu_abort (cpu_single_env, "gic_dist_readb: Bad offset %x\n", offset);
                    288:     return 0;
                    289: }
                    290: 
                    291: static uint32_t gic_dist_readw(void *opaque, target_phys_addr_t offset)
                    292: {
                    293:     uint32_t val;
                    294:     val = gic_dist_readb(opaque, offset);
                    295:     val |= gic_dist_readb(opaque, offset + 1) << 8;
                    296:     return val;
                    297: }
                    298: 
                    299: static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset)
                    300: {
                    301:     uint32_t val;
                    302:     val = gic_dist_readw(opaque, offset);
                    303:     val |= gic_dist_readw(opaque, offset + 2) << 16;
                    304:     return val;
                    305: }
                    306: 
                    307: static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
                    308:                             uint32_t value)
                    309: {
                    310:     gic_state *s = (gic_state *)opaque;
                    311:     int irq;
                    312:     int i;
                    313: 
                    314:     offset -= s->base + 0x1000;
                    315:     if (offset < 0x100) {
                    316:         if (offset == 0) {
                    317:             s->enabled = (value & 1);
                    318:             DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
                    319:         } else if (offset < 4) {
                    320:             /* ignored.  */
                    321:         } else {
                    322:             goto bad_reg;
                    323:         }
                    324:     } else if (offset < 0x180) {
                    325:         /* Interrupt Set Enable.  */
                    326:         irq = (offset - 0x100) * 8;
                    327:         if (irq >= GIC_NIRQ)
                    328:             goto bad_reg;
                    329:         for (i = 0; i < 8; i++) {
                    330:             if (value & (1 << i)) {
                    331:                 if (!GIC_TEST_ENABLED(irq + i))
                    332:                     DPRINTF("Enabled IRQ %d\n", irq + i);
                    333:                 GIC_SET_ENABLED(irq + i);
                    334:                 /* If a raised level triggered IRQ enabled then mark
                    335:                    is as pending.  */
                    336:                 if (GIC_TEST_LEVEL(irq + i) && !GIC_TEST_TRIGGER(irq + i))
                    337:                     GIC_SET_PENDING(irq + i);
                    338:             }
                    339:         }
                    340:     } else if (offset < 0x200) {
                    341:         /* Interrupt Clear Enable.  */
                    342:         irq = (offset - 0x180) * 8;
                    343:         if (irq >= GIC_NIRQ)
                    344:             goto bad_reg;
                    345:         for (i = 0; i < 8; i++) {
                    346:             if (value & (1 << i)) {
                    347:                 if (GIC_TEST_ENABLED(irq + i))
                    348:                     DPRINTF("Disabled IRQ %d\n", irq + i);
                    349:                 GIC_CLEAR_ENABLED(irq + i);
                    350:             }
                    351:         }
                    352:     } else if (offset < 0x280) {
                    353:         /* Interrupt Set Pending.  */
                    354:         irq = (offset - 0x200) * 8;
                    355:         if (irq >= GIC_NIRQ)
                    356:             goto bad_reg;
                    357:         for (i = 0; i < 8; i++) {
                    358:             if (value & (1 << i)) {
                    359:                 GIC_SET_PENDING(irq + i);
                    360:             }
                    361:         }
                    362:     } else if (offset < 0x300) {
                    363:         /* Interrupt Clear Pending.  */
                    364:         irq = (offset - 0x280) * 8;
                    365:         if (irq >= GIC_NIRQ)
                    366:             goto bad_reg;
                    367:         for (i = 0; i < 8; i++) {
                    368:             if (value & (1 << i)) {
                    369:                 GIC_CLEAR_PENDING(irq + i);
                    370:             }
                    371:         }
                    372:     } else if (offset < 0x400) {
                    373:         /* Interrupt Active.  */
                    374:         goto bad_reg;
                    375:     } else if (offset < 0x800) {
                    376:         /* Interrupt Priority.  */
                    377:         irq = offset - 0x400;
                    378:         if (irq >= GIC_NIRQ)
                    379:             goto bad_reg;
                    380:         s->priority[irq] = value;
                    381:     } else if (offset < 0xc00) {
                    382:         /* Interrupt CPU Target.  */
                    383:         irq = offset - 0x800;
                    384:         if (irq >= GIC_NIRQ)
                    385:             goto bad_reg;
                    386:         s->irq_target[irq] = value;
                    387:     } else if (offset < 0xf00) {
                    388:         /* Interrupt Configuration.  */
                    389:         irq = (offset - 0xc00) * 4;
                    390:         if (irq >= GIC_NIRQ)
                    391:             goto bad_reg;
                    392:         for (i = 0; i < 4; i++) {
                    393:             if (value & (1 << (i * 2))) {
                    394:                 GIC_SET_MODEL(irq + i);
                    395:             } else {
                    396:                 GIC_CLEAR_MODEL(irq + i);
                    397:             }
                    398:             if (value & (2 << (i * 2))) {
                    399:                 GIC_SET_TRIGGER(irq + i);
                    400:             } else {
                    401:                 GIC_CLEAR_TRIGGER(irq + i);
                    402:             }
                    403:         }
                    404:     } else {
                    405:         /* 0xf00 is only handled for word writes.  */
                    406:         goto bad_reg;
                    407:     }
                    408:     gic_update(s);
                    409:     return;
                    410: bad_reg:
                    411:     cpu_abort (cpu_single_env, "gic_dist_writeb: Bad offset %x\n", offset);
                    412: }
                    413: 
                    414: static void gic_dist_writew(void *opaque, target_phys_addr_t offset,
                    415:                             uint32_t value)
                    416: {
                    417:     gic_state *s = (gic_state *)opaque;
                    418:     if (offset - s->base == 0xf00) {
                    419:         GIC_SET_PENDING(value & 0x3ff);
                    420:         gic_update(s);
                    421:         return;
                    422:     }
                    423:     gic_dist_writeb(opaque, offset, value & 0xff);
                    424:     gic_dist_writeb(opaque, offset + 1, value >> 8);
                    425: }
                    426: 
                    427: static void gic_dist_writel(void *opaque, target_phys_addr_t offset,
                    428:                             uint32_t value)
                    429: {
                    430:     gic_dist_writew(opaque, offset, value & 0xffff);
                    431:     gic_dist_writew(opaque, offset + 2, value >> 16);
                    432: }
                    433: 
                    434: static CPUReadMemoryFunc *gic_dist_readfn[] = {
                    435:    gic_dist_readb,
                    436:    gic_dist_readw,
                    437:    gic_dist_readl
                    438: };
                    439: 
                    440: static CPUWriteMemoryFunc *gic_dist_writefn[] = {
                    441:    gic_dist_writeb,
                    442:    gic_dist_writew,
                    443:    gic_dist_writel
                    444: };
                    445: 
                    446: static uint32_t gic_cpu_read(void *opaque, target_phys_addr_t offset)
                    447: {
                    448:     gic_state *s = (gic_state *)opaque;
                    449:     offset -= s->base;
                    450:     switch (offset) {
                    451:     case 0x00: /* Control */
                    452:         return s->cpu_enabled;
                    453:     case 0x04: /* Priority mask */
                    454:         return s->priority_mask;
                    455:     case 0x08: /* Binary Point */
                    456:         /* ??? Not implemented.  */
                    457:         return 0;
                    458:     case 0x0c: /* Acknowledge */
                    459:         return gic_acknowledge_irq(s);
                    460:     case 0x14: /* Runing Priority */
                    461:         return s->running_priority;
                    462:     case 0x18: /* Highest Pending Interrupt */
                    463:         return s->current_pending;
                    464:     default:
                    465:         cpu_abort (cpu_single_env, "gic_cpu_writeb: Bad offset %x\n", offset);
                    466:         return 0;
                    467:     }
                    468: }
                    469: 
                    470: static void gic_cpu_write(void *opaque, target_phys_addr_t offset,
                    471:                           uint32_t value)
                    472: {
                    473:     gic_state *s = (gic_state *)opaque;
                    474:     offset -= s->base;
                    475:     switch (offset) {
                    476:     case 0x00: /* Control */
                    477:         s->cpu_enabled = (value & 1);
                    478:         DPRINTF("CPU %sabled\n", s->cpu_enabled ? "En" : "Dis");
                    479:         break;
                    480:     case 0x04: /* Priority mask */
                    481:         s->priority_mask = (value & 0x3ff);
                    482:         break;
                    483:     case 0x08: /* Binary Point */
                    484:         /* ??? Not implemented.  */
                    485:         break;
                    486:     case 0x10: /* End Of Interrupt */
                    487:         return gic_complete_irq(s, value & 0x3ff);
                    488:     default:
                    489:         cpu_abort (cpu_single_env, "gic_cpu_writeb: Bad offset %x\n", offset);
                    490:         return;
                    491:     }
                    492:     gic_update(s);
                    493: }
                    494: 
                    495: static CPUReadMemoryFunc *gic_cpu_readfn[] = {
                    496:    gic_cpu_read,
                    497:    gic_cpu_read,
                    498:    gic_cpu_read
                    499: };
                    500: 
                    501: static CPUWriteMemoryFunc *gic_cpu_writefn[] = {
                    502:    gic_cpu_write,
                    503:    gic_cpu_write,
                    504:    gic_cpu_write
                    505: };
                    506: 
                    507: static void gic_reset(gic_state *s)
                    508: {
                    509:     int i;
                    510:     memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state));
                    511:     s->priority_mask = 0xf0;
                    512:     s->current_pending = 1023;
                    513:     s->running_irq = 1023;
                    514:     s->running_priority = 0x100;
                    515:     for (i = 0; i < 15; i++) {
                    516:         GIC_SET_ENABLED(i);
                    517:         GIC_SET_TRIGGER(i);
                    518:     }
                    519:     s->enabled = 0;
                    520:     s->cpu_enabled = 0;
                    521: }
                    522: 
                    523: void *arm_gic_init(uint32_t base, void *parent, int parent_irq)
                    524: {
                    525:     gic_state *s;
                    526:     int iomemtype;
                    527: 
                    528:     s = (gic_state *)qemu_mallocz(sizeof(gic_state));
                    529:     if (!s)
                    530:         return NULL;
                    531:     s->handler = gic_set_irq;
                    532:     s->parent = parent;
                    533:     s->parent_irq = parent_irq;
                    534:     if (base != 0xffffffff) {
                    535:         iomemtype = cpu_register_io_memory(0, gic_cpu_readfn,
                    536:                                            gic_cpu_writefn, s);
                    537:         cpu_register_physical_memory(base, 0x00000fff, iomemtype);
                    538:         iomemtype = cpu_register_io_memory(0, gic_dist_readfn,
                    539:                                            gic_dist_writefn, s);
                    540:         cpu_register_physical_memory(base + 0x1000, 0x00000fff, iomemtype);
                    541:         s->base = base;
                    542:     } else {
                    543:         s->base = 0;
                    544:     }
                    545:     gic_reset(s);
                    546:     return s;
                    547: }

unix.superglobalmegacorp.com

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