^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Simple MTD partitioning layer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright © 2000 Nicolas Pitre <nico@fluxnic.net>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright © 2002 Thomas Gleixner <gleixner@linutronix.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright © 2000-2010 David Woodhouse <dwmw2@infradead.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/kmod.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/mtd/mtd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/mtd/partitions.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include "mtdcore.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * MTD methods which simply translate the effective address and pass through
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * to the _real_ device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static inline void free_partition(struct mtd_info *mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) kfree(mtd->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) kfree(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static struct mtd_info *allocate_partition(struct mtd_info *parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) const struct mtd_partition *part,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) int partno, uint64_t cur_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct mtd_info *master = mtd_get_master(parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) int wr_alignment = (parent->flags & MTD_NO_ERASE) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) master->writesize : master->erasesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) u64 parent_size = mtd_is_partition(parent) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) parent->part.size : parent->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct mtd_info *child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) u32 remainder;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) u64 tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) /* allocate the partition structure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) child = kzalloc(sizeof(*child), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) name = kstrdup(part->name, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if (!name || !child) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) parent->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) kfree(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) kfree(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /* set up the MTD object for this partition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) child->type = parent->type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) child->part.flags = parent->flags & ~part->mask_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) child->part.flags |= part->add_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) child->flags = child->part.flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) child->part.size = part->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) child->writesize = parent->writesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) child->writebufsize = parent->writebufsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) child->oobsize = parent->oobsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) child->oobavail = parent->oobavail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) child->subpage_sft = parent->subpage_sft;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) child->name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) child->owner = parent->owner;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) /* NOTE: Historically, we didn't arrange MTDs as a tree out of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * concern for showing the same data in multiple partitions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * However, it is very useful to have the master node present,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * so the MTD_PARTITIONED_MASTER option allows that. The master
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * will have device nodes etc only if this is set, so make the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * parent conditional on that option. Note, this is a way to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * distinguish between the parent and its partitions in sysfs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) child->dev.parent = IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) || mtd_is_partition(parent) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) &parent->dev : parent->dev.parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) child->dev.of_node = part->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) child->parent = parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) child->part.offset = part->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) INIT_LIST_HEAD(&child->partitions);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (child->part.offset == MTDPART_OFS_APPEND)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) child->part.offset = cur_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (child->part.offset == MTDPART_OFS_NXTBLK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) tmp = cur_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) child->part.offset = cur_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) remainder = do_div(tmp, wr_alignment);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (remainder) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) child->part.offset += wr_alignment - remainder;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) printk(KERN_NOTICE "Moving partition %d: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) "0x%012llx -> 0x%012llx\n", partno,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) (unsigned long long)cur_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) child->part.offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (child->part.offset == MTDPART_OFS_RETAIN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) child->part.offset = cur_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if (parent_size - child->part.offset >= child->part.size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) child->part.size = parent_size - child->part.offset -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) child->part.size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) printk(KERN_ERR "mtd partition \"%s\" doesn't have enough space: %#llx < %#llx, disabled\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) part->name, parent_size - child->part.offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) child->part.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) /* register to preserve ordering */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) goto out_register;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (child->part.size == MTDPART_SIZ_FULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) child->part.size = parent_size - child->part.offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) printk(KERN_NOTICE "0x%012llx-0x%012llx : \"%s\"\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) child->part.offset, child->part.offset + child->part.size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) child->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /* let's do some sanity checks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (child->part.offset >= parent_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /* let's register it anyway to preserve ordering */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) child->part.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) child->part.size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) /* Initialize ->erasesize to make add_mtd_device() happy. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) child->erasesize = parent->erasesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) printk(KERN_ERR"mtd: partition \"%s\" is out of reach -- disabled\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) part->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) goto out_register;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (child->part.offset + child->part.size > parent->size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) child->part.size = parent_size - child->part.offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) part->name, parent->name, child->part.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (parent->numeraseregions > 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) /* Deal with variable erase size stuff */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) int i, max = parent->numeraseregions;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) u64 end = child->part.offset + child->part.size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) struct mtd_erase_region_info *regions = parent->eraseregions;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) /* Find the first erase regions which is part of this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * partition. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) for (i = 0; i < max && regions[i].offset <= child->part.offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) /* The loop searched for the region _behind_ the first one */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (i > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) i--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) /* Pick biggest erasesize */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) for (; i < max && regions[i].offset < end; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (child->erasesize < regions[i].erasesize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) child->erasesize = regions[i].erasesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) BUG_ON(child->erasesize == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) /* Single erase size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) child->erasesize = master->erasesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) * Child erasesize might differ from the parent one if the parent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * exposes several regions with different erasesize. Adjust
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * wr_alignment accordingly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (!(child->flags & MTD_NO_ERASE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) wr_alignment = child->erasesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) tmp = mtd_get_master_ofs(child, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) remainder = do_div(tmp, wr_alignment);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if ((child->flags & MTD_WRITEABLE) && remainder) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /* Doesn't start on a boundary of major erase size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) /* FIXME: Let it be writable if it is on a boundary of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) * _minor_ erase size though */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) child->flags &= ~MTD_WRITEABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) part->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) tmp = mtd_get_master_ofs(child, 0) + child->part.size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) remainder = do_div(tmp, wr_alignment);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if ((child->flags & MTD_WRITEABLE) && remainder) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) child->flags &= ~MTD_WRITEABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) part->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) child->size = child->part.size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) child->ecc_step_size = parent->ecc_step_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) child->ecc_strength = parent->ecc_strength;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) child->bitflip_threshold = parent->bitflip_threshold;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (master->_block_isbad) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) uint64_t offs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) while (offs < child->part.size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (mtd_block_isreserved(child, offs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) child->ecc_stats.bbtblocks++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) else if (mtd_block_isbad(child, offs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) child->ecc_stats.badblocks++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) offs += child->erasesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) out_register:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) return child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) static ssize_t mtd_partition_offset_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) struct mtd_info *mtd = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) return snprintf(buf, PAGE_SIZE, "%lld\n", mtd->part.offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) static DEVICE_ATTR(offset, S_IRUGO, mtd_partition_offset_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) static const struct attribute *mtd_partition_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) &dev_attr_offset.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) static int mtd_add_partition_attrs(struct mtd_info *new)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) int ret = sysfs_create_files(&new->dev.kobj, mtd_partition_attrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) printk(KERN_WARNING
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) "mtd: failed to create partition attrs, err=%d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) int mtd_add_partition(struct mtd_info *parent, const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) long long offset, long long length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) struct mtd_info *master = mtd_get_master(parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) u64 parent_size = mtd_is_partition(parent) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) parent->part.size : parent->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) struct mtd_partition part;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) struct mtd_info *child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) /* the direct offset is expected */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (offset == MTDPART_OFS_APPEND ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) offset == MTDPART_OFS_NXTBLK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if (length == MTDPART_SIZ_FULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) length = parent_size - offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (length <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) memset(&part, 0, sizeof(part));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) part.name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) part.size = length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) part.offset = offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) child = allocate_partition(parent, &part, -1, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if (IS_ERR(child))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) return PTR_ERR(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) mutex_lock(&master->master.partitions_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) list_add_tail(&child->part.node, &parent->partitions);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) mutex_unlock(&master->master.partitions_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) ret = add_mtd_device(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) goto err_remove_part;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) mtd_add_partition_attrs(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) err_remove_part:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) mutex_lock(&master->master.partitions_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) list_del(&child->part.node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) mutex_unlock(&master->master.partitions_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) free_partition(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) EXPORT_SYMBOL_GPL(mtd_add_partition);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) * __mtd_del_partition - delete MTD partition
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) * @priv: MTD structure to be deleted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) * This function must be called with the partitions mutex locked.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) static int __mtd_del_partition(struct mtd_info *mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) struct mtd_info *child, *next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) list_for_each_entry_safe(child, next, &mtd->partitions, part.node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) err = __mtd_del_partition(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) sysfs_remove_files(&mtd->dev.kobj, mtd_partition_attrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) err = del_mtd_device(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) list_del(&mtd->part.node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) free_partition(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) * This function unregisters and destroy all slave MTD objects which are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) * attached to the given MTD object, recursively.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) static int __del_mtd_partitions(struct mtd_info *mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) struct mtd_info *child, *next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) LIST_HEAD(tmp_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) int ret, err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) list_for_each_entry_safe(child, next, &mtd->partitions, part.node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (mtd_has_partitions(child))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) __del_mtd_partitions(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) pr_info("Deleting %s MTD partition\n", child->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) ret = del_mtd_device(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) pr_err("Error when deleting partition \"%s\" (%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) child->name, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) err = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) list_del(&child->part.node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) free_partition(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) int del_mtd_partitions(struct mtd_info *mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) struct mtd_info *master = mtd_get_master(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) pr_info("Deleting MTD partitions on \"%s\":\n", mtd->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) mutex_lock(&master->master.partitions_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) ret = __del_mtd_partitions(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) mutex_unlock(&master->master.partitions_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) int mtd_del_partition(struct mtd_info *mtd, int partno)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) struct mtd_info *child, *master = mtd_get_master(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) mutex_lock(&master->master.partitions_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) list_for_each_entry(child, &mtd->partitions, part.node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) if (child->index == partno) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) ret = __mtd_del_partition(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) mutex_unlock(&master->master.partitions_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) EXPORT_SYMBOL_GPL(mtd_del_partition);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) * This function, given a parent MTD object and a partition table, creates
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) * and registers the child MTD objects which are bound to the parent according
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) * to the partition definitions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) * For historical reasons, this function's caller only registers the parent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) * if the MTD_PARTITIONED_MASTER config option is set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) int add_mtd_partitions(struct mtd_info *parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) const struct mtd_partition *parts,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) int nbparts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) struct mtd_info *child, *master = mtd_get_master(parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) uint64_t cur_offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) int i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) nbparts, parent->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) for (i = 0; i < nbparts; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) child = allocate_partition(parent, parts + i, i, cur_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) if (IS_ERR(child)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) ret = PTR_ERR(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) goto err_del_partitions;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) mutex_lock(&master->master.partitions_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) list_add_tail(&child->part.node, &parent->partitions);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) mutex_unlock(&master->master.partitions_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) ret = add_mtd_device(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) mutex_lock(&master->master.partitions_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) list_del(&child->part.node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) mutex_unlock(&master->master.partitions_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) free_partition(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) goto err_del_partitions;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) mtd_add_partition_attrs(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) /* Look for subpartitions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) parse_mtd_partitions(child, parts[i].types, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) cur_offset = child->part.offset + child->part.size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) err_del_partitions:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) del_mtd_partitions(master);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) static DEFINE_SPINLOCK(part_parser_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) static LIST_HEAD(part_parsers);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) static struct mtd_part_parser *mtd_part_parser_get(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) struct mtd_part_parser *p, *ret = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) spin_lock(&part_parser_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) list_for_each_entry(p, &part_parsers, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) if (!strcmp(p->name, name) && try_module_get(p->owner)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) ret = p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) spin_unlock(&part_parser_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) module_put(p->owner);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) * Many partition parsers just expected the core to kfree() all their data in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) * one chunk. Do that by default.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) static void mtd_part_parser_cleanup_default(const struct mtd_partition *pparts,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) int nr_parts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) kfree(pparts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) int __register_mtd_parser(struct mtd_part_parser *p, struct module *owner)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) p->owner = owner;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) if (!p->cleanup)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) p->cleanup = &mtd_part_parser_cleanup_default;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) spin_lock(&part_parser_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) list_add(&p->list, &part_parsers);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) spin_unlock(&part_parser_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) EXPORT_SYMBOL_GPL(__register_mtd_parser);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) void deregister_mtd_parser(struct mtd_part_parser *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) spin_lock(&part_parser_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) list_del(&p->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) spin_unlock(&part_parser_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) EXPORT_SYMBOL_GPL(deregister_mtd_parser);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) * Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) * are changing this array!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) static const char * const default_mtd_part_types[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) "cmdlinepart",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) "ofpart",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) /* Check DT only when looking for subpartitions. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) static const char * const default_subpartition_types[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) "ofpart",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) static int mtd_part_do_parse(struct mtd_part_parser *parser,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) struct mtd_info *master,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) struct mtd_partitions *pparts,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) struct mtd_part_parser_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) ret = (*parser->parse_fn)(master, &pparts->parts, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) pr_debug("%s: parser %s: %i\n", master->name, parser->name, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) if (ret <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) pr_notice("%d %s partitions found on MTD device %s\n", ret,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) parser->name, master->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) pparts->nr_parts = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) pparts->parser = parser;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) * mtd_part_get_compatible_parser - find MTD parser by a compatible string
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) * @compat: compatible string describing partitions in a device tree
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) * MTD parsers can specify supported partitions by providing a table of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) * compatibility strings. This function finds a parser that advertises support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) * for a passed value of "compatible".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) static struct mtd_part_parser *mtd_part_get_compatible_parser(const char *compat)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) struct mtd_part_parser *p, *ret = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) spin_lock(&part_parser_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) list_for_each_entry(p, &part_parsers, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) const struct of_device_id *matches;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) matches = p->of_match_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) if (!matches)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) for (; matches->compatible[0]; matches++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) if (!strcmp(matches->compatible, compat) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) try_module_get(p->owner)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) ret = p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) spin_unlock(&part_parser_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) static int mtd_part_of_parse(struct mtd_info *master,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) struct mtd_partitions *pparts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) struct mtd_part_parser *parser;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) struct property *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) const char *compat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) const char *fixed = "fixed-partitions";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) int ret, err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) np = mtd_get_of_node(master);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) if (mtd_is_partition(master))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) of_node_get(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) np = of_get_child_by_name(np, "partitions");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) of_property_for_each_string(np, "compatible", prop, compat) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) parser = mtd_part_get_compatible_parser(compat);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) if (!parser)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) ret = mtd_part_do_parse(parser, master, pparts, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) if (ret > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) mtd_part_parser_put(parser);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) if (ret < 0 && !err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) err = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) * For backward compatibility we have to try the "fixed-partitions"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) * parser. It supports old DT format with partitions specified as a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) * direct subnodes of a flash device DT node without any compatibility
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) * specified we could match.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) parser = mtd_part_parser_get(fixed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) if (!parser && !request_module("%s", fixed))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) parser = mtd_part_parser_get(fixed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) if (parser) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) ret = mtd_part_do_parse(parser, master, pparts, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) if (ret > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) mtd_part_parser_put(parser);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) if (ret < 0 && !err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) err = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) * parse_mtd_partitions - parse and register MTD partitions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) * @master: the master partition (describes whole MTD device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) * @types: names of partition parsers to try or %NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) * @data: MTD partition parser-specific data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) * This function tries to find & register partitions on MTD device @master. It
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) * uses MTD partition parsers, specified in @types. However, if @types is %NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) * then the default list of parsers is used. The default list contains only the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) * "cmdlinepart" and "ofpart" parsers ATM.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) * Note: If there are more then one parser in @types, the kernel only takes the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) * partitions parsed out by the first parser.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) * This function may return:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) * o a negative error code in case of failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) * o number of found partitions otherwise
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) struct mtd_part_parser_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) struct mtd_partitions pparts = { };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) struct mtd_part_parser *parser;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) int ret, err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) if (!types)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) types = mtd_is_partition(master) ? default_subpartition_types :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) default_mtd_part_types;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) for ( ; *types; types++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) * ofpart is a special type that means OF partitioning info
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) * should be used. It requires a bit different logic so it is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) * handled in a separated function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) if (!strcmp(*types, "ofpart")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) ret = mtd_part_of_parse(master, &pparts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) pr_debug("%s: parsing partitions %s\n", master->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) *types);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) parser = mtd_part_parser_get(*types);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) if (!parser && !request_module("%s", *types))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) parser = mtd_part_parser_get(*types);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) pr_debug("%s: got parser %s\n", master->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) parser ? parser->name : NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) if (!parser)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) ret = mtd_part_do_parse(parser, master, &pparts, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) if (ret <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) mtd_part_parser_put(parser);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) /* Found partitions! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) if (ret > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) err = add_mtd_partitions(master, pparts.parts,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) pparts.nr_parts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) mtd_part_parser_cleanup(&pparts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) return err ? err : pparts.nr_parts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) * Stash the first error we see; only report it if no parser
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) * succeeds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) if (ret < 0 && !err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) err = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) void mtd_part_parser_cleanup(struct mtd_partitions *parts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) const struct mtd_part_parser *parser;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) if (!parts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) parser = parts->parser;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) if (parser) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) if (parser->cleanup)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) parser->cleanup(parts->parts, parts->nr_parts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) mtd_part_parser_put(parser);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) /* Returns the size of the entire flash chip */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) uint64_t mtd_get_device_size(const struct mtd_info *mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) struct mtd_info *master = mtd_get_master((struct mtd_info *)mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) return master->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) EXPORT_SYMBOL_GPL(mtd_get_device_size);