1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
|
From 5b644aa012f67fd211138a067b9f351f30bdcc60 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Wed, 14 Mar 2018 13:10:42 +0100
Subject: [PATCH] mtd: partitions: add of_match_table parser matching for the
"ofpart" type
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
In order to properly support compatibility strings as described in the
bindings/mtd/partition.txt "ofpart" type should be treated as an
indication for looking into OF. MTD should check "compatible" property
and search for a matching parser rather than blindly trying the one
supporting "fixed-partitions".
It also means that existing "fixed-partitions" parser should get renamed
to use a more meaningful name.
This commit achievies that aim by introducing a new mtd_part_of_parse().
It works by looking for a matching parser for every string in the
"compatibility" property (starting with the most specific one).
Please note that driver-specified parsers still take a precedence. It's
assumed that driver providing a parser type has a good reason for that
(e.g. having platform data with device-specific info). Also doing
otherwise could break existing setups. The same applies to using default
parsers (including "cmdlinepart") as some overwrite DT data with cmdline
argument.
Partition parsers can now provide an of_match_table to enable
flash<-->parser matching via device tree as documented in the
mtd/partition.txt.
This support is currently limited to built-in parsers as it uses
request_module() and friends. This should be sufficient for most cases
though as compiling parsers as modules isn't a common choice.
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Tested-by: Peter Rosin <peda@axentia.se>
Reviewed-by: Richard Weinberger <richard@nod.at>
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
---
drivers/mtd/mtdpart.c | 116 +++++++++++++++++++++++++++++++++++++----
include/linux/mtd/partitions.h | 1 +
2 files changed, 108 insertions(+), 9 deletions(-)
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -30,6 +30,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/err.h>
+#include <linux/of.h>
#include "mtdcore.h"
@@ -919,6 +920,92 @@ static int mtd_part_do_parse(struct mtd_
}
/**
+ * mtd_part_get_compatible_parser - find MTD parser by a compatible string
+ *
+ * @compat: compatible string describing partitions in a device tree
+ *
+ * MTD parsers can specify supported partitions by providing a table of
+ * compatibility strings. This function finds a parser that advertises support
+ * for a passed value of "compatible".
+ */
+static struct mtd_part_parser *mtd_part_get_compatible_parser(const char *compat)
+{
+ struct mtd_part_parser *p, *ret = NULL;
+
+ spin_lock(&part_parser_lock);
+
+ list_for_each_entry(p, &part_parsers, list) {
+ const struct of_device_id *matches;
+
+ matches = p->of_match_table;
+ if (!matches)
+ continue;
+
+ for (; matches->compatible[0]; matches++) {
+ if (!strcmp(matches->compatible, compat) &&
+ try_module_get(p->owner)) {
+ ret = p;
+ break;
+ }
+ }
+
+ if (ret)
+ break;
+ }
+
+ spin_unlock(&part_parser_lock);
+
+ return ret;
+}
+
+static int mtd_part_of_parse(struct mtd_info *master,
+ struct mtd_partitions *pparts)
+{
+ struct mtd_part_parser *parser;
+ struct device_node *np;
+ struct property *prop;
+ const char *compat;
+ const char *fixed = "ofpart";
+ int ret, err = 0;
+
+ np = of_get_child_by_name(mtd_get_of_node(master), "partitions");
+ of_property_for_each_string(np, "compatible", prop, compat) {
+ parser = mtd_part_get_compatible_parser(compat);
+ if (!parser)
+ continue;
+ ret = mtd_part_do_parse(parser, master, pparts, NULL);
+ if (ret > 0) {
+ of_node_put(np);
+ return ret;
+ }
+ mtd_part_parser_put(parser);
+ if (ret < 0 && !err)
+ err = ret;
+ }
+ of_node_put(np);
+
+ /*
+ * For backward compatibility we have to try the "ofpart"
+ * parser. It supports old DT format with partitions specified as a
+ * direct subnodes of a flash device DT node without any compatibility
+ * specified we could match.
+ */
+ parser = mtd_part_parser_get(fixed);
+ if (!parser && !request_module("%s", fixed))
+ parser = mtd_part_parser_get(fixed);
+ if (parser) {
+ ret = mtd_part_do_parse(parser, master, pparts, NULL);
+ if (ret > 0)
+ return ret;
+ mtd_part_parser_put(parser);
+ if (ret < 0 && !err)
+ err = ret;
+ }
+
+ return err;
+}
+
+/**
* parse_mtd_partitions - parse MTD partitions
* @master: the master partition (describes whole MTD device)
* @types: names of partition parsers to try or %NULL
@@ -950,19 +1037,30 @@ int parse_mtd_partitions(struct mtd_info
types = default_mtd_part_types;
for ( ; *types; types++) {
- pr_debug("%s: parsing partitions %s\n", master->name, *types);
- parser = mtd_part_parser_get(*types);
- if (!parser && !request_module("%s", *types))
+ /*
+ * ofpart is a special type that means OF partitioning info
+ * should be used. It requires a bit different logic so it is
+ * handled in a separated function.
+ */
+ if (!strcmp(*types, "ofpart")) {
+ ret = mtd_part_of_parse(master, pparts);
+ } else {
+ pr_debug("%s: parsing partitions %s\n", master->name,
+ *types);
parser = mtd_part_parser_get(*types);
- pr_debug("%s: got parser %s\n", master->name,
- parser ? parser->name : NULL);
- if (!parser)
- continue;
- ret = mtd_part_do_parse(parser, master, pparts, data);
+ if (!parser && !request_module("%s", *types))
+ parser = mtd_part_parser_get(*types);
+ pr_debug("%s: got parser %s\n", master->name,
+ parser ? parser->name : NULL);
+ if (!parser)
+ continue;
+ ret = mtd_part_do_parse(parser, master, pparts, data);
+ if (ret <= 0)
+ mtd_part_parser_put(parser);
+ }
/* Found partitions! */
if (ret > 0)
return 0;
- mtd_part_parser_put(parser);
/*
* Stash the first error we see; only report it if no parser
* succeeds
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -77,6 +77,7 @@ struct mtd_part_parser {
struct list_head list;
struct module *owner;
const char *name;
+ const struct of_device_id *of_match_table;
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);
|