Path: blob/master/arch/x86/platform/olpc/olpc_ofw.c
10821 views
#include <linux/kernel.h>1#include <linux/module.h>2#include <linux/init.h>3#include <asm/page.h>4#include <asm/setup.h>5#include <asm/io.h>6#include <asm/pgtable.h>7#include <asm/olpc_ofw.h>89/* address of OFW callback interface; will be NULL if OFW isn't found */10static int (*olpc_ofw_cif)(int *);1112/* page dir entry containing OFW's pgdir table; filled in by head_32.S */13u32 olpc_ofw_pgd __initdata;1415static DEFINE_SPINLOCK(ofw_lock);1617#define MAXARGS 101819void __init setup_olpc_ofw_pgd(void)20{21pgd_t *base, *ofw_pde;2223if (!olpc_ofw_cif)24return;2526/* fetch OFW's PDE */27base = early_ioremap(olpc_ofw_pgd, sizeof(olpc_ofw_pgd) * PTRS_PER_PGD);28if (!base) {29printk(KERN_ERR "failed to remap OFW's pgd - disabling OFW!\n");30olpc_ofw_cif = NULL;31return;32}33ofw_pde = &base[OLPC_OFW_PDE_NR];3435/* install OFW's PDE permanently into the kernel's pgtable */36set_pgd(&swapper_pg_dir[OLPC_OFW_PDE_NR], *ofw_pde);37/* implicit optimization barrier here due to uninline function return */3839early_iounmap(base, sizeof(olpc_ofw_pgd) * PTRS_PER_PGD);40}4142int __olpc_ofw(const char *name, int nr_args, const void **args, int nr_res,43void **res)44{45int ofw_args[MAXARGS + 3];46unsigned long flags;47int ret, i, *p;4849BUG_ON(nr_args + nr_res > MAXARGS);5051if (!olpc_ofw_cif)52return -EIO;5354ofw_args[0] = (int)name;55ofw_args[1] = nr_args;56ofw_args[2] = nr_res;5758p = &ofw_args[3];59for (i = 0; i < nr_args; i++, p++)60*p = (int)args[i];6162/* call into ofw */63spin_lock_irqsave(&ofw_lock, flags);64ret = olpc_ofw_cif(ofw_args);65spin_unlock_irqrestore(&ofw_lock, flags);6667if (!ret) {68for (i = 0; i < nr_res; i++, p++)69*((int *)res[i]) = *p;70}7172return ret;73}74EXPORT_SYMBOL_GPL(__olpc_ofw);7576bool olpc_ofw_present(void)77{78return olpc_ofw_cif != NULL;79}80EXPORT_SYMBOL_GPL(olpc_ofw_present);8182/* OFW cif _should_ be above this address */83#define OFW_MIN 0xff0000008485/* OFW starts on a 1MB boundary */86#define OFW_BOUND (1<<20)8788void __init olpc_ofw_detect(void)89{90struct olpc_ofw_header *hdr = &boot_params.olpc_ofw_header;91unsigned long start;9293/* ensure OFW booted us by checking for "OFW " string */94if (hdr->ofw_magic != OLPC_OFW_SIG)95return;9697olpc_ofw_cif = (int (*)(int *))hdr->cif_handler;9899if ((unsigned long)olpc_ofw_cif < OFW_MIN) {100printk(KERN_ERR "OFW detected, but cif has invalid address 0x%lx - disabling.\n",101(unsigned long)olpc_ofw_cif);102olpc_ofw_cif = NULL;103return;104}105106/* determine where OFW starts in memory */107start = round_down((unsigned long)olpc_ofw_cif, OFW_BOUND);108printk(KERN_INFO "OFW detected in memory, cif @ 0x%lx (reserving top %ldMB)\n",109(unsigned long)olpc_ofw_cif, (-start) >> 20);110reserve_top_address(-start);111}112113bool __init olpc_ofw_is_installed(void)114{115return olpc_ofw_cif != NULL;116}117118119