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