mirror of
https://github.com/armbian/build.git
synced 2025-09-19 04:31:38 +02:00
- materialized overwrites: - `add-board-helios64.patch` - `add-board-orangepi-r1-plus.patch` - `add-driver-for-Motorcomm-YT85xx+PHYs.patch` - `add-board-rk3328-roc-pc.patch` - not touched: wifi patches, those still require work before rebase is consistent. - `wifi-4003-uwe5622-adjust-for-rockchip.patch` - this patch is done on top of the wifi drivers patches exclusively, and fails to apply out of tree. - we should probably consider moving this into the wifi drivers patch harness, not in the rockchip tree.
402 lines
11 KiB
Diff
402 lines
11 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: schwar3kat <61094841+schwar3kat@users.noreply.github.com>
|
|
Date: Mon, 16 Jan 2023 22:57:26 +1300
|
|
Subject: OF: DT-Overlay configfs interface
|
|
|
|
Commit message: Clean up mbox format in general-add-overlay-configfs.patch. No diff changes.
|
|
|
|
Below patch is a squash of 4 commits borrowed from ayufan's
|
|
https://github.com/ayufan-rock64/linux-mainline-kernel repo:
|
|
|
|
This is a port of Pantelis Antoniou's v3 port that makes use of the
|
|
upstreamed configfs support for binary attributes.
|
|
|
|
Original commit message:
|
|
Add a runtime interface to using configfs for generic device tree overlay
|
|
usage. With it its possible to use device tree overlays without having
|
|
to use a per-platform overlay manager.
|
|
Please see Documentation/devicetree/configfs-overlays.txt for more info.
|
|
|
|
Changes since v2:
|
|
- Removed ifdef CONFIG_OF_OVERLAY (since for now it's required)
|
|
- Created a documentation entry
|
|
- Slight rewording in Kconfig
|
|
- Fix build errors
|
|
|
|
Changes since v1:
|
|
- of_resolve() -> of_resolve_phandles().
|
|
|
|
Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
|
|
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
|
---
|
|
Documentation/devicetree/configfs-overlays.txt | 31 +
|
|
drivers/of/Kconfig | 7 +
|
|
drivers/of/Makefile | 1 +
|
|
drivers/of/configfs.c | 290 ++++++++++
|
|
4 files changed, 329 insertions(+)
|
|
|
|
diff --git a/Documentation/devicetree/configfs-overlays.txt b/Documentation/devicetree/configfs-overlays.txt
|
|
new file mode 100644
|
|
index 000000000000..5fa43e064307
|
|
--- /dev/null
|
|
+++ b/Documentation/devicetree/configfs-overlays.txt
|
|
@@ -0,0 +1,31 @@
|
|
+Howto use the configfs overlay interface.
|
|
+
|
|
+A device-tree configfs entry is created in /config/device-tree/overlays
|
|
+and and it is manipulated using standard file system I/O.
|
|
+Note that this is a debug level interface, for use by developers and
|
|
+not necessarily something accessed by normal users due to the
|
|
+security implications of having direct access to the kernel's device tree.
|
|
+
|
|
+* To create an overlay you mkdir the directory:
|
|
+
|
|
+ # mkdir /config/device-tree/overlays/foo
|
|
+
|
|
+* Either you echo the overlay firmware file to the path property file.
|
|
+
|
|
+ # echo foo.dtbo >/config/device-tree/overlays/foo/path
|
|
+
|
|
+* Or you cat the contents of the overlay to the dtbo file
|
|
+
|
|
+ # cat foo.dtbo >/config/device-tree/overlays/foo/dtbo
|
|
+
|
|
+The overlay file will be applied, and devices will be created/destroyed
|
|
+as required.
|
|
+
|
|
+To remove it simply rmdir the directory.
|
|
+
|
|
+ # rmdir /config/device-tree/overlays/foo
|
|
+
|
|
+The rationalle of the dual interface (firmware & direct copy) is that each is
|
|
+better suited to different use patterns. The firmware interface is what's
|
|
+intended to be used by hardware managers in the kernel, while the copy interface
|
|
+make sense for developers (since it avoids problems with namespaces).
|
|
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
|
|
index 644386833a7b..622237fd6145 100644
|
|
--- a/drivers/of/Kconfig
|
|
+++ b/drivers/of/Kconfig
|
|
@@ -106,4 +106,11 @@ config OF_DMA_DEFAULT_COHERENT
|
|
# arches should select this if DMA is coherent by default for OF devices
|
|
bool
|
|
|
|
+config OF_CONFIGFS
|
|
+ bool "Device Tree Overlay ConfigFS interface"
|
|
+ select CONFIGFS_FS
|
|
+ select OF_OVERLAY
|
|
+ help
|
|
+ Enable a simple user-space driven DT overlay interface.
|
|
+
|
|
endif # OF
|
|
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
|
|
index e0360a44306e..90c92ced24e6 100644
|
|
--- a/drivers/of/Makefile
|
|
+++ b/drivers/of/Makefile
|
|
@@ -1,6 +1,7 @@
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
obj-y = base.o device.o platform.o property.o
|
|
obj-$(CONFIG_OF_KOBJ) += kobj.o
|
|
+obj-$(CONFIG_OF_CONFIGFS) += configfs.o
|
|
obj-$(CONFIG_OF_DYNAMIC) += dynamic.o
|
|
obj-$(CONFIG_OF_FLATTREE) += fdt.o
|
|
obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
|
|
diff --git a/drivers/of/configfs.c b/drivers/of/configfs.c
|
|
new file mode 100644
|
|
index 000000000000..5dd509e8fc87
|
|
--- /dev/null
|
|
+++ b/drivers/of/configfs.c
|
|
@@ -0,0 +1,290 @@
|
|
+/*
|
|
+ * Configfs entries for device-tree
|
|
+ *
|
|
+ * Copyright (C) 2013 - Pantelis Antoniou <panto@antoniou-consulting.com>
|
|
+ *
|
|
+ * 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 option) any later version.
|
|
+ */
|
|
+#include <linux/ctype.h>
|
|
+#include <linux/cpu.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_fdt.h>
|
|
+#include <linux/spinlock.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/proc_fs.h>
|
|
+#include <linux/configfs.h>
|
|
+#include <linux/types.h>
|
|
+#include <linux/stat.h>
|
|
+#include <linux/limits.h>
|
|
+#include <linux/file.h>
|
|
+#include <linux/vmalloc.h>
|
|
+#include <linux/firmware.h>
|
|
+#include <linux/sizes.h>
|
|
+
|
|
+#include "of_private.h"
|
|
+
|
|
+struct cfs_overlay_item {
|
|
+ struct config_item item;
|
|
+
|
|
+ char path[PATH_MAX];
|
|
+
|
|
+ const struct firmware *fw;
|
|
+ struct device_node *overlay;
|
|
+ int ov_id;
|
|
+
|
|
+ void *dtbo;
|
|
+ int dtbo_size;
|
|
+};
|
|
+
|
|
+static int create_overlay(struct cfs_overlay_item *overlay, void *blob, u32 blob_size)
|
|
+{
|
|
+ int err;
|
|
+
|
|
+ err = of_overlay_fdt_apply(blob, blob_size, &overlay->ov_id);
|
|
+ if (err < 0) {
|
|
+ pr_err("%s: Failed to create overlay (err=%d)\n",
|
|
+ __func__, err);
|
|
+ goto out_err;
|
|
+ }
|
|
+
|
|
+out_err:
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static inline struct cfs_overlay_item *to_cfs_overlay_item(
|
|
+ struct config_item *item)
|
|
+{
|
|
+ return item ? container_of(item, struct cfs_overlay_item, item) : NULL;
|
|
+}
|
|
+
|
|
+static ssize_t cfs_overlay_item_path_show(struct config_item *item,
|
|
+ char *page)
|
|
+{
|
|
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
|
|
+ return sprintf(page, "%s\n", overlay->path);
|
|
+}
|
|
+
|
|
+static ssize_t cfs_overlay_item_path_store(struct config_item *item,
|
|
+ const char *page, size_t count)
|
|
+{
|
|
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
|
|
+ const char *p = page;
|
|
+ char *s;
|
|
+ int err;
|
|
+
|
|
+ /* if it's set do not allow changes */
|
|
+ if (overlay->path[0] != '\0' || overlay->dtbo_size > 0)
|
|
+ return -EPERM;
|
|
+
|
|
+ /* copy to path buffer (and make sure it's always zero terminated */
|
|
+ count = snprintf(overlay->path, sizeof(overlay->path) - 1, "%s", p);
|
|
+ overlay->path[sizeof(overlay->path) - 1] = '\0';
|
|
+
|
|
+ /* strip trailing newlines */
|
|
+ s = overlay->path + strlen(overlay->path);
|
|
+ while (s > overlay->path && *--s == '\n')
|
|
+ *s = '\0';
|
|
+
|
|
+ pr_debug("%s: path is '%s'\n", __func__, overlay->path);
|
|
+
|
|
+ err = request_firmware(&overlay->fw, overlay->path, NULL);
|
|
+ if (err != 0)
|
|
+ goto out_err;
|
|
+
|
|
+ err = create_overlay(overlay, (void *)overlay->fw->data, overlay->fw->size);
|
|
+ if (err != 0)
|
|
+ goto out_err;
|
|
+
|
|
+ return count;
|
|
+
|
|
+out_err:
|
|
+
|
|
+ release_firmware(overlay->fw);
|
|
+ overlay->fw = NULL;
|
|
+
|
|
+ overlay->path[0] = '\0';
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static ssize_t cfs_overlay_item_status_show(struct config_item *item,
|
|
+ char *page)
|
|
+{
|
|
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
|
|
+
|
|
+ return sprintf(page, "%s\n",
|
|
+ overlay->ov_id >= 0 ? "applied" : "unapplied");
|
|
+}
|
|
+
|
|
+CONFIGFS_ATTR(cfs_overlay_item_, path);
|
|
+CONFIGFS_ATTR_RO(cfs_overlay_item_, status);
|
|
+
|
|
+static struct configfs_attribute *cfs_overlay_attrs[] = {
|
|
+ &cfs_overlay_item_attr_path,
|
|
+ &cfs_overlay_item_attr_status,
|
|
+ NULL,
|
|
+};
|
|
+
|
|
+ssize_t cfs_overlay_item_dtbo_read(struct config_item *item,
|
|
+ void *buf, size_t max_count)
|
|
+{
|
|
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
|
|
+
|
|
+ pr_debug("%s: buf=%p max_count=%zu\n", __func__,
|
|
+ buf, max_count);
|
|
+
|
|
+ if (overlay->dtbo == NULL)
|
|
+ return 0;
|
|
+
|
|
+ /* copy if buffer provided */
|
|
+ if (buf != NULL) {
|
|
+ /* the buffer must be large enough */
|
|
+ if (overlay->dtbo_size > max_count)
|
|
+ return -ENOSPC;
|
|
+
|
|
+ memcpy(buf, overlay->dtbo, overlay->dtbo_size);
|
|
+ }
|
|
+
|
|
+ return overlay->dtbo_size;
|
|
+}
|
|
+
|
|
+ssize_t cfs_overlay_item_dtbo_write(struct config_item *item,
|
|
+ const void *buf, size_t count)
|
|
+{
|
|
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
|
|
+ int err;
|
|
+
|
|
+ /* if it's set do not allow changes */
|
|
+ if (overlay->path[0] != '\0' || overlay->dtbo_size > 0)
|
|
+ return -EPERM;
|
|
+
|
|
+ /* copy the contents */
|
|
+ overlay->dtbo = kmemdup(buf, count, GFP_KERNEL);
|
|
+ if (overlay->dtbo == NULL)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ overlay->dtbo_size = count;
|
|
+
|
|
+ err = create_overlay(overlay, overlay->dtbo, overlay->dtbo_size);
|
|
+ if (err != 0)
|
|
+ goto out_err;
|
|
+
|
|
+ return count;
|
|
+
|
|
+out_err:
|
|
+ kfree(overlay->dtbo);
|
|
+ overlay->dtbo = NULL;
|
|
+ overlay->dtbo_size = 0;
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+CONFIGFS_BIN_ATTR(cfs_overlay_item_, dtbo, NULL, SZ_1M);
|
|
+
|
|
+static struct configfs_bin_attribute *cfs_overlay_bin_attrs[] = {
|
|
+ &cfs_overlay_item_attr_dtbo,
|
|
+ NULL,
|
|
+};
|
|
+
|
|
+static void cfs_overlay_release(struct config_item *item)
|
|
+{
|
|
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
|
|
+
|
|
+ if (overlay->ov_id >= 0)
|
|
+ of_overlay_remove(&overlay->ov_id);
|
|
+ if (overlay->fw)
|
|
+ release_firmware(overlay->fw);
|
|
+ /* kfree with NULL is safe */
|
|
+ kfree(overlay->dtbo);
|
|
+ kfree(overlay);
|
|
+}
|
|
+
|
|
+static struct configfs_item_operations cfs_overlay_item_ops = {
|
|
+ .release = cfs_overlay_release,
|
|
+};
|
|
+
|
|
+static struct config_item_type cfs_overlay_type = {
|
|
+ .ct_item_ops = &cfs_overlay_item_ops,
|
|
+ .ct_attrs = cfs_overlay_attrs,
|
|
+ .ct_bin_attrs = cfs_overlay_bin_attrs,
|
|
+ .ct_owner = THIS_MODULE,
|
|
+};
|
|
+
|
|
+static struct config_item *cfs_overlay_group_make_item(
|
|
+ struct config_group *group, const char *name)
|
|
+{
|
|
+ struct cfs_overlay_item *overlay;
|
|
+
|
|
+ overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
|
|
+ if (!overlay)
|
|
+ return ERR_PTR(-ENOMEM);
|
|
+ overlay->ov_id = -1;
|
|
+
|
|
+ config_item_init_type_name(&overlay->item, name, &cfs_overlay_type);
|
|
+ return &overlay->item;
|
|
+}
|
|
+
|
|
+static void cfs_overlay_group_drop_item(struct config_group *group,
|
|
+ struct config_item *item)
|
|
+{
|
|
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
|
|
+
|
|
+ config_item_put(&overlay->item);
|
|
+}
|
|
+
|
|
+static struct configfs_group_operations overlays_ops = {
|
|
+ .make_item = cfs_overlay_group_make_item,
|
|
+ .drop_item = cfs_overlay_group_drop_item,
|
|
+};
|
|
+
|
|
+static struct config_item_type overlays_type = {
|
|
+ .ct_group_ops = &overlays_ops,
|
|
+ .ct_owner = THIS_MODULE,
|
|
+};
|
|
+
|
|
+static struct configfs_group_operations of_cfs_ops = {
|
|
+ /* empty - we don't allow anything to be created */
|
|
+};
|
|
+
|
|
+static struct config_item_type of_cfs_type = {
|
|
+ .ct_group_ops = &of_cfs_ops,
|
|
+ .ct_owner = THIS_MODULE,
|
|
+};
|
|
+
|
|
+struct config_group of_cfs_overlay_group;
|
|
+
|
|
+static struct configfs_subsystem of_cfs_subsys = {
|
|
+ .su_group = {
|
|
+ .cg_item = {
|
|
+ .ci_namebuf = "device-tree",
|
|
+ .ci_type = &of_cfs_type,
|
|
+ },
|
|
+ },
|
|
+ .su_mutex = __MUTEX_INITIALIZER(of_cfs_subsys.su_mutex),
|
|
+};
|
|
+
|
|
+static int __init of_cfs_init(void)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ pr_info("%s\n", __func__);
|
|
+
|
|
+ config_group_init(&of_cfs_subsys.su_group);
|
|
+ config_group_init_type_name(&of_cfs_overlay_group, "overlays",
|
|
+ &overlays_type);
|
|
+ configfs_add_default_group(&of_cfs_overlay_group,
|
|
+ &of_cfs_subsys.su_group);
|
|
+
|
|
+ ret = configfs_register_subsystem(&of_cfs_subsys);
|
|
+ if (ret != 0) {
|
|
+ pr_err("%s: failed to register subsys\n", __func__);
|
|
+ goto out;
|
|
+ }
|
|
+ pr_info("%s: OK\n", __func__);
|
|
+out:
|
|
+ return ret;
|
|
+}
|
|
+late_initcall(of_cfs_init);
|
|
--
|
|
Armbian
|
|
|