Annotation of qemu/hw/slavio_intctl.c, revision 1.1.1.3

1.1       root        1: /*
                      2:  * QEMU Sparc SLAVIO interrupt controller emulation
                      3:  * 
                      4:  * Copyright (c) 2003-2005 Fabrice Bellard
                      5:  * 
                      6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      7:  * of this software and associated documentation files (the "Software"), to deal
                      8:  * in the Software without restriction, including without limitation the rights
                      9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     10:  * copies of the Software, and to permit persons to whom the Software is
                     11:  * furnished to do so, subject to the following conditions:
                     12:  *
                     13:  * The above copyright notice and this permission notice shall be included in
                     14:  * all copies or substantial portions of the Software.
                     15:  *
                     16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     22:  * THE SOFTWARE.
                     23:  */
                     24: #include "vl.h"
                     25: //#define DEBUG_IRQ_COUNT
                     26: //#define DEBUG_IRQ
                     27: 
                     28: #ifdef DEBUG_IRQ
                     29: #define DPRINTF(fmt, args...) \
                     30: do { printf("IRQ: " fmt , ##args); } while (0)
                     31: #else
                     32: #define DPRINTF(fmt, args...)
                     33: #endif
                     34: 
                     35: /*
                     36:  * Registers of interrupt controller in sun4m.
                     37:  *
                     38:  * This is the interrupt controller part of chip STP2001 (Slave I/O), also
                     39:  * produced as NCR89C105. See
                     40:  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
                     41:  *
                     42:  * There is a system master controller and one for each cpu.
                     43:  * 
                     44:  */
                     45: 
                     46: #define MAX_CPUS 16
                     47: 
                     48: typedef struct SLAVIO_INTCTLState {
                     49:     uint32_t intreg_pending[MAX_CPUS];
                     50:     uint32_t intregm_pending;
                     51:     uint32_t intregm_disabled;
                     52:     uint32_t target_cpu;
                     53: #ifdef DEBUG_IRQ_COUNT
                     54:     uint64_t irq_count[32];
                     55: #endif
1.1.1.2   root       56:     CPUState *cpu_envs[MAX_CPUS];
1.1       root       57: } SLAVIO_INTCTLState;
                     58: 
                     59: #define INTCTL_MAXADDR 0xf
                     60: #define INTCTLM_MAXADDR 0xf
                     61: static void slavio_check_interrupts(void *opaque);
                     62: 
                     63: // per-cpu interrupt controller
                     64: static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
                     65: {
                     66:     SLAVIO_INTCTLState *s = opaque;
                     67:     uint32_t saddr;
                     68:     int cpu;
                     69: 
                     70:     cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
                     71:     saddr = (addr & INTCTL_MAXADDR) >> 2;
                     72:     switch (saddr) {
                     73:     case 0:
                     74:        return s->intreg_pending[cpu];
                     75:     default:
                     76:        break;
                     77:     }
                     78:     return 0;
                     79: }
                     80: 
                     81: static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
                     82: {
                     83:     SLAVIO_INTCTLState *s = opaque;
                     84:     uint32_t saddr;
                     85:     int cpu;
                     86: 
                     87:     cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
                     88:     saddr = (addr & INTCTL_MAXADDR) >> 2;
                     89:     switch (saddr) {
                     90:     case 1: // clear pending softints
                     91:        if (val & 0x4000)
                     92:            val |= 80000000;
                     93:        val &= 0xfffe0000;
                     94:        s->intreg_pending[cpu] &= ~val;
                     95:        DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
                     96:        break;
                     97:     case 2: // set softint
                     98:        val &= 0xfffe0000;
                     99:        s->intreg_pending[cpu] |= val;
1.1.1.2   root      100:         slavio_check_interrupts(s);
1.1       root      101:        DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
                    102:        break;
                    103:     default:
                    104:        break;
                    105:     }
                    106: }
                    107: 
                    108: static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = {
                    109:     slavio_intctl_mem_readl,
                    110:     slavio_intctl_mem_readl,
                    111:     slavio_intctl_mem_readl,
                    112: };
                    113: 
                    114: static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = {
                    115:     slavio_intctl_mem_writel,
                    116:     slavio_intctl_mem_writel,
                    117:     slavio_intctl_mem_writel,
                    118: };
                    119: 
                    120: // master system interrupt controller
                    121: static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
                    122: {
                    123:     SLAVIO_INTCTLState *s = opaque;
                    124:     uint32_t saddr;
                    125: 
                    126:     saddr = (addr & INTCTLM_MAXADDR) >> 2;
                    127:     switch (saddr) {
                    128:     case 0:
                    129:        return s->intregm_pending & 0x7fffffff;
                    130:     case 1:
                    131:        return s->intregm_disabled;
                    132:     case 4:
                    133:        return s->target_cpu;
                    134:     default:
                    135:        break;
                    136:     }
                    137:     return 0;
                    138: }
                    139: 
                    140: static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
                    141: {
                    142:     SLAVIO_INTCTLState *s = opaque;
                    143:     uint32_t saddr;
                    144: 
                    145:     saddr = (addr & INTCTLM_MAXADDR) >> 2;
                    146:     switch (saddr) {
                    147:     case 2: // clear (enable)
                    148:        // Force clear unused bits
                    149:        val &= ~0x4fb2007f;
                    150:        s->intregm_disabled &= ~val;
                    151:        DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
                    152:        slavio_check_interrupts(s);
                    153:        break;
                    154:     case 3: // set (disable, clear pending)
                    155:        // Force clear unused bits
                    156:        val &= ~0x4fb2007f;
                    157:        s->intregm_disabled |= val;
                    158:        s->intregm_pending &= ~val;
                    159:        DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
                    160:        break;
                    161:     case 4:
                    162:        s->target_cpu = val & (MAX_CPUS - 1);
                    163:        DPRINTF("Set master irq cpu %d\n", s->target_cpu);
                    164:        break;
                    165:     default:
                    166:        break;
                    167:     }
                    168: }
                    169: 
                    170: static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = {
                    171:     slavio_intctlm_mem_readl,
                    172:     slavio_intctlm_mem_readl,
                    173:     slavio_intctlm_mem_readl,
                    174: };
                    175: 
                    176: static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = {
                    177:     slavio_intctlm_mem_writel,
                    178:     slavio_intctlm_mem_writel,
                    179:     slavio_intctlm_mem_writel,
                    180: };
                    181: 
                    182: void slavio_pic_info(void *opaque)
                    183: {
                    184:     SLAVIO_INTCTLState *s = opaque;
                    185:     int i;
                    186: 
                    187:     for (i = 0; i < MAX_CPUS; i++) {
                    188:        term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]);
                    189:     }
                    190:     term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled);
                    191: }
                    192: 
                    193: void slavio_irq_info(void *opaque)
                    194: {
                    195: #ifndef DEBUG_IRQ_COUNT
                    196:     term_printf("irq statistic code not compiled.\n");
                    197: #else
                    198:     SLAVIO_INTCTLState *s = opaque;
                    199:     int i;
                    200:     int64_t count;
                    201: 
                    202:     term_printf("IRQ statistics:\n");
                    203:     for (i = 0; i < 32; i++) {
                    204:         count = s->irq_count[i];
                    205:         if (count > 0)
1.1.1.3 ! root      206:             term_printf("%2d: %" PRId64 "\n", i, count);
1.1       root      207:     }
                    208: #endif
                    209: }
                    210: 
                    211: static const uint32_t intbit_to_level[32] = {
                    212:     2, 3, 5, 7, 9, 11, 0, 14,  3, 5, 7, 9, 11, 13, 12, 12,
                    213:     6, 0, 4, 10, 8, 0, 11, 0,  0, 0, 0, 0, 15, 0, 15, 0,
                    214: };
                    215: 
                    216: static void slavio_check_interrupts(void *opaque)
                    217: {
1.1.1.2   root      218:     CPUState *env;
1.1       root      219:     SLAVIO_INTCTLState *s = opaque;
                    220:     uint32_t pending = s->intregm_pending;
1.1.1.2   root      221:     unsigned int i, j, max = 0;
1.1       root      222: 
                    223:     pending &= ~s->intregm_disabled;
                    224: 
                    225:     if (pending && !(s->intregm_disabled & 0x80000000)) {
                    226:        for (i = 0; i < 32; i++) {
                    227:            if (pending & (1 << i)) {
                    228:                if (max < intbit_to_level[i])
                    229:                    max = intbit_to_level[i];
                    230:            }
                    231:        }
1.1.1.2   root      232:         env = s->cpu_envs[s->target_cpu];
                    233:         if (!env) {
                    234:            DPRINTF("No CPU %d, not triggered (pending %x)\n", s->target_cpu, pending);
                    235:         }
                    236:        else {
                    237:             if (env->halted)
                    238:                 env->halted = 0;
                    239:             if (env->interrupt_index == 0) {
                    240:                 DPRINTF("Triggered CPU %d pil %d\n", s->target_cpu, max);
1.1       root      241: #ifdef DEBUG_IRQ_COUNT
1.1.1.2   root      242:                 s->irq_count[max]++;
1.1       root      243: #endif
1.1.1.2   root      244:                 env->interrupt_index = TT_EXTINT | max;
                    245:                 cpu_interrupt(env, CPU_INTERRUPT_HARD);
                    246:             }
                    247:             else
                    248:                 DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, env->interrupt_index);
1.1       root      249:        }
                    250:     }
                    251:     else
                    252:        DPRINTF("Not triggered (pending %x), disabled %x\n", pending, s->intregm_disabled);
