📄 rtas.c
字号:
spin_unlock_irqrestore(&rtas.lock, s); if (buff_copy) { log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0); if (mem_init_done) kfree(buff_copy); } return ret;}/* Given an RTAS status code of 990n compute the hinted delay of 10^n * (last digit) milliseconds. For now we bound at n=5 (100 sec). */unsigned int rtas_extended_busy_delay_time(int status){ int order = status - 9900; unsigned long ms; if (order < 0) order = 0; /* RTC depends on this for -2 clock busy */ else if (order > 5) order = 5; /* bound */ /* Use microseconds for reasonable accuracy */ for (ms = 1; order > 0; order--) ms *= 10; return ms; }int rtas_error_rc(int rtas_rc){ int rc; switch (rtas_rc) { case -1: /* Hardware Error */ rc = -EIO; break; case -3: /* Bad indicator/domain/etc */ rc = -EINVAL; break; case -9000: /* Isolation error */ rc = -EFAULT; break; case -9001: /* Outstanding TCE/PTE */ rc = -EEXIST; break; case -9002: /* No usable slot */ rc = -ENODEV; break; default: printk(KERN_ERR "%s: unexpected RTAS error %d\n", __FUNCTION__, rtas_rc); rc = -ERANGE; break; } return rc;}int rtas_get_power_level(int powerdomain, int *level){ int token = rtas_token("get-power-level"); int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; while ((rc = rtas_call(token, 1, 2, level, powerdomain)) == RTAS_BUSY) udelay(1); if (rc < 0) return rtas_error_rc(rc); return rc;}int rtas_set_power_level(int powerdomain, int level, int *setlevel){ int token = rtas_token("set-power-level"); unsigned int wait_time; int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; while (1) { rc = rtas_call(token, 2, 2, setlevel, powerdomain, level); if (rc == RTAS_BUSY) udelay(1); else if (rtas_is_extended_busy(rc)) { wait_time = rtas_extended_busy_delay_time(rc); udelay(wait_time * 1000); } else break; } if (rc < 0) return rtas_error_rc(rc); return rc;}int rtas_get_sensor(int sensor, int index, int *state){ int token = rtas_token("get-sensor-state"); unsigned int wait_time; int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; while (1) { rc = rtas_call(token, 2, 2, state, sensor, index); if (rc == RTAS_BUSY) udelay(1); else if (rtas_is_extended_busy(rc)) { wait_time = rtas_extended_busy_delay_time(rc); udelay(wait_time * 1000); } else break; } if (rc < 0) return rtas_error_rc(rc); return rc;}int rtas_set_indicator(int indicator, int index, int new_value){ int token = rtas_token("set-indicator"); unsigned int wait_time; int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; while (1) { rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value); if (rc == RTAS_BUSY) udelay(1); else if (rtas_is_extended_busy(rc)) { wait_time = rtas_extended_busy_delay_time(rc); udelay(wait_time * 1000); } else break; } if (rc < 0) return rtas_error_rc(rc); return rc;}void rtas_restart(char *cmd){ if (rtas_flash_term_hook) rtas_flash_term_hook(SYS_RESTART); printk("RTAS system-reboot returned %d\n", rtas_call(rtas_token("system-reboot"), 0, 1, NULL)); for (;;);}void rtas_power_off(void){ if (rtas_flash_term_hook) rtas_flash_term_hook(SYS_POWER_OFF); /* allow power on only with power button press */ printk("RTAS power-off returned %d\n", rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1)); for (;;);}void rtas_halt(void){ if (rtas_flash_term_hook) rtas_flash_term_hook(SYS_HALT); /* allow power on only with power button press */ printk("RTAS power-off returned %d\n", rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1)); for (;;);}/* Must be in the RMO region, so we place it here */static char rtas_os_term_buf[2048];void rtas_os_term(char *str){ int status; if (RTAS_UNKNOWN_SERVICE == rtas_token("ibm,os-term")) return; snprintf(rtas_os_term_buf, 2048, "OS panic: %s", str); do { status = rtas_call(rtas_token("ibm,os-term"), 1, 1, NULL, __pa(rtas_os_term_buf)); if (status == RTAS_BUSY) udelay(1); else if (status != 0) printk(KERN_EMERG "ibm,os-term call failed %d\n", status); } while (status == RTAS_BUSY);}asmlinkage int ppc_rtas(struct rtas_args __user *uargs){ struct rtas_args args; unsigned long flags; char *buff_copy, *errbuf = NULL; int nargs; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user(&args, uargs, 3 * sizeof(u32)) != 0) return -EFAULT; nargs = args.nargs; if (nargs > ARRAY_SIZE(args.args) || args.nret > ARRAY_SIZE(args.args) || nargs + args.nret > ARRAY_SIZE(args.args)) return -EINVAL; /* Copy in args. */ if (copy_from_user(args.args, uargs->args, nargs * sizeof(rtas_arg_t)) != 0) return -EFAULT; buff_copy = get_errorlog_buffer(); spin_lock_irqsave(&rtas.lock, flags); rtas.args = args; enter_rtas(__pa(&rtas.args)); args = rtas.args; args.rets = &args.args[nargs]; /* A -1 return code indicates that the last command couldn't be completed due to a hardware error. */ if (args.rets[0] == -1) errbuf = __fetch_rtas_last_error(buff_copy); spin_unlock_irqrestore(&rtas.lock, flags); if (buff_copy) { if (errbuf) log_error(errbuf, ERR_TYPE_RTAS_LOG, 0); kfree(buff_copy); } /* Copy out args. */ if (copy_to_user(uargs->args + nargs, args.args + nargs, args.nret * sizeof(rtas_arg_t)) != 0) return -EFAULT; return 0;}/* This version can't take the spinlock, because it never returns */struct rtas_args rtas_stop_self_args = { /* The token is initialized for real in setup_system() */ .token = RTAS_UNKNOWN_SERVICE, .nargs = 0, .nret = 1, .rets = &rtas_stop_self_args.args[0],};void rtas_stop_self(void){ struct rtas_args *rtas_args = &rtas_stop_self_args; local_irq_disable(); BUG_ON(rtas_args->token == RTAS_UNKNOWN_SERVICE); printk("cpu %u (hwid %u) Ready to die...\n", smp_processor_id(), hard_smp_processor_id()); enter_rtas(__pa(rtas_args)); panic("Alas, I survived.\n");}/* * Call early during boot, before mem init or bootmem, to retreive the RTAS * informations from the device-tree and allocate the RMO buffer for userland * accesses. */void __init rtas_initialize(void){ unsigned long rtas_region = RTAS_INSTANTIATE_MAX; /* Get RTAS dev node and fill up our "rtas" structure with infos * about it. */ rtas.dev = of_find_node_by_name(NULL, "rtas"); if (rtas.dev) { u32 *basep, *entryp; u32 *sizep; basep = (u32 *)get_property(rtas.dev, "linux,rtas-base", NULL); sizep = (u32 *)get_property(rtas.dev, "rtas-size", NULL); if (basep != NULL && sizep != NULL) { rtas.base = *basep; rtas.size = *sizep; entryp = (u32 *)get_property(rtas.dev, "linux,rtas-entry", NULL); if (entryp == NULL) /* Ugh */ rtas.entry = rtas.base; else rtas.entry = *entryp; } else rtas.dev = NULL; } if (!rtas.dev) return; /* If RTAS was found, allocate the RMO buffer for it and look for * the stop-self token if any */#ifdef CONFIG_PPC64 if (_machine == PLATFORM_PSERIES_LPAR) rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX);#endif rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, rtas_region);#ifdef CONFIG_HOTPLUG_CPU rtas_stop_self_args.token = rtas_token("stop-self");#endif /* CONFIG_HOTPLUG_CPU */#ifdef CONFIG_RTAS_ERROR_LOGGING rtas_last_error_token = rtas_token("rtas-last-error");#endif}EXPORT_SYMBOL(rtas_token);EXPORT_SYMBOL(rtas_call);EXPORT_SYMBOL(rtas_data_buf);EXPORT_SYMBOL(rtas_data_buf_lock);EXPORT_SYMBOL(rtas_extended_busy_delay_time);EXPORT_SYMBOL(rtas_get_sensor);EXPORT_SYMBOL(rtas_get_power_level);EXPORT_SYMBOL(rtas_set_power_level);EXPORT_SYMBOL(rtas_set_indicator);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -