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 "hw/hw.h" 31 #include "trace.h" 32 #include "qemu/timer.h" 33 #include "hw/ppc/spapr.h" 34 #include "hw/ppc/spapr_cpu_core.h" 35 #include "hw/ppc/xics.h" 36 #include "hw/ppc/xics_spapr.h" 37 #include "hw/ppc/fdt.h" 38 #include "qapi/visitor.h" 39 40 /* 41 * Guest interfaces 42 */ 43 44 static bool check_in_kernel_xics(const char *func) 45 { 46 if (kvm_irqchip_in_kernel()) { 47 error_report("pseries: %s must never be called for in-kernel XICS", 48 func); 49 return true; 50 } 51 52 return false; 53 } 54 55 #define CHECK_IN_KERNEL_XICS_HCALL \ 56 do { \ 57 if (check_in_kernel_xics(__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_IN_KERNEL_XICS_HCALL; 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_IN_KERNEL_XICS_HCALL; 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_IN_KERNEL_XICS_HCALL; 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_IN_KERNEL_XICS_HCALL; 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_IN_KERNEL_XICS_HCALL; 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_IN_KERNEL_XICS_HCALL; 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_IN_KERNEL_XICS_RTAS(rets) \ 145 do { \ 146 if (check_in_kernel_xics(__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_IN_KERNEL_XICS_RTAS(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_IN_KERNEL_XICS_RTAS(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_IN_KERNEL_XICS_RTAS(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_IN_KERNEL_XICS_RTAS(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 /* Emulated mode can only be initialized once. */ 289 if (spapr->ics->init) { 290 return; 291 } 292 293 spapr->ics->init = true; 294 295 /* Registration of global state belongs into realize */ 296 spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive); 297 spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive); 298 spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off); 299 spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_int_on); 300 301 spapr_register_hypercall(H_CPPR, h_cppr); 302 spapr_register_hypercall(H_IPI, h_ipi); 303 spapr_register_hypercall(H_XIRR, h_xirr); 304 spapr_register_hypercall(H_XIRR_X, h_xirr_x); 305 spapr_register_hypercall(H_EOI, h_eoi); 306 spapr_register_hypercall(H_IPOLL, h_ipoll); 307 } 308 309 void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt, 310 uint32_t phandle) 311 { 312 uint32_t interrupt_server_ranges_prop[] = { 313 0, cpu_to_be32(nr_servers), 314 }; 315 int node; 316 317 _FDT(node = fdt_add_subnode(fdt, 0, XICS_NODENAME)); 318 319 _FDT(fdt_setprop_string(fdt, node, "device_type", 320 "PowerPC-External-Interrupt-Presentation")); 321 _FDT(fdt_setprop_string(fdt, node, "compatible", "IBM,ppc-xicp")); 322 _FDT(fdt_setprop(fdt, node, "interrupt-controller", NULL, 0)); 323 _FDT(fdt_setprop(fdt, node, "ibm,interrupt-server-ranges", 324 interrupt_server_ranges_prop, 325 sizeof(interrupt_server_ranges_prop))); 326 _FDT(fdt_setprop_cell(fdt, node, "#interrupt-cells", 2)); 327 _FDT(fdt_setprop_cell(fdt, node, "linux,phandle", phandle)); 328 _FDT(fdt_setprop_cell(fdt, node, "phandle", phandle)); 329 } 330