aboutsummaryrefslogtreecommitdiff
path: root/nixos/modules/kernel-patches/0044-mtd-mtdsplit-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/kernel-patches/0044-mtd-mtdsplit-support.patch')
-rw-r--r--nixos/modules/kernel-patches/0044-mtd-mtdsplit-support.patch340
1 files changed, 340 insertions, 0 deletions
diff --git a/nixos/modules/kernel-patches/0044-mtd-mtdsplit-support.patch b/nixos/modules/kernel-patches/0044-mtd-mtdsplit-support.patch
new file mode 100644
index 0000000..cf98c20
--- /dev/null
+++ b/nixos/modules/kernel-patches/0044-mtd-mtdsplit-support.patch
@@ -0,0 +1,340 @@
+From 3048cf485cbb35e59865e1d841bfbb06a093987a Mon Sep 17 00:00:00 2001
+From: OpenWrt community <openwrt-devel@lists.openwrt.org>
+Date: Wed, 13 Jul 2022 11:47:35 +0200
+Subject: [PATCH 44/96] mtd: mtdsplit support
+
+---
+ drivers/mtd/Kconfig | 19 ++++
+ drivers/mtd/Makefile | 2 +
+ drivers/mtd/mtdpart.c | 169 ++++++++++++++++++++++++++++-----
+ include/linux/mtd/mtd.h | 25 +++++
+ include/linux/mtd/partitions.h | 7 ++
+ 5 files changed, 197 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
+index 796a2eccbef0..f9ed93c4cf0f 100644
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -12,6 +12,25 @@ menuconfig MTD
+
+ if MTD
+
++menu "OpenWrt specific MTD options"
++
++config MTD_ROOTFS_ROOT_DEV
++ bool "Automatically set 'rootfs' partition to be root filesystem"
++ default y
++
++config MTD_SPLIT_FIRMWARE
++ bool "Automatically split firmware partition for kernel+rootfs"
++ default y
++
++config MTD_SPLIT_FIRMWARE_NAME
++ string "Firmware partition name"
++ depends on MTD_SPLIT_FIRMWARE
++ default "firmware"
++
++source "drivers/mtd/mtdsplit/Kconfig"
++
++endmenu
++
+ config MTD_TESTS
+ tristate "MTD tests support (DANGEROUS)"
+ depends on m
+diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
+index 593d0593a038..b14b7fe0f597 100644
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -9,6 +9,8 @@ mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o
+
+ obj-y += parsers/
+
++obj-$(CONFIG_MTD_SPLIT) += mtdsplit/
++
+ # 'Users' - code which presents functionality to userspace.
+ obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o
+ obj-$(CONFIG_MTD_BLOCK) += mtdblock.o
+diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
+index d442fa94c872..f1ed12aae1fe 100644
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -15,11 +15,13 @@
+ #include <linux/kmod.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
++#include <linux/magic.h>
+ #include <linux/err.h>
+ #include <linux/of.h>
+ #include <linux/of_platform.h>
+
+ #include "mtdcore.h"
++#include "mtdsplit/mtdsplit.h"
+
+ /*
+ * MTD methods which simply translate the effective address and pass through
+@@ -236,6 +238,146 @@ static int mtd_add_partition_attrs(struct mtd_info *new)
+ return ret;
+ }
+
++static DEFINE_SPINLOCK(part_parser_lock);
++static LIST_HEAD(part_parsers);
++
++static struct mtd_part_parser *mtd_part_parser_get(const char *name)
++{
++ struct mtd_part_parser *p, *ret = NULL;
++
++ spin_lock(&part_parser_lock);
++
++ list_for_each_entry(p, &part_parsers, list)
++ if (!strcmp(p->name, name) && try_module_get(p->owner)) {
++ ret = p;
++ break;
++ }
++
++ spin_unlock(&part_parser_lock);
++
++ return ret;
++}
++
++static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
++{
++ module_put(p->owner);
++}
++
++static struct mtd_part_parser *
++get_partition_parser_by_type(enum mtd_parser_type type,
++ struct mtd_part_parser *start)
++{
++ struct mtd_part_parser *p, *ret = NULL;
++
++ spin_lock(&part_parser_lock);
++
++ p = list_prepare_entry(start, &part_parsers, list);
++ if (start)
++ mtd_part_parser_put(start);
++
++ list_for_each_entry_continue(p, &part_parsers, list) {
++ if (p->type == type && try_module_get(p->owner)) {
++ ret = p;
++ break;
++ }
++ }
++
++ spin_unlock(&part_parser_lock);
++
++ return ret;
++}
++
++static int parse_mtd_partitions_by_type(struct mtd_info *master,
++ enum mtd_parser_type type,
++ const struct mtd_partition **pparts,
++ struct mtd_part_parser_data *data)
++{
++ struct mtd_part_parser *prev = NULL;
++ int ret = 0;
++
++ while (1) {
++ struct mtd_part_parser *parser;
++
++ parser = get_partition_parser_by_type(type, prev);
++ if (!parser)
++ break;
++
++ ret = (*parser->parse_fn)(master, pparts, data);
++
++ if (ret > 0) {
++ mtd_part_parser_put(parser);
++ printk(KERN_NOTICE
++ "%d %s partitions found on MTD device %s\n",
++ ret, parser->name, master->name);
++ break;
++ }
++
++ prev = parser;
++ }
++
++ return ret;
++}
++
++static int
++run_parsers_by_type(struct mtd_info *child, enum mtd_parser_type type)
++{
++ struct mtd_partition *parts;
++ int nr_parts;
++ int i;
++
++ nr_parts = parse_mtd_partitions_by_type(child, type, (const struct mtd_partition **)&parts,
++ NULL);
++ if (nr_parts <= 0)
++ return nr_parts;
++
++ if (WARN_ON(!parts))
++ return 0;
++
++ for (i = 0; i < nr_parts; i++) {
++ /* adjust partition offsets */
++ parts[i].offset += child->part.offset;
++
++ mtd_add_partition(child->parent,
++ parts[i].name,
++ parts[i].offset,
++ parts[i].size);
++ }
++
++ kfree(parts);
++
++ return nr_parts;
++}
++
++#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
++#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
++#else
++#define SPLIT_FIRMWARE_NAME "unused"
++#endif
++
++static void split_firmware(struct mtd_info *master, struct mtd_info *part)
++{
++ run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
++}
++
++static void mtd_partition_split(struct mtd_info *master, struct mtd_info *part)
++{
++ static int rootfs_found = 0;
++
++ if (rootfs_found)
++ return;
++
++ if (!strcmp(part->name, "rootfs")) {
++ run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
++
++ rootfs_found = 1;
++ }
++
++ if (IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE) &&
++ !strcmp(part->name, SPLIT_FIRMWARE_NAME) &&
++ !of_find_property(mtd_get_of_node(part), "compatible", NULL))
++ split_firmware(master, part);
++}
++
+ int mtd_add_partition(struct mtd_info *parent, const char *name,
+ long long offset, long long length)
+ {
+@@ -274,6 +416,7 @@ int mtd_add_partition(struct mtd_info *parent, const char *name,
+ if (ret)
+ goto err_remove_part;
+
++ mtd_partition_split(parent, child);
+ mtd_add_partition_attrs(child);
+
+ return 0;
+@@ -422,6 +565,7 @@ int add_mtd_partitions(struct mtd_info *parent,
+ goto err_del_partitions;
+ }
+
++ mtd_partition_split(master, child);
+ mtd_add_partition_attrs(child);
+
+ /* Look for subpartitions */
+@@ -438,31 +582,6 @@ int add_mtd_partitions(struct mtd_info *parent,
+ return ret;
+ }
+
+-static DEFINE_SPINLOCK(part_parser_lock);
+-static LIST_HEAD(part_parsers);
+-
+-static struct mtd_part_parser *mtd_part_parser_get(const char *name)
+-{
+- struct mtd_part_parser *p, *ret = NULL;
+-
+- spin_lock(&part_parser_lock);
+-
+- list_for_each_entry(p, &part_parsers, list)
+- if (!strcmp(p->name, name) && try_module_get(p->owner)) {
+- ret = p;
+- break;
+- }
+-
+- spin_unlock(&part_parser_lock);
+-
+- return ret;
+-}
+-
+-static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
+-{
+- module_put(p->owner);
+-}
+-
+ /*
+ * Many partition parsers just expected the core to kfree() all their data in
+ * one chunk. Do that by default.
+diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
+index 955aee14b0f7..e2359a3569f0 100644
+--- a/include/linux/mtd/mtd.h
++++ b/include/linux/mtd/mtd.h
+@@ -608,6 +608,24 @@ static inline void mtd_align_erase_req(struct mtd_info *mtd,
+ req->len += mtd->erasesize - mod;
+ }
+
++static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd)
++{
++ if (mtd_mod_by_eb(sz, mtd) == 0)
++ return sz;
++
++ /* Round up to next erase block */
++ return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize;
++}
++
++static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd)
++{
++ if (mtd_mod_by_eb(sz, mtd) == 0)
++ return sz;
++
++ /* Round down to the start of the current erase block */
++ return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize;
++}
++
+ static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd)
+ {
+ if (mtd->writesize_shift)
+@@ -680,6 +698,13 @@ extern void __put_mtd_device(struct mtd_info *mtd);
+ extern struct mtd_info *get_mtd_device_nm(const char *name);
+ extern void put_mtd_device(struct mtd_info *mtd);
+
++static inline uint64_t mtdpart_get_offset(const struct mtd_info *mtd)
++{
++ if (!mtd_is_partition(mtd))
++ return 0;
++
++ return mtd->part.offset;
++}
+
+ struct mtd_notifier {
+ void (*add)(struct mtd_info *mtd);
+diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
+index b74a539ec581..65ba0dbf961d 100644
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -75,6 +75,12 @@ struct mtd_part_parser_data {
+ * Functions dealing with the various ways of partitioning the space
+ */
+
++enum mtd_parser_type {
++ MTD_PARSER_TYPE_DEVICE = 0,
++ MTD_PARSER_TYPE_ROOTFS,
++ MTD_PARSER_TYPE_FIRMWARE,
++};
++
+ struct mtd_part_parser {
+ struct list_head list;
+ struct module *owner;
+@@ -83,6 +89,7 @@ struct mtd_part_parser {
+ int (*parse_fn)(struct mtd_info *, const struct mtd_partition **,
+ struct mtd_part_parser_data *);
+ void (*cleanup)(const struct mtd_partition *pparts, int nr_parts);
++ enum mtd_parser_type type;
+ };
+
+ /* Container for passing around a set of parsed partitions */
+--
+2.37.2
+