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