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

yamon-dt.c (5751B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2016 Imagination Technologies
      4 * Author: Paul Burton <paul.burton@mips.com>
      5 */
      6
      7#define pr_fmt(fmt) "yamon-dt: " fmt
      8
      9#include <linux/bug.h>
     10#include <linux/errno.h>
     11#include <linux/kernel.h>
     12#include <linux/libfdt.h>
     13#include <linux/printk.h>
     14
     15#include <asm/fw/fw.h>
     16#include <asm/yamon-dt.h>
     17
     18#define MAX_MEM_ARRAY_ENTRIES	2
     19
     20__init int yamon_dt_append_cmdline(void *fdt)
     21{
     22	int err, chosen_off;
     23
     24	/* find or add chosen node */
     25	chosen_off = fdt_path_offset(fdt, "/chosen");
     26	if (chosen_off == -FDT_ERR_NOTFOUND)
     27		chosen_off = fdt_add_subnode(fdt, 0, "chosen");
     28	if (chosen_off < 0) {
     29		pr_err("Unable to find or add DT chosen node: %d\n",
     30		       chosen_off);
     31		return chosen_off;
     32	}
     33
     34	err = fdt_setprop_string(fdt, chosen_off, "bootargs", fw_getcmdline());
     35	if (err) {
     36		pr_err("Unable to set bootargs property: %d\n", err);
     37		return err;
     38	}
     39
     40	return 0;
     41}
     42
     43static unsigned int __init gen_fdt_mem_array(
     44					const struct yamon_mem_region *regions,
     45					__be32 *mem_array,
     46					unsigned int max_entries,
     47					unsigned long memsize)
     48{
     49	const struct yamon_mem_region *mr;
     50	unsigned long size;
     51	unsigned int entries = 0;
     52
     53	for (mr = regions; mr->size && memsize; ++mr) {
     54		if (entries >= max_entries) {
     55			pr_warn("Number of regions exceeds max %u\n",
     56				max_entries);
     57			break;
     58		}
     59
     60		/* How much of the remaining RAM fits in the next region? */
     61		size = min_t(unsigned long, memsize, mr->size);
     62		memsize -= size;
     63
     64		/* Emit a memory region */
     65		*(mem_array++) = cpu_to_be32(mr->start);
     66		*(mem_array++) = cpu_to_be32(size);
     67		++entries;
     68
     69		/* Discard the next mr->discard bytes */
     70		memsize -= min_t(unsigned long, memsize, mr->discard);
     71	}
     72	return entries;
     73}
     74
     75__init int yamon_dt_append_memory(void *fdt,
     76				  const struct yamon_mem_region *regions)
     77{
     78	unsigned long phys_memsize = 0, memsize;
     79	__be32 mem_array[2 * MAX_MEM_ARRAY_ENTRIES];
     80	unsigned int mem_entries;
     81	int i, err, mem_off;
     82	char *var, param_name[10], *var_names[] = {
     83		"ememsize", "memsize",
     84	};
     85
     86	/* find memory size from the bootloader environment */
     87	for (i = 0; i < ARRAY_SIZE(var_names); i++) {
     88		var = fw_getenv(var_names[i]);
     89		if (!var)
     90			continue;
     91
     92		err = kstrtoul(var, 0, &phys_memsize);
     93		if (!err)
     94			break;
     95
     96		pr_warn("Failed to read the '%s' env variable '%s'\n",
     97			var_names[i], var);
     98	}
     99
    100	if (!phys_memsize) {
    101		pr_warn("The bootloader didn't provide memsize: defaulting to 32MB\n");
    102		phys_memsize = 32 << 20;
    103	}
    104
    105	/* default to using all available RAM */
    106	memsize = phys_memsize;
    107
    108	/* allow the user to override the usable memory */
    109	for (i = 0; i < ARRAY_SIZE(var_names); i++) {
    110		snprintf(param_name, sizeof(param_name), "%s=", var_names[i]);
    111		var = strstr(arcs_cmdline, param_name);
    112		if (!var)
    113			continue;
    114
    115		memsize = memparse(var + strlen(param_name), NULL);
    116	}
    117
    118	/* if the user says there's more RAM than we thought, believe them */
    119	phys_memsize = max_t(unsigned long, phys_memsize, memsize);
    120
    121	/* find or add a memory node */
    122	mem_off = fdt_path_offset(fdt, "/memory");
    123	if (mem_off == -FDT_ERR_NOTFOUND)
    124		mem_off = fdt_add_subnode(fdt, 0, "memory");
    125	if (mem_off < 0) {
    126		pr_err("Unable to find or add memory DT node: %d\n", mem_off);
    127		return mem_off;
    128	}
    129
    130	err = fdt_setprop_string(fdt, mem_off, "device_type", "memory");
    131	if (err) {
    132		pr_err("Unable to set memory node device_type: %d\n", err);
    133		return err;
    134	}
    135
    136	mem_entries = gen_fdt_mem_array(regions, mem_array,
    137					MAX_MEM_ARRAY_ENTRIES, phys_memsize);
    138	err = fdt_setprop(fdt, mem_off, "reg",
    139			  mem_array, mem_entries * 2 * sizeof(mem_array[0]));
    140	if (err) {
    141		pr_err("Unable to set memory regs property: %d\n", err);
    142		return err;
    143	}
    144
    145	mem_entries = gen_fdt_mem_array(regions, mem_array,
    146					MAX_MEM_ARRAY_ENTRIES, memsize);
    147	err = fdt_setprop(fdt, mem_off, "linux,usable-memory",
    148			  mem_array, mem_entries * 2 * sizeof(mem_array[0]));
    149	if (err) {
    150		pr_err("Unable to set linux,usable-memory property: %d\n", err);
    151		return err;
    152	}
    153
    154	return 0;
    155}
    156
    157__init int yamon_dt_serial_config(void *fdt)
    158{
    159	const char *yamontty, *mode_var;
    160	char mode_var_name[9], path[20], parity;
    161	unsigned int uart, baud, stop_bits;
    162	bool hw_flow;
    163	int chosen_off, err;
    164
    165	yamontty = fw_getenv("yamontty");
    166	if (!yamontty || !strcmp(yamontty, "tty0")) {
    167		uart = 0;
    168	} else if (!strcmp(yamontty, "tty1")) {
    169		uart = 1;
    170	} else {
    171		pr_warn("yamontty environment variable '%s' invalid\n",
    172			yamontty);
    173		uart = 0;
    174	}
    175
    176	baud = stop_bits = 0;
    177	parity = 0;
    178	hw_flow = false;
    179
    180	snprintf(mode_var_name, sizeof(mode_var_name), "modetty%u", uart);
    181	mode_var = fw_getenv(mode_var_name);
    182	if (mode_var) {
    183		while (mode_var[0] >= '0' && mode_var[0] <= '9') {
    184			baud *= 10;
    185			baud += mode_var[0] - '0';
    186			mode_var++;
    187		}
    188		if (mode_var[0] == ',')
    189			mode_var++;
    190		if (mode_var[0])
    191			parity = mode_var[0];
    192		if (mode_var[0] == ',')
    193			mode_var++;
    194		if (mode_var[0])
    195			stop_bits = mode_var[0] - '0';
    196		if (mode_var[0] == ',')
    197			mode_var++;
    198		if (!strcmp(mode_var, "hw"))
    199			hw_flow = true;
    200	}
    201
    202	if (!baud)
    203		baud = 38400;
    204
    205	if (parity != 'e' && parity != 'n' && parity != 'o')
    206		parity = 'n';
    207
    208	if (stop_bits != 7 && stop_bits != 8)
    209		stop_bits = 8;
    210
    211	WARN_ON(snprintf(path, sizeof(path), "serial%u:%u%c%u%s",
    212			 uart, baud, parity, stop_bits,
    213			 hw_flow ? "r" : "") >= sizeof(path));
    214
    215	/* find or add chosen node */
    216	chosen_off = fdt_path_offset(fdt, "/chosen");
    217	if (chosen_off == -FDT_ERR_NOTFOUND)
    218		chosen_off = fdt_add_subnode(fdt, 0, "chosen");
    219	if (chosen_off < 0) {
    220		pr_err("Unable to find or add DT chosen node: %d\n",
    221		       chosen_off);
    222		return chosen_off;
    223	}
    224
    225	err = fdt_setprop_string(fdt, chosen_off, "stdout-path", path);
    226	if (err) {
    227		pr_err("Unable to set stdout-path property: %d\n", err);
    228		return err;
    229	}
    230
    231	return 0;
    232}