0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #define pr_fmt(fmt) "nand-bbt: " fmt
0011
0012 #include <linux/mtd/nand.h>
0013 #include <linux/slab.h>
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 int nanddev_bbt_init(struct nand_device *nand)
0024 {
0025 unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
0026 unsigned int nblocks = nanddev_neraseblocks(nand);
0027 unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block,
0028 BITS_PER_LONG);
0029
0030 nand->bbt.cache = kcalloc(nwords, sizeof(*nand->bbt.cache),
0031 GFP_KERNEL);
0032 if (!nand->bbt.cache)
0033 return -ENOMEM;
0034
0035 return 0;
0036 }
0037 EXPORT_SYMBOL_GPL(nanddev_bbt_init);
0038
0039
0040
0041
0042
0043
0044
0045 void nanddev_bbt_cleanup(struct nand_device *nand)
0046 {
0047 kfree(nand->bbt.cache);
0048 }
0049 EXPORT_SYMBOL_GPL(nanddev_bbt_cleanup);
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060 int nanddev_bbt_update(struct nand_device *nand)
0061 {
0062 return 0;
0063 }
0064 EXPORT_SYMBOL_GPL(nanddev_bbt_update);
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074 int nanddev_bbt_get_block_status(const struct nand_device *nand,
0075 unsigned int entry)
0076 {
0077 unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
0078 unsigned long *pos = nand->bbt.cache +
0079 ((entry * bits_per_block) / BITS_PER_LONG);
0080 unsigned int offs = (entry * bits_per_block) % BITS_PER_LONG;
0081 unsigned long status;
0082
0083 if (entry >= nanddev_neraseblocks(nand))
0084 return -ERANGE;
0085
0086 status = pos[0] >> offs;
0087 if (bits_per_block + offs > BITS_PER_LONG)
0088 status |= pos[1] << (BITS_PER_LONG - offs);
0089
0090 return status & GENMASK(bits_per_block - 1, 0);
0091 }
0092 EXPORT_SYMBOL_GPL(nanddev_bbt_get_block_status);
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107 int nanddev_bbt_set_block_status(struct nand_device *nand, unsigned int entry,
0108 enum nand_bbt_block_status status)
0109 {
0110 unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
0111 unsigned long *pos = nand->bbt.cache +
0112 ((entry * bits_per_block) / BITS_PER_LONG);
0113 unsigned int offs = (entry * bits_per_block) % BITS_PER_LONG;
0114 unsigned long val = status & GENMASK(bits_per_block - 1, 0);
0115
0116 if (entry >= nanddev_neraseblocks(nand))
0117 return -ERANGE;
0118
0119 pos[0] &= ~GENMASK(offs + bits_per_block - 1, offs);
0120 pos[0] |= val << offs;
0121
0122 if (bits_per_block + offs > BITS_PER_LONG) {
0123 unsigned int rbits = bits_per_block + offs - BITS_PER_LONG;
0124
0125 pos[1] &= ~GENMASK(rbits - 1, 0);
0126 pos[1] |= val >> (bits_per_block - rbits);
0127 }
0128
0129 return 0;
0130 }
0131 EXPORT_SYMBOL_GPL(nanddev_bbt_set_block_status);