mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH] commands: implement of_compatible command
@ 2023-04-20 20:09 Ahmad Fatoum
  2023-05-02 11:17 ` Sascha Hauer
  0 siblings, 1 reply; 2+ messages in thread
From: Ahmad Fatoum @ 2023-04-20 20:09 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

Currently, the usual way within scripts to differentiate between machines
is to compare global.model or global.hostname. Both are suboptimal,
because they may change between releases or overridden by the user.

In C code, the machine compatible is used for this purpose. Add a new
of_compatible command that makes of_machine_is_compatible/
of_device_is_compatible available to scripts. Example use:

/env/init/fixups:

  #!/bin/sh

  if of_compatible -k radxa,rock3a ; then
    of_property -df mmc0 sd-uhs-sdr104
  fi

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 commands/Kconfig         |  15 +++++
 commands/Makefile        |   1 +
 commands/of_compatible.c | 139 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 155 insertions(+)
 create mode 100644 commands/of_compatible.c

diff --git a/commands/Kconfig b/commands/Kconfig
index b9abd8565523..59e8d6fb382d 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -2201,6 +2201,21 @@ config CMD_LSMOD
 	help
 	  List loaded barebox modules.
 
+config CMD_OF_COMPATIBLE
+	tristate
+	select OFTREE
+	prompt "of_compatible"
+	help
+	  Check DT node's compatible
+
+	  Usage: [-fFnk] [COMPAT]
+
+	  Options:
+          	-f dtb	work on dtb instead of internal devicetree
+          	-F	apply fixups on devicetree before compare
+          	-n node	node path or alias to compare its comptible (default is /)
+          	-k	compare $global.of.kernel.add_machine_compatible as well
+
 config CMD_OF_DIFF
 	tristate
 	select OFTREE
diff --git a/commands/Makefile b/commands/Makefile
index e5cc21f1970a..0ac84076f83d 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_CMD_USB)		+= usb.o
 obj-$(CONFIG_CMD_TIME)		+= time.o
 obj-$(CONFIG_CMD_UPTIME)	+= uptime.o
 obj-$(CONFIG_CMD_OFTREE)	+= oftree.o
+obj-$(CONFIG_CMD_OF_COMPATIBLE)	+= of_compatible.o
 obj-$(CONFIG_CMD_OF_DIFF)	+= of_diff.o
 obj-$(CONFIG_CMD_OF_PROPERTY)	+= of_property.o
 obj-$(CONFIG_CMD_OF_NODE)	+= of_node.o
diff --git a/commands/of_compatible.c b/commands/of_compatible.c
new file mode 100644
index 000000000000..e4684f23b71d
--- /dev/null
+++ b/commands/of_compatible.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: © 2023 Ahmad Fatoum <a.fatoum@pengutronix.de>
+
+#include <common.h>
+#include <libfile.h>
+#include <fdt.h>
+#include <of.h>
+#include <command.h>
+#include <complete.h>
+#include <errno.h>
+#include <getopt.h>
+
+static int do_of_compatible(int argc, char *argv[])
+{
+	int opt;
+	int ret = 0;
+	bool fix = false, kernel_compat = false;
+	struct device_node *root = NULL, *node, *of_free = NULL;
+	char *dtbfile = NULL;
+	const char *compat, *nodename = "/";
+
+	while ((opt = getopt(argc, argv, "f:n:Fk")) > 0) {
+		switch (opt) {
+		case 'f':
+			dtbfile = optarg;
+			break;
+		case 'n':
+			nodename = optarg;
+			break;
+		case 'F':
+			fix = true;
+			break;
+		case 'k':
+			kernel_compat = true;
+			break;
+		default:
+			return COMMAND_ERROR_USAGE;
+		}
+	}
+
+	if (argc - optind != 1)
+		return COMMAND_ERROR_USAGE;
+
+	compat = argv[optind];
+
+	if (dtbfile) {
+		size_t size;
+		void *fdt;
+
+		fdt = read_file(dtbfile, &size);
+		if (!fdt) {
+			printf("unable to read %s: %s\n", dtbfile, strerror(errno));
+			return -errno;
+		}
+
+		root = of_unflatten_dtb(fdt, size);
+
+		free(fdt);
+
+		if (IS_ERR(root)) {
+			ret = PTR_ERR(root);
+			goto out;
+		}
+
+		of_free = root;
+	} else {
+		root = of_get_root_node();
+
+		if (fix) {
+			/* create a copy of internal devicetree */
+			void *fdt;
+			fdt = of_flatten_dtb(root);
+			root = of_unflatten_dtb(fdt, fdt_totalsize(fdt));
+
+			free(fdt);
+
+			if (IS_ERR(root)) {
+				ret = PTR_ERR(root);
+				goto out;
+			}
+
+			of_free = root;
+		}
+	}
+
+	if (fix) {
+		ret = of_fix_tree(root);
+		if (ret)
+			goto out;
+	}
+
+	node = of_find_node_by_path_or_alias(root, nodename);
+	if (!node) {
+		printf("Cannot find nodepath %s\n", nodename);
+		ret = -ENOENT;
+		goto out;
+	}
+
+	if (kernel_compat) {
+		const char *compat_override;
+
+		if (node->parent) {
+			printf("-k only valid for root node\n");
+			ret = COMMAND_ERROR_USAGE;
+			goto out;
+		}
+
+		compat_override = barebox_get_of_machine_compatible() ?: "";
+		if (strcmp(compat_override, compat) == 0) {
+			ret = 0;
+			goto out;
+		}
+	}
+
+	ret = !of_device_is_compatible(node, compat);
+
+out:
+	if (of_free)
+		of_delete_node(of_free);
+
+	return ret;
+}
+
+BAREBOX_CMD_HELP_START(of_compatible)
+BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT  ("-f dtb",  "work on dtb instead of internal devicetree")
+BAREBOX_CMD_HELP_OPT  ("-F",      "apply fixups on devicetree before compare")
+BAREBOX_CMD_HELP_OPT  ("-n NODE", "node path or alias to compare its compatible (default is /)")
+BAREBOX_CMD_HELP_OPT  ("-k",      "compare $global.of.kernel.add_machine_compatible as well")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(of_compatible)
+	.cmd		= do_of_compatible,
+	BAREBOX_CMD_DESC("Check DT node's compatible")
+	BAREBOX_CMD_OPTS("[-fFnk] [COMPAT]")
+	BAREBOX_CMD_GROUP(CMD_GRP_MISC)
+	BAREBOX_CMD_COMPLETE(empty_complete)
+	BAREBOX_CMD_HELP(cmd_of_compatible_help)
+BAREBOX_CMD_END
-- 
2.39.2




^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] commands: implement of_compatible command
  2023-04-20 20:09 [PATCH] commands: implement of_compatible command Ahmad Fatoum
@ 2023-05-02 11:17 ` Sascha Hauer
  0 siblings, 0 replies; 2+ messages in thread