1.1.1.2   root      253:     
                    254:     for (i = 0; i < MAX_CPUS; i++) {
                    255:         max = 0;
                    256:         env = s->cpu_envs[i];
                    257:         if (!env)
                    258:             continue;
                    259:         for (j = 17; j < 32; j++) {
                    260:             if (s->intreg_pending[i] & (1 << j)) {
                    261:                 if (max < j - 16)
                    262:                     max = j - 16;
                    263:             }
                    264:         }
                    265:        if (max > 0) {
                    266:             if (env->halted)
                    267:                 env->halted = 0;
                    268:             if (env->interrupt_index == 0) {
                    269:                 DPRINTF("Triggered softint %d for cpu %d (pending %x)\n", max, i, pending);
                    270: #ifdef DEBUG_IRQ_COUNT
                    271:                 s->irq_count[max]++;
                    272: #endif
                    273:                 env->interrupt_index = TT_EXTINT | max;
                    274:                 cpu_interrupt(env, CPU_INTERRUPT_HARD);
                    275:             }
                    276:         }
                    277:     }
1.1       root      278: }
                    279: 
                    280: /*
                    281:  * "irq" here is the bit number in the system interrupt register to
                    282:  * separate serial and keyboard interrupts sharing a level.
                    283:  */
                    284: void slavio_pic_set_irq(void *opaque, int irq, int level)
                    285: {
                    286:     SLAVIO_INTCTLState *s = opaque;
                    287: 
1.1.1.2   root      288:     DPRINTF("Set cpu %d irq %d level %d\n", s->target_cpu, irq, level);
1.1       root      289:     if (irq < 32) {
                    290:        uint32_t mask = 1 << irq;
                    291:        uint32_t pil = intbit_to_level[irq];
                    292:        if (pil > 0) {
                    293:            if (level) {
                    294:                s->intregm_pending |= mask;
                    295:                s->intreg_pending[s->target_cpu] |= 1 << pil;
                    296:            }
                    297:            else {
                    298:                s->intregm_pending &= ~mask;
                    299:                s->intreg_pending[s->target_cpu] &= ~(1 << pil);
                    300:            }
                    301:        }
                    302:     }
                    303:     slavio_check_interrupts(s);
                    304: }
                    305: 
