xref: /openbmc/qemu/hw/ppc/spapr_events.c (revision 7c754c78)
19f64bd8aSPaolo Bonzini /*
29f64bd8aSPaolo Bonzini  * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
39f64bd8aSPaolo Bonzini  *
49f64bd8aSPaolo Bonzini  * RTAS events handling
59f64bd8aSPaolo Bonzini  *
69f64bd8aSPaolo Bonzini  * Copyright (c) 2012 David Gibson, IBM Corporation.
79f64bd8aSPaolo Bonzini  *
89f64bd8aSPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
99f64bd8aSPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
109f64bd8aSPaolo Bonzini  * in the Software without restriction, including without limitation the rights
119f64bd8aSPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
129f64bd8aSPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
139f64bd8aSPaolo Bonzini  * furnished to do so, subject to the following conditions:
149f64bd8aSPaolo Bonzini  *
159f64bd8aSPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
169f64bd8aSPaolo Bonzini  * all copies or substantial portions of the Software.
179f64bd8aSPaolo Bonzini  *
189f64bd8aSPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
199f64bd8aSPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
209f64bd8aSPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
219f64bd8aSPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
229f64bd8aSPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
239f64bd8aSPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
249f64bd8aSPaolo Bonzini  * THE SOFTWARE.
259f64bd8aSPaolo Bonzini  *
269f64bd8aSPaolo Bonzini  */
2764552b6bSMarkus Armbruster 
280d75590dSPeter Maydell #include "qemu/osdep.h"
29da34e65cSMarkus Armbruster #include "qapi/error.h"
309f64bd8aSPaolo Bonzini #include "sysemu/device_tree.h"
3154d31236SMarkus Armbruster #include "sysemu/runstate.h"
329f64bd8aSPaolo Bonzini 
337804c353SCédric Le Goater #include "hw/ppc/fdt.h"
340d09e41aSPaolo Bonzini #include "hw/ppc/spapr.h"
350d09e41aSPaolo Bonzini #include "hw/ppc/spapr_vio.h"
3631fe14d1SNathan Fontenot #include "hw/pci/pci.h"
3764552b6bSMarkus Armbruster #include "hw/irq.h"
3831fe14d1SNathan Fontenot #include "hw/pci-host/spapr.h"
3931fe14d1SNathan Fontenot #include "hw/ppc/spapr_drc.h"
40f348b6d1SVeronia Bahaa #include "qemu/help_option.h"
41f348b6d1SVeronia Bahaa #include "qemu/bcd.h"
429ac703acSAravinda Prasad #include "qemu/main-loop.h"
43ffbb1705SMichael Roth #include "hw/ppc/spapr_ovec.h"
449f64bd8aSPaolo Bonzini #include <libfdt.h>
452500fb42SAravinda Prasad #include "migration/blocker.h"
469f64bd8aSPaolo Bonzini 
479f64bd8aSPaolo Bonzini #define RTAS_LOG_VERSION_MASK                   0xff000000
489f64bd8aSPaolo Bonzini #define   RTAS_LOG_VERSION_6                    0x06000000
499f64bd8aSPaolo Bonzini #define RTAS_LOG_SEVERITY_MASK                  0x00e00000
509f64bd8aSPaolo Bonzini #define   RTAS_LOG_SEVERITY_ALREADY_REPORTED    0x00c00000
519f64bd8aSPaolo Bonzini #define   RTAS_LOG_SEVERITY_FATAL               0x00a00000
529f64bd8aSPaolo Bonzini #define   RTAS_LOG_SEVERITY_ERROR               0x00800000
539f64bd8aSPaolo Bonzini #define   RTAS_LOG_SEVERITY_ERROR_SYNC          0x00600000
549f64bd8aSPaolo Bonzini #define   RTAS_LOG_SEVERITY_WARNING             0x00400000
559f64bd8aSPaolo Bonzini #define   RTAS_LOG_SEVERITY_EVENT               0x00200000
569f64bd8aSPaolo Bonzini #define   RTAS_LOG_SEVERITY_NO_ERROR            0x00000000
579f64bd8aSPaolo Bonzini #define RTAS_LOG_DISPOSITION_MASK               0x00180000
589f64bd8aSPaolo Bonzini #define   RTAS_LOG_DISPOSITION_FULLY_RECOVERED  0x00000000
599f64bd8aSPaolo Bonzini #define   RTAS_LOG_DISPOSITION_LIMITED_RECOVERY 0x00080000
609f64bd8aSPaolo Bonzini #define   RTAS_LOG_DISPOSITION_NOT_RECOVERED    0x00100000
619f64bd8aSPaolo Bonzini #define RTAS_LOG_OPTIONAL_PART_PRESENT          0x00040000
629f64bd8aSPaolo Bonzini #define RTAS_LOG_INITIATOR_MASK                 0x0000f000
639f64bd8aSPaolo Bonzini #define   RTAS_LOG_INITIATOR_UNKNOWN            0x00000000
649f64bd8aSPaolo Bonzini #define   RTAS_LOG_INITIATOR_CPU                0x00001000
659f64bd8aSPaolo Bonzini #define   RTAS_LOG_INITIATOR_PCI                0x00002000
669f64bd8aSPaolo Bonzini #define   RTAS_LOG_INITIATOR_MEMORY             0x00004000
679f64bd8aSPaolo Bonzini #define   RTAS_LOG_INITIATOR_HOTPLUG            0x00006000
689f64bd8aSPaolo Bonzini #define RTAS_LOG_TARGET_MASK                    0x00000f00
699f64bd8aSPaolo Bonzini #define   RTAS_LOG_TARGET_UNKNOWN               0x00000000
709f64bd8aSPaolo Bonzini #define   RTAS_LOG_TARGET_CPU                   0x00000100
719f64bd8aSPaolo Bonzini #define   RTAS_LOG_TARGET_PCI                   0x00000200
729f64bd8aSPaolo Bonzini #define   RTAS_LOG_TARGET_MEMORY                0x00000400
739f64bd8aSPaolo Bonzini #define   RTAS_LOG_TARGET_HOTPLUG               0x00000600
749f64bd8aSPaolo Bonzini #define RTAS_LOG_TYPE_MASK                      0x000000ff
759f64bd8aSPaolo Bonzini #define   RTAS_LOG_TYPE_OTHER                   0x00000000
769f64bd8aSPaolo Bonzini #define   RTAS_LOG_TYPE_RETRY                   0x00000001
779f64bd8aSPaolo Bonzini #define   RTAS_LOG_TYPE_TCE_ERR                 0x00000002
789f64bd8aSPaolo Bonzini #define   RTAS_LOG_TYPE_INTERN_DEV_FAIL         0x00000003
799f64bd8aSPaolo Bonzini #define   RTAS_LOG_TYPE_TIMEOUT                 0x00000004
809f64bd8aSPaolo Bonzini #define   RTAS_LOG_TYPE_DATA_PARITY             0x00000005
819f64bd8aSPaolo Bonzini #define   RTAS_LOG_TYPE_ADDR_PARITY             0x00000006
829f64bd8aSPaolo Bonzini #define   RTAS_LOG_TYPE_CACHE_PARITY            0x00000007
839f64bd8aSPaolo Bonzini #define   RTAS_LOG_TYPE_ADDR_INVALID            0x00000008
849f64bd8aSPaolo Bonzini #define   RTAS_LOG_TYPE_ECC_UNCORR              0x00000009
859f64bd8aSPaolo Bonzini #define   RTAS_LOG_TYPE_ECC_CORR                0x0000000a
869f64bd8aSPaolo Bonzini #define   RTAS_LOG_TYPE_EPOW                    0x00000040
8731fe14d1SNathan Fontenot #define   RTAS_LOG_TYPE_HOTPLUG                 0x000000e5
889f64bd8aSPaolo Bonzini 
895341258eSDavid Gibson struct rtas_error_log {
905341258eSDavid Gibson     uint32_t summary;
915341258eSDavid Gibson     uint32_t extended_length;
925341258eSDavid Gibson } QEMU_PACKED;
935341258eSDavid Gibson 
949f64bd8aSPaolo Bonzini struct rtas_event_log_v6 {
959f64bd8aSPaolo Bonzini     uint8_t b0;
969f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_B0_VALID                          0x80
979f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_B0_UNRECOVERABLE_ERROR            0x40
989f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_B0_RECOVERABLE_ERROR              0x20
999f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_B0_DEGRADED_OPERATION             0x10
1009f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_B0_PREDICTIVE_ERROR               0x08
1019f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_B0_NEW_LOG                        0x04
1029f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_B0_BIGENDIAN                      0x02
1039f64bd8aSPaolo Bonzini     uint8_t _resv1;
1049f64bd8aSPaolo Bonzini     uint8_t b2;
1059f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_B2_POWERPC_FORMAT                 0x80
1069f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_B2_LOG_FORMAT_MASK                0x0f
1079f64bd8aSPaolo Bonzini #define   RTAS_LOG_V6_B2_LOG_FORMAT_PLATFORM_EVENT    0x0e
1089f64bd8aSPaolo Bonzini     uint8_t _resv2[9];
1099f64bd8aSPaolo Bonzini     uint32_t company;
1109f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_COMPANY_IBM                 0x49424d00 /* IBM<null> */
1119f64bd8aSPaolo Bonzini } QEMU_PACKED;
1129f64bd8aSPaolo Bonzini 
1139f64bd8aSPaolo Bonzini struct rtas_event_log_v6_section_header {
1149f64bd8aSPaolo Bonzini     uint16_t section_id;
1159f64bd8aSPaolo Bonzini     uint16_t section_length;
1169f64bd8aSPaolo Bonzini     uint8_t section_version;
1179f64bd8aSPaolo Bonzini     uint8_t section_subtype;
1189f64bd8aSPaolo Bonzini     uint16_t creator_component_id;
1199f64bd8aSPaolo Bonzini } QEMU_PACKED;
1209f64bd8aSPaolo Bonzini 
1219f64bd8aSPaolo Bonzini struct rtas_event_log_v6_maina {
1229f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_SECTION_ID_MAINA                0x5048 /* PH */
1239f64bd8aSPaolo Bonzini     struct rtas_event_log_v6_section_header hdr;
1249f64bd8aSPaolo Bonzini     uint32_t creation_date; /* BCD: YYYYMMDD */
1259f64bd8aSPaolo Bonzini     uint32_t creation_time; /* BCD: HHMMSS00 */
1269f64bd8aSPaolo Bonzini     uint8_t _platform1[8];
1279f64bd8aSPaolo Bonzini     char creator_id;
1289f64bd8aSPaolo Bonzini     uint8_t _resv1[2];
1299f64bd8aSPaolo Bonzini     uint8_t section_count;
1309f64bd8aSPaolo Bonzini     uint8_t _resv2[4];
1319f64bd8aSPaolo Bonzini     uint8_t _platform2[8];
1329f64bd8aSPaolo Bonzini     uint32_t plid;
1339f64bd8aSPaolo Bonzini     uint8_t _platform3[4];
1349f64bd8aSPaolo Bonzini } QEMU_PACKED;
1359f64bd8aSPaolo Bonzini 
1369f64bd8aSPaolo Bonzini struct rtas_event_log_v6_mainb {
1379f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_SECTION_ID_MAINB                0x5548 /* UH */
1389f64bd8aSPaolo Bonzini     struct rtas_event_log_v6_section_header hdr;
1399f64bd8aSPaolo Bonzini     uint8_t subsystem_id;
1409f64bd8aSPaolo Bonzini     uint8_t _platform1;
1419f64bd8aSPaolo Bonzini     uint8_t event_severity;
1429f64bd8aSPaolo Bonzini     uint8_t event_subtype;
1439f64bd8aSPaolo Bonzini     uint8_t _platform2[4];
1449f64bd8aSPaolo Bonzini     uint8_t _resv1[2];
1459f64bd8aSPaolo Bonzini     uint16_t action_flags;
1469f64bd8aSPaolo Bonzini     uint8_t _resv2[4];
1479f64bd8aSPaolo Bonzini } QEMU_PACKED;
1489f64bd8aSPaolo Bonzini 
1499f64bd8aSPaolo Bonzini struct rtas_event_log_v6_epow {
1509f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_SECTION_ID_EPOW                 0x4550 /* EP */
1519f64bd8aSPaolo Bonzini     struct rtas_event_log_v6_section_header hdr;
1529f64bd8aSPaolo Bonzini     uint8_t sensor_value;
1539f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_EPOW_ACTION_RESET                    0
1549f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_EPOW_ACTION_WARN_COOLING             1
1559f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_EPOW_ACTION_WARN_POWER               2
1569f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_EPOW_ACTION_SYSTEM_SHUTDOWN          3
1579f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_EPOW_ACTION_SYSTEM_HALT              4
1589f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_EPOW_ACTION_MAIN_ENCLOSURE           5
1599f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_EPOW_ACTION_POWER_OFF                7
1609f64bd8aSPaolo Bonzini     uint8_t event_modifier;
1619f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_EPOW_MODIFIER_NORMAL                 1
1629f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_EPOW_MODIFIER_ON_UPS                 2
1639f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_EPOW_MODIFIER_CRITICAL               3
1649f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_EPOW_MODIFIER_TEMPERATURE            4
1659f64bd8aSPaolo Bonzini     uint8_t extended_modifier;
1669f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_EPOW_XMODIFIER_SYSTEM_WIDE           0
1679f64bd8aSPaolo Bonzini #define RTAS_LOG_V6_EPOW_XMODIFIER_PARTITION_SPECIFIC    1
1689f64bd8aSPaolo Bonzini     uint8_t _resv;
1699f64bd8aSPaolo Bonzini     uint64_t reason_code;
1709f64bd8aSPaolo Bonzini } QEMU_PACKED;
1719f64bd8aSPaolo Bonzini 
172fd38804bSDaniel Henrique Barboza struct epow_extended_log {
1739f64bd8aSPaolo Bonzini     struct rtas_event_log_v6 v6hdr;
1749f64bd8aSPaolo Bonzini     struct rtas_event_log_v6_maina maina;
1759f64bd8aSPaolo Bonzini     struct rtas_event_log_v6_mainb mainb;
1769f64bd8aSPaolo Bonzini     struct rtas_event_log_v6_epow epow;
1779f64bd8aSPaolo Bonzini } QEMU_PACKED;
1789f64bd8aSPaolo Bonzini 
179afdbd403SBharata B Rao union drc_identifier {
180afdbd403SBharata B Rao     uint32_t index;
181afdbd403SBharata B Rao     uint32_t count;
182afdbd403SBharata B Rao     struct {
183afdbd403SBharata B Rao         uint32_t count;
184afdbd403SBharata B Rao         uint32_t index;
185afdbd403SBharata B Rao     } count_indexed;
186afdbd403SBharata B Rao     char name[1];
187afdbd403SBharata B Rao } QEMU_PACKED;
188afdbd403SBharata B Rao 
18931fe14d1SNathan Fontenot struct rtas_event_log_v6_hp {
19031fe14d1SNathan Fontenot #define RTAS_LOG_V6_SECTION_ID_HOTPLUG              0x4850 /* HP */
19131fe14d1SNathan Fontenot     struct rtas_event_log_v6_section_header hdr;
19231fe14d1SNathan Fontenot     uint8_t hotplug_type;
19331fe14d1SNathan Fontenot #define RTAS_LOG_V6_HP_TYPE_CPU                          1
19431fe14d1SNathan Fontenot #define RTAS_LOG_V6_HP_TYPE_MEMORY                       2
19531fe14d1SNathan Fontenot #define RTAS_LOG_V6_HP_TYPE_SLOT                         3
19631fe14d1SNathan Fontenot #define RTAS_LOG_V6_HP_TYPE_PHB                          4
19731fe14d1SNathan Fontenot #define RTAS_LOG_V6_HP_TYPE_PCI                          5
198ee3a71e3SShivaprasad G Bhat #define RTAS_LOG_V6_HP_TYPE_PMEM                         6
19931fe14d1SNathan Fontenot     uint8_t hotplug_action;
20031fe14d1SNathan Fontenot #define RTAS_LOG_V6_HP_ACTION_ADD                        1
20131fe14d1SNathan Fontenot #define RTAS_LOG_V6_HP_ACTION_REMOVE                     2
20231fe14d1SNathan Fontenot     uint8_t hotplug_identifier;
20331fe14d1SNathan Fontenot #define RTAS_LOG_V6_HP_ID_DRC_NAME                       1
20431fe14d1SNathan Fontenot #define RTAS_LOG_V6_HP_ID_DRC_INDEX                      2
20531fe14d1SNathan Fontenot #define RTAS_LOG_V6_HP_ID_DRC_COUNT                      3
206afdbd403SBharata B Rao #define RTAS_LOG_V6_HP_ID_DRC_COUNT_INDEXED              4
20731fe14d1SNathan Fontenot     uint8_t reserved;
208afdbd403SBharata B Rao     union drc_identifier drc_id;
20931fe14d1SNathan Fontenot } QEMU_PACKED;
21031fe14d1SNathan Fontenot 
211fd38804bSDaniel Henrique Barboza struct hp_extended_log {
21231fe14d1SNathan Fontenot     struct rtas_event_log_v6 v6hdr;
21331fe14d1SNathan Fontenot     struct rtas_event_log_v6_maina maina;
21431fe14d1SNathan Fontenot     struct rtas_event_log_v6_mainb mainb;
21531fe14d1SNathan Fontenot     struct rtas_event_log_v6_hp hp;
21631fe14d1SNathan Fontenot } QEMU_PACKED;
21731fe14d1SNathan Fontenot 
21881fe70e4SAravinda Prasad struct rtas_event_log_v6_mc {
21981fe70e4SAravinda Prasad #define RTAS_LOG_V6_SECTION_ID_MC                   0x4D43 /* MC */
22081fe70e4SAravinda Prasad     struct rtas_event_log_v6_section_header hdr;
22181fe70e4SAravinda Prasad     uint32_t fru_id;
22281fe70e4SAravinda Prasad     uint32_t proc_id;
22381fe70e4SAravinda Prasad     uint8_t error_type;
22481fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_TYPE_UE                           0
22581fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_TYPE_SLB                          1
22681fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_TYPE_ERAT                         2
22781fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_TYPE_TLB                          4
22881fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_TYPE_D_CACHE                      5
22981fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_TYPE_I_CACHE                      7
23081fe70e4SAravinda Prasad     uint8_t sub_err_type;
23181fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_UE_INDETERMINATE                  0
23281fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_UE_IFETCH                         1
23381fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_UE_PAGE_TABLE_WALK_IFETCH         2
23481fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_UE_LOAD_STORE                     3
23581fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_UE_PAGE_TABLE_WALK_LOAD_STORE     4
23681fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_SLB_PARITY                        0
23781fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_SLB_MULTIHIT                      1
23881fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_SLB_INDETERMINATE                 2
23981fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_ERAT_PARITY                       1
24081fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_ERAT_MULTIHIT                     2
24181fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_ERAT_INDETERMINATE                3
24281fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_TLB_PARITY                        1
24381fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_TLB_MULTIHIT                      2
24481fe70e4SAravinda Prasad #define RTAS_LOG_V6_MC_TLB_INDETERMINATE                 3
245cb9fb64dSMahesh Salgaonkar /*
246cb9fb64dSMahesh Salgaonkar  * Per PAPR,
247cb9fb64dSMahesh Salgaonkar  * For UE error type, set bit 1 of sub_err_type to indicate effective addr is
248cb9fb64dSMahesh Salgaonkar  * provided. For other error types (SLB/ERAT/TLB), set bit 0 to indicate
249cb9fb64dSMahesh Salgaonkar  * same.
250cb9fb64dSMahesh Salgaonkar  */
251cb9fb64dSMahesh Salgaonkar #define RTAS_LOG_V6_MC_UE_EA_ADDR_PROVIDED               0x40
252cb9fb64dSMahesh Salgaonkar #define RTAS_LOG_V6_MC_EA_ADDR_PROVIDED                  0x80
25381fe70e4SAravinda Prasad     uint8_t reserved_1[6];
25481fe70e4SAravinda Prasad     uint64_t effective_address;
25581fe70e4SAravinda Prasad     uint64_t logical_address;
25681fe70e4SAravinda Prasad } QEMU_PACKED;
25781fe70e4SAravinda Prasad 
25881fe70e4SAravinda Prasad struct mc_extended_log {
25981fe70e4SAravinda Prasad     struct rtas_event_log_v6 v6hdr;
26081fe70e4SAravinda Prasad     struct rtas_event_log_v6_mc mc;
26181fe70e4SAravinda Prasad } QEMU_PACKED;
26281fe70e4SAravinda Prasad 
26381fe70e4SAravinda Prasad struct MC_ierror_table {
26481fe70e4SAravinda Prasad     unsigned long srr1_mask;
26581fe70e4SAravinda Prasad     unsigned long srr1_value;
26681fe70e4SAravinda Prasad     bool nip_valid; /* nip is a valid indicator of faulting address */
26781fe70e4SAravinda Prasad     uint8_t error_type;
26881fe70e4SAravinda Prasad     uint8_t error_subtype;
26981fe70e4SAravinda Prasad     unsigned int initiator;
27081fe70e4SAravinda Prasad     unsigned int severity;
27181fe70e4SAravinda Prasad };
27281fe70e4SAravinda Prasad 
27381fe70e4SAravinda Prasad static const struct MC_ierror_table mc_ierror_table[] = {
27481fe70e4SAravinda Prasad { 0x00000000081c0000, 0x0000000000040000, true,
27581fe70e4SAravinda Prasad   RTAS_LOG_V6_MC_TYPE_UE, RTAS_LOG_V6_MC_UE_IFETCH,
27681fe70e4SAravinda Prasad   RTAS_LOG_INITIATOR_CPU, RTAS_LOG_SEVERITY_ERROR_SYNC, },
27781fe70e4SAravinda Prasad { 0x00000000081c0000, 0x0000000000080000, true,
27881fe70e4SAravinda Prasad   RTAS_LOG_V6_MC_TYPE_SLB, RTAS_LOG_V6_MC_SLB_PARITY,
27981fe70e4SAravinda Prasad   RTAS_LOG_INITIATOR_CPU, RTAS_LOG_SEVERITY_ERROR_SYNC, },
28081fe70e4SAravinda Prasad { 0x00000000081c0000, 0x00000000000c0000, true,
28181fe70e4SAravinda Prasad   RTAS_LOG_V6_MC_TYPE_SLB, RTAS_LOG_V6_MC_SLB_MULTIHIT,
28281fe70e4SAravinda Prasad   RTAS_LOG_INITIATOR_CPU, RTAS_LOG_SEVERITY_ERROR_SYNC, },
28381fe70e4SAravinda Prasad { 0x00000000081c0000, 0x0000000000100000, true,
28481fe70e4SAravinda Prasad   RTAS_LOG_V6_MC_TYPE_ERAT, RTAS_LOG_V6_MC_ERAT_MULTIHIT,
28581fe70e4SAravinda Prasad   RTAS_LOG_INITIATOR_CPU, RTAS_LOG_SEVERITY_ERROR_SYNC, },
28681fe70e4SAravinda Prasad { 0x00000000081c0000, 0x0000000000140000, true,
28781fe70e4SAravinda Prasad   RTAS_LOG_V6_MC_TYPE_TLB, RTAS_LOG_V6_MC_TLB_MULTIHIT,
28881fe70e4SAravinda Prasad   RTAS_LOG_INITIATOR_CPU, RTAS_LOG_SEVERITY_ERROR_SYNC, },
28981fe70e4SAravinda Prasad { 0x00000000081c0000, 0x0000000000180000, true,
29081fe70e4SAravinda Prasad   RTAS_LOG_V6_MC_TYPE_UE, RTAS_LOG_V6_MC_UE_PAGE_TABLE_WALK_IFETCH,
29181fe70e4SAravinda Prasad   RTAS_LOG_INITIATOR_CPU, RTAS_LOG_SEVERITY_ERROR_SYNC, } };
29281fe70e4SAravinda Prasad 
29381fe70e4SAravinda Prasad struct MC_derror_table {
29481fe70e4SAravinda Prasad     unsigned long dsisr_value;
29581fe70e4SAravinda Prasad     bool dar_valid; /* dar is a valid indicator of faulting address */
29681fe70e4SAravinda Prasad     uint8_t error_type;
29781fe70e4SAravinda Prasad     uint8_t error_subtype;
29881fe70e4SAravinda Prasad     unsigned int initiator;
29981fe70e4SAravinda Prasad     unsigned int severity;
30081fe70e4SAravinda Prasad };
30181fe70e4SAravinda Prasad 
30281fe70e4SAravinda Prasad static const struct MC_derror_table mc_derror_table[] = {
30381fe70e4SAravinda Prasad { 0x00008000, false,
30481fe70e4SAravinda Prasad   RTAS_LOG_V6_MC_TYPE_UE, RTAS_LOG_V6_MC_UE_LOAD_STORE,
30581fe70e4SAravinda Prasad   RTAS_LOG_INITIATOR_CPU, RTAS_LOG_SEVERITY_ERROR_SYNC, },
30681fe70e4SAravinda Prasad { 0x00004000, true,
30781fe70e4SAravinda Prasad   RTAS_LOG_V6_MC_TYPE_UE, RTAS_LOG_V6_MC_UE_PAGE_TABLE_WALK_LOAD_STORE,
30881fe70e4SAravinda Prasad   RTAS_LOG_INITIATOR_CPU, RTAS_LOG_SEVERITY_ERROR_SYNC, },
30981fe70e4SAravinda Prasad { 0x00000800, true,
31081fe70e4SAravinda Prasad   RTAS_LOG_V6_MC_TYPE_ERAT, RTAS_LOG_V6_MC_ERAT_MULTIHIT,
31181fe70e4SAravinda Prasad   RTAS_LOG_INITIATOR_CPU, RTAS_LOG_SEVERITY_ERROR_SYNC, },
31281fe70e4SAravinda Prasad { 0x00000400, true,
31381fe70e4SAravinda Prasad   RTAS_LOG_V6_MC_TYPE_TLB, RTAS_LOG_V6_MC_TLB_MULTIHIT,
31481fe70e4SAravinda Prasad   RTAS_LOG_INITIATOR_CPU, RTAS_LOG_SEVERITY_ERROR_SYNC, },
31581fe70e4SAravinda Prasad { 0x00000080, true,
31681fe70e4SAravinda Prasad   RTAS_LOG_V6_MC_TYPE_SLB, RTAS_LOG_V6_MC_SLB_MULTIHIT,  /* Before PARITY */
31781fe70e4SAravinda Prasad   RTAS_LOG_INITIATOR_CPU, RTAS_LOG_SEVERITY_ERROR_SYNC, },
31881fe70e4SAravinda Prasad { 0x00000100, true,
31981fe70e4SAravinda Prasad   RTAS_LOG_V6_MC_TYPE_SLB, RTAS_LOG_V6_MC_SLB_PARITY,
32081fe70e4SAravinda Prasad   RTAS_LOG_INITIATOR_CPU, RTAS_LOG_SEVERITY_ERROR_SYNC, } };
32181fe70e4SAravinda Prasad 
32281fe70e4SAravinda Prasad #define SRR1_MC_LOADSTORE(srr1) ((srr1) & PPC_BIT(42))
32381fe70e4SAravinda Prasad 
324ffbb1705SMichael Roth typedef enum EventClass {
325ffbb1705SMichael Roth     EVENT_CLASS_INTERNAL_ERRORS     = 0,
326ffbb1705SMichael Roth     EVENT_CLASS_EPOW                = 1,
327ffbb1705SMichael Roth     EVENT_CLASS_RESERVED            = 2,
328ffbb1705SMichael Roth     EVENT_CLASS_HOT_PLUG            = 3,
329ffbb1705SMichael Roth     EVENT_CLASS_IO                  = 4,
330ffbb1705SMichael Roth     EVENT_CLASS_MAX
331ffbb1705SMichael Roth } EventClassIndex;
332ffbb1705SMichael Roth #define EVENT_CLASS_MASK(index) (1 << (31 - index))
3339f64bd8aSPaolo Bonzini 
334ffbb1705SMichael Roth static const char * const event_names[EVENT_CLASS_MAX] = {
335ffbb1705SMichael Roth     [EVENT_CLASS_INTERNAL_ERRORS]       = "internal-errors",
336ffbb1705SMichael Roth     [EVENT_CLASS_EPOW]                  = "epow-events",
337ffbb1705SMichael Roth     [EVENT_CLASS_HOT_PLUG]              = "hot-plug-events",
338ffbb1705SMichael Roth     [EVENT_CLASS_IO]                    = "ibm,io-events",
339ffbb1705SMichael Roth };
340ffbb1705SMichael Roth 
341ce2918cbSDavid Gibson struct SpaprEventSource {
342ffbb1705SMichael Roth     int irq;
343ffbb1705SMichael Roth     uint32_t mask;
344ffbb1705SMichael Roth     bool enabled;
345ffbb1705SMichael Roth };
346ffbb1705SMichael Roth 
spapr_event_sources_new(void)347ce2918cbSDavid Gibson static SpaprEventSource *spapr_event_sources_new(void)
3489f64bd8aSPaolo Bonzini {
349ce2918cbSDavid Gibson     return g_new0(SpaprEventSource, EVENT_CLASS_MAX);
350ffbb1705SMichael Roth }
351ffbb1705SMichael Roth 
spapr_event_sources_register(SpaprEventSource * event_sources,EventClassIndex index,int irq)352ce2918cbSDavid Gibson static void spapr_event_sources_register(SpaprEventSource *event_sources,
353ffbb1705SMichael Roth                                         EventClassIndex index, int irq)
354ffbb1705SMichael Roth {
355ffbb1705SMichael Roth     /* we only support 1 irq per event class at the moment */
356ffbb1705SMichael Roth     g_assert(event_sources);
357ffbb1705SMichael Roth     g_assert(!event_sources[index].enabled);
358ffbb1705SMichael Roth     event_sources[index].irq = irq;
359ffbb1705SMichael Roth     event_sources[index].mask = EVENT_CLASS_MASK(index);
360ffbb1705SMichael Roth     event_sources[index].enabled = true;
361ffbb1705SMichael Roth }
362ffbb1705SMichael Roth 
363ce2918cbSDavid Gibson static const SpaprEventSource *
spapr_event_sources_get_source(SpaprEventSource * event_sources,EventClassIndex index)364ce2918cbSDavid Gibson spapr_event_sources_get_source(SpaprEventSource *event_sources,
365ffbb1705SMichael Roth                                EventClassIndex index)
366ffbb1705SMichael Roth {
367ffbb1705SMichael Roth     g_assert(index < EVENT_CLASS_MAX);
368ffbb1705SMichael Roth     g_assert(event_sources);
369ffbb1705SMichael Roth 
370ffbb1705SMichael Roth     return &event_sources[index];
371ffbb1705SMichael Roth }
372ffbb1705SMichael Roth 
spapr_dt_events(SpaprMachineState * spapr,void * fdt)373ce2918cbSDavid Gibson void spapr_dt_events(SpaprMachineState *spapr, void *fdt)
374ffbb1705SMichael Roth {
375ffbb1705SMichael Roth     uint32_t irq_ranges[EVENT_CLASS_MAX * 2];
376ffbb1705SMichael Roth     int i, count = 0, event_sources;
377ce2918cbSDavid Gibson     SpaprEventSource *events = spapr->event_sources;
378ffbb1705SMichael Roth 
379ffbb1705SMichael Roth     g_assert(events);
3809f64bd8aSPaolo Bonzini 
381ffb1e275SDavid Gibson     _FDT(event_sources = fdt_add_subnode(fdt, 0, "event-sources"));
3829f64bd8aSPaolo Bonzini 
383ffbb1705SMichael Roth     for (i = 0, count = 0; i < EVENT_CLASS_MAX; i++) {
384ffbb1705SMichael Roth         int node_offset;
385ffbb1705SMichael Roth         uint32_t interrupts[2];
386ce2918cbSDavid Gibson         const SpaprEventSource *source =
387ffbb1705SMichael Roth             spapr_event_sources_get_source(events, i);
388ffbb1705SMichael Roth         const char *source_name = event_names[i];
3899f64bd8aSPaolo Bonzini 
390ffbb1705SMichael Roth         if (!source->enabled) {
391ffbb1705SMichael Roth             continue;
392ffbb1705SMichael Roth         }
393ffbb1705SMichael Roth 
3945c7adcf4SGreg Kurz         spapr_dt_irq(interrupts, source->irq, false);
395ffbb1705SMichael Roth 
396ffbb1705SMichael Roth         _FDT(node_offset = fdt_add_subnode(fdt, event_sources, source_name));
397ffbb1705SMichael Roth         _FDT(fdt_setprop(fdt, node_offset, "interrupts", interrupts,
398ffbb1705SMichael Roth                          sizeof(interrupts)));
399ffbb1705SMichael Roth 
400ffbb1705SMichael Roth         irq_ranges[count++] = interrupts[0];
401ffbb1705SMichael Roth         irq_ranges[count++] = cpu_to_be32(1);
402ffbb1705SMichael Roth     }
403ffbb1705SMichael Roth 
404ffbb1705SMichael Roth     _FDT((fdt_setprop(fdt, event_sources, "interrupt-controller", NULL, 0)));
405ffbb1705SMichael Roth     _FDT((fdt_setprop_cell(fdt, event_sources, "#interrupt-cells", 2)));
406ffbb1705SMichael Roth     _FDT((fdt_setprop(fdt, event_sources, "interrupt-ranges",
407ffbb1705SMichael Roth                       irq_ranges, count * sizeof(uint32_t))));
408ffbb1705SMichael Roth }
409ffbb1705SMichael Roth 
410ce2918cbSDavid Gibson static const SpaprEventSource *
rtas_event_log_to_source(SpaprMachineState * spapr,int log_type)411ce2918cbSDavid Gibson rtas_event_log_to_source(SpaprMachineState *spapr, int log_type)
412ffbb1705SMichael Roth {
413ce2918cbSDavid Gibson     const SpaprEventSource *source;
414ffbb1705SMichael Roth 
415ffbb1705SMichael Roth     g_assert(spapr->event_sources);
416ffbb1705SMichael Roth 
417ffbb1705SMichael Roth     switch (log_type) {
418ffbb1705SMichael Roth     case RTAS_LOG_TYPE_HOTPLUG:
419ffbb1705SMichael Roth         source = spapr_event_sources_get_source(spapr->event_sources,
420ffbb1705SMichael Roth                                                 EVENT_CLASS_HOT_PLUG);
421ffbb1705SMichael Roth         if (spapr_ovec_test(spapr->ov5_cas, OV5_HP_EVT)) {
422ffbb1705SMichael Roth             g_assert(source->enabled);
423ffbb1705SMichael Roth             break;
424ffbb1705SMichael Roth         }
42554db89f5SPhilippe Mathieu-Daudé         /* fall through back to epow for legacy hotplug interrupt source */
426ffbb1705SMichael Roth     case RTAS_LOG_TYPE_EPOW:
427ffbb1705SMichael Roth         source = spapr_event_sources_get_source(spapr->event_sources,
428ffbb1705SMichael Roth                                                 EVENT_CLASS_EPOW);
429ffbb1705SMichael Roth         break;
430ffbb1705SMichael Roth     default:
431ffbb1705SMichael Roth         source = NULL;
432ffbb1705SMichael Roth     }
433ffbb1705SMichael Roth 
434ffbb1705SMichael Roth     return source;
435ffbb1705SMichael Roth }
436ffbb1705SMichael Roth 
rtas_event_log_to_irq(SpaprMachineState * spapr,int log_type)437ce2918cbSDavid Gibson static int rtas_event_log_to_irq(SpaprMachineState *spapr, int log_type)
438ffbb1705SMichael Roth {
439ce2918cbSDavid Gibson     const SpaprEventSource *source;
440ffbb1705SMichael Roth 
441ffbb1705SMichael Roth     source = rtas_event_log_to_source(spapr, log_type);
442ffbb1705SMichael Roth     g_assert(source);
443ffbb1705SMichael Roth     g_assert(source->enabled);
444ffbb1705SMichael Roth 
445ffbb1705SMichael Roth     return source->irq;
4469f64bd8aSPaolo Bonzini }
4479f64bd8aSPaolo Bonzini 
spapr_event_log_entry_type(SpaprEventLogEntry * entry)448ce2918cbSDavid Gibson static uint32_t spapr_event_log_entry_type(SpaprEventLogEntry *entry)
44931fe14d1SNathan Fontenot {
4505341258eSDavid Gibson     return entry->summary & RTAS_LOG_TYPE_MASK;
451fd38804bSDaniel Henrique Barboza }
45231fe14d1SNathan Fontenot 
rtas_event_log_queue(SpaprMachineState * spapr,SpaprEventLogEntry * entry)453ce2918cbSDavid Gibson static void rtas_event_log_queue(SpaprMachineState *spapr,
454ce2918cbSDavid Gibson                                  SpaprEventLogEntry *entry)
455fd38804bSDaniel Henrique Barboza {
45631fe14d1SNathan Fontenot     QTAILQ_INSERT_TAIL(&spapr->pending_events, entry, next);
45731fe14d1SNathan Fontenot }
45831fe14d1SNathan Fontenot 
rtas_event_log_dequeue(SpaprMachineState * spapr,uint32_t event_mask)459ce2918cbSDavid Gibson static SpaprEventLogEntry *rtas_event_log_dequeue(SpaprMachineState *spapr,
460fd38804bSDaniel Henrique Barboza                                                   uint32_t event_mask)
46131fe14d1SNathan Fontenot {
462ce2918cbSDavid Gibson     SpaprEventLogEntry *entry = NULL;
46331fe14d1SNathan Fontenot 
46431fe14d1SNathan Fontenot     QTAILQ_FOREACH(entry, &spapr->pending_events, next) {
465ce2918cbSDavid Gibson         const SpaprEventSource *source =
466fd38804bSDaniel Henrique Barboza             rtas_event_log_to_source(spapr,
467fd38804bSDaniel Henrique Barboza                                      spapr_event_log_entry_type(entry));
468ffbb1705SMichael Roth 
46959d0533bSPanNengyuan         g_assert(source);
470ffbb1705SMichael Roth         if (source->mask & event_mask) {
47131fe14d1SNathan Fontenot             break;
47231fe14d1SNathan Fontenot         }
47331fe14d1SNathan Fontenot     }
47431fe14d1SNathan Fontenot 
47531fe14d1SNathan Fontenot     if (entry) {
47631fe14d1SNathan Fontenot         QTAILQ_REMOVE(&spapr->pending_events, entry, next);
47731fe14d1SNathan Fontenot     }
47831fe14d1SNathan Fontenot 
47931fe14d1SNathan Fontenot     return entry;
48031fe14d1SNathan Fontenot }
48131fe14d1SNathan Fontenot 
rtas_event_log_contains(SpaprMachineState * spapr,uint32_t event_mask)4820ff6b520SGreg Kurz static bool rtas_event_log_contains(SpaprMachineState *spapr, uint32_t event_mask)
48331fe14d1SNathan Fontenot {
484ce2918cbSDavid Gibson     SpaprEventLogEntry *entry = NULL;
48531fe14d1SNathan Fontenot 
48631fe14d1SNathan Fontenot     QTAILQ_FOREACH(entry, &spapr->pending_events, next) {
487ce2918cbSDavid Gibson         const SpaprEventSource *source =
488fd38804bSDaniel Henrique Barboza             rtas_event_log_to_source(spapr,
489fd38804bSDaniel Henrique Barboza                                      spapr_event_log_entry_type(entry));
490ffbb1705SMichael Roth 
491ffbb1705SMichael Roth         if (source->mask & event_mask) {
49231fe14d1SNathan Fontenot             return true;
49331fe14d1SNathan Fontenot         }
49431fe14d1SNathan Fontenot     }
49531fe14d1SNathan Fontenot 
49631fe14d1SNathan Fontenot     return false;
49731fe14d1SNathan Fontenot }
49831fe14d1SNathan Fontenot 
4999f64bd8aSPaolo Bonzini static uint32_t next_plid;
5009f64bd8aSPaolo Bonzini 
spapr_init_v6hdr(struct rtas_event_log_v6 * v6hdr)50131fe14d1SNathan Fontenot static void spapr_init_v6hdr(struct rtas_event_log_v6 *v6hdr)
5029f64bd8aSPaolo Bonzini {
5039f64bd8aSPaolo Bonzini     v6hdr->b0 = RTAS_LOG_V6_B0_VALID | RTAS_LOG_V6_B0_NEW_LOG
5049f64bd8aSPaolo Bonzini         | RTAS_LOG_V6_B0_BIGENDIAN;
5059f64bd8aSPaolo Bonzini     v6hdr->b2 = RTAS_LOG_V6_B2_POWERPC_FORMAT
5069f64bd8aSPaolo Bonzini         | RTAS_LOG_V6_B2_LOG_FORMAT_PLATFORM_EVENT;
5079f64bd8aSPaolo Bonzini     v6hdr->company = cpu_to_be32(RTAS_LOG_V6_COMPANY_IBM);
50831fe14d1SNathan Fontenot }
50931fe14d1SNathan Fontenot 
spapr_init_maina(SpaprMachineState * spapr,struct rtas_event_log_v6_maina * maina,int section_count)5100ff6b520SGreg Kurz static void spapr_init_maina(SpaprMachineState *spapr,
5110ff6b520SGreg Kurz                              struct rtas_event_log_v6_maina *maina,
51231fe14d1SNathan Fontenot                              int section_count)
51331fe14d1SNathan Fontenot {
51431fe14d1SNathan Fontenot     struct tm tm;
51531fe14d1SNathan Fontenot     int year;
5169f64bd8aSPaolo Bonzini 
5179f64bd8aSPaolo Bonzini     maina->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINA);
5189f64bd8aSPaolo Bonzini     maina->hdr.section_length = cpu_to_be16(sizeof(*maina));
5199f64bd8aSPaolo Bonzini     /* FIXME: section version, subtype and creator id? */
520147ff807SCédric Le Goater     spapr_rtc_read(&spapr->rtc, &tm, NULL);
5219f64bd8aSPaolo Bonzini     year = tm.tm_year + 1900;
5229f64bd8aSPaolo Bonzini     maina->creation_date = cpu_to_be32((to_bcd(year / 100) << 24)
5239f64bd8aSPaolo Bonzini                                        | (to_bcd(year % 100) << 16)
5249f64bd8aSPaolo Bonzini                                        | (to_bcd(tm.tm_mon + 1) << 8)
5259f64bd8aSPaolo Bonzini                                        | to_bcd(tm.tm_mday));
5269f64bd8aSPaolo Bonzini     maina->creation_time = cpu_to_be32((to_bcd(tm.tm_hour) << 24)
5279f64bd8aSPaolo Bonzini                                        | (to_bcd(tm.tm_min) << 16)
5289f64bd8aSPaolo Bonzini                                        | (to_bcd(tm.tm_sec) << 8));
5299f64bd8aSPaolo Bonzini     maina->creator_id = 'H'; /* Hypervisor */
53031fe14d1SNathan Fontenot     maina->section_count = section_count;
5319f64bd8aSPaolo Bonzini     maina->plid = next_plid++;
53231fe14d1SNathan Fontenot }
53331fe14d1SNathan Fontenot 
spapr_powerdown_req(Notifier * n,void * opaque)53431fe14d1SNathan Fontenot static void spapr_powerdown_req(Notifier *n, void *opaque)
53531fe14d1SNathan Fontenot {
536ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
537ce2918cbSDavid Gibson     SpaprEventLogEntry *entry;
53831fe14d1SNathan Fontenot     struct rtas_event_log_v6 *v6hdr;
53931fe14d1SNathan Fontenot     struct rtas_event_log_v6_maina *maina;
54031fe14d1SNathan Fontenot     struct rtas_event_log_v6_mainb *mainb;
54131fe14d1SNathan Fontenot     struct rtas_event_log_v6_epow *epow;
542fd38804bSDaniel Henrique Barboza     struct epow_extended_log *new_epow;
54331fe14d1SNathan Fontenot 
544ce2918cbSDavid Gibson     entry = g_new(SpaprEventLogEntry, 1);
54531fe14d1SNathan Fontenot     new_epow = g_malloc0(sizeof(*new_epow));
546fd38804bSDaniel Henrique Barboza     entry->extended_log = new_epow;
547fd38804bSDaniel Henrique Barboza 
54831fe14d1SNathan Fontenot     v6hdr = &new_epow->v6hdr;
54931fe14d1SNathan Fontenot     maina = &new_epow->maina;
55031fe14d1SNathan Fontenot     mainb = &new_epow->mainb;
55131fe14d1SNathan Fontenot     epow = &new_epow->epow;
55231fe14d1SNathan Fontenot 
5535341258eSDavid Gibson     entry->summary = RTAS_LOG_VERSION_6
55431fe14d1SNathan Fontenot                        | RTAS_LOG_SEVERITY_EVENT
55531fe14d1SNathan Fontenot                        | RTAS_LOG_DISPOSITION_NOT_RECOVERED
55631fe14d1SNathan Fontenot                        | RTAS_LOG_OPTIONAL_PART_PRESENT
557fd38804bSDaniel Henrique Barboza                        | RTAS_LOG_TYPE_EPOW;
5585341258eSDavid Gibson     entry->extended_length = sizeof(*new_epow);
55931fe14d1SNathan Fontenot 
56031fe14d1SNathan Fontenot     spapr_init_v6hdr(v6hdr);
5610ff6b520SGreg Kurz     spapr_init_maina(spapr, maina, 3 /* Main-A, Main-B and EPOW */);
5629f64bd8aSPaolo Bonzini 
5639f64bd8aSPaolo Bonzini     mainb->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINB);
5649f64bd8aSPaolo Bonzini     mainb->hdr.section_length = cpu_to_be16(sizeof(*mainb));
5659f64bd8aSPaolo Bonzini     /* FIXME: section version, subtype and creator id? */
5669f64bd8aSPaolo Bonzini     mainb->subsystem_id = 0xa0; /* External environment */
5679f64bd8aSPaolo Bonzini     mainb->event_severity = 0x00; /* Informational / non-error */
5689f64bd8aSPaolo Bonzini     mainb->event_subtype = 0xd0; /* Normal shutdown */
5699f64bd8aSPaolo Bonzini 
5709f64bd8aSPaolo Bonzini     epow->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_EPOW);
5719f64bd8aSPaolo Bonzini     epow->hdr.section_length = cpu_to_be16(sizeof(*epow));
5729f64bd8aSPaolo Bonzini     epow->hdr.section_version = 2; /* includes extended modifier */
5739f64bd8aSPaolo Bonzini     /* FIXME: section subtype and creator id? */
5749f64bd8aSPaolo Bonzini     epow->sensor_value = RTAS_LOG_V6_EPOW_ACTION_SYSTEM_SHUTDOWN;
5759f64bd8aSPaolo Bonzini     epow->event_modifier = RTAS_LOG_V6_EPOW_MODIFIER_NORMAL;
5769f64bd8aSPaolo Bonzini     epow->extended_modifier = RTAS_LOG_V6_EPOW_XMODIFIER_PARTITION_SPECIFIC;
5779f64bd8aSPaolo Bonzini 
578fd38804bSDaniel Henrique Barboza     rtas_event_log_queue(spapr, entry);
57931fe14d1SNathan Fontenot 
58077183755SCédric Le Goater     qemu_irq_pulse(spapr_qirq(spapr,
58177183755SCédric Le Goater                    rtas_event_log_to_irq(spapr, RTAS_LOG_TYPE_EPOW)));
58231fe14d1SNathan Fontenot }
58331fe14d1SNathan Fontenot 
spapr_hotplug_req_event(uint8_t hp_id,uint8_t hp_action,SpaprDrcType drc_type,union drc_identifier * drc_id)5847a36ae7aSBharata B Rao static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action,
585ce2918cbSDavid Gibson                                     SpaprDrcType drc_type,
586afdbd403SBharata B Rao                                     union drc_identifier *drc_id)
58731fe14d1SNathan Fontenot {
588ce2918cbSDavid Gibson     SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
589ce2918cbSDavid Gibson     SpaprEventLogEntry *entry;
590fd38804bSDaniel Henrique Barboza     struct hp_extended_log *new_hp;
59131fe14d1SNathan Fontenot     struct rtas_event_log_v6 *v6hdr;
59231fe14d1SNathan Fontenot     struct rtas_event_log_v6_maina *maina;
59331fe14d1SNathan Fontenot     struct rtas_event_log_v6_mainb *mainb;
59431fe14d1SNathan Fontenot     struct rtas_event_log_v6_hp *hp;
59531fe14d1SNathan Fontenot 
596ce2918cbSDavid Gibson     entry = g_new(SpaprEventLogEntry, 1);
597b21e2380SMarkus Armbruster     new_hp = g_new0(struct hp_extended_log, 1);
598fd38804bSDaniel Henrique Barboza     entry->extended_log = new_hp;
599fd38804bSDaniel Henrique Barboza 
60031fe14d1SNathan Fontenot     v6hdr = &new_hp->v6hdr;
60131fe14d1SNathan Fontenot     maina = &new_hp->maina;
60231fe14d1SNathan Fontenot     mainb = &new_hp->mainb;
60331fe14d1SNathan Fontenot     hp = &new_hp->hp;
60431fe14d1SNathan Fontenot 
6055341258eSDavid Gibson     entry->summary = RTAS_LOG_VERSION_6
60631fe14d1SNathan Fontenot         | RTAS_LOG_SEVERITY_EVENT
60731fe14d1SNathan Fontenot         | RTAS_LOG_DISPOSITION_NOT_RECOVERED
60831fe14d1SNathan Fontenot         | RTAS_LOG_OPTIONAL_PART_PRESENT
60931fe14d1SNathan Fontenot         | RTAS_LOG_INITIATOR_HOTPLUG
610fd38804bSDaniel Henrique Barboza         | RTAS_LOG_TYPE_HOTPLUG;
6115341258eSDavid Gibson     entry->extended_length = sizeof(*new_hp);
61231fe14d1SNathan Fontenot 
61331fe14d1SNathan Fontenot     spapr_init_v6hdr(v6hdr);
6140ff6b520SGreg Kurz     spapr_init_maina(spapr, maina, 3 /* Main-A, Main-B, HP */);
61531fe14d1SNathan Fontenot 
61631fe14d1SNathan Fontenot     mainb->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINB);
61731fe14d1SNathan Fontenot     mainb->hdr.section_length = cpu_to_be16(sizeof(*mainb));
61831fe14d1SNathan Fontenot     mainb->subsystem_id = 0x80; /* External environment */
61931fe14d1SNathan Fontenot     mainb->event_severity = 0x00; /* Informational / non-error */
62031fe14d1SNathan Fontenot     mainb->event_subtype = 0x00; /* Normal shutdown */
62131fe14d1SNathan Fontenot 
62231fe14d1SNathan Fontenot     hp->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_HOTPLUG);
62331fe14d1SNathan Fontenot     hp->hdr.section_length = cpu_to_be16(sizeof(*hp));
62431fe14d1SNathan Fontenot     hp->hdr.section_version = 1; /* includes extended modifier */
62531fe14d1SNathan Fontenot     hp->hotplug_action = hp_action;
6267a36ae7aSBharata B Rao     hp->hotplug_identifier = hp_id;
62731fe14d1SNathan Fontenot 
62831fe14d1SNathan Fontenot     switch (drc_type) {
62931fe14d1SNathan Fontenot     case SPAPR_DR_CONNECTOR_TYPE_PCI:
63031fe14d1SNathan Fontenot         hp->hotplug_type = RTAS_LOG_V6_HP_TYPE_PCI;
63131fe14d1SNathan Fontenot         break;
632c20d332aSBharata B Rao     case SPAPR_DR_CONNECTOR_TYPE_LMB:
633c20d332aSBharata B Rao         hp->hotplug_type = RTAS_LOG_V6_HP_TYPE_MEMORY;
634c20d332aSBharata B Rao         break;
635af81cf32SBharata B Rao     case SPAPR_DR_CONNECTOR_TYPE_CPU:
636af81cf32SBharata B Rao         hp->hotplug_type = RTAS_LOG_V6_HP_TYPE_CPU;
637af81cf32SBharata B Rao         break;
6384b6d336fSMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_PHB:
6394b6d336fSMichael Roth         hp->hotplug_type = RTAS_LOG_V6_HP_TYPE_PHB;
6404b6d336fSMichael Roth         break;
641ee3a71e3SShivaprasad G Bhat     case SPAPR_DR_CONNECTOR_TYPE_PMEM:
642ee3a71e3SShivaprasad G Bhat         hp->hotplug_type = RTAS_LOG_V6_HP_TYPE_PMEM;
643ee3a71e3SShivaprasad G Bhat         break;
64431fe14d1SNathan Fontenot     default:
64531fe14d1SNathan Fontenot         /* we shouldn't be signaling hotplug events for resources
64631fe14d1SNathan Fontenot          * that don't support them
64731fe14d1SNathan Fontenot          */
64831fe14d1SNathan Fontenot         g_assert(false);
64931fe14d1SNathan Fontenot         return;
65031fe14d1SNathan Fontenot     }
65131fe14d1SNathan Fontenot 
6527a36ae7aSBharata B Rao     if (hp_id == RTAS_LOG_V6_HP_ID_DRC_COUNT) {
653afdbd403SBharata B Rao         hp->drc_id.count = cpu_to_be32(drc_id->count);
6547a36ae7aSBharata B Rao     } else if (hp_id == RTAS_LOG_V6_HP_ID_DRC_INDEX) {
655afdbd403SBharata B Rao         hp->drc_id.index = cpu_to_be32(drc_id->index);
656afdbd403SBharata B Rao     } else if (hp_id == RTAS_LOG_V6_HP_ID_DRC_COUNT_INDEXED) {
657afdbd403SBharata B Rao         /* we should not be using count_indexed value unless the guest
658afdbd403SBharata B Rao          * supports dedicated hotplug event source
659afdbd403SBharata B Rao          */
66073598c75SGreg Kurz         g_assert(spapr_memory_hot_unplug_supported(spapr));
661afdbd403SBharata B Rao         hp->drc_id.count_indexed.count =
662afdbd403SBharata B Rao             cpu_to_be32(drc_id->count_indexed.count);
663afdbd403SBharata B Rao         hp->drc_id.count_indexed.index =
664afdbd403SBharata B Rao             cpu_to_be32(drc_id->count_indexed.index);
6657a36ae7aSBharata B Rao     }
6667a36ae7aSBharata B Rao 
667fd38804bSDaniel Henrique Barboza     rtas_event_log_queue(spapr, entry);
66831fe14d1SNathan Fontenot 
66977183755SCédric Le Goater     qemu_irq_pulse(spapr_qirq(spapr,
67077183755SCédric Le Goater                    rtas_event_log_to_irq(spapr, RTAS_LOG_TYPE_HOTPLUG)));
67131fe14d1SNathan Fontenot }
67231fe14d1SNathan Fontenot 
spapr_hotplug_req_add_by_index(SpaprDrc * drc)673ce2918cbSDavid Gibson void spapr_hotplug_req_add_by_index(SpaprDrc *drc)
67431fe14d1SNathan Fontenot {
675ce2918cbSDavid Gibson     SpaprDrcType drc_type = spapr_drc_type(drc);
676afdbd403SBharata B Rao     union drc_identifier drc_id;
6777a36ae7aSBharata B Rao 
6780b55aa91SDavid Gibson     drc_id.index = spapr_drc_index(drc);
6797a36ae7aSBharata B Rao     spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_INDEX,
680afdbd403SBharata B Rao                             RTAS_LOG_V6_HP_ACTION_ADD, drc_type, &drc_id);
68131fe14d1SNathan Fontenot }
68231fe14d1SNathan Fontenot 
spapr_hotplug_req_remove_by_index(SpaprDrc * drc)683ce2918cbSDavid Gibson void spapr_hotplug_req_remove_by_index(SpaprDrc *drc)
68431fe14d1SNathan Fontenot {
685ce2918cbSDavid Gibson     SpaprDrcType drc_type = spapr_drc_type(drc);
686afdbd403SBharata B Rao     union drc_identifier drc_id;
6877a36ae7aSBharata B Rao 
6880b55aa91SDavid Gibson     drc_id.index = spapr_drc_index(drc);
6897a36ae7aSBharata B Rao     spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_INDEX,
690afdbd403SBharata B Rao                             RTAS_LOG_V6_HP_ACTION_REMOVE, drc_type, &drc_id);
6917a36ae7aSBharata B Rao }
6927a36ae7aSBharata B Rao 
spapr_hotplug_req_add_by_count(SpaprDrcType drc_type,uint32_t count)693ce2918cbSDavid Gibson void spapr_hotplug_req_add_by_count(SpaprDrcType drc_type,
6947a36ae7aSBharata B Rao                                        uint32_t count)
6957a36ae7aSBharata B Rao {
696afdbd403SBharata B Rao     union drc_identifier drc_id;
697afdbd403SBharata B Rao 
698afdbd403SBharata B Rao     drc_id.count = count;
6997a36ae7aSBharata B Rao     spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_COUNT,
700afdbd403SBharata B Rao                             RTAS_LOG_V6_HP_ACTION_ADD, drc_type, &drc_id);
7017a36ae7aSBharata B Rao }
7027a36ae7aSBharata B Rao 
spapr_hotplug_req_remove_by_count(SpaprDrcType drc_type,uint32_t count)703ce2918cbSDavid Gibson void spapr_hotplug_req_remove_by_count(SpaprDrcType drc_type,
7047a36ae7aSBharata B Rao                                           uint32_t count)
7057a36ae7aSBharata B Rao {
706afdbd403SBharata B Rao     union drc_identifier drc_id;
707afdbd403SBharata B Rao 
708afdbd403SBharata B Rao     drc_id.count = count;
7097a36ae7aSBharata B Rao     spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_COUNT,
710afdbd403SBharata B Rao                             RTAS_LOG_V6_HP_ACTION_REMOVE, drc_type, &drc_id);
711afdbd403SBharata B Rao }
712afdbd403SBharata B Rao 
spapr_hotplug_req_add_by_count_indexed(SpaprDrcType drc_type,uint32_t count,uint32_t index)713ce2918cbSDavid Gibson void spapr_hotplug_req_add_by_count_indexed(SpaprDrcType drc_type,
714afdbd403SBharata B Rao                                             uint32_t count, uint32_t index)
715afdbd403SBharata B Rao {
716afdbd403SBharata B Rao     union drc_identifier drc_id;
717afdbd403SBharata B Rao 
718afdbd403SBharata B Rao     drc_id.count_indexed.count = count;
719afdbd403SBharata B Rao     drc_id.count_indexed.index = index;
720afdbd403SBharata B Rao     spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_COUNT_INDEXED,
721afdbd403SBharata B Rao                             RTAS_LOG_V6_HP_ACTION_ADD, drc_type, &drc_id);
722afdbd403SBharata B Rao }
723afdbd403SBharata B Rao 
spapr_hotplug_req_remove_by_count_indexed(SpaprDrcType drc_type,uint32_t count,uint32_t index)724ce2918cbSDavid Gibson void spapr_hotplug_req_remove_by_count_indexed(SpaprDrcType drc_type,
725afdbd403SBharata B Rao                                                uint32_t count, uint32_t index)
726afdbd403SBharata B Rao {
727afdbd403SBharata B Rao     union drc_identifier drc_id;
728afdbd403SBharata B Rao 
729afdbd403SBharata B Rao     drc_id.count_indexed.count = count;
730afdbd403SBharata B Rao     drc_id.count_indexed.index = index;
731afdbd403SBharata B Rao     spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_COUNT_INDEXED,
732afdbd403SBharata B Rao                             RTAS_LOG_V6_HP_ACTION_REMOVE, drc_type, &drc_id);
7339f64bd8aSPaolo Bonzini }
7349f64bd8aSPaolo Bonzini 
spapr_mc_set_ea_provided_flag(struct mc_extended_log * ext_elog)735cb9fb64dSMahesh Salgaonkar static void spapr_mc_set_ea_provided_flag(struct mc_extended_log *ext_elog)
736cb9fb64dSMahesh Salgaonkar {
737cb9fb64dSMahesh Salgaonkar     switch (ext_elog->mc.error_type) {
738cb9fb64dSMahesh Salgaonkar     case RTAS_LOG_V6_MC_TYPE_UE:
739cb9fb64dSMahesh Salgaonkar         ext_elog->mc.sub_err_type |= RTAS_LOG_V6_MC_UE_EA_ADDR_PROVIDED;
740cb9fb64dSMahesh Salgaonkar         break;
741cb9fb64dSMahesh Salgaonkar     case RTAS_LOG_V6_MC_TYPE_SLB:
742cb9fb64dSMahesh Salgaonkar     case RTAS_LOG_V6_MC_TYPE_ERAT:
743cb9fb64dSMahesh Salgaonkar     case RTAS_LOG_V6_MC_TYPE_TLB:
744cb9fb64dSMahesh Salgaonkar         ext_elog->mc.sub_err_type |= RTAS_LOG_V6_MC_EA_ADDR_PROVIDED;
745cb9fb64dSMahesh Salgaonkar         break;
746cb9fb64dSMahesh Salgaonkar     default:
747cb9fb64dSMahesh Salgaonkar         break;
748cb9fb64dSMahesh Salgaonkar     }
749cb9fb64dSMahesh Salgaonkar }
750cb9fb64dSMahesh Salgaonkar 
spapr_mce_get_elog_type(PowerPCCPU * cpu,bool recovered,struct mc_extended_log * ext_elog)75181fe70e4SAravinda Prasad static uint32_t spapr_mce_get_elog_type(PowerPCCPU *cpu, bool recovered,
75281fe70e4SAravinda Prasad                                         struct mc_extended_log *ext_elog)
75381fe70e4SAravinda Prasad {
75481fe70e4SAravinda Prasad     int i;
75581fe70e4SAravinda Prasad     CPUPPCState *env = &cpu->env;
75681fe70e4SAravinda Prasad     uint32_t summary;
75781fe70e4SAravinda Prasad     uint64_t dsisr = env->spr[SPR_DSISR];
75881fe70e4SAravinda Prasad 
75981fe70e4SAravinda Prasad     summary = RTAS_LOG_VERSION_6 | RTAS_LOG_OPTIONAL_PART_PRESENT;
76081fe70e4SAravinda Prasad     if (recovered) {
76181fe70e4SAravinda Prasad         summary |= RTAS_LOG_DISPOSITION_FULLY_RECOVERED;
76281fe70e4SAravinda Prasad     } else {
76381fe70e4SAravinda Prasad         summary |= RTAS_LOG_DISPOSITION_NOT_RECOVERED;
76481fe70e4SAravinda Prasad     }
76581fe70e4SAravinda Prasad 
76681fe70e4SAravinda Prasad     if (SRR1_MC_LOADSTORE(env->spr[SPR_SRR1])) {
76781fe70e4SAravinda Prasad         for (i = 0; i < ARRAY_SIZE(mc_derror_table); i++) {
76881fe70e4SAravinda Prasad             if (!(dsisr & mc_derror_table[i].dsisr_value)) {
76981fe70e4SAravinda Prasad                 continue;
77081fe70e4SAravinda Prasad             }
77181fe70e4SAravinda Prasad 
77281fe70e4SAravinda Prasad             ext_elog->mc.error_type = mc_derror_table[i].error_type;
77381fe70e4SAravinda Prasad             ext_elog->mc.sub_err_type = mc_derror_table[i].error_subtype;
77481fe70e4SAravinda Prasad             if (mc_derror_table[i].dar_valid) {
77581fe70e4SAravinda Prasad                 ext_elog->mc.effective_address = cpu_to_be64(env->spr[SPR_DAR]);
776cb9fb64dSMahesh Salgaonkar                 spapr_mc_set_ea_provided_flag(ext_elog);
77781fe70e4SAravinda Prasad             }
77881fe70e4SAravinda Prasad 
77981fe70e4SAravinda Prasad             summary |= mc_derror_table[i].initiator
78081fe70e4SAravinda Prasad                         | mc_derror_table[i].severity;
78181fe70e4SAravinda Prasad 
78281fe70e4SAravinda Prasad             return summary;
78381fe70e4SAravinda Prasad         }
78481fe70e4SAravinda Prasad     } else {
78581fe70e4SAravinda Prasad         for (i = 0; i < ARRAY_SIZE(mc_ierror_table); i++) {
78681fe70e4SAravinda Prasad             if ((env->spr[SPR_SRR1] & mc_ierror_table[i].srr1_mask) !=
78781fe70e4SAravinda Prasad                     mc_ierror_table[i].srr1_value) {
78881fe70e4SAravinda Prasad                 continue;
78981fe70e4SAravinda Prasad             }
79081fe70e4SAravinda Prasad 
79181fe70e4SAravinda Prasad             ext_elog->mc.error_type = mc_ierror_table[i].error_type;
79281fe70e4SAravinda Prasad             ext_elog->mc.sub_err_type = mc_ierror_table[i].error_subtype;
79381fe70e4SAravinda Prasad             if (mc_ierror_table[i].nip_valid) {
79481fe70e4SAravinda Prasad                 ext_elog->mc.effective_address = cpu_to_be64(env->nip);
795cb9fb64dSMahesh Salgaonkar                 spapr_mc_set_ea_provided_flag(ext_elog);
79681fe70e4SAravinda Prasad             }
79781fe70e4SAravinda Prasad 
79881fe70e4SAravinda Prasad             summary |= mc_ierror_table[i].initiator
79981fe70e4SAravinda Prasad                         | mc_ierror_table[i].severity;
80081fe70e4SAravinda Prasad 
80181fe70e4SAravinda Prasad             return summary;
80281fe70e4SAravinda Prasad         }
80381fe70e4SAravinda Prasad     }
80481fe70e4SAravinda Prasad 
80581fe70e4SAravinda Prasad     summary |= RTAS_LOG_INITIATOR_CPU;
80681fe70e4SAravinda Prasad     return summary;
80781fe70e4SAravinda Prasad }
80881fe70e4SAravinda Prasad 
spapr_mce_dispatch_elog(SpaprMachineState * spapr,PowerPCCPU * cpu,bool recovered)8090ff6b520SGreg Kurz static void spapr_mce_dispatch_elog(SpaprMachineState *spapr, PowerPCCPU *cpu,
8100ff6b520SGreg Kurz                                     bool recovered)
81181fe70e4SAravinda Prasad {
812ad77c6caSNicholas Piggin     CPUState *cs = CPU(cpu);
81381fe70e4SAravinda Prasad     CPUPPCState *env = &cpu->env;
814ad77c6caSNicholas Piggin     uint64_t rtas_addr;
81581fe70e4SAravinda Prasad     struct rtas_error_log log;
81681fe70e4SAravinda Prasad     struct mc_extended_log *ext_elog;
81781fe70e4SAravinda Prasad     uint32_t summary;
81881fe70e4SAravinda Prasad 
81981fe70e4SAravinda Prasad     ext_elog = g_malloc0(sizeof(*ext_elog));
82081fe70e4SAravinda Prasad     summary = spapr_mce_get_elog_type(cpu, recovered, ext_elog);
82181fe70e4SAravinda Prasad 
82281fe70e4SAravinda Prasad     log.summary = cpu_to_be32(summary);
82381fe70e4SAravinda Prasad     log.extended_length = cpu_to_be32(sizeof(*ext_elog));
82481fe70e4SAravinda Prasad 
82581fe70e4SAravinda Prasad     spapr_init_v6hdr(&ext_elog->v6hdr);
82681fe70e4SAravinda Prasad     ext_elog->mc.hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MC);
82781fe70e4SAravinda Prasad     ext_elog->mc.hdr.section_length =
82881fe70e4SAravinda Prasad                     cpu_to_be16(sizeof(struct rtas_event_log_v6_mc));
82981fe70e4SAravinda Prasad     ext_elog->mc.hdr.section_version = 1;
83081fe70e4SAravinda Prasad 
83181fe70e4SAravinda Prasad     /* get rtas addr from fdt */
83281fe70e4SAravinda Prasad     rtas_addr = spapr_get_rtas_addr();
83381fe70e4SAravinda Prasad     if (!rtas_addr) {
8344f7a11f9SNicholas Piggin         if (!recovered) {
835b90b9ecbSNicholas Piggin             error_report(
836b90b9ecbSNicholas Piggin "FWNMI: Unable to deliver machine check to guest: rtas_addr not found.");
837bae9dc4fSNicholas Piggin             qemu_system_guest_panicked(NULL);
8384f7a11f9SNicholas Piggin         } else {
8394f7a11f9SNicholas Piggin             warn_report(
8404f7a11f9SNicholas Piggin "FWNMI: Unable to deliver machine check to guest: rtas_addr not found. "
8414f7a11f9SNicholas Piggin "Machine check recovered.");
8424f7a11f9SNicholas Piggin         }
84381fe70e4SAravinda Prasad         g_free(ext_elog);
84481fe70e4SAravinda Prasad         return;
84581fe70e4SAravinda Prasad     }
84681fe70e4SAravinda Prasad 
8474f7a11f9SNicholas Piggin     /*
8484f7a11f9SNicholas Piggin      * By taking the interlock, we assume that the MCE will be
8494f7a11f9SNicholas Piggin      * delivered to the guest. CAUTION: don't add anything that could
8504f7a11f9SNicholas Piggin      * prevent the MCE to be delivered after this line, otherwise the
8514f7a11f9SNicholas Piggin      * guest won't be able to release the interlock and ultimately
8524f7a11f9SNicholas Piggin      * hang/crash?
8534f7a11f9SNicholas Piggin      */
8544f7a11f9SNicholas Piggin     spapr->fwnmi_machine_check_interlock = cpu->vcpu_id;
8554f7a11f9SNicholas Piggin 
85681fe70e4SAravinda Prasad     stq_be_phys(&address_space_memory, rtas_addr + RTAS_ERROR_LOG_OFFSET,
85781fe70e4SAravinda Prasad                 env->gpr[3]);
85881fe70e4SAravinda Prasad     cpu_physical_memory_write(rtas_addr + RTAS_ERROR_LOG_OFFSET +
85981fe70e4SAravinda Prasad                               sizeof(env->gpr[3]), &log, sizeof(log));
86081fe70e4SAravinda Prasad     cpu_physical_memory_write(rtas_addr + RTAS_ERROR_LOG_OFFSET +
86181fe70e4SAravinda Prasad                               sizeof(env->gpr[3]) + sizeof(log), ext_elog,
86281fe70e4SAravinda Prasad                               sizeof(*ext_elog));
863ad77c6caSNicholas Piggin     g_free(ext_elog);
86481fe70e4SAravinda Prasad 
86581fe70e4SAravinda Prasad     env->gpr[3] = rtas_addr + RTAS_ERROR_LOG_OFFSET;
86681fe70e4SAravinda Prasad 
867ad77c6caSNicholas Piggin     ppc_cpu_do_fwnmi_machine_check(cs, spapr->fwnmi_machine_check_addr);
86881fe70e4SAravinda Prasad }
86981fe70e4SAravinda Prasad 
spapr_mce_req_event(PowerPCCPU * cpu,bool recovered)87081fe70e4SAravinda Prasad void spapr_mce_req_event(PowerPCCPU *cpu, bool recovered)
8719ac703acSAravinda Prasad {
8729ac703acSAravinda Prasad     SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
8739ac703acSAravinda Prasad     CPUState *cs = CPU(cpu);
8742500fb42SAravinda Prasad     int ret;
8759ac703acSAravinda Prasad 
8768af7e1feSNicholas Piggin     if (spapr->fwnmi_machine_check_addr == -1) {
8776c3dd24cSNicholas Piggin         /* Non-FWNMI case, deliver it like an architected CPU interrupt. */
8789ac703acSAravinda Prasad         cs->exception_index = POWERPC_EXCP_MCHECK;
8799ac703acSAravinda Prasad         ppc_cpu_do_interrupt(cs);
8809ac703acSAravinda Prasad         return;
8819ac703acSAravinda Prasad     }
8829ac703acSAravinda Prasad 
8836c3dd24cSNicholas Piggin     /* Wait for FWNMI interlock. */
8848af7e1feSNicholas Piggin     while (spapr->fwnmi_machine_check_interlock != -1) {
8859ac703acSAravinda Prasad         /*
8869ac703acSAravinda Prasad          * Check whether the same CPU got machine check error
8879ac703acSAravinda Prasad          * while still handling the mc error (i.e., before
8889ac703acSAravinda Prasad          * that CPU called "ibm,nmi-interlock")
8899ac703acSAravinda Prasad          */
8908af7e1feSNicholas Piggin         if (spapr->fwnmi_machine_check_interlock == cpu->vcpu_id) {
8914f7a11f9SNicholas Piggin             if (!recovered) {
892b90b9ecbSNicholas Piggin                 error_report(
893b90b9ecbSNicholas Piggin "FWNMI: Unable to deliver machine check to guest: nested machine check.");
8949ac703acSAravinda Prasad                 qemu_system_guest_panicked(NULL);
8954f7a11f9SNicholas Piggin             } else {
8964f7a11f9SNicholas Piggin                 warn_report(
8974f7a11f9SNicholas Piggin "FWNMI: Unable to deliver machine check to guest: nested machine check. "
8984f7a11f9SNicholas Piggin "Machine check recovered.");
8994f7a11f9SNicholas Piggin             }
9009ac703acSAravinda Prasad             return;
9019ac703acSAravinda Prasad         }
902*7c754c78SStefan Hajnoczi         qemu_cond_wait_bql(&spapr->fwnmi_machine_check_interlock_cond);
9038af7e1feSNicholas Piggin         if (spapr->fwnmi_machine_check_addr == -1) {
9046c3dd24cSNicholas Piggin             /*
9056c3dd24cSNicholas Piggin              * If the machine was reset while waiting for the interlock,
9066c3dd24cSNicholas Piggin              * abort the delivery. The machine check applies to a context
9076c3dd24cSNicholas Piggin              * that no longer exists, so it wouldn't make sense to deliver
9086c3dd24cSNicholas Piggin              * it now.
9096c3dd24cSNicholas Piggin              */
9109ac703acSAravinda Prasad             return;
9119ac703acSAravinda Prasad         }
9129ac703acSAravinda Prasad     }
91381fe70e4SAravinda Prasad 
914d7f5013eSMarkus Armbruster     /*
915d7f5013eSMarkus Armbruster      * Try to block migration while FWNMI is being handled, so the
916d7f5013eSMarkus Armbruster      * machine check handler runs where the information passed to it
917d7f5013eSMarkus Armbruster      * actually makes sense.  This shouldn't actually block migration,
918d7f5013eSMarkus Armbruster      * only delay it slightly, assuming migration is retried.  If the
919d7f5013eSMarkus Armbruster      * attempt to block fails, carry on.  Unfortunately, it always
920d7f5013eSMarkus Armbruster      * fails when running with -only-migrate.  A proper interface to
921d7f5013eSMarkus Armbruster      * delay migration completion for a bit could avoid that.
922d7f5013eSMarkus Armbruster      */
923c8a7fc51SSteve Sistare     error_setg(&spapr->fwnmi_migration_blocker,
924c8a7fc51SSteve Sistare         "A machine check is being handled during migration. The handler"
925c8a7fc51SSteve Sistare         "may run and log hardware error on the destination");
926c8a7fc51SSteve Sistare 
927c8a7fc51SSteve Sistare     ret = migrate_add_blocker(&spapr->fwnmi_migration_blocker, NULL);
9282500fb42SAravinda Prasad     if (ret == -EBUSY) {
9292500fb42SAravinda Prasad         warn_report("Received a fwnmi while migration was in progress");
9302500fb42SAravinda Prasad     }
9312500fb42SAravinda Prasad 
9320ff6b520SGreg Kurz     spapr_mce_dispatch_elog(spapr, cpu, recovered);
9339ac703acSAravinda Prasad }
9349ac703acSAravinda Prasad 
check_exception(PowerPCCPU * cpu,SpaprMachineState * spapr,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)935ce2918cbSDavid Gibson static void check_exception(PowerPCCPU *cpu, SpaprMachineState *spapr,
9369f64bd8aSPaolo Bonzini                             uint32_t token, uint32_t nargs,
9379f64bd8aSPaolo Bonzini                             target_ulong args,
9389f64bd8aSPaolo Bonzini                             uint32_t nret, target_ulong rets)
9399f64bd8aSPaolo Bonzini {
94031fe14d1SNathan Fontenot     uint32_t mask, buf, len, event_len;
941ce2918cbSDavid Gibson     SpaprEventLogEntry *event;
9425341258eSDavid Gibson     struct rtas_error_log header;
943ffbb1705SMichael Roth     int i;
9449f64bd8aSPaolo Bonzini 
9459f64bd8aSPaolo Bonzini     if ((nargs < 6) || (nargs > 7) || nret != 1) {
946a64d325dSAlexey Kardashevskiy         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
9479f64bd8aSPaolo Bonzini         return;
9489f64bd8aSPaolo Bonzini     }
9499f64bd8aSPaolo Bonzini 
9509f64bd8aSPaolo Bonzini     mask = rtas_ld(args, 2);
9519f64bd8aSPaolo Bonzini     buf = rtas_ld(args, 4);
9529f64bd8aSPaolo Bonzini     len = rtas_ld(args, 5);
9539f64bd8aSPaolo Bonzini 
954fd38804bSDaniel Henrique Barboza     event = rtas_event_log_dequeue(spapr, mask);
95531fe14d1SNathan Fontenot     if (!event) {
95631fe14d1SNathan Fontenot         goto out_no_events;
9579f64bd8aSPaolo Bonzini     }
9589f64bd8aSPaolo Bonzini 
9595341258eSDavid Gibson     event_len = event->extended_length + sizeof(header);
96031fe14d1SNathan Fontenot 
96131fe14d1SNathan Fontenot     if (event_len < len) {
96231fe14d1SNathan Fontenot         len = event_len;
9639f64bd8aSPaolo Bonzini     }
96431fe14d1SNathan Fontenot 
9655341258eSDavid Gibson     header.summary = cpu_to_be32(event->summary);
9665341258eSDavid Gibson     header.extended_length = cpu_to_be32(event->extended_length);
9675341258eSDavid Gibson     cpu_physical_memory_write(buf, &header, sizeof(header));
9685341258eSDavid Gibson     cpu_physical_memory_write(buf + sizeof(header), event->extended_log,
9695341258eSDavid Gibson                               event->extended_length);
97031fe14d1SNathan Fontenot     rtas_st(rets, 0, RTAS_OUT_SUCCESS);
971fd38804bSDaniel Henrique Barboza     g_free(event->extended_log);
97231fe14d1SNathan Fontenot     g_free(event);
97331fe14d1SNathan Fontenot 
97431fe14d1SNathan Fontenot     /* according to PAPR+, the IRQ must be left asserted, or re-asserted, if
97531fe14d1SNathan Fontenot      * there are still pending events to be fetched via check-exception. We
97631fe14d1SNathan Fontenot      * do the latter here, since our code relies on edge-triggered
97731fe14d1SNathan Fontenot      * interrupts.
97831fe14d1SNathan Fontenot      */
979ffbb1705SMichael Roth     for (i = 0; i < EVENT_CLASS_MAX; i++) {
9800ff6b520SGreg Kurz         if (rtas_event_log_contains(spapr, EVENT_CLASS_MASK(i))) {
981ce2918cbSDavid Gibson             const SpaprEventSource *source =
982ffbb1705SMichael Roth                 spapr_event_sources_get_source(spapr->event_sources, i);
983ffbb1705SMichael Roth 
984ffbb1705SMichael Roth             g_assert(source->enabled);
98577183755SCédric Le Goater             qemu_irq_pulse(spapr_qirq(spapr, source->irq));
986ffbb1705SMichael Roth         }
98731fe14d1SNathan Fontenot     }
98831fe14d1SNathan Fontenot 
98931fe14d1SNathan Fontenot     return;
99031fe14d1SNathan Fontenot 
99131fe14d1SNathan Fontenot out_no_events:
99231fe14d1SNathan Fontenot     rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
9939f64bd8aSPaolo Bonzini }
9949f64bd8aSPaolo Bonzini 
event_scan(PowerPCCPU * cpu,SpaprMachineState * spapr,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)995ce2918cbSDavid Gibson static void event_scan(PowerPCCPU *cpu, SpaprMachineState *spapr,
99679853e18STyrel Datwyler                        uint32_t token, uint32_t nargs,
99779853e18STyrel Datwyler                        target_ulong args,
99879853e18STyrel Datwyler                        uint32_t nret, target_ulong rets)
99979853e18STyrel Datwyler {
1000dff669d6SLaurent Vivier     int i;
100179853e18STyrel Datwyler     if (nargs != 4 || nret != 1) {
100279853e18STyrel Datwyler         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
100379853e18STyrel Datwyler         return;
100479853e18STyrel Datwyler     }
1005dff669d6SLaurent Vivier 
1006dff669d6SLaurent Vivier     for (i = 0; i < EVENT_CLASS_MAX; i++) {
10070ff6b520SGreg Kurz         if (rtas_event_log_contains(spapr, EVENT_CLASS_MASK(i))) {
1008dff669d6SLaurent Vivier             const SpaprEventSource *source =
1009dff669d6SLaurent Vivier                 spapr_event_sources_get_source(spapr->event_sources, i);
1010dff669d6SLaurent Vivier 
1011dff669d6SLaurent Vivier             g_assert(source->enabled);
1012dff669d6SLaurent Vivier             qemu_irq_pulse(spapr_qirq(spapr, source->irq));
1013dff669d6SLaurent Vivier         }
1014dff669d6SLaurent Vivier     }
1015dff669d6SLaurent Vivier 
101679853e18STyrel Datwyler     rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
101779853e18STyrel Datwyler }
101879853e18STyrel Datwyler 
spapr_clear_pending_events(SpaprMachineState * spapr)1019ce2918cbSDavid Gibson void spapr_clear_pending_events(SpaprMachineState *spapr)
102056258174SDaniel Henrique Barboza {
1021ce2918cbSDavid Gibson     SpaprEventLogEntry *entry = NULL, *next_entry;
102256258174SDaniel Henrique Barboza 
1023d492a75cSGreg Kurz     QTAILQ_FOREACH_SAFE(entry, &spapr->pending_events, next, next_entry) {
102456258174SDaniel Henrique Barboza         QTAILQ_REMOVE(&spapr->pending_events, entry, next);
102556258174SDaniel Henrique Barboza         g_free(entry->extended_log);
102656258174SDaniel Henrique Barboza         g_free(entry);
102756258174SDaniel Henrique Barboza     }
102856258174SDaniel Henrique Barboza }
102956258174SDaniel Henrique Barboza 
spapr_clear_pending_hotplug_events(SpaprMachineState * spapr)1030ad334d89SGreg Kurz void spapr_clear_pending_hotplug_events(SpaprMachineState *spapr)
1031ad334d89SGreg Kurz {
1032ad334d89SGreg Kurz     SpaprEventLogEntry *entry = NULL, *next_entry;
1033ad334d89SGreg Kurz 
1034ad334d89SGreg Kurz     QTAILQ_FOREACH_SAFE(entry, &spapr->pending_events, next, next_entry) {
1035ad334d89SGreg Kurz         if (spapr_event_log_entry_type(entry) == RTAS_LOG_TYPE_HOTPLUG) {
1036ad334d89SGreg Kurz             QTAILQ_REMOVE(&spapr->pending_events, entry, next);
1037ad334d89SGreg Kurz             g_free(entry->extended_log);
1038ad334d89SGreg Kurz             g_free(entry);
1039ad334d89SGreg Kurz         }
1040ad334d89SGreg Kurz     }
1041ad334d89SGreg Kurz }
1042ad334d89SGreg Kurz 
spapr_events_init(SpaprMachineState * spapr)1043ce2918cbSDavid Gibson void spapr_events_init(SpaprMachineState *spapr)
10449f64bd8aSPaolo Bonzini {
104582cffa2eSCédric Le Goater     int epow_irq = SPAPR_IRQ_EPOW;
10464fe75a8cSCédric Le Goater 
104782cffa2eSCédric Le Goater     if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
10484fe75a8cSCédric Le Goater         epow_irq = spapr_irq_findone(spapr, &error_fatal);
104982cffa2eSCédric Le Goater     }
10504fe75a8cSCédric Le Goater 
10514fe75a8cSCédric Le Goater     spapr_irq_claim(spapr, epow_irq, false, &error_fatal);
10524fe75a8cSCédric Le Goater 
105331fe14d1SNathan Fontenot     QTAILQ_INIT(&spapr->pending_events);
1054ffbb1705SMichael Roth 
1055ffbb1705SMichael Roth     spapr->event_sources = spapr_event_sources_new();
1056ffbb1705SMichael Roth 
1057ffbb1705SMichael Roth     spapr_event_sources_register(spapr->event_sources, EVENT_CLASS_EPOW,
10584fe75a8cSCédric Le Goater                                  epow_irq);
1059ffbb1705SMichael Roth 
1060ffbb1705SMichael Roth     /* NOTE: if machine supports modern/dedicated hotplug event source,
1061ffbb1705SMichael Roth      * we add it to the device-tree unconditionally. This means we may
1062ffbb1705SMichael Roth      * have cases where the source is enabled in QEMU, but unused by the
1063ffbb1705SMichael Roth      * guest because it does not support modern hotplug events, so we
1064ffbb1705SMichael Roth      * take care to rely on checking for negotiation of OV5_HP_EVT option
1065ffbb1705SMichael Roth      * before attempting to use it to signal events, rather than simply
1066ffbb1705SMichael Roth      * checking that it's enabled.
1067ffbb1705SMichael Roth      */
1068ffbb1705SMichael Roth     if (spapr->use_hotplug_event_source) {
106982cffa2eSCédric Le Goater         int hp_irq = SPAPR_IRQ_HOTPLUG;
10704fe75a8cSCédric Le Goater 
107182cffa2eSCédric Le Goater         if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
10724fe75a8cSCédric Le Goater             hp_irq = spapr_irq_findone(spapr, &error_fatal);
107382cffa2eSCédric Le Goater         }
10744fe75a8cSCédric Le Goater 
10754fe75a8cSCédric Le Goater         spapr_irq_claim(spapr, hp_irq, false, &error_fatal);
10764fe75a8cSCédric Le Goater 
1077ffbb1705SMichael Roth         spapr_event_sources_register(spapr->event_sources, EVENT_CLASS_HOT_PLUG,
10784fe75a8cSCédric Le Goater                                      hp_irq);
1079ffbb1705SMichael Roth     }
1080ffbb1705SMichael Roth 
10819f64bd8aSPaolo Bonzini     spapr->epow_notifier.notify = spapr_powerdown_req;
10829f64bd8aSPaolo Bonzini     qemu_register_powerdown_notifier(&spapr->epow_notifier);
10833a3b8502SAlexey Kardashevskiy     spapr_rtas_register(RTAS_CHECK_EXCEPTION, "check-exception",
10843a3b8502SAlexey Kardashevskiy                         check_exception);
108579853e18STyrel Datwyler     spapr_rtas_register(RTAS_EVENT_SCAN, "event-scan", event_scan);
10869f64bd8aSPaolo Bonzini }
1087