Skip to content

Commit 8cba323

Browse files
sknseanmiquelraynal
authored andcommitted
mtd: rawnand: protect access to rawnand devices while in suspend
Prevent rawnand access while in a suspended state. Commit 013e629 ("mtd: rawnand: Simplify the locking") allows the rawnand layer to return errors rather than waiting in a blocking wait. Tested on a iMX6ULL. Fixes: 013e629 ("mtd: rawnand: Simplify the locking") Signed-off-by: Sean Nyekjaer <[email protected]> Reviewed-by: Boris Brezillon <[email protected]> Cc: [email protected] Signed-off-by: Miquel Raynal <[email protected]> Link: https://lore.kernel.org/linux-mtd/[email protected]
1 parent d430e4a commit 8cba323

File tree

2 files changed

+22
-24
lines changed

2 files changed

+22
-24
lines changed

drivers/mtd/nand/raw/nand_base.c

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -338,16 +338,19 @@ static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs)
338338
*
339339
* Return: -EBUSY if the chip has been suspended, 0 otherwise
340340
*/
341-
static int nand_get_device(struct nand_chip *chip)
341+
static void nand_get_device(struct nand_chip *chip)
342342
{
343-
mutex_lock(&chip->lock);
344-
if (chip->suspended) {
343+
/* Wait until the device is resumed. */
344+
while (1) {
345+
mutex_lock(&chip->lock);
346+
if (!chip->suspended) {
347+
mutex_lock(&chip->controller->lock);
348+
return;
349+
}
345350
mutex_unlock(&chip->lock);
346-
return -EBUSY;
347-
}
348-
mutex_lock(&chip->controller->lock);
349351

350-
return 0;
352+
wait_event(chip->resume_wq, !chip->suspended);
353+
}
351354
}
352355

353356
/**
@@ -576,9 +579,7 @@ static int nand_block_markbad_lowlevel(struct nand_chip *chip, loff_t ofs)
576579
nand_erase_nand(chip, &einfo, 0);
577580

578581
/* Write bad block marker to OOB */
579-
ret = nand_get_device(chip);
580-
if (ret)
581-
return ret;
582+
nand_get_device(chip);
582583

583584
ret = nand_markbad_bbm(chip, ofs);
584585
nand_release_device(chip);
@@ -3826,9 +3827,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
38263827
ops->mode != MTD_OPS_RAW)
38273828
return -ENOTSUPP;
38283829

3829-
ret = nand_get_device(chip);
3830-
if (ret)
3831-
return ret;
3830+
nand_get_device(chip);
38323831

38333832
if (!ops->datbuf)
38343833
ret = nand_do_read_oob(chip, from, ops);
@@ -4415,13 +4414,11 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
44154414
struct mtd_oob_ops *ops)
44164415
{
44174416
struct nand_chip *chip = mtd_to_nand(mtd);
4418-
int ret;
4417+
int ret = 0;
44194418

44204419
ops->retlen = 0;
44214420

4422-
ret = nand_get_device(chip);
4423-
if (ret)
4424-
return ret;
4421+
nand_get_device(chip);
44254422

44264423
switch (ops->mode) {
44274424
case MTD_OPS_PLACE_OOB:
@@ -4481,9 +4478,7 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
44814478
return -EIO;
44824479

44834480
/* Grab the lock and see if the device is available */
4484-
ret = nand_get_device(chip);
4485-
if (ret)
4486-
return ret;
4481+
nand_get_device(chip);
44874482

44884483
/* Shift to get first page */
44894484
page = (int)(instr->addr >> chip->page_shift);
@@ -4570,7 +4565,7 @@ static void nand_sync(struct mtd_info *mtd)
45704565
pr_debug("%s: called\n", __func__);
45714566

45724567
/* Grab the lock and see if the device is available */
4573-
WARN_ON(nand_get_device(chip));
4568+
nand_get_device(chip);
45744569
/* Release it and go back */
45754570
nand_release_device(chip);
45764571
}
@@ -4587,9 +4582,7 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
45874582
int ret;
45884583

45894584
/* Select the NAND device */
4590-
ret = nand_get_device(chip);
4591-
if (ret)
4592-
return ret;
4585+
nand_get_device(chip);
45934586

45944587
nand_select_target(chip, chipnr);
45954588

@@ -4660,6 +4653,8 @@ static void nand_resume(struct mtd_info *mtd)
46604653
__func__);
46614654
}
46624655
mutex_unlock(&chip->lock);
4656+
4657+
wake_up_all(&chip->resume_wq);
46634658
}
46644659

46654660
/**
@@ -5438,6 +5433,7 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
54385433
chip->cur_cs = -1;
54395434

54405435
mutex_init(&chip->lock);
5436+
init_waitqueue_head(&chip->resume_wq);
54415437

54425438
/* Enforce the right timings for reset/detection */
54435439
chip->current_interface_config = nand_get_reset_interface_config();

include/linux/mtd/rawnand.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,6 +1240,7 @@ struct nand_secure_region {
12401240
* @lock: Lock protecting the suspended field. Also used to serialize accesses
12411241
* to the NAND device
12421242
* @suspended: Set to 1 when the device is suspended, 0 when it's not
1243+
* @resume_wq: wait queue to sleep if rawnand is in suspended state.
12431244
* @cur_cs: Currently selected target. -1 means no target selected, otherwise we
12441245
* should always have cur_cs >= 0 && cur_cs < nanddev_ntargets().
12451246
* NAND Controller drivers should not modify this value, but they're
@@ -1294,6 +1295,7 @@ struct nand_chip {
12941295
/* Internals */
12951296
struct mutex lock;
12961297
unsigned int suspended : 1;
1298+
wait_queue_head_t resume_wq;
12971299
int cur_cs;
12981300
int read_retries;
12991301
struct nand_secure_region *secure_regions;

0 commit comments

Comments
 (0)