cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

bbt.c (3572B)


      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 */
     23int 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}
     37EXPORT_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 */
     45void nanddev_bbt_cleanup(struct nand_device *nand)
     46{
     47	kfree(nand->bbt.cache);
     48}
     49EXPORT_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 */
     60int nanddev_bbt_update(struct nand_device *nand)
     61{
     62	return 0;
     63}
     64EXPORT_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 */
     74int 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}
     92EXPORT_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 */
    107int 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 >> (bits_per_block - rbits);
    127	}
    128
    129	return 0;
    130}
    131EXPORT_SYMBOL_GPL(nanddev_bbt_set_block_status);