xref: /openbmc/qemu/hw/ppc/spapr_events.c (revision 35658f6e)
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 
44 struct 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 
90 struct 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 
109 struct 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 
117 struct 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 
132 struct 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 
145 struct 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 
168 struct 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 
176 struct 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 
200 struct 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 
223 void 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 
242 static 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 
254 static 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 
284 static 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 
309 static uint32_t next_plid;
310 
311 static 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 
320 static 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 
344 static 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 
392 static 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 
399 static 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     case SPAPR_DR_CONNECTOR_TYPE_CPU:
453         hp->hotplug_type = RTAS_LOG_V6_HP_TYPE_CPU;
454         break;
455     default:
456         /* we shouldn't be signaling hotplug events for resources
457          * that don't support them
458          */
459         g_assert(false);
460         return;
461     }
462 
463     if (hp_id == RTAS_LOG_V6_HP_ID_DRC_COUNT) {
464         hp->drc.count = cpu_to_be32(drc);
465     } else if (hp_id == RTAS_LOG_V6_HP_ID_DRC_INDEX) {
466         hp->drc.index = cpu_to_be32(drc);
467     }
468 
469     rtas_event_log_queue(RTAS_LOG_TYPE_HOTPLUG, new_hp, true);
470 
471     qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq));
472 }
473 
474 void spapr_hotplug_req_add_by_index(sPAPRDRConnector *drc)
475 {
476     sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
477     sPAPRDRConnectorType drc_type = drck->get_type(drc);
478     uint32_t index = drck->get_index(drc);
479 
480     spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_INDEX,
481                             RTAS_LOG_V6_HP_ACTION_ADD, drc_type, index);
482 }
483 
484 void spapr_hotplug_req_remove_by_index(sPAPRDRConnector *drc)
485 {
486     sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
487     sPAPRDRConnectorType drc_type = drck->get_type(drc);
488     uint32_t index = drck->get_index(drc);
489 
490     spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_INDEX,
491                             RTAS_LOG_V6_HP_ACTION_REMOVE, drc_type, index);
492 }
493 
494 void spapr_hotplug_req_add_by_count(sPAPRDRConnectorType drc_type,
495                                        uint32_t count)
496 {
497     spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_COUNT,
498                             RTAS_LOG_V6_HP_ACTION_ADD, drc_type, count);
499 }
500 
501 void spapr_hotplug_req_remove_by_count(sPAPRDRConnectorType drc_type,
502                                           uint32_t count)
503 {
504     spapr_hotplug_req_event(RTAS_LOG_V6_HP_ID_DRC_COUNT,
505                             RTAS_LOG_V6_HP_ACTION_REMOVE, drc_type, count);
506 }
507 
508 static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr,
509                             uint32_t token, uint32_t nargs,
510                             target_ulong args,
511                             uint32_t nret, target_ulong rets)
512 {
513     uint32_t mask, buf, len, event_len;
514     uint64_t xinfo;
515     sPAPREventLogEntry *event;
516     struct rtas_error_log *hdr;
517 
518     if ((nargs < 6) || (nargs > 7) || nret != 1) {
519         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
520         return;
521     }
522 
523     xinfo = rtas_ld(args, 1);
524     mask = rtas_ld(args, 2);
525     buf = rtas_ld(args, 4);
526     len = rtas_ld(args, 5);
527     if (nargs == 7) {
528         xinfo |= (uint64_t)rtas_ld(args, 6) << 32;
529     }
530 
531     event = rtas_event_log_dequeue(mask, true);
532     if (!event) {
533         goto out_no_events;
534     }
535 
536     hdr = event->data;
537     event_len = be32_to_cpu(hdr->extended_length) + sizeof(*hdr);
538 
539     if (event_len < len) {
540         len = event_len;
541     }
542 
543     cpu_physical_memory_write(buf, event->data, len);
544     rtas_st(rets, 0, RTAS_OUT_SUCCESS);
545     g_free(event->data);
546     g_free(event);
547 
548     /* according to PAPR+, the IRQ must be left asserted, or re-asserted, if
549      * there are still pending events to be fetched via check-exception. We
550      * do the latter here, since our code relies on edge-triggered
551      * interrupts.
552      */
553     if (rtas_event_log_contains(mask, true)) {
554         qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq));
555     }
556 
557     return;
558 
559 out_no_events:
560     rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
561 }
562 
563 static void event_scan(PowerPCCPU *cpu, sPAPRMachineState *spapr,
564                        uint32_t token, uint32_t nargs,
565                        target_ulong args,
566                        uint32_t nret, target_ulong rets)
567 {
568     uint32_t mask, buf, len, event_len;
569     sPAPREventLogEntry *event;
570     struct rtas_error_log *hdr;
571 
572     if (nargs != 4 || nret != 1) {
573         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
574         return;
575     }
576 
577     mask = rtas_ld(args, 0);
578     buf = rtas_ld(args, 2);
579     len = rtas_ld(args, 3);
580 
581     event = rtas_event_log_dequeue(mask, false);
582     if (!event) {
583         goto out_no_events;
584     }
585 
586     hdr = event->data;
587     event_len = be32_to_cpu(hdr->extended_length) + sizeof(*hdr);
588 
589     if (event_len < len) {
590         len = event_len;
591     }
592 
593     cpu_physical_memory_write(buf, event->data, len);
594     rtas_st(rets, 0, RTAS_OUT_SUCCESS);
595     g_free(event->data);
596     g_free(event);
597     return;
598 
599 out_no_events:
600     rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
601 }
602 
603 void spapr_events_init(sPAPRMachineState *spapr)
604 {
605     QTAILQ_INIT(&spapr->pending_events);
606     spapr->check_exception_irq = xics_alloc(spapr->icp, 0, 0, false,
607                                             &error_fatal);
608     spapr->epow_notifier.notify = spapr_powerdown_req;
609     qemu_register_powerdown_notifier(&spapr->epow_notifier);
610     spapr_rtas_register(RTAS_CHECK_EXCEPTION, "check-exception",
611                         check_exception);
612     spapr_rtas_register(RTAS_EVENT_SCAN, "event-scan", event_scan);
613 }
614