root/drivers/mtd/nand/bbt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nanddev_bbt_init
  2. nanddev_bbt_cleanup
  3. nanddev_bbt_update
  4. nanddev_bbt_get_block_status
  5. nanddev_bbt_set_block_status

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (c) 2017 Free Electrons
   4  *
   5  * Authors:
   6  *      Boris Brezillon <boris.brezillon@free-electrons.com>
   7  *      Peter Pan <peterpandong@micron.com>
   8  */
   9 
  10 #define pr_fmt(fmt)     "nand-bbt: " fmt
  11 
  12 #include <linux/mtd/nand.h>
  13 #include <linux/slab.h>
  14 
  15 /**
  16  * nanddev_bbt_init() - Initialize the BBT (Bad Block Table)
  17  * @nand: NAND device
  18  *
  19  * Initialize the in-memory BBT.
  20  *
  21  * Return: 0 in case of success, a negative error code otherwise.
  22  */
  23 int nanddev_bbt_init(struct nand_device *nand)
  24 {
  25         unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
  26         unsigned int nblocks = nanddev_neraseblocks(nand);
  27         unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block,
  28                                            BITS_PER_LONG);
  29 
  30         nand->bbt.cache = kcalloc(nwords, sizeof(*nand->bbt.cache),
  31                                   GFP_KERNEL);
  32         if (!nand->bbt.cache)
  33                 return -ENOMEM;
  34 
  35         return 0;
  36 }
  37 EXPORT_SYMBOL_GPL(nanddev_bbt_init);
  38 
  39 /**
  40  * nanddev_bbt_cleanup() - Cleanup the BBT (Bad Block Table)
  41  * @nand: NAND device
  42  *
  43  * Undoes what has been done in nanddev_bbt_init()
  44  */
  45 void nanddev_bbt_cleanup(struct nand_device *nand)
  46 {
  47         kfree(nand->bbt.cache);
  48 }
  49 EXPORT_SYMBOL_GPL(nanddev_bbt_cleanup);
  50 
  51 /**
  52  * nanddev_bbt_update() - Update a BBT
  53  * @nand: nand device
  54  *
  55  * Update the BBT. Currently a NOP function since on-flash bbt is not yet
  56  * supported.
  57  *
  58  * Return: 0 in case of success, a negative error code otherwise.
  59  */
  60 int nanddev_bbt_update(struct nand_device *nand)
  61 {
  62         return 0;
  63 }
  64 EXPORT_SYMBOL_GPL(nanddev_bbt_update);
  65 
  66 /**
  67  * nanddev_bbt_get_block_status() - Return the status of an eraseblock
  68  * @nand: nand device
  69  * @entry: the BBT entry
  70  *
  71  * Return: a positive number nand_bbt_block_status status or -%ERANGE if @entry
  72  *         is bigger than the BBT size.
  73  */
  74 int nanddev_bbt_get_block_status(const struct nand_device *nand,
  75                                  unsigned int entry)
  76 {
  77         unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
  78         unsigned long *pos = nand->bbt.cache +
  79                              ((entry * bits_per_block) / BITS_PER_LONG);
  80         unsigned int offs = (entry * bits_per_block) % BITS_PER_LONG;
  81         unsigned long status;
  82 
  83         if (entry >= nanddev_neraseblocks(nand))
  84                 return -ERANGE;
  85 
  86         status = pos[0] >> offs;
  87         if (bits_per_block + offs > BITS_PER_LONG)
  88                 status |= pos[1] << (BITS_PER_LONG - offs);
  89 
  90         return status & GENMASK(bits_per_block - 1, 0);
  91 }
  92 EXPORT_SYMBOL_GPL(nanddev_bbt_get_block_status);
  93 
  94 /**
  95  * nanddev_bbt_set_block_status() - Update the status of an eraseblock in the
  96  *                                  in-memory BBT
  97  * @nand: nand device
  98  * @entry: the BBT entry to update
  99  * @status: the new status
 100  *
 101  * Update an entry of the in-memory BBT. If you want to push the updated BBT
 102  * the NAND you should call nanddev_bbt_update().
 103  *
 104  * Return: 0 in case of success or -%ERANGE if @entry is bigger than the BBT
 105  *         size.
 106  */
 107 int nanddev_bbt_set_block_status(struct nand_device *nand, unsigned int entry,
 108                                  enum nand_bbt_block_status status)
 109 {
 110         unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
 111         unsigned long *pos = nand->bbt.cache +
 112                              ((entry * bits_per_block) / BITS_PER_LONG);
 113         unsigned int offs = (entry * bits_per_block) % BITS_PER_LONG;
 114         unsigned long val = status & GENMASK(bits_per_block - 1, 0);
 115 
 116         if (entry >= nanddev_neraseblocks(nand))
 117                 return -ERANGE;
 118 
 119         pos[0] &= ~GENMASK(offs + bits_per_block - 1, offs);
 120         pos[0] |= val << offs;
 121 
 122         if (bits_per_block + offs > BITS_PER_LONG) {
 123                 unsigned int rbits = bits_per_block + offs - BITS_PER_LONG;
 124 
 125                 pos[1] &= ~GENMASK(rbits - 1, 0);
 126                 pos[1] |= val >> rbits;
 127         }
 128 
 129         return 0;
 130 }
 131 EXPORT_SYMBOL_GPL(nanddev_bbt_set_block_status);

/* [<][>][^][v][top][bottom][index][help] */