diff options
Diffstat (limited to 'drivers/mtd/nand/nand_base.c')
| -rw-r--r-- | drivers/mtd/nand/nand_base.c | 114 | 
1 files changed, 65 insertions, 49 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 1a03b7f673c..8323ac991ad 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -93,8 +93,7 @@ static struct nand_ecclayout nand_oob_128 = {  		 .length = 78} }  }; -static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, -			   int new_state); +static int nand_get_device(struct mtd_info *mtd, int new_state);  static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,  			     struct mtd_oob_ops *ops); @@ -130,15 +129,12 @@ static int check_offs_len(struct mtd_info *mtd,   * nand_release_device - [GENERIC] release chip   * @mtd: MTD device structure   * - * Deselect, release chip lock and wake up anyone waiting on the device. + * Release chip lock and wake up anyone waiting on the device.   */  static void nand_release_device(struct mtd_info *mtd)  {  	struct nand_chip *chip = mtd->priv; -	/* De-select the NAND device */ -	chip->select_chip(mtd, -1); -  	/* Release the controller and the chip */  	spin_lock(&chip->controller->lock);  	chip->controller->active = NULL; @@ -160,7 +156,7 @@ static uint8_t nand_read_byte(struct mtd_info *mtd)  }  /** - * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip + * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip   * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip   * @mtd: MTD device structure   * @@ -303,7 +299,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)  	if (getchip) {  		chipnr = (int)(ofs >> chip->chip_shift); -		nand_get_device(chip, mtd, FL_READING); +		nand_get_device(mtd, FL_READING);  		/* Select the NAND device */  		chip->select_chip(mtd, chipnr); @@ -333,8 +329,10 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)  		i++;  	} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE)); -	if (getchip) +	if (getchip) { +		chip->select_chip(mtd, -1);  		nand_release_device(mtd); +	}  	return res;  } @@ -383,7 +381,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)  		struct mtd_oob_ops ops;  		loff_t wr_ofs = ofs; -		nand_get_device(chip, mtd, FL_WRITING); +		nand_get_device(mtd, FL_WRITING);  		ops.datbuf = NULL;  		ops.oobbuf = buf; @@ -492,7 +490,7 @@ static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)  void nand_wait_ready(struct mtd_info *mtd)  {  	struct nand_chip *chip = mtd->priv; -	unsigned long timeo = jiffies + 2; +	unsigned long timeo = jiffies + msecs_to_jiffies(20);  	/* 400ms timeout */  	if (in_interrupt() || oops_in_progress) @@ -750,15 +748,15 @@ static void panic_nand_get_device(struct nand_chip *chip,  /**   * 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   *   * Get the device and lock it for exclusive access   */  static int -nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) +nand_get_device(struct mtd_info *mtd, int new_state)  { +	struct nand_chip *chip = mtd->priv;  	spinlock_t *lock = &chip->controller->lock;  	wait_queue_head_t *wq = &chip->controller->wq;  	DECLARE_WAITQUEUE(wait, current); @@ -865,6 +863,8 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)  	led_trigger_event(nand_led_trigger, LED_OFF);  	status = (int)chip->read_byte(mtd); +	/* This can happen if in case of timeout or buggy dev_ready */ +	WARN_ON(!(status & NAND_STATUS_READY));  	return status;  } @@ -899,7 +899,7 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs,  	/* Call wait ready function */  	status = chip->waitfunc(mtd, chip);  	/* See if device thinks it succeeded */ -	if (status & 0x01) { +	if (status & NAND_STATUS_FAIL) {  		pr_debug("%s: error status = 0x%08x\n",  					__func__, status);  		ret = -EIO; @@ -932,7 +932,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  	if (ofs + len == mtd->size)  		len -= mtd->erasesize; -	nand_get_device(chip, mtd, FL_UNLOCKING); +	nand_get_device(mtd, FL_UNLOCKING);  	/* Shift to get chip number */  	chipnr = ofs >> chip->chip_shift; @@ -950,6 +950,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  	ret = __nand_unlock(mtd, ofs, len, 0);  out: +	chip->select_chip(mtd, -1);  	nand_release_device(mtd);  	return ret; @@ -981,7 +982,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  	if (check_offs_len(mtd, ofs, len))  		ret = -EINVAL; -	nand_get_device(chip, mtd, FL_LOCKING); +	nand_get_device(mtd, FL_LOCKING);  	/* Shift to get chip number */  	chipnr = ofs >> chip->chip_shift; @@ -1004,7 +1005,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  	/* Call wait ready function */  	status = chip->waitfunc(mtd, chip);  	/* See if device thinks it succeeded */ -	if (status & 0x01) { +	if (status & NAND_STATUS_FAIL) {  		pr_debug("%s: error status = 0x%08x\n",  					__func__, status);  		ret = -EIO; @@ -1014,6 +1015,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  	ret = __nand_unlock(mtd, ofs, len, 0x1);  out: +	chip->select_chip(mtd, -1);  	nand_release_device(mtd);  	return ret; @@ -1550,6 +1552,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  			chip->select_chip(mtd, chipnr);  		}  	} +	chip->select_chip(mtd, -1);  	ops->retlen = ops->len - (size_t) readlen;  	if (oob) @@ -1577,11 +1580,10 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,  		     size_t *retlen, uint8_t *buf)  { -	struct nand_chip *chip = mtd->priv;  	struct mtd_oob_ops ops;  	int ret; -	nand_get_device(chip, mtd, FL_READING); +	nand_get_device(mtd, FL_READING);  	ops.len = len;  	ops.datbuf = buf;  	ops.oobbuf = NULL; @@ -1804,6 +1806,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,  			chip->select_chip(mtd, chipnr);  		}  	} +	chip->select_chip(mtd, -1);  	ops->oobretlen = ops->ooblen - readlen; @@ -1827,7 +1830,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,  static int nand_read_oob(struct mtd_info *mtd, loff_t from,  			 struct mtd_oob_ops *ops)  { -	struct nand_chip *chip = mtd->priv;  	int ret = -ENOTSUPP;  	ops->retlen = 0; @@ -1839,7 +1841,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,  		return -EINVAL;  	} -	nand_get_device(chip, mtd, FL_READING); +	nand_get_device(mtd, FL_READING);  	switch (ops->mode) {  	case MTD_OPS_PLACE_OOB: @@ -2186,8 +2188,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,  	chip->select_chip(mtd, chipnr);  	/* Check, if it is write protected */ -	if (nand_check_wp(mtd)) -		return -EIO; +	if (nand_check_wp(mtd)) { +		ret = -EIO; +		goto err_out; +	}  	realpage = (int)(to >> chip->page_shift);  	page = realpage & chip->pagemask; @@ -2199,8 +2203,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,  		chip->pagebuf = -1;  	/* Don't allow multipage oob writes with offset */ -	if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) -		return -EINVAL; +	if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) { +		ret = -EINVAL; +		goto err_out; +	}  	while (1) {  		int bytes = mtd->writesize; @@ -2251,6 +2257,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,  	ops->retlen = ops->len - writelen;  	if (unlikely(oob))  		ops->oobretlen = ops->ooblen; + +err_out: +	chip->select_chip(mtd, -1);  	return ret;  } @@ -2302,11 +2311,10 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,  static int 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;  	struct mtd_oob_ops ops;  	int ret; -	nand_get_device(chip, mtd, FL_WRITING); +	nand_get_device(mtd, FL_WRITING);  	ops.len = len;  	ops.datbuf = (uint8_t *)buf;  	ops.oobbuf = NULL; @@ -2377,8 +2385,10 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,  	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);  	/* Check, if it is write protected */ -	if (nand_check_wp(mtd)) +	if (nand_check_wp(mtd)) { +		chip->select_chip(mtd, -1);  		return -EROFS; +	}  	/* Invalidate the page cache, if we write to the cached page */  	if (page == chip->pagebuf) @@ -2391,6 +2401,8 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,  	else  		status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); +	chip->select_chip(mtd, -1); +  	if (status)  		return status; @@ -2408,7 +2420,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,  static int nand_write_oob(struct mtd_info *mtd, loff_t to,  			  struct mtd_oob_ops *ops)  { -	struct nand_chip *chip = mtd->priv;  	int ret = -ENOTSUPP;  	ops->retlen = 0; @@ -2420,7 +2431,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,  		return -EINVAL;  	} -	nand_get_device(chip, mtd, FL_WRITING); +	nand_get_device(mtd, FL_WRITING);  	switch (ops->mode) {  	case MTD_OPS_PLACE_OOB: @@ -2513,7 +2524,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  		return -EINVAL;  	/* Grab the lock and see if the device is available */ -	nand_get_device(chip, mtd, FL_ERASING); +	nand_get_device(mtd, FL_ERASING);  	/* Shift to get first page */  	page = (int)(instr->addr >> chip->page_shift); @@ -2623,6 +2634,7 @@ erase_exit:  	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;  	/* Deselect and wake up anyone waiting on the device */ +	chip->select_chip(mtd, -1);  	nand_release_device(mtd);  	/* Do call back function */ @@ -2658,12 +2670,10 @@ erase_exit:   */  static void nand_sync(struct mtd_info *mtd)  { -	struct nand_chip *chip = mtd->priv; -  	pr_debug("%s: called\n", __func__);  	/* Grab the lock and see if the device is available */ -	nand_get_device(chip, mtd, FL_SYNCING); +	nand_get_device(mtd, FL_SYNCING);  	/* Release it and go back */  	nand_release_device(mtd);  } @@ -2749,9 +2759,7 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,   */  static int nand_suspend(struct mtd_info *mtd)  { -	struct nand_chip *chip = mtd->priv; - -	return nand_get_device(chip, mtd, FL_PM_SUSPENDED); +	return nand_get_device(mtd, FL_PM_SUSPENDED);  }  /** @@ -2849,6 +2857,8 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,  	int i;  	int val; +	/* ONFI need to be probed in 8 bits mode */ +	WARN_ON(chip->options & NAND_BUSWIDTH_16);  	/* Try ONFI for unknown chip or LP */  	chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);  	if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || @@ -2913,7 +2923,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,   *   * Check if an ID string is repeated within a given sequence of bytes at   * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a - * period of 2). This is a helper function for nand_id_len(). Returns non-zero + * period of 3). This is a helper function for nand_id_len(). Returns non-zero   * if the repetition has a period of @period; otherwise, returns zero.   */  static int nand_id_has_period(u8 *id_data, int arrlen, int period) @@ -3242,11 +3252,15 @@ ident_done:  			break;  	} -	/* -	 * Check, if buswidth is correct. Hardware drivers should set -	 * chip correct! -	 */ -	if (busw != (chip->options & NAND_BUSWIDTH_16)) { +	if (chip->options & NAND_BUSWIDTH_AUTO) { +		WARN_ON(chip->options & NAND_BUSWIDTH_16); +		chip->options |= busw; +		nand_set_defaults(chip, busw); +	} else if (busw != (chip->options & NAND_BUSWIDTH_16)) { +		/* +		 * Check, if buswidth is correct. Hardware drivers should set +		 * chip correct! +		 */  		pr_info("NAND device: Manufacturer ID:"  			" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,  			*dev_id, nand_manuf_ids[maf_idx].name, mtd->name); @@ -3285,10 +3299,10 @@ ident_done:  		chip->cmdfunc = nand_command_lp;  	pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s)," -		" page size: %d, OOB size: %d\n", +		" %dMiB, page size: %d, OOB size: %d\n",  		*maf_id, *dev_id, nand_manuf_ids[maf_idx].name,  		chip->onfi_version ? chip->onfi_params.model : type->name, -		mtd->writesize, mtd->oobsize); +		(int)(chip->chipsize >> 20), mtd->writesize, mtd->oobsize);  	return type;  } @@ -3327,6 +3341,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,  		return PTR_ERR(type);  	} +	chip->select_chip(mtd, -1); +  	/* Check for a chip array */  	for (i = 1; i < maxchips; i++) {  		chip->select_chip(mtd, i); @@ -3336,8 +3352,11 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,  		chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);  		/* Read manufacturer and device IDs */  		if (nand_maf_id != chip->read_byte(mtd) || -		    nand_dev_id != chip->read_byte(mtd)) +		    nand_dev_id != chip->read_byte(mtd)) { +			chip->select_chip(mtd, -1);  			break; +		} +		chip->select_chip(mtd, -1);  	}  	if (i > 1)  		pr_info("%d NAND chips detected\n", i); @@ -3596,9 +3615,6 @@ int nand_scan_tail(struct mtd_info *mtd)  	/* Initialize state */  	chip->state = FL_READY; -	/* De-select the device */ -	chip->select_chip(mtd, -1); -  	/* Invalidate the pagebuffer reference */  	chip->pagebuf = -1;  |