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 "qapi/visitor.h"
  36#include "qapi/error.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    CPUState *cs = CPU(cpu);
  46    target_ulong cppr = args[0];
  47
  48    icp_set_cppr(spapr->xics, cs->cpu_index, cppr);
  49    return H_SUCCESS;
  50}
  51
  52static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
  53                          target_ulong opcode, target_ulong *args)
  54{
  55    target_ulong server = xics_get_cpu_index_by_dt_id(args[0]);
  56    target_ulong mfrr = args[1];
  57
  58    if (server >= spapr->xics->nr_servers) {
  59        return H_PARAMETER;
  60    }
  61
  62    icp_set_mfrr(spapr->xics, server, mfrr);
  63    return H_SUCCESS;
  64}
  65
  66static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
  67                           target_ulong opcode, target_ulong *args)
  68{
  69    CPUState *cs = CPU(cpu);
  70    uint32_t xirr = icp_accept(spapr->xics->ss + cs->cpu_index);
  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    CPUState *cs = CPU(cpu);
  80    ICPState *ss = &spapr->xics->ss[cs->cpu_index];
  81    uint32_t xirr = icp_accept(ss);
  82
  83    args[0] = xirr;
  84    args[1] = cpu_get_host_ticks();
  85    return H_SUCCESS;
  86}
  87
  88static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
  89                          target_ulong opcode, target_ulong *args)
  90{
  91    CPUState *cs = CPU(cpu);
  92    target_ulong xirr = args[0];
  93
  94    icp_eoi(spapr->xics, cs->cpu_index, xirr);
  95    return H_SUCCESS;
  96}
  97
  98static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr,
  99                            target_ulong opcode, target_ulong *args)
 100{
 101    CPUState *cs = CPU(cpu);
 102    uint32_t mfrr;
 103    uint32_t xirr = icp_ipoll(spapr->xics->ss + cs->cpu_index, &mfrr);
 104
 105    args[0] = xirr;
 106    args[1] = mfrr;
 107
 108    return H_SUCCESS;
 109}
 110
 111static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
 112                          uint32_t token,
 113                          uint32_t nargs, target_ulong args,
 114                          uint32_t nret, target_ulong rets)
 115{
 116    ICSState *ics = spapr->xics->ics;
 117    uint32_t nr, server, priority;
 118
 119    if ((nargs != 3) || (nret != 1)) {
 120        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
 121        return;
 122    }
 123
 124    nr = rtas_ld(args, 0);
 125    server = xics_get_cpu_index_by_dt_id(rtas_ld(args, 1));
 126    priority = rtas_ld(args, 2);
 127
 128    if (!ics_valid_irq(ics, nr) || (server >= ics->xics->nr_servers)
 129        || (priority > 0xff)) {
 130        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
 131        return;
 132    }
 133
 134    ics_write_xive(ics, nr, server, priority, priority);
 135
 136    rtas_st(rets, 0, RTAS_OUT_SUCCESS);
 137}
 138
 139static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
 140                          uint32_t token,
 141                          uint32_t nargs, target_ulong args,
 142                          uint32_t nret, target_ulong rets)
 143{
 144    ICSState *ics = spapr->xics->ics;
 145    uint32_t nr;
 146
 147    if ((nargs != 1) || (nret != 3)) {
 148        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
 149        return;
 150    }
 151
 152    nr = rtas_ld(args, 0);
 153
 154    if (!ics_valid_irq(ics, nr)) {
 155        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
 156        return;
 157    }
 158
 159    rtas_st(rets, 0, RTAS_OUT_SUCCESS);
 160    rtas_st(rets, 1, ics->irqs[nr - ics->offset].server);
 161    rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
 162}
 163
 164static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
 165                         uint32_t token,
 166                         uint32_t nargs, target_ulong args,
 167                         uint32_t nret, target_ulong rets)
 168{
 169    ICSState *ics = spapr->xics->ics;
 170    uint32_t nr;
 171
 172    if ((nargs != 1) || (nret != 1)) {
 173        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
 174        return;
 175    }
 176
 177    nr = rtas_ld(args, 0);
 178
 179    if (!ics_valid_irq(ics, nr)) {
 180        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
 181        return;
 182    }
 183
 184    ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff,
 185                   ics->irqs[nr - ics->offset].priority);
 186
 187    rtas_st(rets, 0, RTAS_OUT_SUCCESS);
 188}
 189
 190static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr,
 191                        uint32_t token,
 192                        uint32_t nargs, target_ulong args,
 193                        uint32_t nret, target_ulong rets)
 194{
 195    ICSState *ics = spapr->xics->ics;
 196    uint32_t nr;
 197
 198    if ((nargs != 1) || (nret != 1)) {
 199        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
 200        return;
 201    }
 202
 203    nr = rtas_ld(args, 0);
 204
 205    if (!ics_valid_irq(ics, nr)) {
 206        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
 207        return;
 208    }
 209
 210    ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server,
 211                   ics->irqs[nr - ics->offset].saved_priority,
 212                   ics->irqs[nr - ics->offset].saved_priority);
 213
 214    rtas_st(rets, 0, RTAS_OUT_SUCCESS);
 215}
 216
 217static void xics_spapr_set_nr_irqs(XICSState *xics, uint32_t nr_irqs,
 218                                   Error **errp)
 219{
 220    xics->nr_irqs = xics->ics->nr_irqs = nr_irqs;
 221}
 222
 223static void xics_spapr_set_nr_servers(XICSState *xics, uint32_t nr_servers,
 224                                      Error **errp)
 225{
 226    int i;
 227
 228    xics->nr_servers = nr_servers;
 229
 230    xics->ss = g_malloc0(xics->nr_servers * sizeof(ICPState));
 231    for (i = 0; i < xics->nr_servers; i++) {
 232        char buffer[32];
 233        object_initialize(&xics->ss[i], sizeof(xics->ss[i]), TYPE_ICP);
 234        snprintf(buffer, sizeof(buffer), "icp[%d]", i);
 235        object_property_add_child(OBJECT(xics), buffer, OBJECT(&xics->ss[i]),
 236                                  errp);
 237    }
 238}
 239
 240static void xics_spapr_realize(DeviceState *dev, Error **errp)
 241{
 242    XICSState *xics = XICS_SPAPR(dev);
 243    Error *error = NULL;
 244    int i;
 245
 246    if (!xics->nr_servers) {
 247        error_setg(errp, "Number of servers needs to be greater 0");
 248        return;
 249    }
 250
 251    /* Registration of global state belongs into realize */
 252    spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive);
 253    spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive);
 254    spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off);
 255    spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_int_on);
 256
 257    spapr_register_hypercall(H_CPPR, h_cppr);
 258    spapr_register_hypercall(H_IPI, h_ipi);
 259    spapr_register_hypercall(H_XIRR, h_xirr);
 260    spapr_register_hypercall(H_XIRR_X, h_xirr_x);
 261    spapr_register_hypercall(H_EOI, h_eoi);
 262    spapr_register_hypercall(H_IPOLL, h_ipoll);
 263
 264    object_property_set_bool(OBJECT(xics->ics), true, "realized", &error);
 265    if (error) {
 266        error_propagate(errp, error);
 267        return;
 268    }
 269
 270    for (i = 0; i < xics->nr_servers; i++) {
 271        object_property_set_bool(OBJECT(&xics->ss[i]), true, "realized",
 272                                 &error);
 273        if (error) {
 274            error_propagate(errp, error);
 275            return;
 276        }
 277    }
 278}
 279
 280static void xics_spapr_initfn(Object *obj)
 281{
 282    XICSState *xics = XICS_SPAPR(obj);
 283
 284    xics->ics = ICS(object_new(TYPE_ICS));
 285    object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL);
 286    xics->ics->xics = xics;
 287}
 288
 289static void xics_spapr_class_init(ObjectClass *oc, void *data)
 290{
 291    DeviceClass *dc = DEVICE_CLASS(oc);
 292    XICSStateClass *xsc = XICS_SPAPR_CLASS(oc);
 293
 294    dc->realize = xics_spapr_realize;
 295    xsc->set_nr_irqs = xics_spapr_set_nr_irqs;
 296    xsc->set_nr_servers = xics_spapr_set_nr_servers;
 297}
 298
 299static const TypeInfo xics_spapr_info = {
 300    .name          = TYPE_XICS_SPAPR,
 301    .parent        = TYPE_XICS_COMMON,
 302    .instance_size = sizeof(XICSState),
 303    .class_size = sizeof(XICSStateClass),
 304    .class_init    = xics_spapr_class_init,
 305    .instance_init = xics_spapr_initfn,
 306};
 307
 308#define ICS_IRQ_FREE(ics, srcno)   \
 309    (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
 310
 311static int ics_find_free_block(ICSState *ics, int num, int alignnum)
 312{
 313    int first, i;
 314
 315    for (first = 0; first < ics->nr_irqs; first += alignnum) {
 316        if (num > (ics->nr_irqs - first)) {
 317            return -1;
 318        }
 319        for (i = first; i < first + num; ++i) {
 320            if (!ICS_IRQ_FREE(ics, i)) {
 321                break;
 322            }
 323        }
 324        if (i == (first + num)) {
 325            return first;
 326        }
 327    }
 328
 329    return -1;
 330}
 331
 332int xics_spapr_alloc(XICSState *xics, int src, int irq_hint, bool lsi,
 333                     Error **errp)
 334{
 335    ICSState *ics = &xics->ics[src];
 336    int irq;
 337
 338    if (irq_hint) {
 339        assert(src == xics_find_source(xics, irq_hint));
 340        if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) {
 341            error_setg(errp, "can't allocate IRQ %d: already in use", irq_hint);
 342            return -1;
 343        }
 344        irq = irq_hint;
 345    } else {
 346        irq = ics_find_free_block(ics, 1, 1);
 347        if (irq < 0) {
 348            error_setg(errp, "can't allocate IRQ: no IRQ left");
 349            return -1;
 350        }
 351        irq += ics->offset;
 352    }
 353
 354    ics_set_irq_type(ics, irq - ics->offset, lsi);
 355    trace_xics_alloc(src, irq);
 356
 357    return irq;
 358}
 359
 360/*
 361 * Allocate block of consecutive IRQs, and return the number of the first IRQ in
 362 * the block. If align==true, aligns the first IRQ number to num.
 363 */
 364int xics_spapr_alloc_block(XICSState *xics, int src, int num, bool lsi,
 365                           bool align, Error **errp)
 366{
 367    int i, first = -1;
 368    ICSState *ics = &xics->ics[src];
 369
 370    assert(src == 0);
 371    /*
 372     * MSIMesage::data is used for storing VIRQ so
 373     * it has to be aligned to num to support multiple
 374     * MSI vectors. MSI-X is not affected by this.
 375     * The hint is used for the first IRQ, the rest should
 376     * be allocated continuously.
 377     */
 378    if (align) {
 379        assert((num == 1) || (num == 2) || (num == 4) ||
 380               (num == 8) || (num == 16) || (num == 32));
 381        first = ics_find_free_block(ics, num, num);
 382    } else {
 383        first = ics_find_free_block(ics, num, 1);
 384    }
 385    if (first < 0) {
 386        error_setg(errp, "can't find a free %d-IRQ block", num);
 387        return -1;
 388    }
 389
 390    if (first >= 0) {
 391        for (i = first; i < first + num; ++i) {
 392            ics_set_irq_type(ics, i, lsi);
 393        }
 394    }
 395    first += ics->offset;
 396
 397    trace_xics_alloc_block(src, first, num, lsi, align);
 398
 399    return first;
 400}
 401
 402static void ics_free(ICSState *ics, int srcno, int num)
 403{
 404    int i;
 405
 406    for (i = srcno; i < srcno + num; ++i) {
 407        if (ICS_IRQ_FREE(ics, i)) {
 408            trace_xics_ics_free_warn(ics - ics->xics->ics, i + ics->offset);
 409        }
 410        memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
 411    }
 412}
 413
 414void xics_spapr_free(XICSState *xics, int irq, int num)
 415{
 416    int src = xics_find_source(xics, irq);
 417
 418    if (src >= 0) {
 419        ICSState *ics = &xics->ics[src];
 420
 421        /* FIXME: implement multiple sources */
 422        assert(src == 0);
 423
 424        trace_xics_ics_free(ics - xics->ics, irq, num);
 425        ics_free(ics, irq - ics->offset, num);
 426    }
 427}
 428
 429static void xics_spapr_register_types(void)
 430{
 431    type_register_static(&xics_spapr_info);
 432}
 433
 434type_init(xics_spapr_register_types)
 435