diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-07 09:11:16 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-07 09:11:16 -0800 | 
| commit | e0d65113a70f1dc514e625cc4e7a7485a4bf72df (patch) | |
| tree | 7320a130dc304623f5cf4b5dd8f67fb1776225ca | |
| parent | cf5e15fbd72c13977720aa15b7b7e00e1d8fd8f2 (diff) | |
| parent | 48e546b7f281f251893baa40769581fd15f085fb (diff) | |
| download | linux-e0d65113a70f1dc514e625cc4e7a7485a4bf72df.tar.bz2 | |
Merge git://git.infradead.org/mtd-2.6
* git://git.infradead.org/mtd-2.6: (226 commits)
  mtd: tests: annotate as DANGEROUS in Kconfig
  mtd: tests: don't use mtd0 as a default
  mtd: clean up usage of MTD_DOCPROBE_ADDRESS
  jffs2: add compr=lzo and compr=zlib options
  jffs2: implement mount option parsing and compression overriding
  mtd: nand: initialize ops.mode
  mtd: provide an alias for the redboot module name
  mtd: m25p80: don't probe device which has status of 'disabled'
  mtd: nand_h1900 never worked
  mtd: Add DiskOnChip G3 support
  mtd: m25p80: add EON flash EN25Q32B into spi flash id table
  mtd: mark block device queue as non-rotational
  mtd: r852: make r852_pm_ops static
  mtd: m25p80: add support for at25df321a spi data flash
  mtd: mxc_nand: preset_v1_v2: unlock all NAND flash blocks
  mtd: nand: switch `check_pattern()' to standard `memcmp()'
  mtd: nand: invalidate cache on unaligned reads
  mtd: nand: do not scan bad blocks with NAND_BBT_NO_OOB set
  mtd: nand: wait to set BBT version
  mtd: nand: scrub BBT on ECC errors
  ...
Fix up trivial conflicts:
 - arch/arm/mach-at91/board-usb-a9260.c
	Merged into board-usb-a926x.c
 - drivers/mtd/maps/lantiq-flash.c
	add_mtd_partitions -> mtd_device_register vs changed to use
	mtd_device_parse_register.
190 files changed, 7583 insertions, 4046 deletions
diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl index 17910e2052ad..0c674be0d3c6 100644 --- a/Documentation/DocBook/mtdnand.tmpl +++ b/Documentation/DocBook/mtdnand.tmpl @@ -572,7 +572,7 @@ static void board_select_chip (struct mtd_info *mtd, int chip)  			</para>  			<para>  				The simplest way to activate the FLASH based bad block table support  -				is to set the option NAND_USE_FLASH_BBT in the option field of +				is to set the option NAND_BBT_USE_FLASH in the bbt_option field of  				the nand chip structure before calling nand_scan(). For AG-AND  				chips is this done by default.  				This activates the default FLASH based bad block table functionality  @@ -773,20 +773,6 @@ struct nand_oobinfo {  				done according to the default builtin scheme.  			</para>  		</sect2> -		<sect2 id="User_space_placement_selection"> -			<title>User space placement selection</title> -		<para> -			All non ecc functions like mtd->read and mtd->write use an internal  -			structure, which can be set by an ioctl. This structure is preset  -			to the autoplacement default. -	     		<programlisting> -	ioctl (fd, MEMSETOOBSEL, oobsel); -	     		</programlisting> -			oobsel is a pointer to a user supplied structure of type -			nand_oobconfig. The contents of this structure must match the  -			criteria of the filesystem, which will be used. See an example in utils/nandwrite.c. -		</para> -		</sect2>  	</sect1>	  	<sect1 id="Spare_area_autoplacement_default">  		<title>Spare area autoplacement default schemes</title> @@ -1158,9 +1144,6 @@ in this page</entry>  		These constants are defined in nand.h. They are ored together to describe  		the functionality.       		<programlisting> -/* Use a flash based bad block table. This option is parsed by the - * default bad block table function (nand_default_bbt). */ -#define NAND_USE_FLASH_BBT	0x00010000  /* The hw ecc generator provides a syndrome instead a ecc value on read    * This can only work if we have the ecc bytes directly behind the    * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */ diff --git a/Documentation/devicetree/bindings/mtd/atmel-dataflash.txt b/Documentation/devicetree/bindings/mtd/atmel-dataflash.txt new file mode 100644 index 000000000000..ef66ddd01da0 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/atmel-dataflash.txt @@ -0,0 +1,14 @@ +* Atmel Data Flash + +Required properties: +- compatible : "atmel,<model>", "atmel,<series>", "atmel,dataflash". + +Example: + +flash@1 { +	#address-cells = <1>; +	#size-cells = <1>; +	compatible = "atmel,at45db321d", "atmel,at45", "atmel,dataflash"; +	spi-max-frequency = <25000000>; +	reg = <1>; +}; diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c index 0487ea10c2d6..4282d96dffa8 100644 --- a/arch/arm/mach-at91/board-afeb-9260v1.c +++ b/arch/arm/mach-at91/board-afeb-9260v1.c @@ -130,19 +130,14 @@ static struct mtd_partition __initdata afeb9260_nand_partition[] = {  	},  }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ -	*num_partitions = ARRAY_SIZE(afeb9260_nand_partition); -	return afeb9260_nand_partition; -} -  static struct atmel_nand_data __initdata afeb9260_nand_data = {  	.ale		= 21,  	.cle		= 22,  	.rdy_pin	= AT91_PIN_PC13,  	.enable_pin	= AT91_PIN_PC14, -	.partition_info	= nand_partitions,  	.bus_width_16	= 0, +	.parts		= afeb9260_nand_partition, +	.num_parts	= ARRAY_SIZE(afeb9260_nand_partition),  }; diff --git a/arch/arm/mach-at91/board-cam60.c b/arch/arm/mach-at91/board-cam60.c index 747b2eaa9737..f90cfb32bad2 100644 --- a/arch/arm/mach-at91/board-cam60.c +++ b/arch/arm/mach-at91/board-cam60.c @@ -132,19 +132,14 @@ static struct mtd_partition __initdata cam60_nand_partition[] = {  	},  }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ -	*num_partitions = ARRAY_SIZE(cam60_nand_partition); -	return cam60_nand_partition; -} -  static struct atmel_nand_data __initdata cam60_nand_data = {  	.ale		= 21,  	.cle		= 22,  	// .det_pin	= ... not there  	.rdy_pin	= AT91_PIN_PA9,  	.enable_pin	= AT91_PIN_PA7, -	.partition_info	= nand_partitions, +	.parts		= cam60_nand_partition, +	.num_parts	= ARRAY_SIZE(cam60_nand_partition),  };  static struct sam9_smc_config __initdata cam60_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-cap9adk.c b/arch/arm/mach-at91/board-cap9adk.c index 062670351a6a..5dffd3be62d2 100644 --- a/arch/arm/mach-at91/board-cap9adk.c +++ b/arch/arm/mach-at91/board-cap9adk.c @@ -169,19 +169,14 @@ static struct mtd_partition __initdata cap9adk_nand_partitions[] = {  	},  }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ -	*num_partitions = ARRAY_SIZE(cap9adk_nand_partitions); -	return cap9adk_nand_partitions; -} -  static struct atmel_nand_data __initdata cap9adk_nand_data = {  	.ale		= 21,  	.cle		= 22,  //	.det_pin	= ... not connected  //	.rdy_pin	= ... not connected  	.enable_pin	= AT91_PIN_PD15, -	.partition_info	= nand_partitions, +	.parts		= cap9adk_nand_partitions, +	.num_parts	= ARRAY_SIZE(cap9adk_nand_partitions),  };  static struct sam9_smc_config __initdata cap9adk_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c index 15a3f1a87ab0..e61351ffad50 100644 --- a/arch/arm/mach-at91/board-kb9202.c +++ b/arch/arm/mach-at91/board-kb9202.c @@ -97,19 +97,14 @@ static struct mtd_partition __initdata kb9202_nand_partition[] = {  	},  }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ -	*num_partitions = ARRAY_SIZE(kb9202_nand_partition); -	return kb9202_nand_partition; -} -  static struct atmel_nand_data __initdata kb9202_nand_data = {  	.ale		= 22,  	.cle		= 21,  	// .det_pin	= ... not there  	.rdy_pin	= AT91_PIN_PC29,  	.enable_pin	= AT91_PIN_PC28, -	.partition_info	= nand_partitions, +	.parts		= kb9202_nand_partition, +	.num_parts	= ARRAY_SIZE(kb9202_nand_partition),  };  static void __init kb9202_board_init(void) diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c index 6094496f7edb..ef816c17dc61 100644 --- a/arch/arm/mach-at91/board-neocore926.c +++ b/arch/arm/mach-at91/board-neocore926.c @@ -182,19 +182,14 @@ static struct mtd_partition __initdata neocore926_nand_partition[] = {  	},  }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ -	*num_partitions = ARRAY_SIZE(neocore926_nand_partition); -	return neocore926_nand_partition; -} -  static struct atmel_nand_data __initdata neocore926_nand_data = {  	.ale			= 21,  	.cle			= 22,  	.rdy_pin		= AT91_PIN_PB19,  	.rdy_pin_active_low	= 1,  	.enable_pin		= AT91_PIN_PD15, -	.partition_info		= nand_partitions, +	.parts			= neocore926_nand_partition, +	.num_parts		= ARRAY_SIZE(neocore926_nand_partition),  };  static struct sam9_smc_config __initdata neocore926_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c index 938cc390bea3..07421bdb88ea 100644 --- a/arch/arm/mach-at91/board-qil-a9260.c +++ b/arch/arm/mach-at91/board-qil-a9260.c @@ -130,19 +130,14 @@ static struct mtd_partition __initdata ek_nand_partition[] = {  	},  }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ -	*num_partitions = ARRAY_SIZE(ek_nand_partition); -	return ek_nand_partition; -} -  static struct atmel_nand_data __initdata ek_nand_data = {  	.ale		= 21,  	.cle		= 22,  //	.det_pin	= ... not connected  	.rdy_pin	= AT91_PIN_PC13,  	.enable_pin	= AT91_PIN_PC14, -	.partition_info	= nand_partitions, +	.parts		= ek_nand_partition, +	.num_parts	= ARRAY_SIZE(ek_nand_partition),  };  static struct sam9_smc_config __initdata ek_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c index b4ac30e38a9e..80a8c9c6e922 100644 --- a/arch/arm/mach-at91/board-rm9200dk.c +++ b/arch/arm/mach-at91/board-rm9200dk.c @@ -138,19 +138,14 @@ static struct mtd_partition __initdata dk_nand_partition[] = {  	},  }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ -	*num_partitions = ARRAY_SIZE(dk_nand_partition); -	return dk_nand_partition; -} -  static struct atmel_nand_data __initdata dk_nand_data = {  	.ale		= 22,  	.cle		= 21,  	.det_pin	= AT91_PIN_PB1,  	.rdy_pin	= AT91_PIN_PC2,  	// .enable_pin	= ... not there -	.partition_info	= nand_partitions, +	.parts		= dk_nand_partition, +	.num_parts	= ARRAY_SIZE(dk_nand_partition),  };  #define DK_FLASH_BASE	AT91_CHIPSELECT_0 diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c index 2a21e790250e..072d53af98d9 100644 --- a/arch/arm/mach-at91/board-sam9-l9260.c +++ b/arch/arm/mach-at91/board-sam9-l9260.c @@ -131,19 +131,14 @@ static struct mtd_partition __initdata ek_nand_partition[] = {  	},  }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ -	*num_partitions = ARRAY_SIZE(ek_nand_partition); -	return ek_nand_partition; -} -  static struct atmel_nand_data __initdata ek_nand_data = {  	.ale		= 21,  	.cle		= 22,  //	.det_pin	= ... not connected  	.rdy_pin	= AT91_PIN_PC13,  	.enable_pin	= AT91_PIN_PC14, -	.partition_info	= nand_partitions, +	.parts		= ek_nand_partition, +	.num_parts	= ARRAY_SIZE(ek_nand_partition),  };  static struct sam9_smc_config __initdata ek_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c index 89c8b579bfda..4f10181a0782 100644 --- a/arch/arm/mach-at91/board-sam9260ek.c +++ b/arch/arm/mach-at91/board-sam9260ek.c @@ -173,19 +173,14 @@ static struct mtd_partition __initdata ek_nand_partition[] = {  	},  }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ -	*num_partitions = ARRAY_SIZE(ek_nand_partition); -	return ek_nand_partition; -} -  static struct atmel_nand_data __initdata ek_nand_data = {  	.ale		= 21,  	.cle		= 22,  //	.det_pin	= ... not connected  	.rdy_pin	= AT91_PIN_PC13,  	.enable_pin	= AT91_PIN_PC14, -	.partition_info	= nand_partitions, +	.parts		= ek_nand_partition, +	.num_parts	= ARRAY_SIZE(ek_nand_partition),  };  static struct sam9_smc_config __initdata ek_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c index 3741f43cdae9..b005b738e8ff 100644 --- a/arch/arm/mach-at91/board-sam9261ek.c +++ b/arch/arm/mach-at91/board-sam9261ek.c @@ -179,19 +179,14 @@ static struct mtd_partition __initdata ek_nand_partition[] = {  	},  }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ -	*num_partitions = ARRAY_SIZE(ek_nand_partition); -	return ek_nand_partition; -} -  static struct atmel_nand_data __initdata ek_nand_data = {  	.ale		= 22,  	.cle		= 21,  //	.det_pin	= ... not connected  	.rdy_pin	= AT91_PIN_PC15,  	.enable_pin	= AT91_PIN_PC14, -	.partition_info	= nand_partitions, +	.parts		= ek_nand_partition, +	.num_parts	= ARRAY_SIZE(ek_nand_partition),  };  static struct sam9_smc_config __initdata ek_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c index a580dd451a41..bccdcf23caa1 100644 --- a/arch/arm/mach-at91/board-sam9263ek.c +++ b/arch/arm/mach-at91/board-sam9263ek.c @@ -180,19 +180,14 @@ static struct mtd_partition __initdata ek_nand_partition[] = {  	},  }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ -	*num_partitions = ARRAY_SIZE(ek_nand_partition); -	return ek_nand_partition; -} -  static struct atmel_nand_data __initdata ek_nand_data = {  	.ale		= 21,  	.cle		= 22,  //	.det_pin	= ... not connected  	.rdy_pin	= AT91_PIN_PA22,  	.enable_pin	= AT91_PIN_PD15, -	.partition_info	= nand_partitions, +	.parts		= ek_nand_partition, +	.num_parts	= ARRAY_SIZE(ek_nand_partition),  };  static struct sam9_smc_config __initdata ek_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c index 8d77c2ff96b2..64fc75c9d0ac 100644 --- a/arch/arm/mach-at91/board-sam9g20ek.c +++ b/arch/arm/mach-at91/board-sam9g20ek.c @@ -157,19 +157,14 @@ static struct mtd_partition __initdata ek_nand_partition[] = {  	},  }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ -	*num_partitions = ARRAY_SIZE(ek_nand_partition); -	return ek_nand_partition; -} -  /* det_pin is not connected */  static struct atmel_nand_data __initdata ek_nand_data = {  	.ale		= 21,  	.cle		= 22,  	.rdy_pin	= AT91_PIN_PC13,  	.enable_pin	= AT91_PIN_PC14, -	.partition_info	= nand_partitions, +	.parts		= ek_nand_partition, +	.num_parts	= ARRAY_SIZE(ek_nand_partition),  };  static struct sam9_smc_config __initdata ek_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c index 2d6203ac1a42..92de9127923a 100644 --- a/arch/arm/mach-at91/board-sam9m10g45ek.c +++ b/arch/arm/mach-at91/board-sam9m10g45ek.c @@ -137,19 +137,14 @@ static struct mtd_partition __initdata ek_nand_partition[] = {  	},  }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ -	*num_partitions = ARRAY_SIZE(ek_nand_partition); -	return ek_nand_partition; -} -  /* det_pin is not connected */  static struct atmel_nand_data __initdata ek_nand_data = {  	.ale		= 21,  	.cle		= 22,  	.rdy_pin	= AT91_PIN_PC8,  	.enable_pin	= AT91_PIN_PC14, -	.partition_info	= nand_partitions, +	.parts		= ek_nand_partition, +	.num_parts	= ARRAY_SIZE(ek_nand_partition),  };  static struct sam9_smc_config __initdata ek_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c index 39a28effc3df..b2b748239f36 100644 --- a/arch/arm/mach-at91/board-sam9rlek.c +++ b/arch/arm/mach-at91/board-sam9rlek.c @@ -88,19 +88,14 @@ static struct mtd_partition __initdata ek_nand_partition[] = {  	},  }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ -	*num_partitions = ARRAY_SIZE(ek_nand_partition); -	return ek_nand_partition; -} -  static struct atmel_nand_data __initdata ek_nand_data = {  	.ale		= 21,  	.cle		= 22,  //	.det_pin	= ... not connected  	.rdy_pin	= AT91_PIN_PD17,  	.enable_pin	= AT91_PIN_PB6, -	.partition_info	= nand_partitions, +	.parts		= ek_nand_partition, +	.num_parts	= ARRAY_SIZE(ek_nand_partition),  };  static struct sam9_smc_config __initdata ek_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c index c73d25e5faea..0df01c6e2d0c 100644 --- a/arch/arm/mach-at91/board-snapper9260.c +++ b/arch/arm/mach-at91/board-snapper9260.c @@ -97,18 +97,12 @@ static struct mtd_partition __initdata snapper9260_nand_partitions[] = {  	},  }; -static struct mtd_partition * __init -snapper9260_nand_partition_info(int size, int *num_partitions) -{ -	*num_partitions = ARRAY_SIZE(snapper9260_nand_partitions); -	return snapper9260_nand_partitions; -} -  static struct atmel_nand_data __initdata snapper9260_nand_data = {  	.ale		= 21,  	.cle		= 22,  	.rdy_pin	= AT91_PIN_PC13, -	.partition_info	= snapper9260_nand_partition_info, +	.parts		= snapper9260_nand_partitions, +	.num_parts	= ARRAY_SIZE(snapper9260_nand_partitions),  	.bus_width_16	= 0,  }; diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c index 5852d3d9890c..0a20bab21f99 100644 --- a/arch/arm/mach-at91/board-usb-a926x.c +++ b/arch/arm/mach-at91/board-usb-a926x.c @@ -190,19 +190,14 @@ static struct mtd_partition __initdata ek_nand_partition[] = {  	}  }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ -	*num_partitions = ARRAY_SIZE(ek_nand_partition); -	return ek_nand_partition; -} -  static struct atmel_nand_data __initdata ek_nand_data = {  	.ale		= 21,  	.cle		= 22,  //	.det_pin	= ... not connected  	.rdy_pin	= AT91_PIN_PA22,  	.enable_pin	= AT91_PIN_PD15, -	.partition_info	= nand_partitions, +	.parts		= ek_nand_partition, +	.num_parts	= ARRAY_SIZE(ek_nand_partition),  };  static struct sam9_smc_config __initdata usb_a9260_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c index 3c288b396fc4..649b052231f5 100644 --- a/arch/arm/mach-at91/board-yl-9200.c +++ b/arch/arm/mach-at91/board-yl-9200.c @@ -172,19 +172,14 @@ static struct mtd_partition __initdata yl9200_nand_partition[] = {  	}  }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ -	*num_partitions = ARRAY_SIZE(yl9200_nand_partition); -	return yl9200_nand_partition; -} -  static struct atmel_nand_data __initdata yl9200_nand_data = {  	.ale		= 6,  	.cle		= 7,  	// .det_pin	= ... not connected  	.rdy_pin	= AT91_PIN_PC14,	/* R/!B (Sheet10) */  	.enable_pin	= AT91_PIN_PC15,	/* !CE  (Sheet10) */ -	.partition_info	= nand_partitions, +	.parts		= yl9200_nand_partition, +	.num_parts	= ARRAY_SIZE(yl9200_nand_partition),  };  /* diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h index d07767f4052e..eac92e995bb5 100644 --- a/arch/arm/mach-at91/include/mach/board.h +++ b/arch/arm/mach-at91/include/mach/board.h @@ -117,7 +117,8 @@ struct atmel_nand_data {  	u8		ale;		/* address line number connected to ALE */  	u8		cle;		/* address line number connected to CLE */  	u8		bus_width_16;	/* buswidth is 16 bit */ -	struct mtd_partition* (*partition_info)(int, int*); +	struct mtd_partition *parts; +	unsigned int	num_parts;  };  extern void __init at91_add_device_nand(struct atmel_nand_data *data); diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index 26d94c0b555c..11c3db985285 100644 --- a/arch/arm/mach-davinci/board-da830-evm.c +++ b/arch/arm/mach-davinci/board-da830-evm.c @@ -377,7 +377,7 @@ static struct davinci_nand_pdata da830_evm_nand_pdata = {  	.nr_parts	= ARRAY_SIZE(da830_evm_nand_partitions),  	.ecc_mode	= NAND_ECC_HW,  	.ecc_bits	= 4, -	.options	= NAND_USE_FLASH_BBT, +	.bbt_options	= NAND_BBT_USE_FLASH,  	.bbt_td		= &da830_evm_nand_bbt_main_descr,  	.bbt_md		= &da830_evm_nand_bbt_mirror_descr,  	.timing         = &da830_evm_nandflash_timing, diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index ec21663f8ddc..1d7d24995226 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -256,7 +256,7 @@ static struct davinci_nand_pdata da850_evm_nandflash_data = {  	.nr_parts	= ARRAY_SIZE(da850_evm_nandflash_partition),  	.ecc_mode	= NAND_ECC_HW,  	.ecc_bits	= 4, -	.options	= NAND_USE_FLASH_BBT, +	.bbt_options	= NAND_BBT_USE_FLASH,  	.timing		= &da850_evm_nandflash_timing,  }; diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index 65566280b7c9..4e0e707c313d 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -77,7 +77,7 @@ static struct davinci_nand_pdata davinci_nand_data = {  	.parts			= davinci_nand_partitions,  	.nr_parts		= ARRAY_SIZE(davinci_nand_partitions),  	.ecc_mode		= NAND_ECC_HW, -	.options		= NAND_USE_FLASH_BBT, +	.bbt_options		= NAND_BBT_USE_FLASH,  	.ecc_bits		= 4,  }; diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c index b307470b071d..ff2d2413279a 100644 --- a/arch/arm/mach-davinci/board-dm355-leopard.c +++ b/arch/arm/mach-davinci/board-dm355-leopard.c @@ -74,7 +74,7 @@ static struct davinci_nand_pdata davinci_nand_data = {  	.parts			= davinci_nand_partitions,  	.nr_parts		= ARRAY_SIZE(davinci_nand_partitions),  	.ecc_mode		= NAND_ECC_HW_SYNDROME, -	.options		= NAND_USE_FLASH_BBT, +	.bbt_options		= NAND_BBT_USE_FLASH,  };  static struct resource davinci_nand_resources[] = { diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index 04c43abcca66..1918ae711428 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -139,7 +139,7 @@ static struct davinci_nand_pdata davinci_nand_data = {  	.parts			= davinci_nand_partitions,  	.nr_parts		= ARRAY_SIZE(davinci_nand_partitions),  	.ecc_mode		= NAND_ECC_HW, -	.options		= NAND_USE_FLASH_BBT, +	.bbt_options		= NAND_BBT_USE_FLASH,  	.ecc_bits		= 4,  }; diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 28fafa7819bc..0cf8abf78d33 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -151,7 +151,7 @@ static struct davinci_nand_pdata davinci_evm_nandflash_data = {  	.parts		= davinci_evm_nandflash_partition,  	.nr_parts	= ARRAY_SIZE(davinci_evm_nandflash_partition),  	.ecc_mode	= NAND_ECC_HW, -	.options	= NAND_USE_FLASH_BBT, +	.bbt_options	= NAND_BBT_USE_FLASH,  	.timing		= &davinci_evm_nandflash_timing,  }; diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index 6efc84cceca0..3cfff555e8f2 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -396,7 +396,8 @@ static struct davinci_nand_pdata mityomapl138_nandflash_data = {  	.parts		= mityomapl138_nandflash_partition,  	.nr_parts	= ARRAY_SIZE(mityomapl138_nandflash_partition),  	.ecc_mode	= NAND_ECC_HW, -	.options	= NAND_USE_FLASH_BBT | NAND_BUSWIDTH_16, +	.bbt_options	= NAND_BBT_USE_FLASH, +	.options	= NAND_BUSWIDTH_16,  	.ecc_bits	= 1, /* 4 bit mode is not supported with 16 bit NAND */  }; diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c index 38d6f644d8b9..e5f231aefee4 100644 --- a/arch/arm/mach-davinci/board-neuros-osd2.c +++ b/arch/arm/mach-davinci/board-neuros-osd2.c @@ -87,7 +87,7 @@ static struct davinci_nand_pdata davinci_ntosd2_nandflash_data = {  	.parts		= davinci_ntosd2_nandflash_partition,  	.nr_parts	= ARRAY_SIZE(davinci_ntosd2_nandflash_partition),  	.ecc_mode	= NAND_ECC_HW, -	.options	= NAND_USE_FLASH_BBT, +	.bbt_options	= NAND_BBT_USE_FLASH,  };  static struct resource davinci_ntosd2_nandflash_resource[] = { diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c index 90ee7b5aabdc..f69e40a29e02 100644 --- a/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c @@ -144,7 +144,7 @@ static struct davinci_nand_pdata nand_config = {  	.parts		= nand_partitions,  	.nr_parts	= ARRAY_SIZE(nand_partitions),  	.ecc_mode	= NAND_ECC_HW, -	.options	= NAND_USE_FLASH_BBT, +	.bbt_options	= NAND_BBT_USE_FLASH,  	.ecc_bits	= 1,  }; diff --git a/arch/arm/mach-davinci/include/mach/nand.h b/arch/arm/mach-davinci/include/mach/nand.h index 025151049f05..1cf555aef896 100644 --- a/arch/arm/mach-davinci/include/mach/nand.h +++ b/arch/arm/mach-davinci/include/mach/nand.h @@ -74,8 +74,10 @@ struct davinci_nand_pdata {		/* platform_data */  	nand_ecc_modes_t	ecc_mode;  	u8			ecc_bits; -	/* e.g. NAND_BUSWIDTH_16 or NAND_USE_FLASH_BBT */ +	/* e.g. NAND_BUSWIDTH_16 */  	unsigned		options; +	/* e.g. NAND_BBT_USE_FLASH */ +	unsigned		bbt_options;  	/* Main and mirror bbt descriptor overrides */  	struct nand_bbt_descr	*bbt_td; diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c index 1ade3c340507..8b2f1435bcac 100644 --- a/arch/arm/mach-ep93xx/ts72xx.c +++ b/arch/arm/mach-ep93xx/ts72xx.c @@ -116,8 +116,9 @@ static struct mtd_partition ts72xx_nand_parts[] = {  		.mask_flags	= MTD_WRITEABLE,	/* force read-only */  	}, {  		.name		= "Linux", -		.offset		= MTDPART_OFS_APPEND, -		.size		= 0,			/* filled in later */ +		.offset		= MTDPART_OFS_RETAIN, +		.size		= TS72XX_REDBOOT_PART_SIZE, +				/* leave so much for last partition */  	}, {  		.name		= "RedBoot",  		.offset		= MTDPART_OFS_APPEND, @@ -126,28 +127,14 @@ static struct mtd_partition ts72xx_nand_parts[] = {  	},  }; -static void ts72xx_nand_set_parts(uint64_t size, -				  struct platform_nand_chip *chip) -{ -	/* Factory TS-72xx boards only come with 32MiB or 128MiB NAND options */ -	if (size == SZ_32M || size == SZ_128M) { -		/* Set the "Linux" partition size */ -		ts72xx_nand_parts[1].size = size - TS72XX_REDBOOT_PART_SIZE; - -		chip->partitions = ts72xx_nand_parts; -		chip->nr_partitions = ARRAY_SIZE(ts72xx_nand_parts); -	} else { -		pr_warning("Unknown nand disk size:%lluMiB\n", size >> 20); -	} -} -  static struct platform_nand_data ts72xx_nand_data = {  	.chip = {  		.nr_chips	= 1,  		.chip_offset	= 0,  		.chip_delay	= 15,  		.part_probe_types = ts72xx_nand_part_probes, -		.set_parts	= ts72xx_nand_set_parts, +		.partitions	= ts72xx_nand_parts, +		.nr_partitions	= ARRAY_SIZE(ts72xx_nand_parts),  	},  	.ctrl = {  		.cmd_ctrl	= ts72xx_nand_hwcontrol, diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c index 06b5ad774604..7a60bbbce7a4 100644 --- a/arch/arm/mach-mmp/aspenite.c +++ b/arch/arm/mach-mmp/aspenite.c @@ -167,8 +167,9 @@ static struct mtd_partition aspenite_nand_partitions[] = {  static struct pxa3xx_nand_platform_data aspenite_nand_info = {  	.enable_arbiter	= 1, -	.parts		= aspenite_nand_partitions, -	.nr_parts	= ARRAY_SIZE(aspenite_nand_partitions), +	.num_cs = 1, +	.parts[0]	= aspenite_nand_partitions, +	.nr_parts[0]	= ARRAY_SIZE(aspenite_nand_partitions),  };  static struct i2c_board_info aspenite_i2c_info[] __initdata = { diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c index 6c75cd35c4c8..b35e2005a348 100644 --- a/arch/arm/mach-orion5x/ts78xx-setup.c +++ b/arch/arm/mach-orion5x/ts78xx-setup.c @@ -275,7 +275,7 @@ static struct platform_nand_data ts78xx_ts_nand_data = {  		.partitions		= ts78xx_ts_nand_parts,  		.nr_partitions		= ARRAY_SIZE(ts78xx_ts_nand_parts),  		.chip_delay		= 15, -		.options		= NAND_USE_FLASH_BBT, +		.bbt_options		= NAND_BBT_USE_FLASH,  	},  	.ctrl	= {  		/* diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c index 3a7387f93c38..e096bba8fd57 100644 --- a/arch/arm/mach-pxa/cm-x300.c +++ b/arch/arm/mach-pxa/cm-x300.c @@ -424,8 +424,9 @@ static struct mtd_partition cm_x300_nand_partitions[] = {  static struct pxa3xx_nand_platform_data cm_x300_nand_info = {  	.enable_arbiter	= 1,  	.keep_config	= 1, -	.parts		= cm_x300_nand_partitions, -	.nr_parts	= ARRAY_SIZE(cm_x300_nand_partitions), +	.num_cs		= 1, +	.parts[0]	= cm_x300_nand_partitions, +	.nr_parts[0]	= ARRAY_SIZE(cm_x300_nand_partitions),  };  static void __init cm_x300_init_nand(void) diff --git a/arch/arm/mach-pxa/colibri-pxa3xx.c b/arch/arm/mach-pxa/colibri-pxa3xx.c index 3f9be419959d..2b8ca0de8a3d 100644 --- a/arch/arm/mach-pxa/colibri-pxa3xx.c +++ b/arch/arm/mach-pxa/colibri-pxa3xx.c @@ -139,8 +139,9 @@ static struct mtd_partition colibri_nand_partitions[] = {  static struct pxa3xx_nand_platform_data colibri_nand_info = {  	.enable_arbiter	= 1,  	.keep_config	= 1, -	.parts		= colibri_nand_partitions, -	.nr_parts	= ARRAY_SIZE(colibri_nand_partitions), +	.num_cs		= 1, +	.parts[0]	= colibri_nand_partitions, +	.nr_parts[0]	= ARRAY_SIZE(colibri_nand_partitions),  };  void __init colibri_pxa3xx_init_nand(void) diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c index 0037e57e0cec..7b324ec6449f 100644 --- a/arch/arm/mach-pxa/littleton.c +++ b/arch/arm/mach-pxa/littleton.c @@ -325,8 +325,9 @@ static struct mtd_partition littleton_nand_partitions[] = {  static struct pxa3xx_nand_platform_data littleton_nand_info = {  	.enable_arbiter	= 1, -	.parts		= littleton_nand_partitions, -	.nr_parts	= ARRAY_SIZE(littleton_nand_partitions), +	.num_cs		= 1, +	.parts[0]	= littleton_nand_partitions, +	.nr_parts[0]	= ARRAY_SIZE(littleton_nand_partitions),  };  static void __init littleton_init_nand(void) diff --git a/arch/arm/mach-pxa/mxm8x10.c b/arch/arm/mach-pxa/mxm8x10.c index b5a8fd3fce04..90928d6e1a5b 100644 --- a/arch/arm/mach-pxa/mxm8x10.c +++ b/arch/arm/mach-pxa/mxm8x10.c @@ -389,10 +389,11 @@ static struct mtd_partition mxm_8x10_nand_partitions[] = {  };  static struct pxa3xx_nand_platform_data mxm_8x10_nand_info = { -	.enable_arbiter = 1, -	.keep_config = 1, -	.parts = mxm_8x10_nand_partitions, -	.nr_parts = ARRAY_SIZE(mxm_8x10_nand_partitions) +	.enable_arbiter	= 1, +	.keep_config	= 1, +	.num_cs		= 1, +	.parts[0]	= mxm_8x10_nand_partitions, +	.nr_parts[0]	= ARRAY_SIZE(mxm_8x10_nand_partitions)  };  static void __init mxm_8x10_nand_init(void) diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index 6810cddec927..f0c05f4d12ed 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -346,8 +346,9 @@ static struct mtd_partition raumfeld_nand_partitions[] = {  static struct pxa3xx_nand_platform_data raumfeld_nand_info = {  	.enable_arbiter	= 1,  	.keep_config	= 1, -	.parts		= raumfeld_nand_partitions, -	.nr_parts	= ARRAY_SIZE(raumfeld_nand_partitions), +	.num_cs		= 1, +	.parts[0]	= raumfeld_nand_partitions, +	.nr_parts[0]	= ARRAY_SIZE(raumfeld_nand_partitions),  };  /** diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c index 31d496891891..6c39c3328418 100644 --- a/arch/arm/mach-pxa/zylonite.c +++ b/arch/arm/mach-pxa/zylonite.c @@ -366,8 +366,9 @@ static struct mtd_partition zylonite_nand_partitions[] = {  static struct pxa3xx_nand_platform_data zylonite_nand_info = {  	.enable_arbiter	= 1, -	.parts		= zylonite_nand_partitions, -	.nr_parts	= ARRAY_SIZE(zylonite_nand_partitions), +	.num_cs		= 1, +	.parts[0]	= zylonite_nand_partitions, +	.nr_parts[0]	= ARRAY_SIZE(zylonite_nand_partitions),  };  static void __init zylonite_init_nand(void) diff --git a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h index 442301fe48b4..c42f39f20195 100644 --- a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +++ b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h @@ -41,6 +41,19 @@ struct pxa3xx_nand_flash {  	struct pxa3xx_nand_timing *timing;	/* NAND Flash timing */  }; +/* + * Current pxa3xx_nand controller has two chip select which + * both be workable. + * + * Notice should be taken that: + * When you want to use this feature, you should not enable the + * keep configuration feature, for two chip select could be + * attached with different nand chip. The different page size + * and timing requirement make the keep configuration impossible. + */ + +/* The max num of chip select current support */ +#define NUM_CHIP_SELECT		(2)  struct pxa3xx_nand_platform_data {  	/* the data flash bus is shared between the Static Memory @@ -52,8 +65,11 @@ struct pxa3xx_nand_platform_data {  	/* allow platform code to keep OBM/bootloader defined NFC config */  	int	keep_config; -	const struct mtd_partition		*parts; -	unsigned int				nr_parts; +	/* indicate how many chip selects will be used */ +	int	num_cs; + +	const struct mtd_partition		*parts[NUM_CHIP_SELECT]; +	unsigned int				nr_parts[NUM_CHIP_SELECT];  	const struct pxa3xx_nand_flash * 	flash;  	size_t					num_flash; diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c index fafed4c38fd2..1f17bde52cd4 100644 --- a/arch/avr32/boards/atngw100/setup.c +++ b/arch/avr32/boards/atngw100/setup.c @@ -90,11 +90,6 @@ static struct mtd_partition nand_partitions[] = {  	},  }; -static struct mtd_partition *nand_part_info(int size, int *num_partitions) -{ -	*num_partitions = ARRAY_SIZE(nand_partitions); -	return nand_partitions; -}  static struct atmel_nand_data atngw100mkii_nand_data __initdata = {  	.cle		= 21, @@ -102,7 +97,8 @@ static struct atmel_nand_data atngw100mkii_nand_data __initdata = {  	.rdy_pin	= GPIO_PIN_PB(28),  	.enable_pin	= GPIO_PIN_PE(23),  	.bus_width_16	= true, -	.partition_info	= nand_part_info, +	.parts		= nand_partitions, +	.num_parts	= ARRAY_SIZE(nand_partitions),  };  #endif diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c index 6ce30fb2ec94..4643ff5107c9 100644 --- a/arch/avr32/boards/atstk1000/atstk1002.c +++ b/arch/avr32/boards/atstk1000/atstk1002.c @@ -90,18 +90,13 @@ static struct mtd_partition nand_partitions[] = {  	},  }; -static struct mtd_partition *nand_part_info(int size, int *num_partitions) -{ -	*num_partitions = ARRAY_SIZE(nand_partitions); -	return nand_partitions; -} -  static struct atmel_nand_data atstk1006_nand_data __initdata = {  	.cle		= 21,  	.ale		= 22,  	.rdy_pin	= GPIO_PIN_PB(30),  	.enable_pin	= GPIO_PIN_PB(29), -	.partition_info	= nand_part_info, +	.parts		= nand_partitions, +	.num_parts	= ARRAY_SIZE(num_partitions),  };  #endif diff --git a/arch/avr32/mach-at32ap/include/mach/board.h b/arch/avr32/mach-at32ap/include/mach/board.h index 679458d9a622..5d7ffca7d69f 100644 --- a/arch/avr32/mach-at32ap/include/mach/board.h +++ b/arch/avr32/mach-at32ap/include/mach/board.h @@ -128,7 +128,8 @@ struct atmel_nand_data {  	u8	ale;		/* address line number connected to ALE */  	u8	cle;		/* address line number connected to CLE */  	u8	bus_width_16;	/* buswidth is 16 bit */ -	struct mtd_partition *(*partition_info)(int size, int *num_partitions); +	struct mtd_partition *parts; +	unsigned int	num_parts;  };  struct platform_device *  at32_add_device_nand(unsigned int id, struct atmel_nand_data *data); diff --git a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c index f58f2c1c5295..7fb52128ddc9 100644 --- a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c +++ b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c @@ -163,7 +163,7 @@ struct mtd_info *__init crisv32_nand_flash_probe(void)  	this->ecc.mode = NAND_ECC_SOFT;  	/* Enable the following for a flash based bad block table */ -	/* this->options = NAND_USE_FLASH_BBT; */ +	/* this->bbt_options = NAND_BBT_USE_FLASH; */  	/* Scan to find existence of the device */  	if (nand_scan(crisv32_mtd, 1)) { diff --git a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c index d5b0cc9f976b..e03238454b0e 100644 --- a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c +++ b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c @@ -154,7 +154,7 @@ struct mtd_info *__init crisv32_nand_flash_probe(void)  	this->ecc.mode = NAND_ECC_SOFT;  	/* Enable the following for a flash based bad block table */ -	/* this->options = NAND_USE_FLASH_BBT; */ +	/* this->bbt_options = NAND_BBT_USE_FLASH; */  	/* Scan to find existence of the device */  	if (nand_scan(crisv32_mtd, 1)) { diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 66b616ebe536..318a869286ab 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -12,27 +12,17 @@ menuconfig MTD  if MTD -config MTD_DEBUG -	bool "Debugging" -	help -	  This turns on low-level debugging for the entire MTD sub-system. -	  Normally, you should say 'N'. - -config MTD_DEBUG_VERBOSE -	int "Debugging verbosity (0 = quiet, 3 = noisy)" -	depends on MTD_DEBUG -	default "0" -	help -	  Determines the verbosity level of the MTD debugging messages. -  config MTD_TESTS -	tristate "MTD tests support" +	tristate "MTD tests support (DANGEROUS)"  	depends on m  	help  	  This option includes various MTD tests into compilation. The tests  	  should normally be compiled as kernel modules. The modules perform  	  various checks and verifications when loaded. +	  WARNING: some of the tests will ERASE entire MTD device which they +	  test. Do not use these tests unless you really know what you do. +  config MTD_REDBOOT_PARTS  	tristate "RedBoot partition table parsing"  	---help--- @@ -137,7 +127,8 @@ config MTD_AFS_PARTS  	  'physmap' map driver (CONFIG_MTD_PHYSMAP) does this, for example.  config MTD_OF_PARTS -	def_bool y +	tristate "OpenFirmware partitioning information support" +	default Y  	depends on OF  	help  	  This provides a partition parsing function which derives diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 39664c4229ff..9aaac3ac89f3 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -5,8 +5,8 @@  # Core functionality.  obj-$(CONFIG_MTD)		+= mtd.o  mtd-y				:= mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o -mtd-$(CONFIG_MTD_OF_PARTS)	+= ofpart.o +obj-$(CONFIG_MTD_OF_PARTS)	+= ofpart.o  obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o  obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o  obj-$(CONFIG_MTD_AFS_PARTS)	+= afs.o diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c index 302372c08b56..89a02f6f65dc 100644 --- a/drivers/mtd/afs.c +++ b/drivers/mtd/afs.c @@ -162,8 +162,8 @@ afs_read_iis(struct mtd_info *mtd, struct image_info_struct *iis, u_int ptr)  }  static int parse_afs_partitions(struct mtd_info *mtd, -                         struct mtd_partition **pparts, -                         unsigned long origin) +				struct mtd_partition **pparts, +				struct mtd_part_parser_data *data)  {  	struct mtd_partition *parts;  	u_int mask, off, idx, sz; diff --git a/drivers/mtd/ar7part.c b/drivers/mtd/ar7part.c index 95949b97de6a..f40ea4547554 100644 --- a/drivers/mtd/ar7part.c +++ b/drivers/mtd/ar7part.c @@ -47,7 +47,7 @@ struct ar7_bin_rec {  static int create_mtd_partitions(struct mtd_info *master,  				 struct mtd_partition **pparts, -				 unsigned long origin) +				 struct mtd_part_parser_data *data)  {  	struct ar7_bin_rec header;  	unsigned int offset; diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 23175edd5634..8d70895a58d6 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -145,8 +145,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd)  	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 +165,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd)  			 * 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,8 +176,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd)  			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");  	} @@ -191,7 +188,7 @@ 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" ); +		pr_debug("Using buffer write method\n" );  		mtd->write = cfi_amdstd_write_buffers;  	}  } @@ -443,8 +440,8 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)  	mtd->writesize = 1;  	mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; -	DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): write buffer size %d\n", -		__func__, mtd->writebufsize); +	pr_debug("MTD %s(): write buffer size %d\n", __func__, +			mtd->writebufsize);  	mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot; @@ -1163,7 +1160,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] );  	/* @@ -1174,7 +1171,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;  	} @@ -1400,7 +1397,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); @@ -1587,7 +1584,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); @@ -1675,7 +1672,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); @@ -1801,8 +1798,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); @@ -1837,8 +1833,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); diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h index 5e3cc80128aa..89c6595454a5 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;  	} diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index ea832ea0e4aa..c443f527a53a 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -1914,11 +1914,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); @@ -1941,7 +1940,7 @@ static int cfi_jedec_setup(struct map_info *map, struct cfi_private *cfi, int in  	uint8_t uaddr;  	if (!(jedec_table[index].devtypes & cfi->device_type)) { -		DEBUG(MTD_DEBUG_LEVEL1, "Rejecting potential %s with incompatible %d-bit device type\n", +		pr_debug("Rejecting potential %s with incompatible %d-bit device type\n",  		      jedec_table[index].name, 4 * (1<<cfi->device_type));  		return 0;  	} @@ -2021,7 +2020,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;  		} @@ -2045,12 +2044,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; @@ -2061,13 +2058,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); @@ -2083,15 +2079,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; @@ -2104,7 +2098,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); @@ -2167,13 +2161,11 @@ 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(map, cfi, i)) diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index 8cf667da2408..ddf9ec6d9168 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c @@ -189,10 +189,7 @@ static struct mtd_partition * newpart(char *s,  			     extra_mem_size;  		parts = kzalloc(alloc_size, GFP_KERNEL);  		if (!parts) -		{ -			printk(KERN_ERR ERRP "out of memory\n");  			return NULL; -		}  		extra_mem = (unsigned char *)(parts + *num_parts);  	}  	/* enter this partition (offset will be calculated later if it is zero at this point) */ @@ -317,8 +314,8 @@ static int mtdpart_setup_real(char *s)   * the first one in the chain if a NULL mtd_id is passed in.   */  static int parse_cmdline_partitions(struct mtd_info *master, -                             struct mtd_partition **pparts, -                             unsigned long origin) +				    struct mtd_partition **pparts, +				    struct mtd_part_parser_data *data)  {  	unsigned long offset;  	int i; diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 35081ce77fbd..283d887f7825 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -249,6 +249,16 @@ config MTD_DOC2001PLUS  	  under "NAND Flash Device Drivers" (currently that driver does not  	  support all Millennium Plus devices). +config MTD_DOCG3 +	tristate "M-Systems Disk-On-Chip G3" +	---help--- +	  This provides an MTD device driver for the M-Systems DiskOnChip +	  G3 devices. + +	  The driver provides access to G3 DiskOnChip, distributed by +	  M-Systems and now Sandisk. The support is very experimental, +	  and doesn't give access to any write operations. +  config MTD_DOCPROBE  	tristate  	select MTD_DOCECC @@ -268,8 +278,7 @@ config MTD_DOCPROBE_ADVANCED  config MTD_DOCPROBE_ADDRESS  	hex "Physical address of DiskOnChip" if MTD_DOCPROBE_ADVANCED  	depends on MTD_DOCPROBE -	default "0x0000" if MTD_DOCPROBE_ADVANCED -	default "0" if !MTD_DOCPROBE_ADVANCED +	default "0x0"  	---help---  	  By default, the probe for DiskOnChip devices will look for a  	  DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000. diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index f3226b1d38fc..56c7cd462f11 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -5,6 +5,7 @@  obj-$(CONFIG_MTD_DOC2000)	+= doc2000.o  obj-$(CONFIG_MTD_DOC2001)	+= doc2001.o  obj-$(CONFIG_MTD_DOC2001PLUS)	+= doc2001plus.o +obj-$(CONFIG_MTD_DOCG3)		+= docg3.o  obj-$(CONFIG_MTD_DOCPROBE)	+= docprobe.o  obj-$(CONFIG_MTD_DOCECC)	+= docecc.o  obj-$(CONFIG_MTD_SLRAM)		+= slram.o @@ -17,3 +18,5 @@ obj-$(CONFIG_MTD_BLOCK2MTD)	+= block2mtd.o  obj-$(CONFIG_MTD_DATAFLASH)	+= mtd_dataflash.o  obj-$(CONFIG_MTD_M25P80)	+= m25p80.o  obj-$(CONFIG_MTD_SST25L)	+= sst25l.o + +CFLAGS_docg3.o			+= -I$(src)
\ No newline at end of file diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index f7fbf6025ef2..e9fad9151219 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c @@ -82,8 +82,7 @@ static int _DoC_WaitReady(struct DiskOnChip *doc)  	void __iomem *docptr = doc->virtadr;  	unsigned long timeo = jiffies + (HZ * 10); -	DEBUG(MTD_DEBUG_LEVEL3, -	      "_DoC_WaitReady called for out-of-line wait\n"); +	pr_debug("_DoC_WaitReady called for out-of-line wait\n");  	/* Out-of-line routine to wait for chip response */  	while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) { @@ -92,7 +91,7 @@ static int _DoC_WaitReady(struct DiskOnChip *doc)  		DoC_Delay(doc, 2);  		if (time_after(jiffies, timeo)) { -			DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n"); +			pr_debug("_DoC_WaitReady timed out.\n");  			return -EIO;  		}  		udelay(1); @@ -323,8 +322,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)  	/* Reset the chip */  	if (DoC_Command(doc, NAND_CMD_RESET, CDSN_CTRL_WP)) { -		DEBUG(MTD_DEBUG_LEVEL2, -		      "DoC_Command (reset) for %d,%d returned true\n", +		pr_debug("DoC_Command (reset) for %d,%d returned true\n",  		      floor, chip);  		return 0;  	} @@ -332,8 +330,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)  	/* Read the NAND chip ID: 1. Send ReadID command */  	if (DoC_Command(doc, NAND_CMD_READID, CDSN_CTRL_WP)) { -		DEBUG(MTD_DEBUG_LEVEL2, -		      "DoC_Command (ReadID) for %d,%d returned true\n", +		pr_debug("DoC_Command (ReadID) for %d,%d returned true\n",  		      floor, chip);  		return 0;  	} @@ -699,7 +696,7 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,  #ifdef ECC_DEBUG  			printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from);  #endif -			/* Read the ECC syndrom through the DiskOnChip ECC +			/* Read the ECC syndrome through the DiskOnChip ECC  			   logic.  These syndrome will be all ZERO when there  			   is no error */  			for (i = 0; i < 6; i++) { @@ -930,7 +927,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,  	uint8_t *buf = ops->oobbuf;  	size_t len = ops->len; -	BUG_ON(ops->mode != MTD_OOB_PLACE); +	BUG_ON(ops->mode != MTD_OPS_PLACE_OOB);  	ofs += ops->ooboffs; @@ -1094,7 +1091,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,  	struct DiskOnChip *this = mtd->priv;  	int ret; -	BUG_ON(ops->mode != MTD_OOB_PLACE); +	BUG_ON(ops->mode != MTD_OPS_PLACE_OOB);  	mutex_lock(&this->lock);  	ret = doc_write_oob_nolock(mtd, ofs + ops->ooboffs, ops->len, diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c index 241192f05bc8..a3f7a27499be 100644 --- a/drivers/mtd/devices/doc2001.c +++ b/drivers/mtd/devices/doc2001.c @@ -55,15 +55,14 @@ static int _DoC_WaitReady(void __iomem * docptr)  {  	unsigned short c = 0xffff; -	DEBUG(MTD_DEBUG_LEVEL3, -	      "_DoC_WaitReady called for out-of-line wait\n"); +	pr_debug("_DoC_WaitReady called for out-of-line wait\n");  	/* Out-of-line routine to wait for chip response */  	while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B) && --c)  		;  	if (c == 0) -		DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n"); +		pr_debug("_DoC_WaitReady timed out.\n");  	return (c == 0);  } @@ -464,7 +463,7 @@ static int doc_read (struct mtd_info *mtd, loff_t from, size_t len,  #ifdef ECC_DEBUG  		printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);  #endif -		/* Read the ECC syndrom through the DiskOnChip ECC logic. +		/* Read the ECC syndrome through the DiskOnChip ECC logic.  		   These syndrome will be all ZERO when there is no error */  		for (i = 0; i < 6; i++) {  			syndrome[i] = ReadDOC(docptr, ECCSyndrome0 + i); @@ -632,7 +631,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,  	uint8_t *buf = ops->oobbuf;  	size_t len = ops->len; -	BUG_ON(ops->mode != MTD_OOB_PLACE); +	BUG_ON(ops->mode != MTD_OPS_PLACE_OOB);  	ofs += ops->ooboffs; @@ -690,7 +689,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,  	uint8_t *buf = ops->oobbuf;  	size_t len = ops->len; -	BUG_ON(ops->mode != MTD_OOB_PLACE); +	BUG_ON(ops->mode != MTD_OPS_PLACE_OOB);  	ofs += ops->ooboffs; diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index 09ae0adc3ad0..99351bc3e0ed 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c @@ -61,15 +61,14 @@ static int _DoC_WaitReady(void __iomem * docptr)  {  	unsigned int c = 0xffff; -	DEBUG(MTD_DEBUG_LEVEL3, -	      "_DoC_WaitReady called for out-of-line wait\n"); +	pr_debug("_DoC_WaitReady called for out-of-line wait\n");  	/* Out-of-line routine to wait for chip response */  	while (((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) && --c)  		;  	if (c == 0) -		DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n"); +		pr_debug("_DoC_WaitReady timed out.\n");  	return (c == 0);  } @@ -655,7 +654,7 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,  #ifdef ECC_DEBUG  		printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);  #endif -		/* Read the ECC syndrom through the DiskOnChip ECC logic. +		/* Read the ECC syndrome through the DiskOnChip ECC logic.  		   These syndrome will be all ZERO when there is no error */  		for (i = 0; i < 6; i++)  			syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i); @@ -835,7 +834,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,  	uint8_t *buf = ops->oobbuf;  	size_t len = ops->len; -	BUG_ON(ops->mode != MTD_OOB_PLACE); +	BUG_ON(ops->mode != MTD_OPS_PLACE_OOB);  	ofs += ops->ooboffs; @@ -920,7 +919,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,  	uint8_t *buf = ops->oobbuf;  	size_t len = ops->len; -	BUG_ON(ops->mode != MTD_OOB_PLACE); +	BUG_ON(ops->mode != MTD_OPS_PLACE_OOB);  	ofs += ops->ooboffs; diff --git a/drivers/mtd/devices/docecc.c b/drivers/mtd/devices/docecc.c index 37ef29a73ee4..4a1c39b6f37d 100644 --- a/drivers/mtd/devices/docecc.c +++ b/drivers/mtd/devices/docecc.c @@ -2,7 +2,7 @@   * ECC algorithm for M-systems disk on chip. We use the excellent Reed   * Solmon code of Phil Karn (karn@ka9q.ampr.org) available under the   * GNU GPL License. The rest is simply to convert the disk on chip - * syndrom into a standard syndom. + * syndrome into a standard syndome.   *   * Author: Fabrice Bellard (fabrice.bellard@netgem.com)   * Copyright (C) 2000 Netgem S.A. diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c new file mode 100644 index 000000000000..bdcf5df982e8 --- /dev/null +++ b/drivers/mtd/devices/docg3.c @@ -0,0 +1,1114 @@ +/* + * Handles the M-Systems DiskOnChip G3 chip + * + * Copyright (C) 2011 Robert Jarzmik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/platform_device.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> + +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +#define CREATE_TRACE_POINTS +#include "docg3.h" + +/* + * This driver handles the DiskOnChip G3 flash memory. + * + * As no specification is available from M-Systems/Sandisk, this drivers lacks + * several functions available on the chip, as : + *  - block erase + *  - page write + *  - IPL write + *  - ECC fixing (lack of BCH algorith understanding) + *  - powerdown / powerup + * + * The bus data width (8bits versus 16bits) is not handled (if_cfg flag), and + * the driver assumes a 16bits data bus. + * + * DocG3 relies on 2 ECC algorithms, which are handled in hardware : + *  - a 1 byte Hamming code stored in the OOB for each page + *  - a 7 bytes BCH code stored in the OOB for each page + * The BCH part is only used for check purpose, no correction is available as + * some information is missing. What is known is that : + *  - BCH is in GF(2^14) + *  - BCH is over data of 520 bytes (512 page + 7 page_info bytes + *                                   + 1 hamming byte) + *  - BCH can correct up to 4 bits (t = 4) + *  - BCH syndroms are calculated in hardware, and checked in hardware as well + * + */ + +static inline u8 doc_readb(struct docg3 *docg3, u16 reg) +{ +	u8 val = readb(docg3->base + reg); + +	trace_docg3_io(0, 8, reg, (int)val); +	return val; +} + +static inline u16 doc_readw(struct docg3 *docg3, u16 reg) +{ +	u16 val = readw(docg3->base + reg); + +	trace_docg3_io(0, 16, reg, (int)val); +	return val; +} + +static inline void doc_writeb(struct docg3 *docg3, u8 val, u16 reg) +{ +	writeb(val, docg3->base + reg); +	trace_docg3_io(1, 16, reg, val); +} + +static inline void doc_writew(struct docg3 *docg3, u16 val, u16 reg) +{ +	writew(val, docg3->base + reg); +	trace_docg3_io(1, 16, reg, val); +} + +static inline void doc_flash_command(struct docg3 *docg3, u8 cmd) +{ +	doc_writeb(docg3, cmd, DOC_FLASHCOMMAND); +} + +static inline void doc_flash_sequence(struct docg3 *docg3, u8 seq) +{ +	doc_writeb(docg3, seq, DOC_FLASHSEQUENCE); +} + +static inline void doc_flash_address(struct docg3 *docg3, u8 addr) +{ +	doc_writeb(docg3, addr, DOC_FLASHADDRESS); +} + +static char const *part_probes[] = { "cmdlinepart", "saftlpart", NULL }; + +static int doc_register_readb(struct docg3 *docg3, int reg) +{ +	u8 val; + +	doc_writew(docg3, reg, DOC_READADDRESS); +	val = doc_readb(docg3, reg); +	doc_vdbg("Read register %04x : %02x\n", reg, val); +	return val; +} + +static int doc_register_readw(struct docg3 *docg3, int reg) +{ +	u16 val; + +	doc_writew(docg3, reg, DOC_READADDRESS); +	val = doc_readw(docg3, reg); +	doc_vdbg("Read register %04x : %04x\n", reg, val); +	return val; +} + +/** + * doc_delay - delay docg3 operations + * @docg3: the device + * @nbNOPs: the number of NOPs to issue + * + * As no specification is available, the right timings between chip commands are + * unknown. The only available piece of information are the observed nops on a + * working docg3 chip. + * Therefore, doc_delay relies on a busy loop of NOPs, instead of scheduler + * friendlier msleep() functions or blocking mdelay(). + */ +static void doc_delay(struct docg3 *docg3, int nbNOPs) +{ +	int i; + +	doc_dbg("NOP x %d\n", nbNOPs); +	for (i = 0; i < nbNOPs; i++) +		doc_writeb(docg3, 0, DOC_NOP); +} + +static int is_prot_seq_error(struct docg3 *docg3) +{ +	int ctrl; + +	ctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); +	return ctrl & (DOC_CTRL_PROTECTION_ERROR | DOC_CTRL_SEQUENCE_ERROR); +} + +static int doc_is_ready(struct docg3 *docg3) +{ +	int ctrl; + +	ctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); +	return ctrl & DOC_CTRL_FLASHREADY; +} + +static int doc_wait_ready(struct docg3 *docg3) +{ +	int maxWaitCycles = 100; + +	do { +		doc_delay(docg3, 4); +		cpu_relax(); +	} while (!doc_is_ready(docg3) && maxWaitCycles--); +	doc_delay(docg3, 2); +	if (maxWaitCycles > 0) +		return 0; +	else +		return -EIO; +} + +static int doc_reset_seq(struct docg3 *docg3) +{ +	int ret; + +	doc_writeb(docg3, 0x10, DOC_FLASHCONTROL); +	doc_flash_sequence(docg3, DOC_SEQ_RESET); +	doc_flash_command(docg3, DOC_CMD_RESET); +	doc_delay(docg3, 2); +	ret = doc_wait_ready(docg3); + +	doc_dbg("doc_reset_seq() -> isReady=%s\n", ret ? "false" : "true"); +	return ret; +} + +/** + * doc_read_data_area - Read data from data area + * @docg3: the device + * @buf: the buffer to fill in + * @len: the lenght to read + * @first: first time read, DOC_READADDRESS should be set + * + * Reads bytes from flash data. Handles the single byte / even bytes reads. + */ +static void doc_read_data_area(struct docg3 *docg3, void *buf, int len, +			       int first) +{ +	int i, cdr, len4; +	u16 data16, *dst16; +	u8 data8, *dst8; + +	doc_dbg("doc_read_data_area(buf=%p, len=%d)\n", buf, len); +	cdr = len & 0x3; +	len4 = len - cdr; + +	if (first) +		doc_writew(docg3, DOC_IOSPACE_DATA, DOC_READADDRESS); +	dst16 = buf; +	for (i = 0; i < len4; i += 2) { +		data16 = doc_readw(docg3, DOC_IOSPACE_DATA); +		*dst16 = data16; +		dst16++; +	} + +	if (cdr) { +		doc_writew(docg3, DOC_IOSPACE_DATA | DOC_READADDR_ONE_BYTE, +			   DOC_READADDRESS); +		doc_delay(docg3, 1); +		dst8 = (u8 *)dst16; +		for (i = 0; i < cdr; i++) { +			data8 = doc_readb(docg3, DOC_IOSPACE_DATA); +			*dst8 = data8; +			dst8++; +		} +	} +} + +/** + * doc_set_data_mode - Sets the flash to reliable data mode + * @docg3: the device + * + * The reliable data mode is a bit slower than the fast mode, but less errors + * occur.  Entering the reliable mode cannot be done without entering the fast + * mode first. + */ +static void doc_set_reliable_mode(struct docg3 *docg3) +{ +	doc_dbg("doc_set_reliable_mode()\n"); +	doc_flash_sequence(docg3, DOC_SEQ_SET_MODE); +	doc_flash_command(docg3, DOC_CMD_FAST_MODE); +	doc_flash_command(docg3, DOC_CMD_RELIABLE_MODE); +	doc_delay(docg3, 2); +} + +/** + * doc_set_asic_mode - Set the ASIC mode + * @docg3: the device + * @mode: the mode + * + * The ASIC can work in 3 modes : + *  - RESET: all registers are zeroed + *  - NORMAL: receives and handles commands + *  - POWERDOWN: minimal poweruse, flash parts shut off + */ +static void doc_set_asic_mode(struct docg3 *docg3, u8 mode) +{ +	int i; + +	for (i = 0; i < 12; i++) +		doc_readb(docg3, DOC_IOSPACE_IPL); + +	mode |= DOC_ASICMODE_MDWREN; +	doc_dbg("doc_set_asic_mode(%02x)\n", mode); +	doc_writeb(docg3, mode, DOC_ASICMODE); +	doc_writeb(docg3, ~mode, DOC_ASICMODECONFIRM); +	doc_delay(docg3, 1); +} + +/** + * doc_set_device_id - Sets the devices id for cascaded G3 chips + * @docg3: the device + * @id: the chip to select (amongst 0, 1, 2, 3) + * + * There can be 4 cascaded G3 chips. This function selects the one which will + * should be the active one. + */ +static void doc_set_device_id(struct docg3 *docg3, int id) +{ +	u8 ctrl; + +	doc_dbg("doc_set_device_id(%d)\n", id); +	doc_writeb(docg3, id, DOC_DEVICESELECT); +	ctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); + +	ctrl &= ~DOC_CTRL_VIOLATION; +	ctrl |= DOC_CTRL_CE; +	doc_writeb(docg3, ctrl, DOC_FLASHCONTROL); +} + +/** + * doc_set_extra_page_mode - Change flash page layout + * @docg3: the device + * + * Normally, the flash page is split into the data (512 bytes) and the out of + * band data (16 bytes). For each, 4 more bytes can be accessed, where the wear + * leveling counters are stored.  To access this last area of 4 bytes, a special + * mode must be input to the flash ASIC. + * + * Returns 0 if no error occured, -EIO else. + */ +static int doc_set_extra_page_mode(struct docg3 *docg3) +{ +	int fctrl; + +	doc_dbg("doc_set_extra_page_mode()\n"); +	doc_flash_sequence(docg3, DOC_SEQ_PAGE_SIZE_532); +	doc_flash_command(docg3, DOC_CMD_PAGE_SIZE_532); +	doc_delay(docg3, 2); + +	fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); +	if (fctrl & (DOC_CTRL_PROTECTION_ERROR | DOC_CTRL_SEQUENCE_ERROR)) +		return -EIO; +	else +		return 0; +} + +/** + * doc_seek - Set both flash planes to the specified block, page for reading + * @docg3: the device + * @block0: the first plane block index + * @block1: the second plane block index + * @page: the page index within the block + * @wear: if true, read will occur on the 4 extra bytes of the wear area + * @ofs: offset in page to read + * + * Programs the flash even and odd planes to the specific block and page. + * Alternatively, programs the flash to the wear area of the specified page. + */ +static int doc_read_seek(struct docg3 *docg3, int block0, int block1, int page, +			 int wear, int ofs) +{ +	int sector, ret = 0; + +	doc_dbg("doc_seek(blocks=(%d,%d), page=%d, ofs=%d, wear=%d)\n", +		block0, block1, page, ofs, wear); + +	if (!wear && (ofs < 2 * DOC_LAYOUT_PAGE_SIZE)) { +		doc_flash_sequence(docg3, DOC_SEQ_SET_PLANE1); +		doc_flash_command(docg3, DOC_CMD_READ_PLANE1); +		doc_delay(docg3, 2); +	} else { +		doc_flash_sequence(docg3, DOC_SEQ_SET_PLANE2); +		doc_flash_command(docg3, DOC_CMD_READ_PLANE2); +		doc_delay(docg3, 2); +	} + +	doc_set_reliable_mode(docg3); +	if (wear) +		ret = doc_set_extra_page_mode(docg3); +	if (ret) +		goto out; + +	sector = (block0 << DOC_ADDR_BLOCK_SHIFT) + (page & DOC_ADDR_PAGE_MASK); +	doc_flash_sequence(docg3, DOC_SEQ_READ); +	doc_flash_command(docg3, DOC_CMD_PROG_BLOCK_ADDR); +	doc_delay(docg3, 1); +	doc_flash_address(docg3, sector & 0xff); +	doc_flash_address(docg3, (sector >> 8) & 0xff); +	doc_flash_address(docg3, (sector >> 16) & 0xff); +	doc_delay(docg3, 1); + +	sector = (block1 << DOC_ADDR_BLOCK_SHIFT) + (page & DOC_ADDR_PAGE_MASK); +	doc_flash_command(docg3, DOC_CMD_PROG_BLOCK_ADDR); +	doc_delay(docg3, 1); +	doc_flash_address(docg3, sector & 0xff); +	doc_flash_address(docg3, (sector >> 8) & 0xff); +	doc_flash_address(docg3, (sector >> 16) & 0xff); +	doc_delay(docg3, 2); + +out: +	return ret; +} + +/** + * doc_read_page_ecc_init - Initialize hardware ECC engine + * @docg3: the device + * @len: the number of bytes covered by the ECC (BCH covered) + * + * The function does initialize the hardware ECC engine to compute the Hamming + * ECC (on 1 byte) and the BCH Syndroms (on 7 bytes). + * + * Return 0 if succeeded, -EIO on error + */ +static int doc_read_page_ecc_init(struct docg3 *docg3, int len) +{ +	doc_writew(docg3, DOC_ECCCONF0_READ_MODE +		   | DOC_ECCCONF0_BCH_ENABLE | DOC_ECCCONF0_HAMMING_ENABLE +		   | (len & DOC_ECCCONF0_DATA_BYTES_MASK), +		   DOC_ECCCONF0); +	doc_delay(docg3, 4); +	doc_register_readb(docg3, DOC_FLASHCONTROL); +	return doc_wait_ready(docg3); +} + +/** + * doc_read_page_prepare - Prepares reading data from a flash page + * @docg3: the device + * @block0: the first plane block index on flash memory + * @block1: the second plane block index on flash memory + * @page: the page index in the block + * @offset: the offset in the page (must be a multiple of 4) + * + * Prepares the page to be read in the flash memory : + *   - tell ASIC to map the flash pages + *   - tell ASIC to be in read mode + * + * After a call to this method, a call to doc_read_page_finish is mandatory, + * to end the read cycle of the flash. + * + * Read data from a flash page. The length to be read must be between 0 and + * (page_size + oob_size + wear_size), ie. 532, and a multiple of 4 (because + * the extra bytes reading is not implemented). + * + * As pages are grouped by 2 (in 2 planes), reading from a page must be done + * in two steps: + *  - one read of 512 bytes at offset 0 + *  - one read of 512 bytes at offset 512 + 16 + * + * Returns 0 if successful, -EIO if a read error occured. + */ +static int doc_read_page_prepare(struct docg3 *docg3, int block0, int block1, +				 int page, int offset) +{ +	int wear_area = 0, ret = 0; + +	doc_dbg("doc_read_page_prepare(blocks=(%d,%d), page=%d, ofsInPage=%d)\n", +		block0, block1, page, offset); +	if (offset >= DOC_LAYOUT_WEAR_OFFSET) +		wear_area = 1; +	if (!wear_area && offset > (DOC_LAYOUT_PAGE_OOB_SIZE * 2)) +		return -EINVAL; + +	doc_set_device_id(docg3, docg3->device_id); +	ret = doc_reset_seq(docg3); +	if (ret) +		goto err; + +	/* Program the flash address block and page */ +	ret = doc_read_seek(docg3, block0, block1, page, wear_area, offset); +	if (ret) +		goto err; + +	doc_flash_command(docg3, DOC_CMD_READ_ALL_PLANES); +	doc_delay(docg3, 2); +	doc_wait_ready(docg3); + +	doc_flash_command(docg3, DOC_CMD_SET_ADDR_READ); +	doc_delay(docg3, 1); +	if (offset >= DOC_LAYOUT_PAGE_SIZE * 2) +		offset -= 2 * DOC_LAYOUT_PAGE_SIZE; +	doc_flash_address(docg3, offset >> 2); +	doc_delay(docg3, 1); +	doc_wait_ready(docg3); + +	doc_flash_command(docg3, DOC_CMD_READ_FLASH); + +	return 0; +err: +	doc_writeb(docg3, 0, DOC_DATAEND); +	doc_delay(docg3, 2); +	return -EIO; +} + +/** + * doc_read_page_getbytes - Reads bytes from a prepared page + * @docg3: the device + * @len: the number of bytes to be read (must be a multiple of 4) + * @buf: the buffer to be filled in + * @first: 1 if first time read, DOC_READADDRESS should be set + * + */ +static int doc_read_page_getbytes(struct docg3 *docg3, int len, u_char *buf, +				  int first) +{ +	doc_read_data_area(docg3, buf, len, first); +	doc_delay(docg3, 2); +	return len; +} + +/** + * doc_get_hw_bch_syndroms - Get hardware calculated BCH syndroms + * @docg3: the device + * @syns:  the array of 7 integers where the syndroms will be stored + */ +static void doc_get_hw_bch_syndroms(struct docg3 *docg3, int *syns) +{ +	int i; + +	for (i = 0; i < DOC_ECC_BCH_SIZE; i++) +		syns[i] = doc_register_readb(docg3, DOC_BCH_SYNDROM(i)); +} + +/** + * doc_read_page_finish - Ends reading of a flash page + * @docg3: the device + * + * As a side effect, resets the chip selector to 0. This ensures that after each + * read operation, the floor 0 is selected. Therefore, if the systems halts, the + * reboot will boot on floor 0, where the IPL is. + */ +static void doc_read_page_finish(struct docg3 *docg3) +{ +	doc_writeb(docg3, 0, DOC_DATAEND); +	doc_delay(docg3, 2); +	doc_set_device_id(docg3, 0); +} + +/** + * calc_block_sector - Calculate blocks, pages and ofs. + + * @from: offset in flash + * @block0: first plane block index calculated + * @block1: second plane block index calculated + * @page: page calculated + * @ofs: offset in page + */ +static void calc_block_sector(loff_t from, int *block0, int *block1, int *page, +			      int *ofs) +{ +	uint sector; + +	sector = from / DOC_LAYOUT_PAGE_SIZE; +	*block0 = sector / (DOC_LAYOUT_PAGES_PER_BLOCK * DOC_LAYOUT_NBPLANES) +		* DOC_LAYOUT_NBPLANES; +	*block1 = *block0 + 1; +	*page = sector % (DOC_LAYOUT_PAGES_PER_BLOCK * DOC_LAYOUT_NBPLANES); +	*page /= DOC_LAYOUT_NBPLANES; +	if (sector % 2) +		*ofs = DOC_LAYOUT_PAGE_OOB_SIZE; +	else +		*ofs = 0; +} + +/** + * doc_read - Read bytes from flash + * @mtd: the device + * @from: the offset from first block and first page, in bytes, aligned on page + *        size + * @len: the number of bytes to read (must be a multiple of 4) + * @retlen: the number of bytes actually read + * @buf: the filled in buffer + * + * Reads flash memory pages. This function does not read the OOB chunk, but only + * the page data. + * + * Returns 0 if read successfull, of -EIO, -EINVAL if an error occured + */ +static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, +	     size_t *retlen, u_char *buf) +{ +	struct docg3 *docg3 = mtd->priv; +	int block0, block1, page, readlen, ret, ofs = 0; +	int syn[DOC_ECC_BCH_SIZE], eccconf1; +	u8 oob[DOC_LAYOUT_OOB_SIZE]; + +	ret = -EINVAL; +	doc_dbg("doc_read(from=%lld, len=%zu, buf=%p)\n", from, len, buf); +	if (from % DOC_LAYOUT_PAGE_SIZE) +		goto err; +	if (len % 4) +		goto err; +	calc_block_sector(from, &block0, &block1, &page, &ofs); +	if (block1 > docg3->max_block) +		goto err; + +	*retlen = 0; +	ret = 0; +	readlen = min_t(size_t, len, (size_t)DOC_LAYOUT_PAGE_SIZE); +	while (!ret && len > 0) { +		readlen = min_t(size_t, len, (size_t)DOC_LAYOUT_PAGE_SIZE); +		ret = doc_read_page_prepare(docg3, block0, block1, page, ofs); +		if (ret < 0) +			goto err; +		ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_COVERED_BYTES); +		if (ret < 0) +			goto err_in_read; +		ret = doc_read_page_getbytes(docg3, readlen, buf, 1); +		if (ret < readlen) +			goto err_in_read; +		ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE, +					     oob, 0); +		if (ret < DOC_LAYOUT_OOB_SIZE) +			goto err_in_read; + +		*retlen += readlen; +		buf += readlen; +		len -= readlen; + +		ofs ^= DOC_LAYOUT_PAGE_OOB_SIZE; +		if (ofs == 0) +			page += 2; +		if (page > DOC_ADDR_PAGE_MASK) { +			page = 0; +			block0 += 2; +			block1 += 2; +		} + +		/* +		 * There should be a BCH bitstream fixing algorithm here ... +		 * By now, a page read failure is triggered by BCH error +		 */ +		doc_get_hw_bch_syndroms(docg3, syn); +		eccconf1 = doc_register_readb(docg3, DOC_ECCCONF1); + +		doc_dbg("OOB - INFO: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", +			 oob[0], oob[1], oob[2], oob[3], oob[4], +			 oob[5], oob[6]); +		doc_dbg("OOB - HAMMING: %02x\n", oob[7]); +		doc_dbg("OOB - BCH_ECC: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", +			 oob[8], oob[9], oob[10], oob[11], oob[12], +			 oob[13], oob[14]); +		doc_dbg("OOB - UNUSED: %02x\n", oob[15]); +		doc_dbg("ECC checks: ECCConf1=%x\n", eccconf1); +		doc_dbg("ECC BCH syndrom: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", +			syn[0], syn[1], syn[2], syn[3], syn[4], syn[5], syn[6]); + +		ret = -EBADMSG; +		if (block0 >= DOC_LAYOUT_BLOCK_FIRST_DATA) { +			if (eccconf1 & DOC_ECCCONF1_BCH_SYNDROM_ERR) +				goto err_in_read; +			if (is_prot_seq_error(docg3)) +				goto err_in_read; +		} +		doc_read_page_finish(docg3); +	} + +	return 0; +err_in_read: +	doc_read_page_finish(docg3); +err: +	return ret; +} + +/** + * doc_read_oob - Read out of band bytes from flash + * @mtd: the device + * @from: the offset from first block and first page, in bytes, aligned on page + *        size + * @ops: the mtd oob structure + * + * Reads flash memory OOB area of pages. + * + * Returns 0 if read successfull, of -EIO, -EINVAL if an error occured + */ +static int doc_read_oob(struct mtd_info *mtd, loff_t from, +			struct mtd_oob_ops *ops) +{ +	struct docg3 *docg3 = mtd->priv; +	int block0, block1, page, ofs, ret; +	u8 *buf = ops->oobbuf; +	size_t len = ops->ooblen; + +	doc_dbg("doc_read_oob(from=%lld, buf=%p, len=%zu)\n", from, buf, len); +	if (len != DOC_LAYOUT_OOB_SIZE) +		return -EINVAL; + +	switch (ops->mode) { +	case MTD_OPS_PLACE_OOB: +		buf += ops->ooboffs; +		break; +	default: +		break; +	} + +	calc_block_sector(from, &block0, &block1, &page, &ofs); +	if (block1 > docg3->max_block) +		return -EINVAL; + +	ret = doc_read_page_prepare(docg3, block0, block1, page, +				    ofs + DOC_LAYOUT_PAGE_SIZE); +	if (!ret) +		ret = doc_read_page_ecc_init(docg3, DOC_LAYOUT_OOB_SIZE); +	if (!ret) +		ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE, +					     buf, 1); +	doc_read_page_finish(docg3); + +	if (ret > 0) +		ops->oobretlen = ret; +	else +		ops->oobretlen = 0; +	return (ret > 0) ? 0 : ret; +} + +static int doc_reload_bbt(struct docg3 *docg3) +{ +	int block = DOC_LAYOUT_BLOCK_BBT; +	int ret = 0, nbpages, page; +	u_char *buf = docg3->bbt; + +	nbpages = DIV_ROUND_UP(docg3->max_block + 1, 8 * DOC_LAYOUT_PAGE_SIZE); +	for (page = 0; !ret && (page < nbpages); page++) { +		ret = doc_read_page_prepare(docg3, block, block + 1, +					    page + DOC_LAYOUT_PAGE_BBT, 0); +		if (!ret) +			ret = doc_read_page_ecc_init(docg3, +						     DOC_LAYOUT_PAGE_SIZE); +		if (!ret) +			doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE, +					       buf, 1); +		buf += DOC_LAYOUT_PAGE_SIZE; +	} +	doc_read_page_finish(docg3); +	return ret; +} + +/** + * doc_block_isbad - Checks whether a block is good or not + * @mtd: the device + * @from: the offset to find the correct block + * + * Returns 1 if block is bad, 0 if block is good + */ +static int doc_block_isbad(struct mtd_info *mtd, loff_t from) +{ +	struct docg3 *docg3 = mtd->priv; +	int block0, block1, page, ofs, is_good; + +	calc_block_sector(from, &block0, &block1, &page, &ofs); +	doc_dbg("doc_block_isbad(from=%lld) => block=(%d,%d), page=%d, ofs=%d\n", +		from, block0, block1, page, ofs); + +	if (block0 < DOC_LAYOUT_BLOCK_FIRST_DATA) +		return 0; +	if (block1 > docg3->max_block) +		return -EINVAL; + +	is_good = docg3->bbt[block0 >> 3] & (1 << (block0 & 0x7)); +	return !is_good; +} + +/** + * doc_get_erase_count - Get block erase count + * @docg3: the device + * @from: the offset in which the block is. + * + * Get the number of times a block was erased. The number is the maximum of + * erase times between first and second plane (which should be equal normally). + * + * Returns The number of erases, or -EINVAL or -EIO on error. + */ +static int doc_get_erase_count(struct docg3 *docg3, loff_t from) +{ +	u8 buf[DOC_LAYOUT_WEAR_SIZE]; +	int ret, plane1_erase_count, plane2_erase_count; +	int block0, block1, page, ofs; + +	doc_dbg("doc_get_erase_count(from=%lld, buf=%p)\n", from, buf); +	if (from % DOC_LAYOUT_PAGE_SIZE) +		return -EINVAL; +	calc_block_sector(from, &block0, &block1, &page, &ofs); +	if (block1 > docg3->max_block) +		return -EINVAL; + +	ret = doc_reset_seq(docg3); +	if (!ret) +		ret = doc_read_page_prepare(docg3, block0, block1, page, +					    ofs + DOC_LAYOUT_WEAR_OFFSET); +	if (!ret) +		ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_WEAR_SIZE, +					     buf, 1); +	doc_read_page_finish(docg3); + +	if (ret || (buf[0] != DOC_ERASE_MARK) || (buf[2] != DOC_ERASE_MARK)) +		return -EIO; +	plane1_erase_count = (u8)(~buf[1]) | ((u8)(~buf[4]) << 8) +		| ((u8)(~buf[5]) << 16); +	plane2_erase_count = (u8)(~buf[3]) | ((u8)(~buf[6]) << 8) +		| ((u8)(~buf[7]) << 16); + +	return max(plane1_erase_count, plane2_erase_count); +} + +/* + * Debug sysfs entries + */ +static int dbg_flashctrl_show(struct seq_file *s, void *p) +{ +	struct docg3 *docg3 = (struct docg3 *)s->private; + +	int pos = 0; +	u8 fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); + +	pos += seq_printf(s, +		 "FlashControl : 0x%02x (%s,CE# %s,%s,%s,flash %s)\n", +		 fctrl, +		 fctrl & DOC_CTRL_VIOLATION ? "protocol violation" : "-", +		 fctrl & DOC_CTRL_CE ? "active" : "inactive", +		 fctrl & DOC_CTRL_PROTECTION_ERROR ? "protection error" : "-", +		 fctrl & DOC_CTRL_SEQUENCE_ERROR ? "sequence error" : "-", +		 fctrl & DOC_CTRL_FLASHREADY ? "ready" : "not ready"); +	return pos; +} +DEBUGFS_RO_ATTR(flashcontrol, dbg_flashctrl_show); + +static int dbg_asicmode_show(struct seq_file *s, void *p) +{ +	struct docg3 *docg3 = (struct docg3 *)s->private; + +	int pos = 0; +	int pctrl = doc_register_readb(docg3, DOC_ASICMODE); +	int mode = pctrl & 0x03; + +	pos += seq_printf(s, +			 "%04x : RAM_WE=%d,RSTIN_RESET=%d,BDETCT_RESET=%d,WRITE_ENABLE=%d,POWERDOWN=%d,MODE=%d%d (", +			 pctrl, +			 pctrl & DOC_ASICMODE_RAM_WE ? 1 : 0, +			 pctrl & DOC_ASICMODE_RSTIN_RESET ? 1 : 0, +			 pctrl & DOC_ASICMODE_BDETCT_RESET ? 1 : 0, +			 pctrl & DOC_ASICMODE_MDWREN ? 1 : 0, +			 pctrl & DOC_ASICMODE_POWERDOWN ? 1 : 0, +			 mode >> 1, mode & 0x1); + +	switch (mode) { +	case DOC_ASICMODE_RESET: +		pos += seq_printf(s, "reset"); +		break; +	case DOC_ASICMODE_NORMAL: +		pos += seq_printf(s, "normal"); +		break; +	case DOC_ASICMODE_POWERDOWN: +		pos += seq_printf(s, "powerdown"); +		break; +	} +	pos += seq_printf(s, ")\n"); +	return pos; +} +DEBUGFS_RO_ATTR(asic_mode, dbg_asicmode_show); + +static int dbg_device_id_show(struct seq_file *s, void *p) +{ +	struct docg3 *docg3 = (struct docg3 *)s->private; +	int pos = 0; +	int id = doc_register_readb(docg3, DOC_DEVICESELECT); + +	pos += seq_printf(s, "DeviceId = %d\n", id); +	return pos; +} +DEBUGFS_RO_ATTR(device_id, dbg_device_id_show); + +static int dbg_protection_show(struct seq_file *s, void *p) +{ +	struct docg3 *docg3 = (struct docg3 *)s->private; +	int pos = 0; +	int protect = doc_register_readb(docg3, DOC_PROTECTION); +	int dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS); +	int dps0_low = doc_register_readb(docg3, DOC_DPS0_ADDRLOW); +	int dps0_high = doc_register_readb(docg3, DOC_DPS0_ADDRHIGH); +	int dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS); +	int dps1_low = doc_register_readb(docg3, DOC_DPS1_ADDRLOW); +	int dps1_high = doc_register_readb(docg3, DOC_DPS1_ADDRHIGH); + +	pos += seq_printf(s, "Protection = 0x%02x (", +			 protect); +	if (protect & DOC_PROTECT_FOUNDRY_OTP_LOCK) +		pos += seq_printf(s, "FOUNDRY_OTP_LOCK,"); +	if (protect & DOC_PROTECT_CUSTOMER_OTP_LOCK) +		pos += seq_printf(s, "CUSTOMER_OTP_LOCK,"); +	if (protect & DOC_PROTECT_LOCK_INPUT) +		pos += seq_printf(s, "LOCK_INPUT,"); +	if (protect & DOC_PROTECT_STICKY_LOCK) +		pos += seq_printf(s, "STICKY_LOCK,"); +	if (protect & DOC_PROTECT_PROTECTION_ENABLED) +		pos += seq_printf(s, "PROTECTION ON,"); +	if (protect & DOC_PROTECT_IPL_DOWNLOAD_LOCK) +		pos += seq_printf(s, "IPL_DOWNLOAD_LOCK,"); +	if (protect & DOC_PROTECT_PROTECTION_ERROR) +		pos += seq_printf(s, "PROTECT_ERR,"); +	else +		pos += seq_printf(s, "NO_PROTECT_ERR"); +	pos += seq_printf(s, ")\n"); + +	pos += seq_printf(s, "DPS0 = 0x%02x : " +			 "Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, " +			 "WRITE=%d, HW_LOCK=%d, KEY_OK=%d\n", +			 dps0, dps0_low, dps0_high, +			 !!(dps0 & DOC_DPS_OTP_PROTECTED), +			 !!(dps0 & DOC_DPS_READ_PROTECTED), +			 !!(dps0 & DOC_DPS_WRITE_PROTECTED), +			 !!(dps0 & DOC_DPS_HW_LOCK_ENABLED), +			 !!(dps0 & DOC_DPS_KEY_OK)); +	pos += seq_printf(s, "DPS1 = 0x%02x : " +			 "Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, " +			 "WRITE=%d, HW_LOCK=%d, KEY_OK=%d\n", +			 dps1, dps1_low, dps1_high, +			 !!(dps1 & DOC_DPS_OTP_PROTECTED), +			 !!(dps1 & DOC_DPS_READ_PROTECTED), +			 !!(dps1 & DOC_DPS_WRITE_PROTECTED), +			 !!(dps1 & DOC_DPS_HW_LOCK_ENABLED), +			 !!(dps1 & DOC_DPS_KEY_OK)); +	return pos; +} +DEBUGFS_RO_ATTR(protection, dbg_protection_show); + +static int __init doc_dbg_register(struct docg3 *docg3) +{ +	struct dentry *root, *entry; + +	root = debugfs_create_dir("docg3", NULL); +	if (!root) +		return -ENOMEM; + +	entry = debugfs_create_file("flashcontrol", S_IRUSR, root, docg3, +				  &flashcontrol_fops); +	if (entry) +		entry = debugfs_create_file("asic_mode", S_IRUSR, root, +					    docg3, &asic_mode_fops); +	if (entry) +		entry = debugfs_create_file("device_id", S_IRUSR, root, +					    docg3, &device_id_fops); +	if (entry) +		entry = debugfs_create_file("protection", S_IRUSR, root, +					    docg3, &protection_fops); +	if (entry) { +		docg3->debugfs_root = root; +		return 0; +	} else { +		debugfs_remove_recursive(root); +		return -ENOMEM; +	} +} + +static void __exit doc_dbg_unregister(struct docg3 *docg3) +{ +	debugfs_remove_recursive(docg3->debugfs_root); +} + +/** + * doc_set_driver_info - Fill the mtd_info structure and docg3 structure + * @chip_id: The chip ID of the supported chip + * @mtd: The structure to fill + */ +static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) +{ +	struct docg3 *docg3 = mtd->priv; +	int cfg; + +	cfg = doc_register_readb(docg3, DOC_CONFIGURATION); +	docg3->if_cfg = (cfg & DOC_CONF_IF_CFG ? 1 : 0); + +	switch (chip_id) { +	case DOC_CHIPID_G3: +		mtd->name = "DiskOnChip G3"; +		docg3->max_block = 2047; +		break; +	} +	mtd->type = MTD_NANDFLASH; +	/* +	 * Once write methods are added, the correct flags will be set. +	 * mtd->flags = MTD_CAP_NANDFLASH; +	 */ +	mtd->flags = MTD_CAP_ROM; +	mtd->size = (docg3->max_block + 1) * DOC_LAYOUT_BLOCK_SIZE; +	mtd->erasesize = DOC_LAYOUT_BLOCK_SIZE * DOC_LAYOUT_NBPLANES; +	mtd->writesize = DOC_LAYOUT_PAGE_SIZE; +	mtd->oobsize = DOC_LAYOUT_OOB_SIZE; +	mtd->owner = THIS_MODULE; +	mtd->erase = NULL; +	mtd->point = NULL; +	mtd->unpoint = NULL; +	mtd->read = doc_read; +	mtd->write = NULL; +	mtd->read_oob = doc_read_oob; +	mtd->write_oob = NULL; +	mtd->sync = NULL; +	mtd->block_isbad = doc_block_isbad; +} + +/** + * doc_probe - Probe the IO space for a DiskOnChip G3 chip + * @pdev: platform device + * + * Probes for a G3 chip at the specified IO space in the platform data + * ressources. + * + * Returns 0 on success, -ENOMEM, -ENXIO on error + */ +static int __init docg3_probe(struct platform_device *pdev) +{ +	struct device *dev = &pdev->dev; +	struct docg3 *docg3; +	struct mtd_info *mtd; +	struct resource *ress; +	int ret, bbt_nbpages; +	u16 chip_id, chip_id_inv; + +	ret = -ENOMEM; +	docg3 = kzalloc(sizeof(struct docg3), GFP_KERNEL); +	if (!docg3) +		goto nomem1; +	mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL); +	if (!mtd) +		goto nomem2; +	mtd->priv = docg3; + +	ret = -ENXIO; +	ress = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	if (!ress) { +		dev_err(dev, "No I/O memory resource defined\n"); +		goto noress; +	} +	docg3->base = ioremap(ress->start, DOC_IOSPACE_SIZE); + +	docg3->dev = &pdev->dev; +	docg3->device_id = 0; +	doc_set_device_id(docg3, docg3->device_id); +	doc_set_asic_mode(docg3, DOC_ASICMODE_RESET); +	doc_set_asic_mode(docg3, DOC_ASICMODE_NORMAL); + +	chip_id = doc_register_readw(docg3, DOC_CHIPID); +	chip_id_inv = doc_register_readw(docg3, DOC_CHIPID_INV); + +	ret = -ENODEV; +	if (chip_id != (u16)(~chip_id_inv)) { +		doc_info("No device found at IO addr %p\n", +			 (void *)ress->start); +		goto nochipfound; +	} + +	switch (chip_id) { +	case DOC_CHIPID_G3: +		doc_info("Found a G3 DiskOnChip at addr %p\n", +			 (void *)ress->start); +		break; +	default: +		doc_err("Chip id %04x is not a DiskOnChip G3 chip\n", chip_id); +		goto nochipfound; +	} + +	doc_set_driver_info(chip_id, mtd); +	platform_set_drvdata(pdev, mtd); + +	ret = -ENOMEM; +	bbt_nbpages = DIV_ROUND_UP(docg3->max_block + 1, +				   8 * DOC_LAYOUT_PAGE_SIZE); +	docg3->bbt = kzalloc(bbt_nbpages * DOC_LAYOUT_PAGE_SIZE, GFP_KERNEL); +	if (!docg3->bbt) +		goto nochipfound; +	doc_reload_bbt(docg3); + +	ret = mtd_device_parse_register(mtd, part_probes, +					NULL, NULL, 0); +	if (ret) +		goto register_error; + +	doc_dbg_register(docg3); +	return 0; + +register_error: +	kfree(docg3->bbt); +nochipfound: +	iounmap(docg3->base); +noress: +	kfree(mtd); +nomem2: +	kfree(docg3); +nomem1: +	return ret; +} + +/** + * docg3_release - Release the driver + * @pdev: the platform device + * + * Returns 0 + */ +static int __exit docg3_release(struct platform_device *pdev) +{ +	struct mtd_info *mtd = platform_get_drvdata(pdev); +	struct docg3 *docg3 = mtd->priv; + +	doc_dbg_unregister(docg3); +	mtd_device_unregister(mtd); +	iounmap(docg3->base); +	kfree(docg3->bbt); +	kfree(docg3); +	kfree(mtd); +	return 0; +} + +static struct platform_driver g3_driver = { +	.driver		= { +		.name	= "docg3", +		.owner	= THIS_MODULE, +	}, +	.remove		= __exit_p(docg3_release), +}; + +static int __init docg3_init(void) +{ +	return platform_driver_probe(&g3_driver, docg3_probe); +} +module_init(docg3_init); + + +static void __exit docg3_exit(void) +{ +	platform_driver_unregister(&g3_driver); +} +module_exit(docg3_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>"); +MODULE_DESCRIPTION("MTD driver for DiskOnChip G3"); diff --git a/drivers/mtd/devices/docg3.h b/drivers/mtd/devices/docg3.h new file mode 100644 index 000000000000..0d407be24594 --- /dev/null +++ b/drivers/mtd/devices/docg3.h @@ -0,0 +1,297 @@ +/* + * Handles the M-Systems DiskOnChip G3 chip + * + * Copyright (C) 2011 Robert Jarzmik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * + */ + +#ifndef _MTD_DOCG3_H +#define _MTD_DOCG3_H + +/* + * Flash memory areas : + *   - 0x0000 .. 0x07ff : IPL + *   - 0x0800 .. 0x0fff : Data area + *   - 0x1000 .. 0x17ff : Registers + *   - 0x1800 .. 0x1fff : Unknown + */ +#define DOC_IOSPACE_IPL			0x0000 +#define DOC_IOSPACE_DATA		0x0800 +#define DOC_IOSPACE_SIZE		0x2000 + +/* + * DOC G3 layout and adressing scheme + *   A page address for the block "b", plane "P" and page "p": + *   address = [bbbb bPpp pppp] + */ + +#define DOC_ADDR_PAGE_MASK		0x3f +#define DOC_ADDR_BLOCK_SHIFT		6 +#define DOC_LAYOUT_NBPLANES		2 +#define DOC_LAYOUT_PAGES_PER_BLOCK	64 +#define DOC_LAYOUT_PAGE_SIZE		512 +#define DOC_LAYOUT_OOB_SIZE		16 +#define DOC_LAYOUT_WEAR_SIZE		8 +#define DOC_LAYOUT_PAGE_OOB_SIZE				\ +	(DOC_LAYOUT_PAGE_SIZE + DOC_LAYOUT_OOB_SIZE) +#define DOC_LAYOUT_WEAR_OFFSET		(DOC_LAYOUT_PAGE_OOB_SIZE * 2) +#define DOC_LAYOUT_BLOCK_SIZE					\ +	(DOC_LAYOUT_PAGES_PER_BLOCK * DOC_LAYOUT_PAGE_SIZE) +#define DOC_ECC_BCH_SIZE		7 +#define DOC_ECC_BCH_COVERED_BYTES				\ +	(DOC_LAYOUT_PAGE_SIZE + DOC_LAYOUT_OOB_PAGEINFO_SZ +	\ +	 DOC_LAYOUT_OOB_HAMMING_SZ + DOC_LAYOUT_OOB_BCH_SZ) + +/* + * Blocks distribution + */ +#define DOC_LAYOUT_BLOCK_BBT		0 +#define DOC_LAYOUT_BLOCK_OTP		0 +#define DOC_LAYOUT_BLOCK_FIRST_DATA	6 + +#define DOC_LAYOUT_PAGE_BBT		4 + +/* + * Extra page OOB (16 bytes wide) layout + */ +#define DOC_LAYOUT_OOB_PAGEINFO_OFS	0 +#define DOC_LAYOUT_OOB_HAMMING_OFS	7 +#define DOC_LAYOUT_OOB_BCH_OFS		8 +#define DOC_LAYOUT_OOB_UNUSED_OFS	15 +#define DOC_LAYOUT_OOB_PAGEINFO_SZ	7 +#define DOC_LAYOUT_OOB_HAMMING_SZ	1 +#define DOC_LAYOUT_OOB_BCH_SZ		7 +#define DOC_LAYOUT_OOB_UNUSED_SZ	1 + + +#define DOC_CHIPID_G3			0x200 +#define DOC_ERASE_MARK			0xaa +/* + * Flash registers + */ +#define DOC_CHIPID			0x1000 +#define DOC_TEST			0x1004 +#define DOC_BUSLOCK			0x1006 +#define DOC_ENDIANCONTROL		0x1008 +#define DOC_DEVICESELECT		0x100a +#define DOC_ASICMODE			0x100c +#define DOC_CONFIGURATION		0x100e +#define DOC_INTERRUPTCONTROL		0x1010 +#define DOC_READADDRESS			0x101a +#define DOC_DATAEND			0x101e +#define DOC_INTERRUPTSTATUS		0x1020 + +#define DOC_FLASHSEQUENCE		0x1032 +#define DOC_FLASHCOMMAND		0x1034 +#define DOC_FLASHADDRESS		0x1036 +#define DOC_FLASHCONTROL		0x1038 +#define DOC_NOP				0x103e + +#define DOC_ECCCONF0			0x1040 +#define DOC_ECCCONF1			0x1042 +#define DOC_ECCPRESET			0x1044 +#define DOC_HAMMINGPARITY		0x1046 +#define DOC_BCH_SYNDROM(idx)		(0x1048 + (idx << 1)) + +#define DOC_PROTECTION			0x1056 +#define DOC_DPS0_ADDRLOW		0x1060 +#define DOC_DPS0_ADDRHIGH		0x1062 +#define DOC_DPS1_ADDRLOW		0x1064 +#define DOC_DPS1_ADDRHIGH		0x1066 +#define DOC_DPS0_STATUS			0x106c +#define DOC_DPS1_STATUS			0x106e + +#define DOC_ASICMODECONFIRM		0x1072 +#define DOC_CHIPID_INV			0x1074 + +/* + * Flash sequences + * A sequence is preset before one or more commands are input to the chip. + */ +#define DOC_SEQ_RESET			0x00 +#define DOC_SEQ_PAGE_SIZE_532		0x03 +#define DOC_SEQ_SET_MODE		0x09 +#define DOC_SEQ_READ			0x12 +#define DOC_SEQ_SET_PLANE1		0x0e +#define DOC_SEQ_SET_PLANE2		0x10 +#define DOC_SEQ_PAGE_SETUP		0x1d + +/* + * Flash commands + */ +#define DOC_CMD_READ_PLANE1		0x00 +#define DOC_CMD_SET_ADDR_READ		0x05 +#define DOC_CMD_READ_ALL_PLANES		0x30 +#define DOC_CMD_READ_PLANE2		0x50 +#define DOC_CMD_READ_FLASH		0xe0 +#define DOC_CMD_PAGE_SIZE_532		0x3c + +#define DOC_CMD_PROG_BLOCK_ADDR		0x60 +#define DOC_CMD_PROG_CYCLE1		0x80 +#define DOC_CMD_PROG_CYCLE2		0x10 +#define DOC_CMD_ERASECYCLE2		0xd0 + +#define DOC_CMD_RELIABLE_MODE		0x22 +#define DOC_CMD_FAST_MODE		0xa2 + +#define DOC_CMD_RESET			0xff + +/* + * Flash register : DOC_FLASHCONTROL + */ +#define DOC_CTRL_VIOLATION		0x20 +#define DOC_CTRL_CE			0x10 +#define DOC_CTRL_UNKNOWN_BITS		0x08 +#define DOC_CTRL_PROTECTION_ERROR	0x04 +#define DOC_CTRL_SEQUENCE_ERROR		0x02 +#define DOC_CTRL_FLASHREADY		0x01 + +/* + * Flash register : DOC_ASICMODE + */ +#define DOC_ASICMODE_RESET		0x00 +#define DOC_ASICMODE_NORMAL		0x01 +#define DOC_ASICMODE_POWERDOWN		0x02 +#define DOC_ASICMODE_MDWREN		0x04 +#define DOC_ASICMODE_BDETCT_RESET	0x08 +#define DOC_ASICMODE_RSTIN_RESET	0x10 +#define DOC_ASICMODE_RAM_WE		0x20 + +/* + * Flash register : DOC_ECCCONF0 + */ +#define DOC_ECCCONF0_READ_MODE		0x8000 +#define DOC_ECCCONF0_AUTO_ECC_ENABLE	0x4000 +#define DOC_ECCCONF0_HAMMING_ENABLE	0x1000 +#define DOC_ECCCONF0_BCH_ENABLE		0x0800 +#define DOC_ECCCONF0_DATA_BYTES_MASK	0x07ff + +/* + * Flash register : DOC_ECCCONF1 + */ +#define DOC_ECCCONF1_BCH_SYNDROM_ERR	0x80 +#define DOC_ECCCONF1_UNKOWN1		0x40 +#define DOC_ECCCONF1_UNKOWN2		0x20 +#define DOC_ECCCONF1_UNKOWN3		0x10 +#define DOC_ECCCONF1_HAMMING_BITS_MASK	0x0f + +/* + * Flash register : DOC_PROTECTION + */ +#define DOC_PROTECT_FOUNDRY_OTP_LOCK	0x01 +#define DOC_PROTECT_CUSTOMER_OTP_LOCK	0x02 +#define DOC_PROTECT_LOCK_INPUT		0x04 +#define DOC_PROTECT_STICKY_LOCK		0x08 +#define DOC_PROTECT_PROTECTION_ENABLED	0x10 +#define DOC_PROTECT_IPL_DOWNLOAD_LOCK	0x20 +#define DOC_PROTECT_PROTECTION_ERROR	0x80 + +/* + * Flash register : DOC_DPS0_STATUS and DOC_DPS1_STATUS + */ +#define DOC_DPS_OTP_PROTECTED		0x01 +#define DOC_DPS_READ_PROTECTED		0x02 +#define DOC_DPS_WRITE_PROTECTED		0x04 +#define DOC_DPS_HW_LOCK_ENABLED		0x08 +#define DOC_DPS_KEY_OK			0x80 + +/* + * Flash register : DOC_CONFIGURATION + */ +#define DOC_CONF_IF_CFG			0x80 +#define DOC_CONF_MAX_ID_MASK		0x30 +#define DOC_CONF_VCCQ_3V		0x01 + +/* + * Flash register : DOC_READADDRESS + */ +#define DOC_READADDR_INC		0x8000 +#define DOC_READADDR_ONE_BYTE		0x4000 +#define DOC_READADDR_ADDR_MASK		0x1fff + +/** + * struct docg3 - DiskOnChip driver private data + * @dev: the device currently under control + * @base: mapped IO space + * @device_id: number of the cascaded DoCG3 device (0, 1, 2 or 3) + * @if_cfg: if true, reads are on 16bits, else reads are on 8bits + * @bbt: bad block table cache + * @debugfs_root: debugfs root node + */ +struct docg3 { +	struct device *dev; +	void __iomem *base; +	unsigned int device_id:4; +	unsigned int if_cfg:1; +	int max_block; +	u8 *bbt; +	struct dentry *debugfs_root; +}; + +#define doc_err(fmt, arg...) dev_err(docg3->dev, (fmt), ## arg) +#define doc_info(fmt, arg...) dev_info(docg3->dev, (fmt), ## arg) +#define doc_dbg(fmt, arg...) dev_dbg(docg3->dev, (fmt), ## arg) +#define doc_vdbg(fmt, arg...) dev_vdbg(docg3->dev, (fmt), ## arg) + +#define DEBUGFS_RO_ATTR(name, show_fct) \ +	static int name##_open(struct inode *inode, struct file *file) \ +	{ return single_open(file, show_fct, inode->i_private); }      \ +	static const struct file_operations name##_fops = { \ +		.owner = THIS_MODULE, \ +		.open = name##_open, \ +		.llseek = seq_lseek, \ +		.read = seq_read, \ +		.release = single_release \ +	}; +#endif + +/* + * Trace events part + */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM docg3 + +#if !defined(_MTD_DOCG3_TRACE) || defined(TRACE_HEADER_MULTI_READ) +#define _MTD_DOCG3_TRACE + +#include <linux/tracepoint.h> + +TRACE_EVENT(docg3_io, +	    TP_PROTO(int op, int width, u16 reg, int val), +	    TP_ARGS(op, width, reg, val), +	    TP_STRUCT__entry( +		    __field(int, op) +		    __field(unsigned char, width) +		    __field(u16, reg) +		    __field(int, val)), +	    TP_fast_assign( +		    __entry->op = op; +		    __entry->width = width; +		    __entry->reg = reg; +		    __entry->val = val;), +	    TP_printk("docg3: %s%02d reg=%04x, val=%04x", +		      __entry->op ? "write" : "read", __entry->width, +		      __entry->reg, __entry->val) +	); +#endif + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE docg3 +#include <trace/define_trace.h> diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c index d374603493a7..45116bb30297 100644 --- a/drivers/mtd/devices/docprobe.c +++ b/drivers/mtd/devices/docprobe.c @@ -50,11 +50,6 @@  #include <linux/mtd/nand.h>  #include <linux/mtd/doc2000.h> -/* Where to look for the devices? */ -#ifndef CONFIG_MTD_DOCPROBE_ADDRESS -#define CONFIG_MTD_DOCPROBE_ADDRESS 0 -#endif -  static unsigned long doc_config_location = CONFIG_MTD_DOCPROBE_ADDRESS;  module_param(doc_config_location, ulong, 0); diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c index 772a0ff89e0f..3a11ea628e58 100644 --- a/drivers/mtd/devices/lart.c +++ b/drivers/mtd/devices/lart.c @@ -34,9 +34,6 @@  /* debugging */  //#define LART_DEBUG -/* partition support */ -#define HAVE_PARTITIONS -  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/types.h> @@ -44,9 +41,7 @@  #include <linux/errno.h>  #include <linux/string.h>  #include <linux/mtd/mtd.h> -#ifdef HAVE_PARTITIONS  #include <linux/mtd/partitions.h> -#endif  #ifndef CONFIG_SA1100_LART  #error This is for LART architecture only @@ -598,7 +593,6 @@ static struct mtd_erase_region_info erase_regions[] = {  	}  }; -#ifdef HAVE_PARTITIONS  static struct mtd_partition lart_partitions[] = {  	/* blob */  	{ @@ -619,7 +613,7 @@ static struct mtd_partition lart_partitions[] = {  		.size	= INITRD_LEN,		/* MTDPART_SIZ_FULL */  	}  }; -#endif +#define NUM_PARTITIONS ARRAY_SIZE(lart_partitions)  static int __init lart_flash_init (void)  { @@ -668,7 +662,6 @@ static int __init lart_flash_init (void)  			   result,mtd.eraseregions[result].erasesize,mtd.eraseregions[result].erasesize / 1024,  			   result,mtd.eraseregions[result].numblocks); -#ifdef HAVE_PARTITIONS     printk ("\npartitions = %d\n", ARRAY_SIZE(lart_partitions));     for (result = 0; result < ARRAY_SIZE(lart_partitions); result++) @@ -681,25 +674,16 @@ static int __init lart_flash_init (void)  			 result,lart_partitions[result].offset,  			 result,lart_partitions[result].size,lart_partitions[result].size / 1024);  #endif -#endif -#ifndef HAVE_PARTITIONS -   result = mtd_device_register(&mtd, NULL, 0); -#else     result = mtd_device_register(&mtd, lart_partitions,                                  ARRAY_SIZE(lart_partitions)); -#endif     return (result);  }  static void __exit lart_flash_exit (void)  { -#ifndef HAVE_PARTITIONS -   mtd_device_unregister(&mtd); -#else     mtd_device_unregister(&mtd); -#endif  }  module_init (lart_flash_init); diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 35180e475c4c..884904d3f9d2 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -30,6 +30,7 @@  #include <linux/mtd/cfi.h>  #include <linux/mtd/mtd.h>  #include <linux/mtd/partitions.h> +#include <linux/of_platform.h>  #include <linux/spi/spi.h>  #include <linux/spi/flash.h> @@ -88,7 +89,6 @@ struct m25p {  	struct spi_device	*spi;  	struct mutex		lock;  	struct mtd_info		mtd; -	unsigned		partitioned:1;  	u16			page_size;  	u16			addr_width;  	u8			erase_opcode; @@ -209,9 +209,8 @@ static int wait_till_ready(struct m25p *flash)   */  static int erase_chip(struct m25p *flash)  { -	DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %lldKiB\n", -	      dev_name(&flash->spi->dev), __func__, -	      (long long)(flash->mtd.size >> 10)); +	pr_debug("%s: %s %lldKiB\n", dev_name(&flash->spi->dev), __func__, +			(long long)(flash->mtd.size >> 10));  	/* Wait until finished previous write command. */  	if (wait_till_ready(flash)) @@ -250,9 +249,8 @@ static int m25p_cmdsz(struct m25p *flash)   */  static int erase_sector(struct m25p *flash, u32 offset)  { -	DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB at 0x%08x\n", -			dev_name(&flash->spi->dev), __func__, -			flash->mtd.erasesize / 1024, offset); +	pr_debug("%s: %s %dKiB at 0x%08x\n", dev_name(&flash->spi->dev), +			__func__, flash->mtd.erasesize / 1024, offset);  	/* Wait until finished previous write command. */  	if (wait_till_ready(flash)) @@ -286,9 +284,9 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)  	u32 addr,len;  	uint32_t rem; -	DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%llx, len %lld\n", -	      dev_name(&flash->spi->dev), __func__, "at", -	      (long long)instr->addr, (long long)instr->len); +	pr_debug("%s: %s at 0x%llx, len %lld\n", dev_name(&flash->spi->dev), +			__func__, (long long)instr->addr, +			(long long)instr->len);  	/* sanity checks */  	if (instr->addr + instr->len > flash->mtd.size) @@ -348,9 +346,8 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,  	struct spi_transfer t[2];  	struct spi_message m; -	DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", -			dev_name(&flash->spi->dev), __func__, "from", -			(u32)from, len); +	pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev), +			__func__, (u32)from, len);  	/* sanity checks */  	if (!len) @@ -417,9 +414,8 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,  	struct spi_transfer t[2];  	struct spi_message m; -	DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", -			dev_name(&flash->spi->dev), __func__, "to", -			(u32)to, len); +	pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev), +			__func__, (u32)to, len);  	*retlen = 0; @@ -510,9 +506,8 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,  	size_t actual;  	int cmd_sz, ret; -	DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", -			dev_name(&flash->spi->dev), __func__, "to", -			(u32)to, len); +	pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev), +			__func__, (u32)to, len);  	*retlen = 0; @@ -661,6 +656,7 @@ static const struct spi_device_id m25p_ids[] = {  	{ "at25fs040",  INFO(0x1f6604, 0, 64 * 1024,   8, SECT_4K) },  	{ "at25df041a", INFO(0x1f4401, 0, 64 * 1024,   8, SECT_4K) }, +	{ "at25df321a", INFO(0x1f4701, 0, 64 * 1024,  64, SECT_4K) },  	{ "at25df641",  INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) },  	{ "at26f004",   INFO(0x1f0400, 0, 64 * 1024,  8, SECT_4K) }, @@ -671,6 +667,7 @@ static const struct spi_device_id m25p_ids[] = {  	/* EON -- en25xxx */  	{ "en25f32", INFO(0x1c3116, 0, 64 * 1024,  64, SECT_4K) },  	{ "en25p32", INFO(0x1c2016, 0, 64 * 1024,  64, 0) }, +	{ "en25q32b", INFO(0x1c3016, 0, 64 * 1024,  64, 0) },  	{ "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) },  	/* Intel/Numonyx -- xxxs33b */ @@ -788,8 +785,8 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi)  	 */  	tmp = spi_write_then_read(spi, &code, 1, id, 5);  	if (tmp < 0) { -		DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n", -			dev_name(&spi->dev), tmp); +		pr_debug("%s: error %d reading JEDEC ID\n", +				dev_name(&spi->dev), tmp);  		return ERR_PTR(tmp);  	}  	jedec = id[0]; @@ -825,8 +822,12 @@ static int __devinit m25p_probe(struct spi_device *spi)  	struct m25p			*flash;  	struct flash_info		*info;  	unsigned			i; -	struct mtd_partition		*parts = NULL; -	int				nr_parts = 0; +	struct mtd_part_parser_data	ppdata; + +#ifdef CONFIG_MTD_OF_PARTS +	if (!of_device_is_available(spi->dev.of_node)) +		return -ENODEV; +#endif  	/* Platform data helps sort out which chip type we have, as  	 * well as how this board partitions it.  If we don't have @@ -928,6 +929,7 @@ static int __devinit m25p_probe(struct spi_device *spi)  	if (info->flags & M25P_NO_ERASE)  		flash->mtd.flags |= MTD_NO_ERASE; +	ppdata.of_node = spi->dev.of_node;  	flash->mtd.dev.parent = &spi->dev;  	flash->page_size = info->page_size; @@ -945,8 +947,7 @@ static int __devinit m25p_probe(struct spi_device *spi)  	dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name,  			(long long)flash->mtd.size >> 10); -	DEBUG(MTD_DEBUG_LEVEL2, -		"mtd .name = %s, .size = 0x%llx (%lldMiB) " +	pr_debug("mtd .name = %s, .size = 0x%llx (%lldMiB) "  			".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",  		flash->mtd.name,  		(long long)flash->mtd.size, (long long)(flash->mtd.size >> 20), @@ -955,8 +956,7 @@ static int __devinit m25p_probe(struct spi_device *spi)  	if (flash->mtd.numeraseregions)  		for (i = 0; i < flash->mtd.numeraseregions; i++) -			DEBUG(MTD_DEBUG_LEVEL2, -				"mtd.eraseregions[%d] = { .offset = 0x%llx, " +			pr_debug("mtd.eraseregions[%d] = { .offset = 0x%llx, "  				".erasesize = 0x%.8x (%uKiB), "  				".numblocks = %d }\n",  				i, (long long)flash->mtd.eraseregions[i].offset, @@ -968,41 +968,9 @@ static int __devinit m25p_probe(struct spi_device *spi)  	/* partitions should match sector boundaries; and it may be good to  	 * use readonly partitions for writeprotected sectors (BP2..BP0).  	 */ -	if (mtd_has_cmdlinepart()) { -		static const char *part_probes[] -			= { "cmdlinepart", NULL, }; - -		nr_parts = parse_mtd_partitions(&flash->mtd, -						part_probes, &parts, 0); -	} - -	if (nr_parts <= 0 && data && data->parts) { -		parts = data->parts; -		nr_parts = data->nr_parts; -	} - -#ifdef CONFIG_MTD_OF_PARTS -	if (nr_parts <= 0 && spi->dev.of_node) { -		nr_parts = of_mtd_parse_partitions(&spi->dev, -						   spi->dev.of_node, &parts); -	} -#endif - -	if (nr_parts > 0) { -		for (i = 0; i < nr_parts; i++) { -			DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = " -			      "{.name = %s, .offset = 0x%llx, " -			      ".size = 0x%llx (%lldKiB) }\n", -			      i, parts[i].name, -			      (long long)parts[i].offset, -			      (long long)parts[i].size, -			      (long long)(parts[i].size >> 10)); -		} -		flash->partitioned = 1; -	} - -	return mtd_device_register(&flash->mtd, parts, nr_parts) == 1 ? -		-ENODEV : 0; +	return mtd_device_parse_register(&flash->mtd, NULL, &ppdata, +			data ? data->parts : NULL, +			data ? data->nr_parts : 0);  } diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 13749d458a31..d75c7af18a63 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -17,6 +17,8 @@  #include <linux/mutex.h>  #include <linux/err.h>  #include <linux/math64.h> +#include <linux/of.h> +#include <linux/of_device.h>  #include <linux/spi/spi.h>  #include <linux/spi/flash.h> @@ -24,7 +26,6 @@  #include <linux/mtd/mtd.h>  #include <linux/mtd/partitions.h> -  /*   * DataFlash is a kind of SPI flash.  Most AT45 chips have two buffers in   * each chip, which may be used for double buffered I/O; but this driver @@ -98,6 +99,16 @@ struct dataflash {  	struct mtd_info		mtd;  }; +#ifdef CONFIG_OF +static const struct of_device_id dataflash_dt_ids[] = { +	{ .compatible = "atmel,at45", }, +	{ .compatible = "atmel,dataflash", }, +	{ /* sentinel */ } +}; +#else +#define dataflash_dt_ids NULL +#endif +  /* ......................................................................... */  /* @@ -122,7 +133,7 @@ static int dataflash_waitready(struct spi_device *spi)  	for (;;) {  		status = dataflash_status(spi);  		if (status < 0) { -			DEBUG(MTD_DEBUG_LEVEL1, "%s: status %d?\n", +			pr_debug("%s: status %d?\n",  					dev_name(&spi->dev), status);  			status = 0;  		} @@ -149,7 +160,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)  	uint8_t			*command;  	uint32_t		rem; -	DEBUG(MTD_DEBUG_LEVEL2, "%s: erase addr=0x%llx len 0x%llx\n", +	pr_debug("%s: erase addr=0x%llx len 0x%llx\n",  	      dev_name(&spi->dev), (long long)instr->addr,  	      (long long)instr->len); @@ -187,7 +198,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)  		command[2] = (uint8_t)(pageaddr >> 8);  		command[3] = 0; -		DEBUG(MTD_DEBUG_LEVEL3, "ERASE %s: (%x) %x %x %x [%i]\n", +		pr_debug("ERASE %s: (%x) %x %x %x [%i]\n",  			do_block ? "block" : "page",  			command[0], command[1], command[2], command[3],  			pageaddr); @@ -238,8 +249,8 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,  	uint8_t			*command;  	int			status; -	DEBUG(MTD_DEBUG_LEVEL2, "%s: read 0x%x..0x%x\n", -		dev_name(&priv->spi->dev), (unsigned)from, (unsigned)(from + len)); +	pr_debug("%s: read 0x%x..0x%x\n", dev_name(&priv->spi->dev), +			(unsigned)from, (unsigned)(from + len));  	*retlen = 0; @@ -255,7 +266,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,  	command = priv->command; -	DEBUG(MTD_DEBUG_LEVEL3, "READ: (%x) %x %x %x\n", +	pr_debug("READ: (%x) %x %x %x\n",  		command[0], command[1], command[2], command[3]);  	spi_message_init(&msg); @@ -287,7 +298,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,  		*retlen = msg.actual_length - 8;  		status = 0;  	} else -		DEBUG(MTD_DEBUG_LEVEL1, "%s: read %x..%x --> %d\n", +		pr_debug("%s: read %x..%x --> %d\n",  			dev_name(&priv->spi->dev),  			(unsigned)from, (unsigned)(from + len),  			status); @@ -314,7 +325,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,  	int			status = -EINVAL;  	uint8_t			*command; -	DEBUG(MTD_DEBUG_LEVEL2, "%s: write 0x%x..0x%x\n", +	pr_debug("%s: write 0x%x..0x%x\n",  		dev_name(&spi->dev), (unsigned)to, (unsigned)(to + len));  	*retlen = 0; @@ -340,7 +351,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,  	mutex_lock(&priv->lock);  	while (remaining > 0) { -		DEBUG(MTD_DEBUG_LEVEL3, "write @ %i:%i len=%i\n", +		pr_debug("write @ %i:%i len=%i\n",  			pageaddr, offset, writelen);  		/* REVISIT: @@ -368,12 +379,12 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,  			command[2] = (addr & 0x0000FF00) >> 8;  			command[3] = 0; -			DEBUG(MTD_DEBUG_LEVEL3, "TRANSFER: (%x) %x %x %x\n", +			pr_debug("TRANSFER: (%x) %x %x %x\n",  				command[0], command[1], command[2], command[3]);  			status = spi_sync(spi, &msg);  			if (status < 0) -				DEBUG(MTD_DEBUG_LEVEL1, "%s: xfer %u -> %d \n", +				pr_debug("%s: xfer %u -> %d\n",  					dev_name(&spi->dev), addr, status);  			(void) dataflash_waitready(priv->spi); @@ -386,7 +397,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,  		command[2] = (addr & 0x0000FF00) >> 8;  		command[3] = (addr & 0x000000FF); -		DEBUG(MTD_DEBUG_LEVEL3, "PROGRAM: (%x) %x %x %x\n", +		pr_debug("PROGRAM: (%x) %x %x %x\n",  			command[0], command[1], command[2], command[3]);  		x[1].tx_buf = writebuf; @@ -395,7 +406,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,  		status = spi_sync(spi, &msg);  		spi_transfer_del(x + 1);  		if (status < 0) -			DEBUG(MTD_DEBUG_LEVEL1, "%s: pgm %u/%u -> %d \n", +			pr_debug("%s: pgm %u/%u -> %d\n",  				dev_name(&spi->dev), addr, writelen, status);  		(void) dataflash_waitready(priv->spi); @@ -410,12 +421,12 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,  		command[2] = (addr & 0x0000FF00) >> 8;  		command[3] = 0; -		DEBUG(MTD_DEBUG_LEVEL3, "COMPARE: (%x) %x %x %x\n", +		pr_debug("COMPARE: (%x) %x %x %x\n",  			command[0], command[1], command[2], command[3]);  		status = spi_sync(spi, &msg);  		if (status < 0) -			DEBUG(MTD_DEBUG_LEVEL1, "%s: compare %u -> %d \n", +			pr_debug("%s: compare %u -> %d\n",  				dev_name(&spi->dev), addr, status);  		status = dataflash_waitready(priv->spi); @@ -634,11 +645,10 @@ add_dataflash_otp(struct spi_device *spi, char *name,  {  	struct dataflash		*priv;  	struct mtd_info			*device; +	struct mtd_part_parser_data	ppdata;  	struct flash_platform_data	*pdata = spi->dev.platform_data;  	char				*otp_tag = "";  	int				err = 0; -	struct mtd_partition		*parts; -	int				nr_parts = 0;  	priv = kzalloc(sizeof *priv, GFP_KERNEL);  	if (!priv) @@ -677,28 +687,11 @@ add_dataflash_otp(struct spi_device *spi, char *name,  			pagesize, otp_tag);  	dev_set_drvdata(&spi->dev, priv); -	if (mtd_has_cmdlinepart()) { -		static const char *part_probes[] = { "cmdlinepart", NULL, }; - -		nr_parts = parse_mtd_partitions(device, part_probes, &parts, -						0); -	} +	ppdata.of_node = spi->dev.of_node; +	err = mtd_device_parse_register(device, NULL, &ppdata, +			pdata ? pdata->parts : NULL, +			pdata ? pdata->nr_parts : 0); -	if (nr_parts <= 0 && pdata && pdata->parts) { -		parts = pdata->parts; -		nr_parts = pdata->nr_parts; -	} - -	if (nr_parts > 0) { -		priv->partitioned = 1; -		err = mtd_device_register(device, parts, nr_parts); -		goto out; -	} - -	if (mtd_device_register(device, NULL, 0) == 1) -		err = -ENODEV; - -out:  	if (!err)  		return 0; @@ -787,7 +780,7 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi)  	 */  	tmp = spi_write_then_read(spi, &code, 1, id, 3);  	if (tmp < 0) { -		DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n", +		pr_debug("%s: error %d reading JEDEC ID\n",  			dev_name(&spi->dev), tmp);  		return ERR_PTR(tmp);  	} @@ -804,7 +797,7 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi)  			tmp < ARRAY_SIZE(dataflash_data);  			tmp++, info++) {  		if (info->jedec_id == jedec) { -			DEBUG(MTD_DEBUG_LEVEL1, "%s: OTP, sector protect%s\n", +			pr_debug("%s: OTP, sector protect%s\n",  				dev_name(&spi->dev),  				(info->flags & SUP_POW2PS)  					? ", binary pagesize" : "" @@ -812,8 +805,7 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi)  			if (info->flags & SUP_POW2PS) {  				status = dataflash_status(spi);  				if (status < 0) { -					DEBUG(MTD_DEBUG_LEVEL1, -						"%s: status error %d\n", +					pr_debug("%s: status error %d\n",  						dev_name(&spi->dev), status);  					return ERR_PTR(status);  				} @@ -878,7 +870,7 @@ static int __devinit dataflash_probe(struct spi_device *spi)  	 */  	status = dataflash_status(spi);  	if (status <= 0 || status == 0xff) { -		DEBUG(MTD_DEBUG_LEVEL1, "%s: status error %d\n", +		pr_debug("%s: status error %d\n",  				dev_name(&spi->dev), status);  		if (status == 0 || status == 0xff)  			status = -ENODEV; @@ -914,14 +906,14 @@ static int __devinit dataflash_probe(struct spi_device *spi)  		break;  	/* obsolete AT45DB1282 not (yet?) supported */  	default: -		DEBUG(MTD_DEBUG_LEVEL1, "%s: unsupported device (%x)\n", -				dev_name(&spi->dev), status & 0x3c); +		pr_debug("%s: unsupported device (%x)\n", dev_name(&spi->dev), +				status & 0x3c);  		status = -ENODEV;  	}  	if (status < 0) -		DEBUG(MTD_DEBUG_LEVEL1, "%s: add_dataflash --> %d\n", -				dev_name(&spi->dev), status); +		pr_debug("%s: add_dataflash --> %d\n", dev_name(&spi->dev), +				status);  	return status;  } @@ -931,7 +923,7 @@ static int __devexit dataflash_remove(struct spi_device *spi)  	struct dataflash	*flash = dev_get_drvdata(&spi->dev);  	int			status; -	DEBUG(MTD_DEBUG_LEVEL1, "%s: remove\n", dev_name(&spi->dev)); +	pr_debug("%s: remove\n", dev_name(&spi->dev));  	status = mtd_device_unregister(&flash->mtd);  	if (status == 0) { @@ -946,6 +938,7 @@ static struct spi_driver dataflash_driver = {  		.name		= "mtd_dataflash",  		.bus		= &spi_bus_type,  		.owner		= THIS_MODULE, +		.of_match_table = dataflash_dt_ids,  	},  	.probe		= dataflash_probe, diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c index 83e80c65d6e7..d38ef3bffe8d 100644 --- a/drivers/mtd/devices/sst25l.c +++ b/drivers/mtd/devices/sst25l.c @@ -52,8 +52,6 @@ struct sst25l_flash {  	struct spi_device	*spi;  	struct mutex		lock;  	struct mtd_info		mtd; - -	int 			partitioned;  };  struct flash_info { @@ -381,8 +379,6 @@ static int __devinit sst25l_probe(struct spi_device *spi)  	struct sst25l_flash *flash;  	struct flash_platform_data *data;  	int ret, i; -	struct mtd_partition *parts = NULL; -	int nr_parts = 0;  	flash_info = sst25l_match_device(spi);  	if (!flash_info) @@ -414,8 +410,7 @@ static int __devinit sst25l_probe(struct spi_device *spi)  	dev_info(&spi->dev, "%s (%lld KiB)\n", flash_info->name,  		 (long long)flash->mtd.size >> 10); -	DEBUG(MTD_DEBUG_LEVEL2, -	      "mtd .name = %s, .size = 0x%llx (%lldMiB) " +	pr_debug("mtd .name = %s, .size = 0x%llx (%lldMiB) "  	      ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",  	      flash->mtd.name,  	      (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20), @@ -423,37 +418,10 @@ static int __devinit sst25l_probe(struct spi_device *spi)  	      flash->mtd.numeraseregions); -	if (mtd_has_cmdlinepart()) { -		static const char *part_probes[] = {"cmdlinepart", NULL}; - -		nr_parts = parse_mtd_partitions(&flash->mtd, -						part_probes, -						&parts, 0); -	} - -	if (nr_parts <= 0 && data && data->parts) { -		parts = data->parts; -		nr_parts = data->nr_parts; -	} - -	if (nr_parts > 0) { -		for (i = 0; i < nr_parts; i++) { -			DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = " -			      "{.name = %s, .offset = 0x%llx, " -			      ".size = 0x%llx (%lldKiB) }\n", -			      i, parts[i].name, -			      (long long)parts[i].offset, -			      (long long)parts[i].size, -			      (long long)(parts[i].size >> 10)); -		} - -		flash->partitioned = 1; -		return mtd_device_register(&flash->mtd, parts, -					   nr_parts); -	} - -	ret = mtd_device_register(&flash->mtd, NULL, 0); -	if (ret == 1) { +	ret = mtd_device_parse_register(&flash->mtd, NULL, 0, +			data ? data->parts : NULL, +			data ? data->nr_parts : 0); +	if (ret) {  		kfree(flash);  		dev_set_drvdata(&spi->dev, NULL);  		return -ENODEV; diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 037b399df3f1..c7382bb686c6 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -339,7 +339,7 @@ static int erase_xfer(partition_t *part,      struct erase_info *erase;      xfer = &part->XferInfo[xfernum]; -    DEBUG(1, "ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset); +    pr_debug("ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset);      xfer->state = XFER_ERASING;      /* Is there a free erase slot? Always in MTD. */ @@ -415,7 +415,7 @@ static int prepare_xfer(partition_t *part, int i)      xfer = &part->XferInfo[i];      xfer->state = XFER_FAILED; -    DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset); +    pr_debug("ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);      /* Write the transfer unit header */      header = part->header; @@ -476,7 +476,7 @@ static int copy_erase_unit(partition_t *part, uint16_t srcunit,      eun = &part->EUNInfo[srcunit];      xfer = &part->XferInfo[xferunit]; -    DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n", +    pr_debug("ftl_cs: copying block 0x%x to 0x%x\n",  	  eun->Offset, xfer->Offset); @@ -598,7 +598,7 @@ static int copy_erase_unit(partition_t *part, uint16_t srcunit,      unit with the fewest erases, and usually pick the data unit with      the most deleted blocks.  But with a small probability, pick the      oldest data unit instead.  This means that we generally postpone -    the next reclaimation as long as possible, but shuffle static +    the next reclamation as long as possible, but shuffle static      stuff around a bit for wear leveling.  ======================================================================*/ @@ -609,8 +609,8 @@ static int reclaim_block(partition_t *part)      uint32_t best;      int queued, ret; -    DEBUG(0, "ftl_cs: reclaiming space...\n"); -    DEBUG(3, "NumTransferUnits == %x\n", part->header.NumTransferUnits); +    pr_debug("ftl_cs: reclaiming space...\n"); +    pr_debug("NumTransferUnits == %x\n", part->header.NumTransferUnits);      /* Pick the least erased transfer unit */      best = 0xffffffff; xfer = 0xffff;      do { @@ -618,22 +618,22 @@ static int reclaim_block(partition_t *part)  	for (i = 0; i < part->header.NumTransferUnits; i++) {  	    int n=0;  	    if (part->XferInfo[i].state == XFER_UNKNOWN) { -		DEBUG(3,"XferInfo[%d].state == XFER_UNKNOWN\n",i); +		pr_debug("XferInfo[%d].state == XFER_UNKNOWN\n",i);  		n=1;  		erase_xfer(part, i);  	    }  	    if (part->XferInfo[i].state == XFER_ERASING) { -		DEBUG(3,"XferInfo[%d].state == XFER_ERASING\n",i); +		pr_debug("XferInfo[%d].state == XFER_ERASING\n",i);  		n=1;  		queued = 1;  	    }  	    else if (part->XferInfo[i].state == XFER_ERASED) { -		DEBUG(3,"XferInfo[%d].state == XFER_ERASED\n",i); +		pr_debug("XferInfo[%d].state == XFER_ERASED\n",i);  		n=1;  		prepare_xfer(part, i);  	    }  	    if (part->XferInfo[i].state == XFER_PREPARED) { -		DEBUG(3,"XferInfo[%d].state == XFER_PREPARED\n",i); +		pr_debug("XferInfo[%d].state == XFER_PREPARED\n",i);  		n=1;  		if (part->XferInfo[i].EraseCount <= best) {  		    best = part->XferInfo[i].EraseCount; @@ -641,12 +641,12 @@ static int reclaim_block(partition_t *part)  		}  	    }  		if (!n) -		    DEBUG(3,"XferInfo[%d].state == %x\n",i, part->XferInfo[i].state); +		    pr_debug("XferInfo[%d].state == %x\n",i, part->XferInfo[i].state);  	}  	if (xfer == 0xffff) {  	    if (queued) { -		DEBUG(1, "ftl_cs: waiting for transfer " +		pr_debug("ftl_cs: waiting for transfer "  		      "unit to be prepared...\n");  		if (part->mbd.mtd->sync)  			part->mbd.mtd->sync(part->mbd.mtd); @@ -656,7 +656,7 @@ static int reclaim_block(partition_t *part)  		    printk(KERN_NOTICE "ftl_cs: reclaim failed: no "  			   "suitable transfer units!\n");  		else -		    DEBUG(1, "ftl_cs: reclaim failed: no " +		    pr_debug("ftl_cs: reclaim failed: no "  			  "suitable transfer units!\n");  		return -EIO; @@ -666,7 +666,7 @@ static int reclaim_block(partition_t *part)      eun = 0;      if ((jiffies % shuffle_freq) == 0) { -	DEBUG(1, "ftl_cs: recycling freshest block...\n"); +	pr_debug("ftl_cs: recycling freshest block...\n");  	best = 0xffffffff;  	for (i = 0; i < part->DataUnits; i++)  	    if (part->EUNInfo[i].EraseCount <= best) { @@ -686,7 +686,7 @@ static int reclaim_block(partition_t *part)  		printk(KERN_NOTICE "ftl_cs: reclaim failed: "  		       "no free blocks!\n");  	    else -		DEBUG(1,"ftl_cs: reclaim failed: " +		pr_debug("ftl_cs: reclaim failed: "  		       "no free blocks!\n");  	    return -EIO; @@ -771,7 +771,7 @@ static uint32_t find_free(partition_t *part)  	printk(KERN_NOTICE "ftl_cs: bad free list!\n");  	return 0;      } -    DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun); +    pr_debug("ftl_cs: found free block at %d in %d\n", blk, eun);      return blk;  } /* find_free */ @@ -791,7 +791,7 @@ static int ftl_read(partition_t *part, caddr_t buffer,      int ret;      size_t offset, retlen; -    DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n", +    pr_debug("ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",  	  part, sector, nblocks);      if (!(part->state & FTL_FORMATTED)) {  	printk(KERN_NOTICE "ftl_cs: bad partition\n"); @@ -840,7 +840,7 @@ static int set_bam_entry(partition_t *part, uint32_t log_addr,      int ret;      size_t retlen, offset; -    DEBUG(2, "ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n", +    pr_debug("ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",  	  part, log_addr, virt_addr);      bsize = 1 << part->header.EraseUnitSize;      eun = log_addr / bsize; @@ -905,7 +905,7 @@ static int ftl_write(partition_t *part, caddr_t buffer,      int ret;      size_t retlen, offset; -    DEBUG(2, "ftl_cs: ftl_write(0x%p, %ld, %ld)\n", +    pr_debug("ftl_cs: ftl_write(0x%p, %ld, %ld)\n",  	  part, sector, nblocks);      if (!(part->state & FTL_FORMATTED)) {  	printk(KERN_NOTICE "ftl_cs: bad partition\n"); @@ -1011,7 +1011,7 @@ static int ftl_discardsect(struct mtd_blktrans_dev *dev,  	partition_t *part = (void *)dev;  	uint32_t bsize = 1 << part->header.EraseUnitSize; -	DEBUG(1, "FTL erase sector %ld for %d sectors\n", +	pr_debug("FTL erase sector %ld for %d sectors\n",  	      sector, nr_sects);  	while (nr_sects) { diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index d7592e67d048..dd034efd1875 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -63,14 +63,12 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)  		return;  	} -	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: add_mtd for %s\n", mtd->name); +	pr_debug("INFTL: add_mtd for %s\n", mtd->name);  	inftl = kzalloc(sizeof(*inftl), GFP_KERNEL); -	if (!inftl) { -		printk(KERN_WARNING "INFTL: Out of memory for data structures\n"); +	if (!inftl)  		return; -	}  	inftl->mbd.mtd = mtd;  	inftl->mbd.devnum = -1; @@ -133,7 +131,7 @@ static void inftl_remove_dev(struct mtd_blktrans_dev *dev)  {  	struct INFTLrecord *inftl = (void *)dev; -	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: remove_dev (i=%d)\n", dev->devnum); +	pr_debug("INFTL: remove_dev (i=%d)\n", dev->devnum);  	del_mtd_blktrans_dev(dev); @@ -154,7 +152,7 @@ int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,  	struct mtd_oob_ops ops;  	int res; -	ops.mode = MTD_OOB_PLACE; +	ops.mode = MTD_OPS_PLACE_OOB;  	ops.ooboffs = offs & (mtd->writesize - 1);  	ops.ooblen = len;  	ops.oobbuf = buf; @@ -174,7 +172,7 @@ int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,  	struct mtd_oob_ops ops;  	int res; -	ops.mode = MTD_OOB_PLACE; +	ops.mode = MTD_OPS_PLACE_OOB;  	ops.ooboffs = offs & (mtd->writesize - 1);  	ops.ooblen = len;  	ops.oobbuf = buf; @@ -194,7 +192,7 @@ static int inftl_write(struct mtd_info *mtd, loff_t offs, size_t len,  	struct mtd_oob_ops ops;  	int res; -	ops.mode = MTD_OOB_PLACE; +	ops.mode = MTD_OPS_PLACE_OOB;  	ops.ooboffs = offs;  	ops.ooblen = mtd->oobsize;  	ops.oobbuf = oob; @@ -215,16 +213,16 @@ static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate)  	u16 pot = inftl->LastFreeEUN;  	int silly = inftl->nb_blocks; -	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findfreeblock(inftl=%p," -		"desperate=%d)\n", inftl, desperate); +	pr_debug("INFTL: INFTL_findfreeblock(inftl=%p,desperate=%d)\n", +			inftl, desperate);  	/*  	 * Normally, we force a fold to happen before we run out of free  	 * blocks completely.  	 */  	if (!desperate && inftl->numfreeEUNs < 2) { -		DEBUG(MTD_DEBUG_LEVEL1, "INFTL: there are too few free " -			"EUNs (%d)\n", inftl->numfreeEUNs); +		pr_debug("INFTL: there are too few free EUNs (%d)\n", +				inftl->numfreeEUNs);  		return BLOCK_NIL;  	} @@ -259,8 +257,8 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned  	struct inftl_oob oob;  	size_t retlen; -	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d," -		"pending=%d)\n", inftl, thisVUC, pendingblock); +	pr_debug("INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d,pending=%d)\n", +			inftl, thisVUC, pendingblock);  	memset(BlockMap, 0xff, sizeof(BlockMap));  	memset(BlockDeleted, 0, sizeof(BlockDeleted)); @@ -323,8 +321,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned  	 * Chain, and the Erase Unit into which we are supposed to be copying.  	 * Go for it.  	 */ -	DEBUG(MTD_DEBUG_LEVEL1, "INFTL: folding chain %d into unit %d\n", -		thisVUC, targetEUN); +	pr_debug("INFTL: folding chain %d into unit %d\n", thisVUC, targetEUN);  	for (block = 0; block < inftl->EraseSize/SECTORSIZE ; block++) {  		unsigned char movebuf[SECTORSIZE]; @@ -349,14 +346,13 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned  		ret = mtd->read(mtd, (inftl->EraseSize * BlockMap[block]) +  				(block * SECTORSIZE), SECTORSIZE, &retlen,  				movebuf); -		if (ret < 0 && ret != -EUCLEAN) { +		if (ret < 0 && !mtd_is_bitflip(ret)) {  			ret = mtd->read(mtd,  					(inftl->EraseSize * BlockMap[block]) +  					(block * SECTORSIZE), SECTORSIZE,  					&retlen, movebuf);  			if (ret != -EIO) -				DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went " -				      "away on retry?\n"); +				pr_debug("INFTL: error went away on retry?\n");  		}  		memset(&oob, 0xff, sizeof(struct inftl_oob));  		oob.b.Status = oob.b.Status1 = SECTOR_USED; @@ -372,8 +368,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned  	 * is important, by doing oldest first if we crash/reboot then it  	 * it is relatively simple to clean up the mess).  	 */ -	DEBUG(MTD_DEBUG_LEVEL1, "INFTL: want to erase virtual chain %d\n", -		thisVUC); +	pr_debug("INFTL: want to erase virtual chain %d\n", thisVUC);  	for (;;) {  		/* Find oldest unit in chain. */ @@ -421,7 +416,7 @@ static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock)  	u16 ChainLength = 0, thislen;  	u16 chain, EUN; -	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_makefreeblock(inftl=%p," +	pr_debug("INFTL: INFTL_makefreeblock(inftl=%p,"  		"pending=%d)\n", inftl, pendingblock);  	for (chain = 0; chain < inftl->nb_blocks; chain++) { @@ -484,8 +479,8 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)  	size_t retlen;  	int silly, silly2 = 3; -	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findwriteunit(inftl=%p," -		"block=%d)\n", inftl, block); +	pr_debug("INFTL: INFTL_findwriteunit(inftl=%p,block=%d)\n", +			inftl, block);  	do {  		/* @@ -501,8 +496,8 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)  				       blockofs, 8, &retlen, (char *)&bci);  			status = bci.Status | bci.Status1; -			DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in " -				"EUN %d is %x\n", block , writeEUN, status); +			pr_debug("INFTL: status of block %d in EUN %d is %x\n", +					block , writeEUN, status);  			switch(status) {  			case SECTOR_FREE: @@ -555,9 +550,9 @@ hitused:  			 * Hopefully we free something, lets try again.  			 * This time we are desperate...  			 */ -			DEBUG(MTD_DEBUG_LEVEL1, "INFTL: using desperate==1 " -				"to find free EUN to accommodate write to " -				"VUC %d\n", thisVUC); +			pr_debug("INFTL: using desperate==1 to find free EUN " +					"to accommodate write to VUC %d\n", +					thisVUC);  			writeEUN = INFTL_findfreeblock(inftl, 1);  			if (writeEUN == BLOCK_NIL) {  				/* @@ -647,7 +642,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)  	struct inftl_bci bci;  	size_t retlen; -	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_trydeletechain(inftl=%p," +	pr_debug("INFTL: INFTL_trydeletechain(inftl=%p,"  		"thisVUC=%d)\n", inftl, thisVUC);  	memset(BlockUsed, 0, sizeof(BlockUsed)); @@ -711,7 +706,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)  	 * For each block in the chain free it and make it available  	 * for future use. Erase from the oldest unit first.  	 */ -	DEBUG(MTD_DEBUG_LEVEL1, "INFTL: deleting empty VUC %d\n", thisVUC); +	pr_debug("INFTL: deleting empty VUC %d\n", thisVUC);  	for (;;) {  		u16 *prevEUN = &inftl->VUtable[thisVUC]; @@ -719,7 +714,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)  		/* If the chain is all gone already, we're done */  		if (thisEUN == BLOCK_NIL) { -			DEBUG(MTD_DEBUG_LEVEL2, "INFTL: Empty VUC %d for deletion was already absent\n", thisEUN); +			pr_debug("INFTL: Empty VUC %d for deletion was already absent\n", thisEUN);  			return;  		} @@ -731,7 +726,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)  			thisEUN = *prevEUN;  		} -		DEBUG(MTD_DEBUG_LEVEL3, "Deleting EUN %d from VUC %d\n", +		pr_debug("Deleting EUN %d from VUC %d\n",  		      thisEUN, thisVUC);  		if (INFTL_formatblock(inftl, thisEUN) < 0) { @@ -767,7 +762,7 @@ static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block)  	size_t retlen;  	struct inftl_bci bci; -	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_deleteblock(inftl=%p," +	pr_debug("INFTL: INFTL_deleteblock(inftl=%p,"  		"block=%d)\n", inftl, block);  	while (thisEUN < inftl->nb_blocks) { @@ -826,7 +821,7 @@ static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,  	struct inftl_oob oob;  	char *p, *pend; -	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_writeblock(inftl=%p,block=%ld," +	pr_debug("INFTL: inftl_writeblock(inftl=%p,block=%ld,"  		"buffer=%p)\n", inftl, block, buffer);  	/* Is block all zero? */ @@ -876,7 +871,7 @@ static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,  	struct inftl_bci bci;  	size_t retlen; -	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=%p,block=%ld," +	pr_debug("INFTL: inftl_readblock(inftl=%p,block=%ld,"  		"buffer=%p)\n", inftl, block, buffer);  	while (thisEUN < inftl->nb_blocks) { @@ -922,7 +917,7 @@ foundit:  		int ret = mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer);  		/* Handle corrected bit flips gracefully */ -		if (ret < 0 && ret != -EUCLEAN) +		if (ret < 0 && !mtd_is_bitflip(ret))  			return -EIO;  	}  	return 0; diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index 104052e774b0..2ff601f816ce 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -53,7 +53,7 @@ static int find_boot_record(struct INFTLrecord *inftl)  	struct INFTLPartition *ip;  	size_t retlen; -	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: find_boot_record(inftl=%p)\n", inftl); +	pr_debug("INFTL: find_boot_record(inftl=%p)\n", inftl);          /*  	 * Assume logical EraseSize == physical erasesize for starting the @@ -139,24 +139,20 @@ static int find_boot_record(struct INFTLrecord *inftl)  		mh->FormatFlags = le32_to_cpu(mh->FormatFlags);  		mh->PercentUsed = le32_to_cpu(mh->PercentUsed); -#ifdef CONFIG_MTD_DEBUG_VERBOSE -		if (CONFIG_MTD_DEBUG_VERBOSE >= 2) { -			printk("INFTL: Media Header ->\n" -				"    bootRecordID          = %s\n" -				"    NoOfBootImageBlocks   = %d\n" -				"    NoOfBinaryPartitions  = %d\n" -				"    NoOfBDTLPartitions    = %d\n" -				"    BlockMultiplerBits    = %d\n" -				"    FormatFlgs            = %d\n" -				"    OsakVersion           = 0x%x\n" -				"    PercentUsed           = %d\n", -				mh->bootRecordID, mh->NoOfBootImageBlocks, -				mh->NoOfBinaryPartitions, -				mh->NoOfBDTLPartitions, -				mh->BlockMultiplierBits, mh->FormatFlags, -				mh->OsakVersion, mh->PercentUsed); -		} -#endif +		pr_debug("INFTL: Media Header ->\n" +			 "    bootRecordID          = %s\n" +			 "    NoOfBootImageBlocks   = %d\n" +			 "    NoOfBinaryPartitions  = %d\n" +			 "    NoOfBDTLPartitions    = %d\n" +			 "    BlockMultiplerBits    = %d\n" +			 "    FormatFlgs            = %d\n" +			 "    OsakVersion           = 0x%x\n" +			 "    PercentUsed           = %d\n", +			 mh->bootRecordID, mh->NoOfBootImageBlocks, +			 mh->NoOfBinaryPartitions, +			 mh->NoOfBDTLPartitions, +			 mh->BlockMultiplierBits, mh->FormatFlags, +			 mh->OsakVersion, mh->PercentUsed);  		if (mh->NoOfBDTLPartitions == 0) {  			printk(KERN_WARNING "INFTL: Media Header sanity check " @@ -200,19 +196,15 @@ static int find_boot_record(struct INFTLrecord *inftl)  			ip->spareUnits = le32_to_cpu(ip->spareUnits);  			ip->Reserved0 = le32_to_cpu(ip->Reserved0); -#ifdef CONFIG_MTD_DEBUG_VERBOSE -			if (CONFIG_MTD_DEBUG_VERBOSE >= 2) { -				printk("    PARTITION[%d] ->\n" -					"        virtualUnits    = %d\n" -					"        firstUnit       = %d\n" -					"        lastUnit        = %d\n" -					"        flags           = 0x%x\n" -					"        spareUnits      = %d\n", -					i, ip->virtualUnits, ip->firstUnit, -					ip->lastUnit, ip->flags, -					ip->spareUnits); -			} -#endif +			pr_debug("    PARTITION[%d] ->\n" +				 "        virtualUnits    = %d\n" +				 "        firstUnit       = %d\n" +				 "        lastUnit        = %d\n" +				 "        flags           = 0x%x\n" +				 "        spareUnits      = %d\n", +				 i, ip->virtualUnits, ip->firstUnit, +				 ip->lastUnit, ip->flags, +				 ip->spareUnits);  			if (ip->Reserved0 != ip->firstUnit) {  				struct erase_info *instr = &inftl->instr; @@ -375,7 +367,7 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,   *   * Return: 0 when succeed, -1 on error.   * - * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? + * ToDo: 1. Is it necessary to check_free_sector after erasing ??   */  int INFTL_formatblock(struct INFTLrecord *inftl, int block)  { @@ -385,8 +377,7 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block)  	struct mtd_info *mtd = inftl->mbd.mtd;  	int physblock; -	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=%p," -		"block=%d)\n", inftl, block); +	pr_debug("INFTL: INFTL_formatblock(inftl=%p,block=%d)\n", inftl, block);  	memset(instr, 0, sizeof(struct erase_info)); @@ -476,30 +467,30 @@ void INFTL_dumptables(struct INFTLrecord *s)  {  	int i; -	printk("-------------------------------------------" +	pr_debug("-------------------------------------------"  		"----------------------------------\n"); -	printk("VUtable[%d] ->", s->nb_blocks); +	pr_debug("VUtable[%d] ->", s->nb_blocks);  	for (i = 0; i < s->nb_blocks; i++) {  		if ((i % 8) == 0) -			printk("\n%04x: ", i); -		printk("%04x ", s->VUtable[i]); +			pr_debug("\n%04x: ", i); +		pr_debug("%04x ", s->VUtable[i]);  	} -	printk("\n-------------------------------------------" +	pr_debug("\n-------------------------------------------"  		"----------------------------------\n"); -	printk("PUtable[%d-%d=%d] ->", s->firstEUN, s->lastEUN, s->nb_blocks); +	pr_debug("PUtable[%d-%d=%d] ->", s->firstEUN, s->lastEUN, s->nb_blocks);  	for (i = 0; i <= s->lastEUN; i++) {  		if ((i % 8) == 0) -			printk("\n%04x: ", i); -		printk("%04x ", s->PUtable[i]); +			pr_debug("\n%04x: ", i); +		pr_debug("%04x ", s->PUtable[i]);  	} -	printk("\n-------------------------------------------" +	pr_debug("\n-------------------------------------------"  		"----------------------------------\n"); -	printk("INFTL ->\n" +	pr_debug("INFTL ->\n"  		"  EraseSize       = %d\n"  		"  h/s/c           = %d/%d/%d\n"  		"  numvunits       = %d\n" @@ -513,7 +504,7 @@ void INFTL_dumptables(struct INFTLrecord *s)  		s->numvunits, s->firstEUN, s->lastEUN, s->numfreeEUNs,  		s->LastFreeEUN, s->nb_blocks, s->nb_boot_blocks); -	printk("\n-------------------------------------------" +	pr_debug("\n-------------------------------------------"  		"----------------------------------\n");  } @@ -521,25 +512,25 @@ void INFTL_dumpVUchains(struct INFTLrecord *s)  {  	int logical, block, i; -	printk("-------------------------------------------" +	pr_debug("-------------------------------------------"  		"----------------------------------\n"); -	printk("INFTL Virtual Unit Chains:\n"); +	pr_debug("INFTL Virtual Unit Chains:\n");  	for (logical = 0; logical < s->nb_blocks; logical++) {  		block = s->VUtable[logical];  		if (block > s->nb_blocks)  			continue; -		printk("  LOGICAL %d --> %d ", logical, block); +		pr_debug("  LOGICAL %d --> %d ", logical, block);  		for (i = 0; i < s->nb_blocks; i++) {  			if (s->PUtable[block] == BLOCK_NIL)  				break;  			block = s->PUtable[block]; -			printk("%d ", block); +			pr_debug("%d ", block);  		} -		printk("\n"); +		pr_debug("\n");  	} -	printk("-------------------------------------------" +	pr_debug("-------------------------------------------"  		"----------------------------------\n");  } @@ -555,7 +546,7 @@ int INFTL_mount(struct INFTLrecord *s)  	int i;  	u8 *ANACtable, ANAC; -	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_mount(inftl=%p)\n", s); +	pr_debug("INFTL: INFTL_mount(inftl=%p)\n", s);  	/* Search for INFTL MediaHeader and Spare INFTL Media Header */  	if (find_boot_record(s) < 0) { @@ -585,7 +576,7 @@ int INFTL_mount(struct INFTLrecord *s)  	 * NOTEXPLORED state. Then at the end we will try to format it and  	 * mark it as free.  	 */ -	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 1, explore each unit\n"); +	pr_debug("INFTL: pass 1, explore each unit\n");  	for (first_block = s->firstEUN; first_block <= s->lastEUN; first_block++) {  		if (s->PUtable[first_block] != BLOCK_NOTEXPLORED)  			continue; @@ -717,17 +708,14 @@ int INFTL_mount(struct INFTLrecord *s)  		logical_block = BLOCK_NIL;  	} -#ifdef CONFIG_MTD_DEBUG_VERBOSE -	if (CONFIG_MTD_DEBUG_VERBOSE >= 2) -		INFTL_dumptables(s); -#endif +	INFTL_dumptables(s);  	/*  	 * Second pass, check for infinite loops in chains. These are  	 * possible because we don't update the previous pointers when  	 * we fold chains. No big deal, just fix them up in PUtable.  	 */ -	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 2, validate virtual chains\n"); +	pr_debug("INFTL: pass 2, validate virtual chains\n");  	for (logical_block = 0; logical_block < s->numvunits; logical_block++) {  		block = s->VUtable[logical_block];  		last_block = BLOCK_NIL; @@ -772,12 +760,8 @@ int INFTL_mount(struct INFTLrecord *s)  		}  	} -#ifdef CONFIG_MTD_DEBUG_VERBOSE -	if (CONFIG_MTD_DEBUG_VERBOSE >= 2) -		INFTL_dumptables(s); -	if (CONFIG_MTD_DEBUG_VERBOSE >= 2) -		INFTL_dumpVUchains(s); -#endif +	INFTL_dumptables(s); +	INFTL_dumpVUchains(s);  	/*  	 * Third pass, format unreferenced blocks and init free block count. @@ -785,7 +769,7 @@ int INFTL_mount(struct INFTLrecord *s)  	s->numfreeEUNs = 0;  	s->LastFreeEUN = BLOCK_NIL; -	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 3, format unused blocks\n"); +	pr_debug("INFTL: pass 3, format unused blocks\n");  	for (block = s->firstEUN; block <= s->lastEUN; block++) {  		if (s->PUtable[block] == BLOCK_NOTEXPLORED) {  			printk("INFTL: unreferenced block %d, formatting it\n", diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index c0c328c5b133..8e0c4bf9f7fb 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -41,8 +41,6 @@ config MTD_PHYSMAP_START  	  are mapped on your particular target board. Refer to the  	  memory map which should hopefully be in the documentation for  	  your board. -	  Ignore this option if you use run-time physmap configuration -	  (i.e., run-time calling physmap_configure()).  config MTD_PHYSMAP_LEN  	hex "Physical length of flash mapping" @@ -55,8 +53,6 @@ config MTD_PHYSMAP_LEN  	  than the total amount of flash present. Refer to the memory  	  map which should hopefully be in the documentation for your  	  board. -	  Ignore this option if you use run-time physmap configuration -	  (i.e., run-time calling physmap_configure()).  config MTD_PHYSMAP_BANKWIDTH  	int "Bank width in octets" @@ -67,8 +63,6 @@ config MTD_PHYSMAP_BANKWIDTH  	  in octets. For example, if you have a data bus width of 32  	  bits, you would set the bus width octet value to 4. This is  	  used internally by the CFI drivers. -	  Ignore this option if you use run-time physmap configuration -	  (i.e., run-time calling physmap_configure()).  config MTD_PHYSMAP_OF  	tristate "Flash device in physical memory map based on OF description" @@ -260,7 +254,6 @@ config MTD_BCM963XX  config MTD_LANTIQ  	tristate "Lantiq SoC NOR support"  	depends on LANTIQ -	select MTD_PARTITIONS  	help  	  Support for NOR flash attached to the Lantiq SoC's External Bus Unit. @@ -339,10 +332,6 @@ config MTD_SOLUTIONENGINE  	  This enables access to the flash chips on the Hitachi SolutionEngine and  	  similar boards. Say 'Y' if you are building a kernel for such a board. -config MTD_ARM_INTEGRATOR -	tristate "CFI Flash device mapped on ARM Integrator/P720T" -	depends on ARM && MTD_CFI -  config MTD_CDB89712  	tristate "Cirrus CDB89712 evaluation board mappings"  	depends on MTD_CFI && ARCH_CDB89712 @@ -398,13 +387,6 @@ config MTD_AUTCPU12  	  This enables access to the NV-RAM on autronix autcpu12 board.  	  If you have such a board, say 'Y'. -config MTD_EDB7312 -	tristate "CFI Flash device mapped on EDB7312" -	depends on ARCH_EDB7312 && MTD_CFI -	help -	  This enables access to the CFI Flash on the Cogent EDB7312 board. -	  If you have such a board, say 'Y' here. -  config MTD_IMPA7  	tristate "JEDEC Flash device mapped on impA7"  	depends on ARM && MTD_JEDECPROBE @@ -412,14 +394,6 @@ config MTD_IMPA7  	  This enables access to the NOR Flash on the impA7 board of  	  implementa GmbH. If you have such a board, say 'Y' here. -config MTD_CEIVA -	tristate "JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame" -	depends on MTD_JEDECPROBE && ARCH_CEIVA -	help -	  This enables access to the flash chips on the Ceiva/Polaroid -	  PhotoMax Digital Picture Frame. -	  If you have such a device, say 'Y'. -  config MTD_H720X  	tristate "Hynix evaluation board mappings"  	depends on MTD_CFI && ( ARCH_H7201 || ARCH_H7202 ) diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index cb48b11affff..45dcb8b14f22 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -19,7 +19,6 @@ obj-$(CONFIG_MTD_CK804XROM)	+= ck804xrom.o  obj-$(CONFIG_MTD_TSUNAMI)	+= tsunami_flash.o  obj-$(CONFIG_MTD_PXA2XX)	+= pxa2xx-flash.o  obj-$(CONFIG_MTD_MBX860)	+= mbx860.o -obj-$(CONFIG_MTD_CEIVA)		+= ceiva.o  obj-$(CONFIG_MTD_OCTAGON)	+= octagon-5066.o  obj-$(CONFIG_MTD_PHYSMAP)	+= physmap.o  obj-$(CONFIG_MTD_PHYSMAP_OF)	+= physmap_of.o @@ -40,7 +39,6 @@ obj-$(CONFIG_MTD_DBOX2)		+= dbox2-flash.o  obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o  obj-$(CONFIG_MTD_PCI)		+= pci.o  obj-$(CONFIG_MTD_AUTCPU12)	+= autcpu12-nvram.o -obj-$(CONFIG_MTD_EDB7312)	+= edb7312.o  obj-$(CONFIG_MTD_IMPA7)		+= impa7.o  obj-$(CONFIG_MTD_FORTUNET)	+= fortunet.o  obj-$(CONFIG_MTD_UCLINUX)	+= uclinux.o diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c index 67815eed2f00..6d6b2b5674ee 100644 --- a/drivers/mtd/maps/bfin-async-flash.c +++ b/drivers/mtd/maps/bfin-async-flash.c @@ -41,7 +41,6 @@ struct async_state {  	uint32_t flash_ambctl0, flash_ambctl1;  	uint32_t save_ambctl0, save_ambctl1;  	unsigned long irq_flags; -	struct mtd_partition *parts;  };  static void switch_to_flash(struct async_state *state) @@ -165,18 +164,8 @@ static int __devinit bfin_flash_probe(struct platform_device *pdev)  		return -ENXIO;  	} -	ret = parse_mtd_partitions(state->mtd, part_probe_types, &pdata->parts, 0); -	if (ret > 0) { -		pr_devinit(KERN_NOTICE DRIVER_NAME ": Using commandline partition definition\n"); -		mtd_device_register(state->mtd, pdata->parts, ret); -		state->parts = pdata->parts; -	} else if (pdata->nr_parts) { -		pr_devinit(KERN_NOTICE DRIVER_NAME ": Using board partition definition\n"); -		mtd_device_register(state->mtd, pdata->parts, pdata->nr_parts); -	} else { -		pr_devinit(KERN_NOTICE DRIVER_NAME ": no partition info available, registering whole flash at once\n"); -		mtd_device_register(state->mtd, NULL, 0); -	} +	mtd_device_parse_register(state->mtd, part_probe_types, 0, +			pdata->parts, pdata->nr_parts);  	platform_set_drvdata(pdev, state); @@ -188,7 +177,6 @@ static int __devexit bfin_flash_remove(struct platform_device *pdev)  	struct async_state *state = platform_get_drvdata(pdev);  	gpio_free(state->enet_flash_pin);  	mtd_device_unregister(state->mtd); -	kfree(state->parts);  	map_destroy(state->mtd);  	kfree(state);  	return 0; diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c deleted file mode 100644 index 06f9c9815720..000000000000 --- a/drivers/mtd/maps/ceiva.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Ceiva flash memory driver. - * Copyright (C) 2002 Rob Scott <rscott@mtrob.fdns.net> - * - * Note: this driver supports jedec compatible devices. Modification - * for CFI compatible devices should be straight forward: change - * jedec_probe to cfi_probe. - * - * Based on: sa1100-flash.c, which has the following copyright: - * Flash memory access on SA11x0 based devices - * - * (C) 2000 Nicolas Pitre <nico@fluxnic.net> - * - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/ioport.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/slab.h> - -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> -#include <linux/mtd/concat.h> - -#include <mach/hardware.h> -#include <asm/mach-types.h> -#include <asm/io.h> -#include <asm/sizes.h> - -/* - * This isn't complete yet, so... - */ -#define CONFIG_MTD_CEIVA_STATICMAP - -#ifdef CONFIG_MTD_CEIVA_STATICMAP -/* - * See include/linux/mtd/partitions.h for definition of the mtd_partition - * structure. - * - * Please note: - *  1. The flash size given should be the largest flash size that can - *     be accommodated. - * - *  2. The bus width must defined in clps_setup_flash. - * - * The MTD layer will detect flash chip aliasing and reduce the size of - * the map accordingly. - * - */ - -#ifdef CONFIG_ARCH_CEIVA -/* Flash / Partition sizing */ -/* For the 28F8003, we use the block mapping to calcuate the sizes */ -#define MAX_SIZE_KiB                  (16 + 8 + 8 + 96 + (7*128)) -#define BOOT_PARTITION_SIZE_KiB       (16) -#define PARAMS_PARTITION_SIZE_KiB     (8) -#define KERNEL_PARTITION_SIZE_KiB     (4*128) -/* Use both remaining portion of first flash, and all of second flash */ -#define ROOT_PARTITION_SIZE_KiB       (3*128) + (8*128) - -static struct mtd_partition ceiva_partitions[] = { -	{ -		.name = "Ceiva BOOT partition", -		.size   = BOOT_PARTITION_SIZE_KiB*1024, -		.offset = 0, - -	},{ -		.name = "Ceiva parameters partition", -		.size   = PARAMS_PARTITION_SIZE_KiB*1024, -		.offset = (16 + 8) * 1024, -	},{ -		.name = "Ceiva kernel partition", -		.size = (KERNEL_PARTITION_SIZE_KiB)*1024, -		.offset = 0x20000, - -	},{ -		.name = "Ceiva root filesystem partition", -		.offset = MTDPART_OFS_APPEND, -		.size = (ROOT_PARTITION_SIZE_KiB)*1024, -	} -}; -#endif - -static int __init clps_static_partitions(struct mtd_partition **parts) -{ -	int nb_parts = 0; - -#ifdef CONFIG_ARCH_CEIVA -	if (machine_is_ceiva()) { -		*parts       = ceiva_partitions; -		nb_parts     = ARRAY_SIZE(ceiva_partitions); -	} -#endif -	return nb_parts; -} -#endif - -struct clps_info { -	unsigned long base; -	unsigned long size; -	int width; -	void *vbase; -	struct map_info *map; -	struct mtd_info *mtd; -	struct resource *res; -}; - -#define NR_SUBMTD 4 - -static struct clps_info info[NR_SUBMTD]; - -static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info **rmtd) -{ -	struct mtd_info *subdev[nr]; -	struct map_info *maps; -	int i, found = 0, ret = 0; - -	/* -	 * Allocate the map_info structs in one go. -	 */ -	maps = kzalloc(sizeof(struct map_info) * nr, GFP_KERNEL); -	if (!maps) -		return -ENOMEM; -	/* -	 * Claim and then map the memory regions. -	 */ -	for (i = 0; i < nr; i++) { -		if (clps[i].base == (unsigned long)-1) -			break; - -		clps[i].res = request_mem_region(clps[i].base, clps[i].size, "clps flash"); -		if (!clps[i].res) { -			ret = -EBUSY; -			break; -		} - -		clps[i].map = maps + i; - -		clps[i].map->name = "clps flash"; -		clps[i].map->phys = clps[i].base; - -		clps[i].vbase = ioremap(clps[i].base, clps[i].size); -		if (!clps[i].vbase) { -			ret = -ENOMEM; -			break; -		} - -		clps[i].map->virt = (void __iomem *)clps[i].vbase; -		clps[i].map->bankwidth = clps[i].width; -		clps[i].map->size = clps[i].size; - -		simple_map_init(&clps[i].map); - -		clps[i].mtd = do_map_probe("jedec_probe", clps[i].map); -		if (clps[i].mtd == NULL) { -			ret = -ENXIO; -			break; -		} -		clps[i].mtd->owner = THIS_MODULE; -		subdev[i] = clps[i].mtd; - -		printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, " -			"%d-bit\n", clps[i].base, clps[i].mtd->size >> 20, -			clps[i].width * 8); -		found += 1; -	} - -	/* -	 * ENXIO is special.  It means we didn't find a chip when -	 * we probed.  We need to tear down the mapping, free the -	 * resource and mark it as such. -	 */ -	if (ret == -ENXIO) { -		iounmap(clps[i].vbase); -		clps[i].vbase = NULL; -		release_resource(clps[i].res); -		clps[i].res = NULL; -	} - -	/* -	 * If we found one device, don't bother with concat support. -	 * If we found multiple devices, use concat if we have it -	 * available, otherwise fail. -	 */ -	if (ret == 0 || ret == -ENXIO) { -		if (found == 1) { -			*rmtd = subdev[0]; -			ret = 0; -		} else if (found > 1) { -			/* -			 * We detected multiple devices.  Concatenate -			 * them together. -			 */ -			*rmtd = mtd_concat_create(subdev, found, -						  "clps flash"); -			if (*rmtd == NULL) -				ret = -ENXIO; -		} -	} - -	/* -	 * If we failed, clean up. -	 */ -	if (ret) { -		do { -			if (clps[i].mtd) -				map_destroy(clps[i].mtd); -			if (clps[i].vbase) -				iounmap(clps[i].vbase); -			if (clps[i].res) -				release_resource(clps[i].res); -		} while (i--); - -		kfree(maps); -	} - -	return ret; -} - -static void __exit clps_destroy_mtd(struct clps_info *clps, struct mtd_info *mtd) -{ -	int i; - -	mtd_device_unregister(mtd); - -	if (mtd != clps[0].mtd) -		mtd_concat_destroy(mtd); - -	for (i = NR_SUBMTD; i >= 0; i--) { -		if (clps[i].mtd) -			map_destroy(clps[i].mtd); -		if (clps[i].vbase) -			iounmap(clps[i].vbase); -		if (clps[i].res) -			release_resource(clps[i].res); -	} -	kfree(clps[0].map); -} - -/* - * We define the memory space, size, and width for the flash memory - * space here. - */ - -static int __init clps_setup_flash(void) -{ -	int nr = 0; - -#ifdef CONFIG_ARCH_CEIVA -	if (machine_is_ceiva()) { -		info[0].base = CS0_PHYS_BASE; -		info[0].size = SZ_32M; -		info[0].width = CEIVA_FLASH_WIDTH; -		info[1].base = CS1_PHYS_BASE; -		info[1].size = SZ_32M; -		info[1].width = CEIVA_FLASH_WIDTH; -		nr = 2; -	} -#endif -	return nr; -} - -static struct mtd_partition *parsed_parts; -static const char *probes[] = { "cmdlinepart", "RedBoot", NULL }; - -static void __init clps_locate_partitions(struct mtd_info *mtd) -{ -	const char *part_type = NULL; -	int nr_parts = 0; -	do { -		/* -		 * Partition selection stuff. -		 */ -		nr_parts = parse_mtd_partitions(mtd, probes, &parsed_parts, 0); -		if (nr_parts > 0) { -			part_type = "command line"; -			break; -		} -#ifdef CONFIG_MTD_CEIVA_STATICMAP -		nr_parts = clps_static_partitions(&parsed_parts); -		if (nr_parts > 0) { -			part_type = "static"; -			break; -		} -		printk("found: %d partitions\n", nr_parts); -#endif -	} while (0); - -	if (nr_parts == 0) { -		printk(KERN_NOTICE "clps flash: no partition info " -			"available, registering whole flash\n"); -		mtd_device_register(mtd, NULL, 0); -	} else { -		printk(KERN_NOTICE "clps flash: using %s partition " -			"definition\n", part_type); -		mtd_device_register(mtd, parsed_parts, nr_parts); -	} - -	/* Always succeeds. */ -} - -static void __exit clps_destroy_partitions(void) -{ -	kfree(parsed_parts); -} - -static struct mtd_info *mymtd; - -static int __init clps_mtd_init(void) -{ -	int ret; -	int nr; - -	nr = clps_setup_flash(); -	if (nr < 0) -		return nr; - -	ret = clps_setup_mtd(info, nr, &mymtd); -	if (ret) -		return ret; - -	clps_locate_partitions(mymtd); - -	return 0; -} - -static void __exit clps_mtd_cleanup(void) -{ -	clps_destroy_mtd(info, mymtd); -	clps_destroy_partitions(); -} - -module_init(clps_mtd_init); -module_exit(clps_mtd_cleanup); - -MODULE_AUTHOR("Rob Scott"); -MODULE_DESCRIPTION("Cirrus Logic JEDEC map driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c index 7a9e1989c977..f43b365b848c 100644 --- a/drivers/mtd/maps/dc21285.c +++ b/drivers/mtd/maps/dc21285.c @@ -145,14 +145,10 @@ static struct map_info dc21285_map = {  /* Partition stuff */ -static struct mtd_partition *dc21285_parts;  static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };  static int __init init_dc21285(void)  { - -	int nrparts; -  	/* Determine bankwidth */  	switch (*CSR_SA110_CNTL & (3<<14)) {  		case SA110_CNTL_ROMWIDTH_8: @@ -200,8 +196,7 @@ static int __init init_dc21285(void)  	dc21285_mtd->owner = THIS_MODULE; -	nrparts = parse_mtd_partitions(dc21285_mtd, probes, &dc21285_parts, 0); -	mtd_device_register(dc21285_mtd, dc21285_parts, nrparts); +	mtd_device_parse_register(dc21285_mtd, probes, 0, NULL, 0);  	if(machine_is_ebsa285()) {  		/* @@ -224,8 +219,6 @@ static int __init init_dc21285(void)  static void __exit cleanup_dc21285(void)  {  	mtd_device_unregister(dc21285_mtd); -	if (dc21285_parts) -		kfree(dc21285_parts);  	map_destroy(dc21285_mtd);  	iounmap(dc21285_map.virt);  } diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c deleted file mode 100644 index fe42a212bb3e..000000000000 --- a/drivers/mtd/maps/edb7312.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Handle mapping of the NOR flash on Cogent EDB7312 boards - * - * Copyright 2002 SYSGO Real-Time Solutions GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <asm/io.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> - -#define WINDOW_ADDR 0x00000000      /* physical properties of flash */ -#define WINDOW_SIZE 0x01000000 -#define BUSWIDTH    2 -#define FLASH_BLOCKSIZE_MAIN	0x20000 -#define FLASH_NUMBLOCKS_MAIN	128 -/* can be "cfi_probe", "jedec_probe", "map_rom", NULL }; */ -#define PROBETYPES { "cfi_probe", NULL } - -#define MSG_PREFIX "EDB7312-NOR:"   /* prefix for our printk()'s */ -#define MTDID      "edb7312-nor"    /* for mtdparts= partitioning */ - -static struct mtd_info *mymtd; - -struct map_info edb7312nor_map = { -	.name = "NOR flash on EDB7312", -	.size = WINDOW_SIZE, -	.bankwidth = BUSWIDTH, -	.phys = WINDOW_ADDR, -}; - -/* - * MTD partitioning stuff - */ -static struct mtd_partition static_partitions[3] = -{ -	{ -		.name = "ARMboot", -		.size = 0x40000, -		.offset = 0 -	}, -	{ -		.name = "Kernel", -		.size = 0x200000, -		.offset = 0x40000 -	}, -	{ -		.name = "RootFS", -		.size = 0xDC0000, -		.offset = 0x240000 -	}, -}; - -static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; - -static int                   mtd_parts_nb = 0; -static struct mtd_partition *mtd_parts    = 0; - -static int __init init_edb7312nor(void) -{ -	static const char *rom_probe_types[] = PROBETYPES; -	const char **type; -	const char *part_type = 0; - -       	printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", -	       WINDOW_SIZE, WINDOW_ADDR); -	edb7312nor_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); - -	if (!edb7312nor_map.virt) { -		printk(MSG_PREFIX "failed to ioremap\n"); -		return -EIO; -	} - -	simple_map_init(&edb7312nor_map); - -	mymtd = 0; -	type = rom_probe_types; -	for(; !mymtd && *type; type++) { -		mymtd = do_map_probe(*type, &edb7312nor_map); -	} -	if (mymtd) { -		mymtd->owner = THIS_MODULE; - -		mtd_parts_nb = parse_mtd_partitions(mymtd, probes, &mtd_parts, MTDID); -		if (mtd_parts_nb > 0) -			part_type = "detected"; - -		if (mtd_parts_nb == 0) { -			mtd_parts = static_partitions; -			mtd_parts_nb = ARRAY_SIZE(static_partitions); -			part_type = "static"; -		} - -		if (mtd_parts_nb == 0) -			printk(KERN_NOTICE MSG_PREFIX "no partition info available\n"); -		else -			printk(KERN_NOTICE MSG_PREFIX -			       "using %s partition definition\n", part_type); -		/* Register the whole device first. */ -		mtd_device_register(mymtd, NULL, 0); -		mtd_device_register(mymtd, mtd_parts, mtd_parts_nb); -		return 0; -	} - -	iounmap((void *)edb7312nor_map.virt); -	return -ENXIO; -} - -static void __exit cleanup_edb7312nor(void) -{ -	if (mymtd) { -		mtd_device_unregister(mymtd); -		map_destroy(mymtd); -	} -	if (edb7312nor_map.virt) { -		iounmap((void *)edb7312nor_map.virt); -		edb7312nor_map.virt = 0; -	} -} - -module_init(init_edb7312nor); -module_exit(cleanup_edb7312nor); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>"); -MODULE_DESCRIPTION("Generic configurable MTD map driver"); diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c index 7568c5f8b8ae..1ec66f031c51 100644 --- a/drivers/mtd/maps/gpio-addr-flash.c +++ b/drivers/mtd/maps/gpio-addr-flash.c @@ -187,7 +187,6 @@ static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };   */  static int __devinit gpio_flash_probe(struct platform_device *pdev)  { -	int nr_parts;  	size_t i, arr_size;  	struct physmap_flash_data *pdata;  	struct resource *memory; @@ -252,20 +251,9 @@ static int __devinit gpio_flash_probe(struct platform_device *pdev)  		return -ENXIO;  	} -	nr_parts = parse_mtd_partitions(state->mtd, part_probe_types, -					&pdata->parts, 0); -	if (nr_parts > 0) { -		pr_devinit(KERN_NOTICE PFX "Using commandline partition definition\n"); -		kfree(pdata->parts); -	} else if (pdata->nr_parts) { -		pr_devinit(KERN_NOTICE PFX "Using board partition definition\n"); -		nr_parts = pdata->nr_parts; -	} else { -		pr_devinit(KERN_NOTICE PFX "no partition info available, registering whole flash at once\n"); -		nr_parts = 0; -	} -	mtd_device_register(state->mtd, pdata->parts, nr_parts); +	mtd_device_parse_register(state->mtd, part_probe_types, 0, +			pdata->parts, pdata->nr_parts);  	return 0;  } diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c index 7f035860a36b..49c14187fc66 100644 --- a/drivers/mtd/maps/h720x-flash.c +++ b/drivers/mtd/maps/h720x-flash.c @@ -58,18 +58,11 @@ static struct mtd_partition h720x_partitions[] = {  #define NUM_PARTITIONS ARRAY_SIZE(h720x_partitions) -static int                   nr_mtd_parts; -static struct mtd_partition *mtd_parts; -static const char *probes[] = { "cmdlinepart", NULL }; -  /*   * Initialize FLASH support   */  static int __init h720x_mtd_init(void)  { - -	char	*part_type = NULL; -  	h720x_map.virt = ioremap(h720x_map.phys, h720x_map.size);  	if (!h720x_map.virt) { @@ -92,16 +85,8 @@ static int __init h720x_mtd_init(void)  	if (mymtd) {  		mymtd->owner = THIS_MODULE; -		nr_mtd_parts = parse_mtd_partitions(mymtd, probes, &mtd_parts, 0); -		if (nr_mtd_parts > 0) -			part_type = "command line"; -		if (nr_mtd_parts <= 0) { -			mtd_parts = h720x_partitions; -			nr_mtd_parts = NUM_PARTITIONS; -			part_type = "builtin"; -		} -		printk(KERN_INFO "Using %s partition table\n", part_type); -		mtd_device_register(mymtd, mtd_parts, nr_mtd_parts); +		mtd_device_parse_register(mymtd, NULL, 0, +				h720x_partitions, NUM_PARTITIONS);  		return 0;  	} @@ -120,10 +105,6 @@ static void __exit h720x_mtd_cleanup(void)  		map_destroy(mymtd);  	} -	/* Free partition info, if commandline partition was used */ -	if (mtd_parts && (mtd_parts != h720x_partitions)) -		kfree (mtd_parts); -  	if (h720x_map.virt) {  		iounmap((void *)h720x_map.virt);  		h720x_map.virt = 0; diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c index 404a50cbafa0..f47aedb24366 100644 --- a/drivers/mtd/maps/impa7.c +++ b/drivers/mtd/maps/impa7.c @@ -49,7 +49,7 @@ static struct map_info impa7_map[NUM_FLASHBANKS] = {  /*   * MTD partitioning stuff   */ -static struct mtd_partition static_partitions[] = +static struct mtd_partition partitions[] =  {  	{  		.name = "FileSystem", @@ -58,16 +58,10 @@ static struct mtd_partition static_partitions[] =  	},  }; -static int mtd_parts_nb[NUM_FLASHBANKS]; -static struct mtd_partition *mtd_parts[NUM_FLASHBANKS]; - -static const char *probes[] = { "cmdlinepart", NULL }; -  static int __init init_impa7(void)  {  	static const char *rom_probe_types[] = PROBETYPES;  	const char **type; -	const char *part_type = 0;  	int i;  	static struct { u_long addr; u_long size; } pt[NUM_FLASHBANKS] = {  	  { WINDOW_ADDR0, WINDOW_SIZE0 }, @@ -97,23 +91,9 @@ static int __init init_impa7(void)  		if (impa7_mtd[i]) {  			impa7_mtd[i]->owner = THIS_MODULE;  			devicesfound++; -			mtd_parts_nb[i] = parse_mtd_partitions(impa7_mtd[i], -							       probes, -							       &mtd_parts[i], -							       0); -			if (mtd_parts_nb[i] > 0) { -				part_type = "command line"; -			} else { -				mtd_parts[i] = static_partitions; -				mtd_parts_nb[i] = ARRAY_SIZE(static_partitions); -				part_type = "static"; -			} - -			printk(KERN_NOTICE MSG_PREFIX -			       "using %s partition definition\n", -			       part_type); -			mtd_device_register(impa7_mtd[i], -					    mtd_parts[i], mtd_parts_nb[i]); +			mtd_device_parse_register(impa7_mtd[i], NULL, 0, +						  partitions, +						  ARRAY_SIZE(partitions));  		}  		else  			iounmap((void *)impa7_map[i].virt); diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c index d2f47be8754b..08c239604ee4 100644 --- a/drivers/mtd/maps/intel_vr_nor.c +++ b/drivers/mtd/maps/intel_vr_nor.c @@ -44,7 +44,6 @@ struct vr_nor_mtd {  	void __iomem *csr_base;  	struct map_info map;  	struct mtd_info *info; -	int nr_parts;  	struct pci_dev *dev;  }; @@ -71,13 +70,9 @@ static void __devexit vr_nor_destroy_partitions(struct vr_nor_mtd *p)  static int __devinit vr_nor_init_partitions(struct vr_nor_mtd *p)  { -	struct mtd_partition *parts; -	static const char *part_probes[] = { "cmdlinepart", NULL }; -  	/* register the flash bank */  	/* partition the flash bank */ -	p->nr_parts = parse_mtd_partitions(p->info, part_probes, &parts, 0); -	return mtd_device_register(p->info, parts, p->nr_parts); +	return mtd_device_parse_register(p->info, NULL, 0, NULL, 0);  }  static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p) diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c index 1594a802631d..437fcd2f352f 100644 --- a/drivers/mtd/maps/ixp2000.c +++ b/drivers/mtd/maps/ixp2000.c @@ -38,7 +38,6 @@  struct ixp2000_flash_info {  	struct		mtd_info *mtd;  	struct		map_info map; -	struct		mtd_partition *partitions;  	struct		resource *res;  }; @@ -125,8 +124,6 @@ static int ixp2000_flash_remove(struct platform_device *dev)  	if (info->map.map_priv_1)  		iounmap((void *) info->map.map_priv_1); -	kfree(info->partitions); -  	if (info->res) {  		release_resource(info->res);  		kfree(info->res); @@ -229,13 +226,7 @@ static int ixp2000_flash_probe(struct platform_device *dev)  	}  	info->mtd->owner = THIS_MODULE; -	err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0); -	if (err > 0) { -		err = mtd_device_register(info->mtd, info->partitions, err); -		if(err) -			dev_err(&dev->dev, "Could not parse partitions\n"); -	} - +	err = mtd_device_parse_register(info->mtd, probes, 0, NULL, 0);  	if (err)  		goto Error; diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index 155b21942f47..30409015a3de 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c @@ -145,7 +145,6 @@ static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr)  struct ixp4xx_flash_info {  	struct mtd_info *mtd;  	struct map_info map; -	struct mtd_partition *partitions;  	struct resource *res;  }; @@ -168,8 +167,6 @@ static int ixp4xx_flash_remove(struct platform_device *dev)  	if (info->map.virt)  		iounmap(info->map.virt); -	kfree(info->partitions); -  	if (info->res) {  		release_resource(info->res);  		kfree(info->res); @@ -185,8 +182,6 @@ static int ixp4xx_flash_probe(struct platform_device *dev)  {  	struct flash_platform_data *plat = dev->dev.platform_data;  	struct ixp4xx_flash_info *info; -	const char *part_type = NULL; -	int nr_parts = 0;  	int err = -1;  	if (!plat) @@ -252,28 +247,12 @@ static int ixp4xx_flash_probe(struct platform_device *dev)  	/* Use the fast version */  	info->map.write = ixp4xx_write16; -	nr_parts = parse_mtd_partitions(info->mtd, probes, &info->partitions, -					dev->resource->start); -	if (nr_parts > 0) { -		part_type = "dynamic"; -	} else { -		info->partitions = plat->parts; -		nr_parts = plat->nr_parts; -		part_type = "static"; -	} -	if (nr_parts == 0) -		printk(KERN_NOTICE "IXP4xx flash: no partition info " -			"available, registering whole flash\n"); -	else -		printk(KERN_NOTICE "IXP4xx flash: using %s partition " -			"definition\n", part_type); - -	err = mtd_device_register(info->mtd, info->partitions, nr_parts); -	if (err) +	err = mtd_device_parse_register(info->mtd, probes, dev->resource->start, +			plat->parts, plat->nr_parts); +	if (err) {  		printk(KERN_ERR "Could not parse partitions\n"); - -	if (err)  		goto Error; +	}  	return 0; diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c index 7e508969239e..4f10e27ada55 100644 --- a/drivers/mtd/maps/lantiq-flash.c +++ b/drivers/mtd/maps/lantiq-flash.c @@ -107,16 +107,12 @@ ltq_copy_to(struct map_info *map, unsigned long to,  	spin_unlock_irqrestore(&ebu_lock, flags);  } -static const char const *part_probe_types[] = { "cmdlinepart", NULL }; -  static int __init  ltq_mtd_probe(struct platform_device *pdev)  {  	struct physmap_flash_data *ltq_mtd_data = dev_get_platdata(&pdev->dev);  	struct ltq_mtd *ltq_mtd; -	struct mtd_partition *parts;  	struct resource *res; -	int nr_parts = 0;  	struct cfi_private *cfi;  	int err; @@ -172,17 +168,8 @@ ltq_mtd_probe(struct platform_device *pdev)  	cfi->addr_unlock1 ^= 1;  	cfi->addr_unlock2 ^= 1; -	nr_parts = parse_mtd_partitions(ltq_mtd->mtd, -				part_probe_types, &parts, 0); -	if (nr_parts > 0) { -		dev_info(&pdev->dev, -			"using %d partitions from cmdline", nr_parts); -	} else { -		nr_parts = ltq_mtd_data->nr_parts; -		parts = ltq_mtd_data->parts; -	} - -	err = mtd_device_register(ltq_mtd->mtd, parts, nr_parts); +	err = mtd_device_parse_register(ltq_mtd->mtd, NULL, 0, +			ltq_mtd_data->parts, ltq_mtd_data->nr_parts);  	if (err) {  		dev_err(&pdev->dev, "failed to add partitions\n");  		goto err_destroy; diff --git a/drivers/mtd/maps/latch-addr-flash.c b/drivers/mtd/maps/latch-addr-flash.c index 5936c466e901..119baa7d7477 100644 --- a/drivers/mtd/maps/latch-addr-flash.c +++ b/drivers/mtd/maps/latch-addr-flash.c @@ -33,9 +33,6 @@ struct latch_addr_flash_info {  	/* cache; could be found out of res */  	unsigned long		win_mask; -	int			nr_parts; -	struct mtd_partition	*parts; -  	spinlock_t		lock;  }; @@ -97,8 +94,6 @@ static void lf_copy_from(struct map_info *map, void *to,  static char *rom_probe_types[] = { "cfi_probe", NULL }; -static char *part_probe_types[] = { "cmdlinepart", NULL }; -  static int latch_addr_flash_remove(struct platform_device *dev)  {  	struct latch_addr_flash_info *info; @@ -112,8 +107,6 @@ static int latch_addr_flash_remove(struct platform_device *dev)  	latch_addr_data = dev->dev.platform_data;  	if (info->mtd != NULL) { -		if (info->nr_parts) -			kfree(info->parts);  		mtd_device_unregister(info->mtd);  		map_destroy(info->mtd);  	} @@ -206,21 +199,8 @@ static int __devinit latch_addr_flash_probe(struct platform_device *dev)  	}  	info->mtd->owner = THIS_MODULE; -	err = parse_mtd_partitions(info->mtd, (const char **)part_probe_types, -				   &info->parts, 0); -	if (err > 0) { -		mtd_device_register(info->mtd, info->parts, err); -		return 0; -	} -	if (latch_addr_data->nr_parts) { -		pr_notice("Using latch-addr-flash partition information\n"); -		mtd_device_register(info->mtd, -				    latch_addr_data->parts, -				    latch_addr_data->nr_parts); -		return 0; -	} - -	mtd_device_register(info->mtd, NULL, 0); +	mtd_device_parse_register(info->mtd, NULL, 0, +			latch_addr_data->parts, latch_addr_data->nr_parts);  	return 0;  iounmap: diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index bbe168b65c26..e8e9fec23553 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -22,22 +22,6 @@  #include <linux/mtd/map.h>  #include <linux/mtd/mtd.h> -#ifdef CONFIG_MTD_DEBUG -static int debug = CONFIG_MTD_DEBUG_VERBOSE; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Set Debug Level 0=quiet, 5=noisy"); -#undef DEBUG -#define DEBUG(n, format, arg...) \ -	if (n <= debug) {	 \ -		printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __func__ , ## arg); \ -	} - -#else -#undef DEBUG -#define DEBUG(n, arg...) -static const int debug = 0; -#endif -  #define info(format, arg...) printk(KERN_INFO "pcmciamtd: " format "\n" , ## arg)  #define DRIVER_DESC	"PCMCIA Flash memory card driver" @@ -105,13 +89,13 @@ static caddr_t remap_window(struct map_info *map, unsigned long to)  	int ret;  	if (!pcmcia_dev_present(dev->p_dev)) { -		DEBUG(1, "device removed"); +		pr_debug("device removed\n");  		return 0;  	}  	offset = to & ~(dev->win_size-1);  	if (offset != dev->offset) { -		DEBUG(2, "Remapping window from 0x%8.8x to 0x%8.8x", +		pr_debug("Remapping window from 0x%8.8x to 0x%8.8x\n",  		      dev->offset, offset);  		ret = pcmcia_map_mem_page(dev->p_dev, win, offset);  		if (ret != 0) @@ -132,7 +116,7 @@ static map_word pcmcia_read8_remap(struct map_info *map, unsigned long ofs)  		return d;  	d.x[0] = readb(addr); -	DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02lx", ofs, addr, d.x[0]); +	pr_debug("ofs = 0x%08lx (%p) data = 0x%02lx\n", ofs, addr, d.x[0]);  	return d;  } @@ -147,7 +131,7 @@ static map_word pcmcia_read16_remap(struct map_info *map, unsigned long ofs)  		return d;  	d.x[0] = readw(addr); -	DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04lx", ofs, addr, d.x[0]); +	pr_debug("ofs = 0x%08lx (%p) data = 0x%04lx\n", ofs, addr, d.x[0]);  	return d;  } @@ -157,7 +141,7 @@ static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long  	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;  	unsigned long win_size = dev->win_size; -	DEBUG(3, "to = %p from = %lu len = %zd", to, from, len); +	pr_debug("to = %p from = %lu len = %zd\n", to, from, len);  	while(len) {  		int toread = win_size - (from & (win_size-1));  		caddr_t addr; @@ -169,7 +153,7 @@ static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long  		if(!addr)  			return; -		DEBUG(4, "memcpy from %p to %p len = %d", addr, to, toread); +		pr_debug("memcpy from %p to %p len = %d\n", addr, to, toread);  		memcpy_fromio(to, addr, toread);  		len -= toread;  		to += toread; @@ -185,7 +169,7 @@ static void pcmcia_write8_remap(struct map_info *map, map_word d, unsigned long  	if(!addr)  		return; -	DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%02lx", adr, addr, d.x[0]); +	pr_debug("adr = 0x%08lx (%p)  data = 0x%02lx\n", adr, addr, d.x[0]);  	writeb(d.x[0], addr);  } @@ -196,7 +180,7 @@ static void pcmcia_write16_remap(struct map_info *map, map_word d, unsigned long  	if(!addr)  		return; -	DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%04lx", adr, addr, d.x[0]); +	pr_debug("adr = 0x%08lx (%p)  data = 0x%04lx\n", adr, addr, d.x[0]);  	writew(d.x[0], addr);  } @@ -206,7 +190,7 @@ static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const v  	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;  	unsigned long win_size = dev->win_size; -	DEBUG(3, "to = %lu from = %p len = %zd", to, from, len); +	pr_debug("to = %lu from = %p len = %zd\n", to, from, len);  	while(len) {  		int towrite = win_size - (to & (win_size-1));  		caddr_t addr; @@ -218,7 +202,7 @@ static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const v  		if(!addr)  			return; -		DEBUG(4, "memcpy from %p to %p len = %d", from, addr, towrite); +		pr_debug("memcpy from %p to %p len = %d\n", from, addr, towrite);  		memcpy_toio(addr, from, towrite);  		len -= towrite;  		to += towrite; @@ -240,7 +224,7 @@ static map_word pcmcia_read8(struct map_info *map, unsigned long ofs)  		return d;  	d.x[0] = readb(win_base + ofs); -	DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02lx", +	pr_debug("ofs = 0x%08lx (%p) data = 0x%02lx\n",  	      ofs, win_base + ofs, d.x[0]);  	return d;  } @@ -255,7 +239,7 @@ static map_word pcmcia_read16(struct map_info *map, unsigned long ofs)  		return d;  	d.x[0] = readw(win_base + ofs); -	DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04lx", +	pr_debug("ofs = 0x%08lx (%p) data = 0x%04lx\n",  	      ofs, win_base + ofs, d.x[0]);  	return d;  } @@ -268,7 +252,7 @@ static void pcmcia_copy_from(struct map_info *map, void *to, unsigned long from,  	if(DEV_REMOVED(map))  		return; -	DEBUG(3, "to = %p from = %lu len = %zd", to, from, len); +	pr_debug("to = %p from = %lu len = %zd\n", to, from, len);  	memcpy_fromio(to, win_base + from, len);  } @@ -280,7 +264,7 @@ static void pcmcia_write8(struct map_info *map, map_word d, unsigned long adr)  	if(DEV_REMOVED(map))  		return; -	DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%02lx", +	pr_debug("adr = 0x%08lx (%p)  data = 0x%02lx\n",  	      adr, win_base + adr, d.x[0]);  	writeb(d.x[0], win_base + adr);  } @@ -293,7 +277,7 @@ static void pcmcia_write16(struct map_info *map, map_word d, unsigned long adr)  	if(DEV_REMOVED(map))  		return; -	DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%04lx", +	pr_debug("adr = 0x%08lx (%p)  data = 0x%04lx\n",  	      adr, win_base + adr, d.x[0]);  	writew(d.x[0], win_base + adr);  } @@ -306,7 +290,7 @@ static void pcmcia_copy_to(struct map_info *map, unsigned long to, const void *f  	if(DEV_REMOVED(map))  		return; -	DEBUG(3, "to = %lu from = %p len = %zd", to, from, len); +	pr_debug("to = %lu from = %p len = %zd\n", to, from, len);  	memcpy_toio(win_base + to, from, len);  } @@ -316,7 +300,7 @@ static void pcmciamtd_set_vpp(struct map_info *map, int on)  	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;  	struct pcmcia_device *link = dev->p_dev; -	DEBUG(2, "dev = %p on = %d vpp = %d\n", dev, on, dev->vpp); +	pr_debug("dev = %p on = %d vpp = %d\n\n", dev, on, dev->vpp);  	pcmcia_fixup_vpp(link, on ? dev->vpp : 0);  } @@ -325,7 +309,7 @@ static void pcmciamtd_release(struct pcmcia_device *link)  {  	struct pcmciamtd_dev *dev = link->priv; -	DEBUG(3, "link = 0x%p", link); +	pr_debug("link = 0x%p\n", link);  	if (link->resource[2]->end) {  		if(dev->win_base) { @@ -337,7 +321,6 @@ static void pcmciamtd_release(struct pcmcia_device *link)  } -#ifdef CONFIG_MTD_DEBUG  static int pcmciamtd_cistpl_format(struct pcmcia_device *p_dev,  				tuple_t *tuple,  				void *priv_data) @@ -347,7 +330,7 @@ static int pcmciamtd_cistpl_format(struct pcmcia_device *p_dev,  	if (!pcmcia_parse_tuple(tuple, &parse)) {  		cistpl_format_t *t = &parse.format;  		(void)t; /* Shut up, gcc */ -		DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u", +		pr_debug("Format type: %u, Error Detection: %u, offset = %u, length =%u\n",  			t->type, t->edc, t->offset, t->length);  	}  	return -ENOSPC; @@ -363,12 +346,11 @@ static int pcmciamtd_cistpl_jedec(struct pcmcia_device *p_dev,  	if (!pcmcia_parse_tuple(tuple, &parse)) {  		cistpl_jedec_t *t = &parse.jedec;  		for (i = 0; i < t->nid; i++) -			DEBUG(2, "JEDEC: 0x%02x 0x%02x", +			pr_debug("JEDEC: 0x%02x 0x%02x\n",  			      t->id[i].mfr, t->id[i].info);  	}  	return -ENOSPC;  } -#endif  static int pcmciamtd_cistpl_device(struct pcmcia_device *p_dev,  				tuple_t *tuple, @@ -382,14 +364,14 @@ static int pcmciamtd_cistpl_device(struct pcmcia_device *p_dev,  	if (pcmcia_parse_tuple(tuple, &parse))  		return -EINVAL; -	DEBUG(2, "Common memory:"); +	pr_debug("Common memory:\n");  	dev->pcmcia_map.size = t->dev[0].size;  	/* from here on: DEBUG only */  	for (i = 0; i < t->ndev; i++) { -		DEBUG(2, "Region %d, type = %u", i, t->dev[i].type); -		DEBUG(2, "Region %d, wp = %u", i, t->dev[i].wp); -		DEBUG(2, "Region %d, speed = %u ns", i, t->dev[i].speed); -		DEBUG(2, "Region %d, size = %u bytes", i, t->dev[i].size); +		pr_debug("Region %d, type = %u\n", i, t->dev[i].type); +		pr_debug("Region %d, wp = %u\n", i, t->dev[i].wp); +		pr_debug("Region %d, speed = %u ns\n", i, t->dev[i].speed); +		pr_debug("Region %d, size = %u bytes\n", i, t->dev[i].size);  	}  	return 0;  } @@ -409,12 +391,12 @@ static int pcmciamtd_cistpl_geo(struct pcmcia_device *p_dev,  	dev->pcmcia_map.bankwidth = t->geo[0].buswidth;  	/* from here on: DEBUG only */  	for (i = 0; i < t->ngeo; i++) { -		DEBUG(2, "region: %d bankwidth = %u", i, t->geo[i].buswidth); -		DEBUG(2, "region: %d erase_block = %u", i, t->geo[i].erase_block); -		DEBUG(2, "region: %d read_block = %u", i, t->geo[i].read_block); -		DEBUG(2, "region: %d write_block = %u", i, t->geo[i].write_block); -		DEBUG(2, "region: %d partition = %u", i, t->geo[i].partition); -		DEBUG(2, "region: %d interleave = %u", i, t->geo[i].interleave); +		pr_debug("region: %d bankwidth = %u\n", i, t->geo[i].buswidth); +		pr_debug("region: %d erase_block = %u\n", i, t->geo[i].erase_block); +		pr_debug("region: %d read_block = %u\n", i, t->geo[i].read_block); +		pr_debug("region: %d write_block = %u\n", i, t->geo[i].write_block); +		pr_debug("region: %d partition = %u\n", i, t->geo[i].partition); +		pr_debug("region: %d interleave = %u\n", i, t->geo[i].interleave);  	}  	return 0;  } @@ -432,13 +414,11 @@ static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *p_dev  			if (p_dev->prod_id[i])  				strcat(dev->mtd_name, p_dev->prod_id[i]);  		} -		DEBUG(2, "Found name: %s", dev->mtd_name); +		pr_debug("Found name: %s\n", dev->mtd_name);  	} -#ifdef CONFIG_MTD_DEBUG  	pcmcia_loop_tuple(p_dev, CISTPL_FORMAT, pcmciamtd_cistpl_format, NULL);  	pcmcia_loop_tuple(p_dev, CISTPL_JEDEC_C, pcmciamtd_cistpl_jedec, NULL); -#endif  	pcmcia_loop_tuple(p_dev, CISTPL_DEVICE, pcmciamtd_cistpl_device, dev);  	pcmcia_loop_tuple(p_dev, CISTPL_DEVICE_GEO, pcmciamtd_cistpl_geo, dev); @@ -450,12 +430,12 @@ static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *p_dev  	if(force_size) {  		dev->pcmcia_map.size = force_size << 20; -		DEBUG(2, "size forced to %dM", force_size); +		pr_debug("size forced to %dM\n", force_size);  	}  	if(bankwidth) {  		dev->pcmcia_map.bankwidth = bankwidth; -		DEBUG(2, "bankwidth forced to %d", bankwidth); +		pr_debug("bankwidth forced to %d\n", bankwidth);  	}  	dev->pcmcia_map.name = dev->mtd_name; @@ -464,7 +444,7 @@ static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *p_dev  		*new_name = 1;  	} -	DEBUG(1, "Device: Size: %lu Width:%d Name: %s", +	pr_debug("Device: Size: %lu Width:%d Name: %s\n",  	      dev->pcmcia_map.size,  	      dev->pcmcia_map.bankwidth << 3, dev->mtd_name);  } @@ -479,7 +459,7 @@ static int pcmciamtd_config(struct pcmcia_device *link)  	static char *probes[] = { "jedec_probe", "cfi_probe" };  	int new_name = 0; -	DEBUG(3, "link=0x%p", link); +	pr_debug("link=0x%p\n", link);  	card_settings(dev, link, &new_name); @@ -512,11 +492,11 @@ static int pcmciamtd_config(struct pcmcia_device *link)  	do {  		int ret; -		DEBUG(2, "requesting window with size = %luKiB memspeed = %d", +		pr_debug("requesting window with size = %luKiB memspeed = %d\n",  			(unsigned long) resource_size(link->resource[2]) >> 10,  			mem_speed);  		ret = pcmcia_request_window(link, link->resource[2], mem_speed); -		DEBUG(2, "ret = %d dev->win_size = %d", ret, dev->win_size); +		pr_debug("ret = %d dev->win_size = %d\n", ret, dev->win_size);  		if(ret) {  			j++;  			link->resource[2]->start = 0; @@ -524,21 +504,21 @@ static int pcmciamtd_config(struct pcmcia_device *link)  					force_size << 20 : MAX_PCMCIA_ADDR;  			link->resource[2]->end >>= j;  		} else { -			DEBUG(2, "Got window of size %luKiB", (unsigned long) +			pr_debug("Got window of size %luKiB\n", (unsigned long)  				resource_size(link->resource[2]) >> 10);  			dev->win_size = resource_size(link->resource[2]);  			break;  		}  	} while (link->resource[2]->end >= 0x1000); -	DEBUG(2, "dev->win_size = %d", dev->win_size); +	pr_debug("dev->win_size = %d\n", dev->win_size);  	if(!dev->win_size) {  		dev_err(&dev->p_dev->dev, "Cannot allocate memory window\n");  		pcmciamtd_release(link);  		return -ENODEV;  	} -	DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10); +	pr_debug("Allocated a window of %dKiB\n", dev->win_size >> 10);  	/* Get write protect status */  	dev->win_base = ioremap(link->resource[2]->start, @@ -549,7 +529,7 @@ static int pcmciamtd_config(struct pcmcia_device *link)  		pcmciamtd_release(link);  		return -ENODEV;  	} -	DEBUG(1, "mapped window dev = %p @ %pR, base = %p", +	pr_debug("mapped window dev = %p @ %pR, base = %p\n",  	      dev, link->resource[2], dev->win_base);  	dev->offset = 0; @@ -564,7 +544,7 @@ static int pcmciamtd_config(struct pcmcia_device *link)  	}  	link->config_index = 0; -	DEBUG(2, "Setting Configuration"); +	pr_debug("Setting Configuration\n");  	ret = pcmcia_enable_device(link);  	if (ret != 0) {  		if (dev->win_base) { @@ -580,17 +560,17 @@ static int pcmciamtd_config(struct pcmcia_device *link)  		mtd = do_map_probe("map_rom", &dev->pcmcia_map);  	} else {  		for(i = 0; i < ARRAY_SIZE(probes); i++) { -			DEBUG(1, "Trying %s", probes[i]); +			pr_debug("Trying %s\n", probes[i]);  			mtd = do_map_probe(probes[i], &dev->pcmcia_map);  			if(mtd)  				break; -			DEBUG(1, "FAILED: %s", probes[i]); +			pr_debug("FAILED: %s\n", probes[i]);  		}  	}  	if(!mtd) { -		DEBUG(1, "Can not find an MTD"); +		pr_debug("Can not find an MTD\n");  		pcmciamtd_release(link);  		return -ENODEV;  	} @@ -617,7 +597,7 @@ static int pcmciamtd_config(struct pcmcia_device *link)  	/* If the memory found is fits completely into the mapped PCMCIA window,  	   use the faster non-remapping read/write functions */  	if(mtd->size <= dev->win_size) { -		DEBUG(1, "Using non remapping memory functions"); +		pr_debug("Using non remapping memory functions\n");  		dev->pcmcia_map.map_priv_2 = (unsigned long)dev->win_base;  		if (dev->pcmcia_map.bankwidth == 1) {  			dev->pcmcia_map.read = pcmcia_read8; @@ -645,7 +625,7 @@ static int pcmciamtd_config(struct pcmcia_device *link)  static int pcmciamtd_suspend(struct pcmcia_device *dev)  { -	DEBUG(2, "EVENT_PM_RESUME"); +	pr_debug("EVENT_PM_RESUME\n");  	/* get_lock(link); */ @@ -654,7 +634,7 @@ static int pcmciamtd_suspend(struct pcmcia_device *dev)  static int pcmciamtd_resume(struct pcmcia_device *dev)  { -	DEBUG(2, "EVENT_PM_SUSPEND"); +	pr_debug("EVENT_PM_SUSPEND\n");  	/* free_lock(link); */ @@ -666,7 +646,7 @@ static void pcmciamtd_detach(struct pcmcia_device *link)  {  	struct pcmciamtd_dev *dev = link->priv; -	DEBUG(3, "link=0x%p", link); +	pr_debug("link=0x%p\n", link);  	if(dev->mtd_info) {  		mtd_device_unregister(dev->mtd_info); @@ -686,7 +666,7 @@ static int pcmciamtd_probe(struct pcmcia_device *link)  	/* Create new memory card device */  	dev = kzalloc(sizeof(*dev), GFP_KERNEL);  	if (!dev) return -ENOMEM; -	DEBUG(1, "dev=0x%p", dev); +	pr_debug("dev=0x%p\n", dev);  	dev->p_dev = link;  	link->priv = dev; @@ -755,7 +735,7 @@ static int __init init_pcmciamtd(void)  static void __exit exit_pcmciamtd(void)  { -	DEBUG(1, DRIVER_DESC " unloading"); +	pr_debug(DRIVER_DESC " unloading");  	pcmcia_unregister_driver(&pcmciamtd_driver);  } diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index f64cee4a3bfb..66e8200079c2 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c @@ -27,8 +27,6 @@ struct physmap_flash_info {  	struct mtd_info		*mtd[MAX_RESOURCES];  	struct mtd_info		*cmtd;  	struct map_info		map[MAX_RESOURCES]; -	int			nr_parts; -	struct mtd_partition	*parts;  };  static int physmap_flash_remove(struct platform_device *dev) @@ -46,8 +44,6 @@ static int physmap_flash_remove(struct platform_device *dev)  	if (info->cmtd) {  		mtd_device_unregister(info->cmtd); -		if (info->nr_parts) -			kfree(info->parts);  		if (info->cmtd != info->mtd[0])  			mtd_concat_destroy(info->cmtd);  	} @@ -175,23 +171,8 @@ static int physmap_flash_probe(struct platform_device *dev)  	if (err)  		goto err_out; -	err = parse_mtd_partitions(info->cmtd, part_probe_types, -				   &info->parts, 0); -	if (err > 0) { -		mtd_device_register(info->cmtd, info->parts, err); -		info->nr_parts = err; -		return 0; -	} - -	if (physmap_data->nr_parts) { -		printk(KERN_NOTICE "Using physmap partition information\n"); -		mtd_device_register(info->cmtd, physmap_data->parts, -				    physmap_data->nr_parts); -		return 0; -	} - -	mtd_device_register(info->cmtd, NULL, 0); - +	mtd_device_parse_register(info->cmtd, part_probe_types, 0, +				  physmap_data->parts, physmap_data->nr_parts);  	return 0;  err_out: @@ -245,21 +226,6 @@ static struct platform_device physmap_flash = {  	.num_resources	= 1,  	.resource	= &physmap_flash_resource,  }; - -void physmap_configure(unsigned long addr, unsigned long size, -		int bankwidth, void (*set_vpp)(struct map_info *, int)) -{ -	physmap_flash_resource.start = addr; -	physmap_flash_resource.end = addr + size - 1; -	physmap_flash_data.width = bankwidth; -	physmap_flash_data.set_vpp = set_vpp; -} - -void physmap_set_partitions(struct mtd_partition *parts, int num_parts) -{ -	physmap_flash_data.nr_parts = num_parts; -	physmap_flash_data.parts = parts; -}  #endif  static int __init physmap_init(void) diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index d251d1db129b..7d65f9d3e690 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -34,58 +34,10 @@ struct of_flash_list {  struct of_flash {  	struct mtd_info		*cmtd; -	struct mtd_partition	*parts;  	int list_size; /* number of elements in of_flash_list */  	struct of_flash_list	list[0];  }; -#define OF_FLASH_PARTS(info)	((info)->parts) -static int parse_obsolete_partitions(struct platform_device *dev, -				     struct of_flash *info, -				     struct device_node *dp) -{ -	int i, plen, nr_parts; -	const struct { -		__be32 offset, len; -	} *part; -	const char *names; - -	part = of_get_property(dp, "partitions", &plen); -	if (!part) -		return 0; /* No partitions found */ - -	dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n"); - -	nr_parts = plen / sizeof(part[0]); - -	info->parts = kzalloc(nr_parts * sizeof(*info->parts), GFP_KERNEL); -	if (!info->parts) -		return -ENOMEM; - -	names = of_get_property(dp, "partition-names", &plen); - -	for (i = 0; i < nr_parts; i++) { -		info->parts[i].offset = be32_to_cpu(part->offset); -		info->parts[i].size   = be32_to_cpu(part->len) & ~1; -		if (be32_to_cpu(part->len) & 1) /* bit 0 set signifies read only partition */ -			info->parts[i].mask_flags = MTD_WRITEABLE; - -		if (names && (plen > 0)) { -			int len = strlen(names) + 1; - -			info->parts[i].name = (char *)names; -			plen -= len; -			names += len; -		} else { -			info->parts[i].name = "unnamed"; -		} - -		part++; -	} - -	return nr_parts; -} -  static int of_flash_remove(struct platform_device *dev)  {  	struct of_flash *info; @@ -101,11 +53,8 @@ static int of_flash_remove(struct platform_device *dev)  		mtd_concat_destroy(info->cmtd);  	} -	if (info->cmtd) { -		if (OF_FLASH_PARTS(info)) -			kfree(OF_FLASH_PARTS(info)); +	if (info->cmtd)  		mtd_device_unregister(info->cmtd); -	}  	for (i = 0; i < info->list_size; i++) {  		if (info->list[i].mtd) @@ -165,7 +114,8 @@ static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev,     specifies the list of partition probers to use. If none is given then the     default is use. These take precedence over other device tree     information. */ -static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot", NULL }; +static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot", +					"ofpart", "ofoldpart", NULL };  static const char ** __devinit of_get_probes(struct device_node *dp)  {  	const char *cp; @@ -218,6 +168,7 @@ static int __devinit of_flash_probe(struct platform_device *dev)  	int reg_tuple_size;  	struct mtd_info **mtd_list = NULL;  	resource_size_t res_size; +	struct mtd_part_parser_data ppdata;  	match = of_match_device(of_flash_match, &dev->dev);  	if (!match) @@ -331,29 +282,12 @@ static int __devinit of_flash_probe(struct platform_device *dev)  	if (err)  		goto err_out; +	ppdata.of_node = dp;  	part_probe_types = of_get_probes(dp); -	err = parse_mtd_partitions(info->cmtd, part_probe_types, -				   &info->parts, 0); -	if (err < 0) { -		of_free_probes(part_probe_types); -		goto err_out; -	} +	mtd_device_parse_register(info->cmtd, part_probe_types, &ppdata, +			NULL, 0);  	of_free_probes(part_probe_types); -	if (err == 0) { -		err = of_mtd_parse_partitions(&dev->dev, dp, &info->parts); -		if (err < 0) -			goto err_out; -	} - -	if (err == 0) { -		err = parse_obsolete_partitions(dev, info, dp); -		if (err < 0) -			goto err_out; -	} - -	mtd_device_register(info->cmtd, info->parts, err); -  	kfree(mtd_list);  	return 0; diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 9ca1eccba4bc..94f553489725 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -44,8 +44,6 @@ struct platram_info {  	struct device		*dev;  	struct mtd_info		*mtd;  	struct map_info		 map; -	struct mtd_partition	*partitions; -	bool			free_partitions;  	struct resource		*area;  	struct platdata_mtd_ram	*pdata;  }; @@ -95,10 +93,6 @@ static int platram_remove(struct platform_device *pdev)  	if (info->mtd) {  		mtd_device_unregister(info->mtd); -		if (info->partitions) { -			if (info->free_partitions) -				kfree(info->partitions); -		}  		map_destroy(info->mtd);  	} @@ -228,21 +222,8 @@ static int platram_probe(struct platform_device *pdev)  	/* check to see if there are any available partitions, or wether  	 * to add this device whole */ -	if (!pdata->nr_partitions) { -		/* try to probe using the supplied probe type */ -		if (pdata->probes) { -			err = parse_mtd_partitions(info->mtd, pdata->probes, -					   &info->partitions, 0); -			info->free_partitions = 1; -			if (err > 0) -				err = mtd_device_register(info->mtd, -					info->partitions, err); -		} -	} -	/* use the static mapping */ -	else -		err = mtd_device_register(info->mtd, pdata->partitions, -					  pdata->nr_partitions); +	err = mtd_device_parse_register(info->mtd, pdata->probes, 0, +			pdata->partitions, pdata->nr_partitions);  	if (!err)  		dev_info(&pdev->dev, "registered mtd device\n"); diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index 7ae137d4b998..411a17df9fc1 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -41,8 +41,6 @@ static void pxa2xx_map_inval_cache(struct map_info *map, unsigned long from,  }  struct pxa2xx_flash_info { -	struct mtd_partition	*parts; -	int			nr_parts;  	struct mtd_info		*mtd;  	struct map_info		map;  }; @@ -55,9 +53,7 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev)  {  	struct flash_platform_data *flash = pdev->dev.platform_data;  	struct pxa2xx_flash_info *info; -	struct mtd_partition *parts;  	struct resource *res; -	int ret = 0;  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!res) @@ -71,8 +67,6 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev)  	info->map.bankwidth = flash->width;  	info->map.phys = res->start;  	info->map.size = resource_size(res); -	info->parts = flash->parts; -	info->nr_parts = flash->nr_parts;  	info->map.virt = ioremap(info->map.phys, info->map.size);  	if (!info->map.virt) { @@ -104,18 +98,7 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev)  	}  	info->mtd->owner = THIS_MODULE; -	ret = parse_mtd_partitions(info->mtd, probes, &parts, 0); - -	if (ret > 0) { -		info->nr_parts = ret; -		info->parts = parts; -	} - -	if (!info->nr_parts) -		printk("Registering %s as whole device\n", -		       info->map.name); - -	mtd_device_register(info->mtd, info->parts, info->nr_parts); +	mtd_device_parse_register(info->mtd, probes, 0, NULL, 0);  	platform_set_drvdata(pdev, info);  	return 0; @@ -133,7 +116,6 @@ static int __devexit pxa2xx_flash_remove(struct platform_device *dev)  	iounmap(info->map.virt);  	if (info->map.cached)  		iounmap(info->map.cached); -	kfree(info->parts);  	kfree(info);  	return 0;  } diff --git a/drivers/mtd/maps/rbtx4939-flash.c b/drivers/mtd/maps/rbtx4939-flash.c index 761fb459d2c7..0237f197fd12 100644 --- a/drivers/mtd/maps/rbtx4939-flash.c +++ b/drivers/mtd/maps/rbtx4939-flash.c @@ -25,8 +25,6 @@  struct rbtx4939_flash_info {  	struct mtd_info *mtd;  	struct map_info map; -	int nr_parts; -	struct mtd_partition *parts;  };  static int rbtx4939_flash_remove(struct platform_device *dev) @@ -41,8 +39,6 @@ static int rbtx4939_flash_remove(struct platform_device *dev)  	if (info->mtd) {  		struct rbtx4939_flash_data *pdata = dev->dev.platform_data; -		if (info->nr_parts) -			kfree(info->parts);  		mtd_device_unregister(info->mtd);  		map_destroy(info->mtd);  	} @@ -50,7 +46,6 @@ static int rbtx4939_flash_remove(struct platform_device *dev)  }  static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; -static const char *part_probe_types[] = { "cmdlinepart", NULL };  static int rbtx4939_flash_probe(struct platform_device *dev)  { @@ -107,22 +102,11 @@ static int rbtx4939_flash_probe(struct platform_device *dev)  	info->mtd->owner = THIS_MODULE;  	if (err)  		goto err_out; +	err = mtd_device_parse_register(info->mtd, NULL, 0, +			pdata->parts, pdata->nr_parts); -	err = parse_mtd_partitions(info->mtd, part_probe_types, -				&info->parts, 0); -	if (err > 0) { -		mtd_device_register(info->mtd, info->parts, err); -		info->nr_parts = err; -		return 0; -	} - -	if (pdata->nr_parts) { -		pr_notice("Using rbtx4939 partition information\n"); -		mtd_device_register(info->mtd, pdata->parts, pdata->nr_parts); -		return 0; -	} - -	mtd_device_register(info->mtd, NULL, 0); +	if (err) +		goto err_out;  	return 0;  err_out: diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index a9b5e0e5c4c5..fa9c0a9670cd 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -131,10 +131,8 @@ struct sa_subdev_info {  };  struct sa_info { -	struct mtd_partition	*parts;  	struct mtd_info		*mtd;  	int			num_subdev; -	unsigned int		nr_parts;  	struct sa_subdev_info	subdev[0];  }; @@ -231,8 +229,6 @@ static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *pla  			mtd_concat_destroy(info->mtd);  	} -	kfree(info->parts); -  	for (i = info->num_subdev - 1; i >= 0; i--)  		sa1100_destroy_subdev(&info->subdev[i]);  	kfree(info); @@ -341,10 +337,8 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };  static int __devinit sa1100_mtd_probe(struct platform_device *pdev)  {  	struct flash_platform_data *plat = pdev->dev.platform_data; -	struct mtd_partition *parts; -	const char *part_type = NULL;  	struct sa_info *info; -	int err, nr_parts = 0; +	int err;  	if (!plat)  		return -ENODEV; @@ -358,26 +352,8 @@ static int __devinit sa1100_mtd_probe(struct platform_device *pdev)  	/*  	 * Partition selection stuff.  	 */ -	nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0); -	if (nr_parts > 0) { -		info->parts = parts; -		part_type = "dynamic"; -	} else { -		parts = plat->parts; -		nr_parts = plat->nr_parts; -		part_type = "static"; -	} - -	if (nr_parts == 0) -		printk(KERN_NOTICE "SA1100 flash: no partition info " -			"available, registering whole flash\n"); -	else -		printk(KERN_NOTICE "SA1100 flash: using %s partition " -			"definition\n", part_type); - -	mtd_device_register(info->mtd, parts, nr_parts); - -	info->nr_parts = nr_parts; +	mtd_device_parse_register(info->mtd, part_probes, 0, +			plat->parts, plat->nr_parts);  	platform_set_drvdata(pdev, info);  	err = 0; diff --git a/drivers/mtd/maps/solutionengine.c b/drivers/mtd/maps/solutionengine.c index cbf6bade9354..496c40704aff 100644 --- a/drivers/mtd/maps/solutionengine.c +++ b/drivers/mtd/maps/solutionengine.c @@ -19,8 +19,6 @@  static struct mtd_info *flash_mtd;  static struct mtd_info *eprom_mtd; -static struct mtd_partition *parsed_parts; -  struct map_info soleng_eprom_map = {  	.name = "Solution Engine EPROM",  	.size = 0x400000, @@ -51,12 +49,14 @@ static struct mtd_partition superh_se_partitions[] = {  		.size = MTDPART_SIZ_FULL,  	}  }; +#define NUM_PARTITIONS ARRAY_SIZE(superh_se_partitions) +#else +#define superh_se_partitions NULL +#define NUM_PARTITIONS 0  #endif /* CONFIG_MTD_SUPERH_RESERVE */  static int __init init_soleng_maps(void)  { -	int nr_parts = 0; -  	/* First probe at offset 0 */  	soleng_flash_map.phys = 0;  	soleng_flash_map.virt = (void __iomem *)P2SEGADDR(0); @@ -92,21 +92,8 @@ static int __init init_soleng_maps(void)  		mtd_device_register(eprom_mtd, NULL, 0);  	} -	nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0); - -#ifdef CONFIG_MTD_SUPERH_RESERVE -	if (nr_parts <= 0) { -		printk(KERN_NOTICE "Using configured partition at 0x%08x.\n", -		       CONFIG_MTD_SUPERH_RESERVE); -		parsed_parts = superh_se_partitions; -		nr_parts = sizeof(superh_se_partitions)/sizeof(*parsed_parts); -	} -#endif /* CONFIG_MTD_SUPERH_RESERVE */ - -	if (nr_parts > 0) -		mtd_device_register(flash_mtd, parsed_parts, nr_parts); -	else -		mtd_device_register(flash_mtd, NULL, 0); +	mtd_device_parse_register(flash_mtd, probes, 0, +			superh_se_partitions, NUM_PARTITIONS);  	return 0;  } @@ -118,10 +105,7 @@ static void __exit cleanup_soleng_maps(void)  		map_destroy(eprom_mtd);  	} -	if (parsed_parts) -		mtd_device_unregister(flash_mtd); -	else -		mtd_device_unregister(flash_mtd); +	mtd_device_unregister(flash_mtd);  	map_destroy(flash_mtd);  } diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c index 901ce968efae..aa7e0cb2893c 100644 --- a/drivers/mtd/maps/wr_sbc82xx_flash.c +++ b/drivers/mtd/maps/wr_sbc82xx_flash.c @@ -20,7 +20,6 @@  #include <asm/immap_cpm2.h>  static struct mtd_info *sbcmtd[3]; -static struct mtd_partition *sbcmtd_parts[3];  struct map_info sbc82xx_flash_map[3] = {  	{.name = "Boot flash"}, @@ -101,6 +100,7 @@ static int __init init_sbc82xx_flash(void)  	for (i=0; i<3; i++) {  		int8_t flashcs[3] = { 0, 6, 1 };  		int nr_parts; +		struct mtd_partition *defparts;  		printk(KERN_NOTICE "PowerQUICC II %s (%ld MiB on CS%d",  		       sbc82xx_flash_map[i].name, @@ -113,7 +113,8 @@ static int __init init_sbc82xx_flash(void)  		}  		printk(" at %08lx)\n",  sbc82xx_flash_map[i].phys); -		sbc82xx_flash_map[i].virt = ioremap(sbc82xx_flash_map[i].phys, sbc82xx_flash_map[i].size); +		sbc82xx_flash_map[i].virt = ioremap(sbc82xx_flash_map[i].phys, +						    sbc82xx_flash_map[i].size);  		if (!sbc82xx_flash_map[i].virt) {  			printk("Failed to ioremap\n"); @@ -129,24 +130,20 @@ static int __init init_sbc82xx_flash(void)  		sbcmtd[i]->owner = THIS_MODULE; -		nr_parts = parse_mtd_partitions(sbcmtd[i], part_probes, -						&sbcmtd_parts[i], 0); -		if (nr_parts > 0) { -			mtd_device_register(sbcmtd[i], sbcmtd_parts[i], -					    nr_parts); -			continue; -		} -  		/* No partitioning detected. Use default */  		if (i == 2) { -			mtd_device_register(sbcmtd[i], NULL, 0); +			defparts = NULL; +			nr_parts = 0;  		} else if (i == bigflash) { -			mtd_device_register(sbcmtd[i], bigflash_parts, -					    ARRAY_SIZE(bigflash_parts)); +			defparts = bigflash_parts; +			nr_parts = ARRAY_SIZE(bigflash_parts);  		} else { -			mtd_device_register(sbcmtd[i], smallflash_parts, -					    ARRAY_SIZE(smallflash_parts)); +			defparts = smallflash_parts; +			nr_parts = ARRAY_SIZE(smallflash_parts);  		} + +		mtd_device_parse_register(sbcmtd[i], part_probes, 0, +					  defparts, nr_parts);  	}  	return 0;  } @@ -159,12 +156,8 @@ static void __exit cleanup_sbc82xx_flash(void)  		if (!sbcmtd[i])  			continue; -		if (i<2 || sbcmtd_parts[i]) -			mtd_device_unregister(sbcmtd[i]); -		else -			mtd_device_unregister(sbcmtd[i]); +		mtd_device_unregister(sbcmtd[i]); -		kfree(sbcmtd_parts[i]);  		map_destroy(sbcmtd[i]);  		iounmap((void *)sbc82xx_flash_map[i].virt); diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index ca385697446e..ed8b5e744b12 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -426,6 +426,8 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)  	new->rq->queuedata = new;  	blk_queue_logical_block_size(new->rq, tr->blksize); +	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, new->rq); +  	if (tr->discard) {  		queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, new->rq);  		new->rq->limits.max_discard_sectors = UINT_MAX; diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 3326615ad66b..7c1dc908a174 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -44,7 +44,7 @@ struct mtdblk_dev {  	enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;  }; -static struct mutex mtdblks_lock; +static DEFINE_MUTEX(mtdblks_lock);  /*   * Cache stuff... @@ -119,7 +119,7 @@ static int write_cached_data (struct mtdblk_dev *mtdblk)  	if (mtdblk->cache_state != STATE_DIRTY)  		return 0; -	DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for \"%s\" " +	pr_debug("mtdblock: writing cached data for \"%s\" "  			"at 0x%lx, size 0x%x\n", mtd->name,  			mtdblk->cache_offset, mtdblk->cache_size); @@ -148,7 +148,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,  	size_t retlen;  	int ret; -	DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n", +	pr_debug("mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n",  		mtd->name, pos, len);  	if (!sect_size) @@ -218,7 +218,7 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,  	size_t retlen;  	int ret; -	DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n", +	pr_debug("mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n",  			mtd->name, pos, len);  	if (!sect_size) @@ -283,7 +283,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)  {  	struct mtdblk_dev *mtdblk = container_of(mbd, struct mtdblk_dev, mbd); -	DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n"); +	pr_debug("mtdblock_open\n");  	mutex_lock(&mtdblks_lock);  	if (mtdblk->count) { @@ -303,7 +303,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)  	mutex_unlock(&mtdblks_lock); -	DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); +	pr_debug("ok\n");  	return 0;  } @@ -312,7 +312,7 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd)  {  	struct mtdblk_dev *mtdblk = container_of(mbd, struct mtdblk_dev, mbd); -   	DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n"); +	pr_debug("mtdblock_release\n");  	mutex_lock(&mtdblks_lock); @@ -329,7 +329,7 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd)  	mutex_unlock(&mtdblks_lock); -	DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); +	pr_debug("ok\n");  	return 0;  } @@ -389,8 +389,6 @@ static struct mtd_blktrans_ops mtdblock_tr = {  static int __init init_mtdblock(void)  { -	mutex_init(&mtdblks_lock); -  	return register_mtd_blktrans(&mtdblock_tr);  } diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 61086ea3cc6b..e7dc732ddabc 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -43,7 +43,7 @@ static struct vfsmount *mtd_inode_mnt __read_mostly;  /*   * Data structure to hold the pointer to the mtd device as well - * as mode information ofr various use cases. + * as mode information of various use cases.   */  struct mtd_file_info {  	struct mtd_info *mtd; @@ -86,7 +86,7 @@ static int mtd_open(struct inode *inode, struct file *file)  	struct mtd_file_info *mfi;  	struct inode *mtd_ino; -	DEBUG(MTD_DEBUG_LEVEL0, "MTD_open\n"); +	pr_debug("MTD_open\n");  	/* You can't open the RO devices RW */  	if ((file->f_mode & FMODE_WRITE) && (minor & 1)) @@ -151,7 +151,7 @@ static int mtd_close(struct inode *inode, struct file *file)  	struct mtd_file_info *mfi = file->private_data;  	struct mtd_info *mtd = mfi->mtd; -	DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); +	pr_debug("MTD_close\n");  	/* Only sync if opened RW */  	if ((file->f_mode & FMODE_WRITE) && mtd->sync) @@ -195,7 +195,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t  	size_t size = count;  	char *kbuf; -	DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n"); +	pr_debug("MTD_read\n");  	if (*ppos + count > mtd->size)  		count = mtd->size - *ppos; @@ -211,17 +211,17 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t  		len = min_t(size_t, count, size);  		switch (mfi->mode) { -		case MTD_MODE_OTP_FACTORY: +		case MTD_FILE_MODE_OTP_FACTORY:  			ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf);  			break; -		case MTD_MODE_OTP_USER: +		case MTD_FILE_MODE_OTP_USER:  			ret = mtd->read_user_prot_reg(mtd, *ppos, len, &retlen, kbuf);  			break; -		case MTD_MODE_RAW: +		case MTD_FILE_MODE_RAW:  		{  			struct mtd_oob_ops ops; -			ops.mode = MTD_OOB_RAW; +			ops.mode = MTD_OPS_RAW;  			ops.datbuf = kbuf;  			ops.oobbuf = NULL;  			ops.len = len; @@ -233,16 +233,16 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t  		default:  			ret = mtd->read(mtd, *ppos, len, &retlen, kbuf);  		} -		/* Nand returns -EBADMSG on ecc errors, but it returns +		/* Nand returns -EBADMSG on ECC errors, but it returns  		 * the data. For our userspace tools it is important -		 * to dump areas with ecc errors ! +		 * to dump areas with ECC errors!  		 * For kernel internal usage it also might return -EUCLEAN  		 * to signal the caller that a bitflip has occurred and has  		 * been corrected by the ECC algorithm.  		 * Userspace software which accesses NAND this way  		 * must be aware of the fact that it deals with NAND  		 */ -		if (!ret || (ret == -EUCLEAN) || (ret == -EBADMSG)) { +		if (!ret || mtd_is_bitflip_or_eccerr(ret)) {  			*ppos += retlen;  			if (copy_to_user(buf, kbuf, retlen)) {  				kfree(kbuf); @@ -278,7 +278,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count  	int ret=0;  	int len; -	DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n"); +	pr_debug("MTD_write\n");  	if (*ppos == mtd->size)  		return -ENOSPC; @@ -302,10 +302,10 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count  		}  		switch (mfi->mode) { -		case MTD_MODE_OTP_FACTORY: +		case MTD_FILE_MODE_OTP_FACTORY:  			ret = -EROFS;  			break; -		case MTD_MODE_OTP_USER: +		case MTD_FILE_MODE_OTP_USER:  			if (!mtd->write_user_prot_reg) {  				ret = -EOPNOTSUPP;  				break; @@ -313,13 +313,14 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count  			ret = mtd->write_user_prot_reg(mtd, *ppos, len, &retlen, kbuf);  			break; -		case MTD_MODE_RAW: +		case MTD_FILE_MODE_RAW:  		{  			struct mtd_oob_ops ops; -			ops.mode = MTD_OOB_RAW; +			ops.mode = MTD_OPS_RAW;  			ops.datbuf = kbuf;  			ops.oobbuf = NULL; +			ops.ooboffs = 0;  			ops.len = len;  			ret = mtd->write_oob(mtd, *ppos, &ops); @@ -367,13 +368,13 @@ static int otp_select_filemode(struct mtd_file_info *mfi, int mode)  		if (!mtd->read_fact_prot_reg)  			ret = -EOPNOTSUPP;  		else -			mfi->mode = MTD_MODE_OTP_FACTORY; +			mfi->mode = MTD_FILE_MODE_OTP_FACTORY;  		break;  	case MTD_OTP_USER:  		if (!mtd->read_fact_prot_reg)  			ret = -EOPNOTSUPP;  		else -			mfi->mode = MTD_MODE_OTP_USER; +			mfi->mode = MTD_FILE_MODE_OTP_USER;  		break;  	default:  		ret = -EINVAL; @@ -390,6 +391,7 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd,  	uint64_t start, uint32_t length, void __user *ptr,  	uint32_t __user *retp)  { +	struct mtd_file_info *mfi = file->private_data;  	struct mtd_oob_ops ops;  	uint32_t retlen;  	int ret = 0; @@ -409,9 +411,10 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd,  		return ret;  	ops.ooblen = length; -	ops.ooboffs = start & (mtd->oobsize - 1); +	ops.ooboffs = start & (mtd->writesize - 1);  	ops.datbuf = NULL; -	ops.mode = MTD_OOB_PLACE; +	ops.mode = (mfi->mode == MTD_FILE_MODE_RAW) ? MTD_OPS_RAW : +		MTD_OPS_PLACE_OOB;  	if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))  		return -EINVAL; @@ -420,7 +423,7 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd,  	if (IS_ERR(ops.oobbuf))  		return PTR_ERR(ops.oobbuf); -	start &= ~((uint64_t)mtd->oobsize - 1); +	start &= ~((uint64_t)mtd->writesize - 1);  	ret = mtd->write_oob(mtd, start, &ops);  	if (ops.oobretlen > 0xFFFFFFFFU) @@ -433,9 +436,11 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd,  	return ret;  } -static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, -	uint32_t length, void __user *ptr, uint32_t __user *retp) +static int mtd_do_readoob(struct file *file, struct mtd_info *mtd, +	uint64_t start, uint32_t length, void __user *ptr, +	uint32_t __user *retp)  { +	struct mtd_file_info *mfi = file->private_data;  	struct mtd_oob_ops ops;  	int ret = 0; @@ -451,9 +456,10 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start,  		return ret;  	ops.ooblen = length; -	ops.ooboffs = start & (mtd->oobsize - 1); +	ops.ooboffs = start & (mtd->writesize - 1);  	ops.datbuf = NULL; -	ops.mode = MTD_OOB_PLACE; +	ops.mode = (mfi->mode == MTD_FILE_MODE_RAW) ? MTD_OPS_RAW : +		MTD_OPS_PLACE_OOB;  	if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))  		return -EINVAL; @@ -462,7 +468,7 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start,  	if (!ops.oobbuf)  		return -ENOMEM; -	start &= ~((uint64_t)mtd->oobsize - 1); +	start &= ~((uint64_t)mtd->writesize - 1);  	ret = mtd->read_oob(mtd, start, &ops);  	if (put_user(ops.oobretlen, retp)) @@ -472,13 +478,29 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start,  		ret = -EFAULT;  	kfree(ops.oobbuf); + +	/* +	 * NAND returns -EBADMSG on ECC errors, but it returns the OOB +	 * data. For our userspace tools it is important to dump areas +	 * with ECC errors! +	 * For kernel internal usage it also might return -EUCLEAN +	 * to signal the caller that a bitflip has occured and has +	 * been corrected by the ECC algorithm. +	 * +	 * Note: currently the standard NAND function, nand_read_oob_std, +	 * does not calculate ECC for the OOB area, so do not rely on +	 * this behavior unless you have replaced it with your own. +	 */ +	if (mtd_is_bitflip_or_eccerr(ret)) +		return 0; +  	return ret;  }  /*   * Copies (and truncates, if necessary) data from the larger struct,   * nand_ecclayout, to the smaller, deprecated layout struct, - * nand_ecclayout_user. This is necessary only to suppport the deprecated + * nand_ecclayout_user. This is necessary only to support the deprecated   * API ioctl ECCGETLAYOUT while allowing all new functionality to use   * nand_ecclayout flexibly (i.e. the struct may change size in new   * releases without requiring major rewrites). @@ -544,6 +566,55 @@ static int mtd_blkpg_ioctl(struct mtd_info *mtd,  	}  } +static int mtd_write_ioctl(struct mtd_info *mtd, +		struct mtd_write_req __user *argp) +{ +	struct mtd_write_req req; +	struct mtd_oob_ops ops; +	void __user *usr_data, *usr_oob; +	int ret; + +	if (copy_from_user(&req, argp, sizeof(req)) || +			!access_ok(VERIFY_READ, req.usr_data, req.len) || +			!access_ok(VERIFY_READ, req.usr_oob, req.ooblen)) +		return -EFAULT; +	if (!mtd->write_oob) +		return -EOPNOTSUPP; + +	ops.mode = req.mode; +	ops.len = (size_t)req.len; +	ops.ooblen = (size_t)req.ooblen; +	ops.ooboffs = 0; + +	usr_data = (void __user *)(uintptr_t)req.usr_data; +	usr_oob = (void __user *)(uintptr_t)req.usr_oob; + +	if (req.usr_data) { +		ops.datbuf = memdup_user(usr_data, ops.len); +		if (IS_ERR(ops.datbuf)) +			return PTR_ERR(ops.datbuf); +	} else { +		ops.datbuf = NULL; +	} + +	if (req.usr_oob) { +		ops.oobbuf = memdup_user(usr_oob, ops.ooblen); +		if (IS_ERR(ops.oobbuf)) { +			kfree(ops.datbuf); +			return PTR_ERR(ops.oobbuf); +		} +	} else { +		ops.oobbuf = NULL; +	} + +	ret = mtd->write_oob(mtd, (loff_t)req.start, &ops); + +	kfree(ops.datbuf); +	kfree(ops.oobbuf); + +	return ret; +} +  static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)  {  	struct mtd_file_info *mfi = file->private_data; @@ -553,7 +624,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)  	u_long size;  	struct mtd_info_user info; -	DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n"); +	pr_debug("MTD_ioctl\n");  	size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;  	if (cmd & IOC_IN) { @@ -601,8 +672,8 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)  		info.erasesize	= mtd->erasesize;  		info.writesize	= mtd->writesize;  		info.oobsize	= mtd->oobsize; -		/* The below fields are obsolete */ -		info.ecctype	= -1; +		/* The below field is obsolete */ +		info.padding	= 0;  		if (copy_to_user(argp, &info, sizeof(struct mtd_info_user)))  			return -EFAULT;  		break; @@ -698,7 +769,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)  		if (copy_from_user(&buf, argp, sizeof(buf)))  			ret = -EFAULT;  		else -			ret = mtd_do_readoob(mtd, buf.start, buf.length, +			ret = mtd_do_readoob(file, mtd, buf.start, buf.length,  				buf.ptr, &buf_user->start);  		break;  	} @@ -725,12 +796,19 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)  		if (copy_from_user(&buf, argp, sizeof(buf)))  			ret = -EFAULT;  		else -			ret = mtd_do_readoob(mtd, buf.start, buf.length, +			ret = mtd_do_readoob(file, mtd, buf.start, buf.length,  				(void __user *)(uintptr_t)buf.usr_ptr,  				&buf_user->length);  		break;  	} +	case MEMWRITE: +	{ +		ret = mtd_write_ioctl(mtd, +		      (struct mtd_write_req __user *)arg); +		break; +	} +  	case MEMLOCK:  	{  		struct erase_info_user einfo; @@ -827,7 +905,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)  		if (copy_from_user(&mode, argp, sizeof(int)))  			return -EFAULT; -		mfi->mode = MTD_MODE_NORMAL; +		mfi->mode = MTD_FILE_MODE_NORMAL;  		ret = otp_select_filemode(mfi, mode); @@ -843,11 +921,11 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)  			return -ENOMEM;  		ret = -EOPNOTSUPP;  		switch (mfi->mode) { -		case MTD_MODE_OTP_FACTORY: +		case MTD_FILE_MODE_OTP_FACTORY:  			if (mtd->get_fact_prot_info)  				ret = mtd->get_fact_prot_info(mtd, buf, 4096);  			break; -		case MTD_MODE_OTP_USER: +		case MTD_FILE_MODE_OTP_USER:  			if (mtd->get_user_prot_info)  				ret = mtd->get_user_prot_info(mtd, buf, 4096);  			break; @@ -871,7 +949,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)  	{  		struct otp_info oinfo; -		if (mfi->mode != MTD_MODE_OTP_USER) +		if (mfi->mode != MTD_FILE_MODE_OTP_USER)  			return -EINVAL;  		if (copy_from_user(&oinfo, argp, sizeof(oinfo)))  			return -EFAULT; @@ -882,7 +960,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)  	}  #endif -	/* This ioctl is being deprecated - it truncates the ecc layout */ +	/* This ioctl is being deprecated - it truncates the ECC layout */  	case ECCGETLAYOUT:  	{  		struct nand_ecclayout_user *usrlay; @@ -915,17 +993,17 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)  		mfi->mode = 0;  		switch(arg) { -		case MTD_MODE_OTP_FACTORY: -		case MTD_MODE_OTP_USER: +		case MTD_FILE_MODE_OTP_FACTORY: +		case MTD_FILE_MODE_OTP_USER:  			ret = otp_select_filemode(mfi, arg);  			break; -		case MTD_MODE_RAW: +		case MTD_FILE_MODE_RAW:  			if (!mtd->read_oob || !mtd->write_oob)  				return -EOPNOTSUPP;  			mfi->mode = arg; -		case MTD_MODE_NORMAL: +		case MTD_FILE_MODE_NORMAL:  			break;  		default:  			ret = -EINVAL; @@ -1011,7 +1089,7 @@ static long mtd_compat_ioctl(struct file *file, unsigned int cmd,  		if (copy_from_user(&buf, argp, sizeof(buf)))  			ret = -EFAULT;  		else -			ret = mtd_do_readoob(mtd, buf.start, +			ret = mtd_do_readoob(file, mtd, buf.start,  				buf.length, compat_ptr(buf.ptr),  				&buf_user->start);  		break; diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index e601672a5305..6df4d4d4eb92 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -95,10 +95,10 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,  		/* Save information about bitflips! */  		if (unlikely(err)) { -			if (err == -EBADMSG) { +			if (mtd_is_eccerr(err)) {  				mtd->ecc_stats.failed++;  				ret = err; -			} else if (err == -EUCLEAN) { +			} else if (mtd_is_bitflip(err)) {  				mtd->ecc_stats.corrected++;  				/* Do not overwrite -EBADMSG !! */  				if (!ret) @@ -279,10 +279,10 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)  		/* Save information about bitflips! */  		if (unlikely(err)) { -			if (err == -EBADMSG) { +			if (mtd_is_eccerr(err)) {  				mtd->ecc_stats.failed++;  				ret = err; -			} else if (err == -EUCLEAN) { +			} else if (mtd_is_bitflip(err)) {  				mtd->ecc_stats.corrected++;  				/* Do not overwrite -EBADMSG !! */  				if (!ret) @@ -770,7 +770,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],	/* subdevices to c  	/*  	 * Set up the new "super" device's MTD object structure, check for -	 * incompatibilites between the subdevices. +	 * incompatibilities between the subdevices.  	 */  	concat->mtd.type = subdev[0]->type;  	concat->mtd.flags = subdev[0]->flags; diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index c510aff289a8..b01993ea260e 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -362,7 +362,7 @@ int add_mtd_device(struct mtd_info *mtd)  			      MTD_DEVT(i) + 1,  			      NULL, "mtd%dro", i); -	DEBUG(0, "mtd: Giving out device %d to %s\n", i, mtd->name); +	pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name);  	/* No need to get a refcount on the module containing  	   the notifier, since we hold the mtd_table_mutex */  	list_for_each_entry(not, &mtd_notifiers, list) @@ -429,27 +429,63 @@ out_error:  }  /** - * mtd_device_register - register an MTD device. + * mtd_device_parse_register - parse partitions and register an MTD device.   * - * @master: the MTD device to register - * @parts: the partitions to register - only valid if nr_parts > 0 - * @nr_parts: the number of partitions in parts.  If zero then the full MTD - *            device is registered + * @mtd: the MTD device to register + * @types: the list of MTD partition probes to try, see + *         'parse_mtd_partitions()' for more information + * @parser_data: MTD partition parser-specific data + * @parts: fallback partition information to register, if parsing fails; + *         only valid if %nr_parts > %0 + * @nr_parts: the number of partitions in parts, if zero then the full + *            MTD device is registered if no partition info is found   * - * Register an MTD device with the system and optionally, a number of - * partitions.  If nr_parts is 0 then the whole device is registered, otherwise - * only the partitions are registered.  To register both the full device *and* - * the partitions, call mtd_device_register() twice, once with nr_parts == 0 - * and once equal to the number of partitions. + * This function aggregates MTD partitions parsing (done by + * 'parse_mtd_partitions()') and MTD device and partitions registering. It + * basically follows the most common pattern found in many MTD drivers: + * + * * It first tries to probe partitions on MTD device @mtd using parsers + *   specified in @types (if @types is %NULL, then the default list of parsers + *   is used, see 'parse_mtd_partitions()' for more information). If none are + *   found this functions tries to fallback to information specified in + *   @parts/@nr_parts. + * * If any partitioning info was found, this function registers the found + *   partitions. + * * If no partitions were found this function just registers the MTD device + *   @mtd and exits. + * + * Returns zero in case of success and a negative error code in case of failure.   */ -int mtd_device_register(struct mtd_info *master, -			const struct mtd_partition *parts, -			int nr_parts) +int mtd_device_parse_register(struct mtd_info *mtd, const char **types, +			      struct mtd_part_parser_data *parser_data, +			      const struct mtd_partition *parts, +			      int nr_parts)  { -	return parts ? add_mtd_partitions(master, parts, nr_parts) : -		add_mtd_device(master); +	int err; +	struct mtd_partition *real_parts; + +	err = parse_mtd_partitions(mtd, types, &real_parts, parser_data); +	if (err <= 0 && nr_parts && parts) { +		real_parts = kmemdup(parts, sizeof(*parts) * nr_parts, +				     GFP_KERNEL); +		if (!real_parts) +			err = -ENOMEM; +		else +			err = nr_parts; +	} + +	if (err > 0) { +		err = add_mtd_partitions(mtd, real_parts, err); +		kfree(real_parts); +	} else if (err == 0) { +		err = add_mtd_device(mtd); +		if (err == 1) +			err = -ENODEV; +	} + +	return err;  } -EXPORT_SYMBOL_GPL(mtd_device_register); +EXPORT_SYMBOL_GPL(mtd_device_parse_register);  /**   * mtd_device_unregister - unregister an existing MTD device. diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h index 0ed6126b4c1f..961a38408542 100644 --- a/drivers/mtd/mtdcore.h +++ b/drivers/mtd/mtdcore.h @@ -15,6 +15,9 @@ extern int del_mtd_device(struct mtd_info *mtd);  extern int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *,  			      int);  extern int del_mtd_partitions(struct mtd_info *); +extern int parse_mtd_partitions(struct mtd_info *master, const char **types, +				struct mtd_partition **pparts, +				struct mtd_part_parser_data *data);  #define mtd_for_each_device(mtd)			\  	for ((mtd) = __mtd_next_device(0);		\ diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index e3e40f440323..1e2fa6236705 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -258,7 +258,7 @@ static void find_next_position(struct mtdoops_context *cxt)  		ret = mtd->read(mtd, page * record_size, MTDOOPS_HEADER_SIZE,  				&retlen, (u_char *) &count[0]);  		if (retlen != MTDOOPS_HEADER_SIZE || -				(ret < 0 && ret != -EUCLEAN)) { +				(ret < 0 && !mtd_is_bitflip(ret))) {  			printk(KERN_ERR "mtdoops: read failure at %ld (%td of %d read), err %d\n",  			       page * record_size, retlen,  			       MTDOOPS_HEADER_SIZE, ret); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 630be3e7da04..a0bd2de4752b 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -73,9 +73,9 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,  	res = part->master->read(part->master, from + part->offset,  				   len, retlen, buf);  	if (unlikely(res)) { -		if (res == -EUCLEAN) +		if (mtd_is_bitflip(res))  			mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected; -		if (res == -EBADMSG) +		if (mtd_is_eccerr(res))  			mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed;  	}  	return res; @@ -130,7 +130,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,  	if (ops->oobbuf) {  		size_t len, pages; -		if (ops->mode == MTD_OOB_AUTO) +		if (ops->mode == MTD_OPS_AUTO_OOB)  			len = mtd->oobavail;  		else  			len = mtd->oobsize; @@ -142,9 +142,9 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,  	res = part->master->read_oob(part->master, from + part->offset, ops);  	if (unlikely(res)) { -		if (res == -EUCLEAN) +		if (mtd_is_bitflip(res))  			mtd->ecc_stats.corrected++; -		if (res == -EBADMSG) +		if (mtd_is_eccerr(res))  			mtd->ecc_stats.failed++;  	}  	return res; @@ -479,6 +479,19 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,  			       (unsigned long long)cur_offset, (unsigned long long)slave->offset);  		}  	} +	if (slave->offset == MTDPART_OFS_RETAIN) { +		slave->offset = cur_offset; +		if (master->size - slave->offset >= slave->mtd.size) { +			slave->mtd.size = master->size - slave->offset +							- slave->mtd.size; +		} else { +			printk(KERN_ERR "mtd partition \"%s\" doesn't have enough space: %#llx < %#llx, disabled\n", +				part->name, master->size - slave->offset, +				slave->mtd.size); +			/* register to preserve ordering */ +			goto out_register; +		} +	}  	if (slave->mtd.size == MTDPART_SIZ_FULL)  		slave->mtd.size = master->size - slave->offset; @@ -693,6 +706,8 @@ static struct mtd_part_parser *get_partition_parser(const char *name)  	return ret;  } +#define put_partition_parser(p) do { module_put((p)->owner); } while (0) +  int register_mtd_parser(struct mtd_part_parser *p)  {  	spin_lock(&part_parser_lock); @@ -712,19 +727,51 @@ int deregister_mtd_parser(struct mtd_part_parser *p)  }  EXPORT_SYMBOL_GPL(deregister_mtd_parser); +/* + * Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you + * are changing this array! + */ +static const char *default_mtd_part_types[] = { +	"cmdlinepart", +	"ofpart", +	NULL +}; + +/** + * parse_mtd_partitions - parse MTD partitions + * @master: the master partition (describes whole MTD device) + * @types: names of partition parsers to try or %NULL + * @pparts: array of partitions found is returned here + * @data: MTD partition parser-specific data + * + * This function tries to find partition on MTD device @master. It uses MTD + * partition parsers, specified in @types. However, if @types is %NULL, then + * the default list of parsers is used. The default list contains only the + * "cmdlinepart" and "ofpart" parsers ATM. + * + * This function may return: + * o a negative error code in case of failure + * o zero if no partitions were found + * o a positive number of found partitions, in which case on exit @pparts will + *   point to an array containing this number of &struct mtd_info objects. + */  int parse_mtd_partitions(struct mtd_info *master, const char **types, -			 struct mtd_partition **pparts, unsigned long origin) +			 struct mtd_partition **pparts, +			 struct mtd_part_parser_data *data)  {  	struct mtd_part_parser *parser;  	int ret = 0; +	if (!types) +		types = default_mtd_part_types; +  	for ( ; ret <= 0 && *types; types++) {  		parser = get_partition_parser(*types);  		if (!parser && !request_module("%s", *types))  				parser = get_partition_parser(*types);  		if (!parser)  			continue; -		ret = (*parser->parse_fn)(master, pparts, origin); +		ret = (*parser->parse_fn)(master, pparts, data);  		if (ret > 0) {  			printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",  			       ret, parser->name, master->name); @@ -733,7 +780,6 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types,  	}  	return ret;  } -EXPORT_SYMBOL_GPL(parse_mtd_partitions);  int mtd_is_partition(struct mtd_info *mtd)  { diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c index 89f8e66448ab..a90bfe79916d 100644 --- a/drivers/mtd/mtdsuper.c +++ b/drivers/mtd/mtdsuper.c @@ -27,12 +27,12 @@ static int get_sb_mtd_compare(struct super_block *sb, void *_mtd)  	struct mtd_info *mtd = _mtd;  	if (sb->s_mtd == mtd) { -		DEBUG(2, "MTDSB: Match on device %d (\"%s\")\n", +		pr_debug("MTDSB: Match on device %d (\"%s\")\n",  		      mtd->index, mtd->name);  		return 1;  	} -	DEBUG(2, "MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")\n", +	pr_debug("MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")\n",  	      sb->s_mtd->index, sb->s_mtd->name, mtd->index, mtd->name);  	return 0;  } @@ -71,7 +71,7 @@ static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags,  		goto already_mounted;  	/* fresh new superblock */ -	DEBUG(1, "MTDSB: New superblock for device %d (\"%s\")\n", +	pr_debug("MTDSB: New superblock for device %d (\"%s\")\n",  	      mtd->index, mtd->name);  	sb->s_flags = flags; @@ -88,7 +88,7 @@ static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags,  	/* new mountpoint for an already mounted superblock */  already_mounted: -	DEBUG(1, "MTDSB: Device %d (\"%s\") is already mounted\n", +	pr_debug("MTDSB: Device %d (\"%s\") is already mounted\n",  	      mtd->index, mtd->name);  	put_mtd_device(mtd);  	return dget(sb->s_root); @@ -109,7 +109,7 @@ static struct dentry *mount_mtd_nr(struct file_system_type *fs_type, int flags,  	mtd = get_mtd_device(NULL, mtdnr);  	if (IS_ERR(mtd)) { -		DEBUG(0, "MTDSB: Device #%u doesn't appear to exist\n", mtdnr); +		pr_debug("MTDSB: Device #%u doesn't appear to exist\n", mtdnr);  		return ERR_CAST(mtd);  	} @@ -132,7 +132,7 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags,  	if (!dev_name)  		return ERR_PTR(-EINVAL); -	DEBUG(2, "MTDSB: dev_name \"%s\"\n", dev_name); +	pr_debug("MTDSB: dev_name \"%s\"\n", dev_name);  	/* the preferred way of mounting in future; especially when  	 * CONFIG_BLOCK=n - we specify the underlying MTD device by number or @@ -143,7 +143,7 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags,  			struct mtd_info *mtd;  			/* mount by MTD device name */ -			DEBUG(1, "MTDSB: mtd:%%s, name \"%s\"\n", +			pr_debug("MTDSB: mtd:%%s, name \"%s\"\n",  			      dev_name + 4);  			mtd = get_mtd_device_nm(dev_name + 4); @@ -164,7 +164,7 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags,  			mtdnr = simple_strtoul(dev_name + 3, &endptr, 0);  			if (!*endptr) {  				/* It was a valid number */ -				DEBUG(1, "MTDSB: mtd%%d, mtdnr %d\n", +				pr_debug("MTDSB: mtd%%d, mtdnr %d\n",  				      mtdnr);  				return mount_mtd_nr(fs_type, flags,  						     dev_name, data, @@ -180,10 +180,10 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags,  	bdev = lookup_bdev(dev_name);  	if (IS_ERR(bdev)) {  		ret = PTR_ERR(bdev); -		DEBUG(1, "MTDSB: lookup_bdev() returned %d\n", ret); +		pr_debug("MTDSB: lookup_bdev() returned %d\n", ret);  		return ERR_PTR(ret);  	} -	DEBUG(1, "MTDSB: lookup_bdev() returned 0\n"); +	pr_debug("MTDSB: lookup_bdev() returned 0\n");  	ret = -EINVAL; diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index fd7885327611..bd9590c723e4 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -86,7 +86,7 @@ struct swap_eb {  	unsigned int flags;  	unsigned int active_count;  	unsigned int erase_count; -	unsigned int pad;		/* speeds up pointer decremtnt */ +	unsigned int pad;		/* speeds up pointer decrement */  };  #define MTDSWAP_ECNT_MIN(rbroot) (rb_entry(rb_first(rbroot), struct swap_eb, \ @@ -314,7 +314,7 @@ static int mtdswap_read_oob(struct mtdswap_dev *d, loff_t from,  {  	int ret = d->mtd->read_oob(d->mtd, from, ops); -	if (ret == -EUCLEAN) +	if (mtd_is_bitflip(ret))  		return ret;  	if (ret) { @@ -350,11 +350,11 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb)  	ops.oobbuf = d->oob_buf;  	ops.ooboffs = 0;  	ops.datbuf = NULL; -	ops.mode = MTD_OOB_AUTO; +	ops.mode = MTD_OPS_AUTO_OOB;  	ret = mtdswap_read_oob(d, offset, &ops); -	if (ret && ret != -EUCLEAN) +	if (ret && !mtd_is_bitflip(ret))  		return ret;  	data = (struct mtdswap_oobdata *)d->oob_buf; @@ -363,7 +363,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb)  	if (le16_to_cpu(data->magic) == MTDSWAP_MAGIC_CLEAN) {  		eb->erase_count = le32_to_cpu(data->count); -		if (ret == -EUCLEAN) +		if (mtd_is_bitflip(ret))  			ret = MTDSWAP_SCANNED_BITFLIP;  		else {  			if (le16_to_cpu(data2->magic) == MTDSWAP_MAGIC_DIRTY) @@ -389,7 +389,7 @@ static int mtdswap_write_marker(struct mtdswap_dev *d, struct swap_eb *eb,  	ops.ooboffs = 0;  	ops.oobbuf = (uint8_t *)&n; -	ops.mode = MTD_OOB_AUTO; +	ops.mode = MTD_OPS_AUTO_OOB;  	ops.datbuf = NULL;  	if (marker == MTDSWAP_TYPE_CLEAN) { @@ -408,7 +408,7 @@ static int mtdswap_write_marker(struct mtdswap_dev *d, struct swap_eb *eb,  	if (ret) {  		dev_warn(d->dev, "Write OOB failed for block at %08llx "  			"error %d\n", offset, ret); -		if (ret == -EIO || ret == -EBADMSG) +		if (ret == -EIO || mtd_is_eccerr(ret))  			mtdswap_handle_write_error(d, eb);  		return ret;  	} @@ -628,7 +628,7 @@ static int mtdswap_map_free_block(struct mtdswap_dev *d, unsigned int page,  			TREE_COUNT(d, CLEAN)--;  			ret = mtdswap_write_marker(d, eb, MTDSWAP_TYPE_DIRTY); -		} while (ret == -EIO || ret == -EBADMSG); +		} while (ret == -EIO || mtd_is_eccerr(ret));  		if (ret)  			return ret; @@ -678,7 +678,7 @@ retry:  	ret = mtdswap_map_free_block(d, page, bp);  	eb = d->eb_data + (*bp / d->pages_per_eblk); -	if (ret == -EIO || ret == -EBADMSG) { +	if (ret == -EIO || mtd_is_eccerr(ret)) {  		d->curr_write = NULL;  		eb->active_count--;  		d->revmap[*bp] = PAGE_UNDEF; @@ -690,7 +690,7 @@ retry:  	writepos = (loff_t)*bp << PAGE_SHIFT;  	ret =  mtd->write(mtd, writepos, PAGE_SIZE, &retlen, buf); -	if (ret == -EIO || ret == -EBADMSG) { +	if (ret == -EIO || mtd_is_eccerr(ret)) {  		d->curr_write_pos--;  		eb->active_count--;  		d->revmap[*bp] = PAGE_UNDEF; @@ -738,7 +738,7 @@ static int mtdswap_move_block(struct mtdswap_dev *d, unsigned int oldblock,  retry:  	ret = mtd->read(mtd, readpos, PAGE_SIZE, &retlen, d->page_buf); -	if (ret < 0 && ret != -EUCLEAN) { +	if (ret < 0 && !mtd_is_bitflip(ret)) {  		oldeb = d->eb_data + oldblock / d->pages_per_eblk;  		oldeb->flags |= EBLOCK_READERR; @@ -931,7 +931,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d,  	struct mtd_oob_ops ops;  	int ret; -	ops.mode = MTD_OOB_AUTO; +	ops.mode = MTD_OPS_AUTO_OOB;  	ops.len = mtd->writesize;  	ops.ooblen = mtd->ecclayout->oobavail;  	ops.ooboffs = 0; @@ -1016,7 +1016,7 @@ static int mtdswap_gc(struct mtdswap_dev *d, unsigned int background)  	if (ret == 0)  		mtdswap_rb_add(d, eb, MTDSWAP_CLEAN); -	else if (ret != -EIO && ret != -EBADMSG) +	else if (ret != -EIO && !mtd_is_eccerr(ret))  		mtdswap_rb_add(d, eb, MTDSWAP_DIRTY);  	return 0; @@ -1164,7 +1164,7 @@ retry:  	ret = mtd->read(mtd, readpos, PAGE_SIZE, &retlen, buf);  	d->mtd_read_count++; -	if (ret == -EUCLEAN) { +	if (mtd_is_bitflip(ret)) {  		eb->flags |= EBLOCK_BITFLIP;  		mtdswap_rb_add(d, eb, MTDSWAP_BITFLIP);  		ret = 0; @@ -1374,11 +1374,10 @@ static int mtdswap_init(struct mtdswap_dev *d, unsigned int eblocks,  		goto revmap_fail;  	eblk_bytes = sizeof(struct swap_eb)*d->eblks; -	d->eb_data = vmalloc(eblk_bytes); +	d->eb_data = vzalloc(eblk_bytes);  	if (!d->eb_data)  		goto eb_data_fail; -	memset(d->eb_data, 0, eblk_bytes);  	for (i = 0; i < pages; i++)  		d->page_data[i] = BLOCK_UNDEF; diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index dbfa0f7fb464..cce7b70824c3 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -83,16 +83,9 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR            scratch register here to enable this feature. On Intel Moorestown            boards, the scratch register is at 0xFF108018. -config MTD_NAND_EDB7312 -	tristate "Support for Cirrus Logic EBD7312 evaluation board" -	depends on ARCH_EDB7312 -	help -	  This enables the driver for the Cirrus Logic EBD7312 evaluation -	  board to access the onboard NAND Flash. -  config MTD_NAND_H1900  	tristate "iPAQ H1900 flash" -	depends on ARCH_PXA +	depends on ARCH_PXA && BROKEN  	help  	  This enables the driver for the iPAQ h1900 flash. @@ -116,10 +109,11 @@ config MTD_NAND_AMS_DELTA  	  Support for NAND flash on Amstrad E3 (Delta).  config MTD_NAND_OMAP2 -	tristate "NAND Flash device on OMAP2 and OMAP3" -	depends on ARM && (ARCH_OMAP2 || ARCH_OMAP3) +	tristate "NAND Flash device on OMAP2, OMAP3 and OMAP4" +	depends on ARM && (ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4)  	help -          Support for NAND flash on Texas Instruments OMAP2 and OMAP3 platforms. +          Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4 +	  platforms.  config MTD_NAND_IDS  	tristate @@ -423,6 +417,19 @@ config MTD_NAND_NANDSIM  	  The simulator may simulate various NAND flash chips for the  	  MTD nand layer. +config MTD_NAND_GPMI_NAND +        bool "GPMI NAND Flash Controller driver" +        depends on MTD_NAND && (SOC_IMX23 || SOC_IMX28) +	select MTD_PARTITIONS +	select MTD_CMDLINE_PARTS +        help +	 Enables NAND Flash support for IMX23 or IMX28. +	 The GPMI controller is very powerful, with the help of BCH +	 module, it can do the hardware ECC. The GPMI supports several +	 NAND flashs at the same time. The GPMI may conflicts with other +	 block, such as SD card. So pay attention to it when you enable +	 the GPMI. +  config MTD_NAND_PLATFORM  	tristate "Support for generic platform NAND driver"  	help diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 5745d831168e..618f4ba23699 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_MTD_NAND_SPIA)		+= spia.o  obj-$(CONFIG_MTD_NAND_AMS_DELTA)	+= ams-delta.o  obj-$(CONFIG_MTD_NAND_AUTCPU12)		+= autcpu12.o  obj-$(CONFIG_MTD_NAND_DENALI)		+= denali.o -obj-$(CONFIG_MTD_NAND_EDB7312)		+= edb7312.o  obj-$(CONFIG_MTD_NAND_AU1550)		+= au1550nd.o  obj-$(CONFIG_MTD_NAND_BF5XX)		+= bf5xx_nand.o  obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB)	+= ppchameleonevb.o @@ -49,5 +48,6 @@ obj-$(CONFIG_MTD_NAND_BCM_UMI)		+= bcm_umi_nand.o nand_bcm_umi.o  obj-$(CONFIG_MTD_NAND_MPC5121_NFC)	+= mpc5121_nfc.o  obj-$(CONFIG_MTD_NAND_RICOH)		+= r852.o  obj-$(CONFIG_MTD_NAND_JZ4740)		+= jz4740_nand.o +obj-$(CONFIG_MTD_NAND_GPMI_NAND)	+= gpmi-nand/  nand-objs := nand_base.o nand_bbt.o diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 55da20ccc7a8..23e5d77c39fc 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -161,37 +161,6 @@ static int atmel_nand_device_ready(struct mtd_info *mtd)                  !!host->board->rdy_pin_active_low;  } -/* - * Minimal-overhead PIO for data access. - */ -static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len) -{ -	struct nand_chip	*nand_chip = mtd->priv; - -	__raw_readsb(nand_chip->IO_ADDR_R, buf, len); -} - -static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) -{ -	struct nand_chip	*nand_chip = mtd->priv; - -	__raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); -} - -static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len) -{ -	struct nand_chip	*nand_chip = mtd->priv; - -	__raw_writesb(nand_chip->IO_ADDR_W, buf, len); -} - -static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) -{ -	struct nand_chip	*nand_chip = mtd->priv; - -	__raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); -} -  static void dma_complete_func(void *completion)  {  	complete(completion); @@ -266,33 +235,27 @@ err_buf:  static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len)  {  	struct nand_chip *chip = mtd->priv; -	struct atmel_nand_host *host = chip->priv;  	if (use_dma && len > mtd->oobsize)  		/* only use DMA for bigger than oob size: better performances */  		if (atmel_nand_dma_op(mtd, buf, len, 1) == 0)  			return; -	if (host->board->bus_width_16) -		atmel_read_buf16(mtd, buf, len); -	else -		atmel_read_buf8(mtd, buf, len); +	/* if no DMA operation possible, use PIO */ +	memcpy_fromio(buf, chip->IO_ADDR_R, len);  }  static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)  {  	struct nand_chip *chip = mtd->priv; -	struct atmel_nand_host *host = chip->priv;  	if (use_dma && len > mtd->oobsize)  		/* only use DMA for bigger than oob size: better performances */  		if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0)  			return; -	if (host->board->bus_width_16) -		atmel_write_buf16(mtd, buf, len); -	else -		atmel_write_buf8(mtd, buf, len); +	/* if no DMA operation possible, use PIO */ +	memcpy_toio(chip->IO_ADDR_W, buf, len);  }  /* @@ -481,10 +444,6 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)  	}  } -#ifdef CONFIG_MTD_CMDLINE_PARTS -static const char *part_probes[] = { "cmdlinepart", NULL }; -#endif -  /*   * Probe for the NAND device.   */ @@ -496,8 +455,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev)  	struct resource *regs;  	struct resource *mem;  	int res; -	struct mtd_partition *partitions = NULL; -	int num_partitions = 0;  	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!mem) { @@ -583,7 +540,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)  	if (on_flash_bbt) {  		printk(KERN_INFO "atmel_nand: Use On Flash BBT\n"); -		nand_chip->options |= NAND_USE_FLASH_BBT; +		nand_chip->bbt_options |= NAND_BBT_USE_FLASH;  	}  	if (!cpu_has_dma()) @@ -594,7 +551,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)  		dma_cap_zero(mask);  		dma_cap_set(DMA_MEMCPY, mask); -		host->dma_chan = dma_request_channel(mask, 0, NULL); +		host->dma_chan = dma_request_channel(mask, NULL, NULL);  		if (!host->dma_chan) {  			dev_err(host->dev, "Failed to request DMA channel\n");  			use_dma = 0; @@ -655,27 +612,12 @@ static int __init atmel_nand_probe(struct platform_device *pdev)  		goto err_scan_tail;  	} -#ifdef CONFIG_MTD_CMDLINE_PARTS  	mtd->name = "atmel_nand"; -	num_partitions = parse_mtd_partitions(mtd, part_probes, -					      &partitions, 0); -#endif -	if (num_partitions <= 0 && host->board->partition_info) -		partitions = host->board->partition_info(mtd->size, -							 &num_partitions); - -	if ((!partitions) || (num_partitions == 0)) { -		printk(KERN_ERR "atmel_nand: No partitions defined, or unsupported device.\n"); -		res = -ENXIO; -		goto err_no_partitions; -	} - -	res = mtd_device_register(mtd, partitions, num_partitions); +	res = mtd_device_parse_register(mtd, NULL, 0, +			host->board->parts, host->board->num_parts);  	if (!res)  		return res; -err_no_partitions: -	nand_release(mtd);  err_scan_tail:  err_scan_ident:  err_no_card: diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index fa5736b9286c..7dd3700f2303 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -52,7 +52,7 @@ static const struct mtd_partition partition_info[] = {   * au_read_byte -  read one byte from the chip   * @mtd:	MTD device structure   * - *  read function for 8bit buswith + * read function for 8bit buswidth   */  static u_char au_read_byte(struct mtd_info *mtd)  { @@ -67,7 +67,7 @@ static u_char au_read_byte(struct mtd_info *mtd)   * @mtd:	MTD device structure   * @byte:	pointer to data byte to write   * - *  write function for 8it buswith + * write function for 8it buswidth   */  static void au_write_byte(struct mtd_info *mtd, u_char byte)  { @@ -77,11 +77,10 @@ static void au_write_byte(struct mtd_info *mtd, u_char byte)  }  /** - * au_read_byte16 -  read one byte endianess aware from the chip + * au_read_byte16 -  read one byte endianness aware from the chip   * @mtd:	MTD device structure   * - *  read function for 16bit buswith with - * endianess conversion + * read function for 16bit buswidth with endianness conversion   */  static u_char au_read_byte16(struct mtd_info *mtd)  { @@ -92,12 +91,11 @@ static u_char au_read_byte16(struct mtd_info *mtd)  }  /** - * au_write_byte16 -  write one byte endianess aware to the chip + * au_write_byte16 -  write one byte endianness aware to the chip   * @mtd:	MTD device structure   * @byte:	pointer to data byte to write   * - *  write function for 16bit buswith with - * endianess conversion + * write function for 16bit buswidth with endianness conversion   */  static void au_write_byte16(struct mtd_info *mtd, u_char byte)  { @@ -110,8 +108,7 @@ static void au_write_byte16(struct mtd_info *mtd, u_char byte)   * au_read_word -  read one word from the chip   * @mtd:	MTD device structure   * - *  read function for 16bit buswith without - * endianess conversion + * read function for 16bit buswidth without endianness conversion   */  static u16 au_read_word(struct mtd_info *mtd)  { @@ -127,7 +124,7 @@ static u16 au_read_word(struct mtd_info *mtd)   * @buf:	data buffer   * @len:	number of bytes to write   * - *  write function for 8bit buswith + * write function for 8bit buswidth   */  static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len)  { @@ -146,7 +143,7 @@ static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len)   * @buf:	buffer to store date   * @len:	number of bytes to read   * - *  read function for 8bit buswith + * read function for 8bit buswidth   */  static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)  { @@ -165,7 +162,7 @@ static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)   * @buf:	buffer containing the data to compare   * @len:	number of bytes to compare   * - *  verify function for 8bit buswith + * verify function for 8bit buswidth   */  static int au_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)  { @@ -187,7 +184,7 @@ static int au_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)   * @buf:	data buffer   * @len:	number of bytes to write   * - *  write function for 16bit buswith + * write function for 16bit buswidth   */  static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)  { @@ -209,7 +206,7 @@ static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)   * @buf:	buffer to store date   * @len:	number of bytes to read   * - *  read function for 16bit buswith + * read function for 16bit buswidth   */  static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)  { @@ -230,7 +227,7 @@ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)   * @buf:	buffer containing the data to compare   * @len:	number of bytes to compare   * - *  verify function for 16bit buswith + * verify function for 16bit buswidth   */  static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)  { diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index eddc9a224985..2e42ec2e8ff4 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c @@ -172,9 +172,9 @@ static int __init autcpu12_init(void)  	/* Enable the following for a flash based bad block table */  	/* -	   this->options = NAND_USE_FLASH_BBT; +	   this->bbt_options = NAND_BBT_USE_FLASH;  	 */ -	this->options = NAND_USE_FLASH_BBT; +	this->bbt_options = NAND_BBT_USE_FLASH;  	/* Scan to find existence of the device */  	if (nand_scan(autcpu12_mtd, 1)) { diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c index 8c569e454dc5..46b58d672847 100644 --- a/drivers/mtd/nand/bcm_umi_nand.c +++ b/drivers/mtd/nand/bcm_umi_nand.c @@ -52,8 +52,6 @@  static const __devinitconst char gBanner[] = KERN_INFO \  	"BCM UMI MTD NAND Driver: 1.00\n"; -const char *part_probes[] = { "cmdlinepart", NULL }; -  #if NAND_ECC_BCH  static uint8_t scan_ff_pattern[] = { 0xff }; @@ -376,16 +374,18 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev)  	r = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!r) -		return -ENXIO; +	if (!r) { +		err = -ENXIO; +		goto out_free; +	}  	/* map physical address */  	bcm_umi_io_base = ioremap(r->start, resource_size(r));  	if (!bcm_umi_io_base) {  		printk(KERN_ERR "ioremap to access BCM UMI NAND chip failed\n"); -		kfree(board_mtd); -		return -EIO; +		err = -EIO; +		goto out_free;  	}  	/* Get pointer to private data */ @@ -401,9 +401,8 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev)  	/* Initialize the NAND hardware.  */  	if (bcm_umi_nand_inithw() < 0) {  		printk(KERN_ERR "BCM UMI NAND chip could not be initialized\n"); -		iounmap(bcm_umi_io_base); -		kfree(board_mtd); -		return -EIO; +		err = -EIO; +		goto out_unmap;  	}  	/* Set address of NAND IO lines */ @@ -436,7 +435,7 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev)  #if USE_DMA  	err = nand_dma_init();  	if (err != 0) -		return err; +		goto out_unmap;  #endif  	/* Figure out the size of the device that we have. @@ -447,9 +446,7 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev)  	err = nand_scan_ident(board_mtd, 1, NULL);  	if (err) {  		printk(KERN_ERR "nand_scan failed: %d\n", err); -		iounmap(bcm_umi_io_base); -		kfree(board_mtd); -		return err; +		goto out_unmap;  	}  	/* Now that we know the nand size, we can setup the ECC layout */ @@ -468,13 +465,14 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev)  		{  			printk(KERN_ERR "NAND - Unrecognized pagesize: %d\n",  					 board_mtd->writesize); -			return -EINVAL; +			err = -EINVAL; +			goto out_unmap;  		}  	}  #if NAND_ECC_BCH  	if (board_mtd->writesize > 512) { -		if (this->options & NAND_USE_FLASH_BBT) +		if (this->bbt_options & NAND_BBT_USE_FLASH)  			largepage_bbt.options = NAND_BBT_SCAN2NDPAGE;  		this->badblock_pattern = &largepage_bbt;  	} @@ -485,33 +483,20 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev)  	err = nand_scan_tail(board_mtd);  	if (err) {  		printk(KERN_ERR "nand_scan failed: %d\n", err); -		iounmap(bcm_umi_io_base); -		kfree(board_mtd); -		return err; +		goto out_unmap;  	}  	/* Register the partitions */ -	{ -		int nr_partitions; -		struct mtd_partition *partition_info; - -		board_mtd->name = "bcm_umi-nand"; -		nr_partitions = -		    parse_mtd_partitions(board_mtd, part_probes, -					 &partition_info, 0); - -		if (nr_partitions <= 0) { -			printk(KERN_ERR "BCM UMI NAND: Too few partitions - %d\n", -			       nr_partitions); -			iounmap(bcm_umi_io_base); -			kfree(board_mtd); -			return -EIO; -		} -		mtd_device_register(board_mtd, partition_info, nr_partitions); -	} +	board_mtd->name = "bcm_umi-nand"; +	mtd_device_parse_register(board_mtd, NULL, 0, NULL, 0);  	/* Return happy */  	return 0; +out_unmap: +	iounmap(bcm_umi_io_base); +out_free: +	kfree(board_mtd); +	return err;  }  static int bcm_umi_nand_remove(struct platform_device *pdev) diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 7c8df837d3b8..72d3f23490c5 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -58,7 +58,6 @@  struct cafe_priv {  	struct nand_chip nand; -	struct mtd_partition *parts;  	struct pci_dev *pdev;  	void __iomem *mmio;  	struct rs_control *rs; @@ -372,7 +371,7 @@ static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,  	return 1;  }  /** - * cafe_nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read + * cafe_nand_read_page_syndrome - [REPLACEABLE] hardware ecc syndrome based page read   * @mtd:	mtd info structure   * @chip:	nand chip info structure   * @buf:	buffer to store read data @@ -631,8 +630,6 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,  	struct cafe_priv *cafe;  	uint32_t ctrl;  	int err = 0; -	struct mtd_partition *parts; -	int nr_parts;  	/* Very old versions shared the same PCI ident for all three  	   functions on the chip. Verify the class too... */ @@ -687,7 +684,8 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,  	cafe->nand.chip_delay = 0;  	/* Enable the following for a flash based bad block table */ -	cafe->nand.options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR | NAND_OWN_BUFFERS; +	cafe->nand.bbt_options = NAND_BBT_USE_FLASH; +	cafe->nand.options = NAND_NO_AUTOINCR | NAND_OWN_BUFFERS;  	if (skipbbt) {  		cafe->nand.options |= NAND_SKIP_BBTSCAN; @@ -800,18 +798,9 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,  	pci_set_drvdata(pdev, mtd); -	/* We register the whole device first, separate from the partitions */ -	mtd_device_register(mtd, NULL, 0); - -#ifdef CONFIG_MTD_CMDLINE_PARTS  	mtd->name = "cafe_nand"; -#endif -	nr_parts = parse_mtd_partitions(mtd, part_probes, &parts, 0); -	if (nr_parts > 0) { -		cafe->parts = parts; -		dev_info(&cafe->pdev->dev, "%d partitions found\n", nr_parts); -		mtd_device_register(mtd, parts, nr_parts); -	} +	mtd_device_parse_register(mtd, part_probes, 0, NULL, 0); +  	goto out;   out_irq: diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c index be33b0f4634d..737ef9a04fdb 100644 --- a/drivers/mtd/nand/cmx270_nand.c +++ b/drivers/mtd/nand/cmx270_nand.c @@ -51,8 +51,6 @@ static struct mtd_partition partition_info[] = {  };  #define NUM_PARTITIONS (ARRAY_SIZE(partition_info)) -const char *part_probes[] = { "cmdlinepart", NULL }; -  static u_char cmx270_read_byte(struct mtd_info *mtd)  {  	struct nand_chip *this = mtd->priv; @@ -152,9 +150,6 @@ static int cmx270_device_ready(struct mtd_info *mtd)  static int __init cmx270_init(void)  {  	struct nand_chip *this; -	const char *part_type; -	struct mtd_partition *mtd_parts; -	int mtd_parts_nb = 0;  	int ret;  	if (!(machine_is_armcore() && cpu_is_pxa27x())) @@ -223,23 +218,9 @@ static int __init cmx270_init(void)  		goto err_scan;  	} -#ifdef CONFIG_MTD_CMDLINE_PARTS -	mtd_parts_nb = parse_mtd_partitions(cmx270_nand_mtd, part_probes, -					    &mtd_parts, 0); -	if (mtd_parts_nb > 0) -		part_type = "command line"; -	else -		mtd_parts_nb = 0; -#endif -	if (!mtd_parts_nb) { -		mtd_parts = partition_info; -		mtd_parts_nb = NUM_PARTITIONS; -		part_type = "static"; -	} -  	/* Register the partitions */ -	pr_notice("Using %s partition definition\n", part_type); -	ret = mtd_device_register(cmx270_nand_mtd, mtd_parts, mtd_parts_nb); +	ret = mtd_device_parse_register(cmx270_nand_mtd, NULL, 0, +					partition_info, NUM_PARTITIONS);  	if (ret)  		goto err_scan; diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index f59ad1f2d5db..414afa793563 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -239,7 +239,8 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)  	this->ecc.correct  = nand_correct_data;  	/* Enable the following for a flash based bad block table */ -	this->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR; +	this->bbt_options = NAND_BBT_USE_FLASH; +	this->options = NAND_NO_AUTOINCR;  	/* Scan to find existence of the device */  	if (nand_scan(new_mtd, 1)) { @@ -277,15 +278,11 @@ static int is_geode(void)  	return 0;  } -static const char *part_probes[] = { "cmdlinepart", NULL }; -  static int __init cs553x_init(void)  {  	int err = -ENXIO;  	int i;  	uint64_t val; -	int mtd_parts_nb = 0; -	struct mtd_partition *mtd_parts = NULL;  	/* If the CPU isn't a Geode GX or LX, abort */  	if (!is_geode()) @@ -315,13 +312,9 @@ static int __init cs553x_init(void)  	   do mtdconcat etc. if we want to. */  	for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {  		if (cs553x_mtd[i]) { -  			/* If any devices registered, return success. Else the last error. */ -			mtd_parts_nb = parse_mtd_partitions(cs553x_mtd[i], part_probes, &mtd_parts, 0); -			if (mtd_parts_nb > 0) -				printk(KERN_NOTICE "Using command line partition definition\n"); -			mtd_device_register(cs553x_mtd[i], mtd_parts, -					    mtd_parts_nb); +			mtd_device_parse_register(cs553x_mtd[i], NULL, 0, +						  NULL, 0);  			err = 0;  		}  	} diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 1f34951ae1a7..c153e1f77f90 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -57,7 +57,6 @@ struct davinci_nand_info {  	struct device		*dev;  	struct clk		*clk; -	bool			partitioned;  	bool			is_readmode; @@ -530,8 +529,6 @@ static int __init nand_davinci_probe(struct platform_device *pdev)  	int				ret;  	uint32_t			val;  	nand_ecc_modes_t		ecc_mode; -	struct mtd_partition		*mtd_parts = NULL; -	int				mtd_parts_nb = 0;  	/* insist on board-specific configuration */  	if (!pdata) @@ -581,7 +578,9 @@ static int __init nand_davinci_probe(struct platform_device *pdev)  	info->chip.chip_delay	= 0;  	info->chip.select_chip	= nand_davinci_select_chip; -	/* options such as NAND_USE_FLASH_BBT or 16-bit widths */ +	/* options such as NAND_BBT_USE_FLASH */ +	info->chip.bbt_options	= pdata->bbt_options; +	/* options such as 16-bit widths */  	info->chip.options	= pdata->options;  	info->chip.bbt_td	= pdata->bbt_td;  	info->chip.bbt_md	= pdata->bbt_md; @@ -751,33 +750,8 @@ syndrome_done:  	if (ret < 0)  		goto err_scan; -	if (mtd_has_cmdlinepart()) { -		static const char *probes[] __initconst = { -			"cmdlinepart", NULL -		}; - -		mtd_parts_nb = parse_mtd_partitions(&info->mtd, probes, -						    &mtd_parts, 0); -	} - -	if (mtd_parts_nb <= 0) { -		mtd_parts = pdata->parts; -		mtd_parts_nb = pdata->nr_parts; -	} - -	/* Register any partitions */ -	if (mtd_parts_nb > 0) { -		ret = mtd_device_register(&info->mtd, mtd_parts, -					  mtd_parts_nb); -		if (ret == 0) -			info->partitioned = true; -	} - -	/* If there's no partition info, just package the whole chip -	 * as a single MTD device. -	 */ -	if (!info->partitioned) -		ret = mtd_device_register(&info->mtd, NULL, 0) ? -ENODEV : 0; +	ret = mtd_device_parse_register(&info->mtd, NULL, 0, +			pdata->parts, pdata->nr_parts);  	if (ret < 0)  		goto err_scan; @@ -816,9 +790,6 @@ err_nomem:  static int __exit nand_davinci_remove(struct platform_device *pdev)  {  	struct davinci_nand_info *info = platform_get_drvdata(pdev); -	int status; - -	status = mtd_device_unregister(&info->mtd);  	spin_lock_irq(&davinci_nand_lock);  	if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index d5276218945f..3984d488f9ab 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1346,6 +1346,7 @@ static void denali_hw_init(struct denali_nand_info *denali)  	 * */  	denali->bbtskipbytes = ioread32(denali->flash_reg +  						SPARE_AREA_SKIP_BYTES); +	detect_max_banks(denali);  	denali_nand_reset(denali);  	iowrite32(0x0F, denali->flash_reg + RB_PIN_ENABLED);  	iowrite32(CHIP_EN_DONT_CARE__FLAG, @@ -1356,7 +1357,6 @@ static void denali_hw_init(struct denali_nand_info *denali)  	/* Should set value for these registers when init */  	iowrite32(0, denali->flash_reg + TWO_ROW_ADDR_CYCLES);  	iowrite32(1, denali->flash_reg + ECC_ENABLE); -	detect_max_banks(denali);  	denali_nand_timing_set(denali);  	denali_irq_init(denali);  } @@ -1577,7 +1577,8 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)  	denali->nand.bbt_md = &bbt_mirror_descr;  	/* skip the scan for now until we have OOB read and write support */ -	denali->nand.options |= NAND_USE_FLASH_BBT | NAND_SKIP_BBTSCAN; +	denali->nand.bbt_options |= NAND_BBT_USE_FLASH; +	denali->nand.options |= NAND_SKIP_BBTSCAN;  	denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME;  	/* Denali Controller only support 15bit and 8bit ECC in MRST, @@ -1676,7 +1677,6 @@ static void denali_pci_remove(struct pci_dev *dev)  	struct denali_nand_info *denali = pci_get_drvdata(dev);  	nand_release(&denali->mtd); -	mtd_device_unregister(&denali->mtd);  	denali_irq_cleanup(dev->irq, denali); diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index e1b84cb90f0d..5780dbab6113 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -133,7 +133,7 @@ static struct rs_control *rs_decoder;  /*   * The HW decoder in the DoC ASIC's provides us a error syndrome, - * which we must convert to a standard syndrom usable by the generic + * which we must convert to a standard syndrome usable by the generic   * Reed-Solomon library code.   *   * Fabrice Bellard figured this out in the old docecc code. I added @@ -154,7 +154,7 @@ static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)  	ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2);  	parity = ecc[1]; -	/* Initialize the syndrom buffer */ +	/* Initialize the syndrome buffer */  	for (i = 0; i < NROOTS; i++)  		s[i] = ds[0];  	/* @@ -1032,7 +1032,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,  		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);  	else  		WriteDOC(DOC_ECC_DIS, docptr, ECCConf); -	if (no_ecc_failures && (ret == -EBADMSG)) { +	if (no_ecc_failures && mtd_is_eccerr(ret)) {  		printk(KERN_ERR "suppressing ECC failure\n");  		ret = 0;  	} @@ -1653,7 +1653,7 @@ static int __init doc_probe(unsigned long physadr)  	nand->ecc.mode		= NAND_ECC_HW_SYNDROME;  	nand->ecc.size		= 512;  	nand->ecc.bytes		= 6; -	nand->options		= NAND_USE_FLASH_BBT; +	nand->bbt_options	= NAND_BBT_USE_FLASH;  	doc->physadr		= physadr;  	doc->virtadr		= virtadr; diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c deleted file mode 100644 index 8400d0f6dada..000000000000 --- a/drivers/mtd/nand/edb7312.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - *  drivers/mtd/nand/edb7312.c - * - *  Copyright (C) 2002 Marius Gröger (mag@sysgo.de) - * - *  Derived from drivers/mtd/nand/autcpu12.c - *       Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - *  Overview: - *   This is a device driver for the NAND flash device found on the - *   CLEP7312 board which utilizes the Toshiba TC58V64AFT part. This is - *   a 64Mibit (8MiB x 8 bits) NAND flash device. - */ - -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/nand.h> -#include <linux/mtd/partitions.h> -#include <asm/io.h> -#include <mach/hardware.h>	/* for CLPS7111_VIRT_BASE */ -#include <asm/sizes.h> -#include <asm/hardware/clps7111.h> - -/* - * MTD structure for EDB7312 board - */ -static struct mtd_info *ep7312_mtd = NULL; - -/* - * Values specific to the EDB7312 board (used with EP7312 processor) - */ -#define EP7312_FIO_PBASE 0x10000000	/* Phys address of flash */ -#define EP7312_PXDR	0x0001	/* -				 * IO offset to Port B data register -				 * where the CLE, ALE and NCE pins -				 * are wired to. -				 */ -#define EP7312_PXDDR	0x0041	/* -				 * IO offset to Port B data direction -				 * register so we can control the IO -				 * lines. -				 */ - -/* - * Module stuff - */ - -static unsigned long ep7312_fio_pbase = EP7312_FIO_PBASE; -static void __iomem *ep7312_pxdr = (void __iomem *)EP7312_PXDR; -static void __iomem *ep7312_pxddr = (void __iomem *)EP7312_PXDDR; - -/* - * Define static partitions for flash device - */ -static struct mtd_partition partition_info[] = { -	{.name = "EP7312 Nand Flash", -	 .offset = 0, -	 .size = 8 * 1024 * 1024} -}; - -#define NUM_PARTITIONS 1 - -/* - *	hardware specific access to control-lines - * - *	NAND_NCE: bit 0 -> bit 6 (bit 7 = 1) - *	NAND_CLE: bit 1 -> bit 4 - *	NAND_ALE: bit 2 -> bit 5 - */ -static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ -	struct nand_chip *chip = mtd->priv; - -	if (ctrl & NAND_CTRL_CHANGE) { -		unsigned char bits = 0x80; - -		bits |= (ctrl & (NAND_CLE | NAND_ALE)) << 3; -		bits |= (ctrl & NAND_NCE) ? 0x00 : 0x40; - -		clps_writeb((clps_readb(ep7312_pxdr)  & 0xF0) | bits, -			    ep7312_pxdr); -	} -	if (cmd != NAND_CMD_NONE) -		writeb(cmd, chip->IO_ADDR_W); -} - -/* - *	read device ready pin - */ -static int ep7312_device_ready(struct mtd_info *mtd) -{ -	return 1; -} - -const char *part_probes[] = { "cmdlinepart", NULL }; - -/* - * Main initialization routine - */ -static int __init ep7312_init(void) -{ -	struct nand_chip *this; -	const char *part_type = 0; -	int mtd_parts_nb = 0; -	struct mtd_partition *mtd_parts = 0; -	void __iomem *ep7312_fio_base; - -	/* Allocate memory for MTD device structure and private data */ -	ep7312_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); -	if (!ep7312_mtd) { -		printk("Unable to allocate EDB7312 NAND MTD device structure.\n"); -		return -ENOMEM; -	} - -	/* map physical address */ -	ep7312_fio_base = ioremap(ep7312_fio_pbase, SZ_1K); -	if (!ep7312_fio_base) { -		printk("ioremap EDB7312 NAND flash failed\n"); -		kfree(ep7312_mtd); -		return -EIO; -	} - -	/* Get pointer to private data */ -	this = (struct nand_chip *)(&ep7312_mtd[1]); - -	/* Initialize structures */ -	memset(ep7312_mtd, 0, sizeof(struct mtd_info)); -	memset(this, 0, sizeof(struct nand_chip)); - -	/* Link the private data with the MTD structure */ -	ep7312_mtd->priv = this; -	ep7312_mtd->owner = THIS_MODULE; - -	/* -	 * Set GPIO Port B control register so that the pins are configured -	 * to be outputs for controlling the NAND flash. -	 */ -	clps_writeb(0xf0, ep7312_pxddr); - -	/* insert callbacks */ -	this->IO_ADDR_R = ep7312_fio_base; -	this->IO_ADDR_W = ep7312_fio_base; -	this->cmd_ctrl = ep7312_hwcontrol; -	this->dev_ready = ep7312_device_ready; -	/* 15 us command delay time */ -	this->chip_delay = 15; - -	/* Scan to find existence of the device */ -	if (nand_scan(ep7312_mtd, 1)) { -		iounmap((void *)ep7312_fio_base); -		kfree(ep7312_mtd); -		return -ENXIO; -	} -	ep7312_mtd->name = "edb7312-nand"; -	mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes, &mtd_parts, 0); -	if (mtd_parts_nb > 0) -		part_type = "command line"; -	else -		mtd_parts_nb = 0; -	if (mtd_parts_nb == 0) { -		mtd_parts = partition_info; -		mtd_parts_nb = NUM_PARTITIONS; -		part_type = "static"; -	} - -	/* Register the partitions */ -	printk(KERN_NOTICE "Using %s partition definition\n", part_type); -	mtd_device_register(ep7312_mtd, mtd_parts, mtd_parts_nb); - -	/* Return happy */ -	return 0; -} - -module_init(ep7312_init); - -/* - * Clean up routine - */ -static void __exit ep7312_cleanup(void) -{ -	struct nand_chip *this = (struct nand_chip *)&ep7312_mtd[1]; - -	/* Release resources, unregister device */ -	nand_release(ap7312_mtd); - -	/* Release io resource */ -	iounmap(this->IO_ADDR_R); - -	/* Free the MTD device structure */ -	kfree(ep7312_mtd); -} - -module_exit(ep7312_cleanup); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>"); -MODULE_DESCRIPTION("MTD map driver for Cogent EDB7312 board"); diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 33d8aad8bba5..eedd8ee2c9ac 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -75,7 +75,6 @@ struct fsl_elbc_fcm_ctrl {  	unsigned int use_mdr;    /* Non zero if the MDR is to be set      */  	unsigned int oob;        /* Non zero if operating on OOB data     */  	unsigned int counter;	 /* counter for the initializations	  */ -	char *oob_poi;           /* Place to write ECC after read back    */  };  /* These map to the positions used by the FCM hardware ECC generator */ @@ -244,6 +243,25 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)  		return -EIO;  	} +	if (chip->ecc.mode != NAND_ECC_HW) +		return 0; + +	if (elbc_fcm_ctrl->read_bytes == mtd->writesize + mtd->oobsize) { +		uint32_t lteccr = in_be32(&lbc->lteccr); +		/* +		 * if command was a full page read and the ELBC +		 * has the LTECCR register, then bits 12-15 (ppc order) of +		 * LTECCR indicates which 512 byte sub-pages had fixed errors. +		 * bits 28-31 are uncorrectable errors, marked elsewhere. +		 * for small page nand only 1 bit is used. +		 * if the ELBC doesn't have the lteccr register it reads 0 +		 */ +		if (lteccr & 0x000F000F) +			out_be32(&lbc->lteccr, 0x000F000F); /* clear lteccr */ +		if (lteccr & 0x000F0000) +			mtd->ecc_stats.corrected++; +	} +  	return 0;  } @@ -435,7 +453,6 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,  	/* PAGEPROG reuses all of the setup from SEQIN and adds the length */  	case NAND_CMD_PAGEPROG: { -		int full_page;  		dev_vdbg(priv->dev,  		         "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "  			 "writing %d bytes.\n", elbc_fcm_ctrl->index); @@ -445,34 +462,12 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,  		 * write so the HW generates the ECC.  		 */  		if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 || -		    elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize) { +		    elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize)  			out_be32(&lbc->fbcr, elbc_fcm_ctrl->index); -			full_page = 0; -		} else { +		else  			out_be32(&lbc->fbcr, 0); -			full_page = 1; -		}  		fsl_elbc_run_command(mtd); - -		/* Read back the page in order to fill in the ECC for the -		 * caller.  Is this really needed? -		 */ -		if (full_page && elbc_fcm_ctrl->oob_poi) { -			out_be32(&lbc->fbcr, 3); -			set_addr(mtd, 6, page_addr, 1); - -			elbc_fcm_ctrl->read_bytes = mtd->writesize + 9; - -			fsl_elbc_do_read(chip, 1); -			fsl_elbc_run_command(mtd); - -			memcpy_fromio(elbc_fcm_ctrl->oob_poi + 6, -				&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], 3); -			elbc_fcm_ctrl->index += 3; -		} - -		elbc_fcm_ctrl->oob_poi = NULL;  		return;  	} @@ -752,13 +747,8 @@ static void fsl_elbc_write_page(struct mtd_info *mtd,                                  struct nand_chip *chip,                                  const uint8_t *buf)  { -	struct fsl_elbc_mtd *priv = chip->priv; -	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; -  	fsl_elbc_write_buf(mtd, buf, mtd->writesize);  	fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); - -	elbc_fcm_ctrl->oob_poi = chip->oob_poi;  }  static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) @@ -791,8 +781,8 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)  	chip->bbt_md = &bbt_mirror_descr;  	/* set up nand options */ -	chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR | -			NAND_USE_FLASH_BBT; +	chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR; +	chip->bbt_options = NAND_BBT_USE_FLASH;  	chip->controller = &elbc_fcm_ctrl->controller;  	chip->priv = priv; @@ -829,7 +819,6 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)  	elbc_fcm_ctrl->chips[priv->bank] = NULL;  	kfree(priv); -	kfree(elbc_fcm_ctrl);  	return 0;  } @@ -842,13 +831,14 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev)  	struct resource res;  	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl;  	static const char *part_probe_types[] -		= { "cmdlinepart", "RedBoot", NULL }; -	struct mtd_partition *parts; +		= { "cmdlinepart", "RedBoot", "ofpart", NULL };  	int ret;  	int bank;  	struct device *dev;  	struct device_node *node = pdev->dev.of_node; +	struct mtd_part_parser_data ppdata; +	ppdata.of_node = pdev->dev.of_node;  	if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)  		return -ENODEV;  	lbc = fsl_lbc_ctrl_dev->regs; @@ -934,17 +924,8 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev)  	/* First look for RedBoot table or partitions on the command  	 * line, these take precedence over device tree information */ -	ret = parse_mtd_partitions(&priv->mtd, part_probe_types, &parts, 0); -	if (ret < 0) -		goto err; - -	if (ret == 0) { -		ret = of_mtd_parse_partitions(priv->dev, node, &parts); -		if (ret < 0) -			goto err; -	} - -	mtd_device_register(&priv->mtd, parts, ret); +	mtd_device_parse_register(&priv->mtd, part_probe_types, &ppdata, +				  NULL, 0);  	printk(KERN_INFO "eLBC NAND device at 0x%llx, bank %d\n",  	       (unsigned long long)res.start, priv->bank); diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 23752fd5bc59..b4f3cc9f32fb 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -158,7 +158,7 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun,  {  	int ret;  	struct device_node *flash_np; -	static const char *part_types[] = { "cmdlinepart", NULL, }; +	struct mtd_part_parser_data ppdata;  	fun->chip.IO_ADDR_R = fun->io_base;  	fun->chip.IO_ADDR_W = fun->io_base; @@ -192,18 +192,12 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun,  	if (ret)  		goto err; -	ret = parse_mtd_partitions(&fun->mtd, part_types, &fun->parts, 0); - -#ifdef CONFIG_MTD_OF_PARTS -	if (ret == 0) { -		ret = of_mtd_parse_partitions(fun->dev, flash_np, &fun->parts); -		if (ret < 0) -			goto err; -	} -#endif -	ret = mtd_device_register(&fun->mtd, fun->parts, ret); +	ppdata.of_node = flash_np; +	ret = mtd_device_parse_register(&fun->mtd, NULL, &ppdata, NULL, 0);  err:  	of_node_put(flash_np); +	if (ret) +		kfree(fun->mtd.name);  	return ret;  } diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index e9b275ac381c..e53b76064133 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -146,7 +146,7 @@ static struct mtd_partition partition_info_16KB_blk[] = {  	{  		.name = "Root File System",  		.offset = 0x460000, -		.size = 0, +		.size = MTDPART_SIZ_FULL,  	},  }; @@ -173,13 +173,10 @@ static struct mtd_partition partition_info_128KB_blk[] = {  	{  		.name = "Root File System",  		.offset = 0x800000, -		.size = 0, +		.size = MTDPART_SIZ_FULL,  	},  }; -#ifdef CONFIG_MTD_CMDLINE_PARTS -const char *part_probes[] = { "cmdlinepart", NULL }; -#endif  /**   * struct fsmc_nand_data - structure for FSMC NAND device state @@ -187,8 +184,6 @@ const char *part_probes[] = { "cmdlinepart", NULL };   * @pid:		Part ID on the AMBA PrimeCell format   * @mtd:		MTD info for a NAND flash.   * @nand:		Chip related info for a NAND flash. - * @partitions:		Partition info for a NAND Flash. - * @nr_partitions:	Total number of partition of a NAND flash.   *   * @ecc_place:		ECC placing locations in oobfree type format.   * @bank:		Bank number for probed device. @@ -203,8 +198,6 @@ struct fsmc_nand_data {  	u32			pid;  	struct mtd_info		mtd;  	struct nand_chip	nand; -	struct mtd_partition	*partitions; -	unsigned int		nr_partitions;  	struct fsmc_eccplace	*ecc_place;  	unsigned int		bank; @@ -716,65 +709,17 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)  	 * platform data,  	 * default partition information present in driver.  	 */ -#ifdef CONFIG_MTD_CMDLINE_PARTS  	/* -	 * Check if partition info passed via command line +	 * Check for partition info passed  	 */  	host->mtd.name = "nand"; -	host->nr_partitions = parse_mtd_partitions(&host->mtd, part_probes, -			&host->partitions, 0); -	if (host->nr_partitions <= 0) { -#endif -		/* -		 * Check if partition info passed via command line -		 */ -		if (pdata->partitions) { -			host->partitions = pdata->partitions; -			host->nr_partitions = pdata->nr_partitions; -		} else { -			struct mtd_partition *partition; -			int i; - -			/* Select the default partitions info */ -			switch (host->mtd.size) { -			case 0x01000000: -			case 0x02000000: -			case 0x04000000: -				host->partitions = partition_info_16KB_blk; -				host->nr_partitions = -					sizeof(partition_info_16KB_blk) / -					sizeof(struct mtd_partition); -				break; -			case 0x08000000: -			case 0x10000000: -			case 0x20000000: -			case 0x40000000: -				host->partitions = partition_info_128KB_blk; -				host->nr_partitions = -					sizeof(partition_info_128KB_blk) / -					sizeof(struct mtd_partition); -				break; -			default: -				ret = -ENXIO; -				pr_err("Unsupported NAND size\n"); -				goto err_probe; -			} - -			partition = host->partitions; -			for (i = 0; i < host->nr_partitions; i++, partition++) { -				if (partition->size == 0) { -					partition->size = host->mtd.size - -						partition->offset; -					break; -				} -			} -		} -#ifdef CONFIG_MTD_CMDLINE_PARTS -	} -#endif - -	ret = mtd_device_register(&host->mtd, host->partitions, -				  host->nr_partitions); +	ret = mtd_device_parse_register(&host->mtd, NULL, 0, +			host->mtd.size <= 0x04000000 ? +				partition_info_16KB_blk : +				partition_info_128KB_blk, +			host->mtd.size <= 0x04000000 ? +				ARRAY_SIZE(partition_info_16KB_blk) : +				ARRAY_SIZE(partition_info_128KB_blk));  	if (ret)  		goto err_probe; @@ -822,7 +767,7 @@ static int fsmc_nand_remove(struct platform_device *pdev)  	platform_set_drvdata(pdev, NULL);  	if (host) { -		mtd_device_unregister(&host->mtd); +		nand_release(&host->mtd);  		clk_disable(host->clk);  		clk_put(host->clk); diff --git a/drivers/mtd/nand/gpmi-nand/Makefile b/drivers/mtd/nand/gpmi-nand/Makefile new file mode 100644 index 000000000000..3a462487c35e --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi_nand.o +gpmi_nand-objs += gpmi-nand.o +gpmi_nand-objs += gpmi-lib.o diff --git a/drivers/mtd/nand/gpmi-nand/bch-regs.h b/drivers/mtd/nand/gpmi-nand/bch-regs.h new file mode 100644 index 000000000000..4effb8c579db --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/bch-regs.h @@ -0,0 +1,84 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright 2008 Embedded Alley Solutions, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef __GPMI_NAND_BCH_REGS_H +#define __GPMI_NAND_BCH_REGS_H + +#define HW_BCH_CTRL				0x00000000 +#define HW_BCH_CTRL_SET				0x00000004 +#define HW_BCH_CTRL_CLR				0x00000008 +#define HW_BCH_CTRL_TOG				0x0000000c + +#define BM_BCH_CTRL_COMPLETE_IRQ_EN		(1 << 8) +#define BM_BCH_CTRL_COMPLETE_IRQ		(1 << 0) + +#define HW_BCH_STATUS0				0x00000010 +#define HW_BCH_MODE				0x00000020 +#define HW_BCH_ENCODEPTR			0x00000030 +#define HW_BCH_DATAPTR				0x00000040 +#define HW_BCH_METAPTR				0x00000050 +#define HW_BCH_LAYOUTSELECT			0x00000070 + +#define HW_BCH_FLASH0LAYOUT0			0x00000080 + +#define BP_BCH_FLASH0LAYOUT0_NBLOCKS		24 +#define BM_BCH_FLASH0LAYOUT0_NBLOCKS	(0xff << BP_BCH_FLASH0LAYOUT0_NBLOCKS) +#define BF_BCH_FLASH0LAYOUT0_NBLOCKS(v)		\ +	(((v) << BP_BCH_FLASH0LAYOUT0_NBLOCKS) & BM_BCH_FLASH0LAYOUT0_NBLOCKS) + +#define BP_BCH_FLASH0LAYOUT0_META_SIZE		16 +#define BM_BCH_FLASH0LAYOUT0_META_SIZE	(0xff << BP_BCH_FLASH0LAYOUT0_META_SIZE) +#define BF_BCH_FLASH0LAYOUT0_META_SIZE(v)	\ +	(((v) << BP_BCH_FLASH0LAYOUT0_META_SIZE)\ +					 & BM_BCH_FLASH0LAYOUT0_META_SIZE) + +#define BP_BCH_FLASH0LAYOUT0_ECC0		12 +#define BM_BCH_FLASH0LAYOUT0_ECC0	(0xf << BP_BCH_FLASH0LAYOUT0_ECC0) +#define BF_BCH_FLASH0LAYOUT0_ECC0(v)		\ +	(((v) << BP_BCH_FLASH0LAYOUT0_ECC0) & BM_BCH_FLASH0LAYOUT0_ECC0) + +#define BP_BCH_FLASH0LAYOUT0_DATA0_SIZE		0 +#define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE		\ +			(0xfff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE) +#define BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v)	\ +	(((v) << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE)\ +					 & BM_BCH_FLASH0LAYOUT0_DATA0_SIZE) + +#define HW_BCH_FLASH0LAYOUT1			0x00000090 + +#define BP_BCH_FLASH0LAYOUT1_PAGE_SIZE		16 +#define BM_BCH_FLASH0LAYOUT1_PAGE_SIZE		\ +			(0xffff << BP_BCH_FLASH0LAYOUT1_PAGE_SIZE) +#define BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(v)	\ +	(((v) << BP_BCH_FLASH0LAYOUT1_PAGE_SIZE) \ +					 & BM_BCH_FLASH0LAYOUT1_PAGE_SIZE) + +#define BP_BCH_FLASH0LAYOUT1_ECCN		12 +#define BM_BCH_FLASH0LAYOUT1_ECCN	(0xf << BP_BCH_FLASH0LAYOUT1_ECCN) +#define BF_BCH_FLASH0LAYOUT1_ECCN(v)		\ +	(((v) << BP_BCH_FLASH0LAYOUT1_ECCN) & BM_BCH_FLASH0LAYOUT1_ECCN) + +#define BP_BCH_FLASH0LAYOUT1_DATAN_SIZE		0 +#define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE		\ +			(0xfff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE) +#define BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v)	\ +	(((v) << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE) \ +					 & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE) +#endif diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c new file mode 100644 index 000000000000..de4db7604a3f --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -0,0 +1,1057 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008 Embedded Alley Solutions, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include <linux/mtd/gpmi-nand.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <mach/mxs.h> + +#include "gpmi-nand.h" +#include "gpmi-regs.h" +#include "bch-regs.h" + +struct timing_threshod timing_default_threshold = { +	.max_data_setup_cycles       = (BM_GPMI_TIMING0_DATA_SETUP >> +						BP_GPMI_TIMING0_DATA_SETUP), +	.internal_data_setup_in_ns   = 0, +	.max_sample_delay_factor     = (BM_GPMI_CTRL1_RDN_DELAY >> +						BP_GPMI_CTRL1_RDN_DELAY), +	.max_dll_clock_period_in_ns  = 32, +	.max_dll_delay_in_ns         = 16, +}; + +/* + * Clear the bit and poll it cleared.  This is usually called with + * a reset address and mask being either SFTRST(bit 31) or CLKGATE + * (bit 30). + */ +static int clear_poll_bit(void __iomem *addr, u32 mask) +{ +	int timeout = 0x400; + +	/* clear the bit */ +	__mxs_clrl(mask, addr); + +	/* +	 * SFTRST needs 3 GPMI clocks to settle, the reference manual +	 * recommends to wait 1us. +	 */ +	udelay(1); + +	/* poll the bit becoming clear */ +	while ((readl(addr) & mask) && --timeout) +		/* nothing */; + +	return !timeout; +} + +#define MODULE_CLKGATE		(1 << 30) +#define MODULE_SFTRST		(1 << 31) +/* + * The current mxs_reset_block() will do two things: + *  [1] enable the module. + *  [2] reset the module. + * + * In most of the cases, it's ok. But there is a hardware bug in the BCH block. + * If you try to soft reset the BCH block, it becomes unusable until + * the next hard reset. This case occurs in the NAND boot mode. When the board + * boots by NAND, the ROM of the chip will initialize the BCH blocks itself. + * So If the driver tries to reset the BCH again, the BCH will not work anymore. + * You will see a DMA timeout in this case. + * + * To avoid this bug, just add a new parameter `just_enable` for + * the mxs_reset_block(), and rewrite it here. + */ +int gpmi_reset_block(void __iomem *reset_addr, bool just_enable) +{ +	int ret; +	int timeout = 0x400; + +	/* clear and poll SFTRST */ +	ret = clear_poll_bit(reset_addr, MODULE_SFTRST); +	if (unlikely(ret)) +		goto error; + +	/* clear CLKGATE */ +	__mxs_clrl(MODULE_CLKGATE, reset_addr); + +	if (!just_enable) { +		/* set SFTRST to reset the block */ +		__mxs_setl(MODULE_SFTRST, reset_addr); +		udelay(1); + +		/* poll CLKGATE becoming set */ +		while ((!(readl(reset_addr) & MODULE_CLKGATE)) && --timeout) +			/* nothing */; +		if (unlikely(!timeout)) +			goto error; +	} + +	/* clear and poll SFTRST */ +	ret = clear_poll_bit(reset_addr, MODULE_SFTRST); +	if (unlikely(ret)) +		goto error; + +	/* clear and poll CLKGATE */ +	ret = clear_poll_bit(reset_addr, MODULE_CLKGATE); +	if (unlikely(ret)) +		goto error; + +	return 0; + +error: +	pr_err("%s(%p): module reset timeout\n", __func__, reset_addr); +	return -ETIMEDOUT; +} + +int gpmi_init(struct gpmi_nand_data *this) +{ +	struct resources *r = &this->resources; +	int ret; + +	ret = clk_enable(r->clock); +	if (ret) +		goto err_out; +	ret = gpmi_reset_block(r->gpmi_regs, false); +	if (ret) +		goto err_out; + +	/* Choose NAND mode. */ +	writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR); + +	/* Set the IRQ polarity. */ +	writel(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY, +				r->gpmi_regs + HW_GPMI_CTRL1_SET); + +	/* Disable Write-Protection. */ +	writel(BM_GPMI_CTRL1_DEV_RESET, r->gpmi_regs + HW_GPMI_CTRL1_SET); + +	/* Select BCH ECC. */ +	writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET); + +	clk_disable(r->clock); +	return 0; +err_out: +	return ret; +} + +/* This function is very useful. It is called only when the bug occur. */ +void gpmi_dump_info(struct gpmi_nand_data *this) +{ +	struct resources *r = &this->resources; +	struct bch_geometry *geo = &this->bch_geometry; +	u32 reg; +	int i; + +	pr_err("Show GPMI registers :\n"); +	for (i = 0; i <= HW_GPMI_DEBUG / 0x10 + 1; i++) { +		reg = readl(r->gpmi_regs + i * 0x10); +		pr_err("offset 0x%.3x : 0x%.8x\n", i * 0x10, reg); +	} + +	/* start to print out the BCH info */ +	pr_err("BCH Geometry :\n"); +	pr_err("GF length              : %u\n", geo->gf_len); +	pr_err("ECC Strength           : %u\n", geo->ecc_strength); +	pr_err("Page Size in Bytes     : %u\n", geo->page_size); +	pr_err("Metadata Size in Bytes : %u\n", geo->metadata_size); +	pr_err("ECC Chunk Size in Bytes: %u\n", geo->ecc_chunk_size); +	pr_err("ECC Chunk Count        : %u\n", geo->ecc_chunk_count); +	pr_err("Payload Size in Bytes  : %u\n", geo->payload_size); +	pr_err("Auxiliary Size in Bytes: %u\n", geo->auxiliary_size); +	pr_err("Auxiliary Status Offset: %u\n", geo->auxiliary_status_offset); +	pr_err("Block Mark Byte Offset : %u\n", geo->block_mark_byte_offset); +	pr_err("Block Mark Bit Offset  : %u\n", geo->block_mark_bit_offset); +} + +/* Configures the geometry for BCH.  */ +int bch_set_geometry(struct gpmi_nand_data *this) +{ +	struct resources *r = &this->resources; +	struct bch_geometry *bch_geo = &this->bch_geometry; +	unsigned int block_count; +	unsigned int block_size; +	unsigned int metadata_size; +	unsigned int ecc_strength; +	unsigned int page_size; +	int ret; + +	if (common_nfc_set_geometry(this)) +		return !0; + +	block_count   = bch_geo->ecc_chunk_count - 1; +	block_size    = bch_geo->ecc_chunk_size; +	metadata_size = bch_geo->metadata_size; +	ecc_strength  = bch_geo->ecc_strength >> 1; +	page_size     = bch_geo->page_size; + +	ret = clk_enable(r->clock); +	if (ret) +		goto err_out; + +	ret = gpmi_reset_block(r->bch_regs, true); +	if (ret) +		goto err_out; + +	/* Configure layout 0. */ +	writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count) +			| BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size) +			| BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength) +			| BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size), +			r->bch_regs + HW_BCH_FLASH0LAYOUT0); + +	writel(BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size) +			| BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength) +			| BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size), +			r->bch_regs + HW_BCH_FLASH0LAYOUT1); + +	/* Set *all* chip selects to use layout 0. */ +	writel(0, r->bch_regs + HW_BCH_LAYOUTSELECT); + +	/* Enable interrupts. */ +	writel(BM_BCH_CTRL_COMPLETE_IRQ_EN, +				r->bch_regs + HW_BCH_CTRL_SET); + +	clk_disable(r->clock); +	return 0; +err_out: +	return ret; +} + +/* Converts time in nanoseconds to cycles. */ +static unsigned int ns_to_cycles(unsigned int time, +			unsigned int period, unsigned int min) +{ +	unsigned int k; + +	k = (time + period - 1) / period; +	return max(k, min); +} + +/* Apply timing to current hardware conditions. */ +static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, +					struct gpmi_nfc_hardware_timing *hw) +{ +	struct gpmi_nand_platform_data *pdata = this->pdata; +	struct timing_threshod *nfc = &timing_default_threshold; +	struct nand_chip *nand = &this->nand; +	struct nand_timing target = this->timing; +	bool improved_timing_is_available; +	unsigned long clock_frequency_in_hz; +	unsigned int clock_period_in_ns; +	bool dll_use_half_periods; +	unsigned int dll_delay_shift; +	unsigned int max_sample_delay_in_ns; +	unsigned int address_setup_in_cycles; +	unsigned int data_setup_in_ns; +	unsigned int data_setup_in_cycles; +	unsigned int data_hold_in_cycles; +	int ideal_sample_delay_in_ns; +	unsigned int sample_delay_factor; +	int tEYE; +	unsigned int min_prop_delay_in_ns = pdata->min_prop_delay_in_ns; +	unsigned int max_prop_delay_in_ns = pdata->max_prop_delay_in_ns; + +	/* +	 * If there are multiple chips, we need to relax the timings to allow +	 * for signal distortion due to higher capacitance. +	 */ +	if (nand->numchips > 2) { +		target.data_setup_in_ns    += 10; +		target.data_hold_in_ns     += 10; +		target.address_setup_in_ns += 10; +	} else if (nand->numchips > 1) { +		target.data_setup_in_ns    += 5; +		target.data_hold_in_ns     += 5; +		target.address_setup_in_ns += 5; +	} + +	/* Check if improved timing information is available. */ +	improved_timing_is_available = +		(target.tREA_in_ns  >= 0) && +		(target.tRLOH_in_ns >= 0) && +		(target.tRHOH_in_ns >= 0) ; + +	/* Inspect the clock. */ +	clock_frequency_in_hz = nfc->clock_frequency_in_hz; +	clock_period_in_ns    = 1000000000 / clock_frequency_in_hz; + +	/* +	 * The NFC quantizes setup and hold parameters in terms of clock cycles. +	 * Here, we quantize the setup and hold timing parameters to the +	 * next-highest clock period to make sure we apply at least the +	 * specified times. +	 * +	 * For data setup and data hold, the hardware interprets a value of zero +	 * as the largest possible delay. This is not what's intended by a zero +	 * in the input parameter, so we impose a minimum of one cycle. +	 */ +	data_setup_in_cycles    = ns_to_cycles(target.data_setup_in_ns, +							clock_period_in_ns, 1); +	data_hold_in_cycles     = ns_to_cycles(target.data_hold_in_ns, +							clock_period_in_ns, 1); +	address_setup_in_cycles = ns_to_cycles(target.address_setup_in_ns, +							clock_period_in_ns, 0); + +	/* +	 * The clock's period affects the sample delay in a number of ways: +	 * +	 * (1) The NFC HAL tells us the maximum clock period the sample delay +	 *     DLL can tolerate. If the clock period is greater than half that +	 *     maximum, we must configure the DLL to be driven by half periods. +	 * +	 * (2) We need to convert from an ideal sample delay, in ns, to a +	 *     "sample delay factor," which the NFC uses. This factor depends on +	 *     whether we're driving the DLL with full or half periods. +	 *     Paraphrasing the reference manual: +	 * +	 *         AD = SDF x 0.125 x RP +	 * +	 * where: +	 * +	 *     AD   is the applied delay, in ns. +	 *     SDF  is the sample delay factor, which is dimensionless. +	 *     RP   is the reference period, in ns, which is a full clock period +	 *          if the DLL is being driven by full periods, or half that if +	 *          the DLL is being driven by half periods. +	 * +	 * Let's re-arrange this in a way that's more useful to us: +	 * +	 *                        8 +	 *         SDF  =  AD x ---- +	 *                       RP +	 * +	 * The reference period is either the clock period or half that, so this +	 * is: +	 * +	 *                        8       AD x DDF +	 *         SDF  =  AD x -----  =  -------- +	 *                      f x P        P +	 * +	 * where: +	 * +	 *       f  is 1 or 1/2, depending on how we're driving the DLL. +	 *       P  is the clock period. +	 *     DDF  is the DLL Delay Factor, a dimensionless value that +	 *          incorporates all the constants in the conversion. +	 * +	 * DDF will be either 8 or 16, both of which are powers of two. We can +	 * reduce the cost of this conversion by using bit shifts instead of +	 * multiplication or division. Thus: +	 * +	 *                 AD << DDS +	 *         SDF  =  --------- +	 *                     P +	 * +	 *     or +	 * +	 *         AD  =  (SDF >> DDS) x P +	 * +	 * where: +	 * +	 *     DDS  is the DLL Delay Shift, the logarithm to base 2 of the DDF. +	 */ +	if (clock_period_in_ns > (nfc->max_dll_clock_period_in_ns >> 1)) { +		dll_use_half_periods = true; +		dll_delay_shift      = 3 + 1; +	} else { +		dll_use_half_periods = false; +		dll_delay_shift      = 3; +	} + +	/* +	 * Compute the maximum sample delay the NFC allows, under current +	 * conditions. If the clock is running too slowly, no sample delay is +	 * possible. +	 */ +	if (clock_period_in_ns > nfc->max_dll_clock_period_in_ns) +		max_sample_delay_in_ns = 0; +	else { +		/* +		 * Compute the delay implied by the largest sample delay factor +		 * the NFC allows. +		 */ +		max_sample_delay_in_ns = +			(nfc->max_sample_delay_factor * clock_period_in_ns) >> +								dll_delay_shift; + +		/* +		 * Check if the implied sample delay larger than the NFC +		 * actually allows. +		 */ +		if (max_sample_delay_in_ns > nfc->max_dll_delay_in_ns) +			max_sample_delay_in_ns = nfc->max_dll_delay_in_ns; +	} + +	/* +	 * Check if improved timing information is available. If not, we have to +	 * use a less-sophisticated algorithm. +	 */ +	if (!improved_timing_is_available) { +		/* +		 * Fold the read setup time required by the NFC into the ideal +		 * sample delay. +		 */ +		ideal_sample_delay_in_ns = target.gpmi_sample_delay_in_ns + +						nfc->internal_data_setup_in_ns; + +		/* +		 * The ideal sample delay may be greater than the maximum +		 * allowed by the NFC. If so, we can trade off sample delay time +		 * for more data setup time. +		 * +		 * In each iteration of the following loop, we add a cycle to +		 * the data setup time and subtract a corresponding amount from +		 * the sample delay until we've satisified the constraints or +		 * can't do any better. +		 */ +		while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) && +			(data_setup_in_cycles < nfc->max_data_setup_cycles)) { + +			data_setup_in_cycles++; +			ideal_sample_delay_in_ns -= clock_period_in_ns; + +			if (ideal_sample_delay_in_ns < 0) +				ideal_sample_delay_in_ns = 0; + +		} + +		/* +		 * Compute the sample delay factor that corresponds most closely +		 * to the ideal sample delay. If the result is too large for the +		 * NFC, use the maximum value. +		 * +		 * Notice that we use the ns_to_cycles function to compute the +		 * sample delay factor. We do this because the form of the +		 * computation is the same as that for calculating cycles. +		 */ +		sample_delay_factor = +			ns_to_cycles( +				ideal_sample_delay_in_ns << dll_delay_shift, +							clock_period_in_ns, 0); + +		if (sample_delay_factor > nfc->max_sample_delay_factor) +			sample_delay_factor = nfc->max_sample_delay_factor; + +		/* Skip to the part where we return our results. */ +		goto return_results; +	} + +	/* +	 * If control arrives here, we have more detailed timing information, +	 * so we can use a better algorithm. +	 */ + +	/* +	 * Fold the read setup time required by the NFC into the maximum +	 * propagation delay. +	 */ +	max_prop_delay_in_ns += nfc->internal_data_setup_in_ns; + +	/* +	 * Earlier, we computed the number of clock cycles required to satisfy +	 * the data setup time. Now, we need to know the actual nanoseconds. +	 */ +	data_setup_in_ns = clock_period_in_ns * data_setup_in_cycles; + +	/* +	 * Compute tEYE, the width of the data eye when reading from the NAND +	 * Flash. The eye width is fundamentally determined by the data setup +	 * time, perturbed by propagation delays and some characteristics of the +	 * NAND Flash device. +	 * +	 * start of the eye = max_prop_delay + tREA +	 * end of the eye   = min_prop_delay + tRHOH + data_setup +	 */ +	tEYE = (int)min_prop_delay_in_ns + (int)target.tRHOH_in_ns + +							(int)data_setup_in_ns; + +	tEYE -= (int)max_prop_delay_in_ns + (int)target.tREA_in_ns; + +	/* +	 * The eye must be open. If it's not, we can try to open it by +	 * increasing its main forcer, the data setup time. +	 * +	 * In each iteration of the following loop, we increase the data setup +	 * time by a single clock cycle. We do this until either the eye is +	 * open or we run into NFC limits. +	 */ +	while ((tEYE <= 0) && +			(data_setup_in_cycles < nfc->max_data_setup_cycles)) { +		/* Give a cycle to data setup. */ +		data_setup_in_cycles++; +		/* Synchronize the data setup time with the cycles. */ +		data_setup_in_ns += clock_period_in_ns; +		/* Adjust tEYE accordingly. */ +		tEYE += clock_period_in_ns; +	} + +	/* +	 * When control arrives here, the eye is open. The ideal time to sample +	 * the data is in the center of the eye: +	 * +	 *     end of the eye + start of the eye +	 *     ---------------------------------  -  data_setup +	 *                    2 +	 * +	 * After some algebra, this simplifies to the code immediately below. +	 */ +	ideal_sample_delay_in_ns = +		((int)max_prop_delay_in_ns + +			(int)target.tREA_in_ns + +				(int)min_prop_delay_in_ns + +					(int)target.tRHOH_in_ns - +						(int)data_setup_in_ns) >> 1; + +	/* +	 * The following figure illustrates some aspects of a NAND Flash read: +	 * +	 * +	 *           __                   _____________________________________ +	 * RDN         \_________________/ +	 * +	 *                                         <---- tEYE -----> +	 *                                        /-----------------\ +	 * Read Data ----------------------------<                   >--------- +	 *                                        \-----------------/ +	 *             ^                 ^                 ^              ^ +	 *             |                 |                 |              | +	 *             |<--Data Setup -->|<--Delay Time -->|              | +	 *             |                 |                 |              | +	 *             |                 |                                | +	 *             |                 |<--   Quantized Delay Time   -->| +	 *             |                 |                                | +	 * +	 * +	 * We have some issues we must now address: +	 * +	 * (1) The *ideal* sample delay time must not be negative. If it is, we +	 *     jam it to zero. +	 * +	 * (2) The *ideal* sample delay time must not be greater than that +	 *     allowed by the NFC. If it is, we can increase the data setup +	 *     time, which will reduce the delay between the end of the data +	 *     setup and the center of the eye. It will also make the eye +	 *     larger, which might help with the next issue... +	 * +	 * (3) The *quantized* sample delay time must not fall either before the +	 *     eye opens or after it closes (the latter is the problem +	 *     illustrated in the above figure). +	 */ + +	/* Jam a negative ideal sample delay to zero. */ +	if (ideal_sample_delay_in_ns < 0) +		ideal_sample_delay_in_ns = 0; + +	/* +	 * Extend the data setup as needed to reduce the ideal sample delay +	 * below the maximum permitted by the NFC. +	 */ +	while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) && +			(data_setup_in_cycles < nfc->max_data_setup_cycles)) { + +		/* Give a cycle to data setup. */ +		data_setup_in_cycles++; +		/* Synchronize the data setup time with the cycles. */ +		data_setup_in_ns += clock_period_in_ns; +		/* Adjust tEYE accordingly. */ +		tEYE += clock_period_in_ns; + +		/* +		 * Decrease the ideal sample delay by one half cycle, to keep it +		 * in the middle of the eye. +		 */ +		ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1); + +		/* Jam a negative ideal sample delay to zero. */ +		if (ideal_sample_delay_in_ns < 0) +			ideal_sample_delay_in_ns = 0; +	} + +	/* +	 * Compute the sample delay factor that corresponds to the ideal sample +	 * delay. If the result is too large, then use the maximum allowed +	 * value. +	 * +	 * Notice that we use the ns_to_cycles function to compute the sample +	 * delay factor. We do this because the form of the computation is the +	 * same as that for calculating cycles. +	 */ +	sample_delay_factor = +		ns_to_cycles(ideal_sample_delay_in_ns << dll_delay_shift, +							clock_period_in_ns, 0); + +	if (sample_delay_factor > nfc->max_sample_delay_factor) +		sample_delay_factor = nfc->max_sample_delay_factor; + +	/* +	 * These macros conveniently encapsulate a computation we'll use to +	 * continuously evaluate whether or not the data sample delay is inside +	 * the eye. +	 */ +	#define IDEAL_DELAY  ((int) ideal_sample_delay_in_ns) + +	#define QUANTIZED_DELAY  \ +		((int) ((sample_delay_factor * clock_period_in_ns) >> \ +							dll_delay_shift)) + +	#define DELAY_ERROR  (abs(QUANTIZED_DELAY - IDEAL_DELAY)) + +	#define SAMPLE_IS_NOT_WITHIN_THE_EYE  (DELAY_ERROR > (tEYE >> 1)) + +	/* +	 * While the quantized sample time falls outside the eye, reduce the +	 * sample delay or extend the data setup to move the sampling point back +	 * toward the eye. Do not allow the number of data setup cycles to +	 * exceed the maximum allowed by the NFC. +	 */ +	while (SAMPLE_IS_NOT_WITHIN_THE_EYE && +			(data_setup_in_cycles < nfc->max_data_setup_cycles)) { +		/* +		 * If control arrives here, the quantized sample delay falls +		 * outside the eye. Check if it's before the eye opens, or after +		 * the eye closes. +		 */ +		if (QUANTIZED_DELAY > IDEAL_DELAY) { +			/* +			 * If control arrives here, the quantized sample delay +			 * falls after the eye closes. Decrease the quantized +			 * delay time and then go back to re-evaluate. +			 */ +			if (sample_delay_factor != 0) +				sample_delay_factor--; +			continue; +		} + +		/* +		 * If control arrives here, the quantized sample delay falls +		 * before the eye opens. Shift the sample point by increasing +		 * data setup time. This will also make the eye larger. +		 */ + +		/* Give a cycle to data setup. */ +		data_setup_in_cycles++; +		/* Synchronize the data setup time with the cycles. */ +		data_setup_in_ns += clock_period_in_ns; +		/* Adjust tEYE accordingly. */ +		tEYE += clock_period_in_ns; + +		/* +		 * Decrease the ideal sample delay by one half cycle, to keep it +		 * in the middle of the eye. +		 */ +		ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1); + +		/* ...and one less period for the delay time. */ +		ideal_sample_delay_in_ns -= clock_period_in_ns; + +		/* Jam a negative ideal sample delay to zero. */ +		if (ideal_sample_delay_in_ns < 0) +			ideal_sample_delay_in_ns = 0; + +		/* +		 * We have a new ideal sample delay, so re-compute the quantized +		 * delay. +		 */ +		sample_delay_factor = +			ns_to_cycles( +				ideal_sample_delay_in_ns << dll_delay_shift, +							clock_period_in_ns, 0); + +		if (sample_delay_factor > nfc->max_sample_delay_factor) +			sample_delay_factor = nfc->max_sample_delay_factor; +	} + +	/* Control arrives here when we're ready to return our results. */ +return_results: +	hw->data_setup_in_cycles    = data_setup_in_cycles; +	hw->data_hold_in_cycles     = data_hold_in_cycles; +	hw->address_setup_in_cycles = address_setup_in_cycles; +	hw->use_half_periods        = dll_use_half_periods; +	hw->sample_delay_factor     = sample_delay_factor; + +	/* Return success. */ +	return 0; +} + +/* Begin the I/O */ +void gpmi_begin(struct gpmi_nand_data *this) +{ +	struct resources *r = &this->resources; +	struct timing_threshod *nfc = &timing_default_threshold; +	unsigned char  *gpmi_regs = r->gpmi_regs; +	unsigned int   clock_period_in_ns; +	uint32_t       reg; +	unsigned int   dll_wait_time_in_us; +	struct gpmi_nfc_hardware_timing  hw; +	int ret; + +	/* Enable the clock. */ +	ret = clk_enable(r->clock); +	if (ret) { +		pr_err("We failed in enable the clk\n"); +		goto err_out; +	} + +	/* set ready/busy timeout */ +	writel(0x500 << BP_GPMI_TIMING1_BUSY_TIMEOUT, +		gpmi_regs + HW_GPMI_TIMING1); + +	/* Get the timing information we need. */ +	nfc->clock_frequency_in_hz = clk_get_rate(r->clock); +	clock_period_in_ns = 1000000000 / nfc->clock_frequency_in_hz; + +	gpmi_nfc_compute_hardware_timing(this, &hw); + +	/* Set up all the simple timing parameters. */ +	reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw.address_setup_in_cycles) | +		BF_GPMI_TIMING0_DATA_HOLD(hw.data_hold_in_cycles)         | +		BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles)       ; + +	writel(reg, gpmi_regs + HW_GPMI_TIMING0); + +	/* +	 * DLL_ENABLE must be set to 0 when setting RDN_DELAY or HALF_PERIOD. +	 */ +	writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_CLR); + +	/* Clear out the DLL control fields. */ +	writel(BM_GPMI_CTRL1_RDN_DELAY,   gpmi_regs + HW_GPMI_CTRL1_CLR); +	writel(BM_GPMI_CTRL1_HALF_PERIOD, gpmi_regs + HW_GPMI_CTRL1_CLR); + +	/* If no sample delay is called for, return immediately. */ +	if (!hw.sample_delay_factor) +		return; + +	/* Configure the HALF_PERIOD flag. */ +	if (hw.use_half_periods) +		writel(BM_GPMI_CTRL1_HALF_PERIOD, +						gpmi_regs + HW_GPMI_CTRL1_SET); + +	/* Set the delay factor. */ +	writel(BF_GPMI_CTRL1_RDN_DELAY(hw.sample_delay_factor), +						gpmi_regs + HW_GPMI_CTRL1_SET); + +	/* Enable the DLL. */ +	writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_SET); + +	/* +	 * After we enable the GPMI DLL, we have to wait 64 clock cycles before +	 * we can use the GPMI. +	 * +	 * Calculate the amount of time we need to wait, in microseconds. +	 */ +	dll_wait_time_in_us = (clock_period_in_ns * 64) / 1000; + +	if (!dll_wait_time_in_us) +		dll_wait_time_in_us = 1; + +	/* Wait for the DLL to settle. */ +	udelay(dll_wait_time_in_us); + +err_out: +	return; +} + +void gpmi_end(struct gpmi_nand_data *this) +{ +	struct resources *r = &this->resources; +	clk_disable(r->clock); +} + +/* Clears a BCH interrupt. */ +void gpmi_clear_bch(struct gpmi_nand_data *this) +{ +	struct resources *r = &this->resources; +	writel(BM_BCH_CTRL_COMPLETE_IRQ, r->bch_regs + HW_BCH_CTRL_CLR); +} + +/* Returns the Ready/Busy status of the given chip. */ +int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip) +{ +	struct resources *r = &this->resources; +	uint32_t mask = 0; +	uint32_t reg = 0; + +	if (GPMI_IS_MX23(this)) { +		mask = MX23_BM_GPMI_DEBUG_READY0 << chip; +		reg = readl(r->gpmi_regs + HW_GPMI_DEBUG); +	} else if (GPMI_IS_MX28(this)) { +		mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip); +		reg = readl(r->gpmi_regs + HW_GPMI_STAT); +	} else +		pr_err("unknow arch.\n"); +	return reg & mask; +} + +static inline void set_dma_type(struct gpmi_nand_data *this, +					enum dma_ops_type type) +{ +	this->last_dma_type = this->dma_type; +	this->dma_type = type; +} + +int gpmi_send_command(struct gpmi_nand_data *this) +{ +	struct dma_chan *channel = get_dma_chan(this); +	struct dma_async_tx_descriptor *desc; +	struct scatterlist *sgl; +	int chip = this->current_chip; +	u32 pio[3]; + +	/* [1] send out the PIO words */ +	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE) +		| BM_GPMI_CTRL0_WORD_LENGTH +		| BF_GPMI_CTRL0_CS(chip, this) +		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) +		| BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_CLE) +		| BM_GPMI_CTRL0_ADDRESS_INCREMENT +		| BF_GPMI_CTRL0_XFER_COUNT(this->command_length); +	pio[1] = pio[2] = 0; +	desc = channel->device->device_prep_slave_sg(channel, +					(struct scatterlist *)pio, +					ARRAY_SIZE(pio), DMA_NONE, 0); +	if (!desc) { +		pr_err("step 1 error\n"); +		return -1; +	} + +	/* [2] send out the COMMAND + ADDRESS string stored in @buffer */ +	sgl = &this->cmd_sgl; + +	sg_init_one(sgl, this->cmd_buffer, this->command_length); +	dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE); +	desc = channel->device->device_prep_slave_sg(channel, +					sgl, 1, DMA_TO_DEVICE, 1); +	if (!desc) { +		pr_err("step 2 error\n"); +		return -1; +	} + +	/* [3] submit the DMA */ +	set_dma_type(this, DMA_FOR_COMMAND); +	return start_dma_without_bch_irq(this, desc); +} + +int gpmi_send_data(struct gpmi_nand_data *this) +{ +	struct dma_async_tx_descriptor *desc; +	struct dma_chan *channel = get_dma_chan(this); +	int chip = this->current_chip; +	uint32_t command_mode; +	uint32_t address; +	u32 pio[2]; + +	/* [1] PIO */ +	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE; +	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; + +	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) +		| BM_GPMI_CTRL0_WORD_LENGTH +		| BF_GPMI_CTRL0_CS(chip, this) +		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) +		| BF_GPMI_CTRL0_ADDRESS(address) +		| BF_GPMI_CTRL0_XFER_COUNT(this->upper_len); +	pio[1] = 0; +	desc = channel->device->device_prep_slave_sg(channel, +					(struct scatterlist *)pio, +					ARRAY_SIZE(pio), DMA_NONE, 0); +	if (!desc) { +		pr_err("step 1 error\n"); +		return -1; +	} + +	/* [2] send DMA request */ +	prepare_data_dma(this, DMA_TO_DEVICE); +	desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl, +						1, DMA_TO_DEVICE, 1); +	if (!desc) { +		pr_err("step 2 error\n"); +		return -1; +	} +	/* [3] submit the DMA */ +	set_dma_type(this, DMA_FOR_WRITE_DATA); +	return start_dma_without_bch_irq(this, desc); +} + +int gpmi_read_data(struct gpmi_nand_data *this) +{ +	struct dma_async_tx_descriptor *desc; +	struct dma_chan *channel = get_dma_chan(this); +	int chip = this->current_chip; +	u32 pio[2]; + +	/* [1] : send PIO */ +	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ) +		| BM_GPMI_CTRL0_WORD_LENGTH +		| BF_GPMI_CTRL0_CS(chip, this) +		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) +		| BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) +		| BF_GPMI_CTRL0_XFER_COUNT(this->upper_len); +	pio[1] = 0; +	desc = channel->device->device_prep_slave_sg(channel, +					(struct scatterlist *)pio, +					ARRAY_SIZE(pio), DMA_NONE, 0); +	if (!desc) { +		pr_err("step 1 error\n"); +		return -1; +	} + +	/* [2] : send DMA request */ +	prepare_data_dma(this, DMA_FROM_DEVICE); +	desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl, +						1, DMA_FROM_DEVICE, 1); +	if (!desc) { +		pr_err("step 2 error\n"); +		return -1; +	} + +	/* [3] : submit the DMA */ +	set_dma_type(this, DMA_FOR_READ_DATA); +	return start_dma_without_bch_irq(this, desc); +} + +int gpmi_send_page(struct gpmi_nand_data *this, +			dma_addr_t payload, dma_addr_t auxiliary) +{ +	struct bch_geometry *geo = &this->bch_geometry; +	uint32_t command_mode; +	uint32_t address; +	uint32_t ecc_command; +	uint32_t buffer_mask; +	struct dma_async_tx_descriptor *desc; +	struct dma_chan *channel = get_dma_chan(this); +	int chip = this->current_chip; +	u32 pio[6]; + +	/* A DMA descriptor that does an ECC page read. */ +	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE; +	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; +	ecc_command  = BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE; +	buffer_mask  = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE | +				BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY; + +	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) +		| BM_GPMI_CTRL0_WORD_LENGTH +		| BF_GPMI_CTRL0_CS(chip, this) +		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) +		| BF_GPMI_CTRL0_ADDRESS(address) +		| BF_GPMI_CTRL0_XFER_COUNT(0); +	pio[1] = 0; +	pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC +		| BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) +		| BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask); +	pio[3] = geo->page_size; +	pio[4] = payload; +	pio[5] = auxiliary; + +	desc = channel->device->device_prep_slave_sg(channel, +					(struct scatterlist *)pio, +					ARRAY_SIZE(pio), DMA_NONE, 0); +	if (!desc) { +		pr_err("step 2 error\n"); +		return -1; +	} +	set_dma_type(this, DMA_FOR_WRITE_ECC_PAGE); +	return start_dma_with_bch_irq(this, desc); +} + +int gpmi_read_page(struct gpmi_nand_data *this, +				dma_addr_t payload, dma_addr_t auxiliary) +{ +	struct bch_geometry *geo = &this->bch_geometry; +	uint32_t command_mode; +	uint32_t address; +	uint32_t ecc_command; +	uint32_t buffer_mask; +	struct dma_async_tx_descriptor *desc; +	struct dma_chan *channel = get_dma_chan(this); +	int chip = this->current_chip; +	u32 pio[6]; + +	/* [1] Wait for the chip to report ready. */ +	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY; +	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; + +	pio[0] =  BF_GPMI_CTRL0_COMMAND_MODE(command_mode) +		| BM_GPMI_CTRL0_WORD_LENGTH +		| BF_GPMI_CTRL0_CS(chip, this) +		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) +		| BF_GPMI_CTRL0_ADDRESS(address) +		| BF_GPMI_CTRL0_XFER_COUNT(0); +	pio[1] = 0; +	desc = channel->device->device_prep_slave_sg(channel, +				(struct scatterlist *)pio, 2, DMA_NONE, 0); +	if (!desc) { +		pr_err("step 1 error\n"); +		return -1; +	} + +	/* [2] Enable the BCH block and read. */ +	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__READ; +	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; +	ecc_command  = BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE; +	buffer_mask  = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE +			| BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY; + +	pio[0] =  BF_GPMI_CTRL0_COMMAND_MODE(command_mode) +		| BM_GPMI_CTRL0_WORD_LENGTH +		| BF_GPMI_CTRL0_CS(chip, this) +		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) +		| BF_GPMI_CTRL0_ADDRESS(address) +		| BF_GPMI_CTRL0_XFER_COUNT(geo->page_size); + +	pio[1] = 0; +	pio[2] =  BM_GPMI_ECCCTRL_ENABLE_ECC +		| BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) +		| BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask); +	pio[3] = geo->page_size; +	pio[4] = payload; +	pio[5] = auxiliary; +	desc = channel->device->device_prep_slave_sg(channel, +					(struct scatterlist *)pio, +					ARRAY_SIZE(pio), DMA_NONE, 1); +	if (!desc) { +		pr_err("step 2 error\n"); +		return -1; +	} + +	/* [3] Disable the BCH block */ +	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY; +	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; + +	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) +		| BM_GPMI_CTRL0_WORD_LENGTH +		| BF_GPMI_CTRL0_CS(chip, this) +		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) +		| BF_GPMI_CTRL0_ADDRESS(address) +		| BF_GPMI_CTRL0_XFER_COUNT(geo->page_size); +	pio[1] = 0; +	desc = channel->device->device_prep_slave_sg(channel, +				(struct scatterlist *)pio, 2, DMA_NONE, 1); +	if (!desc) { +		pr_err("step 3 error\n"); +		return -1; +	} + +	/* [4] submit the DMA */ +	set_dma_type(this, DMA_FOR_READ_ECC_PAGE); +	return start_dma_with_bch_irq(this, desc); +} diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c new file mode 100644 index 000000000000..071b63420f0e --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -0,0 +1,1619 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008 Embedded Alley Solutions, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include <linux/clk.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/mtd/gpmi-nand.h> +#include <linux/mtd/partitions.h> + +#include "gpmi-nand.h" + +/* add our owner bbt descriptor */ +static uint8_t scan_ff_pattern[] = { 0xff }; +static struct nand_bbt_descr gpmi_bbt_descr = { +	.options	= 0, +	.offs		= 0, +	.len		= 1, +	.pattern	= scan_ff_pattern +}; + +/*  We will use all the (page + OOB). */ +static struct nand_ecclayout gpmi_hw_ecclayout = { +	.eccbytes = 0, +	.eccpos = { 0, }, +	.oobfree = { {.offset = 0, .length = 0} } +}; + +static irqreturn_t bch_irq(int irq, void *cookie) +{ +	struct gpmi_nand_data *this = cookie; + +	gpmi_clear_bch(this); +	complete(&this->bch_done); +	return IRQ_HANDLED; +} + +/* + *  Calculate the ECC strength by hand: + *	E : The ECC strength. + *	G : the length of Galois Field. + *	N : The chunk count of per page. + *	O : the oobsize of the NAND chip. + *	M : the metasize of per page. + * + *	The formula is : + *		E * G * N + *	      ------------ <= (O - M) + *                  8 + * + *      So, we get E by: + *                    (O - M) * 8 + *              E <= ------------- + *                       G * N + */ +static inline int get_ecc_strength(struct gpmi_nand_data *this) +{ +	struct bch_geometry *geo = &this->bch_geometry; +	struct mtd_info	*mtd = &this->mtd; +	int ecc_strength; + +	ecc_strength = ((mtd->oobsize - geo->metadata_size) * 8) +			/ (geo->gf_len * geo->ecc_chunk_count); + +	/* We need the minor even number. */ +	return round_down(ecc_strength, 2); +} + +int common_nfc_set_geometry(struct gpmi_nand_data *this) +{ +	struct bch_geometry *geo = &this->bch_geometry; +	struct mtd_info *mtd = &this->mtd; +	unsigned int metadata_size; +	unsigned int status_size; +	unsigned int block_mark_bit_offset; + +	/* +	 * The size of the metadata can be changed, though we set it to 10 +	 * bytes now. But it can't be too large, because we have to save +	 * enough space for BCH. +	 */ +	geo->metadata_size = 10; + +	/* The default for the length of Galois Field. */ +	geo->gf_len = 13; + +	/* The default for chunk size. There is no oobsize greater then 512. */ +	geo->ecc_chunk_size = 512; +	while (geo->ecc_chunk_size < mtd->oobsize) +		geo->ecc_chunk_size *= 2; /* keep C >= O */ + +	geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size; + +	/* We use the same ECC strength for all chunks. */ +	geo->ecc_strength = get_ecc_strength(this); +	if (!geo->ecc_strength) { +		pr_err("We get a wrong ECC strength.\n"); +		return -EINVAL; +	} + +	geo->page_size = mtd->writesize + mtd->oobsize; +	geo->payload_size = mtd->writesize; + +	/* +	 * The auxiliary buffer contains the metadata and the ECC status. The +	 * metadata is padded to the nearest 32-bit boundary. The ECC status +	 * contains one byte for every ECC chunk, and is also padded to the +	 * nearest 32-bit boundary. +	 */ +	metadata_size = ALIGN(geo->metadata_size, 4); +	status_size   = ALIGN(geo->ecc_chunk_count, 4); + +	geo->auxiliary_size = metadata_size + status_size; +	geo->auxiliary_status_offset = metadata_size; + +	if (!this->swap_block_mark) +		return 0; + +	/* +	 * We need to compute the byte and bit offsets of +	 * the physical block mark within the ECC-based view of the page. +	 * +	 * NAND chip with 2K page shows below: +	 *                                             (Block Mark) +	 *                                                   |      | +	 *                                                   |  D   | +	 *                                                   |<---->| +	 *                                                   V      V +	 *    +---+----------+-+----------+-+----------+-+----------+-+ +	 *    | M |   data   |E|   data   |E|   data   |E|   data   |E| +	 *    +---+----------+-+----------+-+----------+-+----------+-+ +	 * +	 * The position of block mark moves forward in the ECC-based view +	 * of page, and the delta is: +	 * +	 *                   E * G * (N - 1) +	 *             D = (---------------- + M) +	 *                          8 +	 * +	 * With the formula to compute the ECC strength, and the condition +	 *       : C >= O         (C is the ecc chunk size) +	 * +	 * It's easy to deduce to the following result: +	 * +	 *         E * G       (O - M)      C - M         C - M +	 *      ----------- <= ------- <=  --------  <  --------- +	 *           8            N           N          (N - 1) +	 * +	 *  So, we get: +	 * +	 *                   E * G * (N - 1) +	 *             D = (---------------- + M) < C +	 *                          8 +	 * +	 *  The above inequality means the position of block mark +	 *  within the ECC-based view of the page is still in the data chunk, +	 *  and it's NOT in the ECC bits of the chunk. +	 * +	 *  Use the following to compute the bit position of the +	 *  physical block mark within the ECC-based view of the page: +	 *          (page_size - D) * 8 +	 * +	 *  --Huang Shijie +	 */ +	block_mark_bit_offset = mtd->writesize * 8 - +		(geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - 1) +				+ geo->metadata_size * 8); + +	geo->block_mark_byte_offset = block_mark_bit_offset / 8; +	geo->block_mark_bit_offset  = block_mark_bit_offset % 8; +	return 0; +} + +struct dma_chan *get_dma_chan(struct gpmi_nand_data *this) +{ +	int chipnr = this->current_chip; + +	return this->dma_chans[chipnr]; +} + +/* Can we use the upper's buffer directly for DMA? */ +void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr) +{ +	struct scatterlist *sgl = &this->data_sgl; +	int ret; + +	this->direct_dma_map_ok = true; + +	/* first try to map the upper buffer directly */ +	sg_init_one(sgl, this->upper_buf, this->upper_len); +	ret = dma_map_sg(this->dev, sgl, 1, dr); +	if (ret == 0) { +		/* We have to use our own DMA buffer. */ +		sg_init_one(sgl, this->data_buffer_dma, PAGE_SIZE); + +		if (dr == DMA_TO_DEVICE) +			memcpy(this->data_buffer_dma, this->upper_buf, +				this->upper_len); + +		ret = dma_map_sg(this->dev, sgl, 1, dr); +		if (ret == 0) +			pr_err("map failed.\n"); + +		this->direct_dma_map_ok = false; +	} +} + +/* This will be called after the DMA operation is finished. */ +static void dma_irq_callback(void *param) +{ +	struct gpmi_nand_data *this = param; +	struct completion *dma_c = &this->dma_done; + +	complete(dma_c); + +	switch (this->dma_type) { +	case DMA_FOR_COMMAND: +		dma_unmap_sg(this->dev, &this->cmd_sgl, 1, DMA_TO_DEVICE); +		break; + +	case DMA_FOR_READ_DATA: +		dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_FROM_DEVICE); +		if (this->direct_dma_map_ok == false) +			memcpy(this->upper_buf, this->data_buffer_dma, +				this->upper_len); +		break; + +	case DMA_FOR_WRITE_DATA: +		dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_TO_DEVICE); +		break; + +	case DMA_FOR_READ_ECC_PAGE: +	case DMA_FOR_WRITE_ECC_PAGE: +		/* We have to wait the BCH interrupt to finish. */ +		break; + +	default: +		pr_err("in wrong DMA operation.\n"); +	} +} + +int start_dma_without_bch_irq(struct gpmi_nand_data *this, +				struct dma_async_tx_descriptor *desc) +{ +	struct completion *dma_c = &this->dma_done; +	int err; + +	init_completion(dma_c); + +	desc->callback		= dma_irq_callback; +	desc->callback_param	= this; +	dmaengine_submit(desc); + +	/* Wait for the interrupt from the DMA block. */ +	err = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000)); +	if (!err) { +		pr_err("DMA timeout, last DMA :%d\n", this->last_dma_type); +		gpmi_dump_info(this); +		return -ETIMEDOUT; +	} +	return 0; +} + +/* + * This function is used in BCH reading or BCH writing pages. + * It will wait for the BCH interrupt as long as ONE second. + * Actually, we must wait for two interrupts : + *	[1] firstly the DMA interrupt and + *	[2] secondly the BCH interrupt. + */ +int start_dma_with_bch_irq(struct gpmi_nand_data *this, +			struct dma_async_tx_descriptor *desc) +{ +	struct completion *bch_c = &this->bch_done; +	int err; + +	/* Prepare to receive an interrupt from the BCH block. */ +	init_completion(bch_c); + +	/* start the DMA */ +	start_dma_without_bch_irq(this, desc); + +	/* Wait for the interrupt from the BCH block. */ +	err = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000)); +	if (!err) { +		pr_err("BCH timeout, last DMA :%d\n", this->last_dma_type); +		gpmi_dump_info(this); +		return -ETIMEDOUT; +	} +	return 0; +} + +static int __devinit +acquire_register_block(struct gpmi_nand_data *this, const char *res_name) +{ +	struct platform_device *pdev = this->pdev; +	struct resources *res = &this->resources; +	struct resource *r; +	void *p; + +	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name); +	if (!r) { +		pr_err("Can't get resource for %s\n", res_name); +		return -ENXIO; +	} + +	p = ioremap(r->start, resource_size(r)); +	if (!p) { +		pr_err("Can't remap %s\n", res_name); +		return -ENOMEM; +	} + +	if (!strcmp(res_name, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME)) +		res->gpmi_regs = p; +	else if (!strcmp(res_name, GPMI_NAND_BCH_REGS_ADDR_RES_NAME)) +		res->bch_regs = p; +	else +		pr_err("unknown resource name : %s\n", res_name); + +	return 0; +} + +static void release_register_block(struct gpmi_nand_data *this) +{ +	struct resources *res = &this->resources; +	if (res->gpmi_regs) +		iounmap(res->gpmi_regs); +	if (res->bch_regs) +		iounmap(res->bch_regs); +	res->gpmi_regs = NULL; +	res->bch_regs = NULL; +} + +static int __devinit +acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h) +{ +	struct platform_device *pdev = this->pdev; +	struct resources *res = &this->resources; +	const char *res_name = GPMI_NAND_BCH_INTERRUPT_RES_NAME; +	struct resource *r; +	int err; + +	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name); +	if (!r) { +		pr_err("Can't get resource for %s\n", res_name); +		return -ENXIO; +	} + +	err = request_irq(r->start, irq_h, 0, res_name, this); +	if (err) { +		pr_err("Can't own %s\n", res_name); +		return err; +	} + +	res->bch_low_interrupt = r->start; +	res->bch_high_interrupt = r->end; +	return 0; +} + +static void release_bch_irq(struct gpmi_nand_data *this) +{ +	struct resources *res = &this->resources; +	int i = res->bch_low_interrupt; + +	for (; i <= res->bch_high_interrupt; i++) +		free_irq(i, this); +} + +static bool gpmi_dma_filter(struct dma_chan *chan, void *param) +{ +	struct gpmi_nand_data *this = param; +	struct resource *r = this->private; + +	if (!mxs_dma_is_apbh(chan)) +		return false; +	/* +	 * only catch the GPMI dma channels : +	 *	for mx23 :	MX23_DMA_GPMI0 ~ MX23_DMA_GPMI3 +	 *		(These four channels share the same IRQ!) +	 * +	 *	for mx28 :	MX28_DMA_GPMI0 ~ MX28_DMA_GPMI7 +	 *		(These eight channels share the same IRQ!) +	 */ +	if (r->start <= chan->chan_id && chan->chan_id <= r->end) { +		chan->private = &this->dma_data; +		return true; +	} +	return false; +} + +static void release_dma_channels(struct gpmi_nand_data *this) +{ +	unsigned int i; +	for (i = 0; i < DMA_CHANS; i++) +		if (this->dma_chans[i]) { +			dma_release_channel(this->dma_chans[i]); +			this->dma_chans[i] = NULL; +		} +} + +static int __devinit acquire_dma_channels(struct gpmi_nand_data *this) +{ +	struct platform_device *pdev = this->pdev; +	struct gpmi_nand_platform_data *pdata = this->pdata; +	struct resources *res = &this->resources; +	struct resource *r, *r_dma; +	unsigned int i; + +	r = platform_get_resource_byname(pdev, IORESOURCE_DMA, +					GPMI_NAND_DMA_CHANNELS_RES_NAME); +	r_dma = platform_get_resource_byname(pdev, IORESOURCE_IRQ, +					GPMI_NAND_DMA_INTERRUPT_RES_NAME); +	if (!r || !r_dma) { +		pr_err("Can't get resource for DMA\n"); +		return -ENXIO; +	} + +	/* used in gpmi_dma_filter() */ +	this->private = r; + +	for (i = r->start; i <= r->end; i++) { +		struct dma_chan *dma_chan; +		dma_cap_mask_t mask; + +		if (i - r->start >= pdata->max_chip_count) +			break; + +		dma_cap_zero(mask); +		dma_cap_set(DMA_SLAVE, mask); + +		/* get the DMA interrupt */ +		if (r_dma->start == r_dma->end) { +			/* only register the first. */ +			if (i == r->start) +				this->dma_data.chan_irq = r_dma->start; +			else +				this->dma_data.chan_irq = NO_IRQ; +		} else +			this->dma_data.chan_irq = r_dma->start + (i - r->start); + +		dma_chan = dma_request_channel(mask, gpmi_dma_filter, this); +		if (!dma_chan) +			goto acquire_err; + +		/* fill the first empty item */ +		this->dma_chans[i - r->start] = dma_chan; +	} + +	res->dma_low_channel = r->start; +	res->dma_high_channel = i; +	return 0; + +acquire_err: +	pr_err("Can't acquire DMA channel %u\n", i); +	release_dma_channels(this); +	return -EINVAL; +} + +static int __devinit acquire_resources(struct gpmi_nand_data *this) +{ +	struct resources *res = &this->resources; +	int ret; + +	ret = acquire_register_block(this, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME); +	if (ret) +		goto exit_regs; + +	ret = acquire_register_block(this, GPMI_NAND_BCH_REGS_ADDR_RES_NAME); +	if (ret) +		goto exit_regs; + +	ret = acquire_bch_irq(this, bch_irq); +	if (ret) +		goto exit_regs; + +	ret = acquire_dma_channels(this); +	if (ret) +		goto exit_dma_channels; + +	res->clock = clk_get(&this->pdev->dev, NULL); +	if (IS_ERR(res->clock)) { +		pr_err("can not get the clock\n"); +		ret = -ENOENT; +		goto exit_clock; +	} +	return 0; + +exit_clock: +	release_dma_channels(this); +exit_dma_channels: +	release_bch_irq(this); +exit_regs: +	release_register_block(this); +	return ret; +} + +static void release_resources(struct gpmi_nand_data *this) +{ +	struct resources *r = &this->resources; + +	clk_put(r->clock); +	release_register_block(this); +	release_bch_irq(this); +	release_dma_channels(this); +} + +static int __devinit init_hardware(struct gpmi_nand_data *this) +{ +	int ret; + +	/* +	 * This structure contains the "safe" GPMI timing that should succeed +	 * with any NAND Flash device +	 * (although, with less-than-optimal performance). +	 */ +	struct nand_timing  safe_timing = { +		.data_setup_in_ns        = 80, +		.data_hold_in_ns         = 60, +		.address_setup_in_ns     = 25, +		.gpmi_sample_delay_in_ns =  6, +		.tREA_in_ns              = -1, +		.tRLOH_in_ns             = -1, +		.tRHOH_in_ns             = -1, +	}; + +	/* Initialize the hardwares. */ +	ret = gpmi_init(this); +	if (ret) +		return ret; + +	this->timing = safe_timing; +	return 0; +} + +static int read_page_prepare(struct gpmi_nand_data *this, +			void *destination, unsigned length, +			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, +			void **use_virt, dma_addr_t *use_phys) +{ +	struct device *dev = this->dev; + +	if (virt_addr_valid(destination)) { +		dma_addr_t dest_phys; + +		dest_phys = dma_map_single(dev, destination, +						length, DMA_FROM_DEVICE); +		if (dma_mapping_error(dev, dest_phys)) { +			if (alt_size < length) { +				pr_err("Alternate buffer is too small\n"); +				return -ENOMEM; +			} +			goto map_failed; +		} +		*use_virt = destination; +		*use_phys = dest_phys; +		this->direct_dma_map_ok = true; +		return 0; +	} + +map_failed: +	*use_virt = alt_virt; +	*use_phys = alt_phys; +	this->direct_dma_map_ok = false; +	return 0; +} + +static inline void read_page_end(struct gpmi_nand_data *this, +			void *destination, unsigned length, +			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, +			void *used_virt, dma_addr_t used_phys) +{ +	if (this->direct_dma_map_ok) +		dma_unmap_single(this->dev, used_phys, length, DMA_FROM_DEVICE); +} + +static inline void read_page_swap_end(struct gpmi_nand_data *this, +			void *destination, unsigned length, +			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, +			void *used_virt, dma_addr_t used_phys) +{ +	if (!this->direct_dma_map_ok) +		memcpy(destination, alt_virt, length); +} + +static int send_page_prepare(struct gpmi_nand_data *this, +			const void *source, unsigned length, +			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, +			const void **use_virt, dma_addr_t *use_phys) +{ +	struct device *dev = this->dev; + +	if (virt_addr_valid(source)) { +		dma_addr_t source_phys; + +		source_phys = dma_map_single(dev, (void *)source, length, +						DMA_TO_DEVICE); +		if (dma_mapping_error(dev, source_phys)) { +			if (alt_size < length) { +				pr_err("Alternate buffer is too small\n"); +				return -ENOMEM; +			} +			goto map_failed; +		} +		*use_virt = source; +		*use_phys = source_phys; +		return 0; +	} +map_failed: +	/* +	 * Copy the content of the source buffer into the alternate +	 * buffer and set up the return values accordingly. +	 */ +	memcpy(alt_virt, source, length); + +	*use_virt = alt_virt; +	*use_phys = alt_phys; +	return 0; +} + +static void send_page_end(struct gpmi_nand_data *this, +			const void *source, unsigned length, +			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, +			const void *used_virt, dma_addr_t used_phys) +{ +	struct device *dev = this->dev; +	if (used_virt == source) +		dma_unmap_single(dev, used_phys, length, DMA_TO_DEVICE); +} + +static void gpmi_free_dma_buffer(struct gpmi_nand_data *this) +{ +	struct device *dev = this->dev; + +	if (this->page_buffer_virt && virt_addr_valid(this->page_buffer_virt)) +		dma_free_coherent(dev, this->page_buffer_size, +					this->page_buffer_virt, +					this->page_buffer_phys); +	kfree(this->cmd_buffer); +	kfree(this->data_buffer_dma); + +	this->cmd_buffer	= NULL; +	this->data_buffer_dma	= NULL; +	this->page_buffer_virt	= NULL; +	this->page_buffer_size	=  0; +} + +/* Allocate the DMA buffers */ +static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) +{ +	struct bch_geometry *geo = &this->bch_geometry; +	struct device *dev = this->dev; + +	/* [1] Allocate a command buffer. PAGE_SIZE is enough. */ +	this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA); +	if (this->cmd_buffer == NULL) +		goto error_alloc; + +	/* [2] Allocate a read/write data buffer. PAGE_SIZE is enough. */ +	this->data_buffer_dma = kzalloc(PAGE_SIZE, GFP_DMA); +	if (this->data_buffer_dma == NULL) +		goto error_alloc; + +	/* +	 * [3] Allocate the page buffer. +	 * +	 * Both the payload buffer and the auxiliary buffer must appear on +	 * 32-bit boundaries. We presume the size of the payload buffer is a +	 * power of two and is much larger than four, which guarantees the +	 * auxiliary buffer will appear on a 32-bit boundary. +	 */ +	this->page_buffer_size = geo->payload_size + geo->auxiliary_size; +	this->page_buffer_virt = dma_alloc_coherent(dev, this->page_buffer_size, +					&this->page_buffer_phys, GFP_DMA); +	if (!this->page_buffer_virt) +		goto error_alloc; + + +	/* Slice up the page buffer. */ +	this->payload_virt = this->page_buffer_virt; +	this->payload_phys = this->page_buffer_phys; +	this->auxiliary_virt = this->payload_virt + geo->payload_size; +	this->auxiliary_phys = this->payload_phys + geo->payload_size; +	return 0; + +error_alloc: +	gpmi_free_dma_buffer(this); +	pr_err("allocate DMA buffer ret!!\n"); +	return -ENOMEM; +} + +static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) +{ +	struct nand_chip *chip = mtd->priv; +	struct gpmi_nand_data *this = chip->priv; +	int ret; + +	/* +	 * Every operation begins with a command byte and a series of zero or +	 * more address bytes. These are distinguished by either the Address +	 * Latch Enable (ALE) or Command Latch Enable (CLE) signals being +	 * asserted. When MTD is ready to execute the command, it will deassert +	 * both latch enables. +	 * +	 * Rather than run a separate DMA operation for every single byte, we +	 * queue them up and run a single DMA operation for the entire series +	 * of command and data bytes. NAND_CMD_NONE means the END of the queue. +	 */ +	if ((ctrl & (NAND_ALE | NAND_CLE))) { +		if (data != NAND_CMD_NONE) +			this->cmd_buffer[this->command_length++] = data; +		return; +	} + +	if (!this->command_length) +		return; + +	ret = gpmi_send_command(this); +	if (ret) +		pr_err("Chip: %u, Error %d\n", this->current_chip, ret); + +	this->command_length = 0; +} + +static int gpmi_dev_ready(struct mtd_info *mtd) +{ +	struct nand_chip *chip = mtd->priv; +	struct gpmi_nand_data *this = chip->priv; + +	return gpmi_is_ready(this, this->current_chip); +} + +static void gpmi_select_chip(struct mtd_info *mtd, int chipnr) +{ +	struct nand_chip *chip = mtd->priv; +	struct gpmi_nand_data *this = chip->priv; + +	if ((this->current_chip < 0) && (chipnr >= 0)) +		gpmi_begin(this); +	else if ((this->current_chip >= 0) && (chipnr < 0)) +		gpmi_end(this); + +	this->current_chip = chipnr; +} + +static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ +	struct nand_chip *chip = mtd->priv; +	struct gpmi_nand_data *this = chip->priv; + +	pr_debug("len is %d\n", len); +	this->upper_buf	= buf; +	this->upper_len	= len; + +	gpmi_read_data(this); +} + +static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ +	struct nand_chip *chip = mtd->priv; +	struct gpmi_nand_data *this = chip->priv; + +	pr_debug("len is %d\n", len); +	this->upper_buf	= (uint8_t *)buf; +	this->upper_len	= len; + +	gpmi_send_data(this); +} + +static uint8_t gpmi_read_byte(struct mtd_info *mtd) +{ +	struct nand_chip *chip = mtd->priv; +	struct gpmi_nand_data *this = chip->priv; +	uint8_t *buf = this->data_buffer_dma; + +	gpmi_read_buf(mtd, buf, 1); +	return buf[0]; +} + +/* + * Handles block mark swapping. + * It can be called in swapping the block mark, or swapping it back, + * because the the operations are the same. + */ +static void block_mark_swapping(struct gpmi_nand_data *this, +				void *payload, void *auxiliary) +{ +	struct bch_geometry *nfc_geo = &this->bch_geometry; +	unsigned char *p; +	unsigned char *a; +	unsigned int  bit; +	unsigned char mask; +	unsigned char from_data; +	unsigned char from_oob; + +	if (!this->swap_block_mark) +		return; + +	/* +	 * If control arrives here, we're swapping. Make some convenience +	 * variables. +	 */ +	bit = nfc_geo->block_mark_bit_offset; +	p   = payload + nfc_geo->block_mark_byte_offset; +	a   = auxiliary; + +	/* +	 * Get the byte from the data area that overlays the block mark. Since +	 * the ECC engine applies its own view to the bits in the page, the +	 * physical block mark won't (in general) appear on a byte boundary in +	 * the data. +	 */ +	from_data = (p[0] >> bit) | (p[1] << (8 - bit)); + +	/* Get the byte from the OOB. */ +	from_oob = a[0]; + +	/* Swap them. */ +	a[0] = from_data; + +	mask = (0x1 << bit) - 1; +	p[0] = (p[0] & mask) | (from_oob << bit); + +	mask = ~0 << bit; +	p[1] = (p[1] & mask) | (from_oob >> (8 - bit)); +} + +static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, +				uint8_t *buf, int page) +{ +	struct gpmi_nand_data *this = chip->priv; +	struct bch_geometry *nfc_geo = &this->bch_geometry; +	void          *payload_virt; +	dma_addr_t    payload_phys; +	void          *auxiliary_virt; +	dma_addr_t    auxiliary_phys; +	unsigned int  i; +	unsigned char *status; +	unsigned int  failed; +	unsigned int  corrected; +	int           ret; + +	pr_debug("page number is : %d\n", page); +	ret = read_page_prepare(this, buf, mtd->writesize, +					this->payload_virt, this->payload_phys, +					nfc_geo->payload_size, +					&payload_virt, &payload_phys); +	if (ret) { +		pr_err("Inadequate DMA buffer\n"); +		ret = -ENOMEM; +		return ret; +	} +	auxiliary_virt = this->auxiliary_virt; +	auxiliary_phys = this->auxiliary_phys; + +	/* go! */ +	ret = gpmi_read_page(this, payload_phys, auxiliary_phys); +	read_page_end(this, buf, mtd->writesize, +			this->payload_virt, this->payload_phys, +			nfc_geo->payload_size, +			payload_virt, payload_phys); +	if (ret) { +		pr_err("Error in ECC-based read: %d\n", ret); +		goto exit_nfc; +	} + +	/* handle the block mark swapping */ +	block_mark_swapping(this, payload_virt, auxiliary_virt); + +	/* Loop over status bytes, accumulating ECC status. */ +	failed		= 0; +	corrected	= 0; +	status		= auxiliary_virt + nfc_geo->auxiliary_status_offset; + +	for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) { +		if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED)) +			continue; + +		if (*status == STATUS_UNCORRECTABLE) { +			failed++; +			continue; +		} +		corrected += *status; +	} + +	/* +	 * Propagate ECC status to the owning MTD only when failed or +	 * corrected times nearly reaches our ECC correction threshold. +	 */ +	if (failed || corrected >= (nfc_geo->ecc_strength - 1)) { +		mtd->ecc_stats.failed    += failed; +		mtd->ecc_stats.corrected += corrected; +	} + +	/* +	 * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob() for +	 * details about our policy for delivering the OOB. +	 * +	 * We fill the caller's buffer with set bits, and then copy the block +	 * mark to th caller's buffer. Note that, if block mark swapping was +	 * necessary, it has already been done, so we can rely on the first +	 * byte of the auxiliary buffer to contain the block mark. +	 */ +	memset(chip->oob_poi, ~0, mtd->oobsize); +	chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0]; + +	read_page_swap_end(this, buf, mtd->writesize, +			this->payload_virt, this->payload_phys, +			nfc_geo->payload_size, +			payload_virt, payload_phys); +exit_nfc: +	return ret; +} + +static void gpmi_ecc_write_page(struct mtd_info *mtd, +				struct nand_chip *chip, const uint8_t *buf) +{ +	struct gpmi_nand_data *this = chip->priv; +	struct bch_geometry *nfc_geo = &this->bch_geometry; +	const void *payload_virt; +	dma_addr_t payload_phys; +	const void *auxiliary_virt; +	dma_addr_t auxiliary_phys; +	int        ret; + +	pr_debug("ecc write page.\n"); +	if (this->swap_block_mark) { +		/* +		 * If control arrives here, we're doing block mark swapping. +		 * Since we can't modify the caller's buffers, we must copy them +		 * into our own. +		 */ +		memcpy(this->payload_virt, buf, mtd->writesize); +		payload_virt = this->payload_virt; +		payload_phys = this->payload_phys; + +		memcpy(this->auxiliary_virt, chip->oob_poi, +				nfc_geo->auxiliary_size); +		auxiliary_virt = this->auxiliary_virt; +		auxiliary_phys = this->auxiliary_phys; + +		/* Handle block mark swapping. */ +		block_mark_swapping(this, +				(void *) payload_virt, (void *) auxiliary_virt); +	} else { +		/* +		 * If control arrives here, we're not doing block mark swapping, +		 * so we can to try and use the caller's buffers. +		 */ +		ret = send_page_prepare(this, +				buf, mtd->writesize, +				this->payload_virt, this->payload_phys, +				nfc_geo->payload_size, +				&payload_virt, &payload_phys); +		if (ret) { +			pr_err("Inadequate payload DMA buffer\n"); +			return; +		} + +		ret = send_page_prepare(this, +				chip->oob_poi, mtd->oobsize, +				this->auxiliary_virt, this->auxiliary_phys, +				nfc_geo->auxiliary_size, +				&auxiliary_virt, &auxiliary_phys); +		if (ret) { +			pr_err("Inadequate auxiliary DMA buffer\n"); +			goto exit_auxiliary; +		} +	} + +	/* Ask the NFC. */ +	ret = gpmi_send_page(this, payload_phys, auxiliary_phys); +	if (ret) +		pr_err("Error in ECC-based write: %d\n", ret); + +	if (!this->swap_block_mark) { +		send_page_end(this, chip->oob_poi, mtd->oobsize, +				this->auxiliary_virt, this->auxiliary_phys, +				nfc_geo->auxiliary_size, +				auxiliary_virt, auxiliary_phys); +exit_auxiliary: +		send_page_end(this, buf, mtd->writesize, +				this->payload_virt, this->payload_phys, +				nfc_geo->payload_size, +				payload_virt, payload_phys); +	} +} + +/* + * There are several places in this driver where we have to handle the OOB and + * block marks. This is the function where things are the most complicated, so + * this is where we try to explain it all. All the other places refer back to + * here. + * + * These are the rules, in order of decreasing importance: + * + * 1) Nothing the caller does can be allowed to imperil the block mark. + * + * 2) In read operations, the first byte of the OOB we return must reflect the + *    true state of the block mark, no matter where that block mark appears in + *    the physical page. + * + * 3) ECC-based read operations return an OOB full of set bits (since we never + *    allow ECC-based writes to the OOB, it doesn't matter what ECC-based reads + *    return). + * + * 4) "Raw" read operations return a direct view of the physical bytes in the + *    page, using the conventional definition of which bytes are data and which + *    are OOB. This gives the caller a way to see the actual, physical bytes + *    in the page, without the distortions applied by our ECC engine. + * + * + * What we do for this specific read operation depends on two questions: + * + * 1) Are we doing a "raw" read, or an ECC-based read? + * + * 2) Are we using block mark swapping or transcription? + * + * There are four cases, illustrated by the following Karnaugh map: + * + *                    |           Raw           |         ECC-based       | + *       -------------+-------------------------+-------------------------+ + *                    | Read the conventional   |                         | + *                    | OOB at the end of the   |                         | + *       Swapping     | page and return it. It  |                         | + *                    | contains exactly what   |                         | + *                    | we want.                | Read the block mark and | + *       -------------+-------------------------+ return it in a buffer   | + *                    | Read the conventional   | full of set bits.       | + *                    | OOB at the end of the   |                         | + *                    | page and also the block |                         | + *       Transcribing | mark in the metadata.   |                         | + *                    | Copy the block mark     |                         | + *                    | into the first byte of  |                         | + *                    | the OOB.                |                         | + *       -------------+-------------------------+-------------------------+ + * + * Note that we break rule #4 in the Transcribing/Raw case because we're not + * giving an accurate view of the actual, physical bytes in the page (we're + * overwriting the block mark). That's OK because it's more important to follow + * rule #2. + * + * It turns out that knowing whether we want an "ECC-based" or "raw" read is not + * easy. When reading a page, for example, the NAND Flash MTD code calls our + * ecc.read_page or ecc.read_page_raw function. Thus, the fact that MTD wants an + * ECC-based or raw view of the page is implicit in which function it calls + * (there is a similar pair of ECC-based/raw functions for writing). + * + * Since MTD assumes the OOB is not covered by ECC, there is no pair of + * ECC-based/raw functions for reading or or writing the OOB. The fact that the + * caller wants an ECC-based or raw view of the page is not propagated down to + * this driver. + */ +static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, +				int page, int sndcmd) +{ +	struct gpmi_nand_data *this = chip->priv; + +	pr_debug("page number is %d\n", page); +	/* clear the OOB buffer */ +	memset(chip->oob_poi, ~0, mtd->oobsize); + +	/* Read out the conventional OOB. */ +	chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); +	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + +	/* +	 * Now, we want to make sure the block mark is correct. In the +	 * Swapping/Raw case, we already have it. Otherwise, we need to +	 * explicitly read it. +	 */ +	if (!this->swap_block_mark) { +		/* Read the block mark into the first byte of the OOB buffer. */ +		chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); +		chip->oob_poi[0] = chip->read_byte(mtd); +	} + +	/* +	 * Return true, indicating that the next call to this function must send +	 * a command. +	 */ +	return true; +} + +static int +gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) +{ +	/* +	 * The BCH will use all the (page + oob). +	 * Our gpmi_hw_ecclayout can only prohibit the JFFS2 to write the oob. +	 * But it can not stop some ioctls such MEMWRITEOOB which uses +	 * MTD_OPS_PLACE_OOB. So We have to implement this function to prohibit +	 * these ioctls too. +	 */ +	return -EPERM; +} + +static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) +{ +	struct nand_chip *chip = mtd->priv; +	struct gpmi_nand_data *this = chip->priv; +	int block, ret = 0; +	uint8_t *block_mark; +	int column, page, status, chipnr; + +	/* Get block number */ +	block = (int)(ofs >> chip->bbt_erase_shift); +	if (chip->bbt) +		chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); + +	/* Do we have a flash based bad block table ? */ +	if (chip->options & NAND_BBT_USE_FLASH) +		ret = nand_update_bbt(mtd, ofs); +	else { +		chipnr = (int)(ofs >> chip->chip_shift); +		chip->select_chip(mtd, chipnr); + +		column = this->swap_block_mark ? mtd->writesize : 0; + +		/* Write the block mark. */ +		block_mark = this->data_buffer_dma; +		block_mark[0] = 0; /* bad block marker */ + +		/* Shift to get page */ +		page = (int)(ofs >> chip->page_shift); + +		chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page); +		chip->write_buf(mtd, block_mark, 1); +		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + +		status = chip->waitfunc(mtd, chip); +		if (status & NAND_STATUS_FAIL) +			ret = -EIO; + +		chip->select_chip(mtd, -1); +	} +	if (!ret) +		mtd->ecc_stats.badblocks++; + +	return ret; +} + +static int __devinit nand_boot_set_geometry(struct gpmi_nand_data *this) +{ +	struct boot_rom_geometry *geometry = &this->rom_geometry; + +	/* +	 * Set the boot block stride size. +	 * +	 * In principle, we should be reading this from the OTP bits, since +	 * that's where the ROM is going to get it. In fact, we don't have any +	 * way to read the OTP bits, so we go with the default and hope for the +	 * best. +	 */ +	geometry->stride_size_in_pages = 64; + +	/* +	 * Set the search area stride exponent. +	 * +	 * In principle, we should be reading this from the OTP bits, since +	 * that's where the ROM is going to get it. In fact, we don't have any +	 * way to read the OTP bits, so we go with the default and hope for the +	 * best. +	 */ +	geometry->search_area_stride_exponent = 2; +	return 0; +} + +static const char  *fingerprint = "STMP"; +static int __devinit mx23_check_transcription_stamp(struct gpmi_nand_data *this) +{ +	struct boot_rom_geometry *rom_geo = &this->rom_geometry; +	struct device *dev = this->dev; +	struct mtd_info *mtd = &this->mtd; +	struct nand_chip *chip = &this->nand; +	unsigned int search_area_size_in_strides; +	unsigned int stride; +	unsigned int page; +	loff_t byte; +	uint8_t *buffer = chip->buffers->databuf; +	int saved_chip_number; +	int found_an_ncb_fingerprint = false; + +	/* Compute the number of strides in a search area. */ +	search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent; + +	saved_chip_number = this->current_chip; +	chip->select_chip(mtd, 0); + +	/* +	 * Loop through the first search area, looking for the NCB fingerprint. +	 */ +	dev_dbg(dev, "Scanning for an NCB fingerprint...\n"); + +	for (stride = 0; stride < search_area_size_in_strides; stride++) { +		/* Compute the page and byte addresses. */ +		page = stride * rom_geo->stride_size_in_pages; +		byte = page   * mtd->writesize; + +		dev_dbg(dev, "Looking for a fingerprint in page 0x%x\n", page); + +		/* +		 * Read the NCB fingerprint. The fingerprint is four bytes long +		 * and starts in the 12th byte of the page. +		 */ +		chip->cmdfunc(mtd, NAND_CMD_READ0, 12, page); +		chip->read_buf(mtd, buffer, strlen(fingerprint)); + +		/* Look for the fingerprint. */ +		if (!memcmp(buffer, fingerprint, strlen(fingerprint))) { +			found_an_ncb_fingerprint = true; +			break; +		} + +	} + +	chip->select_chip(mtd, saved_chip_number); + +	if (found_an_ncb_fingerprint) +		dev_dbg(dev, "\tFound a fingerprint\n"); +	else +		dev_dbg(dev, "\tNo fingerprint found\n"); +	return found_an_ncb_fingerprint; +} + +/* Writes a transcription stamp. */ +static int __devinit mx23_write_transcription_stamp(struct gpmi_nand_data *this) +{ +	struct device *dev = this->dev; +	struct boot_rom_geometry *rom_geo = &this->rom_geometry; +	struct mtd_info *mtd = &this->mtd; +	struct nand_chip *chip = &this->nand; +	unsigned int block_size_in_pages; +	unsigned int search_area_size_in_strides; +	unsigned int search_area_size_in_pages; +	unsigned int search_area_size_in_blocks; +	unsigned int block; +	unsigned int stride; +	unsigned int page; +	loff_t       byte; +	uint8_t      *buffer = chip->buffers->databuf; +	int saved_chip_number; +	int status; + +	/* Compute the search area geometry. */ +	block_size_in_pages = mtd->erasesize / mtd->writesize; +	search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent; +	search_area_size_in_pages = search_area_size_in_strides * +					rom_geo->stride_size_in_pages; +	search_area_size_in_blocks = +		  (search_area_size_in_pages + (block_size_in_pages - 1)) / +				    block_size_in_pages; + +	dev_dbg(dev, "Search Area Geometry :\n"); +	dev_dbg(dev, "\tin Blocks : %u\n", search_area_size_in_blocks); +	dev_dbg(dev, "\tin Strides: %u\n", search_area_size_in_strides); +	dev_dbg(dev, "\tin Pages  : %u\n", search_area_size_in_pages); + +	/* Select chip 0. */ +	saved_chip_number = this->current_chip; +	chip->select_chip(mtd, 0); + +	/* Loop over blocks in the first search area, erasing them. */ +	dev_dbg(dev, "Erasing the search area...\n"); + +	for (block = 0; block < search_area_size_in_blocks; block++) { +		/* Compute the page address. */ +		page = block * block_size_in_pages; + +		/* Erase this block. */ +		dev_dbg(dev, "\tErasing block 0x%x\n", block); +		chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); +		chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); + +		/* Wait for the erase to finish. */ +		status = chip->waitfunc(mtd, chip); +		if (status & NAND_STATUS_FAIL) +			dev_err(dev, "[%s] Erase failed.\n", __func__); +	} + +	/* Write the NCB fingerprint into the page buffer. */ +	memset(buffer, ~0, mtd->writesize); +	memset(chip->oob_poi, ~0, mtd->oobsize); +	memcpy(buffer + 12, fingerprint, strlen(fingerprint)); + +	/* Loop through the first search area, writing NCB fingerprints. */ +	dev_dbg(dev, "Writing NCB fingerprints...\n"); +	for (stride = 0; stride < search_area_size_in_strides; stride++) { +		/* Compute the page and byte addresses. */ +		page = stride * rom_geo->stride_size_in_pages; +		byte = page   * mtd->writesize; + +		/* Write the first page of the current stride. */ +		dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page); +		chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); +		chip->ecc.write_page_raw(mtd, chip, buffer); +		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + +		/* Wait for the write to finish. */ +		status = chip->waitfunc(mtd, chip); +		if (status & NAND_STATUS_FAIL) +			dev_err(dev, "[%s] Write failed.\n", __func__); +	} + +	/* Deselect chip 0. */ +	chip->select_chip(mtd, saved_chip_number); +	return 0; +} + +static int __devinit mx23_boot_init(struct gpmi_nand_data  *this) +{ +	struct device *dev = this->dev; +	struct nand_chip *chip = &this->nand; +	struct mtd_info *mtd = &this->mtd; +	unsigned int block_count; +	unsigned int block; +	int     chipnr; +	int     page; +	loff_t  byte; +	uint8_t block_mark; +	int     ret = 0; + +	/* +	 * If control arrives here, we can't use block mark swapping, which +	 * means we're forced to use transcription. First, scan for the +	 * transcription stamp. If we find it, then we don't have to do +	 * anything -- the block marks are already transcribed. +	 */ +	if (mx23_check_transcription_stamp(this)) +		return 0; + +	/* +	 * If control arrives here, we couldn't find a transcription stamp, so +	 * so we presume the block marks are in the conventional location. +	 */ +	dev_dbg(dev, "Transcribing bad block marks...\n"); + +	/* Compute the number of blocks in the entire medium. */ +	block_count = chip->chipsize >> chip->phys_erase_shift; + +	/* +	 * Loop over all the blocks in the medium, transcribing block marks as +	 * we go. +	 */ +	for (block = 0; block < block_count; block++) { +		/* +		 * Compute the chip, page and byte addresses for this block's +		 * conventional mark. +		 */ +		chipnr = block >> (chip->chip_shift - chip->phys_erase_shift); +		page = block << (chip->phys_erase_shift - chip->page_shift); +		byte = block <<  chip->phys_erase_shift; + +		/* Send the command to read the conventional block mark. */ +		chip->select_chip(mtd, chipnr); +		chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); +		block_mark = chip->read_byte(mtd); +		chip->select_chip(mtd, -1); + +		/* +		 * Check if the block is marked bad. If so, we need to mark it +		 * again, but this time the result will be a mark in the +		 * location where we transcribe block marks. +		 */ +		if (block_mark != 0xff) { +			dev_dbg(dev, "Transcribing mark in block %u\n", block); +			ret = chip->block_markbad(mtd, byte); +			if (ret) +				dev_err(dev, "Failed to mark block bad with " +							"ret %d\n", ret); +		} +	} + +	/* Write the stamp that indicates we've transcribed the block marks. */ +	mx23_write_transcription_stamp(this); +	return 0; +} + +static int __devinit nand_boot_init(struct gpmi_nand_data  *this) +{ +	nand_boot_set_geometry(this); + +	/* This is ROM arch-specific initilization before the BBT scanning. */ +	if (GPMI_IS_MX23(this)) +		return mx23_boot_init(this); +	return 0; +} + +static int __devinit gpmi_set_geometry(struct gpmi_nand_data *this) +{ +	int ret; + +	/* Free the temporary DMA memory for reading ID. */ +	gpmi_free_dma_buffer(this); + +	/* Set up the NFC geometry which is used by BCH. */ +	ret = bch_set_geometry(this); +	if (ret) { +		pr_err("set geometry ret : %d\n", ret); +		return ret; +	} + +	/* Alloc the new DMA buffers according to the pagesize and oobsize */ +	return gpmi_alloc_dma_buffer(this); +} + +static int gpmi_pre_bbt_scan(struct gpmi_nand_data  *this) +{ +	int ret; + +	/* Set up swap_block_mark, must be set before the gpmi_set_geometry() */ +	if (GPMI_IS_MX23(this)) +		this->swap_block_mark = false; +	else +		this->swap_block_mark = true; + +	/* Set up the medium geometry */ +	ret = gpmi_set_geometry(this); +	if (ret) +		return ret; + +	/* NAND boot init, depends on the gpmi_set_geometry(). */ +	return nand_boot_init(this); +} + +static int gpmi_scan_bbt(struct mtd_info *mtd) +{ +	struct nand_chip *chip = mtd->priv; +	struct gpmi_nand_data *this = chip->priv; +	int ret; + +	/* Prepare for the BBT scan. */ +	ret = gpmi_pre_bbt_scan(this); +	if (ret) +		return ret; + +	/* use the default BBT implementation */ +	return nand_default_bbt(mtd); +} + +void gpmi_nfc_exit(struct gpmi_nand_data *this) +{ +	nand_release(&this->mtd); +	gpmi_free_dma_buffer(this); +} + +static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) +{ +	struct gpmi_nand_platform_data *pdata = this->pdata; +	struct mtd_info  *mtd = &this->mtd; +	struct nand_chip *chip = &this->nand; +	int ret; + +	/* init current chip */ +	this->current_chip	= -1; + +	/* init the MTD data structures */ +	mtd->priv		= chip; +	mtd->name		= "gpmi-nand"; +	mtd->owner		= THIS_MODULE; + +	/* init the nand_chip{}, we don't support a 16-bit NAND Flash bus. */ +	chip->priv		= this; +	chip->select_chip	= gpmi_select_chip; +	chip->cmd_ctrl		= gpmi_cmd_ctrl; +	chip->dev_ready		= gpmi_dev_ready; +	chip->read_byte		= gpmi_read_byte; +	chip->read_buf		= gpmi_read_buf; +	chip->write_buf		= gpmi_write_buf; +	chip->ecc.read_page	= gpmi_ecc_read_page; +	chip->ecc.write_page	= gpmi_ecc_write_page; +	chip->ecc.read_oob	= gpmi_ecc_read_oob; +	chip->ecc.write_oob	= gpmi_ecc_write_oob; +	chip->scan_bbt		= gpmi_scan_bbt; +	chip->badblock_pattern	= &gpmi_bbt_descr; +	chip->block_markbad	= gpmi_block_markbad; +	chip->options		|= NAND_NO_SUBPAGE_WRITE; +	chip->ecc.mode		= NAND_ECC_HW; +	chip->ecc.size		= 1; +	chip->ecc.layout	= &gpmi_hw_ecclayout; + +	/* Allocate a temporary DMA buffer for reading ID in the nand_scan() */ +	this->bch_geometry.payload_size = 1024; +	this->bch_geometry.auxiliary_size = 128; +	ret = gpmi_alloc_dma_buffer(this); +	if (ret) +		goto err_out; + +	ret = nand_scan(mtd, pdata->max_chip_count); +	if (ret) { +		pr_err("Chip scan failed\n"); +		goto err_out; +	} + +	ret = mtd_device_parse_register(mtd, NULL, NULL, +			pdata->partitions, pdata->partition_count); +	if (ret) +		goto err_out; +	return 0; + +err_out: +	gpmi_nfc_exit(this); +	return ret; +} + +static int __devinit gpmi_nand_probe(struct platform_device *pdev) +{ +	struct gpmi_nand_platform_data *pdata = pdev->dev.platform_data; +	struct gpmi_nand_data *this; +	int ret; + +	this = kzalloc(sizeof(*this), GFP_KERNEL); +	if (!this) { +		pr_err("Failed to allocate per-device memory\n"); +		return -ENOMEM; +	} + +	platform_set_drvdata(pdev, this); +	this->pdev  = pdev; +	this->dev   = &pdev->dev; +	this->pdata = pdata; + +	if (pdata->platform_init) { +		ret = pdata->platform_init(); +		if (ret) +			goto platform_init_error; +	} + +	ret = acquire_resources(this); +	if (ret) +		goto exit_acquire_resources; + +	ret = init_hardware(this); +	if (ret) +		goto exit_nfc_init; + +	ret = gpmi_nfc_init(this); +	if (ret) +		goto exit_nfc_init; + +	return 0; + +exit_nfc_init: +	release_resources(this); +platform_init_error: +exit_acquire_resources: +	platform_set_drvdata(pdev, NULL); +	kfree(this); +	return ret; +} + +static int __exit gpmi_nand_remove(struct platform_device *pdev) +{ +	struct gpmi_nand_data *this = platform_get_drvdata(pdev); + +	gpmi_nfc_exit(this); +	release_resources(this); +	platform_set_drvdata(pdev, NULL); +	kfree(this); +	return 0; +} + +static const struct platform_device_id gpmi_ids[] = { +	{ +		.name = "imx23-gpmi-nand", +		.driver_data = IS_MX23, +	}, { +		.name = "imx28-gpmi-nand", +		.driver_data = IS_MX28, +	}, {}, +}; + +static struct platform_driver gpmi_nand_driver = { +	.driver = { +		.name = "gpmi-nand", +	}, +	.probe   = gpmi_nand_probe, +	.remove  = __exit_p(gpmi_nand_remove), +	.id_table = gpmi_ids, +}; + +static int __init gpmi_nand_init(void) +{ +	int err; + +	err = platform_driver_register(&gpmi_nand_driver); +	if (err == 0) +		printk(KERN_INFO "GPMI NAND driver registered. (IMX)\n"); +	else +		pr_err("i.MX GPMI NAND driver registration failed\n"); +	return err; +} + +static void __exit gpmi_nand_exit(void) +{ +	platform_driver_unregister(&gpmi_nand_driver); +} + +module_init(gpmi_nand_init); +module_exit(gpmi_nand_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("i.MX GPMI NAND Flash Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h new file mode 100644 index 000000000000..e023bccb7781 --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h @@ -0,0 +1,273 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008 Embedded Alley Solutions, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ +#ifndef __DRIVERS_MTD_NAND_GPMI_NAND_H +#define __DRIVERS_MTD_NAND_GPMI_NAND_H + +#include <linux/mtd/nand.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <mach/dma.h> + +struct resources { +	void          *gpmi_regs; +	void          *bch_regs; +	unsigned int  bch_low_interrupt; +	unsigned int  bch_high_interrupt; +	unsigned int  dma_low_channel; +	unsigned int  dma_high_channel; +	struct clk    *clock; +}; + +/** + * struct bch_geometry - BCH geometry description. + * @gf_len:                   The length of Galois Field. (e.g., 13 or 14) + * @ecc_strength:             A number that describes the strength of the ECC + *                            algorithm. + * @page_size:                The size, in bytes, of a physical page, including + *                            both data and OOB. + * @metadata_size:            The size, in bytes, of the metadata. + * @ecc_chunk_size:           The size, in bytes, of a single ECC chunk. Note + *                            the first chunk in the page includes both data and + *                            metadata, so it's a bit larger than this value. + * @ecc_chunk_count:          The number of ECC chunks in the page, + * @payload_size:             The size, in bytes, of the payload buffer. + * @auxiliary_size:           The size, in bytes, of the auxiliary buffer. + * @auxiliary_status_offset:  The offset into the auxiliary buffer at which + *                            the ECC status appears. + * @block_mark_byte_offset:   The byte offset in the ECC-based page view at + *                            which the underlying physical block mark appears. + * @block_mark_bit_offset:    The bit offset into the ECC-based page view at + *                            which the underlying physical block mark appears. + */ +struct bch_geometry { +	unsigned int  gf_len; +	unsigned int  ecc_strength; +	unsigned int  page_size; +	unsigned int  metadata_size; +	unsigned int  ecc_chunk_size; +	unsigned int  ecc_chunk_count; +	unsigned int  payload_size; +	unsigned int  auxiliary_size; +	unsigned int  auxiliary_status_offset; +	unsigned int  block_mark_byte_offset; +	unsigned int  block_mark_bit_offset; +}; + +/** + * struct boot_rom_geometry - Boot ROM geometry description. + * @stride_size_in_pages:        The size of a boot block stride, in pages. + * @search_area_stride_exponent: The logarithm to base 2 of the size of a + *                               search area in boot block strides. + */ +struct boot_rom_geometry { +	unsigned int  stride_size_in_pages; +	unsigned int  search_area_stride_exponent; +}; + +/* DMA operations types */ +enum dma_ops_type { +	DMA_FOR_COMMAND = 1, +	DMA_FOR_READ_DATA, +	DMA_FOR_WRITE_DATA, +	DMA_FOR_READ_ECC_PAGE, +	DMA_FOR_WRITE_ECC_PAGE +}; + +/** + * struct nand_timing - Fundamental timing attributes for NAND. + * @data_setup_in_ns:         The data setup time, in nanoseconds. Usually the + *                            maximum of tDS and tWP. A negative value + *                            indicates this characteristic isn't known. + * @data_hold_in_ns:          The data hold time, in nanoseconds. Usually the + *                            maximum of tDH, tWH and tREH. A negative value + *                            indicates this characteristic isn't known. + * @address_setup_in_ns:      The address setup time, in nanoseconds. Usually + *                            the maximum of tCLS, tCS and tALS. A negative + *                            value indicates this characteristic isn't known. + * @gpmi_sample_delay_in_ns:  A GPMI-specific timing parameter. A negative value + *                            indicates this characteristic isn't known. + * @tREA_in_ns:               tREA, in nanoseconds, from the data sheet. A + *                            negative value indicates this characteristic isn't + *                            known. + * @tRLOH_in_ns:              tRLOH, in nanoseconds, from the data sheet. A + *                            negative value indicates this characteristic isn't + *                            known. + * @tRHOH_in_ns:              tRHOH, in nanoseconds, from the data sheet. A + *                            negative value indicates this characteristic isn't + *                            known. + */ +struct nand_timing { +	int8_t  data_setup_in_ns; +	int8_t  data_hold_in_ns; +	int8_t  address_setup_in_ns; +	int8_t  gpmi_sample_delay_in_ns; +	int8_t  tREA_in_ns; +	int8_t  tRLOH_in_ns; +	int8_t  tRHOH_in_ns; +}; + +struct gpmi_nand_data { +	/* System Interface */ +	struct device		*dev; +	struct platform_device	*pdev; +	struct gpmi_nand_platform_data	*pdata; + +	/* Resources */ +	struct resources	resources; + +	/* Flash Hardware */ +	struct nand_timing	timing; + +	/* BCH */ +	struct bch_geometry	bch_geometry; +	struct completion	bch_done; + +	/* NAND Boot issue */ +	bool			swap_block_mark; +	struct boot_rom_geometry rom_geometry; + +	/* MTD / NAND */ +	struct nand_chip	nand; +	struct mtd_info		mtd; + +	/* General-use Variables */ +	int			current_chip; +	unsigned int		command_length; + +	/* passed from upper layer */ +	uint8_t			*upper_buf; +	int			upper_len; + +	/* for DMA operations */ +	bool			direct_dma_map_ok; + +	struct scatterlist	cmd_sgl; +	char			*cmd_buffer; + +	struct scatterlist	data_sgl; +	char			*data_buffer_dma; + +	void			*page_buffer_virt; +	dma_addr_t		page_buffer_phys; +	unsigned int		page_buffer_size; + +	void			*payload_virt; +	dma_addr_t		payload_phys; + +	void			*auxiliary_virt; +	dma_addr_t		auxiliary_phys; + +	/* DMA channels */ +#define DMA_CHANS		8 +	struct dma_chan		*dma_chans[DMA_CHANS]; +	struct mxs_dma_data	dma_data; +	enum dma_ops_type	last_dma_type; +	enum dma_ops_type	dma_type; +	struct completion	dma_done; + +	/* private */ +	void			*private; +}; + +/** + * struct gpmi_nfc_hardware_timing - GPMI hardware timing parameters. + * @data_setup_in_cycles:      The data setup time, in cycles. + * @data_hold_in_cycles:       The data hold time, in cycles. + * @address_setup_in_cycles:   The address setup time, in cycles. + * @use_half_periods:          Indicates the clock is running slowly, so the + *                             NFC DLL should use half-periods. + * @sample_delay_factor:       The sample delay factor. + */ +struct gpmi_nfc_hardware_timing { +	uint8_t  data_setup_in_cycles; +	uint8_t  data_hold_in_cycles; +	uint8_t  address_setup_in_cycles; +	bool     use_half_periods; +	uint8_t  sample_delay_factor; +}; + +/** + * struct timing_threshod - Timing threshold + * @max_data_setup_cycles:       The maximum number of data setup cycles that + *                               can be expressed in the hardware. + * @internal_data_setup_in_ns:   The time, in ns, that the NFC hardware requires + *                               for data read internal setup. In the Reference + *                               Manual, see the chapter "High-Speed NAND + *                               Timing" for more details. + * @max_sample_delay_factor:     The maximum sample delay factor that can be + *                               expressed in the hardware. + * @max_dll_clock_period_in_ns:  The maximum period of the GPMI clock that the + *                               sample delay DLL hardware can possibly work + *                               with (the DLL is unusable with longer periods). + *                               If the full-cycle period is greater than HALF + *                               this value, the DLL must be configured to use + *                               half-periods. + * @max_dll_delay_in_ns:         The maximum amount of delay, in ns, that the + *                               DLL can implement. + * @clock_frequency_in_hz:       The clock frequency, in Hz, during the current + *                               I/O transaction. If no I/O transaction is in + *                               progress, this is the clock frequency during + *                               the most recent I/O transaction. + */ +struct timing_threshod { +	const unsigned int      max_chip_count; +	const unsigned int      max_data_setup_cycles; +	const unsigned int      internal_data_setup_in_ns; +	const unsigned int      max_sample_delay_factor; +	const unsigned int      max_dll_clock_period_in_ns; +	const unsigned int      max_dll_delay_in_ns; +	unsigned long           clock_frequency_in_hz; + +}; + +/* Common Services */ +extern int common_nfc_set_geometry(struct gpmi_nand_data *); +extern struct dma_chan *get_dma_chan(struct gpmi_nand_data *); +extern void prepare_data_dma(struct gpmi_nand_data *, +				enum dma_data_direction dr); +extern int start_dma_without_bch_irq(struct gpmi_nand_data *, +				struct dma_async_tx_descriptor *); +extern int start_dma_with_bch_irq(struct gpmi_nand_data *, +				struct dma_async_tx_descriptor *); + +/* GPMI-NAND helper function library */ +extern int gpmi_init(struct gpmi_nand_data *); +extern void gpmi_clear_bch(struct gpmi_nand_data *); +extern void gpmi_dump_info(struct gpmi_nand_data *); +extern int bch_set_geometry(struct gpmi_nand_data *); +extern int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip); +extern int gpmi_send_command(struct gpmi_nand_data *); +extern void gpmi_begin(struct gpmi_nand_data *); +extern void gpmi_end(struct gpmi_nand_data *); +extern int gpmi_read_data(struct gpmi_nand_data *); +extern int gpmi_send_data(struct gpmi_nand_data *); +extern int gpmi_send_page(struct gpmi_nand_data *, +			dma_addr_t payload, dma_addr_t auxiliary); +extern int gpmi_read_page(struct gpmi_nand_data *, +			dma_addr_t payload, dma_addr_t auxiliary); + +/* BCH : Status Block Completion Codes */ +#define STATUS_GOOD		0x00 +#define STATUS_ERASED		0xff +#define STATUS_UNCORRECTABLE	0xfe + +/* Use the platform_id to distinguish different Archs. */ +#define IS_MX23			0x1 +#define IS_MX28			0x2 +#define GPMI_IS_MX23(x)		((x)->pdev->id_entry->driver_data == IS_MX23) +#define GPMI_IS_MX28(x)		((x)->pdev->id_entry->driver_data == IS_MX28) +#endif diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-regs.h b/drivers/mtd/nand/gpmi-nand/gpmi-regs.h new file mode 100644 index 000000000000..83431240e2f2 --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/gpmi-regs.h @@ -0,0 +1,172 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright 2008 Embedded Alley Solutions, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef __GPMI_NAND_GPMI_REGS_H +#define __GPMI_NAND_GPMI_REGS_H + +#define HW_GPMI_CTRL0					0x00000000 +#define HW_GPMI_CTRL0_SET				0x00000004 +#define HW_GPMI_CTRL0_CLR				0x00000008 +#define HW_GPMI_CTRL0_TOG				0x0000000c + +#define BP_GPMI_CTRL0_COMMAND_MODE			24 +#define BM_GPMI_CTRL0_COMMAND_MODE	(3 << BP_GPMI_CTRL0_COMMAND_MODE) +#define BF_GPMI_CTRL0_COMMAND_MODE(v)	\ +	(((v) << BP_GPMI_CTRL0_COMMAND_MODE) & BM_GPMI_CTRL0_COMMAND_MODE) +#define BV_GPMI_CTRL0_COMMAND_MODE__WRITE		0x0 +#define BV_GPMI_CTRL0_COMMAND_MODE__READ		0x1 +#define BV_GPMI_CTRL0_COMMAND_MODE__READ_AND_COMPARE	0x2 +#define BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY	0x3 + +#define BM_GPMI_CTRL0_WORD_LENGTH			(1 << 23) +#define BV_GPMI_CTRL0_WORD_LENGTH__16_BIT		0x0 +#define BV_GPMI_CTRL0_WORD_LENGTH__8_BIT		0x1 + +/* + *  Difference in LOCK_CS between imx23 and imx28 : + *  This bit may impact the _POWER_ consumption. So some chips + *  do not set it. + */ +#define MX23_BP_GPMI_CTRL0_LOCK_CS			22 +#define MX28_BP_GPMI_CTRL0_LOCK_CS			27 +#define LOCK_CS_ENABLE					0x1 +#define BF_GPMI_CTRL0_LOCK_CS(v, x)			0x0 + +/* Difference in CS between imx23 and imx28 */ +#define BP_GPMI_CTRL0_CS				20 +#define MX23_BM_GPMI_CTRL0_CS		(3 << BP_GPMI_CTRL0_CS) +#define MX28_BM_GPMI_CTRL0_CS		(7 << BP_GPMI_CTRL0_CS) +#define BF_GPMI_CTRL0_CS(v, x)		(((v) << BP_GPMI_CTRL0_CS) & \ +						(GPMI_IS_MX23((x)) \ +						? MX23_BM_GPMI_CTRL0_CS	\ +						: MX28_BM_GPMI_CTRL0_CS)) + +#define BP_GPMI_CTRL0_ADDRESS				17 +#define BM_GPMI_CTRL0_ADDRESS		(3 << BP_GPMI_CTRL0_ADDRESS) +#define BF_GPMI_CTRL0_ADDRESS(v)	\ +		(((v) << BP_GPMI_CTRL0_ADDRESS) & BM_GPMI_CTRL0_ADDRESS) +#define BV_GPMI_CTRL0_ADDRESS__NAND_DATA		0x0 +#define BV_GPMI_CTRL0_ADDRESS__NAND_CLE			0x1 +#define BV_GPMI_CTRL0_ADDRESS__NAND_ALE			0x2 + +#define BM_GPMI_CTRL0_ADDRESS_INCREMENT			(1 << 16) +#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__DISABLED	0x0 +#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__ENABLED	0x1 + +#define BP_GPMI_CTRL0_XFER_COUNT			0 +#define BM_GPMI_CTRL0_XFER_COUNT	(0xffff << BP_GPMI_CTRL0_XFER_COUNT) +#define BF_GPMI_CTRL0_XFER_COUNT(v)	\ +		(((v) << BP_GPMI_CTRL0_XFER_COUNT) & BM_GPMI_CTRL0_XFER_COUNT) + +#define HW_GPMI_COMPARE					0x00000010 + +#define HW_GPMI_ECCCTRL					0x00000020 +#define HW_GPMI_ECCCTRL_SET				0x00000024 +#define HW_GPMI_ECCCTRL_CLR				0x00000028 +#define HW_GPMI_ECCCTRL_TOG				0x0000002c + +#define BP_GPMI_ECCCTRL_ECC_CMD				13 +#define BM_GPMI_ECCCTRL_ECC_CMD		(3 << BP_GPMI_ECCCTRL_ECC_CMD) +#define BF_GPMI_ECCCTRL_ECC_CMD(v)	\ +		(((v) << BP_GPMI_ECCCTRL_ECC_CMD) & BM_GPMI_ECCCTRL_ECC_CMD) +#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE		0x0 +#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE		0x1 + +#define BM_GPMI_ECCCTRL_ENABLE_ECC			(1 << 12) +#define BV_GPMI_ECCCTRL_ENABLE_ECC__ENABLE		0x1 +#define BV_GPMI_ECCCTRL_ENABLE_ECC__DISABLE		0x0 + +#define BP_GPMI_ECCCTRL_BUFFER_MASK			0 +#define BM_GPMI_ECCCTRL_BUFFER_MASK	(0x1ff << BP_GPMI_ECCCTRL_BUFFER_MASK) +#define BF_GPMI_ECCCTRL_BUFFER_MASK(v)	\ +	(((v) << BP_GPMI_ECCCTRL_BUFFER_MASK) & BM_GPMI_ECCCTRL_BUFFER_MASK) +#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY	0x100 +#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE		0x1FF + +#define HW_GPMI_ECCCOUNT				0x00000030 +#define HW_GPMI_PAYLOAD					0x00000040 +#define HW_GPMI_AUXILIARY				0x00000050 +#define HW_GPMI_CTRL1					0x00000060 +#define HW_GPMI_CTRL1_SET				0x00000064 +#define HW_GPMI_CTRL1_CLR				0x00000068 +#define HW_GPMI_CTRL1_TOG				0x0000006c + +#define BM_GPMI_CTRL1_BCH_MODE				(1 << 18) + +#define BP_GPMI_CTRL1_DLL_ENABLE			17 +#define BM_GPMI_CTRL1_DLL_ENABLE	(1 << BP_GPMI_CTRL1_DLL_ENABLE) + +#define BP_GPMI_CTRL1_HALF_PERIOD			16 +#define BM_GPMI_CTRL1_HALF_PERIOD	(1 << BP_GPMI_CTRL1_HALF_PERIOD) + +#define BP_GPMI_CTRL1_RDN_DELAY				12 +#define BM_GPMI_CTRL1_RDN_DELAY		(0xf << BP_GPMI_CTRL1_RDN_DELAY) +#define BF_GPMI_CTRL1_RDN_DELAY(v)	\ +		(((v) << BP_GPMI_CTRL1_RDN_DELAY) & BM_GPMI_CTRL1_RDN_DELAY) + +#define BM_GPMI_CTRL1_DEV_RESET				(1 << 3) +#define BV_GPMI_CTRL1_DEV_RESET__ENABLED		0x0 +#define BV_GPMI_CTRL1_DEV_RESET__DISABLED		0x1 + +#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY		(1 << 2) +#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVELOW	0x0 +#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVEHIGH	0x1 + +#define BM_GPMI_CTRL1_CAMERA_MODE			(1 << 1) +#define BV_GPMI_CTRL1_GPMI_MODE__NAND			0x0 +#define BV_GPMI_CTRL1_GPMI_MODE__ATA			0x1 + +#define BM_GPMI_CTRL1_GPMI_MODE				(1 << 0) + +#define HW_GPMI_TIMING0					0x00000070 + +#define BP_GPMI_TIMING0_ADDRESS_SETUP			16 +#define BM_GPMI_TIMING0_ADDRESS_SETUP	(0xff << BP_GPMI_TIMING0_ADDRESS_SETUP) +#define BF_GPMI_TIMING0_ADDRESS_SETUP(v)	\ +	(((v) << BP_GPMI_TIMING0_ADDRESS_SETUP) & BM_GPMI_TIMING0_ADDRESS_SETUP) + +#define BP_GPMI_TIMING0_DATA_HOLD			8 +#define BM_GPMI_TIMING0_DATA_HOLD	(0xff << BP_GPMI_TIMING0_DATA_HOLD) +#define BF_GPMI_TIMING0_DATA_HOLD(v)		\ +	(((v) << BP_GPMI_TIMING0_DATA_HOLD) & BM_GPMI_TIMING0_DATA_HOLD) + +#define BP_GPMI_TIMING0_DATA_SETUP			0 +#define BM_GPMI_TIMING0_DATA_SETUP	(0xff << BP_GPMI_TIMING0_DATA_SETUP) +#define BF_GPMI_TIMING0_DATA_SETUP(v)		\ +	(((v) << BP_GPMI_TIMING0_DATA_SETUP) & BM_GPMI_TIMING0_DATA_SETUP) + +#define HW_GPMI_TIMING1					0x00000080 +#define BP_GPMI_TIMING1_BUSY_TIMEOUT			16 + +#define HW_GPMI_TIMING2					0x00000090 +#define HW_GPMI_DATA					0x000000a0 + +/* MX28 uses this to detect READY. */ +#define HW_GPMI_STAT					0x000000b0 +#define MX28_BP_GPMI_STAT_READY_BUSY			24 +#define MX28_BM_GPMI_STAT_READY_BUSY	(0xff << MX28_BP_GPMI_STAT_READY_BUSY) +#define MX28_BF_GPMI_STAT_READY_BUSY(v)		\ +	(((v) << MX28_BP_GPMI_STAT_READY_BUSY) & MX28_BM_GPMI_STAT_READY_BUSY) + +/* MX23 uses this to detect READY. */ +#define HW_GPMI_DEBUG					0x000000c0 +#define MX23_BP_GPMI_DEBUG_READY0			28 +#define MX23_BM_GPMI_DEBUG_READY0	(1 << MX23_BP_GPMI_DEBUG_READY0) +#endif diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index 02a03e67109c..5dc6f0d92f1a 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c @@ -81,9 +81,6 @@ static int h1910_device_ready(struct mtd_info *mtd)  static int __init h1910_init(void)  {  	struct nand_chip *this; -	const char *part_type = 0; -	int mtd_parts_nb = 0; -	struct mtd_partition *mtd_parts = 0;  	void __iomem *nandaddr;  	if (!machine_is_h1900()) @@ -136,22 +133,10 @@ static int __init h1910_init(void)  		iounmap((void *)nandaddr);  		return -ENXIO;  	} -#ifdef CONFIG_MTD_CMDLINE_PARTS -	mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts, "h1910-nand"); -	if (mtd_parts_nb > 0) -		part_type = "command line"; -	else -		mtd_parts_nb = 0; -#endif -	if (mtd_parts_nb == 0) { -		mtd_parts = partition_info; -		mtd_parts_nb = NUM_PARTITIONS; -		part_type = "static"; -	}  	/* Register the partitions */ -	printk(KERN_NOTICE "Using %s partition definition\n", part_type); -	mtd_device_register(h1910_nand_mtd, mtd_parts, mtd_parts_nb); +	mtd_device_parse_register(h1910_nand_mtd, NULL, 0, +			partition_info, NUM_PARTITIONS);  	/* Return happy */  	return 0; diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index 6e813daed068..e2664073a89b 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -251,10 +251,6 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,  	return 0;  } -#ifdef CONFIG_MTD_CMDLINE_PARTS -static const char *part_probes[] = {"cmdline", NULL}; -#endif -  static int jz_nand_ioremap_resource(struct platform_device *pdev,  	const char *name, struct resource **res, void __iomem **base)  { @@ -299,8 +295,6 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)  	struct nand_chip *chip;  	struct mtd_info *mtd;  	struct jz_nand_platform_data *pdata = pdev->dev.platform_data; -	struct mtd_partition *partition_info; -	int num_partitions = 0;  	nand = kzalloc(sizeof(*nand), GFP_KERNEL);  	if (!nand) { @@ -373,15 +367,9 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)  		goto err_gpio_free;  	} -#ifdef CONFIG_MTD_CMDLINE_PARTS -	num_partitions = parse_mtd_partitions(mtd, part_probes, -						&partition_info, 0); -#endif -	if (num_partitions <= 0 && pdata) { -		num_partitions = pdata->num_partitions; -		partition_info = pdata->partitions; -	} -	ret = mtd_device_register(mtd, partition_info, num_partitions); +	ret = mtd_device_parse_register(mtd, NULL, 0, +			pdata ? pdata->partitions : NULL, +			pdata ? pdata->num_partitions : 0);  	if (ret) {  		dev_err(&pdev->dev, "Failed to add mtd device\n"); diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index eb1fbac63eb6..5ede64706346 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -131,8 +131,6 @@ struct mpc5121_nfc_prv {  static void mpc5121_nfc_done(struct mtd_info *mtd); -static const char *mpc5121_nfc_pprobes[] = { "cmdlinepart", NULL }; -  /* Read NFC register */  static inline u16 nfc_read(struct mtd_info *mtd, uint reg)  { @@ -656,13 +654,13 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op)  	struct mpc5121_nfc_prv *prv;  	struct resource res;  	struct mtd_info *mtd; -	struct mtd_partition *parts;  	struct nand_chip *chip;  	unsigned long regs_paddr, regs_size;  	const __be32 *chips_no;  	int resettime = 0;  	int retval = 0;  	int rev, len; +	struct mtd_part_parser_data ppdata;  	/*  	 * Check SoC revision. This driver supports only NFC @@ -727,6 +725,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op)  	}  	mtd->name = "MPC5121 NAND"; +	ppdata.of_node = dn;  	chip->dev_ready = mpc5121_nfc_dev_ready;  	chip->cmdfunc = mpc5121_nfc_command;  	chip->read_byte = mpc5121_nfc_read_byte; @@ -735,7 +734,8 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op)  	chip->write_buf = mpc5121_nfc_write_buf;  	chip->verify_buf = mpc5121_nfc_verify_buf;  	chip->select_chip = mpc5121_nfc_select_chip; -	chip->options = NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT; +	chip->options = NAND_NO_AUTOINCR; +	chip->bbt_options = NAND_BBT_USE_FLASH;  	chip->ecc.mode = NAND_ECC_SOFT;  	/* Support external chip-select logic on ADS5121 board */ @@ -837,19 +837,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op)  	dev_set_drvdata(dev, mtd);  	/* Register device in MTD */ -	retval = parse_mtd_partitions(mtd, mpc5121_nfc_pprobes, &parts, 0); -#ifdef CONFIG_MTD_OF_PARTS -	if (retval == 0) -		retval = of_mtd_parse_partitions(dev, dn, &parts); -#endif -	if (retval < 0) { -		dev_err(dev, "Error parsing MTD partitions!\n"); -		devm_free_irq(dev, prv->irq, mtd); -		retval = -EINVAL; -		goto error; -	} - -	retval = mtd_device_register(mtd, parts, retval); +	retval = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);  	if (retval) {  		dev_err(dev, "Error adding MTD device!\n");  		devm_free_irq(dev, prv->irq, mtd); diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 90df34c4d26c..74a43b818d0e 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -41,7 +41,7 @@  #define nfc_is_v21()		(cpu_is_mx25() || cpu_is_mx35())  #define nfc_is_v1()		(cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21()) -#define nfc_is_v3_2()		cpu_is_mx51() +#define nfc_is_v3_2()		(cpu_is_mx51() || cpu_is_mx53())  #define nfc_is_v3()		nfc_is_v3_2()  /* Addresses for NFC registers */ @@ -143,7 +143,6 @@  struct mxc_nand_host {  	struct mtd_info		mtd;  	struct nand_chip	nand; -	struct mtd_partition	*parts;  	struct device		*dev;  	void			*spare0; @@ -350,8 +349,7 @@ static void wait_op_done(struct mxc_nand_host *host, int useirq)  			udelay(1);  		}  		if (max_retries < 0) -			DEBUG(MTD_DEBUG_LEVEL0, "%s: INT not set\n", -			      __func__); +			pr_debug("%s: INT not set\n", __func__);  	}  } @@ -371,7 +369,7 @@ static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq)   * waits for completion. */  static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq)  { -	DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x, %d)\n", cmd, useirq); +	pr_debug("send_cmd(host, 0x%x, %d)\n", cmd, useirq);  	writew(cmd, NFC_V1_V2_FLASH_CMD);  	writew(NFC_CMD, NFC_V1_V2_CONFIG2); @@ -387,8 +385,7 @@ static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq)  			udelay(1);  		}  		if (max_retries < 0) -			DEBUG(MTD_DEBUG_LEVEL0, "%s: RESET failed\n", -			      __func__); +			pr_debug("%s: RESET failed\n", __func__);  	} else {  		/* Wait for operation to complete */  		wait_op_done(host, useirq); @@ -411,7 +408,7 @@ static void send_addr_v3(struct mxc_nand_host *host, uint16_t addr, int islast)   * a NAND command. */  static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islast)  { -	DEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x %d)\n", addr, islast); +	pr_debug("send_addr(host, 0x%x %d)\n", addr, islast);  	writew(addr, NFC_V1_V2_FLASH_ADDR);  	writew(NFC_ADDR, NFC_V1_V2_CONFIG2); @@ -561,8 +558,7 @@ static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat,  	uint16_t ecc_status = readw(NFC_V1_V2_ECC_STATUS_RESULT);  	if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { -		DEBUG(MTD_DEBUG_LEVEL0, -		      "MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); +		pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");  		return -1;  	} @@ -849,7 +845,7 @@ static void preset_v1_v2(struct mtd_info *mtd)  		writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3);  	} else if (nfc_is_v1()) {  		writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR); -		writew(0x4000, NFC_V1_UNLOCKEND_BLKADDR); +		writew(0xffff, NFC_V1_UNLOCKEND_BLKADDR);  	} else  		BUG(); @@ -932,8 +928,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,  	struct nand_chip *nand_chip = mtd->priv;  	struct mxc_nand_host *host = nand_chip->priv; -	DEBUG(MTD_DEBUG_LEVEL3, -	      "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", +	pr_debug("mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",  	      command, column, page_addr);  	/* Reset command state information */ @@ -1044,7 +1039,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)  	struct mxc_nand_platform_data *pdata = pdev->dev.platform_data;  	struct mxc_nand_host *host;  	struct resource *res; -	int err = 0, __maybe_unused nr_parts = 0; +	int err = 0;  	struct nand_ecclayout *oob_smallpage, *oob_largepage;  	/* Allocate memory for MTD device structure and private data */ @@ -1179,7 +1174,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)  		this->bbt_td = &bbt_main_descr;  		this->bbt_md = &bbt_mirror_descr;  		/* update flash based bbt */ -		this->options |= NAND_USE_FLASH_BBT; +		this->bbt_options |= NAND_BBT_USE_FLASH;  	}  	init_completion(&host->op_completion); @@ -1231,16 +1226,8 @@ static int __init mxcnd_probe(struct platform_device *pdev)  	}  	/* Register the partitions */ -	nr_parts = -	    parse_mtd_partitions(mtd, part_probes, &host->parts, 0); -	if (nr_parts > 0) -		mtd_device_register(mtd, host->parts, nr_parts); -	else if (pdata->parts) -		mtd_device_register(mtd, pdata->parts, pdata->nr_parts); -	else { -		pr_info("Registering %s as whole device\n", mtd->name); -		mtd_device_register(mtd, NULL, 0); -	} +	mtd_device_parse_register(mtd, part_probes, 0, +			pdata->parts, pdata->nr_parts);  	platform_set_drvdata(pdev, host); diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index a46e9bb847bd..3ed9c5e4d34e 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -21,7 +21,7 @@   *  TODO:   *	Enable cached programming for 2k page size chips   *	Check, if mtd->ecctype should be set to MTD_ECC_HW - *	if we have HW ecc support. + *	if we have HW ECC support.   *	The AG-AND chips have nice features for speed improvement,   *	which are not supported yet. Read / program 4 pages in one go.   *	BBT table is not serialized, has to be fixed @@ -113,21 +113,19 @@ static int check_offs_len(struct mtd_info *mtd,  	/* Start address must align on block boundary */  	if (ofs & ((1 << chip->phys_erase_shift) - 1)) { -		DEBUG(MTD_DEBUG_LEVEL0, "%s: Unaligned address\n", __func__); +		pr_debug("%s: unaligned address\n", __func__);  		ret = -EINVAL;  	}  	/* Length must align on block boundary */  	if (len & ((1 << chip->phys_erase_shift) - 1)) { -		DEBUG(MTD_DEBUG_LEVEL0, "%s: Length not block aligned\n", -					__func__); +		pr_debug("%s: length not block aligned\n", __func__);  		ret = -EINVAL;  	}  	/* Do not allow past end of device */  	if (ofs + len > mtd->size) { -		DEBUG(MTD_DEBUG_LEVEL0, "%s: Past end of device\n", -					__func__); +		pr_debug("%s: past end of device\n", __func__);  		ret = -EINVAL;  	} @@ -136,9 +134,9 @@ static int check_offs_len(struct mtd_info *mtd,  /**   * nand_release_device - [GENERIC] release chip - * @mtd:	MTD device structure + * @mtd: MTD device structure   * - * Deselect, release chip lock and wake up anyone waiting on the device + * Deselect, release chip lock and wake up anyone waiting on the device.   */  static void nand_release_device(struct mtd_info *mtd)  { @@ -157,9 +155,9 @@ static void nand_release_device(struct mtd_info *mtd)  /**   * nand_read_byte - [DEFAULT] read one byte from the chip - * @mtd:	MTD device structure + * @mtd: MTD device structure   * - * Default read function for 8bit buswith + * Default read function for 8bit buswidth   */  static uint8_t nand_read_byte(struct mtd_info *mtd)  { @@ -169,10 +167,11 @@ static uint8_t nand_read_byte(struct mtd_info *mtd)  /**   * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip - * @mtd:	MTD device structure + * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip + * @mtd: MTD device structure + * + * Default read function for 16bit buswidth with endianness conversion.   * - * Default read function for 16bit buswith with - * endianess conversion   */  static uint8_t nand_read_byte16(struct mtd_info *mtd)  { @@ -182,10 +181,9 @@ static uint8_t nand_read_byte16(struct mtd_info *mtd)  /**   * nand_read_word - [DEFAULT] read one word from the chip - * @mtd:	MTD device structure + * @mtd: MTD device structure   * - * Default read function for 16bit buswith without - * endianess conversion + * Default read function for 16bit buswidth without endianness conversion.   */  static u16 nand_read_word(struct mtd_info *mtd)  { @@ -195,8 +193,8 @@ static u16 nand_read_word(struct mtd_info *mtd)  /**   * nand_select_chip - [DEFAULT] control CE line - * @mtd:	MTD device structure - * @chipnr:	chipnumber to select, -1 for deselect + * @mtd: MTD device structure + * @chipnr: chipnumber to select, -1 for deselect   *   * Default select function for 1 chip devices.   */ @@ -218,11 +216,11 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr)  /**   * nand_write_buf - [DEFAULT] write buffer to chip - * @mtd:	MTD device structure - * @buf:	data buffer - * @len:	number of bytes to write + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write   * - * Default write function for 8bit buswith + * Default write function for 8bit buswidth.   */  static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)  { @@ -235,11 +233,11 @@ static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)  /**   * nand_read_buf - [DEFAULT] read chip data into buffer - * @mtd:	MTD device structure - * @buf:	buffer to store date - * @len:	number of bytes to read + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read   * - * Default read function for 8bit buswith + * Default read function for 8bit buswidth.   */  static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)  { @@ -252,11 +250,11 @@ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)  /**   * nand_verify_buf - [DEFAULT] Verify chip data against buffer - * @mtd:	MTD device structure - * @buf:	buffer containing the data to compare - * @len:	number of bytes to compare + * @mtd: MTD device structure + * @buf: buffer containing the data to compare + * @len: number of bytes to compare   * - * Default verify function for 8bit buswith + * Default verify function for 8bit buswidth.   */  static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)  { @@ -271,11 +269,11 @@ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)  /**   * nand_write_buf16 - [DEFAULT] write buffer to chip - * @mtd:	MTD device structure - * @buf:	data buffer - * @len:	number of bytes to write + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write   * - * Default write function for 16bit buswith + * Default write function for 16bit buswidth.   */  static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)  { @@ -291,11 +289,11 @@ static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)  /**   * nand_read_buf16 - [DEFAULT] read chip data into buffer - * @mtd:	MTD device structure - * @buf:	buffer to store date - * @len:	number of bytes to read + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read   * - * Default read function for 16bit buswith + * Default read function for 16bit buswidth.   */  static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)  { @@ -310,11 +308,11 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)  /**   * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer - * @mtd:	MTD device structure - * @buf:	buffer containing the data to compare - * @len:	number of bytes to compare + * @mtd: MTD device structure + * @buf: buffer containing the data to compare + * @len: number of bytes to compare   * - * Default verify function for 16bit buswith + * Default verify function for 16bit buswidth.   */  static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)  { @@ -332,9 +330,9 @@ static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)  /**   * nand_block_bad - [DEFAULT] Read bad block marker from the chip - * @mtd:	MTD device structure - * @ofs:	offset from device start - * @getchip:	0, if the chip is already selected + * @mtd: MTD device structure + * @ofs: offset from device start + * @getchip: 0, if the chip is already selected   *   * Check, if the block is bad.   */ @@ -344,7 +342,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)  	struct nand_chip *chip = mtd->priv;  	u16 bad; -	if (chip->options & NAND_BBT_SCANLASTPAGE) +	if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)  		ofs += mtd->erasesize - mtd->writesize;  	page = (int)(ofs >> chip->page_shift) & chip->pagemask; @@ -384,11 +382,11 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)  /**   * nand_default_block_markbad - [DEFAULT] mark a block bad - * @mtd:	MTD device structure - * @ofs:	offset from device start + * @mtd: MTD device structure + * @ofs: offset from device start   * - * This is the default implementation, which can be overridden by - * a hardware specific driver. + * This is the default implementation, which can be overridden by a hardware + * specific driver.  */  static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)  { @@ -396,7 +394,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)  	uint8_t buf[2] = { 0, 0 };  	int block, ret, i = 0; -	if (chip->options & NAND_BBT_SCANLASTPAGE) +	if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)  		ofs += mtd->erasesize - mtd->writesize;  	/* Get block number */ @@ -404,33 +402,31 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)  	if (chip->bbt)  		chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); -	/* Do we have a flash based bad block table ? */ -	if (chip->options & NAND_USE_FLASH_BBT) +	/* Do we have a flash based bad block table? */ +	if (chip->bbt_options & NAND_BBT_USE_FLASH)  		ret = nand_update_bbt(mtd, ofs);  	else { +		struct mtd_oob_ops ops; +  		nand_get_device(chip, mtd, FL_WRITING); -		/* Write to first two pages and to byte 1 and 6 if necessary. -		 * If we write to more than one location, the first error -		 * encountered quits the procedure. We write two bytes per -		 * location, so we dont have to mess with 16 bit access. +		/* +		 * Write to first two pages if necessary. If we write to more +		 * than one location, the first error encountered quits the +		 * procedure. We write two bytes per location, so we dont have +		 * to mess with 16 bit access.  		 */ +		ops.len = ops.ooblen = 2; +		ops.datbuf = NULL; +		ops.oobbuf = buf; +		ops.ooboffs = chip->badblockpos & ~0x01; +		ops.mode = MTD_OPS_PLACE_OOB;  		do { -			chip->ops.len = chip->ops.ooblen = 2; -			chip->ops.datbuf = NULL; -			chip->ops.oobbuf = buf; -			chip->ops.ooboffs = chip->badblockpos & ~0x01; - -			ret = nand_do_write_oob(mtd, ofs, &chip->ops); +			ret = nand_do_write_oob(mtd, ofs, &ops); -			if (!ret && (chip->options & NAND_BBT_SCANBYTE1AND6)) { -				chip->ops.ooboffs = NAND_SMALL_BADBLOCK_POS -					& ~0x01; -				ret = nand_do_write_oob(mtd, ofs, &chip->ops); -			}  			i++;  			ofs += mtd->writesize; -		} while (!ret && (chip->options & NAND_BBT_SCAN2NDPAGE) && +		} while (!ret && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) &&  				i < 2);  		nand_release_device(mtd); @@ -443,16 +439,16 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)  /**   * nand_check_wp - [GENERIC] check if the chip is write protected - * @mtd:	MTD device structure - * Check, if the device is write protected + * @mtd: MTD device structure   * - * The function expects, that the device is already selected + * Check, if the device is write protected. The function expects, that the + * device is already selected.   */  static int nand_check_wp(struct mtd_info *mtd)  {  	struct nand_chip *chip = mtd->priv; -	/* broken xD cards report WP despite being writable */ +	/* Broken xD cards report WP despite being writable */  	if (chip->options & NAND_BROKEN_XD)  		return 0; @@ -463,10 +459,10 @@ static int nand_check_wp(struct mtd_info *mtd)  /**   * nand_block_checkbad - [GENERIC] Check if a block is marked bad - * @mtd:	MTD device structure - * @ofs:	offset from device start - * @getchip:	0, if the chip is already selected - * @allowbbt:	1, if its allowed to access the bbt area + * @mtd: MTD device structure + * @ofs: offset from device start + * @getchip: 0, if the chip is already selected + * @allowbbt: 1, if its allowed to access the bbt area   *   * Check, if the block is bad. Either by reading the bad block table or   * calling of the scan function. @@ -485,8 +481,8 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,  /**   * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands. - * @mtd:	MTD device structure - * @timeo:	Timeout + * @mtd: MTD device structure + * @timeo: Timeout   *   * Helper function for nand_wait_ready used when needing to wait in interrupt   * context. @@ -505,10 +501,7 @@ static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)  	}  } -/* - * Wait for the ready pin, after a command - * The timeout is catched later. - */ +/* Wait for the ready pin, after a command. The timeout is caught later. */  void nand_wait_ready(struct mtd_info *mtd)  {  	struct nand_chip *chip = mtd->priv; @@ -519,7 +512,7 @@ void nand_wait_ready(struct mtd_info *mtd)  		return panic_nand_wait_ready(mtd, 400);  	led_trigger_event(nand_led_trigger, LED_FULL); -	/* wait until command is processed or timeout occures */ +	/* Wait until command is processed or timeout occurs */  	do {  		if (chip->dev_ready(mtd))  			break; @@ -531,13 +524,13 @@ EXPORT_SYMBOL_GPL(nand_wait_ready);  /**   * nand_command - [DEFAULT] Send command to NAND device - * @mtd:	MTD device structure - * @command:	the command to be sent - * @column:	the column address for this command, -1 if none - * @page_addr:	the page address for this command, -1 if none + * @mtd: MTD device structure + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none   * - * Send command to NAND device. This function is used for small page - * devices (256/512 Bytes per page) + * Send command to NAND device. This function is used for small page devices + * (256/512 Bytes per page).   */  static void nand_command(struct mtd_info *mtd, unsigned int command,  			 int column, int page_addr) @@ -545,9 +538,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,  	register struct nand_chip *chip = mtd->priv;  	int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; -	/* -	 * Write out the command to the device. -	 */ +	/* Write out the command to the device */  	if (command == NAND_CMD_SEQIN) {  		int readcmd; @@ -567,9 +558,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,  	}  	chip->cmd_ctrl(mtd, command, ctrl); -	/* -	 * Address cycle, when necessary -	 */ +	/* Address cycle, when necessary */  	ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;  	/* Serially input address */  	if (column != -1) { @@ -590,8 +579,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,  	chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);  	/* -	 * program and erase have their own busy handlers -	 * status and sequential in needs no delay +	 * Program and erase have their own busy handlers status and sequential +	 * in needs no delay  	 */  	switch (command) { @@ -625,8 +614,10 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,  			return;  		}  	} -	/* Apply this short delay always to ensure that we do wait tWB in -	 * any case on any machine. */ +	/* +	 * Apply this short delay always to ensure that we do wait tWB in +	 * any case on any machine. +	 */  	ndelay(100);  	nand_wait_ready(mtd); @@ -634,14 +625,14 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,  /**   * nand_command_lp - [DEFAULT] Send command to NAND large page device - * @mtd:	MTD device structure - * @command:	the command to be sent - * @column:	the column address for this command, -1 if none - * @page_addr:	the page address for this command, -1 if none + * @mtd: MTD device structure + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none   *   * Send command to NAND device. This is the version for the new large page - * devices We dont have the separate regions as we have in the small page - * devices.  We must emulate NAND_CMD_READOOB to keep the code compatible. + * devices. We don't have the separate regions as we have in the small page + * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.   */  static void nand_command_lp(struct mtd_info *mtd, unsigned int command,  			    int column, int page_addr) @@ -683,8 +674,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,  	chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);  	/* -	 * program and erase have their own busy handlers -	 * status, sequential in, and deplete1 need no delay +	 * Program and erase have their own busy handlers status, sequential +	 * in, and deplete1 need no delay.  	 */  	switch (command) { @@ -698,14 +689,12 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,  	case NAND_CMD_DEPLETE1:  		return; -		/* -		 * read error status commands require only a short delay -		 */  	case NAND_CMD_STATUS_ERROR:  	case NAND_CMD_STATUS_ERROR0:  	case NAND_CMD_STATUS_ERROR1:  	case NAND_CMD_STATUS_ERROR2:  	case NAND_CMD_STATUS_ERROR3: +		/* Read error status commands require only a short delay */  		udelay(chip->chip_delay);  		return; @@ -739,7 +728,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,  	default:  		/*  		 * If we don't have access to the busy pin, we apply the given -		 * command delay +		 * command delay.  		 */  		if (!chip->dev_ready) {  			udelay(chip->chip_delay); @@ -747,8 +736,10 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,  		}  	} -	/* Apply this short delay always to ensure that we do wait tWB in -	 * any case on any machine. */ +	/* +	 * Apply this short delay always to ensure that we do wait tWB in +	 * any case on any machine. +	 */  	ndelay(100);  	nand_wait_ready(mtd); @@ -756,25 +747,25 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,  /**   * panic_nand_get_device - [GENERIC] Get chip for selected access - * @chip:	the nand chip descriptor - * @mtd:	MTD device structure - * @new_state:	the state which is requested + * @chip: the nand chip descriptor + * @mtd: MTD device structure + * @new_state: the state which is requested   *   * Used when in panic, no locks are taken.   */  static void panic_nand_get_device(struct nand_chip *chip,  		      struct mtd_info *mtd, int new_state)  { -	/* Hardware controller shared among independend devices */ +	/* Hardware controller shared among independent devices */  	chip->controller->active = chip;  	chip->state = new_state;  }  /**   * 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 + * @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   */ @@ -812,10 +803,10 @@ retry:  }  /** - * panic_nand_wait - [GENERIC]  wait until the command is done - * @mtd:	MTD device structure - * @chip:	NAND chip structure - * @timeo:	Timeout + * panic_nand_wait - [GENERIC] wait until the command is done + * @mtd: MTD device structure + * @chip: NAND chip structure + * @timeo: timeout   *   * Wait for command done. This is a helper function for nand_wait used when   * we are in interrupt context. May happen when in panic and trying to write @@ -838,13 +829,13 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,  }  /** - * nand_wait - [DEFAULT]  wait until the command is done - * @mtd:	MTD device structure - * @chip:	NAND chip structure + * nand_wait - [DEFAULT] wait until the command is done + * @mtd: MTD device structure + * @chip: NAND chip structure   * - * Wait for command done. This applies to erase and program only - * Erase can take up to 400ms and program up to 20ms according to - * general NAND and SmartMedia specs + * Wait for command done. This applies to erase and program only. Erase can + * take up to 400ms and program up to 20ms according to general NAND and + * SmartMedia specs.   */  static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)  { @@ -859,8 +850,10 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)  	led_trigger_event(nand_led_trigger, LED_FULL); -	/* Apply this short delay always to ensure that we do wait tWB in -	 * any case on any machine. */ +	/* +	 * Apply this short delay always to ensure that we do wait tWB in any +	 * case on any machine. +	 */  	ndelay(100);  	if ((state == FL_ERASING) && (chip->options & NAND_IS_AND)) @@ -890,16 +883,15 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)  /**   * __nand_unlock - [REPLACEABLE] unlocks specified locked blocks - *   * @mtd: mtd info   * @ofs: offset to start unlock from   * @len: length to unlock - * @invert:   when = 0, unlock the range of blocks within the lower and - *                      upper boundary address - *            when = 1, unlock the range of blocks outside the boundaries - *                      of the lower and upper boundary address + * @invert: when = 0, unlock the range of blocks within the lower and + *                    upper boundary address + *          when = 1, unlock the range of blocks outside the boundaries + *                    of the lower and upper boundary address   * - * return - unlock status + * Returs unlock status.   */  static int __nand_unlock(struct mtd_info *mtd, loff_t ofs,  					uint64_t len, int invert) @@ -919,10 +911,9 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs,  	/* Call wait ready function */  	status = chip->waitfunc(mtd, chip); -	udelay(1000);  	/* See if device thinks it succeeded */  	if (status & 0x01) { -		DEBUG(MTD_DEBUG_LEVEL0, "%s: Error status = 0x%08x\n", +		pr_debug("%s: error status = 0x%08x\n",  					__func__, status);  		ret = -EIO;  	} @@ -932,12 +923,11 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs,  /**   * nand_unlock - [REPLACEABLE] unlocks specified locked blocks - *   * @mtd: mtd info   * @ofs: offset to start unlock from   * @len: length to unlock   * - * return - unlock status + * Returns unlock status.   */  int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  { @@ -945,7 +935,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  	int chipnr;  	struct nand_chip *chip = mtd->priv; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n", +	pr_debug("%s: start = 0x%012llx, len = %llu\n",  			__func__, (unsigned long long)ofs, len);  	if (check_offs_len(mtd, ofs, len)) @@ -964,7 +954,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  	/* Check, if it is write protected */  	if (nand_check_wp(mtd)) { -		DEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n", +		pr_debug("%s: device is write protected!\n",  					__func__);  		ret = -EIO;  		goto out; @@ -981,18 +971,16 @@ EXPORT_SYMBOL(nand_unlock);  /**   * nand_lock - [REPLACEABLE] locks all blocks present in the device - *   * @mtd: mtd info   * @ofs: offset to start unlock from   * @len: length to unlock   * - * return - lock status + * This feature is not supported in many NAND parts. 'Micron' NAND parts do + * have this feature, but it allows only to lock all blocks, not for specified + * range for block. Implementing 'lock' feature by making use of 'unlock', for + * now.   * - * This feature is not supported in many NAND parts. 'Micron' NAND parts - * do have this feature, but it allows only to lock all blocks, not for - * specified range for block. - * - * Implementing 'lock' feature by making use of 'unlock', for now. + * Returns lock status.   */  int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  { @@ -1000,7 +988,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  	int chipnr, status, page;  	struct nand_chip *chip = mtd->priv; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n", +	pr_debug("%s: start = 0x%012llx, len = %llu\n",  			__func__, (unsigned long long)ofs, len);  	if (check_offs_len(mtd, ofs, len)) @@ -1015,7 +1003,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  	/* Check, if it is write protected */  	if (nand_check_wp(mtd)) { -		DEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n", +		pr_debug("%s: device is write protected!\n",  					__func__);  		status = MTD_ERASE_FAILED;  		ret = -EIO; @@ -1028,10 +1016,9 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)  	/* Call wait ready function */  	status = chip->waitfunc(mtd, chip); -	udelay(1000);  	/* See if device thinks it succeeded */  	if (status & 0x01) { -		DEBUG(MTD_DEBUG_LEVEL0, "%s: Error status = 0x%08x\n", +		pr_debug("%s: error status = 0x%08x\n",  					__func__, status);  		ret = -EIO;  		goto out; @@ -1047,13 +1034,13 @@ out:  EXPORT_SYMBOL(nand_lock);  /** - * nand_read_page_raw - [Intern] read raw page data without ecc - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	buffer to store read data - * @page:	page number to read + * nand_read_page_raw - [INTERN] read raw page data without ecc + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read   * - * Not for syndrome calculating ecc controllers, which use a special oob layout + * Not for syndrome calculating ECC controllers, which use a special oob layout.   */  static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,  			      uint8_t *buf, int page) @@ -1064,11 +1051,11 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,  }  /** - * nand_read_page_raw_syndrome - [Intern] read raw page data without ecc - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	buffer to store read data - * @page:	page number to read + * nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read   *   * We need a special oob layout and handling even when OOB isn't used.   */ @@ -1107,11 +1094,11 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd,  }  /** - * nand_read_page_swecc - [REPLACABLE] software ecc based page read function - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	buffer to store read data - * @page:	page number to read + * nand_read_page_swecc - [REPLACEABLE] software ECC based page read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read   */  static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,  				uint8_t *buf, int page) @@ -1148,12 +1135,12 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,  }  /** - * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @data_offs:	offset of requested data within the page - * @readlen:	data length - * @bufpoi:	buffer to store read data + * nand_read_subpage - [REPLACEABLE] software ECC based sub-page read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @data_offs: offset of requested data within the page + * @readlen: data length + * @bufpoi: buffer to store read data   */  static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,  			uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) @@ -1166,12 +1153,12 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,  	int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;  	int index = 0; -	/* Column address wihin the page aligned to ECC size (256bytes). */ +	/* Column address within the page aligned to ECC size (256bytes) */  	start_step = data_offs / chip->ecc.size;  	end_step = (data_offs + readlen - 1) / chip->ecc.size;  	num_steps = end_step - start_step + 1; -	/* Data size aligned to ECC ecc.size*/ +	/* Data size aligned to ECC ecc.size */  	datafrag_len = num_steps * chip->ecc.size;  	eccfrag_len = num_steps * chip->ecc.bytes; @@ -1183,13 +1170,14 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,  	p = bufpoi + data_col_addr;  	chip->read_buf(mtd, p, datafrag_len); -	/* Calculate  ECC */ +	/* Calculate ECC */  	for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)  		chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]); -	/* The performance is faster if to position offsets -	   according to ecc.pos. Let make sure here that -	   there are no gaps in ecc positions */ +	/* +	 * The performance is faster if we position offsets according to +	 * ecc.pos. Let's make sure that there are no gaps in ECC positions. +	 */  	for (i = 0; i < eccfrag_len - 1; i++) {  		if (eccpos[i + start_step * chip->ecc.bytes] + 1 !=  			eccpos[i + start_step * chip->ecc.bytes + 1]) { @@ -1201,8 +1189,10 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,  		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);  		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);  	} else { -		/* send the command to read the particular ecc bytes */ -		/* take care about buswidth alignment in read_buf */ +		/* +		 * Send the command to read the particular ECC bytes take care +		 * about buswidth alignment in read_buf. +		 */  		index = start_step * chip->ecc.bytes;  		aligned_pos = eccpos[index] & ~(busw - 1); @@ -1235,13 +1225,13 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,  }  /** - * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	buffer to store read data - * @page:	page number to read + * nand_read_page_hwecc - [REPLACEABLE] hardware ECC based page read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read   * - * Not for syndrome calculating ecc controllers which need a special oob layout + * Not for syndrome calculating ECC controllers which need a special oob layout.   */  static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,  				uint8_t *buf, int page) @@ -1280,18 +1270,17 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,  }  /** - * nand_read_page_hwecc_oob_first - [REPLACABLE] hw ecc, read oob first - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	buffer to store read data - * @page:	page number to read + * nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read   * - * Hardware ECC for large page chips, require OOB to be read first. - * For this ECC mode, the write_page method is re-used from ECC_HW. - * These methods read/write ECC from the OOB area, unlike the - * ECC_HW_SYNDROME support with multiple ECC steps, follows the - * "infix ECC" scheme and reads/writes ECC from the data area, by - * overwriting the NAND manufacturer bad block markings. + * Hardware ECC for large page chips, require OOB to be read first. For this + * ECC mode, the write_page method is re-used from ECC_HW. These methods + * read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with + * multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from + * the data area, by overwriting the NAND manufacturer bad block markings.   */  static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,  	struct nand_chip *chip, uint8_t *buf, int page) @@ -1329,14 +1318,14 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,  }  /** - * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	buffer to store read data - * @page:	page number to read + * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read   * - * The hw generator calculates the error syndrome automatically. Therefor - * we need a special oob layout and handling. + * The hw generator calculates the error syndrome automatically. Therefore we + * need a special oob layout and handling.   */  static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,  				   uint8_t *buf, int page) @@ -1384,29 +1373,29 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,  }  /** - * nand_transfer_oob - [Internal] Transfer oob to client buffer - * @chip:	nand chip structure - * @oob:	oob destination address - * @ops:	oob ops structure - * @len:	size of oob to transfer + * nand_transfer_oob - [INTERN] Transfer oob to client buffer + * @chip: nand chip structure + * @oob: oob destination address + * @ops: oob ops structure + * @len: size of oob to transfer   */  static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,  				  struct mtd_oob_ops *ops, size_t len)  {  	switch (ops->mode) { -	case MTD_OOB_PLACE: -	case MTD_OOB_RAW: +	case MTD_OPS_PLACE_OOB: +	case MTD_OPS_RAW:  		memcpy(oob, chip->oob_poi + ops->ooboffs, len);  		return oob + len; -	case MTD_OOB_AUTO: { +	case MTD_OPS_AUTO_OOB: {  		struct nand_oobfree *free = chip->ecc.layout->oobfree;  		uint32_t boffs = 0, roffs = ops->ooboffs;  		size_t bytes = 0;  		for (; free->length && len; free++, len -= bytes) { -			/* Read request not from offset 0 ? */ +			/* Read request not from offset 0? */  			if (unlikely(roffs)) {  				if (roffs >= free->length) {  					roffs -= free->length; @@ -1432,11 +1421,10 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,  }  /** - * nand_do_read_ops - [Internal] Read data with ECC - * - * @mtd:	MTD device structure - * @from:	offset to read from - * @ops:	oob ops structure + * nand_do_read_ops - [INTERN] Read data with ECC + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob ops structure   *   * Internal function. Called with chip held.   */ @@ -1451,7 +1439,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  	int ret = 0;  	uint32_t readlen = ops->len;  	uint32_t oobreadlen = ops->ooblen; -	uint32_t max_oobsize = ops->mode == MTD_OOB_AUTO ? +	uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ?  		mtd->oobavail : mtd->oobsize;  	uint8_t *bufpoi, *oob, *buf; @@ -1473,7 +1461,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  		bytes = min(mtd->writesize - col, readlen);  		aligned = (bytes == mtd->writesize); -		/* Is the current page in the buffer ? */ +		/* Is the current page in the buffer? */  		if (realpage != chip->pagebuf || oob) {  			bufpoi = aligned ? buf : chip->buffers->databuf; @@ -1483,7 +1471,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  			}  			/* Now read the page into the buffer */ -			if (unlikely(ops->mode == MTD_OOB_RAW)) +			if (unlikely(ops->mode == MTD_OPS_RAW))  				ret = chip->ecc.read_page_raw(mtd, chip,  							      bufpoi, page);  			else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) @@ -1492,14 +1480,22 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  			else  				ret = chip->ecc.read_page(mtd, chip, bufpoi,  							  page); -			if (ret < 0) +			if (ret < 0) { +				if (!aligned) +					/* Invalidate page cache */ +					chip->pagebuf = -1;  				break; +			}  			/* Transfer not aligned data */  			if (!aligned) {  				if (!NAND_SUBPAGE_READ(chip) && !oob && -				    !(mtd->ecc_stats.failed - stats.failed)) +				    !(mtd->ecc_stats.failed - stats.failed) && +				    (ops->mode != MTD_OPS_RAW))  					chip->pagebuf = realpage; +				else +					/* Invalidate page cache */ +					chip->pagebuf = -1;  				memcpy(buf, chip->buffers->databuf + col, bytes);  			} @@ -1539,7 +1535,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  		if (!readlen)  			break; -		/* For subsequent reads align to page boundary. */ +		/* For subsequent reads align to page boundary */  		col = 0;  		/* Increment page address */  		realpage++; @@ -1552,8 +1548,9 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  			chip->select_chip(mtd, chipnr);  		} -		/* Check, if the chip supports auto page increment -		 * or if we have hit a block boundary. +		/* +		 * Check, if the chip supports auto page increment or if we +		 * have hit a block boundary.  		 */  		if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))  			sndcmd = 1; @@ -1574,18 +1571,19 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  /**   * nand_read - [MTD Interface] MTD compatibility function for nand_do_read_ecc - * @mtd:	MTD device structure - * @from:	offset to read from - * @len:	number of bytes to read - * @retlen:	pointer to variable to store the number of read bytes - * @buf:	the databuffer to put data + * @mtd: MTD device structure + * @from: offset to read from + * @len: number of bytes to read + * @retlen: pointer to variable to store the number of read bytes + * @buf: the databuffer to put data   * - * Get hold of the chip and call nand_do_read + * Get hold of the chip and call nand_do_read.   */  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;  	/* Do not allow reads past end of device */ @@ -1596,13 +1594,14 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,  	nand_get_device(chip, mtd, FL_READING); -	chip->ops.len = len; -	chip->ops.datbuf = buf; -	chip->ops.oobbuf = NULL; +	ops.len = len; +	ops.datbuf = buf; +	ops.oobbuf = NULL; +	ops.mode = 0; -	ret = nand_do_read_ops(mtd, from, &chip->ops); +	ret = nand_do_read_ops(mtd, from, &ops); -	*retlen = chip->ops.retlen; +	*retlen = ops.retlen;  	nand_release_device(mtd); @@ -1610,11 +1609,11 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,  }  /** - * nand_read_oob_std - [REPLACABLE] the most common OOB data read function - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @page:	page number to read - * @sndcmd:	flag whether to issue read command or not + * nand_read_oob_std - [REPLACEABLE] the most common OOB data read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to read + * @sndcmd: flag whether to issue read command or not   */  static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,  			     int page, int sndcmd) @@ -1628,12 +1627,12 @@ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,  }  /** - * nand_read_oob_syndrome - [REPLACABLE] OOB data read function for HW ECC + * nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC   *			    with syndromes - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @page:	page number to read - * @sndcmd:	flag whether to issue read command or not + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to read + * @sndcmd: flag whether to issue read command or not   */  static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,  				  int page, int sndcmd) @@ -1667,10 +1666,10 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,  }  /** - * nand_write_oob_std - [REPLACABLE] the most common OOB data write function - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @page:	page number to write + * nand_write_oob_std - [REPLACEABLE] the most common OOB data write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to write   */  static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,  			      int page) @@ -1690,11 +1689,11 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,  }  /** - * nand_write_oob_syndrome - [REPLACABLE] OOB data write function for HW ECC - *			     with syndrome - only for large page flash ! - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @page:	page number to write + * nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC + *			     with syndrome - only for large page flash + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to write   */  static int nand_write_oob_syndrome(struct mtd_info *mtd,  				   struct nand_chip *chip, int page) @@ -1749,34 +1748,37 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd,  }  /** - * nand_do_read_oob - [Intern] NAND read out-of-band - * @mtd:	MTD device structure - * @from:	offset to read from - * @ops:	oob operations description structure + * nand_do_read_oob - [INTERN] NAND read out-of-band + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob operations description structure   * - * NAND read out-of-band data from the spare area + * NAND read out-of-band data from the spare area.   */  static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,  			    struct mtd_oob_ops *ops)  {  	int page, realpage, chipnr, sndcmd = 1;  	struct nand_chip *chip = mtd->priv; +	struct mtd_ecc_stats stats;  	int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;  	int readlen = ops->ooblen;  	int len;  	uint8_t *buf = ops->oobbuf; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08Lx, len = %i\n", +	pr_debug("%s: from = 0x%08Lx, len = %i\n",  			__func__, (unsigned long long)from, readlen); -	if (ops->mode == MTD_OOB_AUTO) +	stats = mtd->ecc_stats; + +	if (ops->mode == MTD_OPS_AUTO_OOB)  		len = chip->ecc.layout->oobavail;  	else  		len = mtd->oobsize;  	if (unlikely(ops->ooboffs >= len)) { -		DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start read " -					"outside oob\n", __func__); +		pr_debug("%s: attempt to start read outside oob\n", +				__func__);  		return -EINVAL;  	} @@ -1784,8 +1786,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,  	if (unlikely(from >= mtd->size ||  		     ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) -  					(from >> chip->page_shift)) * len)) { -		DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt read beyond end " -					"of device\n", __func__); +		pr_debug("%s: attempt to read beyond end of device\n", +				__func__);  		return -EINVAL;  	} @@ -1797,7 +1799,10 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,  	page = realpage & chip->pagemask;  	while (1) { -		sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); +		if (ops->mode == MTD_OPS_RAW) +			sndcmd = chip->ecc.read_oob_raw(mtd, chip, page, sndcmd); +		else +			sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);  		len = min(len, readlen);  		buf = nand_transfer_oob(chip, buf, ops, len); @@ -1830,24 +1835,29 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,  			chip->select_chip(mtd, chipnr);  		} -		/* Check, if the chip supports auto page increment -		 * or if we have hit a block boundary. +		/* +		 * Check, if the chip supports auto page increment or if we +		 * have hit a block boundary.  		 */  		if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))  			sndcmd = 1;  	}  	ops->oobretlen = ops->ooblen; -	return 0; + +	if (mtd->ecc_stats.failed - stats.failed) +		return -EBADMSG; + +	return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;  }  /**   * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band - * @mtd:	MTD device structure - * @from:	offset to read from - * @ops:	oob operation description structure + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob operation description structure   * - * NAND read data and/or out-of-band data + * NAND read data and/or out-of-band data.   */  static int nand_read_oob(struct mtd_info *mtd, loff_t from,  			 struct mtd_oob_ops *ops) @@ -1859,17 +1869,17 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,  	/* Do not allow reads past end of device */  	if (ops->datbuf && (from + ops->len) > mtd->size) { -		DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt read " -				"beyond end of device\n", __func__); +		pr_debug("%s: attempt to read beyond end of device\n", +				__func__);  		return -EINVAL;  	}  	nand_get_device(chip, mtd, FL_READING);  	switch (ops->mode) { -	case MTD_OOB_PLACE: -	case MTD_OOB_AUTO: -	case MTD_OOB_RAW: +	case MTD_OPS_PLACE_OOB: +	case MTD_OPS_AUTO_OOB: +	case MTD_OPS_RAW:  		break;  	default: @@ -1888,12 +1898,12 @@ out:  /** - * nand_write_page_raw - [Intern] raw page write function - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	data buffer + * nand_write_page_raw - [INTERN] raw page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer   * - * Not for syndrome calculating ecc controllers, which use a special oob layout + * Not for syndrome calculating ECC controllers, which use a special oob layout.   */  static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,  				const uint8_t *buf) @@ -1903,10 +1913,10 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,  }  /** - * nand_write_page_raw_syndrome - [Intern] raw page write function - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	data buffer + * nand_write_page_raw_syndrome - [INTERN] raw page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer   *   * We need a special oob layout and handling even when ECC isn't checked.   */ @@ -1942,10 +1952,10 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd,  		chip->write_buf(mtd, oob, size);  }  /** - * nand_write_page_swecc - [REPLACABLE] software ecc based page write function - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	data buffer + * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer   */  static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,  				  const uint8_t *buf) @@ -1957,7 +1967,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,  	const uint8_t *p = buf;  	uint32_t *eccpos = chip->ecc.layout->eccpos; -	/* Software ecc calculation */ +	/* Software ECC calculation */  	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)  		chip->ecc.calculate(mtd, p, &ecc_calc[i]); @@ -1968,10 +1978,10 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,  }  /** - * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	data buffer + * nand_write_page_hwecc - [REPLACEABLE] hardware ECC based page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer   */  static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,  				  const uint8_t *buf) @@ -1996,13 +2006,13 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,  }  /** - * nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write - * @mtd:	mtd info structure - * @chip:	nand chip info structure - * @buf:	data buffer + * nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer   * - * The hw generator calculates the error syndrome automatically. Therefor - * we need a special oob layout and handling. + * The hw generator calculates the error syndrome automatically. Therefore we + * need a special oob layout and handling.   */  static void nand_write_page_syndrome(struct mtd_info *mtd,  				    struct nand_chip *chip, const uint8_t *buf) @@ -2041,12 +2051,12 @@ static void nand_write_page_syndrome(struct mtd_info *mtd,  /**   * nand_write_page - [REPLACEABLE] write one page - * @mtd:	MTD device structure - * @chip:	NAND chip descriptor - * @buf:	the data to write - * @page:	page number to write - * @cached:	cached programming - * @raw:	use _raw version of write_page + * @mtd: MTD device structure + * @chip: NAND chip descriptor + * @buf: the data to write + * @page: page number to write + * @cached: cached programming + * @raw: use _raw version of write_page   */  static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,  			   const uint8_t *buf, int page, int cached, int raw) @@ -2061,8 +2071,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,  		chip->ecc.write_page(mtd, chip, buf);  	/* -	 * Cached progamming disabled for now, Not sure if its worth the -	 * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s) +	 * Cached progamming disabled for now. Not sure if it's worth the +	 * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s).  	 */  	cached = 0; @@ -2072,7 +2082,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,  		status = chip->waitfunc(mtd, chip);  		/*  		 * See if operation failed and additional status checks are -		 * available +		 * available.  		 */  		if ((status & NAND_STATUS_FAIL) && (chip->errstat))  			status = chip->errstat(mtd, chip, FL_WRITING, status, @@ -2096,29 +2106,37 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,  }  /** - * nand_fill_oob - [Internal] Transfer client buffer to oob - * @chip:	nand chip structure - * @oob:	oob data buffer - * @len:	oob data write length - * @ops:	oob ops structure + * nand_fill_oob - [INTERN] Transfer client buffer to oob + * @mtd: MTD device structure + * @oob: oob data buffer + * @len: oob data write length + * @ops: oob ops structure   */ -static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, -						struct mtd_oob_ops *ops) +static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len, +			      struct mtd_oob_ops *ops)  { +	struct nand_chip *chip = mtd->priv; + +	/* +	 * Initialise to all 0xFF, to avoid the possibility of left over OOB +	 * data from a previous OOB read. +	 */ +	memset(chip->oob_poi, 0xff, mtd->oobsize); +  	switch (ops->mode) { -	case MTD_OOB_PLACE: -	case MTD_OOB_RAW: +	case MTD_OPS_PLACE_OOB: +	case MTD_OPS_RAW:  		memcpy(chip->oob_poi + ops->ooboffs, oob, len);  		return oob + len; -	case MTD_OOB_AUTO: { +	case MTD_OPS_AUTO_OOB: {  		struct nand_oobfree *free = chip->ecc.layout->oobfree;  		uint32_t boffs = 0, woffs = ops->ooboffs;  		size_t bytes = 0;  		for (; free->length && len; free++, len -= bytes) { -			/* Write request not from offset 0 ? */ +			/* Write request not from offset 0? */  			if (unlikely(woffs)) {  				if (woffs >= free->length) {  					woffs -= free->length; @@ -2146,12 +2164,12 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len,  #define NOTALIGNED(x)	((x & (chip->subpagesize - 1)) != 0)  /** - * nand_do_write_ops - [Internal] NAND write with ECC - * @mtd:	MTD device structure - * @to:		offset to write to - * @ops:	oob operations description structure + * nand_do_write_ops - [INTERN] NAND write with ECC + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operations description structure   * - * NAND write with ECC + * NAND write with ECC.   */  static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,  			     struct mtd_oob_ops *ops) @@ -2161,7 +2179,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,  	uint32_t writelen = ops->len;  	uint32_t oobwritelen = ops->ooblen; -	uint32_t oobmaxlen = ops->mode == MTD_OOB_AUTO ? +	uint32_t oobmaxlen = ops->mode == MTD_OPS_AUTO_OOB ?  				mtd->oobavail : mtd->oobsize;  	uint8_t *oob = ops->oobbuf; @@ -2172,10 +2190,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,  	if (!writelen)  		return 0; -	/* reject writes, which are not page aligned */ +	/* Reject writes, which are not page aligned */  	if (NOTALIGNED(to) || NOTALIGNED(ops->len)) { -		printk(KERN_NOTICE "%s: Attempt to write not " -				"page aligned data\n", __func__); +		pr_notice("%s: attempt to write non page aligned data\n", +			   __func__);  		return -EINVAL;  	} @@ -2201,10 +2219,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,  	    (chip->pagebuf << chip->page_shift) < (to + ops->len))  		chip->pagebuf = -1; -	/* If we're not given explicit OOB data, let it be 0xFF */ -	if (likely(!oob)) -		memset(chip->oob_poi, 0xff, mtd->oobsize); -  	/* Don't allow multipage oob writes with offset */  	if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen))  		return -EINVAL; @@ -2214,7 +2228,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,  		int cached = writelen > bytes && page != blockmask;  		uint8_t *wbuf = buf; -		/* Partial page write ? */ +		/* Partial page write? */  		if (unlikely(column || writelen < (mtd->writesize - 1))) {  			cached = 0;  			bytes = min_t(int, bytes - column, (int) writelen); @@ -2226,12 +2240,15 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,  		if (unlikely(oob)) {  			size_t len = min(oobwritelen, oobmaxlen); -			oob = nand_fill_oob(chip, oob, len, ops); +			oob = nand_fill_oob(mtd, oob, len, ops);  			oobwritelen -= len; +		} else { +			/* We still need to erase leftover OOB data */ +			memset(chip->oob_poi, 0xff, mtd->oobsize);  		}  		ret = chip->write_page(mtd, chip, wbuf, page, cached, -				       (ops->mode == MTD_OOB_RAW)); +				       (ops->mode == MTD_OPS_RAW));  		if (ret)  			break; @@ -2260,11 +2277,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,  /**   * panic_nand_write - [MTD Interface] NAND write with ECC - * @mtd:	MTD device structure - * @to:		offset to write to - * @len:	number of bytes to write - * @retlen:	pointer to variable to store the number of written bytes - * @buf:	the data to write + * @mtd: MTD device structure + * @to: offset to write to + * @len: number of bytes to write + * @retlen: pointer to variable to store the number of written bytes + * @buf: the data to write   *   * NAND write with ECC. Used when performing writes in interrupt context, this   * may for example be called by mtdoops when writing an oops while in panic. @@ -2273,6 +2290,7 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,  			    size_t *retlen, const uint8_t *buf)  {  	struct nand_chip *chip = mtd->priv; +	struct mtd_oob_ops ops;  	int ret;  	/* Do not allow reads past end of device */ @@ -2281,36 +2299,38 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,  	if (!len)  		return 0; -	/* Wait for the device to get ready.  */ +	/* Wait for the device to get ready */  	panic_nand_wait(mtd, chip, 400); -	/* Grab the device.  */ +	/* Grab the device */  	panic_nand_get_device(chip, mtd, FL_WRITING); -	chip->ops.len = len; -	chip->ops.datbuf = (uint8_t *)buf; -	chip->ops.oobbuf = NULL; +	ops.len = len; +	ops.datbuf = (uint8_t *)buf; +	ops.oobbuf = NULL; +	ops.mode = 0; -	ret = nand_do_write_ops(mtd, to, &chip->ops); +	ret = nand_do_write_ops(mtd, to, &ops); -	*retlen = chip->ops.retlen; +	*retlen = ops.retlen;  	return ret;  }  /**   * nand_write - [MTD Interface] NAND write with ECC - * @mtd:	MTD device structure - * @to:		offset to write to - * @len:	number of bytes to write - * @retlen:	pointer to variable to store the number of written bytes - * @buf:	the data to write + * @mtd: MTD device structure + * @to: offset to write to + * @len: number of bytes to write + * @retlen: pointer to variable to store the number of written bytes + * @buf: the data to write   * - * NAND write with ECC + * NAND write with ECC.   */  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;  	/* Do not allow reads past end of device */ @@ -2321,13 +2341,14 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,  	nand_get_device(chip, mtd, FL_WRITING); -	chip->ops.len = len; -	chip->ops.datbuf = (uint8_t *)buf; -	chip->ops.oobbuf = NULL; +	ops.len = len; +	ops.datbuf = (uint8_t *)buf; +	ops.oobbuf = NULL; +	ops.mode = 0; -	ret = nand_do_write_ops(mtd, to, &chip->ops); +	ret = nand_do_write_ops(mtd, to, &ops); -	*retlen = chip->ops.retlen; +	*retlen = ops.retlen;  	nand_release_device(mtd); @@ -2336,11 +2357,11 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,  /**   * nand_do_write_oob - [MTD Interface] NAND write out-of-band - * @mtd:	MTD device structure - * @to:		offset to write to - * @ops:	oob operation description structure + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operation description structure   * - * NAND write out-of-band + * NAND write out-of-band.   */  static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,  			     struct mtd_oob_ops *ops) @@ -2348,24 +2369,24 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,  	int chipnr, page, status, len;  	struct nand_chip *chip = mtd->priv; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", +	pr_debug("%s: to = 0x%08x, len = %i\n",  			 __func__, (unsigned int)to, (int)ops->ooblen); -	if (ops->mode == MTD_OOB_AUTO) +	if (ops->mode == MTD_OPS_AUTO_OOB)  		len = chip->ecc.layout->oobavail;  	else  		len = mtd->oobsize;  	/* Do not allow write past end of page */  	if ((ops->ooboffs + ops->ooblen) > len) { -		DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to write " -				"past end of page\n", __func__); +		pr_debug("%s: attempt to write past end of page\n", +				__func__);  		return -EINVAL;  	}  	if (unlikely(ops->ooboffs >= len)) { -		DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start " -				"write outside oob\n", __func__); +		pr_debug("%s: attempt to start write outside oob\n", +				__func__);  		return -EINVAL;  	} @@ -2374,8 +2395,8 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,  		     ops->ooboffs + ops->ooblen >  			((mtd->size >> chip->page_shift) -  			 (to >> chip->page_shift)) * len)) { -		DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt write beyond " -				"end of device\n", __func__); +		pr_debug("%s: attempt to write beyond end of device\n", +				__func__);  		return -EINVAL;  	} @@ -2401,10 +2422,12 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,  	if (page == chip->pagebuf)  		chip->pagebuf = -1; -	memset(chip->oob_poi, 0xff, mtd->oobsize); -	nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops); -	status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); -	memset(chip->oob_poi, 0xff, mtd->oobsize); +	nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops); + +	if (ops->mode == MTD_OPS_RAW) +		status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask); +	else +		status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);  	if (status)  		return status; @@ -2416,9 +2439,9 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,  /**   * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band - * @mtd:	MTD device structure - * @to:		offset to write to - * @ops:	oob operation description structure + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operation description structure   */  static int nand_write_oob(struct mtd_info *mtd, loff_t to,  			  struct mtd_oob_ops *ops) @@ -2430,17 +2453,17 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,  	/* Do not allow writes past end of device */  	if (ops->datbuf && (to + ops->len) > mtd->size) { -		DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt write beyond " -				"end of device\n", __func__); +		pr_debug("%s: attempt to write beyond end of device\n", +				__func__);  		return -EINVAL;  	}  	nand_get_device(chip, mtd, FL_WRITING);  	switch (ops->mode) { -	case MTD_OOB_PLACE: -	case MTD_OOB_AUTO: -	case MTD_OOB_RAW: +	case MTD_OPS_PLACE_OOB: +	case MTD_OPS_AUTO_OOB: +	case MTD_OPS_RAW:  		break;  	default: @@ -2458,11 +2481,11 @@ out:  }  /** - * single_erease_cmd - [GENERIC] NAND standard block erase command function - * @mtd:	MTD device structure - * @page:	the page address of the block which will be erased + * single_erase_cmd - [GENERIC] NAND standard block erase command function + * @mtd: MTD device structure + * @page: the page address of the block which will be erased   * - * Standard erase command for NAND chips + * Standard erase command for NAND chips.   */  static void single_erase_cmd(struct mtd_info *mtd, int page)  { @@ -2473,12 +2496,11 @@ static void single_erase_cmd(struct mtd_info *mtd, int page)  }  /** - * multi_erease_cmd - [GENERIC] AND specific block erase command function - * @mtd:	MTD device structure - * @page:	the page address of the block which will be erased + * multi_erase_cmd - [GENERIC] AND specific block erase command function + * @mtd: MTD device structure + * @page: the page address of the block which will be erased   * - * AND multi block erase command function - * Erase 4 consecutive blocks + * AND multi block erase command function. Erase 4 consecutive blocks.   */  static void multi_erase_cmd(struct mtd_info *mtd, int page)  { @@ -2493,10 +2515,10 @@ static void multi_erase_cmd(struct mtd_info *mtd, int page)  /**   * nand_erase - [MTD Interface] erase block(s) - * @mtd:	MTD device structure - * @instr:	erase instruction + * @mtd: MTD device structure + * @instr: erase instruction   * - * Erase one ore more blocks + * Erase one ore more blocks.   */  static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)  { @@ -2505,12 +2527,12 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)  #define BBT_PAGE_MASK	0xffffff3f  /** - * nand_erase_nand - [Internal] erase block(s) - * @mtd:	MTD device structure - * @instr:	erase instruction - * @allowbbt:	allow erasing the bbt area + * nand_erase_nand - [INTERN] erase block(s) + * @mtd: MTD device structure + * @instr: erase instruction + * @allowbbt: allow erasing the bbt area   * - * Erase one ore more blocks + * Erase one ore more blocks.   */  int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  		    int allowbbt) @@ -2521,9 +2543,9 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  	unsigned int bbt_masked_page = 0xffffffff;  	loff_t len; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n", -				__func__, (unsigned long long)instr->addr, -				(unsigned long long)instr->len); +	pr_debug("%s: start = 0x%012llx, len = %llu\n", +			__func__, (unsigned long long)instr->addr, +			(unsigned long long)instr->len);  	if (check_offs_len(mtd, instr->addr, instr->len))  		return -EINVAL; @@ -2545,8 +2567,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  	/* Check, if it is write protected */  	if (nand_check_wp(mtd)) { -		DEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n", -					__func__); +		pr_debug("%s: device is write protected!\n", +				__func__);  		instr->state = MTD_ERASE_FAILED;  		goto erase_exit;  	} @@ -2555,7 +2577,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  	 * If BBT requires refresh, set the BBT page mask to see if the BBT  	 * should be rewritten. Otherwise the mask is set to 0xffffffff which  	 * can not be matched. This is also done when the bbt is actually -	 * erased to avoid recusrsive updates +	 * erased to avoid recursive updates.  	 */  	if (chip->options & BBT_AUTO_REFRESH && !allowbbt)  		bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK; @@ -2566,20 +2588,18 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  	instr->state = MTD_ERASING;  	while (len) { -		/* -		 * heck if we have a bad block, we do not erase bad blocks ! -		 */ +		/* Heck if we have a bad block, we do not erase bad blocks! */  		if (nand_block_checkbad(mtd, ((loff_t) page) <<  					chip->page_shift, 0, allowbbt)) { -			printk(KERN_WARNING "%s: attempt to erase a bad block " -					"at page 0x%08x\n", __func__, page); +			pr_warn("%s: attempt to erase a bad block at page 0x%08x\n", +				    __func__, page);  			instr->state = MTD_ERASE_FAILED;  			goto erase_exit;  		}  		/*  		 * Invalidate the page cache, if we erase the block which -		 * contains the current cached page +		 * contains the current cached page.  		 */  		if (page <= chip->pagebuf && chip->pagebuf <  		    (page + pages_per_block)) @@ -2599,8 +2619,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  		/* See if block erase succeeded */  		if (status & NAND_STATUS_FAIL) { -			DEBUG(MTD_DEBUG_LEVEL0, "%s: Failed erase, " -					"page 0x%08x\n", __func__, page); +			pr_debug("%s: failed erase, page 0x%08x\n", +					__func__, page);  			instr->state = MTD_ERASE_FAILED;  			instr->fail_addr =  				((loff_t)page << chip->page_shift); @@ -2609,7 +2629,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  		/*  		 * If BBT requires refresh, set the BBT rewrite flag to the -		 * page being erased +		 * page being erased.  		 */  		if (bbt_masked_page != 0xffffffff &&  		    (page & BBT_PAGE_MASK) == bbt_masked_page) @@ -2628,7 +2648,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  			/*  			 * If BBT requires refresh and BBT-PERCHIP, set the BBT -			 * page mask to see if this BBT should be rewritten +			 * page mask to see if this BBT should be rewritten.  			 */  			if (bbt_masked_page != 0xffffffff &&  			    (chip->bbt_td->options & NAND_BBT_PERCHIP)) @@ -2651,7 +2671,7 @@ erase_exit:  	/*  	 * If BBT requires refresh and erase was successful, rewrite any -	 * selected bad block tables +	 * selected bad block tables.  	 */  	if (bbt_masked_page == 0xffffffff || ret)  		return ret; @@ -2659,10 +2679,10 @@ erase_exit:  	for (chipnr = 0; chipnr < chip->numchips; chipnr++) {  		if (!rewrite_bbt[chipnr])  			continue; -		/* update the BBT for chip */ -		DEBUG(MTD_DEBUG_LEVEL0, "%s: nand_update_bbt " -			"(%d:0x%0llx 0x%0x)\n", __func__, chipnr, -			rewrite_bbt[chipnr], chip->bbt_td->pages[chipnr]); +		/* Update the BBT for chip */ +		pr_debug("%s: nand_update_bbt (%d:0x%0llx 0x%0x)\n", +				__func__, chipnr, rewrite_bbt[chipnr], +				chip->bbt_td->pages[chipnr]);  		nand_update_bbt(mtd, rewrite_bbt[chipnr]);  	} @@ -2672,15 +2692,15 @@ erase_exit:  /**   * nand_sync - [MTD Interface] sync - * @mtd:	MTD device structure + * @mtd: MTD device structure   * - * Sync is actually a wait for chip ready function + * Sync is actually a wait for chip ready function.   */  static void nand_sync(struct mtd_info *mtd)  {  	struct nand_chip *chip = mtd->priv; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: called\n", __func__); +	pr_debug("%s: called\n", __func__);  	/* Grab the lock and see if the device is available */  	nand_get_device(chip, mtd, FL_SYNCING); @@ -2690,8 +2710,8 @@ static void nand_sync(struct mtd_info *mtd)  /**   * nand_block_isbad - [MTD Interface] Check if block at offset is bad - * @mtd:	MTD device structure - * @offs:	offset relative to mtd start + * @mtd: MTD device structure + * @offs: offset relative to mtd start   */  static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)  { @@ -2704,8 +2724,8 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)  /**   * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad - * @mtd:	MTD device structure - * @ofs:	offset relative to mtd start + * @mtd: MTD device structure + * @ofs: offset relative to mtd start   */  static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)  { @@ -2714,7 +2734,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)  	ret = nand_block_isbad(mtd, ofs);  	if (ret) { -		/* If it was bad already, return success and do nothing. */ +		/* If it was bad already, return success and do nothing */  		if (ret > 0)  			return 0;  		return ret; @@ -2725,7 +2745,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)  /**   * nand_suspend - [MTD Interface] Suspend the NAND flash - * @mtd:	MTD device structure + * @mtd: MTD device structure   */  static int nand_suspend(struct mtd_info *mtd)  { @@ -2736,7 +2756,7 @@ static int nand_suspend(struct mtd_info *mtd)  /**   * nand_resume - [MTD Interface] Resume the NAND flash - * @mtd:	MTD device structure + * @mtd: MTD device structure   */  static void nand_resume(struct mtd_info *mtd)  { @@ -2745,13 +2765,11 @@ static void nand_resume(struct mtd_info *mtd)  	if (chip->state == FL_PM_SUSPENDED)  		nand_release_device(mtd);  	else -		printk(KERN_ERR "%s called for a chip which is not " -		       "in suspended state\n", __func__); +		pr_err("%s called for a chip which is not in suspended state\n", +			__func__);  } -/* - * Set default functions - */ +/* Set default functions */  static void nand_set_defaults(struct nand_chip *chip, int busw)  {  	/* check for proper chip_delay setup, set 20us if not */ @@ -2793,23 +2811,21 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)  } -/* - * sanitize ONFI strings so we can safely print them - */ +/* Sanitize ONFI strings so we can safely print them */  static void sanitize_string(uint8_t *s, size_t len)  {  	ssize_t i; -	/* null terminate */ +	/* Null terminate */  	s[len - 1] = 0; -	/* remove non printable chars */ +	/* Remove non printable chars */  	for (i = 0; i < len - 1; i++) {  		if (s[i] < ' ' || s[i] > 127)  			s[i] = '?';  	} -	/* remove trailing spaces */ +	/* Remove trailing spaces */  	strim(s);  } @@ -2826,28 +2842,28 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)  }  /* - * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise + * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.   */  static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, -					int busw) +					int *busw)  {  	struct nand_onfi_params *p = &chip->onfi_params;  	int i;  	int val; -	/* try ONFI for unknow chip or LP */ +	/* 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' ||  		chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')  		return 0; -	printk(KERN_INFO "ONFI flash detected\n"); +	pr_info("ONFI flash detected\n");  	chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);  	for (i = 0; i < 3; i++) {  		chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));  		if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==  				le16_to_cpu(p->crc)) { -			printk(KERN_INFO "ONFI param page %d valid\n", i); +			pr_info("ONFI param page %d valid\n", i);  			break;  		}  	} @@ -2855,7 +2871,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,  	if (i == 3)  		return 0; -	/* check version */ +	/* Check version */  	val = le16_to_cpu(p->revision);  	if (val & (1 << 5))  		chip->onfi_version = 23; @@ -2871,8 +2887,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,  		chip->onfi_version = 0;  	if (!chip->onfi_version) { -		printk(KERN_INFO "%s: unsupported ONFI version: %d\n", -								__func__, val); +		pr_info("%s: unsupported ONFI version: %d\n", __func__, val);  		return 0;  	} @@ -2884,9 +2899,9 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,  	mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize;  	mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);  	chip->chipsize = (uint64_t)le32_to_cpu(p->blocks_per_lun) * mtd->erasesize; -	busw = 0; +	*busw = 0;  	if (le16_to_cpu(p->features) & 1) -		busw = NAND_BUSWIDTH_16; +		*busw = NAND_BUSWIDTH_16;  	chip->options &= ~NAND_CHIPOPTIONS_MSK;  	chip->options |= (NAND_NO_READRDY | @@ -2896,7 +2911,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,  }  /* - * Get the flash and manufacturer id and lookup if the type is supported + * Get the flash and manufacturer id and lookup if the type is supported.   */  static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  						  struct nand_chip *chip, @@ -2913,7 +2928,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  	/*  	 * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) -	 * after power-up +	 * after power-up.  	 */  	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); @@ -2924,7 +2939,8 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  	*maf_id = chip->read_byte(mtd);  	*dev_id = chip->read_byte(mtd); -	/* Try again to make sure, as some systems the bus-hold or other +	/* +	 * Try again to make sure, as some systems the bus-hold or other  	 * interface concerns can cause random data which looks like a  	 * possibly credible NAND flash to appear. If the two results do  	 * not match, ignore the device completely. @@ -2936,9 +2952,9 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  		id_data[i] = chip->read_byte(mtd);  	if (id_data[0] != *maf_id || id_data[1] != *dev_id) { -		printk(KERN_INFO "%s: second ID read did not match " -		       "%02x,%02x against %02x,%02x\n", __func__, -		       *maf_id, *dev_id, id_data[0], id_data[1]); +		pr_info("%s: second ID read did not match " +			"%02x,%02x against %02x,%02x\n", __func__, +			*maf_id, *dev_id, id_data[0], id_data[1]);  		return ERR_PTR(-ENODEV);  	} @@ -2952,7 +2968,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  	chip->onfi_version = 0;  	if (!type->name || !type->pagesize) {  		/* Check is chip is ONFI compliant */ -		ret = nand_flash_detect_onfi(mtd, chip, busw); +		ret = nand_flash_detect_onfi(mtd, chip, &busw);  		if (ret)  			goto ident_done;  	} @@ -2973,7 +2989,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  	chip->chipsize = (uint64_t)type->chipsize << 20;  	if (!type->pagesize && chip->init_size) { -		/* set the pagesize, oobsize, erasesize by the driver*/ +		/* Set the pagesize, oobsize, erasesize by the driver */  		busw = chip->init_size(mtd, chip, id_data);  	} else if (!type->pagesize) {  		int extid; @@ -3033,7 +3049,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  		}  	} else {  		/* -		 * Old devices have chip data hardcoded in the device id table +		 * Old devices have chip data hardcoded in the device id table.  		 */  		mtd->erasesize = type->erasesize;  		mtd->writesize = type->pagesize; @@ -3043,7 +3059,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  		/*  		 * Check for Spansion/AMD ID + repeating 5th, 6th byte since  		 * some Spansion chips have erasesize that conflicts with size -		 * listed in nand_ids table +		 * listed in nand_ids table.  		 * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)  		 */  		if (*maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && @@ -3057,15 +3073,16 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  	chip->options &= ~NAND_CHIPOPTIONS_MSK;  	chip->options |= type->options & NAND_CHIPOPTIONS_MSK; -	/* Check if chip is a not a samsung device. Do not clear the -	 * options for chips which are not having an extended id. +	/* +	 * Check if chip is not a Samsung device. Do not clear the +	 * options for chips which do not have an extended id.  	 */  	if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)  		chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;  ident_done:  	/* -	 * Set chip as a default. Board drivers can override it, if necessary +	 * Set chip as a default. Board drivers can override it, if necessary.  	 */  	chip->options |= NAND_NO_AUTOINCR; @@ -3077,21 +3094,21 @@ ident_done:  	/*  	 * Check, if buswidth is correct. Hardware drivers should set -	 * chip correct ! +	 * chip correct!  	 */  	if (busw != (chip->options & NAND_BUSWIDTH_16)) { -		printk(KERN_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); -		printk(KERN_WARNING "NAND bus width %d instead %d bit\n", -		       (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, -		       busw ? 16 : 8); +		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); +		pr_warn("NAND bus width %d instead %d bit\n", +			   (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, +			   busw ? 16 : 8);  		return ERR_PTR(-EINVAL);  	}  	/* Calculate the address shift from the page size */  	chip->page_shift = ffs(mtd->writesize) - 1; -	/* Convert chipsize to number of pages per chip -1. */ +	/* Convert chipsize to number of pages per chip -1 */  	chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;  	chip->bbt_erase_shift = chip->phys_erase_shift = @@ -3121,7 +3138,7 @@ ident_done:  	if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&  			(*maf_id == NAND_MFR_SAMSUNG ||  			 *maf_id == NAND_MFR_HYNIX)) -		chip->options |= NAND_BBT_SCANLASTPAGE; +		chip->bbt_options |= NAND_BBT_SCANLASTPAGE;  	else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&  				(*maf_id == NAND_MFR_SAMSUNG ||  				 *maf_id == NAND_MFR_HYNIX || @@ -3129,17 +3146,7 @@ ident_done:  				 *maf_id == NAND_MFR_AMD)) ||  			(mtd->writesize == 2048 &&  			 *maf_id == NAND_MFR_MICRON)) -		chip->options |= NAND_BBT_SCAN2NDPAGE; - -	/* -	 * Numonyx/ST 2K pages, x8 bus use BOTH byte 1 and 6 -	 */ -	if (!(busw & NAND_BUSWIDTH_16) && -			*maf_id == NAND_MFR_STMICRO && -			mtd->writesize == 2048) { -		chip->options |= NAND_BBT_SCANBYTE1AND6; -		chip->badblockpos = 0; -	} +		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;  	/* Check for AND chips with 4 page planes */  	if (chip->options & NAND_4PAGE_ARRAY) @@ -3147,12 +3154,11 @@ ident_done:  	else  		chip->erase_cmd = single_erase_cmd; -	/* Do not replace user supplied command function ! */ +	/* Do not replace user supplied command function! */  	if (mtd->writesize > 512 && chip->cmdfunc == nand_command)  		chip->cmdfunc = nand_command_lp; -	/* TODO onfi flash name */ -	printk(KERN_INFO "NAND device: Manufacturer ID:" +	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,  		chip->onfi_version ? chip->onfi_params.model : type->name); @@ -3162,12 +3168,12 @@ ident_done:  /**   * nand_scan_ident - [NAND Interface] Scan for the NAND device - * @mtd:	     MTD device structure - * @maxchips:	     Number of chips to scan for - * @table:	     Alternative NAND ID table + * @mtd: MTD device structure + * @maxchips: number of chips to scan for + * @table: alternative NAND ID table   * - * This is the first phase of the normal nand_scan() function. It - * reads the flash ID and sets up MTD fields accordingly. + * This is the first phase of the normal nand_scan() function. It reads the + * flash ID and sets up MTD fields accordingly.   *   * The mtd->owner field must be set to the module of the caller.   */ @@ -3189,7 +3195,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,  	if (IS_ERR(type)) {  		if (!(chip->options & NAND_SCAN_SILENT_NODEV)) -			printk(KERN_WARNING "No NAND device found.\n"); +			pr_warn("No NAND device found\n");  		chip->select_chip(mtd, -1);  		return PTR_ERR(type);  	} @@ -3207,7 +3213,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,  			break;  	}  	if (i > 1) -		printk(KERN_INFO "%d NAND chips detected\n", i); +		pr_info("%d NAND chips detected\n", i);  	/* Store the number of chips and calc total size for mtd */  	chip->numchips = i; @@ -3220,11 +3226,11 @@ EXPORT_SYMBOL(nand_scan_ident);  /**   * nand_scan_tail - [NAND Interface] Scan for the NAND device - * @mtd:	    MTD device structure + * @mtd: MTD device structure   * - * This is the second phase of the normal nand_scan() function. It - * fills out all the uninitialized function pointers with the defaults - * and scans for a bad block table if appropriate. + * This is the second phase of the normal nand_scan() function. It fills out + * all the uninitialized function pointers with the defaults and scans for a + * bad block table if appropriate.   */  int nand_scan_tail(struct mtd_info *mtd)  { @@ -3240,7 +3246,7 @@ int nand_scan_tail(struct mtd_info *mtd)  	chip->oob_poi = chip->buffers->databuf + mtd->writesize;  	/* -	 * If no default placement scheme is given, select an appropriate one +	 * If no default placement scheme is given, select an appropriate one.  	 */  	if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) {  		switch (mtd->oobsize) { @@ -3257,8 +3263,8 @@ int nand_scan_tail(struct mtd_info *mtd)  			chip->ecc.layout = &nand_oob_128;  			break;  		default: -			printk(KERN_WARNING "No oob scheme defined for " -			       "oobsize %d\n", mtd->oobsize); +			pr_warn("No oob scheme defined for oobsize %d\n", +				   mtd->oobsize);  			BUG();  		}  	} @@ -3267,7 +3273,7 @@ int nand_scan_tail(struct mtd_info *mtd)  		chip->write_page = nand_write_page;  	/* -	 * check ECC mode, default to software if 3byte/512byte hardware ECC is +	 * Check ECC mode, default to software if 3byte/512byte hardware ECC is  	 * selected and we have 256 byte pagesize fallback to software ECC  	 */ @@ -3276,15 +3282,15 @@ int nand_scan_tail(struct mtd_info *mtd)  		/* Similar to NAND_ECC_HW, but a separate read_page handle */  		if (!chip->ecc.calculate || !chip->ecc.correct ||  		     !chip->ecc.hwctl) { -			printk(KERN_WARNING "No ECC functions supplied; " -			       "Hardware ECC not possible\n"); +			pr_warn("No ECC functions supplied; " +				   "hardware ECC not possible\n");  			BUG();  		}  		if (!chip->ecc.read_page)  			chip->ecc.read_page = nand_read_page_hwecc_oob_first;  	case NAND_ECC_HW: -		/* Use standard hwecc read page function ? */ +		/* Use standard hwecc read page function? */  		if (!chip->ecc.read_page)  			chip->ecc.read_page = nand_read_page_hwecc;  		if (!chip->ecc.write_page) @@ -3305,11 +3311,11 @@ int nand_scan_tail(struct mtd_info *mtd)  		     chip->ecc.read_page == nand_read_page_hwecc ||  		     !chip->ecc.write_page ||  		     chip->ecc.write_page == nand_write_page_hwecc)) { -			printk(KERN_WARNING "No ECC functions supplied; " -			       "Hardware ECC not possible\n"); +			pr_warn("No ECC functions supplied; " +				   "hardware ECC not possible\n");  			BUG();  		} -		/* Use standard syndrome read/write page function ? */ +		/* Use standard syndrome read/write page function? */  		if (!chip->ecc.read_page)  			chip->ecc.read_page = nand_read_page_syndrome;  		if (!chip->ecc.write_page) @@ -3325,9 +3331,9 @@ int nand_scan_tail(struct mtd_info *mtd)  		if (mtd->writesize >= chip->ecc.size)  			break; -		printk(KERN_WARNING "%d byte HW ECC not possible on " -		       "%d byte page size, fallback to SW ECC\n", -		       chip->ecc.size, mtd->writesize); +		pr_warn("%d byte HW ECC not possible on " +			   "%d byte page size, fallback to SW ECC\n", +			   chip->ecc.size, mtd->writesize);  		chip->ecc.mode = NAND_ECC_SOFT;  	case NAND_ECC_SOFT: @@ -3347,7 +3353,7 @@ int nand_scan_tail(struct mtd_info *mtd)  	case NAND_ECC_SOFT_BCH:  		if (!mtd_nand_has_bch()) { -			printk(KERN_WARNING "CONFIG_MTD_ECC_BCH not enabled\n"); +			pr_warn("CONFIG_MTD_ECC_BCH not enabled\n");  			BUG();  		}  		chip->ecc.calculate = nand_bch_calculate_ecc; @@ -3362,8 +3368,8 @@ int nand_scan_tail(struct mtd_info *mtd)  		/*  		 * Board driver should supply ecc.size and ecc.bytes values to  		 * select how many bits are correctable; see nand_bch_init() -		 * for details. -		 * Otherwise, default to 4 bits for large page devices +		 * for details. Otherwise, default to 4 bits for large page +		 * devices.  		 */  		if (!chip->ecc.size && (mtd->oobsize >= 64)) {  			chip->ecc.size = 512; @@ -3374,14 +3380,14 @@ int nand_scan_tail(struct mtd_info *mtd)  					       chip->ecc.bytes,  					       &chip->ecc.layout);  		if (!chip->ecc.priv) { -			printk(KERN_WARNING "BCH ECC initialization failed!\n"); +			pr_warn("BCH ECC initialization failed!\n");  			BUG();  		}  		break;  	case NAND_ECC_NONE: -		printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " -		       "This is not recommended !!\n"); +		pr_warn("NAND_ECC_NONE selected by board driver. " +			   "This is not recommended!\n");  		chip->ecc.read_page = nand_read_page_raw;  		chip->ecc.write_page = nand_write_page_raw;  		chip->ecc.read_oob = nand_read_oob_std; @@ -3393,14 +3399,19 @@ int nand_scan_tail(struct mtd_info *mtd)  		break;  	default: -		printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", -		       chip->ecc.mode); +		pr_warn("Invalid NAND_ECC_MODE %d\n", chip->ecc.mode);  		BUG();  	} +	/* For many systems, the standard OOB write also works for raw */ +	if (!chip->ecc.read_oob_raw) +		chip->ecc.read_oob_raw = chip->ecc.read_oob; +	if (!chip->ecc.write_oob_raw) +		chip->ecc.write_oob_raw = chip->ecc.write_oob; +  	/*  	 * The number of bytes available for a client to place data into -	 * the out of band area +	 * the out of band area.  	 */  	chip->ecc.layout->oobavail = 0;  	for (i = 0; chip->ecc.layout->oobfree[i].length @@ -3411,19 +3422,16 @@ int nand_scan_tail(struct mtd_info *mtd)  	/*  	 * Set the number of read / write steps for one page depending on ECC -	 * mode +	 * mode.  	 */  	chip->ecc.steps = mtd->writesize / chip->ecc.size;  	if (chip->ecc.steps * chip->ecc.size != mtd->writesize) { -		printk(KERN_WARNING "Invalid ecc parameters\n"); +		pr_warn("Invalid ECC parameters\n");  		BUG();  	}  	chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; -	/* -	 * Allow subpage writes up to ecc.steps. Not possible for MLC -	 * FLASH. -	 */ +	/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */  	if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&  	    !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {  		switch (chip->ecc.steps) { @@ -3481,9 +3489,11 @@ int nand_scan_tail(struct mtd_info *mtd)  }  EXPORT_SYMBOL(nand_scan_tail); -/* is_module_text_address() isn't exported, and it's mostly a pointless +/* + * is_module_text_address() isn't exported, and it's mostly a pointless   * test if this is a module _anyway_ -- they'd have to try _really_ hard - * to call us from in-kernel code if the core NAND support is modular. */ + * to call us from in-kernel code if the core NAND support is modular. + */  #ifdef MODULE  #define caller_is_module() (1)  #else @@ -3493,15 +3503,13 @@ EXPORT_SYMBOL(nand_scan_tail);  /**   * nand_scan - [NAND Interface] Scan for the NAND device - * @mtd:	MTD device structure - * @maxchips:	Number of chips to scan for - * - * This fills out all the uninitialized function pointers - * with the defaults. - * The flash ID is read and the mtd/chip structures are - * filled with the appropriate values. - * The mtd->owner field must be set to the module of the caller + * @mtd: MTD device structure + * @maxchips: number of chips to scan for   * + * This fills out all the uninitialized function pointers with the defaults. + * The flash ID is read and the mtd/chip structures are filled with the + * appropriate values. The mtd->owner field must be set to the module of the + * caller.   */  int nand_scan(struct mtd_info *mtd, int maxchips)  { @@ -3509,8 +3517,7 @@ int nand_scan(struct mtd_info *mtd, int maxchips)  	/* Many callers got this wrong, so check for it for a while... */  	if (!mtd->owner && caller_is_module()) { -		printk(KERN_CRIT "%s called with NULL mtd->owner!\n", -				__func__); +		pr_crit("%s called with NULL mtd->owner!\n", __func__);  		BUG();  	} @@ -3523,8 +3530,8 @@ EXPORT_SYMBOL(nand_scan);  /**   * nand_release - [NAND Interface] Free resources held by the NAND device - * @mtd:	MTD device structure -*/ + * @mtd: MTD device structure + */  void nand_release(struct mtd_info *mtd)  {  	struct nand_chip *chip = mtd->priv; diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 4165857752ca..69148ae3bf58 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -14,7 +14,7 @@   *   * When nand_scan_bbt is called, then it tries to find the bad block table   * depending on the options in the BBT descriptor(s). If no flash based BBT - * (NAND_USE_FLASH_BBT) is specified then the device is scanned for factory + * (NAND_BBT_USE_FLASH) is specified then the device is scanned for factory   * marked good / bad blocks. This information is used to create a memory BBT.   * Once a new bad block is discovered then the "factory" information is updated   * on the device. @@ -36,9 +36,9 @@   * The table is marked in the OOB area with an ident pattern and a version   * number which indicates which of both tables is more up to date. If the NAND   * controller needs the complete OOB area for the ECC information then the - * option NAND_USE_FLASH_BBT_NO_OOB should be used: it moves the ident pattern - * and the version byte into the data area and the OOB area will remain - * untouched. + * option NAND_BBT_NO_OOB should be used (along with NAND_BBT_USE_FLASH, of + * course): it moves the ident pattern and the version byte into the data area + * and the OOB area will remain untouched.   *   * The table uses 2 bits per block   * 11b:		block is good @@ -81,17 +81,15 @@ static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)  /**   * check_pattern - [GENERIC] check if a pattern is in the buffer - * @buf:	the buffer to search - * @len:	the length of buffer to search - * @paglen:	the pagelength - * @td:		search pattern descriptor + * @buf: the buffer to search + * @len: the length of buffer to search + * @paglen: the pagelength + * @td: search pattern descriptor   * - * Check for a pattern at the given place. Used to search bad block - * tables and good / bad block identifiers. - * If the SCAN_EMPTY option is set then check, if all bytes except the - * pattern area contain 0xff - * -*/ + * Check for a pattern at the given place. Used to search bad block tables and + * good / bad block identifiers. If the SCAN_EMPTY option is set then check, if + * all bytes except the pattern area contain 0xff. + */  static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)  {  	int i, end = 0; @@ -110,32 +108,8 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc  	p += end;  	/* Compare the pattern */ -	for (i = 0; i < td->len; i++) { -		if (p[i] != td->pattern[i]) -			return -1; -	} - -	/* Check both positions 1 and 6 for pattern? */ -	if (td->options & NAND_BBT_SCANBYTE1AND6) { -		if (td->options & NAND_BBT_SCANEMPTY) { -			p += td->len; -			end += NAND_SMALL_BADBLOCK_POS - td->offs; -			/* Check region between positions 1 and 6 */ -			for (i = 0; i < NAND_SMALL_BADBLOCK_POS - td->offs - td->len; -					i++) { -				if (*p++ != 0xff) -					return -1; -			} -		} -		else { -			p += NAND_SMALL_BADBLOCK_POS - td->offs; -		} -		/* Compare the pattern */ -		for (i = 0; i < td->len; i++) { -			if (p[i] != td->pattern[i]) -				return -1; -		} -	} +	if (memcmp(p, td->pattern, td->len)) +		return -1;  	if (td->options & NAND_BBT_SCANEMPTY) {  		p += td->len; @@ -150,14 +124,13 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc  /**   * check_short_pattern - [GENERIC] check if a pattern is in the buffer - * @buf:	the buffer to search - * @td:		search pattern descriptor - * - * Check for a pattern at the given place. Used to search bad block - * tables and good / bad block identifiers. Same as check_pattern, but - * no optional empty check + * @buf: the buffer to search + * @td:	search pattern descriptor   * -*/ + * Check for a pattern at the given place. Used to search bad block tables and + * good / bad block identifiers. Same as check_pattern, but no optional empty + * check. + */  static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)  {  	int i; @@ -168,21 +141,14 @@ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)  		if (p[td->offs + i] != td->pattern[i])  			return -1;  	} -	/* Need to check location 1 AND 6? */ -	if (td->options & NAND_BBT_SCANBYTE1AND6) { -		for (i = 0; i < td->len; i++) { -			if (p[NAND_SMALL_BADBLOCK_POS + i] != td->pattern[i]) -				return -1; -		} -	}  	return 0;  }  /**   * add_marker_len - compute the length of the marker in data area - * @td:		BBT descriptor used for computation + * @td: BBT descriptor used for computation   * - * The length will be 0 if the markeris located in OOB area. + * The length will be 0 if the marker is located in OOB area.   */  static u32 add_marker_len(struct nand_bbt_descr *td)  { @@ -199,34 +165,33 @@ static u32 add_marker_len(struct nand_bbt_descr *td)  /**   * read_bbt - [GENERIC] Read the bad block table starting from page - * @mtd:	MTD device structure - * @buf:	temporary buffer - * @page:	the starting page - * @num:	the number of bbt descriptors to read - * @td:		the bbt describtion table - * @offs:	offset in the memory table + * @mtd: MTD device structure + * @buf: temporary buffer + * @page: the starting page + * @num: the number of bbt descriptors to read + * @td: the bbt describtion table + * @offs: offset in the memory table   *   * Read the bad block table starting from page. - *   */  static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,  		struct nand_bbt_descr *td, int offs)  { -	int res, i, j, act = 0; +	int res, ret = 0, i, j, act = 0;  	struct nand_chip *this = mtd->priv;  	size_t retlen, len, totlen;  	loff_t from;  	int bits = td->options & NAND_BBT_NRBITS_MSK; -	uint8_t msk = (uint8_t) ((1 << bits) - 1); +	uint8_t msk = (uint8_t)((1 << bits) - 1);  	u32 marker_len;  	int reserved_block_code = td->reserved_block_code;  	totlen = (num * bits) >> 3;  	marker_len = add_marker_len(td); -	from = ((loff_t) page) << this->page_shift; +	from = ((loff_t)page) << this->page_shift;  	while (totlen) { -		len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); +		len = min(totlen, (size_t)(1 << this->bbt_erase_shift));  		if (marker_len) {  			/*  			 * In case the BBT marker is not in the OOB area it @@ -238,11 +203,18 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,  		}  		res = mtd->read(mtd, from, len, &retlen, buf);  		if (res < 0) { -			if (retlen != len) { -				printk(KERN_INFO "nand_bbt: Error reading bad block table\n"); +			if (mtd_is_eccerr(res)) { +				pr_info("nand_bbt: ECC error in BBT at " +					"0x%012llx\n", from & ~mtd->writesize); +				return res; +			} else if (mtd_is_bitflip(res)) { +				pr_info("nand_bbt: corrected error in BBT at " +					"0x%012llx\n", from & ~mtd->writesize); +				ret = res; +			} else { +				pr_info("nand_bbt: error reading BBT\n");  				return res;  			} -			printk(KERN_WARNING "nand_bbt: ECC error while reading bad block table\n");  		}  		/* Analyse data */ @@ -253,17 +225,19 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,  				if (tmp == msk)  					continue;  				if (reserved_block_code && (tmp == reserved_block_code)) { -					printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%012llx\n", -					       (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); +					pr_info("nand_read_bbt: reserved block at 0x%012llx\n", +						 (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);  					this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);  					mtd->ecc_stats.bbtblocks++;  					continue;  				} -				/* Leave it for now, if its matured we can move this -				 * message to MTD_DEBUG_LEVEL0 */ -				printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%012llx\n", -				       (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); -				/* Factory marked bad or worn out ? */ +				/* +				 * Leave it for now, if it's matured we can +				 * move this message to pr_debug. +				 */ +				pr_info("nand_read_bbt: bad block at 0x%012llx\n", +					 (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); +				/* Factory marked bad or worn out? */  				if (tmp == 0)  					this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);  				else @@ -274,20 +248,20 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,  		totlen -= len;  		from += len;  	} -	return 0; +	return ret;  }  /**   * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page - * @mtd:	MTD device structure - * @buf:	temporary buffer - * @td:		descriptor for the bad block table - * @chip:	read the table for a specific chip, -1 read all chips. - *		Applies only if NAND_BBT_PERCHIP option is set + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @chip: read the table for a specific chip, -1 read all chips; applies only if + *        NAND_BBT_PERCHIP option is set   * - * Read the bad block table for all chips starting at a given page - * We assume that the bbt bits are in consecutive order. -*/ + * Read the bad block table for all chips starting at a given page. We assume + * that the bbt bits are in consecutive order. + */  static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)  {  	struct nand_chip *this = mtd->priv; @@ -313,9 +287,7 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc  	return 0;  } -/* - * BBT marker is in the first page, no OOB. - */ +/* BBT marker is in the first page, no OOB */  static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,  			 struct nand_bbt_descr *td)  { @@ -329,35 +301,26 @@ static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,  	return mtd->read(mtd, offs, len, &retlen, buf);  } -/* - * Scan read raw data from flash - */ +/* Scan read raw data from flash */  static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,  			 size_t len)  {  	struct mtd_oob_ops ops;  	int res; -	ops.mode = MTD_OOB_RAW; +	ops.mode = MTD_OPS_RAW;  	ops.ooboffs = 0;  	ops.ooblen = mtd->oobsize; -  	while (len > 0) { -		if (len <= mtd->writesize) { -			ops.oobbuf = buf + len; -			ops.datbuf = buf; -			ops.len = len; -			return mtd->read_oob(mtd, offs, &ops); -		} else { -			ops.oobbuf = buf + mtd->writesize; -			ops.datbuf = buf; -			ops.len = mtd->writesize; -			res = mtd->read_oob(mtd, offs, &ops); +		ops.datbuf = buf; +		ops.len = min(len, (size_t)mtd->writesize); +		ops.oobbuf = buf + ops.len; -			if (res) -				return res; -		} +		res = mtd->read_oob(mtd, offs, &ops); + +		if (res) +			return res;  		buf += mtd->oobsize + mtd->writesize;  		len -= mtd->writesize; @@ -374,15 +337,13 @@ static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs,  		return scan_read_raw_oob(mtd, buf, offs, len);  } -/* - * Scan write data with oob to flash - */ +/* Scan write data with oob to flash */  static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,  			  uint8_t *buf, uint8_t *oob)  {  	struct mtd_oob_ops ops; -	ops.mode = MTD_OOB_PLACE; +	ops.mode = MTD_OPS_PLACE_OOB;  	ops.ooboffs = 0;  	ops.ooblen = mtd->oobsize;  	ops.datbuf = buf; @@ -403,15 +364,14 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)  /**   * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page - * @mtd:	MTD device structure - * @buf:	temporary buffer - * @td:		descriptor for the bad block table - * @md:		descriptor for the bad block table mirror + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md:	descriptor for the bad block table mirror   * - * Read the bad block table(s) for all chips starting at a given page - * We assume that the bbt bits are in consecutive order. - * -*/ + * Read the bad block table(s) for all chips starting at a given page. We + * assume that the bbt bits are in consecutive order. + */  static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,  			 struct nand_bbt_descr *td, struct nand_bbt_descr *md)  { @@ -422,8 +382,8 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,  		scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift,  			      mtd->writesize, td);  		td->version[0] = buf[bbt_get_ver_offs(mtd, td)]; -		printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", -		       td->pages[0], td->version[0]); +		pr_info("Bad block table at page %d, version 0x%02X\n", +			 td->pages[0], td->version[0]);  	}  	/* Read the mirror version, if available */ @@ -431,15 +391,13 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,  		scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift,  			      mtd->writesize, td);  		md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; -		printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", -		       md->pages[0], md->version[0]); +		pr_info("Bad block table at page %d, version 0x%02X\n", +			 md->pages[0], md->version[0]);  	}  	return 1;  } -/* - * Scan a given block full - */ +/* Scan a given block full */  static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,  			   loff_t offs, uint8_t *buf, size_t readlen,  			   int scanlen, int len) @@ -447,7 +405,8 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,  	int ret, j;  	ret = scan_read_raw_oob(mtd, buf, offs, readlen); -	if (ret) +	/* Ignore ECC errors when checking for BBM */ +	if (ret && !mtd_is_bitflip_or_eccerr(ret))  		return ret;  	for (j = 0; j < len; j++, buf += scanlen) { @@ -457,9 +416,7 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,  	return 0;  } -/* - * Scan a given block partially - */ +/* Scan a given block partially */  static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,  			   loff_t offs, uint8_t *buf, int len)  { @@ -470,16 +427,16 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,  	ops.oobbuf = buf;  	ops.ooboffs = 0;  	ops.datbuf = NULL; -	ops.mode = MTD_OOB_PLACE; +	ops.mode = MTD_OPS_PLACE_OOB;  	for (j = 0; j < len; j++) {  		/* -		 * Read the full oob until read_oob is fixed to -		 * handle single byte reads for 16 bit -		 * buswidth +		 * Read the full oob until read_oob is fixed to handle single +		 * byte reads for 16 bit buswidth.  		 */  		ret = mtd->read_oob(mtd, offs, &ops); -		if (ret) +		/* Ignore ECC errors when checking for BBM */ +		if (ret && !mtd_is_bitflip_or_eccerr(ret))  			return ret;  		if (check_short_pattern(buf, bd)) @@ -492,14 +449,14 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,  /**   * create_bbt - [GENERIC] Create a bad block table by scanning the device - * @mtd:	MTD device structure - * @buf:	temporary buffer - * @bd:		descriptor for the good/bad block search pattern - * @chip:	create the table for a specific chip, -1 read all chips. - *		Applies only if NAND_BBT_PERCHIP option is set + * @mtd: MTD device structure + * @buf: temporary buffer + * @bd: descriptor for the good/bad block search pattern + * @chip: create the table for a specific chip, -1 read all chips; applies only + *        if NAND_BBT_PERCHIP option is set   * - * Create a bad block table by scanning the device - * for the given good/bad block identify pattern + * Create a bad block table by scanning the device for the given good/bad block + * identify pattern.   */  static int create_bbt(struct mtd_info *mtd, uint8_t *buf,  	struct nand_bbt_descr *bd, int chip) @@ -510,7 +467,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,  	loff_t from;  	size_t readlen; -	printk(KERN_INFO "Scanning device for bad blocks\n"); +	pr_info("Scanning device for bad blocks\n");  	if (bd->options & NAND_BBT_SCANALLPAGES)  		len = 1 << (this->bbt_erase_shift - this->page_shift); @@ -530,14 +487,16 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,  	}  	if (chip == -1) { -		/* Note that numblocks is 2 * (real numblocks) here, see i+=2 -		 * below as it makes shifting and masking less painful */ +		/* +		 * Note that numblocks is 2 * (real numblocks) here, see i+=2 +		 * below as it makes shifting and masking less painful +		 */  		numblocks = mtd->size >> (this->bbt_erase_shift - 1);  		startblock = 0;  		from = 0;  	} else {  		if (chip >= this->numchips) { -			printk(KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", +			pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n",  			       chip + 1, this->numchips);  			return -EINVAL;  		} @@ -547,7 +506,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,  		from = (loff_t)startblock << (this->bbt_erase_shift - 1);  	} -	if (this->options & NAND_BBT_SCANLASTPAGE) +	if (this->bbt_options & NAND_BBT_SCANLASTPAGE)  		from += mtd->erasesize - (mtd->writesize * len);  	for (i = startblock; i < numblocks;) { @@ -566,8 +525,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,  		if (ret) {  			this->bbt[i >> 3] |= 0x03 << (i & 0x6); -			printk(KERN_WARNING "Bad eraseblock %d at 0x%012llx\n", -			       i >> 1, (unsigned long long)from); +			pr_warn("Bad eraseblock %d at 0x%012llx\n", +				i >> 1, (unsigned long long)from);  			mtd->ecc_stats.badblocks++;  		} @@ -579,20 +538,18 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,  /**   * search_bbt - [GENERIC] scan the device for a specific bad block table - * @mtd:	MTD device structure - * @buf:	temporary buffer - * @td:		descriptor for the bad block table + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table   * - * Read the bad block table by searching for a given ident pattern. - * Search is preformed either from the beginning up or from the end of - * the device downwards. The search starts always at the start of a - * block. - * If the option NAND_BBT_PERCHIP is given, each chip is searched - * for a bbt, which contains the bad block information of this chip. - * This is necessary to provide support for certain DOC devices. + * Read the bad block table by searching for a given ident pattern. Search is + * preformed either from the beginning up or from the end of the device + * downwards. The search starts always at the start of a block. If the option + * NAND_BBT_PERCHIP is given, each chip is searched for a bbt, which contains + * the bad block information of this chip. This is necessary to provide support + * for certain DOC devices.   * - * The bbt ident pattern resides in the oob area of the first page - * in a block. + * The bbt ident pattern resides in the oob area of the first page in a block.   */  static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)  { @@ -603,7 +560,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr  	int bbtblocks;  	int blocktopage = this->bbt_erase_shift - this->page_shift; -	/* Search direction top -> down ? */ +	/* Search direction top -> down? */  	if (td->options & NAND_BBT_LASTBLOCK) {  		startblock = (mtd->size >> this->bbt_erase_shift) - 1;  		dir = -1; @@ -612,7 +569,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr  		dir = 1;  	} -	/* Do we have a bbt per chip ? */ +	/* Do we have a bbt per chip? */  	if (td->options & NAND_BBT_PERCHIP) {  		chips = this->numchips;  		bbtblocks = this->chipsize >> this->bbt_erase_shift; @@ -651,23 +608,23 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr  	/* Check, if we found a bbt for each requested chip */  	for (i = 0; i < chips; i++) {  		if (td->pages[i] == -1) -			printk(KERN_WARNING "Bad block table not found for chip %d\n", i); +			pr_warn("Bad block table not found for chip %d\n", i);  		else -			printk(KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], -			       td->version[i]); +			pr_info("Bad block table found at page %d, version " +				 "0x%02X\n", td->pages[i], td->version[i]);  	}  	return 0;  }  /**   * search_read_bbts - [GENERIC] scan the device for bad block table(s) - * @mtd:	MTD device structure - * @buf:	temporary buffer - * @td:		descriptor for the bad block table - * @md:		descriptor for the bad block table mirror + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror   * - * Search and read the bad block table(s) -*/ + * Search and read the bad block table(s). + */  static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md)  {  	/* Search the primary table */ @@ -683,16 +640,14 @@ static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt  /**   * write_bbt - [GENERIC] (Re)write the bad block table + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror + * @chipsel: selector for a specific chip, -1 for all   * - * @mtd:	MTD device structure - * @buf:	temporary buffer - * @td:		descriptor for the bad block table - * @md:		descriptor for the bad block table mirror - * @chipsel:	selector for a specific chip, -1 for all - * - * (Re)write the bad block table - * -*/ + * (Re)write the bad block table. + */  static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  		     struct nand_bbt_descr *td, struct nand_bbt_descr *md,  		     int chipsel) @@ -711,14 +666,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  	ops.ooblen = mtd->oobsize;  	ops.ooboffs = 0;  	ops.datbuf = NULL; -	ops.mode = MTD_OOB_PLACE; +	ops.mode = MTD_OPS_PLACE_OOB;  	if (!rcode)  		rcode = 0xff; -	/* Write bad block table per chip rather than per device ? */ +	/* Write bad block table per chip rather than per device? */  	if (td->options & NAND_BBT_PERCHIP) {  		numblocks = (int)(this->chipsize >> this->bbt_erase_shift); -		/* Full device write or specific chip ? */ +		/* Full device write or specific chip? */  		if (chipsel == -1) {  			nrchips = this->numchips;  		} else { @@ -732,8 +687,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  	/* Loop through the chips */  	for (; chip < nrchips; chip++) { - -		/* There was already a version of the table, reuse the page +		/* +		 * There was already a version of the table, reuse the page  		 * This applies for absolute placement too, as we have the  		 * page nr. in td->pages.  		 */ @@ -742,8 +697,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  			goto write;  		} -		/* Automatic placement of the bad block table */ -		/* Search direction top -> down ? */ +		/* +		 * Automatic placement of the bad block table. Search direction +		 * top -> down? +		 */  		if (td->options & NAND_BBT_LASTBLOCK) {  			startblock = numblocks * (chip + 1) - 1;  			dir = -1; @@ -767,7 +724,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  			if (!md || md->pages[chip] != page)  				goto write;  		} -		printk(KERN_ERR "No space left to write bad block table\n"); +		pr_err("No space left to write bad block table\n");  		return -ENOSPC;  	write: @@ -792,24 +749,22 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  		bbtoffs = chip * (numblocks >> 2); -		to = ((loff_t) page) << this->page_shift; +		to = ((loff_t)page) << this->page_shift; -		/* Must we save the block contents ? */ +		/* Must we save the block contents? */  		if (td->options & NAND_BBT_SAVECONTENT) {  			/* Make it block aligned */ -			to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1)); +			to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1));  			len = 1 << this->bbt_erase_shift;  			res = mtd->read(mtd, to, len, &retlen, buf);  			if (res < 0) {  				if (retlen != len) { -					printk(KERN_INFO "nand_bbt: Error " -					       "reading block for writing " -					       "the bad block table\n"); +					pr_info("nand_bbt: error reading block " +						"for writing the bad block table\n");  					return res;  				} -				printk(KERN_WARNING "nand_bbt: ECC error " -				       "while reading block for writing " -				       "bad block table\n"); +				pr_warn("nand_bbt: ECC error while reading " +					"block for writing bad block table\n");  			}  			/* Read oob data */  			ops.ooblen = (len >> this->page_shift) * mtd->oobsize; @@ -822,19 +777,19 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  			pageoffs = page - (int)(to >> this->page_shift);  			offs = pageoffs << this->page_shift;  			/* Preset the bbt area with 0xff */ -			memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); +			memset(&buf[offs], 0xff, (size_t)(numblocks >> sft));  			ooboffs = len + (pageoffs * mtd->oobsize);  		} else if (td->options & NAND_BBT_NO_OOB) {  			ooboffs = 0;  			offs = td->len; -			/* the version byte */ +			/* The version byte */  			if (td->options & NAND_BBT_VERSION)  				offs++;  			/* Calc length */ -			len = (size_t) (numblocks >> sft); +			len = (size_t)(numblocks >> sft);  			len += offs; -			/* Make it page aligned ! */ +			/* Make it page aligned! */  			len = ALIGN(len, mtd->writesize);  			/* Preset the buffer with 0xff */  			memset(buf, 0xff, len); @@ -842,8 +797,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  			memcpy(buf, td->pattern, td->len);  		} else {  			/* Calc length */ -			len = (size_t) (numblocks >> sft); -			/* Make it page aligned ! */ +			len = (size_t)(numblocks >> sft); +			/* Make it page aligned! */  			len = ALIGN(len, mtd->writesize);  			/* Preset the buffer with 0xff */  			memset(buf, 0xff, len + @@ -857,13 +812,13 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  		if (td->options & NAND_BBT_VERSION)  			buf[ooboffs + td->veroffs] = td->version[chip]; -		/* walk through the memory table */ +		/* Walk through the memory table */  		for (i = 0; i < numblocks;) {  			uint8_t dat;  			dat = this->bbt[bbtoffs + (i >> 2)];  			for (j = 0; j < 4; j++, i++) {  				int sftcnt = (i << (3 - sft)) & sftmsk; -				/* Do not store the reserved bbt blocks ! */ +				/* Do not store the reserved bbt blocks! */  				buf[offs + (i >> sft)] &=  					~(msk[dat & 0x03] << sftcnt);  				dat >>= 2; @@ -884,8 +839,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  		if (res < 0)  			goto outerr; -		printk(KERN_DEBUG "Bad block table written to 0x%012llx, version " -		       "0x%02X\n", (unsigned long long)to, td->version[chip]); +		pr_info("Bad block table written to 0x%012llx, version 0x%02X\n", +			 (unsigned long long)to, td->version[chip]);  		/* Mark it as used */  		td->pages[chip] = page; @@ -893,19 +848,18 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  	return 0;   outerr: -	printk(KERN_WARNING -	       "nand_bbt: Error while writing bad block table %d\n", res); +	pr_warn("nand_bbt: error while writing bad block table %d\n", res);  	return res;  }  /**   * nand_memory_bbt - [GENERIC] create a memory based bad block table - * @mtd:	MTD device structure - * @bd:		descriptor for the good/bad block search pattern + * @mtd: MTD device structure + * @bd: descriptor for the good/bad block search pattern   * - * The function creates a memory based bbt by scanning the device - * for manufacturer / software marked good / bad blocks -*/ + * The function creates a memory based bbt by scanning the device for + * manufacturer / software marked good / bad blocks. + */  static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)  {  	struct nand_chip *this = mtd->priv; @@ -916,25 +870,24 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b  /**   * check_create - [GENERIC] create and write bbt(s) if necessary - * @mtd:	MTD device structure - * @buf:	temporary buffer - * @bd:		descriptor for the good/bad block search pattern + * @mtd: MTD device structure + * @buf: temporary buffer + * @bd: descriptor for the good/bad block search pattern   * - * The function checks the results of the previous call to read_bbt - * and creates / updates the bbt(s) if necessary - * Creation is necessary if no bbt was found for the chip/device - * Update is necessary if one of the tables is missing or the - * version nr. of one table is less than the other -*/ + * The function checks the results of the previous call to read_bbt and creates + * / updates the bbt(s) if necessary. Creation is necessary if no bbt was found + * for the chip/device. Update is necessary if one of the tables is missing or + * the version nr. of one table is less than the other. + */  static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)  { -	int i, chips, writeops, chipsel, res; +	int i, chips, writeops, create, chipsel, res, res2;  	struct nand_chip *this = mtd->priv;  	struct nand_bbt_descr *td = this->bbt_td;  	struct nand_bbt_descr *md = this->bbt_md;  	struct nand_bbt_descr *rd, *rd2; -	/* Do we have a bbt per chip ? */ +	/* Do we have a bbt per chip? */  	if (td->options & NAND_BBT_PERCHIP)  		chips = this->numchips;  	else @@ -942,86 +895,98 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc  	for (i = 0; i < chips; i++) {  		writeops = 0; +		create = 0;  		rd = NULL;  		rd2 = NULL; -		/* Per chip or per device ? */ +		res = res2 = 0; +		/* Per chip or per device? */  		chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1; -		/* Mirrored table available ? */ +		/* Mirrored table available? */  		if (md) {  			if (td->pages[i] == -1 && md->pages[i] == -1) { +				create = 1;  				writeops = 0x03; -				goto create; -			} - -			if (td->pages[i] == -1) { +			} else if (td->pages[i] == -1) {  				rd = md; -				td->version[i] = md->version[i]; -				writeops = 1; -				goto writecheck; -			} - -			if (md->pages[i] == -1) { +				writeops = 0x01; +			} else if (md->pages[i] == -1) {  				rd = td; -				md->version[i] = td->version[i]; -				writeops = 2; -				goto writecheck; -			} - -			if (td->version[i] == md->version[i]) { +				writeops = 0x02; +			} else if (td->version[i] == md->version[i]) {  				rd = td;  				if (!(td->options & NAND_BBT_VERSION))  					rd2 = md; -				goto writecheck; -			} - -			if (((int8_t) (td->version[i] - md->version[i])) > 0) { +			} else if (((int8_t)(td->version[i] - md->version[i])) > 0) {  				rd = td; -				md->version[i] = td->version[i]; -				writeops = 2; +				writeops = 0x02;  			} else {  				rd = md; -				td->version[i] = md->version[i]; -				writeops = 1; +				writeops = 0x01;  			} - -			goto writecheck; -  		} else {  			if (td->pages[i] == -1) { +				create = 1;  				writeops = 0x01; -				goto create; +			} else { +				rd = td;  			} -			rd = td; -			goto writecheck;  		} -	create: -		/* Create the bad block table by scanning the device ? */ -		if (!(td->options & NAND_BBT_CREATE)) -			continue; -		/* Create the table in memory by scanning the chip(s) */ -		if (!(this->options & NAND_CREATE_EMPTY_BBT)) -			create_bbt(mtd, buf, bd, chipsel); - -		td->version[i] = 1; -		if (md) -			md->version[i] = 1; -	writecheck: -		/* read back first ? */ -		if (rd) -			read_abs_bbt(mtd, buf, rd, chipsel); -		/* If they weren't versioned, read both. */ -		if (rd2) -			read_abs_bbt(mtd, buf, rd2, chipsel); - -		/* Write the bad block table to the device ? */ +		if (create) { +			/* Create the bad block table by scanning the device? */ +			if (!(td->options & NAND_BBT_CREATE)) +				continue; + +			/* Create the table in memory by scanning the chip(s) */ +			if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY)) +				create_bbt(mtd, buf, bd, chipsel); + +			td->version[i] = 1; +			if (md) +				md->version[i] = 1; +		} + +		/* Read back first? */ +		if (rd) { +			res = read_abs_bbt(mtd, buf, rd, chipsel); +			if (mtd_is_eccerr(res)) { +				/* Mark table as invalid */ +				rd->pages[i] = -1; +				rd->version[i] = 0; +				i--; +				continue; +			} +		} +		/* If they weren't versioned, read both */ +		if (rd2) { +			res2 = read_abs_bbt(mtd, buf, rd2, chipsel); +			if (mtd_is_eccerr(res2)) { +				/* Mark table as invalid */ +				rd2->pages[i] = -1; +				rd2->version[i] = 0; +				i--; +				continue; +			} +		} + +		/* Scrub the flash table(s)? */ +		if (mtd_is_bitflip(res) || mtd_is_bitflip(res2)) +			writeops = 0x03; + +		/* Update version numbers before writing */ +		if (md) { +			td->version[i] = max(td->version[i], md->version[i]); +			md->version[i] = td->version[i]; +		} + +		/* Write the bad block table to the device? */  		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {  			res = write_bbt(mtd, buf, td, md, chipsel);  			if (res < 0)  				return res;  		} -		/* Write the mirror bad block table to the device ? */ +		/* Write the mirror bad block table to the device? */  		if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {  			res = write_bbt(mtd, buf, md, td, chipsel);  			if (res < 0) @@ -1033,20 +998,19 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc  /**   * mark_bbt_regions - [GENERIC] mark the bad block table regions - * @mtd:	MTD device structure - * @td:		bad block table descriptor + * @mtd: MTD device structure + * @td: bad block table descriptor   * - * The bad block table regions are marked as "bad" to prevent - * accidental erasures / writes. The regions are identified by - * the mark 0x02. -*/ + * The bad block table regions are marked as "bad" to prevent accidental + * erasures / writes. The regions are identified by the mark 0x02. + */  static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)  {  	struct nand_chip *this = mtd->priv;  	int i, j, chips, block, nrblocks, update;  	uint8_t oldval, newval; -	/* Do we have a bbt per chip ? */ +	/* Do we have a bbt per chip? */  	if (td->options & NAND_BBT_PERCHIP) {  		chips = this->numchips;  		nrblocks = (int)(this->chipsize >> this->bbt_erase_shift); @@ -1083,9 +1047,11 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)  				update = 1;  			block += 2;  		} -		/* If we want reserved blocks to be recorded to flash, and some -		   new ones have been marked, then we need to update the stored -		   bbts.  This should only happen once. */ +		/* +		 * If we want reserved blocks to be recorded to flash, and some +		 * new ones have been marked, then we need to update the stored +		 * bbts.  This should only happen once. +		 */  		if (update && td->reserved_block_code)  			nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1));  	} @@ -1093,8 +1059,8 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)  /**   * verify_bbt_descr - verify the bad block description - * @mtd:	MTD device structure - * @bd:		the table to verify + * @mtd: MTD device structure + * @bd: the table to verify   *   * This functions performs a few sanity checks on the bad block description   * table. @@ -1112,16 +1078,16 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)  	pattern_len = bd->len;  	bits = bd->options & NAND_BBT_NRBITS_MSK; -	BUG_ON((this->options & NAND_USE_FLASH_BBT_NO_OOB) && -			!(this->options & NAND_USE_FLASH_BBT)); +	BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) && +			!(this->bbt_options & NAND_BBT_USE_FLASH));  	BUG_ON(!bits);  	if (bd->options & NAND_BBT_VERSION)  		pattern_len++;  	if (bd->options & NAND_BBT_NO_OOB) { -		BUG_ON(!(this->options & NAND_USE_FLASH_BBT)); -		BUG_ON(!(this->options & NAND_USE_FLASH_BBT_NO_OOB)); +		BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH)); +		BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB));  		BUG_ON(bd->offs);  		if (bd->options & NAND_BBT_VERSION)  			BUG_ON(bd->veroffs != bd->len); @@ -1141,18 +1107,16 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)  /**   * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) - * @mtd:	MTD device structure - * @bd:		descriptor for the good/bad block search pattern - * - * The function checks, if a bad block table(s) is/are already - * available. If not it scans the device for manufacturer - * marked good / bad blocks and writes the bad block table(s) to - * the selected place. + * @mtd: MTD device structure + * @bd: descriptor for the good/bad block search pattern   * - * The bad block table memory is allocated here. It must be freed - * by calling the nand_free_bbt function. + * The function checks, if a bad block table(s) is/are already available. If + * not it scans the device for manufacturer marked good / bad blocks and writes + * the bad block table(s) to the selected place.   * -*/ + * The bad block table memory is allocated here. It must be freed by calling + * the nand_free_bbt function. + */  int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)  {  	struct nand_chip *this = mtd->priv; @@ -1162,19 +1126,21 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)  	struct nand_bbt_descr *md = this->bbt_md;  	len = mtd->size >> (this->bbt_erase_shift + 2); -	/* Allocate memory (2bit per block) and clear the memory bad block table */ +	/* +	 * Allocate memory (2bit per block) and clear the memory bad block +	 * table. +	 */  	this->bbt = kzalloc(len, GFP_KERNEL); -	if (!this->bbt) { -		printk(KERN_ERR "nand_scan_bbt: Out of memory\n"); +	if (!this->bbt)  		return -ENOMEM; -	} -	/* If no primary table decriptor is given, scan the device -	 * to build a memory based bad block table +	/* +	 * If no primary table decriptor is given, scan the device to build a +	 * memory based bad block table.  	 */  	if (!td) {  		if ((res = nand_memory_bbt(mtd, bd))) { -			printk(KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n"); +			pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");  			kfree(this->bbt);  			this->bbt = NULL;  		} @@ -1188,13 +1154,12 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)  	len += (len >> this->page_shift) * mtd->oobsize;  	buf = vmalloc(len);  	if (!buf) { -		printk(KERN_ERR "nand_bbt: Out of memory\n");  		kfree(this->bbt);  		this->bbt = NULL;  		return -ENOMEM;  	} -	/* Is the bbt at a given page ? */ +	/* Is the bbt at a given page? */  	if (td->options & NAND_BBT_ABSPAGE) {  		res = read_abs_bbts(mtd, buf, td, md);  	} else { @@ -1216,15 +1181,15 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)  /**   * nand_update_bbt - [NAND Interface] update bad block table(s) - * @mtd:	MTD device structure - * @offs:	the offset of the newly marked block + * @mtd: MTD device structure + * @offs: the offset of the newly marked block   * - * The function updates the bad block table(s) -*/ + * The function updates the bad block table(s). + */  int nand_update_bbt(struct mtd_info *mtd, loff_t offs)  {  	struct nand_chip *this = mtd->priv; -	int len, res = 0, writeops = 0; +	int len, res = 0;  	int chip, chipsel;  	uint8_t *buf;  	struct nand_bbt_descr *td = this->bbt_td; @@ -1237,14 +1202,10 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)  	len = (1 << this->bbt_erase_shift);  	len += (len >> this->page_shift) * mtd->oobsize;  	buf = kmalloc(len, GFP_KERNEL); -	if (!buf) { -		printk(KERN_ERR "nand_update_bbt: Out of memory\n"); +	if (!buf)  		return -ENOMEM; -	} - -	writeops = md != NULL ? 0x03 : 0x01; -	/* Do we have a bbt per chip ? */ +	/* Do we have a bbt per chip? */  	if (td->options & NAND_BBT_PERCHIP) {  		chip = (int)(offs >> this->chip_shift);  		chipsel = chip; @@ -1257,14 +1218,14 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)  	if (md)  		md->version[chip]++; -	/* Write the bad block table to the device ? */ -	if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { +	/* Write the bad block table to the device? */ +	if (td->options & NAND_BBT_WRITE) {  		res = write_bbt(mtd, buf, td, md, chipsel);  		if (res < 0)  			goto out;  	} -	/* Write the mirror bad block table to the device ? */ -	if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { +	/* Write the mirror bad block table to the device? */ +	if (md && (md->options & NAND_BBT_WRITE)) {  		res = write_bbt(mtd, buf, md, td, chipsel);  	} @@ -1273,8 +1234,10 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)  	return res;  } -/* Define some generic bad / good block scan pattern which are used - * while scanning a device for factory marked good / bad blocks. */ +/* + * Define some generic bad / good block scan pattern which are used + * while scanning a device for factory marked good / bad blocks. + */  static uint8_t scan_ff_pattern[] = { 0xff, 0xff };  static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 }; @@ -1286,8 +1249,7 @@ static struct nand_bbt_descr agand_flashbased = {  	.pattern = scan_agand_pattern  }; -/* Generic flash bbt decriptors -*/ +/* Generic flash bbt descriptors */  static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };  static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; @@ -1331,31 +1293,27 @@ static struct nand_bbt_descr bbt_mirror_no_bbt_descr = {  	.pattern = mirror_pattern  }; -#define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE | \ -		NAND_BBT_SCANBYTE1AND6) +#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB)  /** - * nand_create_default_bbt_descr - [Internal] Creates a BBT descriptor structure - * @this:	NAND chip to create descriptor for + * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure + * @this: NAND chip to create descriptor for   *   * This function allocates and initializes a nand_bbt_descr for BBM detection - * based on the properties of "this". The new descriptor is stored in + * based on the properties of @this. The new descriptor is stored in   * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when   * passed to this function. - *   */ -static int nand_create_default_bbt_descr(struct nand_chip *this) +static int nand_create_badblock_pattern(struct nand_chip *this)  {  	struct nand_bbt_descr *bd;  	if (this->badblock_pattern) { -		printk(KERN_WARNING "BBT descr already allocated; not replacing.\n"); +		pr_warn("Bad block pattern already allocated; not replacing\n");  		return -EINVAL;  	}  	bd = kzalloc(sizeof(*bd), GFP_KERNEL); -	if (!bd) { -		printk(KERN_ERR "nand_create_default_bbt_descr: Out of memory\n"); +	if (!bd)  		return -ENOMEM; -	} -	bd->options = this->options & BBT_SCAN_OPTIONS; +	bd->options = this->bbt_options & BADBLOCK_SCAN_MASK;  	bd->offs = this->badblockpos;  	bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1;  	bd->pattern = scan_ff_pattern; @@ -1366,22 +1324,20 @@ static int nand_create_default_bbt_descr(struct nand_chip *this)  /**   * nand_default_bbt - [NAND Interface] Select a default bad block table for the device - * @mtd:	MTD device structure - * - * This function selects the default bad block table - * support for the device and calls the nand_scan_bbt function + * @mtd: MTD device structure   * -*/ + * This function selects the default bad block table support for the device and + * calls the nand_scan_bbt function. + */  int nand_default_bbt(struct mtd_info *mtd)  {  	struct nand_chip *this = mtd->priv; -	/* Default for AG-AND. We must use a flash based -	 * bad block table as the devices have factory marked -	 * _good_ blocks. Erasing those blocks leads to loss -	 * of the good / bad information, so we _must_ store -	 * this information in a good / bad table during -	 * startup +	/* +	 * Default for AG-AND. We must use a flash based bad block table as the +	 * devices have factory marked _good_ blocks. Erasing those blocks +	 * leads to loss of the good / bad information, so we _must_ store this +	 * information in a good / bad table during startup.  	 */  	if (this->options & NAND_IS_AND) {  		/* Use the default pattern descriptors */ @@ -1389,15 +1345,15 @@ int nand_default_bbt(struct mtd_info *mtd)  			this->bbt_td = &bbt_main_descr;  			this->bbt_md = &bbt_mirror_descr;  		} -		this->options |= NAND_USE_FLASH_BBT; +		this->bbt_options |= NAND_BBT_USE_FLASH;  		return nand_scan_bbt(mtd, &agand_flashbased);  	} -	/* Is a flash based bad block table requested ? */ -	if (this->options & NAND_USE_FLASH_BBT) { +	/* Is a flash based bad block table requested? */ +	if (this->bbt_options & NAND_BBT_USE_FLASH) {  		/* Use the default pattern descriptors */  		if (!this->bbt_td) { -			if (this->options & NAND_USE_FLASH_BBT_NO_OOB) { +			if (this->bbt_options & NAND_BBT_NO_OOB) {  				this->bbt_td = &bbt_main_no_bbt_descr;  				this->bbt_md = &bbt_mirror_no_bbt_descr;  			} else { @@ -1411,18 +1367,17 @@ int nand_default_bbt(struct mtd_info *mtd)  	}  	if (!this->badblock_pattern) -		nand_create_default_bbt_descr(this); +		nand_create_badblock_pattern(this);  	return nand_scan_bbt(mtd, this->badblock_pattern);  }  /**   * nand_isbad_bbt - [NAND Interface] Check if a block is bad - * @mtd:	MTD device structure - * @offs:	offset in the device - * @allowbbt:	allow access to bad block table region - * -*/ + * @mtd: MTD device structure + * @offs: offset in the device + * @allowbbt: allow access to bad block table region + */  int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)  {  	struct nand_chip *this = mtd->priv; @@ -1433,8 +1388,9 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)  	block = (int)(offs >> (this->bbt_erase_shift - 1));  	res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; -	DEBUG(MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", -	      (unsigned int)offs, block >> 1, res); +	pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: " +			"(block %d) 0x%02x\n", +			(unsigned int)offs, block >> 1, res);  	switch ((int)res) {  	case 0x00: diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c index 0f931e757116..3803e0bba23b 100644 --- a/drivers/mtd/nand/nand_bch.c +++ b/drivers/mtd/nand/nand_bch.c @@ -93,8 +93,8 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,  				buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7));  			/* else error in ecc, no action needed */ -			DEBUG(MTD_DEBUG_LEVEL0, "%s: corrected bitflip %u\n", -			      __func__, errloc[i]); +			pr_debug("%s: corrected bitflip %u\n", __func__, +					errloc[i]);  		}  	} else if (count < 0) {  		printk(KERN_ERR "ecc unrecoverable error\n"); diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 271b8e735e8f..b7cfe0d37121 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c @@ -110,7 +110,7 @@ static const char bitsperbyte[256] = {  /*   * addressbits is a lookup table to filter out the bits from the xor-ed - * ecc data that identify the faulty location. + * ECC data that identify the faulty location.   * this is only used for repairing parity   * see the comments in nand_correct_data for more details   */ @@ -153,7 +153,7 @@ static const char addressbits[256] = {   * __nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte   *			 block   * @buf:	input buffer with raw data - * @eccsize:	data bytes per ecc step (256 or 512) + * @eccsize:	data bytes per ECC step (256 or 512)   * @code:	output buffer with ECC   */  void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize, @@ -348,7 +348,7 @@ void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,  		rp17 = (par ^ rp16) & 0xff;  	/* -	 * Finally calculate the ecc bits. +	 * Finally calculate the ECC bits.  	 * Again here it might seem that there are performance optimisations  	 * possible, but benchmarks showed that on the system this is developed  	 * the code below is the fastest @@ -436,7 +436,7 @@ EXPORT_SYMBOL(nand_calculate_ecc);   * @buf:	raw data read from the chip   * @read_ecc:	ECC from the chip   * @calc_ecc:	the ECC calculated from raw data - * @eccsize:	data bytes per ecc step (256 or 512) + * @eccsize:	data bytes per ECC step (256 or 512)   *   * Detect and correct a 1 bit error for eccsize byte block   */ @@ -505,7 +505,7 @@ int __nand_correct_data(unsigned char *buf,  	}  	/* count nr of bits; use table lookup, faster than calculating it */  	if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1) -		return 1;	/* error in ecc data; no action needed */ +		return 1;	/* error in ECC data; no action needed */  	printk(KERN_ERR "uncorrectable error : ");  	return -1; diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 357e8c5252a8..34c03be77301 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -2273,9 +2273,9 @@ static int __init ns_init_module(void)  	switch (bbt) {  	case 2: -		 chip->options |= NAND_USE_FLASH_BBT_NO_OOB; +		 chip->bbt_options |= NAND_BBT_NO_OOB;  	case 1: -		 chip->options |= NAND_USE_FLASH_BBT; +		 chip->bbt_options |= NAND_BBT_USE_FLASH;  	case 0:  		break;  	default: diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index ea2dea8a9c88..ee1713907b92 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -42,7 +42,6 @@ struct ndfc_controller {  	struct nand_chip chip;  	int chip_select;  	struct nand_hw_control ndfc_control; -	struct mtd_partition *parts;  };  static struct ndfc_controller ndfc_ctrl[NDFC_MAX_CS]; @@ -159,13 +158,9 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)  static int ndfc_chip_init(struct ndfc_controller *ndfc,  			  struct device_node *node)  { -#ifdef CONFIG_MTD_CMDLINE_PARTS -	static const char *part_types[] = { "cmdlinepart", NULL }; -#else -	static const char *part_types[] = { NULL }; -#endif  	struct device_node *flash_np;  	struct nand_chip *chip = &ndfc->chip; +	struct mtd_part_parser_data ppdata;  	int ret;  	chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; @@ -193,6 +188,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,  	if (!flash_np)  		return -ENODEV; +	ppdata->of_node = flash_np;  	ndfc->mtd.name = kasprintf(GFP_KERNEL, "%s.%s",  			dev_name(&ndfc->ofdev->dev), flash_np->name);  	if (!ndfc->mtd.name) { @@ -204,18 +200,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,  	if (ret)  		goto err; -	ret = parse_mtd_partitions(&ndfc->mtd, part_types, &ndfc->parts, 0); -	if (ret < 0) -		goto err; - -	if (ret == 0) { -		ret = of_mtd_parse_partitions(&ndfc->ofdev->dev, flash_np, -					      &ndfc->parts); -		if (ret < 0) -			goto err; -	} - -	ret = mtd_device_register(&ndfc->mtd, ndfc->parts, ret); +	ret = mtd_device_parse_register(&ndfc->mtd, NULL, &ppdata, NULL, 0);  err:  	of_node_put(flash_np); @@ -288,6 +273,7 @@ static int __devexit ndfc_remove(struct platform_device *ofdev)  	struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);  	nand_release(&ndfc->mtd); +	kfree(ndfc->mtd.name);  	return 0;  } diff --git a/drivers/mtd/nand/nomadik_nand.c b/drivers/mtd/nand/nomadik_nand.c index b6a5c86ab31e..b463ecfb4c1a 100644 --- a/drivers/mtd/nand/nomadik_nand.c +++ b/drivers/mtd/nand/nomadik_nand.c @@ -187,6 +187,7 @@ static int nomadik_nand_remove(struct platform_device *pdev)  		pdata->exit();  	if (host) { +		nand_release(&host->mtd);  		iounmap(host->cmd_va);  		iounmap(host->data_va);  		iounmap(host->addr_va); diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c index 9c30a0b03171..fa8faedfad6e 100644 --- a/drivers/mtd/nand/nuc900_nand.c +++ b/drivers/mtd/nand/nuc900_nand.c @@ -339,6 +339,7 @@ static int __devexit nuc900_nand_remove(struct platform_device *pdev)  	struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev);  	struct resource *res; +	nand_release(&nuc900_nand->mtd);  	iounmap(nuc900_nand->reg);  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index ec22a5aab038..f745f00f3167 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -95,8 +95,6 @@  #define P4e_s(a)	(TF(a & NAND_Ecc_P4e)		<< 0)  #define P4o_s(a)	(TF(a & NAND_Ecc_P4o)		<< 1) -static const char *part_probes[] = { "cmdlinepart", NULL }; -  /* oob info generated runtime depending on ecc algorithm and layout selected */  static struct nand_ecclayout omap_oobinfo;  /* Define some generic bad / good block scan pattern which are used @@ -115,7 +113,6 @@ struct omap_nand_info {  	struct nand_hw_control		controller;  	struct omap_nand_platform_data	*pdata;  	struct mtd_info			mtd; -	struct mtd_partition		*parts;  	struct nand_chip		nand;  	struct platform_device		*pdev; @@ -745,12 +742,12 @@ static int omap_compare_ecc(u8 *ecc_data1,	/* read from NAND memory */  	case 1:  		/* Uncorrectable error */ -		DEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n"); +		pr_debug("ECC UNCORRECTED_ERROR 1\n");  		return -1;  	case 11:  		/* UN-Correctable error */ -		DEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR B\n"); +		pr_debug("ECC UNCORRECTED_ERROR B\n");  		return -1;  	case 12: @@ -767,8 +764,8 @@ static int omap_compare_ecc(u8 *ecc_data1,	/* read from NAND memory */  		find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1]; -		DEBUG(MTD_DEBUG_LEVEL0, "Correcting single bit ECC error at " -				"offset: %d, bit: %d\n", find_byte, find_bit); +		pr_debug("Correcting single bit ECC error at offset: " +				"%d, bit: %d\n", find_byte, find_bit);  		page_data[find_byte] ^= (1 << find_bit); @@ -780,7 +777,7 @@ static int omap_compare_ecc(u8 *ecc_data1,	/* read from NAND memory */  			    ecc_data2[2] == 0)  				return 0;  		} -		DEBUG(MTD_DEBUG_LEVEL0, "UNCORRECTED_ERROR default\n"); +		pr_debug("UNCORRECTED_ERROR default\n");  		return -1;  	}  } @@ -1104,13 +1101,8 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)  		goto out_release_mem_region;  	} -	err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0); -	if (err > 0) -		mtd_device_register(&info->mtd, info->parts, err); -	else if (pdata->parts) -		mtd_device_register(&info->mtd, pdata->parts, pdata->nr_parts); -	else -		mtd_device_register(&info->mtd, NULL, 0); +	mtd_device_parse_register(&info->mtd, NULL, 0, +			pdata->parts, pdata->nr_parts);  	platform_set_drvdata(pdev, &info->mtd); diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index 7794d0680f91..29f505adaf84 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -21,8 +21,6 @@  #include <mach/hardware.h>  #include <plat/orion_nand.h> -static const char *part_probes[] = { "cmdlinepart", NULL }; -  static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)  {  	struct nand_chip *nc = mtd->priv; @@ -81,8 +79,6 @@ static int __init orion_nand_probe(struct platform_device *pdev)  	struct resource *res;  	void __iomem *io_base;  	int ret = 0; -	struct mtd_partition *partitions = NULL; -	int num_part = 0;  	nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL);  	if (!nc) { @@ -132,17 +128,9 @@ static int __init orion_nand_probe(struct platform_device *pdev)  		goto no_dev;  	} -#ifdef CONFIG_MTD_CMDLINE_PARTS  	mtd->name = "orion_nand"; -	num_part = parse_mtd_partitions(mtd, part_probes, &partitions, 0); -#endif -	/* If cmdline partitions have been passed, let them be used */ -	if (num_part <= 0) { -		num_part = board->nr_parts; -		partitions = board->parts; -	} - -	ret = mtd_device_register(mtd, partitions, num_part); +	ret = mtd_device_parse_register(mtd, NULL, 0, +			board->parts, board->nr_parts);  	if (ret) {  		nand_release(mtd);  		goto no_dev; diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index b1aa41b8a4eb..a97264ececdb 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c @@ -155,7 +155,8 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev)  	chip->ecc.mode = NAND_ECC_SOFT;  	/* Enable the following for a flash based bad block table */ -	chip->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR; +	chip->options = NAND_NO_AUTOINCR; +	chip->bbt_options = NAND_BBT_USE_FLASH;  	/* Scan to find existence of the device */  	if (nand_scan(pasemi_nand_mtd, 1)) { diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index 633c04bf76f6..ea8e1234e0e2 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -21,8 +21,6 @@ struct plat_nand_data {  	struct nand_chip	chip;  	struct mtd_info		mtd;  	void __iomem		*io_base; -	int			nr_parts; -	struct mtd_partition	*parts;  };  /* @@ -79,6 +77,7 @@ static int __devinit plat_nand_probe(struct platform_device *pdev)  	data->chip.read_buf = pdata->ctrl.read_buf;  	data->chip.chip_delay = pdata->chip.chip_delay;  	data->chip.options |= pdata->chip.options; +	data->chip.bbt_options |= pdata->chip.bbt_options;  	data->chip.ecc.hwctl = pdata->ctrl.hwcontrol;  	data->chip.ecc.layout = pdata->chip.ecclayout; @@ -99,23 +98,9 @@ static int __devinit plat_nand_probe(struct platform_device *pdev)  		goto out;  	} -	if (pdata->chip.part_probe_types) { -		err = parse_mtd_partitions(&data->mtd, -					pdata->chip.part_probe_types, -					&data->parts, 0); -		if (err > 0) { -			mtd_device_register(&data->mtd, data->parts, err); -			return 0; -		} -	} -	if (pdata->chip.set_parts) -		pdata->chip.set_parts(data->mtd.size, &pdata->chip); -	if (pdata->chip.partitions) { -		data->parts = pdata->chip.partitions; -		err = mtd_device_register(&data->mtd, data->parts, -			pdata->chip.nr_partitions); -	} else -		err = mtd_device_register(&data->mtd, NULL, 0); +	err = mtd_device_parse_register(&data->mtd, +			pdata->chip.part_probe_types, 0, +			pdata->chip.partitions, pdata->chip.nr_partitions);  	if (!err)  		return err; @@ -145,8 +130,6 @@ static int __devexit plat_nand_remove(struct platform_device *pdev)  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	nand_release(&data->mtd); -	if (data->parts && data->parts != pdata->chip.partitions) -		kfree(data->parts);  	if (pdata->ctrl.remove)  		pdata->ctrl.remove(pdev);  	iounmap(data->io_base); diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c index 3bbb796b451c..7e52af51a198 100644 --- a/drivers/mtd/nand/ppchameleonevb.c +++ b/drivers/mtd/nand/ppchameleonevb.c @@ -99,8 +99,6 @@ static struct mtd_partition partition_info_evb[] = {  #define NUM_PARTITIONS 1 -extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, const char *mtd_id); -  /*   *	hardware specific access to control-lines   */ @@ -187,18 +185,12 @@ static int ppchameleonevb_device_ready(struct mtd_info *minfo)  }  #endif -const char *part_probes[] = { "cmdlinepart", NULL }; -const char *part_probes_evb[] = { "cmdlinepart", NULL }; -  /*   * Main initialization routine   */  static int __init ppchameleonevb_init(void)  {  	struct nand_chip *this; -	const char *part_type = 0; -	int mtd_parts_nb = 0; -	struct mtd_partition *mtd_parts = 0;  	void __iomem *ppchameleon_fio_base;  	void __iomem *ppchameleonevb_fio_base; @@ -281,24 +273,13 @@ static int __init ppchameleonevb_init(void)  #endif  	ppchameleon_mtd->name = "ppchameleon-nand"; -	mtd_parts_nb = parse_mtd_partitions(ppchameleon_mtd, part_probes, &mtd_parts, 0); -	if (mtd_parts_nb > 0) -		part_type = "command line"; -	else -		mtd_parts_nb = 0; - -	if (mtd_parts_nb == 0) { -		if (ppchameleon_mtd->size == NAND_SMALL_SIZE) -			mtd_parts = partition_info_me; -		else -			mtd_parts = partition_info_hi; -		mtd_parts_nb = NUM_PARTITIONS; -		part_type = "static"; -	}  	/* Register the partitions */ -	printk(KERN_NOTICE "Using %s partition definition\n", part_type); -	mtd_device_register(ppchameleon_mtd, mtd_parts, mtd_parts_nb); +	mtd_device_parse_register(ppchameleon_mtd, NULL, 0, +			ppchameleon_mtd->size == NAND_SMALL_SIZE ? +				partition_info_me : +				partition_info_hi, +			NUM_PARTITIONS);   nand_evb_init:  	/**************************** @@ -382,21 +363,13 @@ static int __init ppchameleonevb_init(void)  	}  	ppchameleonevb_mtd->name = NAND_EVB_MTD_NAME; -	mtd_parts_nb = parse_mtd_partitions(ppchameleonevb_mtd, part_probes_evb, &mtd_parts, 0); -	if (mtd_parts_nb > 0) -		part_type = "command line"; -	else -		mtd_parts_nb = 0; - -	if (mtd_parts_nb == 0) { -		mtd_parts = partition_info_evb; -		mtd_parts_nb = NUM_PARTITIONS; -		part_type = "static"; -	}  	/* Register the partitions */ -	printk(KERN_NOTICE "Using %s partition definition\n", part_type); -	mtd_device_register(ppchameleonevb_mtd, mtd_parts, mtd_parts_nb); +	mtd_device_parse_register(ppchameleonevb_mtd, NULL, 0, +			ppchameleon_mtd->size == NAND_SMALL_SIZE ? +				partition_info_me : +				partition_info_hi, +			NUM_PARTITIONS);  	/* Return happy */  	return 0; diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 1fb3b3a80581..9eb7f879969e 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -110,6 +110,7 @@ enum {  enum {  	STATE_IDLE = 0, +	STATE_PREPARED,  	STATE_CMD_HANDLE,  	STATE_DMA_READING,  	STATE_DMA_WRITING, @@ -120,21 +121,40 @@ enum {  	STATE_READY,  }; -struct pxa3xx_nand_info { -	struct nand_chip	nand_chip; +struct pxa3xx_nand_host { +	struct nand_chip	chip; +	struct pxa3xx_nand_cmdset *cmdset; +	struct mtd_info         *mtd; +	void			*info_data; + +	/* page size of attached chip */ +	unsigned int		page_size; +	int			use_ecc; +	int			cs; +	/* calculated from pxa3xx_nand_flash data */ +	unsigned int		col_addr_cycles; +	unsigned int		row_addr_cycles; +	size_t			read_id_bytes; + +	/* cached register value */ +	uint32_t		reg_ndcr; +	uint32_t		ndtr0cs0; +	uint32_t		ndtr1cs0; +}; + +struct pxa3xx_nand_info {  	struct nand_hw_control	controller;  	struct platform_device	 *pdev; -	struct pxa3xx_nand_cmdset *cmdset;  	struct clk		*clk;  	void __iomem		*mmio_base;  	unsigned long		mmio_phys; +	struct completion	cmd_complete;  	unsigned int 		buf_start;  	unsigned int		buf_count; -	struct mtd_info         *mtd;  	/* DMA information */  	int			drcmr_dat;  	int			drcmr_cmd; @@ -142,44 +162,27 @@ struct pxa3xx_nand_info {  	unsigned char		*data_buff;  	unsigned char		*oob_buff;  	dma_addr_t 		data_buff_phys; -	size_t			data_buff_size;  	int 			data_dma_ch;  	struct pxa_dma_desc	*data_desc;  	dma_addr_t 		data_desc_addr; -	uint32_t		reg_ndcr; - -	/* saved column/page_addr during CMD_SEQIN */ -	int			seqin_column; -	int			seqin_page_addr; - -	/* relate to the command */ +	struct pxa3xx_nand_host *host[NUM_CHIP_SELECT];  	unsigned int		state; +	int			cs;  	int			use_ecc;	/* use HW ECC ? */  	int			use_dma;	/* use DMA ? */  	int			is_ready;  	unsigned int		page_size;	/* page size of attached chip */  	unsigned int		data_size;	/* data size in FIFO */ +	unsigned int		oob_size;  	int 			retcode; -	struct completion 	cmd_complete;  	/* generated NDCBx register values */  	uint32_t		ndcb0;  	uint32_t		ndcb1;  	uint32_t		ndcb2; - -	/* timing calcuted from setting */ -	uint32_t		ndtr0cs0; -	uint32_t		ndtr1cs0; - -	/* calculated from pxa3xx_nand_flash data */ -	size_t		oob_size; -	size_t		read_id_bytes; - -	unsigned int	col_addr_cycles; -	unsigned int	row_addr_cycles;  };  static int use_dma = 1; @@ -225,7 +228,7 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = {  /* Define a default flash type setting serve as flash detecting only */  #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) -const char *mtd_names[] = {"pxa3xx_nand-0", NULL}; +const char *mtd_names[] = {"pxa3xx_nand-0", "pxa3xx_nand-1", NULL};  #define NDTR0_tCH(c)	(min((c), 7) << 19)  #define NDTR0_tCS(c)	(min((c), 7) << 16) @@ -241,9 +244,10 @@ const char *mtd_names[] = {"pxa3xx_nand-0", NULL};  /* convert nano-seconds to nand flash controller clock cycles */  #define ns2cycle(ns, clk)	(int)((ns) * (clk / 1000000) / 1000) -static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, +static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,  				   const struct pxa3xx_nand_timing *t)  { +	struct pxa3xx_nand_info *info = host->info_data;  	unsigned long nand_clk = clk_get_rate(info->clk);  	uint32_t ndtr0, ndtr1; @@ -258,23 +262,24 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info,  		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |  		NDTR1_tAR(ns2cycle(t->tAR, nand_clk)); -	info->ndtr0cs0 = ndtr0; -	info->ndtr1cs0 = ndtr1; +	host->ndtr0cs0 = ndtr0; +	host->ndtr1cs0 = ndtr1;  	nand_writel(info, NDTR0CS0, ndtr0);  	nand_writel(info, NDTR1CS0, ndtr1);  }  static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)  { -	int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; +	struct pxa3xx_nand_host *host = info->host[info->cs]; +	int oob_enable = host->reg_ndcr & NDCR_SPARE_EN; -	info->data_size = info->page_size; +	info->data_size = host->page_size;  	if (!oob_enable) {  		info->oob_size = 0;  		return;  	} -	switch (info->page_size) { +	switch (host->page_size) {  	case 2048:  		info->oob_size = (info->use_ecc) ? 40 : 64;  		break; @@ -292,9 +297,10 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)   */  static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)  { +	struct pxa3xx_nand_host *host = info->host[info->cs];  	uint32_t ndcr; -	ndcr = info->reg_ndcr; +	ndcr = host->reg_ndcr;  	ndcr |= info->use_ecc ? NDCR_ECC_EN : 0;  	ndcr |= info->use_dma ? NDCR_DMA_EN : 0;  	ndcr |= NDCR_ND_RUN; @@ -359,7 +365,7 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)  					DIV_ROUND_UP(info->oob_size, 4));  		break;  	default: -		printk(KERN_ERR "%s: invalid state %d\n", __func__, +		dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,  				info->state);  		BUG();  	} @@ -385,7 +391,7 @@ static void start_data_dma(struct pxa3xx_nand_info *info)  		desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC;  		break;  	default: -		printk(KERN_ERR "%s: invalid state %d\n", __func__, +		dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,  				info->state);  		BUG();  	} @@ -416,6 +422,15 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)  {  	struct pxa3xx_nand_info *info = devid;  	unsigned int status, is_completed = 0; +	unsigned int ready, cmd_done; + +	if (info->cs == 0) { +		ready           = NDSR_FLASH_RDY; +		cmd_done        = NDSR_CS0_CMDD; +	} else { +		ready           = NDSR_RDY; +		cmd_done        = NDSR_CS1_CMDD; +	}  	status = nand_readl(info, NDSR); @@ -437,11 +452,11 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)  			handle_data_pio(info);  		}  	} -	if (status & NDSR_CS0_CMDD) { +	if (status & cmd_done) {  		info->state = STATE_CMD_DONE;  		is_completed = 1;  	} -	if (status & NDSR_FLASH_RDY) { +	if (status & ready) {  		info->is_ready = 1;  		info->state = STATE_READY;  	} @@ -463,12 +478,6 @@ NORMAL_IRQ_EXIT:  	return IRQ_HANDLED;  } -static int pxa3xx_nand_dev_ready(struct mtd_info *mtd) -{ -	struct pxa3xx_nand_info *info = mtd->priv; -	return (nand_readl(info, NDSR) & NDSR_RDY) ? 1 : 0; -} -  static inline int is_buf_blank(uint8_t *buf, size_t len)  {  	for (; len > 0; len--) @@ -481,10 +490,12 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,  		uint16_t column, int page_addr)  {  	uint16_t cmd; -	int addr_cycle, exec_cmd, ndcb0; -	struct mtd_info *mtd = info->mtd; +	int addr_cycle, exec_cmd; +	struct pxa3xx_nand_host *host; +	struct mtd_info *mtd; -	ndcb0 = 0; +	host = info->host[info->cs]; +	mtd = host->mtd;  	addr_cycle = 0;  	exec_cmd = 1; @@ -495,6 +506,10 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,  	info->use_ecc		= 0;  	info->is_ready		= 0;  	info->retcode		= ERR_NONE; +	if (info->cs != 0) +		info->ndcb0 = NDCB0_CSEL; +	else +		info->ndcb0 = 0;  	switch (command) {  	case NAND_CMD_READ0: @@ -512,20 +527,19 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,  		break;  	} -	info->ndcb0 = ndcb0; -	addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles -				    + info->col_addr_cycles); +	addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles +				    + host->col_addr_cycles);  	switch (command) {  	case NAND_CMD_READOOB:  	case NAND_CMD_READ0: -		cmd = info->cmdset->read1; +		cmd = host->cmdset->read1;  		if (command == NAND_CMD_READOOB)  			info->buf_start = mtd->writesize + column;  		else  			info->buf_start = column; -		if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) +		if (unlikely(host->page_size < PAGE_CHUNK_SIZE))  			info->ndcb0 |= NDCB0_CMD_TYPE(0)  					| addr_cycle  					| (cmd & NDCB0_CMD1_MASK); @@ -537,7 +551,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,  	case NAND_CMD_SEQIN:  		/* small page addr setting */ -		if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) { +		if (unlikely(host->page_size < PAGE_CHUNK_SIZE)) {  			info->ndcb1 = ((page_addr & 0xFFFFFF) << 8)  					| (column & 0xFF); @@ -564,7 +578,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,  			break;  		} -		cmd = info->cmdset->program; +		cmd = host->cmdset->program;  		info->ndcb0 |= NDCB0_CMD_TYPE(0x1)  				| NDCB0_AUTO_RS  				| NDCB0_ST_ROW_EN @@ -574,8 +588,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,  		break;  	case NAND_CMD_READID: -		cmd = info->cmdset->read_id; -		info->buf_count = info->read_id_bytes; +		cmd = host->cmdset->read_id; +		info->buf_count = host->read_id_bytes;  		info->ndcb0 |= NDCB0_CMD_TYPE(3)  				| NDCB0_ADDR_CYC(1)  				| cmd; @@ -583,7 +597,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,  		info->data_size = 8;  		break;  	case NAND_CMD_STATUS: -		cmd = info->cmdset->read_status; +		cmd = host->cmdset->read_status;  		info->buf_count = 1;  		info->ndcb0 |= NDCB0_CMD_TYPE(4)  				| NDCB0_ADDR_CYC(1) @@ -593,7 +607,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,  		break;  	case NAND_CMD_ERASE1: -		cmd = info->cmdset->erase; +		cmd = host->cmdset->erase;  		info->ndcb0 |= NDCB0_CMD_TYPE(2)  				| NDCB0_AUTO_RS  				| NDCB0_ADDR_CYC(3) @@ -604,7 +618,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,  		break;  	case NAND_CMD_RESET: -		cmd = info->cmdset->reset; +		cmd = host->cmdset->reset;  		info->ndcb0 |= NDCB0_CMD_TYPE(5)  				| cmd; @@ -616,8 +630,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,  	default:  		exec_cmd = 0; -		printk(KERN_ERR "pxa3xx-nand: non-supported" -			" command %x\n", command); +		dev_err(&info->pdev->dev, "non-supported command %x\n", +				command);  		break;  	} @@ -627,7 +641,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,  static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,  				int column, int page_addr)  { -	struct pxa3xx_nand_info *info = mtd->priv; +	struct pxa3xx_nand_host *host = mtd->priv; +	struct pxa3xx_nand_info *info = host->info_data;  	int ret, exec_cmd;  	/* @@ -635,9 +650,21 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,  	 * "byte" address into a "word" address appropriate  	 * for indexing a word-oriented device  	 */ -	if (info->reg_ndcr & NDCR_DWIDTH_M) +	if (host->reg_ndcr & NDCR_DWIDTH_M)  		column /= 2; +	/* +	 * There may be different NAND chip hooked to +	 * different chip select, so check whether +	 * chip select has been changed, if yes, reset the timing +	 */ +	if (info->cs != host->cs) { +		info->cs = host->cs; +		nand_writel(info, NDTR0CS0, host->ndtr0cs0); +		nand_writel(info, NDTR1CS0, host->ndtr1cs0); +	} + +	info->state = STATE_PREPARED;  	exec_cmd = prepare_command_pool(info, command, column, page_addr);  	if (exec_cmd) {  		init_completion(&info->cmd_complete); @@ -646,12 +673,12 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,  		ret = wait_for_completion_timeout(&info->cmd_complete,  				CHIP_DELAY_TIMEOUT);  		if (!ret) { -			printk(KERN_ERR "Wait time out!!!\n"); +			dev_err(&info->pdev->dev, "Wait time out!!!\n");  			/* Stop State Machine for next command cycle */  			pxa3xx_nand_stop(info);  		} -		info->state = STATE_IDLE;  	} +	info->state = STATE_IDLE;  }  static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, @@ -664,7 +691,8 @@ static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,  static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,  		struct nand_chip *chip, uint8_t *buf, int page)  { -	struct pxa3xx_nand_info *info = mtd->priv; +	struct pxa3xx_nand_host *host = mtd->priv; +	struct pxa3xx_nand_info *info = host->info_data;  	chip->read_buf(mtd, buf, mtd->writesize);  	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -685,6 +713,8 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,  		 * OOB, ignore such double bit errors  		 */  		if (is_buf_blank(buf, mtd->writesize)) +			info->retcode = ERR_NONE; +		else  			mtd->ecc_stats.failed++;  	} @@ -693,7 +723,8 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,  static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)  { -	struct pxa3xx_nand_info *info = mtd->priv; +	struct pxa3xx_nand_host *host = mtd->priv; +	struct pxa3xx_nand_info *info = host->info_data;  	char retval = 0xFF;  	if (info->buf_start < info->buf_count) @@ -705,7 +736,8 @@ static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)  static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)  { -	struct pxa3xx_nand_info *info = mtd->priv; +	struct pxa3xx_nand_host *host = mtd->priv; +	struct pxa3xx_nand_info *info = host->info_data;  	u16 retval = 0xFFFF;  	if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) { @@ -717,7 +749,8 @@ static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)  static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)  { -	struct pxa3xx_nand_info *info = mtd->priv; +	struct pxa3xx_nand_host *host = mtd->priv; +	struct pxa3xx_nand_info *info = host->info_data;  	int real_len = min_t(size_t, len, info->buf_count - info->buf_start);  	memcpy(buf, info->data_buff + info->buf_start, real_len); @@ -727,7 +760,8 @@ static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)  static void pxa3xx_nand_write_buf(struct mtd_info *mtd,  		const uint8_t *buf, int len)  { -	struct pxa3xx_nand_info *info = mtd->priv; +	struct pxa3xx_nand_host *host = mtd->priv; +	struct pxa3xx_nand_info *info = host->info_data;  	int real_len = min_t(size_t, len, info->buf_count - info->buf_start);  	memcpy(info->data_buff + info->buf_start, buf, real_len); @@ -747,7 +781,8 @@ static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip)  static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)  { -	struct pxa3xx_nand_info *info = mtd->priv; +	struct pxa3xx_nand_host *host = mtd->priv; +	struct pxa3xx_nand_info *info = host->info_data;  	/* pxa3xx_nand_send_command has waited for command complete */  	if (this->state == FL_WRITING || this->state == FL_ERASING) { @@ -770,54 +805,70 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,  {  	struct platform_device *pdev = info->pdev;  	struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; +	struct pxa3xx_nand_host *host = info->host[info->cs];  	uint32_t ndcr = 0x0; /* enable all interrupts */ -	if (f->page_size != 2048 && f->page_size != 512) +	if (f->page_size != 2048 && f->page_size != 512) { +		dev_err(&pdev->dev, "Current only support 2048 and 512 size\n");  		return -EINVAL; +	} -	if (f->flash_width != 16 && f->flash_width != 8) +	if (f->flash_width != 16 && f->flash_width != 8) { +		dev_err(&pdev->dev, "Only support 8bit and 16 bit!\n");  		return -EINVAL; +	}  	/* calculate flash information */ -	info->cmdset = &default_cmdset; -	info->page_size = f->page_size; -	info->read_id_bytes = (f->page_size == 2048) ? 4 : 2; +	host->cmdset = &default_cmdset; +	host->page_size = f->page_size; +	host->read_id_bytes = (f->page_size == 2048) ? 4 : 2;  	/* calculate addressing information */ -	info->col_addr_cycles = (f->page_size == 2048) ? 2 : 1; +	host->col_addr_cycles = (f->page_size == 2048) ? 2 : 1;  	if (f->num_blocks * f->page_per_block > 65536) -		info->row_addr_cycles = 3; +		host->row_addr_cycles = 3;  	else -		info->row_addr_cycles = 2; +		host->row_addr_cycles = 2;  	ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; -	ndcr |= (info->col_addr_cycles == 2) ? NDCR_RA_START : 0; +	ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0;  	ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0;  	ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0;  	ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0;  	ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0; -	ndcr |= NDCR_RD_ID_CNT(info->read_id_bytes); +	ndcr |= NDCR_RD_ID_CNT(host->read_id_bytes);  	ndcr |= NDCR_SPARE_EN; /* enable spare by default */ -	info->reg_ndcr = ndcr; +	host->reg_ndcr = ndcr; -	pxa3xx_nand_set_timing(info, f->timing); +	pxa3xx_nand_set_timing(host, f->timing);  	return 0;  }  static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)  { +	/* +	 * We set 0 by hard coding here, for we don't support keep_config +	 * when there is more than one chip attached to the controller +	 */ +	struct pxa3xx_nand_host *host = info->host[0];  	uint32_t ndcr = nand_readl(info, NDCR); -	info->page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; -	/* set info fields needed to read id */ -	info->read_id_bytes = (info->page_size == 2048) ? 4 : 2; -	info->reg_ndcr = ndcr; -	info->cmdset = &default_cmdset; -	info->ndtr0cs0 = nand_readl(info, NDTR0CS0); -	info->ndtr1cs0 = nand_readl(info, NDTR1CS0); +	if (ndcr & NDCR_PAGE_SZ) { +		host->page_size = 2048; +		host->read_id_bytes = 4; +	} else { +		host->page_size = 512; +		host->read_id_bytes = 2; +	} + +	host->reg_ndcr = ndcr & ~NDCR_INT_MASK; +	host->cmdset = &default_cmdset; + +	host->ndtr0cs0 = nand_readl(info, NDTR0CS0); +	host->ndtr1cs0 = nand_readl(info, NDTR1CS0);  	return 0;  } @@ -847,7 +898,6 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)  		return -ENOMEM;  	} -	info->data_buff_size = MAX_BUFF_SIZE;  	info->data_desc = (void *)info->data_buff + data_desc_offset;  	info->data_desc_addr = info->data_buff_phys + data_desc_offset; @@ -855,7 +905,7 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)  				pxa3xx_nand_data_dma_irq, info);  	if (info->data_dma_ch < 0) {  		dev_err(&pdev->dev, "failed to request data dma\n"); -		dma_free_coherent(&pdev->dev, info->data_buff_size, +		dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE,  				info->data_buff, info->data_buff_phys);  		return info->data_dma_ch;  	} @@ -865,24 +915,28 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)  static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info)  { -	struct mtd_info *mtd = info->mtd; -	struct nand_chip *chip = mtd->priv; - +	struct mtd_info *mtd; +	int ret; +	mtd = info->host[info->cs]->mtd;  	/* use the common timing to make a try */ -	pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); -	chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0); +	ret = pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); +	if (ret) +		return ret; + +	pxa3xx_nand_cmdfunc(mtd, NAND_CMD_RESET, 0, 0);  	if (info->is_ready) -		return 1; -	else  		return 0; + +	return -ENODEV;  }  static int pxa3xx_nand_scan(struct mtd_info *mtd)  { -	struct pxa3xx_nand_info *info = mtd->priv; +	struct pxa3xx_nand_host *host = mtd->priv; +	struct pxa3xx_nand_info *info = host->info_data;  	struct platform_device *pdev = info->pdev;  	struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; -	struct nand_flash_dev pxa3xx_flash_ids[2] = { {NULL,}, {NULL,} }; +	struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL;  	const struct pxa3xx_nand_flash *f = NULL;  	struct nand_chip *chip = mtd->priv;  	uint32_t id = -1; @@ -893,22 +947,20 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)  		goto KEEP_CONFIG;  	ret = pxa3xx_nand_sensing(info); -	if (!ret) { -		kfree(mtd); -		info->mtd = NULL; -		printk(KERN_INFO "There is no nand chip on cs 0!\n"); +	if (ret) { +		dev_info(&info->pdev->dev, "There is no chip on cs %d!\n", +			 info->cs); -		return -EINVAL; +		return ret;  	}  	chip->cmdfunc(mtd, NAND_CMD_READID, 0, 0);  	id = *((uint16_t *)(info->data_buff));  	if (id != 0) -		printk(KERN_INFO "Detect a flash id %x\n", id); +		dev_info(&info->pdev->dev, "Detect a flash id %x\n", id);  	else { -		kfree(mtd); -		info->mtd = NULL; -		printk(KERN_WARNING "Read out ID 0, potential timing set wrong!!\n"); +		dev_warn(&info->pdev->dev, +			 "Read out ID 0, potential timing set wrong!!\n");  		return -EINVAL;  	} @@ -926,14 +978,17 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)  	}  	if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1)) { -		kfree(mtd); -		info->mtd = NULL; -		printk(KERN_ERR "ERROR!! flash not defined!!!\n"); +		dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n");  		return -EINVAL;  	} -	pxa3xx_nand_config_flash(info, f); +	ret = pxa3xx_nand_config_flash(info, f); +	if (ret) { +		dev_err(&info->pdev->dev, "ERROR! Configure failed\n"); +		return ret; +	} +  	pxa3xx_flash_ids[0].name = f->name;  	pxa3xx_flash_ids[0].id = (f->chip_id >> 8) & 0xffff;  	pxa3xx_flash_ids[0].pagesize = f->page_size; @@ -942,62 +997,78 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)  	pxa3xx_flash_ids[0].erasesize = f->page_size * f->page_per_block;  	if (f->flash_width == 16)  		pxa3xx_flash_ids[0].options = NAND_BUSWIDTH_16; +	pxa3xx_flash_ids[1].name = NULL; +	def = pxa3xx_flash_ids;  KEEP_CONFIG: -	if (nand_scan_ident(mtd, 1, pxa3xx_flash_ids)) +	chip->ecc.mode = NAND_ECC_HW; +	chip->ecc.size = host->page_size; + +	chip->options = NAND_NO_AUTOINCR; +	chip->options |= NAND_NO_READRDY; +	if (host->reg_ndcr & NDCR_DWIDTH_M) +		chip->options |= NAND_BUSWIDTH_16; + +	if (nand_scan_ident(mtd, 1, def))  		return -ENODEV;  	/* calculate addressing information */ -	info->col_addr_cycles = (mtd->writesize >= 2048) ? 2 : 1; +	if (mtd->writesize >= 2048) +		host->col_addr_cycles = 2; +	else +		host->col_addr_cycles = 1; +  	info->oob_buff = info->data_buff + mtd->writesize;  	if ((mtd->size >> chip->page_shift) > 65536) -		info->row_addr_cycles = 3; +		host->row_addr_cycles = 3;  	else -		info->row_addr_cycles = 2; -	mtd->name = mtd_names[0]; -	chip->ecc.mode = NAND_ECC_HW; -	chip->ecc.size = f->page_size; - -	chip->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16 : 0; -	chip->options |= NAND_NO_AUTOINCR; -	chip->options |= NAND_NO_READRDY; +		host->row_addr_cycles = 2; +	mtd->name = mtd_names[0];  	return nand_scan_tail(mtd);  } -static -struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) +static int alloc_nand_resource(struct platform_device *pdev)  { +	struct pxa3xx_nand_platform_data *pdata;  	struct pxa3xx_nand_info *info; +	struct pxa3xx_nand_host *host;  	struct nand_chip *chip;  	struct mtd_info *mtd;  	struct resource *r; -	int ret, irq; +	int ret, irq, cs; -	mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct pxa3xx_nand_info), -			GFP_KERNEL); -	if (!mtd) { +	pdata = pdev->dev.platform_data; +	info = kzalloc(sizeof(*info) + (sizeof(*mtd) + +		       sizeof(*host)) * pdata->num_cs, GFP_KERNEL); +	if (!info) {  		dev_err(&pdev->dev, "failed to allocate memory\n"); -		return NULL; +		return -ENOMEM;  	} -	info = (struct pxa3xx_nand_info *)(&mtd[1]); -	chip = (struct nand_chip *)(&mtd[1]);  	info->pdev = pdev; -	info->mtd = mtd; -	mtd->priv = info; -	mtd->owner = THIS_MODULE; - -	chip->ecc.read_page	= pxa3xx_nand_read_page_hwecc; -	chip->ecc.write_page	= pxa3xx_nand_write_page_hwecc; -	chip->controller        = &info->controller; -	chip->waitfunc		= pxa3xx_nand_waitfunc; -	chip->select_chip	= pxa3xx_nand_select_chip; -	chip->dev_ready		= pxa3xx_nand_dev_ready; -	chip->cmdfunc		= pxa3xx_nand_cmdfunc; -	chip->read_word		= pxa3xx_nand_read_word; -	chip->read_byte		= pxa3xx_nand_read_byte; -	chip->read_buf		= pxa3xx_nand_read_buf; -	chip->write_buf		= pxa3xx_nand_write_buf; -	chip->verify_buf	= pxa3xx_nand_verify_buf; +	for (cs = 0; cs < pdata->num_cs; cs++) { +		mtd = (struct mtd_info *)((unsigned int)&info[1] + +		      (sizeof(*mtd) + sizeof(*host)) * cs); +		chip = (struct nand_chip *)(&mtd[1]); +		host = (struct pxa3xx_nand_host *)chip; +		info->host[cs] = host; +		host->mtd = mtd; +		host->cs = cs; +		host->info_data = info; +		mtd->priv = host; +		mtd->owner = THIS_MODULE; + +		chip->ecc.read_page	= pxa3xx_nand_read_page_hwecc; +		chip->ecc.write_page	= pxa3xx_nand_write_page_hwecc; +		chip->controller        = &info->controller; +		chip->waitfunc		= pxa3xx_nand_waitfunc; +		chip->select_chip	= pxa3xx_nand_select_chip; +		chip->cmdfunc		= pxa3xx_nand_cmdfunc; +		chip->read_word		= pxa3xx_nand_read_word; +		chip->read_byte		= pxa3xx_nand_read_byte; +		chip->read_buf		= pxa3xx_nand_read_buf; +		chip->write_buf		= pxa3xx_nand_write_buf; +		chip->verify_buf	= pxa3xx_nand_verify_buf; +	}  	spin_lock_init(&chip->controller->lock);  	init_waitqueue_head(&chip->controller->wq); @@ -1070,13 +1141,13 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev)  	platform_set_drvdata(pdev, info); -	return info; +	return 0;  fail_free_buf:  	free_irq(irq, info);  	if (use_dma) {  		pxa_free_dma(info->data_dma_ch); -		dma_free_coherent(&pdev->dev, info->data_buff_size, +		dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE,  			info->data_buff, info->data_buff_phys);  	} else  		kfree(info->data_buff); @@ -1088,17 +1159,21 @@ fail_put_clk:  	clk_disable(info->clk);  	clk_put(info->clk);  fail_free_mtd: -	kfree(mtd); -	return NULL; +	kfree(info); +	return ret;  }  static int pxa3xx_nand_remove(struct platform_device *pdev)  {  	struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); -	struct mtd_info *mtd = info->mtd; +	struct pxa3xx_nand_platform_data *pdata;  	struct resource *r; -	int irq; +	int irq, cs; +	if (!info) +		return 0; + +	pdata = pdev->dev.platform_data;  	platform_set_drvdata(pdev, NULL);  	irq = platform_get_irq(pdev, 0); @@ -1106,7 +1181,7 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)  		free_irq(irq, info);  	if (use_dma) {  		pxa_free_dma(info->data_dma_ch); -		dma_free_writecombine(&pdev->dev, info->data_buff_size, +		dma_free_writecombine(&pdev->dev, MAX_BUFF_SIZE,  				info->data_buff, info->data_buff_phys);  	} else  		kfree(info->data_buff); @@ -1118,10 +1193,9 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)  	clk_disable(info->clk);  	clk_put(info->clk); -	if (mtd) { -		mtd_device_unregister(mtd); -		kfree(mtd); -	} +	for (cs = 0; cs < pdata->num_cs; cs++) +		nand_release(info->host[cs]->mtd); +	kfree(info);  	return 0;  } @@ -1129,6 +1203,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)  {  	struct pxa3xx_nand_platform_data *pdata;  	struct pxa3xx_nand_info *info; +	int ret, cs, probe_success;  	pdata = pdev->dev.platform_data;  	if (!pdata) { @@ -1136,52 +1211,88 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)  		return -ENODEV;  	} -	info = alloc_nand_resource(pdev); -	if (info == NULL) -		return -ENOMEM; - -	if (pxa3xx_nand_scan(info->mtd)) { -		dev_err(&pdev->dev, "failed to scan nand\n"); -		pxa3xx_nand_remove(pdev); -		return -ENODEV; +	ret = alloc_nand_resource(pdev); +	if (ret) { +		dev_err(&pdev->dev, "alloc nand resource failed\n"); +		return ret;  	} -	if (mtd_has_cmdlinepart()) { -		const char *probes[] = { "cmdlinepart", NULL }; -		struct mtd_partition *parts; -		int nr_parts; +	info = platform_get_drvdata(pdev); +	probe_success = 0; +	for (cs = 0; cs < pdata->num_cs; cs++) { +		info->cs = cs; +		ret = pxa3xx_nand_scan(info->host[cs]->mtd); +		if (ret) { +			dev_warn(&pdev->dev, "failed to scan nand at cs %d\n", +				cs); +			continue; +		} -		nr_parts = parse_mtd_partitions(info->mtd, probes, &parts, 0); +		ret = mtd_device_parse_register(info->host[cs]->mtd, NULL, 0, +				pdata->parts[cs], pdata->nr_parts[cs]); +		if (!ret) +			probe_success = 1; +	} -		if (nr_parts) -			return mtd_device_register(info->mtd, parts, nr_parts); +	if (!probe_success) { +		pxa3xx_nand_remove(pdev); +		return -ENODEV;  	} -	return mtd_device_register(info->mtd, pdata->parts, pdata->nr_parts); +	return 0;  }  #ifdef CONFIG_PM  static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state)  {  	struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); -	struct mtd_info *mtd = info->mtd; +	struct pxa3xx_nand_platform_data *pdata; +	struct mtd_info *mtd; +	int cs; +	pdata = pdev->dev.platform_data;  	if (info->state) {  		dev_err(&pdev->dev, "driver busy, state = %d\n", info->state);  		return -EAGAIN;  	} +	for (cs = 0; cs < pdata->num_cs; cs++) { +		mtd = info->host[cs]->mtd; +		mtd->suspend(mtd); +	} +  	return 0;  }  static int pxa3xx_nand_resume(struct platform_device *pdev)  {  	struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); -	struct mtd_info *mtd = info->mtd; +	struct pxa3xx_nand_platform_data *pdata; +	struct mtd_info *mtd; +	int cs; -	nand_writel(info, NDTR0CS0, info->ndtr0cs0); -	nand_writel(info, NDTR1CS0, info->ndtr1cs0); -	clk_enable(info->clk); +	pdata = pdev->dev.platform_data; +	/* We don't want to handle interrupt without calling mtd routine */ +	disable_int(info, NDCR_INT_MASK); + +	/* +	 * Directly set the chip select to a invalid value, +	 * then the driver would reset the timing according +	 * to current chip select at the beginning of cmdfunc +	 */ +	info->cs = 0xff; + +	/* +	 * As the spec says, the NDSR would be updated to 0x1800 when +	 * doing the nand_clk disable/enable. +	 * To prevent it damaging state machine of the driver, clear +	 * all status before resume +	 */ +	nand_writel(info, NDSR, NDSR_MASK); +	for (cs = 0; cs < pdata->num_cs; cs++) { +		mtd = info->host[cs]->mtd; +		mtd->resume(mtd); +	}  	return 0;  } diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index cae2e013c986..f20f393bfda6 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -1027,7 +1027,7 @@ void r852_shutdown(struct pci_dev *pci_dev)  }  #ifdef CONFIG_PM -int r852_suspend(struct device *device) +static int r852_suspend(struct device *device)  {  	struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); @@ -1048,7 +1048,7 @@ int r852_suspend(struct device *device)  	return 0;  } -int r852_resume(struct device *device) +static int r852_resume(struct device *device)  {  	struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); @@ -1092,7 +1092,7 @@ static const struct pci_device_id r852_pci_id_tbl[] = {  MODULE_DEVICE_TABLE(pci, r852_pci_id_tbl); -SIMPLE_DEV_PM_OPS(r852_pm_ops, r852_suspend, r852_resume); +static SIMPLE_DEV_PM_OPS(r852_pm_ops, r852_suspend, r852_resume);  static struct pci_driver r852_pci_driver = {  	.name		= DRV_NAME, diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index c9f9127ff770..f309addc2fa0 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c @@ -351,7 +351,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha  		return 0;  	} -	/* Read the syndrom pattern from the FPGA and correct the bitorder */ +	/* Read the syndrome pattern from the FPGA and correct the bitorder */  	rs_ecc = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC);  	for (i = 0; i < 8; i++) {  		ecc[i] = bitrev8(*rs_ecc); @@ -380,7 +380,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha  	/* Let the library code do its magic. */  	res = decode_rs8(rs_decoder, (uint8_t *) buf, par, 512, syn, 0, NULL, 0xff, NULL);  	if (res > 0) { -		DEBUG(MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " "ECC corrected %d errors on read\n", res); +		pr_debug("rtc_from4_correct_data: " "ECC corrected %d errors on read\n", res);  	}  	return res;  } @@ -444,7 +444,6 @@ static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this,  		len = mtd->writesize;  		buf = kmalloc(len, GFP_KERNEL);  		if (!buf) { -			printk(KERN_ERR "rtc_from4_errstat: Out of memory!\n");  			er_stat = 1;  			goto out;  		} diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 4405468f196b..868685db6712 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -723,7 +723,7 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)  	/* free the common resources */ -	if (info->clk != NULL && !IS_ERR(info->clk)) { +	if (!IS_ERR(info->clk)) {  		s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);  		clk_put(info->clk);  	} @@ -744,26 +744,15 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)  	return 0;  } -const char *part_probes[] = { "cmdlinepart", NULL };  static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,  				      struct s3c2410_nand_mtd *mtd,  				      struct s3c2410_nand_set *set)  { -	struct mtd_partition *part_info; -	int nr_part = 0; +	if (set) +		mtd->mtd.name = set->name; -	if (set == NULL) -		return mtd_device_register(&mtd->mtd, NULL, 0); - -	mtd->mtd.name = set->name; -	nr_part = parse_mtd_partitions(&mtd->mtd, part_probes, &part_info, 0); - -	if (nr_part <= 0 && set->nr_partitions > 0) { -		nr_part = set->nr_partitions; -		part_info = set->partitions; -	} - -	return mtd_device_register(&mtd->mtd, part_info, nr_part); +	return mtd_device_parse_register(&mtd->mtd, NULL, 0, +			set->partitions, set->nr_partitions);  }  /** @@ -880,8 +869,10 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,  	/* If you use u-boot BBT creation code, specifying this flag will  	 * let the kernel fish out the BBT from the NAND, and also skip the  	 * full NAND scan that can take 1/2s or so. Little things... */ -	if (set->flash_bbt) -		chip->options |= NAND_USE_FLASH_BBT | NAND_SKIP_BBTSCAN; +	if (set->flash_bbt) { +		chip->bbt_options |= NAND_BBT_USE_FLASH; +		chip->options |= NAND_SKIP_BBTSCAN; +	}  }  /** diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 19e24ed089ea..619d2a504788 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -103,16 +103,12 @@ static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat,  	return readb(sharpsl->io + ECCCNTR) != 0;  } -static const char *part_probes[] = { "cmdlinepart", NULL }; -  /*   * Main initialization routine   */  static int __devinit sharpsl_nand_probe(struct platform_device *pdev)  {  	struct nand_chip *this; -	struct mtd_partition *sharpsl_partition_info; -	int nr_partitions;  	struct resource *r;  	int err = 0;  	struct sharpsl_nand *sharpsl; @@ -184,14 +180,9 @@ static int __devinit sharpsl_nand_probe(struct platform_device *pdev)  	/* Register the partitions */  	sharpsl->mtd.name = "sharpsl-nand"; -	nr_partitions = parse_mtd_partitions(&sharpsl->mtd, part_probes, &sharpsl_partition_info, 0); -	if (nr_partitions <= 0) { -		nr_partitions = data->nr_partitions; -		sharpsl_partition_info = data->partitions; -	} -	err = mtd_device_register(&sharpsl->mtd, sharpsl_partition_info, -				  nr_partitions); +	err = mtd_device_parse_register(&sharpsl->mtd, NULL, 0, +			data->partitions, data->nr_partitions);  	if (err)  		goto err_add; diff --git a/drivers/mtd/nand/sm_common.c b/drivers/mtd/nand/sm_common.c index 43469715b3fa..32ae5af7444f 100644 --- a/drivers/mtd/nand/sm_common.c +++ b/drivers/mtd/nand/sm_common.c @@ -48,7 +48,7 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)  	/* As long as this function is called on erase block boundaries  		it will work correctly for 256 byte nand */ -	ops.mode = MTD_OOB_PLACE; +	ops.mode = MTD_OPS_PLACE_OOB;  	ops.ooboffs = 0;  	ops.ooblen = mtd->oobsize;  	ops.oobbuf = (void *)&oob; diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c index ca2d0555729e..0fb24f9c2327 100644 --- a/drivers/mtd/nand/socrates_nand.c +++ b/drivers/mtd/nand/socrates_nand.c @@ -155,8 +155,6 @@ static int socrates_nand_device_ready(struct mtd_info *mtd)  	return 1;  } -static const char *part_probes[] = { "cmdlinepart", NULL }; -  /*   * Probe for the NAND device.   */ @@ -166,8 +164,7 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev)  	struct mtd_info *mtd;  	struct nand_chip *nand_chip;  	int res; -	struct mtd_partition *partitions = NULL; -	int num_partitions = 0; +	struct mtd_part_parser_data ppdata;  	/* Allocate memory for the device structure (and zero it) */  	host = kzalloc(sizeof(struct socrates_nand_host), GFP_KERNEL); @@ -193,6 +190,7 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev)  	mtd->name = "socrates_nand";  	mtd->owner = THIS_MODULE;  	mtd->dev.parent = &ofdev->dev; +	ppdata.of_node = ofdev->dev.of_node;  	/*should never be accessed directly */  	nand_chip->IO_ADDR_R = (void *)0xdeadbeef; @@ -225,30 +223,10 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev)  		goto out;  	} -#ifdef CONFIG_MTD_CMDLINE_PARTS -	num_partitions = parse_mtd_partitions(mtd, part_probes, -					      &partitions, 0); -	if (num_partitions < 0) { -		res = num_partitions; -		goto release; -	} -#endif - -	if (num_partitions == 0) { -		num_partitions = of_mtd_parse_partitions(&ofdev->dev, -							 ofdev->dev.of_node, -							 &partitions); -		if (num_partitions < 0) { -			res = num_partitions; -			goto release; -		} -	} - -	res = mtd_device_register(mtd, partitions, num_partitions); +	res = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);  	if (!res)  		return res; -release:  	nand_release(mtd);  out: diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index 11e8371b5683..beebd95f7690 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -121,9 +121,6 @@ struct tmio_nand {  #define mtd_to_tmio(m)			container_of(m, struct tmio_nand, mtd) -#ifdef CONFIG_MTD_CMDLINE_PARTS -static const char *part_probes[] = { "cmdlinepart", NULL }; -#endif  /*--------------------------------------------------------------------------*/ @@ -381,8 +378,6 @@ static int tmio_probe(struct platform_device *dev)  	struct tmio_nand *tmio;  	struct mtd_info *mtd;  	struct nand_chip *nand_chip; -	struct mtd_partition *parts; -	int nbparts = 0;  	int retval;  	if (data == NULL) @@ -461,15 +456,9 @@ static int tmio_probe(struct platform_device *dev)  		goto err_scan;  	}  	/* Register the partitions */ -#ifdef CONFIG_MTD_CMDLINE_PARTS -	nbparts = parse_mtd_partitions(mtd, part_probes, &parts, 0); -#endif -	if (nbparts <= 0 && data) { -		parts = data->partition; -		nbparts = data->num_partitions; -	} - -	retval = mtd_device_register(mtd, parts, nbparts); +	retval = mtd_device_parse_register(mtd, NULL, 0, +			data ? data->partition : NULL, +			data ? data->num_partitions : 0);  	if (!retval)  		return retval; diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c index bfba4e39a6c5..ace46fdaef58 100644 --- a/drivers/mtd/nand/txx9ndfmc.c +++ b/drivers/mtd/nand/txx9ndfmc.c @@ -74,7 +74,6 @@ struct txx9ndfmc_drvdata {  	unsigned char hold;	/* in gbusclock */  	unsigned char spw;	/* in gbusclock */  	struct nand_hw_control hw_control; -	struct mtd_partition *parts[MAX_TXX9NDFMC_DEV];  };  static struct platform_device *mtd_to_platdev(struct mtd_info *mtd) @@ -287,7 +286,6 @@ static int txx9ndfmc_nand_scan(struct mtd_info *mtd)  static int __init txx9ndfmc_probe(struct platform_device *dev)  {  	struct txx9ndfmc_platform_data *plat = dev->dev.platform_data; -	static const char *probes[] = { "cmdlinepart", NULL };  	int hold, spw;  	int i;  	struct txx9ndfmc_drvdata *drvdata; @@ -333,7 +331,6 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)  		struct txx9ndfmc_priv *txx9_priv;  		struct nand_chip *chip;  		struct mtd_info *mtd; -		int nr_parts;  		if (!(plat->ch_mask & (1 << i)))  			continue; @@ -393,9 +390,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)  		}  		mtd->name = txx9_priv->mtdname; -		nr_parts = parse_mtd_partitions(mtd, probes, -						&drvdata->parts[i], 0); -		mtd_device_register(mtd, drvdata->parts[i], nr_parts); +		mtd_device_parse_register(mtd, NULL, 0, NULL, 0);  		drvdata->mtds[i] = mtd;  	} @@ -421,7 +416,6 @@ static int __exit txx9ndfmc_remove(struct platform_device *dev)  		txx9_priv = chip->priv;  		nand_release(mtd); -		kfree(drvdata->parts[i]);  		kfree(txx9_priv->mtdname);  		kfree(txx9_priv);  	} diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index b155666acfbe..cda77b562ad4 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -63,14 +63,12 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)  		return;  	} -	DEBUG(MTD_DEBUG_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name); +	pr_debug("NFTL: add_mtd for %s\n", mtd->name);  	nftl = kzalloc(sizeof(struct NFTLrecord), GFP_KERNEL); -	if (!nftl) { -		printk(KERN_WARNING "NFTL: out of memory for data structures\n"); +	if (!nftl)  		return; -	}  	nftl->mbd.mtd = mtd;  	nftl->mbd.devnum = -1; @@ -132,7 +130,7 @@ static void nftl_remove_dev(struct mtd_blktrans_dev *dev)  {  	struct NFTLrecord *nftl = (void *)dev; -	DEBUG(MTD_DEBUG_LEVEL1, "NFTL: remove_dev (i=%d)\n", dev->devnum); +	pr_debug("NFTL: remove_dev (i=%d)\n", dev->devnum);  	del_mtd_blktrans_dev(dev);  	kfree(nftl->ReplUnitTable); @@ -149,7 +147,7 @@ int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,  	struct mtd_oob_ops ops;  	int res; -	ops.mode = MTD_OOB_PLACE; +	ops.mode = MTD_OPS_PLACE_OOB;  	ops.ooboffs = offs & mask;  	ops.ooblen = len;  	ops.oobbuf = buf; @@ -170,7 +168,7 @@ int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,  	struct mtd_oob_ops ops;  	int res; -	ops.mode = MTD_OOB_PLACE; +	ops.mode = MTD_OPS_PLACE_OOB;  	ops.ooboffs = offs & mask;  	ops.ooblen = len;  	ops.oobbuf = buf; @@ -193,7 +191,7 @@ static int nftl_write(struct mtd_info *mtd, loff_t offs, size_t len,  	struct mtd_oob_ops ops;  	int res; -	ops.mode = MTD_OOB_PLACE; +	ops.mode = MTD_OPS_PLACE_OOB;  	ops.ooboffs = offs & mask;  	ops.ooblen = mtd->oobsize;  	ops.oobbuf = oob; @@ -220,7 +218,7 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )  	/* Normally, we force a fold to happen before we run out of free blocks completely */  	if (!desperate && nftl->numfreeEUNs < 2) { -		DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n"); +		pr_debug("NFTL_findfreeblock: there are too few free EUNs\n");  		return BLOCK_NIL;  	} @@ -291,8 +289,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p  			if (block == 2) {  				foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;  				if (foldmark == FOLD_MARK_IN_PROGRESS) { -					DEBUG(MTD_DEBUG_LEVEL1, -					      "Write Inhibited on EUN %d\n", thisEUN); +					pr_debug("Write Inhibited on EUN %d\n", thisEUN);  					inplace = 0;  				} else {  					/* There's no other reason not to do inplace, @@ -357,7 +354,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p  			if (BlockLastState[block] != SECTOR_FREE &&  			    BlockMap[block] != BLOCK_NIL &&  			    BlockMap[block] != targetEUN) { -				DEBUG(MTD_DEBUG_LEVEL1, "Setting inplace to 0. VUC %d, " +				pr_debug("Setting inplace to 0. VUC %d, "  				      "block %d was %x lastEUN, "  				      "and is in EUN %d (%s) %d\n",  				      thisVUC, block, BlockLastState[block], @@ -373,14 +370,14 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p  		    pendingblock < ((thisVUC + 1)* (nftl->EraseSize / 512)) &&  		    BlockLastState[pendingblock - (thisVUC * (nftl->EraseSize / 512))] !=  		    SECTOR_FREE) { -			DEBUG(MTD_DEBUG_LEVEL1, "Pending write not free in EUN %d. " +			pr_debug("Pending write not free in EUN %d. "  			      "Folding out of place.\n", targetEUN);  			inplace = 0;  		}  	}  	if (!inplace) { -		DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. " +		pr_debug("Cannot fold Virtual Unit Chain %d in place. "  		      "Trying out-of-place\n", thisVUC);  		/* We need to find a targetEUN to fold into. */  		targetEUN = NFTL_findfreeblock(nftl, 1); @@ -410,7 +407,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p  	   and the Erase Unit into which we are supposed to be copying.  	   Go for it.  	*/ -	DEBUG(MTD_DEBUG_LEVEL1,"Folding chain %d into unit %d\n", thisVUC, targetEUN); +	pr_debug("Folding chain %d into unit %d\n", thisVUC, targetEUN);  	for (block = 0; block < nftl->EraseSize / 512 ; block++) {  		unsigned char movebuf[512];  		int ret; @@ -428,7 +425,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p  		ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),  				512, &retlen, movebuf); -		if (ret < 0 && ret != -EUCLEAN) { +		if (ret < 0 && !mtd_is_bitflip(ret)) {  			ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block])  					+ (block * 512), 512, &retlen,  					movebuf); @@ -457,7 +454,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p  	   has duplicate chains, we need to free one of the chains because it's not necessary any more.  	*/  	thisEUN = nftl->EUNtable[thisVUC]; -	DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n"); +	pr_debug("Want to erase\n");  	/* For each block in the old chain (except the targetEUN of course),  	   free it and make it available for future use */ @@ -570,7 +567,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)  				      (writeEUN * nftl->EraseSize) + blockofs,  				      8, &retlen, (char *)&bci); -			DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n", +			pr_debug("Status of block %d in EUN %d is %x\n",  			      block , writeEUN, le16_to_cpu(bci.Status));  			status = bci.Status | bci.Status1; @@ -623,7 +620,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)  				   but they are reserved for when we're  				   desperate. Well, now we're desperate.  				*/ -				DEBUG(MTD_DEBUG_LEVEL1, "Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC); +				pr_debug("Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC);  				writeEUN = NFTL_findfreeblock(nftl, 1);  			}  			if (writeEUN == BLOCK_NIL) { @@ -776,7 +773,7 @@ static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,  		size_t retlen;  		int res = mtd->read(mtd, ptr, 512, &retlen, buffer); -		if (res < 0 && res != -EUCLEAN) +		if (res < 0 && !mtd_is_bitflip(res))  			return -EIO;  	}  	return 0; diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index e3cd1ffad2f6..ac4092591aea 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c @@ -32,7 +32,7 @@  /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the   *	various device information of the NFTL partition and Bad Unit Table. Update - *	the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[] + *	the ReplUnitTable[] table according to the Bad Unit Table. ReplUnitTable[]   *	is used for management of Erase Unit in other routines in nftl.c and nftlmount.c   */  static int find_boot_record(struct NFTLrecord *nftl) @@ -297,7 +297,7 @@ static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int   *   * Return: 0 when succeed, -1 on error.   * - *  ToDo: 1. Is it neceressary to check_free_sector after erasing ?? + *  ToDo: 1. Is it necessary to check_free_sector after erasing ??   */  int NFTL_formatblock(struct NFTLrecord *nftl, int block)  { @@ -337,7 +337,7 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block)  		nb_erases = le32_to_cpu(uci.WearInfo);  		nb_erases++; -		/* wrap (almost impossible with current flashs) or free block */ +		/* wrap (almost impossible with current flash) or free block */  		if (nb_erases == 0)  			nb_erases = 1; @@ -363,10 +363,10 @@ fail:   *	Mark as 'IGNORE' each incorrect sector. This check is only done if the chain   *	was being folded when NFTL was interrupted.   * - *	The check_free_sectors in this function is neceressary. There is a possible + *	The check_free_sectors in this function is necessary. There is a possible   *	situation that after writing the Data area, the Block Control Information is   *	not updated according (due to power failure or something) which leaves the block - *	in an umconsistent state. So we have to check if a block is really FREE in this + *	in an inconsistent state. So we have to check if a block is really FREE in this   *	case. */  static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_block)  { @@ -428,7 +428,7 @@ static int calc_chain_length(struct NFTLrecord *nftl, unsigned int first_block)  	for (;;) {  		length++; -		/* avoid infinite loops, although this is guaranted not to +		/* avoid infinite loops, although this is guaranteed not to  		   happen because of the previous checks */  		if (length >= nftl->nb_blocks) {  			printk("nftl: length too long %d !\n", length); @@ -447,11 +447,11 @@ static int calc_chain_length(struct NFTLrecord *nftl, unsigned int first_block)  /* format_chain: Format an invalid Virtual Unit chain. It frees all the Erase Units in a   *	Virtual Unit Chain, i.e. all the units are disconnected.   * - *	It is not stricly correct to begin from the first block of the chain because + *	It is not strictly correct to begin from the first block of the chain because   *	if we stop the code, we may see again a valid chain if there was a first_block   *	flag in a block inside it. But is it really a problem ?   * - * FixMe: Figure out what the last statesment means. What if power failure when we are + * FixMe: Figure out what the last statement means. What if power failure when we are   *	in the for (;;) loop formatting blocks ??   */  static void format_chain(struct NFTLrecord *nftl, unsigned int first_block) @@ -485,7 +485,7 @@ static void format_chain(struct NFTLrecord *nftl, unsigned int first_block)   *	totally free (only 0xff).   *   * Definition: Free Erase Unit -- A properly erased/formatted Free Erase Unit should have meet the - *	following critia: + *	following criteria:   *	1. */  static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)  { @@ -502,7 +502,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)  	erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1));  	if (erase_mark != ERASE_MARK) {  		/* if no erase mark, the block must be totally free. This is -		   possible in two cases : empty filsystem or interrupted erase (very unlikely) */ +		   possible in two cases : empty filesystem or interrupted erase (very unlikely) */  		if (check_free_sectors (nftl, block * nftl->EraseSize, nftl->EraseSize, 1) != 0)  			return -1; @@ -544,7 +544,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)  /* get_fold_mark: Read fold mark from Unit Control Information #2, we use FOLD_MARK_IN_PROGRESS   *	to indicate that we are in the progression of a Virtual Unit Chain folding. If the UCI #2   *	is FOLD_MARK_IN_PROGRESS when mounting the NFTL, the (previous) folding process is interrupted - *	for some reason. A clean up/check of the VUC is neceressary in this case. + *	for some reason. A clean up/check of the VUC is necessary in this case.   *   * WARNING: return 0 if read error   */ @@ -657,7 +657,7 @@ int NFTL_mount(struct NFTLrecord *s)  						printk("Block %d: incorrect logical block: %d expected: %d\n",  						       block, logical_block, first_logical_block);  						/* the chain is incorrect : we must format it, -						   but we need to read it completly */ +						   but we need to read it completely */  						do_format_chain = 1;  					}  					if (is_first_block) { @@ -669,7 +669,7 @@ int NFTL_mount(struct NFTLrecord *s)  							printk("Block %d: incorrectly marked as first block in chain\n",  							       block);  							/* the chain is incorrect : we must format it, -							   but we need to read it completly */ +							   but we need to read it completely */  							do_format_chain = 1;  						} else {  							printk("Block %d: folding in progress - ignoring first block flag\n", diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index a996718fa6b0..64be8f0848b0 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -20,14 +20,23 @@  #include <linux/slab.h>  #include <linux/mtd/partitions.h> -int __devinit of_mtd_parse_partitions(struct device *dev, -                                      struct device_node *node, -                                      struct mtd_partition **pparts) +static int parse_ofpart_partitions(struct mtd_info *master, +				   struct mtd_partition **pparts, +				   struct mtd_part_parser_data *data)  { +	struct device_node *node;  	const char *partname;  	struct device_node *pp;  	int nr_parts, i; + +	if (!data) +		return 0; + +	node = data->of_node; +	if (!node) +		return 0; +  	/* First count the subnodes */  	pp = NULL;  	nr_parts = 0; @@ -69,7 +78,7 @@ int __devinit of_mtd_parse_partitions(struct device *dev,  	if (!i) {  		of_node_put(pp); -		dev_err(dev, "No valid partition found on %s\n", node->full_name); +		pr_err("No valid partition found on %s\n", node->full_name);  		kfree(*pparts);  		*pparts = NULL;  		return -EINVAL; @@ -77,6 +86,99 @@ int __devinit of_mtd_parse_partitions(struct device *dev,  	return nr_parts;  } -EXPORT_SYMBOL(of_mtd_parse_partitions); + +static struct mtd_part_parser ofpart_parser = { +	.owner = THIS_MODULE, +	.parse_fn = parse_ofpart_partitions, +	.name = "ofpart", +}; + +static int parse_ofoldpart_partitions(struct mtd_info *master, +				      struct mtd_partition **pparts, +				      struct mtd_part_parser_data *data) +{ +	struct device_node *dp; +	int i, plen, nr_parts; +	const struct { +		__be32 offset, len; +	} *part; +	const char *names; + +	if (!data) +		return 0; + +	dp = data->of_node; +	if (!dp) +		return 0; + +	part = of_get_property(dp, "partitions", &plen); +	if (!part) +		return 0; /* No partitions found */ + +	pr_warning("Device tree uses obsolete partition map binding: %s\n", +			dp->full_name); + +	nr_parts = plen / sizeof(part[0]); + +	*pparts = kzalloc(nr_parts * sizeof(*(*pparts)), GFP_KERNEL); +	if (!pparts) +		return -ENOMEM; + +	names = of_get_property(dp, "partition-names", &plen); + +	for (i = 0; i < nr_parts; i++) { +		(*pparts)[i].offset = be32_to_cpu(part->offset); +		(*pparts)[i].size   = be32_to_cpu(part->len) & ~1; +		/* bit 0 set signifies read only partition */ +		if (be32_to_cpu(part->len) & 1) +			(*pparts)[i].mask_flags = MTD_WRITEABLE; + +		if (names && (plen > 0)) { +			int len = strlen(names) + 1; + +			(*pparts)[i].name = (char *)names; +			plen -= len; +			names += len; +		} else { +			(*pparts)[i].name = "unnamed"; +		} + +		part++; +	} + +	return nr_parts; +} + +static struct mtd_part_parser ofoldpart_parser = { +	.owner = THIS_MODULE, +	.parse_fn = parse_ofoldpart_partitions, +	.name = "ofoldpart", +}; + +static int __init ofpart_parser_init(void) +{ +	int rc; +	rc = register_mtd_parser(&ofpart_parser); +	if (rc) +		goto out; + +	rc = register_mtd_parser(&ofoldpart_parser); +	if (!rc) +		return 0; + +	deregister_mtd_parser(&ofoldpart_parser); +out: +	return rc; +} + +module_init(ofpart_parser_init);  MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree"); +MODULE_AUTHOR("Vitaly Wool, David Gibson"); +/* + * When MTD core cannot find the requested parser, it tries to load the module + * with the same name. Since we provide the ofoldpart parser, we should have + * the corresponding alias. + */ +MODULE_ALIAS("ofoldpart"); diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index 2d70d354d846..7813095264a5 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c @@ -30,11 +30,8 @@   */  #define DRIVER_NAME	"onenand-flash" -static const char *part_probes[] = { "cmdlinepart", NULL,  }; -  struct onenand_info {  	struct mtd_info		mtd; -	struct mtd_partition	*parts;  	struct onenand_chip	onenand;  }; @@ -73,13 +70,9 @@ static int __devinit generic_onenand_probe(struct platform_device *pdev)  		goto out_iounmap;  	} -	err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0); -	if (err > 0) -		mtd_device_register(&info->mtd, info->parts, err); -	else if (err <= 0 && pdata && pdata->parts) -		mtd_device_register(&info->mtd, pdata->parts, pdata->nr_parts); -	else -		err = mtd_device_register(&info->mtd, NULL, 0); +	err = mtd_device_parse_register(&info->mtd, NULL, 0, +			pdata ? pdata->parts : NULL, +			pdata ? pdata->nr_parts : 0);  	platform_set_drvdata(pdev, info); @@ -104,7 +97,6 @@ static int __devexit generic_onenand_remove(struct platform_device *pdev)  	platform_set_drvdata(pdev, NULL);  	if (info) { -		mtd_device_unregister(&info->mtd);  		onenand_release(&info->mtd);  		release_mem_region(res->start, size);  		iounmap(info->onenand.base); diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 6a1d6d9a2df9..7e9ea6852b67 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -57,7 +57,6 @@ struct omap2_onenand {  	unsigned long phys_base;  	int gpio_irq;  	struct mtd_info mtd; -	struct mtd_partition *parts;  	struct onenand_chip onenand;  	struct completion irq_done;  	struct completion dma_done; @@ -67,8 +66,6 @@ struct omap2_onenand {  	struct regulator *regulator;  }; -static const char *part_probes[] = { "cmdlinepart", NULL,  }; -  static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data)  {  	struct omap2_onenand *c = data; @@ -741,6 +738,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)  		c->regulator = regulator_get(&pdev->dev, "vonenand");  		if (IS_ERR(c->regulator)) {  			dev_err(&pdev->dev,  "Failed to get regulator\n"); +			r = PTR_ERR(c->regulator);  			goto err_release_dma;  		}  		c->onenand.enable = omap2_onenand_enable; @@ -753,13 +751,9 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)  	if ((r = onenand_scan(&c->mtd, 1)) < 0)  		goto err_release_regulator; -	r = parse_mtd_partitions(&c->mtd, part_probes, &c->parts, 0); -	if (r > 0) -		r = mtd_device_register(&c->mtd, c->parts, r); -	else if (pdata->parts != NULL) -		r = mtd_device_register(&c->mtd, pdata->parts, pdata->nr_parts); -	else -		r = mtd_device_register(&c->mtd, NULL, 0); +	r = mtd_device_parse_register(&c->mtd, NULL, 0, +			pdata ? pdata->parts : NULL, +			pdata ? pdata->nr_parts : 0);  	if (r)  		goto err_release_onenand; @@ -786,7 +780,6 @@ err_release_mem_region:  err_free_cs:  	gpmc_cs_free(c->gpmc_cs);  err_kfree: -	kfree(c->parts);  	kfree(c);  	return r; @@ -809,7 +802,6 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev)  	iounmap(c->onenand.base);  	release_mem_region(c->phys_base, ONENAND_IO_SIZE);  	gpmc_cs_free(c->gpmc_cs); -	kfree(c->parts);  	kfree(c);  	return 0; diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index ac9e959802a7..a8394730b4b6 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1015,7 +1015,7 @@ static void onenand_release_device(struct mtd_info *mtd)  }  /** - * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer + * onenand_transfer_auto_oob - [INTERN] oob auto-placement transfer   * @param mtd		MTD device structure   * @param buf		destination address   * @param column	oob offset to read from @@ -1079,7 +1079,7 @@ static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status)  		return status;  	/* check if we failed due to uncorrectable error */ -	if (status != -EBADMSG && status != ONENAND_BBT_READ_ECC_ERROR) +	if (!mtd_is_eccerr(status) && status != ONENAND_BBT_READ_ECC_ERROR)  		return status;  	/* check if address lies in MLC region */ @@ -1122,10 +1122,10 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,  	int ret = 0;  	int writesize = this->writesize; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n", -	      __func__, (unsigned int) from, (int) len); +	pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from, +			(int)len); -	if (ops->mode == MTD_OOB_AUTO) +	if (ops->mode == MTD_OPS_AUTO_OOB)  		oobsize = this->ecclayout->oobavail;  	else  		oobsize = mtd->oobsize; @@ -1159,7 +1159,7 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,  			if (unlikely(ret))  				ret = onenand_recover_lsb(mtd, from, ret);  			onenand_update_bufferram(mtd, from, !ret); -			if (ret == -EBADMSG) +			if (mtd_is_eccerr(ret))  				ret = 0;  			if (ret)  				break; @@ -1170,7 +1170,7 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,  			thisooblen = oobsize - oobcolumn;  			thisooblen = min_t(int, thisooblen, ooblen - oobread); -			if (ops->mode == MTD_OOB_AUTO) +			if (ops->mode == MTD_OPS_AUTO_OOB)  				onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);  			else  				this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); @@ -1226,10 +1226,10 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,  	int ret = 0, boundary = 0;  	int writesize = this->writesize; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n", -			__func__, (unsigned int) from, (int) len); +	pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from, +			(int)len); -	if (ops->mode == MTD_OOB_AUTO) +	if (ops->mode == MTD_OPS_AUTO_OOB)  		oobsize = this->ecclayout->oobavail;  	else  		oobsize = mtd->oobsize; @@ -1255,7 +1255,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,  			this->command(mtd, ONENAND_CMD_READ, from, writesize);   			ret = this->wait(mtd, FL_READING);   			onenand_update_bufferram(mtd, from, !ret); -			if (ret == -EBADMSG) +			if (mtd_is_eccerr(ret))  				ret = 0;   		}   	} @@ -1291,7 +1291,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,  			thisooblen = oobsize - oobcolumn;  			thisooblen = min_t(int, thisooblen, ooblen - oobread); -			if (ops->mode == MTD_OOB_AUTO) +			if (ops->mode == MTD_OPS_AUTO_OOB)  				onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);  			else  				this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); @@ -1315,7 +1315,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,   		/* Now wait for load */   		ret = this->wait(mtd, FL_READING);   		onenand_update_bufferram(mtd, from, !ret); -		if (ret == -EBADMSG) +		if (mtd_is_eccerr(ret))  			ret = 0;   	} @@ -1351,19 +1351,19 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,  	struct mtd_ecc_stats stats;  	int read = 0, thislen, column, oobsize;  	size_t len = ops->ooblen; -	mtd_oob_mode_t mode = ops->mode; +	unsigned int mode = ops->mode;  	u_char *buf = ops->oobbuf;  	int ret = 0, readcmd;  	from += ops->ooboffs; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n", -		__func__, (unsigned int) from, (int) len); +	pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from, +			(int)len);  	/* Initialize return length value */  	ops->oobretlen = 0; -	if (mode == MTD_OOB_AUTO) +	if (mode == MTD_OPS_AUTO_OOB)  		oobsize = this->ecclayout->oobavail;  	else  		oobsize = mtd->oobsize; @@ -1403,13 +1403,13 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,  		if (unlikely(ret))  			ret = onenand_recover_lsb(mtd, from, ret); -		if (ret && ret != -EBADMSG) { +		if (ret && !mtd_is_eccerr(ret)) {  			printk(KERN_ERR "%s: read failed = 0x%x\n",  				__func__, ret);  			break;  		} -		if (mode == MTD_OOB_AUTO) +		if (mode == MTD_OPS_AUTO_OOB)  			onenand_transfer_auto_oob(mtd, buf, column, thislen);  		else  			this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); @@ -1487,10 +1487,10 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from,  	int ret;  	switch (ops->mode) { -	case MTD_OOB_PLACE: -	case MTD_OOB_AUTO: +	case MTD_OPS_PLACE_OOB: +	case MTD_OPS_AUTO_OOB:  		break; -	case MTD_OOB_RAW: +	case MTD_OPS_RAW:  		/* Not implemented yet */  	default:  		return -EINVAL; @@ -1576,8 +1576,8 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,  	size_t len = ops->ooblen;  	u_char *buf = ops->oobbuf; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %zi\n", -		__func__, (unsigned int) from, len); +	pr_debug("%s: from = 0x%08x, len = %zi\n", __func__, (unsigned int)from, +			len);  	/* Initialize return value */  	ops->oobretlen = 0; @@ -1750,8 +1750,8 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,  	/* Wait for any existing operation to clear */  	onenand_panic_wait(mtd); -	DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", -		__func__, (unsigned int) to, (int) len); +	pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, +			(int)len);  	/* Initialize retlen, in case of early exit */  	*retlen = 0; @@ -1821,7 +1821,7 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,  }  /** - * onenand_fill_auto_oob - [Internal] oob auto-placement transfer + * onenand_fill_auto_oob - [INTERN] oob auto-placement transfer   * @param mtd		MTD device structure   * @param oob_buf	oob buffer   * @param buf		source address @@ -1883,8 +1883,8 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,  	u_char *oobbuf;  	int ret = 0, cmd; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", -		__func__, (unsigned int) to, (int) len); +	pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, +			(int)len);  	/* Initialize retlen, in case of early exit */  	ops->retlen = 0; @@ -1908,7 +1908,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,  	if (!len)  		return 0; -	if (ops->mode == MTD_OOB_AUTO) +	if (ops->mode == MTD_OPS_AUTO_OOB)  		oobsize = this->ecclayout->oobavail;  	else  		oobsize = mtd->oobsize; @@ -1945,7 +1945,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,  				/* We send data to spare ram with oobsize  				 * to prevent byte access */  				memset(oobbuf, 0xff, mtd->oobsize); -				if (ops->mode == MTD_OOB_AUTO) +				if (ops->mode == MTD_OPS_AUTO_OOB)  					onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);  				else  					memcpy(oobbuf + oobcolumn, oob, thisooblen); @@ -2055,7 +2055,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,  /** - * onenand_write_oob_nolock - [Internal] OneNAND write out-of-band + * onenand_write_oob_nolock - [INTERN] OneNAND write out-of-band   * @param mtd		MTD device structure   * @param to		offset to write to   * @param len		number of bytes to write @@ -2074,17 +2074,17 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,  	u_char *oobbuf;  	size_t len = ops->ooblen;  	const u_char *buf = ops->oobbuf; -	mtd_oob_mode_t mode = ops->mode; +	unsigned int mode = ops->mode;  	to += ops->ooboffs; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", -		__func__, (unsigned int) to, (int) len); +	pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, +			(int)len);  	/* Initialize retlen, in case of early exit */  	ops->oobretlen = 0; -	if (mode == MTD_OOB_AUTO) +	if (mode == MTD_OPS_AUTO_OOB)  		oobsize = this->ecclayout->oobavail;  	else  		oobsize = mtd->oobsize; @@ -2128,7 +2128,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,  		/* We send data to spare ram with oobsize  		 * to prevent byte access */  		memset(oobbuf, 0xff, mtd->oobsize); -		if (mode == MTD_OOB_AUTO) +		if (mode == MTD_OPS_AUTO_OOB)  			onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen);  		else  			memcpy(oobbuf + column, buf, thislen); @@ -2217,10 +2217,10 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to,  	int ret;  	switch (ops->mode) { -	case MTD_OOB_PLACE: -	case MTD_OOB_AUTO: +	case MTD_OPS_PLACE_OOB: +	case MTD_OPS_AUTO_OOB:  		break; -	case MTD_OOB_RAW: +	case MTD_OPS_RAW:  		/* Not implemented yet */  	default:  		return -EINVAL; @@ -2281,7 +2281,7 @@ static int onenand_multiblock_erase_verify(struct mtd_info *mtd,  }  /** - * onenand_multiblock_erase - [Internal] erase block(s) using multiblock erase + * onenand_multiblock_erase - [INTERN] erase block(s) using multiblock erase   * @param mtd		MTD device structure   * @param instr		erase instruction   * @param region	erase region @@ -2397,7 +2397,7 @@ static int onenand_multiblock_erase(struct mtd_info *mtd,  /** - * onenand_block_by_block_erase - [Internal] erase block(s) using regular erase + * onenand_block_by_block_erase - [INTERN] erase block(s) using regular erase   * @param mtd		MTD device structure   * @param instr		erase instruction   * @param region	erase region @@ -2489,8 +2489,9 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)  	struct mtd_erase_region_info *region = NULL;  	loff_t region_offset = 0; -	DEBUG(MTD_DEBUG_LEVEL3, "%s: start=0x%012llx, len=%llu\n", __func__, -	      (unsigned long long) instr->addr, (unsigned long long) instr->len); +	pr_debug("%s: start=0x%012llx, len=%llu\n", __func__, +			(unsigned long long)instr->addr, +			(unsigned long long)instr->len);  	/* Do not allow erase past end of device */  	if (unlikely((len + addr) > mtd->size)) { @@ -2558,7 +2559,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)   */  static void onenand_sync(struct mtd_info *mtd)  { -	DEBUG(MTD_DEBUG_LEVEL3, "%s: called\n", __func__); +	pr_debug("%s: called\n", __func__);  	/* Grab the lock and see if the device is available */  	onenand_get_device(mtd, FL_SYNCING); @@ -2602,7 +2603,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)  	struct bbm_info *bbm = this->bbm;  	u_char buf[2] = {0, 0};  	struct mtd_oob_ops ops = { -		.mode = MTD_OOB_PLACE, +		.mode = MTD_OPS_PLACE_OOB,  		.ooblen = 2,  		.oobbuf = buf,  		.ooboffs = 0, @@ -2922,7 +2923,7 @@ static int onenand_otp_command(struct mtd_info *mtd, int cmd, loff_t addr,  }  /** - * onenand_otp_write_oob_nolock - [Internal] OneNAND write out-of-band, specific to OTP + * onenand_otp_write_oob_nolock - [INTERN] OneNAND write out-of-band, specific to OTP   * @param mtd		MTD device structure   * @param to		offset to write to   * @param len		number of bytes to write @@ -3170,7 +3171,7 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len,  		this->command(mtd, ONENAND_CMD_RESET, 0, 0);  		this->wait(mtd, FL_RESETING);  	} else { -		ops.mode = MTD_OOB_PLACE; +		ops.mode = MTD_OPS_PLACE_OOB;  		ops.ooblen = len;  		ops.oobbuf = buf;  		ops.ooboffs = 0; @@ -3429,6 +3430,19 @@ static void onenand_check_features(struct mtd_info *mtd)  		else if (numbufs == 1) {  			this->options |= ONENAND_HAS_4KB_PAGE;  			this->options |= ONENAND_HAS_CACHE_PROGRAM; +			/* +			 * There are two different 4KiB pagesize chips +			 * and no way to detect it by H/W config values. +			 * +			 * To detect the correct NOP for each chips, +			 * It should check the version ID as workaround. +			 * +			 * Now it has as following +			 * KFM4G16Q4M has NOP 4 with version ID 0x0131 +			 * KFM4G16Q5M has NOP 1 with versoin ID 0x013e +			 */ +			if ((this->version_id & 0xf) == 0xe) +				this->options |= ONENAND_HAS_NOP_1;  		}  	case ONENAND_DEVICE_DENSITY_2Gb: @@ -3663,7 +3677,7 @@ static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int  	int i, ret;  	int block;  	struct mtd_oob_ops ops = { -		.mode = MTD_OOB_PLACE, +		.mode = MTD_OPS_PLACE_OOB,  		.ooboffs = 0,  		.ooblen	= mtd->oobsize,  		.datbuf	= NULL, @@ -4054,6 +4068,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)  			this->ecclayout = &onenand_oob_128;  			mtd->subpage_sft = 2;  		} +		if (ONENAND_IS_NOP_1(this)) +			mtd->subpage_sft = 0;  		break;  	case 64:  		this->ecclayout = &onenand_oob_64; diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index b2d7fc5ea25d..66fe3b7e7851 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c @@ -81,7 +81,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr  	startblock = 0;  	from = 0; -	ops.mode = MTD_OOB_PLACE; +	ops.mode = MTD_OPS_PLACE_OOB;  	ops.ooblen = readlen;  	ops.oobbuf = buf;  	ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; @@ -154,7 +154,7 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)  	block = (int) (onenand_block(this, offs) << 1);  	res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03; -	DEBUG(MTD_DEBUG_LEVEL2, "onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n", +	pr_debug("onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n",  		(unsigned int) offs, block >> 1, res);  	switch ((int) res) { @@ -189,10 +189,8 @@ int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)  	len = this->chipsize >> (this->erase_shift + 2);  	/* Allocate memory (2bit per block) and clear the memory bad block table */  	bbm->bbt = kzalloc(len, GFP_KERNEL); -	if (!bbm->bbt) { -		printk(KERN_ERR "onenand_scan_bbt: Out of memory\n"); +	if (!bbm->bbt)  		return -ENOMEM; -	}  	/* Set the bad block position */  	bbm->badblockpos = ONENAND_BADBLOCK_POS; diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c index 3306b5b3c736..5474547eafc2 100644 --- a/drivers/mtd/onenand/samsung.c +++ b/drivers/mtd/onenand/samsung.c @@ -147,7 +147,6 @@ struct s3c_onenand {  	struct resource *dma_res;  	unsigned long	phys_base;  	struct completion	complete; -	struct mtd_partition *parts;  };  #define CMD_MAP_00(dev, addr)		(dev->cmd_map(MAP_00, ((addr) << 1))) @@ -157,8 +156,6 @@ struct s3c_onenand {  static struct s3c_onenand *onenand; -static const char *part_probes[] = { "cmdlinepart", NULL, }; -  static inline int s3c_read_reg(int offset)  {  	return readl(onenand->base + offset); @@ -1017,13 +1014,9 @@ static int s3c_onenand_probe(struct platform_device *pdev)  	if (s3c_read_reg(MEM_CFG_OFFSET) & ONENAND_SYS_CFG1_SYNC_READ)  		dev_info(&onenand->pdev->dev, "OneNAND Sync. Burst Read enabled\n"); -	err = parse_mtd_partitions(mtd, part_probes, &onenand->parts, 0); -	if (err > 0) -		mtd_device_register(mtd, onenand->parts, err); -	else if (err <= 0 && pdata && pdata->parts) -		mtd_device_register(mtd, pdata->parts, pdata->nr_parts); -	else -		err = mtd_device_register(mtd, NULL, 0); +	err = mtd_device_parse_register(mtd, NULL, 0, +					pdata ? pdata->parts : NULL, +					pdata ? pdata->nr_parts : 0);  	platform_set_drvdata(pdev, mtd); diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index 84b4dda023f4..e366b1d84ead 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c @@ -57,8 +57,8 @@ static inline int redboot_checksum(struct fis_image_desc *img)  }  static int parse_redboot_partitions(struct mtd_info *master, -                             struct mtd_partition **pparts, -                             unsigned long fis_origin) +				    struct mtd_partition **pparts, +				    struct mtd_part_parser_data *data)  {  	int nrparts = 0;  	struct fis_image_desc *buf; @@ -198,11 +198,10 @@ static int parse_redboot_partitions(struct mtd_info *master,  			goto out;  		}  		new_fl->img = &buf[i]; -                if (fis_origin) { -                        buf[i].flash_base -= fis_origin; -                } else { -                        buf[i].flash_base &= master->size-1; -                } +		if (data && data->origin) +			buf[i].flash_base -= data->origin; +		else +			buf[i].flash_base &= master->size-1;  		/* I'm sure the JFFS2 code has done me permanent damage.  		 * I now think the following is _normal_ @@ -298,6 +297,9 @@ static struct mtd_part_parser redboot_parser = {  	.name = "RedBoot",  }; +/* mtd parsers will request the module by parser name */ +MODULE_ALIAS("RedBoot"); +  static int __init redboot_parser_init(void)  {  	return register_mtd_parser(&redboot_parser); diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index ed3d6cd2c6dc..fddb714e323c 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -34,7 +34,7 @@ module_param(debug, int, S_IRUGO | S_IWUSR);  MODULE_PARM_DESC(debug, "Debug level (0-2)"); -/* ------------------- sysfs attributtes ---------------------------------- */ +/* ------------------- sysfs attributes ---------------------------------- */  struct sm_sysfs_attribute {  	struct device_attribute dev_attr;  	char *data; @@ -138,7 +138,7 @@ static int sm_get_lba(uint8_t *lba)  	if ((lba[0] & 0xF8) != 0x10)  		return -2; -	/* check parity - endianess doesn't matter */ +	/* check parity - endianness doesn't matter */  	if (hweight16(*(uint16_t *)lba) & 1)  		return -2; @@ -147,7 +147,7 @@ static int sm_get_lba(uint8_t *lba)  /* - * Read LBA asscociated with block + * Read LBA associated with block   * returns -1, if block is erased   * returns -2 if error happens   */ @@ -252,11 +252,11 @@ static int sm_read_sector(struct sm_ftl *ftl,  		return 0;  	} -	/* User might not need the oob, but we do for data vertification */ +	/* User might not need the oob, but we do for data verification */  	if (!oob)  		oob = &tmp_oob; -	ops.mode = ftl->smallpagenand ? MTD_OOB_RAW : MTD_OOB_PLACE; +	ops.mode = ftl->smallpagenand ? MTD_OPS_RAW : MTD_OPS_PLACE_OOB;  	ops.ooboffs = 0;  	ops.ooblen = SM_OOB_SIZE;  	ops.oobbuf = (void *)oob; @@ -276,12 +276,12 @@ again:  			return ret;  	} -	/* Unfortunelly, oob read will _always_ succeed, +	/* Unfortunately, oob read will _always_ succeed,  		despite card removal..... */  	ret = mtd->read_oob(mtd, sm_mkoffset(ftl, zone, block, boffset), &ops);  	/* Test for unknown errors */ -	if (ret != 0 && ret != -EUCLEAN && ret != -EBADMSG) { +	if (ret != 0 && !mtd_is_bitflip_or_eccerr(ret)) {  		dbg("read of block %d at zone %d, failed due to error (%d)",  			block, zone, ret);  		goto again; @@ -306,7 +306,7 @@ again:  	}  	/* Test ECC*/ -	if (ret == -EBADMSG || +	if (mtd_is_eccerr(ret) ||  		(ftl->smallpagenand && sm_correct_sector(buffer, oob))) {  		dbg("read of block %d at zone %d, failed due to ECC error", @@ -336,7 +336,7 @@ static int sm_write_sector(struct sm_ftl *ftl,  	if (ftl->unstable)  		return -EIO; -	ops.mode = ftl->smallpagenand ? MTD_OOB_RAW : MTD_OOB_PLACE; +	ops.mode = ftl->smallpagenand ? MTD_OPS_RAW : MTD_OPS_PLACE_OOB;  	ops.len = SM_SECTOR_SIZE;  	ops.datbuf = buffer;  	ops.ooboffs = 0; @@ -447,14 +447,14 @@ static void sm_mark_block_bad(struct sm_ftl *ftl, int zone, int block)  	/* We aren't checking the return value, because we don't care */  	/* This also fails on fake xD cards, but I guess these won't expose -		any bad blocks till fail completly */ +		any bad blocks till fail completely */  	for (boffset = 0; boffset < ftl->block_size; boffset += SM_SECTOR_SIZE)  		sm_write_sector(ftl, zone, block, boffset, NULL, &oob);  }  /*   * Erase a block within a zone - * If erase succedes, it updates free block fifo, otherwise marks block as bad + * If erase succeeds, it updates free block fifo, otherwise marks block as bad   */  static int sm_erase_block(struct sm_ftl *ftl, int zone_num, uint16_t block,  			  int put_free) @@ -510,7 +510,7 @@ static void sm_erase_callback(struct erase_info *self)  	complete(&ftl->erase_completion);  } -/* Throughtly test that block is valid. */ +/* Thoroughly test that block is valid. */  static int sm_check_block(struct sm_ftl *ftl, int zone, int block)  {  	int boffset; @@ -526,7 +526,7 @@ static int sm_check_block(struct sm_ftl *ftl, int zone, int block)  	for (boffset = 0; boffset < ftl->block_size;  					boffset += SM_SECTOR_SIZE) { -		/* This shoudn't happen anyway */ +		/* This shouldn't happen anyway */  		if (sm_read_sector(ftl, zone, block, boffset, NULL, &oob))  			return -2; diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c index 5cd189793332..976e3d28b962 100644 --- a/drivers/mtd/ssfdc.c +++ b/drivers/mtd/ssfdc.c @@ -135,8 +135,7 @@ static int get_valid_cis_sector(struct mtd_info *mtd)  				/* Found */  				cis_sector = (int)(offset >> SECTOR_SHIFT);  			} else { -				DEBUG(MTD_DEBUG_LEVEL1, -					"SSFDC_RO: CIS/IDI sector not found" +				pr_debug("SSFDC_RO: CIS/IDI sector not found"  					" on %s (mtd%d)\n", mtd->name,  					mtd->index);  			} @@ -170,7 +169,7 @@ static int read_raw_oob(struct mtd_info *mtd, loff_t offs, uint8_t *buf)  	struct mtd_oob_ops ops;  	int ret; -	ops.mode = MTD_OOB_RAW; +	ops.mode = MTD_OPS_RAW;  	ops.ooboffs = 0;  	ops.ooblen = OOB_SIZE;  	ops.oobbuf = buf; @@ -221,8 +220,7 @@ static int get_logical_address(uint8_t *oob_buf)  			block_address >>= 1;  			if (get_parity(block_address, 10) != parity) { -				DEBUG(MTD_DEBUG_LEVEL0, -					"SSFDC_RO: logical address field%d" +				pr_debug("SSFDC_RO: logical address field%d"  					"parity error(0x%04X)\n", j+1,  					block_address);  			} else { @@ -235,7 +233,7 @@ static int get_logical_address(uint8_t *oob_buf)  	if (!ok)  		block_address = -2; -	DEBUG(MTD_DEBUG_LEVEL3, "SSFDC_RO: get_logical_address() %d\n", +	pr_debug("SSFDC_RO: get_logical_address() %d\n",  		block_address);  	return block_address; @@ -249,7 +247,7 @@ static int build_logical_block_map(struct ssfdcr_record *ssfdc)  	int ret, block_address, phys_block;  	struct mtd_info *mtd = ssfdc->mbd.mtd; -	DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: build_block_map() nblks=%d (%luK)\n", +	pr_debug("SSFDC_RO: build_block_map() nblks=%d (%luK)\n",  	      ssfdc->map_len,  	      (unsigned long)ssfdc->map_len * ssfdc->erase_size / 1024); @@ -262,8 +260,7 @@ static int build_logical_block_map(struct ssfdcr_record *ssfdc)  		ret = read_raw_oob(mtd, offset, oob_buf);  		if (ret < 0) { -			DEBUG(MTD_DEBUG_LEVEL0, -				"SSFDC_RO: mtd read_oob() failed at %lu\n", +			pr_debug("SSFDC_RO: mtd read_oob() failed at %lu\n",  				offset);  			return -1;  		} @@ -279,8 +276,7 @@ static int build_logical_block_map(struct ssfdcr_record *ssfdc)  			ssfdc->logic_block_map[block_address] =  				(unsigned short)phys_block; -			DEBUG(MTD_DEBUG_LEVEL2, -				"SSFDC_RO: build_block_map() phys_block=%d," +			pr_debug("SSFDC_RO: build_block_map() phys_block=%d,"  				"logic_block_addr=%d, zone=%d\n",  				phys_block, block_address, zone_index);  		} @@ -304,11 +300,8 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)  		return;  	ssfdc = kzalloc(sizeof(struct ssfdcr_record), GFP_KERNEL); -	if (!ssfdc) { -		printk(KERN_WARNING -			"SSFDC_RO: out of memory for data structures\n"); +	if (!ssfdc)  		return; -	}  	ssfdc->mbd.mtd = mtd;  	ssfdc->mbd.devnum = -1; @@ -319,8 +312,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)  	ssfdc->erase_size = mtd->erasesize;  	ssfdc->map_len = (u32)mtd->size / mtd->erasesize; -	DEBUG(MTD_DEBUG_LEVEL1, -		"SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n", +	pr_debug("SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n",  		ssfdc->cis_block, ssfdc->erase_size, ssfdc->map_len,  		DIV_ROUND_UP(ssfdc->map_len, MAX_PHYS_BLK_PER_ZONE)); @@ -331,7 +323,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)  	ssfdc->cylinders = (unsigned short)(((u32)mtd->size >> SECTOR_SHIFT) /  			((long)ssfdc->sectors * (long)ssfdc->heads)); -	DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n", +	pr_debug("SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n",  		ssfdc->cylinders, ssfdc->heads , ssfdc->sectors,  		(long)ssfdc->cylinders * (long)ssfdc->heads *  		(long)ssfdc->sectors); @@ -342,11 +334,8 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)  	/* Allocate logical block map */  	ssfdc->logic_block_map = kmalloc(sizeof(ssfdc->logic_block_map[0]) *  					 ssfdc->map_len, GFP_KERNEL); -	if (!ssfdc->logic_block_map) { -		printk(KERN_WARNING -			"SSFDC_RO: out of memory for data structures\n"); +	if (!ssfdc->logic_block_map)  		goto out_err; -	}  	memset(ssfdc->logic_block_map, 0xff, sizeof(ssfdc->logic_block_map[0]) *  		ssfdc->map_len); @@ -371,7 +360,7 @@ static void ssfdcr_remove_dev(struct mtd_blktrans_dev *dev)  {  	struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev; -	DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: remove_dev (i=%d)\n", dev->devnum); +	pr_debug("SSFDC_RO: remove_dev (i=%d)\n", dev->devnum);  	del_mtd_blktrans_dev(dev);  	kfree(ssfdc->logic_block_map); @@ -387,8 +376,7 @@ static int ssfdcr_readsect(struct mtd_blktrans_dev *dev,  	offset = (int)(logic_sect_no % sectors_per_block);  	block_address = (int)(logic_sect_no / sectors_per_block); -	DEBUG(MTD_DEBUG_LEVEL3, -		"SSFDC_RO: ssfdcr_readsect(%lu) sec_per_blk=%d, ofst=%d," +	pr_debug("SSFDC_RO: ssfdcr_readsect(%lu) sec_per_blk=%d, ofst=%d,"  		" block_addr=%d\n", logic_sect_no, sectors_per_block, offset,  		block_address); @@ -397,8 +385,7 @@ static int ssfdcr_readsect(struct mtd_blktrans_dev *dev,  	block_address = ssfdc->logic_block_map[block_address]; -	DEBUG(MTD_DEBUG_LEVEL3, -		"SSFDC_RO: ssfdcr_readsect() phys_block_addr=%d\n", +	pr_debug("SSFDC_RO: ssfdcr_readsect() phys_block_addr=%d\n",  		block_address);  	if (block_address < 0xffff) { @@ -407,8 +394,7 @@ static int ssfdcr_readsect(struct mtd_blktrans_dev *dev,  		sect_no = (unsigned long)block_address * sectors_per_block +  				offset; -		DEBUG(MTD_DEBUG_LEVEL3, -			"SSFDC_RO: ssfdcr_readsect() phys_sect_no=%lu\n", +		pr_debug("SSFDC_RO: ssfdcr_readsect() phys_sect_no=%lu\n",  			sect_no);  		if (read_physical_sector(ssfdc->mbd.mtd, buf, sect_no) < 0) @@ -424,7 +410,7 @@ static int ssfdcr_getgeo(struct mtd_blktrans_dev *dev,  struct hd_geometry *geo)  {  	struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev; -	DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: ssfdcr_getgeo() C=%d, H=%d, S=%d\n", +	pr_debug("SSFDC_RO: ssfdcr_getgeo() C=%d, H=%d, S=%d\n",  			ssfdc->cylinders, ssfdc->heads, ssfdc->sectors);  	geo->heads = ssfdc->heads; diff --git a/drivers/mtd/tests/mtd_oobtest.c b/drivers/mtd/tests/mtd_oobtest.c index dec92ae6111a..933f7e5f32d3 100644 --- a/drivers/mtd/tests/mtd_oobtest.c +++ b/drivers/mtd/tests/mtd_oobtest.c @@ -30,7 +30,7 @@  #define PRINT_PREF KERN_INFO "mtd_oobtest: " -static int dev; +static int dev = -EINVAL;  module_param(dev, int, S_IRUGO);  MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -131,7 +131,7 @@ static int write_eraseblock(int ebnum)  	for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {  		set_random_data(writebuf, use_len); -		ops.mode      = MTD_OOB_AUTO; +		ops.mode      = MTD_OPS_AUTO_OOB;  		ops.len       = 0;  		ops.retlen    = 0;  		ops.ooblen    = use_len; @@ -184,7 +184,7 @@ static int verify_eraseblock(int ebnum)  	for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {  		set_random_data(writebuf, use_len); -		ops.mode      = MTD_OOB_AUTO; +		ops.mode      = MTD_OPS_AUTO_OOB;  		ops.len       = 0;  		ops.retlen    = 0;  		ops.ooblen    = use_len; @@ -211,7 +211,7 @@ static int verify_eraseblock(int ebnum)  		if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) {  			int k; -			ops.mode      = MTD_OOB_AUTO; +			ops.mode      = MTD_OPS_AUTO_OOB;  			ops.len       = 0;  			ops.retlen    = 0;  			ops.ooblen    = mtd->ecclayout->oobavail; @@ -276,7 +276,7 @@ static int verify_eraseblock_in_one_go(int ebnum)  	size_t len = mtd->ecclayout->oobavail * pgcnt;  	set_random_data(writebuf, len); -	ops.mode      = MTD_OOB_AUTO; +	ops.mode      = MTD_OPS_AUTO_OOB;  	ops.len       = 0;  	ops.retlen    = 0;  	ops.ooblen    = len; @@ -366,6 +366,13 @@ static int __init mtd_oobtest_init(void)  	printk(KERN_INFO "\n");  	printk(KERN_INFO "=================================================\n"); + +	if (dev < 0) { +		printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); +		printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); +		return -EINVAL; +	} +  	printk(PRINT_PREF "MTD device: %d\n", dev);  	mtd = get_mtd_device(NULL, dev); @@ -507,7 +514,7 @@ static int __init mtd_oobtest_init(void)  		addr0 += mtd->erasesize;  	/* Attempt to write off end of OOB */ -	ops.mode      = MTD_OOB_AUTO; +	ops.mode      = MTD_OPS_AUTO_OOB;  	ops.len       = 0;  	ops.retlen    = 0;  	ops.ooblen    = 1; @@ -527,7 +534,7 @@ static int __init mtd_oobtest_init(void)  	}  	/* Attempt to read off end of OOB */ -	ops.mode      = MTD_OOB_AUTO; +	ops.mode      = MTD_OPS_AUTO_OOB;  	ops.len       = 0;  	ops.retlen    = 0;  	ops.ooblen    = 1; @@ -551,7 +558,7 @@ static int __init mtd_oobtest_init(void)  		       "block is bad\n");  	else {  		/* Attempt to write off end of device */ -		ops.mode      = MTD_OOB_AUTO; +		ops.mode      = MTD_OPS_AUTO_OOB;  		ops.len       = 0;  		ops.retlen    = 0;  		ops.ooblen    = mtd->ecclayout->oobavail + 1; @@ -571,7 +578,7 @@ static int __init mtd_oobtest_init(void)  		}  		/* Attempt to read off end of device */ -		ops.mode      = MTD_OOB_AUTO; +		ops.mode      = MTD_OPS_AUTO_OOB;  		ops.len       = 0;  		ops.retlen    = 0;  		ops.ooblen    = mtd->ecclayout->oobavail + 1; @@ -595,7 +602,7 @@ static int __init mtd_oobtest_init(void)  			goto out;  		/* Attempt to write off end of device */ -		ops.mode      = MTD_OOB_AUTO; +		ops.mode      = MTD_OPS_AUTO_OOB;  		ops.len       = 0;  		ops.retlen    = 0;  		ops.ooblen    = mtd->ecclayout->oobavail; @@ -615,7 +622,7 @@ static int __init mtd_oobtest_init(void)  		}  		/* Attempt to read off end of device */ -		ops.mode      = MTD_OOB_AUTO; +		ops.mode      = MTD_OPS_AUTO_OOB;  		ops.len       = 0;  		ops.retlen    = 0;  		ops.ooblen    = mtd->ecclayout->oobavail; @@ -655,7 +662,7 @@ static int __init mtd_oobtest_init(void)  		addr = (i + 1) * mtd->erasesize - mtd->writesize;  		for (pg = 0; pg < cnt; ++pg) {  			set_random_data(writebuf, sz); -			ops.mode      = MTD_OOB_AUTO; +			ops.mode      = MTD_OPS_AUTO_OOB;  			ops.len       = 0;  			ops.retlen    = 0;  			ops.ooblen    = sz; @@ -683,7 +690,7 @@ static int __init mtd_oobtest_init(void)  			continue;  		set_random_data(writebuf, mtd->ecclayout->oobavail * 2);  		addr = (i + 1) * mtd->erasesize - mtd->writesize; -		ops.mode      = MTD_OOB_AUTO; +		ops.mode      = MTD_OPS_AUTO_OOB;  		ops.len       = 0;  		ops.retlen    = 0;  		ops.ooblen    = mtd->ecclayout->oobavail * 2; diff --git a/drivers/mtd/tests/mtd_pagetest.c b/drivers/mtd/tests/mtd_pagetest.c index 00b937e38c1d..afafb6935fd0 100644 --- a/drivers/mtd/tests/mtd_pagetest.c +++ b/drivers/mtd/tests/mtd_pagetest.c @@ -30,7 +30,7 @@  #define PRINT_PREF KERN_INFO "mtd_pagetest: " -static int dev; +static int dev = -EINVAL;  module_param(dev, int, S_IRUGO);  MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -128,7 +128,7 @@ static int verify_eraseblock(int ebnum)  	for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) {  		/* Do a read to set the internal dataRAMs to different data */  		err = mtd->read(mtd, addr0, bufsize, &read, twopages); -		if (err == -EUCLEAN) +		if (mtd_is_bitflip(err))  			err = 0;  		if (err || read != bufsize) {  			printk(PRINT_PREF "error: read failed at %#llx\n", @@ -136,7 +136,7 @@ static int verify_eraseblock(int ebnum)  			return err;  		}  		err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages); -		if (err == -EUCLEAN) +		if (mtd_is_bitflip(err))  			err = 0;  		if (err || read != bufsize) {  			printk(PRINT_PREF "error: read failed at %#llx\n", @@ -146,7 +146,7 @@ static int verify_eraseblock(int ebnum)  		memset(twopages, 0, bufsize);  		read = 0;  		err = mtd->read(mtd, addr, bufsize, &read, twopages); -		if (err == -EUCLEAN) +		if (mtd_is_bitflip(err))  			err = 0;  		if (err || read != bufsize) {  			printk(PRINT_PREF "error: read failed at %#llx\n", @@ -164,7 +164,7 @@ static int verify_eraseblock(int ebnum)  		unsigned long oldnext = next;  		/* Do a read to set the internal dataRAMs to different data */  		err = mtd->read(mtd, addr0, bufsize, &read, twopages); -		if (err == -EUCLEAN) +		if (mtd_is_bitflip(err))  			err = 0;  		if (err || read != bufsize) {  			printk(PRINT_PREF "error: read failed at %#llx\n", @@ -172,7 +172,7 @@ static int verify_eraseblock(int ebnum)  			return err;  		}  		err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages); -		if (err == -EUCLEAN) +		if (mtd_is_bitflip(err))  			err = 0;  		if (err || read != bufsize) {  			printk(PRINT_PREF "error: read failed at %#llx\n", @@ -182,7 +182,7 @@ static int verify_eraseblock(int ebnum)  		memset(twopages, 0, bufsize);  		read = 0;  		err = mtd->read(mtd, addr, bufsize, &read, twopages); -		if (err == -EUCLEAN) +		if (mtd_is_bitflip(err))  			err = 0;  		if (err || read != bufsize) {  			printk(PRINT_PREF "error: read failed at %#llx\n", @@ -231,7 +231,7 @@ static int crosstest(void)  	read = 0;  	addr = addrn - pgsize - pgsize;  	err = mtd->read(mtd, addr, pgsize, &read, pp1); -	if (err == -EUCLEAN) +	if (mtd_is_bitflip(err))  		err = 0;  	if (err || read != pgsize) {  		printk(PRINT_PREF "error: read failed at %#llx\n", @@ -244,7 +244,7 @@ static int crosstest(void)  	read = 0;  	addr = addrn - pgsize - pgsize - pgsize;  	err = mtd->read(mtd, addr, pgsize, &read, pp1); -	if (err == -EUCLEAN) +	if (mtd_is_bitflip(err))  		err = 0;  	if (err || read != pgsize) {  		printk(PRINT_PREF "error: read failed at %#llx\n", @@ -258,7 +258,7 @@ static int crosstest(void)  	addr = addr0;  	printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);  	err = mtd->read(mtd, addr, pgsize, &read, pp2); -	if (err == -EUCLEAN) +	if (mtd_is_bitflip(err))  		err = 0;  	if (err || read != pgsize) {  		printk(PRINT_PREF "error: read failed at %#llx\n", @@ -272,7 +272,7 @@ static int crosstest(void)  	addr = addrn - pgsize;  	printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);  	err = mtd->read(mtd, addr, pgsize, &read, pp3); -	if (err == -EUCLEAN) +	if (mtd_is_bitflip(err))  		err = 0;  	if (err || read != pgsize) {  		printk(PRINT_PREF "error: read failed at %#llx\n", @@ -286,7 +286,7 @@ static int crosstest(void)  	addr = addr0;  	printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);  	err = mtd->read(mtd, addr, pgsize, &read, pp4); -	if (err == -EUCLEAN) +	if (mtd_is_bitflip(err))  		err = 0;  	if (err || read != pgsize) {  		printk(PRINT_PREF "error: read failed at %#llx\n", @@ -345,7 +345,7 @@ static int erasecrosstest(void)  	printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);  	memset(readbuf, 0, pgsize);  	err = mtd->read(mtd, addr0, pgsize, &read, readbuf); -	if (err == -EUCLEAN) +	if (mtd_is_bitflip(err))  		err = 0;  	if (err || read != pgsize) {  		printk(PRINT_PREF "error: read failed at %#llx\n", @@ -383,7 +383,7 @@ static int erasecrosstest(void)  	printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);  	memset(readbuf, 0, pgsize);  	err = mtd->read(mtd, addr0, pgsize, &read, readbuf); -	if (err == -EUCLEAN) +	if (mtd_is_bitflip(err))  		err = 0;  	if (err || read != pgsize) {  		printk(PRINT_PREF "error: read failed at %#llx\n", @@ -439,7 +439,7 @@ static int erasetest(void)  	printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);  	err = mtd->read(mtd, addr0, pgsize, &read, twopages); -	if (err == -EUCLEAN) +	if (mtd_is_bitflip(err))  		err = 0;  	if (err || read != pgsize) {  		printk(PRINT_PREF "error: read failed at %#llx\n", @@ -504,6 +504,13 @@ static int __init mtd_pagetest_init(void)  	printk(KERN_INFO "\n");  	printk(KERN_INFO "=================================================\n"); + +	if (dev < 0) { +		printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); +		printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); +		return -EINVAL; +	} +  	printk(PRINT_PREF "MTD device: %d\n", dev);  	mtd = get_mtd_device(NULL, dev); diff --git a/drivers/mtd/tests/mtd_readtest.c b/drivers/mtd/tests/mtd_readtest.c index afe71aa15c4b..550fe51225a7 100644 --- a/drivers/mtd/tests/mtd_readtest.c +++ b/drivers/mtd/tests/mtd_readtest.c @@ -29,7 +29,7 @@  #define PRINT_PREF KERN_INFO "mtd_readtest: " -static int dev; +static int dev = -EINVAL;  module_param(dev, int, S_IRUGO);  MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -66,7 +66,7 @@ static int read_eraseblock_by_page(int ebnum)  		if (mtd->oobsize) {  			struct mtd_oob_ops ops; -			ops.mode      = MTD_OOB_PLACE; +			ops.mode      = MTD_OPS_PLACE_OOB;  			ops.len       = 0;  			ops.retlen    = 0;  			ops.ooblen    = mtd->oobsize; @@ -75,7 +75,8 @@ static int read_eraseblock_by_page(int ebnum)  			ops.datbuf    = NULL;  			ops.oobbuf    = oobbuf;  			ret = mtd->read_oob(mtd, addr, &ops); -			if (ret || ops.oobretlen != mtd->oobsize) { +			if ((ret && !mtd_is_bitflip(ret)) || +					ops.oobretlen != mtd->oobsize) {  				printk(PRINT_PREF "error: read oob failed at "  						  "%#llx\n", (long long)addr);  				if (!err) @@ -169,6 +170,12 @@ static int __init mtd_readtest_init(void)  	printk(KERN_INFO "\n");  	printk(KERN_INFO "=================================================\n"); + +	if (dev < 0) { +		printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); +		return -EINVAL; +	} +  	printk(PRINT_PREF "MTD device: %d\n", dev);  	mtd = get_mtd_device(NULL, dev); diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c index 627d4e2466a3..493b367bdd35 100644 --- a/drivers/mtd/tests/mtd_speedtest.c +++ b/drivers/mtd/tests/mtd_speedtest.c @@ -29,7 +29,7 @@  #define PRINT_PREF KERN_INFO "mtd_speedtest: " -static int dev; +static int dev = -EINVAL;  module_param(dev, int, S_IRUGO);  MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -216,7 +216,7 @@ static int read_eraseblock(int ebnum)  	err = mtd->read(mtd, addr, mtd->erasesize, &read, iobuf);  	/* Ignore corrected ECC errors */ -	if (err == -EUCLEAN) +	if (mtd_is_bitflip(err))  		err = 0;  	if (err || read != mtd->erasesize) {  		printk(PRINT_PREF "error: read failed at %#llx\n", addr); @@ -237,7 +237,7 @@ static int read_eraseblock_by_page(int ebnum)  	for (i = 0; i < pgcnt; i++) {  		err = mtd->read(mtd, addr, pgsize, &read, buf);  		/* Ignore corrected ECC errors */ -		if (err == -EUCLEAN) +		if (mtd_is_bitflip(err))  			err = 0;  		if (err || read != pgsize) {  			printk(PRINT_PREF "error: read failed at %#llx\n", @@ -263,7 +263,7 @@ static int read_eraseblock_by_2pages(int ebnum)  	for (i = 0; i < n; i++) {  		err = mtd->read(mtd, addr, sz, &read, buf);  		/* Ignore corrected ECC errors */ -		if (err == -EUCLEAN) +		if (mtd_is_bitflip(err))  			err = 0;  		if (err || read != sz) {  			printk(PRINT_PREF "error: read failed at %#llx\n", @@ -278,7 +278,7 @@ static int read_eraseblock_by_2pages(int ebnum)  	if (pgcnt % 2) {  		err = mtd->read(mtd, addr, pgsize, &read, buf);  		/* Ignore corrected ECC errors */ -		if (err == -EUCLEAN) +		if (mtd_is_bitflip(err))  			err = 0;  		if (err || read != pgsize) {  			printk(PRINT_PREF "error: read failed at %#llx\n", @@ -361,6 +361,13 @@ static int __init mtd_speedtest_init(void)  	printk(KERN_INFO "\n");  	printk(KERN_INFO "=================================================\n"); + +	if (dev < 0) { +		printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); +		printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); +		return -EINVAL; +	} +  	if (count)  		printk(PRINT_PREF "MTD device: %d    count: %d\n", dev, count);  	else diff --git a/drivers/mtd/tests/mtd_stresstest.c b/drivers/mtd/tests/mtd_stresstest.c index 531625fc9259..52ffd9120e0d 100644 --- a/drivers/mtd/tests/mtd_stresstest.c +++ b/drivers/mtd/tests/mtd_stresstest.c @@ -30,7 +30,7 @@  #define PRINT_PREF KERN_INFO "mtd_stresstest: " -static int dev; +static int dev = -EINVAL;  module_param(dev, int, S_IRUGO);  MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -154,7 +154,7 @@ static int do_read(void)  	}  	addr = eb * mtd->erasesize + offs;  	err = mtd->read(mtd, addr, len, &read, readbuf); -	if (err == -EUCLEAN) +	if (mtd_is_bitflip(err))  		err = 0;  	if (unlikely(err || read != len)) {  		printk(PRINT_PREF "error: read failed at 0x%llx\n", @@ -250,6 +250,13 @@ static int __init mtd_stresstest_init(void)  	printk(KERN_INFO "\n");  	printk(KERN_INFO "=================================================\n"); + +	if (dev < 0) { +		printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); +		printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); +		return -EINVAL; +	} +  	printk(PRINT_PREF "MTD device: %d\n", dev);  	mtd = get_mtd_device(NULL, dev); diff --git a/drivers/mtd/tests/mtd_subpagetest.c b/drivers/mtd/tests/mtd_subpagetest.c index 334eae53a3db..1a05bfac4eee 100644 --- a/drivers/mtd/tests/mtd_subpagetest.c +++ b/drivers/mtd/tests/mtd_subpagetest.c @@ -29,7 +29,7 @@  #define PRINT_PREF KERN_INFO "mtd_subpagetest: " -static int dev; +static int dev = -EINVAL;  module_param(dev, int, S_IRUGO);  MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -198,7 +198,7 @@ static int verify_eraseblock(int ebnum)  	read = 0;  	err = mtd->read(mtd, addr, subpgsize, &read, readbuf);  	if (unlikely(err || read != subpgsize)) { -		if (err == -EUCLEAN && read == subpgsize) { +		if (mtd_is_bitflip(err) && read == subpgsize) {  			printk(PRINT_PREF "ECC correction at %#llx\n",  			       (long long)addr);  			err = 0; @@ -226,7 +226,7 @@ static int verify_eraseblock(int ebnum)  	read = 0;  	err = mtd->read(mtd, addr, subpgsize, &read, readbuf);  	if (unlikely(err || read != subpgsize)) { -		if (err == -EUCLEAN && read == subpgsize) { +		if (mtd_is_bitflip(err) && read == subpgsize) {  			printk(PRINT_PREF "ECC correction at %#llx\n",  			       (long long)addr);  			err = 0; @@ -264,7 +264,7 @@ static int verify_eraseblock2(int ebnum)  		read = 0;  		err = mtd->read(mtd, addr, subpgsize * k, &read, readbuf);  		if (unlikely(err || read != subpgsize * k)) { -			if (err == -EUCLEAN && read == subpgsize * k) { +			if (mtd_is_bitflip(err) && read == subpgsize * k) {  				printk(PRINT_PREF "ECC correction at %#llx\n",  				       (long long)addr);  				err = 0; @@ -298,7 +298,7 @@ static int verify_eraseblock_ff(int ebnum)  		read = 0;  		err = mtd->read(mtd, addr, subpgsize, &read, readbuf);  		if (unlikely(err || read != subpgsize)) { -			if (err == -EUCLEAN && read == subpgsize) { +			if (mtd_is_bitflip(err) && read == subpgsize) {  				printk(PRINT_PREF "ECC correction at %#llx\n",  				       (long long)addr);  				err = 0; @@ -379,6 +379,13 @@ static int __init mtd_subpagetest_init(void)  	printk(KERN_INFO "\n");  	printk(KERN_INFO "=================================================\n"); + +	if (dev < 0) { +		printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); +		printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); +		return -EINVAL; +	} +  	printk(PRINT_PREF "MTD device: %d\n", dev);  	mtd = get_mtd_device(NULL, dev); diff --git a/drivers/mtd/tests/mtd_torturetest.c b/drivers/mtd/tests/mtd_torturetest.c index 5c6c3d248901..03ab649a6964 100644 --- a/drivers/mtd/tests/mtd_torturetest.c +++ b/drivers/mtd/tests/mtd_torturetest.c @@ -46,7 +46,7 @@ static int pgcnt;  module_param(pgcnt, int, S_IRUGO);  MODULE_PARM_DESC(pgcnt, "number of pages per eraseblock to torture (0 => all)"); -static int dev; +static int dev = -EINVAL;  module_param(dev, int, S_IRUGO);  MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -138,7 +138,7 @@ static inline int check_eraseblock(int ebnum, unsigned char *buf)  retry:  	err = mtd->read(mtd, addr, len, &read, check_buf); -	if (err == -EUCLEAN) +	if (mtd_is_bitflip(err))  		printk(PRINT_PREF "single bit flip occurred at EB %d "  		       "MTD reported that it was fixed.\n", ebnum);  	else if (err) { @@ -213,6 +213,13 @@ static int __init tort_init(void)  	printk(KERN_INFO "=================================================\n");  	printk(PRINT_PREF "Warning: this program is trying to wear out your "  	       "flash, stop it if this is not wanted.\n"); + +	if (dev < 0) { +		printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); +		printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); +		return -EINVAL; +	} +  	printk(PRINT_PREF "MTD device: %d\n", dev);  	printk(PRINT_PREF "torture %d eraseblocks (%d-%d) of mtd%d\n",  	       ebcnt, eb, eb + ebcnt - 1, dev); diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 4be671815014..fb7f19b62d91 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -443,7 +443,7 @@ retry:  		if (err == UBI_IO_BITFLIPS) {  			scrub = 1;  			err = 0; -		} else if (err == -EBADMSG) { +		} else if (mtd_is_eccerr(err)) {  			if (vol->vol_type == UBI_DYNAMIC_VOLUME)  				goto out_unlock;  			scrub = 1; diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 6ba55c235873..f20b6f22f240 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -172,9 +172,9 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,  retry:  	err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);  	if (err) { -		const char *errstr = (err == -EBADMSG) ? " (ECC error)" : ""; +		const char *errstr = mtd_is_eccerr(err) ? " (ECC error)" : ""; -		if (err == -EUCLEAN) { +		if (mtd_is_bitflip(err)) {  			/*  			 * -EUCLEAN is reported if there was a bit-flip which  			 * was corrected, so this is harmless. @@ -205,7 +205,7 @@ retry:  		 * all the requested data. But some buggy drivers might do  		 * this, so we change it to -EIO.  		 */ -		if (read != len && err == -EBADMSG) { +		if (read != len && mtd_is_eccerr(err)) {  			ubi_assert(0);  			err = -EIO;  		} @@ -469,7 +469,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum)  out:  	mutex_unlock(&ubi->buf_mutex); -	if (err == UBI_IO_BITFLIPS || err == -EBADMSG) { +	if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) {  		/*  		 * If a bit-flip or data integrity error was detected, the test  		 * has not passed because it happened on a freshly erased @@ -760,7 +760,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,  	read_err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE);  	if (read_err) { -		if (read_err != UBI_IO_BITFLIPS && read_err != -EBADMSG) +		if (read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err))  			return read_err;  		/* @@ -776,7 +776,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,  	magic = be32_to_cpu(ec_hdr->magic);  	if (magic != UBI_EC_HDR_MAGIC) { -		if (read_err == -EBADMSG) +		if (mtd_is_eccerr(read_err))  			return UBI_IO_BAD_HDR_EBADMSG;  		/* @@ -1032,12 +1032,12 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,  	p = (char *)vid_hdr - ubi->vid_hdr_shift;  	read_err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,  			  ubi->vid_hdr_alsize); -	if (read_err && read_err != UBI_IO_BITFLIPS && read_err != -EBADMSG) +	if (read_err && read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err))  		return read_err;  	magic = be32_to_cpu(vid_hdr->magic);  	if (magic != UBI_VID_HDR_MAGIC) { -		if (read_err == -EBADMSG) +		if (mtd_is_eccerr(read_err))  			return UBI_IO_BAD_HDR_EBADMSG;  		if (ubi_check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) { @@ -1219,7 +1219,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)  		return -ENOMEM;  	err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE); -	if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG) +	if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err))  		goto exit;  	crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); @@ -1306,7 +1306,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)  	p = (char *)vid_hdr - ubi->vid_hdr_shift;  	err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,  			  ubi->vid_hdr_alsize); -	if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG) +	if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err))  		goto exit;  	crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC); @@ -1358,7 +1358,7 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,  	}  	err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf1); -	if (err && err != -EUCLEAN) +	if (err && !mtd_is_bitflip(err))  		goto out_free;  	for (i = 0; i < len; i++) { @@ -1422,7 +1422,7 @@ int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)  	}  	err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); -	if (err && err != -EUCLEAN) { +	if (err && !mtd_is_bitflip(err)) {  		ubi_err("error %d while reading %d bytes from PEB %d:%d, "  			"read %zd bytes", err, len, pnum, offset, read);  		goto error; diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index d39716e5b204..1a35fc5e3b40 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -410,7 +410,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,  		return 0;  	err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check); -	if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) { +	if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) {  		ubi_warn("mark volume %d as corrupted", vol_id);  		vol->corrupted = 1;  	} diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c index ff2a65c37f69..f6a7d7ac4b98 100644 --- a/drivers/mtd/ubi/misc.c +++ b/drivers/mtd/ubi/misc.c @@ -81,7 +81,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)  		err = ubi_eba_read_leb(ubi, vol, i, buf, 0, size, 1);  		if (err) { -			if (err == -EBADMSG) +			if (mtd_is_eccerr(err))  				err = 1;  			break;  		} diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index a3a198f9b98d..0cb17d936b5a 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -395,7 +395,7 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,  	}  	err = ubi_io_read_data(ubi, buf, pnum, 0, len); -	if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG) +	if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err))  		goto out_free_buf;  	data_crc = be32_to_cpu(vid_hdr->data_crc); @@ -793,7 +793,7 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,  	err = ubi_io_read(ubi, ubi->peb_buf1, pnum, ubi->leb_start,  			  ubi->leb_size); -	if (err == UBI_IO_BITFLIPS || err == -EBADMSG) { +	if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) {  		/*  		 * Bit-flips or integrity errors while reading the data area.  		 * It is difficult to say for sure what type of corruption is diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 4b50a3029b84..9ad18da1891d 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -423,7 +423,7 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,  		err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,  				       ubi->vtbl_size); -		if (err == UBI_IO_BITFLIPS || err == -EBADMSG) +		if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err))  			/*  			 * Scrub the PEB later. Note, -EBADMSG indicates an  			 * uncorrectable ECC error, but we have our own CRC and diff --git a/drivers/staging/spectra/lld_mtd.c b/drivers/staging/spectra/lld_mtd.c index 2bd34662beb5..a9c309a167c2 100644 --- a/drivers/staging/spectra/lld_mtd.c +++ b/drivers/staging/spectra/lld_mtd.c @@ -340,7 +340,7 @@ u16 mtd_Read_Page_Main_Spare(u8 *read_data, u32 Block,  		struct mtd_oob_ops ops;  		int ret; -		ops.mode = MTD_OOB_AUTO; +		ops.mode = MTD_OPS_AUTO_OOB;  		ops.datbuf = read_data;  		ops.len = DeviceInfo.wPageDataSize;  		ops.oobbuf = read_data + DeviceInfo.wPageDataSize + BTSIG_OFFSET; @@ -400,7 +400,7 @@ u16 mtd_Write_Page_Main_Spare(u8 *write_data, u32 Block,  		struct mtd_oob_ops ops;  		int ret; -		ops.mode = MTD_OOB_AUTO; +		ops.mode = MTD_OPS_AUTO_OOB;  		ops.datbuf = write_data;  		ops.len = DeviceInfo.wPageDataSize;  		ops.oobbuf = write_data + DeviceInfo.wPageDataSize + BTSIG_OFFSET; @@ -473,7 +473,7 @@ u16 mtd_Read_Page_Spare(u8 *read_data, u32 Block,  		struct mtd_oob_ops ops;  		int ret; -		ops.mode = MTD_OOB_AUTO; +		ops.mode = MTD_OPS_AUTO_OOB;  		ops.datbuf = NULL;  		ops.len = 0;  		ops.oobbuf = read_data; diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index de4247021d25..5b6c9d1a2fb9 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c @@ -53,6 +53,78 @@ static int jffs2_is_best_compression(struct jffs2_compressor *this,  	return 0;  } +/* + * jffs2_selected_compress: + * @compr: Explicit compression type to use (ie, JFFS2_COMPR_ZLIB). + *	If 0, just take the first available compression mode. + * @data_in: Pointer to uncompressed data + * @cpage_out: Pointer to returned pointer to buffer for compressed data + * @datalen: On entry, holds the amount of data available for compression. + *	On exit, expected to hold the amount of data actually compressed. + * @cdatalen: On entry, holds the amount of space available for compressed + *	data. On exit, expected to hold the actual size of the compressed + *	data. + * + * Returns: the compression type used.  Zero is used to show that the data + * could not be compressed; probably because we couldn't find the requested + * compression mode. + */ +static int jffs2_selected_compress(u8 compr, unsigned char *data_in, +		unsigned char **cpage_out, u32 *datalen, u32 *cdatalen) +{ +	struct jffs2_compressor *this; +	int err, ret = JFFS2_COMPR_NONE; +	uint32_t orig_slen, orig_dlen; +	char *output_buf; + +	output_buf = kmalloc(*cdatalen, GFP_KERNEL); +	if (!output_buf) { +		printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n"); +		return ret; +	} +	orig_slen = *datalen; +	orig_dlen = *cdatalen; +	spin_lock(&jffs2_compressor_list_lock); +	list_for_each_entry(this, &jffs2_compressor_list, list) { +		/* Skip decompress-only and disabled modules */ +		if (!this->compress || this->disabled) +			continue; + +		/* Skip if not the desired compression type */ +		if (compr && (compr != this->compr)) +			continue; + +		/* +		 * Either compression type was unspecified, or we found our +		 * compressor; either way, we're good to go. +		 */ +		this->usecount++; +		spin_unlock(&jffs2_compressor_list_lock); + +		*datalen  = orig_slen; +		*cdatalen = orig_dlen; +		err = this->compress(data_in, output_buf, datalen, cdatalen); + +		spin_lock(&jffs2_compressor_list_lock); +		this->usecount--; +		if (!err) { +			/* Success */ +			ret = this->compr; +			this->stat_compr_blocks++; +			this->stat_compr_orig_size += *datalen; +			this->stat_compr_new_size += *cdatalen; +			break; +		} +	} +	spin_unlock(&jffs2_compressor_list_lock); +	if (ret == JFFS2_COMPR_NONE) +		kfree(output_buf); +	else +		*cpage_out = output_buf; + +	return ret; +} +  /* jffs2_compress:   * @data_in: Pointer to uncompressed data   * @cpage_out: Pointer to returned pointer to buffer for compressed data @@ -76,47 +148,23 @@ uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,  			uint32_t *datalen, uint32_t *cdatalen)  {  	int ret = JFFS2_COMPR_NONE; -	int compr_ret; +	int mode, compr_ret;  	struct jffs2_compressor *this, *best=NULL;  	unsigned char *output_buf = NULL, *tmp_buf;  	uint32_t orig_slen, orig_dlen;  	uint32_t best_slen=0, best_dlen=0; -	switch (jffs2_compression_mode) { +	if (c->mount_opts.override_compr) +		mode = c->mount_opts.compr; +	else +		mode = jffs2_compression_mode; + +	switch (mode) {  	case JFFS2_COMPR_MODE_NONE:  		break;  	case JFFS2_COMPR_MODE_PRIORITY: -		output_buf = kmalloc(*cdatalen,GFP_KERNEL); -		if (!output_buf) { -			printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n"); -			goto out; -		} -		orig_slen = *datalen; -		orig_dlen = *cdatalen; -		spin_lock(&jffs2_compressor_list_lock); -		list_for_each_entry(this, &jffs2_compressor_list, list) { -			/* Skip decompress-only backwards-compatibility and disabled modules */ -			if ((!this->compress)||(this->disabled)) -				continue; - -			this->usecount++; -			spin_unlock(&jffs2_compressor_list_lock); -			*datalen  = orig_slen; -			*cdatalen = orig_dlen; -			compr_ret = this->compress(data_in, output_buf, datalen, cdatalen); -			spin_lock(&jffs2_compressor_list_lock); -			this->usecount--; -			if (!compr_ret) { -				ret = this->compr; -				this->stat_compr_blocks++; -				this->stat_compr_orig_size += *datalen; -				this->stat_compr_new_size  += *cdatalen; -				break; -			} -		} -		spin_unlock(&jffs2_compressor_list_lock); -		if (ret == JFFS2_COMPR_NONE) -			kfree(output_buf); +		ret = jffs2_selected_compress(0, data_in, cpage_out, datalen, +				cdatalen);  		break;  	case JFFS2_COMPR_MODE_SIZE:  	case JFFS2_COMPR_MODE_FAVOURLZO: @@ -174,22 +222,28 @@ uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,  			best->stat_compr_orig_size += best_slen;  			best->stat_compr_new_size  += best_dlen;  			ret = best->compr; +			*cpage_out = output_buf;  		}  		spin_unlock(&jffs2_compressor_list_lock);  		break; +	case JFFS2_COMPR_MODE_FORCELZO: +		ret = jffs2_selected_compress(JFFS2_COMPR_LZO, data_in, +				cpage_out, datalen, cdatalen); +		break; +	case JFFS2_COMPR_MODE_FORCEZLIB: +		ret = jffs2_selected_compress(JFFS2_COMPR_ZLIB, data_in, +				cpage_out, datalen, cdatalen); +		break;  	default:  		printk(KERN_ERR "JFFS2: unknown compression mode.\n");  	} - out: +  	if (ret == JFFS2_COMPR_NONE) {  		*cpage_out = data_in;  		*datalen = *cdatalen;  		none_stat_compr_blocks++;  		none_stat_compr_size += *datalen;  	} -	else { -		*cpage_out = output_buf; -	}  	return ret;  } diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h index 13bb7597ab39..5e91d578f4ed 100644 --- a/fs/jffs2/compr.h +++ b/fs/jffs2/compr.h @@ -40,6 +40,8 @@  #define JFFS2_COMPR_MODE_PRIORITY   1  #define JFFS2_COMPR_MODE_SIZE       2  #define JFFS2_COMPR_MODE_FAVOURLZO  3 +#define JFFS2_COMPR_MODE_FORCELZO   4 +#define JFFS2_COMPR_MODE_FORCEZLIB  5  #define FAVOUR_LZO_PERCENT 80 diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 7286e44ac665..4b8afe39a87f 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -379,7 +379,7 @@ void jffs2_dirty_inode(struct inode *inode, int flags)  	jffs2_do_setattr(inode, &iattr);  } -int jffs2_remount_fs (struct super_block *sb, int *flags, char *data) +int jffs2_do_remount_fs(struct super_block *sb, int *flags, char *data)  {  	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 0bc6a6c80a56..55a0c1dceadf 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h @@ -29,6 +29,11 @@  struct jffs2_inodirty; +struct jffs2_mount_opts { +	bool override_compr; +	unsigned int compr; +}; +  /* A struct for the overall file system control.  Pointers to     jffs2_sb_info structs are named `c' in the source code.     Nee jffs_control @@ -126,6 +131,7 @@ struct jffs2_sb_info {  #endif  	struct jffs2_summary *summary;		/* Summary information */ +	struct jffs2_mount_opts mount_opts;  #ifdef CONFIG_JFFS2_FS_XATTR  #define XATTRINDEX_HASHSIZE	(57) diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 6c1755c59c0f..ab65ee3ec858 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -176,7 +176,7 @@ void jffs2_dirty_inode(struct inode *inode, int flags);  struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode,  			       struct jffs2_raw_inode *ri);  int jffs2_statfs (struct dentry *, struct kstatfs *); -int jffs2_remount_fs (struct super_block *, int *, char *); +int jffs2_do_remount_fs(struct super_block *, int *, char *);  int jffs2_do_fill_super(struct super_block *sb, void *data, int silent);  void jffs2_gc_release_inode(struct jffs2_sb_info *c,  			    struct jffs2_inode_info *f); diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 8d8cd3419d02..28107ca136e4 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -275,9 +275,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)  	else  		c->mtd->unpoint(c->mtd, 0, c->mtd->size);  #endif -	if (s) -		kfree(s); - +	kfree(s);  	return ret;  } diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 853b8e300084..e7e974454115 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -17,11 +17,13 @@  #include <linux/fs.h>  #include <linux/err.h>  #include <linux/mount.h> +#include <linux/parser.h>  #include <linux/jffs2.h>  #include <linux/pagemap.h>  #include <linux/mtd/super.h>  #include <linux/ctype.h>  #include <linux/namei.h> +#include <linux/seq_file.h>  #include <linux/exportfs.h>  #include "compr.h"  #include "nodelist.h" @@ -75,6 +77,37 @@ static void jffs2_write_super(struct super_block *sb)  	unlock_super(sb);  } +static const char *jffs2_compr_name(unsigned int compr) +{ +	switch (compr) { +	case JFFS2_COMPR_MODE_NONE: +		return "none"; +#ifdef CONFIG_JFFS2_LZO +	case JFFS2_COMPR_MODE_FORCELZO: +		return "lzo"; +#endif +#ifdef CONFIG_JFFS2_ZLIB +	case JFFS2_COMPR_MODE_FORCEZLIB: +		return "zlib"; +#endif +	default: +		/* should never happen; programmer error */ +		WARN_ON(1); +		return ""; +	} +} + +static int jffs2_show_options(struct seq_file *s, struct vfsmount *mnt) +{ +	struct jffs2_sb_info *c = JFFS2_SB_INFO(mnt->mnt_sb); +	struct jffs2_mount_opts *opts = &c->mount_opts; + +	if (opts->override_compr) +		seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr)); + +	return 0; +} +  static int jffs2_sync_fs(struct super_block *sb, int wait)  {  	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); @@ -133,6 +166,85 @@ static const struct export_operations jffs2_export_ops = {  	.fh_to_parent = jffs2_fh_to_parent,  }; +/* + * JFFS2 mount options. + * + * Opt_override_compr: override default compressor + * Opt_err: just end of array marker + */ +enum { +	Opt_override_compr, +	Opt_err, +}; + +static const match_table_t tokens = { +	{Opt_override_compr, "compr=%s"}, +	{Opt_err, NULL}, +}; + +static int jffs2_parse_options(struct jffs2_sb_info *c, char *data) +{ +	substring_t args[MAX_OPT_ARGS]; +	char *p, *name; + +	if (!data) +		return 0; + +	while ((p = strsep(&data, ","))) { +		int token; + +		if (!*p) +			continue; + +		token = match_token(p, tokens, args); +		switch (token) { +		case Opt_override_compr: +			name = match_strdup(&args[0]); + +			if (!name) +				return -ENOMEM; +			if (!strcmp(name, "none")) +				c->mount_opts.compr = JFFS2_COMPR_MODE_NONE; +#ifdef CONFIG_JFFS2_LZO +			else if (!strcmp(name, "lzo")) +				c->mount_opts.compr = JFFS2_COMPR_MODE_FORCELZO; +#endif +#ifdef CONFIG_JFFS2_ZLIB +			else if (!strcmp(name, "zlib")) +				c->mount_opts.compr = +						JFFS2_COMPR_MODE_FORCEZLIB; +#endif +			else { +				printk(KERN_ERR "JFFS2 Error: unknown compressor \"%s\"", +						name); +				kfree(name); +				return -EINVAL; +			} +			kfree(name); +			c->mount_opts.override_compr = true; +			break; +		default: +			printk(KERN_ERR "JFFS2 Error: unrecognized mount option '%s' or missing value\n", +					p); +			return -EINVAL; +		} +	} + +	return 0; +} + +static int jffs2_remount_fs(struct super_block *sb, int *flags, char *data) +{ +	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); +	int err; + +	err = jffs2_parse_options(c, data); +	if (err) +		return -EINVAL; + +	return jffs2_do_remount_fs(sb, flags, data); +} +  static const struct super_operations jffs2_super_operations =  {  	.alloc_inode =	jffs2_alloc_inode, @@ -143,6 +255,7 @@ static const struct super_operations jffs2_super_operations =  	.remount_fs =	jffs2_remount_fs,  	.evict_inode =	jffs2_evict_inode,  	.dirty_inode =	jffs2_dirty_inode, +	.show_options =	jffs2_show_options,  	.sync_fs =	jffs2_sync_fs,  }; @@ -166,6 +279,12 @@ static int jffs2_fill_super(struct super_block *sb, void *data, int silent)  	c->os_priv = sb;  	sb->s_fs_info = c; +	ret = jffs2_parse_options(c, data); +	if (ret) { +		kfree(c); +		return -EINVAL; +	} +  	/* Initialize JFFS2 superblock locks, the further initialization will  	 * be done later */  	mutex_init(&c->alloc_sem); diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 4515bea0268f..b09e51d2f81f 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -578,8 +578,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)  	if (!jffs2_is_writebuffered(c))  		return 0; -	if (mutex_trylock(&c->alloc_sem)) { -		mutex_unlock(&c->alloc_sem); +	if (!mutex_is_locked(&c->alloc_sem)) {  		printk(KERN_CRIT "jffs2_flush_wbuf() called with alloc_sem not locked!\n");  		BUG();  	} @@ -1026,7 +1025,7 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c,  	int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE);  	struct mtd_oob_ops ops; -	ops.mode = MTD_OOB_AUTO; +	ops.mode = MTD_OPS_AUTO_OOB;  	ops.ooblen = NR_OOB_SCAN_PAGES * c->oobavail;  	ops.oobbuf = c->oobbuf;  	ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; @@ -1069,7 +1068,7 @@ int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c,  	struct mtd_oob_ops ops;  	int ret, cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); -	ops.mode = MTD_OOB_AUTO; +	ops.mode = MTD_OPS_AUTO_OOB;  	ops.ooblen = cmlen;  	ops.oobbuf = c->oobbuf;  	ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; @@ -1095,7 +1094,7 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c,  	struct mtd_oob_ops ops;  	int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); -	ops.mode = MTD_OOB_AUTO; +	ops.mode = MTD_OPS_AUTO_OOB;  	ops.ooblen = cmlen;  	ops.oobbuf = (uint8_t *)&oob_cleanmarker;  	ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h index 57cc0e63714f..c4eec228eef9 100644 --- a/include/linux/mtd/bbm.h +++ b/include/linux/mtd/bbm.h @@ -86,24 +86,39 @@ struct nand_bbt_descr {  #define NAND_BBT_VERSION	0x00000100  /* Create a bbt if none exists */  #define NAND_BBT_CREATE		0x00000200 +/* + * Create an empty BBT with no vendor information. Vendor's information may be + * unavailable, for example, if the NAND controller has a different data and OOB + * layout or if this information is already purged. Must be used in conjunction + * with NAND_BBT_CREATE. + */ +#define NAND_BBT_CREATE_EMPTY	0x00000400  /* Search good / bad pattern through all pages of a block */ -#define NAND_BBT_SCANALLPAGES	0x00000400 +#define NAND_BBT_SCANALLPAGES	0x00000800  /* Scan block empty during good / bad block scan */ -#define NAND_BBT_SCANEMPTY	0x00000800 +#define NAND_BBT_SCANEMPTY	0x00001000  /* Write bbt if neccecary */ -#define NAND_BBT_WRITE		0x00001000 +#define NAND_BBT_WRITE		0x00002000  /* Read and write back block contents when writing bbt */ -#define NAND_BBT_SAVECONTENT	0x00002000 +#define NAND_BBT_SAVECONTENT	0x00004000  /* Search good / bad pattern on the first and the second page */ -#define NAND_BBT_SCAN2NDPAGE	0x00004000 +#define NAND_BBT_SCAN2NDPAGE	0x00008000  /* Search good / bad pattern on the last page of the eraseblock */ -#define NAND_BBT_SCANLASTPAGE	0x00008000 -/* Chip stores bad block marker on BOTH 1st and 6th bytes of OOB */ -#define NAND_BBT_SCANBYTE1AND6 0x00100000 -/* The nand_bbt_descr was created dynamicaly and must be freed */ -#define NAND_BBT_DYNAMICSTRUCT 0x00200000 -/* The bad block table does not OOB for marker */ -#define NAND_BBT_NO_OOB		0x00400000 +#define NAND_BBT_SCANLASTPAGE	0x00010000 +/* + * Use a flash based bad block table. By default, OOB identifier is saved in + * OOB area. This option is passed to the default bad block table function. + */ +#define NAND_BBT_USE_FLASH	0x00020000 +/* Do not store flash based bad block table in OOB area; store it in-band */ +#define NAND_BBT_NO_OOB		0x00040000 + +/* + * Flag set by nand_create_default_bbt_descr(), marking that the nand_bbt_descr + * was allocated dynamicaly and must be freed in nand_release(). Has no meaning + * in nand_chip.bbt_options. + */ +#define NAND_BBT_DYNAMICSTRUCT	0x80000000  /* The maximum number of blocks to scan for a bbt */  #define NAND_BBT_SCAN_MAXBLOCKS	4 diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 37be05bbfbc8..9f5b312af783 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -32,17 +32,19 @@  #define MTD_CHAR_MAJOR 90  #define MTD_BLOCK_MAJOR 31 -#define MTD_ERASE_PENDING      	0x01 +#define MTD_ERASE_PENDING	0x01  #define MTD_ERASING		0x02  #define MTD_ERASE_SUSPEND	0x04 -#define MTD_ERASE_DONE          0x08 -#define MTD_ERASE_FAILED        0x10 +#define MTD_ERASE_DONE		0x08 +#define MTD_ERASE_FAILED	0x10  #define MTD_FAIL_ADDR_UNKNOWN -1LL -/* If the erase fails, fail_addr might indicate exactly which block failed.  If -   fail_addr = MTD_FAIL_ADDR_UNKNOWN, the failure was not at the device level or was not -   specific to any particular block. */ +/* + * If the erase fails, fail_addr might indicate exactly which block failed. If + * fail_addr = MTD_FAIL_ADDR_UNKNOWN, the failure was not at the device level + * or was not specific to any particular block. + */  struct erase_info {  	struct mtd_info *mtd;  	uint64_t addr; @@ -59,26 +61,12 @@ struct erase_info {  };  struct mtd_erase_region_info { -	uint64_t offset;			/* At which this region starts, from the beginning of the MTD */ +	uint64_t offset;		/* At which this region starts, from the beginning of the MTD */  	uint32_t erasesize;		/* For this region */  	uint32_t numblocks;		/* Number of blocks of erasesize in this region */  	unsigned long *lockmap;		/* If keeping bitmap of locks */  }; -/* - * oob operation modes - * - * MTD_OOB_PLACE:	oob data are placed at the given offset - * MTD_OOB_AUTO:	oob data are automatically placed at the free areas - *			which are defined by the ecclayout - * MTD_OOB_RAW:		mode to read oob and data without doing ECC checking - */ -typedef enum { -	MTD_OOB_PLACE, -	MTD_OOB_AUTO, -	MTD_OOB_RAW, -} mtd_oob_mode_t; -  /**   * struct mtd_oob_ops - oob operation operands   * @mode:	operation mode @@ -90,7 +78,7 @@ typedef enum {   * @ooblen:	number of oob bytes to write/read   * @oobretlen:	number of oob bytes written/read   * @ooboffs:	offset of oob data in the oob area (only relevant when - *		mode = MTD_OOB_PLACE) + *		mode = MTD_OPS_PLACE_OOB or MTD_OPS_RAW)   * @datbuf:	data buffer - if NULL only oob data are read/written   * @oobbuf:	oob data buffer   * @@ -99,7 +87,7 @@ typedef enum {   * OOB area.   */  struct mtd_oob_ops { -	mtd_oob_mode_t	mode; +	unsigned int	mode;  	size_t		len;  	size_t		retlen;  	size_t		ooblen; @@ -173,7 +161,7 @@ struct mtd_info {  	const char *name;  	int index; -	/* ecc layout structure pointer - read only ! */ +	/* ECC layout structure pointer - read only! */  	struct nand_ecclayout *ecclayout;  	/* Data for variable erase regions. If numeraseregions is zero, @@ -324,10 +312,15 @@ static inline uint32_t mtd_mod_by_ws(uint64_t sz, struct mtd_info *mtd)  	/* Kernel-side ioctl definitions */  struct mtd_partition; - -extern int mtd_device_register(struct mtd_info *master, -			       const struct mtd_partition *parts, -			       int nr_parts); +struct mtd_part_parser_data; + +extern int mtd_device_parse_register(struct mtd_info *mtd, +			      const char **part_probe_types, +			      struct mtd_part_parser_data *parser_data, +			      const struct mtd_partition *defparts, +			      int defnr_parts); +#define mtd_device_register(master, parts, nr_parts)	\ +	mtd_device_parse_register(master, NULL, NULL, parts, nr_parts)  extern int mtd_device_unregister(struct mtd_info *master);  extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num);  extern int __get_mtd_device(struct mtd_info *mtd); @@ -356,27 +349,16 @@ void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size);  void mtd_erase_callback(struct erase_info *instr); -/* - * Debugging macro and defines - */ -#define MTD_DEBUG_LEVEL0	(0)	/* Quiet   */ -#define MTD_DEBUG_LEVEL1	(1)	/* Audible */ -#define MTD_DEBUG_LEVEL2	(2)	/* Loud    */ -#define MTD_DEBUG_LEVEL3	(3)	/* Noisy   */ - -#ifdef CONFIG_MTD_DEBUG -#define DEBUG(n, args...)				\ -	do {						\ -		if (n <= CONFIG_MTD_DEBUG_VERBOSE)	\ -			printk(KERN_INFO args);		\ -	} while(0) -#else /* CONFIG_MTD_DEBUG */ -#define DEBUG(n, args...)				\ -	do {						\ -		if (0)					\ -			printk(KERN_INFO args);		\ -	} while(0) - -#endif /* CONFIG_MTD_DEBUG */ +static inline int mtd_is_bitflip(int err) { +	return err == -EUCLEAN; +} + +static inline int mtd_is_eccerr(int err) { +	return err == -EBADMSG; +} + +static inline int mtd_is_bitflip_or_eccerr(int err) { +	return mtd_is_bitflip(err) || mtd_is_eccerr(err); +}  #endif /* __MTD_MTD_H__ */ diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index c2b9ac4fbc4a..904131bab501 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -42,10 +42,10 @@ extern void nand_release(struct mtd_info *mtd);  /* Internal helper for board drivers which need to override command function */  extern void nand_wait_ready(struct mtd_info *mtd); -/* locks all blockes present in the device */ +/* locks all blocks present in the device */  extern int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); -/* unlocks specified locked blockes */ +/* unlocks specified locked blocks */  extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);  /* The maximum number of NAND chips in an array */ @@ -150,7 +150,7 @@ typedef enum {  #define NAND_ECC_READ		0  /* Reset Hardware ECC for write */  #define NAND_ECC_WRITE		1 -/* Enable Hardware ECC before syndrom is read back from flash */ +/* Enable Hardware ECC before syndrome is read back from flash */  #define NAND_ECC_READSYN	2  /* Bit mask for flags passed to do_nand_read_ecc */ @@ -163,7 +163,7 @@ typedef enum {   */  /* Chip can not auto increment pages */  #define NAND_NO_AUTOINCR	0x00000001 -/* Buswitdh is 16 bit */ +/* Buswidth is 16 bit */  #define NAND_BUSWIDTH_16	0x00000002  /* Device supports partial programming without padding */  #define NAND_NO_PADDING		0x00000004 @@ -219,27 +219,15 @@ typedef enum {  #define NAND_CHIPOPTIONS_MSK	(0x0000ffff & ~NAND_NO_AUTOINCR)  /* Non chip related options */ -/* - * Use a flash based bad block table. OOB identifier is saved in OOB area. - * This option is passed to the default bad block table function. - */ -#define NAND_USE_FLASH_BBT	0x00010000  /* This option skips the bbt scan during initialization. */ -#define NAND_SKIP_BBTSCAN	0x00020000 +#define NAND_SKIP_BBTSCAN	0x00010000  /*   * This option is defined if the board driver allocates its own buffers   * (e.g. because it needs them DMA-coherent).   */ -#define NAND_OWN_BUFFERS	0x00040000 +#define NAND_OWN_BUFFERS	0x00020000  /* Chip may not exist, so silence any errors in scan */ -#define NAND_SCAN_SILENT_NODEV	0x00080000 -/* - * If passed additionally to NAND_USE_FLASH_BBT then BBT code will not touch - * the OOB area. - */ -#define NAND_USE_FLASH_BBT_NO_OOB	0x00800000 -/* Create an empty BBT with no vendor information if the BBT is available */ -#define NAND_CREATE_EMPTY_BBT		0x01000000 +#define NAND_SCAN_SILENT_NODEV	0x00040000  /* Options set by nand scan */  /* Nand scan has allocated controller struct */ @@ -331,27 +319,29 @@ struct nand_hw_control {  };  /** - * struct nand_ecc_ctrl - Control structure for ecc - * @mode:	ecc mode - * @steps:	number of ecc steps per page - * @size:	data bytes per ecc step - * @bytes:	ecc bytes per step - * @total:	total number of ecc bytes per page - * @prepad:	padding information for syndrome based ecc generators - * @postpad:	padding information for syndrome based ecc generators + * struct nand_ecc_ctrl - Control structure for ECC + * @mode:	ECC mode + * @steps:	number of ECC steps per page + * @size:	data bytes per ECC step + * @bytes:	ECC bytes per step + * @total:	total number of ECC bytes per page + * @prepad:	padding information for syndrome based ECC generators + * @postpad:	padding information for syndrome based ECC generators   * @layout:	ECC layout control struct pointer - * @priv:	pointer to private ecc control data - * @hwctl:	function to control hardware ecc generator. Must only + * @priv:	pointer to private ECC control data + * @hwctl:	function to control hardware ECC generator. Must only   *		be provided if an hardware ECC is available - * @calculate:	function for ecc calculation or readback from ecc hardware - * @correct:	function for ecc correction, matching to ecc generator (sw/hw) + * @calculate:	function for ECC calculation or readback from ECC hardware + * @correct:	function for ECC correction, matching to ECC generator (sw/hw)   * @read_page_raw:	function to read a raw page without ECC   * @write_page_raw:	function to write a raw page without ECC - * @read_page:	function to read a page according to the ecc generator + * @read_page:	function to read a page according to the ECC generator   *		requirements.   * @read_subpage:	function to read parts of the page covered by ECC. - * @write_page:	function to write a page according to the ecc generator + * @write_page:	function to write a page according to the ECC generator   *		requirements. + * @write_oob_raw:	function to write chip OOB data without ECC + * @read_oob_raw:	function to read chip OOB data without ECC   * @read_oob:	function to read chip OOB data   * @write_oob:	function to write chip OOB data   */ @@ -380,6 +370,10 @@ struct nand_ecc_ctrl {  			uint32_t offs, uint32_t len, uint8_t *buf);  	void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,  			const uint8_t *buf); +	int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip, +			int page); +	int (*read_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip, +			int page, int sndcmd);  	int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page,  			int sndcmd);  	int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip, @@ -388,8 +382,8 @@ struct nand_ecc_ctrl {  /**   * struct nand_buffers - buffer structure for read/write - * @ecccalc:	buffer for calculated ecc - * @ecccode:	buffer for ecc read from flash + * @ecccalc:	buffer for calculated ECC + * @ecccode:	buffer for ECC read from flash   * @databuf:	buffer for data - dynamically sized   *   * Do not change the order of buffers. databuf and oobrbuf must be in @@ -422,7 +416,7 @@ struct nand_buffers {   *			mtd->oobsize, mtd->writesize and so on.   *			@id_data contains the 8 bytes values of NAND_CMD_READID.   *			Return with the bus width. - * @dev_ready:		[BOARDSPECIFIC] hardwarespecific function for accesing + * @dev_ready:		[BOARDSPECIFIC] hardwarespecific function for accessing   *			device ready/busy line. If set to NULL no access to   *			ready/busy is available and the ready/busy information   *			is read from the chip status register. @@ -430,17 +424,17 @@ struct nand_buffers {   *			commands to the chip.   * @waitfunc:		[REPLACEABLE] hardwarespecific function for wait on   *			ready. - * @ecc:		[BOARDSPECIFIC] ecc control ctructure + * @ecc:		[BOARDSPECIFIC] ECC control structure   * @buffers:		buffer structure for read/write   * @hwcontrol:		platform-specific hardware control structure - * @ops:		oob operation operands   * @erase_cmd:		[INTERN] erase command write function, selectable due   *			to AND support.   * @scan_bbt:		[REPLACEABLE] function to scan bad block table   * @chip_delay:		[BOARDSPECIFIC] chip dependent delay for transferring   *			data from array to read regs (tR).   * @state:		[INTERN] the current state of the NAND device - * @oob_poi:		poison value buffer + * @oob_poi:		"poison value buffer," used for laying out OOB data + *			before writing   * @page_shift:		[INTERN] number of address bits in a page (column   *			address bits).   * @phys_erase_shift:	[INTERN] number of address bits in a physical eraseblock @@ -449,6 +443,9 @@ struct nand_buffers {   * @options:		[BOARDSPECIFIC] various chip options. They can partly   *			be set to inform nand_scan about special functionality.   *			See the defines for further explanation. + * @bbt_options:	[INTERN] bad block specific options. All options used + *			here must come from bbm.h. By default, these options + *			will be copied to the appropriate nand_bbt_descr's.   * @badblockpos:	[INTERN] position of the bad block marker in the oob   *			area.   * @badblockbits:	[INTERN] number of bits to left-shift the bad block @@ -464,7 +461,7 @@ struct nand_buffers {   *			non 0 if ONFI supported.   * @onfi_params:	[INTERN] holds the ONFI page parameter when ONFI is   *			supported, 0 otherwise. - * @ecclayout:		[REPLACEABLE] the default ecc placement scheme + * @ecclayout:		[REPLACEABLE] the default ECC placement scheme   * @bbt:		[INTERN] bad block table pointer   * @bbt_td:		[REPLACEABLE] bad block table descriptor for flash   *			lookup. @@ -472,9 +469,9 @@ struct nand_buffers {   * @badblock_pattern:	[REPLACEABLE] bad block scan pattern used for initial   *			bad block scan.   * @controller:		[REPLACEABLE] a pointer to a hardware controller - *			structure which is shared among multiple independend + *			structure which is shared among multiple independent   *			devices. - * @priv:		[OPTIONAL] pointer to private chip date + * @priv:		[OPTIONAL] pointer to private chip data   * @errstat:		[OPTIONAL] hardware specific function to perform   *			additional error status checks (determine if errors are   *			correctable). @@ -509,6 +506,7 @@ struct nand_chip {  	int chip_delay;  	unsigned int options; +	unsigned int bbt_options;  	int page_shift;  	int phys_erase_shift; @@ -536,8 +534,6 @@ struct nand_chip {  	struct nand_buffers *buffers;  	struct nand_hw_control hwcontrol; -	struct mtd_oob_ops ops; -  	uint8_t *bbt;  	struct nand_bbt_descr *bbt_td;  	struct nand_bbt_descr *bbt_md; @@ -611,10 +607,9 @@ extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,   * @partitions:		mtd partition list   * @chip_delay:		R/B delay value in us   * @options:		Option flags, e.g. 16bit buswidth - * @ecclayout:		ecc layout info structure + * @bbt_options:	BBT option flags, e.g. NAND_BBT_USE_FLASH + * @ecclayout:		ECC layout info structure   * @part_probe_types:	NULL-terminated array of probe types - * @set_parts:		platform specific function to set partitions - * @priv:		hardware controller specific settings   */  struct platform_nand_chip {  	int nr_chips; @@ -624,9 +619,8 @@ struct platform_nand_chip {  	struct nand_ecclayout *ecclayout;  	int chip_delay;  	unsigned int options; +	unsigned int bbt_options;  	const char **part_probe_types; -	void (*set_parts)(uint64_t size, struct platform_nand_chip *chip); -	void *priv;  };  /* Keep gcc happy */ diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h index 52b6f187bf49..4596503c9da9 100644 --- a/include/linux/mtd/onenand.h +++ b/include/linux/mtd/onenand.h @@ -184,6 +184,9 @@ struct onenand_chip {  #define ONENAND_IS_CACHE_PROGRAM(this)					\  	(this->options & ONENAND_HAS_CACHE_PROGRAM) +#define ONENAND_IS_NOP_1(this)						\ +	(this->options & ONENAND_HAS_NOP_1) +  /* Check byte access in OneNAND */  #define ONENAND_CHECK_BYTE_ACCESS(addr)		(addr & 0x1) @@ -195,6 +198,7 @@ struct onenand_chip {  #define ONENAND_HAS_2PLANE		(0x0004)  #define ONENAND_HAS_4KB_PAGE		(0x0008)  #define ONENAND_HAS_CACHE_PROGRAM	(0x0010) +#define ONENAND_HAS_NOP_1		(0x0020)  #define ONENAND_SKIP_UNLOCK_CHECK	(0x0100)  #define ONENAND_PAGEBUF_ALLOC		(0x1000)  #define ONENAND_OOBBUF_ALLOC		(0x2000) diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index 3a6f0372fc96..2475228c1158 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -24,7 +24,9 @@   * 	will extend to the end of the master MTD device.   * offset: absolute starting position within the master MTD device; if   * 	defined as MTDPART_OFS_APPEND, the partition will start where the - * 	previous one ended; if MTDPART_OFS_NXTBLK, at the next erase block. + *	previous one ended; if MTDPART_OFS_NXTBLK, at the next erase block; + *	if MTDPART_OFS_RETAIN, consume as much as possible, leaving size + *	after the end of partition.   * mask_flags: contains flags that have to be masked (removed) from the   * 	master MTD flag set for the corresponding MTD partition.   * 	For example, to force a read-only partition, simply adding @@ -42,12 +44,25 @@ struct mtd_partition {  	struct nand_ecclayout *ecclayout;	/* out of band layout for this partition (NAND only) */  }; +#define MTDPART_OFS_RETAIN	(-3)  #define MTDPART_OFS_NXTBLK	(-2)  #define MTDPART_OFS_APPEND	(-1)  #define MTDPART_SIZ_FULL	(0)  struct mtd_info; +struct device_node; + +/** + * struct mtd_part_parser_data - used to pass data to MTD partition parsers. + * @origin: for RedBoot, start address of MTD device + * @of_node: for OF parsers, device node containing partitioning information + */ +struct mtd_part_parser_data { +	unsigned long origin; +	struct device_node *of_node; +}; +  /*   * Functions dealing with the various ways of partitioning the space @@ -57,37 +72,12 @@ struct mtd_part_parser {  	struct list_head list;  	struct module *owner;  	const char *name; -	int (*parse_fn)(struct mtd_info *, struct mtd_partition **, unsigned long); +	int (*parse_fn)(struct mtd_info *, struct mtd_partition **, +			struct mtd_part_parser_data *);  };  extern int register_mtd_parser(struct mtd_part_parser *parser);  extern int deregister_mtd_parser(struct mtd_part_parser *parser); -extern int parse_mtd_partitions(struct mtd_info *master, const char **types, -				struct mtd_partition **pparts, unsigned long origin); - -#define put_partition_parser(p) do { module_put((p)->owner); } while(0) - -struct device; -struct device_node; - -#ifdef CONFIG_MTD_OF_PARTS -int __devinit of_mtd_parse_partitions(struct device *dev, -                                      struct device_node *node, -                                      struct mtd_partition **pparts); -#else -static inline int of_mtd_parse_partitions(struct device *dev, -					  struct device_node *node, -					  struct mtd_partition **pparts) -{ -	return 0; -} -#endif - -#ifdef CONFIG_MTD_CMDLINE_PARTS -static inline int mtd_has_cmdlinepart(void) { return 1; } -#else -static inline int mtd_has_cmdlinepart(void) { return 0; } -#endif  int mtd_is_partition(struct mtd_info *mtd);  int mtd_add_partition(struct mtd_info *master, char *name, diff --git a/include/linux/mtd/physmap.h b/include/linux/mtd/physmap.h index e5f21d293c70..04e018160e2b 100644 --- a/include/linux/mtd/physmap.h +++ b/include/linux/mtd/physmap.h @@ -32,21 +32,4 @@ struct physmap_flash_data {  	struct mtd_partition	*parts;  }; -/* - * Board needs to specify the exact mapping during their setup time. - */ -void physmap_configure(unsigned long addr, unsigned long size, -		int bankwidth, void (*set_vpp)(struct map_info *, int) ); - -/* - * Machines that wish to do flash partition may want to call this function in - * their setup routine. - * - *	physmap_set_partitions(mypartitions, num_parts); - * - * Note that one can always override this hard-coded partition with - * command line partition (you need to enable CONFIG_MTD_CMDLINE_PARTS). - */ -void physmap_set_partitions(struct mtd_partition *parts, int num_parts); -  #endif /* __LINUX_MTD_PHYSMAP__ */ diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h index 2f7d45bcbd24..1a7e1d20adf9 100644 --- a/include/mtd/mtd-abi.h +++ b/include/mtd/mtd-abi.h @@ -45,6 +45,51 @@ struct mtd_oob_buf64 {  	__u64 usr_ptr;  }; +/** + * MTD operation modes + * + * @MTD_OPS_PLACE_OOB:	OOB data are placed at the given offset (default) + * @MTD_OPS_AUTO_OOB:	OOB data are automatically placed at the free areas + *			which are defined by the internal ecclayout + * @MTD_OPS_RAW:	data are transferred as-is, with no error correction; + *			this mode implies %MTD_OPS_PLACE_OOB + * + * These modes can be passed to ioctl(MEMWRITE) and are also used internally. + * See notes on "MTD file modes" for discussion on %MTD_OPS_RAW vs. + * %MTD_FILE_MODE_RAW. + */ +enum { +	MTD_OPS_PLACE_OOB = 0, +	MTD_OPS_AUTO_OOB = 1, +	MTD_OPS_RAW = 2, +}; + +/** + * struct mtd_write_req - data structure for requesting a write operation + * + * @start:	start address + * @len:	length of data buffer + * @ooblen:	length of OOB buffer + * @usr_data:	user-provided data buffer + * @usr_oob:	user-provided OOB buffer + * @mode:	MTD mode (see "MTD operation modes") + * @padding:	reserved, must be set to 0 + * + * This structure supports ioctl(MEMWRITE) operations, allowing data and/or OOB + * writes in various modes. To write to OOB-only, set @usr_data == NULL, and to + * write data-only, set @usr_oob == NULL. However, setting both @usr_data and + * @usr_oob to NULL is not allowed. + */ +struct mtd_write_req { +	__u64 start; +	__u64 len; +	__u64 ooblen; +	__u64 usr_data; +	__u64 usr_oob; +	__u8 mode; +	__u8 padding[7]; +}; +  #define MTD_ABSENT		0  #define MTD_RAM			1  #define MTD_ROM			2 @@ -59,13 +104,13 @@ struct mtd_oob_buf64 {  #define MTD_NO_ERASE		0x1000	/* No erase necessary */  #define MTD_POWERUP_LOCK	0x2000	/* Always locked after reset */ -// Some common devices / combinations of capabilities +/* Some common devices / combinations of capabilities */  #define MTD_CAP_ROM		0  #define MTD_CAP_RAM		(MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE)  #define MTD_CAP_NORFLASH	(MTD_WRITEABLE | MTD_BIT_WRITEABLE)  #define MTD_CAP_NANDFLASH	(MTD_WRITEABLE) -/* ECC byte placement */ +/* Obsolete ECC byte placement modes (used with obsolete MEMGETOOBSEL) */  #define MTD_NANDECC_OFF		0	// Switch off ECC (Not recommended)  #define MTD_NANDECC_PLACE	1	// Use the given placement in the structure (YAFFS1 legacy mode)  #define MTD_NANDECC_AUTOPLACE	2	// Use the default placement scheme @@ -80,21 +125,18 @@ struct mtd_oob_buf64 {  struct mtd_info_user {  	__u8 type;  	__u32 flags; -	__u32 size;	 // Total size of the MTD +	__u32 size;	/* Total size of the MTD */  	__u32 erasesize;  	__u32 writesize; -	__u32 oobsize;   // Amount of OOB data per block (e.g. 16) -	/* The below two fields are obsolete and broken, do not use them -	 * (TODO: remove at some point) */ -	__u32 ecctype; -	__u32 eccsize; +	__u32 oobsize;	/* Amount of OOB data per block (e.g. 16) */ +	__u64 padding;	/* Old obsolete field; do not use */  };  struct region_info_user {  	__u32 offset;		/* At which this region starts, -					 * from the beginning of the MTD */ -	__u32 erasesize;		/* For this region */ -	__u32 numblocks;		/* Number of blocks in this region */ +				 * from the beginning of the MTD */ +	__u32 erasesize;	/* For this region */ +	__u32 numblocks;	/* Number of blocks in this region */  	__u32 regionindex;  }; @@ -104,29 +146,61 @@ struct otp_info {  	__u32 locked;  }; +/* + * Note, the following ioctl existed in the past and was removed: + * #define MEMSETOOBSEL           _IOW('M', 9, struct nand_oobinfo) + * Try to avoid adding a new ioctl with the same ioctl number. + */ + +/* Get basic MTD characteristics info (better to use sysfs) */  #define MEMGETINFO		_IOR('M', 1, struct mtd_info_user) +/* Erase segment of MTD */  #define MEMERASE		_IOW('M', 2, struct erase_info_user) +/* Write out-of-band data from MTD */  #define MEMWRITEOOB		_IOWR('M', 3, struct mtd_oob_buf) +/* Read out-of-band data from MTD */  #define MEMREADOOB		_IOWR('M', 4, struct mtd_oob_buf) +/* Lock a chip (for MTD that supports it) */  #define MEMLOCK			_IOW('M', 5, struct erase_info_user) +/* Unlock a chip (for MTD that supports it) */  #define MEMUNLOCK		_IOW('M', 6, struct erase_info_user) +/* Get the number of different erase regions */  #define MEMGETREGIONCOUNT	_IOR('M', 7, int) +/* Get information about the erase region for a specific index */  #define MEMGETREGIONINFO	_IOWR('M', 8, struct region_info_user) -#define MEMSETOOBSEL		_IOW('M', 9, struct nand_oobinfo) +/* Get info about OOB modes (e.g., RAW, PLACE, AUTO) - legacy interface */  #define MEMGETOOBSEL		_IOR('M', 10, struct nand_oobinfo) +/* Check if an eraseblock is bad */  #define MEMGETBADBLOCK		_IOW('M', 11, __kernel_loff_t) +/* Mark an eraseblock as bad */  #define MEMSETBADBLOCK		_IOW('M', 12, __kernel_loff_t) +/* Set OTP (One-Time Programmable) mode (factory vs. user) */  #define OTPSELECT		_IOR('M', 13, int) +/* Get number of OTP (One-Time Programmable) regions */  #define OTPGETREGIONCOUNT	_IOW('M', 14, int) +/* Get all OTP (One-Time Programmable) info about MTD */  #define OTPGETREGIONINFO	_IOW('M', 15, struct otp_info) +/* Lock a given range of user data (must be in mode %MTD_FILE_MODE_OTP_USER) */  #define OTPLOCK			_IOR('M', 16, struct otp_info) +/* Get ECC layout (deprecated) */  #define ECCGETLAYOUT		_IOR('M', 17, struct nand_ecclayout_user) +/* Get statistics about corrected/uncorrected errors */  #define ECCGETSTATS		_IOR('M', 18, struct mtd_ecc_stats) +/* Set MTD mode on a per-file-descriptor basis (see "MTD file modes") */  #define MTDFILEMODE		_IO('M', 19) +/* Erase segment of MTD (supports 64-bit address) */  #define MEMERASE64		_IOW('M', 20, struct erase_info_user64) +/* Write data to OOB (64-bit version) */  #define MEMWRITEOOB64		_IOWR('M', 21, struct mtd_oob_buf64) +/* Read data from OOB (64-bit version) */  #define MEMREADOOB64		_IOWR('M', 22, struct mtd_oob_buf64) +/* Check if chip is locked (for MTD that supports it) */  #define MEMISLOCKED		_IOR('M', 23, struct erase_info_user) +/* + * Most generic write interface; can write in-band and/or out-of-band in various + * modes (see "struct mtd_write_req") + */ +#define MEMWRITE		_IOWR('M', 24, struct mtd_write_req)  /*   * Obsolete legacy interface. Keep it in order not to break userspace @@ -177,13 +251,27 @@ struct mtd_ecc_stats {  };  /* - * Read/write file modes for access to MTD + * MTD file modes - for read/write access to MTD + * + * @MTD_FILE_MODE_NORMAL:	OTP disabled, ECC enabled + * @MTD_FILE_MODE_OTP_FACTORY:	OTP enabled in factory mode + * @MTD_FILE_MODE_OTP_USER:	OTP enabled in user mode + * @MTD_FILE_MODE_RAW:		OTP disabled, ECC disabled + * + * These modes can be set via ioctl(MTDFILEMODE). The mode mode will be retained + * separately for each open file descriptor. + * + * Note: %MTD_FILE_MODE_RAW provides the same functionality as %MTD_OPS_RAW - + * raw access to the flash, without error correction or autoplacement schemes. + * Wherever possible, the MTD_OPS_* mode will override the MTD_FILE_MODE_* mode + * (e.g., when using ioctl(MEMWRITE)), but in some cases, the MTD_FILE_MODE is + * used out of necessity (e.g., `write()', ioctl(MEMWRITEOOB64)).   */  enum mtd_file_modes { -	MTD_MODE_NORMAL = MTD_OTP_OFF, -	MTD_MODE_OTP_FACTORY = MTD_OTP_FACTORY, -	MTD_MODE_OTP_USER = MTD_OTP_USER, -	MTD_MODE_RAW, +	MTD_FILE_MODE_NORMAL = MTD_OTP_OFF, +	MTD_FILE_MODE_OTP_FACTORY = MTD_OTP_FACTORY, +	MTD_FILE_MODE_OTP_USER = MTD_OTP_USER, +	MTD_FILE_MODE_RAW,  };  #endif /* __MTD_ABI_H__ */  |