1.1.1.2   root      306: void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu)
                    307: {
                    308:     SLAVIO_INTCTLState *s = opaque;
                    309: 
                    310:     DPRINTF("Set cpu %d local irq %d level %d\n", cpu, irq, level);
                    311:     if (cpu == (unsigned int)-1) {
                    312:         slavio_pic_set_irq(opaque, irq, level);
                    313:         return;
                    314:     }
                    315:     if (irq < 32) {
                    316:        uint32_t pil = intbit_to_level[irq];
                    317:        if (pil > 0) {
                    318:            if (level) {
                    319:                s->intreg_pending[cpu] |= 1 << pil;
                    320:            }
                    321:            else {
                    322:                s->intreg_pending[cpu] &= ~(1 << pil);
                    323:            }
                    324:        }
                    325:     }
                    326:     slavio_check_interrupts(s);
                    327: }
                    328: 
1.1       root      329: static void slavio_intctl_save(QEMUFile *f, void *opaque)
                    330: {
                    331:     SLAVIO_INTCTLState *s = opaque;
                    332:     int i;
                    333:     
                    334:     for (i = 0; i < MAX_CPUS; i++) {
                    335:        qemu_put_be32s(f, &s->intreg_pending[i]);
                    336:     }
                    337:     qemu_put_be32s(f, &s->intregm_pending);
                    338:     qemu_put_be32s(f, &s->intregm_disabled);
                    339:     qemu_put_be32s(f, &s->target_cpu);
                    340: }
                    341: 
                    342: static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id)
                    343: {
                    344:     SLAVIO_INTCTLState *s = opaque;
                    345:     int i;
                    346: 
                    347:     if (version_id != 1)
                    348:         return -EINVAL;
                    349: 
                    350:     for (i = 0; i < MAX_CPUS; i++) {
                    351:        qemu_get_be32s(f, &s->intreg_pending[i]);
                    352:     }
                    353:     qemu_get_be32s(f, &s->intregm_pending);
                    354:     qemu_get_be32s(f, &s->intregm_disabled);
                    355:     qemu_get_be32s(f, &s->target_cpu);
                    356:     return 0;
                    357: }
                    358: 
                    359: static void slavio_intctl_reset(void *opaque)
                    360: {
                    361:     SLAVIO_INTCTLState *s = opaque;
                    362:     int i;
                    363: 
                    364:     for (i = 0; i < MAX_CPUS; i++) {
                    365:        s->intreg_pending[i] = 0;
                    366:     }
                    367:     s->intregm_disabled = ~0xffb2007f;
                    368:     s->intregm_pending = 0;
                    369:     s->target_cpu = 0;
                    370: }
                    371: 
1.1.1.2   root      372: void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env)
                    373: {
                    374:     SLAVIO_INTCTLState *s = opaque;
                    375:     s->cpu_envs[cpu] = env;
                    376: }
                    377: 
1.1       root      378: void *slavio_intctl_init(uint32_t addr, uint32_t addrg)
                    379: {
                    380:     int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;
                    381:     SLAVIO_INTCTLState *s;
                    382: 
                    383:     s = qemu_mallocz(sizeof(SLAVIO_INTCTLState));
                    384:     if (!s)
                    385:         return NULL;
                    386: 
                    387:     for (i = 0; i < MAX_CPUS; i++) {
                    388:        slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s);
                    389:        cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory);
                    390:     }
                    391: 
                    392:     slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s);
                    393:     cpu_register_physical_memory(addrg, INTCTLM_MAXADDR, slavio_intctlm_io_memory);
                    394: 
                    395:     register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s);
                    396:     qemu_register_reset(slavio_intctl_reset, s);
                    397:     slavio_intctl_reset(s);
                    398:     return s;
                    399: }
                    400: 

unix.superglobalmegacorp.com

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