diff options
Diffstat (limited to 'drivers/mtd/chips')
| -rw-r--r-- | drivers/mtd/chips/Kconfig | 32 | ||||
| -rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0001.c | 294 | ||||
| -rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0002.c | 778 | ||||
| -rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0020.c | 55 | ||||
| -rw-r--r-- | drivers/mtd/chips/cfi_probe.c | 4 | ||||
| -rw-r--r-- | drivers/mtd/chips/cfi_util.c | 16 | ||||
| -rw-r--r-- | drivers/mtd/chips/chipreg.c | 5 | ||||
| -rw-r--r-- | drivers/mtd/chips/fwh_lock.h | 9 | ||||
| -rw-r--r-- | drivers/mtd/chips/gen_probe.c | 8 | ||||
| -rw-r--r-- | drivers/mtd/chips/jedec_probe.c | 84 | ||||
| -rw-r--r-- | drivers/mtd/chips/map_absent.c | 10 | ||||
| -rw-r--r-- | drivers/mtd/chips/map_ram.c | 14 | ||||
| -rw-r--r-- | drivers/mtd/chips/map_rom.c | 13 | 
13 files changed, 922 insertions, 400 deletions
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig index 35c6a23b183..9f02c28c020 100644 --- a/drivers/mtd/chips/Kconfig +++ b/drivers/mtd/chips/Kconfig @@ -19,7 +19,7 @@ config MTD_JEDECPROBE  	help  	  This option enables JEDEC-style probing of flash chips which are not  	  compatible with the Common Flash Interface, but will use the common -	  CFI-targetted flash drivers for any chips which are identified which +	  CFI-targeted flash drivers for any chips which are identified which  	  are in fact compatible in all but the probe method. This actually  	  covers most AMD/Fujitsu-compatible chips and also non-CFI  	  Intel chips. @@ -43,9 +43,6 @@ choice  	prompt "Flash cmd/query data swapping"  	depends on MTD_CFI_ADV_OPTIONS  	default MTD_CFI_NOSWAP - -config MTD_CFI_NOSWAP -	bool "NO"  	---help---  	  This option defines the way in which the CPU attempts to arrange  	  data bits when writing the 'magic' commands to the chips. Saying @@ -55,12 +52,8 @@ config MTD_CFI_NOSWAP  	  Specific arrangements are possible with the BIG_ENDIAN_BYTE and  	  LITTLE_ENDIAN_BYTE, if the bytes are reversed. -	  If you have a LART, on which the data (and address) lines were -	  connected in a fashion which ensured that the nets were as short -	  as possible, resulting in a bit-shuffling which seems utterly -	  random to the untrained eye, you need the LART_ENDIAN_BYTE option. - -	  Yes, there really exists something sicker than PDP-endian :) +config MTD_CFI_NOSWAP +	bool "NO"  config MTD_CFI_BE_BYTE_SWAP  	bool "BIG_ENDIAN_BYTE" @@ -153,7 +146,6 @@ config MTD_CFI_I8  config MTD_OTP  	bool "Protection Registers aka one-time programmable (OTP) bits"  	depends on MTD_CFI_ADV_OPTIONS -	select HAVE_MTD_OTP  	default n  	help  	  This enables support for reading, writing and locking so called @@ -177,33 +169,33 @@ config MTD_OTP  	  in the programming of OTP bits will waste them.  config MTD_CFI_INTELEXT -	tristate "Support for Intel/Sharp flash chips" +	tristate "Support for CFI command set 0001 (Intel/Sharp chips)"  	depends on MTD_GEN_PROBE  	select MTD_CFI_UTIL  	help  	  The Common Flash Interface defines a number of different command  	  sets which a CFI-compliant chip may claim to implement. This code -	  provides support for one of those command sets, used on Intel -	  StrataFlash and other parts. +	  provides support for command set 0001, used on Intel StrataFlash +	  and other parts.  config MTD_CFI_AMDSTD -	tristate "Support for AMD/Fujitsu/Spansion flash chips" +	tristate "Support for CFI command set 0002 (AMD/Fujitsu/Spansion chips)"  	depends on MTD_GEN_PROBE  	select MTD_CFI_UTIL  	help  	  The Common Flash Interface defines a number of different command  	  sets which a CFI-compliant chip may claim to implement. This code -	  provides support for one of those command sets, used on chips -	  including the AMD Am29LV320. +	  provides support for command set 0002, used on chips including +	  the AMD Am29LV320.  config MTD_CFI_STAA -	tristate "Support for ST (Advanced Architecture) flash chips" +	tristate "Support for CFI command set 0020 (ST (Advanced Architecture) chips)"  	depends on MTD_GEN_PROBE  	select MTD_CFI_UTIL  	help  	  The Common Flash Interface defines a number of different command  	  sets which a CFI-compliant chip may claim to implement. This code -	  provides support for one of those command sets. +	  provides support for command set 0020.  config MTD_CFI_UTIL  	tristate @@ -232,7 +224,7 @@ config MTD_ABSENT  config MTD_XIP  	bool "XIP aware MTD support" -	depends on !SMP && (MTD_CFI_INTELEXT || MTD_CFI_AMDSTD) && EXPERIMENTAL && ARCH_MTD_XIP +	depends on !SMP && (MTD_CFI_INTELEXT || MTD_CFI_AMDSTD) && ARCH_MTD_XIP  	default y if XIP_KERNEL  	help  	  This allows MTD support to work with flash memory which is also diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index ad9268b4441..a7543ba3e19 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -21,7 +21,6 @@  #include <linux/types.h>  #include <linux/kernel.h>  #include <linux/sched.h> -#include <linux/init.h>  #include <asm/io.h>  #include <asm/byteorder.h> @@ -53,6 +52,11 @@  /* Atmel chips */  #define AT49BV640D	0x02de  #define AT49BV640DT	0x02db +/* Sharp chips */ +#define LH28F640BFHE_PTTL90	0x00b0 +#define LH28F640BFHE_PBTL90	0x00b1 +#define LH28F640BFHE_PTTL70A	0x00b2 +#define LH28F640BFHE_PBTL70A	0x00b3  static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);  static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); @@ -69,10 +73,10 @@ static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, s  static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);  static int cfi_intelext_write_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);  static int cfi_intelext_lock_user_prot_reg (struct mtd_info *, loff_t, size_t); -static int cfi_intelext_get_fact_prot_info (struct mtd_info *, -					    struct otp_info *, size_t); -static int cfi_intelext_get_user_prot_info (struct mtd_info *, -					    struct otp_info *, size_t); +static int cfi_intelext_get_fact_prot_info(struct mtd_info *, size_t, +					   size_t *, struct otp_info *); +static int cfi_intelext_get_user_prot_info(struct mtd_info *, size_t, +					   size_t *, struct otp_info *);  #endif  static int cfi_intelext_suspend (struct mtd_info *);  static void cfi_intelext_resume (struct mtd_info *); @@ -87,7 +91,7 @@ static int cfi_intelext_partition_fixup(struct mtd_info *, struct cfi_private **  static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,  		     size_t *retlen, void **virt, resource_size_t *phys); -static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len); +static int cfi_intelext_unpoint(struct mtd_info *mtd, 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); @@ -162,7 +166,7 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp)  #endif  /* Atmel chips don't use the same PRI format as Intel chips */ -static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) +static void fixup_convert_atmel_pri(struct mtd_info *mtd)  {  	struct map_info *map = mtd->priv;  	struct cfi_private *cfi = map->fldrv_priv; @@ -202,7 +206,7 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)  	cfi->cfiq->BufWriteTimeoutMax = 0;  } -static void fixup_at49bv640dx_lock(struct mtd_info *mtd, void *param) +static void fixup_at49bv640dx_lock(struct mtd_info *mtd)  {  	struct map_info *map = mtd->priv;  	struct cfi_private *cfi = map->fldrv_priv; @@ -214,7 +218,7 @@ static void fixup_at49bv640dx_lock(struct mtd_info *mtd, void *param)  #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE  /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ -static void fixup_intel_strataflash(struct mtd_info *mtd, void* param) +static void fixup_intel_strataflash(struct mtd_info *mtd)  {  	struct map_info *map = mtd->priv;  	struct cfi_private *cfi = map->fldrv_priv; @@ -227,7 +231,7 @@ static void fixup_intel_strataflash(struct mtd_info *mtd, void* param)  #endif  #ifdef CMDSET0001_DISABLE_WRITE_SUSPEND -static void fixup_no_write_suspend(struct mtd_info *mtd, void* param) +static void fixup_no_write_suspend(struct mtd_info *mtd)  {  	struct map_info *map = mtd->priv;  	struct cfi_private *cfi = map->fldrv_priv; @@ -240,7 +244,7 @@ static void fixup_no_write_suspend(struct mtd_info *mtd, void* param)  }  #endif -static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param) +static void fixup_st_m28w320ct(struct mtd_info *mtd)  {  	struct map_info *map = mtd->priv;  	struct cfi_private *cfi = map->fldrv_priv; @@ -249,7 +253,7 @@ static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param)  	cfi->cfiq->BufWriteTimeoutMax = 0;	/* Not supported */  } -static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param) +static void fixup_st_m28w320cb(struct mtd_info *mtd)  {  	struct map_info *map = mtd->priv;  	struct cfi_private *cfi = map->fldrv_priv; @@ -259,30 +263,60 @@ static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param)  		(cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e;  }; -static void fixup_use_point(struct mtd_info *mtd, void *param) +static int is_LH28F640BF(struct cfi_private *cfi) +{ +	/* Sharp LH28F640BF Family */ +	if (cfi->mfr == CFI_MFR_SHARP && ( +	    cfi->id == LH28F640BFHE_PTTL90 || cfi->id == LH28F640BFHE_PBTL90 || +	    cfi->id == LH28F640BFHE_PTTL70A || cfi->id == LH28F640BFHE_PBTL70A)) +		return 1; +	return 0; +} + +static void fixup_LH28F640BF(struct mtd_info *mtd) +{ +	struct map_info *map = mtd->priv; +	struct cfi_private *cfi = map->fldrv_priv; +	struct cfi_pri_intelext *extp = cfi->cmdset_priv; + +	/* Reset the Partition Configuration Register on LH28F640BF +	 * to a single partition (PCR = 0x000): PCR is embedded into A0-A15. */ +	if (is_LH28F640BF(cfi)) { +		printk(KERN_INFO "Reset Partition Config. Register: 1 Partition of 4 planes\n"); +		map_write(map, CMD(0x60), 0); +		map_write(map, CMD(0x04), 0); + +		/* We have set one single partition thus +		 * Simultaneous Operations are not allowed */ +		printk(KERN_INFO "cfi_cmdset_0001: Simultaneous Operations disabled\n"); +		extp->FeatureSupport &= ~512; +	} +} + +static void fixup_use_point(struct mtd_info *mtd)  {  	struct map_info *map = mtd->priv; -	if (!mtd->point && map_is_linear(map)) { -		mtd->point   = cfi_intelext_point; -		mtd->unpoint = cfi_intelext_unpoint; +	if (!mtd->_point && map_is_linear(map)) { +		mtd->_point   = cfi_intelext_point; +		mtd->_unpoint = cfi_intelext_unpoint;  	}  } -static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) +static void fixup_use_write_buffers(struct mtd_info *mtd)  {  	struct map_info *map = mtd->priv;  	struct cfi_private *cfi = map->fldrv_priv;  	if (cfi->cfiq->BufWriteTimeoutTyp) {  		printk(KERN_INFO "Using buffer write method\n" ); -		mtd->write = cfi_intelext_write_buffers; -		mtd->writev = cfi_intelext_writev; +		mtd->_write = cfi_intelext_write_buffers; +		mtd->_writev = cfi_intelext_writev;  	}  }  /*   * Some chips power-up with all sectors locked by default.   */ -static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param) +static void fixup_unlock_powerup_lock(struct mtd_info *mtd)  {  	struct map_info *map = mtd->priv;  	struct cfi_private *cfi = map->fldrv_priv; @@ -295,31 +329,33 @@ static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param)  }  static struct cfi_fixup cfi_fixup_table[] = { -	{ CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL }, -	{ CFI_MFR_ATMEL, AT49BV640D, fixup_at49bv640dx_lock, NULL }, -	{ CFI_MFR_ATMEL, AT49BV640DT, fixup_at49bv640dx_lock, NULL }, +	{ CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri }, +	{ CFI_MFR_ATMEL, AT49BV640D, fixup_at49bv640dx_lock }, +	{ CFI_MFR_ATMEL, AT49BV640DT, fixup_at49bv640dx_lock },  #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE -	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, +	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash },  #endif  #ifdef CMDSET0001_DISABLE_WRITE_SUSPEND -	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend, NULL }, +	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend },  #endif  #if !FORCE_WORD_WRITE -	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL }, +	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers },  #endif -	{ CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL }, -	{ CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL }, -	{ CFI_MFR_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock, NULL, }, -	{ 0, 0, NULL, NULL } +	{ CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct }, +	{ CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb }, +	{ CFI_MFR_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock }, +	{ CFI_MFR_SHARP, CFI_ID_ANY, fixup_unlock_powerup_lock }, +	{ CFI_MFR_SHARP, CFI_ID_ANY, fixup_LH28F640BF }, +	{ 0, 0, NULL }  };  static struct cfi_fixup jedec_fixup_table[] = { -	{ CFI_MFR_INTEL, I82802AB,   fixup_use_fwh_lock, NULL, }, -	{ CFI_MFR_INTEL, I82802AC,   fixup_use_fwh_lock, NULL, }, -	{ CFI_MFR_ST,    M50LPW080,  fixup_use_fwh_lock, NULL, }, -	{ CFI_MFR_ST,    M50FLW080A, fixup_use_fwh_lock, NULL, }, -	{ CFI_MFR_ST,    M50FLW080B, fixup_use_fwh_lock, NULL, }, -	{ 0, 0, NULL, NULL } +	{ CFI_MFR_INTEL, I82802AB,   fixup_use_fwh_lock }, +	{ CFI_MFR_INTEL, I82802AC,   fixup_use_fwh_lock }, +	{ CFI_MFR_ST,    M50LPW080,  fixup_use_fwh_lock }, +	{ CFI_MFR_ST,    M50FLW080A, fixup_use_fwh_lock }, +	{ CFI_MFR_ST,    M50FLW080B, fixup_use_fwh_lock }, +	{ 0, 0, NULL }  };  static struct cfi_fixup fixup_table[] = {  	/* The CFI vendor ids and the JEDEC vendor IDs appear @@ -327,8 +363,8 @@ static struct cfi_fixup fixup_table[] = {  	 * well.  This table is to pick all cases where  	 * we know that is the case.  	 */ -	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_point, NULL }, -	{ 0, 0, NULL, NULL } +	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_point }, +	{ 0, 0, NULL }  };  static void cfi_fixup_major_minor(struct cfi_private *cfi, @@ -435,26 +471,25 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)  	int i;  	mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); -	if (!mtd) { -		printk(KERN_ERR "Failed to allocate memory for MTD device\n"); +	if (!mtd)  		return NULL; -	}  	mtd->priv = map;  	mtd->type = MTD_NORFLASH;  	/* Fill in the default mtd operations */ -	mtd->erase   = cfi_intelext_erase_varsize; -	mtd->read    = cfi_intelext_read; -	mtd->write   = cfi_intelext_write_words; -	mtd->sync    = cfi_intelext_sync; -	mtd->lock    = cfi_intelext_lock; -	mtd->unlock  = cfi_intelext_unlock; -	mtd->is_locked = cfi_intelext_is_locked; -	mtd->suspend = cfi_intelext_suspend; -	mtd->resume  = cfi_intelext_resume; +	mtd->_erase   = cfi_intelext_erase_varsize; +	mtd->_read    = cfi_intelext_read; +	mtd->_write   = cfi_intelext_write_words; +	mtd->_sync    = cfi_intelext_sync; +	mtd->_lock    = cfi_intelext_lock; +	mtd->_unlock  = cfi_intelext_unlock; +	mtd->_is_locked = cfi_intelext_is_locked; +	mtd->_suspend = cfi_intelext_suspend; +	mtd->_resume  = cfi_intelext_resume;  	mtd->flags   = MTD_CAP_NORFLASH;  	mtd->name    = map->name;  	mtd->writesize = 1; +	mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;  	mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; @@ -563,10 +598,8 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)  	mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;  	mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)  			* mtd->numeraseregions, GFP_KERNEL); -	if (!mtd->eraseregions) { -		printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n"); +	if (!mtd->eraseregions)  		goto setup_err; -	}  	for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {  		unsigned long ernum, ersize; @@ -599,12 +632,12 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)  	}  #ifdef CONFIG_MTD_OTP -	mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg; -	mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg; -	mtd->write_user_prot_reg = cfi_intelext_write_user_prot_reg; -	mtd->lock_user_prot_reg = cfi_intelext_lock_user_prot_reg; -	mtd->get_fact_prot_info = cfi_intelext_get_fact_prot_info; -	mtd->get_user_prot_info = cfi_intelext_get_user_prot_info; +	mtd->_read_fact_prot_reg = cfi_intelext_read_fact_prot_reg; +	mtd->_read_user_prot_reg = cfi_intelext_read_user_prot_reg; +	mtd->_write_user_prot_reg = cfi_intelext_write_user_prot_reg; +	mtd->_lock_user_prot_reg = cfi_intelext_lock_user_prot_reg; +	mtd->_get_fact_prot_info = cfi_intelext_get_fact_prot_info; +	mtd->_get_user_prot_info = cfi_intelext_get_user_prot_info;  #endif  	/* This function has the potential to distort the reality @@ -811,12 +844,9 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long  			        break;  			if (time_after(jiffies, timeo)) { -				/* Urgh. Resume and pretend we weren't here.  */ -				map_write(map, CMD(0xd0), adr); -				/* Make sure we're in 'read status' mode if it had finished */ -				map_write(map, CMD(0x70), adr); -				chip->state = FL_ERASING; -				chip->oldstate = FL_READY; +				/* Urgh. Resume and pretend we weren't here. +				 * Make sure we're in 'read status' mode if it had finished */ +				put_chip(map, chip, adr);  				printk(KERN_ERR "%s: Chip not ready after erase "  				       "suspended: status = 0x%lx\n", map->name, status.x[0]);  				return -EIO; @@ -996,7 +1026,6 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad  	switch(chip->oldstate) {  	case FL_ERASING: -		chip->state = chip->oldstate;  		/* What if one interleaved chip has finished and the  		   other hasn't? The old code would leave the finished  		   one in READY mode. That's bad, and caused -EROFS @@ -1020,8 +1049,6 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad  	case FL_READY:  	case FL_STATUS:  	case FL_JEDEC_QUERY: -		/* We should really make set_vpp() count, rather than doing this */ -		DISABLE_VPP(map);  		break;  	default:  		printk(KERN_ERR "%s: put_chip() called with oldstate %d!!\n", map->name, chip->oldstate); @@ -1229,10 +1256,32 @@ static int inval_cache_and_wait_for_operation(  	sleep_time = chip_op_time / 2;  	for (;;) { +		if (chip->state != chip_state) { +			/* Someone's suspended the operation: sleep */ +			DECLARE_WAITQUEUE(wait, current); +			set_current_state(TASK_UNINTERRUPTIBLE); +			add_wait_queue(&chip->wq, &wait); +			mutex_unlock(&chip->mutex); +			schedule(); +			remove_wait_queue(&chip->wq, &wait); +			mutex_lock(&chip->mutex); +			continue; +		} +  		status = map_read(map, cmd_adr);  		if (map_word_andequal(map, status, status_OK, status_OK))  			break; +		if (chip->erase_suspended && chip_state == FL_ERASING)  { +			/* Erase suspend occurred while sleep: reset timeout */ +			timeo = reset_timeo; +			chip->erase_suspended = 0; +		} +		if (chip->write_suspended && chip_state == FL_WRITING)  { +			/* Write suspend occurred while sleep: reset timeout */ +			timeo = reset_timeo; +			chip->write_suspended = 0; +		}  		if (!timeo) {  			map_write(map, CMD(0x70), cmd_adr);  			chip->state = FL_STATUS; @@ -1256,27 +1305,6 @@ static int inval_cache_and_wait_for_operation(  			timeo--;  		}  		mutex_lock(&chip->mutex); - -		while (chip->state != chip_state) { -			/* Someone's suspended the operation: sleep */ -			DECLARE_WAITQUEUE(wait, current); -			set_current_state(TASK_UNINTERRUPTIBLE); -			add_wait_queue(&chip->wq, &wait); -			mutex_unlock(&chip->mutex); -			schedule(); -			remove_wait_queue(&chip->wq, &wait); -			mutex_lock(&chip->mutex); -		} -		if (chip->erase_suspended && chip_state == FL_ERASING)  { -			/* Erase suspend occured while sleep: reset timeout */ -			timeo = reset_timeo; -			chip->erase_suspended = 0; -		} -		if (chip->write_suspended && chip_state == FL_WRITING)  { -			/* Write suspend occured while sleep: reset timeout */ -			timeo = reset_timeo; -			chip->write_suspended = 0; -		}  	}  	/* Done and happy. */ @@ -1326,7 +1354,7 @@ static int cfi_intelext_point(struct mtd_info *mtd, loff_t from, size_t len,  	int chipnum;  	int ret = 0; -	if (!map->virt || (from + len > mtd->size)) +	if (!map->virt)  		return -EINVAL;  	/* Now lock the chip(s) to POINT state */ @@ -1336,7 +1364,6 @@ static int cfi_intelext_point(struct mtd_info *mtd, loff_t from, size_t len,  	ofs = from - (chipnum << cfi->chipshift);  	*virt = map->virt + cfi->chips[chipnum].start + ofs; -	*retlen = 0;  	if (phys)  		*phys = map->phys + cfi->chips[chipnum].start + ofs; @@ -1371,12 +1398,12 @@ static int cfi_intelext_point(struct mtd_info *mtd, loff_t from, size_t len,  	return 0;  } -static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len) +static int cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len)  {  	struct map_info *map = mtd->priv;  	struct cfi_private *cfi = map->fldrv_priv;  	unsigned long ofs; -	int chipnum; +	int chipnum, err = 0;  	/* Now unlock the chip(s) POINT state */ @@ -1384,7 +1411,7 @@ static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len)  	chipnum = (from >> cfi->chipshift);  	ofs = from - (chipnum <<  cfi->chipshift); -	while (len) { +	while (len && !err) {  		unsigned long thislen;  		struct flchip *chip; @@ -1402,8 +1429,10 @@ static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len)  			chip->ref_point_counter--;  			if(chip->ref_point_counter == 0)  				chip->state = FL_READY; -		} else -			printk(KERN_ERR "%s: Warning: unpoint called on non pointed region\n", map->name); /* Should this give an error? */ +		} else { +			printk(KERN_ERR "%s: Error: unpoint called on non pointed region\n", map->name); +			err = -EINVAL; +		}  		put_chip(map, chip, chip->start);  		mutex_unlock(&chip->mutex); @@ -1412,6 +1441,8 @@ static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len)  		ofs = 0;  		chipnum++;  	} + +	return err;  }  static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) @@ -1458,8 +1489,6 @@ static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, siz  	chipnum = (from >> cfi->chipshift);  	ofs = from - (chipnum <<  cfi->chipshift); -	*retlen = 0; -  	while (len) {  		unsigned long thislen; @@ -1553,7 +1582,8 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,  	}  	xip_enable(map, chip, adr); - out:	put_chip(map, chip, adr); + out:	DISABLE_VPP(map); +	put_chip(map, chip, adr);  	mutex_unlock(&chip->mutex);  	return ret;  } @@ -1567,10 +1597,6 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le  	int chipnum;  	unsigned long ofs; -	*retlen = 0; -	if (!len) -		return 0; -  	chipnum = to >> cfi->chipshift;  	ofs = to  - (chipnum << cfi->chipshift); @@ -1660,6 +1686,12 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,  	initial_adr = adr;  	cmd_adr = adr & ~(wbufsize-1); +	/* Sharp LH28F640BF chips need the first address for the +	 * Page Buffer Program command. See Table 5 of +	 * LH28F320BF, LH28F640BF, LH28F128BF Series (Appendix FUM00701) */ +	if (is_LH28F640BF(cfi)) +		cmd_adr = adr; +  	/* Let's determine this according to the interleave only once */  	write_cmd = (cfi->cfiq->P_ID != P_ID_INTEL_PERFORMANCE) ? CMD(0xe8) : CMD(0xe9); @@ -1796,7 +1828,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,  	}  	xip_enable(map, chip, cmd_adr); - out:	put_chip(map, chip, cmd_adr); + out:	DISABLE_VPP(map); +	put_chip(map, chip, cmd_adr);  	mutex_unlock(&chip->mutex);  	return ret;  } @@ -1815,7 +1848,6 @@ static int cfi_intelext_writev (struct mtd_info *mtd, const struct kvec *vecs,  	for (i = 0; i < count; i++)  		len += vecs[i].iov_len; -	*retlen = 0;  	if (!len)  		return 0; @@ -1934,6 +1966,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,  			ret = -EIO;  		} else if (chipstatus & 0x20 && retries--) {  			printk(KERN_DEBUG "block erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus); +			DISABLE_VPP(map);  			put_chip(map, chip, adr);  			mutex_unlock(&chip->mutex);  			goto retry; @@ -1946,7 +1979,8 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,  	}  	xip_enable(map, chip, adr); - out:	put_chip(map, chip, adr); + out:	DISABLE_VPP(map); +	put_chip(map, chip, adr);  	mutex_unlock(&chip->mutex);  	return ret;  } @@ -2047,7 +2081,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip  {  	struct cfi_private *cfi = map->fldrv_priv;  	struct cfi_pri_intelext *extp = cfi->cmdset_priv; -	int udelay; +	int mdelay;  	int ret;  	adr += chip->start; @@ -2076,9 +2110,17 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip  	 * If Instant Individual Block Locking supported then no need  	 * to delay.  	 */ -	udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000/HZ : 0; +	/* +	 * Unlocking may take up to 1.4 seconds on some Intel flashes. So +	 * lets use a max of 1.5 seconds (1500ms) as timeout. +	 * +	 * See "Clear Block Lock-Bits Time" on page 40 in +	 * "3 Volt Intel StrataFlash Memory" 28F128J3,28F640J3,28F320J3 manual +	 * from February 2003 +	 */ +	mdelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1500 : 0; -	ret = WAIT_TIMEOUT(map, chip, adr, udelay, udelay * 100); +	ret = WAIT_TIMEOUT(map, chip, adr, mdelay, mdelay * 1000);  	if (ret) {  		map_write(map, CMD(0x70), adr);  		chip->state = FL_STATUS; @@ -2088,7 +2130,8 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip  	}  	xip_enable(map, chip, adr); -out:	put_chip(map, chip, adr); + out:	DISABLE_VPP(map); +	put_chip(map, chip, adr);  	mutex_unlock(&chip->mutex);  	return ret;  } @@ -2394,24 +2437,19 @@ static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd,  				     NULL, do_otp_lock, 1);  } -static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd, -					   struct otp_info *buf, size_t len) -{ -	size_t retlen; -	int ret; +static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd, size_t len, +					   size_t *retlen, struct otp_info *buf) -	ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 0); -	return ret ? : retlen; +{ +	return cfi_intelext_otp_walk(mtd, 0, len, retlen, (u_char *)buf, +				     NULL, 0);  } -static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd, -					   struct otp_info *buf, size_t len) +static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd, size_t len, +					   size_t *retlen, struct otp_info *buf)  { -	size_t retlen; -	int ret; - -	ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 1); -	return ret ? : retlen; +	return cfi_intelext_otp_walk(mtd, 0, len, retlen, (u_char *)buf, +				     NULL, 1);  }  #endif @@ -2485,7 +2523,7 @@ static int cfi_intelext_suspend(struct mtd_info *mtd)  			   allowed to. Or should we return -EAGAIN, because the upper layers  			   ought to have already shut down anything which was using the device  			   anyway? The latter for now. */ -			printk(KERN_NOTICE "Flash device refused suspend due to active operation (state %d)\n", chip->oldstate); +			printk(KERN_NOTICE "Flash device refused suspend due to active operation (state %d)\n", chip->state);  			ret = -EAGAIN;  		case FL_PM_SUSPENDED:  			break; @@ -2528,12 +2566,10 @@ static void cfi_intelext_restore_locks(struct mtd_info *mtd)  		if (!region->lockmap)  			continue; -		for (block = 0; block < region->numblocks; block++) { +		for_each_clear_bit(block, region->lockmap, region->numblocks) {  			len = region->erasesize;  			adr = region->offset + block * len; - -			if (!test_bit(block, region->lockmap)) -				cfi_intelext_unlock(mtd, adr, len); +			cfi_intelext_unlock(mtd, adr, len);  		}  	}  } diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 3b8e32d8797..e21fde9d4d7 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -24,7 +24,6 @@  #include <linux/types.h>  #include <linux/kernel.h>  #include <linux/sched.h> -#include <linux/init.h>  #include <asm/io.h>  #include <asm/byteorder.h> @@ -33,6 +32,8 @@  #include <linux/delay.h>  #include <linux/interrupt.h>  #include <linux/reboot.h> +#include <linux/of.h> +#include <linux/of_platform.h>  #include <linux/mtd/map.h>  #include <linux/mtd/mtd.h>  #include <linux/mtd/cfi.h> @@ -59,6 +60,9 @@ static void cfi_amdstd_resume (struct mtd_info *);  static int cfi_amdstd_reboot(struct notifier_block *, unsigned long, void *);  static int cfi_amdstd_secsi_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); +static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, +				  size_t *retlen, const u_char *buf); +  static void cfi_amdstd_destroy(struct mtd_info *);  struct mtd_info *cfi_cmdset_0002(struct map_info *, int); @@ -71,6 +75,10 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad  static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);  static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); +static int cfi_ppb_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); +static int cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); +static int cfi_ppb_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len); +  static struct mtd_chip_driver cfi_amdstd_chipdrv = {  	.probe		= NULL, /* Not usable directly */  	.destroy	= cfi_amdstd_destroy, @@ -134,7 +142,7 @@ static void cfi_tell_features(struct cfi_pri_amdstd *extp)  #ifdef AMD_BOOTLOC_BUG  /* Wheee. Bring me the head of someone at AMD. */ -static void fixup_amd_bootblock(struct mtd_info *mtd, void* param) +static void fixup_amd_bootblock(struct mtd_info *mtd)  {  	struct map_info *map = mtd->priv;  	struct cfi_private *cfi = map->fldrv_priv; @@ -145,8 +153,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd, void* param)  	if (((major << 8) | minor) < 0x3131) {  		/* CFI version 1.0 => don't trust bootloc */ -		DEBUG(MTD_DEBUG_LEVEL1, -			"%s: JEDEC Vendor ID is 0x%02X Device ID is 0x%02X\n", +		pr_debug("%s: JEDEC Vendor ID is 0x%02X Device ID is 0x%02X\n",  			map->name, cfi->mfr, cfi->id);  		/* AFAICS all 29LV400 with a bottom boot block have a device ID @@ -166,8 +173,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd, void* param)  			 * the 8-bit device ID.  			 */  			(cfi->mfr == CFI_MFR_MACRONIX)) { -			DEBUG(MTD_DEBUG_LEVEL1, -				"%s: Macronix MX29LV400C with bottom boot block" +			pr_debug("%s: Macronix MX29LV400C with bottom boot block"  				" detected\n", map->name);  			extp->TopBottom = 2;	/* bottom boot */  		} else @@ -178,26 +184,25 @@ static void fixup_amd_bootblock(struct mtd_info *mtd, void* param)  			extp->TopBottom = 2;	/* bottom boot */  		} -		DEBUG(MTD_DEBUG_LEVEL1, -			"%s: AMD CFI PRI V%c.%c has no boot block field;" +		pr_debug("%s: AMD CFI PRI V%c.%c has no boot block field;"  			" deduced %s from Device ID\n", map->name, major, minor,  			extp->TopBottom == 2 ? "bottom" : "top");  	}  }  #endif -static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) +static void fixup_use_write_buffers(struct mtd_info *mtd)  {  	struct map_info *map = mtd->priv;  	struct cfi_private *cfi = map->fldrv_priv;  	if (cfi->cfiq->BufWriteTimeoutTyp) { -		DEBUG(MTD_DEBUG_LEVEL1, "Using buffer write method\n" ); -		mtd->write = cfi_amdstd_write_buffers; +		pr_debug("Using buffer write method\n" ); +		mtd->_write = cfi_amdstd_write_buffers;  	}  }  /* Atmel chips don't use the same PRI format as AMD chips */ -static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) +static void fixup_convert_atmel_pri(struct mtd_info *mtd)  {  	struct map_info *map = mtd->priv;  	struct cfi_private *cfi = map->fldrv_priv; @@ -228,20 +233,20 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)  	cfi->cfiq->BufWriteTimeoutMax = 0;  } -static void fixup_use_secsi(struct mtd_info *mtd, void *param) +static void fixup_use_secsi(struct mtd_info *mtd)  {  	/* Setup for chips with a secsi area */ -	mtd->read_user_prot_reg = cfi_amdstd_secsi_read; -	mtd->read_fact_prot_reg = cfi_amdstd_secsi_read; +	mtd->_read_user_prot_reg = cfi_amdstd_secsi_read; +	mtd->_read_fact_prot_reg = cfi_amdstd_secsi_read;  } -static void fixup_use_erase_chip(struct mtd_info *mtd, void *param) +static void fixup_use_erase_chip(struct mtd_info *mtd)  {  	struct map_info *map = mtd->priv;  	struct cfi_private *cfi = map->fldrv_priv;  	if ((cfi->cfiq->NumEraseRegions == 1) &&  		((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0)) { -		mtd->erase = cfi_amdstd_erase_chip; +		mtd->_erase = cfi_amdstd_erase_chip;  	}  } @@ -250,10 +255,10 @@ static void fixup_use_erase_chip(struct mtd_info *mtd, void *param)   * Some Atmel chips (e.g. the AT49BV6416) power-up with all sectors   * locked by default.   */ -static void fixup_use_atmel_lock(struct mtd_info *mtd, void *param) +static void fixup_use_atmel_lock(struct mtd_info *mtd)  { -	mtd->lock = cfi_atmel_lock; -	mtd->unlock = cfi_atmel_unlock; +	mtd->_lock = cfi_atmel_lock; +	mtd->_unlock = cfi_atmel_unlock;  	mtd->flags |= MTD_POWERUP_LOCK;  } @@ -263,7 +268,7 @@ static void fixup_old_sst_eraseregion(struct mtd_info *mtd)  	struct cfi_private *cfi = map->fldrv_priv;  	/* -	 * These flashes report two seperate eraseblock regions based on the +	 * These flashes report two separate eraseblock regions based on the  	 * sector_erase-size and block_erase-size, although they both operate on the  	 * same memory. This is not allowed according to CFI, so we just pick the  	 * sector_erase-size. @@ -271,7 +276,7 @@ static void fixup_old_sst_eraseregion(struct mtd_info *mtd)  	cfi->cfiq->NumEraseRegions = 1;  } -static void fixup_sst39vf(struct mtd_info *mtd, void *param) +static void fixup_sst39vf(struct mtd_info *mtd)  {  	struct map_info *map = mtd->priv;  	struct cfi_private *cfi = map->fldrv_priv; @@ -282,7 +287,7 @@ static void fixup_sst39vf(struct mtd_info *mtd, void *param)  	cfi->addr_unlock2 = 0x2AAA;  } -static void fixup_sst39vf_rev_b(struct mtd_info *mtd, void *param) +static void fixup_sst39vf_rev_b(struct mtd_info *mtd)  {  	struct map_info *map = mtd->priv;  	struct cfi_private *cfi = map->fldrv_priv; @@ -295,12 +300,12 @@ static void fixup_sst39vf_rev_b(struct mtd_info *mtd, void *param)  	cfi->sector_erase_cmd = CMD(0x50);  } -static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd, void *param) +static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd)  {  	struct map_info *map = mtd->priv;  	struct cfi_private *cfi = map->fldrv_priv; -	fixup_sst39vf_rev_b(mtd, param); +	fixup_sst39vf_rev_b(mtd);  	/*  	 * CFI reports 1024 sectors (0x03ff+1) of 64KBytes (0x0100*256) where @@ -310,71 +315,86 @@ static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd, void *param)  	pr_warning("%s: Bad 38VF640x CFI data; adjusting sector size from 64 to 8KiB\n", mtd->name);  } -static void fixup_s29gl064n_sectors(struct mtd_info *mtd, void *param) +static void fixup_s29gl064n_sectors(struct mtd_info *mtd)  {  	struct map_info *map = mtd->priv;  	struct cfi_private *cfi = map->fldrv_priv;  	if ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0x003f) {  		cfi->cfiq->EraseRegionInfo[0] |= 0x0040; -		pr_warning("%s: Bad S29GL064N CFI data, adjust from 64 to 128 sectors\n", mtd->name); +		pr_warning("%s: Bad S29GL064N CFI data; adjust from 64 to 128 sectors\n", mtd->name);  	}  } -static void fixup_s29gl032n_sectors(struct mtd_info *mtd, void *param) +static void fixup_s29gl032n_sectors(struct mtd_info *mtd)  {  	struct map_info *map = mtd->priv;  	struct cfi_private *cfi = map->fldrv_priv;  	if ((cfi->cfiq->EraseRegionInfo[1] & 0xffff) == 0x007e) {  		cfi->cfiq->EraseRegionInfo[1] &= ~0x0040; -		pr_warning("%s: Bad S29GL032N CFI data, adjust from 127 to 63 sectors\n", mtd->name); +		pr_warning("%s: Bad S29GL032N CFI data; adjust from 127 to 63 sectors\n", mtd->name);  	}  } +static void fixup_s29ns512p_sectors(struct mtd_info *mtd) +{ +	struct map_info *map = mtd->priv; +	struct cfi_private *cfi = map->fldrv_priv; + +	/* +	 *  S29NS512P flash uses more than 8bits to report number of sectors, +	 * which is not permitted by CFI. +	 */ +	cfi->cfiq->EraseRegionInfo[0] = 0x020001ff; +	pr_warning("%s: Bad S29NS512P CFI data; adjust to 512 sectors\n", mtd->name); +} +  /* Used to fix CFI-Tables of chips without Extended Query Tables */  static struct cfi_fixup cfi_nopri_fixup_table[] = { -	{ CFI_MFR_SST, 0x234A, fixup_sst39vf, NULL, }, /* SST39VF1602 */ -	{ CFI_MFR_SST, 0x234B, fixup_sst39vf, NULL, }, /* SST39VF1601 */ -	{ CFI_MFR_SST, 0x235A, fixup_sst39vf, NULL, }, /* SST39VF3202 */ -	{ CFI_MFR_SST, 0x235B, fixup_sst39vf, NULL, }, /* SST39VF3201 */ -	{ CFI_MFR_SST, 0x235C, fixup_sst39vf_rev_b, NULL, }, /* SST39VF3202B */ -	{ CFI_MFR_SST, 0x235D, fixup_sst39vf_rev_b, NULL, }, /* SST39VF3201B */ -	{ CFI_MFR_SST, 0x236C, fixup_sst39vf_rev_b, NULL, }, /* SST39VF6402B */ -	{ CFI_MFR_SST, 0x236D, fixup_sst39vf_rev_b, NULL, }, /* SST39VF6401B */ -	{ 0, 0, NULL, NULL } +	{ CFI_MFR_SST, 0x234a, fixup_sst39vf }, /* SST39VF1602 */ +	{ CFI_MFR_SST, 0x234b, fixup_sst39vf }, /* SST39VF1601 */ +	{ CFI_MFR_SST, 0x235a, fixup_sst39vf }, /* SST39VF3202 */ +	{ CFI_MFR_SST, 0x235b, fixup_sst39vf }, /* SST39VF3201 */ +	{ CFI_MFR_SST, 0x235c, fixup_sst39vf_rev_b }, /* SST39VF3202B */ +	{ CFI_MFR_SST, 0x235d, fixup_sst39vf_rev_b }, /* SST39VF3201B */ +	{ CFI_MFR_SST, 0x236c, fixup_sst39vf_rev_b }, /* SST39VF6402B */ +	{ CFI_MFR_SST, 0x236d, fixup_sst39vf_rev_b }, /* SST39VF6401B */ +	{ 0, 0, NULL }  };  static struct cfi_fixup cfi_fixup_table[] = { -	{ CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL }, +	{ CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri },  #ifdef AMD_BOOTLOC_BUG -	{ CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL }, -	{ CFI_MFR_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock, NULL }, +	{ CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock }, +	{ CFI_MFR_AMIC, CFI_ID_ANY, fixup_amd_bootblock }, +	{ CFI_MFR_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock },  #endif -	{ CFI_MFR_AMD, 0x0050, fixup_use_secsi, NULL, }, -	{ CFI_MFR_AMD, 0x0053, fixup_use_secsi, NULL, }, -	{ CFI_MFR_AMD, 0x0055, fixup_use_secsi, NULL, }, -	{ CFI_MFR_AMD, 0x0056, fixup_use_secsi, NULL, }, -	{ CFI_MFR_AMD, 0x005C, fixup_use_secsi, NULL, }, -	{ CFI_MFR_AMD, 0x005F, fixup_use_secsi, NULL, }, -	{ CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors, NULL, }, -	{ CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors, NULL, }, -	{ CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors, NULL, }, -	{ CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors, NULL, }, -	{ CFI_MFR_SST, 0x536A, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6402 */ -	{ CFI_MFR_SST, 0x536B, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6401 */ -	{ CFI_MFR_SST, 0x536C, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6404 */ -	{ CFI_MFR_SST, 0x536D, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6403 */ +	{ CFI_MFR_AMD, 0x0050, fixup_use_secsi }, +	{ CFI_MFR_AMD, 0x0053, fixup_use_secsi }, +	{ CFI_MFR_AMD, 0x0055, fixup_use_secsi }, +	{ CFI_MFR_AMD, 0x0056, fixup_use_secsi }, +	{ CFI_MFR_AMD, 0x005C, fixup_use_secsi }, +	{ CFI_MFR_AMD, 0x005F, fixup_use_secsi }, +	{ CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors }, +	{ CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors }, +	{ CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors }, +	{ CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors }, +	{ CFI_MFR_AMD, 0x3f00, fixup_s29ns512p_sectors }, +	{ CFI_MFR_SST, 0x536a, fixup_sst38vf640x_sectorsize }, /* SST38VF6402 */ +	{ CFI_MFR_SST, 0x536b, fixup_sst38vf640x_sectorsize }, /* SST38VF6401 */ +	{ CFI_MFR_SST, 0x536c, fixup_sst38vf640x_sectorsize }, /* SST38VF6404 */ +	{ CFI_MFR_SST, 0x536d, fixup_sst38vf640x_sectorsize }, /* SST38VF6403 */  #if !FORCE_WORD_WRITE -	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, }, +	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers },  #endif -	{ 0, 0, NULL, NULL } +	{ 0, 0, NULL }  };  static struct cfi_fixup jedec_fixup_table[] = { -	{ CFI_MFR_SST, SST49LF004B, fixup_use_fwh_lock, NULL, }, -	{ CFI_MFR_SST, SST49LF040B, fixup_use_fwh_lock, NULL, }, -	{ CFI_MFR_SST, SST49LF008A, fixup_use_fwh_lock, NULL, }, -	{ 0, 0, NULL, NULL } +	{ CFI_MFR_SST, SST49LF004B, fixup_use_fwh_lock }, +	{ CFI_MFR_SST, SST49LF040B, fixup_use_fwh_lock }, +	{ CFI_MFR_SST, SST49LF008A, fixup_use_fwh_lock }, +	{ 0, 0, NULL }  };  static struct cfi_fixup fixup_table[] = { @@ -383,18 +403,30 @@ static struct cfi_fixup fixup_table[] = {  	 * well.  This table is to pick all cases where  	 * we know that is the case.  	 */ -	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip, NULL }, -	{ CFI_MFR_ATMEL, AT49BV6416, fixup_use_atmel_lock, NULL }, -	{ 0, 0, NULL, NULL } +	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip }, +	{ CFI_MFR_ATMEL, AT49BV6416, fixup_use_atmel_lock }, +	{ 0, 0, NULL }  };  static void cfi_fixup_major_minor(struct cfi_private *cfi,  				  struct cfi_pri_amdstd *extp)  { -	if (cfi->mfr == CFI_MFR_SAMSUNG && cfi->id == 0x257e && -	    extp->MajorVersion == '0') -		extp->MajorVersion = '1'; +	if (cfi->mfr == CFI_MFR_SAMSUNG) { +		if ((extp->MajorVersion == '0' && extp->MinorVersion == '0') || +		    (extp->MajorVersion == '3' && extp->MinorVersion == '3')) { +			/* +			 * Samsung K8P2815UQB and K8D6x16UxM chips +			 * report major=0 / minor=0. +			 * K8D3x16UxC chips report major=3 / minor=3. +			 */ +			printk(KERN_NOTICE "  Fixing Samsung's Amd/Fujitsu" +			       " Extended Query version to 1.%c\n", +			       extp->MinorVersion); +			extp->MajorVersion = '1'; +		} +	} +  	/*  	 * SST 38VF640x chips report major=0xFF / minor=0xFF.  	 */ @@ -404,31 +436,97 @@ static void cfi_fixup_major_minor(struct cfi_private *cfi,  	}  } +static int is_m29ew(struct cfi_private *cfi) +{ +	if (cfi->mfr == CFI_MFR_INTEL && +	    ((cfi->device_type == CFI_DEVICETYPE_X8 && (cfi->id & 0xff) == 0x7e) || +	     (cfi->device_type == CFI_DEVICETYPE_X16 && cfi->id == 0x227e))) +		return 1; +	return 0; +} + +/* + * From TN-13-07: Patching the Linux Kernel and U-Boot for M29 Flash, page 20: + * Some revisions of the M29EW suffer from erase suspend hang ups. In + * particular, it can occur when the sequence + * Erase Confirm -> Suspend -> Program -> Resume + * causes a lockup due to internal timing issues. The consequence is that the + * erase cannot be resumed without inserting a dummy command after programming + * and prior to resuming. [...] The work-around is to issue a dummy write cycle + * that writes an F0 command code before the RESUME command. + */ +static void cfi_fixup_m29ew_erase_suspend(struct map_info *map, +					  unsigned long adr) +{ +	struct cfi_private *cfi = map->fldrv_priv; +	/* before resume, insert a dummy 0xF0 cycle for Micron M29EW devices */ +	if (is_m29ew(cfi)) +		map_write(map, CMD(0xF0), adr); +} + +/* + * From TN-13-07: Patching the Linux Kernel and U-Boot for M29 Flash, page 22: + * + * Some revisions of the M29EW (for example, A1 and A2 step revisions) + * are affected by a problem that could cause a hang up when an ERASE SUSPEND + * command is issued after an ERASE RESUME operation without waiting for a + * minimum delay.  The result is that once the ERASE seems to be completed + * (no bits are toggling), the contents of the Flash memory block on which + * the erase was ongoing could be inconsistent with the expected values + * (typically, the array value is stuck to the 0xC0, 0xC4, 0x80, or 0x84 + * values), causing a consequent failure of the ERASE operation. + * The occurrence of this issue could be high, especially when file system + * operations on the Flash are intensive.  As a result, it is recommended + * that a patch be applied.  Intensive file system operations can cause many + * calls to the garbage routine to free Flash space (also by erasing physical + * Flash blocks) and as a result, many consecutive SUSPEND and RESUME + * commands can occur.  The problem disappears when a delay is inserted after + * the RESUME command by using the udelay() function available in Linux. + * The DELAY value must be tuned based on the customer's platform. + * The maximum value that fixes the problem in all cases is 500us. + * But, in our experience, a delay of 30 µs to 50 µs is sufficient + * in most cases. + * We have chosen 500µs because this latency is acceptable. + */ +static void cfi_fixup_m29ew_delay_after_resume(struct cfi_private *cfi) +{ +	/* +	 * Resolving the Delay After Resume Issue see Micron TN-13-07 +	 * Worst case delay must be 500µs but 30-50µs should be ok as well +	 */ +	if (is_m29ew(cfi)) +		cfi_udelay(500); +} +  struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)  {  	struct cfi_private *cfi = map->fldrv_priv; +	struct device_node __maybe_unused *np = map->device_node;  	struct mtd_info *mtd;  	int i;  	mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); -	if (!mtd) { -		printk(KERN_WARNING "Failed to allocate memory for MTD device\n"); +	if (!mtd)  		return NULL; -	}  	mtd->priv = map;  	mtd->type = MTD_NORFLASH;  	/* Fill in the default mtd operations */ -	mtd->erase   = cfi_amdstd_erase_varsize; -	mtd->write   = cfi_amdstd_write_words; -	mtd->read    = cfi_amdstd_read; -	mtd->sync    = cfi_amdstd_sync; -	mtd->suspend = cfi_amdstd_suspend; -	mtd->resume  = cfi_amdstd_resume; +	mtd->_erase   = cfi_amdstd_erase_varsize; +	mtd->_write   = cfi_amdstd_write_words; +	mtd->_read    = cfi_amdstd_read; +	mtd->_sync    = cfi_amdstd_sync; +	mtd->_suspend = cfi_amdstd_suspend; +	mtd->_resume  = cfi_amdstd_resume;  	mtd->flags   = MTD_CAP_NORFLASH;  	mtd->name    = map->name;  	mtd->writesize = 1; +	mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; +	pr_debug("MTD %s(): write buffer size %d\n", __func__, +			mtd->writebufsize); + +	mtd->_panic_write = cfi_amdstd_panic_write;  	mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot;  	if (cfi->cfi_mode==CFI_MODE_CFI){ @@ -445,13 +543,14 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)  			cfi_fixup_major_minor(cfi, extp);  			/* -			 * Valid primary extension versions are: 1.0, 1.1, 1.2, 1.3, 1.4 +			 * Valid primary extension versions are: 1.0, 1.1, 1.2, 1.3, 1.4, 1.5  			 * see: http://cs.ozerki.net/zap/pub/axim-x5/docs/cfi_r20.pdf, page 19   			 *      http://www.spansion.com/Support/AppNotes/cfi_100_20011201.pdf  			 *      http://www.spansion.com/Support/Datasheets/s29ws-p_00_a12_e.pdf +			 *      http://www.spansion.com/Support/Datasheets/S29GL_128S_01GS_00_02_e.pdf  			 */  			if (extp->MajorVersion != '1' || -			    (extp->MajorVersion == '1' && (extp->MinorVersion < '0' || extp->MinorVersion > '4'))) { +			    (extp->MajorVersion == '1' && (extp->MinorVersion < '0' || extp->MinorVersion > '5'))) {  				printk(KERN_ERR "  Unknown Amd/Fujitsu Extended Query "  				       "version %c.%c (%#02x/%#02x).\n",  				       extp->MajorVersion, extp->MinorVersion, @@ -475,6 +574,17 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)  			cfi_tell_features(extp);  #endif +#ifdef CONFIG_OF +			if (np && of_property_read_bool( +				    np, "use-advanced-sector-protection") +			    && extp->BlkProtUnprot == 8) { +				printk(KERN_INFO "  Advanced Sector Protection (PPB Locking) supported\n"); +				mtd->_lock = cfi_ppb_lock; +				mtd->_unlock = cfi_ppb_unlock; +				mtd->_is_locked = cfi_ppb_is_locked; +			} +#endif +  			bootloc = extp->TopBottom;  			if ((bootloc < 2) || (bootloc > 5)) {  				printk(KERN_WARNING "%s: CFI contains unrecognised boot " @@ -548,10 +658,8 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)  	mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;  	mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)  				    * mtd->numeraseregions, GFP_KERNEL); -	if (!mtd->eraseregions) { -		printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n"); +	if (!mtd->eraseregions)  		goto setup_err; -	}  	for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {  		unsigned long ernum, ersize; @@ -594,8 +702,8 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)   *   * Note that anything more complicated than checking if no bits are toggling   * (including checking DQ5 for an error status) is tricky to get working - * correctly and is therefore not done	(particulary with interleaved chips - * as each chip must be checked independantly of the others). + * correctly and is therefore not done	(particularly with interleaved chips + * as each chip must be checked independently of the others).   */  static int __xipram chip_ready(struct map_info *map, unsigned long addr)  { @@ -618,8 +726,8 @@ static int __xipram chip_ready(struct map_info *map, unsigned long addr)   *   * Note that anything more complicated than checking if no bits are toggling   * (including checking DQ5 for an error status) is tricky to get working - * correctly and is therefore not done	(particulary with interleaved chips - * as each chip must be checked independantly of the others). + * correctly and is therefore not done	(particularly with interleaved chips + * as each chip must be checked independently of the others).   *   */  static int __xipram chip_good(struct map_info *map, unsigned long addr, map_word expected) @@ -693,9 +801,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr  				 * there was an error (so leave the erase  				 * routine to recover from it) or we trying to  				 * use the erase-in-progress sector. */ -				map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr); -				chip->state = FL_ERASING; -				chip->oldstate = FL_READY; +				put_chip(map, chip, adr);  				printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__);  				return -EIO;  			} @@ -745,8 +851,10 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad  	switch(chip->oldstate) {  	case FL_ERASING: -		chip->state = chip->oldstate; +		cfi_fixup_m29ew_erase_suspend(map, +			chip->in_progress_block_addr);  		map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr); +		cfi_fixup_m29ew_delay_after_resume(cfi);  		chip->oldstate = FL_READY;  		chip->state = FL_ERASING;  		break; @@ -758,8 +866,6 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad  	case FL_READY:  	case FL_STATUS: -		/* We should really make set_vpp() count, rather than doing this */ -		DISABLE_VPP(map);  		break;  	default:  		printk(KERN_ERR "MTD: put_chip() called with oldstate %d!!\n", chip->oldstate); @@ -888,6 +994,8 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,  			/* Disallow XIP again */  			local_irq_disable(); +			/* Correct Erase Suspend Hangups for M29EW */ +			cfi_fixup_m29ew_erase_suspend(map, adr);  			/* Resume the write or erase operation */  			map_write(map, cfi->sector_erase_cmd, adr);  			chip->state = oldstate; @@ -1001,13 +1109,9 @@ static int cfi_amdstd_read (struct mtd_info *mtd, loff_t from, size_t len, size_  	int ret = 0;  	/* ofs: offset within the first chip that the first read should start */ -  	chipnum = (from >> cfi->chipshift);  	ofs = from - (chipnum <<  cfi->chipshift); - -	*retlen = 0; -  	while (len) {  		unsigned long thislen; @@ -1085,16 +1189,11 @@ static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len,  	int chipnum;  	int ret = 0; -  	/* ofs: offset within the first chip that the first read should start */ -  	/* 8 secsi bytes per chip */  	chipnum=from>>3;  	ofs=from & 7; - -	*retlen = 0; -  	while (len) {  		unsigned long thislen; @@ -1148,7 +1247,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,  		return ret;  	} -	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", +	pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",  	       __func__, adr, datum.x[0] );  	/* @@ -1159,7 +1258,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,  	 */  	oldd = map_read(map, adr);  	if (map_word_equal(map, oldd, datum)) { -		DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): NOP\n", +		pr_debug("MTD %s(): NOP\n",  		       __func__);  		goto op_done;  	} @@ -1222,6 +1321,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,  	xip_enable(map, chip, adr);   op_done:  	chip->state = FL_READY; +	DISABLE_VPP(map);  	put_chip(map, chip, adr);  	mutex_unlock(&chip->mutex); @@ -1239,10 +1339,6 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,  	unsigned long ofs, chipstart;  	DECLARE_WAITQUEUE(wait, current); -	*retlen = 0; -	if (!len) -		return 0; -  	chipnum = to >> cfi->chipshift;  	ofs = to  - (chipnum << cfi->chipshift);  	chipstart = cfi->chips[chipnum].start; @@ -1385,7 +1481,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,  	datum = map_word_load(map, buf); -	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", +	pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",  	       __func__, adr, datum.x[0] );  	XIP_INVAL_CACHED_RANGE(map, adr, len); @@ -1453,17 +1549,30 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,  		UDELAY(map, chip, adr, 1);  	} -	/* reset on all failures. */ -	map_write( map, CMD(0xF0), chip->start ); +	/* +	 * Recovery from write-buffer programming failures requires +	 * the write-to-buffer-reset sequence.  Since the last part +	 * of the sequence also works as a normal reset, we can run +	 * the same commands regardless of why we are here. +	 * See e.g. +	 * http://www.spansion.com/Support/Application%20Notes/MirrorBit_Write_Buffer_Prog_Page_Buffer_Read_AN.pdf +	 */ +	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, +			 cfi->device_type, NULL); +	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, +			 cfi->device_type, NULL); +	cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, chip->start, map, cfi, +			 cfi->device_type, NULL);  	xip_enable(map, chip, adr);  	/* FIXME - should have reset delay before continuing */ -	printk(KERN_WARNING "MTD %s(): software timeout\n", -	       __func__ ); +	printk(KERN_WARNING "MTD %s(): software timeout, address:0x%.8lx.\n", +	       __func__, adr);  	ret = -EIO;   op_done:  	chip->state = FL_READY; +	DISABLE_VPP(map);  	put_chip(map, chip, adr);  	mutex_unlock(&chip->mutex); @@ -1481,10 +1590,6 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,  	int chipnum;  	unsigned long ofs; -	*retlen = 0; -	if (!len) -		return 0; -  	chipnum = to >> cfi->chipshift;  	ofs = to  - (chipnum << cfi->chipshift); @@ -1550,6 +1655,238 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,  	return 0;  } +/* + * Wait for the flash chip to become ready to write data + * + * This is only called during the panic_write() path. When panic_write() + * is called, the kernel is in the process of a panic, and will soon be + * dead. Therefore we don't take any locks, and attempt to get access + * to the chip as soon as possible. + */ +static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip, +				 unsigned long adr) +{ +	struct cfi_private *cfi = map->fldrv_priv; +	int retries = 10; +	int i; + +	/* +	 * If the driver thinks the chip is idle, and no toggle bits +	 * are changing, then the chip is actually idle for sure. +	 */ +	if (chip->state == FL_READY && chip_ready(map, adr)) +		return 0; + +	/* +	 * Try several times to reset the chip and then wait for it +	 * to become idle. The upper limit of a few milliseconds of +	 * delay isn't a big problem: the kernel is dying anyway. It +	 * is more important to save the messages. +	 */ +	while (retries > 0) { +		const unsigned long timeo = (HZ / 1000) + 1; + +		/* send the reset command */ +		map_write(map, CMD(0xF0), chip->start); + +		/* wait for the chip to become ready */ +		for (i = 0; i < jiffies_to_usecs(timeo); i++) { +			if (chip_ready(map, adr)) +				return 0; + +			udelay(1); +		} +	} + +	/* the chip never became ready */ +	return -EBUSY; +} + +/* + * Write out one word of data to a single flash chip during a kernel panic + * + * This is only called during the panic_write() path. When panic_write() + * is called, the kernel is in the process of a panic, and will soon be + * dead. Therefore we don't take any locks, and attempt to get access + * to the chip as soon as possible. + * + * The implementation of this routine is intentionally similar to + * do_write_oneword(), in order to ease code maintenance. + */ +static int do_panic_write_oneword(struct map_info *map, struct flchip *chip, +				  unsigned long adr, map_word datum) +{ +	const unsigned long uWriteTimeout = (HZ / 1000) + 1; +	struct cfi_private *cfi = map->fldrv_priv; +	int retry_cnt = 0; +	map_word oldd; +	int ret = 0; +	int i; + +	adr += chip->start; + +	ret = cfi_amdstd_panic_wait(map, chip, adr); +	if (ret) +		return ret; + +	pr_debug("MTD %s(): PANIC WRITE 0x%.8lx(0x%.8lx)\n", +			__func__, adr, datum.x[0]); + +	/* +	 * Check for a NOP for the case when the datum to write is already +	 * present - it saves time and works around buggy chips that corrupt +	 * data at other locations when 0xff is written to a location that +	 * already contains 0xff. +	 */ +	oldd = map_read(map, adr); +	if (map_word_equal(map, oldd, datum)) { +		pr_debug("MTD %s(): NOP\n", __func__); +		goto op_done; +	} + +	ENABLE_VPP(map); + +retry: +	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); +	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); +	cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); +	map_write(map, datum, adr); + +	for (i = 0; i < jiffies_to_usecs(uWriteTimeout); i++) { +		if (chip_ready(map, adr)) +			break; + +		udelay(1); +	} + +	if (!chip_good(map, adr, datum)) { +		/* reset on all failures. */ +		map_write(map, CMD(0xF0), chip->start); +		/* FIXME - should have reset delay before continuing */ + +		if (++retry_cnt <= MAX_WORD_RETRIES) +			goto retry; + +		ret = -EIO; +	} + +op_done: +	DISABLE_VPP(map); +	return ret; +} + +/* + * Write out some data during a kernel panic + * + * This is used by the mtdoops driver to save the dying messages from a + * kernel which has panic'd. + * + * This routine ignores all of the locking used throughout the rest of the + * driver, in order to ensure that the data gets written out no matter what + * state this driver (and the flash chip itself) was in when the kernel crashed. + * + * The implementation of this routine is intentionally similar to + * cfi_amdstd_write_words(), in order to ease code maintenance. + */ +static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, +				  size_t *retlen, const u_char *buf) +{ +	struct map_info *map = mtd->priv; +	struct cfi_private *cfi = map->fldrv_priv; +	unsigned long ofs, chipstart; +	int ret = 0; +	int chipnum; + +	chipnum = to >> cfi->chipshift; +	ofs = to - (chipnum << cfi->chipshift); +	chipstart = cfi->chips[chipnum].start; + +	/* If it's not bus aligned, do the first byte write */ +	if (ofs & (map_bankwidth(map) - 1)) { +		unsigned long bus_ofs = ofs & ~(map_bankwidth(map) - 1); +		int i = ofs - bus_ofs; +		int n = 0; +		map_word tmp_buf; + +		ret = cfi_amdstd_panic_wait(map, &cfi->chips[chipnum], bus_ofs); +		if (ret) +			return ret; + +		/* Load 'tmp_buf' with old contents of flash */ +		tmp_buf = map_read(map, bus_ofs + chipstart); + +		/* Number of bytes to copy from buffer */ +		n = min_t(int, len, map_bankwidth(map) - i); + +		tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n); + +		ret = do_panic_write_oneword(map, &cfi->chips[chipnum], +					     bus_ofs, tmp_buf); +		if (ret) +			return ret; + +		ofs += n; +		buf += n; +		(*retlen) += n; +		len -= n; + +		if (ofs >> cfi->chipshift) { +			chipnum++; +			ofs = 0; +			if (chipnum == cfi->numchips) +				return 0; +		} +	} + +	/* We are now aligned, write as much as possible */ +	while (len >= map_bankwidth(map)) { +		map_word datum; + +		datum = map_word_load(map, buf); + +		ret = do_panic_write_oneword(map, &cfi->chips[chipnum], +					     ofs, datum); +		if (ret) +			return ret; + +		ofs += map_bankwidth(map); +		buf += map_bankwidth(map); +		(*retlen) += map_bankwidth(map); +		len -= map_bankwidth(map); + +		if (ofs >> cfi->chipshift) { +			chipnum++; +			ofs = 0; +			if (chipnum == cfi->numchips) +				return 0; + +			chipstart = cfi->chips[chipnum].start; +		} +	} + +	/* Write the trailing bytes if any */ +	if (len & (map_bankwidth(map) - 1)) { +		map_word tmp_buf; + +		ret = cfi_amdstd_panic_wait(map, &cfi->chips[chipnum], ofs); +		if (ret) +			return ret; + +		tmp_buf = map_read(map, ofs + chipstart); + +		tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len); + +		ret = do_panic_write_oneword(map, &cfi->chips[chipnum], +					     ofs, tmp_buf); +		if (ret) +			return ret; + +		(*retlen) += len; +	} + +	return 0; +} +  /*   * Handle devices with one erase region, that only implement @@ -1572,7 +1909,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)  		return ret;  	} -	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", +	pr_debug("MTD %s(): ERASE 0x%.8lx\n",  	       __func__, chip->start );  	XIP_INVAL_CACHED_RANGE(map, adr, map->size); @@ -1637,6 +1974,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)  	chip->state = FL_READY;  	xip_enable(map, chip, adr); +	DISABLE_VPP(map);  	put_chip(map, chip, adr);  	mutex_unlock(&chip->mutex); @@ -1660,7 +1998,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,  		return ret;  	} -	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", +	pr_debug("MTD %s(): ERASE 0x%.8lx\n",  	       __func__, adr );  	XIP_INVAL_CACHED_RANGE(map, adr, len); @@ -1727,6 +2065,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,  	}  	chip->state = FL_READY; +	DISABLE_VPP(map);  	put_chip(map, chip, adr);  	mutex_unlock(&chip->mutex);  	return ret; @@ -1786,8 +2125,7 @@ static int do_atmel_lock(struct map_info *map, struct flchip *chip,  		goto out_unlock;  	chip->state = FL_LOCKING; -	DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): LOCK 0x%08lx len %d\n", -	      __func__, adr, len); +	pr_debug("MTD %s(): LOCK 0x%08lx len %d\n", __func__, adr, len);  	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,  			 cfi->device_type, NULL); @@ -1822,8 +2160,7 @@ static int do_atmel_unlock(struct map_info *map, struct flchip *chip,  		goto out_unlock;  	chip->state = FL_UNLOCKING; -	DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): LOCK 0x%08lx len %d\n", -	      __func__, adr, len); +	pr_debug("MTD %s(): LOCK 0x%08lx len %d\n", __func__, adr, len);  	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,  			 cfi->device_type, NULL); @@ -1848,6 +2185,205 @@ static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  	return cfi_varsize_frob(mtd, do_atmel_unlock, ofs, len, NULL);  } +/* + * Advanced Sector Protection - PPB (Persistent Protection Bit) locking + */ + +struct ppb_lock { +	struct flchip *chip; +	loff_t offset; +	int locked; +}; + +#define MAX_SECTORS			512 + +#define DO_XXLOCK_ONEBLOCK_LOCK		((void *)1) +#define DO_XXLOCK_ONEBLOCK_UNLOCK	((void *)2) +#define DO_XXLOCK_ONEBLOCK_GETLOCK	((void *)3) + +static int __maybe_unused do_ppb_xxlock(struct map_info *map, +					struct flchip *chip, +					unsigned long adr, int len, void *thunk) +{ +	struct cfi_private *cfi = map->fldrv_priv; +	unsigned long timeo; +	int ret; + +	mutex_lock(&chip->mutex); +	ret = get_chip(map, chip, adr + chip->start, FL_LOCKING); +	if (ret) { +		mutex_unlock(&chip->mutex); +		return ret; +	} + +	pr_debug("MTD %s(): XXLOCK 0x%08lx len %d\n", __func__, adr, len); + +	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, +			 cfi->device_type, NULL); +	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, +			 cfi->device_type, NULL); +	/* PPB entry command */ +	cfi_send_gen_cmd(0xC0, cfi->addr_unlock1, chip->start, map, cfi, +			 cfi->device_type, NULL); + +	if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) { +		chip->state = FL_LOCKING; +		map_write(map, CMD(0xA0), chip->start + adr); +		map_write(map, CMD(0x00), chip->start + adr); +	} else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) { +		/* +		 * Unlocking of one specific sector is not supported, so we +		 * have to unlock all sectors of this device instead +		 */ +		chip->state = FL_UNLOCKING; +		map_write(map, CMD(0x80), chip->start); +		map_write(map, CMD(0x30), chip->start); +	} else if (thunk == DO_XXLOCK_ONEBLOCK_GETLOCK) { +		chip->state = FL_JEDEC_QUERY; +		/* Return locked status: 0->locked, 1->unlocked */ +		ret = !cfi_read_query(map, adr); +	} else +		BUG(); + +	/* +	 * Wait for some time as unlocking of all sectors takes quite long +	 */ +	timeo = jiffies + msecs_to_jiffies(2000);	/* 2s max (un)locking */ +	for (;;) { +		if (chip_ready(map, adr)) +			break; + +		if (time_after(jiffies, timeo)) { +			printk(KERN_ERR "Waiting for chip to be ready timed out.\n"); +			ret = -EIO; +			break; +		} + +		UDELAY(map, chip, adr, 1); +	} + +	/* Exit BC commands */ +	map_write(map, CMD(0x90), chip->start); +	map_write(map, CMD(0x00), chip->start); + +	chip->state = FL_READY; +	put_chip(map, chip, adr + chip->start); +	mutex_unlock(&chip->mutex); + +	return ret; +} + +static int __maybe_unused cfi_ppb_lock(struct mtd_info *mtd, loff_t ofs, +				       uint64_t len) +{ +	return cfi_varsize_frob(mtd, do_ppb_xxlock, ofs, len, +				DO_XXLOCK_ONEBLOCK_LOCK); +} + +static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, +					 uint64_t len) +{ +	struct mtd_erase_region_info *regions = mtd->eraseregions; +	struct map_info *map = mtd->priv; +	struct cfi_private *cfi = map->fldrv_priv; +	struct ppb_lock *sect; +	unsigned long adr; +	loff_t offset; +	uint64_t length; +	int chipnum; +	int i; +	int sectors; +	int ret; + +	/* +	 * PPB unlocking always unlocks all sectors of the flash chip. +	 * We need to re-lock all previously locked sectors. So lets +	 * first check the locking status of all sectors and save +	 * it for future use. +	 */ +	sect = kzalloc(MAX_SECTORS * sizeof(struct ppb_lock), GFP_KERNEL); +	if (!sect) +		return -ENOMEM; + +	/* +	 * This code to walk all sectors is a slightly modified version +	 * of the cfi_varsize_frob() code. +	 */ +	i = 0; +	chipnum = 0; +	adr = 0; +	sectors = 0; +	offset = 0; +	length = mtd->size; + +	while (length) { +		int size = regions[i].erasesize; + +		/* +		 * Only test sectors that shall not be unlocked. The other +		 * sectors shall be unlocked, so lets keep their locking +		 * status at "unlocked" (locked=0) for the final re-locking. +		 */ +		if ((adr < ofs) || (adr >= (ofs + len))) { +			sect[sectors].chip = &cfi->chips[chipnum]; +			sect[sectors].offset = offset; +			sect[sectors].locked = do_ppb_xxlock( +				map, &cfi->chips[chipnum], adr, 0, +				DO_XXLOCK_ONEBLOCK_GETLOCK); +		} + +		adr += size; +		offset += size; +		length -= size; + +		if (offset == regions[i].offset + size * regions[i].numblocks) +			i++; + +		if (adr >> cfi->chipshift) { +			adr = 0; +			chipnum++; + +			if (chipnum >= cfi->numchips) +				break; +		} + +		sectors++; +		if (sectors >= MAX_SECTORS) { +			printk(KERN_ERR "Only %d sectors for PPB locking supported!\n", +			       MAX_SECTORS); +			kfree(sect); +			return -EINVAL; +		} +	} + +	/* Now unlock the whole chip */ +	ret = cfi_varsize_frob(mtd, do_ppb_xxlock, ofs, len, +			       DO_XXLOCK_ONEBLOCK_UNLOCK); +	if (ret) { +		kfree(sect); +		return ret; +	} + +	/* +	 * PPB unlocking always unlocks all sectors of the flash chip. +	 * We need to re-lock all previously locked sectors. +	 */ +	for (i = 0; i < sectors; i++) { +		if (sect[i].locked) +			do_ppb_xxlock(map, sect[i].chip, sect[i].offset, 0, +				      DO_XXLOCK_ONEBLOCK_LOCK); +	} + +	kfree(sect); +	return ret; +} + +static int __maybe_unused cfi_ppb_is_locked(struct mtd_info *mtd, loff_t ofs, +					    uint64_t len) +{ +	return cfi_varsize_frob(mtd, do_ppb_xxlock, ofs, len, +				DO_XXLOCK_ONEBLOCK_GETLOCK) ? 1 : 0; +}  static void cfi_amdstd_sync (struct mtd_info *mtd)  { diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index 314af1f5a37..423666b51ef 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -22,7 +22,6 @@  #include <linux/types.h>  #include <linux/kernel.h>  #include <linux/sched.h> -#include <linux/init.h>  #include <asm/io.h>  #include <asm/byteorder.h> @@ -139,8 +138,9 @@ struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary)  		}  		/* Do some byteswapping if necessary */ -		extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport); -		extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask); +		extp->FeatureSupport = cfi32_to_cpu(map, extp->FeatureSupport); +		extp->BlkStatusRegMask = cfi32_to_cpu(map, +						extp->BlkStatusRegMask);  #ifdef DEBUG_CFI_FEATURES  		/* Tell the user about it in lots of lovely detail */ @@ -175,7 +175,6 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)  	//printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips);  	if (!mtd) { -		printk(KERN_ERR "Failed to allocate memory for MTD device\n");  		kfree(cfi->cmdset_priv);  		return NULL;  	} @@ -188,7 +187,6 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)  	mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)  			* mtd->numeraseregions, GFP_KERNEL);  	if (!mtd->eraseregions) { -		printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n");  		kfree(cfi->cmdset_priv);  		kfree(mtd);  		return NULL; @@ -227,17 +225,18 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)  		}  	/* Also select the correct geometry setup too */ -	mtd->erase = cfi_staa_erase_varsize; -	mtd->read = cfi_staa_read; -        mtd->write = cfi_staa_write_buffers; -	mtd->writev = cfi_staa_writev; -	mtd->sync = cfi_staa_sync; -	mtd->lock = cfi_staa_lock; -	mtd->unlock = cfi_staa_unlock; -	mtd->suspend = cfi_staa_suspend; -	mtd->resume = cfi_staa_resume; +	mtd->_erase = cfi_staa_erase_varsize; +	mtd->_read = cfi_staa_read; +	mtd->_write = cfi_staa_write_buffers; +	mtd->_writev = cfi_staa_writev; +	mtd->_sync = cfi_staa_sync; +	mtd->_lock = cfi_staa_lock; +	mtd->_unlock = cfi_staa_unlock; +	mtd->_suspend = cfi_staa_suspend; +	mtd->_resume = cfi_staa_resume;  	mtd->flags = MTD_CAP_NORFLASH & ~MTD_BIT_WRITEABLE;  	mtd->writesize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */ +	mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;  	map->fldrv = &cfi_staa_chipdrv;  	__module_get(THIS_MODULE);  	mtd->name = map->name; @@ -295,6 +294,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof  				/* make sure we're in 'read status' mode */  				map_write(map, CMD(0x70), cmd_addr);  				chip->state = FL_ERASING; +				wake_up(&chip->wq);  				mutex_unlock(&chip->mutex);  				printk(KERN_ERR "Chip not ready after erase "  				       "suspended: status = 0x%lx\n", status.x[0]); @@ -391,8 +391,6 @@ static int cfi_staa_read (struct mtd_info *mtd, loff_t from, size_t len, size_t  	chipnum = (from >> cfi->chipshift);  	ofs = from - (chipnum <<  cfi->chipshift); -	*retlen = 0; -  	while (len) {  		unsigned long thislen; @@ -614,10 +612,6 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to,  	int chipnum;  	unsigned long ofs; -	*retlen = 0; -	if (!len) -		return 0; -  	chipnum = to >> cfi->chipshift;  	ofs = to  - (chipnum << cfi->chipshift); @@ -696,7 +690,8 @@ cfi_staa_writev(struct mtd_info *mtd, const struct kvec *vecs,  				continue;  			}  			memcpy(buffer+buflen, elem_base, ECCBUF_SIZE-buflen); -			ret = mtd->write(mtd, to, ECCBUF_SIZE, &thislen, buffer); +			ret = mtd_write(mtd, to, ECCBUF_SIZE, &thislen, +					buffer);  			totlen += thislen;  			if (ret || thislen != ECCBUF_SIZE)  				goto write_error; @@ -705,7 +700,8 @@ cfi_staa_writev(struct mtd_info *mtd, const struct kvec *vecs,  			to += ECCBUF_SIZE;  		}  		if (ECCBUF_DIV(elem_len)) { /* write clean aligned data */ -			ret = mtd->write(mtd, to, ECCBUF_DIV(elem_len), &thislen, elem_base); +			ret = mtd_write(mtd, to, ECCBUF_DIV(elem_len), +					&thislen, elem_base);  			totlen += thislen;  			if (ret || thislen != ECCBUF_DIV(elem_len))  				goto write_error; @@ -719,7 +715,7 @@ cfi_staa_writev(struct mtd_info *mtd, const struct kvec *vecs,  	}  	if (buflen) { /* flush last page, even if not full */  		/* This is sometimes intended behaviour, really */ -		ret = mtd->write(mtd, to, buflen, &thislen, buffer); +		ret = mtd_write(mtd, to, buflen, &thislen, buffer);  		totlen += thislen;  		if (ret || thislen != ECCBUF_SIZE)  			goto write_error; @@ -899,12 +895,6 @@ static int cfi_staa_erase_varsize(struct mtd_info *mtd,  	int i, first;  	struct mtd_erase_region_info *regions = mtd->eraseregions; -	if (instr->addr > mtd->size) -		return -EINVAL; - -	if ((instr->len + instr->addr) > mtd->size) -		return -EINVAL; -  	/* Check that both start and end of the requested erase are  	 * aligned with the erasesize at the appropriate addresses.  	 */ @@ -971,7 +961,7 @@ static int cfi_staa_erase_varsize(struct mtd_info *mtd,  			chipnum++;  			if (chipnum >= cfi->numchips) -			break; +				break;  		}  	} @@ -1150,9 +1140,6 @@ static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  	if (len & (mtd->erasesize -1))  		return -EINVAL; -	if ((len + ofs) > mtd->size) -		return -EINVAL; -  	chipnum = ofs >> cfi->chipshift;  	adr = ofs - (chipnum << cfi->chipshift); @@ -1183,7 +1170,7 @@ static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  			chipnum++;  			if (chipnum >= cfi->numchips) -			break; +				break;  		}  	}  	return 0; diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c index d2553527940..e8d0164498b 100644 --- a/drivers/mtd/chips/cfi_probe.c +++ b/drivers/mtd/chips/cfi_probe.c @@ -168,10 +168,8 @@ static int __xipram cfi_chip_setup(struct map_info *map,  		return 0;  	cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL); -	if (!cfi->cfiq) { -		printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name); +	if (!cfi->cfiq)  		return 0; -	}  	memset(cfi->cfiq,0,sizeof(struct cfi_ident)); diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c index 360525c637d..09c79bd0b4f 100644 --- a/drivers/mtd/chips/cfi_util.c +++ b/drivers/mtd/chips/cfi_util.c @@ -1,6 +1,6 @@  /*   * Common Flash Interface support: - *   Generic utility functions not dependant on command set + *   Generic utility functions not dependent on command set   *   * Copyright (C) 2002 Red Hat   * Copyright (C) 2003 STMicroelectronics Limited @@ -116,10 +116,8 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n  	printk(KERN_INFO "%s Extended Query Table at 0x%4.4X\n", name, adr);  	extp = kmalloc(size, GFP_KERNEL); -	if (!extp) { -		printk(KERN_ERR "Failed to allocate memory\n"); +	if (!extp)  		goto out; -	}  #ifdef CONFIG_MTD_XIP  	local_irq_disable(); @@ -156,7 +154,7 @@ void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup *fixups)  	for (f=fixups; f->fixup; f++) {  		if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi->mfr)) &&  		    ((f->id  == CFI_ID_ANY)  || (f->id  == cfi->id))) { -			f->fixup(mtd, f->param); +			f->fixup(mtd);  		}  	}  } @@ -173,12 +171,6 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,  	int i, first;  	struct mtd_erase_region_info *regions = mtd->eraseregions; -	if (ofs > mtd->size) -		return -EINVAL; - -	if ((len + ofs) > mtd->size) -		return -EINVAL; -  	/* Check that both start and end of the requested erase are  	 * aligned with the erasesize at the appropriate addresses.  	 */ @@ -247,7 +239,7 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,  			chipnum++;  			if (chipnum >= cfi->numchips) -			break; +				break;  		}  	} diff --git a/drivers/mtd/chips/chipreg.c b/drivers/mtd/chips/chipreg.c index da1f96f385c..0bbc61ba952 100644 --- a/drivers/mtd/chips/chipreg.c +++ b/drivers/mtd/chips/chipreg.c @@ -76,10 +76,7 @@ struct mtd_info *do_map_probe(const char *name, struct map_info *map)  	*/  	module_put(drv->module); -	if (ret) -		return ret; - -	return NULL; +	return ret;  }  /*   * Destroy an MTD device which was created for a map device. diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h index d1806497719..800b0e853e8 100644 --- a/drivers/mtd/chips/fwh_lock.h +++ b/drivers/mtd/chips/fwh_lock.h @@ -34,8 +34,7 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip,  	/* Refuse the operation if the we cannot look behind the chip */  	if (chip->start < 0x400000) { -		DEBUG( MTD_DEBUG_LEVEL3, -			"MTD %s(): chip->start: %lx wanted >= 0x400000\n", +		pr_debug( "MTD %s(): chip->start: %lx wanted >= 0x400000\n",  			__func__, chip->start );  		return -EIO;  	} @@ -98,11 +97,11 @@ static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, uint64_t len)  	return ret;  } -static void fixup_use_fwh_lock(struct mtd_info *mtd, void *param) +static void fixup_use_fwh_lock(struct mtd_info *mtd)  {  	printk(KERN_NOTICE "using fwh lock/unlock method\n");  	/* Setup for the chips with the fwh lock method */ -	mtd->lock   = fwh_lock_varsize; -	mtd->unlock = fwh_unlock_varsize; +	mtd->_lock   = fwh_lock_varsize; +	mtd->_unlock = fwh_unlock_varsize;  }  #endif /* FWH_LOCK_H */ diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c index 3b9a2843c5f..b57ceea2151 100644 --- a/drivers/mtd/chips/gen_probe.c +++ b/drivers/mtd/chips/gen_probe.c @@ -114,7 +114,6 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi  	mapsize = sizeof(long) * DIV_ROUND_UP(max_chips, BITS_PER_LONG);  	chip_map = kzalloc(mapsize, GFP_KERNEL);  	if (!chip_map) { -		printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name);  		kfree(cfi.cfiq);  		return NULL;  	} @@ -139,7 +138,6 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi  	retcfi = kmalloc(sizeof(struct cfi_private) + cfi.numchips * sizeof(struct flchip), GFP_KERNEL);  	if (!retcfi) { -		printk(KERN_WARNING "%s: kmalloc failed for CFI private structure\n", map->name);  		kfree(cfi.cfiq);  		kfree(chip_map);  		return NULL; @@ -204,14 +202,14 @@ static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map,  	struct cfi_private *cfi = map->fldrv_priv;  	__u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID;  #ifdef CONFIG_MODULES -	char probename[16+sizeof(MODULE_SYMBOL_PREFIX)]; +	char probename[sizeof(VMLINUX_SYMBOL_STR(cfi_cmdset_%4.4X))];  	cfi_cmdset_fn_t *probe_function; -	sprintf(probename, MODULE_SYMBOL_PREFIX "cfi_cmdset_%4.4X", type); +	sprintf(probename, VMLINUX_SYMBOL_STR(cfi_cmdset_%4.4X), type);  	probe_function = __symbol_get(probename);  	if (!probe_function) { -		request_module(probename + sizeof(MODULE_SYMBOL_PREFIX) - 1); +		request_module("cfi_cmdset_%4.4X", type);  		probe_function = __symbol_get(probename);  	} diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index d72a5fb2d04..7c0b27d132b 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -120,7 +120,7 @@  #define PM49FL008	0x006A  /* Sharp */ -#define LH28F640BF	0x00b0 +#define LH28F640BF	0x00B0  /* ST - www.st.com */  #define M29F800AB	0x0058 @@ -1299,13 +1299,14 @@ static const struct amd_flash_info jedec_table[] = {  		.mfr_id		= CFI_MFR_SHARP,  		.dev_id		= LH28F640BF,  		.name		= "LH28F640BF", -		.devtypes	= CFI_DEVICETYPE_X8, +		.devtypes	= CFI_DEVICETYPE_X16,  		.uaddr		= MTD_UADDR_UNNECESSARY, -		.dev_size	= SIZE_4MiB, -		.cmd_set	= P_ID_INTEL_STD, -		.nr_regions	= 1, +		.dev_size	= SIZE_8MiB, +		.cmd_set	= P_ID_INTEL_EXT, +		.nr_regions	= 2,  		.regions	= { -			ERASEINFO(0x40000,16), +			ERASEINFO(0x10000, 127), +			ERASEINFO(0x02000, 8),  		}  	}, {  		.mfr_id		= CFI_MFR_SST, @@ -1914,11 +1915,10 @@ static void jedec_reset(u32 base, struct map_info *map, struct cfi_private *cfi)  	 * (oh and incidentaly the jedec spec - 3.5.3.3) the reset  	 * sequence is *supposed* to be 0xaa at 0x5555, 0x55 at  	 * 0x2aaa, 0xF0 at 0x5555 this will not affect the AMD chips -	 * as they will ignore the writes and dont care what address +	 * as they will ignore the writes and don't care what address  	 * the F0 is written to */  	if (cfi->addr_unlock1) { -		DEBUG( MTD_DEBUG_LEVEL3, -		       "reset unlock called %x %x \n", +		pr_debug( "reset unlock called %x %x \n",  		       cfi->addr_unlock1,cfi->addr_unlock2);  		cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);  		cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL); @@ -1935,14 +1935,14 @@ static void jedec_reset(u32 base, struct map_info *map, struct cfi_private *cfi)  } -static int cfi_jedec_setup(struct cfi_private *p_cfi, int index) +static int cfi_jedec_setup(struct map_info *map, struct cfi_private *cfi, int index)  {  	int i,num_erase_regions;  	uint8_t uaddr; -	if (! (jedec_table[index].devtypes & p_cfi->device_type)) { -		DEBUG(MTD_DEBUG_LEVEL1, "Rejecting potential %s with incompatible %d-bit device type\n", -		      jedec_table[index].name, 4 * (1<<p_cfi->device_type)); +	if (!(jedec_table[index].devtypes & cfi->device_type)) { +		pr_debug("Rejecting potential %s with incompatible %d-bit device type\n", +		      jedec_table[index].name, 4 * (1<<cfi->device_type));  		return 0;  	} @@ -1950,27 +1950,28 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)  	num_erase_regions = jedec_table[index].nr_regions; -	p_cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL); -	if (!p_cfi->cfiq) { +	cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL); +	if (!cfi->cfiq) {  		//xx printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name);  		return 0;  	} -	memset(p_cfi->cfiq,0,sizeof(struct cfi_ident)); +	memset(cfi->cfiq, 0, sizeof(struct cfi_ident)); -	p_cfi->cfiq->P_ID = jedec_table[index].cmd_set; -	p_cfi->cfiq->NumEraseRegions = jedec_table[index].nr_regions; -	p_cfi->cfiq->DevSize = jedec_table[index].dev_size; -	p_cfi->cfi_mode = CFI_MODE_JEDEC; +	cfi->cfiq->P_ID = jedec_table[index].cmd_set; +	cfi->cfiq->NumEraseRegions = jedec_table[index].nr_regions; +	cfi->cfiq->DevSize = jedec_table[index].dev_size; +	cfi->cfi_mode = CFI_MODE_JEDEC; +	cfi->sector_erase_cmd = CMD(0x30);  	for (i=0; i<num_erase_regions; i++){ -		p_cfi->cfiq->EraseRegionInfo[i] = jedec_table[index].regions[i]; +		cfi->cfiq->EraseRegionInfo[i] = jedec_table[index].regions[i];  	} -	p_cfi->cmdset_priv = NULL; +	cfi->cmdset_priv = NULL;  	/* This may be redundant for some cases, but it doesn't hurt */ -	p_cfi->mfr = jedec_table[index].mfr_id; -	p_cfi->id = jedec_table[index].dev_id; +	cfi->mfr = jedec_table[index].mfr_id; +	cfi->id = jedec_table[index].dev_id;  	uaddr = jedec_table[index].uaddr; @@ -1978,8 +1979,8 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)  	   our brains explode when we see the datasheets talking about address  	   lines numbered from A-1 to A18. The CFI table has unlock addresses  	   in device-words according to the mode the device is connected in */ -	p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1 / p_cfi->device_type; -	p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2 / p_cfi->device_type; +	cfi->addr_unlock1 = unlock_addrs[uaddr].addr1 / cfi->device_type; +	cfi->addr_unlock2 = unlock_addrs[uaddr].addr2 / cfi->device_type;  	return 1;	/* ok */  } @@ -2020,7 +2021,7 @@ static inline int jedec_match( uint32_t base,  		 * there aren't.  		 */  		if (finfo->dev_id > 0xff) { -			DEBUG( MTD_DEBUG_LEVEL3, "%s(): ID is not 8bit\n", +			pr_debug("%s(): ID is not 8bit\n",  			       __func__);  			goto match_done;  		} @@ -2044,12 +2045,10 @@ static inline int jedec_match( uint32_t base,  	}  	/* the part size must fit in the memory window */ -	DEBUG( MTD_DEBUG_LEVEL3, -	       "MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n", +	pr_debug("MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n",  	       __func__, base, 1 << finfo->dev_size, base + (1 << finfo->dev_size) );  	if ( base + cfi_interleave(cfi) * ( 1 << finfo->dev_size ) > map->size ) { -		DEBUG( MTD_DEBUG_LEVEL3, -		       "MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n", +		pr_debug("MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n",  		       __func__, finfo->mfr_id, finfo->dev_id,  		       1 << finfo->dev_size );  		goto match_done; @@ -2060,13 +2059,12 @@ static inline int jedec_match( uint32_t base,  	uaddr = finfo->uaddr; -	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n", +	pr_debug("MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n",  	       __func__, cfi->addr_unlock1, cfi->addr_unlock2 );  	if ( MTD_UADDR_UNNECESSARY != uaddr && MTD_UADDR_DONT_CARE != uaddr  	     && ( unlock_addrs[uaddr].addr1 / cfi->device_type != cfi->addr_unlock1 ||  		  unlock_addrs[uaddr].addr2 / cfi->device_type != cfi->addr_unlock2 ) ) { -		DEBUG( MTD_DEBUG_LEVEL3, -			"MTD %s(): 0x%.4x 0x%.4x did not match\n", +		pr_debug("MTD %s(): 0x%.4x 0x%.4x did not match\n",  			__func__,  			unlock_addrs[uaddr].addr1,  			unlock_addrs[uaddr].addr2); @@ -2074,7 +2072,7 @@ static inline int jedec_match( uint32_t base,  	}  	/* -	 * Make sure the ID's dissappear when the device is taken out of +	 * Make sure the ID's disappear when the device is taken out of  	 * ID mode.  The only time this should fail when it should succeed  	 * is when the ID's are written as data to the same  	 * addresses.  For this rare and unfortunate case the chip @@ -2082,15 +2080,13 @@ static inline int jedec_match( uint32_t base,  	 * FIXME - write a driver that takes all of the chip info as  	 * module parameters, doesn't probe but forces a load.  	 */ -	DEBUG( MTD_DEBUG_LEVEL3, -	       "MTD %s(): check ID's disappear when not in ID mode\n", +	pr_debug("MTD %s(): check ID's disappear when not in ID mode\n",  	       __func__ );  	jedec_reset( base, map, cfi );  	mfr = jedec_read_mfr( map, base, cfi );  	id = jedec_read_id( map, base, cfi );  	if ( mfr == cfi->mfr && id == cfi->id ) { -		DEBUG( MTD_DEBUG_LEVEL3, -		       "MTD %s(): ID 0x%.2x:0x%.2x did not change after reset:\n" +		pr_debug("MTD %s(): ID 0x%.2x:0x%.2x did not change after reset:\n"  		       "You might need to manually specify JEDEC parameters.\n",  			__func__, cfi->mfr, cfi->id );  		goto match_done; @@ -2103,7 +2099,7 @@ static inline int jedec_match( uint32_t base,  	 * Put the device back in ID mode - only need to do this if we  	 * were truly frobbing a real device.  	 */ -	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): return to ID mode\n", __func__ ); +	pr_debug("MTD %s(): return to ID mode\n", __func__ );  	if (cfi->addr_unlock1) {  		cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);  		cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL); @@ -2166,16 +2162,14 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,  		cfi->mfr = jedec_read_mfr(map, base, cfi);  		cfi->id = jedec_read_id(map, base, cfi); -		DEBUG(MTD_DEBUG_LEVEL3, -		      "Search for id:(%02x %02x) interleave(%d) type(%d)\n", +		pr_debug("Search for id:(%02x %02x) interleave(%d) type(%d)\n",  			cfi->mfr, cfi->id, cfi_interleave(cfi), cfi->device_type);  		for (i = 0; i < ARRAY_SIZE(jedec_table); i++) {  			if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) { -				DEBUG( MTD_DEBUG_LEVEL3, -				       "MTD %s(): matched device 0x%x,0x%x unlock_addrs: 0x%.4x 0x%.4x\n", +				pr_debug("MTD %s(): matched device 0x%x,0x%x unlock_addrs: 0x%.4x 0x%.4x\n",  				       __func__, cfi->mfr, cfi->id,  				       cfi->addr_unlock1, cfi->addr_unlock2 ); -				if (!cfi_jedec_setup(cfi, i)) +				if (!cfi_jedec_setup(map, cfi, i))  					return 0;  				goto ok_out;  			} diff --git a/drivers/mtd/chips/map_absent.c b/drivers/mtd/chips/map_absent.c index f2b87294687..f7a5bca92ae 100644 --- a/drivers/mtd/chips/map_absent.c +++ b/drivers/mtd/chips/map_absent.c @@ -55,10 +55,10 @@ static struct mtd_info *map_absent_probe(struct map_info *map)  	mtd->name 	= map->name;  	mtd->type 	= MTD_ABSENT;  	mtd->size 	= map->size; -	mtd->erase 	= map_absent_erase; -	mtd->read 	= map_absent_read; -	mtd->write 	= map_absent_write; -	mtd->sync 	= map_absent_sync; +	mtd->_erase 	= map_absent_erase; +	mtd->_read 	= map_absent_read; +	mtd->_write 	= map_absent_write; +	mtd->_sync 	= map_absent_sync;  	mtd->flags 	= 0;  	mtd->erasesize  = PAGE_SIZE;  	mtd->writesize  = 1; @@ -70,13 +70,11 @@ static struct mtd_info *map_absent_probe(struct map_info *map)  static int map_absent_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)  { -	*retlen = 0;  	return -ENODEV;  }  static int map_absent_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)  { -	*retlen = 0;  	return -ENODEV;  } diff --git a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c index 67640ccb2d4..991c2a1c05d 100644 --- a/drivers/mtd/chips/map_ram.c +++ b/drivers/mtd/chips/map_ram.c @@ -64,11 +64,11 @@ static struct mtd_info *map_ram_probe(struct map_info *map)  	mtd->name = map->name;  	mtd->type = MTD_RAM;  	mtd->size = map->size; -	mtd->erase = mapram_erase; -	mtd->get_unmapped_area = mapram_unmapped_area; -	mtd->read = mapram_read; -	mtd->write = mapram_write; -	mtd->sync = mapram_nop; +	mtd->_erase = mapram_erase; +	mtd->_get_unmapped_area = mapram_unmapped_area; +	mtd->_read = mapram_read; +	mtd->_write = mapram_write; +	mtd->_sync = mapram_nop;  	mtd->flags = MTD_CAP_RAM;  	mtd->writesize = 1; @@ -122,14 +122,10 @@ static int mapram_erase (struct mtd_info *mtd, struct erase_info *instr)  	unsigned long i;  	allff = map_word_ff(map); -  	for (i=0; i<instr->len; i += map_bankwidth(map))  		map_write(map, allff, instr->addr + i); -  	instr->state = MTD_ERASE_DONE; -  	mtd_erase_callback(instr); -  	return 0;  } diff --git a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c index 593f73d480d..47a43cf7e5c 100644 --- a/drivers/mtd/chips/map_rom.c +++ b/drivers/mtd/chips/map_rom.c @@ -41,11 +41,11 @@ static struct mtd_info *map_rom_probe(struct map_info *map)  	mtd->name = map->name;  	mtd->type = MTD_ROM;  	mtd->size = map->size; -	mtd->get_unmapped_area = maprom_unmapped_area; -	mtd->read = maprom_read; -	mtd->write = maprom_write; -	mtd->sync = maprom_nop; -	mtd->erase = maprom_erase; +	mtd->_get_unmapped_area = maprom_unmapped_area; +	mtd->_read = maprom_read; +	mtd->_write = maprom_write; +	mtd->_sync = maprom_nop; +	mtd->_erase = maprom_erase;  	mtd->flags = MTD_CAP_ROM;  	mtd->erasesize = map->size;  	mtd->writesize = 1; @@ -85,8 +85,7 @@ static void maprom_nop(struct mtd_info *mtd)  static int maprom_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)  { -	printk(KERN_NOTICE "maprom_write called\n"); -	return -EIO; +	return -EROFS;  }  static int maprom_erase (struct mtd_info *mtd, struct erase_info *info)  | 
