|
|
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 ! 56: } SLAVIO_INTCTLState; ! 57: ! 58: #define INTCTL_MAXADDR 0xf ! 59: #define INTCTLM_MAXADDR 0xf ! 60: static void slavio_check_interrupts(void *opaque); ! 61: ! 62: // per-cpu interrupt controller ! 63: static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr) ! 64: { ! 65: SLAVIO_INTCTLState *s = opaque; ! 66: uint32_t saddr; ! 67: int cpu; ! 68: ! 69: cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12; ! 70: saddr = (addr & INTCTL_MAXADDR) >> 2; ! 71: switch (saddr) { ! 72: case 0: ! 73: return s->intreg_pending[cpu]; ! 74: default: ! 75: break; ! 76: } ! 77: return 0; ! 78: } ! 79: ! 80: static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) ! 81: { ! 82: SLAVIO_INTCTLState *s = opaque; ! 83: uint32_t saddr; ! 84: int cpu; ! 85: ! 86: cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12; ! 87: saddr = (addr & INTCTL_MAXADDR) >> 2; ! 88: switch (saddr) { ! 89: case 1: // clear pending softints ! 90: if (val & 0x4000) ! 91: val |= 80000000; ! 92: val &= 0xfffe0000; ! 93: s->intreg_pending[cpu] &= ~val; ! 94: DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); ! 95: break; ! 96: case 2: // set softint ! 97: val &= 0xfffe0000; ! 98: s->intreg_pending[cpu] |= val; ! 99: DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); ! 100: break; ! 101: default: ! 102: break; ! 103: } ! 104: } ! 105: ! 106: static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = { ! 107: slavio_intctl_mem_readl, ! 108: slavio_intctl_mem_readl, ! 109: slavio_intctl_mem_readl, ! 110: }; ! 111: ! 112: static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = { ! 113: slavio_intctl_mem_writel, ! 114: slavio_intctl_mem_writel, ! 115: slavio_intctl_mem_writel, ! 116: }; ! 117: ! 118: // master system interrupt controller ! 119: static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr) ! 120: { ! 121: SLAVIO_INTCTLState *s = opaque; ! 122: uint32_t saddr; ! 123: ! 124: saddr = (addr & INTCTLM_MAXADDR) >> 2; ! 125: switch (saddr) { ! 126: case 0: ! 127: return s->intregm_pending & 0x7fffffff; ! 128: case 1: ! 129: return s->intregm_disabled; ! 130: case 4: ! 131: return s->target_cpu; ! 132: default: ! 133: break; ! 134: } ! 135: return 0; ! 136: } ! 137: ! 138: static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) ! 139: { ! 140: SLAVIO_INTCTLState *s = opaque; ! 141: uint32_t saddr; ! 142: ! 143: saddr = (addr & INTCTLM_MAXADDR) >> 2; ! 144: switch (saddr) { ! 145: case 2: // clear (enable) ! 146: // Force clear unused bits ! 147: val &= ~0x4fb2007f; ! 148: s->intregm_disabled &= ~val; ! 149: DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); ! 150: slavio_check_interrupts(s); ! 151: break; ! 152: case 3: // set (disable, clear pending) ! 153: // Force clear unused bits ! 154: val &= ~0x4fb2007f; ! 155: s->intregm_disabled |= val; ! 156: s->intregm_pending &= ~val; ! 157: DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); ! 158: break; ! 159: case 4: ! 160: s->target_cpu = val & (MAX_CPUS - 1); ! 161: DPRINTF("Set master irq cpu %d\n", s->target_cpu); ! 162: break; ! 163: default: ! 164: break; ! 165: } ! 166: } ! 167: ! 168: static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = { ! 169: slavio_intctlm_mem_readl, ! 170: slavio_intctlm_mem_readl, ! 171: slavio_intctlm_mem_readl, ! 172: }; ! 173: ! 174: static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = { ! 175: slavio_intctlm_mem_writel, ! 176: slavio_intctlm_mem_writel, ! 177: slavio_intctlm_mem_writel, ! 178: }; ! 179: ! 180: void slavio_pic_info(void *opaque) ! 181: { ! 182: SLAVIO_INTCTLState *s = opaque; ! 183: int i; ! 184: ! 185: for (i = 0; i < MAX_CPUS; i++) { ! 186: term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]); ! 187: } ! 188: term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled); ! 189: } ! 190: ! 191: void slavio_irq_info(void *opaque) ! 192: { ! 193: #ifndef DEBUG_IRQ_COUNT ! 194: term_printf("irq statistic code not compiled.\n"); ! 195: #else ! 196: SLAVIO_INTCTLState *s = opaque; ! 197: int i; ! 198: int64_t count; ! 199: ! 200: term_printf("IRQ statistics:\n"); ! 201: for (i = 0; i < 32; i++) { ! 202: count = s->irq_count[i]; ! 203: if (count > 0) ! 204: term_printf("%2d: %lld\n", i, count); ! 205: } ! 206: #endif ! 207: } ! 208: ! 209: static const uint32_t intbit_to_level[32] = { ! 210: 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, ! 211: 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, ! 212: }; ! 213: ! 214: static void slavio_check_interrupts(void *opaque) ! 215: { ! 216: SLAVIO_INTCTLState *s = opaque; ! 217: uint32_t pending = s->intregm_pending; ! 218: unsigned int i, max = 0; ! 219: ! 220: pending &= ~s->intregm_disabled; ! 221: ! 222: if (pending && !(s->intregm_disabled & 0x80000000)) { ! 223: for (i = 0; i < 32; i++) { ! 224: if (pending & (1 << i)) { ! 225: if (max < intbit_to_level[i]) ! 226: max = intbit_to_level[i]; ! 227: } ! 228: } ! 229: if (cpu_single_env->interrupt_index == 0) { ! 230: DPRINTF("Triggered pil %d\n", max); ! 231: #ifdef DEBUG_IRQ_COUNT ! 232: s->irq_count[max]++; ! 233: #endif ! 234: cpu_single_env->interrupt_index = TT_EXTINT | max; ! 235: cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); ! 236: } ! 237: else ! 238: DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, cpu_single_env->interrupt_index); ! 239: } ! 240: else ! 241: DPRINTF("Not triggered (pending %x), disabled %x\n", pending, s->intregm_disabled); ! 242: } ! 243: ! 244: /* ! 245: * "irq" here is the bit number in the system interrupt register to ! 246: * separate serial and keyboard interrupts sharing a level. ! 247: */ ! 248: void slavio_pic_set_irq(void *opaque, int irq, int level) ! 249: { ! 250: SLAVIO_INTCTLState *s = opaque; ! 251: ! 252: DPRINTF("Set irq %d level %d\n", irq, level); ! 253: if (irq < 32) { ! 254: uint32_t mask = 1 << irq; ! 255: uint32_t pil = intbit_to_level[irq]; ! 256: if (pil > 0) { ! 257: if (level) { ! 258: s->intregm_pending |= mask; ! 259: s->intreg_pending[s->target_cpu] |= 1 << pil; ! 260: } ! 261: else { ! 262: s->intregm_pending &= ~mask; ! 263: s->intreg_pending[s->target_cpu] &= ~(1 << pil); ! 264: } ! 265: } ! 266: } ! 267: slavio_check_interrupts(s); ! 268: } ! 269: ! 270: static void slavio_intctl_save(QEMUFile *f, void *opaque) ! 271: { ! 272: SLAVIO_INTCTLState *s = opaque; ! 273: int i; ! 274: ! 275: for (i = 0; i < MAX_CPUS; i++) { ! 276: qemu_put_be32s(f, &s->intreg_pending[i]); ! 277: } ! 278: qemu_put_be32s(f, &s->intregm_pending); ! 279: qemu_put_be32s(f, &s->intregm_disabled); ! 280: qemu_put_be32s(f, &s->target_cpu); ! 281: } ! 282: ! 283: static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id) ! 284: { ! 285: SLAVIO_INTCTLState *s = opaque; ! 286: int i; ! 287: ! 288: if (version_id != 1) ! 289: return -EINVAL; ! 290: ! 291: for (i = 0; i < MAX_CPUS; i++) { ! 292: qemu_get_be32s(f, &s->intreg_pending[i]); ! 293: } ! 294: qemu_get_be32s(f, &s->intregm_pending); ! 295: qemu_get_be32s(f, &s->intregm_disabled); ! 296: qemu_get_be32s(f, &s->target_cpu); ! 297: return 0; ! 298: } ! 299: ! 300: static void slavio_intctl_reset(void *opaque) ! 301: { ! 302: SLAVIO_INTCTLState *s = opaque; ! 303: int i; ! 304: ! 305: for (i = 0; i < MAX_CPUS; i++) { ! 306: s->intreg_pending[i] = 0; ! 307: } ! 308: s->intregm_disabled = ~0xffb2007f; ! 309: s->intregm_pending = 0; ! 310: s->target_cpu = 0; ! 311: } ! 312: ! 313: void *slavio_intctl_init(uint32_t addr, uint32_t addrg) ! 314: { ! 315: int slavio_intctl_io_memory, slavio_intctlm_io_memory, i; ! 316: SLAVIO_INTCTLState *s; ! 317: ! 318: s = qemu_mallocz(sizeof(SLAVIO_INTCTLState)); ! 319: if (!s) ! 320: return NULL; ! 321: ! 322: for (i = 0; i < MAX_CPUS; i++) { ! 323: slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s); ! 324: cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory); ! 325: } ! 326: ! 327: slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s); ! 328: cpu_register_physical_memory(addrg, INTCTLM_MAXADDR, slavio_intctlm_io_memory); ! 329: ! 330: register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s); ! 331: qemu_register_reset(slavio_intctl_reset, s); ! 332: slavio_intctl_reset(s); ! 333: return s; ! 334: } ! 335:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.