Commit b9f2b21a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'dt-for-linus' of git://git.secretlab.ca/git/linux

Pull devicetree changes from Grant Likely:
 "Updates to devicetree core code.  This branch contains the following
  notable changes:

   - add reserved memory binding
   - make struct device_node a kobject and remove legacy
     /proc/device-tree
   - ePAPR conformance fixes
   - update in-kernel DTC copy to version v1.4.0
   - preparatory changes for dynamic device tree overlays
   - minor bug fixes and documentation changes

  The most significant change in this branch is the conversion of struct
  device_node to be a kobject that is exposed via sysfs and removal of
  the old /proc/device-tree code.  This simplifies the device tree
  handling code and tightens up the lifecycle on device tree nodes.

  [updated: added fix for dangling select PROC_DEVICETREE]"

* tag 'dt-for-linus' of git://git.secretlab.ca/git/linux: (29 commits)
  dt: Remove dangling "select PROC_DEVICETREE"
  of: Add support for ePAPR "stdout-path" property
  of: device_node kobject lifecycle fixes
  of: only scan for reserved mem when fdt present
  powerpc: add support for reserved memory defined by device tree
  arm64: add support for reserved memory defined by device tree
  of: add missing major vendors
  of: add vendor prefix for SMSC
  of: remove /proc/device-tree
  of/selftest: Add self tests for manipulation of properties
  of: Make device nodes kobjects so they show up in sysfs
  arm: add support for reserved memory defined by device tree
  drivers: of: add support for custom reserved memory drivers
  drivers: of: add initialization code for dynamic reserved memory
  drivers: of: add initialization code for static reserved memory
  of: document bindings for reserved-memory nodes
  Revert "of: fix of_update_property()"
  kbuild: dtbs_install: new make target
  ARM: mvebu: Allows to get the SoC ID even without PCI enabled
  of: Allows to use the PCI translator without the PCI core
  ...
