DeviceTree for 3.16:

- Another round of clean-up of FDT related code in architecture code.
   This removes knowledge of internal FDT details from most architectures
   except powerpc.
 - Conversion of kernel's custom FDT parsing code to use libfdt.
 - DT based initialization for generic serial earlycon. The introduction
   of generic serial earlycon support went in thru tty tree.
 - Improve the platform device naming for DT probed devices to ensure
   unique naming and use parent names instead of a global index.
 - Fix a race condition in of_update_property.
 - Unify the various linker section OF match tables and fix several
   function prototype errors.
 - Update platform_get_irq_byname to work in deferred probe cases.
 - 2 binding doc updates
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABAgAGBQJTjzgyAAoJEMhvYp4jgsXiFsUH/1PMTGo8CyD62VQD5ZKdAoW+
 Fq6vCiRQ8assF5i5ZLcW1DqhjtoRaCKYhVbRKa5lj7cZdjlSpacI/qQPrF5Br2Ii
 bTE3Ff/AQwipQaz/Bj7HqJCgGwfWK8xdfgW0abKsyXMWDN86Bov/zzeu8apmws0x
 H1XjJRgnc/rzM4m9ny6+lss0iq6YL54SuTYNzHR33+Ywxls69SfHXIhCW0KpZcBl
 5U3YUOomt40GfO46sxFA4xApAhypEK4oVq7asyiA2ArTZ/c2Pkc9p5CBqzhDLmlq
 yioWTwHIISv0q+yMLCuQrVGIsbUDkQyy7RQ15z6U+/e/iGO/M+j3A5yxMc3qOi4=
 =Onff
 -----END PGP SIGNATURE-----

Merge tag 'devicetree-for-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux into next

Pull DeviceTree updates from Rob Herring:
 - Another round of clean-up of FDT related code in architecture code.
   This removes knowledge of internal FDT details from most
   architectures except powerpc.
 - Conversion of kernel's custom FDT parsing code to use libfdt.
 - DT based initialization for generic serial earlycon.  The
   introduction of generic serial earlycon support went in through the
   tty tree.
 - Improve the platform device naming for DT probed devices to ensure
   unique naming and use parent names instead of a global index.
 - Fix a race condition in of_update_property.
 - Unify the various linker section OF match tables and fix several
   function prototype errors.
 - Update platform_get_irq_byname to work in deferred probe cases.
 - 2 binding doc updates

* tag 'devicetree-for-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux: (58 commits)
  of: handle NULL node in next_child iterators
  of/irq: provide more wrappers for !CONFIG_OF
  devicetree: bindings: Document micrel vendor prefix
  dt: bindings: dwc2: fix required value for the phy-names property
  of_pci_irq: kill useless variable in of_irq_parse_pci()
  of/irq: do irq resolution in platform_get_irq_byname()
  of: Add a testcase for of_find_node_by_path()
  of: Make of_find_node_by_path() handle /aliases
  of: Create unlocked version of for_each_child_of_node()
  lib: add glibc style strchrnul() variant
  of: Handle memory@0 node on PPC32 only
  pci/of: Remove dead code
  of: fix race between search and remove in of_update_property()
  of: Use NULL for pointers
  of: Stop naming platform_device using dcr address
  of: Ensure unique names without sacrificing determinism
  tty/serial: pl011: add DT based earlycon support
  of/fdt: add FDT serial scanning for earlycon
  of/fdt: add FDT address translation support
  serial: earlycon: add DT support
  ...
This commit is contained in:
Linus Torvalds 2014-06-04 10:02:38 -07:00
commit d27050641e
76 changed files with 1004 additions and 834 deletions

View File

@ -13,7 +13,7 @@ Refer to clk/clock-bindings.txt for generic clock consumer properties
Optional properties:
- phys: phy provider specifier
- phy-names: shall be "device"
- phy-names: shall be "usb2-phy"
Refer to phy/phy-bindings.txt for generic phy consumer properties
Example:

View File

@ -77,6 +77,7 @@ lsi LSI Corp. (LSI Logic)
lltc Linear Technology Corporation
marvell Marvell Technology Group Ltd.
maxim Maxim Integrated Products
micrel Micrel Inc.
microchip Microchip Technology Inc.
mosaixtech Mosaix Technologies, Inc.
moxa Moxa

View File

@ -12,6 +12,5 @@
#include <asm-generic/sections.h>
extern char __arc_dccm_base[];
extern char __dtb_start[];
#endif

View File

@ -42,7 +42,7 @@ const struct machine_desc * __init setup_machine_fdt(void *dt)
const struct machine_desc *mdesc;
unsigned long dt_root;
void *clk;
unsigned long len;
int len;
if (!early_init_dt_scan(dt))
return NULL;

View File

@ -14,7 +14,6 @@
#ifdef CONFIG_OF
extern const struct machine_desc *setup_machine_fdt(unsigned int dt_phys);
extern void arm_dt_memblock_reserve(void);
extern void __init arm_dt_init_cpu_maps(void);
#else /* CONFIG_OF */
@ -24,7 +23,6 @@ static inline const struct machine_desc *setup_machine_fdt(unsigned int dt_phys)
return NULL;
}
static inline void arm_dt_memblock_reserve(void) { }
static inline void arm_dt_init_cpu_maps(void) { }
#endif /* CONFIG_OF */

View File

