xref: /qemu/hw/ppc/spapr_rtas.c (revision db4ef288f4a6d285b39dc8ac477092d76971a300)
139ac8455SDavid Gibson /*
239ac8455SDavid Gibson  * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
339ac8455SDavid Gibson  *
439ac8455SDavid Gibson  * Hypercall based emulated RTAS
539ac8455SDavid Gibson  *
639ac8455SDavid Gibson  * Copyright (c) 2010-2011 David Gibson, IBM Corporation.
739ac8455SDavid Gibson  *
839ac8455SDavid Gibson  * Permission is hereby granted, free of charge, to any person obtaining a copy
939ac8455SDavid Gibson  * of this software and associated documentation files (the "Software"), to deal
1039ac8455SDavid Gibson  * in the Software without restriction, including without limitation the rights
1139ac8455SDavid Gibson  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1239ac8455SDavid Gibson  * copies of the Software, and to permit persons to whom the Software is
1339ac8455SDavid Gibson  * furnished to do so, subject to the following conditions:
1439ac8455SDavid Gibson  *
1539ac8455SDavid Gibson  * The above copyright notice and this permission notice shall be included in
1639ac8455SDavid Gibson  * all copies or substantial portions of the Software.
1739ac8455SDavid Gibson  *
1839ac8455SDavid Gibson  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1939ac8455SDavid Gibson  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2039ac8455SDavid Gibson  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2139ac8455SDavid Gibson  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2239ac8455SDavid Gibson  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2339ac8455SDavid Gibson  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2439ac8455SDavid Gibson  * THE SOFTWARE.
2539ac8455SDavid Gibson  *
2639ac8455SDavid Gibson  */
2739ac8455SDavid Gibson #include "cpu.h"
289c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
29dccfcd0eSPaolo Bonzini #include "sysemu/char.h"
3039ac8455SDavid Gibson #include "hw/qdev.h"
319c17d615SPaolo Bonzini #include "sysemu/device_tree.h"
32*db4ef288SBharata B Rao #include "sysemu/cpus.h"
3339ac8455SDavid Gibson 
340d09e41aSPaolo Bonzini #include "hw/ppc/spapr.h"
350d09e41aSPaolo Bonzini #include "hw/ppc/spapr_vio.h"
36e010ad8fSWenchao Xia #include "qapi-event.h"
3739ac8455SDavid Gibson 
3839ac8455SDavid Gibson #include <libfdt.h>
398c8639dfSMike Day #include "hw/ppc/spapr_drc.h"
408c8639dfSMike Day 
418c8639dfSMike Day /* #define DEBUG_SPAPR */
428c8639dfSMike Day 
438c8639dfSMike Day #ifdef DEBUG_SPAPR
448c8639dfSMike Day #define DPRINTF(fmt, ...) \
458c8639dfSMike Day     do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
468c8639dfSMike Day #else
478c8639dfSMike Day #define DPRINTF(fmt, ...) \
488c8639dfSMike Day     do { } while (0)
498c8639dfSMike Day #endif
508c8639dfSMike Day 
5128e02042SDavid Gibson static sPAPRConfigureConnectorState *spapr_ccs_find(sPAPRMachineState *spapr,
5246503c2bSMichael Roth                                                     uint32_t drc_index)
5346503c2bSMichael Roth {
5446503c2bSMichael Roth     sPAPRConfigureConnectorState *ccs = NULL;
5546503c2bSMichael Roth 
5646503c2bSMichael Roth     QTAILQ_FOREACH(ccs, &spapr->ccs_list, next) {
5746503c2bSMichael Roth         if (ccs->drc_index == drc_index) {
5846503c2bSMichael Roth             break;
5946503c2bSMichael Roth         }
6046503c2bSMichael Roth     }
6146503c2bSMichael Roth 
6246503c2bSMichael Roth     return ccs;
6346503c2bSMichael Roth }
6446503c2bSMichael Roth 
6528e02042SDavid Gibson static void spapr_ccs_add(sPAPRMachineState *spapr,
6646503c2bSMichael Roth                           sPAPRConfigureConnectorState *ccs)
6746503c2bSMichael Roth {
6846503c2bSMichael Roth     g_assert(!spapr_ccs_find(spapr, ccs->drc_index));
6946503c2bSMichael Roth     QTAILQ_INSERT_HEAD(&spapr->ccs_list, ccs, next);
7046503c2bSMichael Roth }
7146503c2bSMichael Roth 
7228e02042SDavid Gibson static void spapr_ccs_remove(sPAPRMachineState *spapr,
7346503c2bSMichael Roth                              sPAPRConfigureConnectorState *ccs)
7446503c2bSMichael Roth {
7546503c2bSMichael Roth     QTAILQ_REMOVE(&spapr->ccs_list, ccs, next);
7646503c2bSMichael Roth     g_free(ccs);
7746503c2bSMichael Roth }
7846503c2bSMichael Roth 
7946503c2bSMichael Roth void spapr_ccs_reset_hook(void *opaque)
8046503c2bSMichael Roth {
8128e02042SDavid Gibson     sPAPRMachineState *spapr = opaque;
8246503c2bSMichael Roth     sPAPRConfigureConnectorState *ccs, *ccs_tmp;
8346503c2bSMichael Roth 
8446503c2bSMichael Roth     QTAILQ_FOREACH_SAFE(ccs, &spapr->ccs_list, next, ccs_tmp) {
8546503c2bSMichael Roth         spapr_ccs_remove(spapr, ccs);
8646503c2bSMichael Roth     }
8746503c2bSMichael Roth }
8839ac8455SDavid Gibson 
8928e02042SDavid Gibson static void rtas_display_character(PowerPCCPU *cpu, sPAPRMachineState *spapr,
90821303f5SDavid Gibson                                    uint32_t token, uint32_t nargs,
91821303f5SDavid Gibson                                    target_ulong args,
92821303f5SDavid Gibson                                    uint32_t nret, target_ulong rets)
93821303f5SDavid Gibson {
94821303f5SDavid Gibson     uint8_t c = rtas_ld(args, 0);
955f2e2ba2SDavid Gibson     VIOsPAPRDevice *sdev = vty_lookup(spapr, 0);
96821303f5SDavid Gibson 
97821303f5SDavid Gibson     if (!sdev) {
98a64d325dSAlexey Kardashevskiy         rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
99821303f5SDavid Gibson     } else {
100821303f5SDavid Gibson         vty_putchars(sdev, &c, sizeof(c));
101a64d325dSAlexey Kardashevskiy         rtas_st(rets, 0, RTAS_OUT_SUCCESS);
102821303f5SDavid Gibson     }
103821303f5SDavid Gibson }
104821303f5SDavid Gibson 
10528e02042SDavid Gibson static void rtas_power_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
106821303f5SDavid Gibson                            uint32_t token, uint32_t nargs, target_ulong args,
107821303f5SDavid Gibson                            uint32_t nret, target_ulong rets)
108821303f5SDavid Gibson {
109821303f5SDavid Gibson     if (nargs != 2 || nret != 1) {
110a64d325dSAlexey Kardashevskiy         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
111821303f5SDavid Gibson         return;
112821303f5SDavid Gibson     }
113821303f5SDavid Gibson     qemu_system_shutdown_request();
114a64d325dSAlexey Kardashevskiy     rtas_st(rets, 0, RTAS_OUT_SUCCESS);
115821303f5SDavid Gibson }
116821303f5SDavid Gibson 
11728e02042SDavid Gibson static void rtas_system_reboot(PowerPCCPU *cpu, sPAPRMachineState *spapr,
118c821a43cSDavid Gibson                                uint32_t token, uint32_t nargs,
119c821a43cSDavid Gibson                                target_ulong args,
120c821a43cSDavid Gibson                                uint32_t nret, target_ulong rets)
121c821a43cSDavid Gibson {
122c821a43cSDavid Gibson     if (nargs != 0 || nret != 1) {
123a64d325dSAlexey Kardashevskiy         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
124c821a43cSDavid Gibson         return;
125c821a43cSDavid Gibson     }
126c821a43cSDavid Gibson     qemu_system_reset_request();
127a64d325dSAlexey Kardashevskiy     rtas_st(rets, 0, RTAS_OUT_SUCCESS);
128c821a43cSDavid Gibson }
129c821a43cSDavid Gibson 
130210b580bSAnthony Liguori static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
13128e02042SDavid Gibson                                          sPAPRMachineState *spapr,
132a9f8ad8fSDavid Gibson                                          uint32_t token, uint32_t nargs,
133a9f8ad8fSDavid Gibson                                          target_ulong args,
134a9f8ad8fSDavid Gibson                                          uint32_t nret, target_ulong rets)
135a9f8ad8fSDavid Gibson {
136a9f8ad8fSDavid Gibson     target_ulong id;
1370f20ba62SAlexey Kardashevskiy     PowerPCCPU *cpu;
138a9f8ad8fSDavid Gibson 
139a9f8ad8fSDavid Gibson     if (nargs != 1 || nret != 2) {
140a64d325dSAlexey Kardashevskiy         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
141a9f8ad8fSDavid Gibson         return;
142a9f8ad8fSDavid Gibson     }
143a9f8ad8fSDavid Gibson 
144a9f8ad8fSDavid Gibson     id = rtas_ld(args, 0);
1450f20ba62SAlexey Kardashevskiy     cpu = ppc_get_vcpu_by_dt_id(id);
14605318a85SAndreas Färber     if (cpu != NULL) {
1470f20ba62SAlexey Kardashevskiy         if (CPU(cpu)->halted) {
148a9f8ad8fSDavid Gibson             rtas_st(rets, 1, 0);
149a9f8ad8fSDavid Gibson         } else {
150a9f8ad8fSDavid Gibson             rtas_st(rets, 1, 2);
151a9f8ad8fSDavid Gibson         }
152a9f8ad8fSDavid Gibson 
153a64d325dSAlexey Kardashevskiy         rtas_st(rets, 0, RTAS_OUT_SUCCESS);
154a9f8ad8fSDavid Gibson         return;
155a9f8ad8fSDavid Gibson     }
156a9f8ad8fSDavid Gibson 
157a9f8ad8fSDavid Gibson     /* Didn't find a matching cpu */
158a64d325dSAlexey Kardashevskiy     rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
159a9f8ad8fSDavid Gibson }
160a9f8ad8fSDavid Gibson 
16128e02042SDavid Gibson static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr,
162a9f8ad8fSDavid Gibson                            uint32_t token, uint32_t nargs,
163a9f8ad8fSDavid Gibson                            target_ulong args,
164a9f8ad8fSDavid Gibson                            uint32_t nret, target_ulong rets)
165a9f8ad8fSDavid Gibson {
166a9f8ad8fSDavid Gibson     target_ulong id, start, r3;
1670f20ba62SAlexey Kardashevskiy     PowerPCCPU *cpu;
168a9f8ad8fSDavid Gibson 
169a9f8ad8fSDavid Gibson     if (nargs != 3 || nret != 1) {
170a64d325dSAlexey Kardashevskiy         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
171a9f8ad8fSDavid Gibson         return;
172a9f8ad8fSDavid Gibson     }
173a9f8ad8fSDavid Gibson 
174a9f8ad8fSDavid Gibson     id = rtas_ld(args, 0);
175a9f8ad8fSDavid Gibson     start = rtas_ld(args, 1);
176a9f8ad8fSDavid Gibson     r3 = rtas_ld(args, 2);
177a9f8ad8fSDavid Gibson 
1780f20ba62SAlexey Kardashevskiy     cpu = ppc_get_vcpu_by_dt_id(id);
1790f20ba62SAlexey Kardashevskiy     if (cpu != NULL) {
1800f20ba62SAlexey Kardashevskiy         CPUState *cs = CPU(cpu);
181c67e216bSAndreas Färber         CPUPPCState *env = &cpu->env;
182c08d7424SAndreas Färber 
183c67e216bSAndreas Färber         if (!cs->halted) {
184a64d325dSAlexey Kardashevskiy             rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
185a9f8ad8fSDavid Gibson             return;
186a9f8ad8fSDavid Gibson         }
187a9f8ad8fSDavid Gibson 
188048706d9SDavid Gibson         /* This will make sure qemu state is up to date with kvm, and
189048706d9SDavid Gibson          * mark it dirty so our changes get flushed back before the
190048706d9SDavid Gibson          * new cpu enters */
191dd1750d7SAndreas Färber         kvm_cpu_synchronize_state(cs);
192048706d9SDavid Gibson 
193a9f8ad8fSDavid Gibson         env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME);
194a9f8ad8fSDavid Gibson         env->nip = start;
195a9f8ad8fSDavid Gibson         env->gpr[3] = r3;
196c67e216bSAndreas Färber         cs->halted = 0;
197a9f8ad8fSDavid Gibson 
198c67e216bSAndreas Färber         qemu_cpu_kick(cs);
199a9f8ad8fSDavid Gibson 
200a64d325dSAlexey Kardashevskiy         rtas_st(rets, 0, RTAS_OUT_SUCCESS);
201a9f8ad8fSDavid Gibson         return;
202a9f8ad8fSDavid Gibson     }
203a9f8ad8fSDavid Gibson 
204a9f8ad8fSDavid Gibson     /* Didn't find a matching cpu */
205a64d325dSAlexey Kardashevskiy     rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
206a9f8ad8fSDavid Gibson }
207a9f8ad8fSDavid Gibson 
20828e02042SDavid Gibson static void rtas_stop_self(PowerPCCPU *cpu, sPAPRMachineState *spapr,
20959760f2dSAlexey Kardashevskiy                            uint32_t token, uint32_t nargs,
21059760f2dSAlexey Kardashevskiy                            target_ulong args,
21159760f2dSAlexey Kardashevskiy                            uint32_t nret, target_ulong rets)
21259760f2dSAlexey Kardashevskiy {
21359760f2dSAlexey Kardashevskiy     CPUState *cs = CPU(cpu);
21459760f2dSAlexey Kardashevskiy     CPUPPCState *env = &cpu->env;
21559760f2dSAlexey Kardashevskiy 
21659760f2dSAlexey Kardashevskiy     cs->halted = 1;
21759760f2dSAlexey Kardashevskiy     cpu_exit(cs);
21859760f2dSAlexey Kardashevskiy     /*
21959760f2dSAlexey Kardashevskiy      * While stopping a CPU, the guest calls H_CPPR which
22059760f2dSAlexey Kardashevskiy      * effectively disables interrupts on XICS level.
22159760f2dSAlexey Kardashevskiy      * However decrementer interrupts in TCG can still
22259760f2dSAlexey Kardashevskiy      * wake the CPU up so here we disable interrupts in MSR
22359760f2dSAlexey Kardashevskiy      * as well.
22459760f2dSAlexey Kardashevskiy      * As rtas_start_cpu() resets the whole MSR anyway, there is
22559760f2dSAlexey Kardashevskiy      * no need to bother with specific bits, we just clear it.
22659760f2dSAlexey Kardashevskiy      */
22759760f2dSAlexey Kardashevskiy     env->msr = 0;
22859760f2dSAlexey Kardashevskiy }
22959760f2dSAlexey Kardashevskiy 
2303ada6b11SAlexey Kardashevskiy static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu,
23128e02042SDavid Gibson                                           sPAPRMachineState *spapr,
2323ada6b11SAlexey Kardashevskiy                                           uint32_t token, uint32_t nargs,
2333ada6b11SAlexey Kardashevskiy                                           target_ulong args,
2343ada6b11SAlexey Kardashevskiy                                           uint32_t nret, target_ulong rets)
2353ada6b11SAlexey Kardashevskiy {
2363ada6b11SAlexey Kardashevskiy     target_ulong parameter = rtas_ld(args, 0);
2373ada6b11SAlexey Kardashevskiy     target_ulong buffer = rtas_ld(args, 1);
2383ada6b11SAlexey Kardashevskiy     target_ulong length = rtas_ld(args, 2);
2393052d951SSam bobroff     target_ulong ret = RTAS_OUT_SUCCESS;
2403ada6b11SAlexey Kardashevskiy 
2413ada6b11SAlexey Kardashevskiy     switch (parameter) {
2423b50d897SSam bobroff     case RTAS_SYSPARM_SPLPAR_CHARACTERISTICS: {
2433b50d897SSam bobroff         char *param_val = g_strdup_printf("MaxEntCap=%d,MaxPlatProcs=%d",
2443b50d897SSam bobroff                                           max_cpus, smp_cpus);
2453b50d897SSam bobroff         rtas_st_buffer(buffer, length, (uint8_t *)param_val, strlen(param_val));
2463b50d897SSam bobroff         g_free(param_val);
2473b50d897SSam bobroff         break;
2483b50d897SSam bobroff     }
2493052d951SSam bobroff     case RTAS_SYSPARM_DIAGNOSTICS_RUN_MODE: {
2503052d951SSam bobroff         uint8_t param_val = DIAGNOSTICS_RUN_MODE_DISABLED;
2513052d951SSam bobroff 
2523052d951SSam bobroff         rtas_st_buffer(buffer, length, &param_val, sizeof(param_val));
2533ada6b11SAlexey Kardashevskiy         break;
2543ada6b11SAlexey Kardashevskiy     }
255b907d7b0SSam bobroff     case RTAS_SYSPARM_UUID:
256b907d7b0SSam bobroff         rtas_st_buffer(buffer, length, qemu_uuid, (qemu_uuid_set ? 16 : 0));
257b907d7b0SSam bobroff         break;
2583052d951SSam bobroff     default:
2593052d951SSam bobroff         ret = RTAS_OUT_NOT_SUPPORTED;
2603052d951SSam bobroff     }
2613ada6b11SAlexey Kardashevskiy 
2623ada6b11SAlexey Kardashevskiy     rtas_st(rets, 0, ret);
2633ada6b11SAlexey Kardashevskiy }
2643ada6b11SAlexey Kardashevskiy 
2653ada6b11SAlexey Kardashevskiy static void rtas_ibm_set_system_parameter(PowerPCCPU *cpu,
26628e02042SDavid Gibson                                           sPAPRMachineState *spapr,
2673ada6b11SAlexey Kardashevskiy                                           uint32_t token, uint32_t nargs,
2683ada6b11SAlexey Kardashevskiy                                           target_ulong args,
2693ada6b11SAlexey Kardashevskiy                                           uint32_t nret, target_ulong rets)
2703ada6b11SAlexey Kardashevskiy {
2713ada6b11SAlexey Kardashevskiy     target_ulong parameter = rtas_ld(args, 0);
2723ada6b11SAlexey Kardashevskiy     target_ulong ret = RTAS_OUT_NOT_SUPPORTED;
2733ada6b11SAlexey Kardashevskiy 
2743ada6b11SAlexey Kardashevskiy     switch (parameter) {
2753b50d897SSam bobroff     case RTAS_SYSPARM_SPLPAR_CHARACTERISTICS:
2763052d951SSam bobroff     case RTAS_SYSPARM_DIAGNOSTICS_RUN_MODE:
277b907d7b0SSam bobroff     case RTAS_SYSPARM_UUID:
2783ada6b11SAlexey Kardashevskiy         ret = RTAS_OUT_NOT_AUTHORIZED;
2793ada6b11SAlexey Kardashevskiy         break;
2803ada6b11SAlexey Kardashevskiy     }
2813ada6b11SAlexey Kardashevskiy 
2823ada6b11SAlexey Kardashevskiy     rtas_st(rets, 0, ret);
2833ada6b11SAlexey Kardashevskiy }
2843ada6b11SAlexey Kardashevskiy 
2852e14072fSNikunj A Dadhania static void rtas_ibm_os_term(PowerPCCPU *cpu,
28628e02042SDavid Gibson                             sPAPRMachineState *spapr,
2872e14072fSNikunj A Dadhania                             uint32_t token, uint32_t nargs,
2882e14072fSNikunj A Dadhania                             target_ulong args,
2892e14072fSNikunj A Dadhania                             uint32_t nret, target_ulong rets)
2902e14072fSNikunj A Dadhania {
2912e14072fSNikunj A Dadhania     target_ulong ret = 0;
2922e14072fSNikunj A Dadhania 
2932e14072fSNikunj A Dadhania     qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, &error_abort);
2942e14072fSNikunj A Dadhania 
2952e14072fSNikunj A Dadhania     rtas_st(rets, 0, ret);
2962e14072fSNikunj A Dadhania }
2972e14072fSNikunj A Dadhania 
29828e02042SDavid Gibson static void rtas_set_power_level(PowerPCCPU *cpu, sPAPRMachineState *spapr,
299094d2058SNathan Fontenot                                  uint32_t token, uint32_t nargs,
300094d2058SNathan Fontenot                                  target_ulong args, uint32_t nret,
301094d2058SNathan Fontenot                                  target_ulong rets)
302094d2058SNathan Fontenot {
303094d2058SNathan Fontenot     int32_t power_domain;
304094d2058SNathan Fontenot 
305094d2058SNathan Fontenot     if (nargs != 2 || nret != 2) {
306094d2058SNathan Fontenot         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
307094d2058SNathan Fontenot         return;
308094d2058SNathan Fontenot     }
309094d2058SNathan Fontenot 
310094d2058SNathan Fontenot     /* we currently only use a single, "live insert" powerdomain for
311094d2058SNathan Fontenot      * hotplugged/dlpar'd resources, so the power is always live/full (100)
312094d2058SNathan Fontenot      */
313094d2058SNathan Fontenot     power_domain = rtas_ld(args, 0);
314094d2058SNathan Fontenot     if (power_domain != -1) {
315094d2058SNathan Fontenot         rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
316094d2058SNathan Fontenot         return;
317094d2058SNathan Fontenot     }
318094d2058SNathan Fontenot 
319094d2058SNathan Fontenot     rtas_st(rets, 0, RTAS_OUT_SUCCESS);
320094d2058SNathan Fontenot     rtas_st(rets, 1, 100);
321094d2058SNathan Fontenot }
322094d2058SNathan Fontenot 
32328e02042SDavid Gibson static void rtas_get_power_level(PowerPCCPU *cpu, sPAPRMachineState *spapr,
324094d2058SNathan Fontenot                                   uint32_t token, uint32_t nargs,
325094d2058SNathan Fontenot                                   target_ulong args, uint32_t nret,
326094d2058SNathan Fontenot                                   target_ulong rets)
327094d2058SNathan Fontenot {
328094d2058SNathan Fontenot     int32_t power_domain;
329094d2058SNathan Fontenot 
330094d2058SNathan Fontenot     if (nargs != 1 || nret != 2) {
331094d2058SNathan Fontenot         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
332094d2058SNathan Fontenot         return;
333094d2058SNathan Fontenot     }
334094d2058SNathan Fontenot 
335094d2058SNathan Fontenot     /* we currently only use a single, "live insert" powerdomain for
336094d2058SNathan Fontenot      * hotplugged/dlpar'd resources, so the power is always live/full (100)
337094d2058SNathan Fontenot      */
338094d2058SNathan Fontenot     power_domain = rtas_ld(args, 0);
339094d2058SNathan Fontenot     if (power_domain != -1) {
340094d2058SNathan Fontenot         rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
341094d2058SNathan Fontenot         return;
342094d2058SNathan Fontenot     }
343094d2058SNathan Fontenot 
344094d2058SNathan Fontenot     rtas_st(rets, 0, RTAS_OUT_SUCCESS);
345094d2058SNathan Fontenot     rtas_st(rets, 1, 100);
346094d2058SNathan Fontenot }
347094d2058SNathan Fontenot 
3488c8639dfSMike Day static bool sensor_type_is_dr(uint32_t sensor_type)
3498c8639dfSMike Day {
3508c8639dfSMike Day     switch (sensor_type) {
3518c8639dfSMike Day     case RTAS_SENSOR_TYPE_ISOLATION_STATE:
3528c8639dfSMike Day     case RTAS_SENSOR_TYPE_DR:
3538c8639dfSMike Day     case RTAS_SENSOR_TYPE_ALLOCATION_STATE:
3548c8639dfSMike Day         return true;
3558c8639dfSMike Day     }
3568c8639dfSMike Day 
3578c8639dfSMike Day     return false;
3588c8639dfSMike Day }
3598c8639dfSMike Day 
36028e02042SDavid Gibson static void rtas_set_indicator(PowerPCCPU *cpu, sPAPRMachineState *spapr,
3618c8639dfSMike Day                                uint32_t token, uint32_t nargs,
3628c8639dfSMike Day                                target_ulong args, uint32_t nret,
3638c8639dfSMike Day                                target_ulong rets)
3648c8639dfSMike Day {
3658c8639dfSMike Day     uint32_t sensor_type;
3668c8639dfSMike Day     uint32_t sensor_index;
3678c8639dfSMike Day     uint32_t sensor_state;
3688c8639dfSMike Day     sPAPRDRConnector *drc;
3698c8639dfSMike Day     sPAPRDRConnectorClass *drck;
3708c8639dfSMike Day 
3718c8639dfSMike Day     if (nargs != 3 || nret != 1) {
3728c8639dfSMike Day         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
3738c8639dfSMike Day         return;
3748c8639dfSMike Day     }
3758c8639dfSMike Day 
3768c8639dfSMike Day     sensor_type = rtas_ld(args, 0);
3778c8639dfSMike Day     sensor_index = rtas_ld(args, 1);
3788c8639dfSMike Day     sensor_state = rtas_ld(args, 2);
3798c8639dfSMike Day 
3808c8639dfSMike Day     if (!sensor_type_is_dr(sensor_type)) {
3818c8639dfSMike Day         goto out_unimplemented;
3828c8639dfSMike Day     }
3838c8639dfSMike Day 
3848c8639dfSMike Day     /* if this is a DR sensor we can assume sensor_index == drc_index */
3858c8639dfSMike Day     drc = spapr_dr_connector_by_index(sensor_index);
3868c8639dfSMike Day     if (!drc) {
3878c8639dfSMike Day         DPRINTF("rtas_set_indicator: invalid sensor/DRC index: %xh\n",
3888c8639dfSMike Day                 sensor_index);
3898c8639dfSMike Day         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
3908c8639dfSMike Day         return;
3918c8639dfSMike Day     }
3928c8639dfSMike Day     drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
3938c8639dfSMike Day 
3948c8639dfSMike Day     switch (sensor_type) {
3958c8639dfSMike Day     case RTAS_SENSOR_TYPE_ISOLATION_STATE:
39646503c2bSMichael Roth         /* if the guest is configuring a device attached to this
39746503c2bSMichael Roth          * DRC, we should reset the configuration state at this
39846503c2bSMichael Roth          * point since it may no longer be reliable (guest released
39946503c2bSMichael Roth          * device and needs to start over, or unplug occurred so
40046503c2bSMichael Roth          * the FDT is no longer valid)
40146503c2bSMichael Roth          */
40246503c2bSMichael Roth         if (sensor_state == SPAPR_DR_ISOLATION_STATE_ISOLATED) {
40346503c2bSMichael Roth             sPAPRConfigureConnectorState *ccs = spapr_ccs_find(spapr,
40446503c2bSMichael Roth                                                                sensor_index);
40546503c2bSMichael Roth             if (ccs) {
40646503c2bSMichael Roth                 spapr_ccs_remove(spapr, ccs);
40746503c2bSMichael Roth             }
40846503c2bSMichael Roth         }
4098c8639dfSMike Day         drck->set_isolation_state(drc, sensor_state);
4108c8639dfSMike Day         break;
4118c8639dfSMike Day     case RTAS_SENSOR_TYPE_DR:
4128c8639dfSMike Day         drck->set_indicator_state(drc, sensor_state);
4138c8639dfSMike Day         break;
4148c8639dfSMike Day     case RTAS_SENSOR_TYPE_ALLOCATION_STATE:
4158c8639dfSMike Day         drck->set_allocation_state(drc, sensor_state);
4168c8639dfSMike Day         break;
4178c8639dfSMike Day     default:
4188c8639dfSMike Day         goto out_unimplemented;
4198c8639dfSMike Day     }
4208c8639dfSMike Day 
4218c8639dfSMike Day     rtas_st(rets, 0, RTAS_OUT_SUCCESS);
4228c8639dfSMike Day     return;
4238c8639dfSMike Day 
4248c8639dfSMike Day out_unimplemented:
4258c8639dfSMike Day     /* currently only DR-related sensors are implemented */
4268c8639dfSMike Day     DPRINTF("rtas_set_indicator: sensor/indicator not implemented: %d\n",
4278c8639dfSMike Day             sensor_type);
4288c8639dfSMike Day     rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
4298c8639dfSMike Day }
4308c8639dfSMike Day 
43128e02042SDavid Gibson static void rtas_get_sensor_state(PowerPCCPU *cpu, sPAPRMachineState *spapr,
432886445a6SMike Day                                   uint32_t token, uint32_t nargs,
433886445a6SMike Day                                   target_ulong args, uint32_t nret,
434886445a6SMike Day                                   target_ulong rets)
435886445a6SMike Day {
436886445a6SMike Day     uint32_t sensor_type;
437886445a6SMike Day     uint32_t sensor_index;
438886445a6SMike Day     sPAPRDRConnector *drc;
439886445a6SMike Day     sPAPRDRConnectorClass *drck;
440886445a6SMike Day     uint32_t entity_sense;
441886445a6SMike Day 
442886445a6SMike Day     if (nargs != 2 || nret != 2) {
443886445a6SMike Day         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
444886445a6SMike Day         return;
445886445a6SMike Day     }
446886445a6SMike Day 
447886445a6SMike Day     sensor_type = rtas_ld(args, 0);
448886445a6SMike Day     sensor_index = rtas_ld(args, 1);
449886445a6SMike Day 
450886445a6SMike Day     if (sensor_type != RTAS_SENSOR_TYPE_ENTITY_SENSE) {
451886445a6SMike Day         /* currently only DR-related sensors are implemented */
452886445a6SMike Day         DPRINTF("rtas_get_sensor_state: sensor/indicator not implemented: %d\n",
453886445a6SMike Day                 sensor_type);
454886445a6SMike Day         rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
455886445a6SMike Day         return;
456886445a6SMike Day     }
457886445a6SMike Day 
458886445a6SMike Day     drc = spapr_dr_connector_by_index(sensor_index);
459886445a6SMike Day     if (!drc) {
460886445a6SMike Day         DPRINTF("rtas_get_sensor_state: invalid sensor/DRC index: %xh\n",
461886445a6SMike Day                 sensor_index);
462886445a6SMike Day         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
463886445a6SMike Day         return;
464886445a6SMike Day     }
465886445a6SMike Day     drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
466886445a6SMike Day     entity_sense = drck->entity_sense(drc);
467886445a6SMike Day 
468886445a6SMike Day     rtas_st(rets, 0, RTAS_OUT_SUCCESS);
469886445a6SMike Day     rtas_st(rets, 1, entity_sense);
470886445a6SMike Day }
471886445a6SMike Day 
47246503c2bSMichael Roth /* configure-connector work area offsets, int32_t units for field
47346503c2bSMichael Roth  * indexes, bytes for field offset/len values.
47446503c2bSMichael Roth  *
47546503c2bSMichael Roth  * as documented by PAPR+ v2.7, 13.5.3.5
47646503c2bSMichael Roth  */
47746503c2bSMichael Roth #define CC_IDX_NODE_NAME_OFFSET 2
47846503c2bSMichael Roth #define CC_IDX_PROP_NAME_OFFSET 2
47946503c2bSMichael Roth #define CC_IDX_PROP_LEN 3
48046503c2bSMichael Roth #define CC_IDX_PROP_DATA_OFFSET 4
48146503c2bSMichael Roth #define CC_VAL_DATA_OFFSET ((CC_IDX_PROP_DATA_OFFSET + 1) * 4)
48246503c2bSMichael Roth #define CC_WA_LEN 4096
48346503c2bSMichael Roth 
48446503c2bSMichael Roth static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
48528e02042SDavid Gibson                                          sPAPRMachineState *spapr,
48646503c2bSMichael Roth                                          uint32_t token, uint32_t nargs,
48746503c2bSMichael Roth                                          target_ulong args, uint32_t nret,
48846503c2bSMichael Roth                                          target_ulong rets)
48946503c2bSMichael Roth {
49046503c2bSMichael Roth     uint64_t wa_addr;
49146503c2bSMichael Roth     uint64_t wa_offset;
49246503c2bSMichael Roth     uint32_t drc_index;
49346503c2bSMichael Roth     sPAPRDRConnector *drc;
49446503c2bSMichael Roth     sPAPRDRConnectorClass *drck;
49546503c2bSMichael Roth     sPAPRConfigureConnectorState *ccs;
49646503c2bSMichael Roth     sPAPRDRCCResponse resp = SPAPR_DR_CC_RESPONSE_CONTINUE;
49746503c2bSMichael Roth     int rc;
49846503c2bSMichael Roth     const void *fdt;
49946503c2bSMichael Roth 
50046503c2bSMichael Roth     if (nargs != 2 || nret != 1) {
50146503c2bSMichael Roth         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
50246503c2bSMichael Roth         return;
50346503c2bSMichael Roth     }
50446503c2bSMichael Roth 
50546503c2bSMichael Roth     wa_addr = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 0);
50646503c2bSMichael Roth 
50746503c2bSMichael Roth     drc_index = rtas_ld(wa_addr, 0);
50846503c2bSMichael Roth     drc = spapr_dr_connector_by_index(drc_index);
50946503c2bSMichael Roth     if (!drc) {
51046503c2bSMichael Roth         DPRINTF("rtas_ibm_configure_connector: invalid DRC index: %xh\n",
51146503c2bSMichael Roth                 drc_index);
51246503c2bSMichael Roth         rc = RTAS_OUT_PARAM_ERROR;
51346503c2bSMichael Roth         goto out;
51446503c2bSMichael Roth     }
51546503c2bSMichael Roth 
51646503c2bSMichael Roth     drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
51746503c2bSMichael Roth     fdt = drck->get_fdt(drc, NULL);
51846503c2bSMichael Roth 
51946503c2bSMichael Roth     ccs = spapr_ccs_find(spapr, drc_index);
52046503c2bSMichael Roth     if (!ccs) {
52146503c2bSMichael Roth         ccs = g_new0(sPAPRConfigureConnectorState, 1);
52246503c2bSMichael Roth         (void)drck->get_fdt(drc, &ccs->fdt_offset);
52346503c2bSMichael Roth         ccs->drc_index = drc_index;
52446503c2bSMichael Roth         spapr_ccs_add(spapr, ccs);
52546503c2bSMichael Roth     }
52646503c2bSMichael Roth 
52746503c2bSMichael Roth     do {
52846503c2bSMichael Roth         uint32_t tag;
52946503c2bSMichael Roth         const char *name;
53046503c2bSMichael Roth         const struct fdt_property *prop;
53146503c2bSMichael Roth         int fdt_offset_next, prop_len;
53246503c2bSMichael Roth 
53346503c2bSMichael Roth         tag = fdt_next_tag(fdt, ccs->fdt_offset, &fdt_offset_next);
53446503c2bSMichael Roth 
53546503c2bSMichael Roth         switch (tag) {
53646503c2bSMichael Roth         case FDT_BEGIN_NODE:
53746503c2bSMichael Roth             ccs->fdt_depth++;
53846503c2bSMichael Roth             name = fdt_get_name(fdt, ccs->fdt_offset, NULL);
53946503c2bSMichael Roth 
54046503c2bSMichael Roth             /* provide the name of the next OF node */
54146503c2bSMichael Roth             wa_offset = CC_VAL_DATA_OFFSET;
54246503c2bSMichael Roth             rtas_st(wa_addr, CC_IDX_NODE_NAME_OFFSET, wa_offset);
54346503c2bSMichael Roth             rtas_st_buffer_direct(wa_addr + wa_offset, CC_WA_LEN - wa_offset,
54446503c2bSMichael Roth                                   (uint8_t *)name, strlen(name) + 1);
54546503c2bSMichael Roth             resp = SPAPR_DR_CC_RESPONSE_NEXT_CHILD;
54646503c2bSMichael Roth             break;
54746503c2bSMichael Roth         case FDT_END_NODE:
54846503c2bSMichael Roth             ccs->fdt_depth--;
54946503c2bSMichael Roth             if (ccs->fdt_depth == 0) {
55046503c2bSMichael Roth                 /* done sending the device tree, don't need to track
55146503c2bSMichael Roth                  * the state anymore
55246503c2bSMichael Roth                  */
55346503c2bSMichael Roth                 drck->set_configured(drc);
55446503c2bSMichael Roth                 spapr_ccs_remove(spapr, ccs);
55546503c2bSMichael Roth                 ccs = NULL;
55646503c2bSMichael Roth                 resp = SPAPR_DR_CC_RESPONSE_SUCCESS;
55746503c2bSMichael Roth             } else {
55846503c2bSMichael Roth                 resp = SPAPR_DR_CC_RESPONSE_PREV_PARENT;
55946503c2bSMichael Roth             }
56046503c2bSMichael Roth             break;
56146503c2bSMichael Roth         case FDT_PROP:
56246503c2bSMichael Roth             prop = fdt_get_property_by_offset(fdt, ccs->fdt_offset,
56346503c2bSMichael Roth                                               &prop_len);
56446503c2bSMichael Roth             name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
56546503c2bSMichael Roth 
56646503c2bSMichael Roth             /* provide the name of the next OF property */
56746503c2bSMichael Roth             wa_offset = CC_VAL_DATA_OFFSET;
56846503c2bSMichael Roth             rtas_st(wa_addr, CC_IDX_PROP_NAME_OFFSET, wa_offset);
56946503c2bSMichael Roth             rtas_st_buffer_direct(wa_addr + wa_offset, CC_WA_LEN - wa_offset,
57046503c2bSMichael Roth                                   (uint8_t *)name, strlen(name) + 1);
57146503c2bSMichael Roth 
57246503c2bSMichael Roth             /* provide the length and value of the OF property. data gets
57346503c2bSMichael Roth              * placed immediately after NULL terminator of the OF property's
57446503c2bSMichael Roth              * name string
57546503c2bSMichael Roth              */
57646503c2bSMichael Roth             wa_offset += strlen(name) + 1,
57746503c2bSMichael Roth             rtas_st(wa_addr, CC_IDX_PROP_LEN, prop_len);
57846503c2bSMichael Roth             rtas_st(wa_addr, CC_IDX_PROP_DATA_OFFSET, wa_offset);
57946503c2bSMichael Roth             rtas_st_buffer_direct(wa_addr + wa_offset, CC_WA_LEN - wa_offset,
58046503c2bSMichael Roth                                   (uint8_t *)((struct fdt_property *)prop)->data,
58146503c2bSMichael Roth                                   prop_len);
58246503c2bSMichael Roth             resp = SPAPR_DR_CC_RESPONSE_NEXT_PROPERTY;
58346503c2bSMichael Roth             break;
58446503c2bSMichael Roth         case FDT_END:
58546503c2bSMichael Roth             resp = SPAPR_DR_CC_RESPONSE_ERROR;
58646503c2bSMichael Roth         default:
58746503c2bSMichael Roth             /* keep seeking for an actionable tag */
58846503c2bSMichael Roth             break;
58946503c2bSMichael Roth         }
59046503c2bSMichael Roth         if (ccs) {
59146503c2bSMichael Roth             ccs->fdt_offset = fdt_offset_next;
59246503c2bSMichael Roth         }
59346503c2bSMichael Roth     } while (resp == SPAPR_DR_CC_RESPONSE_CONTINUE);
59446503c2bSMichael Roth 
59546503c2bSMichael Roth     rc = resp;
59646503c2bSMichael Roth out:
59746503c2bSMichael Roth     rtas_st(rets, 0, rc);
59846503c2bSMichael Roth }
59946503c2bSMichael Roth 
60039ac8455SDavid Gibson static struct rtas_call {
60139ac8455SDavid Gibson     const char *name;
60239ac8455SDavid Gibson     spapr_rtas_fn fn;
6033a3b8502SAlexey Kardashevskiy } rtas_table[RTAS_TOKEN_MAX - RTAS_TOKEN_BASE];
60439ac8455SDavid Gibson 
60528e02042SDavid Gibson target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPRMachineState *spapr,
60639ac8455SDavid Gibson                              uint32_t token, uint32_t nargs, target_ulong args,
60739ac8455SDavid Gibson                              uint32_t nret, target_ulong rets)
60839ac8455SDavid Gibson {
6093a3b8502SAlexey Kardashevskiy     if ((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX)) {
6103a3b8502SAlexey Kardashevskiy         struct rtas_call *call = rtas_table + (token - RTAS_TOKEN_BASE);
61139ac8455SDavid Gibson 
61239ac8455SDavid Gibson         if (call->fn) {
613210b580bSAnthony Liguori             call->fn(cpu, spapr, token, nargs, args, nret, rets);
61439ac8455SDavid Gibson             return H_SUCCESS;
61539ac8455SDavid Gibson         }
61639ac8455SDavid Gibson     }
61739ac8455SDavid Gibson 
618821303f5SDavid Gibson     /* HACK: Some Linux early debug code uses RTAS display-character,
619821303f5SDavid Gibson      * but assumes the token value is 0xa (which it is on some real
620821303f5SDavid Gibson      * machines) without looking it up in the device tree.  This
621821303f5SDavid Gibson      * special case makes this work */
622821303f5SDavid Gibson     if (token == 0xa) {
623210b580bSAnthony Liguori         rtas_display_character(cpu, spapr, 0xa, nargs, args, nret, rets);
624821303f5SDavid Gibson         return H_SUCCESS;
625821303f5SDavid Gibson     }
626821303f5SDavid Gibson 
62739ac8455SDavid Gibson     hcall_dprintf("Unknown RTAS token 0x%x\n", token);
628a64d325dSAlexey Kardashevskiy     rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
62939ac8455SDavid Gibson     return H_PARAMETER;
63039ac8455SDavid Gibson }
63139ac8455SDavid Gibson 
6323a3b8502SAlexey Kardashevskiy void spapr_rtas_register(int token, const char *name, spapr_rtas_fn fn)
63339ac8455SDavid Gibson {
6343a3b8502SAlexey Kardashevskiy     if (!((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX))) {
6353a3b8502SAlexey Kardashevskiy         fprintf(stderr, "RTAS invalid token 0x%x\n", token);
636c89d5299SDavid Gibson         exit(1);
637c89d5299SDavid Gibson     }
6383a3b8502SAlexey Kardashevskiy 
6393a3b8502SAlexey Kardashevskiy     token -= RTAS_TOKEN_BASE;
6403a3b8502SAlexey Kardashevskiy     if (rtas_table[token].name) {
6413a3b8502SAlexey Kardashevskiy         fprintf(stderr, "RTAS call \"%s\" is registered already as 0x%x\n",
6423a3b8502SAlexey Kardashevskiy                 rtas_table[token].name, token);
6433a3b8502SAlexey Kardashevskiy         exit(1);
644c89d5299SDavid Gibson     }
645c89d5299SDavid Gibson 
6463a3b8502SAlexey Kardashevskiy     rtas_table[token].name = name;
6473a3b8502SAlexey Kardashevskiy     rtas_table[token].fn = fn;
64839ac8455SDavid Gibson }
64939ac8455SDavid Gibson 
650a8170e5eSAvi Kivity int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
651a8170e5eSAvi Kivity                                  hwaddr rtas_size)
65239ac8455SDavid Gibson {
65339ac8455SDavid Gibson     int ret;
65439ac8455SDavid Gibson     int i;
655*db4ef288SBharata B Rao     uint32_t lrdr_capacity[5];
656*db4ef288SBharata B Rao     MachineState *machine = MACHINE(qdev_get_machine());
65739ac8455SDavid Gibson 
65839ac8455SDavid Gibson     ret = fdt_add_mem_rsv(fdt, rtas_addr, rtas_size);
65939ac8455SDavid Gibson     if (ret < 0) {
66039ac8455SDavid Gibson         fprintf(stderr, "Couldn't add RTAS reserve entry: %s\n",
66139ac8455SDavid Gibson                 fdt_strerror(ret));
66239ac8455SDavid Gibson         return ret;
66339ac8455SDavid Gibson     }
66439ac8455SDavid Gibson 
6655a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-base",
66639ac8455SDavid Gibson                                 rtas_addr);
66739ac8455SDavid Gibson     if (ret < 0) {
66839ac8455SDavid Gibson         fprintf(stderr, "Couldn't add linux,rtas-base property: %s\n",
66939ac8455SDavid Gibson                 fdt_strerror(ret));
67039ac8455SDavid Gibson         return ret;
67139ac8455SDavid Gibson     }
67239ac8455SDavid Gibson 
6735a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-entry",
67439ac8455SDavid Gibson                                 rtas_addr);
67539ac8455SDavid Gibson     if (ret < 0) {
67639ac8455SDavid Gibson         fprintf(stderr, "Couldn't add linux,rtas-entry property: %s\n",
67739ac8455SDavid Gibson                 fdt_strerror(ret));
67839ac8455SDavid Gibson         return ret;
67939ac8455SDavid Gibson     }
68039ac8455SDavid Gibson 
6815a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-size",
68239ac8455SDavid Gibson                                 rtas_size);
68339ac8455SDavid Gibson     if (ret < 0) {
68439ac8455SDavid Gibson         fprintf(stderr, "Couldn't add rtas-size property: %s\n",
68539ac8455SDavid Gibson                 fdt_strerror(ret));
68639ac8455SDavid Gibson         return ret;
68739ac8455SDavid Gibson     }
68839ac8455SDavid Gibson 
6893a3b8502SAlexey Kardashevskiy     for (i = 0; i < RTAS_TOKEN_MAX - RTAS_TOKEN_BASE; i++) {
69039ac8455SDavid Gibson         struct rtas_call *call = &rtas_table[i];
69139ac8455SDavid Gibson 
692d36b66f7SBen Herrenschmidt         if (!call->name) {
69339ac8455SDavid Gibson             continue;
69439ac8455SDavid Gibson         }
69539ac8455SDavid Gibson 
6965a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/rtas", call->name,
6973a3b8502SAlexey Kardashevskiy                                     i + RTAS_TOKEN_BASE);
69839ac8455SDavid Gibson         if (ret < 0) {
69939ac8455SDavid Gibson             fprintf(stderr, "Couldn't add rtas token for %s: %s\n",
70039ac8455SDavid Gibson                     call->name, fdt_strerror(ret));
70139ac8455SDavid Gibson             return ret;
70239ac8455SDavid Gibson         }
70339ac8455SDavid Gibson 
70439ac8455SDavid Gibson     }
705*db4ef288SBharata B Rao 
706*db4ef288SBharata B Rao     lrdr_capacity[0] = cpu_to_be32(((uint64_t)machine->maxram_size) >> 32);
707*db4ef288SBharata B Rao     lrdr_capacity[1] = cpu_to_be32(machine->maxram_size & 0xffffffff);
708*db4ef288SBharata B Rao     lrdr_capacity[2] = 0;
709*db4ef288SBharata B Rao     lrdr_capacity[3] = cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE);
710*db4ef288SBharata B Rao     lrdr_capacity[4] = cpu_to_be32(max_cpus/smp_threads);
711*db4ef288SBharata B Rao     ret = qemu_fdt_setprop(fdt, "/rtas", "ibm,lrdr-capacity", lrdr_capacity,
712*db4ef288SBharata B Rao                      sizeof(lrdr_capacity));
713*db4ef288SBharata B Rao     if (ret < 0) {
714*db4ef288SBharata B Rao         fprintf(stderr, "Couldn't add ibm,lrdr-capacity rtas property\n");
715*db4ef288SBharata B Rao         return ret;
716*db4ef288SBharata B Rao     }
717*db4ef288SBharata B Rao 
71839ac8455SDavid Gibson     return 0;
71939ac8455SDavid Gibson }
720821303f5SDavid Gibson 
72183f7d43aSAndreas Färber static void core_rtas_register_types(void)
722821303f5SDavid Gibson {
7233a3b8502SAlexey Kardashevskiy     spapr_rtas_register(RTAS_DISPLAY_CHARACTER, "display-character",
7243a3b8502SAlexey Kardashevskiy                         rtas_display_character);
7253a3b8502SAlexey Kardashevskiy     spapr_rtas_register(RTAS_POWER_OFF, "power-off", rtas_power_off);
7263a3b8502SAlexey Kardashevskiy     spapr_rtas_register(RTAS_SYSTEM_REBOOT, "system-reboot",
7273a3b8502SAlexey Kardashevskiy                         rtas_system_reboot);
7283a3b8502SAlexey Kardashevskiy     spapr_rtas_register(RTAS_QUERY_CPU_STOPPED_STATE, "query-cpu-stopped-state",
729a9f8ad8fSDavid Gibson                         rtas_query_cpu_stopped_state);
7303a3b8502SAlexey Kardashevskiy     spapr_rtas_register(RTAS_START_CPU, "start-cpu", rtas_start_cpu);
7313a3b8502SAlexey Kardashevskiy     spapr_rtas_register(RTAS_STOP_SELF, "stop-self", rtas_stop_self);
7323a3b8502SAlexey Kardashevskiy     spapr_rtas_register(RTAS_IBM_GET_SYSTEM_PARAMETER,
7333a3b8502SAlexey Kardashevskiy                         "ibm,get-system-parameter",
7343ada6b11SAlexey Kardashevskiy                         rtas_ibm_get_system_parameter);
7353a3b8502SAlexey Kardashevskiy     spapr_rtas_register(RTAS_IBM_SET_SYSTEM_PARAMETER,
7363a3b8502SAlexey Kardashevskiy                         "ibm,set-system-parameter",
7373ada6b11SAlexey Kardashevskiy                         rtas_ibm_set_system_parameter);
7382e14072fSNikunj A Dadhania     spapr_rtas_register(RTAS_IBM_OS_TERM, "ibm,os-term",
7392e14072fSNikunj A Dadhania                         rtas_ibm_os_term);
740094d2058SNathan Fontenot     spapr_rtas_register(RTAS_SET_POWER_LEVEL, "set-power-level",
741094d2058SNathan Fontenot                         rtas_set_power_level);
742094d2058SNathan Fontenot     spapr_rtas_register(RTAS_GET_POWER_LEVEL, "get-power-level",
743094d2058SNathan Fontenot                         rtas_get_power_level);
7448c8639dfSMike Day     spapr_rtas_register(RTAS_SET_INDICATOR, "set-indicator",
7458c8639dfSMike Day                         rtas_set_indicator);
746886445a6SMike Day     spapr_rtas_register(RTAS_GET_SENSOR_STATE, "get-sensor-state",
747886445a6SMike Day                         rtas_get_sensor_state);
74846503c2bSMichael Roth     spapr_rtas_register(RTAS_IBM_CONFIGURE_CONNECTOR, "ibm,configure-connector",
74946503c2bSMichael Roth                         rtas_ibm_configure_connector);
750821303f5SDavid Gibson }
75183f7d43aSAndreas Färber 
75283f7d43aSAndreas Färber type_init(core_rtas_register_types)
753