|
@@ -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"
|
|
|
|
|
@@ -845,6 +846,92 @@ static int mtd_part_do_parse(struct mtd_part_parser *parser,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * 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)
|
|
@@ -877,19 +964,30 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
|
|
|
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
|