d260be168cd5bd91e761f9ec5ab241e4f54d50b1
[openwrt/staging/wigyori.git] /
1 From 884555b557e5e6d41c866e2cd8d7b32f50ec974b Mon Sep 17 00:00:00 2001
2 From: Christian Marangi <ansuelsmth@gmail.com>
3 Date: Thu, 3 Oct 2024 00:11:45 +0200
4 Subject: [PATCH 5/5] block: add support for partition table defined in OF
5
6 Add support for partition table defined in Device Tree. Similar to how
7 it's done with MTD, add support for defining a fixed partition table in
8 device tree.
9
10 A common scenario for this is fixed block (eMMC) embedded devices that
11 have no MBR or GPT partition table to save storage space. Bootloader
12 access the block device with absolute address of data.
13
14 This is to complete the functionality with an equivalent implementation
15 with providing partition table with bootargs, for case where the booargs
16 can't be modified and tweaking the Device Tree is the only solution to
17 have an usabe partition table.
18
19 The implementation follow the fixed-partitions parser used on MTD
20 devices where a "partitions" node is expected to be declared with
21 "fixed-partitions" compatible in the OF node of the disk device
22 (mmc-card for eMMC for example) and each child node declare a label
23 and a reg with offset and size. If label is not declared, the node name
24 is used as fallback. Eventually is also possible to declare the read-only
25 property to flag the partition as read-only.
26
27 Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
28 Reviewed-by: Christoph Hellwig <hch@lst.de>
29 Link: https://lore.kernel.org/r/20241002221306.4403-6-ansuelsmth@gmail.com
30 Signed-off-by: Jens Axboe <axboe@kernel.dk>
31 ---
32 block/partitions/Kconfig | 9 ++++
33 block/partitions/Makefile | 1 +
34 block/partitions/check.h | 1 +
35 block/partitions/core.c | 3 ++
36 block/partitions/of.c | 110 ++++++++++++++++++++++++++++++++++++++
37 5 files changed, 124 insertions(+)
38 create mode 100644 block/partitions/of.c
39
40 --- a/block/partitions/Kconfig
41 +++ b/block/partitions/Kconfig
42 @@ -270,4 +270,13 @@ config CMDLINE_PARTITION
43 Say Y here if you want to read the partition table from bootargs.
44 The format for the command line is just like mtdparts.
45
46 +config OF_PARTITION
47 + bool "Device Tree partition support" if PARTITION_ADVANCED
48 + depends on OF
49 + help
50 + Say Y here if you want to enable support for partition table
51 + defined in Device Tree. (mainly for eMMC)
52 + The format for the device tree node is just like MTD fixed-partition
53 + schema.
54 +
55 endmenu
56 --- a/block/partitions/Makefile
57 +++ b/block/partitions/Makefile
58 @@ -12,6 +12,7 @@ obj-$(CONFIG_CMDLINE_PARTITION) += cmdli
59 obj-$(CONFIG_MAC_PARTITION) += mac.o
60 obj-$(CONFIG_LDM_PARTITION) += ldm.o
61 obj-$(CONFIG_MSDOS_PARTITION) += msdos.o
62 +obj-$(CONFIG_OF_PARTITION) += of.o
63 obj-$(CONFIG_OSF_PARTITION) += osf.o
64 obj-$(CONFIG_SGI_PARTITION) += sgi.o
65 obj-$(CONFIG_SUN_PARTITION) += sun.o
66 --- a/block/partitions/check.h
67 +++ b/block/partitions/check.h
68 @@ -62,6 +62,7 @@ int karma_partition(struct parsed_partit
69 int ldm_partition(struct parsed_partitions *state);
70 int mac_partition(struct parsed_partitions *state);
71 int msdos_partition(struct parsed_partitions *state);
72 +int of_partition(struct parsed_partitions *state);
73 int osf_partition(struct parsed_partitions *state);
74 int sgi_partition(struct parsed_partitions *state);
75 int sun_partition(struct parsed_partitions *state);
76 --- a/block/partitions/core.c
77 +++ b/block/partitions/core.c
78 @@ -43,6 +43,9 @@ static int (*const check_part[])(struct
79 #ifdef CONFIG_CMDLINE_PARTITION
80 cmdline_partition,
81 #endif
82 +#ifdef CONFIG_OF_PARTITION
83 + of_partition, /* cmdline have priority to OF */
84 +#endif
85 #ifdef CONFIG_EFI_PARTITION
86 efi_partition, /* this must come before msdos */
87 #endif
88 --- /dev/null
89 +++ b/block/partitions/of.c
90 @@ -0,0 +1,110 @@
91 +// SPDX-License-Identifier: GPL-2.0
92 +
93 +#include <linux/blkdev.h>
94 +#include <linux/major.h>
95 +#include <linux/of.h>
96 +#include <linux/string.h>
97 +#include "check.h"
98 +
99 +static int validate_of_partition(struct device_node *np, int slot)
100 +{
101 + u64 offset, size;
102 + int len;
103 +
104 + const __be32 *reg = of_get_property(np, "reg", &len);
105 + int a_cells = of_n_addr_cells(np);
106 + int s_cells = of_n_size_cells(np);
107 +
108 + /* Make sure reg len match the expected addr and size cells */
109 + if (len / sizeof(*reg) != a_cells + s_cells)
110 + return -EINVAL;
111 +
112 + /* Validate offset conversion from bytes to sectors */
113 + offset = of_read_number(reg, a_cells);
114 + if (offset % SECTOR_SIZE)
115 + return -EINVAL;
116 +
117 + /* Validate size conversion from bytes to sectors */
118 + size = of_read_number(reg + a_cells, s_cells);
119 + if (!size || size % SECTOR_SIZE)
120 + return -EINVAL;
121 +
122 + return 0;
123 +}
124 +
125 +static void add_of_partition(struct parsed_partitions *state, int slot,
126 + struct device_node *np)
127 +{
128 + struct partition_meta_info *info;
129 + char tmp[sizeof(info->volname) + 4];
130 + const char *partname;
131 + int len;
132 +
133 + const __be32 *reg = of_get_property(np, "reg", &len);
134 + int a_cells = of_n_addr_cells(np);
135 + int s_cells = of_n_size_cells(np);
136 +
137 + /* Convert bytes to sector size */
138 + u64 offset = of_read_number(reg, a_cells) / SECTOR_SIZE;
139 + u64 size = of_read_number(reg + a_cells, s_cells) / SECTOR_SIZE;
140 +
141 + put_partition(state, slot, offset, size);
142 +
143 + if (of_property_read_bool(np, "read-only"))
144 + state->parts[slot].flags |= ADDPART_FLAG_READONLY;
145 +
146 + /*
147 + * Follow MTD label logic, search for label property,
148 + * fallback to node name if not found.
149 + */
150 + info = &state->parts[slot].info;
151 + partname = of_get_property(np, "label", &len);
152 + if (!partname)
153 + partname = of_get_property(np, "name", &len);
154 + strscpy(info->volname, partname, sizeof(info->volname));
155 +
156 + snprintf(tmp, sizeof(tmp), "(%s)", info->volname);
157 + strlcat(state->pp_buf, tmp, PAGE_SIZE);
158 +}
159 +
160 +int of_partition(struct parsed_partitions *state)
161 +{
162 + struct device *ddev = disk_to_dev(state->disk);
163 + struct device_node *np;
164 + int slot;
165 +
166 + struct device_node *partitions_np = of_node_get(ddev->of_node);
167 +
168 + if (!partitions_np ||
169 + !of_device_is_compatible(partitions_np, "fixed-partitions"))
170 + return 0;
171 +
172 + slot = 1;
173 + /* Validate parition offset and size */
174 + for_each_child_of_node(partitions_np, np) {
175 + if (validate_of_partition(np, slot)) {
176 + of_node_put(np);
177 + of_node_put(partitions_np);
178 +
179 + return -1;
180 + }
181 +
182 + slot++;
183 + }
184 +
185 + slot = 1;
186 + for_each_child_of_node(partitions_np, np) {
187 + if (slot >= state->limit) {
188 + of_node_put(np);
189 + break;
190 + }
191 +
192 + add_of_partition(state, slot, np);
193 +
194 + slot++;
195 + }
196 +
197 + strlcat(state->pp_buf, "\n", PAGE_SIZE);
198 +
199 + return 1;
200 +}