cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

olpc_dt.c (7275B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * OLPC-specific OFW device tree support code.
      4 *
      5 * Paul Mackerras	August 1996.
      6 * Copyright (C) 1996-2005 Paul Mackerras.
      7 *
      8 *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
      9 *    {engebret|bergner}@us.ibm.com
     10 *
     11 *  Adapted for sparc by David S. Miller davem@davemloft.net
     12 *  Adapted for x86/OLPC by Andres Salomon <dilinger@queued.net>
     13 */
     14
     15#include <linux/kernel.h>
     16#include <linux/memblock.h>
     17#include <linux/of.h>
     18#include <linux/of_pdt.h>
     19#include <asm/olpc.h>
     20#include <asm/olpc_ofw.h>
     21
     22static phandle __init olpc_dt_getsibling(phandle node)
     23{
     24	const void *args[] = { (void *)node };
     25	void *res[] = { &node };
     26
     27	if ((s32)node == -1)
     28		return 0;
     29
     30	if (olpc_ofw("peer", args, res) || (s32)node == -1)
     31		return 0;
     32
     33	return node;
     34}
     35
     36static phandle __init olpc_dt_getchild(phandle node)
     37{
     38	const void *args[] = { (void *)node };
     39	void *res[] = { &node };
     40
     41	if ((s32)node == -1)
     42		return 0;
     43
     44	if (olpc_ofw("child", args, res) || (s32)node == -1) {
     45		pr_err("PROM: %s: fetching child failed!\n", __func__);
     46		return 0;
     47	}
     48
     49	return node;
     50}
     51
     52static int __init olpc_dt_getproplen(phandle node, const char *prop)
     53{
     54	const void *args[] = { (void *)node, prop };
     55	int len;
     56	void *res[] = { &len };
     57
     58	if ((s32)node == -1)
     59		return -1;
     60
     61	if (olpc_ofw("getproplen", args, res)) {
     62		pr_err("PROM: %s: getproplen failed!\n", __func__);
     63		return -1;
     64	}
     65
     66	return len;
     67}
     68
     69static int __init olpc_dt_getproperty(phandle node, const char *prop,
     70		char *buf, int bufsize)
     71{
     72	int plen;
     73
     74	plen = olpc_dt_getproplen(node, prop);
     75	if (plen > bufsize || plen < 1) {
     76		return -1;
     77	} else {
     78		const void *args[] = { (void *)node, prop, buf, (void *)plen };
     79		void *res[] = { &plen };
     80
     81		if (olpc_ofw("getprop", args, res)) {
     82			pr_err("PROM: %s: getprop failed!\n", __func__);
     83			return -1;
     84		}
     85	}
     86
     87	return plen;
     88}
     89
     90static int __init olpc_dt_nextprop(phandle node, char *prev, char *buf)
     91{
     92	const void *args[] = { (void *)node, prev, buf };
     93	int success;
     94	void *res[] = { &success };
     95
     96	buf[0] = '\0';
     97
     98	if ((s32)node == -1)
     99		return -1;
    100
    101	if (olpc_ofw("nextprop", args, res) || success != 1)
    102		return -1;
    103
    104	return 0;
    105}
    106
    107static int __init olpc_dt_pkg2path(phandle node, char *buf,
    108		const int buflen, int *len)
    109{
    110	const void *args[] = { (void *)node, buf, (void *)buflen };
    111	void *res[] = { len };
    112
    113	if ((s32)node == -1)
    114		return -1;
    115
    116	if (olpc_ofw("package-to-path", args, res) || *len < 1)
    117		return -1;
    118
    119	return 0;
    120}
    121
    122static unsigned int prom_early_allocated __initdata;
    123
    124void * __init prom_early_alloc(unsigned long size)
    125{
    126	static u8 *mem;
    127	static size_t free_mem;
    128	void *res;
    129
    130	if (free_mem < size) {
    131		const size_t chunk_size = max(PAGE_SIZE, size);
    132
    133		/*
    134		 * To minimize the number of allocations, grab at least
    135		 * PAGE_SIZE of memory (that's an arbitrary choice that's
    136		 * fast enough on the platforms we care about while minimizing
    137		 * wasted bootmem) and hand off chunks of it to callers.
    138		 */
    139		res = memblock_alloc(chunk_size, SMP_CACHE_BYTES);
    140		if (!res)
    141			panic("%s: Failed to allocate %zu bytes\n", __func__,
    142			      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
    166static phandle __init olpc_dt_finddevice(const char *path)
    167{
    168	phandle node;
    169	const void *args[] = { path };
    170	void *res[] = { &node };
    171
    172	if (olpc_ofw("finddevice", args, res)) {
    173		pr_err("olpc_dt: finddevice failed!\n");
    174		return 0;
    175	}
    176
    177	if ((s32) node == -1)
    178		return 0;
    179
    180	return node;
    181}
    182
    183static int __init olpc_dt_interpret(const char *words)
    184{
    185	int result;
    186	const void *args[] = { words };
    187	void *res[] = { &result };
    188
    189	if (olpc_ofw("interpret", args, res)) {
    190		pr_err("olpc_dt: interpret failed!\n");
    191		return -1;
    192	}
    193
    194	return result;
    195}
    196
    197/*
    198 * Extract board revision directly from OFW device tree.
    199 * We can't use olpc_platform_info because that hasn't been set up yet.
    200 */
    201static u32 __init olpc_dt_get_board_revision(void)
    202{
    203	phandle node;
    204	__be32 rev;
    205	int r;
    206
    207	node = olpc_dt_finddevice("/");
    208	if (!node)
    209		return 0;
    210
    211	r = olpc_dt_getproperty(node, "board-revision-int",
    212				(char *) &rev, sizeof(rev));
    213	if (r < 0)
    214		return 0;
    215
    216	return be32_to_cpu(rev);
    217}
    218
    219static int __init olpc_dt_compatible_match(phandle node, const char *compat)
    220{
    221	char buf[64], *p;
    222	int plen, len;
    223
    224	plen = olpc_dt_getproperty(node, "compatible", buf, sizeof(buf));
    225	if (plen <= 0)
    226		return 0;
    227
    228	len = strlen(compat);
    229	for (p = buf; p < buf + plen; p += strlen(p) + 1) {
    230		if (strcmp(p, compat) == 0)
    231			return 1;
    232	}
    233
    234	return 0;
    235}
    236
    237void __init olpc_dt_fixup(void)
    238{
    239	phandle node;
    240	u32 board_rev;
    241
    242	node = olpc_dt_finddevice("/battery@0");
    243	if (!node)
    244		return;
    245
    246	board_rev = olpc_dt_get_board_revision();
    247	if (!board_rev)
    248		return;
    249
    250	if (board_rev >= olpc_board_pre(0xd0)) {
    251		/* XO-1.5 */
    252
    253		if (olpc_dt_compatible_match(node, "olpc,xo1.5-battery"))
    254			return;
    255
    256		/* Add olpc,xo1.5-battery compatible marker to battery node */
    257		olpc_dt_interpret("\" /battery@0\" find-device");
    258		olpc_dt_interpret("  \" olpc,xo1.5-battery\" +compatible");
    259		olpc_dt_interpret("device-end");
    260
    261		if (olpc_dt_compatible_match(node, "olpc,xo1-battery")) {
    262			/*
    263			 * If we have a olpc,xo1-battery compatible, then we're
    264			 * running a new enough firmware that already has
    265			 * the dcon node.
    266			 */
    267			return;
    268		}
    269
    270		/* Add dcon device */
    271		olpc_dt_interpret("\" /pci/display@1\" find-device");
    272		olpc_dt_interpret("  new-device");
    273		olpc_dt_interpret("    \" dcon\" device-name");
    274		olpc_dt_interpret("    \" olpc,xo1-dcon\" +compatible");
    275		olpc_dt_interpret("  finish-device");
    276		olpc_dt_interpret("device-end");
    277	} else {
    278		/* XO-1 */
    279
    280		if (olpc_dt_compatible_match(node, "olpc,xo1-battery")) {
    281			/*
    282			 * If we have a olpc,xo1-battery compatible, then we're
    283			 * running a new enough firmware that already has
    284			 * the dcon and RTC nodes.
    285			 */
    286			return;
    287		}
    288
    289		/* Add dcon device, mark RTC as olpc,xo1-rtc */
    290		olpc_dt_interpret("\" /pci/display@1,1\" find-device");
    291		olpc_dt_interpret("  new-device");
    292		olpc_dt_interpret("    \" dcon\" device-name");
    293		olpc_dt_interpret("    \" olpc,xo1-dcon\" +compatible");
    294		olpc_dt_interpret("  finish-device");
    295		olpc_dt_interpret("device-end");
    296
    297		olpc_dt_interpret("\" /rtc\" find-device");
    298		olpc_dt_interpret(" \" olpc,xo1-rtc\" +compatible");
    299		olpc_dt_interpret("device-end");
    300	}
    301
    302	/* Add olpc,xo1-battery compatible marker to battery node */
    303	olpc_dt_interpret("\" /battery@0\" find-device");
    304	olpc_dt_interpret("  \" olpc,xo1-battery\" +compatible");
    305	olpc_dt_interpret("device-end");
    306}
    307
    308void __init olpc_dt_build_devicetree(void)
    309{
    310	phandle root;
    311
    312	if (!olpc_ofw_is_installed())
    313		return;
    314
    315	olpc_dt_fixup();
    316
    317	root = olpc_dt_getsibling(0);
    318	if (!root) {
    319		pr_err("PROM: unable to get root node from OFW!\n");
    320		return;
    321	}
    322	of_pdt_build_devicetree(root, &prom_olpc_ops);
    323
    324	pr_info("PROM DT: Built device tree with %u bytes of memory.\n",
    325			prom_early_allocated);
    326}