Devicetree changes for v3.15
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 * Preparation 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] -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.14 (GNU/Linux) iQIcBAABAgAGBQJTOyNwAAoJEMWQL496c2LNZY0QAIreUrpo3/hKRau61EDPXkOA UFRyPUHD0k/dNXWWDbTfvKH/nAfzdVwejhePqEWiODiFOFkq7JyQlMKPA+CZuZj0 ygN4215A1yj/hDf6JRD5Zn4WGpawDt9InlbZSps6P5dd8voV5t5dz6uzz+Y7uqaK CAjTDlBSmxEen5vRHiHQgKv74au/+b9yfSURjPQVWg46+wl3WJwjsdzerphm4unW tpEr8zkIsm51mqqAx4penIuiovh7+L2J5v4BFeg8o+kaZEuZpVxLHJPOuBd5hdom zeqEIj3AqHTh5suYIHe4aAbZ2wMP3kYGgkPGwfWLnwLyULxalcCtGZeaCi9nwTFj Fdj+7f17ocrt5mif0f5Deufi1LqJsDjhY6G9p7HuV7Y9hsMILpJIUoGENPji+TWj BA4L45eaPmNYdKJytEtFD7F2WnXeHZ6fDtYho/39DWW+Bt16IFX85T199irhxGG4 byN6LRaahk2UeycSXkQHAlWOQHqzBcJJAkQLN2iahzyYRr9Dy+VI2E9clm53m49O YQYcONdUlMYrtfRwJpbB9XHM0HgZUvg0LT5z/iHQs9uJtoo33Oj+zxFixyZLQ9Dq qyLqQWEpV9gFLAo9tpf56gffkLiJRsHkX4UJ6oTtj4DY1WWU9H81jjCvv/7flzp/ 8ZyyZzANQf1DZ9kqO2v+ =lyA5 -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
Коммит
b9f2b21a32
|
@ -0,0 +1,28 @@
|
|||
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.
|
|
@ -0,0 +1,133 @@
|
|||
*** 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.
|
|||
This isn't an exhaustive list, but you should add new prefixes to it before
|
||||
using them to avoid name-space collisions.
|
||||
|
||||
abilis Abilis Systems
|
||||
active-semi Active-Semi International Inc
|
||||
ad Avionic Design GmbH
|
||||
adi Analog Devices, Inc.
|
||||
|
@ -11,14 +12,17 @@ ak Asahi Kasei Corp.
|
|||
allwinner Allwinner Technology Co., Ltd.
|
||||
altr Altera Corp.
|
||||
amcc Applied Micro Circuits Corporation (APM, formally AMCC)
|
||||
amd Advanced Micro Devices (AMD), Inc.
|
||||
amstaos AMS-Taos Inc.
|
||||
apm Applied Micro Circuits Corporation (APM)
|
||||
arm ARM Ltd.
|
||||
armadeus ARMadeus Systems SARL
|
||||
atmel Atmel Corporation
|
||||
auo AU Optronics Corporation
|
||||
avago Avago Technologies
|
||||
bosch Bosch Sensortec GmbH
|
||||
brcm Broadcom Corporation
|
||||
calxeda Calxeda
|
||||
capella Capella Microsystems, Inc
|
||||
cavium Cavium, Inc.
|
||||
cdns Cadence Design Systems Inc.
|
||||
|
@ -26,8 +30,10 @@ chrp Common Hardware Reference Platform
|
|||
chunghwa Chunghwa Picture Tubes Ltd.
|
||||
cirrus Cirrus Logic, Inc.
|
||||
cortina Cortina Systems, Inc.
|
||||
crystalfontz Crystalfontz America, Inc.
|
||||
dallas Maxim Integrated Products (formerly Dallas Semiconductor)
|
||||
davicom DAVICOM Semiconductor, Inc.
|
||||
dlink D-Link Systems, Inc.
|
||||
denx Denx Software Engineering
|
||||
edt Emerging Display Technologies
|
||||
emmicro EM Microelectronic
|
||||
|
@ -37,7 +43,9 @@ est ESTeem Wireless Modems
|
|||
fsl Freescale Semiconductor
|
||||
GEFanuc 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.
|
||||
google Google, Inc.
|
||||
gumstix Gumstix, Inc.
|
||||
haoyu Haoyu Microelectronic Co. Ltd.
|
||||
hisilicon Hisilicon Limited.
|
||||
|
@ -46,9 +54,12 @@ hp Hewlett Packard
|
|||
ibm International Business Machines (IBM)
|
||||
idt Integrated Device Technologies, Inc.
|
||||
img Imagination Technologies Ltd.
|
||||
intel Intel Corporation
|
||||
intercontrol Inter Control Group
|
||||
isl Intersil
|
||||
karo Ka-Ro electronics GmbH
|
||||
lacie LaCie
|
||||
lantiq Lantiq Semiconductor
|
||||
lg LG Corporation
|
||||
linux Linux-specific binding
|
||||
lsi LSI Corp. (LSI Logic)
|
||||
|
@ -56,12 +67,16 @@ marvell Marvell Technology Group Ltd.
|
|||
maxim Maxim Integrated Products
|
||||
microchip Microchip Technology Inc.
|
||||
mosaixtech Mosaix Technologies, Inc.
|
||||
moxa Moxa
|
||||
national National Semiconductor
|
||||
neonode Neonode Inc.
|
||||
netgear NETGEAR
|
||||
nintendo Nintendo
|
||||
nokia Nokia
|
||||
nvidia NVIDIA
|
||||
nxp NXP Semiconductors
|
||||
onnn ON Semiconductor Corp.
|
||||
opencores OpenCores.org
|
||||
panasonic Panasonic Corporation
|
||||
phytec PHYTEC Messtechnik GmbH
|
||||
picochip Picochip Ltd
|
||||
|
@ -80,6 +95,7 @@ sil Silicon Image
|
|||
silabs Silicon Laboratories
|
||||
simtek
|
||||
sirf SiRF Technology, Inc.
|
||||
smsc Standard Microsystems Corporation
|
||||
snps Synopsys, Inc.
|
||||
spansion Spansion Inc.
|
||||
st STMicroelectronics
|
||||
|
@ -94,4 +110,5 @@ via VIA Technologies, Inc.
|
|||
winbond Winbond Electronics corp.
|
||||
wlf Wolfson Microelectronics
|
||||
wm Wondermedia Technologies, Inc.
|
||||
xes Extreme Engineering Solutions (X-ES)
|
||||
xlnx Xilinx
|
||||
|
|
7
Makefile
7
Makefile
|
@ -728,6 +728,13 @@ export KBUILD_IMAGE ?= vmlinux
|
|||
# images. Default is /boot, but you can set it to other values
|
||||
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
|
||||
# relocations required by build roots. This is not defined in the
|
||||
|
|
|
@ -1918,6 +1918,7 @@ config USE_OF
|
|||
select IRQ_DOMAIN
|
||||
select OF
|
||||
select OF_EARLY_FLATTREE
|
||||
select OF_RESERVED_MEM
|
||||
help
|
||||
Include support for flattened device tree machine descriptions.
|
||||
|
||||
|
|
|
@ -310,9 +310,9 @@ $(INSTALL_TARGETS):
|
|||
%.dtb: | scripts
|
||||
$(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $(boot)/dts/$@
|
||||
|
||||
PHONY += dtbs
|
||||
dtbs: scripts
|
||||
$(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) dtbs
|
||||
PHONY += dtbs dtbs_install
|
||||
dtbs dtbs_install: prepare scripts
|
||||
$(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $@
|
||||
|
||||
# We use MRPROPER_FILES and CLEAN_FILES now
|
||||
archclean:
|
||||
|
@ -331,6 +331,7 @@ define archhelp
|
|||
echo ' bootpImage - Combined zImage and initial RAM disk'
|
||||
echo ' (supply initrd image via make variable INITRD=<path>)'
|
||||
echo '* dtbs - Build device tree blobs for enabled boards'
|
||||
echo ' dtbs_install - Install dtbs to $(INSTALL_DTBS_PATH)'
|
||||
echo ' install - Install uncompressed kernel'
|
||||
echo ' zinstall - Install compressed kernel'
|
||||
echo ' uinstall - Install U-Boot wrapped compressed kernel'
|
||||
|
|
|
@ -323,7 +323,7 @@ dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb \
|
|||
zynq-zc706.dtb \
|
||||
zynq-zed.dtb
|
||||
|
||||
targets += dtbs
|
||||
targets += dtbs dtbs_install
|
||||
targets += $(dtb-y)
|
||||
endif
|
||||
|
||||
|
@ -333,3 +333,5 @@ dtbs: $(addprefix $(obj)/, $(dtb-y))
|
|||
$(Q)rm -f $(obj)/../*.dtb
|
||||
|
||||
clean-files := *.dtb
|
||||
|
||||
dtbs_install: $(addsuffix _dtbinst_, $(dtb-y))
|
||||
|
|
|
@ -16,6 +16,7 @@ config ARCH_MVEBU
|
|||
select ARCH_REQUIRE_GPIOLIB
|
||||
select MIGHT_HAVE_PCI
|
||||
select PCI_QUIRKS if PCI
|
||||
select OF_ADDRESS_PCI
|
||||
|
||||
if ARCH_MVEBU
|
||||
|
||||
|
|
|
@ -102,7 +102,6 @@ config ARCH_OMAP2PLUS
|
|||
select MACH_OMAP_GENERIC
|
||||
select OMAP_DM_TIMER
|
||||
select PINCTRL
|
||||
select PROC_DEVICETREE if PROC_FS
|
||||
select SOC_BUS
|
||||
select SPARSE_IRQ
|
||||
select TI_PRIV_EDMA
|
||||
|
|
|
@ -323,6 +323,8 @@ void __init arm_memblock_init(struct meminfo *mi,
|
|||
if (mdesc->reserve)
|
||||
mdesc->reserve();
|
||||
|
||||
early_init_fdt_scan_reserved_mem();
|
||||
|
||||
/*
|
||||
* reserve memory for DMA contigouos allocations,
|
||||
* must come from DMA area inside low memory
|
||||
|
|
|
@ -47,6 +47,7 @@ config ARM64
|
|||
select NO_BOOTMEM
|
||||
select OF
|
||||
select OF_EARLY_FLATTREE
|
||||
select OF_RESERVED_MEM
|
||||
select PERF_USE_VMALLOC
|
||||
select POWER_RESET
|
||||
select POWER_SUPPLY
|
||||
|
|
|
@ -161,6 +161,7 @@ void __init arm64_memblock_init(void)
|
|||
memblock_reserve(base, size);
|
||||
}
|
||||
|
||||
early_init_fdt_scan_reserved_mem();
|
||||
dma_contiguous_reserve(0);
|
||||
|
||||
memblock_allow_resize();
|
||||
|
|
|
@ -90,6 +90,7 @@ config PPC
|
|||
select BINFMT_ELF
|
||||
select OF
|
||||
select OF_EARLY_FLATTREE
|
||||
select OF_RESERVED_MEM
|
||||
select HAVE_FTRACE_MCOUNT_RECORD
|
||||
select HAVE_DYNAMIC_FTRACE
|
||||
select HAVE_FUNCTION_TRACER
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <linux/irq.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_fdt.h>
|
||||
|
||||
#include <asm/prom.h>
|
||||
#include <asm/rtas.h>
|
||||
|
@ -588,6 +589,8 @@ 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)
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/cpu.h>
|
||||
|
@ -87,7 +86,6 @@ static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa,
|
|||
}
|
||||
|
||||
of_node_set_flag(dn, OF_DYNAMIC);
|
||||
kref_init(&dn->kref);
|
||||
|
||||
return dn;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -70,7 +69,6 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist
|
|||
|
||||
np->properties = proplist;
|
||||
of_node_set_flag(np, OF_DYNAMIC);
|
||||
kref_init(&np->kref);
|
||||
|
||||
np->parent = derive_parent(path);
|
||||
if (IS_ERR(np->parent)) {
|
||||
|
|
|
@ -202,7 +202,7 @@ void __init test_of_node(void)
|
|||
|
||||
/* There should really be a struct device_node allocator */
|
||||
memset(&of_node, 0, sizeof(of_node));
|
||||
kref_init(&of_node.kref);
|
||||
kref_init(&of_node.kobj.kref);
|
||||
of_node.full_name = node_name;
|
||||
|
||||
check(0 == msi_bitmap_alloc(&bmp, size, &of_node));
|
||||
|
|
|
@ -7,14 +7,6 @@ config OF
|
|||
menu "Device Tree and Open Firmware support"
|
||||
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
|
||||
bool "Device Tree Runtime self tests"
|
||||
depends on OF_IRQ
|
||||
|
@ -44,6 +36,10 @@ config OF_DYNAMIC
|
|||
config OF_ADDRESS
|
||||
def_bool y
|
||||
depends on !SPARC
|
||||
select OF_ADDRESS_PCI if PCI
|
||||
|
||||
config OF_ADDRESS_PCI
|
||||
bool
|
||||
|
||||
config OF_IRQ
|
||||
def_bool y
|
||||
|
@ -75,4 +71,10 @@ config OF_MTD
|
|||
depends on MTD
|
||||
def_bool y
|
||||
|
||||
config OF_RESERVED_MEM
|
||||
depends on OF_EARLY_FLATTREE
|
||||
bool
|
||||
help
|
||||
Helpers to allow for reservation of memory regions
|
||||
|
||||
endmenu # OF
|
||||
|
|
|
@ -9,3 +9,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o
|
|||
obj-$(CONFIG_OF_PCI) += of_pci.o
|
||||
obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
|
||||
obj-$(CONFIG_OF_MTD) += of_mtd.o
|
||||
obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
|
||||
|
|
|
@ -91,7 +91,7 @@ static unsigned int of_bus_default_get_flags(const __be32 *addr)
|
|||
return IORESOURCE_MEM;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
#ifdef CONFIG_OF_ADDRESS_PCI
|
||||
/*
|
||||
* PCI bus specific translator
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
#endif /* CONFIG_OF_ADDRESS_PCI */
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
|
||||
unsigned int *flags)
|
||||
{
|
||||
|
@ -356,7 +358,7 @@ static unsigned int of_bus_isa_get_flags(const __be32 *addr)
|
|||
*/
|
||||
|
||||
static struct of_bus of_busses[] = {
|
||||
#ifdef CONFIG_PCI
|
||||
#ifdef CONFIG_OF_ADDRESS_PCI
|
||||
/* PCI */
|
||||
{
|
||||
.name = "pci",
|
||||
|
@ -367,7 +369,7 @@ static struct of_bus of_busses[] = {
|
|||
.translate = of_bus_pci_translate,
|
||||
.get_flags = of_bus_pci_get_flags,
|
||||
},
|
||||
#endif /* CONFIG_PCI */
|
||||
#endif /* CONFIG_OF_ADDRESS_PCI */
|
||||
/* ISA */
|
||||
{
|
||||
.name = "isa",
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/of_graph.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/proc_fs.h>
|
||||
|
||||
#include "of_private.h"
|
||||
|
@ -36,6 +37,12 @@ struct device_node *of_chosen;
|
|||
struct device_node *of_aliases;
|
||||
static struct device_node *of_stdout;
|
||||
|
||||
static struct kset *of_kset;
|
||||
|
||||
/*
|
||||
* Used to protect the of_aliases; but also overloaded to hold off addition of
|
||||
* nodes to sysfs
|
||||
*/
|
||||
DEFINE_MUTEX(of_aliases_mutex);
|
||||
|
||||
/* use when traversing tree through the allnext, child, sibling,
|
||||
|
@ -93,14 +100,14 @@ int __weak of_node_to_nid(struct device_node *np)
|
|||
struct device_node *of_node_get(struct device_node *node)
|
||||
{
|
||||
if (node)
|
||||
kref_get(&node->kref);
|
||||
kobject_get(&node->kobj);
|
||||
return node;
|
||||
}
|
||||
EXPORT_SYMBOL(of_node_get);
|
||||
|
||||
static inline struct device_node *kref_to_device_node(struct kref *kref)
|
||||
static inline struct device_node *kobj_to_device_node(struct kobject *kobj)
|
||||
{
|
||||
return container_of(kref, struct device_node, kref);
|
||||
return container_of(kobj, struct device_node, kobj);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -110,16 +117,15 @@ static inline struct device_node *kref_to_device_node(struct kref *kref)
|
|||
* In of_node_put() this function is passed to kref_put()
|
||||
* as the destructor.
|
||||
*/
|
||||
static void of_node_release(struct kref *kref)
|
||||
static void of_node_release(struct kobject *kobj)
|
||||
{
|
||||
struct device_node *node = kref_to_device_node(kref);
|
||||
struct device_node *node = kobj_to_device_node(kobj);
|
||||
struct property *prop = node->properties;
|
||||
|
||||
/* We should never be releasing nodes that haven't been detached. */
|
||||
if (!of_node_check_flag(node, OF_DETACHED)) {
|
||||
pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name);
|
||||
dump_stack();
|
||||
kref_init(&node->kref);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -152,11 +158,154 @@ static void of_node_release(struct kref *kref)
|
|||
void of_node_put(struct device_node *node)
|
||||
{
|
||||
if (node)
|
||||
kref_put(&node->kref, of_node_release);
|
||||
kobject_put(&node->kobj);
|
||||
}
|
||||
EXPORT_SYMBOL(of_node_put);
|
||||
#else
|
||||
static void of_node_release(struct kobject *kobj)
|
||||
{
|
||||
/* Without CONFIG_OF_DYNAMIC, no nodes gets freed */
|
||||
}
|
||||
#endif /* CONFIG_OF_DYNAMIC */
|
||||
|
||||
struct kobj_type of_node_ktype = {
|
||||
.release = of_node_release,
|
||||
};
|
||||
|
||||
static ssize_t of_node_property_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr, char *buf,
|
||||
loff_t offset, size_t count)
|
||||
{
|
||||
struct property *pp = container_of(bin_attr, struct property, attr);
|
||||
return memory_read_from_buffer(buf, count, &offset, pp->value, pp->length);
|
||||
}
|
||||
|
||||
static const char *safe_name(struct kobject *kobj, const char *orig_name)
|
||||
{
|
||||
const char *name = orig_name;
|
||||
struct kernfs_node *kn;
|
||||
int i = 0;
|
||||
|
||||
/* don't be a hero. After 16 tries give up */
|
||||
while (i < 16 && (kn = sysfs_get_dirent(kobj->sd, name))) {
|
||||
sysfs_put(kn);
|
||||
if (name != orig_name)
|
||||
kfree(name);
|
||||
name = kasprintf(GFP_KERNEL, "%s#%i", orig_name, ++i);
|
||||
}
|
||||
|
||||
if (name != orig_name)
|
||||
pr_warn("device-tree: Duplicate name in %s, renamed to \"%s\"\n",
|
||||
kobject_name(kobj), name);
|
||||
return name;
|
||||
}
|
||||
|
||||
static int __of_add_property_sysfs(struct device_node *np, struct property *pp)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Important: Don't leak passwords */
|
||||
bool secure = strncmp(pp->name, "security-", 9) == 0;
|
||||
|
||||
sysfs_bin_attr_init(&pp->attr);
|
||||
pp->attr.attr.name = safe_name(&np->kobj, pp->name);
|
||||
pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO;
|
||||
pp->attr.size = secure ? 0 : pp->length;
|
||||
pp->attr.read = of_node_property_read;
|
||||
|
||||
rc = sysfs_create_bin_file(&np->kobj, &pp->attr);
|
||||
WARN(rc, "error adding attribute %s to node %s\n", pp->name, np->full_name);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __of_node_add(struct device_node *np)
|
||||
{
|
||||
const char *name;
|
||||
struct property *pp;
|
||||
int rc;
|
||||
|
||||
np->kobj.kset = of_kset;
|
||||
if (!np->parent) {
|
||||
/* Nodes without parents are new top level trees */
|
||||
rc = kobject_add(&np->kobj, NULL, safe_name(&of_kset->kobj, "base"));
|
||||
} else {
|
||||
name = safe_name(&np->parent->kobj, kbasename(np->full_name));
|
||||
if (!name || !name[0])
|
||||
return -EINVAL;
|
||||
|
||||
rc = kobject_add(&np->kobj, &np->parent->kobj, "%s", name);
|
||||
}
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
for_each_property_of_node(np, pp)
|
||||
__of_add_property_sysfs(np, pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int of_node_add(struct device_node *np)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
BUG_ON(!of_node_is_initialized(np));
|
||||
|
||||
/*
|
||||
* Grab the mutex here so that in a race condition between of_init() and
|
||||
* of_node_add(), node addition will still be consistent.
|
||||
*/
|
||||
mutex_lock(&of_aliases_mutex);
|
||||
if (of_kset)
|
||||
rc = __of_node_add(np);
|
||||
else
|
||||
/* This scenario may be perfectly valid, but report it anyway */
|
||||
pr_info("of_node_add(%s) before of_init()\n", np->full_name);
|
||||
mutex_unlock(&of_aliases_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OF_DYNAMIC)
|
||||
static void of_node_remove(struct device_node *np)
|
||||
{
|
||||
struct property *pp;
|
||||
|
||||
BUG_ON(!of_node_is_initialized(np));
|
||||
|
||||
/* only remove properties if on sysfs */
|
||||
if (of_node_is_attached(np)) {
|
||||
for_each_property_of_node(np, pp)
|
||||
sysfs_remove_bin_file(&np->kobj, &pp->attr);
|
||||
kobject_del(&np->kobj);
|
||||
}
|
||||
|
||||
/* finally remove the kobj_init ref */
|
||||
of_node_put(np);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init of_init(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
||||
/* Create the kset, and register existing nodes */
|
||||
mutex_lock(&of_aliases_mutex);
|
||||
of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj);
|
||||
if (!of_kset) {
|
||||
mutex_unlock(&of_aliases_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
for_each_of_allnodes(np)
|
||||
__of_node_add(np);
|
||||
mutex_unlock(&of_aliases_mutex);
|
||||
|
||||
/* Symlink in /proc as required by userspace ABI */
|
||||
if (of_allnodes)
|
||||
proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base");
|
||||
|
||||
return 0;
|
||||
}
|
||||
core_initcall(of_init);
|
||||
|
||||
static struct property *__of_find_property(const struct device_node *np,
|
||||
const char *name, int *lenp)
|
||||
{
|
||||
|
@ -1531,6 +1680,10 @@ static int of_property_notify(int action, struct device_node *np,
|
|||
{
|
||||
struct of_prop_reconfig pr;
|
||||
|
||||
/* only call notifiers if the node is attached */
|
||||
if (!of_node_is_attached(np))
|
||||
return 0;
|
||||
|
||||
pr.dn = np;
|
||||
pr.prop = prop;
|
||||
return of_reconfig_notify(action, &pr);
|
||||
|
@ -1543,12 +1696,32 @@ static int of_property_notify(int action, struct device_node *np,
|
|||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* __of_add_property - Add a property to a node without lock operations
|
||||
*/
|
||||
static int __of_add_property(struct device_node *np, struct property *prop)
|
||||
{
|
||||
struct property **next;
|
||||
|
||||
prop->next = NULL;
|
||||
next = &np->properties;
|
||||
while (*next) {
|
||||
if (strcmp(prop->name, (*next)->name) == 0)
|
||||
/* duplicate ! don't insert it */
|
||||
return -EEXIST;
|
||||
|
||||
next = &(*next)->next;
|
||||
}
|
||||
*next = prop;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_add_property - Add a property to a node
|
||||
*/
|
||||
int of_add_property(struct device_node *np, struct property *prop)
|
||||
{
|
||||
struct property **next;
|
||||
unsigned long flags;
|
||||
int rc;
|
||||
|
||||
|
@ -1556,27 +1729,16 @@ int of_add_property(struct device_node *np, struct property *prop)
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
prop->next = NULL;
|
||||
raw_spin_lock_irqsave(&devtree_lock, flags);
|
||||
next = &np->properties;
|
||||
while (*next) {
|
||||
if (strcmp(prop->name, (*next)->name) == 0) {
|
||||
/* duplicate ! don't insert it */
|
||||
raw_spin_unlock_irqrestore(&devtree_lock, flags);
|
||||
return -1;
|
||||
}
|
||||
next = &(*next)->next;
|
||||
}
|
||||
*next = prop;
|
||||
rc = __of_add_property(np, prop);
|
||||
raw_spin_unlock_irqrestore(&devtree_lock, flags);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
#ifdef CONFIG_PROC_DEVICETREE
|
||||
/* try to add to proc as well if it was initialized */
|
||||
if (np->pde)
|
||||
proc_device_tree_add_prop(np->pde, prop);
|
||||
#endif /* CONFIG_PROC_DEVICETREE */
|
||||
if (of_node_is_attached(np))
|
||||
__of_add_property_sysfs(np, prop);
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1616,11 +1778,11 @@ int of_remove_property(struct device_node *np, struct property *prop)
|
|||
if (!found)
|
||||
return -ENODEV;
|
||||
|
||||
#ifdef CONFIG_PROC_DEVICETREE
|
||||
/* try to remove the proc node as well */
|
||||
if (np->pde)
|
||||
proc_device_tree_remove_prop(np->pde, prop);
|
||||
#endif /* CONFIG_PROC_DEVICETREE */
|
||||
/* at early boot, bail hear and defer setup to of_init() */
|
||||
if (!of_kset)
|
||||
return 0;
|
||||
|
||||
sysfs_remove_bin_file(&np->kobj, &prop->attr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1666,16 +1828,17 @@ int of_update_property(struct device_node *np, struct property *newprop)
|
|||
next = &(*next)->next;
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&devtree_lock, flags);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Update the sysfs attribute */
|
||||
if (oldprop)
|
||||
sysfs_remove_bin_file(&np->kobj, &oldprop->attr);
|
||||
__of_add_property_sysfs(np, newprop);
|
||||
|
||||
if (!found)
|
||||
return -ENODEV;
|
||||
|
||||
#ifdef CONFIG_PROC_DEVICETREE
|
||||
/* try to add to proc as well if it was initialized */
|
||||
if (np->pde)
|
||||
proc_device_tree_update_prop(np->pde, newprop, oldprop);
|
||||
#endif /* CONFIG_PROC_DEVICETREE */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1710,22 +1873,6 @@ int of_reconfig_notify(unsigned long action, void *p)
|
|||
return notifier_to_errno(rc);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_DEVICETREE
|
||||
static void of_add_proc_dt_entry(struct device_node *dn)
|
||||
{
|
||||
struct proc_dir_entry *ent;
|
||||
|
||||
ent = proc_mkdir(strrchr(dn->full_name, '/') + 1, dn->parent->pde);
|
||||
if (ent)
|
||||
proc_device_tree_add_node(dn, ent);
|
||||
}
|
||||
#else
|
||||
static void of_add_proc_dt_entry(struct device_node *dn)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* of_attach_node - Plug a device node into the tree and global list.
|
||||
*/
|
||||
|
@ -1743,24 +1890,13 @@ int of_attach_node(struct device_node *np)
|
|||
np->allnext = of_allnodes;
|
||||
np->parent->child = np;
|
||||
of_allnodes = np;
|
||||
of_node_clear_flag(np, OF_DETACHED);
|
||||
raw_spin_unlock_irqrestore(&devtree_lock, flags);
|
||||
|
||||
of_add_proc_dt_entry(np);
|
||||
of_node_add(np);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_DEVICETREE
|
||||
static void of_remove_proc_dt_entry(struct device_node *dn)
|
||||
{
|
||||
proc_remove(dn->pde);
|
||||
}
|
||||
#else
|
||||
static void of_remove_proc_dt_entry(struct device_node *dn)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* of_detach_node - "Unplug" a node from the device tree.
|
||||
*
|
||||
|
@ -1816,7 +1952,7 @@ int of_detach_node(struct device_node *np)
|
|||
of_node_set_flag(np, OF_DETACHED);
|
||||
raw_spin_unlock_irqrestore(&devtree_lock, flags);
|
||||
|
||||
of_remove_proc_dt_entry(np);
|
||||
of_node_remove(np);
|
||||
return rc;
|
||||
}
|
||||
#endif /* defined(CONFIG_OF_DYNAMIC) */
|
||||
|
@ -1852,9 +1988,9 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
|
|||
of_chosen = of_find_node_by_path("/chosen@0");
|
||||
|
||||
if (of_chosen) {
|
||||
const char *name;
|
||||
|
||||
name = of_get_property(of_chosen, "linux,stdout-path", NULL);
|
||||
const char *name = of_get_property(of_chosen, "stdout-path", NULL);
|
||||
if (!name)
|
||||
name = of_get_property(of_chosen, "linux,stdout-path", NULL);
|
||||
if (name)
|
||||
of_stdout = of_find_node_by_path(name);
|
||||
}
|
||||
|
|
145
drivers/of/fdt.c
145
drivers/of/fdt.c
|
@ -15,6 +15,8 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -202,6 +204,7 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
|
|||
__alignof__(struct device_node));
|
||||
if (allnextpp) {
|
||||
char *fn;
|
||||
of_node_init(np);
|
||||
np->full_name = fn = ((char *)np) + sizeof(*np);
|
||||
if (new_format) {
|
||||
/* rebuild full path for new format */
|
||||
|
@ -232,7 +235,6 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
|
|||
dad->next->sibling = np;
|
||||
dad->next = np;
|
||||
}
|
||||
kref_init(&np->kref);
|
||||
}
|
||||
/* process properties */
|
||||
while (1) {
|
||||
|
@ -439,6 +441,129 @@ struct boot_param_header *initial_boot_params;
|
|||
|
||||
#ifdef CONFIG_OF_EARLY_FLATTREE
|
||||
|
||||
/**
|
||||
* res_mem_reserve_reg() - reserve all memory described in 'reg' property
|
||||
*/
|
||||
static int __init __reserved_mem_reserve_reg(unsigned long node,
|
||||
const char *uname)
|
||||
{
|
||||
int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
|
||||
phys_addr_t base, size;
|
||||
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.
|
||||
* @it: callback function
|
||||
|
@ -856,6 +981,16 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 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
|
||||
* 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)
|
|||
{
|
||||
return __va(memblock_alloc(size, align));
|
||||
}
|
||||
#else
|
||||
int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
|
||||
phys_addr_t size, bool nomap)
|
||||
{
|
||||
pr_err("Reserved memory not supported, ignoring range 0x%llx - 0x%llx%s\n",
|
||||
base, size, nomap ? " (nomap)" : "");
|
||||
return -ENOSYS;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool __init early_init_dt_scan(void *params)
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
|
||||
/**
|
||||
* It maps 'enum phy_interface_t' found in include/linux/phy.h
|
||||
* into the device tree binding of 'phy-mode', so that Ethernet
|
||||
* device driver can get phy interface from device tree.
|
||||
* into the device tree binding of 'phy-mode' or 'phy-connection-type',
|
||||
* so that Ethernet device driver can get phy interface from device tree.
|
||||
*/
|
||||
static const char *phy_modes[] = {
|
||||
[PHY_INTERFACE_MODE_NA] = "",
|
||||
|
@ -37,8 +37,9 @@ static const char *phy_modes[] = {
|
|||
* of_get_phy_mode - Get phy mode for given device_node
|
||||
* @np: Pointer to the given device_node
|
||||
*
|
||||
* The function gets phy interface string from property 'phy-mode',
|
||||
* and return its index in phy_modes table, or errno in error case.
|
||||
* The function gets phy interface string from property 'phy-mode' or
|
||||
* '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)
|
||||
{
|
||||
|
@ -46,6 +47,8 @@ int of_get_phy_mode(struct device_node *np)
|
|||
int err, i;
|
||||
|
||||
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)
|
||||
return err;
|
||||
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* Device tree based initialization code for reserved memory.
|
||||
*
|
||||
* Copyright (c) 2013, The Linux Foundation. All Rights Reserved.
|
||||
* Copyright (c) 2013,2014 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
* Author: Marek Szyprowski <m.szyprowski@samsung.com>
|
||||
* Author: Josh Cartwright <joshc@codeaurora.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License or (at your optional) any later version of the license.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
|
||||
#define MAX_RESERVED_REGIONS 16
|
||||
static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
|
||||
static int reserved_mem_count;
|
||||
|
||||
#if defined(CONFIG_HAVE_MEMBLOCK)
|
||||
#include <linux/memblock.h>
|
||||
int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
|
||||
phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
|
||||
phys_addr_t *res_base)
|
||||
{
|
||||
/*
|
||||
* We use __memblock_alloc_base() because memblock_alloc_base()
|
||||
* panic()s on allocation failure.
|
||||
*/
|
||||
phys_addr_t base = __memblock_alloc_base(size, align, end);
|
||||
if (!base)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Check if the allocated region fits in to start..end window
|
||||
*/
|
||||
if (base < start) {
|
||||
memblock_free(base, size);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*res_base = base;
|
||||
if (nomap)
|
||||
return memblock_remove(base, size);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
|
||||
phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
|
||||
phys_addr_t *res_base)
|
||||
{
|
||||
pr_err("Reserved memory not supported, ignoring region 0x%llx%s\n",
|
||||
size, nomap ? " (nomap)" : "");
|
||||
return -ENOSYS;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* res_mem_save_node() - save fdt node for second pass initialization
|
||||
*/
|
||||
void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname,
|
||||
phys_addr_t base, phys_addr_t size)
|
||||
{
|
||||
struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
|
||||
|
||||
if (reserved_mem_count == ARRAY_SIZE(reserved_mem)) {
|
||||
pr_err("Reserved memory: not enough space all defined regions.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
rmem->fdt_node = node;
|
||||
rmem->name = uname;
|
||||
rmem->base = base;
|
||||
rmem->size = size;
|
||||
|
||||
reserved_mem_count++;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* res_mem_alloc_size() - allocate reserved memory described by 'size', 'align'
|
||||
* and 'alloc-ranges' properties
|
||||
*/
|
||||
static int __init __reserved_mem_alloc_size(unsigned long node,
|
||||
const char *uname, phys_addr_t *res_base, phys_addr_t *res_size)
|
||||
{
|
||||
int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
|
||||
phys_addr_t start = 0, end = 0;
|
||||
phys_addr_t base = 0, align = 0, size;
|
||||
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,
|
|||
return NULL;
|
||||
|
||||
dp = prom_early_alloc(sizeof(*dp));
|
||||
of_node_init(dp);
|
||||
of_pdt_incr_unique_id(dp);
|
||||
dp->parent = parent;
|
||||
|
||||
kref_init(&dp->kref);
|
||||
|
||||
dp->name = of_pdt_get_one_property(node, "name");
|
||||
dp->type = of_pdt_get_one_property(node, "device_type");
|
||||
dp->phandle = node;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
@ -378,6 +439,7 @@ static int __init of_selftest(void)
|
|||
of_node_put(np);
|
||||
|
||||
pr_info("start of selftest - you will see error messages\n");
|
||||
of_selftest_dynamic();
|
||||
of_selftest_parse_phandle_with_args();
|
||||
of_selftest_property_match_string();
|
||||
of_selftest_parse_interrupts();
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
|
||||
/ {
|
||||
testcase-data {
|
||||
security-password = "password";
|
||||
duplicate-name = "duplicate";
|
||||
duplicate-name { };
|
||||
phandle-tests {
|
||||
provider0: provider0 {
|
||||
#phandle-cells = <0>;
|
||||
|
|
|
@ -27,6 +27,5 @@ proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o
|
|||
proc-$(CONFIG_NET) += proc_net.o
|
||||
proc-$(CONFIG_PROC_KCORE) += kcore.o
|
||||
proc-$(CONFIG_PROC_VMCORE) += vmcore.o
|
||||
proc-$(CONFIG_PROC_DEVICETREE) += proc_devtree.o
|
||||
proc-$(CONFIG_PRINTK) += kmsg.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
|
|||
extern int proc_fill_super(struct super_block *);
|
||||
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
|
||||
*/
|
||||
|
|
|
@ -1,241 +0,0 @@
|
|||
/*
|
||||
* 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)
|
|||
proc_mkdir("openprom", NULL);
|
||||
#endif
|
||||
proc_tty_init();
|
||||
#ifdef CONFIG_PROC_DEVICETREE
|
||||
proc_device_tree_init();
|
||||
#endif
|
||||
proc_mkdir("bus", NULL);
|
||||
proc_sys_init();
|
||||
}
|
||||
|
|
|
@ -167,6 +167,16 @@
|
|||
#define CLK_OF_TABLES()
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF_RESERVED_MEM
|
||||
#define RESERVEDMEM_OF_TABLES() \
|
||||
. = ALIGN(8); \
|
||||
VMLINUX_SYMBOL(__reservedmem_of_table) = .; \
|
||||
*(__reservedmem_of_table) \
|
||||
*(__reservedmem_of_table_end)
|
||||
#else
|
||||
#define RESERVEDMEM_OF_TABLES()
|
||||
#endif
|
||||
|
||||
#define KERNEL_DTB() \
|
||||
STRUCT_ALIGN(); \
|
||||
VMLINUX_SYMBOL(__dtb_start) = .; \
|
||||
|
@ -490,6 +500,7 @@
|
|||
TRACE_SYSCALLS() \
|
||||
MEM_DISCARD(init.rodata) \
|
||||
CLK_OF_TABLES() \
|
||||
RESERVEDMEM_OF_TABLES() \
|
||||
CLKSRC_OF_TABLES() \
|
||||
KERNEL_DTB() \
|
||||
IRQCHIP_OF_MATCH_TABLE()
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/topology.h>
|
||||
|
@ -37,6 +37,7 @@ struct property {
|
|||
struct property *next;
|
||||
unsigned long _flags;
|
||||
unsigned int unique_id;
|
||||
struct bin_attribute attr;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SPARC)
|
||||
|
@ -56,8 +57,7 @@ struct device_node {
|
|||
struct device_node *sibling;
|
||||
struct device_node *next; /* next device of same type */
|
||||
struct device_node *allnext; /* next in list of all nodes */
|
||||
struct proc_dir_entry *pde; /* this node's proc directory */
|
||||
struct kref kref;
|
||||
struct kobject kobj;
|
||||
unsigned long _flags;
|
||||
void *data;
|
||||
#if defined(CONFIG_SPARC)
|
||||
|
@ -67,13 +67,34 @@ struct device_node {
|
|||
#endif
|
||||
};
|
||||
|
||||
#define MAX_PHANDLE_ARGS 8
|
||||
#define MAX_PHANDLE_ARGS 16
|
||||
struct of_phandle_args {
|
||||
struct device_node *np;
|
||||
int args_count;
|
||||
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
|
||||
extern struct device_node *of_node_get(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)
|
|||
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);
|
||||
|
||||
/*
|
||||
|
@ -167,6 +208,8 @@ static inline const char *of_node_full_name(const struct device_node *np)
|
|||
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,
|
||||
const char *name);
|
||||
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)
|
|||
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 */
|
||||
|
|
|
@ -98,7 +98,10 @@ extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
|
|||
int depth, void *data);
|
||||
extern int early_init_dt_scan_memory(unsigned long node, const char *uname,
|
||||
int depth, void *data);
|
||||
extern void early_init_fdt_scan_reserved_mem(void);
|
||||
extern void early_init_dt_add_memory_arch(u64 base, u64 size);
|
||||
extern int early_init_dt_reserve_memory_arch(phys_addr_t base, phys_addr_t size,
|
||||
bool no_map);
|
||||
extern void * early_init_dt_alloc_memory_arch(u64 size, u64 align);
|
||||
extern u64 dt_mem_next_cell(int s, __be32 **cellp);
|
||||
|
||||
|
@ -118,6 +121,7 @@ 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 *);
|
||||
#else /* CONFIG_OF_FLATTREE */
|
||||
static inline void early_init_fdt_scan_reserved_mem(void) {}
|
||||
static inline const char *of_flat_dt_get_machine_name(void) { return NULL; }
|
||||
static inline void unflatten_device_tree(void) {}
|
||||
static inline void unflatten_and_copy_device_tree(void) {}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
#ifndef __OF_RESERVED_MEM_H
|
||||
#define __OF_RESERVED_MEM_H
|
||||
|
||||
struct device;
|
||||
struct of_phandle_args;
|
||||
struct reserved_mem_ops;
|
||||
|
||||
struct reserved_mem {
|
||||
const char *name;
|
||||
unsigned long fdt_node;
|
||||
const struct reserved_mem_ops *ops;
|
||||
phys_addr_t base;
|
||||
phys_addr_t size;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
struct reserved_mem_ops {
|
||||
void (*device_init)(struct reserved_mem *rmem,
|
||||
struct device *dev);
|
||||
void (*device_release)(struct reserved_mem *rmem,
|
||||
struct device *dev);
|
||||
};
|
||||
|
||||
typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem,
|
||||
unsigned long node, const char *uname);
|
||||
|
||||
#ifdef CONFIG_OF_RESERVED_MEM
|
||||
void fdt_init_reserved_mem(void);
|
||||
void fdt_reserved_mem_save_node(unsigned long node, const char *uname,
|
||||
phys_addr_t base, phys_addr_t size);
|
||||
|
||||
#define RESERVEDMEM_OF_DECLARE(name, compat, init) \
|
||||
static const struct of_device_id __reservedmem_of_table_##name \
|
||||
__used __section(__reservedmem_of_table) \
|
||||
= { .compatible = compat, \
|
||||
.data = (init == (reservedmem_of_init_fn)NULL) ? \
|
||||
init : init }
|
||||
|
||||
#else
|
||||
static inline void fdt_init_reserved_mem(void) { }
|
||||
static inline void fdt_reserved_mem_save_node(unsigned long node,
|
||||
const char *uname, phys_addr_t base, phys_addr_t size) { }
|
||||
|
||||
#define RESERVEDMEM_OF_DECLARE(name, compat, init) \
|
||||
static const struct of_device_id __reservedmem_of_table_##name \
|
||||
__attribute__((unused)) \
|
||||
= { .compatible = compat, \
|
||||
.data = (init == (reservedmem_of_init_fn)NULL) ? \
|
||||
init : init }
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __OF_RESERVED_MEM_H */
|
|
@ -274,6 +274,18 @@ $(obj)/%.dtb: $(src)/%.dts FORCE
|
|||
|
||||
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
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,8 +1,8 @@
|
|||
/* 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
|
||||
|
||||
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
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -30,6 +30,15 @@
|
|||
This special exception was added by the Free Software Foundation in
|
||||
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. */
|
||||
#ifndef YYTOKENTYPE
|
||||
|
@ -63,12 +72,10 @@
|
|||
#endif
|
||||
|
||||
|
||||
|
||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||
typedef union YYSTYPE
|
||||
{
|
||||
|
||||
/* Line 2068 of yacc.c */
|
||||
/* Line 2053 of yacc.c */
|
||||
#line 40 "dtc-parser.y"
|
||||
|
||||
char *propnodename;
|
||||
|
@ -91,9 +98,8 @@ typedef union YYSTYPE
|
|||
uint64_t integer;
|
||||
|
||||
|
||||
|
||||
/* Line 2068 of yacc.c */
|
||||
#line 97 "dtc-parser.tab.h"
|
||||
/* Line 2053 of yacc.c */
|
||||
#line 103 "dtc-parser.tab.h"
|
||||
} YYSTYPE;
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
||||
|
@ -102,4 +108,18 @@ typedef union YYSTYPE
|
|||
|
||||
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 @@
|
|||
#include "dtc.h"
|
||||
#include "srcpos.h"
|
||||
|
||||
#include "version_gen.h"
|
||||
|
||||
/*
|
||||
* Command line options
|
||||
*/
|
||||
|
@ -49,55 +47,60 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
|
|||
fill_fullpaths(child, tree->fullpath);
|
||||
}
|
||||
|
||||
static void __attribute__ ((noreturn)) usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage:\n");
|
||||
fprintf(stderr, "\tdtc [options] <input file>\n");
|
||||
fprintf(stderr, "\nOptions:\n");
|
||||
fprintf(stderr, "\t-h\n");
|
||||
fprintf(stderr, "\t\tThis help text\n");
|
||||
fprintf(stderr, "\t-q\n");
|
||||
fprintf(stderr, "\t\tQuiet: -q suppress warnings, -qq errors, -qqq all\n");
|
||||
fprintf(stderr, "\t-I <input format>\n");
|
||||
fprintf(stderr, "\t\tInput formats are:\n");
|
||||
fprintf(stderr, "\t\t\tdts - device tree source text\n");
|
||||
fprintf(stderr, "\t\t\tdtb - device tree blob\n");
|
||||
fprintf(stderr, "\t\t\tfs - /proc/device-tree style directory\n");
|
||||
fprintf(stderr, "\t-o <output file>\n");
|
||||
fprintf(stderr, "\t-O <output format>\n");
|
||||
fprintf(stderr, "\t\tOutput formats are:\n");
|
||||
fprintf(stderr, "\t\t\tdts - device tree source text\n");
|
||||
fprintf(stderr, "\t\t\tdtb - device tree blob\n");
|
||||
fprintf(stderr, "\t\t\tasm - assembler source\n");
|
||||
fprintf(stderr, "\t-V <output version>\n");
|
||||
fprintf(stderr, "\t\tBlob version to produce, defaults to %d (relevant for dtb\n\t\tand asm output only)\n", DEFAULT_FDT_VERSION);
|
||||
fprintf(stderr, "\t-d <output dependency file>\n");
|
||||
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");
|
||||
fprintf(stderr, "\t-S <bytes>\n");
|
||||
fprintf(stderr, "\t\tMake the blob at least <bytes> long (extra space)\n");
|
||||
fprintf(stderr, "\t-p <bytes>\n");
|
||||
fprintf(stderr, "\t\tAdd padding to the blob of <bytes> long (extra space)\n");
|
||||
fprintf(stderr, "\t-b <number>\n");
|
||||
fprintf(stderr, "\t\tSet the physical boot cpu\n");
|
||||
fprintf(stderr, "\t-f\n");
|
||||
fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n");
|
||||
fprintf(stderr, "\t-i\n");
|
||||
fprintf(stderr, "\t\tAdd a path to search for include files\n");
|
||||
fprintf(stderr, "\t-s\n");
|
||||
fprintf(stderr, "\t\tSort nodes and properties before outputting (only useful for\n\t\tcomparing trees)\n");
|
||||
fprintf(stderr, "\t-v\n");
|
||||
fprintf(stderr, "\t\tPrint DTC version and exit\n");
|
||||
fprintf(stderr, "\t-H <phandle format>\n");
|
||||
fprintf(stderr, "\t\tphandle formats are:\n");
|
||||
fprintf(stderr, "\t\t\tlegacy - \"linux,phandle\" properties only\n");
|
||||
fprintf(stderr, "\t\t\tepapr - \"phandle\" properties only\n");
|
||||
fprintf(stderr, "\t\t\tboth - Both \"linux,phandle\" and \"phandle\" properties\n");
|
||||
fprintf(stderr, "\t-W [no-]<checkname>\n");
|
||||
fprintf(stderr, "\t-E [no-]<checkname>\n");
|
||||
fprintf(stderr, "\t\t\tenable or disable warnings and errors\n");
|
||||
exit(3);
|
||||
}
|
||||
/* Usage related data. */
|
||||
static const char usage_synopsis[] = "dtc [options] <input file>";
|
||||
static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv";
|
||||
static struct option const usage_long_opts[] = {
|
||||
{"quiet", no_argument, NULL, 'q'},
|
||||
{"in-format", a_argument, NULL, 'I'},
|
||||
{"out", a_argument, NULL, 'o'},
|
||||
{"out-format", a_argument, NULL, 'O'},
|
||||
{"out-version", a_argument, NULL, 'V'},
|
||||
{"out-dependency", a_argument, NULL, 'd'},
|
||||
{"reserve", a_argument, NULL, 'R'},
|
||||
{"space", a_argument, NULL, 'S'},
|
||||
{"pad", a_argument, NULL, 'p'},
|
||||
{"boot-cpu", a_argument, NULL, 'b'},
|
||||
{"force", no_argument, NULL, 'f'},
|
||||
{"include", a_argument, NULL, 'i'},
|
||||
{"sort", no_argument, NULL, 's'},
|
||||
{"phandle", a_argument, NULL, 'H'},
|
||||
{"warning", a_argument, NULL, 'W'},
|
||||
{"error", a_argument, NULL, 'E'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"version", no_argument, NULL, 'v'},
|
||||
{NULL, no_argument, NULL, 0x0},
|
||||
};
|
||||
static const char * const usage_opts_help[] = {
|
||||
"\n\tQuiet: -q suppress warnings, -qq errors, -qqq all",
|
||||
"\n\tInput formats are:\n"
|
||||
"\t\tdts - device tree source text\n"
|
||||
"\t\tdtb - device tree blob\n"
|
||||
"\t\tfs - /proc/device-tree style directory",
|
||||
"\n\tOutput file",
|
||||
"\n\tOutput formats are:\n"
|
||||
"\t\tdts - device tree source text\n"
|
||||
"\t\tdtb - device tree blob\n"
|
||||
"\t\tasm - assembler source",
|
||||
"\n\tBlob version to produce, defaults to %d (for dtb and asm output)", //, DEFAULT_FDT_VERSION);
|
||||
"\n\tOutput dependency file",
|
||||
"\n\ttMake space for <number> reserve map entries (for dtb and asm output)",
|
||||
"\n\tMake the blob at least <bytes> long (extra space)",
|
||||
"\n\tAdd padding to the blob of <bytes> long (extra space)",
|
||||
"\n\tSet the physical boot cpu",
|
||||
"\n\tTry to produce output even if the input tree has errors",
|
||||
"\n\tAdd a path to search for include files",
|
||||
"\n\tSort nodes and properties before outputting (useful for comparing trees)",
|
||||
"\n\tValid phandle formats are:\n"
|
||||
"\t\tlegacy - \"linux,phandle\" properties only\n"
|
||||
"\t\tepapr - \"phandle\" properties only\n"
|
||||
"\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[])
|
||||
{
|
||||
|
@ -118,8 +121,7 @@ int main(int argc, char *argv[])
|
|||
minsize = 0;
|
||||
padsize = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fqb:i:vH:sW:E:"))
|
||||
!= EOF) {
|
||||
while ((opt = util_getopt_long()) != EOF) {
|
||||
switch (opt) {
|
||||
case 'I':
|
||||
inform = optarg;
|
||||
|
@ -158,8 +160,7 @@ int main(int argc, char *argv[])
|
|||
srcfile_add_search_path(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
printf("Version: %s\n", DTC_VERSION);
|
||||
exit(0);
|
||||
util_version();
|
||||
case 'H':
|
||||
if (streq(optarg, "legacy"))
|
||||
phandle_format = PHANDLE_LEGACY;
|
||||
|
@ -185,13 +186,14 @@ int main(int argc, char *argv[])
|
|||
break;
|
||||
|
||||
case 'h':
|
||||
usage(NULL);
|
||||
default:
|
||||
usage();
|
||||
usage("unknown option");
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > (optind+1))
|
||||
usage();
|
||||
usage("missing files");
|
||||
else if (argc < (optind+1))
|
||||
arg = "-";
|
||||
else
|
||||
|
@ -201,9 +203,6 @@ int main(int argc, char *argv[])
|
|||
if (minsize && padsize)
|
||||
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) {
|
||||
depfile = fopen(depname, "w");
|
||||
if (!depfile)
|
||||
|
|
|
@ -66,7 +66,6 @@ typedef uint32_t cell_t;
|
|||
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
|
||||
|
||||
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
/* Data blobs */
|
||||
enum markertype {
|
||||
|
|
|
@ -297,9 +297,9 @@ srcpos_verror(struct srcpos *pos, char const *fmt, va_list va)
|
|||
|
||||
srcstr = srcpos_string(pos);
|
||||
|
||||
fprintf(stdout, "Error: %s ", srcstr);
|
||||
vfprintf(stdout, fmt, va);
|
||||
fprintf(stdout, "\n");
|
||||
fprintf(stderr, "Error: %s ", srcstr);
|
||||
vfprintf(stderr, fmt, va);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
#!/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 @@
|
|||
|
||||
#include "libfdt.h"
|
||||
#include "util.h"
|
||||
#include "version_gen.h"
|
||||
|
||||
char *xstrdup(const char *s)
|
||||
{
|
||||
|
@ -72,7 +73,7 @@ char *join_path(const char *path, const char *name)
|
|||
int util_is_printable_string(const void *data, int len)
|
||||
{
|
||||
const char *s = data;
|
||||
const char *ss;
|
||||
const char *ss, *se;
|
||||
|
||||
/* zero length is not */
|
||||
if (len == 0)
|
||||
|
@ -82,13 +83,19 @@ int util_is_printable_string(const void *data, int len)
|
|||
if (s[len - 1] != '\0')
|
||||
return 0;
|
||||
|
||||
ss = s;
|
||||
while (*s && isprint(*s))
|
||||
s++;
|
||||
se = s + len;
|
||||
|
||||
/* not zero, or not done yet */
|
||||
if (*s != '\0' || (s + 1 - ss) < len)
|
||||
return 0;
|
||||
while (s < se) {
|
||||
ss = s;
|
||||
while (s < se && *s && isprint(*s))
|
||||
s++;
|
||||
|
||||
/* not zero, or not done yet */
|
||||
if (*s != '\0' || s == ss)
|
||||
return 0;
|
||||
|
||||
s++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -191,7 +198,7 @@ char get_escape_char(const char *s, int *i)
|
|||
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 */
|
||||
char *buf = NULL;
|
||||
|
@ -206,12 +213,12 @@ int utilfdt_read_err(const char *filename, char **buffp)
|
|||
}
|
||||
|
||||
/* Loop until we have read everything */
|
||||
buf = malloc(bufsize);
|
||||
buf = xmalloc(bufsize);
|
||||
do {
|
||||
/* Expand the buffer to hold the next chunk */
|
||||
if (offset == bufsize) {
|
||||
bufsize *= 2;
|
||||
buf = realloc(buf, bufsize);
|
||||
buf = xrealloc(buf, bufsize);
|
||||
if (!buf) {
|
||||
ret = ENOMEM;
|
||||
break;
|
||||
|
@ -232,13 +239,20 @@ int utilfdt_read_err(const char *filename, char **buffp)
|
|||
free(buf);
|
||||
else
|
||||
*buffp = buf;
|
||||
*len = bufsize;
|
||||
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;
|
||||
int ret = utilfdt_read_err(filename, &buff);
|
||||
int ret = utilfdt_read_err_len(filename, &buff, len);
|
||||
|
||||
if (ret) {
|
||||
fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
|
||||
|
@ -249,6 +263,12 @@ char *utilfdt_read(const char *filename)
|
|||
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 fd = 1; /* assume stdout */
|
||||
|
@ -329,3 +349,100 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size)
|
|||
return -1;
|
||||
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 @@
|
|||
#define _UTIL_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <getopt.h>
|
||||
|
||||
/*
|
||||
* Copyright 2011 The Chromium Authors, All Rights Reserved.
|
||||
|
@ -23,7 +24,9 @@
|
|||
* 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;
|
||||
|
||||
|
@ -57,12 +60,14 @@ extern char *xstrdup(const char *s);
|
|||
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
|
||||
* has a valid terminator.
|
||||
* Check a property of a given length to see if it is all printable and
|
||||
* 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 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);
|
||||
|
||||
/*
|
||||
|
@ -82,6 +87,13 @@ char get_escape_char(const char *s, int *i);
|
|||
*/
|
||||
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
|
||||
* returns them. The value returned can be passed to strerror() to obtain
|
||||
|
@ -93,6 +105,12 @@ char *utilfdt_read(const char *filename);
|
|||
*/
|
||||
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
|
||||
|
@ -148,6 +166,85 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size);
|
|||
#define USAGE_TYPE_MSG \
|
||||
"<type>\ts=string, i=int, u=unsigned, x=hex\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 */
|
||||
|
|
|
@ -1 +1 @@
|
|||
#define DTC_VERSION "DTC 1.2.0-g37c0b6a0"
|
||||
#define DTC_VERSION "DTC 1.4.0-dirty"
|
||||
|
|
Загрузка…
Ссылка в новой задаче