^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Procedures for interfacing to the RTAS on CHRP machines.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Peter Bergner, IBM March 2001.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2001 IBM.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <stdarg.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/capability.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/completion.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/cpumask.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/memblock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/reboot.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/syscalls.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <asm/prom.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <asm/rtas.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <asm/hvcall.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <asm/machdep.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <asm/firmware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <asm/page.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <asm/param.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <asm/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <asm/udbg.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <asm/syscalls.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <asm/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <linux/atomic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <asm/time.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #include <asm/mmu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #include <asm/topology.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #include <asm/paca.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /* This is here deliberately so it's only used in this file */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) void enter_rtas(unsigned long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct rtas_t rtas = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) .lock = __ARCH_SPIN_LOCK_UNLOCKED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) EXPORT_SYMBOL(rtas);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) DEFINE_SPINLOCK(rtas_data_buf_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) EXPORT_SYMBOL(rtas_data_buf_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) char rtas_data_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) EXPORT_SYMBOL(rtas_data_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) unsigned long rtas_rmo_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * If non-NULL, this gets called when the kernel terminates.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * This is done like this so rtas_flash can be a module.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) void (*rtas_flash_term_hook)(int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) EXPORT_SYMBOL(rtas_flash_term_hook);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /* RTAS use home made raw locking instead of spin_lock_irqsave
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * because those can be called from within really nasty contexts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * such as having the timebase stopped which would lockup with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * normal locks and spinlock debugging enabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static unsigned long lock_rtas(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) preempt_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) arch_spin_lock(&rtas.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static void unlock_rtas(unsigned long flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) arch_spin_unlock(&rtas.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) preempt_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * call_rtas_display_status and call_rtas_display_status_delay
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * are designed only for very early low-level debugging, which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * is why the token is hard-coded to 10.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static void call_rtas_display_status(unsigned char c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) unsigned long s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (!rtas.base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) s = lock_rtas();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) rtas_call_unlocked(&rtas.args, 10, 1, 1, NULL, c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) unlock_rtas(s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static void call_rtas_display_status_delay(char c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) static int pending_newline = 0; /* did last write end with unprinted newline? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static int width = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (c == '\n') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) while (width-- > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) call_rtas_display_status(' ');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) width = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) mdelay(500);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) pending_newline = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (pending_newline) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) call_rtas_display_status('\r');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) call_rtas_display_status('\n');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) pending_newline = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (width--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) call_rtas_display_status(c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) udelay(10000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) void __init udbg_init_rtas_panel(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) udbg_putc = call_rtas_display_status_delay;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) #ifdef CONFIG_UDBG_RTAS_CONSOLE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) /* If you think you're dying before early_init_dt_scan_rtas() does its
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * work, you can hard code the token values for your firmware here and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * hardcode rtas.base/entry etc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) static unsigned int rtas_putchar_token = RTAS_UNKNOWN_SERVICE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static unsigned int rtas_getchar_token = RTAS_UNKNOWN_SERVICE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) static void udbg_rtascon_putc(char c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) int tries;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (!rtas.base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) /* Add CRs before LFs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (c == '\n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) udbg_rtascon_putc('\r');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) /* if there is more than one character to be displayed, wait a bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) for (tries = 0; tries < 16; tries++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (rtas_call(rtas_putchar_token, 1, 1, NULL, c) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) udelay(1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) static int udbg_rtascon_getc_poll(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) int c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (!rtas.base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (rtas_call(rtas_getchar_token, 0, 2, &c))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) static int udbg_rtascon_getc(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) int c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) while ((c = udbg_rtascon_getc_poll()) == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) void __init udbg_init_rtas_console(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) udbg_putc = udbg_rtascon_putc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) udbg_getc = udbg_rtascon_getc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) udbg_getc_poll = udbg_rtascon_getc_poll;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) #endif /* CONFIG_UDBG_RTAS_CONSOLE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) void rtas_progress(char *s, unsigned short hex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) struct device_node *root;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) int width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) const __be32 *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) char *os;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) static int display_character, set_indicator;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) static int display_width, display_lines, form_feed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) static const int *row_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) static DEFINE_SPINLOCK(progress_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) static int current_line;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) static int pending_newline = 0; /* did last write end with unprinted newline? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (!rtas.base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (display_width == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) display_width = 0x10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) if ((root = of_find_node_by_path("/rtas"))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) if ((p = of_get_property(root,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) "ibm,display-line-length", NULL)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) display_width = be32_to_cpu(*p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) if ((p = of_get_property(root,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) "ibm,form-feed", NULL)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) form_feed = be32_to_cpu(*p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) if ((p = of_get_property(root,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) "ibm,display-number-of-lines", NULL)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) display_lines = be32_to_cpu(*p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) row_width = of_get_property(root,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) "ibm,display-truncation-length", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) of_node_put(root);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) display_character = rtas_token("display-character");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) set_indicator = rtas_token("set-indicator");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (display_character == RTAS_UNKNOWN_SERVICE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) /* use hex display if available */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if (set_indicator != RTAS_UNKNOWN_SERVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) rtas_call(set_indicator, 3, 1, NULL, 6, 0, hex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) spin_lock(&progress_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) * Last write ended with newline, but we didn't print it since
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) * it would just clear the bottom line of output. Print it now
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) * instead.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) * If no newline is pending and form feed is supported, clear the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) * display with a form feed; otherwise, print a CR to start output
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) * at the beginning of the line.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) if (pending_newline) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) rtas_call(display_character, 1, 1, NULL, '\r');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) rtas_call(display_character, 1, 1, NULL, '\n');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) pending_newline = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) current_line = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (form_feed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) rtas_call(display_character, 1, 1, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) (char)form_feed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) rtas_call(display_character, 1, 1, NULL, '\r');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) if (row_width)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) width = row_width[current_line];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) width = display_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) os = s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) while (*os) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) if (*os == '\n' || *os == '\r') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) /* If newline is the last character, save it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) * until next call to avoid bumping up the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) * display output.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if (*os == '\n' && !os[1]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) pending_newline = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) current_line++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (current_line > display_lines-1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) current_line = display_lines-1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) spin_unlock(&progress_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) /* RTAS wants CR-LF, not just LF */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (*os == '\n') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) rtas_call(display_character, 1, 1, NULL, '\r');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) rtas_call(display_character, 1, 1, NULL, '\n');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) /* CR might be used to re-draw a line, so we'll
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) * leave it alone and not add LF.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) rtas_call(display_character, 1, 1, NULL, *os);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) if (row_width)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) width = row_width[current_line];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) width = display_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) width--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) rtas_call(display_character, 1, 1, NULL, *os);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) os++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) /* if we overwrite the screen length */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) if (width <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) while ((*os != 0) && (*os != '\n') && (*os != '\r'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) os++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) spin_unlock(&progress_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) EXPORT_SYMBOL(rtas_progress); /* needed by rtas_flash module */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) int rtas_token(const char *service)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) const __be32 *tokp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) if (rtas.dev == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) return RTAS_UNKNOWN_SERVICE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) tokp = of_get_property(rtas.dev, service, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) return tokp ? be32_to_cpu(*tokp) : RTAS_UNKNOWN_SERVICE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) EXPORT_SYMBOL(rtas_token);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) int rtas_service_present(const char *service)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) return rtas_token(service) != RTAS_UNKNOWN_SERVICE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) EXPORT_SYMBOL(rtas_service_present);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) #ifdef CONFIG_RTAS_ERROR_LOGGING
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) * Return the firmware-specified size of the error log buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) * for all rtas calls that require an error buffer argument.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) * This includes 'check-exception' and 'rtas-last-error'.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) int rtas_get_error_log_max(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) static int rtas_error_log_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) if (rtas_error_log_max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) return rtas_error_log_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) rtas_error_log_max = rtas_token ("rtas-error-log-max");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) if ((rtas_error_log_max == RTAS_UNKNOWN_SERVICE) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) (rtas_error_log_max > RTAS_ERROR_LOG_MAX)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) printk (KERN_WARNING "RTAS: bad log buffer size %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) rtas_error_log_max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) rtas_error_log_max = RTAS_ERROR_LOG_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) return rtas_error_log_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) EXPORT_SYMBOL(rtas_get_error_log_max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) static char rtas_err_buf[RTAS_ERROR_LOG_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) static int rtas_last_error_token;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) /** Return a copy of the detailed error text associated with the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) * most recent failed call to rtas. Because the error text
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) * might go stale if there are any other intervening rtas calls,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) * this routine must be called atomically with whatever produced
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) * the error (i.e. with rtas.lock still held from the previous call).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) static char *__fetch_rtas_last_error(char *altbuf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) struct rtas_args err_args, save_args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) u32 bufsz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) char *buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) if (rtas_last_error_token == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) bufsz = rtas_get_error_log_max();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) err_args.token = cpu_to_be32(rtas_last_error_token);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) err_args.nargs = cpu_to_be32(2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) err_args.nret = cpu_to_be32(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) err_args.args[0] = cpu_to_be32(__pa(rtas_err_buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) err_args.args[1] = cpu_to_be32(bufsz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) err_args.args[2] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) save_args = rtas.args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) rtas.args = err_args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) enter_rtas(__pa(&rtas.args));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) err_args = rtas.args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) rtas.args = save_args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) /* Log the error in the unlikely case that there was one. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) if (unlikely(err_args.args[2] == 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) if (altbuf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) buf = altbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) buf = rtas_err_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) if (slab_is_available())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) buf = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) if (buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) memcpy(buf, rtas_err_buf, RTAS_ERROR_LOG_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) return buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) #define get_errorlog_buffer() kmalloc(RTAS_ERROR_LOG_MAX, GFP_KERNEL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) #else /* CONFIG_RTAS_ERROR_LOGGING */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) #define __fetch_rtas_last_error(x) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) #define get_errorlog_buffer() NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) va_rtas_call_unlocked(struct rtas_args *args, int token, int nargs, int nret,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) va_list list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) args->token = cpu_to_be32(token);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) args->nargs = cpu_to_be32(nargs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) args->nret = cpu_to_be32(nret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) args->rets = &(args->args[nargs]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) for (i = 0; i < nargs; ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) args->args[i] = cpu_to_be32(va_arg(list, __u32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) for (i = 0; i < nret; ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) args->rets[i] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) enter_rtas(__pa(args));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) void rtas_call_unlocked(struct rtas_args *args, int token, int nargs, int nret, ...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) va_list list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) va_start(list, nret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) va_rtas_call_unlocked(args, token, nargs, nret, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) va_end(list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) int rtas_call(int token, int nargs, int nret, int *outputs, ...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) va_list list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) unsigned long s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) struct rtas_args *rtas_args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) char *buff_copy = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) if (!rtas.entry || token == RTAS_UNKNOWN_SERVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) s = lock_rtas();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) /* We use the global rtas args buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) rtas_args = &rtas.args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) va_start(list, outputs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) va_rtas_call_unlocked(rtas_args, token, nargs, nret, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) va_end(list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) /* A -1 return code indicates that the last command couldn't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) be completed due to a hardware error. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) if (be32_to_cpu(rtas_args->rets[0]) == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) buff_copy = __fetch_rtas_last_error(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) if (nret > 1 && outputs != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) for (i = 0; i < nret-1; ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) outputs[i] = be32_to_cpu(rtas_args->rets[i+1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) ret = (nret > 0)? be32_to_cpu(rtas_args->rets[0]): 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) unlock_rtas(s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) if (buff_copy) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) if (slab_is_available())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) kfree(buff_copy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) EXPORT_SYMBOL(rtas_call);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) /* For RTAS_BUSY (-2), delay for 1 millisecond. For an extended busy status
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) * code of 990n, perform the hinted delay of 10^n (last digit) milliseconds.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) unsigned int rtas_busy_delay_time(int status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) int order;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) unsigned int ms = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) if (status == RTAS_BUSY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) ms = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) } else if (status >= RTAS_EXTENDED_DELAY_MIN &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) status <= RTAS_EXTENDED_DELAY_MAX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) order = status - RTAS_EXTENDED_DELAY_MIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) for (ms = 1; order > 0; order--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) ms *= 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) return ms;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) EXPORT_SYMBOL(rtas_busy_delay_time);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) /* For an RTAS busy status code, perform the hinted delay. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) unsigned int rtas_busy_delay(int status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) unsigned int ms;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) might_sleep();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) ms = rtas_busy_delay_time(status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) if (ms && need_resched())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) msleep(ms);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) return ms;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) EXPORT_SYMBOL(rtas_busy_delay);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) static int rtas_error_rc(int rtas_rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) switch (rtas_rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) case -1: /* Hardware Error */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) rc = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) case -3: /* Bad indicator/domain/etc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) case -9000: /* Isolation error */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) rc = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) case -9001: /* Outstanding TCE/PTE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) rc = -EEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) case -9002: /* No usable slot */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) rc = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) printk(KERN_ERR "%s: unexpected RTAS error %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) __func__, rtas_rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) rc = -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) int rtas_get_power_level(int powerdomain, int *level)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) int token = rtas_token("get-power-level");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) if (token == RTAS_UNKNOWN_SERVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) while ((rc = rtas_call(token, 1, 2, level, powerdomain)) == RTAS_BUSY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) udelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) return rtas_error_rc(rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) EXPORT_SYMBOL(rtas_get_power_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) int rtas_set_power_level(int powerdomain, int level, int *setlevel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) int token = rtas_token("set-power-level");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) if (token == RTAS_UNKNOWN_SERVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) rc = rtas_call(token, 2, 2, setlevel, powerdomain, level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) } while (rtas_busy_delay(rc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) return rtas_error_rc(rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) EXPORT_SYMBOL(rtas_set_power_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) int rtas_get_sensor(int sensor, int index, int *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) int token = rtas_token("get-sensor-state");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) if (token == RTAS_UNKNOWN_SERVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) rc = rtas_call(token, 2, 2, state, sensor, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) } while (rtas_busy_delay(rc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) return rtas_error_rc(rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) EXPORT_SYMBOL(rtas_get_sensor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) int rtas_get_sensor_fast(int sensor, int index, int *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) int token = rtas_token("get-sensor-state");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) if (token == RTAS_UNKNOWN_SERVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) rc = rtas_call(token, 2, 2, state, sensor, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) WARN_ON(rc == RTAS_BUSY || (rc >= RTAS_EXTENDED_DELAY_MIN &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) rc <= RTAS_EXTENDED_DELAY_MAX));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) return rtas_error_rc(rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) bool rtas_indicator_present(int token, int *maxindex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) int proplen, count, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) const struct indicator_elem {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) __be32 token;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) __be32 maxindex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) } *indicators;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) indicators = of_get_property(rtas.dev, "rtas-indicators", &proplen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) if (!indicators)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) count = proplen / sizeof(struct indicator_elem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) for (i = 0; i < count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) if (__be32_to_cpu(indicators[i].token) != token)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) if (maxindex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) *maxindex = __be32_to_cpu(indicators[i].maxindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) EXPORT_SYMBOL(rtas_indicator_present);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) int rtas_set_indicator(int indicator, int index, int new_value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) int token = rtas_token("set-indicator");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) if (token == RTAS_UNKNOWN_SERVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) } while (rtas_busy_delay(rc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) return rtas_error_rc(rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) EXPORT_SYMBOL(rtas_set_indicator);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) * Ignoring RTAS extended delay
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) int rtas_set_indicator_fast(int indicator, int index, int new_value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) int token = rtas_token("set-indicator");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) if (token == RTAS_UNKNOWN_SERVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) WARN_ON(rc == RTAS_BUSY || (rc >= RTAS_EXTENDED_DELAY_MIN &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) rc <= RTAS_EXTENDED_DELAY_MAX));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) return rtas_error_rc(rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) void __noreturn rtas_restart(char *cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) if (rtas_flash_term_hook)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) rtas_flash_term_hook(SYS_RESTART);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) printk("RTAS system-reboot returned %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) rtas_call(rtas_token("system-reboot"), 0, 1, NULL));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) for (;;);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) void rtas_power_off(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) if (rtas_flash_term_hook)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) rtas_flash_term_hook(SYS_POWER_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) /* allow power on only with power button press */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) printk("RTAS power-off returned %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) for (;;);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) void __noreturn rtas_halt(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) if (rtas_flash_term_hook)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) rtas_flash_term_hook(SYS_HALT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) /* allow power on only with power button press */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) printk("RTAS power-off returned %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) for (;;);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) /* Must be in the RMO region, so we place it here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) static char rtas_os_term_buf[2048];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) void rtas_os_term(char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) * Firmware with the ibm,extended-os-term property is guaranteed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) * to always return from an ibm,os-term call. Earlier versions without
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) * this property may terminate the partition which we want to avoid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) * since it interferes with panic_timeout.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) if (RTAS_UNKNOWN_SERVICE == rtas_token("ibm,os-term") ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) RTAS_UNKNOWN_SERVICE == rtas_token("ibm,extended-os-term"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) snprintf(rtas_os_term_buf, 2048, "OS panic: %s", str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) status = rtas_call(rtas_token("ibm,os-term"), 1, 1, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) __pa(rtas_os_term_buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) } while (rtas_busy_delay(status));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) if (status != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) printk(KERN_EMERG "ibm,os-term call failed %d\n", status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) #ifdef CONFIG_PPC_PSERIES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) static int __rtas_suspend_last_cpu(struct rtas_suspend_me_data *data, int wake_when_done)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) u16 slb_size = mmu_slb_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) int rc = H_MULTI_THREADS_ACTIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) int cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) slb_set_size(SLB_MIN_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) printk(KERN_DEBUG "calling ibm,suspend-me on cpu %i\n", smp_processor_id());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) while (rc == H_MULTI_THREADS_ACTIVE && !atomic_read(&data->done) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) !atomic_read(&data->error))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) rc = rtas_call(data->token, 0, 1, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) if (rc || atomic_read(&data->error)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) printk(KERN_DEBUG "ibm,suspend-me returned %d\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) slb_set_size(slb_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) if (atomic_read(&data->error))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) rc = atomic_read(&data->error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) atomic_set(&data->error, rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) pSeries_coalesce_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) if (wake_when_done) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) atomic_set(&data->done, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) for_each_online_cpu(cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) plpar_hcall_norets(H_PROD, get_hard_smp_processor_id(cpu));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) if (atomic_dec_return(&data->working) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) complete(data->complete);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) int rtas_suspend_last_cpu(struct rtas_suspend_me_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) atomic_inc(&data->working);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) return __rtas_suspend_last_cpu(data, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) static int __rtas_suspend_cpu(struct rtas_suspend_me_data *data, int wake_when_done)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) long rc = H_SUCCESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) unsigned long msr_save;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) int cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) atomic_inc(&data->working);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) /* really need to ensure MSR.EE is off for H_JOIN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) msr_save = mfmsr();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) mtmsr(msr_save & ~(MSR_EE));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) while (rc == H_SUCCESS && !atomic_read(&data->done) && !atomic_read(&data->error))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) rc = plpar_hcall_norets(H_JOIN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) mtmsr(msr_save);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) if (rc == H_SUCCESS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) /* This cpu was prodded and the suspend is complete. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) } else if (rc == H_CONTINUE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) /* All other cpus are in H_JOIN, this cpu does
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) * the suspend.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) return __rtas_suspend_last_cpu(data, wake_when_done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) printk(KERN_ERR "H_JOIN on cpu %i failed with rc = %ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) smp_processor_id(), rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) atomic_set(&data->error, rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) if (wake_when_done) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) atomic_set(&data->done, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) /* This cpu did the suspend or got an error; in either case,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) * we need to prod all other other cpus out of join state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) * Extra prods are harmless.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) for_each_online_cpu(cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) plpar_hcall_norets(H_PROD, get_hard_smp_processor_id(cpu));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) if (atomic_dec_return(&data->working) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) complete(data->complete);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) int rtas_suspend_cpu(struct rtas_suspend_me_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) return __rtas_suspend_cpu(data, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) static void rtas_percpu_suspend_me(void *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) __rtas_suspend_cpu((struct rtas_suspend_me_data *)info, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) int rtas_ibm_suspend_me(u64 handle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) long state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) long rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) struct rtas_suspend_me_data data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) DECLARE_COMPLETION_ONSTACK(done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) if (!rtas_service_present("ibm,suspend-me"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) return -ENOSYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) /* Make sure the state is valid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) rc = plpar_hcall(H_VASI_STATE, retbuf, handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) state = retbuf[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) printk(KERN_ERR "rtas_ibm_suspend_me: vasi_state returned %ld\n",rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) } else if (state == H_VASI_ENABLED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) return -EAGAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) } else if (state != H_VASI_SUSPENDING) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) printk(KERN_ERR "rtas_ibm_suspend_me: vasi_state returned state %ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) atomic_set(&data.working, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) atomic_set(&data.done, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) atomic_set(&data.error, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) data.token = rtas_token("ibm,suspend-me");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) data.complete = &done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) lock_device_hotplug();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) cpu_hotplug_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) /* Call function on all CPUs. One of us will make the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) * rtas call
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) on_each_cpu(rtas_percpu_suspend_me, &data, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) wait_for_completion(&done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) if (atomic_read(&data.error) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) printk(KERN_ERR "Error doing global join\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) cpu_hotplug_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) unlock_device_hotplug();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) return atomic_read(&data.error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) * rtas_call_reentrant() - Used for reentrant rtas calls
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) * @token: Token for desired reentrant RTAS call
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) * @nargs: Number of Input Parameters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) * @nret: Number of Output Parameters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) * @outputs: Array of outputs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) * @...: Inputs for desired RTAS call
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) * According to LoPAR documentation, only "ibm,int-on", "ibm,int-off",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) * "ibm,get-xive" and "ibm,set-xive" are currently reentrant.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) * Reentrant calls need their own rtas_args buffer, so not using rtas.args, but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) * PACA one instead.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) * Return: -1 on error,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) * First output value of RTAS call if (nret > 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) * 0 otherwise,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) int rtas_call_reentrant(int token, int nargs, int nret, int *outputs, ...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) va_list list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) struct rtas_args *args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) int i, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) if (!rtas.entry || token == RTAS_UNKNOWN_SERVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) preempt_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) /* We use the per-cpu (PACA) rtas args buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) args = local_paca->rtas_args_reentrant;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) va_start(list, outputs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) va_rtas_call_unlocked(args, token, nargs, nret, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) va_end(list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) if (nret > 1 && outputs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) for (i = 0; i < nret - 1; ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) outputs[i] = be32_to_cpu(args->rets[i + 1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) if (nret > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) ret = be32_to_cpu(args->rets[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) preempt_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) #else /* CONFIG_PPC_PSERIES */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) int rtas_ibm_suspend_me(u64 handle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) return -ENOSYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) * Find a specific pseries error log in an RTAS extended event log.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) * @log: RTAS error/event log
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) * @section_id: two character section identifier
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) * Returns a pointer to the specified errorlog or NULL if not found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) struct pseries_errorlog *get_pseries_errorlog(struct rtas_error_log *log,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) uint16_t section_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) struct rtas_ext_event_log_v6 *ext_log =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) (struct rtas_ext_event_log_v6 *)log->buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) struct pseries_errorlog *sect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) unsigned char *p, *log_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) uint32_t ext_log_length = rtas_error_extended_log_length(log);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) uint8_t log_format = rtas_ext_event_log_format(ext_log);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) uint32_t company_id = rtas_ext_event_company_id(ext_log);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) /* Check that we understand the format */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) if (ext_log_length < sizeof(struct rtas_ext_event_log_v6) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) log_format != RTAS_V6EXT_LOG_FORMAT_EVENT_LOG ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) company_id != RTAS_V6EXT_COMPANY_ID_IBM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) log_end = log->buffer + ext_log_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) p = ext_log->vendor_log;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) while (p < log_end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) sect = (struct pseries_errorlog *)p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) if (pseries_errorlog_id(sect) == section_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) return sect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) p += pseries_errorlog_length(sect);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) #ifdef CONFIG_PPC_RTAS_FILTER
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) * The sys_rtas syscall, as originally designed, allows root to pass
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) * arbitrary physical addresses to RTAS calls. A number of RTAS calls
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) * can be abused to write to arbitrary memory and do other things that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) * are potentially harmful to system integrity, and thus should only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) * be used inside the kernel and not exposed to userspace.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) * All known legitimate users of the sys_rtas syscall will only ever
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) * pass addresses that fall within the RMO buffer, and use a known
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) * subset of RTAS calls.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) * Accordingly, we filter RTAS requests to check that the call is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) * permitted, and that provided pointers fall within the RMO buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) * The rtas_filters list contains an entry for each permitted call,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) * with the indexes of the parameters which are expected to contain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) * addresses and sizes of buffers allocated inside the RMO buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) struct rtas_filter {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) int token;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) /* Indexes into the args buffer, -1 if not used */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) int buf_idx1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) int size_idx1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) int buf_idx2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) int size_idx2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) int fixed_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) static struct rtas_filter rtas_filters[] __ro_after_init = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) { "ibm,activate-firmware", -1, -1, -1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) { "ibm,configure-connector", -1, 0, -1, 1, -1, 4096 }, /* Special cased */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) { "display-character", -1, -1, -1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) { "ibm,display-message", -1, 0, -1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) { "ibm,errinjct", -1, 2, -1, -1, -1, 1024 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) { "ibm,close-errinjct", -1, -1, -1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) { "ibm,open-errinjct", -1, -1, -1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) { "ibm,get-config-addr-info2", -1, -1, -1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) { "ibm,get-dynamic-sensor-state", -1, 1, -1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) { "ibm,get-indices", -1, 2, 3, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) { "get-power-level", -1, -1, -1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) { "get-sensor-state", -1, -1, -1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) { "ibm,get-system-parameter", -1, 1, 2, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) { "get-time-of-day", -1, -1, -1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) { "ibm,get-vpd", -1, 0, -1, 1, 2 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) { "ibm,lpar-perftools", -1, 2, 3, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) { "ibm,platform-dump", -1, 4, 5, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) { "ibm,read-slot-reset-state", -1, -1, -1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) { "ibm,scan-log-dump", -1, 0, 1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) { "ibm,set-dynamic-indicator", -1, 2, -1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) { "ibm,set-eeh-option", -1, -1, -1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) { "set-indicator", -1, -1, -1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) { "set-power-level", -1, -1, -1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) { "set-time-for-power-on", -1, -1, -1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) { "ibm,set-system-parameter", -1, 1, -1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) { "set-time-of-day", -1, -1, -1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) { "ibm,suspend-me", -1, -1, -1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) { "ibm,update-nodes", -1, 0, -1, -1, -1, 4096 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) { "ibm,update-properties", -1, 0, -1, -1, -1, 4096 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) { "ibm,physical-attestation", -1, 0, 1, -1, -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) static bool in_rmo_buf(u32 base, u32 end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) return base >= rtas_rmo_buf &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) base < (rtas_rmo_buf + RTAS_RMOBUF_MAX) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) base <= end &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) end >= rtas_rmo_buf &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) end < (rtas_rmo_buf + RTAS_RMOBUF_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) static bool block_rtas_call(int token, int nargs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) struct rtas_args *args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) for (i = 0; i < ARRAY_SIZE(rtas_filters); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) struct rtas_filter *f = &rtas_filters[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) u32 base, size, end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) if (token != f->token)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) if (f->buf_idx1 != -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) base = be32_to_cpu(args->args[f->buf_idx1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) if (f->size_idx1 != -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) size = be32_to_cpu(args->args[f->size_idx1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) else if (f->fixed_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) size = f->fixed_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) size = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) end = base + size - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) if (!in_rmo_buf(base, end))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) if (f->buf_idx2 != -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) base = be32_to_cpu(args->args[f->buf_idx2]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) if (f->size_idx2 != -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) size = be32_to_cpu(args->args[f->size_idx2]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) else if (f->fixed_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) size = f->fixed_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) size = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) end = base + size - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) * Special case for ibm,configure-connector where the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) * address can be 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) if (!strcmp(f->name, "ibm,configure-connector") &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) base == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) if (!in_rmo_buf(base, end))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) pr_err_ratelimited("sys_rtas: RTAS call blocked - exploit attempt?\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) pr_err_ratelimited("sys_rtas: token=0x%x, nargs=%d (called by %s)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) token, nargs, current->comm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) static bool block_rtas_call(int token, int nargs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) struct rtas_args *args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) #endif /* CONFIG_PPC_RTAS_FILTER */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) /* We assume to be passed big endian arguments */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) struct rtas_args args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) char *buff_copy, *errbuf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) int nargs, nret, token;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) if (!capable(CAP_SYS_ADMIN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) if (!rtas.entry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) if (copy_from_user(&args, uargs, 3 * sizeof(u32)) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) nargs = be32_to_cpu(args.nargs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) nret = be32_to_cpu(args.nret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) token = be32_to_cpu(args.token);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) if (nargs >= ARRAY_SIZE(args.args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) || nret > ARRAY_SIZE(args.args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) || nargs + nret > ARRAY_SIZE(args.args))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) /* Copy in args. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) if (copy_from_user(args.args, uargs->args,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) nargs * sizeof(rtas_arg_t)) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) if (token == RTAS_UNKNOWN_SERVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) args.rets = &args.args[nargs];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) memset(args.rets, 0, nret * sizeof(rtas_arg_t));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) if (block_rtas_call(token, nargs, &args))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) /* Need to handle ibm,suspend_me call specially */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) if (token == ibm_suspend_me_token) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) * rtas_ibm_suspend_me assumes the streamid handle is in cpu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) * endian, or at least the hcall within it requires it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) int rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) u64 handle = ((u64)be32_to_cpu(args.args[0]) << 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) | be32_to_cpu(args.args[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) rc = rtas_ibm_suspend_me(handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) if (rc == -EAGAIN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) args.rets[0] = cpu_to_be32(RTAS_NOT_SUSPENDABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) else if (rc == -EIO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) args.rets[0] = cpu_to_be32(-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) else if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) goto copy_return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) buff_copy = get_errorlog_buffer();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) flags = lock_rtas();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) rtas.args = args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) enter_rtas(__pa(&rtas.args));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) args = rtas.args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) /* A -1 return code indicates that the last command couldn't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) be completed due to a hardware error. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) if (be32_to_cpu(args.rets[0]) == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) errbuf = __fetch_rtas_last_error(buff_copy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) unlock_rtas(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) if (buff_copy) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) if (errbuf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) log_error(errbuf, ERR_TYPE_RTAS_LOG, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) kfree(buff_copy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) copy_return:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) /* Copy out args. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) if (copy_to_user(uargs->args + nargs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) args.args + nargs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) nret * sizeof(rtas_arg_t)) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) * Call early during boot, before mem init, to retrieve the RTAS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) * information from the device-tree and allocate the RMO buffer for userland
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) * accesses.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) void __init rtas_initialize(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) unsigned long rtas_region = RTAS_INSTANTIATE_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) u32 base, size, entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) int no_base, no_size, no_entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) #ifdef CONFIG_PPC_RTAS_FILTER
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) /* Get RTAS dev node and fill up our "rtas" structure with infos
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) * about it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) rtas.dev = of_find_node_by_name(NULL, "rtas");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) if (!rtas.dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) no_base = of_property_read_u32(rtas.dev, "linux,rtas-base", &base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) no_size = of_property_read_u32(rtas.dev, "rtas-size", &size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) if (no_base || no_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) of_node_put(rtas.dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) rtas.dev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) rtas.base = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) rtas.size = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) no_entry = of_property_read_u32(rtas.dev, "linux,rtas-entry", &entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) rtas.entry = no_entry ? rtas.base : entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) /* If RTAS was found, allocate the RMO buffer for it and look for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) * the stop-self token if any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) if (firmware_has_feature(FW_FEATURE_LPAR)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) rtas_region = min(ppc64_rma_size, RTAS_INSTANTIATE_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) ibm_suspend_me_token = rtas_token("ibm,suspend-me");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) rtas_rmo_buf = memblock_phys_alloc_range(RTAS_RMOBUF_MAX, PAGE_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) 0, rtas_region);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) if (!rtas_rmo_buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) panic("ERROR: RTAS: Failed to allocate %lx bytes below %pa\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) PAGE_SIZE, &rtas_region);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) #ifdef CONFIG_RTAS_ERROR_LOGGING
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) rtas_last_error_token = rtas_token("rtas-last-error");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) #ifdef CONFIG_PPC_RTAS_FILTER
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) for (i = 0; i < ARRAY_SIZE(rtas_filters); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) rtas_filters[i].token = rtas_token(rtas_filters[i].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) int __init early_init_dt_scan_rtas(unsigned long node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) const char *uname, int depth, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) const u32 *basep, *entryp, *sizep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) if (depth != 1 || strcmp(uname, "rtas") != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) basep = of_get_flat_dt_prop(node, "linux,rtas-base", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) entryp = of_get_flat_dt_prop(node, "linux,rtas-entry", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) sizep = of_get_flat_dt_prop(node, "rtas-size", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) if (basep && entryp && sizep) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) rtas.base = *basep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) rtas.entry = *entryp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) rtas.size = *sizep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) #ifdef CONFIG_UDBG_RTAS_CONSOLE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) basep = of_get_flat_dt_prop(node, "put-term-char", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) if (basep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) rtas_putchar_token = *basep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) basep = of_get_flat_dt_prop(node, "get-term-char", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) if (basep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) rtas_getchar_token = *basep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) if (rtas_putchar_token != RTAS_UNKNOWN_SERVICE &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) rtas_getchar_token != RTAS_UNKNOWN_SERVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) udbg_init_rtas_console();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) /* break now */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) static arch_spinlock_t timebase_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) static u64 timebase = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) void rtas_give_timebase(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) hard_irq_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) arch_spin_lock(&timebase_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) rtas_call(rtas_token("freeze-time-base"), 0, 1, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) timebase = get_tb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) arch_spin_unlock(&timebase_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) while (timebase)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) barrier();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) rtas_call(rtas_token("thaw-time-base"), 0, 1, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) void rtas_take_timebase(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) while (!timebase)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) barrier();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) arch_spin_lock(&timebase_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) set_tb(timebase >> 32, timebase & 0xffffffff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) timebase = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) arch_spin_unlock(&timebase_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) }