From: Sascha Hauer @ 2023-05-02 11:17 UTC (permalink / raw)
  To: Ahmad Fatoum; +Cc: barebox

On Thu, Apr 20, 2023 at 10:09:28PM +0200, Ahmad Fatoum wrote:
> Currently, the usual way within scripts to differentiate between machines
> is to compare global.model or global.hostname. Both are suboptimal,
> because they may change between releases or overridden by the user.
> 
> In C code, the machine compatible is used for this purpose. Add a new
> of_compatible command that makes of_machine_is_compatible/
> of_device_is_compatible available to scripts. Example use:
> 
> /env/init/fixups:
> 
>   #!/bin/sh
> 
>   if of_compatible -k radxa,rock3a ; then
>     of_property -df mmc0 sd-uhs-sdr104
>   fi
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
> ---
>  commands/Kconfig         |  15 +++++
>  commands/Makefile        |   1 +
>  commands/of_compatible.c | 139 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 155 insertions(+)
>  create mode 100644 commands/of_compatible.c
> 
> diff --git a/commands/Kconfig b/commands/Kconfig
> index b9abd8565523..59e8d6fb382d 100644
> --- a/commands/Kconfig
> +++ b/commands/Kconfig
> @@ -2201,6 +2201,21 @@ config CMD_LSMOD
>  	help
>  	  List loaded barebox modules.
>  
> +config CMD_OF_COMPATIBLE
> +	tristate
> +	select OFTREE
> +	prompt "of_compatible"
> +	help
> +	  Check DT node's compatible
> +
> +	  Usage: [-fFnk] [COMPAT]
> +
> +	  Options:
> +          	-f dtb	work on dtb instead of internal devicetree
> +          	-F	apply fixups on devicetree before compare
> +          	-n node	node path or alias to compare its comptible (default is /)

s/comptible/compatible/

