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