Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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) }