1 /* 2 * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator 3 * 4 * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics 5 * 6 * Copyright (c) 2010,2011 David Gibson, IBM Corporation. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a copy 9 * of this software and associated documentation files (the "Software"), to deal 10 * in the Software without restriction, including without limitation the rights 11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 * copies of the Software, and to permit persons to whom the Software is 13 * furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included in 16 * all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 * THE SOFTWARE. 25 * 26 */ 27 28 #include "qemu/osdep.h" 29 #include "cpu.h" 30 #include "trace.h" 31 #include "qemu/timer.h" 32 #include "hw/ppc/spapr.h" 33 #include "hw/ppc/spapr_cpu_core.h" 34 #include "hw/ppc/xics.h" 35 #include "hw/ppc/xics_spapr.h" 36 #include "hw/ppc/fdt.h" 37 #include "qapi/visitor.h" 38 39 /* 40 * Guest interfaces 41 */ 42 43 static bool check_emulated_xics(SpaprMachineState *spapr, const char *func) 44 { 45 if (spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT) || 46 kvm_irqchip_in_kernel()) { 47 error_report("pseries: %s must only be called for emulated XICS", 48 func); 49 return false; 50 } 51 52 return true; 53 } 54 55 #define CHECK_EMULATED_XICS_HCALL(spapr) \ 56 do { \ 57 if (!check_emulated_xics((spapr), __func__)) { \ 58 return H_HARDWARE; \ 59 } \ 60 } while (0) 61 62 static target_ulong h_cppr(PowerPCCPU *cpu, SpaprMachineState *spapr, 63 target_ulong opcode, target_ulong *args) 64 { 65 target_ulong cppr = args[0]; 66 67 CHECK_EMULATED_XICS_HCALL(spapr); 68 69 icp_set_cppr(spapr_cpu_state(cpu)->icp, cppr); 70 return H_SUCCESS; 71 } 72 73 static target_ulong h_ipi(PowerPCCPU *cpu, SpaprMachineState *spapr, 74 target_ulong opcode, target_ulong *args) 75 { 76 target_ulong mfrr = args[1]; 77 ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), args[0]); 78 79 CHECK_EMULATED_XICS_HCALL(spapr); 80 81 if (!icp) { 82 return H_PARAMETER; 83 } 84 85 icp_set_mfrr(icp, mfrr); 86 return H_SUCCESS; 87 } 88 89 static target_ulong h_xirr(PowerPCCPU *cpu, SpaprMachineState *spapr, 90 target_ulong opcode, target_ulong *args) 91 { 92 uint32_t xirr = icp_accept(spapr_cpu_state(cpu)->icp); 93 94 CHECK_EMULATED_XICS_HCALL(spapr); 95 96 args[0] = xirr; 97 return H_SUCCESS; 98 } 99 100 static target_ulong h_xirr_x(PowerPCCPU *cpu, SpaprMachineState *spapr, 101 target_ulong opcode, target_ulong *args) 102 { 103 uint32_t xirr = icp_accept(spapr_cpu_state(cpu)->icp); 104 105 CHECK_EMULATED_XICS_HCALL(spapr); 106 107 args[0] = xirr; 108 args[1] = cpu_get_host_ticks(); 109 return H_SUCCESS; 110 } 111 112 static target_ulong h_eoi(PowerPCCPU *cpu, SpaprMachineState *spapr, 113 target_ulong opcode, target_ulong *args) 114 { 115 target_ulong xirr = args[0]; 116 117 CHECK_EMULATED_XICS_HCALL(spapr); 118 119 icp_eoi(spapr_cpu_state(cpu)->icp, xirr); 120 return H_SUCCESS; 121 } 122 123 static target_ulong h_ipoll(PowerPCCPU *cpu, SpaprMachineState *spapr, 124 target_ulong opcode, target_ulong *args) 125 { 126 ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), args[0]); 127 uint32_t mfrr; 128 uint32_t xirr; 129 130 CHECK_EMULATED_XICS_HCALL(spapr); 131 132 if (!icp) { 133 return H_PARAMETER; 134 } 135 136 xirr = icp_ipoll(icp, &mfrr); 137 138 args[0] = xirr; 139 args[1] = mfrr; 140 141 return H_SUCCESS; 142 } 143 144 #define CHECK_EMULATED_XICS_RTAS(spapr, rets) \ 145 do { \ 146 if (!check_emulated_xics((spapr), __func__)) { \ 147 rtas_st((rets), 0, RTAS_OUT_HW_ERROR); \ 148 return; \ 149 } \ 150 } while (0) 151 152 static void rtas_set_xive(PowerPCCPU *cpu, SpaprMachineState *spapr, 153 uint32_t token, 154 uint32_t nargs, target_ulong args, 155 uint32_t nret, target_ulong rets) 156 { 157 ICSState *ics = spapr->ics; 158 uint32_t nr, srcno, server, priority; 159 160 CHECK_EMULATED_XICS_RTAS(spapr, rets); 161 162 if ((nargs != 3) || (nret != 1)) { 163 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 164 return; 165 } 166 if (!ics) { 167 rtas_st(rets, 0, RTAS_OUT_HW_ERROR); 168 return; 169 } 170 171 nr = rtas_ld(args, 0); 172 server = rtas_ld(args, 1); 173 priority = rtas_ld(args, 2); 174 175 if (!ics_valid_irq(ics, nr) || !xics_icp_get(XICS_FABRIC(spapr), server) 176 || (priority > 0xff)) { 177 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 178 return; 179 } 180 181 srcno = nr - ics->offset; 182 ics_simple_write_xive(ics, srcno, server, priority, priority); 183 184 rtas_st(rets, 0, RTAS_OUT_SUCCESS); 185 } 186 187 static void rtas_get_xive(PowerPCCPU *cpu, SpaprMachineState *spapr, 188 uint32_t token, 189 uint32_t nargs, target_ulong args, 190 uint32_t nret, target_ulong rets) 191 { 192 ICSState *ics = spapr->ics; 193 uint32_t nr, srcno; 194 195 CHECK_EMULATED_XICS_RTAS(spapr, rets); 196 197 if ((nargs != 1) || (nret != 3)) { 198 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 199 return; 200 } 201 if (!ics) { 202 rtas_st(rets, 0, RTAS_OUT_HW_ERROR); 203 return; 204 } 205 206 nr = rtas_ld(args, 0); 207 208 if (!ics_valid_irq(ics, nr)) { 209 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 210 return; 211 } 212 213 rtas_st(rets, 0, RTAS_OUT_SUCCESS); 214 srcno = nr - ics->offset; 215 rtas_st(rets, 1, ics->irqs[srcno].server); 216 rtas_st(rets, 2, ics->irqs[srcno].priority); 217 } 218 219 static void rtas_int_off(PowerPCCPU *cpu, SpaprMachineState *spapr, 220 uint32_t token, 221 uint32_t nargs, target_ulong args, 222 uint32_t nret, target_ulong rets) 223 { 224 ICSState *ics = spapr->ics; 225 uint32_t nr, srcno; 226 227 CHECK_EMULATED_XICS_RTAS(spapr, rets); 228 229 if ((nargs != 1) || (nret != 1)) { 230 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 231 return; 232 } 233 if (!ics) { 234 rtas_st(rets, 0, RTAS_OUT_HW_ERROR); 235 return; 236 } 237 238 nr = rtas_ld(args, 0); 239 240 if (!ics_valid_irq(ics, nr)) { 241 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 242 return; 243 } 244 245 srcno = nr - ics->offset; 246 ics_simple_write_xive(ics, srcno, ics->irqs[srcno].server, 0xff, 247 ics->irqs[srcno].priority); 248 249 rtas_st(rets, 0, RTAS_OUT_SUCCESS); 250 } 251 252 static void rtas_int_on(PowerPCCPU *cpu, SpaprMachineState *spapr, 253 uint32_t token, 254 uint32_t nargs, target_ulong args, 255 uint32_t nret, target_ulong rets) 256 { 257 ICSState *ics = spapr->ics; 258 uint32_t nr, srcno; 259 260 CHECK_EMULATED_XICS_RTAS(spapr, rets); 261 262 if ((nargs != 1) || (nret != 1)) { 263 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 264 return; 265 } 266 if (!ics) { 267 rtas_st(rets, 0, RTAS_OUT_HW_ERROR); 268 return; 269 } 270 271 nr = rtas_ld(args, 0); 272 273 if (!ics_valid_irq(ics, nr)) { 274 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 275 return; 276 } 277 278 srcno = nr - ics->offset; 279 ics_simple_write_xive(ics, srcno, ics->irqs[srcno].server, 280 ics->irqs[srcno].saved_priority, 281 ics->irqs[srcno].saved_priority); 282 283 rtas_st(rets, 0, RTAS_OUT_SUCCESS); 284 } 285 286 void xics_spapr_init(SpaprMachineState *spapr) 287 { 288 spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive); 289 spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive); 290 spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off); 291 spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_int_on); 292 293 spapr_register_hypercall(H_CPPR, h_cppr); 294 spapr_register_hypercall(H_IPI, h_ipi); 295 spapr_register_hypercall(H_XIRR, h_xirr); 296 spapr_register_hypercall(H_XIRR_X, h_xirr_x); 297 spapr_register_hypercall(H_EOI, h_eoi); 298 spapr_register_hypercall(H_IPOLL, h_ipoll); 299 } 300 301 void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt, 302 uint32_t phandle) 303 { 304 uint32_t interrupt_server_ranges_prop[] = { 305 0, cpu_to_be32(nr_servers), 306 }; 307 int node; 308 309 _FDT(node = fdt_add_subnode(fdt, 0, XICS_NODENAME)); 310 311 _FDT(fdt_setprop_string(fdt, node, "device_type", 312 "PowerPC-External-Interrupt-Presentation")); 313 _FDT(fdt_setprop_string(fdt, node, "compatible", "IBM,ppc-xicp")); 314 _FDT(fdt_setprop(fdt, node, "interrupt-controller", NULL, 0)); 315 _FDT(fdt_setprop(fdt, node, "ibm,interrupt-server-ranges", 316 interrupt_server_ranges_prop, 317 sizeof(interrupt_server_ranges_prop))); 318 _FDT(fdt_setprop_cell(fdt, node, "#interrupt-cells", 2)); 319 _FDT(fdt_setprop_cell(fdt, node, "linux,phandle", phandle)); 320 _FDT(fdt_setprop_cell(fdt, node, "phandle", phandle)); 321 } 322