uboot/drivers/mtd/mtdcore.c
<<
>>
Prefs
   1/*
   2 * Core registration and callback routines for MTD
   3 * drivers and users.
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 as
   7 * published by the Free Software Foundation.
   8 */
   9
  10#include <linux/mtd/mtd.h>
  11#include <linux/compat.h>
  12#include <ubi_uboot.h>
  13
  14struct mtd_info *mtd_table[MAX_MTD_DEVICES];
  15
  16int add_mtd_device(struct mtd_info *mtd)
  17{
  18        int i;
  19
  20        BUG_ON(mtd->writesize == 0);
  21
  22        for (i = 0; i < MAX_MTD_DEVICES; i++)
  23                if (!mtd_table[i]) {
  24                        mtd_table[i] = mtd;
  25                        mtd->index = i;
  26                        mtd->usecount = 0;
  27
  28                        /* default value if not set by driver */
  29                        if (mtd->bitflip_threshold == 0)
  30                                mtd->bitflip_threshold = mtd->ecc_strength;
  31
  32
  33                        /* No need to get a refcount on the module containing
  34                           the notifier, since we hold the mtd_table_mutex */
  35
  36                        /* We _know_ we aren't being removed, because
  37                           our caller is still holding us here. So none
  38                           of this try_ nonsense, and no bitching about it
  39                           either. :) */
  40                        return 0;
  41                }
  42
  43        return 1;
  44}
  45
  46/**
  47 *      del_mtd_device - unregister an MTD device
  48 *      @mtd: pointer to MTD device info structure
  49 *
  50 *      Remove a device from the list of MTD devices present in the system,
  51 *      and notify each currently active MTD 'user' of its departure.
  52 *      Returns zero on success or 1 on failure, which currently will happen
  53 *      if the requested device does not appear to be present in the list.
  54 */
  55int del_mtd_device(struct mtd_info *mtd)
  56{
  57        int ret;
  58
  59        if (mtd_table[mtd->index] != mtd) {
  60                ret = -ENODEV;
  61        } else if (mtd->usecount) {
  62                printk(KERN_NOTICE "Removing MTD device #%d (%s)"
  63                                " with use count %d\n",
  64                                mtd->index, mtd->name, mtd->usecount);
  65                ret = -EBUSY;
  66        } else {
  67                /* No need to get a refcount on the module containing
  68                 * the notifier, since we hold the mtd_table_mutex */
  69                mtd_table[mtd->index] = NULL;
  70
  71                ret = 0;
  72        }
  73
  74        return ret;
  75}
  76
  77/**
  78 *      get_mtd_device - obtain a validated handle for an MTD device
  79 *      @mtd: last known address of the required MTD device
  80 *      @num: internal device number of the required MTD device
  81 *
  82 *      Given a number and NULL address, return the num'th entry in the device
  83 *      table, if any.  Given an address and num == -1, search the device table
  84 *      for a device with that address and return if it's still present. Given
  85 *      both, return the num'th driver only if its address matches. Return
  86 *      error code if not.
  87 */
  88struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
  89{
  90        struct mtd_info *ret = NULL;
  91        int i, err = -ENODEV;
  92
  93        if (num == -1) {
  94                for (i = 0; i < MAX_MTD_DEVICES; i++)
  95                        if (mtd_table[i] == mtd)
  96                                ret = mtd_table[i];
  97        } else if (num < MAX_MTD_DEVICES) {
  98                ret = mtd_table[num];
  99                if (mtd && mtd != ret)
 100                        ret = NULL;
 101        }
 102
 103        if (!ret)
 104                goto out_unlock;
 105
 106        ret->usecount++;
 107        return ret;
 108
 109out_unlock:
 110        return ERR_PTR(err);
 111}
 112
 113/**
 114 *      get_mtd_device_nm - obtain a validated handle for an MTD device by
 115 *      device name
 116 *      @name: MTD device name to open
 117 *
 118 *      This function returns MTD device description structure in case of
 119 *      success and an error code in case of failure.
 120 */
 121struct mtd_info *get_mtd_device_nm(const char *name)
 122{
 123        int i, err = -ENODEV;
 124        struct mtd_info *mtd = NULL;
 125
 126        for (i = 0; i < MAX_MTD_DEVICES; i++) {
 127                if (mtd_table[i] && !strcmp(name, mtd_table[i]->name)) {
 128                        mtd = mtd_table[i];
 129                        break;
 130                }
 131        }
 132
 133        if (!mtd)
 134                goto out_unlock;
 135
 136        mtd->usecount++;
 137        return mtd;
 138
 139out_unlock:
 140        return ERR_PTR(err);
 141}
 142
 143void put_mtd_device(struct mtd_info *mtd)
 144{
 145        int c;
 146
 147        c = --mtd->usecount;
 148        BUG_ON(c < 0);
 149}
 150
 151#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
 152/**
 153 * mtd_get_len_incl_bad
 154 *
 155 * Check if length including bad blocks fits into device.
 156 *
 157 * @param mtd an MTD device
 158 * @param offset offset in flash
 159 * @param length image length
 160 * @return image length including bad blocks in *len_incl_bad and whether or not
 161 *         the length returned was truncated in *truncated
 162 */
 163void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
 164                          const uint64_t length, uint64_t *len_incl_bad,
 165                          int *truncated)
 166{
 167        *truncated = 0;
 168        *len_incl_bad = 0;
 169
 170        if (!mtd->block_isbad) {
 171                *len_incl_bad = length;
 172                return;
 173        }
 174
 175        uint64_t len_excl_bad = 0;
 176        uint64_t block_len;
 177
 178        while (len_excl_bad < length) {
 179                if (offset >= mtd->size) {
 180                        *truncated = 1;
 181                        return;
 182                }
 183
 184                block_len = mtd->erasesize - (offset & (mtd->erasesize - 1));
 185
 186                if (!mtd->block_isbad(mtd, offset & ~(mtd->erasesize - 1)))
 187                        len_excl_bad += block_len;
 188
 189                *len_incl_bad += block_len;
 190                offset       += block_len;
 191        }
 192}
 193#endif /* defined(CONFIG_CMD_MTDPARTS_SPREAD) */
 194
 195 /*
 196 * Erase is an asynchronous operation.  Device drivers are supposed
 197 * to call instr->callback() whenever the operation completes, even
 198 * if it completes with a failure.
 199 * Callers are supposed to pass a callback function and wait for it
 200 * to be called before writing to the block.
 201 */
 202int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
 203{
 204        if (instr->addr > mtd->size || instr->len > mtd->size - instr->addr)
 205                return -EINVAL;
 206        if (!(mtd->flags & MTD_WRITEABLE))
 207                return -EROFS;
 208        instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
 209        if (!instr->len) {
 210                instr->state = MTD_ERASE_DONE;
 211                mtd_erase_callback(instr);
 212                return 0;
 213        }
 214        return mtd->_erase(mtd, instr);
 215}
 216
 217int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
 218             u_char *buf)
 219{
 220        if (from < 0 || from > mtd->size || len > mtd->size - from)
 221                return -EINVAL;
 222        if (!len)
 223                return 0;
 224        return mtd->_read(mtd, from, len, retlen, buf);
 225}
 226
 227int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
 228              const u_char *buf)
 229{
 230        *retlen = 0;
 231        if (to < 0 || to > mtd->size || len > mtd->size - to)
 232                return -EINVAL;
 233        if (!mtd->_write || !(mtd->flags & MTD_WRITEABLE))
 234                return -EROFS;
 235        if (!len)
 236                return 0;
 237        return mtd->_write(mtd, to, len, retlen, buf);
 238}
 239
 240/*
 241 * In blackbox flight recorder like scenarios we want to make successful writes
 242 * in interrupt context. panic_write() is only intended to be called when its
 243 * known the kernel is about to panic and we need the write to succeed. Since
 244 * the kernel is not going to be running for much longer, this function can
 245 * break locks and delay to ensure the write succeeds (but not sleep).
 246 */
 247int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
 248                    const u_char *buf)
 249{
 250        *retlen = 0;
 251        if (!mtd->_panic_write)
 252                return -EOPNOTSUPP;
 253        if (to < 0 || to > mtd->size || len > mtd->size - to)
 254                return -EINVAL;
 255        if (!(mtd->flags & MTD_WRITEABLE))
 256                return -EROFS;
 257        if (!len)
 258                return 0;
 259        return mtd->_panic_write(mtd, to, len, retlen, buf);
 260}
 261
 262int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
 263{
 264        ops->retlen = ops->oobretlen = 0;
 265        if (!mtd->_read_oob)
 266                return -EOPNOTSUPP;
 267        return mtd->_read_oob(mtd, from, ops);
 268}
 269
 270/*
 271 * Method to access the protection register area, present in some flash
 272 * devices. The user data is one time programmable but the factory data is read
 273 * only.
 274 */
 275int mtd_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
 276                           size_t len)
 277{
 278        if (!mtd->_get_fact_prot_info)
 279                return -EOPNOTSUPP;
 280        if (!len)
 281                return 0;
 282        return mtd->_get_fact_prot_info(mtd, buf, len);
 283}
 284
 285int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
 286                           size_t *retlen, u_char *buf)
 287{
 288        *retlen = 0;
 289        if (!mtd->_read_fact_prot_reg)
 290                return -EOPNOTSUPP;
 291        if (!len)
 292                return 0;
 293        return mtd->_read_fact_prot_reg(mtd, from, len, retlen, buf);
 294}
 295
 296int mtd_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf,
 297                           size_t len)
 298{
 299        if (!mtd->_get_user_prot_info)
 300                return -EOPNOTSUPP;
 301        if (!len)
 302                return 0;
 303        return mtd->_get_user_prot_info(mtd, buf, len);
 304}
 305
 306int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
 307                           size_t *retlen, u_char *buf)
 308{
 309        *retlen = 0;
 310        if (!mtd->_read_user_prot_reg)
 311                return -EOPNOTSUPP;
 312        if (!len)
 313                return 0;
 314        return mtd->_read_user_prot_reg(mtd, from, len, retlen, buf);
 315}
 316
 317int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
 318                            size_t *retlen, u_char *buf)
 319{
 320        *retlen = 0;
 321        if (!mtd->_write_user_prot_reg)
 322                return -EOPNOTSUPP;
 323        if (!len)
 324                return 0;
 325        return mtd->_write_user_prot_reg(mtd, to, len, retlen, buf);
 326}
 327
 328int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len)
 329{
 330        if (!mtd->_lock_user_prot_reg)
 331                return -EOPNOTSUPP;
 332        if (!len)
 333                return 0;
 334        return mtd->_lock_user_prot_reg(mtd, from, len);
 335}
 336
 337/* Chip-supported device locking */
 338int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 339{
 340        if (!mtd->_lock)
 341                return -EOPNOTSUPP;
 342        if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
 343                return -EINVAL;
 344        if (!len)
 345                return 0;
 346        return mtd->_lock(mtd, ofs, len);
 347}
 348
 349int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 350{
 351        if (!mtd->_unlock)
 352                return -EOPNOTSUPP;
 353        if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
 354                return -EINVAL;
 355        if (!len)
 356                return 0;
 357        return mtd->_unlock(mtd, ofs, len);
 358}
 359
 360int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs)
 361{
 362        if (!mtd->_block_isbad)
 363                return 0;
 364        if (ofs < 0 || ofs > mtd->size)
 365                return -EINVAL;
 366        return mtd->_block_isbad(mtd, ofs);
 367}
 368
 369int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
 370{
 371        if (!mtd->_block_markbad)
 372                return -EOPNOTSUPP;
 373        if (ofs < 0 || ofs > mtd->size)
 374                return -EINVAL;
 375        if (!(mtd->flags & MTD_WRITEABLE))
 376                return -EROFS;
 377        return mtd->_block_markbad(mtd, ofs);
 378}
 379
 380