Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6e506079 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://git.infradead.org/mtd-2.6:
  [MTD] [NOR] Fix deadlock in Intel chip driver caused by get_chip recursion
  [JFFS2] Fix return value from jffs2_write_end()
  [MTD] [OneNAND] Fix wrong free the static address in onenand_sim
  [MTD] [NAND] Replace -1 with -EBADMSG in nand error correction code
  [RSLIB] BUG() when passing illegal parameters to decode_rs8() or decode_rs16()
  [MTD] [NAND] treat any negative return value from correct() as an error
  [MTD] [NAND] nandsim: bugfix in initialization
  [MTD] Fix typo in Alauda config option help text.
  [MTD] [NAND] add s3c2440-specific read_buf/write_buf
  [MTD] [OneNAND] onenand-sim: fix kernel-doc and typos
  [JFFS2] Tidy up fix for ACL/permissions problem.
parents f3344c54 5a37cf19
Loading
Loading
Loading
Loading
+77 −69
Original line number Diff line number Diff line
@@ -85,6 +85,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
			size_t len);

static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr);
#include "fwh_lock.h"
@@ -641,73 +642,13 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
/*
 *  *********** CHIP ACCESS FUNCTIONS ***********
 */

static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
{
	DECLARE_WAITQUEUE(wait, current);
	struct cfi_private *cfi = map->fldrv_priv;
	map_word status, status_OK = CMD(0x80), status_PWS = CMD(0x01);
	unsigned long timeo;
	struct cfi_pri_intelext *cfip = cfi->cmdset_priv;

 resettime:
	timeo = jiffies + HZ;
 retry:
	if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) {
		/*
		 * OK. We have possibility for contension on the write/erase
		 * operations which are global to the real chip and not per
		 * partition.  So let's fight it over in the partition which
		 * currently has authority on the operation.
		 *
		 * The rules are as follows:
		 *
		 * - any write operation must own shared->writing.
		 *
		 * - any erase operation must own _both_ shared->writing and
		 *   shared->erasing.
		 *
		 * - contension arbitration is handled in the owner's context.
		 *
		 * The 'shared' struct can be read and/or written only when
		 * its lock is taken.
		 */
		struct flchip_shared *shared = chip->priv;
		struct flchip *contender;
		spin_lock(&shared->lock);
		contender = shared->writing;
		if (contender && contender != chip) {
			/*
			 * The engine to perform desired operation on this
			 * partition is already in use by someone else.
			 * Let's fight over it in the context of the chip
			 * currently using it.  If it is possible to suspend,
			 * that other partition will do just that, otherwise
			 * it'll happily send us to sleep.  In any case, when
			 * get_chip returns success we're clear to go ahead.
			 */
			int ret = spin_trylock(contender->mutex);
			spin_unlock(&shared->lock);
			if (!ret)
				goto retry;
			spin_unlock(chip->mutex);
			ret = get_chip(map, contender, contender->start, mode);
			spin_lock(chip->mutex);
			if (ret) {
				spin_unlock(contender->mutex);
				return ret;
			}
			timeo = jiffies + HZ;
			spin_lock(&shared->lock);
			spin_unlock(contender->mutex);
		}

		/* We now own it */
		shared->writing = chip;
		if (mode == FL_ERASING)
			shared->erasing = chip;
		spin_unlock(&shared->lock);
	}
	unsigned long timeo = jiffies + HZ;

	switch (chip->state) {

@@ -722,16 +663,11 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
			if (chip->priv && map_word_andequal(map, status, status_PWS, status_PWS))
				break;

			if (time_after(jiffies, timeo)) {
				printk(KERN_ERR "%s: Waiting for chip to be ready timed out. Status %lx\n",
				       map->name, status.x[0]);
				return -EIO;
			}
			spin_unlock(chip->mutex);
			cfi_udelay(1);
			spin_lock(chip->mutex);
			/* Someone else might have been playing with it. */
			goto retry;
			return -EAGAIN;
		}

	case FL_READY:
@@ -809,8 +745,80 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
		schedule();
		remove_wait_queue(&chip->wq, &wait);
		spin_lock(chip->mutex);
		goto resettime;
		return -EAGAIN;
	}
}