parents 70f6c087 a0e73983
What: /sys/firmware/devicetree/*
Date: November 2013
Contact: Grant Likely <grant.likely@linaro.org>
Description:
When using OpenFirmware or a Flattened Device Tree to enumerate
hardware, the device tree structure will be exposed in this
directory.
It is possible for multiple device-tree directories to exist.
Some device drivers use a separate detached device tree which
have no attachment to the system tree and will appear in a
different subdirectory under /sys/firmware/devicetree.
Userspace must not use the /sys/firmware/devicetree/base
path directly, but instead should follow /proc/device-tree
symlink. It is possible that the absolute path will change
in the future, but the symlink is the stable ABI.
The /proc/device-tree symlink replaces the devicetree /proc
filesystem support, and has largely the same semantics and
should be compatible with existing userspace.
The contents of /sys/firmware/devicetree/ is a
hierarchy of directories, one per device tree node. The
directory name is the resolved path component name (node
name plus address). Properties are represented as files
in the directory. The contents of each file is the exact
binary data from the device tree.
*** Reserved memory regions ***
Reserved memory is specified as a node under the /reserved-memory node.
The operating system shall exclude reserved memory from normal usage
one can create child nodes describing particular reserved (excluded from
normal use) memory regions. Such memory regions are usually designed for
the special usage by various device drivers.
Parameters for each memory region can be encoded into the device tree
with the following nodes:
/reserved-memory node
---------------------
#address-cells, #size-cells (required) - standard definition
- Should use the same values as the root node
ranges (required) - standard definition
- Should be empty
/reserved-memory/ child nodes
-----------------------------
Each child of the reserved-memory node specifies one or more regions of
reserved memory. Each child node may either use a 'reg' property to
specify a specific range of reserved memory, or a 'size' property with
optional constraints to request a dynamically allocated block of memory.
Following the generic-names recommended practice, node names should
reflect the purpose of the node (ie. "framebuffer" or "dma-pool"). Unit
address (@<address>) should be appended to the name if the node is a
static allocation.
Properties:
Requires either a) or b) below.
a) static allocation
reg (required) - standard definition
b) dynamic allocation
size (required) - length based on parent's #size-cells
- Size in bytes of memory to reserve.
alignment (optional) - length based on parent's #size-cells
- Address boundary for alignment of allocation.
alloc-ranges (optional) - prop-encoded-array (address, length pairs).
- Specifies regions of memory that are
acceptable to allocate from.
If both reg and size are present, then the reg property takes precedence
and size is ignored.
Additional properties:
compatible (optional) - standard definition
- may contain the following strings:
- shared-dma-pool: This indicates a region of memory meant to be
used as a shared pool of DMA buffers for a set of devices. It can
be used by an operating system to instanciate the necessary pool
management subsystem if necessary.
- vendor specific string in the form <vendor>,[<device>-]<usage>
no-map (optional) - empty property
- Indicates the operating system must not create a virtual mapping
of the region as part of its standard mapping of system memory,
nor permit speculative access to it under any circumstances other
than under the control of the device driver using the region.
reusable (optional) - empty property
- The operating system can use the memory in this region with the
limitation that the device driver(s) owning the region need to be
able to reclaim it back. Typically that means that the operating
system can use that region to store volatile or cached data that
can be otherwise regenerated or migrated elsewhere.
Linux implementation note:
- If a "linux,cma-default" property is present, then Linux will use the
region for the default pool of the contiguous memory allocator.
Device node references to reserved memory
-----------------------------------------
Regions in the /reserved-memory node may be referenced by other device
nodes by adding a memory-region property to the device node.
memory-region (optional) - phandle, specifier pairs to children of /reserved-memory
Example
-------
This example defines 3 contiguous regions are defined for Linux kernel:
one default of all device drivers (named linux,cma@72000000 and 64MiB in size),
one dedicated to the framebuffer device (named framebuffer@78000000, 8MiB), and
one for multimedia processing (named multimedia-memory@77000000, 64MiB).
/ {
#address-cells = <1>;
#size-cells = <1>;
memory {
reg = <0x40000000 0x40000000>;
};
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
/* global autoconfigured region for contiguous allocations */
linux,cma {
compatible = "shared-dma-pool";
reusable;
size = <0x4000000>;
alignment = <0x2000>;
linux,cma-default;
};
display_reserved: framebuffer@78000000 {
reg = <0x78000000 0x800000>;
};
multimedia_reserved: multimedia@77000000 {
compatible = "acme,multimedia-memory";
reg = <0x77000000 0x4000000>;
};
};
/* ... */
fb0: video@12300000 {
memory-region = <&display_reserved>;
/* ... */
};
scaler: scaler@12500000 {
memory-region = <&multimedia_reserved>;
/* ... */
};
codec: codec@12600000 {
memory-region = <&multimedia_reserved>;
/* ... */
};
};
...@@ -3,6 +3,7 @@ Device tree binding vendor prefix registry. Keep list in alphabetical order. ...@@ -3,6 +3,7 @@ Device tree binding vendor prefix registry. Keep list in alphabetical order.
This isn't an exhaustive list, but you should add new prefixes to it before This isn't an exhaustive list, but you should add new prefixes to it before
using them to avoid name-space collisions. using them to avoid name-space collisions.
abilis Abilis Systems
active-semi Active-Semi International Inc active-semi Active-Semi International Inc
ad Avionic Design GmbH ad Avionic Design GmbH
adi Analog Devices, Inc. adi Analog Devices, Inc.
...@@ -11,14 +12,17 @@ ak Asahi Kasei Corp. ...@@ -11,14 +12,17 @@ ak Asahi Kasei Corp.
allwinner Allwinner Technology Co., Ltd. allwinner Allwinner Technology Co., Ltd.
altr Altera Corp. altr Altera Corp.
amcc Applied Micro Circuits Corporation (APM, formally AMCC) amcc Applied Micro Circuits Corporation (APM, formally AMCC)
amd Advanced Micro Devices (AMD), Inc.
amstaos AMS-Taos Inc. amstaos AMS-Taos Inc.
apm Applied Micro Circuits Corporation (APM) apm Applied Micro Circuits Corporation (APM)
arm ARM Ltd. arm ARM Ltd.
armadeus ARMadeus Systems SARL
atmel Atmel Corporation atmel Atmel Corporation
auo AU Optronics Corporation auo AU Optronics Corporation
avago Avago Technologies avago Avago Technologies
bosch Bosch Sensortec GmbH bosch Bosch Sensortec GmbH
brcm Broadcom Corporation brcm Broadcom Corporation
calxeda Calxeda
capella Capella Microsystems, Inc capella Capella Microsystems, Inc
cavium Cavium, Inc. cavium Cavium, Inc.
cdns Cadence Design Systems Inc. cdns Cadence Design Systems Inc.
...@@ -26,8 +30,10 @@ chrp Common Hardware Reference Platform ...@@ -26,8 +30,10 @@ chrp Common Hardware Reference Platform
chunghwa Chunghwa Picture Tubes Ltd. chunghwa Chunghwa Picture Tubes Ltd.
cirrus Cirrus Logic, Inc. cirrus Cirrus Logic, Inc.
cortina Cortina Systems, Inc. cortina Cortina Systems, Inc.
crystalfontz Crystalfontz America, Inc.
dallas Maxim Integrated Products (formerly Dallas Semiconductor) dallas Maxim Integrated Products (formerly Dallas Semiconductor)
davicom DAVICOM Semiconductor, Inc. davicom DAVICOM Semiconductor, Inc.
dlink D-Link Systems, Inc.
denx Denx Software Engineering denx Denx Software Engineering
edt Emerging Display Technologies edt Emerging Display Technologies
emmicro EM Microelectronic emmicro EM Microelectronic
...@@ -37,7 +43,9 @@ est ESTeem Wireless Modems ...@@ -37,7 +43,9 @@ est ESTeem Wireless Modems
fsl Freescale Semiconductor fsl Freescale Semiconductor
GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc. GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc.
gef GE Fanuc Intelligent Platforms Embedded Systems, Inc. gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
globalscale Globalscale Technologies, Inc.
gmt Global Mixed-mode Technology, Inc. gmt Global Mixed-mode Technology, Inc.
google Google, Inc.
gumstix Gumstix, Inc. gumstix Gumstix, Inc.
haoyu Haoyu Microelectronic Co. Ltd. haoyu Haoyu Microelectronic Co. Ltd.
hisilicon Hisilicon Limited. hisilicon Hisilicon Limited.
...@@ -46,9 +54,12 @@ hp Hewlett Packard ...@@ -46,9 +54,12 @@ hp Hewlett Packard
ibm International Business Machines (IBM) ibm International Business Machines (IBM)
idt Integrated Device Technologies, Inc. idt Integrated Device Technologies, Inc.
img Imagination Technologies Ltd. img Imagination Technologies Ltd.
intel Intel Corporation
intercontrol Inter Control Group intercontrol Inter Control Group
isl Intersil isl Intersil
karo Ka-Ro electronics GmbH karo Ka-Ro electronics GmbH
lacie LaCie
lantiq Lantiq Semiconductor
lg LG Corporation lg LG Corporation
linux Linux-specific binding linux Linux-specific binding
lsi LSI Corp. (LSI Logic) lsi LSI Corp. (LSI Logic)
...@@ -56,12 +67,16 @@ marvell Marvell Technology Group Ltd. ...@@ -56,12 +67,16 @@ marvell Marvell Technology Group Ltd.
maxim Maxim Integrated Products maxim Maxim Integrated Products
microchip Microchip Technology Inc. microchip Microchip Technology Inc.
mosaixtech Mosaix Technologies, Inc. mosaixtech Mosaix Technologies, Inc.
moxa Moxa
national National Semiconductor national National Semiconductor
neonode Neonode Inc. neonode Neonode Inc.
netgear NETGEAR
nintendo Nintendo nintendo Nintendo
nokia Nokia
nvidia NVIDIA nvidia NVIDIA
nxp NXP Semiconductors nxp NXP Semiconductors
onnn ON Semiconductor Corp. onnn ON Semiconductor Corp.
opencores OpenCores.org
panasonic Panasonic Corporation panasonic Panasonic Corporation
phytec PHYTEC Messtechnik GmbH phytec PHYTEC Messtechnik GmbH
picochip Picochip Ltd picochip Picochip Ltd
...@@ -80,6 +95,7 @@ sil Silicon Image ...@@ -80,6 +95,7 @@ sil Silicon Image
silabs Silicon Laboratories silabs Silicon Laboratories
simtek simtek
sirf SiRF Technology, Inc. sirf SiRF Technology, Inc.
smsc Standard Microsystems Corporation
snps Synopsys, Inc. snps Synopsys, Inc.
spansion Spansion Inc. spansion Spansion Inc.
st STMicroelectronics st STMicroelectronics
...@@ -94,4 +110,5 @@ via VIA Technologies, Inc. ...@@ -94,4 +110,5 @@ via VIA Technologies, Inc.
winbond Winbond Electronics corp. winbond Winbond Electronics corp.
wlf Wolfson Microelectronics wlf Wolfson Microelectronics
wm Wondermedia Technologies, Inc. wm Wondermedia Technologies, Inc.
xes Extreme Engineering Solutions (X-ES)
xlnx Xilinx xlnx Xilinx
...@@ -728,6 +728,13 @@ export KBUILD_IMAGE ?= vmlinux ...@@ -728,6 +728,13 @@ export KBUILD_IMAGE ?= vmlinux
# images. Default is /boot, but you can set it to other values # images. Default is /boot, but you can set it to other values
export INSTALL_PATH ?= /boot export INSTALL_PATH ?= /boot
#
# INSTALL_DTBS_PATH specifies a prefix for relocations required by build roots.
# Like INSTALL_MOD_PATH, it isn't defined in the Makefile, but can be passed as
# an argument if needed. Otherwise it defaults to the kernel install path
#
export INSTALL_DTBS_PATH ?= $(INSTALL_PATH)/dtbs/$(KERNELRELEASE)
# #
# INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory # INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory
# relocations required by build roots. This is not defined in the # relocations required by build roots. This is not defined in the
......
...@@ -1918,6 +1918,7 @@ config USE_OF ...@@ -1918,6 +1918,7 @@ config USE_OF
select IRQ_DOMAIN select IRQ_DOMAIN
select OF select OF
select OF_EARLY_FLATTREE select OF_EARLY_FLATTREE
select OF_RESERVED_MEM
help help
Include support for flattened device tree machine descriptions. Include support for flattened device tree machine descriptions.
......
...@@ -310,9 +310,9 @@ $(INSTALL_TARGETS): ...@@ -310,9 +310,9 @@ $(INSTALL_TARGETS):
%.dtb: | scripts %.dtb: | scripts
$(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $(boot)/dts/$@ $(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $(boot)/dts/$@
PHONY += dtbs PHONY += dtbs dtbs_install
dtbs: scripts dtbs dtbs_install: prepare scripts
$(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) dtbs $(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $@
# We use MRPROPER_FILES and CLEAN_FILES now # We use MRPROPER_FILES and CLEAN_FILES now
archclean: archclean:
...@@ -331,6 +331,7 @@ define archhelp ...@@ -331,6 +331,7 @@ define archhelp
echo ' bootpImage - Combined zImage and initial RAM disk' echo ' bootpImage - Combined zImage and initial RAM disk'
echo ' (supply initrd image via make variable INITRD=<path>)' echo ' (supply initrd image via make variable INITRD=<path>)'
echo '* dtbs - Build device tree blobs for enabled boards' echo '* dtbs - Build device tree blobs for enabled boards'
echo ' dtbs_install - Install dtbs to $(INSTALL_DTBS_PATH)'
echo ' install - Install uncompressed kernel' echo ' install - Install uncompressed kernel'
echo ' zinstall - Install compressed kernel' echo ' zinstall - Install compressed kernel'
echo ' uinstall - Install U-Boot wrapped compressed kernel' echo ' uinstall - Install U-Boot wrapped compressed kernel'
......
...@@ -323,7 +323,7 @@ dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb \ ...@@ -323,7 +323,7 @@ dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb \
zynq-zc706.dtb \ zynq-zc706.dtb \
zynq-zed.dtb zynq-zed.dtb
targets += dtbs targets += dtbs dtbs_install
targets += $(dtb-y) targets += $(dtb-y)
endif endif
...@@ -333,3 +333,5 @@ dtbs: $(addprefix $(obj)/, $(dtb-y)) ...@@ -333,3 +333,5 @@ dtbs: $(addprefix $(obj)/, $(dtb-y))
$(Q)rm -f $(obj)/../*.dtb $(Q)rm -f $(obj)/../*.dtb
clean-files := *.dtb clean-files := *.dtb
dtbs_install: $(addsuffix _dtbinst_, $(dtb-y))
...@@ -16,6 +16,7 @@ config ARCH_MVEBU ...@@ -16,6 +16,7 @@ config ARCH_MVEBU
select ARCH_REQUIRE_GPIOLIB select ARCH_REQUIRE_GPIOLIB
select MIGHT_HAVE_PCI select MIGHT_HAVE_PCI
select PCI_QUIRKS if PCI select PCI_QUIRKS if PCI
select OF_ADDRESS_PCI
if ARCH_MVEBU if ARCH_MVEBU
......
...@@ -102,7 +102,6 @@ config ARCH_OMAP2PLUS ...@@ -102,7 +102,6 @@ config ARCH_OMAP2PLUS
select MACH_OMAP_GENERIC select MACH_OMAP_GENERIC
select OMAP_DM_TIMER select OMAP_DM_TIMER
select PINCTRL select PINCTRL
select PROC_DEVICETREE if PROC_FS
select SOC_BUS select SOC_BUS
select SPARSE_IRQ select SPARSE_IRQ
select TI_PRIV_EDMA select TI_PRIV_EDMA
......
...@@ -323,6 +323,8 @@ void __init arm_memblock_init(struct meminfo *mi, ...@@ -323,6 +323,8 @@ void __init arm_memblock_init(struct meminfo *mi,
if (mdesc->reserve) if (mdesc->reserve)
mdesc->reserve(); mdesc->reserve();
early_init_fdt_scan_reserved_mem();
/* /*
* reserve memory for DMA contigouos allocations, * reserve memory for DMA contigouos allocations,
* must come from DMA area inside low memory * must come from DMA area inside low memory
......
...@@ -47,6 +47,7 @@ config ARM64 ...@@ -47,6 +47,7 @@ config ARM64
select NO_BOOTMEM select NO_BOOTMEM
select OF select OF
select OF_EARLY_FLATTREE select OF_EARLY_FLATTREE
select OF_RESERVED_MEM
select PERF_USE_VMALLOC select PERF_USE_VMALLOC
select POWER_RESET select POWER_RESET
select POWER_SUPPLY select POWER_SUPPLY
......
...@@ -161,6 +161,7 @@ void __init arm64_memblock_init(void) ...@@ -161,6 +161,7 @@ void __init arm64_memblock_init(void)
memblock_reserve(base, size); memblock_reserve(base, size);
} }
early_init_fdt_scan_reserved_mem();
dma_contiguous_reserve(0); dma_contiguous_reserve(0);
memblock_allow_resize(); memblock_allow_resize();
......
...@@ -90,6 +90,7 @@ config PPC ...@@ -90,6 +90,7 @@ config PPC
select BINFMT_ELF select BINFMT_ELF
select OF select OF
select OF_EARLY_FLATTREE select OF_EARLY_FLATTREE
select OF_RESERVED_MEM
select HAVE_FTRACE_MCOUNT_RECORD select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_DYNAMIC_FTRACE select HAVE_DYNAMIC_FTRACE
select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_TRACER
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/memblock.h> #include <linux/memblock.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_fdt.h>
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/rtas.h> #include <asm/rtas.h>
...@@ -588,6 +589,8 @@ static void __init early_reserve_mem_dt(void) ...@@ -588,6 +589,8 @@ static void __init early_reserve_mem_dt(void)
memblock_reserve(base, size); memblock_reserve(base, size);
} }
} }
early_init_fdt_scan_reserved_mem();
} }
static void __init early_reserve_mem(void) static void __init early_reserve_mem(void)
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/cpu.h> #include <linux/cpu.h>
...@@ -87,7 +86,6 @@ static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa, ...@@ -87,7 +86,6 @@ static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa,
} }
of_node_set_flag(dn, OF_DYNAMIC); of_node_set_flag(dn, OF_DYNAMIC);
kref_init(&dn->kref);
return dn; return dn;
} }
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -70,7 +69,6 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist ...@@ -70,7 +69,6 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist
np->properties = proplist; np->properties = proplist;
of_node_set_flag(np, OF_DYNAMIC); of_node_set_flag(np, OF_DYNAMIC);
kref_init(&np->kref);
np->parent = derive_parent(path); np->parent = derive_parent(path);
if (IS_ERR(np->parent)) { if (IS_ERR(np->parent)) {
......
...@@ -202,7 +202,7 @@ void __init test_of_node(void) ...@@ -202,7 +202,7 @@ void __init test_of_node(void)
/* There should really be a struct device_node allocator */ /* There should really be a struct device_node allocator */
memset(&of_node, 0, sizeof(of_node)); memset(&of_node, 0, sizeof(of_node));
kref_init(&of_node.kref); kref_init(&of_node.kobj.kref);
of_node.full_name = node_name; of_node.full_name = node_name;
check(0 == msi_bitmap_alloc(&bmp, size, &of_node)); check(0 == msi_bitmap_alloc(&bmp, size, &of_node));
......
...@@ -7,14 +7,6 @@ config OF ...@@ -7,14 +7,6 @@ config OF
menu "Device Tree and Open Firmware support" menu "Device Tree and Open Firmware support"
depends on OF depends on OF
config PROC_DEVICETREE
bool "Support for device tree in /proc"
depends on PROC_FS && !SPARC
help
This option adds a device-tree directory under /proc which contains
an image of the device tree that the kernel copies from Open
Firmware or other boot firmware. If unsure, say Y here.
config OF_SELFTEST config OF_SELFTEST
bool "Device Tree Runtime self tests" bool "Device Tree Runtime self tests"
depends on OF_IRQ depends on OF_IRQ
...@@ -44,6 +36,10 @@ config OF_DYNAMIC ...@@ -44,6 +36,10 @@ config OF_DYNAMIC
config OF_ADDRESS config OF_ADDRESS
def_bool y def_bool y
depends on !SPARC depends on !SPARC
select OF_ADDRESS_PCI if PCI
config OF_ADDRESS_PCI
bool
config OF_IRQ config OF_IRQ
def_bool y def_bool y
...@@ -75,4 +71,10 @@ config OF_MTD ...@@ -75,4 +71,10 @@ config OF_MTD
depends on MTD depends on MTD
def_bool y def_bool y
config OF_RESERVED_MEM
depends on OF_EARLY_FLATTREE
bool
help
Helpers to allow for reservation of memory regions
endmenu # OF endmenu # OF
...@@ -9,3 +9,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o ...@@ -9,3 +9,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o
obj-$(CONFIG_OF_PCI) += of_pci.o obj-$(CONFIG_OF_PCI) += of_pci.o
obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
obj-$(CONFIG_OF_MTD) += of_mtd.o obj-$(CONFIG_OF_MTD) += of_mtd.o
obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
...@@ -91,7 +91,7 @@ static unsigned int of_bus_default_get_flags(const __be32 *addr) ...@@ -91,7 +91,7 @@ static unsigned int of_bus_default_get_flags(const __be32 *addr)
return IORESOURCE_MEM; return IORESOURCE_MEM;
} }
#ifdef CONFIG_PCI #ifdef CONFIG_OF_ADDRESS_PCI
/* /*
* PCI bus specific translator * PCI bus specific translator
*/ */
...@@ -166,7 +166,9 @@ static int of_bus_pci_translate(__be32 *addr, u64 offset, int na) ...@@ -166,7 +166,9 @@ static int of_bus_pci_translate(__be32 *addr, u64 offset, int na)
{ {
return of_bus_default_translate(addr + 1, offset, na - 1); return of_bus_default_translate(addr + 1, offset, na - 1);
} }
#endif /* CONFIG_OF_ADDRESS_PCI */
#ifdef CONFIG_PCI
const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
unsigned int *flags) unsigned int *flags)
{ {
...@@ -356,7 +358,7 @@ static unsigned int of_bus_isa_get_flags(const __be32 *addr) ...@@ -356,7 +358,7 @@ static unsigned int of_bus_isa_get_flags(const __be32 *addr)
*/ */
static struct of_bus of_busses[] = { static struct of_bus of_busses[] = {
#ifdef CONFIG_PCI #ifdef CONFIG_OF_ADDRESS_PCI
/* PCI */ /* PCI */
{ {
.name = "pci", .name = "pci",
...@@ -367,7 +369,7 @@ static struct of_bus of_busses[] = { ...@@ -367,7 +369,7 @@ static struct of_bus of_busses[] = {
.translate = of_bus_pci_translate, .translate = of_bus_pci_translate,
.get_flags = of_bus_pci_get_flags, .get_flags = of_bus_pci_get_flags,
}, },
#endif /* CONFIG_PCI */ #endif /* CONFIG_OF_ADDRESS_PCI */
/* ISA */ /* ISA */
{ {
.name = "isa", .name = "isa",
......
This diff is collapsed.
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_fdt.h> #include <linux/of_fdt.h>
#include <linux/of_reserved_mem.h>
#include <linux/sizes.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -202,6 +204,7 @@ static void * unflatten_dt_node(struct boot_param_header *blob, ...@@ -202,6 +204,7 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
__alignof__(struct device_node)); __alignof__(struct device_node));
if (allnextpp) { if (allnextpp) {
char *fn; char *fn;
of_node_init(np);
np->full_name = fn = ((char *)np) + sizeof(*np); np->full_name = fn = ((char *)np) + sizeof(*np);
if (new_format) { if (new_format) {
/* rebuild full path for new format */ /* rebuild full path for new format */
...@@ -232,7 +235,6 @@ static void * unflatten_dt_node(struct boot_param_header *blob, ...@@ -232,7 +235,6 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
dad->next->sibling = np; dad->next->sibling = np;
dad->next = np; dad->next = np;
} }
kref_init(&np->kref);
} }
/* process properties */ /* process properties */
while (1) { while (1) {
...@@ -439,6 +441,129 @@ struct boot_param_header *initial_boot_params; ...@@ -439,6 +441,129 @@ struct boot_param_header *initial_boot_params;
#ifdef CONFIG_OF_EARLY_FLATTREE #ifdef CONFIG_OF_EARLY_FLATTREE
/**
* res_mem_reserve_reg() - reserve all memory described in 'reg' property
*/
static int __init __reserved_mem_reserve_reg(unsigned long node,
const char *uname)
{
int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
phys_addr_t base, size;
unsigned long len;
__be32 *prop;
int nomap, first = 1;
prop = of_get_flat_dt_prop(node, "reg", &len);
if (!prop)
return -ENOENT;
if (len && len % t_len != 0) {
pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n",
uname);
return -EINVAL;
}
nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
while (len >= t_len) {
base = dt_mem_next_cell(dt_root_addr_cells, &prop);
size = dt_mem_next_cell(dt_root_size_cells, &prop);
if (base && size &&
early_init_dt_reserve_memory_arch(base, size, nomap) == 0)
pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n",
uname, &base, (unsigned long)size / SZ_1M);
else
pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %ld MiB\n",
uname, &base, (unsigned long)size / SZ_1M);
len -= t_len;
if (first) {
fdt_reserved_mem_save_node(node, uname, base, size);
first = 0;
}
}
return 0;
}
/**
* __reserved_mem_check_root() - check if #size-cells, #address-cells provided
* in /reserved-memory matches the values supported by the current implementation,
* also check if ranges property has been provided
*/
static int __reserved_mem_check_root(unsigned long node)
{
__be32 *prop;
prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
if (!prop || be32_to_cpup(prop) != dt_root_size_cells)
return -EINVAL;
prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
if (!prop || be32_to_cpup(prop) != dt_root_addr_cells)
return -EINVAL;
prop = of_get_flat_dt_prop(node, "ranges", NULL);
if (!prop)
return -EINVAL;
return 0;
}
/**
* fdt_scan_reserved_mem() - scan a single FDT node for reserved memory
*/
static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname,
int depth, void *data)
{
static int found;
const char *status;
int err;
if (!found && depth == 1 && strcmp(uname, "reserved-memory") == 0) {
if (__reserved_mem_check_root(node) != 0) {
pr_err("Reserved memory: unsupported node format, ignoring\n");
/* break scan */
return 1;
}
found = 1;
/* scan next node */
return 0;
} else if (!found) {
/* scan next node */
return 0;
} else if (found && depth < 2) {
/* scanning of /reserved-memory has been finished */
return 1;
}
status = of_get_flat_dt_prop(node, "status", NULL);
if (status && strcmp(status, "okay") != 0 && strcmp(status, "ok") != 0)
return 0;
err = __reserved_mem_reserve_reg(node, uname);
if (err == -ENOENT && of_get_flat_dt_prop(node, "size", NULL))
fdt_reserved_mem_save_node(node, uname, 0, 0);
/* scan next node */
return 0;
}
/**
* early_init_fdt_scan_reserved_mem() - create reserved memory regions
*
* This function grabs memory from early allocator for device exclusive use
* defined in device tree structures. It should be called by arch specific code
* once the early allocator (i.e. memblock) has been fully activated.
*/
void __init early_init_fdt_scan_reserved_mem(void)
{
if (!initial_boot_params)
return;
of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);
fdt_init_reserved_mem();
}
/** /**
* of_scan_flat_dt - scan flattened tree blob and call callback on each. * of_scan_flat_dt - scan flattened tree blob and call callback on each.
* @it: callback function * @it: callback function
...@@ -856,6 +981,16 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) ...@@ -856,6 +981,16 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
memblock_add(base, size); memblock_add(base, size);
} }
int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
phys_addr_t size, bool nomap)
{
if (memblock_is_region_reserved(base, size))
return -EBUSY;
if (nomap)
return memblock_remove(base, size);
return memblock_reserve(base, size);
}
/* /*
* called from unflatten_device_tree() to bootstrap devicetree itself * called from unflatten_device_tree() to bootstrap devicetree itself
* Architectures can override this definition if memblock isn't used * Architectures can override this definition if memblock isn't used
...@@ -864,6 +999,14 @@ void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align) ...@@ -864,6 +999,14 @@ void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align)
{ {
return __va(memblock_alloc(size, align)); return __va(memblock_alloc(size, align));
} }
#else
int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
phys_addr_t size, bool nomap)
{
pr_err("Reserved memory not supported, ignoring range 0x%llx - 0x%llx%s\n",
base, size, nomap ? " (nomap)" : "");
return -ENOSYS;
}
#endif #endif
bool __init early_init_dt_scan(void *params) bool __init early_init_dt_scan(void *params)
......
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
/** /**
* It maps 'enum phy_interface_t' found in include/linux/phy.h * It maps 'enum phy_interface_t' found in include/linux/phy.h
* into the device tree binding of 'phy-mode', so that Ethernet * into the device tree binding of 'phy-mode' or 'phy-connection-type',
* device driver can get phy interface from device tree. * so that Ethernet device driver can get phy interface from device tree.
*/ */
static const char *phy_modes[] = { static const char *phy_modes[] = {
[PHY_INTERFACE_MODE_NA] = "", [PHY_INTERFACE_MODE_NA] = "",
...@@ -37,8 +37,9 @@ static const char *phy_modes[] = { ...@@ -37,8 +37,9 @@ static const char *phy_modes[] = {
* of_get_phy_mode - Get phy mode for given device_node * of_get_phy_mode - Get phy mode for given device_node
* @np: Pointer to the given device_node * @np: Pointer to the given device_node
* *
* The function gets phy interface string from property 'phy-mode', * The function gets phy interface string from property 'phy-mode' or
* and return its index in phy_modes table, or errno in error case. * 'phy-connection-type', and return its index in phy_modes table, or errno in
* error case.
*/ */
int of_get_phy_mode(struct device_node *np) int of_get_phy_mode(struct device_node *np)
{ {
...@@ -46,6 +47,8 @@ int of_get_phy_mode(struct device_node *np) ...@@ -46,6 +47,8 @@ int of_get_phy_mode(struct device_node *np)
int err, i; int err, i;
err = of_property_read_string(np, "phy-mode", &pm); err = of_property_read_string(np, "phy-mode", &pm);
if (err < 0)
err = of_property_read_string(np, "phy-connection-type", &pm);
if (err < 0) if (err < 0)
return err; return err;
......
/*
* Device tree based initialization code for reserved memory.
*
* Copyright (c) 2013, The Linux Foundation. All Rights Reserved.
* Copyright (c) 2013,2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com
* Author: Marek Szyprowski <m.szyprowski@samsung.com>
* Author: Josh Cartwright <joshc@codeaurora.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License or (at your optional) any later version of the license.
*/
#include <linux/err.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
#include <linux/mm.h>
#include <linux/sizes.h>
#include <linux/of_reserved_mem.h>
#define MAX_RESERVED_REGIONS 16
static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
static int reserved_mem_count;
#if defined(CONFIG_HAVE_MEMBLOCK)
#include <linux/memblock.h>
int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
phys_addr_t *res_base)
{
/*
* We use __memblock_alloc_base() because memblock_alloc_base()
* panic()s on allocation failure.
*/
phys_addr_t base = __memblock_alloc_base(size, align, end);
if (!base)
return -ENOMEM;
/*
* Check if the allocated region fits in to start..end window
*/
if (base < start) {
memblock_free(base, size);
return -ENOMEM;
}
*res_base = base;
if (nomap)
return memblock_remove(base, size);
return 0;
}
#else
int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
phys_addr_t *res_base)
{
pr_err("Reserved memory not supported, ignoring region 0x%llx%s\n",
size, nomap ? " (nomap)" : "");
return -ENOSYS;
}
#endif
/**
* res_mem_save_node() - save fdt node for second pass initialization
*/
void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname,
phys_addr_t base, phys_addr_t size)
{
struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
if (reserved_mem_count == ARRAY_SIZE(reserved_mem)) {
pr_err("Reserved memory: not enough space all defined regions.\n");
return;
}
rmem->fdt_node = node;
rmem->name = uname;
rmem->base = base;
rmem->size = size;
reserved_mem_count++;
return;
}
/**
* res_mem_alloc_size() - allocate reserved memory described by 'size', 'align'
* and 'alloc-ranges' properties
*/
static int __init __reserved_mem_alloc_size(unsigned long node,
const char *uname, phys_addr_t *res_base, phys_addr_t *res_size)
{
int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
phys_addr_t start = 0, end = 0;
phys_addr_t base = 0, align = 0, size;
unsigned long len;
__be32 *prop;
int nomap;
int ret;
prop = of_get_flat_dt_prop(node, "size", &len);
if (!prop)
return -EINVAL;
if (len != dt_root_size_cells * sizeof(__be32)) {
pr_err("Reserved memory: invalid size property in '%s' node.\n",
uname);
return -EINVAL;
}
size = dt_mem_next_cell(dt_root_size_cells, &prop);
nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
prop = of_get_flat_dt_prop(node, "alignment", &len);
if (prop) {
if (len != dt_root_addr_cells * sizeof(__be32)) {
pr_err("Reserved memory: invalid alignment property in '%s' node.\n",
uname);
return -EINVAL;
}
align = dt_mem_next_cell(dt_root_addr_cells, &prop);
}
prop = of_get_flat_dt_prop(node, "alloc-ranges", &len);
if (prop) {
if (len % t_len != 0) {
pr_err("Reserved memory: invalid alloc-ranges property in '%s', skipping node.\n",
uname);
return -EINVAL;
}
base = 0;
while (len > 0) {
start = dt_mem_next_cell(dt_root_addr_cells, &prop);
end = start + dt_mem_next_cell(dt_root_size_cells,
&prop);
ret = early_init_dt_alloc_reserved_memory_arch(size,
align, start, end, nomap, &base);
if (ret == 0) {
pr_debug("Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n",
uname, &base,
(unsigned long)size / SZ_1M);
break;
}
len -= t_len;
}
} else {
ret = early_init_dt_alloc_reserved_memory_arch(size, align,
0, 0, nomap, &base);
if (ret == 0)
pr_debug("Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n",
uname, &base, (unsigned long)size / SZ_1M);
}
if (base == 0) {
pr_info("Reserved memory: failed to allocate memory for node '%s'\n",
uname);
return -ENOMEM;
}
*res_base = base;
*res_size = size;
return 0;
}
static const struct of_device_id __rmem_of_table_sentinel
__used __section(__reservedmem_of_table_end);
/**
* res_mem_init_node() - call region specific reserved memory init code
*/
static int __init __reserved_mem_init_node(struct reserved_mem *rmem)
{
extern const struct of_device_id __reservedmem_of_table[];
const struct of_device_id *i;
for (i = __reservedmem_of_table; i < &__rmem_of_table_sentinel; i++) {
reservedmem_of_init_fn initfn = i->data;
const char *compat = i->compatible;
if (!of_flat_dt_is_compatible(rmem->fdt_node, compat))
continue;
if (initfn(rmem, rmem->fdt_node, rmem->name) == 0) {
pr_info("Reserved memory: initialized node %s, compatible id %s\n",
rmem->name, compat);
return 0;
}
}
return -ENOENT;
}
/**
* fdt_init_reserved_mem - allocate and init all saved reserved memory regions
*/
void __init fdt_init_reserved_mem(void)
{
int i;
for (i = 0; i < reserved_mem_count; i++) {
struct reserved_mem *rmem = &reserved_mem[i];
unsigned long node = rmem->fdt_node;
int err = 0;
if (rmem->size == 0)
err = __reserved_mem_alloc_size(node, rmem->name,
&rmem->base, &rmem->size);
if (err == 0)
__reserved_mem_init_node(rmem);
}
}
...@@ -176,11 +176,10 @@ static struct device_node * __init of_pdt_create_node(phandle node, ...@@ -176,11 +176,10 @@ static struct device_node * __init of_pdt_create_node(phandle node,
return NULL; return NULL;
dp = prom_early_alloc(sizeof(*dp)); dp = prom_early_alloc(sizeof(*dp));
of_node_init(dp);
of_pdt_incr_unique_id(dp); of_pdt_incr_unique_id(dp);
dp->parent = parent; dp->parent = parent;
kref_init(&dp->kref);
dp->name = of_pdt_get_one_property(node, "name"); dp->name = of_pdt_get_one_property(node, "name");
dp->type = of_pdt_get_one_property(node, "device_type"); dp->type = of_pdt_get_one_property(node, "device_type");
dp->phandle = node; dp->phandle = node;
......
...@@ -30,6 +30,67 @@ static struct selftest_results { ...@@ -30,6 +30,67 @@ static struct selftest_results {
} \ } \
} }
static void __init of_selftest_dynamic(void)
{
struct device_node *np;
struct property *prop;
np = of_find_node_by_path("/testcase-data");
if (!np) {
pr_err("missing testcase data\n");
return;
}
/* Array of 4 properties for the purpose of testing */
prop = kzalloc(sizeof(*prop) * 4, GFP_KERNEL);
if (!prop) {
selftest(0, "kzalloc() failed\n");
return;
}
/* Add a new property - should pass*/
prop->name = "new-property";
prop->value = "new-property-data";
prop->length = strlen(prop->value);
selftest(of_add_property(np, prop) == 0, "Adding a new property failed\n");
/* Try to add an existing property - should fail */
prop++;
prop->name = "new-property";
prop->value = "new-property-data-should-fail";
prop->length = strlen(prop->value);
selftest(of_add_property(np, prop) != 0,
"Adding an existing property should have failed\n");
/* Try to modify an existing property - should pass */
prop->value = "modify-property-data-should-pass";
prop->length = strlen(prop->value);
selftest(of_update_property(np, prop) == 0,
"Updating an existing property should have passed\n");
/* Try to modify non-existent property - should pass*/
prop++;
prop->name = "modify-property";
prop->value = "modify-missing-property-data-should-pass";
prop->length = strlen(prop->value);
selftest(of_update_property(np, prop) == 0,
"Updating a missing property should have passed\n");
/* Remove property - should pass */
selftest(of_remove_property(np, prop) == 0,
"Removing a property should have passed\n");
/* Adding very large property - should pass */
prop++;
prop->name = "large-property-PAGE_SIZEx8";
prop->length = PAGE_SIZE * 8;
prop->value = kzalloc(prop->length, GFP_KERNEL);
selftest(prop->value != NULL, "Unable to allocate large buffer\n");
if (prop->value)
selftest(of_add_property(np, prop) == 0,
"Adding a large property should have passed\n");
}
static void __init of_selftest_parse_phandle_with_args(void) static void __init of_selftest_parse_phandle_with_args(void)
{ {
struct device_node *np; struct device_node *np;
...@@ -378,6 +439,7 @@ static int __init of_selftest(void) ...@@ -378,6 +439,7 @@ static int __init of_selftest(void)
of_node_put(np); of_node_put(np);
pr_info("start of selftest - you will see error messages\n"); pr_info("start of selftest - you will see error messages\n");
of_selftest_dynamic();
of_selftest_parse_phandle_with_args(); of_selftest_parse_phandle_with_args();
of_selftest_property_match_string(); of_selftest_property_match_string();
of_selftest_parse_interrupts(); of_selftest_parse_interrupts();
......
/ { / {
testcase-data { testcase-data {
security-password = "password";
duplicate-name = "duplicate";
duplicate-name { };
phandle-tests { phandle-tests {
provider0: provider0 { provider0: provider0 {
#phandle-cells = <0>; #phandle-cells = <0>;
......
...@@ -27,6 +27,5 @@ proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o ...@@ -27,6 +27,5 @@ proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o
proc-$(CONFIG_NET) += proc_net.o proc-$(CONFIG_NET) += proc_net.o
proc-$(CONFIG_PROC_KCORE) += kcore.o proc-$(CONFIG_PROC_KCORE) += kcore.o
proc-$(CONFIG_PROC_VMCORE) += vmcore.o proc-$(CONFIG_PROC_VMCORE) += vmcore.o
proc-$(CONFIG_PROC_DEVICETREE) += proc_devtree.o
proc-$(CONFIG_PRINTK) += kmsg.o proc-$(CONFIG_PRINTK) += kmsg.o
proc-$(CONFIG_PROC_PAGE_MONITOR) += page.o proc-$(CONFIG_PROC_PAGE_MONITOR) += page.o
...@@ -210,13 +210,6 @@ extern struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry ...@@ -210,13 +210,6 @@ extern struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry
extern int proc_fill_super(struct super_block *); extern int proc_fill_super(struct super_block *);
extern void proc_entry_rundown(struct proc_dir_entry *); extern void proc_entry_rundown(struct proc_dir_entry *);
/*
* proc_devtree.c
*/
#ifdef CONFIG_PROC_DEVICETREE
extern void proc_device_tree_init(void);
#endif
/* /*
* proc_namespaces.c * proc_namespaces.c
*/ */
......
/*
* proc_devtree.c - handles /proc/device-tree
*
* Copyright 1997 Paul Mackerras
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/printk.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/of.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include "internal.h"
static inline void set_node_proc_entry(struct device_node *np,
struct proc_dir_entry *de)
{
np->pde = de;
}
static struct proc_dir_entry *proc_device_tree;
/*
* Supply data on a read from /proc/device-tree/node/property.
*/
static int property_proc_show(struct seq_file *m, void *v)
{
struct property *pp = m->private;
seq_write(m, pp->value, pp->length);
return 0;
}
static int property_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, property_proc_show, __PDE_DATA(inode));
}
static const struct file_operations property_proc_fops = {
.owner = THIS_MODULE,
.open = property_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/*
* For a node with a name like "gc@10", we make symlinks called "gc"
* and "@10" to it.
*/
/*
* Add a property to a node
*/
static struct proc_dir_entry *
__proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp,
const char *name)
{
struct proc_dir_entry *ent;
/*
* Unfortunately proc_register puts each new entry
* at the beginning of the list. So we rearrange them.
*/
ent = proc_create_data(name,
strncmp(name, "security-", 9) ? S_IRUGO : S_IRUSR,
de, &property_proc_fops, pp);
if (ent == NULL)
return NULL;
if (!strncmp(name, "security-", 9))
proc_set_size(ent, 0); /* don't leak number of password chars */
else
proc_set_size(ent, pp->length);
return ent;
}
void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop)
{
__proc_device_tree_add_prop(pde, prop, prop->name);
}
void proc_device_tree_remove_prop(struct proc_dir_entry *pde,
struct property *prop)
{
remove_proc_entry(prop->name, pde);
}
void proc_device_tree_update_prop(struct proc_dir_entry *pde,
struct property *newprop,
struct property *oldprop)
{
struct proc_dir_entry *ent;
if (!oldprop) {
proc_device_tree_add_prop(pde, newprop);
return;
}
for (ent = pde->subdir; ent != NULL; ent = ent->next)
if (ent->data == oldprop)
break;
if (ent == NULL) {
pr_warn("device-tree: property \"%s\" does not exist\n",
oldprop->name);
} else {
ent->data = newprop;
ent->size = newprop->length;
}
}
/*
* Various dodgy firmware might give us nodes and/or properties with
* conflicting names. That's generally ok, except for exporting via /proc,
* so munge names here to ensure they're unique.
*/
static int duplicate_name(struct proc_dir_entry *de, const char *name)
{
struct proc_dir_entry *ent;
int found = 0;
spin_lock(&proc_subdir_lock);
for (ent = de->subdir; ent != NULL; ent = ent->next) {
if (strcmp(ent->name, name) == 0) {
found = 1;
break;
}
}
spin_unlock(&proc_subdir_lock);
return found;
}
static const char *fixup_name(struct device_node *np, struct proc_dir_entry *de,
const char *name)
{
char *fixed_name;
int fixup_len = strlen(name) + 2 + 1; /* name + #x + \0 */
int i = 1, size;
realloc:
fixed_name = kmalloc(fixup_len, GFP_KERNEL);
if (fixed_name == NULL) {
pr_err("device-tree: Out of memory trying to fixup "
"name \"%s\"\n", name);
return name;
}
retry:
size = snprintf(fixed_name, fixup_len, "%s#%d", name, i);
size++; /* account for NULL */
if (size > fixup_len) {
/* We ran out of space, free and reallocate. */
kfree(fixed_name);
fixup_len = size;
goto realloc;
}
if (duplicate_name(de, fixed_name)) {
/* Multiple duplicates. Retry with a different offset. */
i++;
goto retry;
}
pr_warn("device-tree: Duplicate name in %s, renamed to \"%s\"\n",
np->full_name, fixed_name);
return fixed_name;
}
/*
* Process a node, adding entries for its children and its properties.
*/
void proc_device_tree_add_node(struct device_node *np,
struct proc_dir_entry *de)
{
struct property *pp;
struct proc_dir_entry *ent;
struct device_node *child;
const char *p;
set_node_proc_entry(np, de);
for (child = NULL; (child = of_get_next_child(np, child));) {
/* Use everything after the last slash, or the full name */
p = kbasename(child->full_name);
if (duplicate_name(de, p))
p = fixup_name(np, de, p);
ent = proc_mkdir(p, de);
if (ent == NULL)
break;
proc_device_tree_add_node(child, ent);
}
of_node_put(child);
for (pp = np->properties; pp != NULL; pp = pp->next) {
p = pp->name;
if (strchr(p, '/'))
continue;
if (duplicate_name(de, p))
p = fixup_name(np, de, p);
ent = __proc_device_tree_add_prop(de, pp, p);
if (ent == NULL)
break;
}
}
/*
* Called on initialization to set up the /proc/device-tree subtree
*/
void __init proc_device_tree_init(void)
{
struct device_node *root;
proc_device_tree = proc_mkdir("device-tree", NULL);
if (proc_device_tree == NULL)
return;
root = of_find_node_by_path("/");
if (root == NULL) {
remove_proc_entry("device-tree", NULL);
pr_debug("/proc/device-tree: can't find root\n");
return;
}
proc_device_tree_add_node(root, proc_device_tree);
of_node_put(root);
}
...@@ -183,9 +183,6 @@ void __init proc_root_init(void) ...@@ -183,9 +183,6 @@ void __init proc_root_init(void)
proc_mkdir("openprom", NULL); proc_mkdir("openprom", NULL);
#endif #endif
proc_tty_init(); proc_tty_init();
#ifdef CONFIG_PROC_DEVICETREE
proc_device_tree_init();
#endif
proc_mkdir("bus", NULL); proc_mkdir("bus", NULL);
proc_sys_init(); proc_sys_init();
} }
......
...@@ -167,6 +167,16 @@ ...@@ -167,6 +167,16 @@
#define CLK_OF_TABLES() #define CLK_OF_TABLES()
#endif #endif
#ifdef CONFIG_OF_RESERVED_MEM
#define RESERVEDMEM_OF_TABLES() \
. = ALIGN(8); \
VMLINUX_SYMBOL(__reservedmem_of_table) = .; \
*(__reservedmem_of_table) \
*(__reservedmem_of_table_end)
#else
#define RESERVEDMEM_OF_TABLES()
#endif
#define KERNEL_DTB() \ #define KERNEL_DTB() \
STRUCT_ALIGN(); \ STRUCT_ALIGN(); \
VMLINUX_SYMBOL(__dtb_start) = .; \ VMLINUX_SYMBOL(__dtb_start) = .; \
...@@ -490,6 +500,7 @@ ...@@ -490,6 +500,7 @@
TRACE_SYSCALLS() \ TRACE_SYSCALLS() \
MEM_DISCARD(init.rodata) \ MEM_DISCARD(init.rodata) \
CLK_OF_TABLES() \ CLK_OF_TABLES() \
RESERVEDMEM_OF_TABLES() \
CLKSRC_OF_TABLES() \ CLKSRC_OF_TABLES() \
KERNEL_DTB() \ KERNEL_DTB() \
IRQCHIP_OF_MATCH_TABLE() IRQCHIP_OF_MATCH_TABLE()
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/kref.h> #include <linux/kobject.h>
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/topology.h> #include <linux/topology.h>
...@@ -37,6 +37,7 @@ struct property { ...@@ -37,6 +37,7 @@ struct property {
struct property *next; struct property *next;
unsigned long _flags; unsigned long _flags;
unsigned int unique_id; unsigned int unique_id;
struct bin_attribute attr;
}; };
#if defined(CONFIG_SPARC) #if defined(CONFIG_SPARC)
...@@ -56,8 +57,7 @@ struct device_node { ...@@ -56,8 +57,7 @@ struct device_node {
struct device_node *sibling; struct device_node *sibling;
struct device_node *next; /* next device of same type */ struct device_node *next; /* next device of same type */
struct device_node *allnext; /* next in list of all nodes */ struct device_node *allnext; /* next in list of all nodes */
struct proc_dir_entry *pde; /* this node's proc directory */ struct kobject kobj;
struct kref kref;
unsigned long _flags; unsigned long _flags;
void *data; void *data;
#if defined(CONFIG_SPARC) #if defined(CONFIG_SPARC)
...@@ -67,13 +67,34 @@ struct device_node { ...@@ -67,13 +67,34 @@ struct device_node {
#endif #endif
}; };
#define MAX_PHANDLE_ARGS 8 #define MAX_PHANDLE_ARGS 16
struct of_phandle_args { struct of_phandle_args {
struct device_node *np; struct device_node *np;
int args_count; int args_count;
uint32_t args[MAX_PHANDLE_ARGS]; uint32_t args[MAX_PHANDLE_ARGS];
}; };
extern int of_node_add(struct device_node *node);
/* initialize a node */
extern struct kobj_type of_node_ktype;
static inline void of_node_init(struct device_node *node)
{
kobject_init(&node->kobj, &of_node_ktype);
}
/* true when node is initialized */
static inline int of_node_is_initialized(struct device_node *node)
{
return node && node->kobj.state_initialized;
}
/* true when node is attached (i.e. present on sysfs) */
static inline int of_node_is_attached(struct device_node *node)
{
return node && node->kobj.state_in_sysfs;
}
#ifdef CONFIG_OF_DYNAMIC #ifdef CONFIG_OF_DYNAMIC
extern struct device_node *of_node_get(struct device_node *node); extern struct device_node *of_node_get(struct device_node *node);
extern void of_node_put(struct device_node *node); extern void of_node_put(struct device_node *node);
...@@ -114,6 +135,26 @@ static inline void of_node_set_flag(struct device_node *n, unsigned long flag) ...@@ -114,6 +135,26 @@ static inline void of_node_set_flag(struct device_node *n, unsigned long flag)
set_bit(flag, &n->_flags); set_bit(flag, &n->_flags);
} }
static inline void of_node_clear_flag(struct device_node *n, unsigned long flag)
{
clear_bit(flag, &n->_flags);
}
static inline int of_property_check_flag(struct property *p, unsigned long flag)
{
return test_bit(flag, &p->_flags);
}
static inline void of_property_set_flag(struct property *p, unsigned long flag)
{
set_bit(flag, &p->_flags);
}
static inline void of_property_clear_flag(struct property *p, unsigned long flag)
{
clear_bit(flag, &p->_flags);
}
extern struct device_node *of_find_all_nodes(struct device_node *prev); extern struct device_node *of_find_all_nodes(struct device_node *prev);
/* /*
...@@ -167,6 +208,8 @@ static inline const char *of_node_full_name(const struct device_node *np) ...@@ -167,6 +208,8 @@ static inline const char *of_node_full_name(const struct device_node *np)
return np ? np->full_name : "<no-node>"; return np ? np->full_name : "<no-node>";
} }
#define for_each_of_allnodes(dn) \
for (dn = of_allnodes; dn; dn = dn->allnext)
extern struct device_node *of_find_node_by_name(struct device_node *from, extern struct device_node *of_find_node_by_name(struct device_node *from,
const char *name); const char *name);
extern struct device_node *of_find_node_by_type(struct device_node *from, extern struct device_node *of_find_node_by_type(struct device_node *from,
...@@ -709,14 +752,4 @@ static inline int of_get_available_child_count(const struct device_node *np) ...@@ -709,14 +752,4 @@ static inline int of_get_available_child_count(const struct device_node *np)
return num; return num;
} }
#if defined(CONFIG_PROC_FS) && defined(CONFIG_PROC_DEVICETREE)
extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
extern void proc_device_tree_remove_prop(struct proc_dir_entry *pde,
struct property *prop);
extern void proc_device_tree_update_prop(struct proc_dir_entry *pde,
struct property *newprop,
struct property *oldprop);
#endif
#endif /* _LINUX_OF_H */ #endif /* _LINUX_OF_H */
...@@ -98,7 +98,10 @@ extern int early_init_dt_scan_chosen(unsigned long node, const char *uname, ...@@ -98,7 +98,10 @@ extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
int depth, void *data); int depth, void *data);
extern int early_init_dt_scan_memory(unsigned long node, const char *uname, extern int early_init_dt_scan_memory(unsigned long node, const char *uname,
int depth, void *data); int depth, void *data);
extern void early_init_fdt_scan_reserved_mem(void);
extern void early_init_dt_add_memory_arch(u64 base, u64 size); extern 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 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, __be32 **cellp);
...@@ -118,6 +121,7 @@ extern void unflatten_and_copy_device_tree(void); ...@@ -118,6 +121,7 @@ extern void unflatten_and_copy_device_tree(void);
extern void early_init_devtree(void *); extern void early_init_devtree(void *);
extern void early_get_first_memblock_info(void *, phys_addr_t *); extern void early_get_first_memblock_info(void *, phys_addr_t *);
#else /* CONFIG_OF_FLATTREE */ #else /* CONFIG_OF_FLATTREE */
static inline void early_init_fdt_scan_reserved_mem(void) {}
static inline const char *of_flat_dt_get_machine_name(void) { return NULL; } static inline const char *of_flat_dt_get_machine_name(void) { return NULL; }
static inline void unflatten_device_tree(void) {} static inline void unflatten_device_tree(void) {}
static inline void unflatten_and_copy_device_tree(void) {} static inline void unflatten_and_copy_device_tree(void) {}
......
#ifndef __OF_RESERVED_MEM_H
#define __OF_RESERVED_MEM_H
struct device;
struct of_phandle_args;
struct reserved_mem_ops;
struct reserved_mem {
const char *name;
unsigned long fdt_node;
const struct reserved_mem_ops *ops;
phys_addr_t base;
phys_addr_t size;
void *priv;
};
struct reserved_mem_ops {
void (*device_init)(struct reserved_mem *rmem,
struct device *dev);
void (*device_release)(struct reserved_mem *rmem,
struct device *dev);
};
typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem,
unsigned long node, const char *uname);
#ifdef CONFIG_OF_RESERVED_MEM
void fdt_init_reserved_mem(void);
void fdt_reserved_mem_save_node(unsigned long node, const char *uname,
phys_addr_t base, phys_addr_t size);
#define RESERVEDMEM_OF_DECLARE(name, compat, init) \
static const struct of_device_id __reservedmem_of_table_##name \
__used __section(__reservedmem_of_table) \
= { .compatible = compat, \
.data = (init == (reservedmem_of_init_fn)NULL) ? \
init : init }
#else
static inline void fdt_init_reserved_mem(void) { }
static inline void fdt_reserved_mem_save_node(unsigned long node,
const char *uname, phys_addr_t base, phys_addr_t size) { }
#define RESERVEDMEM_OF_DECLARE(name, compat, init) \
static const struct of_device_id __reservedmem_of_table_##name \
__attribute__((unused)) \
= { .compatible = compat, \
.data = (init == (reservedmem_of_init_fn)NULL) ? \
init : init }
#endif
#endif /* __OF_RESERVED_MEM_H */
...@@ -274,6 +274,18 @@ $(obj)/%.dtb: $(src)/%.dts FORCE ...@@ -274,6 +274,18 @@ $(obj)/%.dtb: $(src)/%.dts FORCE
dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp) dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
# Helper targets for Installing DTBs into the boot directory
quiet_cmd_dtb_install = INSTALL $<
cmd_dtb_install = cp $< $(2)
_dtbinst_pre_:
$(Q)if [ -d $(INSTALL_DTBS_PATH).old ]; then rm -rf $(INSTALL_DTBS_PATH).old; fi
$(Q)if [ -d $(INSTALL_DTBS_PATH) ]; then mv $(INSTALL_DTBS_PATH) $(INSTALL_DTBS_PATH).old; fi
$(Q)mkdir -p $(INSTALL_DTBS_PATH)
%.dtb_dtbinst_: $(obj)/%.dtb _dtbinst_pre_
$(call cmd,dtb_install,$(INSTALL_DTBS_PATH))
# Bzip2 # Bzip2
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
......
This diff is collapsed.
/* A Bison parser, made by GNU Bison 2.5. */ /* A Bison parser, made by GNU Bison 2.7.12-4996. */
/* Bison interface for Yacc-like parsers in C /* Bison interface for Yacc-like parsers in C
Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -30,6 +30,15 @@ ...@@ -30,6 +30,15 @@
This special exception was added by the Free Software Foundation in This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */ version 2.2 of Bison. */
#ifndef YY_YY_DTC_PARSER_TAB_H_INCLUDED
# define YY_YY_DTC_PARSER_TAB_H_INCLUDED
/* Enabling traces. */
#ifndef YYDEBUG
# define YYDEBUG 0
#endif
#if YYDEBUG
extern int yydebug;
#endif
/* Tokens. */ /* Tokens. */
#ifndef YYTOKENTYPE #ifndef YYTOKENTYPE
...@@ -63,12 +72,10 @@ ...@@ -63,12 +72,10 @@
#endif #endif
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE typedef union YYSTYPE
{ {
/* Line 2053 of yacc.c */
/* Line 2068 of yacc.c */
#line 40 "dtc-parser.y" #line 40 "dtc-parser.y"
char *propnodename; char *propnodename;
...@@ -91,9 +98,8 @@ typedef union YYSTYPE ...@@ -91,9 +98,8 @@ typedef union YYSTYPE
uint64_t integer; uint64_t integer;
/* Line 2053 of yacc.c */
/* Line 2068 of yacc.c */ #line 103 "dtc-parser.tab.h"
#line 97 "dtc-parser.tab.h"
} YYSTYPE; } YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define yystype YYSTYPE /* obsolescent; will be withdrawn */
...@@ -102,4 +108,18 @@ typedef union YYSTYPE ...@@ -102,4 +108,18 @@ typedef union YYSTYPE
extern YYSTYPE yylval; extern YYSTYPE yylval;
#ifdef YYPARSE_PARAM
#if defined __STDC__ || defined __cplusplus
int yyparse (void *YYPARSE_PARAM);
#else
int yyparse ();
#endif
#else /* ! YYPARSE_PARAM */
#if defined __STDC__ || defined __cplusplus
int yyparse (void);
#else
int yyparse ();
#endif
#endif /* ! YYPARSE_PARAM */
#endif /* !YY_YY_DTC_PARSER_TAB_H_INCLUDED */
...@@ -21,8 +21,6 @@ ...@@ -21,8 +21,6 @@
#include "dtc.h" #include "dtc.h"
#include "srcpos.h" #include "srcpos.h"
#include "version_gen.h"
/* /*
* Command line options * Command line options
*/ */
...@@ -49,55 +47,60 @@ static void fill_fullpaths(struct node *tree, const char *prefix) ...@@ -49,55 +47,60 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
fill_fullpaths(child, tree->fullpath); fill_fullpaths(child, tree->fullpath);
} }
static void __attribute__ ((noreturn)) usage(void) /* Usage related data. */
{ static const char usage_synopsis[] = "dtc [options] <input file>";
fprintf(stderr, "Usage:\n"); static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv";
fprintf(stderr, "\tdtc [options] <input file>\n"); static struct option const usage_long_opts[] = {
fprintf(stderr, "\nOptions:\n"); {"quiet", no_argument, NULL, 'q'},
fprintf(stderr, "\t-h\n"); {"in-format", a_argument, NULL, 'I'},
fprintf(stderr, "\t\tThis help text\n"); {"out", a_argument, NULL, 'o'},
fprintf(stderr, "\t-q\n"); {"out-format", a_argument, NULL, 'O'},
fprintf(stderr, "\t\tQuiet: -q suppress warnings, -qq errors, -qqq all\n"); {"out-version", a_argument, NULL, 'V'},
fprintf(stderr, "\t-I <input format>\n"); {"out-dependency", a_argument, NULL, 'd'},
fprintf(stderr, "\t\tInput formats are:\n"); {"reserve", a_argument, NULL, 'R'},
fprintf(stderr, "\t\t\tdts - device tree source text\n"); {"space", a_argument, NULL, 'S'},
fprintf(stderr, "\t\t\tdtb - device tree blob\n"); {"pad", a_argument, NULL, 'p'},
fprintf(stderr, "\t\t\tfs - /proc/device-tree style directory\n"); {"boot-cpu", a_argument, NULL, 'b'},
fprintf(stderr, "\t-o <output file>\n"); {"force", no_argument, NULL, 'f'},
fprintf(stderr, "\t-O <output format>\n"); {"include", a_argument, NULL, 'i'},
fprintf(stderr, "\t\tOutput formats are:\n"); {"sort", no_argument, NULL, 's'},
fprintf(stderr, "\t\t\tdts - device tree source text\n"); {"phandle", a_argument, NULL, 'H'},
fprintf(stderr, "\t\t\tdtb - device tree blob\n"); {"warning", a_argument, NULL, 'W'},
fprintf(stderr, "\t\t\tasm - assembler source\n"); {"error", a_argument, NULL, 'E'},
fprintf(stderr, "\t-V <output version>\n"); {"help", no_argument, NULL, 'h'},
fprintf(stderr, "\t\tBlob version to produce, defaults to %d (relevant for dtb\n\t\tand asm output only)\n", DEFAULT_FDT_VERSION); {"version", no_argument, NULL, 'v'},
fprintf(stderr, "\t-d <output dependency file>\n"); {NULL, no_argument, NULL, 0x0},
fprintf(stderr, "\t-R <number>\n"); };
fprintf(stderr, "\t\tMake space for <number> reserve map entries (relevant for \n\t\tdtb and asm output only)\n"); static const char * const usage_opts_help[] = {
fprintf(stderr, "\t-S <bytes>\n"); "\n\tQuiet: -q suppress warnings, -qq errors, -qqq all",
fprintf(stderr, "\t\tMake the blob at least <bytes> long (extra space)\n"); "\n\tInput formats are:\n"
fprintf(stderr, "\t-p <bytes>\n"); "\t\tdts - device tree source text\n"
fprintf(stderr, "\t\tAdd padding to the blob of <bytes> long (extra space)\n"); "\t\tdtb - device tree blob\n"
fprintf(stderr, "\t-b <number>\n"); "\t\tfs - /proc/device-tree style directory",
fprintf(stderr, "\t\tSet the physical boot cpu\n"); "\n\tOutput file",
fprintf(stderr, "\t-f\n"); "\n\tOutput formats are:\n"
fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n"); "\t\tdts - device tree source text\n"
fprintf(stderr, "\t-i\n"); "\t\tdtb - device tree blob\n"
fprintf(stderr, "\t\tAdd a path to search for include files\n"); "\t\tasm - assembler source",
fprintf(stderr, "\t-s\n"); "\n\tBlob version to produce, defaults to %d (for dtb and asm output)", //, DEFAULT_FDT_VERSION);
fprintf(stderr, "\t\tSort nodes and properties before outputting (only useful for\n\t\tcomparing trees)\n"); "\n\tOutput dependency file",
fprintf(stderr, "\t-v\n"); "\n\ttMake space for <number> reserve map entries (for dtb and asm output)",
fprintf(stderr, "\t\tPrint DTC version and exit\n"); "\n\tMake the blob at least <bytes> long (extra space)",
fprintf(stderr, "\t-H <phandle format>\n"); "\n\tAdd padding to the blob of <bytes> long (extra space)",
fprintf(stderr, "\t\tphandle formats are:\n"); "\n\tSet the physical boot cpu",
fprintf(stderr, "\t\t\tlegacy - \"linux,phandle\" properties only\n"); "\n\tTry to produce output even if the input tree has errors",
fprintf(stderr, "\t\t\tepapr - \"phandle\" properties only\n"); "\n\tAdd a path to search for include files",
fprintf(stderr, "\t\t\tboth - Both \"linux,phandle\" and \"phandle\" properties\n"); "\n\tSort nodes and properties before outputting (useful for comparing trees)",
fprintf(stderr, "\t-W [no-]<checkname>\n"); "\n\tValid phandle formats are:\n"
fprintf(stderr, "\t-E [no-]<checkname>\n"); "\t\tlegacy - \"linux,phandle\" properties only\n"
fprintf(stderr, "\t\t\tenable or disable warnings and errors\n"); "\t\tepapr - \"phandle\" properties only\n"
exit(3); "\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
} "\n\tEnable/disable warnings (prefix with \"no-\")",
"\n\tEnable/disable errors (prefix with \"no-\")",
"\n\tPrint this help and exit",
"\n\tPrint version and exit",
NULL,
};
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
...@@ -118,8 +121,7 @@ int main(int argc, char *argv[]) ...@@ -118,8 +121,7 @@ int main(int argc, char *argv[])
minsize = 0; minsize = 0;
padsize = 0; padsize = 0;
while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fqb:i:vH:sW:E:")) while ((opt = util_getopt_long()) != EOF) {
!= EOF) {
switch (opt) { switch (opt) {
case 'I': case 'I':
inform = optarg; inform = optarg;
...@@ -158,8 +160,7 @@ int main(int argc, char *argv[]) ...@@ -158,8 +160,7 @@ int main(int argc, char *argv[])
srcfile_add_search_path(optarg); srcfile_add_search_path(optarg);
break; break;
case 'v': case 'v':
printf("Version: %s\n", DTC_VERSION); util_version();
exit(0);
case 'H': case 'H':
if (streq(optarg, "legacy")) if (streq(optarg, "legacy"))
phandle_format = PHANDLE_LEGACY; phandle_format = PHANDLE_LEGACY;
...@@ -185,13 +186,14 @@ int main(int argc, char *argv[]) ...@@ -185,13 +186,14 @@ int main(int argc, char *argv[])
break; break;
case 'h': case 'h':
usage(NULL);
default: default:
usage(); usage("unknown option");
} }
} }
if (argc > (optind+1)) if (argc > (optind+1))
usage(); usage("missing files");
else if (argc < (optind+1)) else if (argc < (optind+1))
arg = "-"; arg = "-";
else else
...@@ -201,9 +203,6 @@ int main(int argc, char *argv[]) ...@@ -201,9 +203,6 @@ int main(int argc, char *argv[])
if (minsize && padsize) if (minsize && padsize)
die("Can't set both -p and -S\n"); die("Can't set both -p and -S\n");
if (minsize)
fprintf(stderr, "DTC: Use of \"-S\" is deprecated; it will be removed soon, use \"-p\" instead\n");
if (depname) { if (depname) {
depfile = fopen(depname, "w"); depfile = fopen(depname, "w");
if (!depfile) if (!depfile)
......
...@@ -66,7 +66,6 @@ typedef uint32_t cell_t; ...@@ -66,7 +66,6 @@ typedef uint32_t cell_t;
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) #define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
/* Data blobs */ /* Data blobs */
enum markertype { enum markertype {
......
...@@ -297,9 +297,9 @@ srcpos_verror(struct srcpos *pos, char const *fmt, va_list va) ...@@ -297,9 +297,9 @@ srcpos_verror(struct srcpos *pos, char const *fmt, va_list va)
srcstr = srcpos_string(pos); srcstr = srcpos_string(pos);
fprintf(stdout, "Error: %s ", srcstr); fprintf(stderr, "Error: %s ", srcstr);
vfprintf(stdout, fmt, va); vfprintf(stderr, fmt, va);
fprintf(stdout, "\n"); fprintf(stderr, "\n");
} }
void void
......
#!/bin/sh
# Simple script to update the version of DTC carried by the Linux kernel
#
# This script assumes that the dtc and the linux git trees are in the
# same directory. After building dtc in the dtc directory, it copies the
# source files and generated source files into the scripts/dtc directory
# in the kernel and creates a git commit updating them to the new
# version.
#
# Usage: from the top level Linux source tree, run:
# $ ./scripts/dtc/update-dtc-source.sh
#
# The script will change into the dtc tree, build and test dtc, copy the
# relevant files into the kernel tree and create a git commit. The commit
# message will need to be modified to reflect the version of DTC being
# imported
#
# TODO:
# This script is pretty basic, but it is seldom used so a few manual tasks
# aren't a big deal. If anyone is interested in making it more robust, the
# the following would be nice:
# * Actually fail to complete if any testcase fails.
# - The dtc "make check" target needs to return a failure
# * Extract the version number from the dtc repo for the commit message
# * Build dtc in the kernel tree
# * run 'make check" on dtc built from the kernel tree
set -ev
DTC_UPSTREAM_PATH=`pwd`/../dtc
DTC_LINUX_PATH=`pwd`/scripts/dtc
DTC_SOURCE="checks.c data.c dtc.c dtc.h flattree.c fstree.c livetree.c srcpos.c \
srcpos.h treesource.c util.c util.h version_gen.h Makefile.dtc \
dtc-lexer.l dtc-parser.y"
DTC_GENERATED="dtc-lexer.lex.c dtc-parser.tab.c dtc-parser.tab.h"
# Build DTC
cd $DTC_UPSTREAM_PATH
make clean
make check
# Copy the files into the Linux tree
cd $DTC_LINUX_PATH
for f in $DTC_SOURCE; do
cp ${DTC_UPSTREAM_PATH}/${f} ${f}
git add ${f}
done
for f in $DTC_GENERATED; do
cp ${DTC_UPSTREAM_PATH}/$f ${f}_shipped
git add ${f}_shipped
done
git commit -e -v -m "scripts/dtc: Update to upstream version [CHANGEME]"
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "libfdt.h" #include "libfdt.h"
#include "util.h" #include "util.h"
#include "version_gen.h"
char *xstrdup(const char *s) char *xstrdup(const char *s)
{ {
...@@ -72,7 +73,7 @@ char *join_path(const char *path, const char *name) ...@@ -72,7 +73,7 @@ char *join_path(const char *path, const char *name)
int util_is_printable_string(const void *data, int len) int util_is_printable_string(const void *data, int len)
{ {
const char *s = data; const char *s = data;
const char *ss; const char *ss, *se;
/* zero length is not */ /* zero length is not */
if (len == 0) if (len == 0)
...@@ -82,13 +83,19 @@ int util_is_printable_string(const void *data, int len) ...@@ -82,13 +83,19 @@ int util_is_printable_string(const void *data, int len)
if (s[len - 1] != '\0') if (s[len - 1] != '\0')
return 0; return 0;
ss = s; se = s + len;
while (*s && isprint(*s))
s++;
/* not zero, or not done yet */ while (s < se) {
if (*s != '\0' || (s + 1 - ss) < len) ss = s;
return 0; while (s < se && *s && isprint(*s))
s++;
/* not zero, or not done yet */
if (*s != '\0' || s == ss)
return 0;
s++;
}
return 1; return 1;
} }
...@@ -191,7 +198,7 @@ char get_escape_char(const char *s, int *i) ...@@ -191,7 +198,7 @@ char get_escape_char(const char *s, int *i)
return val; return val;
} }
int utilfdt_read_err(const char *filename, char **buffp) int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
{ {
int fd = 0; /* assume stdin */ int fd = 0; /* assume stdin */
char *buf = NULL; char *buf = NULL;
...@@ -206,12 +213,12 @@ int utilfdt_read_err(const char *filename, char **buffp) ...@@ -206,12 +213,12 @@ int utilfdt_read_err(const char *filename, char **buffp)
} }
/* Loop until we have read everything */ /* Loop until we have read everything */
buf = malloc(bufsize); buf = xmalloc(bufsize);
do { do {
/* Expand the buffer to hold the next chunk */ /* Expand the buffer to hold the next chunk */
if (offset == bufsize) { if (offset == bufsize) {
bufsize *= 2; bufsize *= 2;
buf = realloc(buf, bufsize); buf = xrealloc(buf, bufsize);
if (!buf) { if (!buf) {
ret = ENOMEM; ret = ENOMEM;
break; break;
...@@ -232,13 +239,20 @@ int utilfdt_read_err(const char *filename, char **buffp) ...@@ -232,13 +239,20 @@ int utilfdt_read_err(const char *filename, char **buffp)
free(buf); free(buf);
else else
*buffp = buf; *buffp = buf;
*len = bufsize;
return ret; return ret;
} }
char *utilfdt_read(const char *filename) int utilfdt_read_err(const char *filename, char **buffp)
{
off_t len;
return utilfdt_read_err_len(filename, buffp, &len);
}
char *utilfdt_read_len(const char *filename, off_t *len)
{ {
char *buff; char *buff;
int ret = utilfdt_read_err(filename, &buff); int ret = utilfdt_read_err_len(filename, &buff, len);
if (ret) { if (ret) {
fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename, fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
...@@ -249,6 +263,12 @@ char *utilfdt_read(const char *filename) ...@@ -249,6 +263,12 @@ char *utilfdt_read(const char *filename)
return buff; return buff;
} }
char *utilfdt_read(const char *filename)
{
off_t len;
return utilfdt_read_len(filename, &len);
}
int utilfdt_write_err(const char *filename, const void *blob) int utilfdt_write_err(const char *filename, const void *blob)
{ {
int fd = 1; /* assume stdout */ int fd = 1; /* assume stdout */
...@@ -329,3 +349,100 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size) ...@@ -329,3 +349,100 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size)
return -1; return -1;
return 0; return 0;
} }
void utilfdt_print_data(const char *data, int len)
{
int i;
const char *p = data;
const char *s;
/* no data, don't print */
if (len == 0)
return;
if (util_is_printable_string(data, len)) {
printf(" = ");
s = data;
do {
printf("\"%s\"", s);
s += strlen(s) + 1;
if (s < data + len)
printf(", ");
} while (s < data + len);
} else if ((len % 4) == 0) {
const uint32_t *cell = (const uint32_t *)data;
printf(" = <");
for (i = 0; i < len; i += 4)
printf("0x%08x%s", fdt32_to_cpu(cell[i]),
i < (len - 4) ? " " : "");
printf(">");
} else {
printf(" = [");
for (i = 0; i < len; i++)
printf("%02x%s", *p++, i < len - 1 ? " " : "");
printf("]");
}
}
void util_version(void)
{
printf("Version: %s\n", DTC_VERSION);
exit(0);
}
void util_usage(const char *errmsg, const char *synopsis,
const char *short_opts, struct option const long_opts[],
const char * const opts_help[])
{
FILE *fp = errmsg ? stderr : stdout;
const char a_arg[] = "<arg>";
size_t a_arg_len = strlen(a_arg) + 1;
size_t i;
int optlen;
fprintf(fp,
"Usage: %s\n"
"\n"
"Options: -[%s]\n", synopsis, short_opts);
/* prescan the --long opt length to auto-align */
optlen = 0;
for (i = 0; long_opts[i].name; ++i) {
/* +1 is for space between --opt and help text */
int l = strlen(long_opts[i].name) + 1;
if (long_opts[i].has_arg == a_argument)
l += a_arg_len;
if (optlen < l)
optlen = l;
}
for (i = 0; long_opts[i].name; ++i) {
/* helps when adding new applets or options */
assert(opts_help[i] != NULL);
/* first output the short flag if it has one */
if (long_opts[i].val > '~')
fprintf(fp, " ");
else
fprintf(fp, " -%c, ", long_opts[i].val);
/* then the long flag */
if (long_opts[i].has_arg == no_argument)
fprintf(fp, "--%-*s", optlen, long_opts[i].name);
else
fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg,
(int)(optlen - strlen(long_opts[i].name) - a_arg_len), "");
/* finally the help text */
fprintf(fp, "%s\n", opts_help[i]);
}
if (errmsg) {
fprintf(fp, "\nError: %s\n", errmsg);
exit(EXIT_FAILURE);
} else
exit(EXIT_SUCCESS);
}
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define _UTIL_H #define _UTIL_H
#include <stdarg.h> #include <stdarg.h>
#include <getopt.h>
/* /*
* Copyright 2011 The Chromium Authors, All Rights Reserved. * Copyright 2011 The Chromium Authors, All Rights Reserved.
...@@ -23,7 +24,9 @@ ...@@ -23,7 +24,9 @@
* USA * USA
*/ */
static inline void __attribute__((noreturn)) die(char * str, ...) #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
static inline void __attribute__((noreturn)) die(const char *str, ...)
{ {
va_list ap; va_list ap;
...@@ -57,12 +60,14 @@ extern char *xstrdup(const char *s); ...@@ -57,12 +60,14 @@ extern char *xstrdup(const char *s);
extern char *join_path(const char *path, const char *name); extern char *join_path(const char *path, const char *name);
/** /**
* Check a string of a given length to see if it is all printable and * Check a property of a given length to see if it is all printable and
* has a valid terminator. * has a valid terminator. The property can contain either a single string,
* or multiple strings each of non-zero length.
* *
* @param data The string to check * @param data The string to check
* @param len The string length including terminator * @param len The string length including terminator
* @return 1 if a valid printable string, 0 if not */ * @return 1 if a valid printable string, 0 if not
*/
int util_is_printable_string(const void *data, int len); int util_is_printable_string(const void *data, int len);
/* /*
...@@ -82,6 +87,13 @@ char get_escape_char(const char *s, int *i); ...@@ -82,6 +87,13 @@ char get_escape_char(const char *s, int *i);
*/ */
char *utilfdt_read(const char *filename); char *utilfdt_read(const char *filename);
/**
* Like utilfdt_read(), but also passes back the size of the file read.
*
* @param len If non-NULL, the amount of data we managed to read
*/
char *utilfdt_read_len(const char *filename, off_t *len);
/** /**
* Read a device tree file into a buffer. Does not report errors, but only * Read a device tree file into a buffer. Does not report errors, but only
* returns them. The value returned can be passed to strerror() to obtain * returns them. The value returned can be passed to strerror() to obtain
...@@ -93,6 +105,12 @@ char *utilfdt_read(const char *filename); ...@@ -93,6 +105,12 @@ char *utilfdt_read(const char *filename);
*/ */
int utilfdt_read_err(const char *filename, char **buffp); int utilfdt_read_err(const char *filename, char **buffp);
/**
* Like utilfdt_read_err(), but also passes back the size of the file read.
*
* @param len If non-NULL, the amount of data we managed to read
*/
int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len);
/** /**
* Write a device tree buffer to a file. This will report any errors on * Write a device tree buffer to a file. This will report any errors on
...@@ -148,6 +166,85 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size); ...@@ -148,6 +166,85 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size);
#define USAGE_TYPE_MSG \ #define USAGE_TYPE_MSG \
"<type>\ts=string, i=int, u=unsigned, x=hex\n" \ "<type>\ts=string, i=int, u=unsigned, x=hex\n" \
"\tOptional modifier prefix:\n" \ "\tOptional modifier prefix:\n" \
"\t\thh or b=byte, h=2 byte, l=4 byte (default)\n"; "\t\thh or b=byte, h=2 byte, l=4 byte (default)";
/**
* Print property data in a readable format to stdout
*
* Properties that look like strings will be printed as strings. Otherwise
* the data will be displayed either as cells (if len is a multiple of 4
* bytes) or bytes.
*
* If len is 0 then this function does nothing.
*
* @param data Pointers to property data
* @param len Length of property data
*/
void utilfdt_print_data(const char *data, int len);
/**
* Show source version and exit
*/
void util_version(void) __attribute__((noreturn));
/**
* Show usage and exit
*
* This helps standardize the output of various utils. You most likely want
* to use the usage() helper below rather than call this.
*
* @param errmsg If non-NULL, an error message to display
* @param synopsis The initial example usage text (and possible examples)
* @param short_opts The string of short options
* @param long_opts The structure of long options
* @param opts_help An array of help strings (should align with long_opts)
*/
void util_usage(const char *errmsg, const char *synopsis,
const char *short_opts, struct option const long_opts[],
const char * const opts_help[]) __attribute__((noreturn));
/**
* Show usage and exit
*
* If you name all your usage variables with usage_xxx, then you can call this
* help macro rather than expanding all arguments yourself.
*
* @param errmsg If non-NULL, an error message to display
*/
#define usage(errmsg) \
util_usage(errmsg, usage_synopsis, usage_short_opts, \
usage_long_opts, usage_opts_help)
/**
* Call getopt_long() with standard options
*
* Since all util code runs getopt in the same way, provide a helper.
*/
#define util_getopt_long() getopt_long(argc, argv, usage_short_opts, \
usage_long_opts, NULL)
/* Helper for aligning long_opts array */
#define a_argument required_argument
/* Helper for usage_short_opts string constant */
#define USAGE_COMMON_SHORT_OPTS "hV"
/* Helper for usage_long_opts option array */
#define USAGE_COMMON_LONG_OPTS \
{"help", no_argument, NULL, 'h'}, \
{"version", no_argument, NULL, 'V'}, \
{NULL, no_argument, NULL, 0x0}
/* Helper for usage_opts_help array */
#define USAGE_COMMON_OPTS_HELP \
"Print this help and exit", \
"Print version and exit", \
NULL
/* Helper for getopt case statements */
#define case_USAGE_COMMON_FLAGS \
case 'h': usage(NULL); \
case 'V': util_version(); \
case '?': usage("unknown option");
#endif /* _UTIL_H */ #endif /* _UTIL_H */
#define DTC_VERSION "DTC 1.2.0-g37c0b6a0" #define DTC_VERSION "DTC 1.4.0-dirty"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment