mtd: rawnand: Reorganize code to avoid forward declarations

Avoid forward declaration of nand_get_device(), nand_do_write_oob()
and nand_update_bbt() by moving functions around.

Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
Tested-by: Janusz Krzysztofik <jmkrzyszt@gmail.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
This commit is contained in:
Boris Brezillon 2018-11-11 08:55:04 +01:00 committed by Miquel Raynal
parent 0813621ba8
commit 99f3351a6d
2 changed files with 246 additions and 254 deletions

View File

@ -49,11 +49,6 @@
#include "internals.h" #include "internals.h"
static int nand_get_device(struct nand_chip *chip, int new_state);
static int nand_do_write_oob(struct nand_chip *chip, loff_t to,
struct mtd_oob_ops *ops);
/* Define default oob placement schemes for large and small page devices */ /* Define default oob placement schemes for large and small page devices */
static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section, static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion) struct mtd_oob_region *oobregion)
@ -286,6 +281,197 @@ static int nand_block_bad(struct nand_chip *chip, loff_t ofs)
return 0; return 0;
} }
static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs)
{
if (chip->legacy.block_bad)
return chip->legacy.block_bad(chip, ofs);
return nand_block_bad(chip, ofs);
}
/**
* panic_nand_get_device - [GENERIC] Get chip for selected access
* @chip: the nand chip descriptor
* @new_state: the state which is requested
*
* Used when in panic, no locks are taken.
*/
static void panic_nand_get_device(struct nand_chip *chip, int new_state)
{
/* Hardware controller shared among independent devices */
chip->controller->active = chip;
chip->state = new_state;
}
/**
* nand_get_device - [GENERIC] Get chip for selected access
* @chip: NAND chip structure
* @new_state: the state which is requested
*
* Get the device and lock it for exclusive access
*/
static int
nand_get_device(struct nand_chip *chip, int new_state)
{
spinlock_t *lock = &chip->controller->lock;
wait_queue_head_t *wq = &chip->controller->wq;
DECLARE_WAITQUEUE(wait, current);
retry:
spin_lock(lock);
/* Hardware controller shared among independent devices */
if (!chip->controller->active)
chip->controller->active = chip;
if (chip->controller->active == chip && chip->state == FL_READY) {
chip->state = new_state;
spin_unlock(lock);
return 0;
}
if (new_state == FL_PM_SUSPENDED) {
if (chip->controller->active->state == FL_PM_SUSPENDED) {
chip->state = FL_PM_SUSPENDED;
spin_unlock(lock);
return 0;
}
}
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(wq, &wait);
spin_unlock(lock);
schedule();
remove_wait_queue(wq, &wait);
goto retry;
}
/**
* nand_check_wp - [GENERIC] check if the chip is write protected
* @chip: NAND chip object
*
* Check, if the device is write protected. The function expects, that the
* device is already selected.
*/
static int nand_check_wp(struct nand_chip *chip)
{
u8 status;
int ret;
/* Broken xD cards report WP despite being writable */
if (chip->options & NAND_BROKEN_XD)
return 0;
/* Check the WP bit */
ret = nand_status_op(chip, &status);
if (ret)
return ret;
return status & NAND_STATUS_WP ? 0 : 1;
}
/**
* nand_fill_oob - [INTERN] Transfer client buffer to oob
* @oob: oob data buffer
* @len: oob data write length
* @ops: oob ops structure
*/
static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len,
struct mtd_oob_ops *ops)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
/*
* Initialise to all 0xFF, to avoid the possibility of left over OOB
* data from a previous OOB read.
*/
memset(chip->oob_poi, 0xff, mtd->oobsize);
switch (ops->mode) {
case MTD_OPS_PLACE_OOB:
case MTD_OPS_RAW:
memcpy(chip->oob_poi + ops->ooboffs, oob, len);
return oob + len;
case MTD_OPS_AUTO_OOB:
ret = mtd_ooblayout_set_databytes(mtd, oob, chip->oob_poi,
ops->ooboffs, len);
BUG_ON(ret);
return oob + len;
default:
BUG();
}
return NULL;
}
/**
* nand_do_write_oob - [MTD Interface] NAND write out-of-band
* @chip: NAND chip object
* @to: offset to write to
* @ops: oob operation description structure
*
* NAND write out-of-band.
*/
static int nand_do_write_oob(struct nand_chip *chip, loff_t to,
struct mtd_oob_ops *ops)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int chipnr, page, status, len;
pr_debug("%s: to = 0x%08x, len = %i\n",
__func__, (unsigned int)to, (int)ops->ooblen);
len = mtd_oobavail(mtd, ops);
/* Do not allow write past end of page */
if ((ops->ooboffs + ops->ooblen) > len) {
pr_debug("%s: attempt to write past end of page\n",
__func__);
return -EINVAL;
}
chipnr = (int)(to >> chip->chip_shift);
/*
* Reset the chip. Some chips (like the Toshiba TC5832DC found in one
* of my DiskOnChip 2000 test units) will clear the whole data page too
* if we don't do this. I have no clue why, but I seem to have 'fixed'
* it in the doc2000 driver in August 1999. dwmw2.
*/
nand_reset(chip, chipnr);
chip->select_chip(chip, chipnr);
/* Shift to get page */
page = (int)(to >> chip->page_shift);
/* Check, if it is write protected */
if (nand_check_wp(chip)) {
chip->select_chip(chip, -1);
return -EROFS;
}
/* Invalidate the page cache, if we write to the cached page */
if (page == chip->pagebuf)
chip->pagebuf = -1;
nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops);
if (ops->mode == MTD_OPS_RAW)
status = chip->ecc.write_oob_raw(chip, page & chip->pagemask);
else
status = chip->ecc.write_oob(chip, page & chip->pagemask);
chip->select_chip(chip, -1);
if (status)
return status;
ops->oobretlen = ops->ooblen;
return 0;
}
/** /**
* nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker
* @chip: NAND chip object * @chip: NAND chip object
@ -341,14 +527,6 @@ int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs)
return nand_default_block_markbad(chip, ofs); return nand_default_block_markbad(chip, ofs);
} }
static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs)
{
if (chip->legacy.block_bad)
return chip->legacy.block_bad(chip, ofs);
return nand_block_bad(chip, ofs);
}
/** /**
* nand_block_markbad_lowlevel - mark a block bad * nand_block_markbad_lowlevel - mark a block bad
* @chip: NAND chip object * @chip: NAND chip object
@ -401,30 +579,6 @@ static int nand_block_markbad_lowlevel(struct nand_chip *chip, loff_t ofs)
return ret; return ret;
} }
/**
* nand_check_wp - [GENERIC] check if the chip is write protected
* @chip: NAND chip object
*
* Check, if the device is write protected. The function expects, that the
* device is already selected.
*/
static int nand_check_wp(struct nand_chip *chip)
{
u8 status;
int ret;
/* Broken xD cards report WP despite being writable */
if (chip->options & NAND_BROKEN_XD)
return 0;
/* Check the WP bit */
ret = nand_status_op(chip, &status);
if (ret)
return ret;
return status & NAND_STATUS_WP ? 0 : 1;
}
/** /**
* nand_block_isreserved - [GENERIC] Check if a block is marked reserved. * nand_block_isreserved - [GENERIC] Check if a block is marked reserved.
* @mtd: MTD device structure * @mtd: MTD device structure
@ -555,60 +709,6 @@ int nand_gpio_waitrdy(struct nand_chip *chip, struct gpio_desc *gpiod,
}; };
EXPORT_SYMBOL_GPL(nand_gpio_waitrdy); EXPORT_SYMBOL_GPL(nand_gpio_waitrdy);
/**
* panic_nand_get_device - [GENERIC] Get chip for selected access
* @chip: the nand chip descriptor
* @new_state: the state which is requested
*
* Used when in panic, no locks are taken.
*/
static void panic_nand_get_device(struct nand_chip *chip, int new_state)
{
/* Hardware controller shared among independent devices */
chip->controller->active = chip;
chip->state = new_state;
}
/**
* nand_get_device - [GENERIC] Get chip for selected access
* @chip: NAND chip structure
* @new_state: the state which is requested
*
* Get the device and lock it for exclusive access
*/
static int
nand_get_device(struct nand_chip *chip, int new_state)
{
spinlock_t *lock = &chip->controller->lock;
wait_queue_head_t *wq = &chip->controller->wq;
DECLARE_WAITQUEUE(wait, current);
retry:
spin_lock(lock);
/* Hardware controller shared among independent devices */
if (!chip->controller->active)
chip->controller->active = chip;
if (chip->controller->active == chip && chip->state == FL_READY) {
chip->state = new_state;
spin_unlock(lock);
return 0;
}
if (new_state == FL_PM_SUSPENDED) {
if (chip->controller->active->state == FL_PM_SUSPENDED) {
chip->state = FL_PM_SUSPENDED;
spin_unlock(lock);
return 0;
}
}
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(wq, &wait);
spin_unlock(lock);
schedule();
remove_wait_queue(wq, &wait);
goto retry;
}
/** /**
* panic_nand_wait - [GENERIC] wait until the command is done * panic_nand_wait - [GENERIC] wait until the command is done
* @chip: NAND chip structure * @chip: NAND chip structure
@ -3807,44 +3907,6 @@ static int nand_write_page(struct nand_chip *chip, uint32_t offset,
return 0; return 0;
} }
/**
* nand_fill_oob - [INTERN] Transfer client buffer to oob
* @chip: NAND chip object
* @oob: oob data buffer
* @len: oob data write length
* @ops: oob ops structure
*/
static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len,
struct mtd_oob_ops *ops)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
/*
* Initialise to all 0xFF, to avoid the possibility of left over OOB
* data from a previous OOB read.
*/
memset(chip->oob_poi, 0xff, mtd->oobsize);
switch (ops->mode) {
case MTD_OPS_PLACE_OOB:
case MTD_OPS_RAW:
memcpy(chip->oob_poi + ops->ooboffs, oob, len);
return oob + len;
case MTD_OPS_AUTO_OOB:
ret = mtd_ooblayout_set_databytes(mtd, oob, chip->oob_poi,
ops->ooboffs, len);
BUG_ON(ret);
return oob + len;
default:
BUG();
}
return NULL;
}
#define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0) #define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0)
/** /**
@ -4012,74 +4074,6 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
return ret; return ret;
} }
/**
* nand_do_write_oob - [MTD Interface] NAND write out-of-band
* @chip: NAND chip object
* @to: offset to write to
* @ops: oob operation description structure
*
* NAND write out-of-band.
*/
static int nand_do_write_oob(struct nand_chip *chip, loff_t to,
struct mtd_oob_ops *ops)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int chipnr, page, status, len;
pr_debug("%s: to = 0x%08x, len = %i\n",
__func__, (unsigned int)to, (int)ops->ooblen);
len = mtd_oobavail(mtd, ops);
/* Do not allow write past end of page */
if ((ops->ooboffs + ops->ooblen) > len) {
pr_debug("%s: attempt to write past end of page\n",
__func__);
return -EINVAL;
}
chipnr = (int)(to >> chip->chip_shift);
/*
* Reset the chip. Some chips (like the Toshiba TC5832DC found in one
* of my DiskOnChip 2000 test units) will clear the whole data page too
* if we don't do this. I have no clue why, but I seem to have 'fixed'
* it in the doc2000 driver in August 1999. dwmw2.
*/
nand_reset(chip, chipnr);
chip->select_chip(chip, chipnr);
/* Shift to get page */
page = (int)(to >> chip->page_shift);
/* Check, if it is write protected */
if (nand_check_wp(chip)) {
chip->select_chip(chip, -1);
return -EROFS;
}
/* Invalidate the page cache, if we write to the cached page */
if (page == chip->pagebuf)
chip->pagebuf = -1;
nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops);
if (ops->mode == MTD_OPS_RAW)
status = chip->ecc.write_oob_raw(chip, page & chip->pagemask);
else
status = chip->ecc.write_oob(chip, page & chip->pagemask);
chip->select_chip(chip, -1);
if (status)
return status;
ops->oobretlen = ops->ooblen;
return 0;
}
/** /**
* nand_write_oob - [MTD Interface] NAND write data and/or out-of-band * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band
* @mtd: MTD device structure * @mtd: MTD device structure

View File

@ -77,8 +77,6 @@
#define BBT_ENTRY_MASK 0x03 #define BBT_ENTRY_MASK 0x03
#define BBT_ENTRY_SHIFT 2 #define BBT_ENTRY_SHIFT 2
static int nand_update_bbt(struct nand_chip *chip, loff_t offs);
static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block) static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block)
{ {
uint8_t entry = chip->bbt[block >> BBT_ENTRY_SHIFT]; uint8_t entry = chip->bbt[block >> BBT_ENTRY_SHIFT];
@ -1034,6 +1032,61 @@ static int check_create(struct nand_chip *this, uint8_t *buf,
return 0; return 0;
} }
/**
* nand_update_bbt - update bad block table(s)
* @this: the NAND device
* @offs: the offset of the newly marked block
*
* The function updates the bad block table(s).
*/
static int nand_update_bbt(struct nand_chip *this, loff_t offs)
{
struct mtd_info *mtd = nand_to_mtd(this);
int len, res = 0;
int chip, chipsel;
uint8_t *buf;
struct nand_bbt_descr *td = this->bbt_td;
struct nand_bbt_descr *md = this->bbt_md;
if (!this->bbt || !td)
return -EINVAL;
/* Allocate a temporary buffer for one eraseblock incl. oob */
len = (1 << this->bbt_erase_shift);
len += (len >> this->page_shift) * mtd->oobsize;
buf = kmalloc(len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
/* Do we have a bbt per chip? */
if (td->options & NAND_BBT_PERCHIP) {
chip = (int)(offs >> this->chip_shift);
chipsel = chip;
} else {
chip = 0;
chipsel = -1;
}
td->version[chip]++;
if (md)
md->version[chip]++;
/* Write the bad block table to the device? */
if (td->options & NAND_BBT_WRITE) {
res = write_bbt(this, buf, td, md, chipsel);
if (res < 0)
goto out;
}
/* Write the mirror bad block table to the device? */
if (md && (md->options & NAND_BBT_WRITE)) {
res = write_bbt(this, buf, md, td, chipsel);
}
out:
kfree(buf);
return res;
}
/** /**
* mark_bbt_regions - [GENERIC] mark the bad block table regions * mark_bbt_regions - [GENERIC] mark the bad block table regions
* @this: the NAND device * @this: the NAND device
@ -1220,61 +1273,6 @@ err:
return res; return res;
} }
/**
* nand_update_bbt - update bad block table(s)
* @this: the NAND device
* @offs: the offset of the newly marked block
*
* The function updates the bad block table(s).
*/
static int nand_update_bbt(struct nand_chip *this, loff_t offs)
{
struct mtd_info *mtd = nand_to_mtd(this);
int len, res = 0;
int chip, chipsel;
uint8_t *buf;
struct nand_bbt_descr *td = this->bbt_td;
struct nand_bbt_descr *md = this->bbt_md;
if (!this->bbt || !td)
return -EINVAL;
/* Allocate a temporary buffer for one eraseblock incl. oob */
len = (1 << this->bbt_erase_shift);
len += (len >> this->page_shift) * mtd->oobsize;
buf = kmalloc(len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
/* Do we have a bbt per chip? */
if (td->options & NAND_BBT_PERCHIP) {
chip = (int)(offs >> this->chip_shift);
chipsel = chip;
} else {
chip = 0;
chipsel = -1;
}
td->version[chip]++;
if (md)
md->version[chip]++;
/* Write the bad block table to the device? */
if (td->options & NAND_BBT_WRITE) {
res = write_bbt(this, buf, td, md, chipsel);
if (res < 0)
goto out;
}
/* Write the mirror bad block table to the device? */
if (md && (md->options & NAND_BBT_WRITE)) {
res = write_bbt(this, buf, md, td, chipsel);
}
out:
kfree(buf);
return res;
}
/* /*
* Define some generic bad / good block scan pattern which are used * Define some generic bad / good block scan pattern which are used
* while scanning a device for factory marked good / bad blocks. * while scanning a device for factory marked good / bad blocks.