static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
{
	int ret;

 retry:
	if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING
			   || mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) {
		/*
		 * OK. We have possibility for contention on the write/erase
		 * operations which are global to the real chip and not per
		 * partition.  So let's fight it over in the partition which
		 * currently has authority on the operation.
		 *
		 * The rules are as follows:
		 *
		 * - any write operation must own shared->writing.
		 *
		 * - any erase operation must own _both_ shared->writing and
		 *   shared->erasing.
		 *
		 * - contention arbitration is handled in the owner's context.
		 *
		 * The 'shared' struct can be read and/or written only when
		 * its lock is taken.
		 */
		struct flchip_shared *shared = chip->priv;
		struct flchip *contender;
		spin_lock(&shared->lock);
		contender = shared->writing;
		if (contender && contender != chip) {
			/*
			 * The engine to perform desired operation on this
			 * partition is already in use by someone else.
			 * Let's fight over it in the context of the chip
			 * currently using it.  If it is possible to suspend,
			 * that other partition will do just that, otherwise
			 * it'll happily send us to sleep.  In any case, when
			 * get_chip returns success we're clear to go ahead.
			 */
			ret = spin_trylock(contender->mutex);
			spin_unlock(&shared->lock);
			if (!ret)
				goto retry;
			spin_unlock(chip->mutex);
			ret = chip_ready(map, contender, contender->start, mode);
			spin_lock(chip->mutex);

			if (ret == -EAGAIN) {
				spin_unlock(contender->mutex);
				goto retry;
			}
			if (ret) {
				spin_unlock(contender->mutex);
				return ret;
			}
			spin_lock(&shared->lock);
			spin_unlock(contender->mutex);
		}

		/* We now own it */
		shared->writing = chip;
		if (mode == FL_ERASING)
			shared->erasing = chip;
		spin_unlock(&shared->lock);
	}
	ret = chip_ready(map, chip, adr, mode);
	if (ret == -EAGAIN)
		goto retry;

	return ret;
}

static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr)
+1 −1
Original line number Diff line number Diff line
@@ -300,7 +300,7 @@ config MTD_NAND_PLATFORM
	  via platform_data.

config MTD_ALAUDA
	tristate "MTD driver for Olympus MAUSB-10 and Fijufilm DPC-R1"
	tristate "MTD driver for Olympus MAUSB-10 and Fujifilm DPC-R1"
	depends on MTD_NAND && USB
	help
	  These two (and possibly other) Alauda-based cardreaders for
+2 −2
Original line number Diff line number Diff line
@@ -220,7 +220,7 @@ static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)
		}
	}
	/* If the parity is wrong, no rescue possible */
	return parity ? -1 : nerr;
	return parity ? -EBADMSG : nerr;
}

static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
@@ -1034,7 +1034,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
	else
		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
	if (no_ecc_failures && (ret == -1)) {
	if (no_ecc_failures && (ret == -EBADMSG)) {
		printk(KERN_ERR "suppressing ECC failure\n");
		ret = 0;
	}
+3 −3
Original line number Diff line number Diff line
@@ -789,7 +789,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
		int stat;

		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
		if (stat == -1)
		if (stat < 0)
			mtd->ecc_stats.failed++;
		else
			mtd->ecc_stats.corrected += stat;
@@ -833,7 +833,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
		int stat;

		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
		if (stat == -1)
		if (stat < 0)
			mtd->ecc_stats.failed++;
		else
			mtd->ecc_stats.corrected += stat;
@@ -874,7 +874,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
		chip->read_buf(mtd, oob, eccbytes);
		stat = chip->ecc.correct(mtd, p, oob, NULL);

		if (stat == -1)
		if (stat < 0)
			mtd->ecc_stats.failed++;
		else
			mtd->ecc_stats.corrected += stat;
+1 −1
Original line number Diff line number Diff line
@@ -189,7 +189,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat,
	if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1)
		return 1;

	return -1;
	return -EBADMSG;
}
EXPORT_SYMBOL(nand_correct_data);

Loading