153018216SPaolo Bonzini /* 253018216SPaolo Bonzini * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. 353018216SPaolo Bonzini * All rights reserved. 453018216SPaolo Bonzini * 553018216SPaolo Bonzini * Redistribution and use in source and binary forms, with or without 653018216SPaolo Bonzini * modification, are permitted provided that the following conditions are met: 753018216SPaolo Bonzini * * Redistributions of source code must retain the above copyright 853018216SPaolo Bonzini * notice, this list of conditions and the following disclaimer. 953018216SPaolo Bonzini * * Redistributions in binary form must reproduce the above copyright 1053018216SPaolo Bonzini * notice, this list of conditions and the following disclaimer in the 1153018216SPaolo Bonzini * documentation and/or other materials provided with the distribution. 1253018216SPaolo Bonzini * * Neither the name of the Open Source and Linux Lab nor the 1353018216SPaolo Bonzini * names of its contributors may be used to endorse or promote products 1453018216SPaolo Bonzini * derived from this software without specific prior written permission. 1553018216SPaolo Bonzini * 1653018216SPaolo Bonzini * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1753018216SPaolo Bonzini * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1853018216SPaolo Bonzini * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1953018216SPaolo Bonzini * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 2053018216SPaolo Bonzini * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2153018216SPaolo Bonzini * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2253018216SPaolo Bonzini * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 2353018216SPaolo Bonzini * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2453018216SPaolo Bonzini * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 2553018216SPaolo Bonzini * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2653018216SPaolo Bonzini */ 2753018216SPaolo Bonzini 2809aae23dSPeter Maydell #include "qemu/osdep.h" 2933c11879SPaolo Bonzini #include "cpu.h" 3064552b6bSMarkus Armbruster #include "hw/irq.h" 3153018216SPaolo Bonzini #include "qemu/log.h" 3253018216SPaolo Bonzini #include "qemu/timer.h" 3353018216SPaolo Bonzini 3453018216SPaolo Bonzini void check_interrupts(CPUXtensaState *env) 3553018216SPaolo Bonzini { 3692fddfbdSRichard Henderson CPUState *cs = env_cpu(env); 3753018216SPaolo Bonzini int minlevel = xtensa_get_cintlevel(env); 38*a7d479eeSMax Filippov uint32_t int_set_enabled = env->sregs[INTSET] & 39*a7d479eeSMax Filippov (env->sregs[INTENABLE] | env->config->inttype_mask[INTTYPE_NMI]); 4053018216SPaolo Bonzini int level; 4153018216SPaolo Bonzini 42*a7d479eeSMax Filippov if (minlevel >= env->config->nmi_level) { 43*a7d479eeSMax Filippov minlevel = env->config->nmi_level - 1; 44*a7d479eeSMax Filippov } 4553018216SPaolo Bonzini for (level = env->config->nlevel; level > minlevel; --level) { 4653018216SPaolo Bonzini if (env->config->level_mask[level] & int_set_enabled) { 4753018216SPaolo Bonzini env->pending_irq_level = level; 48c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_HARD); 4953018216SPaolo Bonzini qemu_log_mask(CPU_LOG_INT, 5053018216SPaolo Bonzini "%s level = %d, cintlevel = %d, " 5153018216SPaolo Bonzini "pc = %08x, a0 = %08x, ps = %08x, " 5253018216SPaolo Bonzini "intset = %08x, intenable = %08x, " 5353018216SPaolo Bonzini "ccount = %08x\n", 5453018216SPaolo Bonzini __func__, level, xtensa_get_cintlevel(env), 5553018216SPaolo Bonzini env->pc, env->regs[0], env->sregs[PS], 5653018216SPaolo Bonzini env->sregs[INTSET], env->sregs[INTENABLE], 5753018216SPaolo Bonzini env->sregs[CCOUNT]); 5853018216SPaolo Bonzini return; 5953018216SPaolo Bonzini } 6053018216SPaolo Bonzini } 6153018216SPaolo Bonzini env->pending_irq_level = 0; 62d8ed887bSAndreas Färber cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); 6353018216SPaolo Bonzini } 6453018216SPaolo Bonzini 6553018216SPaolo Bonzini static void xtensa_set_irq(void *opaque, int irq, int active) 6653018216SPaolo Bonzini { 6753018216SPaolo Bonzini CPUXtensaState *env = opaque; 6853018216SPaolo Bonzini 6953018216SPaolo Bonzini if (irq >= env->config->ninterrupt) { 7053018216SPaolo Bonzini qemu_log("%s: bad IRQ %d\n", __func__, irq); 7153018216SPaolo Bonzini } else { 7253018216SPaolo Bonzini uint32_t irq_bit = 1 << irq; 7353018216SPaolo Bonzini 7453018216SPaolo Bonzini if (active) { 75fa92bd4aSMax Filippov atomic_or(&env->sregs[INTSET], irq_bit); 7653018216SPaolo Bonzini } else if (env->config->interrupt[irq].inttype == INTTYPE_LEVEL) { 77fa92bd4aSMax Filippov atomic_and(&env->sregs[INTSET], ~irq_bit); 7853018216SPaolo Bonzini } 7953018216SPaolo Bonzini 8053018216SPaolo Bonzini check_interrupts(env); 8153018216SPaolo Bonzini } 8253018216SPaolo Bonzini } 8353018216SPaolo Bonzini 8453018216SPaolo Bonzini static void xtensa_ccompare_cb(void *opaque) 8553018216SPaolo Bonzini { 8659a71f75SMax Filippov XtensaCcompareTimer *ccompare = opaque; 8759a71f75SMax Filippov CPUXtensaState *env = ccompare->env; 8859a71f75SMax Filippov unsigned i = ccompare - env->ccompare; 8953018216SPaolo Bonzini 903f75038aSMax Filippov qemu_set_irq(env->irq_inputs[env->config->timerint[i]], 1); 9153018216SPaolo Bonzini } 9253018216SPaolo Bonzini 9317a86b0eSMax Filippov static void xtensa_set_runstall(void *opaque, int irq, int active) 9417a86b0eSMax Filippov { 9517a86b0eSMax Filippov CPUXtensaState *env = opaque; 9617a86b0eSMax Filippov xtensa_runstall(env, active); 9717a86b0eSMax Filippov } 9817a86b0eSMax Filippov 9953018216SPaolo Bonzini void xtensa_irq_init(CPUXtensaState *env) 10053018216SPaolo Bonzini { 10159a71f75SMax Filippov unsigned i; 10259a71f75SMax Filippov 10366f03d7eSMax Filippov env->irq_inputs = qemu_allocate_irqs(xtensa_set_irq, env, 10466f03d7eSMax Filippov env->config->ninterrupt); 10566f03d7eSMax Filippov if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) { 10659a71f75SMax Filippov env->time_base = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 10759a71f75SMax Filippov env->ccount_base = env->sregs[CCOUNT]; 10859a71f75SMax Filippov for (i = 0; i < env->config->nccompare; ++i) { 10959a71f75SMax Filippov env->ccompare[i].env = env; 11059a71f75SMax Filippov env->ccompare[i].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 11159a71f75SMax Filippov xtensa_ccompare_cb, env->ccompare + i); 11259a71f75SMax Filippov } 11353018216SPaolo Bonzini } 11466f03d7eSMax Filippov for (i = 0; i < env->config->nextint; ++i) { 11566f03d7eSMax Filippov unsigned irq = env->config->extint[i]; 11666f03d7eSMax Filippov 11766f03d7eSMax Filippov env->ext_irq_inputs[i] = env->irq_inputs[irq]; 11866f03d7eSMax Filippov } 11917a86b0eSMax Filippov env->runstall_irq = qemu_allocate_irq(xtensa_set_runstall, env, 0); 12053018216SPaolo Bonzini } 12153018216SPaolo Bonzini 12266f03d7eSMax Filippov qemu_irq *xtensa_get_extints(CPUXtensaState *env) 12353018216SPaolo Bonzini { 12466f03d7eSMax Filippov return env->ext_irq_inputs; 12553018216SPaolo Bonzini } 12617a86b0eSMax Filippov 12717a86b0eSMax Filippov qemu_irq xtensa_get_runstall(CPUXtensaState *env) 12817a86b0eSMax Filippov { 12917a86b0eSMax Filippov return env->runstall_irq; 13017a86b0eSMax Filippov } 131