qemu/hw/intc/xics_spapr.c
<<
>>
Prefs
   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
  44static bool check_emulated_xics(SpaprMachineState *spapr, const char *func)
  45{
  46    if (spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT) ||
  47        kvm_irqchip_in_kernel()) {
  48        error_report("pseries: %s must only be called for emulated XICS",
  49                     func);
  50        return false;
  51    }
  52
  53    return true;
  54}
  55
  56#define CHECK_EMULATED_XICS_HCALL(spapr)               \
  57    do {                                               \
  58        if (!check_emulated_xics((spapr), __func__)) { \
  59            return H_HARDWARE;                         \
  60        }                                              \
  61    } while (0)
  62
  63static target_ulong h_cppr(PowerPCCPU *cpu, SpaprMachineState *spapr,
  64                           target_ulong opcode, target_ulong *args)
  65{
  66    target_ulong cppr = args[0];
  67
  68    CHECK_EMULATED_XICS_HCALL(spapr);
  69
  70    icp_set_cppr(spapr_cpu_state(cpu)->icp, cppr);
  71    return H_SUCCESS;
  72}
  73
  74static target_ulong h_ipi(PowerPCCPU *cpu, SpaprMachineState *spapr,
  75                          target_ulong opcode, target_ulong *args)
  76{
  77    target_ulong mfrr = args[1];
  78    ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), args[0]);
  79
  80    CHECK_EMULATED_XICS_HCALL(spapr);
  81
  82    if (!icp) {
  83        return H_PARAMETER;
  84    }
  85
  86    icp_set_mfrr(icp, mfrr);
  87    return H_SUCCESS;
  88}
  89
  90static target_ulong h_xirr(PowerPCCPU *cpu, SpaprMachineState *spapr,
  91                           target_ulong opcode, target_ulong *args)
  92{
  93    uint32_t xirr = icp_accept(spapr_cpu_state(cpu)->icp);
  94
  95    CHECK_EMULATED_XICS_HCALL(spapr);
  96
  97    args[0] = xirr;
  98    return H_SUCCESS;
  99}
 100
 101static target_ulong h_xirr_x(PowerPCCPU *cpu, SpaprMachineState *spapr,
 102                             target_ulong opcode, target_ulong *args)
 103{
 104    uint32_t xirr = icp_accept(spapr_cpu_state(cpu)->icp);
 105
 106    CHECK_EMULATED_XICS_HCALL(spapr);
 107
 108    args[0] = xirr;
 109    args[1] = cpu_get_host_ticks();
 110    return H_SUCCESS;
 111}
 112
 113static target_ulong h_eoi(PowerPCCPU *cpu, SpaprMachineState *spapr,
 114                          target_ulong opcode, target_ulong *args)
 115{
 116    target_ulong xirr = args[0];
 117
 118    CHECK_EMULATED_XICS_HCALL(spapr);
 119
 120    icp_eoi(spapr_cpu_state(cpu)->icp, xirr);
 121    return H_SUCCESS;
 122}
 123
 124static target_ulong h_ipoll(PowerPCCPU *cpu, SpaprMachineState *spapr,
 125                            target_ulong opcode, target_ulong *args)
 126{
 127    ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), args[0]);
 128    uint32_t mfrr;
 129    uint32_t xirr;
 130
 131    CHECK_EMULATED_XICS_HCALL(spapr);
 132
 133    if (!icp) {
 134        return H_PARAMETER;
 135    }
 136
 137    xirr = icp_ipoll(icp, &mfrr);
 138
 139    args[0] = xirr;
 140    args[1] = mfrr;
 141
 142    return H_SUCCESS;
 143}
 144
 145#define CHECK_EMULATED_XICS_RTAS(spapr, rets)          \
 146    do {                                               \
 147        if (!check_emulated_xics((spapr), __func__)) { \
 148            rtas_st((rets), 0, RTAS_OUT_HW_ERROR);     \
 149            return;                                    \
 150        }                                              \
 151    } while (0)
 152
 153static void rtas_set_xive(PowerPCCPU *cpu, SpaprMachineState *spapr,
 154                          uint32_t token,
 155                          uint32_t nargs, target_ulong args,
 156                          uint32_t nret, target_ulong rets)
 157{
 158    ICSState *ics = spapr->ics;
 159    uint32_t nr, srcno, server, priority;
 160
 161    CHECK_EMULATED_XICS_RTAS(spapr, rets);
 162
 163    if ((nargs != 3) || (nret != 1)) {
 164        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
 165        return;
 166    }
 167    if (!ics) {
 168        rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
 169        return;
 170    }
 171
 172    nr = rtas_ld(args, 0);
 173    server = rtas_ld(args, 1);
 174    priority = rtas_ld(args, 2);
 175
 176    if (!ics_valid_irq(ics, nr) || !xics_icp_get(XICS_FABRIC(spapr), server)
 177        || (priority > 0xff)) {
 178        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
 179        return;
 180    }
 181
 182    srcno = nr - ics->offset;
 183    ics_simple_write_xive(ics, srcno, server, priority, priority);
 184
 185    rtas_st(rets, 0, RTAS_OUT_SUCCESS);
 186}
 187
 188static void rtas_get_xive(PowerPCCPU *cpu, SpaprMachineState *spapr,
 189                          uint32_t token,
 190                          uint32_t nargs, target_ulong args,
 191                          uint32_t nret, target_ulong rets)
 192{
 193    ICSState *ics = spapr->ics;
 194    uint32_t nr, srcno;
 195
 196    CHECK_EMULATED_XICS_RTAS(spapr, rets);
 197
 198    if ((nargs != 1) || (nret != 3)) {
 199        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
 200        return;
 201    }
 202    if (!ics) {
 203        rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
 204        return;
 205    }
 206
 207    nr = rtas_ld(args, 0);
 208
 209    if (!ics_valid_irq(ics, nr)) {
 210        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
 211        return;
 212    }
 213
 214    rtas_st(rets, 0, RTAS_OUT_SUCCESS);
 215    srcno = nr - ics->offset;
 216    rtas_st(rets, 1, ics->irqs[srcno].server);
 217    rtas_st(rets, 2, ics->irqs[srcno].priority);
 218}
 219
 220static void rtas_int_off(PowerPCCPU *cpu, SpaprMachineState *spapr,
 221                         uint32_t token,
 222                         uint32_t nargs, target_ulong args,
 223                         uint32_t nret, target_ulong rets)
 224{
 225    ICSState *ics = spapr->ics;
 226    uint32_t nr, srcno;
 227
 228    CHECK_EMULATED_XICS_RTAS(spapr, rets);
 229
 230    if ((nargs != 1) || (nret != 1)) {
 231        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
 232        return;
 233    }
 234    if (!ics) {
 235        rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
 236        return;
 237    }
 238
 239    nr = rtas_ld(args, 0);
 240
 241    if (!ics_valid_irq(ics, nr)) {
 242        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
 243        return;
 244    }
 245
 246    srcno = nr - ics->offset;
 247    ics_simple_write_xive(ics, srcno, ics->irqs[srcno].server, 0xff,
 248                          ics->irqs[srcno].priority);
 249
 250    rtas_st(rets, 0, RTAS_OUT_SUCCESS);
 251}
 252
 253static void rtas_int_on(PowerPCCPU *cpu, SpaprMachineState *spapr,
 254                        uint32_t token,
 255                        uint32_t nargs, target_ulong args,
 256                        uint32_t nret, target_ulong rets)
 257{
 258    ICSState *ics = spapr->ics;
 259    uint32_t nr, srcno;
 260
 261    CHECK_EMULATED_XICS_RTAS(spapr, rets);
 262
 263    if ((nargs != 1) || (nret != 1)) {
 264        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
 265        return;
 266    }
 267    if (!ics) {
 268        rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
 269        return;
 270    }
 271
 272    nr = rtas_ld(args, 0);
 273
 274    if (!ics_valid_irq(ics, nr)) {
 275        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
 276        return;
 277    }
 278
 279    srcno = nr - ics->offset;
 280    ics_simple_write_xive(ics, srcno, ics->irqs[srcno].server,
 281                          ics->irqs[srcno].saved_priority,
 282                          ics->irqs[srcno].saved_priority);
 283
 284    rtas_st(rets, 0, RTAS_OUT_SUCCESS);
 285}
 286
 287void xics_spapr_init(SpaprMachineState *spapr)
 288{
 289    spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive);
 290    spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive);
 291    spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off);
 292    spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_int_on);
 293
 294    spapr_register_hypercall(H_CPPR, h_cppr);
 295    spapr_register_hypercall(H_IPI, h_ipi);
 296    spapr_register_hypercall(H_XIRR, h_xirr);
 297    spapr_register_hypercall(H_XIRR_X, h_xirr_x);
 298    spapr_register_hypercall(H_EOI, h_eoi);
 299    spapr_register_hypercall(H_IPOLL, h_ipoll);
 300}
 301
 302void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt,
 303                   uint32_t phandle)
 304{
 305    uint32_t interrupt_server_ranges_prop[] = {
 306        0, cpu_to_be32(nr_servers),
 307    };
 308    int node;
 309
 310    _FDT(node = fdt_add_subnode(fdt, 0, XICS_NODENAME));
 311
 312    _FDT(fdt_setprop_string(fdt, node, "device_type",
 313                            "PowerPC-External-Interrupt-Presentation"));
 314    _FDT(fdt_setprop_string(fdt, node, "compatible", "IBM,ppc-xicp"));
 315    _FDT(fdt_setprop(fdt, node, "interrupt-controller", NULL, 0));
 316    _FDT(fdt_setprop(fdt, node, "ibm,interrupt-server-ranges",
 317                     interrupt_server_ranges_prop,
 318                     sizeof(interrupt_server_ranges_prop)));
 319    _FDT(fdt_setprop_cell(fdt, node, "#interrupt-cells", 2));
 320    _FDT(fdt_setprop_cell(fdt, node, "linux,phandle", phandle));
 321    _FDT(fdt_setprop_cell(fdt, node, "phandle", phandle));
 322}
 323