> +          	-k	compare $global.of.kernel.add_machine_compatible as well
> +
>  config CMD_OF_DIFF
>  	tristate
>  	select OFTREE
> diff --git a/commands/Makefile b/commands/Makefile
> index e5cc21f1970a..0ac84076f83d 100644
> --- a/commands/Makefile
> +++ b/commands/Makefile
> @@ -82,6 +82,7 @@ obj-$(CONFIG_CMD_USB)		+= usb.o
>  obj-$(CONFIG_CMD_TIME)		+= time.o
>  obj-$(CONFIG_CMD_UPTIME)	+= uptime.o
>  obj-$(CONFIG_CMD_OFTREE)	+= oftree.o
> +obj-$(CONFIG_CMD_OF_COMPATIBLE)	+= of_compatible.o
>  obj-$(CONFIG_CMD_OF_DIFF)	+= of_diff.o
>  obj-$(CONFIG_CMD_OF_PROPERTY)	+= of_property.o
>  obj-$(CONFIG_CMD_OF_NODE)	+= of_node.o
> diff --git a/commands/of_compatible.c b/commands/of_compatible.c
> new file mode 100644
> index 000000000000..e4684f23b71d
> --- /dev/null
> +++ b/commands/of_compatible.c
> @@ -0,0 +1,139 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +// SPDX-FileCopyrightText: © 2023 Ahmad Fatoum <a.fatoum@pengutronix.de>
> +
> +#include <common.h>
> +#include <libfile.h>
> +#include <fdt.h>
> +#include <of.h>
> +#include <command.h>
> +#include <complete.h>
> +#include <errno.h>
> +#include <getopt.h>
> +
> +static int do_of_compatible(int argc, char *argv[])
> +{
> +	int opt;
> +	int ret = 0;
> +	bool fix = false, kernel_compat = false;
> +	struct device_node *root = NULL, *node, *of_free = NULL;
> +	char *dtbfile = NULL;
> +	const char *compat, *nodename = "/";
> +
> +	while ((opt = getopt(argc, argv, "f:n:Fk")) > 0) {
> +		switch (opt) {
> +		case 'f':
> +			dtbfile = optarg;
> +			break;
> +		case 'n':
> +			nodename = optarg;
> +			break;
> +		case 'F':
> +			fix = true;
> +			break;
> +		case 'k':
> +			kernel_compat = true;
> +			break;
> +		default:
> +			return COMMAND_ERROR_USAGE;
> +		}
> +	}
> +
> +	if (argc - optind != 1)
> +		return COMMAND_ERROR_USAGE;
> +
> +	compat = argv[optind];
> +
> +	if (dtbfile) {
> +		size_t size;
> +		void *fdt;
> +
> +		fdt = read_file(dtbfile, &size);
> +		if (!fdt) {
> +			printf("unable to read %s: %s\n", dtbfile, strerror(errno));
> +			return -errno;
> +		}
> +
> +		root = of_unflatten_dtb(fdt, size);
> +
> +		free(fdt);
> +
> +		if (IS_ERR(root)) {
> +			ret = PTR_ERR(root);
> +			goto out;
> +		}

I've seen this pattern once too much and created a helper function to
read a dtb file and to unflatten it. See the patch I just sent.

> +
> +		of_free = root;
> +	} else {
> +		root = of_get_root_node();
> +
> +		if (fix) {
> +			/* create a copy of internal devicetree */
> +			void *fdt;
> +			fdt = of_flatten_dtb(root);
> +			root = of_unflatten_dtb(fdt, fdt_totalsize(fdt));
> +
> +			free(fdt);
> +
> +			if (IS_ERR(root)) {
> +				ret = PTR_ERR(root);
> +				goto out;
> +			}
> +
> +			of_free = root;
> +		}

You could simplify this by doing:

		root = of_free = of_dup(root);

> +	}
> +
> +	if (fix) {
> +		ret = of_fix_tree(root);
> +		if (ret)
> +			goto out;
> +	}
> +
> +	node = of_find_node_by_path_or_alias(root, nodename);
> +	if (!node) {
> +		printf("Cannot find nodepath %s\n", nodename);
> +		ret = -ENOENT;
> +		goto out;
> +	}
> +
> +	if (kernel_compat) {
> +		const char *compat_override;
> +
> +		if (node->parent) {
> +			printf("-k only valid for root node\n");
> +			ret = COMMAND_ERROR_USAGE;
> +			goto out;
> +		}
> +
> +		compat_override = barebox_get_of_machine_compatible() ?: "";
> +		if (strcmp(compat_override, compat) == 0) {
> +			ret = 0;
> +			goto out;
> +		}
> +	}
> +
> +	ret = !of_device_is_compatible(node, compat);
> +
> +out:
> +	if (of_free)
> +		of_delete_node(of_free);

of_delete_node() is safe for being called with a NULL pointer.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2023-05-02 11:18 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-04-20 20:09 [PATCH] commands: implement of_compatible command Ahmad Fatoum
2023-05-02 11:17 ` Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox