aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mtd/mtdpart.c116
-rw-r--r--include/linux/mtd/partitions.h1
2 files changed, 108 insertions, 9 deletions
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 85fea8ea3423..2b7bb834ff40 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -30,6 +30,7 @@
30#include <linux/mtd/mtd.h> 30#include <linux/mtd/mtd.h>
31#include <linux/mtd/partitions.h> 31#include <linux/mtd/partitions.h>
32#include <linux/err.h> 32#include <linux/err.h>
33#include <linux/of.h>
33 34
34#include "mtdcore.h" 35#include "mtdcore.h"
35 36
@@ -846,6 +847,92 @@ static int mtd_part_do_parse(struct mtd_part_parser *parser,
846} 847}
847 848
848/** 849/**
850 * mtd_part_get_compatible_parser - find MTD parser by a compatible string
851 *
852 * @compat: compatible string describing partitions in a device tree
853 *
854 * MTD parsers can specify supported partitions by providing a table of
855 * compatibility strings. This function finds a parser that advertises support
856 * for a passed value of "compatible".
857 */
858static struct mtd_part_parser *mtd_part_get_compatible_parser(const char *compat)
859{
860 struct mtd_part_parser *p, *ret = NULL;
861
862 spin_lock(&part_parser_lock);
863
864 list_for_each_entry(p, &part_parsers, list) {
865 const struct of_device_id *matches;
866
867 matches = p->of_match_table;
868 if (!matches)
869 continue;
870
871 for (; matches->compatible[0]; matches++) {
872 if (!strcmp(matches->compatible, compat) &&
873 try_module_get(p->owner)) {
874 ret = p;
875 break;
876 }
877 }
878
879 if (ret)
880 break;
881 }
882
883 spin_unlock(&part_parser_lock);
884
885 return ret;
886}
887
888static int mtd_part_of_parse(struct mtd_info *master,
889 struct mtd_partitions *pparts)
890{
891 struct mtd_part_parser *parser;
892 struct device_node *np;
893 struct property *prop;
894 const char *compat;
895 const char *fixed = "ofpart";
896 int ret, err = 0;
897
898 np = of_get_child_by_name(mtd_get_of_node(master), "partitions");
899 of_property_for_each_string(np, "compatible", prop, compat) {
900 parser = mtd_part_get_compatible_parser(compat);
901 if (!parser)
902 continue;
903 ret = mtd_part_do_parse(parser, master, pparts, NULL);
904 if (ret > 0) {
905 of_node_put(np);
906 return ret;
907 }
908 mtd_part_parser_put(parser);
909 if (ret < 0 && !err)
910 err = ret;
911 }
912 of_node_put(np);
913
914 /*
915 * For backward compatibility we have to try the "ofpart"
916 * parser. It supports old DT format with partitions specified as a
917 * direct subnodes of a flash device DT node without any compatibility
918 * specified we could match.
919 */
920 parser = mtd_part_parser_get(fixed);
921 if (!parser && !request_module("%s", fixed))
922 parser = mtd_part_parser_get(fixed);
923 if (parser) {
924 ret = mtd_part_do_parse(parser, master, pparts, NULL);
925 if (ret > 0)
926 return ret;
927 mtd_part_parser_put(parser);
928 if (ret < 0 && !err)
929 err = ret;
930 }
931
932 return err;
933}
934
935/**
849 * parse_mtd_partitions - parse MTD partitions 936 * parse_mtd_partitions - parse MTD partitions
850 * @master: the master partition (describes whole MTD device) 937 * @master: the master partition (describes whole MTD device)
851 * @types: names of partition parsers to try or %NULL 938 * @types: names of partition parsers to try or %NULL
@@ -877,19 +964,30 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
877 types = default_mtd_part_types; 964 types = default_mtd_part_types;
878 965
879 for ( ; *types; types++) { 966 for ( ; *types; types++) {
880 pr_debug("%s: parsing partitions %s\n", master->name, *types); 967 /*
881 parser = mtd_part_parser_get(*types); 968 * ofpart is a special type that means OF partitioning info
882 if (!parser && !request_module("%s", *types)) 969 * should be used. It requires a bit different logic so it is
970 * handled in a separated function.
971 */
972 if (!strcmp(*types, "ofpart")) {
973 ret = mtd_part_of_parse(master, pparts);
974 } else {
975 pr_debug("%s: parsing partitions %s\n", master->name,
976 *types);
883 parser = mtd_part_parser_get(*types); 977 parser = mtd_part_parser_get(*types);
884 pr_debug("%s: got parser %s\n", master->name, 978 if (!parser && !request_module("%s", *types))
885 parser ? parser->name : NULL); 979 parser = mtd_part_parser_get(*types);
886 if (!parser) 980 pr_debug("%s: got parser %s\n", master->name,
887 continue; 981 parser ? parser->name : NULL);
888 ret = mtd_part_do_parse(parser, master, pparts, data); 982 if (!parser)
983 continue;
984 ret = mtd_part_do_parse(parser, master, pparts, data);
985 if (ret <= 0)
986 mtd_part_parser_put(parser);
987 }
889 /* Found partitions! */ 988 /* Found partitions! */
890 if (ret > 0) 989 if (ret > 0)
891 return 0; 990 return 0;
892 mtd_part_parser_put(parser);
893 /* 991 /*
894 * Stash the first error we see; only report it if no parser 992 * Stash the first error we see; only report it if no parser
895 * succeeds 993 * succeeds
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
index c4beb70dacbd..11cb0c50cd84 100644
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -77,6 +77,7 @@ struct mtd_part_parser {
77 struct list_head list; 77 struct list_head list;
78 struct module *owner; 78 struct module *owner;
79 const char *name; 79 const char *name;
80 const struct of_device_id *of_match_table;
80 int (*parse_fn)(struct mtd_info *, const struct mtd_partition **, 81 int (*parse_fn)(struct mtd_info *, const struct mtd_partition **,
81 struct mtd_part_parser_data *); 82 struct mtd_part_parser_data *);
82 void (*cleanup)(const struct mtd_partition *pparts, int nr_parts); 83 void (*cleanup)(const struct mtd_partition *pparts, int nr_parts);