/* Call an RTAS method by token */ int rtas_call_method(cell_t token, int nargs, int nreturns, ...) { vm_offset_t argsptr; faultbuf env, *oldfaultbuf; va_list ap; struct { cell_t token; cell_t nargs; cell_t nreturns; cell_t args_n_results[12]; } args; int n, result; if (!rtas_exists() || nargs + nreturns > 12) return (-1); args.token = token; va_start(ap, nreturns); mtx_lock_spin(&rtas_mtx); rtas_bounce_offset = 0; args.nargs = nargs; args.nreturns = nreturns; for (n = 0; n < nargs; n++) args.args_n_results[n] = va_arg(ap, cell_t); argsptr = rtas_real_map(&args, sizeof(args)); /* Get rid of any stale machine checks that have been waiting. */ __asm __volatile ("sync; isync"); oldfaultbuf = curthread->td_pcb->pcb_onfault; if (!setfault(env)) { __asm __volatile ("sync"); result = rtascall(argsptr, rtas_private_data); __asm __volatile ("sync; isync"); } else { result = RTAS_HW_ERROR; } curthread->td_pcb->pcb_onfault = oldfaultbuf; __asm __volatile ("sync"); rtas_real_unmap(argsptr, &args, sizeof(args)); mtx_unlock_spin(&rtas_mtx); if (result < 0) return (result); for (n = nargs; n < nargs + nreturns; n++) *va_arg(ap, cell_t *) = args.args_n_results[n]; return (result); }
static int rtasdev_probe(device_t dev) { const char *name = ofw_bus_get_name(dev); if (strcmp(name, "rtas") != 0) return (ENXIO); if (!rtas_exists()) return (ENXIO); device_set_desc(dev, "Run-Time Abstraction Services"); return (0); }
/* Look up an RTAS token */ cell_t rtas_token_lookup(const char *method) { cell_t token; if (!rtas_exists()) return (-1); if (OF_getprop(rtas, method, &token, sizeof(token)) == -1) return (-1); return (token); }
static int rtaspci_probe(device_t dev) { const char *type; if (!rtas_exists()) return (ENXIO); type = ofw_bus_get_type(dev); if (OF_getproplen(ofw_bus_get_node(dev), "used-by-rtas") < 0) return (ENXIO); if (type == NULL || strcmp(type, "pci") != 0) return (ENXIO); device_set_desc(dev, "RTAS Host-PCI bridge"); return (BUS_PROBE_GENERIC); }
static int chrp_smp_start_cpu(platform_t plat, struct pcpu *pc) { cell_t start_cpu; int result, err, timeout; if (!rtas_exists()) { printf("RTAS uninitialized: unable to start AP %d\n", pc->pc_cpuid); return (ENXIO); } start_cpu = rtas_token_lookup("start-cpu"); if (start_cpu == -1) { printf("RTAS unknown method: unable to start AP %d\n", pc->pc_cpuid); return (ENXIO); } ap_pcpu = pc; powerpc_sync(); result = rtas_call_method(start_cpu, 3, 1, pc->pc_cpuid, EXC_RST, pc, &err); if (result < 0 || err != 0) { printf("RTAS error (%d/%d): unable to start AP %d\n", result, err, pc->pc_cpuid); return (ENXIO); } timeout = 10000; while (!pc->pc_awake && timeout--) DELAY(100); return ((pc->pc_awake) ? 0 : EBUSY); }