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_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_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_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 static void ics_spapr_realize(DeviceState *dev, Error **errp) 287 { 288 ICSState *ics = ICS_SPAPR(dev); 289 ICSStateClass *icsc = ICS_GET_CLASS(ics); 290 Error *local_err = NULL; 291 292 icsc->parent_realize(dev, &local_err); 293 if (local_err) { 294 error_propagate(errp, local_err); 295 return; 296 } 297 298 spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive); 299 spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive); 300 spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off); 301 spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_int_on); 302 303 spapr_register_hypercall(H_CPPR, h_cppr); 304 spapr_register_hypercall(H_IPI, h_ipi); 305 spapr_register_hypercall(H_XIRR, h_xirr); 306 spapr_register_hypercall(H_XIRR_X, h_xirr_x); 307 spapr_register_hypercall(H_EOI, h_eoi); 308 spapr_register_hypercall(H_IPOLL, h_ipoll); 309 } 310 311 void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt, 312 uint32_t phandle) 313 { 314 uint32_t interrupt_server_ranges_prop[] = { 315 0, cpu_to_be32(nr_servers), 316 }; 317 int node; 318 319 _FDT(node = fdt_add_subnode(fdt, 0, XICS_NODENAME)); 320 321 _FDT(fdt_setprop_string(fdt, node, "device_type", 322 "PowerPC-External-Interrupt-Presentation")); 323 _FDT(fdt_setprop_string(fdt, node, "compatible", "IBM,ppc-xicp")); 324 _FDT(fdt_setprop(fdt, node, "interrupt-controller", NULL, 0)); 325 _FDT(fdt_setprop(fdt, node, "ibm,interrupt-server-ranges", 326 interrupt_server_ranges_prop, 327 sizeof(interrupt_server_ranges_prop))); 328 _FDT(fdt_setprop_cell(fdt, node, "#interrupt-cells", 2)); 329 _FDT(fdt_setprop_cell(fdt, node, "linux,phandle", phandle)); 330 _FDT(fdt_setprop_cell(fdt, node, "phandle", phandle)); 331 } 332 333 static void ics_spapr_class_init(ObjectClass *klass, void *data) 334 { 335 DeviceClass *dc = DEVICE_CLASS(klass); 336 ICSStateClass *isc = ICS_CLASS(klass); 337 338 device_class_set_parent_realize(dc, ics_spapr_realize, 339 &isc->parent_realize); 340 } 341 342 static const TypeInfo ics_spapr_info = { 343 .name = TYPE_ICS_SPAPR, 344 .parent = TYPE_ICS, 345 .class_init = ics_spapr_class_init, 346 }; 347 348 static void xics_spapr_register_types(void) 349 { 350 type_register_static(&ics_spapr_info); 351 } 352 353 type_init(xics_spapr_register_types) 354