rtas.c
来自「linux 内核源代码」· C语言 代码 · 共 922 行 · 第 1/2 页
C
922 行
if (status == RTAS_BUSY) { ms = 1; } else if (status >= 9900 && status <= 9905) { order = status - 9900; for (ms = 1; order > 0; order--) ms *= 10; } return ms;}EXPORT_SYMBOL(rtas_busy_delay_time);/* For an RTAS busy status code, perform the hinted delay. */unsigned int rtas_busy_delay(int status){ unsigned int ms; might_sleep(); ms = rtas_busy_delay_time(status); if (ms) msleep(ms); return ms;}EXPORT_SYMBOL(rtas_busy_delay);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;}EXPORT_SYMBOL(rtas_get_power_level);int rtas_set_power_level(int powerdomain, int level, int *setlevel){ int token = rtas_token("set-power-level"); int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; do { rc = rtas_call(token, 2, 2, setlevel, powerdomain, level); } while (rtas_busy_delay(rc)); if (rc < 0) return rtas_error_rc(rc); return rc;}EXPORT_SYMBOL(rtas_set_power_level);int rtas_get_sensor(int sensor, int index, int *state){ int token = rtas_token("get-sensor-state"); int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; do { rc = rtas_call(token, 2, 2, state, sensor, index); } while (rtas_busy_delay(rc)); if (rc < 0) return rtas_error_rc(rc); return rc;}EXPORT_SYMBOL(rtas_get_sensor);int rtas_set_indicator(int indicator, int index, int new_value){ int token = rtas_token("set-indicator"); int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; do { rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value); } while (rtas_busy_delay(rc)); if (rc < 0) return rtas_error_rc(rc); return rc;}EXPORT_SYMBOL(rtas_set_indicator);/* * Ignoring RTAS extended delay */int rtas_set_indicator_fast(int indicator, int index, int new_value){ int rc; int token = rtas_token("set-indicator"); if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value); WARN_ON(rc == -2 || (rc >= 9900 && rc <= 9905)); 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 (panic_timeout) return; 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)); } while (rtas_busy_delay(status)); if (status != 0) printk(KERN_EMERG "ibm,os-term call failed %d\n", status);}static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE;#ifdef CONFIG_PPC_PSERIESstatic void rtas_percpu_suspend_me(void *info){ long rc; unsigned long msr_save; int cpu; struct rtas_suspend_me_data *data = (struct rtas_suspend_me_data *)info; atomic_inc(&data->working); /* really need to ensure MSR.EE is off for H_JOIN */ msr_save = mfmsr(); mtmsr(msr_save & ~(MSR_EE)); rc = plpar_hcall_norets(H_JOIN); mtmsr(msr_save); if (rc == H_SUCCESS) { /* This cpu was prodded and the suspend is complete. */ goto out; } else if (rc == H_CONTINUE) { /* All other cpus are in H_JOIN, this cpu does * the suspend. */ printk(KERN_DEBUG "calling ibm,suspend-me on cpu %i\n", smp_processor_id()); data->error = rtas_call(data->token, 0, 1, NULL); if (data->error) printk(KERN_DEBUG "ibm,suspend-me returned %d\n", data->error); } else { printk(KERN_ERR "H_JOIN on cpu %i failed with rc = %ld\n", smp_processor_id(), rc); data->error = rc; } /* This cpu did the suspend or got an error; in either case, * we need to prod all other other cpus out of join state. * Extra prods are harmless. */ for_each_online_cpu(cpu) plpar_hcall_norets(H_PROD, get_hard_smp_processor_id(cpu));out: if (atomic_dec_return(&data->working) == 0) complete(data->complete);}static int rtas_ibm_suspend_me(struct rtas_args *args){ long state; long rc; unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; struct rtas_suspend_me_data data; DECLARE_COMPLETION_ONSTACK(done); if (!rtas_service_present("ibm,suspend-me")) return -ENOSYS; /* Make sure the state is valid */ rc = plpar_hcall(H_VASI_STATE, retbuf, ((u64)args->args[0] << 32) | args->args[1]); state = retbuf[0]; if (rc) { printk(KERN_ERR "rtas_ibm_suspend_me: vasi_state returned %ld\n",rc); return rc; } else if (state == H_VASI_ENABLED) { args->args[args->nargs] = RTAS_NOT_SUSPENDABLE; return 0; } else if (state != H_VASI_SUSPENDING) { printk(KERN_ERR "rtas_ibm_suspend_me: vasi_state returned state %ld\n", state); args->args[args->nargs] = -1; return 0; } atomic_set(&data.working, 0); data.token = rtas_token("ibm,suspend-me"); data.error = 0; data.complete = &done; /* Call function on all CPUs. One of us will make the * rtas call */ if (on_each_cpu(rtas_percpu_suspend_me, &data, 1, 0)) data.error = -EINVAL; wait_for_completion(&done); if (data.error != 0) printk(KERN_ERR "Error doing global join\n"); return data.error;}#else /* CONFIG_PPC_PSERIES */static int rtas_ibm_suspend_me(struct rtas_args *args){ return -ENOSYS;}#endifasmlinkage int ppc_rtas(struct rtas_args __user *uargs){ struct rtas_args args; unsigned long flags; char *buff_copy, *errbuf = NULL; int nargs; int rc; 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; if (args.token == RTAS_UNKNOWN_SERVICE) return -EINVAL; /* Need to handle ibm,suspend_me call specially */ if (args.token == ibm_suspend_me_token) { rc = rtas_ibm_suspend_me(&args); if (rc) return rc; goto copy_return; } 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_return: /* Copy out args. */ if (copy_to_user(uargs->args + nargs, args.args + nargs, args.nret * sizeof(rtas_arg_t)) != 0) return -EFAULT; return 0;}/* * Call early during boot, before mem init or bootmem, to retrieve 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) { const u32 *basep, *entryp, *sizep; basep = of_get_property(rtas.dev, "linux,rtas-base", NULL); sizep = of_get_property(rtas.dev, "rtas-size", NULL); if (basep != NULL && sizep != NULL) { rtas.base = *basep; rtas.size = *sizep; entryp = of_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_is(pseries) && firmware_has_feature(FW_FEATURE_LPAR)) { rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX); ibm_suspend_me_token = rtas_token("ibm,suspend-me"); }#endif rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, rtas_region);#ifdef CONFIG_RTAS_ERROR_LOGGING rtas_last_error_token = rtas_token("rtas-last-error");#endif}int __init early_init_dt_scan_rtas(unsigned long node, const char *uname, int depth, void *data){ u32 *basep, *entryp, *sizep; if (depth != 1 || strcmp(uname, "rtas") != 0) return 0; basep = of_get_flat_dt_prop(node, "linux,rtas-base", NULL); entryp = of_get_flat_dt_prop(node, "linux,rtas-entry", NULL); sizep = of_get_flat_dt_prop(node, "rtas-size", NULL); if (basep && entryp && sizep) { rtas.base = *basep; rtas.entry = *entryp; rtas.size = *sizep; }#ifdef CONFIG_UDBG_RTAS_CONSOLE basep = of_get_flat_dt_prop(node, "put-term-char", NULL); if (basep) rtas_putchar_token = *basep; basep = of_get_flat_dt_prop(node, "get-term-char", NULL); if (basep) rtas_getchar_token = *basep; if (rtas_putchar_token != RTAS_UNKNOWN_SERVICE && rtas_getchar_token != RTAS_UNKNOWN_SERVICE) udbg_init_rtas_console();#endif /* break now */ return 1;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?