FILE
ofpart_core.c
File preview with syntax highlighting.
linux-6.19.14/drivers/mtd/parsers/ofpart_core.c
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Flash partitions described by the OF (or flattened) device tree 4 * 5 * Copyright © 2006 MontaVista Software Inc. 6 * Author: Vitaly Wool <vwool@ru.mvista.com> 7 * 8 * Revised to handle newer style flash binding by: 9 * Copyright © 2007 David Gibson, IBM Corporation. 10 */ 11 12#include <linux/module.h> 13#include <linux/init.h> 14#include <linux/of.h> 15#include <linux/mtd/mtd.h> 16#include <linux/slab.h> 17#include <linux/mtd/partitions.h> 18 19#include "ofpart_bcm4908.h" 20#include "ofpart_linksys_ns.h" 21 22struct fixed_partitions_quirks { 23 int (*post_parse)(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts); 24}; 25 26static struct fixed_partitions_quirks bcm4908_partitions_quirks = { 27 .post_parse = bcm4908_partitions_post_parse, 28}; 29 30static struct fixed_partitions_quirks linksys_ns_partitions_quirks = { 31 .post_parse = linksys_ns_partitions_post_parse, 32}; 33 34static const struct of_device_id parse_ofpart_match_table[]; 35 36static bool node_has_compatible(struct device_node *pp) 37{ 38 return of_get_property(pp, "compatible", NULL); 39} 40 41static int parse_fixed_partitions(struct mtd_info *master, 42 const struct mtd_partition **pparts, 43 struct mtd_part_parser_data *data) 44{ 45 const struct fixed_partitions_quirks *quirks; 46 const struct of_device_id *of_id; 47 struct mtd_partition *parts; 48 struct device_node *mtd_node; 49 struct device_node *ofpart_node; 50 const char *partname; 51 struct device_node *pp; 52 int nr_parts, i, ret = 0; 53 bool dedicated = true; 54 55 /* Pull of_node from the master device node */ 56 mtd_node = mtd_get_of_node(master); 57 if (!mtd_node) 58 return 0; 59 60 if (!master->parent) { /* Master */ 61 ofpart_node = of_get_child_by_name(mtd_node, "partitions"); 62 if (!ofpart_node) { 63 /* 64 * We might get here even when ofpart isn't used at all (e.g., 65 * when using another parser), so don't be louder than 66 * KERN_DEBUG 67 */ 68 pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n", 69 master->name, mtd_node); 70 ofpart_node = mtd_node; 71 dedicated = false; 72 } 73 } else { /* Partition */ 74 ofpart_node = mtd_node; 75 } 76 77 of_id = of_match_node(parse_ofpart_match_table, ofpart_node); 78 if (dedicated && !of_id) { 79 /* The 'partitions' subnode might be used by another parser */ 80 of_node_put(ofpart_node); 81 return 0; 82 } 83 84 quirks = of_id ? of_id->data : NULL; 85 86 /* First count the subnodes */ 87 nr_parts = 0; 88 for_each_child_of_node(ofpart_node, pp) { 89 if (!dedicated && node_has_compatible(pp)) 90 continue; 91 92 nr_parts++; 93 } 94 95 if (nr_parts == 0) { 96 if (dedicated) 97 of_node_put(ofpart_node); 98 return 0; 99 } 100 101 parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); 102 if (!parts) { 103 if (dedicated) 104 of_node_put(ofpart_node); 105 return -ENOMEM; 106 } 107 108 i = 0; 109 for_each_child_of_node(ofpart_node, pp) { 110 const __be32 *reg; 111 int len; 112 int a_cells, s_cells; 113 114 if (!dedicated && node_has_compatible(pp)) 115 continue; 116 117 reg = of_get_property(pp, "reg", &len); 118 if (!reg) { 119 if (dedicated) { 120 pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n", 121 master->name, pp, 122 mtd_node); 123 goto ofpart_fail; 124 } else { 125 nr_parts--; 126 continue; 127 } 128 } 129 130 a_cells = of_n_addr_cells(pp); 131 s_cells = of_n_size_cells(pp); 132 if (!dedicated && s_cells == 0) { 133 /* 134 * This is a ugly workaround to not create 135 * regression on devices that are still creating 136 * partitions as direct children of the nand controller. 137 * This can happen in case the nand controller node has 138 * #size-cells equal to 0 and the firmware (e.g. 139 * U-Boot) just add the partitions there assuming 140 * 32-bit addressing. 141 * 142 * If you get this warning your firmware and/or DTS 143 * should be really fixed. 144 * 145 * This is working only for devices smaller than 4GiB. 146 */ 147 pr_warn("%s: ofpart partition %pOF (%pOF) #size-cells is wrongly set to <0>, assuming <1> for parsing partitions.\n", 148 master->name, pp, mtd_node); 149 s_cells = 1; 150 } 151 if (len / 4 != a_cells + s_cells) { 152 pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n", 153 master->name, pp, 154 mtd_node); 155 goto ofpart_fail; 156 } 157 158 parts[i].offset = of_read_number(reg, a_cells); 159 parts[i].size = of_read_number(reg + a_cells, s_cells); 160 parts[i].of_node = pp; 161 162 partname = of_get_property(pp, "label", &len); 163 if (!partname) 164 partname = of_get_property(pp, "name", &len); 165 parts[i].name = partname; 166 167 if (of_property_read_bool(pp, "read-only")) 168 parts[i].mask_flags |= MTD_WRITEABLE; 169 170 if (of_property_read_bool(pp, "lock")) 171 parts[i].mask_flags |= MTD_POWERUP_LOCK; 172 173 if (of_property_read_bool(pp, "slc-mode")) 174 parts[i].add_flags |= MTD_SLC_ON_MLC_EMULATION; 175 176 i++; 177 } 178 179 if (!nr_parts) 180 goto ofpart_none; 181 182 if (quirks && quirks->post_parse) 183 quirks->post_parse(master, parts, nr_parts); 184 185 if (dedicated) 186 of_node_put(ofpart_node); 187 188 *pparts = parts; 189 return nr_parts; 190 191ofpart_fail: 192 pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n", 193 master->name, pp, mtd_node); 194 ret = -EINVAL; 195ofpart_none: 196 if (dedicated) 197 of_node_put(ofpart_node); 198 of_node_put(pp); 199 kfree(parts); 200 return ret; 201} 202 203static const struct of_device_id parse_ofpart_match_table[] = { 204 /* Generic */ 205 { .compatible = "fixed-partitions" }, 206 /* Customized */ 207 { .compatible = "brcm,bcm4908-partitions", .data = &bcm4908_partitions_quirks, }, 208 { .compatible = "linksys,ns-partitions", .data = &linksys_ns_partitions_quirks, }, 209 {}, 210}; 211MODULE_DEVICE_TABLE(of, parse_ofpart_match_table); 212 213static struct mtd_part_parser ofpart_parser = { 214 .parse_fn = parse_fixed_partitions, 215 .name = "fixed-partitions", 216 .of_match_table = parse_ofpart_match_table, 217}; 218 219static int parse_ofoldpart_partitions(struct mtd_info *master, 220 const struct mtd_partition **pparts, 221 struct mtd_part_parser_data *data) 222{ 223 struct mtd_partition *parts; 224 struct device_node *dp; 225 int i, plen, nr_parts; 226 const struct { 227 __be32 offset, len; 228 } *part; 229 const char *names; 230 231 /* Pull of_node from the master device node */ 232 dp = mtd_get_of_node(master); 233 if (!dp) 234 return 0; 235 236 part = of_get_property(dp, "partitions", &plen); 237 if (!part) 238 return 0; /* No partitions found */ 239 240 pr_warn("Device tree uses obsolete partition map binding: %pOF\n", dp); 241 242 nr_parts = plen / sizeof(part[0]); 243 244 parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); 245 if (!parts) 246 return -ENOMEM; 247 248 names = of_get_property(dp, "partition-names", &plen); 249 250 for (i = 0; i < nr_parts; i++) { 251 parts[i].offset = be32_to_cpu(part->offset); 252 parts[i].size = be32_to_cpu(part->len) & ~1; 253 /* bit 0 set signifies read only partition */ 254 if (be32_to_cpu(part->len) & 1) 255 parts[i].mask_flags = MTD_WRITEABLE; 256 257 if (names && (plen > 0)) { 258 int len = strlen(names) + 1; 259 260 parts[i].name = names; 261 plen -= len; 262 names += len; 263 } else { 264 parts[i].name = "unnamed"; 265 } 266 267 part++; 268 } 269 270 *pparts = parts; 271 return nr_parts; 272} 273 274static struct mtd_part_parser ofoldpart_parser = { 275 .parse_fn = parse_ofoldpart_partitions, 276 .name = "ofoldpart", 277}; 278 279static int __init ofpart_parser_init(void) 280{ 281 register_mtd_parser(&ofpart_parser); 282 register_mtd_parser(&ofoldpart_parser); 283 return 0; 284} 285 286static void __exit ofpart_parser_exit(void) 287{ 288 deregister_mtd_parser(&ofpart_parser); 289 deregister_mtd_parser(&ofoldpart_parser); 290} 291 292module_init(ofpart_parser_init); 293module_exit(ofpart_parser_exit); 294 295MODULE_LICENSE("GPL"); 296MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree"); 297MODULE_AUTHOR("Vitaly Wool, David Gibson"); 298/* 299 * When MTD core cannot find the requested parser, it tries to load the module 300 * with the same name. Since we provide the ofoldpart parser, we should have 301 * the corresponding alias. 302 */ 303MODULE_ALIAS("fixed-partitions"); 304MODULE_ALIAS("ofoldpart");
~/
Read-only file preview.