@ -32,51 +32,22 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
arm_add_memory(base, size);
}
void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
{
return memblock_virt_alloc(size, align);
}
void __init arm_dt_memblock_reserve(void)
{
u64 *reserve_map, base, size;
if (!initial_boot_params)
return;
/* Reserve the dtb region */
memblock_reserve(virt_to_phys(initial_boot_params),
be32_to_cpu(initial_boot_params->totalsize));
/*
* Process the reserve map. This will probably overlap the initrd
* and dtb locations which are already reserved, but overlaping
* doesn't hurt anything
*/
reserve_map = ((void*)initial_boot_params) +
be32_to_cpu(initial_boot_params->off_mem_rsvmap);
while (1) {
base = be64_to_cpup(reserve_map++);
size = be64_to_cpup(reserve_map++);
if (!size)
break;
memblock_reserve(base, size);
}
}
#ifdef CONFIG_SMP
extern struct of_cpu_method __cpu_method_of_table_begin[];
extern struct of_cpu_method __cpu_method_of_table_end[];
extern struct of_cpu_method __cpu_method_of_table[];
static const struct of_cpu_method __cpu_method_of_table_sentinel
__used __section(__cpu_method_of_table_end);
static int __init set_smp_ops_by_method(struct device_node *node)
{
const char *method;
struct of_cpu_method *m = __cpu_method_of_table_begin;
struct of_cpu_method *m = __cpu_method_of_table;
if (of_property_read_string(node, "enable-method", &method))
return 0;
for (; m < __cpu_method_of_table_end; m++)
for (; m->method; m++)
if (!strcmp(m->method, method)) {
smp_set_ops(m->ops);
return 1;
@ -252,7 +223,7 @@ const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
if (!mdesc) {
const char *prop;
long size;
int size;
unsigned long dt_root;
early_print("\nError: unrecognized/unsupported "

View File

@ -202,7 +202,7 @@ static int __init exynos_fdt_map_chipid(unsigned long node, const char *uname,
{
struct map_desc iodesc;
__be32 *reg;
unsigned long len;
int len;
if (!of_flat_dt_is_compatible(node, "samsung,exynos4210-chipid") &&
!of_flat_dt_is_compatible(node, "samsung,exynos5440-clock"))

View File

@ -289,14 +289,12 @@ int __init mx35_clocks_init(void)
return 0;
}
static int __init mx35_clocks_init_dt(struct device_node *ccm_node)
static void __init mx35_clocks_init_dt(struct device_node *ccm_node)
{
clk_data.clks = clk;
clk_data.clk_num = ARRAY_SIZE(clk);
of_clk_add_provider(ccm_node, of_clk_src_onecell_get, &clk_data);
mx35_clocks_init();
return 0;
}
CLK_OF_DECLARE(imx35, "fsl,imx35-ccm", mx35_clocks_init_dt);

View File

@ -317,7 +317,6 @@ void __init arm_memblock_init(struct meminfo *mi,
#endif
arm_mm_memblock_reserve();
arm_dt_memblock_reserve();
/* reserve any platform specific memblock areas */
if (mdesc->reserve)

View File

@ -125,8 +125,8 @@ device_initcall(s5p_mfc_memory_init);
int __init s5p_fdt_alloc_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;
if (!data)

View File

@ -126,8 +126,6 @@ static void arm64_memory_present(void)
void __init arm64_memblock_init(void)
{
u64 *reserve_map, base, size;
/* Register the kernel text, kernel data and initrd with memblock */
memblock_reserve(__pa(_text), _end - _text);
#ifdef CONFIG_BLK_DEV_INITRD
@ -142,25 +140,6 @@ void __init arm64_memblock_init(void)
memblock_reserve(__pa(swapper_pg_dir), SWAPPER_DIR_SIZE);
memblock_reserve(__pa(idmap_pg_dir), IDMAP_DIR_SIZE);
/* Reserve the dtb region */
memblock_reserve(virt_to_phys(initial_boot_params),
be32_to_cpu(initial_boot_params->totalsize));
/*
* Process the reserve map. This will probably overlap the initrd
* and dtb locations which are already reserved, but overlapping
* doesn't hurt anything
*/
reserve_map = ((void*)initial_boot_params) +
be32_to_cpu(initial_boot_params->off_mem_rsvmap);
while (1) {
base = be64_to_cpup(reserve_map++);
size = be64_to_cpup(reserve_map++);
if (!size)
break;
memblock_reserve(base, size);
}
early_init_fdt_scan_reserved_mem();
dma_contiguous_reserve(0);

View File

@ -265,8 +265,8 @@ int __init c6x_add_memory(phys_addr_t start, unsigned long size)
*/
notrace void __init machine_init(unsigned long dt_ptr)
{
struct boot_param_header *dtb = __va(dt_ptr);
struct boot_param_header *fdt = (struct boot_param_header *)_fdt_start;
const void *dtb = __va(dt_ptr);
const void *fdt = _fdt_start;
/* interrupts must be masked */
set_creg(IER, 2);

View File

@ -105,10 +105,6 @@
extern char _heap_start[];
#ifdef CONFIG_METAG_BUILTIN_DTB
extern u32 __dtb_start[];
#endif
#ifdef CONFIG_DA_CONSOLE
/* Our early channel based console driver */
extern struct console dash_console;

View File

@ -43,13 +43,13 @@
#include <asm/pci-bridge.h>
#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);
@ -80,7 +80,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;
@ -114,34 +114,3 @@ void __init early_init_devtree(void *params)
pr_debug(" <- early_init_devtree()\n");
}
/*******
*
* New implementation of the OF "find" APIs, return a refcounted
* object, call of_node_put() when done. The device tree and list
* are protected by a rw_lock.
*
* Note that property management will need some locking as well,
* this isn't dealt with yet.
*
*******/
#if defined(CONFIG_DEBUG_FS) && defined(DEBUG)
static struct debugfs_blob_wrapper flat_dt_blob;
static int __init export_flat_device_tree(void)
{
struct dentry *d;
flat_dt_blob.data = initial_boot_params;
flat_dt_blob.size = initial_boot_params->totalsize;
d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR,
of_debugfs_root, &flat_dt_blob);
if (!d)
return 1;
return 0;
}
device_initcall(export_flat_device_tree);
#endif

View File

@ -1053,36 +1053,26 @@ void prom_free_prom_memory(void)
int octeon_prune_device_tree(void);
extern const char __dtb_octeon_3xxx_begin;
extern const char __dtb_octeon_3xxx_end;
extern const char __dtb_octeon_68xx_begin;
extern const char __dtb_octeon_68xx_end;
void __init device_tree_init(void)
{
int dt_size;
struct boot_param_header *fdt;
const void *fdt;
bool do_prune;
if (octeon_bootinfo->minor_version >= 3 && octeon_bootinfo->fdt_addr) {
fdt = phys_to_virt(octeon_bootinfo->fdt_addr);
if (fdt_check_header(fdt))
panic("Corrupt Device Tree passed to kernel.");
dt_size = be32_to_cpu(fdt->totalsize);
do_prune = false;
} else if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
fdt = (struct boot_param_header *)&__dtb_octeon_68xx_begin;
dt_size = &__dtb_octeon_68xx_end - &__dtb_octeon_68xx_begin;
fdt = &__dtb_octeon_68xx_begin;
do_prune = true;
} else {
fdt = (struct boot_param_header *)&__dtb_octeon_3xxx_begin;
dt_size = &__dtb_octeon_3xxx_end - &__dtb_octeon_3xxx_begin;
fdt = &__dtb_octeon_3xxx_begin;
do_prune = true;
}
/* Copy the default tree from init memory. */
initial_boot_params = early_init_dt_alloc_memory_arch(dt_size, 8);
if (initial_boot_params == NULL)
panic("Could not allocate initial_boot_params");
memcpy(initial_boot_params, fdt, dt_size);
initial_boot_params = (void *)fdt;
if (do_prune) {
octeon_prune_device_tree();
@ -1090,7 +1080,7 @@ void __init device_tree_init(void)
} else {
pr_info("Using passed Device Tree.\n");
}
unflatten_device_tree();
unflatten_and_copy_device_tree();
}
static int __initdata disable_octeon_edac_p;

View File

@ -67,10 +67,6 @@
extern int mips_revision_sconid;
#ifdef CONFIG_OF
extern struct boot_param_header __dtb_start;
#endif
#ifdef CONFIG_PCI
extern void mips_pcibios_init(void);
#else

View File

@ -21,13 +21,13 @@ extern void device_tree_init(void);
struct boot_param_header;
extern void __dt_setup_arch(struct boot_param_header *bph);
extern void __dt_setup_arch(void *bph);
#define dt_setup_arch(sym) \
({ \
extern struct boot_param_header __dtb_##sym##_begin; \
extern char __dtb_##sym##_begin[]; \
\
__dt_setup_arch(&__dtb_##sym##_begin); \
__dt_setup_arch(__dtb_##sym##_begin); \
})
#else /* CONFIG_OF */

View File

@ -47,7 +47,7 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
return __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS));
}
void __init __dt_setup_arch(struct boot_param_header *bph)
void __init __dt_setup_arch(void *bph)
{
if (!early_init_dt_scan(bph))
return;

View File

@ -71,23 +71,12 @@ void __init plat_mem_setup(void)
* Load the builtin devicetree. This causes the chosen node to be
* parsed resulting in our memory appearing
*/
__dt_setup_arch(&__dtb_start);
__dt_setup_arch(__dtb_start);
}
void __init device_tree_init(void)
{
unsigned long base, size;
if (!initial_boot_params)
return;
base = virt_to_phys((void *)initial_boot_params);
size = be32_to_cpu(initial_boot_params->totalsize);
/* Before we do anything, lets reserve the dt blob */
reserve_bootmem(base, size, BOOTMEM_DEFAULT);
unflatten_device_tree();
unflatten_and_copy_device_tree();
}
void __init prom_init(void)

View File

@ -26,6 +26,4 @@ struct ltq_soc_info {
extern void ltq_soc_detect(struct ltq_soc_info *i);
extern void ltq_soc_init(void);
extern struct boot_param_header __dtb_start;
#endif

View File

@ -69,17 +69,17 @@ static void __init parse_memsize_param(void)
if (!memsize)
return;
offset = fdt_path_offset(&__dtb_start, "/memory");
offset = fdt_path_offset(__dtb_start, "/memory");
if (offset > 0) {
uint64_t new_value;
/*
* reg contains 2 32-bits BE values, offset and size. We just
* want to replace the size value without affecting the offset
*/
prop_value = fdt_getprop(&__dtb_start, offset, "reg", &prop_len);
prop_value = fdt_getprop(__dtb_start, offset, "reg", &prop_len);
new_value = be64_to_cpu(*prop_value);
new_value = (new_value & ~0xffffffffllu) | memsize;
fdt_setprop_inplace_u64(&__dtb_start, offset, "reg", new_value);
fdt_setprop_inplace_u64(__dtb_start, offset, "reg", new_value);
}
}
@ -92,7 +92,7 @@ void __init plat_mem_setup(void)
* Load the builtin devicetree. This causes the chosen node to be
* parsed resulting in our memory appearing
*/
__dt_setup_arch(&__dtb_start);
__dt_setup_arch(__dtb_start);
}
void __init device_tree_init(void)

View File

@ -42,7 +42,7 @@
#include <asm/prom.h>
extern u32 __dtb_xlp_evp_begin[], __dtb_xlp_svp_begin[],
__dtb_xlp_fvp_begin[], __dtb_xlp_gvp_begin[], __dtb_start[];
__dtb_xlp_fvp_begin[], __dtb_xlp_gvp_begin[];
static void *xlp_fdt_blob;
void __init *xlp_dt_init(void *fdtp)
@ -87,22 +87,7 @@ void __init xlp_early_init_devtree(void)
void __init device_tree_init(void)
{
unsigned long base, size;
struct boot_param_header *fdtp = xlp_fdt_blob;
if (!fdtp)
return;
base = virt_to_phys(fdtp);
size = be32_to_cpu(fdtp->totalsize);
/* Before we do anything, lets reserve the dt blob */
reserve_bootmem(base, size, BOOTMEM_DEFAULT);
unflatten_device_tree();
/* free the space reserved for the dt blob */
free_bootmem(base, size);
unflatten_and_copy_device_tree();
}
static struct of_device_id __initdata xlp_ids[] = {

View File

@ -28,8 +28,6 @@
__iomem void *rt_sysc_membase;
__iomem void *rt_memc_membase;
extern struct boot_param_header __dtb_start;
__iomem void *plat_of_remap_node(const char *node)
{
struct resource res;
@ -52,30 +50,7 @@ __iomem void *plat_of_remap_node(const char *node)
void __init device_tree_init(void)
{
unsigned long base, size;
void *fdt_copy;
if (!initial_boot_params)
return;
base = virt_to_phys((void *)initial_boot_params);
size = be32_to_cpu(initial_boot_params->totalsize);
/* Before we do anything, lets reserve the dt blob */
reserve_bootmem(base, size, BOOTMEM_DEFAULT);
/* The strings in the flattened tree are referenced directly by the
* device tree, so copy the flattened device tree from init memory
* to regular memory.
*/
fdt_copy = alloc_bootmem(size);
memcpy(fdt_copy, initial_boot_params, size);
initial_boot_params = fdt_copy;
unflatten_device_tree();
/* free the space reserved for the dt blob */
free_bootmem(base, size);
unflatten_and_copy_device_tree();
}
void __init plat_mem_setup(void)
@ -86,7 +61,7 @@ void __init plat_mem_setup(void)
* Load the builtin devicetree. This causes the chosen node to be
* parsed resulting in our memory appearing
*/
__dt_setup_arch(&__dtb_start);
__dt_setup_arch(__dtb_start);
if (soc_info.mem_size)
add_memory_region(soc_info.mem_base, soc_info.mem_size * SZ_1M,

View File

@ -5,6 +5,4 @@
extern char __initrd_start, __initrd_end;
#endif
extern u32 __dtb_start[];
#endif

View File

@ -51,10 +51,6 @@ static inline void dcr_write_mmio(dcr_host_mmio_t host,
out_be32(host.token + ((host.base + dcr_n) * host.stride), value);
}
extern u64 of_translate_dcr_address(struct device_node *dev,
unsigned int dcr_n,
unsigned int *stride);
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_DCR_MMIO_H */

View File

@ -26,6 +26,45 @@
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */
#define OF_DT_END_NODE 0x2 /* End node */
#define OF_DT_PROP 0x3 /* Property: name off, size,
* content */
#define OF_DT_NOP 0x4 /* nop */
#define OF_DT_END 0x9
#define OF_DT_VERSION 0x10
/*
* This is what gets passed to the kernel by prom_init or kexec
*
* The dt struct contains the device tree structure, full pathes and
* property contents. The dt strings contain a separate block with just
* the strings for the property names, and is fully page aligned and
* self contained in a page, so that it can be kept around by the kernel,
* each property name appears only once in this page (cheap compression)
*
* the mem_rsvmap contains a map of reserved ranges of physical memory,
* passing it here instead of in the device-tree itself greatly simplifies
* the job of everybody. It's just a list of u64 pairs (base/size) that
* ends when size is 0
*/
struct boot_param_header {
__be32 magic; /* magic word OF_DT_HEADER */
__be32 totalsize; /* total size of DT block */
__be32 off_dt_struct; /* offset to structure */
__be32 off_dt_strings; /* offset to strings */
__be32 off_mem_rsvmap; /* offset to memory reserve map */
__be32 version; /* format version */
__be32 last_comp_version; /* last compatible version */
/* version 2 fields below */
__be32 boot_cpuid_phys; /* Physical CPU id we're booting on */
/* version 3 fields below */
__be32 dt_strings_size; /* size of the DT strings block */
/* version 17 fields below */
__be32 dt_struct_size; /* size of the DT structure block */
};
/*
* OF address retreival & translation
*/

View File

@ -2,6 +2,7 @@
# Makefile for the linux kernel.
#
CFLAGS_prom.o = -I$(src)/../../../scripts/dtc/libfdt
CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"'
subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror

View File

@ -36,7 +36,7 @@ static int __init early_init_dt_scan_epapr(unsigned long node,
int depth, void *data)
{
const u32 *insts;
unsigned long len;
int len;
int i;
insts = of_get_flat_dt_prop(node, "hcall-instructions", &len);

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

@ -29,11 +29,11 @@
#include <linux/bitops.h>
#include <linux/export.h>
#include <linux/kexec.h>
#include <linux/debugfs.h>
#include <linux/irq.h>
#include <linux/memblock.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/libfdt.h>
#include <asm/prom.h>
#include <asm/rtas.h>
@ -118,14 +118,14 @@ static void __init move_device_tree(void)
DBG("-> move_device_tree\n");
start = __pa(initial_boot_params);
size = be32_to_cpu(initial_boot_params->totalsize);
size = fdt_totalsize(initial_boot_params);
if ((memory_limit && (start + size) > PHYSICAL_START + memory_limit) ||
overlaps_crashkernel(start, size) ||
overlaps_initrd(start, size)) {
p = __va(memblock_alloc(size, PAGE_SIZE));
memcpy(p, initial_boot_params, size);
initial_boot_params = (struct boot_param_header *)p;
initial_boot_params = p;
DBG("Moved device tree to 0x%p\n", p);
}
@ -163,7 +163,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)
@ -202,8 +202,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)
@ -216,7 +216,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)
{
__be32 *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) {
@ -257,7 +257,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,
@ -295,11 +295,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 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;
@ -325,9 +325,9 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
* version 2 of the kexec param format adds the phys cpuid of
* booted proc.
*/
if (be32_to_cpu(initial_boot_params->version) >= 2) {
if (fdt_version(initial_boot_params) >= 2) {
if (be32_to_cpu(intserv[i]) ==
be32_to_cpu(initial_boot_params->boot_cpuid_phys)) {
fdt_boot_cpuid_phys(initial_boot_params)) {
found = boot_cpu_count;
found_thread = i;
}
@ -392,7 +392,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; /* All these set by kernel, so no need to convert endian */
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)
@ -443,8 +443,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;
@ -564,9 +565,12 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
static void __init early_reserve_mem_dt(void)
{
unsigned long i, len, dt_root;
unsigned long i, dt_root;
int len;
const __be32 *prop;
early_init_fdt_scan_reserved_mem();
dt_root = of_get_flat_dt_root();
prop = of_get_flat_dt_prop(dt_root, "reserved-ranges", &len);
@ -589,24 +593,14 @@ static void __init early_reserve_mem_dt(void)
memblock_reserve(base, size);
}
}
early_init_fdt_scan_reserved_mem();
}
static void __init early_reserve_mem(void)
{
u64 base, size;
__be64 *reserve_map;
unsigned long self_base;
unsigned long self_size;
reserve_map = (__be64 *)(((unsigned long)initial_boot_params) +
be32_to_cpu(initial_boot_params->off_mem_rsvmap));
/* before we do anything, lets reserve the dt blob */
self_base = __pa((unsigned long)initial_boot_params);
self_size = be32_to_cpu(initial_boot_params->totalsize);
memblock_reserve(self_base, self_size);
fdt_off_mem_rsvmap(initial_boot_params));
/* Look for the new "reserved-regions" property in the DT */
early_reserve_mem_dt();
@ -636,26 +630,12 @@ static void __init early_reserve_mem(void)
size_32 = be32_to_cpup(reserve_map_32++);
if (size_32 == 0)
break;
/* skip if the reservation is for the blob */
if (base_32 == self_base && size_32 == self_size)
continue;
DBG("reserving: %x -> %x\n", base_32, size_32);
memblock_reserve(base_32, size_32);
}
return;
}
#endif
DBG("Processing reserve map\n");
/* Handle the reserve map in the fdt blob if it exists */
while (1) {
base = be64_to_cpup(reserve_map++);
size = be64_to_cpup(reserve_map++);
if (size == 0)
break;
DBG("reserving: %llx -> %llx\n", base, size);
memblock_reserve(base, size);
}
}
void __init early_init_devtree(void *params)
@ -922,23 +902,3 @@ bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
{
return (int)phys_id == get_hard_smp_processor_id(cpu);
}
#if defined(CONFIG_DEBUG_FS) && defined(DEBUG)
static struct debugfs_blob_wrapper flat_dt_blob;
static int __init export_flat_device_tree(void)
{
struct dentry *d;
flat_dt_blob.data = initial_boot_params;
flat_dt_blob.size = be32_to_cpu(initial_boot_params->totalsize);
d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR,
powerpc_debugfs_root, &flat_dt_blob);
if (!d)
return 1;
return 0;
}
__initcall(export_flat_device_tree);
#endif

