1 /* 2 * QEMU S/390 Interrupt support 3 * 4 * Copyright IBM Corp. 2012, 2014 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or (at your 7 * option) any later version. See the COPYING file in the top-level directory. 8 */ 9 10 #include "qemu/osdep.h" 11 #include "cpu.h" 12 #include "sysemu/kvm.h" 13 #include "hw/s390x/ioinst.h" 14 15 #if !defined(CONFIG_USER_ONLY) 16 void cpu_inject_ext(S390CPU *cpu, uint32_t code, uint32_t param, 17 uint64_t param64) 18 { 19 CPUS390XState *env = &cpu->env; 20 21 if (env->ext_index == MAX_EXT_QUEUE - 1) { 22 /* ugh - can't queue anymore. Let's drop. */ 23 return; 24 } 25 26 env->ext_index++; 27 assert(env->ext_index < MAX_EXT_QUEUE); 28 29 env->ext_queue[env->ext_index].code = code; 30 env->ext_queue[env->ext_index].param = param; 31 env->ext_queue[env->ext_index].param64 = param64; 32 33 env->pending_int |= INTERRUPT_EXT; 34 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 35 } 36 37 static void cpu_inject_io(S390CPU *cpu, uint16_t subchannel_id, 38 uint16_t subchannel_number, 39 uint32_t io_int_parm, uint32_t io_int_word) 40 { 41 CPUS390XState *env = &cpu->env; 42 int isc = IO_INT_WORD_ISC(io_int_word); 43 44 if (env->io_index[isc] == MAX_IO_QUEUE - 1) { 45 /* ugh - can't queue anymore. Let's drop. */ 46 return; 47 } 48 49 env->io_index[isc]++; 50 assert(env->io_index[isc] < MAX_IO_QUEUE); 51 52 env->io_queue[env->io_index[isc]][isc].id = subchannel_id; 53 env->io_queue[env->io_index[isc]][isc].nr = subchannel_number; 54 env->io_queue[env->io_index[isc]][isc].parm = io_int_parm; 55 env->io_queue[env->io_index[isc]][isc].word = io_int_word; 56 57 env->pending_int |= INTERRUPT_IO; 58 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 59 } 60 61 static void cpu_inject_crw_mchk(S390CPU *cpu) 62 { 63 CPUS390XState *env = &cpu->env; 64 65 if (env->mchk_index == MAX_MCHK_QUEUE - 1) { 66 /* ugh - can't queue anymore. Let's drop. */ 67 return; 68 } 69 70 env->mchk_index++; 71 assert(env->mchk_index < MAX_MCHK_QUEUE); 72 73 env->mchk_queue[env->mchk_index].type = 1; 74 75 env->pending_int |= INTERRUPT_MCHK; 76 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 77 } 78 79 /* 80 * All of the following interrupts are floating, i.e. not per-vcpu. 81 * We just need a dummy cpustate in order to be able to inject in the 82 * non-kvm case. 83 */ 84 void s390_sclp_extint(uint32_t parm) 85 { 86 if (kvm_enabled()) { 87 kvm_s390_service_interrupt(parm); 88 } else { 89 S390CPU *dummy_cpu = s390_cpu_addr2state(0); 90 91 cpu_inject_ext(dummy_cpu, EXT_SERVICE, parm, 0); 92 } 93 } 94 95 void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, 96 uint32_t io_int_parm, uint32_t io_int_word) 97 { 98 if (kvm_enabled()) { 99 kvm_s390_io_interrupt(subchannel_id, subchannel_nr, io_int_parm, 100 io_int_word); 101 } else { 102 S390CPU *dummy_cpu = s390_cpu_addr2state(0); 103 104 cpu_inject_io(dummy_cpu, subchannel_id, subchannel_nr, io_int_parm, 105 io_int_word); 106 } 107 } 108 109 void s390_crw_mchk(void) 110 { 111 if (kvm_enabled()) { 112 kvm_s390_crw_mchk(); 113 } else { 114 S390CPU *dummy_cpu = s390_cpu_addr2state(0); 115 116 cpu_inject_crw_mchk(dummy_cpu); 117 } 118 } 119 120 #endif 121