linux/arch/x86/platform/olpc/olpc_dt.c
<<
>>
Prefs
   1/*
   2 * OLPC-specific OFW device tree support code.
   3 *
   4 * Paul Mackerras       August 1996.
   5 * Copyright (C) 1996-2005 Paul Mackerras.
   6 *
   7 *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
   8 *    {engebret|bergner}@us.ibm.com
   9 *
  10 *  Adapted for sparc by David S. Miller davem@davemloft.net
  11 *  Adapted for x86/OLPC by Andres Salomon <dilinger@queued.net>
  12 *
  13 *      This program is free software; you can redistribute it and/or
  14 *      modify it under the terms of the GNU General Public License
  15 *      as published by the Free Software Foundation; either version
  16 *      2 of the License, or (at your option) any later version.
  17 */
  18
  19#include <linux/kernel.h>
  20#include <linux/bootmem.h>
  21#include <linux/of.h>
  22#include <linux/of_pdt.h>
  23#include <asm/olpc_ofw.h>
  24
  25static phandle __init olpc_dt_getsibling(phandle node)
  26{
  27        const void *args[] = { (void *)node };
  28        void *res[] = { &node };
  29
  30        if ((s32)node == -1)
  31                return 0;
  32
  33        if (olpc_ofw("peer", args, res) || (s32)node == -1)
  34                return 0;
  35
  36        return node;
  37}
  38
  39static phandle __init olpc_dt_getchild(phandle node)
  40{
  41        const void *args[] = { (void *)node };
  42        void *res[] = { &node };
  43
  44        if ((s32)node == -1)
  45                return 0;
  46
  47        if (olpc_ofw("child", args, res) || (s32)node == -1) {
  48                pr_err("PROM: %s: fetching child failed!\n", __func__);
  49                return 0;
  50        }
  51
  52        return node;
  53}
  54
  55static int __init olpc_dt_getproplen(phandle node, const char *prop)
  56{
  57        const void *args[] = { (void *)node, prop };
  58        int len;
  59        void *res[] = { &len };
  60
  61        if ((s32)node == -1)
  62                return -1;
  63
  64        if (olpc_ofw("getproplen", args, res)) {
  65                pr_err("PROM: %s: getproplen failed!\n", __func__);
  66                return -1;
  67        }
  68
  69        return len;
  70}
  71
  72static int __init olpc_dt_getproperty(phandle node, const char *prop,
  73                char *buf, int bufsize)
  74{
  75        int plen;
  76
  77        plen = olpc_dt_getproplen(node, prop);
  78        if (plen > bufsize || plen < 1) {
  79                return -1;
  80        } else {
  81                const void *args[] = { (void *)node, prop, buf, (void *)plen };
  82                void *res[] = { &plen };
  83
  84                if (olpc_ofw("getprop", args, res)) {
  85                        pr_err("PROM: %s: getprop failed!\n", __func__);
  86                        return -1;
  87                }
  88        }
  89
  90        return plen;
  91}
  92
  93static int __init olpc_dt_nextprop(phandle node, char *prev, char *buf)
  94{
  95        const void *args[] = { (void *)node, prev, buf };
  96        int success;
  97        void *res[] = { &success };
  98
  99        buf[0] = '\0';
 100
 101        if ((s32)node == -1)
 102                return -1;
 103
 104        if (olpc_ofw("nextprop", args, res) || success != 1)
 105                return -1;
 106
 107        return 0;
 108}
 109
 110static int __init olpc_dt_pkg2path(phandle node, char *buf,
 111                const int buflen, int *len)
 112{
 113        const void *args[] = { (void *)node, buf, (void *)buflen };
 114        void *res[] = { len };
 115
 116        if ((s32)node == -1)
 117                return -1;
 118
 119        if (olpc_ofw("package-to-path", args, res) || *len < 1)
 120                return -1;
 121
 122        return 0;
 123}
 124
 125static unsigned int prom_early_allocated __initdata;
 126
 127void * __init prom_early_alloc(unsigned long size)
 128{
 129        static u8 *mem;
 130        static size_t free_mem;
 131        void *res;
 132
 133        if (free_mem < size) {
 134                const size_t chunk_size = max(PAGE_SIZE, size);
 135
 136                /*
 137                 * To mimimize the number of allocations, grab at least
 138                 * PAGE_SIZE of memory (that's an arbitrary choice that's
 139                 * fast enough on the platforms we care about while minimizing
 140                 * wasted bootmem) and hand off chunks of it to callers.
 141                 */
 142                res = alloc_bootmem(chunk_size);
 143                BUG_ON(!res);
 144                prom_early_allocated += chunk_size;
 145                memset(res, 0, chunk_size);
 146                free_mem = chunk_size;
 147                mem = res;
 148        }
 149
 150        /* allocate from the local cache */
 151        free_mem -= size;
 152        res = mem;
 153        mem += size;
 154        return res;
 155}
 156
 157static struct of_pdt_ops prom_olpc_ops __initdata = {
 158        .nextprop = olpc_dt_nextprop,
 159        .getproplen = olpc_dt_getproplen,
 160        .getproperty = olpc_dt_getproperty,
 161        .getchild = olpc_dt_getchild,
 162        .getsibling = olpc_dt_getsibling,
 163        .pkg2path = olpc_dt_pkg2path,
 164};
 165
 166void __init olpc_dt_build_devicetree(void)
 167{
 168        phandle root;
 169
 170        if (!olpc_ofw_is_installed())
 171                return;
 172
 173        root = olpc_dt_getsibling(0);
 174        if (!root) {
 175                pr_err("PROM: unable to get root node from OFW!\n");
 176                return;
 177        }
 178        of_pdt_build_devicetree(root, &prom_olpc_ops);
 179
 180        pr_info("PROM DT: Built device tree with %u bytes of memory.\n",
 181                        prom_early_allocated);
 182}
 183