From owner-svn-src-vendor@freebsd.org Fri Jan 12 21:44:55 2018 Return-Path: Delivered-To: svn-src-vendor@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 22181E7E046; Fri, 12 Jan 2018 21:44:55 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id CA499818AD; Fri, 12 Jan 2018 21:44:54 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 05A7A15E0; Fri, 12 Jan 2018 21:44:54 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w0CLirC2057294; Fri, 12 Jan 2018 21:44:53 GMT (envelope-from kevans@FreeBSD.org) Received: (from kevans@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w0CLirYd057288; Fri, 12 Jan 2018 21:44:53 GMT (envelope-from kevans@FreeBSD.org) Message-Id: <201801122144.w0CLirYd057288@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kevans set sender to kevans@FreeBSD.org using -f From: Kyle Evans Date: Fri, 12 Jan 2018 21:44:53 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-vendor@freebsd.org Subject: svn commit: r327893 - in vendor/dtc/dist: . Documentation libfdt pylibfdt tests X-SVN-Group: vendor X-SVN-Commit-Author: kevans X-SVN-Commit-Paths: in vendor/dtc/dist: . Documentation libfdt pylibfdt tests X-SVN-Commit-Revision: 327893 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-vendor@freebsd.org X-Mailman-Version: 2.1.25 Precedence: list List-Id: SVN commit messages for the vendor work area tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 12 Jan 2018 21:44:55 -0000 Author: kevans Date: Fri Jan 12 21:44:53 2018 New Revision: 327893 URL: https://svnweb.freebsd.org/changeset/base/327893 Log: Import dtc 1.4.6 Added: vendor/dtc/dist/fdtoverlay.c (contents, props changed) vendor/dtc/dist/pylibfdt/ vendor/dtc/dist/pylibfdt/Makefile.pylibfdt (contents, props changed) vendor/dtc/dist/pylibfdt/libfdt.i vendor/dtc/dist/pylibfdt/setup.py (contents, props changed) vendor/dtc/dist/tests/bad-chosen.dts (contents, props changed) vendor/dtc/dist/tests/bad-gpio.dts (contents, props changed) vendor/dtc/dist/tests/bad-interrupt-cells.dts (contents, props changed) vendor/dtc/dist/tests/bad-phandle-cells.dts (contents, props changed) vendor/dtc/dist/tests/fdtoverlay-runtest.sh (contents, props changed) vendor/dtc/dist/tests/pci-bridge-bad1.dts (contents, props changed) vendor/dtc/dist/tests/pci-bridge-bad2.dts (contents, props changed) vendor/dtc/dist/tests/pci-bridge-ok.dts (contents, props changed) vendor/dtc/dist/tests/pylibfdt_tests.py (contents, props changed) vendor/dtc/dist/tests/stacked_overlay_bar.dts (contents, props changed) vendor/dtc/dist/tests/stacked_overlay_base.dts (contents, props changed) vendor/dtc/dist/tests/stacked_overlay_baz.dts (contents, props changed) vendor/dtc/dist/tests/unit-addr-leading-0s.dts (contents, props changed) vendor/dtc/dist/tests/unit-addr-leading-0x.dts (contents, props changed) Modified: vendor/dtc/dist/Documentation/manual.txt vendor/dtc/dist/Makefile vendor/dtc/dist/Makefile.utils vendor/dtc/dist/README vendor/dtc/dist/checks.c vendor/dtc/dist/convert-dtsv0-lexer.l vendor/dtc/dist/data.c vendor/dtc/dist/dtc-lexer.l vendor/dtc/dist/dtc-parser.y vendor/dtc/dist/dtc.c vendor/dtc/dist/dtc.h vendor/dtc/dist/fdtdump.c vendor/dtc/dist/fdtget.c vendor/dtc/dist/fdtput.c vendor/dtc/dist/flattree.c vendor/dtc/dist/libfdt/fdt.c vendor/dtc/dist/libfdt/fdt.h vendor/dtc/dist/libfdt/fdt_empty_tree.c vendor/dtc/dist/libfdt/fdt_overlay.c vendor/dtc/dist/libfdt/fdt_ro.c vendor/dtc/dist/libfdt/fdt_rw.c vendor/dtc/dist/libfdt/fdt_sw.c vendor/dtc/dist/libfdt/fdt_wip.c vendor/dtc/dist/libfdt/libfdt.h vendor/dtc/dist/libfdt/libfdt_env.h vendor/dtc/dist/libfdt/libfdt_internal.h vendor/dtc/dist/libfdt/version.lds vendor/dtc/dist/livetree.c vendor/dtc/dist/srcpos.h vendor/dtc/dist/tests/Makefile.tests vendor/dtc/dist/tests/bad-string-props.dts vendor/dtc/dist/tests/char_literal.c vendor/dtc/dist/tests/dtbs_equal_ordered.c vendor/dtc/dist/tests/dtbs_equal_unordered.c vendor/dtc/dist/tests/dumptrees.c vendor/dtc/dist/tests/include7.dts vendor/dtc/dist/tests/integer-expressions.c vendor/dtc/dist/tests/node_check_compatible.c vendor/dtc/dist/tests/node_offset_by_prop_value.c vendor/dtc/dist/tests/nopulate.c vendor/dtc/dist/tests/path-references.c vendor/dtc/dist/tests/path-references.dts vendor/dtc/dist/tests/property_iterate.c vendor/dtc/dist/tests/references.c vendor/dtc/dist/tests/run_tests.sh vendor/dtc/dist/tests/sized_cells.c vendor/dtc/dist/tests/stringlist.c vendor/dtc/dist/tests/subnode_iterate.c vendor/dtc/dist/tests/sw_tree1.c vendor/dtc/dist/tests/test_tree1.dts vendor/dtc/dist/tests/test_tree1_label_noderef.dts vendor/dtc/dist/tests/testdata.h vendor/dtc/dist/tests/tests.h vendor/dtc/dist/tests/tests.sh vendor/dtc/dist/tests/trees.S vendor/dtc/dist/tests/truncated_property.c vendor/dtc/dist/tests/value-labels.c vendor/dtc/dist/treesource.c vendor/dtc/dist/util.c vendor/dtc/dist/util.h Modified: vendor/dtc/dist/Documentation/manual.txt ============================================================================== --- vendor/dtc/dist/Documentation/manual.txt Fri Jan 12 20:40:27 2018 (r327892) +++ vendor/dtc/dist/Documentation/manual.txt Fri Jan 12 21:44:53 2018 (r327893) @@ -674,4 +674,22 @@ The fdtdump program prints a readable version of a fla The syntax of the fdtdump command line is: - fdtdump + fdtdump [options] + +Where options are: + -d,--debug Dump debug information while decoding the file + -s,--scan Scan for an embedded fdt in given file + +3) fdtoverlay -- Flat Device Tree overlay applicator + +The fdtoverlay applies an arbitrary number of FDT overlays to a base FDT blob +to a given output file. + +The syntax of the fdtoverlay command line is: + + fdtoverlay -i -o [ ...] + +Where options are: + -i, --input Input base DT blob + -o, --output Output DT blob + -v, --verbose Verbose message output Modified: vendor/dtc/dist/Makefile ============================================================================== --- vendor/dtc/dist/Makefile Fri Jan 12 20:40:27 2018 (r327892) +++ vendor/dtc/dist/Makefile Fri Jan 12 21:44:53 2018 (r327893) @@ -10,7 +10,7 @@ # VERSION = 1 PATCHLEVEL = 4 -SUBLEVEL = 3 +SUBLEVEL = 6 EXTRAVERSION = LOCAL_VERSION = CONFIG_LOCALVERSION = @@ -18,10 +18,12 @@ CONFIG_LOCALVERSION = CPPFLAGS = -I libfdt -I . WARNINGS = -Wall -Wpointer-arith -Wcast-qual -Wnested-externs \ -Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls -Wshadow -CFLAGS = -g -Os -fPIC -Werror $(WARNINGS) +CFLAGS = -g -Os $(SHAREDLIB_CFLAGS) -Werror $(WARNINGS) BISON = bison LEX = flex +SWIG = swig +PKG_CONFIG ?= pkg-config INSTALL = /usr/bin/install DESTDIR = @@ -31,14 +33,20 @@ LIBDIR = $(PREFIX)/lib INCLUDEDIR = $(PREFIX)/include HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \ - sed -e 's/\(cygwin\).*/cygwin/') + sed -e 's/\(cygwin\|msys\).*/\1/') ifeq ($(HOSTOS),darwin) -SHAREDLIB_EXT=dylib -SHAREDLIB_LINK_OPTIONS=-dynamiclib -Wl,-install_name -Wl, +SHAREDLIB_EXT = dylib +SHAREDLIB_CFLAGS = -fPIC +SHAREDLIB_LDFLAGS = -fPIC -dynamiclib -Wl,-install_name -Wl, +else ifeq ($(HOSTOS),$(filter $(HOSTOS),msys cygwin)) +SHAREDLIB_EXT = so +SHAREDLIB_CFLAGS = +SHAREDLIB_LDFLAGS = -shared -Wl,--version-script=$(LIBFDT_version) -Wl,-soname, else -SHAREDLIB_EXT=so -SHAREDLIB_LINK_OPTIONS=-shared -Wl,--version-script=$(LIBFDT_version) -Wl,-soname, +SHAREDLIB_EXT = so +SHAREDLIB_CFLAGS = -fPIC +SHAREDLIB_LDFLAGS = -fPIC -shared -Wl,--version-script=$(LIBFDT_version) -Wl,-soname, endif # @@ -112,18 +120,38 @@ BIN += dtc BIN += fdtdump BIN += fdtget BIN += fdtput +BIN += fdtoverlay SCRIPTS = dtdiff all: $(BIN) libfdt +# We need both Python and swig to build pylibfdt. +.PHONY: maybe_pylibfdt +maybe_pylibfdt: FORCE + if $(PKG_CONFIG) --cflags python2 >/dev/null 2>&1; then \ + if which swig >/dev/null 2>&1; then \ + can_build=yes; \ + fi; \ + fi; \ + if [ "$$can_build" = "yes" ]; then \ + $(MAKE) pylibfdt; \ + else \ + echo "## Skipping pylibfdt (install python dev and swig to build)"; \ + fi +ifeq ($(NO_PYTHON),) +all: maybe_pylibfdt +endif + + ifneq ($(DEPTARGETS),) -include $(DTC_OBJS:%.o=%.d) -include $(CONVERT_OBJS:%.o=%.d) -include $(FDTDUMP_OBJS:%.o=%.d) -include $(FDTGET_OBJS:%.o=%.d) -include $(FDTPUT_OBJS:%.o=%.d) +-include $(FDTOVERLAY_OBJS:%.o=%.d) endif @@ -180,6 +208,10 @@ install-includes: install: install-bin install-lib install-includes +ifeq ($(NO_PYTHON),) +install: install_pylibfdt +endif + $(VERSION_FILE): Makefile FORCE $(call filechk,version) @@ -196,13 +228,31 @@ fdtget: $(FDTGET_OBJS) $(LIBFDT_archive) fdtput: $(FDTPUT_OBJS) $(LIBFDT_archive) +fdtoverlay: $(FDTOVERLAY_OBJS) $(LIBFDT_archive) + dist: git archive --format=tar --prefix=dtc-$(dtc_version)/ HEAD \ > ../dtc-$(dtc_version).tar cat ../dtc-$(dtc_version).tar | \ gzip -9 > ../dtc-$(dtc_version).tar.gz + # +# Rules for pylibfdt +# +PYLIBFDT_srcdir = pylibfdt +PYLIBFDT_objdir = pylibfdt + +include $(PYLIBFDT_srcdir)/Makefile.pylibfdt + +.PHONY: pylibfdt +pylibfdt: $(PYLIBFDT_objdir)/_libfdt.so + +pylibfdt_clean: + @$(VECHO) CLEAN "(pylibfdt)" + rm -f $(addprefix $(PYLIBFDT_objdir)/,$(PYLIBFDT_cleanfiles)) + +# # Release signing and uploading # This is for maintainer convenience, don't try this at home. # @@ -234,6 +284,10 @@ TESTS_BIN += convert-dtsv0 TESTS_BIN += fdtput TESTS_BIN += fdtget TESTS_BIN += fdtdump +TESTS_BIN += fdtoverlay +ifeq ($(NO_PYTHON),) +TESTS_PYLIBFDT += maybe_pylibfdt +endif include tests/Makefile.tests @@ -243,7 +297,7 @@ include tests/Makefile.tests STD_CLEANFILES = *~ *.o *.$(SHAREDLIB_EXT) *.d *.a *.i *.s core a.out vgcore.* \ *.tab.[ch] *.lex.c *.output -clean: libfdt_clean tests_clean +clean: libfdt_clean pylibfdt_clean tests_clean @$(VECHO) CLEAN rm -f $(STD_CLEANFILES) rm -f $(VERSION_FILE) @@ -287,7 +341,7 @@ clean: libfdt_clean tests_clean $(LIBFDT_lib): @$(VECHO) LD $@ - $(CC) $(LDFLAGS) -fPIC $(SHAREDLIB_LINK_OPTIONS)$(LIBFDT_soname) -o $(LIBFDT_lib) $^ + $(CC) $(LDFLAGS) $(SHAREDLIB_LDFLAGS)$(LIBFDT_soname) -o $(LIBFDT_lib) $^ %.lex.c: %.l @$(VECHO) LEX $@ Modified: vendor/dtc/dist/Makefile.utils ============================================================================== --- vendor/dtc/dist/Makefile.utils Fri Jan 12 20:40:27 2018 (r327892) +++ vendor/dtc/dist/Makefile.utils Fri Jan 12 21:44:53 2018 (r327893) @@ -22,3 +22,9 @@ FDTPUT_SRCS = \ util.c FDTPUT_OBJS = $(FDTPUT_SRCS:%.c=%.o) + +FDTOVERLAY_SRCS = \ + fdtoverlay.c \ + util.c + +FDTOVERLAY_OBJS = $(FDTOVERLAY_SRCS:%.c=%.o) Modified: vendor/dtc/dist/README ============================================================================== --- vendor/dtc/dist/README Fri Jan 12 20:40:27 2018 (r327892) +++ vendor/dtc/dist/README Fri Jan 12 21:44:53 2018 (r327893) @@ -7,6 +7,83 @@ DTC and LIBFDT are maintained by: David Gibson Jon Loeliger + +Python library +-------------- + +A Python library is also available. To build this you will need to install +swig and Python development files. On Debian distributions: + + sudo apt-get install swig python-dev + +The library provides an Fdt class which you can use like this: + +$ PYTHONPATH=../pylibfdt python +>>> import libfdt +>>> fdt = libfdt.Fdt(open('test_tree1.dtb').read()) +>>> node = fdt.path_offset('/subnode@1') +>>> print node +124 +>>> prop_offset = fdt.first_property_offset(node) +>>> prop = fdt.get_property_by_offset(prop_offset) +>>> print '%s=%r' % (prop.name, prop.value) +compatible=bytearray(b'subnode1\x00') +>>> print '%s=%s' % (prop.name, prop.value) +compatible=subnode1 +>>> node2 = fdt.path_offset('/') +>>> print fdt.getprop(node2, 'compatible') +test_tree1 + +You will find tests in tests/pylibfdt_tests.py showing how to use each +method. Help is available using the Python help command, e.g.: + + $ cd pylibfdt + $ python -c "import libfdt; help(libfdt)" + +If you add new features, please check code coverage: + + $ sudo apt-get install python-pip python-pytest + $ sudo pip install coverage + $ cd tests + $ coverage run pylibfdt_tests.py + $ coverage html + # Open 'htmlcov/index.html' in your browser + + +To install the library via the normal setup.py method, use: + + ./pylibfdt/setup.py [--prefix=/path/to/install_dir] + +If --prefix is not provided, the default prefix is used, typically '/usr' +or '/usr/local'. See Python's distutils documentation for details. You can +also install via the Makefile if you like, but the above is more common. + +To install both libfdt and pylibfdt you can use: + + make install [SETUP_PREFIX=/path/to/install_dir] \ + [PREFIX=/path/to/install_dir] + +To disable building the python library, even if swig and Python are available, +use: + + make NO_PYTHON=1 + + +More work remains to support all of libfdt, including access to numeric +values. + + +Tests +----- + +Test files are kept in the tests/ directory. Use 'make check' to build and run +all tests. + +If you want to adjust a test file, be aware that tree_tree1.dts is compiled +and checked against a binary tree from assembler macros in trees.S. So +if you change that file you must change tree.S also. + + Mailing list ------------ The following list is for discussion about dtc and libfdt implementation Modified: vendor/dtc/dist/checks.c ============================================================================== --- vendor/dtc/dist/checks.c Fri Jan 12 20:40:27 2018 (r327892) +++ vendor/dtc/dist/checks.c Fri Jan 12 21:44:53 2018 (r327893) @@ -53,31 +53,27 @@ struct check { struct check **prereq; }; -#define CHECK_ENTRY(_nm, _fn, _d, _w, _e, ...) \ - static struct check *_nm##_prereqs[] = { __VA_ARGS__ }; \ - static struct check _nm = { \ - .name = #_nm, \ - .fn = (_fn), \ - .data = (_d), \ - .warn = (_w), \ - .error = (_e), \ +#define CHECK_ENTRY(nm_, fn_, d_, w_, e_, ...) \ + static struct check *nm_##_prereqs[] = { __VA_ARGS__ }; \ + static struct check nm_ = { \ + .name = #nm_, \ + .fn = (fn_), \ + .data = (d_), \ + .warn = (w_), \ + .error = (e_), \ .status = UNCHECKED, \ - .num_prereqs = ARRAY_SIZE(_nm##_prereqs), \ - .prereq = _nm##_prereqs, \ + .num_prereqs = ARRAY_SIZE(nm_##_prereqs), \ + .prereq = nm_##_prereqs, \ }; -#define WARNING(_nm, _fn, _d, ...) \ - CHECK_ENTRY(_nm, _fn, _d, true, false, __VA_ARGS__) -#define ERROR(_nm, _fn, _d, ...) \ - CHECK_ENTRY(_nm, _fn, _d, false, true, __VA_ARGS__) -#define CHECK(_nm, _fn, _d, ...) \ - CHECK_ENTRY(_nm, _fn, _d, false, false, __VA_ARGS__) +#define WARNING(nm_, fn_, d_, ...) \ + CHECK_ENTRY(nm_, fn_, d_, true, false, __VA_ARGS__) +#define ERROR(nm_, fn_, d_, ...) \ + CHECK_ENTRY(nm_, fn_, d_, false, true, __VA_ARGS__) +#define CHECK(nm_, fn_, d_, ...) \ + CHECK_ENTRY(nm_, fn_, d_, false, false, __VA_ARGS__) -#ifdef __GNUC__ -static inline void check_msg(struct check *c, struct dt_info *dti, - const char *fmt, ...) __attribute__((format (printf, 3, 4))); -#endif -static inline void check_msg(struct check *c, struct dt_info *dti, - const char *fmt, ...) +static inline void PRINTF(3, 4) check_msg(struct check *c, struct dt_info *dti, + const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -183,6 +179,36 @@ static void check_is_string(struct check *c, struct dt #define ERROR_IF_NOT_STRING(nm, propname) \ ERROR(nm, check_is_string, (propname)) +static void check_is_string_list(struct check *c, struct dt_info *dti, + struct node *node) +{ + int rem, l; + struct property *prop; + char *propname = c->data; + char *str; + + prop = get_property(node, propname); + if (!prop) + return; /* Not present, assumed ok */ + + str = prop->val.val; + rem = prop->val.len; + while (rem > 0) { + l = strnlen(str, rem); + if (l == rem) { + FAIL(c, dti, "\"%s\" property in %s is not a string list", + propname, node->fullpath); + break; + } + rem -= l + 1; + str += l + 1; + } +} +#define WARNING_IF_NOT_STRING_LIST(nm, propname) \ + WARNING(nm, check_is_string_list, (propname)) +#define ERROR_IF_NOT_STRING_LIST(nm, propname) \ + ERROR(nm, check_is_string_list, (propname)) + static void check_is_cell(struct check *c, struct dt_info *dti, struct node *node) { @@ -538,13 +564,13 @@ static void fixup_phandle_references(struct check *c, FAIL(c, dti, "Reference to non-existent node or " "label \"%s\"\n", m->ref); else /* mark the entry as unresolved */ - *((cell_t *)(prop->val.val + m->offset)) = + *((fdt32_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(0xffffffff); continue; } phandle = get_node_phandle(dt, refnode); - *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); + *((fdt32_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); } } } @@ -590,7 +616,48 @@ WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interru WARNING_IF_NOT_STRING(device_type_is_string, "device_type"); WARNING_IF_NOT_STRING(model_is_string, "model"); WARNING_IF_NOT_STRING(status_is_string, "status"); +WARNING_IF_NOT_STRING(label_is_string, "label"); +WARNING_IF_NOT_STRING_LIST(compatible_is_string_list, "compatible"); + +static void check_names_is_string_list(struct check *c, struct dt_info *dti, + struct node *node) +{ + struct property *prop; + + for_each_property(node, prop) { + const char *s = strrchr(prop->name, '-'); + if (!s || !streq(s, "-names")) + continue; + + c->data = prop->name; + check_is_string_list(c, dti, node); + } +} +WARNING(names_is_string_list, check_names_is_string_list, NULL); + +static void check_alias_paths(struct check *c, struct dt_info *dti, + struct node *node) +{ + struct property *prop; + + if (!streq(node->name, "aliases")) + return; + + for_each_property(node, prop) { + if (!prop->val.val || !get_node_by_path(dti->dt, prop->val.val)) { + FAIL(c, dti, "aliases property '%s' is not a valid node (%s)", + prop->name, prop->val.val); + continue; + } + if (strspn(prop->name, LOWERCASE DIGITS "-") != strlen(prop->name)) + FAIL(c, dti, "aliases property name '%s' is not valid", + prop->name); + + } +} +WARNING(alias_paths, check_alias_paths, NULL); + static void fixup_addr_size_cells(struct check *c, struct dt_info *dti, struct node *node) { @@ -685,6 +752,229 @@ static void check_ranges_format(struct check *c, struc } WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells); +static const struct bus_type pci_bus = { + .name = "PCI", +}; + +static void check_pci_bridge(struct check *c, struct dt_info *dti, struct node *node) +{ + struct property *prop; + cell_t *cells; + + prop = get_property(node, "device_type"); + if (!prop || !streq(prop->val.val, "pci")) + return; + + node->bus = &pci_bus; + + if (!strprefixeq(node->name, node->basenamelen, "pci") && + !strprefixeq(node->name, node->basenamelen, "pcie")) + FAIL(c, dti, "Node %s node name is not \"pci\" or \"pcie\"", + node->fullpath); + + prop = get_property(node, "ranges"); + if (!prop) + FAIL(c, dti, "Node %s missing ranges for PCI bridge (or not a bridge)", + node->fullpath); + + if (node_addr_cells(node) != 3) + FAIL(c, dti, "Node %s incorrect #address-cells for PCI bridge", + node->fullpath); + if (node_size_cells(node) != 2) + FAIL(c, dti, "Node %s incorrect #size-cells for PCI bridge", + node->fullpath); + + prop = get_property(node, "bus-range"); + if (!prop) { + FAIL(c, dti, "Node %s missing bus-range for PCI bridge", + node->fullpath); + return; + } + if (prop->val.len != (sizeof(cell_t) * 2)) { + FAIL(c, dti, "Node %s bus-range must be 2 cells", + node->fullpath); + return; + } + cells = (cell_t *)prop->val.val; + if (fdt32_to_cpu(cells[0]) > fdt32_to_cpu(cells[1])) + FAIL(c, dti, "Node %s bus-range 1st cell must be less than or equal to 2nd cell", + node->fullpath); + if (fdt32_to_cpu(cells[1]) > 0xff) + FAIL(c, dti, "Node %s bus-range maximum bus number must be less than 256", + node->fullpath); +} +WARNING(pci_bridge, check_pci_bridge, NULL, + &device_type_is_string, &addr_size_cells); + +static void check_pci_device_bus_num(struct check *c, struct dt_info *dti, struct node *node) +{ + struct property *prop; + unsigned int bus_num, min_bus, max_bus; + cell_t *cells; + + if (!node->parent || (node->parent->bus != &pci_bus)) + return; + + prop = get_property(node, "reg"); + if (!prop) + return; + + cells = (cell_t *)prop->val.val; + bus_num = (fdt32_to_cpu(cells[0]) & 0x00ff0000) >> 16; + + prop = get_property(node->parent, "bus-range"); + if (!prop) { + min_bus = max_bus = 0; + } else { + cells = (cell_t *)prop->val.val; + min_bus = fdt32_to_cpu(cells[0]); + max_bus = fdt32_to_cpu(cells[0]); + } + if ((bus_num < min_bus) || (bus_num > max_bus)) + FAIL(c, dti, "Node %s PCI bus number %d out of range, expected (%d - %d)", + node->fullpath, bus_num, min_bus, max_bus); +} +WARNING(pci_device_bus_num, check_pci_device_bus_num, NULL, ®_format, &pci_bridge); + +static void check_pci_device_reg(struct check *c, struct dt_info *dti, struct node *node) +{ + struct property *prop; + const char *unitname = get_unitname(node); + char unit_addr[5]; + unsigned int dev, func, reg; + cell_t *cells; + + if (!node->parent || (node->parent->bus != &pci_bus)) + return; + + prop = get_property(node, "reg"); + if (!prop) { + FAIL(c, dti, "Node %s missing PCI reg property", node->fullpath); + return; + } + + cells = (cell_t *)prop->val.val; + if (cells[1] || cells[2]) + FAIL(c, dti, "Node %s PCI reg config space address cells 2 and 3 must be 0", + node->fullpath); + + reg = fdt32_to_cpu(cells[0]); + dev = (reg & 0xf800) >> 11; + func = (reg & 0x700) >> 8; + + if (reg & 0xff000000) + FAIL(c, dti, "Node %s PCI reg address is not configuration space", + node->fullpath); + if (reg & 0x000000ff) + FAIL(c, dti, "Node %s PCI reg config space address register number must be 0", + node->fullpath); + + if (func == 0) { + snprintf(unit_addr, sizeof(unit_addr), "%x", dev); + if (streq(unitname, unit_addr)) + return; + } + + snprintf(unit_addr, sizeof(unit_addr), "%x,%x", dev, func); + if (streq(unitname, unit_addr)) + return; + + FAIL(c, dti, "Node %s PCI unit address format error, expected \"%s\"", + node->fullpath, unit_addr); +} +WARNING(pci_device_reg, check_pci_device_reg, NULL, ®_format, &pci_bridge); + +static const struct bus_type simple_bus = { + .name = "simple-bus", +}; + +static bool node_is_compatible(struct node *node, const char *compat) +{ + struct property *prop; + const char *str, *end; + + prop = get_property(node, "compatible"); + if (!prop) + return false; + + for (str = prop->val.val, end = str + prop->val.len; str < end; + str += strnlen(str, end - str) + 1) { + if (strprefixeq(str, end - str, compat)) + return true; + } + return false; +} + +static void check_simple_bus_bridge(struct check *c, struct dt_info *dti, struct node *node) +{ + if (node_is_compatible(node, "simple-bus")) + node->bus = &simple_bus; +} +WARNING(simple_bus_bridge, check_simple_bus_bridge, NULL, &addr_size_cells); + +static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct node *node) +{ + struct property *prop; + const char *unitname = get_unitname(node); + char unit_addr[17]; + unsigned int size; + uint64_t reg = 0; + cell_t *cells = NULL; + + if (!node->parent || (node->parent->bus != &simple_bus)) + return; + + prop = get_property(node, "reg"); + if (prop) + cells = (cell_t *)prop->val.val; + else { + prop = get_property(node, "ranges"); + if (prop && prop->val.len) + /* skip of child address */ + cells = ((cell_t *)prop->val.val) + node_addr_cells(node); + } + + if (!cells) { + if (node->parent->parent && !(node->bus == &simple_bus)) + FAIL(c, dti, "Node %s missing or empty reg/ranges property", node->fullpath); + return; + } + + size = node_addr_cells(node->parent); + while (size--) + reg = (reg << 32) | fdt32_to_cpu(*(cells++)); + + snprintf(unit_addr, sizeof(unit_addr), "%"PRIx64, reg); + if (!streq(unitname, unit_addr)) + FAIL(c, dti, "Node %s simple-bus unit address format error, expected \"%s\"", + node->fullpath, unit_addr); +} +WARNING(simple_bus_reg, check_simple_bus_reg, NULL, ®_format, &simple_bus_bridge); + +static void check_unit_address_format(struct check *c, struct dt_info *dti, + struct node *node) +{ + const char *unitname = get_unitname(node); + + if (node->parent && node->parent->bus) + return; + + if (!unitname[0]) + return; + + if (!strncmp(unitname, "0x", 2)) { + FAIL(c, dti, "Node %s unit name should not have leading \"0x\"", + node->fullpath); + /* skip over 0x for next test */ + unitname += 2; + } + if (unitname[0] == '0' && isxdigit(unitname[1])) + FAIL(c, dti, "Node %s unit name should not have leading 0s", + node->fullpath); +} +WARNING(unit_address_format, check_unit_address_format, NULL, + &node_name_format, &pci_bridge, &simple_bus_bridge); + /* * Style checks */ @@ -713,6 +1003,31 @@ static void check_avoid_default_addr_size(struct check WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL, &addr_size_cells); +static void check_avoid_unnecessary_addr_size(struct check *c, struct dt_info *dti, + struct node *node) +{ + struct property *prop; + struct node *child; + bool has_reg = false; + + if (!node->parent || node->addr_cells < 0 || node->size_cells < 0) + return; + + if (get_property(node, "ranges") || !node->children) + return; + + for_each_child(node, child) { + prop = get_property(child, "reg"); + if (prop) + has_reg = true; + } + + if (!has_reg) + FAIL(c, dti, "unnecessary #address-cells/#size-cells without \"ranges\" or child \"reg\" property in %s", + node->fullpath); +} +WARNING(avoid_unnecessary_addr_size, check_avoid_unnecessary_addr_size, NULL, &avoid_default_addr_size); + static void check_obsolete_chosen_interrupt_controller(struct check *c, struct dt_info *dti, struct node *node) @@ -737,6 +1052,324 @@ static void check_obsolete_chosen_interrupt_controller WARNING(obsolete_chosen_interrupt_controller, check_obsolete_chosen_interrupt_controller, NULL); +static void check_chosen_node_is_root(struct check *c, struct dt_info *dti, + struct node *node) +{ + if (!streq(node->name, "chosen")) + return; + + if (node->parent != dti->dt) + FAIL(c, dti, "chosen node '%s' must be at root node", + node->fullpath); +} +WARNING(chosen_node_is_root, check_chosen_node_is_root, NULL); + +static void check_chosen_node_bootargs(struct check *c, struct dt_info *dti, + struct node *node) +{ + struct property *prop; + + if (!streq(node->name, "chosen")) + return; + + prop = get_property(node, "bootargs"); + if (!prop) + return; + + c->data = prop->name; + check_is_string(c, dti, node); +} +WARNING(chosen_node_bootargs, check_chosen_node_bootargs, NULL); + +static void check_chosen_node_stdout_path(struct check *c, struct dt_info *dti, + struct node *node) +{ + struct property *prop; + + if (!streq(node->name, "chosen")) + return; + + prop = get_property(node, "stdout-path"); + if (!prop) { + prop = get_property(node, "linux,stdout-path"); + if (!prop) + return; + FAIL(c, dti, "Use 'stdout-path' instead of 'linux,stdout-path'"); + } + + c->data = prop->name; + check_is_string(c, dti, node); +} +WARNING(chosen_node_stdout_path, check_chosen_node_stdout_path, NULL); + +struct provider { + const char *prop_name; + const char *cell_name; + bool optional; +}; + +static void check_property_phandle_args(struct check *c, + struct dt_info *dti, + struct node *node, + struct property *prop, + const struct provider *provider) +{ + struct node *root = dti->dt; + int cell, cellsize = 0; + + if (prop->val.len % sizeof(cell_t)) { + FAIL(c, dti, "property '%s' size (%d) is invalid, expected multiple of %zu in node %s", + prop->name, prop->val.len, sizeof(cell_t), node->fullpath); + return; + } + + for (cell = 0; cell < prop->val.len / sizeof(cell_t); cell += cellsize + 1) { + struct node *provider_node; + struct property *cellprop; + int phandle; + + phandle = propval_cell_n(prop, cell); + /* + * Some bindings use a cell value 0 or -1 to skip over optional + * entries when each index position has a specific definition. + */ + if (phandle == 0 || phandle == -1) { + /* Give up if this is an overlay with external references */ + if (dti->dtsflags & DTSF_PLUGIN) + break; + + cellsize = 0; + continue; + } + + /* If we have markers, verify the current cell is a phandle */ + if (prop->val.markers) { + struct marker *m = prop->val.markers; + for_each_marker_of_type(m, REF_PHANDLE) { + if (m->offset == (cell * sizeof(cell_t))) + break; + } + if (!m) + FAIL(c, dti, "Property '%s', cell %d is not a phandle reference in %s", + prop->name, cell, node->fullpath); + } + + provider_node = get_node_by_phandle(root, phandle); + if (!provider_node) { + FAIL(c, dti, "Could not get phandle node for %s:%s(cell %d)", + node->fullpath, prop->name, cell); + break; + } + + cellprop = get_property(provider_node, provider->cell_name); + if (cellprop) { + cellsize = propval_cell(cellprop); + } else if (provider->optional) { + cellsize = 0; + } else { + FAIL(c, dti, "Missing property '%s' in node %s or bad phandle (referred from %s:%s[%d])", + provider->cell_name, + provider_node->fullpath, + node->fullpath, prop->name, cell); + break; + } + + if (prop->val.len < ((cell + cellsize + 1) * sizeof(cell_t))) { + FAIL(c, dti, "%s property size (%d) too small for cell size %d in %s", + prop->name, prop->val.len, cellsize, node->fullpath); + } + } +} + +static void check_provider_cells_property(struct check *c, + struct dt_info *dti, + struct node *node) +{ + struct provider *provider = c->data; + struct property *prop; + + prop = get_property(node, provider->prop_name); + if (!prop) + return; + + check_property_phandle_args(c, dti, node, prop, provider); +} +#define WARNING_PROPERTY_PHANDLE_CELLS(nm, propname, cells_name, ...) \ + static struct provider nm##_provider = { (propname), (cells_name), __VA_ARGS__ }; \ + WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &phandle_references); + +WARNING_PROPERTY_PHANDLE_CELLS(clocks, "clocks", "#clock-cells"); +WARNING_PROPERTY_PHANDLE_CELLS(cooling_device, "cooling-device", "#cooling-cells"); +WARNING_PROPERTY_PHANDLE_CELLS(dmas, "dmas", "#dma-cells"); +WARNING_PROPERTY_PHANDLE_CELLS(hwlocks, "hwlocks", "#hwlock-cells"); +WARNING_PROPERTY_PHANDLE_CELLS(interrupts_extended, "interrupts-extended", "#interrupt-cells"); +WARNING_PROPERTY_PHANDLE_CELLS(io_channels, "io-channels", "#io-channel-cells"); +WARNING_PROPERTY_PHANDLE_CELLS(iommus, "iommus", "#iommu-cells"); +WARNING_PROPERTY_PHANDLE_CELLS(mboxes, "mboxes", "#mbox-cells"); +WARNING_PROPERTY_PHANDLE_CELLS(msi_parent, "msi-parent", "#msi-cells", true); +WARNING_PROPERTY_PHANDLE_CELLS(mux_controls, "mux-controls", "#mux-control-cells"); +WARNING_PROPERTY_PHANDLE_CELLS(phys, "phys", "#phy-cells"); +WARNING_PROPERTY_PHANDLE_CELLS(power_domains, "power-domains", "#power-domain-cells"); +WARNING_PROPERTY_PHANDLE_CELLS(pwms, "pwms", "#pwm-cells"); +WARNING_PROPERTY_PHANDLE_CELLS(resets, "resets", "#reset-cells"); +WARNING_PROPERTY_PHANDLE_CELLS(sound_dai, "sound-dai", "#sound-dai-cells"); +WARNING_PROPERTY_PHANDLE_CELLS(thermal_sensors, "thermal-sensors", "#thermal-sensor-cells"); + +static bool prop_is_gpio(struct property *prop) +{ + char *str; + + /* + * *-gpios and *-gpio can appear in property names, + * so skip over any false matches (only one known ATM) + */ + if (strstr(prop->name, "nr-gpio")) + return false; + + str = strrchr(prop->name, '-'); + if (str) + str++; + else + str = prop->name; + if (!(streq(str, "gpios") || streq(str, "gpio"))) + return false; + + return true; +} + +static void check_gpios_property(struct check *c, + struct dt_info *dti, + struct node *node) +{ + struct property *prop; + + /* Skip GPIO hog nodes which have 'gpios' property */ + if (get_property(node, "gpio-hog")) + return; + + for_each_property(node, prop) { + struct provider provider; + + if (!prop_is_gpio(prop)) + continue; + + provider.prop_name = prop->name; + provider.cell_name = "#gpio-cells"; + provider.optional = false; + check_property_phandle_args(c, dti, node, prop, &provider); + } + +} +WARNING(gpios_property, check_gpios_property, NULL, &phandle_references); + +static void check_deprecated_gpio_property(struct check *c, + struct dt_info *dti, + struct node *node) +{ + struct property *prop; + + for_each_property(node, prop) { + char *str; + + if (!prop_is_gpio(prop)) + continue; + + str = strstr(prop->name, "gpio"); + if (!streq(str, "gpio")) + continue; + + FAIL(c, dti, "'[*-]gpio' is deprecated, use '[*-]gpios' instead for %s:%s", + node->fullpath, prop->name); + } + +} +CHECK(deprecated_gpio_property, check_deprecated_gpio_property, NULL); + +static bool node_is_interrupt_provider(struct node *node) +{ + struct property *prop; + + prop = get_property(node, "interrupt-controller"); + if (prop) + return true; + + prop = get_property(node, "interrupt-map"); + if (prop) + return true; + + return false; +} +static void check_interrupts_property(struct check *c, + struct dt_info *dti, + struct node *node) +{ + struct node *root = dti->dt; + struct node *irq_node = NULL, *parent = node; + struct property *irq_prop, *prop = NULL; + int irq_cells, phandle; + + irq_prop = get_property(node, "interrupts"); + if (!irq_prop) + return; + + if (irq_prop->val.len % sizeof(cell_t)) + FAIL(c, dti, "property '%s' size (%d) is invalid, expected multiple of %zu in node %s", + irq_prop->name, irq_prop->val.len, sizeof(cell_t), + node->fullpath); + + while (parent && !prop) { + if (parent != node && node_is_interrupt_provider(parent)) { + irq_node = parent; + break; + } + + prop = get_property(parent, "interrupt-parent"); + if (prop) { + phandle = propval_cell(prop); + /* Give up if this is an overlay with external references */ + if ((phandle == 0 || phandle == -1) && + (dti->dtsflags & DTSF_PLUGIN)) + return; + + irq_node = get_node_by_phandle(root, phandle); + if (!irq_node) { + FAIL(c, dti, "Bad interrupt-parent phandle for %s", + node->fullpath); + return; + } + if (!node_is_interrupt_provider(irq_node)) + FAIL(c, dti, + "Missing interrupt-controller or interrupt-map property in %s", + irq_node->fullpath); + + break; + } + + parent = parent->parent; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***