Commit 2af7c653 authored by Simon Kagstrom's avatar Simon Kagstrom Committed by David Woodhouse

mtd: Add panic_write for NAND flashes

This is a quick and dirty patch to add panic_write for NAND flashes. The
patch seems to work OK on my CRIS board running a 2.6.26 kernel with a
ID: 0x20, Chip ID: 0xf1 (ST Micro NAND 128MiB 3,3V 8-bit), and also on a
OpenRD base (Marvell Kirkwood) board with a Toshiba NAND 512MiB 3,3V
8-bit flash with 2.6.32-pre1.
Signed-off-by: default avatarEdgar E. Iglesias <edgar@axis.com>
Signed-off-by: default avatarSimon Kagstrom <simon.kagstrom@netinsight.net>
Signed-off-by: default avatarArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent c9f7ec30
...@@ -428,6 +428,28 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, ...@@ -428,6 +428,28 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
return nand_isbad_bbt(mtd, ofs, allowbbt); return nand_isbad_bbt(mtd, ofs, allowbbt);
} }
/**
* panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
* @mtd: MTD device structure
* @timeo: Timeout
*
* Helper function for nand_wait_ready used when needing to wait in interrupt
* context.
*/
static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
{
struct nand_chip *chip = mtd->priv;
int i;
/* Wait for the device to get ready */
for (i = 0; i < timeo; i++) {
if (chip->dev_ready(mtd))
break;
touch_softlockup_watchdog();
mdelay(1);
}
}
/* /*
* Wait for the ready pin, after a command * Wait for the ready pin, after a command
* The timeout is catched later. * The timeout is catched later.
...@@ -437,6 +459,10 @@ void nand_wait_ready(struct mtd_info *mtd) ...@@ -437,6 +459,10 @@ void nand_wait_ready(struct mtd_info *mtd)
struct nand_chip *chip = mtd->priv; struct nand_chip *chip = mtd->priv;
unsigned long timeo = jiffies + 2; unsigned long timeo = jiffies + 2;
/* 400ms timeout */
if (in_interrupt() || oops_in_progress)
return panic_nand_wait_ready(mtd, 400);
led_trigger_event(nand_led_trigger, LED_FULL); led_trigger_event(nand_led_trigger, LED_FULL);
/* wait until command is processed or timeout occures */ /* wait until command is processed or timeout occures */
do { do {
...@@ -671,6 +697,22 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, ...@@ -671,6 +697,22 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
nand_wait_ready(mtd); nand_wait_ready(mtd);
} }
/**
* panic_nand_get_device - [GENERIC] Get chip for selected access
* @chip: the nand chip descriptor
* @mtd: MTD device structure
* @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,
struct mtd_info *mtd, int new_state)
{
/* Hardware controller shared among independend devices */
chip->controller->active = chip;
chip->state = new_state;
}
/** /**
* nand_get_device - [GENERIC] Get chip for selected access * nand_get_device - [GENERIC] Get chip for selected access
* @chip: the nand chip descriptor * @chip: the nand chip descriptor
...@@ -709,6 +751,32 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) ...@@ -709,6 +751,32 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)
goto retry; goto retry;
} }
/**
* panic_nand_wait - [GENERIC] wait until the command is done
* @mtd: MTD device structure
* @chip: NAND chip structure
* @timeo: Timeout
*
* Wait for command done. This is a helper function for nand_wait used when
* we are in interrupt context. May happen when in panic and trying to write
* an oops trough mtdoops.
*/
static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
unsigned long timeo)
{
int i;
for (i = 0; i < timeo; i++) {
if (chip->dev_ready) {
if (chip->dev_ready(mtd))
break;
} else {
if (chip->read_byte(mtd) & NAND_STATUS_READY)
break;
}
mdelay(1);
}
}
/** /**
* nand_wait - [DEFAULT] wait until the command is done * nand_wait - [DEFAULT] wait until the command is done
* @mtd: MTD device structure * @mtd: MTD device structure
...@@ -740,15 +808,19 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) ...@@ -740,15 +808,19 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
else else
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
while (time_before(jiffies, timeo)) { if (in_interrupt() || oops_in_progress)
if (chip->dev_ready) { panic_nand_wait(mtd, chip, timeo);
if (chip->dev_ready(mtd)) else {
break; while (time_before(jiffies, timeo)) {
} else { if (chip->dev_ready) {
if (chip->read_byte(mtd) & NAND_STATUS_READY) if (chip->dev_ready(mtd))
break; break;
} else {
if (chip->read_byte(mtd) & NAND_STATUS_READY)
break;
}
cond_resched();
} }
cond_resched();
} }
led_trigger_event(nand_led_trigger, LED_OFF); led_trigger_event(nand_led_trigger, LED_OFF);
...@@ -1948,6 +2020,45 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, ...@@ -1948,6 +2020,45 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
return ret; return ret;
} }
/**
* panic_nand_write - [MTD Interface] NAND write with ECC
* @mtd: MTD device structure
* @to: offset to write to
* @len: number of bytes to write
* @retlen: pointer to variable to store the number of written bytes
* @buf: the data to write
*
* NAND write with ECC. Used when performing writes in interrupt context, this
* may for example be called by mtdoops when writing an oops while in panic.
*/
static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const uint8_t *buf)
{
struct nand_chip *chip = mtd->priv;
int ret;
/* Do not allow reads past end of device */
if ((to + len) > mtd->size)
return -EINVAL;
if (!len)
return 0;
/* Wait for the device to get ready. */
panic_nand_wait(mtd, chip, 400);
/* Grab the device. */
panic_nand_get_device(chip, mtd, FL_WRITING);
chip->ops.len = len;
chip->ops.datbuf = (uint8_t *)buf;
chip->ops.oobbuf = NULL;
ret = nand_do_write_ops(mtd, to, &chip->ops);
*retlen = chip->ops.retlen;
return ret;
}
/** /**
* nand_write - [MTD Interface] NAND write with ECC * nand_write - [MTD Interface] NAND write with ECC
* @mtd: MTD device structure * @mtd: MTD device structure
...@@ -2877,6 +2988,7 @@ int nand_scan_tail(struct mtd_info *mtd) ...@@ -2877,6 +2988,7 @@ int nand_scan_tail(struct mtd_info *mtd)
mtd->unpoint = NULL; mtd->unpoint = NULL;
mtd->read = nand_read; mtd->read = nand_read;
mtd->write = nand_write; mtd->write = nand_write;
mtd->panic_write = panic_nand_write;
mtd->read_oob = nand_read_oob; mtd->read_oob = nand_read_oob;
mtd->write_oob = nand_write_oob; mtd->write_oob = nand_write_oob;
mtd->sync = nand_sync; mtd->sync = nand_sync;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment