Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.20-rc2 240 lines 5.9 kB view raw
1/* 2 * Flash partitions described by the OF (or flattened) device tree 3 * 4 * Copyright © 2006 MontaVista Software Inc. 5 * Author: Vitaly Wool <vwool@ru.mvista.com> 6 * 7 * Revised to handle newer style flash binding by: 8 * Copyright © 2007 David Gibson, IBM Corporation. 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the 12 * Free Software Foundation; either version 2 of the License, or (at your 13 * option) any later version. 14 */ 15 16#include <linux/module.h> 17#include <linux/init.h> 18#include <linux/of.h> 19#include <linux/mtd/mtd.h> 20#include <linux/slab.h> 21#include <linux/mtd/partitions.h> 22 23static bool node_has_compatible(struct device_node *pp) 24{ 25 return of_get_property(pp, "compatible", NULL); 26} 27 28static int parse_fixed_partitions(struct mtd_info *master, 29 const struct mtd_partition **pparts, 30 struct mtd_part_parser_data *data) 31{ 32 struct mtd_partition *parts; 33 struct device_node *mtd_node; 34 struct device_node *ofpart_node; 35 const char *partname; 36 struct device_node *pp; 37 int nr_parts, i, ret = 0; 38 bool dedicated = true; 39 40 41 /* Pull of_node from the master device node */ 42 mtd_node = mtd_get_of_node(master); 43 if (!mtd_node) 44 return 0; 45 46 ofpart_node = of_get_child_by_name(mtd_node, "partitions"); 47 if (!ofpart_node) { 48 /* 49 * We might get here even when ofpart isn't used at all (e.g., 50 * when using another parser), so don't be louder than 51 * KERN_DEBUG 52 */ 53 pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n", 54 master->name, mtd_node); 55 ofpart_node = mtd_node; 56 dedicated = false; 57 } else if (!of_device_is_compatible(ofpart_node, "fixed-partitions")) { 58 /* The 'partitions' subnode might be used by another parser */ 59 return 0; 60 } 61 62 /* First count the subnodes */ 63 nr_parts = 0; 64 for_each_child_of_node(ofpart_node, pp) { 65 if (!dedicated && node_has_compatible(pp)) 66 continue; 67 68 nr_parts++; 69 } 70 71 if (nr_parts == 0) 72 return 0; 73 74 parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); 75 if (!parts) 76 return -ENOMEM; 77 78 i = 0; 79 for_each_child_of_node(ofpart_node, pp) { 80 const __be32 *reg; 81 int len; 82 int a_cells, s_cells; 83 84 if (!dedicated && node_has_compatible(pp)) 85 continue; 86 87 reg = of_get_property(pp, "reg", &len); 88 if (!reg) { 89 if (dedicated) { 90 pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n", 91 master->name, pp, 92 mtd_node); 93 goto ofpart_fail; 94 } else { 95 nr_parts--; 96 continue; 97 } 98 } 99 100 a_cells = of_n_addr_cells(pp); 101 s_cells = of_n_size_cells(pp); 102 if (len / 4 != a_cells + s_cells) { 103 pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n", 104 master->name, pp, 105 mtd_node); 106 goto ofpart_fail; 107 } 108 109 parts[i].offset = of_read_number(reg, a_cells); 110 parts[i].size = of_read_number(reg + a_cells, s_cells); 111 parts[i].of_node = pp; 112 113 partname = of_get_property(pp, "label", &len); 114 if (!partname) 115 partname = of_get_property(pp, "name", &len); 116 parts[i].name = partname; 117 118 if (of_get_property(pp, "read-only", &len)) 119 parts[i].mask_flags |= MTD_WRITEABLE; 120 121 if (of_get_property(pp, "lock", &len)) 122 parts[i].mask_flags |= MTD_POWERUP_LOCK; 123 124 i++; 125 } 126 127 if (!nr_parts) 128 goto ofpart_none; 129 130 *pparts = parts; 131 return nr_parts; 132 133ofpart_fail: 134 pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n", 135 master->name, pp, mtd_node); 136 ret = -EINVAL; 137ofpart_none: 138 of_node_put(pp); 139 kfree(parts); 140 return ret; 141} 142 143static const struct of_device_id parse_ofpart_match_table[] = { 144 { .compatible = "fixed-partitions" }, 145 {}, 146}; 147MODULE_DEVICE_TABLE(of, parse_ofpart_match_table); 148 149static struct mtd_part_parser ofpart_parser = { 150 .parse_fn = parse_fixed_partitions, 151 .name = "fixed-partitions", 152 .of_match_table = parse_ofpart_match_table, 153}; 154 155static int parse_ofoldpart_partitions(struct mtd_info *master, 156 const struct mtd_partition **pparts, 157 struct mtd_part_parser_data *data) 158{ 159 struct mtd_partition *parts; 160 struct device_node *dp; 161 int i, plen, nr_parts; 162 const struct { 163 __be32 offset, len; 164 } *part; 165 const char *names; 166 167 /* Pull of_node from the master device node */ 168 dp = mtd_get_of_node(master); 169 if (!dp) 170 return 0; 171 172 part = of_get_property(dp, "partitions", &plen); 173 if (!part) 174 return 0; /* No partitions found */ 175 176 pr_warn("Device tree uses obsolete partition map binding: %pOF\n", dp); 177 178 nr_parts = plen / sizeof(part[0]); 179 180 parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); 181 if (!parts) 182 return -ENOMEM; 183 184 names = of_get_property(dp, "partition-names", &plen); 185 186 for (i = 0; i < nr_parts; i++) { 187 parts[i].offset = be32_to_cpu(part->offset); 188 parts[i].size = be32_to_cpu(part->len) & ~1; 189 /* bit 0 set signifies read only partition */ 190 if (be32_to_cpu(part->len) & 1) 191 parts[i].mask_flags = MTD_WRITEABLE; 192 193 if (names && (plen > 0)) { 194 int len = strlen(names) + 1; 195 196 parts[i].name = names; 197 plen -= len; 198 names += len; 199 } else { 200 parts[i].name = "unnamed"; 201 } 202 203 part++; 204 } 205 206 *pparts = parts; 207 return nr_parts; 208} 209 210static struct mtd_part_parser ofoldpart_parser = { 211 .parse_fn = parse_ofoldpart_partitions, 212 .name = "ofoldpart", 213}; 214 215static int __init ofpart_parser_init(void) 216{ 217 register_mtd_parser(&ofpart_parser); 218 register_mtd_parser(&ofoldpart_parser); 219 return 0; 220} 221 222static void __exit ofpart_parser_exit(void) 223{ 224 deregister_mtd_parser(&ofpart_parser); 225 deregister_mtd_parser(&ofoldpart_parser); 226} 227 228module_init(ofpart_parser_init); 229module_exit(ofpart_parser_exit); 230 231MODULE_LICENSE("GPL"); 232MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree"); 233MODULE_AUTHOR("Vitaly Wool, David Gibson"); 234/* 235 * When MTD core cannot find the requested parser, it tries to load the module 236 * with the same name. Since we provide the ofoldpart parser, we should have 237 * the corresponding alias. 238 */ 239MODULE_ALIAS("fixed-partitions"); 240MODULE_ALIAS("ofoldpart");