bbt.c 3.4 KB

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