View File

@ -1142,7 +1142,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

@ -269,9 +269,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);
__be32 *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)
@ -324,9 +324,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);
__be32 *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)
@ -406,9 +406,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);
__be64 *addr_prop;
__be32 *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;
@ -550,8 +550,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);
__be32 *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

@ -61,7 +61,7 @@ int __init early_init_dt_scan_opal(unsigned long node,
const char *uname, int depth, void *data)
{
const void *basep, *entryp, *sizep;
unsigned long basesz, entrysz, runtimesz;
int basesz, entrysz, runtimesz;
if (depth != 1 || strcmp(uname, "ibm,opal") != 0)
return 0;
@ -77,11 +77,11 @@ int __init early_init_dt_scan_opal(unsigned long node,
opal.entry = of_read_number(entryp, entrysz/4);
opal.size = of_read_number(sizep, runtimesz/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",
pr_debug("OPAL Entry = 0x%llx (entryp=%p basesz=%d)\n",
opal.entry, entryp, entrysz);
pr_debug("OPAL Entry = 0x%llx (sizep=%p runtimesz=%ld)\n",
pr_debug("OPAL Entry = 0x%llx (sizep=%p runtimesz=%d)\n",
opal.size, sizep, runtimesz);
powerpc_firmware_features |= FW_FEATURE_OPAL;
@ -102,7 +102,7 @@ int __init early_init_dt_scan_opal(unsigned long node,
int __init early_init_dt_scan_recoverable_ranges(unsigned long node,
const char *uname, int depth, void *data)
{
unsigned long i, psize, size;
int i, psize, size;
const __be32 *prop;
if (depth != 1 || strcmp(uname, "ibm,opal") != 0)
@ -359,7 +359,7 @@ int opal_get_chars(uint32_t vtermno, char *buf, int count)
if ((be64_to_cpu(evt) & OPAL_EVENT_CONSOLE_INPUT) == 0)
return 0;
len = cpu_to_be64(count);
rc = opal_console_read(vtermno, &len, buf);
rc = opal_console_read(vtermno, &len, buf);
if (rc == OPAL_SUCCESS)
return be64_to_cpu(len);
return 0;

View File

@ -665,7 +665,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;
@ -698,7 +698,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

@ -152,9 +152,9 @@ EXPORT_SYMBOL_GPL(dcr_resource_len);
#ifdef CONFIG_PPC_DCR_MMIO
u64 of_translate_dcr_address(struct device_node *dev,
unsigned int dcr_n,
unsigned int *out_stride)
static u64 of_translate_dcr_address(struct device_node *dev,
unsigned int dcr_n,
unsigned int *out_stride)
{
struct device_node *dp;
const u32 *p;

View File

@ -206,23 +206,21 @@ static void __init dtb_apic_setup(void)
static void __init x86_flattree_get_config(void)
{
u32 size, map_len;
struct boot_param_header *dt;
void *dt;
if (!initial_dtb)
return;
map_len = max(PAGE_SIZE - (initial_dtb & ~PAGE_MASK),
(u64)sizeof(struct boot_param_header));
map_len = max(PAGE_SIZE - (initial_dtb & ~PAGE_MASK), (u64)128);
dt = early_memremap(initial_dtb, map_len);
size = be32_to_cpu(dt->totalsize);
initial_boot_params = dt = early_memremap(initial_dtb, map_len);
size = of_get_flat_dt_size();
if (map_len < size) {
early_iounmap(dt, map_len);
dt = early_memremap(initial_dtb, size);
initial_boot_params = dt = early_memremap(initial_dtb, size);
map_len = size;
}
initial_boot_params = dt;
unflatten_and_copy_device_tree();
early_iounmap(dt, map_len);
}

View File

@ -74,7 +74,6 @@ extern int initrd_below_start_ok;
#endif
#ifdef CONFIG_OF
extern u32 __dtb_start[];
void *dtb_start = __dtb_start;
#endif
@ -199,7 +198,7 @@ static int __init xtensa_dt_io_area(unsigned long node, const char *uname,
int depth, void *data)
{
const __be32 *ranges;
unsigned long len;
int len;
if (depth > 1)
return 0;

View File

@ -131,9 +131,12 @@ EXPORT_SYMBOL_GPL(platform_get_resource_byname);
*/
int platform_get_irq_byname(struct platform_device *dev, const char *name)
{
struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ,
name);
struct resource *r;
if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node)
return of_irq_get_byname(dev->dev.of_node, name);
r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
return r ? r->start : -ENXIO;
}
EXPORT_SYMBOL_GPL(platform_get_irq_byname);

View File

@ -24,8 +24,7 @@ static DEFINE_SPINLOCK(clk_lock);
* Gate clocks
*/
static void __init rk2928_gate_clk_init(struct device_node *node,
void *data)
static void __init rk2928_gate_clk_init(struct device_node *node)
{
struct clk_onecell_data *clk_data;
const char *clk_parent;

View File

@ -1278,8 +1278,7 @@ static void __init of_sunxi_table_clock_setup(const struct of_device_id *clk_mat
const struct of_device_id *match;
void (*setup_function)(struct device_node *, const void *) = function;
for_each_matching_node(np, clk_match) {
match = of_match_node(clk_match, np);
for_each_matching_node_and_match(np, clk_match, &match) {
data = match->data;
setup_function(np, data);
}
@ -1310,7 +1309,7 @@ static void __init sunxi_clock_protect(void)
}
}
static void __init sunxi_init_clocks(void)
static void __init sunxi_init_clocks(struct device_node *np)
{
/* Register factor clocks */
of_sunxi_table_clock_setup(clk_factors_match, sunxi_factors_clk_setup);

View File

@ -221,7 +221,7 @@ static void __init of_ti_gate_clk_setup(struct device_node *node)
{
_of_ti_gate_clk_setup(node, &omap_gate_clk_ops, NULL);
}
CLK_OF_DECLARE(ti_gate_clk, "ti,gate-clock", of_ti_gate_clk_setup)
CLK_OF_DECLARE(ti_gate_clk, "ti,gate-clock", of_ti_gate_clk_setup);
static void __init of_ti_wait_gate_clk_setup(struct device_node *node)
{

View File

@ -27,7 +27,7 @@ void __init clocksource_of_init(void)
{
struct device_node *np;
const struct of_device_id *match;
clocksource_of_init_fn init_func;
of_init_fn_1 init_func;
unsigned clocksources = 0;
for_each_matching_node_and_match(np, __clksrc_of_table, &match) {

View File

@ -96,7 +96,7 @@ static struct irq_domain_ops icoll_irq_domain_ops = {
.xlate = irq_domain_xlate_onecell,
};
static void __init icoll_of_init(struct device_node *np,
static int __init icoll_of_init(struct device_node *np,
struct device_node *interrupt_parent)
{
icoll_base = of_iomap(np, 0);
@ -110,6 +110,6 @@ static void __init icoll_of_init(struct device_node *np,
icoll_domain = irq_domain_add_linear(np, ICOLL_NUM_IRQS,
&icoll_irq_domain_ops, NULL);
WARN_ON(!icoll_domain);
return icoll_domain ? 0 : -ENODEV;
}
IRQCHIP_DECLARE(mxs, "fsl,icoll", icoll_of_init);

View File

@ -1323,8 +1323,7 @@ static struct s3c24xx_irq_of_ctrl s3c2410_ctrl[] = {
};
int __init s3c2410_init_intc_of(struct device_node *np,
struct device_node *interrupt_parent,
struct s3c24xx_irq_of_ctrl *ctrl, int num_ctrl)
struct device_node *interrupt_parent)
{
return s3c_init_intc_of(np, interrupt_parent,
s3c2410_ctrl, ARRAY_SIZE(s3c2410_ctrl));
@ -1346,8 +1345,7 @@ static struct s3c24xx_irq_of_ctrl s3c2416_ctrl[] = {
};
int __init s3c2416_init_intc_of(struct device_node *np,
struct device_node *interrupt_parent,
struct s3c24xx_irq_of_ctrl *ctrl, int num_ctrl)
struct device_node *interrupt_parent)
{
return s3c_init_intc_of(np, interrupt_parent,
s3c2416_ctrl, ARRAY_SIZE(s3c2416_ctrl));

View File

@ -19,11 +19,11 @@
* special section.
*/
static const struct of_device_id
irqchip_of_match_end __used __section(__irqchip_of_end);
irqchip_of_match_end __used __section(__irqchip_of_table_end);
extern struct of_device_id __irqchip_begin[];
extern struct of_device_id __irqchip_of_table[];
void __init irqchip_init(void)
{
of_irq_init(__irqchip_begin);
of_irq_init(__irqchip_of_table);
}

View File

@ -11,6 +11,8 @@
#ifndef _IRQCHIP_H
#define _IRQCHIP_H
#include <linux/of.h>
/*
* This macro must be used by the different irqchip drivers to declare
* the association between their DT compatible string and their
@ -21,9 +23,6 @@
* @compstr: compatible string of the irqchip driver
* @fn: initialization function
*/
#define IRQCHIP_DECLARE(name,compstr,fn) \
static const struct of_device_id irqchip_of_match_##name \
__used __section(__irqchip_of_table) \
= { .compatible = compstr, .data = fn }
#define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
#endif

View File

@ -20,6 +20,7 @@ config OF_SELFTEST
config OF_FLATTREE
bool
select DTC
select LIBFDT
config OF_EARLY_FLATTREE
bool

View File

@ -1,5 +1,6 @@
obj-y = base.o device.o platform.o
obj-$(CONFIG_OF_FLATTREE) += fdt.o
obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
obj-$(CONFIG_OF_PROMTREE) += pdt.o
obj-$(CONFIG_OF_ADDRESS) += address.o
obj-$(CONFIG_OF_IRQ) += irq.o
@ -10,3 +11,6 @@ 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
CFLAGS_fdt_address.o = -I$(src)/../../scripts/dtc/libfdt

View File

@ -498,8 +498,7 @@ static u64 __of_translate_address(struct device_node *dev,
/* Count address cells & copy address locally */
bus->count_cells(dev, &na, &ns);
if (!OF_CHECK_COUNTS(na, ns)) {
printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
of_node_full_name(dev));
pr_debug("OF: Bad cell count for %s\n", of_node_full_name(dev));
goto bail;
}
memcpy(addr, in_addr, na * 4);
@ -564,25 +563,6 @@ u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr)
}
EXPORT_SYMBOL(of_translate_dma_address);
bool of_can_translate_address(struct device_node *dev)
{
struct device_node *parent;
struct of_bus *bus;
int na, ns;
parent = of_get_parent(dev);
if (parent == NULL)
return false;
bus = of_match_bus(parent);
bus->count_cells(dev, &na, &ns);
of_node_put(parent);
return OF_CHECK_COUNTS(na, ns);
}
EXPORT_SYMBOL(of_can_translate_address);
const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,
unsigned int *flags)
{

View File

@ -695,6 +695,25 @@ struct device_node *of_get_next_parent(struct device_node *node)
}
EXPORT_SYMBOL(of_get_next_parent);
static struct device_node *__of_get_next_child(const struct device_node *node,
struct device_node *prev)
{
struct device_node *next;
if (!node)
return NULL;
next = prev ? prev->sibling : node->child;
for (; next; next = next->sibling)
if (of_node_get(next))
break;
of_node_put(prev);
return next;
}
#define __for_each_child_of_node(parent, child) \
for (child = __of_get_next_child(parent, NULL); child != NULL; \
child = __of_get_next_child(parent, child))
/**
* of_get_next_child - Iterate a node childs
* @node: parent node
@ -710,11 +729,7 @@ struct device_node *of_get_next_child(const struct device_node *node,
unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
next = prev ? prev->sibling : node->child;
for (; next; next = next->sibling)
if (of_node_get(next))
break;
of_node_put(prev);
next = __of_get_next_child(node, prev);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return next;
}
@ -734,6 +749,9 @@ struct device_node *of_get_next_available_child(const struct device_node *node,
struct device_node *next;
unsigned long flags;
if (!node)
return NULL;
raw_spin_lock_irqsave(&devtree_lock, flags);
next = prev ? prev->sibling : node->child;
for (; next; next = next->sibling) {
@ -771,23 +789,78 @@ struct device_node *of_get_child_by_name(const struct device_node *node,
}
EXPORT_SYMBOL(of_get_child_by_name);
static struct device_node *__of_find_node_by_path(struct device_node *parent,
const char *path)
{
struct device_node *child;
int len = strchrnul(path, '/') - path;
if (!len)
return NULL;
__for_each_child_of_node(parent, child) {
const char *name = strrchr(child->full_name, '/');
if (WARN(!name, "malformed device_node %s\n", child->full_name))
continue;
name++;
if (strncmp(path, name, len) == 0 && (strlen(name) == len))
return child;
}
return NULL;
}
/**
* of_find_node_by_path - Find a node matching a full OF path
* @path: The full path to match
* @path: Either the full path to match, or if the path does not
* start with '/', the name of a property of the /aliases
* node (an alias). In the case of an alias, the node
* matching the alias' value will be returned.
*
* Valid paths:
* /foo/bar Full path
* foo Valid alias
* foo/bar Valid alias + relative path
*
* Returns a node pointer with refcount incremented, use
* of_node_put() on it when done.
*/
struct device_node *of_find_node_by_path(const char *path)
{
struct device_node *np = of_allnodes;
struct device_node *np = NULL;
struct property *pp;
unsigned long flags;
if (strcmp(path, "/") == 0)
return of_node_get(of_allnodes);
/* The path could begin with an alias */
if (*path != '/') {
char *p = strchrnul(path, '/');
int len = p - path;
/* of_aliases must not be NULL */
if (!of_aliases)
return NULL;
for_each_property_of_node(of_aliases, pp) {
if (strlen(pp->name) == len && !strncmp(pp->name, path, len)) {
np = of_find_node_by_path(pp->value);
break;
}
}
if (!np)
return NULL;
path = p;
}
/* Step down the tree matching path components */
raw_spin_lock_irqsave(&devtree_lock, flags);
for (; np; np = np->allnext) {
if (np->full_name && (of_node_cmp(np->full_name, path) == 0)
&& of_node_get(np))
break;
if (!np)
np = of_node_get(of_allnodes);
while (np && *path == '/') {
path++; /* Increment past '/' delimiter */
np = __of_find_node_by_path(np, path);
path = strchrnul(path, '/');
}
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
@ -1800,7 +1873,7 @@ int of_update_property(struct device_node *np, struct property *newprop)
{
struct property **next, *oldprop;
unsigned long flags;
int rc, found = 0;
int rc;
rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop);
if (rc)
@ -1809,34 +1882,34 @@ int of_update_property(struct device_node *np, struct property *newprop)
if (!newprop->name)
return -EINVAL;
oldprop = of_find_property(np, newprop->name, NULL);
if (!oldprop)
return of_add_property(np, newprop);
raw_spin_lock_irqsave(&devtree_lock, flags);
next = &np->properties;
while (*next) {
oldprop = __of_find_property(np, newprop->name, NULL);
if (!oldprop) {
/* add the new node */
rc = __of_add_property(np, newprop);
} else while (*next) {
/* replace the node */
if (*next == oldprop) {
/* found the node */
newprop->next = oldprop->next;
*next = newprop;
oldprop->next = np->deadprops;
np->deadprops = oldprop;
found = 1;
break;
}
next = &(*next)->next;
}
raw_spin_unlock_irqrestore(&devtree_lock, flags);
if (!found)
return -ENODEV;
if (rc)
return rc;
/* At early boot, bail out and defer setup to of_init() */
if (!of_kset)
return found ? 0 : -ENODEV;
return 0;
/* Update the sysfs attribute */
sysfs_remove_bin_file(&np->kobj, &oldprop->attr);
if (oldprop)
sysfs_remove_bin_file(&np->kobj, &oldprop->attr);
__of_add_property_sysfs(np, newprop);
return 0;

View File

@ -12,7 +12,6 @@
#include <linux/kernel.h>
#include <linux/initrd.h>
#include <linux/memblock.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_reserved_mem.h>
@ -20,62 +19,13 @@
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/libfdt.h>
#include <linux/debugfs.h>
#include <linux/serial_core.h>
#include <asm/setup.h> /* for COMMAND_LINE_SIZE */
#ifdef CONFIG_PPC
#include <asm/machdep.h>
#endif /* CONFIG_PPC */
#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
@ -86,13 +36,14 @@ void *of_fdt_get_property(struct boot_param_header *blob,
* On match, returns a non-zero value with smaller values returned for more
* specific compatible values.
*/
int of_fdt_is_compatible(struct boot_param_header *blob,
int of_fdt_is_compatible(const void *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) {
@ -110,7 +61,7 @@ int of_fdt_is_compatible(struct boot_param_header *blob,
/**
* of_fdt_match - Return true if node matches a list of compatible values
*/
int of_fdt_match(struct boot_param_header *blob, unsigned long node,
int of_fdt_match(const void *blob, unsigned long node,
const char *const *compat)
{
unsigned int tmp, score = 0;
@ -149,30 +100,29 @@ static void *unflatten_dt_alloc(void **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 void * unflatten_dt_node(struct boot_param_header *blob,
static void * unflatten_dt_node(void *blob,
void *mem,
void **p,
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(*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 = *p;
l = allocl = strlen(pathp) + 1;
*p = PTR_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
@ -190,7 +140,7 @@ static void * 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'
@ -237,32 +187,23 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
}
}
/* 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(*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(*p);
noff = be32_to_cpup(*p + 4);
*p += 8;
if (be32_to_cpu(blob->version) < 0x10)
*p = PTR_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) {
@ -274,26 +215,25 @@ static void * 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 = *p;
pp->value = (__be32 *)p;
*prev_pp = pp;
prev_pp = &pp->next;
}
*p = PTR_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) {
@ -330,19 +270,18 @@ static void * 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(*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;
}
@ -358,12 +297,13 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
* @dt_alloc: An allocator that provides a virtual address to memory
* for the resulting tree
*/
static void __unflatten_device_tree(struct boot_param_header *blob,
static void __unflatten_device_tree(void *blob,
struct device_node **mynodes,
void * (*dt_alloc)(u64 size, u64 align))
{
unsigned long size;
void *start, *mem;
int start;
void *mem;
struct device_node **allnextp = mynodes;
pr_debug(" -> unflatten_device_tree()\n");
@ -374,18 +314,18 @@ static void __unflatten_device_tree(struct boot_param_header *blob,
}
pr_debug("Unflattening device tree:\n");
pr_debug("magic: %08x\n", be32_to_cpu(blob->magic));
pr_debug("size: %08x\n", be32_to_cpu(blob->totalsize));
pr_debug("version: %08x\n", be32_to_cpu(blob->version));
pr_debug("magic: %08x\n", fdt_magic(blob));
pr_debug("size: %08x\n", fdt_totalsize(blob));
pr_debug("version: %08x\n", fdt_version(blob));
if (be32_to_cpu(blob->magic) != OF_DT_HEADER) {
if (fdt_check_header(blob)) {
pr_err("Invalid device tree blob header\n");
return;
}
/* First pass, scan for size */
start = ((void *)blob) + be32_to_cpu(blob->off_dt_struct);
size = (unsigned long)unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);
start = 0;
size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 0);
size = ALIGN(size, 4);
pr_debug(" size is %lx, allocating...\n", size);
@ -399,10 +339,8 @@ static void __unflatten_device_tree(struct boot_param_header *blob,
pr_debug(" unflattening %p...\n", mem);
/* Second pass, do actual unflattening */
start = ((void *)blob) + be32_to_cpu(blob->off_dt_struct);
start = 0;
unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0);
if (be32_to_cpup(start) != OF_DT_END)
pr_warning("Weird tag at end of tree: %08x\n", be32_to_cpup(start));
if (be32_to_cpup(mem + size) != 0xdeadbeef)
pr_warning("End of tree marker overwritten: %08x\n",
be32_to_cpup(mem + size));
@ -427,9 +365,7 @@ static void *kernel_tree_alloc(u64 size, u64 align)
void of_fdt_unflatten_tree(unsigned long *blob,
struct device_node **mynodes)
{
struct boot_param_header *device_tree =
(struct boot_param_header *)blob;
__unflatten_device_tree(device_tree, mynodes, &kernel_tree_alloc);
__unflatten_device_tree(blob, mynodes, &kernel_tree_alloc);
}
EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
@ -437,7 +373,7 @@ EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
int __initdata dt_root_addr_cells;
int __initdata dt_root_size_cells;
struct boot_param_header *initial_boot_params;
void *initial_boot_params;
#ifdef CONFIG_OF_EARLY_FLATTREE
@ -449,8 +385,8 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
{
int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
phys_addr_t base, size;
unsigned long len;
__be32 *prop;
int len;
const __be32 *prop;
int nomap, first = 1;
prop = of_get_flat_dt_prop(node, "reg", &len);
@ -493,7 +429,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
*/
static int __init __reserved_mem_check_root(unsigned long node)
{
__be32 *prop;
const __be32 *prop;
prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
if (!prop || be32_to_cpup(prop) != dt_root_size_cells)
@ -557,9 +493,25 @@ static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname,
*/
void __init early_init_fdt_scan_reserved_mem(void)
{
int n;
u64 base, size;
if (!initial_boot_params)
return;
/* Reserve the dtb region */
early_init_dt_reserve_memory_arch(__pa(initial_boot_params),
fdt_totalsize(initial_boot_params),
0);
/* Process header /memreserve/ fields */
for (n = 0; ; n++) {
fdt_get_mem_rsv(initial_boot_params, n, &base, &size);
if (!size)
break;
early_init_dt_reserve_memory_arch(base, size, 0);
}
of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);
fdt_init_reserved_mem();
}
@ -578,47 +530,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;
}
@ -627,14 +551,15 @@ 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);
return 0;
}
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);
/**
* of_get_flat_dt_size - Return the total size of the FDT
*/
int __init of_get_flat_dt_size(void)
{
return fdt_totalsize(initial_boot_params);
}
/**
@ -643,10 +568,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);
}
/**
@ -676,73 +601,6 @@ struct fdt_scan_status {
void *data;
};
/**
* fdt_scan_node_by_path - iterator for of_scan_flat_dt_by_path function
*/
static int __init fdt_scan_node_by_path(unsigned long node, const char *uname,
int depth, void *data)
{
struct fdt_scan_status *st = data;
/*
* if scan at the requested fdt node has been completed,
* return -ENXIO to abort further scanning
*/
if (depth <= st->depth)
return -ENXIO;
/* requested fdt node has been found, so call iterator function */
if (st->found)
return st->iterator(node, uname, depth, st->data);
/* check if scanning automata is entering next level of fdt nodes */
if (depth == st->depth + 1 &&
strncmp(st->name, uname, st->namelen) == 0 &&
uname[st->namelen] == 0) {
st->depth += 1;
if (st->name[st->namelen] == 0) {
st->found = 1;
} else {
const char *next = st->name + st->namelen + 1;
st->name = next;
st->namelen = strcspn(next, "/");
}
return 0;
}
/* scan next fdt node */
return 0;
}
/**
* of_scan_flat_dt_by_path - scan flattened tree blob and call callback on each
* child of the given path.
* @path: path to start searching for children
* @it: callback function
* @data: context data pointer
*
* This function is used to scan the flattened device-tree starting from the
* node given by path. It is used to extract information (like reserved
* memory), which is required on ealy boot before we can unflatten the tree.
*/
int __init of_scan_flat_dt_by_path(const char *path,
int (*it)(unsigned long node, const char *name, int depth, void *data),
void *data)
{
struct fdt_scan_status st = {path, 0, -1, 0, it, data};
int ret = 0;
if (initial_boot_params)
ret = of_scan_flat_dt(fdt_scan_node_by_path, &st);
if (!st.found)
return -ENOENT;
else if (ret == -ENXIO) /* scan has been completed */
return 0;
else
return ret;
}
const char * __init of_flat_dt_get_machine_name(void)
{
const char *name;
@ -782,7 +640,7 @@ const void * __init of_flat_dt_match_machine(const void *default_match,
}
if (!best_data) {
const char *prop;
long size;
int size;
pr_err("\n unrecognized device tree list:\n[ ");
@ -811,8 +669,8 @@ const void * __init of_flat_dt_match_machine(const void *default_match,
static 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... ");
@ -839,13 +697,68 @@ static inline void early_init_dt_check_for_initrd(unsigned long node)
}
#endif /* CONFIG_BLK_DEV_INITRD */
#ifdef CONFIG_SERIAL_EARLYCON
extern struct of_device_id __earlycon_of_table[];
int __init early_init_dt_scan_chosen_serial(void)
{
int offset;
const char *p;
int l;
const struct of_device_id *match = __earlycon_of_table;
const void *fdt = initial_boot_params;
offset = fdt_path_offset(fdt, "/chosen");
if (offset < 0)
offset = fdt_path_offset(fdt, "/chosen@0");
if (offset < 0)
return -ENOENT;
p = fdt_getprop(fdt, offset, "stdout-path", &l);
if (!p)
p = fdt_getprop(fdt, offset, "linux,stdout-path", &l);
if (!p || !l)
return -ENOENT;
/* Get the node specified by stdout-path */
offset = fdt_path_offset(fdt, p);
if (offset < 0)
return -ENODEV;
while (match->compatible) {
unsigned long addr;
if (fdt_node_check_compatible(fdt, offset, match->compatible)) {
match++;
continue;
}
addr = fdt_translate_address(fdt, offset);
if (!addr)
return -ENXIO;
of_setup_earlycon(addr, match->data);
return 0;
}
return -ENODEV;
}
static int __init setup_of_earlycon(char *buf)
{
if (buf)
return 0;
return early_init_dt_scan_chosen_serial();
}
early_param("earlycon", setup_of_earlycon);
#endif
/**
* early_init_dt_scan_root - fetch the top level address and size cells
*/
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;
@ -867,9 +780,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);
@ -881,9 +794,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) {
@ -891,7 +804,7 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
* The longtrail doesn't have a device_type on the
* /memory node, so look for the node called /memory@0.
*/
if (depth != 1 || strcmp(uname, "memory@0") != 0)
if (!IS_ENABLED(CONFIG_PPC32) || depth != 1 || strcmp(uname, "memory@0") != 0)
return 0;
} else if (strcmp(type, "memory") != 0)
return 0;
@ -904,7 +817,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)) {
@ -927,8 +840,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);
@ -1003,8 +916,8 @@ void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align)
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)" : "");
pr_err("Reserved memory not supported, ignoring range 0x%pa - 0x%pa%s\n",
&base, &size, nomap ? " (nomap)" : "");
return -ENOSYS;
}
#endif
@ -1018,7 +931,7 @@ bool __init early_init_dt_scan(void *params)
initial_boot_params = params;
/* check device tree validity */
if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) {
if (fdt_check_header(params)) {
initial_boot_params = NULL;
return false;
}
@ -1073,9 +986,9 @@ void __init unflatten_and_copy_device_tree(void)
return;
}
size = __be32_to_cpu(initial_boot_params->totalsize);
size = fdt_totalsize(initial_boot_params);
dt = early_init_dt_alloc_memory_arch(size,
__alignof__(struct boot_param_header));
roundup_pow_of_two(FDT_V17_SIZE));
if (dt) {
memcpy(dt, initial_boot_params, size);
@ -1084,4 +997,27 @@ void __init unflatten_and_copy_device_tree(void)
unflatten_device_tree();
}
#if defined(CONFIG_DEBUG_FS) && defined(DEBUG)
static struct debugfs_blob_wrapper flat_dt_blob;
static int __init of_flat_dt_debugfs_export_fdt(void)
{
struct dentry *d = debugfs_create_dir("device-tree", NULL);
if (!d)
return -ENOENT;
flat_dt_blob.data = initial_boot_params;
flat_dt_blob.size = fdt_totalsize(initial_boot_params);
d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR,
d, &flat_dt_blob);
if (!d)
return -ENOENT;
return 0;
}
module_init(of_flat_dt_debugfs_export_fdt);
#endif
#endif /* CONFIG_OF_EARLY_FLATTREE */

241
drivers/of/fdt_address.c Normal file
View File

@ -0,0 +1,241 @@
/*
* FDT Address translation based on u-boot fdt_support.c which in turn was
* based on the kernel unflattened DT address translation code.
*
* (C) Copyright 2007
* Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
*
* Copyright 2010-2011 Freescale Semiconductor, Inc.
*
* 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, or (at your option)
* any later version.
*/
#include <linux/kernel.h>
#include <linux/libfdt.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/sizes.h>
/* Max address size we deal with */
#define OF_MAX_ADDR_CELLS 4
#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
(ns) > 0)
/* Debug utility */
#ifdef DEBUG
static void __init of_dump_addr(const char *s, const __be32 *addr, int na)
{
pr_debug("%s", s);
while(na--)
pr_cont(" %08x", *(addr++));
pr_debug("\n");
}
#else
static void __init of_dump_addr(const char *s, const __be32 *addr, int na) { }
#endif
/* Callbacks for bus specific translators */
struct of_bus {
void (*count_cells)(const void *blob, int parentoffset,
int *addrc, int *sizec);
u64 (*map)(__be32 *addr, const __be32 *range,
int na, int ns, int pna);
int (*translate)(__be32 *addr, u64 offset, int na);
};
/* Default translator (generic bus) */
static void __init fdt_bus_default_count_cells(const void *blob, int parentoffset,
int *addrc, int *sizec)
{
const __be32 *prop;
if (addrc) {
prop = fdt_getprop(blob, parentoffset, "#address-cells", NULL);
if (prop)
*addrc = be32_to_cpup(prop);
else
*addrc = dt_root_addr_cells;
}
if (sizec) {
prop = fdt_getprop(blob, parentoffset, "#size-cells", NULL);
if (prop)
*sizec = be32_to_cpup(prop);
else
*sizec = dt_root_size_cells;
}
}
static u64 __init fdt_bus_default_map(__be32 *addr, const __be32 *range,
int na, int ns, int pna)
{
u64 cp, s, da;
cp = of_read_number(range, na);
s = of_read_number(range + na + pna, ns);
da = of_read_number(addr, na);
pr_debug("FDT: default map, cp=%llx, s=%llx, da=%llx\n",
cp, s, da);
if (da < cp || da >= (cp + s))
return OF_BAD_ADDR;
return da - cp;
}
static int __init fdt_bus_default_translate(__be32 *addr, u64 offset, int na)
{
u64 a = of_read_number(addr, na);
memset(addr, 0, na * 4);
a += offset;
if (na > 1)
addr[na - 2] = cpu_to_fdt32(a >> 32);
addr[na - 1] = cpu_to_fdt32(a & 0xffffffffu);
return 0;
}
/* Array of bus specific translators */
static const struct of_bus of_busses[] __initconst = {
/* Default */
{
.count_cells = fdt_bus_default_count_cells,
.map = fdt_bus_default_map,
.translate = fdt_bus_default_translate,
},
};
static int __init fdt_translate_one(const void *blob, int parent,
const struct of_bus *bus,
const struct of_bus *pbus, __be32 *addr,
int na, int ns, int pna, const char *rprop)
{
const __be32 *ranges;
int rlen;
int rone;
u64 offset = OF_BAD_ADDR;
ranges = fdt_getprop(blob, parent, rprop, &rlen);
if (!ranges)
return 1;
if (rlen == 0) {
offset = of_read_number(addr, na);
memset(addr, 0, pna * 4);
pr_debug("FDT: empty ranges, 1:1 translation\n");
goto finish;
}
pr_debug("FDT: walking ranges...\n");
/* Now walk through the ranges */
rlen /= 4;
rone = na + pna + ns;
for (; rlen >= rone; rlen -= rone, ranges += rone) {
offset = bus->map(addr, ranges, na, ns, pna);
if (offset != OF_BAD_ADDR)
break;
}
if (offset == OF_BAD_ADDR) {
pr_debug("FDT: not found !\n");
return 1;
}
memcpy(addr, ranges + na, 4 * pna);
finish:
of_dump_addr("FDT: parent translation for:", addr, pna);
pr_debug("FDT: with offset: %llx\n", offset);
/* Translate it into parent bus space */
return pbus->translate(addr, offset, pna);
}
/*
* Translate an address from the device-tree into a CPU physical address,
* this walks up the tree and applies the various bus mappings on the
* way.
*
* Note: We consider that crossing any level with #size-cells == 0 to mean
* that translation is impossible (that is we are not dealing with a value
* that can be mapped to a cpu physical address). This is not really specified
* that way, but this is traditionally the way IBM at least do things
*/
u64 __init fdt_translate_address(const void *blob, int node_offset)
{
int parent, len;
const struct of_bus *bus, *pbus;
const __be32 *reg;
__be32 addr[OF_MAX_ADDR_CELLS];
int na, ns, pna, pns;
u64 result = OF_BAD_ADDR;
pr_debug("FDT: ** translation for device %s **\n",
fdt_get_name(blob, node_offset, NULL));
reg = fdt_getprop(blob, node_offset, "reg", &len);
if (!reg) {
pr_err("FDT: warning: device tree node '%s' has no address.\n",
fdt_get_name(blob, node_offset, NULL));
goto bail;
}
/* Get parent & match bus type */
parent = fdt_parent_offset(blob, node_offset);
if (parent < 0)
goto bail;
bus = &of_busses[0];
/* Cound address cells & copy address locally */
bus->count_cells(blob, parent, &na, &ns);
if (!OF_CHECK_COUNTS(na, ns)) {
pr_err("FDT: Bad cell count for %s\n",
fdt_get_name(blob, node_offset, NULL));
goto bail;
}
memcpy(addr, reg, na * 4);
pr_debug("FDT: bus (na=%d, ns=%d) on %s\n",
na, ns, fdt_get_name(blob, parent, NULL));
of_dump_addr("OF: translating address:", addr, na);
/* Translate */
for (;;) {
/* Switch to parent bus */
node_offset = parent;
parent = fdt_parent_offset(blob, node_offset);
/* If root, we have finished */
if (parent < 0) {
pr_debug("FDT: reached root node\n");
result = of_read_number(addr, na);
break;
}
/* Get new parent bus and counts */
pbus = &of_busses[0];
pbus->count_cells(blob, parent, &pna, &pns);
if (!OF_CHECK_COUNTS(pna, pns)) {
pr_err("FDT: Bad cell count for %s\n",
fdt_get_name(blob, node_offset, NULL));
break;
}
pr_debug("FDT: parent bus (na=%d, ns=%d) on %s\n",
pna, pns, fdt_get_name(blob, parent, NULL));
/* Apply bus translation */
if (fdt_translate_one(blob, node_offset, bus, pbus,
addr, na, ns, pna, "ranges"))
break;
/* Complete the move up one level */
na = pna;
ns = pns;
bus = pbus;
of_dump_addr("FDT: one level translation:", addr, na);
}
bail:
return result;
}

View File

@ -405,6 +405,28 @@ int of_irq_get(struct device_node *dev, int index)
return irq_create_of_mapping(&oirq);
}
/**
* of_irq_get_byname - Decode a node's IRQ and return it as a Linux irq number
* @dev: pointer to device tree node
* @name: irq name
*
* Returns Linux irq number on success, or -EPROBE_DEFER if the irq domain
* is not yet created, or error code in case of any other failure.
*/
int of_irq_get_byname(struct device_node *dev, const char *name)
{
int index;
if (unlikely(!name))
return -EINVAL;
index = of_property_match_string(dev, "interrupt-names", name);
if (index < 0)
return index;
return of_irq_get(dev, index);
}
/**
* of_irq_count - Count the number of IRQs a node uses
* @dev: pointer to device tree node

View File

@ -18,8 +18,6 @@ int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq
{
struct device_node *dn, *ppnode;
struct pci_dev *ppdev;
u32 lspec;
__be32 lspec_be;
__be32 laddr[3];
u8 pin;
int rc;
@ -46,7 +44,6 @@ int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq
return -ENODEV;
/* Now we walk up the PCI tree */
lspec = pin;
for (;;) {
/* Get the pci_dev of our parent */
ppdev = pdev->bus->self;
@ -80,14 +77,13 @@ int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq
/* We can only get here if we hit a P2P bridge with no node,
* let's do standard swizzling and try again
*/
lspec = pci_swizzle_interrupt_pin(pdev, lspec);
pin = pci_swizzle_interrupt_pin(pdev, pin);
pdev = ppdev;
}
out_irq->np = ppnode;
out_irq->args_count = 1;
out_irq->args[0] = lspec;
lspec_be = cpu_to_be32(lspec);
out_irq->args[0] = pin;
laddr[0] = cpu_to_be32((pdev->bus->number << 16) | (pdev->devfn << 8));
laddr[1] = laddr[2] = cpu_to_be32(0);
return of_irq_parse_raw(laddr, out_irq);

View File

@ -95,8 +95,8 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
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;
unsigned long len;
__be32 *prop;
int len;
const __be32 *prop;
int nomap;
int ret;
@ -188,7 +188,7 @@ static int __init __reserved_mem_init_node(struct reserved_mem *rmem)
if (!of_flat_dt_is_compatible(rmem->fdt_node, compat))
continue;
if (initfn(rmem, rmem->fdt_node, rmem->name) == 0) {
if (initfn(rmem) == 0) {
pr_info("Reserved memory: initialized node %s, compatible id %s\n",
rmem->name, compat);
return 0;

View File

@ -51,10 +51,6 @@ struct platform_device *of_find_device_by_node(struct device_node *np)
}
EXPORT_SYMBOL(of_find_device_by_node);
#if defined(CONFIG_PPC_DCR)
#include <asm/dcr.h>
#endif
#ifdef CONFIG_OF_ADDRESS
/*
* The following routines scan a subtree and registers a device for
@ -68,66 +64,35 @@ EXPORT_SYMBOL(of_find_device_by_node);
* of_device_make_bus_id - Use the device node data to assign a unique name
* @dev: pointer to device structure that is linked to a device tree node
*
* This routine will first try using either the dcr-reg or the reg property
* value to derive a unique name. As a last resort it will use the node
* name followed by a unique number.
* This routine will first try using the translated bus address to
* derive a unique name. If it cannot, then it will prepend names from
* parent nodes until a unique name can be derived.
*/
void of_device_make_bus_id(struct device *dev)
{
static atomic_t bus_no_reg_magic;
struct device_node *node = dev->of_node;
const __be32 *reg;
u64 addr;
const __be32 *addrp;
int magic;
#ifdef CONFIG_PPC_DCR
/*
* If it's a DCR based device, use 'd' for native DCRs
* and 'D' for MMIO DCRs.
*/
reg = of_get_property(node, "dcr-reg", NULL);
if (reg) {
#ifdef CONFIG_PPC_DCR_NATIVE
dev_set_name(dev, "d%x.%s", *reg, node->name);
#else /* CONFIG_PPC_DCR_NATIVE */
u64 addr = of_translate_dcr_address(node, *reg, NULL);
if (addr != OF_BAD_ADDR) {
dev_set_name(dev, "D%llx.%s",
(unsigned long long)addr, node->name);
/* Construct the name, using parent nodes if necessary to ensure uniqueness */
while (node->parent) {
/*
* If the address can be translated, then that is as much
* uniqueness as we need. Make it the first component and return
*/
reg = of_get_property(node, "reg", NULL);
if (reg && (addr = of_translate_address(node, reg)) != OF_BAD_ADDR) {
dev_set_name(dev, dev_name(dev) ? "%llx.%s:%s" : "%llx.%s",
(unsigned long long)addr, node->name,
dev_name(dev));
return;
}
#endif /* !CONFIG_PPC_DCR_NATIVE */
}
#endif /* CONFIG_PPC_DCR */
/*
* For MMIO, get the physical address
*/
reg = of_get_property(node, "reg", NULL);
if (reg) {
if (of_can_translate_address(node)) {
addr = of_translate_address(node, reg);
} else {
addrp = of_get_address(node, 0, NULL, NULL);
if (addrp)
addr = of_read_number(addrp, 1);
else
addr = OF_BAD_ADDR;
}
if (addr != OF_BAD_ADDR) {
dev_set_name(dev, "%llx.%s",
(unsigned long long)addr, node->name);
return;
}
/* format arguments only used if dev_name() resolves to NULL */
dev_set_name(dev, dev_name(dev) ? "%s:%s" : "%s",
strrchr(node->full_name, '/') + 1, dev_name(dev));
node = node->parent;
}
/*
* No BusID, use the node name and add a globally incremented
* counter (and pray...)
*/
magic = atomic_add_return(1, &bus_no_reg_magic);
dev_set_name(dev, "%s.%d", node->name, magic - 1);
}
/**
@ -149,9 +114,8 @@ struct platform_device *of_device_alloc(struct device_node *np,
return NULL;
/* count the io and irq resources */
if (of_can_translate_address(np))
while (of_address_to_resource(np, num_reg, &temp_res) == 0)
num_reg++;
while (of_address_to_resource(np, num_reg, &temp_res) == 0)
num_reg++;
num_irq = of_irq_count(np);
/* Populate the resource table */

View File

@ -31,6 +31,51 @@ static struct selftest_results {
} \
}
static void __init of_selftest_find_node_by_name(void)
{
struct device_node *np;
np = of_find_node_by_path("/testcase-data");
selftest(np && !strcmp("/testcase-data", np->full_name),
"find /testcase-data failed\n");
of_node_put(np);
/* Test if trailing '/' works */
np = of_find_node_by_path("/testcase-data/");
selftest(!np, "trailing '/' on /testcase-data/ should fail\n");
np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
selftest(np && !strcmp("/testcase-data/phandle-tests/consumer-a", np->full_name),
"find /testcase-data/phandle-tests/consumer-a failed\n");
of_node_put(np);
np = of_find_node_by_path("testcase-alias");
selftest(np && !strcmp("/testcase-data", np->full_name),
"find testcase-alias failed\n");
of_node_put(np);
/* Test if trailing '/' works on aliases */
np = of_find_node_by_path("testcase-alias/");
selftest(!np, "trailing '/' on testcase-alias/ should fail\n");
np = of_find_node_by_path("testcase-alias/phandle-tests/consumer-a");
selftest(np && !strcmp("/testcase-data/phandle-tests/consumer-a", np->full_name),
"find testcase-alias/phandle-tests/consumer-a failed\n");
of_node_put(np);
np = of_find_node_by_path("/testcase-data/missing-path");
selftest(!np, "non-existent path returned node %s\n", np->full_name);
of_node_put(np);
np = of_find_node_by_path("missing-alias");
selftest(!np, "non-existent alias returned node %s\n", np->full_name);
of_node_put(np);
np = of_find_node_by_path("testcase-alias/missing-path");
selftest(!np, "non-existent alias with relative path returned node %s\n", np->full_name);
of_node_put(np);
}
static void __init of_selftest_dynamic(void)
{
struct device_node *np;
@ -431,8 +476,12 @@ static void __init of_selftest_match_node(void)
static void __init of_selftest_platform_populate(void)
{
int irq;
struct device_node *np;
struct device_node *np, *child;
struct platform_device *pdev;
struct of_device_id match[] = {
{ .compatible = "test-device", },
{}
};
np = of_find_node_by_path("/testcase-data");
of_platform_populate(np, of_default_bus_match_table, NULL, NULL);
@ -440,22 +489,32 @@ static void __init of_selftest_platform_populate(void)
/* Test that a missing irq domain returns -EPROBE_DEFER */
np = of_find_node_by_path("/testcase-data/testcase-device1");
pdev = of_find_device_by_node(np);
if (!pdev)
selftest(0, "device 1 creation failed\n");
selftest(pdev, "device 1 creation failed\n");
irq = platform_get_irq(pdev, 0);
if (irq != -EPROBE_DEFER)
selftest(0, "device deferred probe failed - %d\n", irq);
selftest(irq == -EPROBE_DEFER, "device deferred probe failed - %d\n", irq);
/* Test that a parsing failure does not return -EPROBE_DEFER */
np = of_find_node_by_path("/testcase-data/testcase-device2");
pdev = of_find_device_by_node(np);
if (!pdev)
selftest(0, "device 2 creation failed\n");
selftest(pdev, "device 2 creation failed\n");
irq = platform_get_irq(pdev, 0);
if (irq >= 0 || irq == -EPROBE_DEFER)
selftest(0, "device parsing error failed - %d\n", irq);
selftest(irq < 0 && irq != -EPROBE_DEFER, "device parsing error failed - %d\n", irq);
selftest(1, "passed");
np = of_find_node_by_path("/testcase-data/platform-tests");
if (!np) {
pr_err("No testcase data in device tree\n");
return;
}
for_each_child_of_node(np, child) {
struct device_node *grandchild;
of_platform_populate(child, match, NULL, NULL);
for_each_child_of_node(child, grandchild)
selftest(of_find_device_by_node(grandchild),
"Could not create device for node '%s'\n",
grandchild->name);
}
}
static int __init of_selftest(void)
@ -470,6 +529,7 @@ static int __init of_selftest(void)
of_node_put(np);
pr_info("start of selftest - you will see error messages\n");
of_selftest_find_node_by_name();
of_selftest_dynamic();
of_selftest_parse_phandle_with_args();
of_selftest_property_match_string();

View File

@ -1,3 +1,4 @@
#include "tests-phandle.dtsi"
#include "tests-interrupts.dtsi"
#include "tests-match.dtsi"
#include "tests-platform.dtsi"

View File

@ -1,6 +1,10 @@
/ {
testcase-data {
aliases {
testcase-alias = &testcase;
};
testcase: testcase-data {
security-password = "password";
duplicate-name = "duplicate";
duplicate-name { };

View File

@ -0,0 +1,35 @@
/ {
testcase-data {
platform-tests {
#address-cells = <1>;
#size-cells = <0>;
test-device@0 {
compatible = "test-device";
reg = <0x0>;
#address-cells = <1>;
#size-cells = <0>;
dev@100 {
compatible = "test-sub-device";
reg = <0x100>;
};
};
test-device@1 {
compatible = "test-device";
reg = <0x1>;
#address-cells = <1>;
#size-cells = <0>;
dev@100 {
compatible = "test-sub-device";
reg = <0x100>;
};
};
};
};
};

View File

@ -2072,6 +2072,7 @@ static int __init pl011_early_console_setup(struct earlycon_device *device,
return 0;
}
EARLYCON_DECLARE(pl011, pl011_early_console_setup);
OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup);
#else
#define AMBA_CONSOLE NULL

View File

@ -15,6 +15,8 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/serial_core.h>
#include <linux/sizes.h>
#include <linux/mod_devicetable.h>
#ifdef CONFIG_FIX_EARLYCON_MEM
#include <asm/fixmap.h>
@ -32,6 +34,9 @@ static struct earlycon_device early_console_dev = {
.con = &early_con,
};
static const struct of_device_id __earlycon_of_table_sentinel
__used __section(__earlycon_of_table_end);
static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
{
void __iomem *base;
@ -142,3 +147,26 @@ int __init setup_earlycon(char *buf, const char *match,
register_console(early_console_dev.con);
return 0;
}
int __init of_setup_earlycon(unsigned long addr,
int (*setup)(struct earlycon_device *, const char *))
{
int err;
struct uart_port *port = &early_console_dev.port;
port->iotype = UPIO_MEM;
port->mapbase = addr;
port->uartclk = BASE_BAUD * 16;
port->membase = earlycon_map(addr, SZ_4K);
early_console_dev.con->data = &early_console_dev;
err = setup(&early_console_dev, NULL);
if (err < 0)
return err;
if (!early_console_dev.con->write)
return -ENODEV;
register_console(early_console_dev.con);
return 0;
}

View File

@ -139,52 +139,23 @@
#define TRACE_SYSCALLS()
#endif
#ifdef CONFIG_CLKSRC_OF
#define CLKSRC_OF_TABLES() . = ALIGN(8); \
VMLINUX_SYMBOL(__clksrc_of_table) = .; \
*(__clksrc_of_table) \
*(__clksrc_of_table_end)
#else
#define CLKSRC_OF_TABLES()
#endif
#ifdef CONFIG_IRQCHIP
#define IRQCHIP_OF_MATCH_TABLE() \
#define ___OF_TABLE(cfg, name) _OF_TABLE_##cfg(name)
#define __OF_TABLE(cfg, name) ___OF_TABLE(cfg, name)
#define OF_TABLE(cfg, name) __OF_TABLE(config_enabled(cfg), name)
#define _OF_TABLE_0(name)
#define _OF_TABLE_1(name) \
. = ALIGN(8); \
VMLINUX_SYMBOL(__irqchip_begin) = .; \
*(__irqchip_of_table) \
*(__irqchip_of_end)
#else
#define IRQCHIP_OF_MATCH_TABLE()
#endif
VMLINUX_SYMBOL(__##name##_of_table) = .; \
*(__##name##_of_table) \
*(__##name##_of_table_end)
#ifdef CONFIG_COMMON_CLK
#define CLK_OF_TABLES() . = ALIGN(8); \
VMLINUX_SYMBOL(__clk_of_table) = .; \
*(__clk_of_table) \
*(__clk_of_table_end)
#else
#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
#ifdef CONFIG_SMP
#define CPU_METHOD_OF_TABLES() . = ALIGN(8); \
VMLINUX_SYMBOL(__cpu_method_of_table_begin) = .; \
*(__cpu_method_of_table) \
VMLINUX_SYMBOL(__cpu_method_of_table_end) = .;
#else
#define CPU_METHOD_OF_TABLES()
#endif
#define CLKSRC_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc)
#define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip)
#define CLK_OF_TABLES() OF_TABLE(CONFIG_COMMON_CLK, clk)
#define RESERVEDMEM_OF_TABLES() OF_TABLE(CONFIG_OF_RESERVED_MEM, reservedmem)
#define CPU_METHOD_OF_TABLES() OF_TABLE(CONFIG_SMP, cpu_method)
#define EARLYCON_OF_TABLES() OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
#define KERNEL_DTB() \
STRUCT_ALIGN(); \
@ -513,7 +484,8 @@
CLKSRC_OF_TABLES() \
CPU_METHOD_OF_TABLES() \
KERNEL_DTB() \
IRQCHIP_OF_MATCH_TABLE()
IRQCHIP_OF_MATCH_TABLE() \
EARLYCON_OF_TABLES()
#define INIT_TEXT \
*(.init.text) \

View File

@ -529,10 +529,7 @@ struct clk_onecell_data {
extern struct of_device_id __clk_of_table;
#define CLK_OF_DECLARE(name, compat, fn) \
static const struct of_device_id __clk_of_table_##name \
__used __section(__clk_of_table) \
= { .compatible = compat, .data = fn };
#define CLK_OF_DECLARE(name, compat, fn) OF_DECLARE_1(clk, name, compat, fn)
#ifdef CONFIG_OF
int of_clk_add_provider(struct device_node *np,

View File

@ -339,23 +339,13 @@ extern int clocksource_mmio_init(void __iomem *, const char *,
extern int clocksource_i8253_init(void);
struct device_node;
typedef void(*clocksource_of_init_fn)(struct device_node *);
#define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \
OF_DECLARE_1(clksrc, name, compat, fn)
#ifdef CONFIG_CLKSRC_OF
extern void clocksource_of_init(void);
#define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \
static const struct of_device_id __clksrc_of_table_##name \
__used __section(__clksrc_of_table) \
= { .compatible = compat, \
.data = (fn == (clocksource_of_init_fn)NULL) ? fn : fn }
#else
static inline void clocksource_of_init(void) {}
#define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \
static const struct of_device_id __clksrc_of_table_##name \
__attribute__((unused)) \
= { .compatible = compat, \
.data = (fn == (clocksource_of_init_fn)NULL) ? fn : fn }
#endif
#endif /* _LINUX_CLOCKSOURCE_H */

View File

@ -764,4 +764,26 @@ static inline int of_get_available_child_count(const struct device_node *np)
return num;
}
#ifdef CONFIG_OF
#define _OF_DECLARE(table, name, compat, fn, fn_type) \
static const struct of_device_id __of_table_##name \
__used __section(__##table##_of_table) \
= { .compatible = compat, \
.data = (fn == (fn_type)NULL) ? fn : fn }
#else
#define _OF_DECLARE(table, name, compat, fn, fn_type) \
static const struct of_device_id __of_table_##name \
__attribute__((unused)) \
= { .compatible = compat, \
.data = (fn == (fn_type)NULL) ? fn : fn }
#endif
typedef int (*of_init_fn_2)(struct device_node *, struct device_node *);
typedef void (*of_init_fn_1)(struct device_node *);
#define OF_DECLARE_1(table, name, compat, fn) \
_OF_DECLARE(table, name, compat, fn, of_init_fn_1)
#define OF_DECLARE_2(table, name, compat, fn) \
_OF_DECLARE(table, name, compat, fn, of_init_fn_2)
#endif /* _LINUX_OF_H */

View File

@ -40,7 +40,6 @@ extern u64 of_translate_dma_address(struct device_node *dev,
#ifdef CONFIG_OF_ADDRESS
extern u64 of_translate_address(struct device_node *np, const __be32 *addr);
extern bool of_can_translate_address(struct device_node *dev);
extern int of_address_to_resource(struct device_node *dev, int index,
struct resource *r);
extern struct device_node *of_find_matching_node_by_address(

View File

@ -17,60 +17,23 @@
/* Definitions used by the flattened device tree */
#define OF_DT_HEADER 0xd00dfeed /* marker */
#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */
#define OF_DT_END_NODE 0x2 /* End node */
#define OF_DT_PROP 0x3 /* Property: name off, size,
* content */
#define OF_DT_NOP 0x4 /* nop */
#define OF_DT_END 0x9
#define OF_DT_VERSION 0x10
#ifndef __ASSEMBLY__
/*
* This is what gets passed to the kernel by prom_init or kexec
*
* The dt struct contains the device tree structure, full pathes and
* property contents. The dt strings contain a separate block with just
* the strings for the property names, and is fully page aligned and
* self contained in a page, so that it can be kept around by the kernel,
* each property name appears only once in this page (cheap compression)
*
* the mem_rsvmap contains a map of reserved ranges of physical memory,
* passing it here instead of in the device-tree itself greatly simplifies
* the job of everybody. It's just a list of u64 pairs (base/size) that
* ends when size is 0
*/
struct boot_param_header {
__be32 magic; /* magic word OF_DT_HEADER */
__be32 totalsize; /* total size of DT block */
__be32 off_dt_struct; /* offset to structure */
__be32 off_dt_strings; /* offset to strings */
__be32 off_mem_rsvmap; /* offset to memory reserve map */
__be32 version; /* format version */
__be32 last_comp_version; /* last compatible version */
/* version 2 fields below */
__be32 boot_cpuid_phys; /* Physical CPU id we're booting on */
/* version 3 fields below */
__be32 dt_strings_size; /* size of the DT strings block */
/* version 17 fields below */
__be32 dt_struct_size; /* size of the DT structure block */
};
#if defined(CONFIG_OF_FLATTREE)
struct device_node;
/* For scanning an arbitrary device-tree at any time */
extern char *of_fdt_get_string(struct boot_param_header *blob, u32 offset);
extern void *of_fdt_get_property(struct boot_param_header *blob,
extern char *of_fdt_get_string(const void *blob, u32 offset);
extern void *of_fdt_get_property(const void *blob,
unsigned long node,
const char *name,
unsigned long *size);
extern int of_fdt_is_compatible(struct boot_param_header *blob,
int *size);
extern int of_fdt_is_compatible(const void *blob,
unsigned long node,
const char *compat);
extern int of_fdt_match(struct boot_param_header *blob, unsigned long node,
extern int of_fdt_match(const void *blob, unsigned long node,
const char *const *compat);
extern void of_fdt_unflatten_tree(unsigned long *blob,
struct device_node **mynodes);
@ -78,21 +41,21 @@ extern void of_fdt_unflatten_tree(unsigned long *blob,
/* TBD: Temporary export of fdt globals - remove when code fully merged */
extern int __initdata dt_root_addr_cells;
extern int __initdata dt_root_size_cells;
extern struct boot_param_header *initial_boot_params;
extern void *initial_boot_params;
extern char __dtb_start[];
extern char __dtb_end[];
/* 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);
extern int of_scan_flat_dt_by_path(const char *path,
int (*it)(unsigned long node, const char *name, int depth, void *data),
void *data);
extern int of_get_flat_dt_size(void);
extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
int depth, void *data);
@ -103,7 +66,7 @@ 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);
/* Early flat tree scan hooks */
extern int early_init_dt_scan_root(unsigned long node, const char *uname,
@ -120,6 +83,7 @@ extern void unflatten_device_tree(void);
extern void unflatten_and_copy_device_tree(void);
extern void early_init_devtree(void *);
extern void early_get_first_memblock_info(void *, phys_addr_t *);
extern u64 fdt_translate_address(const void *blob, int node_offset);
#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; }

View File

@ -45,6 +45,7 @@ extern void of_irq_init(const struct of_device_id *matches);
#ifdef CONFIG_OF_IRQ
extern int of_irq_count(struct device_node *dev);
extern int of_irq_get(struct device_node *dev, int index);
extern int of_irq_get_byname(struct device_node *dev, const char *name);
#else
static inline int of_irq_count(struct device_node *dev)
{
@ -54,6 +55,10 @@ static inline int of_irq_get(struct device_node *dev, int index)
{
return 0;
}
static inline int of_irq_get_byname(struct device_node *dev, const char *name)
{
return 0;
}
#endif
#if defined(CONFIG_OF)

View File

@ -6,14 +6,44 @@
struct pci_dev;
struct of_phandle_args;
int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq);
int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin);
struct device_node;
#ifdef CONFIG_OF
int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq);
struct device_node *of_pci_find_child_device(struct device_node *parent,
unsigned int devfn);
int of_pci_get_devfn(struct device_node *np);
int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin);
int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
#else
static inline int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq)
{
return 0;
}
static inline struct device_node *of_pci_find_child_device(struct device_node *parent,
unsigned int devfn)
{
return NULL;
}
static inline int of_pci_get_devfn(struct device_node *np)
{
return -EINVAL;
}
static inline int
of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin)
{
return 0;
}
static inline int
of_pci_parse_bus_range(struct device_node *node, struct resource *res)
{
return -EINVAL;
}
#endif
#if defined(CONFIG_OF) && defined(CONFIG_PCI_MSI)
int of_pci_msi_chip_add(struct msi_chip *chip);

View File

@ -21,33 +21,19 @@ struct reserved_mem_ops {
struct device *dev);
};
typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem,
unsigned long node, const char *uname);
typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem);
#define RESERVEDMEM_OF_DECLARE(name, compat, init) \
_OF_DECLARE(reservedmem, name, compat, init, reservedmem_of_init_fn)
#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

@ -294,6 +294,9 @@ struct earlycon_device {
int setup_earlycon(char *buf, const char *match,
int (*setup)(struct earlycon_device *, const char *));
extern int of_setup_earlycon(unsigned long addr,
int (*setup)(struct earlycon_device *, const char *));
#define EARLYCON_DECLARE(name, func) \
static int __init name ## _setup_earlycon(char *buf) \
{ \
@ -301,6 +304,9 @@ static int __init name ## _setup_earlycon(char *buf) \
} \
early_param("earlycon", name ## _setup_earlycon);
#define OF_EARLYCON_DECLARE(name, compat, fn) \
_OF_DECLARE(earlycon, name, compat, fn, void *)
struct uart_port *uart_get_console(struct uart_port *ports, int nr,
struct console *c);
void uart_parse_options(char *options, int *baud, int *parity, int *bits,

View File

@ -52,6 +52,9 @@ extern int strncasecmp(const char *s1, const char *s2, size_t n);
#ifndef __HAVE_ARCH_STRCHR
extern char * strchr(const char *,int);
#endif
#ifndef __HAVE_ARCH_STRCHRNUL
extern char * strchrnul(const char *,int);
#endif
#ifndef __HAVE_ARCH_STRNCHR
extern char * strnchr(const char *, size_t, int);
#endif

View File

@ -301,6 +301,24 @@ char *strchr(const char *s, int c)
EXPORT_SYMBOL(strchr);
#endif
#ifndef __HAVE_ARCH_STRCHRNUL
/**
* strchrnul - Find and return a character in a string, or end of string
* @s: The string to be searched
* @c: The character to search for
*
* Returns pointer to first occurrence of 'c' in s. If c is not found, then
* return a pointer to the null byte at the end of s.
*/
char *strchrnul(const char *s, int c)
{
while (*s && *s != (char)c)
s++;
return (char *)s;
}
EXPORT_SYMBOL(strchrnul);
#endif
#ifndef __HAVE_ARCH_STRRCHR
/**
* strrchr - Find the last occurrence of a character in a string