qemu/hw/ppc/spapr_events.c
<<
>>
Prefs
   1/*
   2 * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
   3 *
   4 * RTAS events handling
   5 *
   6 * Copyright (c) 2012 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#include "qemu/osdep.h"
  28#include "qapi/error.h"
  29#include "cpu.h"
  30#include "sysemu/sysemu.h"
  31#include "sysemu/char.h"
  32#include "hw/qdev.h"
  33#include "sysemu/device_tree.h"
  34
  35#include "hw/ppc/spapr.h"
  36#include "hw/ppc/spapr_vio.h"
  37#include "hw/pci/pci.h"
  38#include "hw/pci-host/spapr.h"
  39#include "hw/ppc/spapr_drc.h"
  40#include "qemu/help_option.h"
  41#include "qemu/bcd.h"
  42#include <libfdt.h>
  43
  44struct rtas_error_log {
  45    uint32_t summary;
  46#define RTAS_LOG_VERSION_MASK                   0xff000000
  47#define   RTAS_LOG_VERSION_6                    0x06000000
  48#define RTAS_LOG_SEVERITY_MASK                  0x00e00000
  49#define   RTAS_LOG_SEVERITY_ALREADY_REPORTED    0x00c00000
  50#define   RTAS_LOG_SEVERITY_FATAL               0x00a00000
  51#define   RTAS_LOG_SEVERITY_ERROR               0x00800000
  52#define   RTAS_LOG_SEVERITY_ERROR_SYNC          0x00600000
  53#define   RTAS_LOG_SEVERITY_WARNING             0x00400000
  54#define   RTAS_LOG_SEVERITY_EVENT               0x00200000
  55#define   RTAS_LOG_SEVERITY_NO_ERROR            0x00000000
  56#define RTAS_LOG_DISPOSITION_MASK               0x00180000
  57#define   RTAS_LOG_DISPOSITION_FULLY_RECOVERED  0x00000000
  58#define   RTAS_LOG_DISPOSITION_LIMITED_RECOVERY 0x00080000
  59#define   RTAS_LOG_DISPOSITION_NOT_RECOVERED    0x00100000
  60#define RTAS_LOG_OPTIONAL_PART_PRESENT          0x00040000
  61#define RTAS_LOG_INITIATOR_MASK                 0x0000f000
  62#define   RTAS_LOG_INITIATOR_UNKNOWN            0x00000000
  63#define   RTAS_LOG_INITIATOR_CPU                0x00001000
  64#define   RTAS_LOG_INITIATOR_PCI                0x00002000
  65#define   RTAS_LOG_INITIATOR_MEMORY             0x00004000
  66#define   RTAS_LOG_INITIATOR_HOTPLUG            0x00006000
  67#define RTAS_LOG_TARGET_MASK                    0x00000f00
  68#define   RTAS_LOG_TARGET_UNKNOWN               0x00000000
  69#define   RTAS_LOG_TARGET_CPU                   0x00000100
  70#define   RTAS_LOG_TARGET_PCI                   0x00000200
  71#define   RTAS_LOG_TARGET_MEMORY                0x00000400
  72#define   RTAS_LOG_TARGET_HOTPLUG               0x00000600
  73#define RTAS_LOG_TYPE_MASK                      0x000000ff
  74#define   RTAS_LOG_TYPE_OTHER                   0x00000000
  75#define   RTAS_LOG_TYPE_RETRY                   0x00000001
  76#define   RTAS_LOG_TYPE_TCE_ERR                 0x00000002
  77#define   RTAS_LOG_TYPE_INTERN_DEV_FAIL         0x00000003
  78#define   RTAS_LOG_TYPE_TIMEOUT                 0x00000004
  79#define   RTAS_LOG_TYPE_DATA_PARITY             0x00000005
  80#define   RTAS_LOG_TYPE_ADDR_PARITY             0x00000006
  81#define   RTAS_LOG_TYPE_CACHE_PARITY            0x00000007
  82#define   RTAS_LOG_TYPE_ADDR_INVALID            0x00000008
  83#define   RTAS_LOG_TYPE_ECC_UNCORR              0x00000009
  84#define   RTAS_LOG_TYPE_ECC_CORR                0x0000000a
  85#define   RTAS_LOG_TYPE_EPOW                    0x00000040
  86#define   RTAS_LOG_TYPE_HOTPLUG                 0x000000e5
  87    uint32_t extended_length;
  88} QEMU_PACKED;
  89
  90struct rtas_event_log_v6 {
  91    uint8_t b0;
  92#define RTAS_LOG_V6_B0_VALID                          0x80
  93#define RTAS_LOG_V6_B0_UNRECOVERABLE_ERROR            0x40
  94#define RTAS_LOG_V6_B0_RECOVERABLE_ERROR              0x20
  95#define RTAS_LOG_V6_B0_DEGRADED_OPERATION             0x10
  96#define RTAS_LOG_V6_B0_PREDICTIVE_ERROR               0x08
  97#define RTAS_LOG_V6_B0_NEW_LOG                        0x04
  98#define RTAS_LOG_V6_B0_BIGENDIAN                      0x02
  99    uint8_t _resv1;
 100    uint8_t b2;
 101#define RTAS_LOG_V6_B2_POWERPC_FORMAT                 0x80
 102#define RTAS_LOG_V6_B2_LOG_FORMAT_MASK                0x0f
 103#define   RTAS_LOG_V6_B2_LOG_FORMAT_PLATFORM_EVENT    0x0e
 104    uint8_t _resv2[9];
 105    uint32_t company;
 106#define RTAS_LOG_V6_COMPANY_IBM                 0x49424d00 /* IBM<null> */
 107} QEMU_PACKED;
 108
 109struct rtas_event_log_v6_section_header {
 110    uint16_t section_id;
 111    uint16_t section_length;
 112    uint8_t section_version;
 113    uint8_t section_subtype;
 114    uint16_t creator_component_id;
 115} QEMU_PACKED;
 116
 117struct rtas_event_log_v6_maina {
 118#define RTAS_LOG_V6_SECTION_ID_MAINA                0x5048 /* PH */
 119    struct rtas_event_log_v6_section_header hdr;
 120    uint32_t creation_date; /* BCD: YYYYMMDD */
 121    uint32_t creation_time; /* BCD: HHMMSS00 */
 122    uint8_t _platform1[8];
 123    char creator_id;
 124    uint8_t _resv1[2];
 125    uint8_t section_count;
 126    uint8_t _resv2[4];
 127    uint8_t _platform2[8];
 128    uint32_t plid;
 129    uint8_t _platform3[4];
 130} QEMU_PACKED;
 131
 132struct rtas_event_log_v6_mainb {
 133#define RTAS_LOG_V6_SECTION_ID_MAINB                0x5548 /* UH */
 134    struct rtas_event_log_v6_section_header hdr;
 135    uint8_t subsystem_id;
 136    uint8_t _platform1;
 137    uint8_t event_severity;
 138    uint8_t event_subtype;
 139    uint8_t _platform2[4];
 140    uint8_t _resv1[2];
 141    uint16_t action_flags;
 142    uint8_t _resv2[4];
 143} QEMU_PACKED;
 144
 145struct rtas_event_log_v6_epow {
 146#define RTAS_LOG_V6_SECTION_ID_EPOW                 0x4550 /* EP */
 147    struct rtas_event_log_v6_section_header hdr;
 148    uint8_t sensor_value;
 149#define RTAS_LOG_V6_EPOW_ACTION_RESET                    0
 150#define RTAS_LOG_V6_EPOW_ACTION_WARN_COOLING             1
 151#define RTAS_LOG_V6_EPOW_ACTION_WARN_POWER               2
 152#define RTAS_LOG_V6_EPOW_ACTION_SYSTEM_SHUTDOWN          3
 153#define RTAS_LOG_V6_EPOW_ACTION_SYSTEM_HALT              4
 154#define RTAS_LOG_V6_EPOW_ACTION_MAIN_ENCLOSURE           5
 155#define RTAS_LOG_V6_EPOW_ACTION_POWER_OFF                7
 156    uint8_t event_modifier;
 157#define RTAS_LOG_V6_EPOW_MODIFIER_NORMAL                 1
 158#define RTAS_LOG_V6_EPOW_MODIFIER_ON_UPS                 2
 159#define RTAS_LOG_V6_EPOW_MODIFIER_CRITICAL               3
 160#define RTAS_LOG_V6_EPOW_MODIFIER_TEMPERATURE            4
 161    uint8_t extended_modifier;
 162#define RTAS_LOG_V6_EPOW_XMODIFIER_SYSTEM_WIDE           0
 163#define RTAS_LOG_V6_EPOW_XMODIFIER_PARTITION_SPECIFIC    1
 164    uint8_t _resv;
 165    uint64_t reason_code;
 166} QEMU_PACKED;
 167
 168struct epow_log_full {
 169    struct rtas_error_log hdr;
 170    struct rtas_event_log_v6 v6hdr;
 171    struct rtas_event_log_v6_maina maina;
 172    struct rtas_event_log_v6_mainb mainb;
 173    struct rtas_event_log_v6_epow epow;
 174} QEMU_PACKED;
 175
 176struct rtas_event_log_v6_hp {
 177#define RTAS_LOG_V6_SECTION_ID_HOTPLUG              0x4850 /* HP */
 178    struct rtas_event_log_v6_section_header hdr;
 179    uint8_t hotplug_type;
 180#define RTAS_LOG_V6_HP_TYPE_CPU                          1
 181#define RTAS_LOG_V6_HP_TYPE_MEMORY                       2
 182#define RTAS_LOG_V6_HP_TYPE_SLOT                         3
 183#define RTAS_LOG_V6_HP_TYPE_PHB                          4
 184#define RTAS_LOG_V6_HP_TYPE_PCI                          5
 185    uint8_t hotplug_action;
 186#define RTAS_LOG_V6_HP_ACTION_ADD                        1
 187#define RTAS_LOG_V6_HP_ACTION_REMOVE                     2
 188    uint8_t hotplug_identifier;
 189#define RTAS_LOG_V6_HP_ID_DRC_NAME                       1
 190#define RTAS_LOG_V6_HP_ID_DRC_INDEX                      2
 191#define RTAS_LOG_V6_HP_ID_DRC_COUNT                      3
 192    uint8_t reserved;
 193    union {
 194        uint32_t index;
 195        uint32_t count;
 196        char name[1];
 197    } drc;
 198} QEMU_PACKED;
 199
 200struct hp_log_full {
 201    struct rtas_error_log hdr;
 202    struct rtas_event_log_v6 v6hdr;
 203    struct rtas_event_log_v6_maina maina;
 204    struct rtas_event_log_v6_mainb mainb;
 205    struct rtas_event_log_v6_hp hp;
 206} QEMU_PACKED;
 207
 208#define EVENT_MASK_INTERNAL_ERRORS           0x80000000
 209#define EVENT_MASK_EPOW                      0x40000000
 210#define EVENT_MASK_HOTPLUG                   0x10000000
 211#define EVENT_MASK_IO                        0x08000000
 212
 213#define _FDT(exp) \
 214    do { \
 215        int ret = (exp);                                           \
 216        if (ret < 0) {                                             \
 217            fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \
 218                    #exp, fdt_strerror(ret));                      \
 219            exit(1);                                               \
 220        }                                                          \
 221    } while (0)
 222
 223void spapr_events_fdt_skel(void *fdt, uint32_t check_exception_irq)
 224{
 225    uint32_t irq_ranges[] = {cpu_to_be32(check_exception_irq), cpu_to_be32(1)};
 226    uint32_t interrupts[] = {cpu_to_be32(check_exception_irq), 0};
 227
 228    _FDT((fdt_begin_node(fdt, "event-sources")));
 229
 230    _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
 231    _FDT((fdt_property_cell(fdt, "#interrupt-cells", 2)));
 232    _FDT((fdt_property(fdt, "interrupt-ranges",
 233                       irq_ranges, sizeof(irq_ranges))));
 234
 235    _FDT((fdt_begin_node(fdt, "epow-events")));
 236    _FDT((fdt_property(fdt, "interrupts", interrupts, sizeof(interrupts))));
 237    _FDT((fdt_end_node(fdt)));
 238
 239    _FDT((fdt_end_node(fdt)));
 240}
 241
 242static void rtas_event_log_queue(int log_type, void *data, bool exception)
 243{
 244    sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
 245    sPAPREventLogEntry *entry = g_new(sPAPREventLogEntry, 1);
 246
 247    g_assert(data);
 248    entry->log_type = log_type;
 249    entry->exception = exception;
 250    entry->data = data;
 251    QTAILQ_INSERT_TAIL(&spapr->pending_events, entry, next);
 252}
 253
 254static sPAPREventLogEntry *rtas_event_log_dequeue(uint32_t event_mask,
 255                                                  bool exception)
 256{
 257    sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
 258    sPAPREventLogEntry *entry = NULL;
 259
 260    /* we only queue EPOW events atm. */
 261    if ((event_mask & EVENT_MASK_EPOW) == 0) {
 262        return NULL;
 263    }
 264
 265    QTAILQ_FOREACH(entry, &spapr->pending_events, next) {
 266        if (entry->exception != exception) {
 267            continue;
 268        }
 269
 270        /* EPOW and hotplug events are surfaced in the same manner */
 271        if (entry->log_type == RTAS_LOG_TYPE_EPOW ||
 272            entry->log_type == RTAS_LOG_TYPE_HOTPLUG) {
 273            break;
 274        }
 275    }
 276
 277    if (entry) {
 278        QTAILQ_REMOVE(&spapr->pending_events, entry, next);
 279    }
 280
 281    return entry;
 282}
 283
 284static bool rtas_event_log_contains(uint32_t event_mask, bool exception)
 285{
 286    sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
 287    sPAPREventLogEntry *entry = NULL;
 288
 289    /* we only queue EPOW events atm. */
 290    if ((event_mask & EVENT_MASK_EPOW) == 0) {
 291        return false;
 292    }
 293
 294    QTAILQ_FOREACH(entry, &spapr->pending_events, next) {
 295        if (entry->exception != exception) {
 296            continue;
 297        }
 298
 299        /* EPOW and hotplug events are surfaced in the same manner */
 300        if (entry->log_type == RTAS_LOG_TYPE_EPOW ||
 301            entry->log_type == RTAS_LOG_TYPE_HOTPLUG) {
 302            return true;
 303        }
 304    }
 305
 306    return false;
 307}
 308
 309static uint32_t next_plid;
 310
 311static void spapr_init_v6hdr(struct rtas_event_log_v6 *v6hdr)
 312{
 313    v6hdr->b0 = RTAS_LOG_V6_B0_VALID | RTAS_LOG_V6_B0_NEW_LOG
 314        | RTAS_LOG_V6_B0_BIGENDIAN;
 315    v6hdr->b2 = RTAS_LOG_V6_B2_POWERPC_FORMAT
 316        | RTAS_LOG_V6_B2_LOG_FORMAT_PLATFORM_EVENT;
 317    v6hdr->company = cpu_to_be32(RTAS_LOG_V6_COMPANY_IBM);
 318}
 319
 320static void spapr_init_maina(struct rtas_event_log_v6_maina *maina,
 321                             int section_count)
 322{
 323    sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
 324    struct tm tm;
 325    int year;
 326
 327    maina->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINA);
 328    maina->hdr.section_length = cpu_to_be16(sizeof(*maina));
 329    /* FIXME: section version, subtype and creator id? */
 330    spapr_rtc_read(spapr->rtc, &tm, NULL);
 331    year = tm.tm_year + 1900;
 332    maina->creation_date = cpu_to_be32((to_bcd(year / 100) << 24)
 333                                       | (to_bcd(year % 100) << 16)
 334                                       | (to_bcd(tm.tm_mon + 1) << 8)
 335                                       | to_bcd(tm.tm_mday));
 336    maina->creation_time = cpu_to_be32((to_bcd(tm.tm_hour) << 24)
 337                                       | (to_bcd(tm.tm_min) << 16)
 338                                       | (to_bcd(tm.tm_sec) << 8));
 339    maina->creator_id = 'H'; /* Hypervisor */
 340    maina->section_count = section_count;
 341    maina->plid = next_plid++;
 342}
 343
 344static void spapr_powerdown_req(Notifier *n, void *opaque)
 345{
 346    sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
 347    struct rtas_error_log *hdr;
 348    struct rtas_event_log_v6 *v6hdr;
 349    struct rtas_event_log_v6_maina *maina;
 350    struct rtas_event_log_v6_mainb *mainb;
 351    struct rtas_event_log_v6_epow *epow;
 352    struct epow_log_full *new_epow;
 353
 354    new_epow = g_malloc0(sizeof(*new_epow));
 355    hdr = &new_epow->hdr;
 356    v6hdr = &new_epow->v6hdr;
 357    maina = &new_epow->maina;
 358    mainb = &new_epow->mainb;
 359    epow = &new_epow->epow;
 360
 361    hdr->summary = cpu_to_be32(RTAS_LOG_VERSION_6
 362                               | RTAS_LOG_SEVERITY_EVENT
 363                               | RTAS_LOG_DISPOSITION_NOT_RECOVERED
 364                               | RTAS_LOG_OPTIONAL_PART_PRESENT
 365                               | RTAS_LOG_TYPE_EPOW);
 366    hdr->extended_length = cpu_to_be32(sizeof(*new_epow)
 367                                       - sizeof(new_epow->hdr));
 368
 369    spapr_init_v6hdr(v6hdr);
 370    spapr_init_maina(maina, 3 /* Main-A, Main-B and EPOW */);
 371
 372    mainb->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINB);
 373    mainb->hdr.section_length = cpu_to_be16(sizeof(*mainb));
 374    /* FIXME: section version, subtype and creator id? */
 375    mainb->subsystem_id = 0xa0; /* External environment */
 376    mainb->event_severity = 0x00; /* Informational / non-error */
 377    mainb->event_subtype = 0xd0; /* Normal shutdown */
 378
 379    epow->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_EPOW);
 380    epow->hdr.section_length = cpu_to_be16(sizeof(*epow));
 381    epow->hdr.section_version = 2; /* includes extended modifier */
 382    /* FIXME: section subtype and creator id? */
 383    epow->sensor_value = RTAS_LOG_V6_EPOW_ACTION_SYSTEM_SHUTDOWN;
 384    epow->event_modifier = RTAS_LOG_V6_EPOW_MODIFIER_NORMAL;
 385    epow->extended_modifier = RTAS_LOG_V6_EPOW_XMODIFIER_PARTITION_SPECIFIC;
 386
 387    rtas_event_log_queue(RTAS_LOG_TYPE_EPOW, new_epow, true);
 388
 389    qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq));
 390}
 391
 392static void spapr_hotplug_set_signalled(uint32_t drc_index)
 393{
 394    sPAPRDRConnector *drc = spapr_dr_connector_by_index(drc_index);
 395    sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
 396    drck->set_signalled(drc);
 397}
 398
 399static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action,
 400                                    sPAPRDRConnectorType drc_type,
 401                                    uint32_t drc)
 402{
 403    sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
 404    struct hp_log_full *new_hp;
 405    struct rtas_error_log *hdr;
 406    struct rtas_event_log_v6 *v6hdr;
 407    struct rtas_event_log_v6_maina *maina;
 408    struct rtas_event_log_v6_mainb *mainb;
 409    struct rtas_event_log_v6_hp *hp;
 410
 411    new_hp = g_malloc0(sizeof(struct hp_log_full));
 412    hdr = &new_hp->hdr;
 413    v6hdr = &new_hp->v6hdr;
 414    maina = &new_hp->maina;
 415    mainb = &new_hp->mainb;
 416    hp = &new_hp->hp;
 417
 418    hdr->summary = cpu_to_be32(RTAS_LOG_VERSION_6
 419                               | RTAS_LOG_SEVERITY_EVENT
 420                               | RTAS_LOG_DISPOSITION_NOT_RECOVERED
 421                               | RTAS_LOG_OPTIONAL_PART_PRESENT
 422                               | RTAS_LOG_INITIATOR_HOTPLUG
 423                               | RTAS_LOG_TYPE_HOTPLUG);
 424    hdr->extended_length = cpu_to_be32(sizeof(*new_hp)
 425                                       - sizeof(new_hp->hdr));
 426
 427    spapr_init_v6hdr(v6hdr);
 428    spapr_init_maina(maina, 3 /* Main-A, Main-B, HP */);
 429
 430    mainb->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINB);
 431    mainb->hdr.section_length = cpu_to_be16(sizeof(*mainb));
 432    mainb->subsystem_id = 0x80; /* External environment */
 433    mainb->event_severity = 0x00; /* Informational / non-error */
 434    mainb->event_subtype = 0x00; /* Normal shutdown */
 435
 436    hp->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_HOTPLUG);
 437    hp->hdr.section_length = cpu_to_be16(sizeof(*hp));
 438    hp->hdr.section_version = 1; /* includes extended modifier */
 439    hp->hotplug_action = hp_action;
 440    hp->hotplug_identifier = hp_id;
 441
 442    switch (drc_type) {
 443    case SPAPR_DR_CONNECTOR_TYPE_PCI:
 444        hp->hotplug_type = RTAS_LOG_V6_HP_TYPE_PCI;
 445        if (hp->hotplug_action == RTAS_LOG_V6_HP_ACTION_ADD) {
 446            spapr_hotplug_set_signalled(drc);
 447        }
 448        break;
 449    case SPAPR_DR_CONNECTOR_TYPE_LMB:
 450        hp->hotplug_type = RTAS_LOG_V6_HP_TYPE_MEMORY;
 451        break;
 452    default:
 453        /* we shouldn't be signaling hotplug events for resources
 454         * that don't support them
 455         */
 456        g_assert(false);
 457        return;
 458    }
 459
 460    if (hp_id == RTAS_LOG_V6_HP_ID_DRC_COUNT) {
 461        hp->drc.count = cpu_to_be32(drc);
 462    } else if (hp_id == RTAS_LOG_V6_HP_ID_DRC_INDEX) {
 463        hp->drc.index = cpu_to_be32(drc);
 464    }
 465
 466    rtas_event_log_queue(RTAS_LOG_TYPE_HOTPLUG, new_hp, true);
 467
 468    qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq));
 469}
 470
 471void spapr_hotplug_req_add_by_index(sPAPRDRConnector *drc)
 472{
 473    sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
 474    sPAPRDRConnectorType drc_type = drck->get_type(drc);
 475    uint32_t index = drck->get_index(drc);
 476
 477    spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_INDEX,
 478                            RTAS_LOG_V6_HP_ACTION_ADD, drc_type, index);
 479}
 480
 481void spapr_hotplug_req_remove_by_index(sPAPRDRConnector *drc)
 482{
 483    sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
 484    sPAPRDRConnectorType drc_type = drck->get_type(drc);
 485    uint32_t index = drck->get_index(drc);
 486
 487    spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_INDEX,
 488                            RTAS_LOG_V6_HP_ACTION_REMOVE, drc_type, index);
 489}
 490
 491void spapr_hotplug_req_add_by_count(sPAPRDRConnectorType drc_type,
 492                                       uint32_t count)
 493{
 494    spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_COUNT,
 495                            RTAS_LOG_V6_HP_ACTION_ADD, drc_type, count);
 496}
 497
 498void spapr_hotplug_req_remove_by_count(sPAPRDRConnectorType drc_type,
 499                                          uint32_t count)
 500{
 501    spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_COUNT,
 502                            RTAS_LOG_V6_HP_ACTION_REMOVE, drc_type, count);
 503}
 504
 505static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr,
 506                            uint32_t token, uint32_t nargs,
 507                            target_ulong args,
 508                            uint32_t nret, target_ulong rets)
 509{
 510    uint32_t mask, buf, len, event_len;
 511    uint64_t xinfo;
 512    sPAPREventLogEntry *event;
 513    struct rtas_error_log *hdr;
 514
 515    if ((nargs < 6) || (nargs > 7) || nret != 1) {
 516        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
 517        return;
 518    }
 519
 520    xinfo = rtas_ld(args, 1);
 521    mask = rtas_ld(args, 2);
 522    buf = rtas_ld(args, 4);
 523    len = rtas_ld(args, 5);
 524    if (nargs == 7) {
 525        xinfo |= (uint64_t)rtas_ld(args, 6) << 32;
 526    }
 527
 528    event = rtas_event_log_dequeue(mask, true);
 529    if (!event) {
 530        goto out_no_events;
 531    }
 532
 533    hdr = event->data;
 534    event_len = be32_to_cpu(hdr->extended_length) + sizeof(*hdr);
 535
 536    if (event_len < len) {
 537        len = event_len;
 538    }
 539
 540    cpu_physical_memory_write(buf, event->data, len);
 541    rtas_st(rets, 0, RTAS_OUT_SUCCESS);
 542    g_free(event->data);
 543    g_free(event);
 544
 545    /* according to PAPR+, the IRQ must be left asserted, or re-asserted, if
 546     * there are still pending events to be fetched via check-exception. We
 547     * do the latter here, since our code relies on edge-triggered
 548     * interrupts.
 549     */
 550    if (rtas_event_log_contains(mask, true)) {
 551        qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq));
 552    }
 553
 554    return;
 555
 556out_no_events:
 557    rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
 558}
 559
 560static void event_scan(PowerPCCPU *cpu, sPAPRMachineState *spapr,
 561                       uint32_t token, uint32_t nargs,
 562                       target_ulong args,
 563                       uint32_t nret, target_ulong rets)
 564{
 565    uint32_t mask, buf, len, event_len;
 566    sPAPREventLogEntry *event;
 567    struct rtas_error_log *hdr;
 568
 569    if (nargs != 4 || nret != 1) {
 570        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
 571        return;
 572    }
 573
 574    mask = rtas_ld(args, 0);
 575    buf = rtas_ld(args, 2);
 576    len = rtas_ld(args, 3);
 577
 578    event = rtas_event_log_dequeue(mask, false);
 579    if (!event) {
 580        goto out_no_events;
 581    }
 582
 583    hdr = event->data;
 584    event_len = be32_to_cpu(hdr->extended_length) + sizeof(*hdr);
 585
 586    if (event_len < len) {
 587        len = event_len;
 588    }
 589
 590    cpu_physical_memory_write(buf, event->data, len);
 591    rtas_st(rets, 0, RTAS_OUT_SUCCESS);
 592    g_free(event->data);
 593    g_free(event);
 594    return;
 595
 596out_no_events:
 597    rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
 598}
 599
 600void spapr_events_init(sPAPRMachineState *spapr)
 601{
 602    QTAILQ_INIT(&spapr->pending_events);
 603    spapr->check_exception_irq = xics_alloc(spapr->icp, 0, 0, false,
 604                                            &error_fatal);
 605    spapr->epow_notifier.notify = spapr_powerdown_req;
 606    qemu_register_powerdown_notifier(&spapr->epow_notifier);
 607    spapr_rtas_register(RTAS_CHECK_EXCEPTION, "check-exception",
 608                        check_exception);
 609    spapr_rtas_register(RTAS_EVENT_SCAN, "event-scan", event_scan);
 610}
 611