/* These are exported solely for the purpose of mtd_blkdevs.c. You
should not use them for _anything_ else */
DEFINE_MUTEX(mtd_table_mutex);
EXPORT_SYMBOL_GPL(mtd_table_mutex);
/* REVISIT once MTD uses the driver model better, whoever allocates * the mtd_info will probably want to use the release() hook...
*/ staticvoid mtd_release(struct device *dev)
{ struct mtd_info *mtd = dev_get_drvdata(dev);
dev_t index = MTD_DEVT(mtd->index);
/* Try to remove the NVMEM provider */
nvmem_unregister(mtd->nvmem);
device_unregister(&mtd->dev);
/* * Clear dev so mtd can be safely re-registered later if desired. * Should not be done for partition, * as it was already destroyed in device_unregister().
*/ if (!is_partition)
memset(&mtd->dev, 0, sizeof(mtd->dev));
switch (mtd->type) { case MTD_ABSENT:
type = "absent"; break; case MTD_RAM:
type = "ram"; break; case MTD_ROM:
type = "rom"; break; case MTD_NORFLASH:
type = "nor"; break; case MTD_NANDFLASH:
type = "nand"; break; case MTD_DATAFLASH:
type = "dataflash"; break; case MTD_UBIVOLUME:
type = "ubi"; break; case MTD_MLCNANDFLASH:
type = "mlc-nand"; break; default:
type = "unknown";
}
#ifdef CONFIG_DEBUG_FS bool mtd_check_expert_analysis_mode(void)
{ constchar *mtd_expert_analysis_warning = "Bad block checks have been entirely disabled.\n" "This is only reserved for post-mortem forensics and debug purposes.\n" "Never enable this mode if you do not know what you are doing!\n";
/** * mtd_wunit_to_pairing_info - get pairing information of a wunit * @mtd: pointer to new MTD device info structure * @wunit: write unit we are interested in * @info: returned pairing information * * Retrieve pairing information associated to the wunit. * This is mainly useful when dealing with MLC/TLC NANDs where pages can be * paired together, and where programming a page may influence the page it is * paired with. * The notion of page is replaced by the term wunit (write-unit) to stay * consistent with the ->writesize field. * * The @wunit argument can be extracted from an absolute offset using * mtd_offset_to_wunit(). @info is filled with the pairing information attached * to @wunit. * * From the pairing info the MTD user can find all the wunits paired with * @wunit using the following loop: * * for (i = 0; i < mtd_pairing_groups(mtd); i++) { * info.pair = i; * mtd_pairing_info_to_wunit(mtd, &info); * ... * }
*/ int mtd_wunit_to_pairing_info(struct mtd_info *mtd, int wunit, struct mtd_pairing_info *info)
{ struct mtd_info *master = mtd_get_master(mtd); int npairs = mtd_wunit_per_eb(master) / mtd_pairing_groups(master);
if (wunit < 0 || wunit >= npairs) return -EINVAL;
if (master->pairing && master->pairing->get_info) return master->pairing->get_info(master, wunit, info);
/** * mtd_pairing_info_to_wunit - get wunit from pairing information * @mtd: pointer to new MTD device info structure * @info: pairing information struct * * Returns a positive number representing the wunit associated to the info * struct, or a negative error code. * * This is the reverse of mtd_wunit_to_pairing_info(), and can help one to * iterate over all wunits of a given pair (see mtd_wunit_to_pairing_info() * doc). * * It can also be used to only program the first page of each pair (i.e. * page attached to group 0), which allows one to use an MLC NAND in * software-emulated SLC mode: * * info.group = 0; * npairs = mtd_wunit_per_eb(mtd) / mtd_pairing_groups(mtd); * for (info.pair = 0; info.pair < npairs; info.pair++) { * wunit = mtd_pairing_info_to_wunit(mtd, &info); * mtd_write(mtd, mtd_wunit_to_offset(mtd, blkoffs, wunit), * mtd->writesize, &retlen, buf + (i * mtd->writesize)); * }
*/ int mtd_pairing_info_to_wunit(struct mtd_info *mtd, conststruct mtd_pairing_info *info)
{ struct mtd_info *master = mtd_get_master(mtd); int ngroups = mtd_pairing_groups(master); int npairs = mtd_wunit_per_eb(master) / ngroups;
/** * mtd_pairing_groups - get the number of pairing groups * @mtd: pointer to new MTD device info structure * * Returns the number of pairing groups. * * This number is usually equal to the number of bits exposed by a single * cell, and can be used in conjunction with mtd_pairing_info_to_wunit() * to iterate over all pages of a given pair.
*/ int mtd_pairing_groups(struct mtd_info *mtd)
{ struct mtd_info *master = mtd_get_master(mtd);
if (!master->pairing || !master->pairing->ngroups) return 1;
mtd->nvmem = nvmem_register(&config); if (IS_ERR(mtd->nvmem)) { /* Just ignore if there is no NVMEM support in the kernel */ if (PTR_ERR(mtd->nvmem) == -EOPNOTSUPP)
mtd->nvmem = NULL; else return dev_err_probe(&mtd->dev, PTR_ERR(mtd->nvmem), "Failed to register NVMEM device\n");
}
/* Search if a partition is defined with the same name */
for_each_child_of_node(partitions, mtd_dn) { /* Skip partition with no/wrong prefix */ if (!of_node_name_prefix(mtd_dn, prefix)) continue;
/* Label have priority. Check that first */ if (!of_property_read_string(mtd_dn, "label", &pname)) {
offset = 0;
} else {
pname = mtd_dn->name;
offset = prefix_len;
}
/** * add_mtd_device - register an MTD device * @mtd: pointer to new MTD device info structure * * Add a device to the list of MTD devices present in the system, and * notify each currently active MTD 'user' of its arrival. Returns * zero on success or non-zero on failure.
*/
int add_mtd_device(struct mtd_info *mtd)
{ struct device_node *np = mtd_get_of_node(mtd); struct mtd_info *master = mtd_get_master(mtd); struct mtd_notifier *not; int i, error, ofidx;
/* * May occur, for instance, on buggy drivers which call * mtd_device_parse_register() multiple times on the same master MTD, * especially with CONFIG_MTD_PARTITIONED_MASTER=y.
*/ if (WARN_ONCE(mtd->dev.type, "MTD already registered\n")) return -EEXIST;
BUG_ON(mtd->writesize == 0);
/* * MTD drivers should implement ->_{write,read}() or * ->_{write,read}_oob(), but not both.
*/ if (WARN_ON((mtd->_write && mtd->_write_oob) ||
(mtd->_read && mtd->_read_oob))) return -EINVAL;
if (WARN_ON((!mtd->erasesize || !master->_erase) &&
!(mtd->flags & MTD_NO_ERASE))) return -EINVAL;
/* * MTD_SLC_ON_MLC_EMULATION can only be set on partitions, when the * master is an MLC NAND and has a proper pairing scheme defined. * We also reject masters that implement ->_writev() for now, because * NAND controller drivers don't implement this hook, and adding the * SLC -> MLC address/length conversion to this path is useless if we * don't have a user.
*/ if (mtd->flags & MTD_SLC_ON_MLC_EMULATION &&
(!mtd_is_partition(mtd) || master->type != MTD_MLCNANDFLASH ||
!master->pairing || master->_writev)) return -EINVAL;
mutex_lock(&mtd_table_mutex);
ofidx = -1; if (np)
ofidx = of_alias_get_id(np, "mtd"); if (ofidx >= 0)
i = idr_alloc(&mtd_idr, mtd, ofidx, ofidx + 1, GFP_KERNEL); else
i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL); if (i < 0) {
error = i; goto fail_locked;
}
mtd->index = i;
kref_init(&mtd->refcnt);
/* default value if not set by driver */ if (mtd->bitflip_threshold == 0)
mtd->bitflip_threshold = mtd->ecc_strength;
if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) { int ngroups = mtd_pairing_groups(master);
pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name); /* No need to get a refcount on the module containing
the notifier, since we hold the mtd_table_mutex */
list_for_each_entry(not, &mtd_notifiers, list)
not->add(mtd);
mutex_unlock(&mtd_table_mutex);
if (of_property_read_bool(mtd_get_of_node(mtd), "linux,rootfs")) { if (IS_BUILTIN(CONFIG_MTD)) {
pr_info("mtd: setting mtd%d (%s) as root device\n", mtd->index, mtd->name);
ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index);
} else {
pr_warn("mtd: can't set mtd%d (%s) as root device - mtd must be builtin\n",
mtd->index, mtd->name);
}
}
/* We _know_ we aren't being removed, because our caller is still holding us here. So none of this try_ nonsense, and no bitching about it
either. :) */
__module_get(THIS_MODULE); return 0;
/** * del_mtd_device - unregister an MTD device * @mtd: pointer to MTD device info structure * * Remove a device from the list of MTD devices present in the system, * and notify each currently active MTD 'user' of its departure. * Returns zero on success or 1 on failure, which currently will happen * if the requested device does not appear to be present in the list.
*/
int del_mtd_device(struct mtd_info *mtd)
{ int ret; struct mtd_notifier *not;
mutex_lock(&mtd_table_mutex);
if (idr_find(&mtd_idr, mtd->index) != mtd) {
ret = -ENODEV; goto out_error;
}
/* No need to get a refcount on the module containing
the notifier, since we hold the mtd_table_mutex */
list_for_each_entry(not, &mtd_notifiers, list)
not->remove(mtd);
kref_put(&mtd->refcnt, mtd_device_release);
ret = 0;
/* * Set a few defaults based on the parent devices, if not provided by the * driver
*/ staticvoid mtd_set_dev_defaults(struct mtd_info *mtd)
{ if (mtd->dev.parent) { if (!mtd->owner && mtd->dev.parent->driver)
mtd->owner = mtd->dev.parent->driver->owner; if (!mtd->name)
mtd->name = dev_name(mtd->dev.parent);
} else {
pr_debug("mtd device won't show a device symlink in sysfs\n");
}
info = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!info) return -ENOMEM;
if (is_user)
ret = mtd_get_user_prot_info(mtd, PAGE_SIZE, &retlen, info); else
ret = mtd_get_fact_prot_info(mtd, PAGE_SIZE, &retlen, info); if (ret) goto err;
for (i = 0; i < retlen / sizeof(*info); i++)
size += info[i].length;
kfree(info); return size;
err:
kfree(info);
/* ENODATA means there is no OTP region. */ return ret == -ENODATA ? 0 : ret;
}
nvmem = nvmem_register(&config); /* Just ignore if there is no NVMEM support in the kernel */ if (IS_ERR(nvmem) && PTR_ERR(nvmem) == -EOPNOTSUPP)
nvmem = NULL;
if (mtd->_get_fact_prot_info && mtd->_read_fact_prot_reg) {
size = mtd_otp_size(mtd, false); if (size < 0) {
err = size; goto err;
}
if (size > 0) { /* * The factory OTP contains thing such as a unique serial * number and is small, so let's read it out and put it * into the entropy pool.
*/ void *otp;
err:
nvmem_unregister(mtd->otp_user_nvmem); /* Don't report error if OTP is not supported. */ if (err == -EOPNOTSUPP) return 0; return dev_err_probe(dev, err, "Failed to register OTP NVMEM device\n");
}
/** * mtd_device_parse_register - parse partitions and register an MTD device. * * @mtd: the MTD device to register * @types: the list of MTD partition probes to try, see * 'parse_mtd_partitions()' for more information * @parser_data: MTD partition parser-specific data * @parts: fallback partition information to register, if parsing fails; * only valid if %nr_parts > %0 * @nr_parts: the number of partitions in parts, if zero then the full * MTD device is registered if no partition info is found * * This function aggregates MTD partitions parsing (done by * 'parse_mtd_partitions()') and MTD device and partitions registering. It * basically follows the most common pattern found in many MTD drivers: * * * If the MTD_PARTITIONED_MASTER option is set, then the device as a whole is * registered first. * * Then It tries to probe partitions on MTD device @mtd using parsers * specified in @types (if @types is %NULL, then the default list of parsers * is used, see 'parse_mtd_partitions()' for more information). If none are * found this functions tries to fallback to information specified in * @parts/@nr_parts. * * If no partitions were found this function just registers the MTD device * @mtd and exits. * * Returns zero in case of success and a negative error code in case of failure.
*/ int mtd_device_parse_register(struct mtd_info *mtd, constchar * const *types, struct mtd_part_parser_data *parser_data, conststruct mtd_partition *parts, int nr_parts)
{ int ret, err;
mtd_set_dev_defaults(mtd);
ret = mtd_otp_nvmem_add(mtd); if (ret) goto out;
if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) {
ret = add_mtd_device(mtd); if (ret) goto out;
}
/* Prefer parsed partitions over driver-provided fallback */
ret = parse_mtd_partitions(mtd, types, parser_data); if (ret == -EPROBE_DEFER) goto out;
if (ret > 0)
ret = 0; elseif (nr_parts)
ret = add_mtd_partitions(mtd, parts, nr_parts); elseif (!device_is_registered(&mtd->dev))
ret = add_mtd_device(mtd); else
ret = 0;
if (ret) goto out;
/* * FIXME: some drivers unfortunately call this function more than once. * So we have to check if we've already assigned the reboot notifier. * * Generally, we can make multiple calls work for most cases, but it * does cause problems with parse_mtd_partitions() above (e.g., * cmdlineparts will register partitions more than once).
*/
WARN_ONCE(mtd->_reboot && mtd->reboot_notifier.notifier_call, "MTD already registered\n"); if (mtd->_reboot && !mtd->reboot_notifier.notifier_call) {
mtd->reboot_notifier.notifier_call = mtd_reboot_notifier;
register_reboot_notifier(&mtd->reboot_notifier);
}
out: if (ret) {
nvmem_unregister(mtd->otp_user_nvmem);
nvmem_unregister(mtd->otp_factory_nvmem);
}
if (ret && device_is_registered(&mtd->dev)) {
err = del_mtd_device(mtd); if (err)
pr_err("Error when deleting MTD device (%d)\n", err);
}
/** * mtd_device_unregister - unregister an existing MTD device. * * @master: the MTD device to unregister. This will unregister both the master * and any partitions if registered.
*/ int mtd_device_unregister(struct mtd_info *master)
{ int err;
if (master->_reboot) {
unregister_reboot_notifier(&master->reboot_notifier);
memset(&master->reboot_notifier, 0, sizeof(master->reboot_notifier));
}
/** * register_mtd_user - register a 'user' of MTD devices. * @new: pointer to notifier info structure * * Registers a pair of callbacks function to be called upon addition * or removal of MTD devices. Causes the 'add' callback to be immediately * invoked for each MTD device currently present in the system.
*/ void register_mtd_user (struct mtd_notifier *new)
{ struct mtd_info *mtd;
/** * unregister_mtd_user - unregister a 'user' of MTD devices. * @old: pointer to notifier info structure * * Removes a callback function pair from the list of 'users' to be * notified upon addition or removal of MTD devices. Causes the * 'remove' callback to be immediately invoked for each MTD device * currently present in the system.
*/ int unregister_mtd_user (struct mtd_notifier *old)
{ struct mtd_info *mtd;
/** * get_mtd_device - obtain a validated handle for an MTD device * @mtd: last known address of the required MTD device * @num: internal device number of the required MTD device * * Given a number and NULL address, return the num'th entry in the device * table, if any. Given an address and num == -1, search the device table * for a device with that address and return if it's still present. Given * both, return the num'th driver only if its address matches. Return * error code if not.
*/ struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
{ struct mtd_info *ret = NULL, *other; int err = -ENODEV;
mutex_lock(&mtd_table_mutex);
if (num == -1) {
mtd_for_each_device(other) { if (other == mtd) {
ret = mtd; break;
}
}
} elseif (num >= 0) {
ret = idr_find(&mtd_idr, num); if (mtd && mtd != ret)
ret = NULL;
}
if (!ret) {
ret = ERR_PTR(err); goto out;
}
err = __get_mtd_device(ret); if (err)
ret = ERR_PTR(err);
out:
mutex_unlock(&mtd_table_mutex); return ret;
}
EXPORT_SYMBOL_GPL(get_mtd_device);
int __get_mtd_device(struct mtd_info *mtd)
{ struct mtd_info *master = mtd_get_master(mtd); int err;
if (master->_get_device) {
err = master->_get_device(mtd); if (err) return err;
}
if (!try_module_get(master->owner)) { if (master->_put_device)
master->_put_device(master); return -ENODEV;
}
while (mtd) { if (mtd != master)
kref_get(&mtd->refcnt);
mtd = mtd->parent;
}
if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER))
kref_get(&master->refcnt);
return 0;
}
EXPORT_SYMBOL_GPL(__get_mtd_device);
/** * of_get_mtd_device_by_node - obtain an MTD device associated with a given node * * @np: device tree node
*/ struct mtd_info *of_get_mtd_device_by_node(struct device_node *np)
{ struct mtd_info *mtd = NULL; struct mtd_info *tmp; int err;
/** * get_mtd_device_nm - obtain a validated handle for an MTD device by * device name * @name: MTD device name to open * * This function returns MTD device description structure in case of * success and an error code in case of failure.
*/ struct mtd_info *get_mtd_device_nm(constchar *name)
{ int err = -ENODEV; struct mtd_info *mtd = NULL, *other;
while (mtd) { /* kref_put() can relese mtd, so keep a reference mtd->parent */ struct mtd_info *parent = mtd->parent;
if (mtd != master)
kref_put(&mtd->refcnt, mtd_device_release);
mtd = parent;
}
if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER))
kref_put(&master->refcnt, mtd_device_release);
module_put(master->owner);
/* must be the last as master can be freed in the _put_device */ if (master->_put_device)
master->_put_device(master);
}
EXPORT_SYMBOL_GPL(__put_mtd_device);
/* * Erase is an synchronous operation. Device drivers are epected to return a * negative error code if the operation failed and update instr->fail_addr * to point the portion that was not properly erased.
*/ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
{ struct mtd_info *master = mtd_get_master(mtd);
u64 mst_ofs = mtd_get_master_ofs(mtd, 0); struct erase_info adjinstr; int ret;
/* * This stuff for eXecute-In-Place. phys is optional and may be set to NULL.
*/ int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, void **virt, resource_size_t *phys)
{ struct mtd_info *master = mtd_get_master(mtd);
*retlen = 0;
*virt = NULL; if (phys)
*phys = 0; if (!master->_point) return -EOPNOTSUPP; if (from < 0 || from >= mtd->size || len > mtd->size - from) return -EINVAL; if (!len) return 0;
/* We probably shouldn't allow XIP if the unpoint isn't a NULL */ int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{ struct mtd_info *master = mtd_get_master(mtd);
if (!master->_unpoint) return -EOPNOTSUPP; if (from < 0 || from >= mtd->size || len > mtd->size - from) return -EINVAL; if (!len) return 0; return master->_unpoint(master, mtd_get_master_ofs(mtd, from), len);
}
EXPORT_SYMBOL_GPL(mtd_unpoint);
/* * Allow NOMMU mmap() to directly map the device (if not NULL) * - return the address to which the offset maps * - return -ENOSYS to indicate refusal to do the mapping
*/ unsignedlong mtd_get_unmapped_area(struct mtd_info *mtd, unsignedlong len, unsignedlong offset, unsignedlong flags)
{
size_t retlen; void *virt; int ret;
ret = mtd_point(mtd, offset, len, &retlen, &virt, NULL); if (ret) return ret; if (retlen != len) {
mtd_unpoint(mtd, offset, retlen); return -ENOSYS;
} return (unsignedlong)virt;
}
EXPORT_SYMBOL_GPL(mtd_get_unmapped_area);
/* * In blackbox flight recorder like scenarios we want to make successful writes * in interrupt context. panic_write() is only intended to be called when its * known the kernel is about to panic and we need the write to succeed. Since * the kernel is not going to be running for much longer, this function can * break locks and delay to ensure the write succeeds (but not sleep).
*/ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
{ struct mtd_info *master = mtd_get_master(mtd);
*retlen = 0; if (!master->_panic_write) return -EOPNOTSUPP; if (to < 0 || to >= mtd->size || len > mtd->size - to) return -EINVAL; if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; if (!len) return 0; if (!master->oops_panic_write)
master->oops_panic_write = true;
staticint mtd_check_oob_ops(struct mtd_info *mtd, loff_t offs, struct mtd_oob_ops *ops)
{ /* * Some users are setting ->datbuf or ->oobbuf to NULL, but are leaving * ->len or ->ooblen uninitialized. Force ->len and ->ooblen to 0 in * this case.
*/ if (!ops->datbuf)
ops->len = 0;
from = mtd_get_master_ofs(mtd, from); if (master->_read_oob)
ret = master->_read_oob(master, from, ops); else
ret = master->_read(master, from, ops->len, &ops->retlen,
ops->datbuf);
return ret;
}
staticint mtd_write_oob_std(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
{ struct mtd_info *master = mtd_get_master(mtd); int ret;
to = mtd_get_master_ofs(mtd, to); if (master->_write_oob)
ret = master->_write_oob(master, to, ops); else
ret = master->_write(master, to, ops->len, &ops->retlen,
ops->datbuf);
/* * In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics * similar to mtd->_read(), returning a non-negative integer * representing max bitflips. In other cases, mtd->_read_oob() may * return -EUCLEAN. In all cases, perform similar logic to mtd_read().
*/ if (unlikely(ret_code < 0)) return ret_code; if (mtd->ecc_strength == 0) return 0; /* device lacks ecc */ if (ops->stats)
ops->stats->max_bitflips = ret_code; return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
}
EXPORT_SYMBOL_GPL(mtd_read_oob);
int mtd_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
{ struct mtd_info *master = mtd_get_master(mtd); int ret;
ops->retlen = ops->oobretlen = 0;
if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS;
ret = mtd_check_oob_ops(mtd, to, ops); if (ret) return ret;
ledtrig_mtd_activity();
/* Check the validity of a potential fallback on mtd->_write */ if (!master->_write_oob && (!master->_write || ops->oobbuf)) return -EOPNOTSUPP;
if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) return mtd_io_emulated_slc(mtd, to, false, ops);
return mtd_write_oob_std(mtd, to, ops);
}
EXPORT_SYMBOL_GPL(mtd_write_oob);
/** * mtd_ooblayout_ecc - Get the OOB region definition of a specific ECC section * @mtd: MTD device structure * @section: ECC section. Depending on the layout you may have all the ECC * bytes stored in a single contiguous section, or one section * per ECC chunk (and sometime several sections for a single ECC * ECC chunk) * @oobecc: OOB region struct filled with the appropriate ECC position * information * * This function returns ECC section information in the OOB area. If you want * to get all the ECC bytes information, then you should call * mtd_ooblayout_ecc(mtd, section++, oobecc) until it returns -ERANGE. * * Returns zero on success, a negative error code otherwise.
*/ int mtd_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *oobecc)
{ struct mtd_info *master = mtd_get_master(mtd);
memset(oobecc, 0, sizeof(*oobecc));
if (!master || section < 0) return -EINVAL;
if (!master->ooblayout || !master->ooblayout->ecc) return -ENOTSUPP;
/** * mtd_ooblayout_free - Get the OOB region definition of a specific free * section * @mtd: MTD device structure * @section: Free section you are interested in. Depending on the layout * you may have all the free bytes stored in a single contiguous * section, or one section per ECC chunk plus an extra section * for the remaining bytes (or other funky layout). * @oobfree: OOB region struct filled with the appropriate free position * information * * This function returns free bytes position in the OOB area. If you want * to get all the free bytes information, then you should call * mtd_ooblayout_free(mtd, section++, oobfree) until it returns -ERANGE. * * Returns zero on success, a negative error code otherwise.
*/ int mtd_ooblayout_free(struct mtd_info *mtd, int section, struct mtd_oob_region *oobfree)
{ struct mtd_info *master = mtd_get_master(mtd);
memset(oobfree, 0, sizeof(*oobfree));
if (!master || section < 0) return -EINVAL;
if (!master->ooblayout || !master->ooblayout->free) return -ENOTSUPP;
/** * mtd_ooblayout_find_region - Find the region attached to a specific byte * @mtd: mtd info structure * @byte: the byte we are searching for * @sectionp: pointer where the section id will be stored * @oobregion: used to retrieve the ECC position * @iter: iterator function. Should be either mtd_ooblayout_free or * mtd_ooblayout_ecc depending on the region type you're searching for * * This function returns the section id and oobregion information of a * specific byte. For example, say you want to know where the 4th ECC byte is * stored, you'll use: * * mtd_ooblayout_find_region(mtd, 3, §ion, &oobregion, mtd_ooblayout_ecc); * * Returns zero on success, a negative error code otherwise.
*/ staticint mtd_ooblayout_find_region(struct mtd_info *mtd, int byte, int *sectionp, struct mtd_oob_region *oobregion, int (*iter)(struct mtd_info *, int section, struct mtd_oob_region *oobregion))
{ int pos = 0, ret, section = 0;
memset(oobregion, 0, sizeof(*oobregion));
while (1) {
ret = iter(mtd, section, oobregion); if (ret) return ret;
if (pos + oobregion->length > byte) break;
pos += oobregion->length;
section++;
}
/* * Adjust region info to make it start at the beginning at the * 'start' ECC byte.
*/
oobregion->offset += byte - pos;
oobregion->length -= byte - pos;
*sectionp = section;
return 0;
}
/** * mtd_ooblayout_find_eccregion - Find the ECC region attached to a specific * ECC byte * @mtd: mtd info structure * @eccbyte: the byte we are searching for * @section: pointer where the section id will be stored * @oobregion: OOB region information * * Works like mtd_ooblayout_find_region() except it searches for a specific ECC * byte. * * Returns zero on success, a negative error code otherwise.
*/ int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte, int *section, struct mtd_oob_region *oobregion)
{ return mtd_ooblayout_find_region(mtd, eccbyte, section, oobregion,
mtd_ooblayout_ecc);
}
EXPORT_SYMBOL_GPL(mtd_ooblayout_find_eccregion);
/** * mtd_ooblayout_get_bytes - Extract OOB bytes from the oob buffer * @mtd: mtd info structure * @buf: destination buffer to store OOB bytes * @oobbuf: OOB buffer * @start: first byte to retrieve * @nbytes: number of bytes to retrieve * @iter: section iterator * * Extract bytes attached to a specific category (ECC or free) * from the OOB buffer and copy them into buf. * * Returns zero on success, a negative error code otherwise.
*/ staticint mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf, const u8 *oobbuf, int start, int nbytes, int (*iter)(struct mtd_info *, int section, struct mtd_oob_region *oobregion))
{ struct mtd_oob_region oobregion; int section, ret;
ret = mtd_ooblayout_find_region(mtd, start, §ion,
&oobregion, iter);
/** * mtd_ooblayout_set_bytes - put OOB bytes into the oob buffer * @mtd: mtd info structure * @buf: source buffer to get OOB bytes from * @oobbuf: OOB buffer * @start: first OOB byte to set * @nbytes: number of OOB bytes to set * @iter: section iterator * * Fill the OOB buffer with data provided in buf. The category (ECC or free) * is selected by passing the appropriate iterator. * * Returns zero on success, a negative error code otherwise.
*/ staticint mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf,
u8 *oobbuf, int start, int nbytes, int (*iter)(struct mtd_info *, int section, struct mtd_oob_region *oobregion))
{ struct mtd_oob_region oobregion; int section, ret;
ret = mtd_ooblayout_find_region(mtd, start, §ion,
&oobregion, iter);
/** * mtd_ooblayout_count_bytes - count the number of bytes in a OOB category * @mtd: mtd info structure * @iter: category iterator * * Count the number of bytes in a given category. * * Returns a positive value on success, a negative error code otherwise.
*/ staticint mtd_ooblayout_count_bytes(struct mtd_info *mtd, int (*iter)(struct mtd_info *, int section, struct mtd_oob_region *oobregion))
{ struct mtd_oob_region oobregion; int section = 0, ret, nbytes = 0;
while (1) {
ret = iter(mtd, section++, &oobregion); if (ret) { if (ret == -ERANGE)
ret = nbytes; break;
}
nbytes += oobregion.length;
}
return ret;
}
/** * mtd_ooblayout_get_eccbytes - extract ECC bytes from the oob buffer * @mtd: mtd info structure * @eccbuf: destination buffer to store ECC bytes * @oobbuf: OOB buffer * @start: first ECC byte to retrieve * @nbytes: number of ECC bytes to retrieve * * Works like mtd_ooblayout_get_bytes(), except it acts on ECC bytes. * * Returns zero on success, a negative error code otherwise.
*/ int mtd_ooblayout_get_eccbytes(struct mtd_info *mtd, u8 *eccbuf, const u8 *oobbuf, int start, int nbytes)
{ return mtd_ooblayout_get_bytes(mtd, eccbuf, oobbuf, start, nbytes,
mtd_ooblayout_ecc);
}
EXPORT_SYMBOL_GPL(mtd_ooblayout_get_eccbytes);
/** * mtd_ooblayout_set_eccbytes - set ECC bytes into the oob buffer * @mtd: mtd info structure * @eccbuf: source buffer to get ECC bytes from * @oobbuf: OOB buffer * @start: first ECC byte to set * @nbytes: number of ECC bytes to set * * Works like mtd_ooblayout_set_bytes(), except it acts on ECC bytes. * * Returns zero on success, a negative error code otherwise.
*/ int mtd_ooblayout_set_eccbytes(struct mtd_info *mtd, const u8 *eccbuf,
u8 *oobbuf, int start, int nbytes)
{ return mtd_ooblayout_set_bytes(mtd, eccbuf, oobbuf, start, nbytes,
mtd_ooblayout_ecc);
}
EXPORT_SYMBOL_GPL(mtd_ooblayout_set_eccbytes);
/** * mtd_ooblayout_get_databytes - extract data bytes from the oob buffer * @mtd: mtd info structure * @databuf: destination buffer to store ECC bytes * @oobbuf: OOB buffer * @start: first ECC byte to retrieve * @nbytes: number of ECC bytes to retrieve * * Works like mtd_ooblayout_get_bytes(), except it acts on free bytes. * * Returns zero on success, a negative error code otherwise.
*/ int mtd_ooblayout_get_databytes(struct mtd_info *mtd, u8 *databuf, const u8 *oobbuf, int start, int nbytes)
{ return mtd_ooblayout_get_bytes(mtd, databuf, oobbuf, start, nbytes,
mtd_ooblayout_free);
}
EXPORT_SYMBOL_GPL(mtd_ooblayout_get_databytes);
/** * mtd_ooblayout_set_databytes - set data bytes into the oob buffer * @mtd: mtd info structure * @databuf: source buffer to get data bytes from * @oobbuf: OOB buffer * @start: first ECC byte to set * @nbytes: number of ECC bytes to set * * Works like mtd_ooblayout_set_bytes(), except it acts on free bytes. * * Returns zero on success, a negative error code otherwise.
*/ int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf,
u8 *oobbuf, int start, int nbytes)
{ return mtd_ooblayout_set_bytes(mtd, databuf, oobbuf, start, nbytes,
mtd_ooblayout_free);
}
EXPORT_SYMBOL_GPL(mtd_ooblayout_set_databytes);
/** * mtd_ooblayout_count_freebytes - count the number of free bytes in OOB * @mtd: mtd info structure * * Works like mtd_ooblayout_count_bytes(), except it count free bytes. * * Returns zero on success, a negative error code otherwise.
*/ int mtd_ooblayout_count_freebytes(struct mtd_info *mtd)
{ return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_free);
}
EXPORT_SYMBOL_GPL(mtd_ooblayout_count_freebytes);
/** * mtd_ooblayout_count_eccbytes - count the number of ECC bytes in OOB * @mtd: mtd info structure * * Works like mtd_ooblayout_count_bytes(), except it count ECC bytes. * * Returns zero on success, a negative error code otherwise.
*/ int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd)
{ return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_ecc);
}
EXPORT_SYMBOL_GPL(mtd_ooblayout_count_eccbytes);
/* * Method to access the protection register area, present in some flash * devices. The user data is one time programmable but the factory data is read * only.
*/ int mtd_get_fact_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen, struct otp_info *buf)
{ struct mtd_info *master = mtd_get_master(mtd);
if (!master->_get_fact_prot_info) return -EOPNOTSUPP; if (!len) return 0; return master->_get_fact_prot_info(master, len, retlen, buf);
}
EXPORT_SYMBOL_GPL(mtd_get_fact_prot_info);
*retlen = 0; if (!master->_read_user_prot_reg) return -EOPNOTSUPP; if (!len) return 0; return master->_read_user_prot_reg(master, from, len, retlen, buf);
}
EXPORT_SYMBOL_GPL(mtd_read_user_prot_reg);
int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{ struct mtd_info *master = mtd_get_master(mtd); int ret;
*retlen = 0; if (!master->_write_user_prot_reg) return -EOPNOTSUPP; if (!len) return 0;
ret = master->_write_user_prot_reg(master, to, len, retlen, buf); if (ret) return ret;
/* * If no data could be written at all, we are out of memory and * must return -ENOSPC.
*/ return (*retlen) ? 0 : -ENOSPC;
}
EXPORT_SYMBOL_GPL(mtd_write_user_prot_reg);
/* * default_mtd_writev - the default writev method * @mtd: mtd device description object pointer * @vecs: the vectors to write * @count: count of vectors in @vecs * @to: the MTD device offset to write to * @retlen: on exit contains the count of bytes written to the MTD device. * * This function returns zero in case of success and a negative error code in * case of failure.
*/ staticint default_mtd_writev(struct mtd_info *mtd, conststruct kvec *vecs, unsignedlong count, loff_t to, size_t *retlen)
{ unsignedlong i;
size_t totlen = 0, thislen; int ret = 0;
for (i = 0; i < count; i++) { if (!vecs[i].iov_len) continue;
ret = mtd_write(mtd, to, vecs[i].iov_len, &thislen,
vecs[i].iov_base);
totlen += thislen; if (ret || thislen != vecs[i].iov_len) break;
to += vecs[i].iov_len;
}
*retlen = totlen; return ret;
}
/* * mtd_writev - the vector-based MTD write method * @mtd: mtd device description object pointer * @vecs: the vectors to write * @count: count of vectors in @vecs * @to: the MTD device offset to write to * @retlen: on exit contains the count of bytes written to the MTD device. * * This function returns zero in case of success and a negative error code in * case of failure.
*/ int mtd_writev(struct mtd_info *mtd, conststruct kvec *vecs, unsignedlong count, loff_t to, size_t *retlen)
{ struct mtd_info *master = mtd_get_master(mtd);
*retlen = 0; if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS;
if (!master->_writev) return default_mtd_writev(mtd, vecs, count, to, retlen);
/** * mtd_kmalloc_up_to - allocate a contiguous buffer up to the specified size * @mtd: mtd device description object pointer * @size: a pointer to the ideal or maximum size of the allocation, points * to the actual allocation size on success. * * This routine attempts to allocate a contiguous kernel buffer up to * the specified size, backing off the size of the request exponentially * until the request succeeds or until the allocation size falls below * the system page size. This attempts to make sure it does not adversely * impact system performance, so when allocating more than one page, we * ask the memory allocator to avoid re-trying, swapping, writing back * or performing I/O. * * Note, this function also makes sure that the allocated buffer is aligned to * the MTD device's min. I/O unit, i.e. the "mtd->writesize" value. * * This is called, for example by mtd_{read,write} and jffs2_scan_medium, * to handle smaller (i.e. degraded) buffer allocations under low- or * fragmented-memory situations where such reduced allocations, from a * requested ideal, are allowed. * * Returns a pointer to the allocated buffer on success; otherwise, NULL.
*/ void *mtd_kmalloc_up_to(conststruct mtd_info *mtd, size_t *size)
{
gfp_t flags = __GFP_NOWARN | __GFP_DIRECT_RECLAIM | __GFP_NORETRY;
size_t min_alloc = max_t(size_t, mtd->writesize, PAGE_SIZE); void *kbuf;
*size = min_t(size_t, *size, KMALLOC_MAX_SIZE);
while (*size > min_alloc) {
kbuf = kmalloc(*size, flags); if (kbuf) return kbuf;
/* * For the last resort allocation allow 'kmalloc()' to do all sorts of * things (write-back, dropping caches, etc) by using GFP_KERNEL.
*/ return kmalloc(*size, GFP_KERNEL);
}
EXPORT_SYMBOL_GPL(mtd_kmalloc_up_to);
#ifdef CONFIG_PROC_FS
/*====================================================================*/ /* Support for /proc/mtd */
/* * We put '-0' suffix to the name to get the same name format as we * used to get. Since this is called only once, we get a unique name.
*/
ret = bdi_register(bdi, "%.28s-0", name); if (ret)
bdi_put(bdi);
return ret ? ERR_PTR(ret) : bdi;
}
staticstruct proc_dir_entry *proc_mtd;
staticint __init init_mtd(void)
{ int ret;
ret = class_register(&mtd_class); if (ret) goto err_reg;
mtd_bdi = mtd_bdi_init("mtd"); if (IS_ERR(mtd_bdi)) {
ret = PTR_ERR(mtd_bdi); goto err_bdi;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.