xref: /qemu/target/s390x/interrupt.c (revision 937470bb)
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