Merge remote-tracking branch 'lsk/v3.10/topic/libfdt' into linux-linaro-lsk

Conflicts:
	drivers/of/fdt.c
This commit is contained in:
Mark Brown
2014-07-24 22:54:49 +01:00
25 changed files with 709 additions and 227 deletions

View File

@@ -40,7 +40,7 @@ struct machine_desc * __init setup_machine_fdt(void *dt)
const char *model, *compat;
void *clk;
char manufacturer[16];
unsigned long len;
int len;
/* check device tree validity */
if (be32_to_cpu(devtree->magic) != OF_DT_HEADER)

View File

@@ -212,7 +212,7 @@ struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
}
if (!mdesc_best) {
const char *prop;
long size;
int size;
early_print("\nError: unrecognized/unsupported "
"device tree compatible list:\n[ ");

View File

@@ -53,7 +53,7 @@ static int __init vexpress_dt_find_scu(unsigned long node,
{
if (of_flat_dt_match(node, vexpress_dt_cortex_a9_match)) {
phys_addr_t phys_addr;
__be32 *reg = of_get_flat_dt_prop(node, "reg", NULL);
const __be32 *reg = of_get_flat_dt_prop(node, "reg", NULL);
if (WARN_ON(!reg))
return -EINVAL;

View File

@@ -116,8 +116,8 @@ device_initcall(s5p_mfc_memory_init);
int __init s5p_fdt_find_mfc_mem(unsigned long node, const char *uname,
int depth, void *data)
{
__be32 *prop;
unsigned long len;
const __be32 *prop;
int len;
struct s5p_mfc_dt_meminfo *mfc_mem = data;
if (!data)

View File

@@ -52,13 +52,13 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
}
#ifdef CONFIG_EARLY_PRINTK
static char *stdout;
static const char *stdout;
static int __init early_init_dt_scan_chosen_serial(unsigned long node,
const char *uname, int depth, void *data)
{
unsigned long l;
char *p;
int l;
const char *p;
pr_debug("%s: depth: %d, uname: %s\n", __func__, depth, uname);
@@ -89,7 +89,7 @@ static int __init early_init_dt_scan_chosen_serial(unsigned long node,
(strncmp(p, "xlnx,opb-uartlite", 17) == 0) ||
(strncmp(p, "xlnx,axi-uartlite", 17) == 0) ||
(strncmp(p, "xlnx,mdm", 8) == 0)) {
unsigned int *addrp;
const unsigned int *addrp;
*(u32 *)data = UARTLITE;

View File

@@ -55,9 +55,9 @@ int crash_mem_ranges;
int __init early_init_dt_scan_fw_dump(unsigned long node,
const char *uname, int depth, void *data)
{
__be32 *sections;
const __be32 *sections;
int i, num_sections;
unsigned long size;
int size;
const int *token;
if (depth != 1 || strcmp(uname, "rtas") != 0)

View File

@@ -162,7 +162,7 @@ static struct ibm_pa_feature {
{CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0},
};
static void __init scan_features(unsigned long node, unsigned char *ftrs,
static void __init scan_features(unsigned long node, const unsigned char *ftrs,
unsigned long tablelen,
struct ibm_pa_feature *fp,
unsigned long ft_size)
@@ -201,8 +201,8 @@ static void __init scan_features(unsigned long node, unsigned char *ftrs,
static void __init check_cpu_pa_features(unsigned long node)
{
unsigned char *pa_ftrs;
unsigned long tablelen;
const unsigned char *pa_ftrs;
int tablelen;
pa_ftrs = of_get_flat_dt_prop(node, "ibm,pa-features", &tablelen);
if (pa_ftrs == NULL)
@@ -215,7 +215,7 @@ static void __init check_cpu_pa_features(unsigned long node)
#ifdef CONFIG_PPC_STD_MMU_64
static void __init check_cpu_slb_size(unsigned long node)
{
u32 *slb_size_ptr;
const __be32 *slb_size_ptr;
slb_size_ptr = of_get_flat_dt_prop(node, "slb-size", NULL);
if (slb_size_ptr != NULL) {
@@ -256,7 +256,7 @@ static struct feature_property {
static inline void identical_pvr_fixup(unsigned long node)
{
unsigned int pvr;
char *model = of_get_flat_dt_prop(node, "model", NULL);
const char *model = of_get_flat_dt_prop(node, "model", NULL);
/*
* Since 440GR(x)/440EP(x) processors have the same pvr,
@@ -294,11 +294,11 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
const char *uname, int depth,
void *data)
{
char *type = of_get_flat_dt_prop(node, "device_type", NULL);
const u32 *prop;
const u32 *intserv;
const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
const __be32 *prop;
const __be32 *intserv;
int i, nthreads;
unsigned long len;
int len;
int found = -1;
int found_thread = 0;
@@ -389,7 +389,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
int __init early_init_dt_scan_chosen_ppc(unsigned long node, const char *uname,
int depth, void *data)
{
unsigned long *lprop;
const unsigned long *lprop; /* All these set by kernel, so no need to convert endian */
/* Use common scan routine to determine if this is the chosen node */
if (early_init_dt_scan_chosen(node, uname, depth, data) == 0)
@@ -440,8 +440,9 @@ int __init early_init_dt_scan_chosen_ppc(unsigned long node, const char *uname,
*/
static int __init early_init_dt_scan_drconf_memory(unsigned long node)
{
__be32 *dm, *ls, *usm;
unsigned long l, n, flags;
const __be32 *dm, *ls, *usm;
int l;
unsigned long n, flags;
u64 base, size, memblock_size;
unsigned int is_kexec_kdump = 0, rngs;

View File

@@ -1135,7 +1135,7 @@ void __init rtas_initialize(void)
int __init early_init_dt_scan_rtas(unsigned long node,
const char *uname, int depth, void *data)
{
u32 *basep, *entryp, *sizep;
const u32 *basep, *entryp, *sizep;
if (depth != 1 || strcmp(uname, "rtas") != 0)
return 0;

View File

@@ -250,9 +250,9 @@ static int __init htab_dt_scan_seg_sizes(unsigned long node,
const char *uname, int depth,
void *data)
{
char *type = of_get_flat_dt_prop(node, "device_type", NULL);
u32 *prop;
unsigned long size = 0;
const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
const __be32 *prop;
int size = 0;
/* We are scanning "cpu" nodes only */
if (type == NULL || strcmp(type, "cpu") != 0)
@@ -306,9 +306,9 @@ static int __init htab_dt_scan_page_sizes(unsigned long node,
const char *uname, int depth,
void *data)
{
char *type = of_get_flat_dt_prop(node, "device_type", NULL);
u32 *prop;
unsigned long size = 0;
const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
const __be32 *prop;
int size = 0;
/* We are scanning "cpu" nodes only */
if (type == NULL || strcmp(type, "cpu") != 0)
@@ -389,9 +389,9 @@ static int __init htab_dt_scan_page_sizes(unsigned long node,
static int __init htab_dt_scan_hugepage_blocks(unsigned long node,
const char *uname, int depth,
void *data) {
char *type = of_get_flat_dt_prop(node, "device_type", NULL);
unsigned long *addr_prop;
u32 *page_count_prop;
const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
const __be64 *addr_prop;
const __be32 *page_count_prop;
unsigned int expected_pages;
long unsigned int phys_addr;
long unsigned int block_size;
@@ -533,8 +533,8 @@ static int __init htab_dt_scan_pftsize(unsigned long node,
const char *uname, int depth,
void *data)
{
char *type = of_get_flat_dt_prop(node, "device_type", NULL);
u32 *prop;
const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
const __be32 *prop;
/* We are scanning "cpu" nodes only */
if (type == NULL || strcmp(type, "cpu") != 0)

View File

@@ -199,8 +199,8 @@ static void __init efika_setup_arch(void)
static int __init efika_probe(void)
{
char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
"model", NULL);
const char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
"model", NULL);
if (model == NULL)
return 0;

View File

@@ -574,8 +574,8 @@ chrp_init2(void)
static int __init chrp_probe(void)
{
char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(),
"device_type", NULL);
const char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(),
"device_type", NULL);
if (dtype == NULL)
return 0;
if (strcmp(dtype, "chrp"))

View File

@@ -35,8 +35,8 @@ static unsigned int opal_irq_count;
int __init early_init_dt_scan_opal(unsigned long node,
const char *uname, int depth, void *data)
{
const void *basep, *entryp;
unsigned long basesz, entrysz;
const void *basep, *entryp, *sizep;
int basesz, entrysz, runtimesz;
if (depth != 1 || strcmp(uname, "ibm,opal") != 0)
return 0;
@@ -50,10 +50,10 @@ int __init early_init_dt_scan_opal(unsigned long node,
opal.base = of_read_number(basep, basesz/4);
opal.entry = of_read_number(entryp, entrysz/4);
pr_debug("OPAL Base = 0x%llx (basep=%p basesz=%ld)\n",
pr_debug("OPAL Base = 0x%llx (basep=%p basesz=%d)\n",
opal.base, basep, basesz);
pr_debug("OPAL Entry = 0x%llx (entryp=%p basesz=%ld)\n",
opal.entry, entryp, entrysz);
pr_debug("OPAL Entry = 0x%llx (sizep=%p runtimesz=%d)\n",
opal.size, sizep, runtimesz);
powerpc_firmware_features |= FW_FEATURE_OPAL;
if (of_flat_dt_is_compatible(node, "ibm,opal-v3")) {
@@ -105,7 +105,7 @@ int opal_get_chars(uint32_t vtermno, char *buf, int count)
opal_poll_events(&evt);
if ((evt & OPAL_EVENT_CONSOLE_INPUT) == 0)
return 0;
len = count;
len = cpu_to_be64(count);
rc = opal_console_read(vtermno, &len, buf);
if (rc == OPAL_SUCCESS)
return len;

View File

@@ -646,7 +646,7 @@ static int __init pseries_probe_fw_features(unsigned long node,
void *data)
{
const char *prop;
unsigned long len;
int len;
static int hypertas_found;
static int vec5_found;
@@ -679,7 +679,7 @@ static int __init pseries_probe_fw_features(unsigned long node,
static int __init pSeries_probe(void)
{
unsigned long root = of_get_flat_dt_root();
char *dtype = of_get_flat_dt_prop(root, "device_type", NULL);
const char *dtype = of_get_flat_dt_prop(root, "device_type", NULL);
if (dtype == NULL)
return 0;

View File

@@ -222,6 +222,43 @@ static int __init parse_bootparam(const bp_tag_t* tag)
}
#ifdef CONFIG_OF
bool __initdata dt_memory_scan = false;
#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY
unsigned long xtensa_kio_paddr = XCHAL_KIO_DEFAULT_PADDR;
EXPORT_SYMBOL(xtensa_kio_paddr);
static int __init xtensa_dt_io_area(unsigned long node, const char *uname,
int depth, void *data)
{
const __be32 *ranges;
int len;
if (depth > 1)
return 0;
if (!of_flat_dt_is_compatible(node, "simple-bus"))
return 0;
ranges = of_get_flat_dt_prop(node, "ranges", &len);
if (!ranges)
return 1;
if (len == 0)
return 1;
xtensa_kio_paddr = of_read_ulong(ranges+1, 1);
/* round down to nearest 256MB boundary */
xtensa_kio_paddr &= 0xf0000000;
return 1;
}
#else
static int __init xtensa_dt_io_area(unsigned long node, const char *uname,
int depth, void *data)
{
return 1;
}
#endif
void __init early_init_dt_add_memory_arch(u64 base, u64 size)
{

View File

@@ -27,6 +27,7 @@ config OF_SELFTEST
config OF_FLATTREE
bool
select DTC
select LIBFDT
config OF_EARLY_FLATTREE
bool
@@ -83,4 +84,10 @@ config OF_MTD
depends on MTD
def_bool y
config OF_RESERVED_MEM
depends on OF_EARLY_FLATTREE
bool
help
Helpers to allow for reservation of memory regions
endmenu # OF

View File

@@ -11,3 +11,6 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o
obj-$(CONFIG_OF_PCI) += of_pci.o
obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
obj-$(CONFIG_OF_MTD) += of_mtd.o
obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
CFLAGS_fdt.o = -I$(src)/../../scripts/dtc/libfdt

View File

@@ -33,6 +33,7 @@ struct device_node *of_allnodes;
EXPORT_SYMBOL(of_allnodes);
struct device_node *of_chosen;
struct device_node *of_aliases;
static struct device_node *of_stdout;
DEFINE_MUTEX(of_aliases_mutex);
@@ -1690,6 +1691,15 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
of_chosen = of_find_node_by_path("/chosen");
if (of_chosen == NULL)
of_chosen = of_find_node_by_path("/chosen@0");
if (of_chosen) {
const char *name;
name = of_get_property(of_chosen, "linux,stdout-path", NULL);
if (name)
of_stdout = of_find_node_by_path(name);
}
of_aliases = of_find_node_by_path("/aliases");
if (!of_aliases)
return;
@@ -1799,3 +1809,19 @@ const char *of_prop_next_string(struct property *prop, const char *cur)
return curv;
}
EXPORT_SYMBOL_GPL(of_prop_next_string);
/**
* of_device_is_stdout_path - check if a device node matches the
* linux,stdout-path property
*
* Check if this device node matches the linux,stdout-path property
* in the chosen node. return true if yes, false otherwise.
*/
int of_device_is_stdout_path(struct device_node *dn)
{
if (!of_stdout)
return false;
return of_stdout == dn;
}
EXPORT_SYMBOL_GPL(of_device_is_stdout_path);

View File

@@ -14,9 +14,13 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_reserved_mem.h>
#include <linux/sizes.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/memblock.h>
#include <linux/libfdt.h>
#include <asm/setup.h> /* for COMMAND_LINE_SIZE */
#ifdef CONFIG_PPC
@@ -25,54 +29,6 @@
#include <asm/page.h>
char *of_fdt_get_string(struct boot_param_header *blob, u32 offset)
{
return ((char *)blob) +
be32_to_cpu(blob->off_dt_strings) + offset;
}
/**
* of_fdt_get_property - Given a node in the given flat blob, return
* the property ptr
*/
void *of_fdt_get_property(struct boot_param_header *blob,
unsigned long node, const char *name,
unsigned long *size)
{
unsigned long p = node;
do {
u32 tag = be32_to_cpup((__be32 *)p);
u32 sz, noff;
const char *nstr;
p += 4;
if (tag == OF_DT_NOP)
continue;
if (tag != OF_DT_PROP)
return NULL;
sz = be32_to_cpup((__be32 *)p);
noff = be32_to_cpup((__be32 *)(p + 4));
p += 8;
if (be32_to_cpu(blob->version) < 0x10)
p = ALIGN(p, sz >= 8 ? 8 : 4);
nstr = of_fdt_get_string(blob, noff);
if (nstr == NULL) {
pr_warning("Can't find property index name !\n");
return NULL;
}
if (strcmp(name, nstr) == 0) {
if (size)
*size = sz;
return (void *)p;
}
p += sz;
p = ALIGN(p, 4);
} while (1);
}
/**
* of_fdt_is_compatible - Return true if given node from the given blob has
* compat in its compatible list
@@ -87,9 +43,10 @@ int of_fdt_is_compatible(struct boot_param_header *blob,
unsigned long node, const char *compat)
{
const char *cp;
unsigned long cplen, l, score = 0;
int cplen;
unsigned long l, score = 0;
cp = of_fdt_get_property(blob, node, "compatible", &cplen);
cp = fdt_getprop(blob, node, "compatible", &cplen);
if (cp == NULL)
return 0;
while (cplen > 0) {
@@ -125,12 +82,12 @@ int of_fdt_match(struct boot_param_header *blob, unsigned long node,
return score;
}
static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size,
static void *unflatten_dt_alloc(void **mem, unsigned long size,
unsigned long align)
{
void *res;
*mem = ALIGN(*mem, align);
*mem = PTR_ALIGN(*mem, align);
res = (void *)*mem;
*mem += size;
@@ -146,30 +103,29 @@ static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size,
* @allnextpp: pointer to ->allnext from last allocated device_node
* @fpsize: Size of the node path up at the current depth.
*/
static unsigned long unflatten_dt_node(struct boot_param_header *blob,
unsigned long mem,
unsigned long *p,
static void * unflatten_dt_node(struct boot_param_header *blob,
void *mem,
int *poffset,
struct device_node *dad,
struct device_node ***allnextpp,
unsigned long fpsize)
{
const __be32 *p;
struct device_node *np;
struct property *pp, **prev_pp = NULL;
char *pathp;
u32 tag;
const char *pathp;
unsigned int l, allocl;
static int depth = 0;
int old_depth;
int offset;
int has_name = 0;
int new_format = 0;
tag = be32_to_cpup((__be32 *)(*p));
if (tag != OF_DT_BEGIN_NODE) {
pr_err("Weird tag at start of node: %x\n", tag);
pathp = fdt_get_name(blob, *poffset, &l);
if (!pathp)
return mem;
}
*p += 4;
pathp = (char *)*p;
l = allocl = strlen(pathp) + 1;
*p = ALIGN(*p + l, 4);
allocl = l++;
/* version 0x10 has a more compact unit name here instead of the full
* path. we accumulate the full path size using "fpsize", we'll rebuild
@@ -187,7 +143,7 @@ static unsigned long unflatten_dt_node(struct boot_param_header *blob,
fpsize = 1;
allocl = 2;
l = 1;
*pathp = '\0';
pathp = "";
} else {
/* account for '/' and path size minus terminal 0
* already in 'l'
@@ -235,32 +191,23 @@ static unsigned long unflatten_dt_node(struct boot_param_header *blob,
kref_init(&np->kref);
}
/* process properties */
while (1) {
u32 sz, noff;
char *pname;
for (offset = fdt_first_property_offset(blob, *poffset);
(offset >= 0);
(offset = fdt_next_property_offset(blob, offset))) {
const char *pname;
u32 sz;
tag = be32_to_cpup((__be32 *)(*p));
if (tag == OF_DT_NOP) {
*p += 4;
continue;
}
if (tag != OF_DT_PROP)
if (!(p = fdt_getprop_by_offset(blob, offset, &pname, &sz))) {
offset = -FDT_ERR_INTERNAL;
break;
*p += 4;
sz = be32_to_cpup((__be32 *)(*p));
noff = be32_to_cpup((__be32 *)((*p) + 4));
*p += 8;
if (be32_to_cpu(blob->version) < 0x10)
*p = ALIGN(*p, sz >= 8 ? 8 : 4);
}
pname = of_fdt_get_string(blob, noff);
if (pname == NULL) {
pr_info("Can't find property name in list !\n");
break;
}
if (strcmp(pname, "name") == 0)
has_name = 1;
l = strlen(pname) + 1;
pp = unflatten_dt_alloc(&mem, sizeof(struct property),
__alignof__(struct property));
if (allnextpp) {
@@ -272,26 +219,25 @@ static unsigned long unflatten_dt_node(struct boot_param_header *blob,
if ((strcmp(pname, "phandle") == 0) ||
(strcmp(pname, "linux,phandle") == 0)) {
if (np->phandle == 0)
np->phandle = be32_to_cpup((__be32*)*p);
np->phandle = be32_to_cpup(p);
}
/* And we process the "ibm,phandle" property
* used in pSeries dynamic device tree
* stuff */
if (strcmp(pname, "ibm,phandle") == 0)
np->phandle = be32_to_cpup((__be32 *)*p);
pp->name = pname;
np->phandle = be32_to_cpup(p);
pp->name = (char *)pname;
pp->length = sz;
pp->value = (void *)*p;
pp->value = (__be32 *)p;
*prev_pp = pp;
prev_pp = &pp->next;
}
*p = ALIGN((*p) + sz, 4);
}
/* with version 0x10 we may not have the name property, recreate
* it here from the unit name if absent
*/
if (!has_name) {
char *p1 = pathp, *ps = pathp, *pa = NULL;
const char *p1 = pathp, *ps = pathp, *pa = NULL;
int sz;
while (*p1) {
@@ -328,19 +274,18 @@ static unsigned long unflatten_dt_node(struct boot_param_header *blob,
if (!np->type)
np->type = "<NULL>";
}
while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) {
if (tag == OF_DT_NOP)
*p += 4;
else
mem = unflatten_dt_node(blob, mem, p, np, allnextpp,
fpsize);
tag = be32_to_cpup((__be32 *)(*p));
}
if (tag != OF_DT_END_NODE) {
pr_err("Weird tag at end of node: %x\n", tag);
return mem;
}
*p += 4;
old_depth = depth;
*poffset = fdt_next_node(blob, *poffset, &depth);
if (depth < 0)
depth = 0;
while (*poffset > 0 && depth > old_depth)
mem = unflatten_dt_node(blob, mem, poffset, np, allnextpp,
fpsize);
if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND)
pr_err("unflatten: error %d processing FDT\n", *poffset);
return mem;
}
@@ -360,7 +305,9 @@ static void __unflatten_device_tree(struct boot_param_header *blob,
struct device_node **mynodes,
void * (*dt_alloc)(u64 size, u64 align))
{
unsigned long start, mem, size;
unsigned long size;
int start;
void *mem;
struct device_node **allnextp = mynodes;
pr_debug(" -> unflatten_device_tree()\n");
@@ -381,30 +328,25 @@ static void __unflatten_device_tree(struct boot_param_header *blob,
}
/* First pass, scan for size */
start = ((unsigned long)blob) +
be32_to_cpu(blob->off_dt_struct);
size = unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);
size = (size | 3) + 1;
start = 0;
size = (unsigned long)unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);
size = ALIGN(size, 4);
pr_debug(" size is %lx, allocating...\n", size);
/* Allocate memory for the expanded device tree */
mem = (unsigned long)
dt_alloc(size + 4, __alignof__(struct device_node));
mem = dt_alloc(size + 4, __alignof__(struct device_node));
memset((void *)mem, 0, size);
((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef);
pr_debug(" unflattening %lx...\n", mem);
pr_debug(" unflattening %p...\n", mem);
/* Second pass, do actual unflattening */
start = ((unsigned long)blob) +
be32_to_cpu(blob->off_dt_struct);
start = 0;
unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0);
if (be32_to_cpup((__be32 *)start) != OF_DT_END)
pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start));
if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef)
if (be32_to_cpup(mem + size) != 0xdeadbeef)
pr_warning("End of tree marker overwritten: %08x\n",
be32_to_cpu(((__be32 *)mem)[size / 4]));
*allnextp = NULL;
@@ -442,6 +384,129 @@ struct boot_param_header *initial_boot_params;
#ifdef CONFIG_OF_EARLY_FLATTREE
/**
* res_mem_reserve_reg() - reserve all memory described in 'reg' property
*/
static int __init __reserved_mem_reserve_reg(unsigned long node,
const char *uname)
{
int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
phys_addr_t base, size;
int len;
const __be32 *prop;
int nomap, first = 1;
prop = of_get_flat_dt_prop(node, "reg", &len);
if (!prop)
return -ENOENT;
if (len && len % t_len != 0) {
pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n",
uname);
return -EINVAL;
}
nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
while (len >= t_len) {
base = dt_mem_next_cell(dt_root_addr_cells, &prop);
size = dt_mem_next_cell(dt_root_size_cells, &prop);
if (base && size &&
early_init_dt_reserve_memory_arch(base, size, nomap) == 0)
pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n",
uname, &base, (unsigned long)size / SZ_1M);
else
pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %ld MiB\n",
uname, &base, (unsigned long)size / SZ_1M);
len -= t_len;
if (first) {
fdt_reserved_mem_save_node(node, uname, base, size);
first = 0;
}
}
return 0;
}
/**
* __reserved_mem_check_root() - check if #size-cells, #address-cells provided
* in /reserved-memory matches the values supported by the current implementation,
* also check if ranges property has been provided
*/
static int __init __reserved_mem_check_root(unsigned long node)
{
const __be32 *prop;
prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
if (!prop || be32_to_cpup(prop) != dt_root_size_cells)
return -EINVAL;
prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
if (!prop || be32_to_cpup(prop) != dt_root_addr_cells)
return -EINVAL;
prop = of_get_flat_dt_prop(node, "ranges", NULL);
if (!prop)
return -EINVAL;
return 0;
}
/**
* fdt_scan_reserved_mem() - scan a single FDT node for reserved memory
*/
static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname,
int depth, void *data)
{
static int found;
const char *status;
int err;
if (!found && depth == 1 && strcmp(uname, "reserved-memory") == 0) {
if (__reserved_mem_check_root(node) != 0) {
pr_err("Reserved memory: unsupported node format, ignoring\n");
/* break scan */
return 1;
}
found = 1;
/* scan next node */
return 0;
} else if (!found) {
/* scan next node */
return 0;
} else if (found && depth < 2) {
/* scanning of /reserved-memory has been finished */
return 1;
}
status = of_get_flat_dt_prop(node, "status", NULL);
if (status && strcmp(status, "okay") != 0 && strcmp(status, "ok") != 0)
return 0;
err = __reserved_mem_reserve_reg(node, uname);
if (err == -ENOENT && of_get_flat_dt_prop(node, "size", NULL))
fdt_reserved_mem_save_node(node, uname, 0, 0);
/* scan next node */
return 0;
}
/**
* early_init_fdt_scan_reserved_mem() - create reserved memory regions
*
* This function grabs memory from early allocator for device exclusive use
* defined in device tree structures. It should be called by arch specific code
* once the early allocator (i.e. memblock) has been fully activated.
*/
void __init early_init_fdt_scan_reserved_mem(void)
{
if (!initial_boot_params)
return;
of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);
fdt_init_reserved_mem();
}
/**
* of_scan_flat_dt - scan flattened tree blob and call callback on each.
* @it: callback function
@@ -456,47 +521,19 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node,
void *data),
void *data)
{
unsigned long p = ((unsigned long)initial_boot_params) +
be32_to_cpu(initial_boot_params->off_dt_struct);
int rc = 0;
int depth = -1;
const void *blob = initial_boot_params;
const char *pathp;
int offset, rc = 0, depth = -1;
do {
u32 tag = be32_to_cpup((__be32 *)p);
const char *pathp;
for (offset = fdt_next_node(blob, -1, &depth);
offset >= 0 && depth >= 0 && !rc;
offset = fdt_next_node(blob, offset, &depth)) {
p += 4;
if (tag == OF_DT_END_NODE) {
depth--;
continue;
}
if (tag == OF_DT_NOP)
continue;
if (tag == OF_DT_END)
break;
if (tag == OF_DT_PROP) {
u32 sz = be32_to_cpup((__be32 *)p);
p += 8;
if (be32_to_cpu(initial_boot_params->version) < 0x10)
p = ALIGN(p, sz >= 8 ? 8 : 4);
p += sz;
p = ALIGN(p, 4);
continue;
}
if (tag != OF_DT_BEGIN_NODE) {
pr_err("Invalid tag %x in flat device tree!\n", tag);
return -EINVAL;
}
depth++;
pathp = (char *)p;
p = ALIGN(p + strlen(pathp) + 1, 4);
pathp = fdt_get_name(blob, offset, NULL);
if (*pathp == '/')
pathp = kbasename(pathp);
rc = it(p, pathp, depth, data);
if (rc != 0)
break;
} while (1);
rc = it(offset, pathp, depth, data);
}
return rc;
}
@@ -505,14 +542,7 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node,
*/
unsigned long __init of_get_flat_dt_root(void)
{
unsigned long p = ((unsigned long)initial_boot_params) +
be32_to_cpu(initial_boot_params->off_dt_struct);
while (be32_to_cpup((__be32 *)p) == OF_DT_NOP)
p += 4;
BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE);
p += 4;
return ALIGN(p + strlen((char *)p) + 1, 4);
return 0;
}
/**
@@ -521,10 +551,10 @@ unsigned long __init of_get_flat_dt_root(void)
* This function can be used within scan_flattened_dt callback to get
* access to properties
*/
void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
unsigned long *size)
const void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
int *size)
{
return of_fdt_get_property(initial_boot_params, node, name, size);
return fdt_getprop(initial_boot_params, node, name, size);
}
/**
@@ -545,6 +575,15 @@ int __init of_flat_dt_match(unsigned long node, const char *const *compat)
return of_fdt_match(initial_boot_params, node, compat);
}
struct fdt_scan_status {
const char *name;
int namelen;
int depth;
int found;
int (*iterator)(unsigned long node, const char *uname, int depth, void *data);
void *data;
};
#ifdef CONFIG_BLK_DEV_INITRD
/**
* early_init_dt_check_for_initrd - Decode initrd location from flat tree
@@ -553,8 +592,8 @@ int __init of_flat_dt_match(unsigned long node, const char *const *compat)
void __init early_init_dt_check_for_initrd(unsigned long node)
{
u64 start, end;
unsigned long len;
__be32 *prop;
int len;
const __be32 *prop;
pr_debug("Looking for initrd properties... ");
@@ -584,7 +623,7 @@ inline void early_init_dt_check_for_initrd(unsigned long node)
int __init early_init_dt_scan_root(unsigned long node, const char *uname,
int depth, void *data)
{
__be32 *prop;
const __be32 *prop;
if (depth != 0)
return 0;
@@ -606,9 +645,9 @@ int __init early_init_dt_scan_root(unsigned long node, const char *uname,
return 1;
}
u64 __init dt_mem_next_cell(int s, __be32 **cellp)
u64 __init dt_mem_next_cell(int s, const __be32 **cellp)
{
__be32 *p = *cellp;
const __be32 *p = *cellp;
*cellp = p + s;
return of_read_number(p, s);
@@ -620,9 +659,9 @@ u64 __init dt_mem_next_cell(int s, __be32 **cellp)
int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
int depth, void *data)
{
char *type = of_get_flat_dt_prop(node, "device_type", NULL);
__be32 *reg, *endp;
unsigned long l;
const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
const __be32 *reg, *endp;
int l;
/* We are scanning "memory" nodes only */
if (type == NULL) {
@@ -643,7 +682,7 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
endp = reg + (l / sizeof(__be32));
pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n",
pr_debug("memory scan node %s, reg size %d, data: %x %x %x %x,\n",
uname, l, reg[0], reg[1], reg[2], reg[3]);
while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
@@ -666,8 +705,8 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
int depth, void *data)
{
unsigned long l;
char *p;
int l;
const char *p;
pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
@@ -700,6 +739,80 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
return 1;
}
#ifdef CONFIG_HAVE_MEMBLOCK
void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
{
const u64 phys_offset = __pa(PAGE_OFFSET);
base &= PAGE_MASK;
size &= PAGE_MASK;
if (base + size < phys_offset) {
pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
base, base + size);
return;
}
if (base < phys_offset) {
pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
base, phys_offset);
size -= phys_offset - base;
base = phys_offset;
}
memblock_add(base, size);
}
int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
phys_addr_t size, bool nomap)
{
if (memblock_is_region_reserved(base, size))
return -EBUSY;
if (nomap)
return memblock_remove(base, size);
return memblock_reserve(base, size);
}
/*
* called from unflatten_device_tree() to bootstrap devicetree itself
* Architectures can override this definition if memblock isn't used
*/
void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align)
{
return __va(memblock_alloc(size, align));
}
#else
int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
phys_addr_t size, bool nomap)
{
pr_err("Reserved memory not supported, ignoring range 0x%llx - 0x%llx%s\n",
base, size, nomap ? " (nomap)" : "");
return -ENOSYS;
}
#endif
bool __init early_init_dt_scan(void *params)
{
if (!params)
return false;
/* Setup flat device-tree pointer */
initial_boot_params = params;
/* check device tree validity */
if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) {
initial_boot_params = NULL;
return false;
}
/* Retrieve various information from the /chosen node */
of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
/* Initialize {size,address}-cells info */
of_scan_flat_dt(early_init_dt_scan_root, NULL);
/* Setup memory, calling early_init_dt_add_memory_arch */
of_scan_flat_dt(early_init_dt_scan_memory, NULL);
return true;
}
/**
* unflatten_device_tree - create tree of device_nodes from flat blob
*

View File

@@ -0,0 +1,217 @@
/*
* Device tree based initialization code for reserved memory.
*
* Copyright (c) 2013, The Linux Foundation. All Rights Reserved.
* Copyright (c) 2013,2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com
* Author: Marek Szyprowski <m.szyprowski@samsung.com>
* Author: Josh Cartwright <joshc@codeaurora.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License or (at your optional) any later version of the license.
*/
#include <linux/err.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
#include <linux/mm.h>
#include <linux/sizes.h>
#include <linux/of_reserved_mem.h>
#define MAX_RESERVED_REGIONS 16
static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
static int reserved_mem_count;
#if defined(CONFIG_HAVE_MEMBLOCK)
#include <linux/memblock.h>
int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
phys_addr_t *res_base)
{
/*
* We use __memblock_alloc_base() because memblock_alloc_base()
* panic()s on allocation failure.
*/
phys_addr_t base = __memblock_alloc_base(size, align, end);
if (!base)
return -ENOMEM;
/*
* Check if the allocated region fits in to start..end window
*/
if (base < start) {
memblock_free(base, size);
return -ENOMEM;
}
*res_base = base;
if (nomap)
return memblock_remove(base, size);
return 0;
}
#else
int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
phys_addr_t *res_base)
{
pr_err("Reserved memory not supported, ignoring region 0x%llx%s\n",
size, nomap ? " (nomap)" : "");
return -ENOSYS;
}
#endif
/**
* res_mem_save_node() - save fdt node for second pass initialization
*/
void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname,
phys_addr_t base, phys_addr_t size)
{
struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
if (reserved_mem_count == ARRAY_SIZE(reserved_mem)) {
pr_err("Reserved memory: not enough space all defined regions.\n");
return;
}
rmem->fdt_node = node;
rmem->name = uname;
rmem->base = base;
rmem->size = size;
reserved_mem_count++;
return;
}
/**
* res_mem_alloc_size() - allocate reserved memory described by 'size', 'align'
* and 'alloc-ranges' properties
*/
static int __init __reserved_mem_alloc_size(unsigned long node,
const char *uname, phys_addr_t *res_base, phys_addr_t *res_size)
{
int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
phys_addr_t start = 0, end = 0;
phys_addr_t base = 0, align = 0, size;
int len;
const __be32 *prop;
int nomap;
int ret;
prop = of_get_flat_dt_prop(node, "size", &len);
if (!prop)
return -EINVAL;
if (len != dt_root_size_cells * sizeof(__be32)) {
pr_err("Reserved memory: invalid size property in '%s' node.\n",
uname);
return -EINVAL;
}
size = dt_mem_next_cell(dt_root_size_cells, &prop);
nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
prop = of_get_flat_dt_prop(node, "alignment", &len);
if (prop) {
if (len != dt_root_addr_cells * sizeof(__be32)) {
pr_err("Reserved memory: invalid alignment property in '%s' node.\n",
uname);
return -EINVAL;
}
align = dt_mem_next_cell(dt_root_addr_cells, &prop);
}
prop = of_get_flat_dt_prop(node, "alloc-ranges", &len);
if (prop) {
if (len % t_len != 0) {
pr_err("Reserved memory: invalid alloc-ranges property in '%s', skipping node.\n",
uname);
return -EINVAL;
}
base = 0;
while (len > 0) {
start = dt_mem_next_cell(dt_root_addr_cells, &prop);
end = start + dt_mem_next_cell(dt_root_size_cells,
&prop);
ret = early_init_dt_alloc_reserved_memory_arch(size,
align, start, end, nomap, &base);
if (ret == 0) {
pr_debug("Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n",
uname, &base,
(unsigned long)size / SZ_1M);
break;
}
len -= t_len;
}
} else {
ret = early_init_dt_alloc_reserved_memory_arch(size, align,
0, 0, nomap, &base);
if (ret == 0)
pr_debug("Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n",
uname, &base, (unsigned long)size / SZ_1M);
}
if (base == 0) {
pr_info("Reserved memory: failed to allocate memory for node '%s'\n",
uname);
return -ENOMEM;
}
*res_base = base;
*res_size = size;
return 0;
}
static const struct of_device_id __rmem_of_table_sentinel
__used __section(__reservedmem_of_table_end);
/**
* res_mem_init_node() - call region specific reserved memory init code
*/
static int __init __reserved_mem_init_node(struct reserved_mem *rmem)
{
extern const struct of_device_id __reservedmem_of_table[];
const struct of_device_id *i;
for (i = __reservedmem_of_table; i < &__rmem_of_table_sentinel; i++) {
reservedmem_of_init_fn initfn = i->data;
const char *compat = i->compatible;
if (!of_flat_dt_is_compatible(rmem->fdt_node, compat))
continue;
if (initfn(rmem, rmem->fdt_node, rmem->name) == 0) {
pr_info("Reserved memory: initialized node %s, compatible id %s\n",
rmem->name, compat);
return 0;
}
}
return -ENOENT;
}
/**
* fdt_init_reserved_mem - allocate and init all saved reserved memory regions
*/
void __init fdt_init_reserved_mem(void)
{
int i;
for (i = 0; i < reserved_mem_count; i++) {
struct reserved_mem *rmem = &reserved_mem[i];
unsigned long node = rmem->fdt_node;
int err = 0;
if (rmem->size == 0)
err = __reserved_mem_alloc_size(node, rmem->name,
&rmem->base, &rmem->size);
if (err == 0)
__reserved_mem_init_node(rmem);
}
}

View File

@@ -171,6 +171,16 @@
#define CLK_OF_TABLES()
#endif
#ifdef CONFIG_OF_RESERVED_MEM
#define RESERVEDMEM_OF_TABLES() \
. = ALIGN(8); \
VMLINUX_SYMBOL(__reservedmem_of_table) = .; \
*(__reservedmem_of_table) \
*(__reservedmem_of_table_end)
#else
#define RESERVEDMEM_OF_TABLES()
#endif
#define KERNEL_DTB() \
STRUCT_ALIGN(); \
VMLINUX_SYMBOL(__dtb_start) = .; \
@@ -515,6 +525,7 @@
CPU_DISCARD(init.rodata) \
MEM_DISCARD(init.rodata) \
CLK_OF_TABLES() \
RESERVEDMEM_OF_TABLES() \
CLKSRC_OF_TABLES() \
KERNEL_DTB() \
IRQCHIP_OF_MATCH_TABLE()

View File

@@ -344,6 +344,8 @@ const char *of_prop_next_string(struct property *prop, const char *cur);
s; \
s = of_prop_next_string(prop, s))
int of_device_is_stdout_path(struct device_node *dn);
#else /* CONFIG_OF */
static inline const char* of_node_full_name(struct device_node *np)
@@ -512,6 +514,11 @@ static inline int of_machine_is_compatible(const char *compat)
return 0;
}
static inline int of_device_is_stdout_path(struct device_node *dn)
{
return 0;
}
#define of_match_ptr(_ptr) NULL
#define of_match_node(_matches, _node) NULL
#define of_property_for_each_u32(np, propname, prop, p, u) \

View File

@@ -66,7 +66,7 @@ extern char *of_fdt_get_string(struct boot_param_header *blob, u32 offset);
extern void *of_fdt_get_property(struct boot_param_header *blob,
unsigned long node,
const char *name,
unsigned long *size);
int *size);
extern int of_fdt_is_compatible(struct boot_param_header *blob,
unsigned long node,
const char *compat);
@@ -81,12 +81,11 @@ extern int __initdata dt_root_size_cells;
extern struct boot_param_header *initial_boot_params;
/* For scanning the flat device-tree at boot time */
extern char *find_flat_dt_string(u32 offset);
extern int of_scan_flat_dt(int (*it)(unsigned long node, const char *uname,
int depth, void *data),
void *data);
extern void *of_get_flat_dt_prop(unsigned long node, const char *name,
unsigned long *size);
extern const void *of_get_flat_dt_prop(unsigned long node, const char *name,
int *size);
extern int of_flat_dt_is_compatible(unsigned long node, const char *name);
extern int of_flat_dt_match(unsigned long node, const char *const *matches);
extern unsigned long of_get_flat_dt_root(void);
@@ -96,9 +95,12 @@ extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
extern void early_init_dt_check_for_initrd(unsigned long node);
extern int early_init_dt_scan_memory(unsigned long node, const char *uname,
int depth, void *data);
extern void early_init_fdt_scan_reserved_mem(void);
extern void early_init_dt_add_memory_arch(u64 base, u64 size);
extern int early_init_dt_reserve_memory_arch(phys_addr_t base, phys_addr_t size,
bool no_map);
extern void * early_init_dt_alloc_memory_arch(u64 size, u64 align);
extern u64 dt_mem_next_cell(int s, __be32 **cellp);
extern u64 dt_mem_next_cell(int s, const __be32 **cellp);
/*
* If BLK_DEV_INITRD, the fdt early init code will call this function,
@@ -117,6 +119,8 @@ extern int early_init_dt_scan_root(unsigned long node, const char *uname,
extern void unflatten_device_tree(void);
extern void early_init_devtree(void *);
#else /* CONFIG_OF_FLATTREE */
static inline void early_init_fdt_scan_reserved_mem(void) {}
static inline const char *of_flat_dt_get_machine_name(void) { return NULL; }
static inline void unflatten_device_tree(void) {}
#endif /* CONFIG_OF_FLATTREE */

View File

@@ -0,0 +1,53 @@
#ifndef __OF_RESERVED_MEM_H
#define __OF_RESERVED_MEM_H
struct device;
struct of_phandle_args;
struct reserved_mem_ops;
struct reserved_mem {
const char *name;
unsigned long fdt_node;
const struct reserved_mem_ops *ops;
phys_addr_t base;
phys_addr_t size;
void *priv;
};
struct reserved_mem_ops {
void (*device_init)(struct reserved_mem *rmem,
struct device *dev);
void (*device_release)(struct reserved_mem *rmem,
struct device *dev);
};
typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem,
unsigned long node, const char *uname);
#ifdef CONFIG_OF_RESERVED_MEM
void fdt_init_reserved_mem(void);
void fdt_reserved_mem_save_node(unsigned long node, const char *uname,
phys_addr_t base, phys_addr_t size);
#define RESERVEDMEM_OF_DECLARE(name, compat, init) \
static const struct of_device_id __reservedmem_of_table_##name \
__used __section(__reservedmem_of_table) \
= { .compatible = compat, \
.data = (init == (reservedmem_of_init_fn)NULL) ? \
init : init }
#else
static inline void fdt_init_reserved_mem(void) { }
static inline void fdt_reserved_mem_save_node(unsigned long node,
const char *uname, phys_addr_t base, phys_addr_t size) { }
#define RESERVEDMEM_OF_DECLARE(name, compat, init) \
static const struct of_device_id __reservedmem_of_table_##name \
__attribute__((unused)) \
= { .compatible = compat, \
.data = (init == (reservedmem_of_init_fn)NULL) ? \
init : init }
#endif
#endif /* __OF_RESERVED_MEM_H */

View File

@@ -140,7 +140,8 @@ obj-$(CONFIG_GENERIC_STRNLEN_USER) += strnlen_user.o
obj-$(CONFIG_STMP_DEVICE) += stmp_device.o
libfdt_files = fdt.o fdt_ro.o fdt_wip.o fdt_rw.o fdt_sw.o fdt_strerror.o
libfdt_files = fdt.o fdt_ro.o fdt_wip.o fdt_rw.o fdt_sw.o fdt_strerror.o \
fdt_empty_tree.o
$(foreach file, $(libfdt_files), \
$(eval CFLAGS_$(file) = -I$(src)/../scripts/dtc/libfdt))
lib-$(CONFIG_LIBFDT) += $(libfdt_files)

2
lib/fdt_empty_tree.c Normal file
View File

@@ -0,0 +1,2 @@
#include <linux/libfdt_env.h>
#include "../scripts/dtc/libfdt/fdt_empty_tree.c"