From bunk at kernel.org  Tue Jan  1 08:48:39 2008
From: bunk at kernel.org (Adrian Bunk)
Date: Tue, 1 Jan 2008 15:48:39 +0200
Subject: [2.6 patch] remove broken MTD drivers
Message-ID: <20080101134839.GN2360@does.not.exist>

This patch removes two MTD drivers that have been marked as
BROKEN 19 months ago due to requiring nonexisting header files.

Signed-off-by: Adrian Bunk <bunk at kernel.org>

---

This patch has been sent on:
- 24 Oct 2007

 drivers/mtd/nand/Kconfig          |   12 
 drivers/mtd/nand/Makefile         |    2 
 drivers/mtd/nand/ppchameleonevb.c |  439 ------------------------------
 drivers/mtd/nand/toto.c           |  208 --------------
 4 files changed, 661 deletions(-)

eb65564be12f427ae8a96a2ffa7e727a814e1129 
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 246d451..fa6b8b5 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -69,12 +69,6 @@ config MTD_NAND_AMS_DELTA
 	help
 	  Support for NAND flash on Amstrad E3 (Delta).
 
-config MTD_NAND_TOTO
-	tristate "NAND Flash device on TOTO board"
-	depends on ARCH_OMAP && BROKEN
-	help
-	  Support for NAND flash on Texas Instruments Toto platform.
-
 config MTD_NAND_TS7250
 	tristate "NAND Flash device on TS-7250 board"
 	depends on MACH_TS72XX
@@ -120,12 +114,6 @@ config MTD_NAND_RTC_FROM4
 	  This enables the driver for the Renesas Technology AG-AND
 	  flash interface board (FROM_BOARD4)
 
-config MTD_NAND_PPCHAMELEONEVB
-	tristate "NAND Flash device on PPChameleonEVB board"
-	depends on PPCHAMELEONEVB && BROKEN
-	help
-	  This enables the NAND flash driver on the PPChameleon EVB Board.
-
 config MTD_NAND_S3C2410
 	tristate "NAND Flash support for S3C2410/S3C2440 SoC"
 	depends on ARCH_S3C2410
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 3ad6c01..f6b27de 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -9,12 +9,10 @@ obj-$(CONFIG_MTD_NAND_IDS)		+= nand_ids.o
 obj-$(CONFIG_MTD_NAND_CAFE)		+= cafe_nand.o
 obj-$(CONFIG_MTD_NAND_SPIA)		+= spia.o
 obj-$(CONFIG_MTD_NAND_AMS_DELTA)	+= ams-delta.o
-obj-$(CONFIG_MTD_NAND_TOTO)		+= toto.o
 obj-$(CONFIG_MTD_NAND_AUTCPU12)		+= autcpu12.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
 obj-$(CONFIG_MTD_NAND_S3C2410)		+= s3c2410.o
 obj-$(CONFIG_MTD_NAND_DISKONCHIP)	+= diskonchip.o
 obj-$(CONFIG_MTD_NAND_H1900)		+= h1910.o
diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c
deleted file mode 100644
index 082073a..0000000
--- a/drivers/mtd/nand/ppchameleonevb.c
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- *  drivers/mtd/nand/ppchameleonevb.c
- *
- *  Copyright (C) 2003 DAVE Srl (info at wawnet.biz)
- *
- *  Derived from drivers/mtd/nand/edb7312.c
- *
- *
- * $Id: ppchameleonevb.c,v 1.7 2005/11/07 11:14:31 gleixner Exp $
- *
- * 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 devices found on the
- *   PPChameleon/PPChameleonEVB system.
- *   PPChameleon options (autodetected):
- *   - BA model: no NAND
- *   - ME model: 32MB (Samsung K9F5608U0B)
- *   - HI model: 128MB (Samsung K9F1G08UOM)
- *   PPChameleonEVB options:
- *   - 32MB (Samsung K9F5608U0B)
- */
-
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/partitions.h>
-#include <asm/io.h>
-#include <platforms/PPChameleonEVB.h>
-
-#undef USE_READY_BUSY_PIN
-#define USE_READY_BUSY_PIN
-/* see datasheets (tR) */
-#define NAND_BIG_DELAY_US		25
-#define NAND_SMALL_DELAY_US		10
-
-/* handy sizes */
-#define SZ_4M                           0x00400000
-#define NAND_SMALL_SIZE                 0x02000000
-#define NAND_MTD_NAME		"ppchameleon-nand"
-#define NAND_EVB_MTD_NAME	"ppchameleonevb-nand"
-
-/* GPIO pins used to drive NAND chip mounted on processor module */
-#define NAND_nCE_GPIO_PIN 		(0x80000000 >> 1)
-#define NAND_CLE_GPIO_PIN 		(0x80000000 >> 2)
-#define NAND_ALE_GPIO_PIN 		(0x80000000 >> 3)
-#define NAND_RB_GPIO_PIN 		(0x80000000 >> 4)
-/* GPIO pins used to drive NAND chip mounted on EVB */
-#define NAND_EVB_nCE_GPIO_PIN 	(0x80000000 >> 14)
-#define NAND_EVB_CLE_GPIO_PIN 	(0x80000000 >> 15)
-#define NAND_EVB_ALE_GPIO_PIN 	(0x80000000 >> 16)
-#define NAND_EVB_RB_GPIO_PIN 	(0x80000000 >> 31)
-
-/*
- * MTD structure for PPChameleonEVB board
- */
-static struct mtd_info *ppchameleon_mtd = NULL;
-static struct mtd_info *ppchameleonevb_mtd = NULL;
-
-/*
- * Module stuff
- */
-static unsigned long ppchameleon_fio_pbase = CFG_NAND0_PADDR;
-static unsigned long ppchameleonevb_fio_pbase = CFG_NAND1_PADDR;
-
-#ifdef MODULE
-module_param(ppchameleon_fio_pbase, ulong, 0);
-module_param(ppchameleonevb_fio_pbase, ulong, 0);
-#else
-__setup("ppchameleon_fio_pbase=", ppchameleon_fio_pbase);
-__setup("ppchameleonevb_fio_pbase=", ppchameleonevb_fio_pbase);
-#endif
-
-#ifdef CONFIG_MTD_PARTITIONS
-/*
- * Define static partitions for flash devices
- */
-static struct mtd_partition partition_info_hi[] = {
-      { .name = "PPChameleon HI Nand Flash",
-	.offset = 0,
-	.size = 128 * 1024 * 1024
-      }
-};
-
-static struct mtd_partition partition_info_me[] = {
-      { .name = "PPChameleon ME Nand Flash",
-	.offset = 0,
-	.size = 32 * 1024 * 1024
-      }
-};
-
-static struct mtd_partition partition_info_evb[] = {
-      { .name = "PPChameleonEVB Nand Flash",
-	.offset = 0,
-	.size = 32 * 1024 * 1024
-      }
-};
-
-#define NUM_PARTITIONS 1
-
-extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, const char *mtd_id);
-#endif
-
-/*
- *	hardware specific access to control-lines
- */
-static void ppchameleon_hwcontrol(struct mtd_info *mtdinfo, int cmd,
-				  unsigned int ctrl)
-{
-	struct nand_chip *chip = mtd->priv;
-
-	if (ctrl & NAND_CTRL_CHANGE) {
-#error Missing headerfiles. No way to fix this. -tglx
-		switch (cmd) {
-		case NAND_CTL_SETCLE:
-			MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND0_PADDR);
-			break;
-		case NAND_CTL_CLRCLE:
-			MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND0_PADDR);
-			break;
-		case NAND_CTL_SETALE:
-			MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND0_PADDR);
-			break;
-		case NAND_CTL_CLRALE:
-			MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND0_PADDR);
-			break;
-		case NAND_CTL_SETNCE:
-			MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND0_PADDR);
-			break;
-		case NAND_CTL_CLRNCE:
-			MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND0_PADDR);
-			break;
-		}
-	}
-	if (cmd != NAND_CMD_NONE)
-		writeb(cmd, chip->IO_ADDR_W);
-}
-
-static void ppchameleonevb_hwcontrol(struct mtd_info *mtdinfo, int cmd,
-				     unsigned int ctrl)
-{
-	struct nand_chip *chip = mtd->priv;
-
-	if (ctrl & NAND_CTRL_CHANGE) {
-#error Missing headerfiles. No way to fix this. -tglx
-		switch (cmd) {
-		case NAND_CTL_SETCLE:
-			MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND1_PADDR);
-			break;
-		case NAND_CTL_CLRCLE:
-			MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND1_PADDR);
-			break;
-		case NAND_CTL_SETALE:
-			MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND1_PADDR);
-			break;
-		case NAND_CTL_CLRALE:
-			MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND1_PADDR);
-			break;
-		case NAND_CTL_SETNCE:
-			MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND1_PADDR);
-			break;
-		case NAND_CTL_CLRNCE:
-			MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND1_PADDR);
-			break;
-		}
-	}
-	if (cmd != NAND_CMD_NONE)
-		writeb(cmd, chip->IO_ADDR_W);
-}
-
-#ifdef USE_READY_BUSY_PIN
-/*
- *	read device ready pin
- */
-static int ppchameleon_device_ready(struct mtd_info *minfo)
-{
-	if (in_be32((volatile unsigned *)GPIO0_IR) & NAND_RB_GPIO_PIN)
-		return 1;
-	return 0;
-}
-
-static int ppchameleonevb_device_ready(struct mtd_info *minfo)
-{
-	if (in_be32((volatile unsigned *)GPIO0_IR) & NAND_EVB_RB_GPIO_PIN)
-		return 1;
-	return 0;
-}
-#endif
-
-#ifdef CONFIG_MTD_PARTITIONS
-const char *part_probes[] = { "cmdlinepart", NULL };
-const char *part_probes_evb[] = { "cmdlinepart", NULL };
-#endif
-
-/*
- * 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;
-
-	/*********************************
-	* Processor module NAND (if any) *
-	*********************************/
-	/* Allocate memory for MTD device structure and private data */
-	ppchameleon_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
-	if (!ppchameleon_mtd) {
-		printk("Unable to allocate PPChameleon NAND MTD device structure.\n");
-		return -ENOMEM;
-	}
-
-	/* map physical address */
-	ppchameleon_fio_base = ioremap(ppchameleon_fio_pbase, SZ_4M);
-	if (!ppchameleon_fio_base) {
-		printk("ioremap PPChameleon NAND flash failed\n");
-		kfree(ppchameleon_mtd);
-		return -EIO;
-	}
-
-	/* Get pointer to private data */
-	this = (struct nand_chip *)(&ppchameleon_mtd[1]);
-
-	/* Initialize structures */
-	memset(ppchameleon_mtd, 0, sizeof(struct mtd_info));
-	memset(this, 0, sizeof(struct nand_chip));
-
-	/* Link the private data with the MTD structure */
-	ppchameleon_mtd->priv = this;
-	ppchameleon_mtd->owner = THIS_MODULE;
-
-	/* Initialize GPIOs */
-	/* Pin mapping for NAND chip */
-	/*
-	   CE   GPIO_01
-	   CLE  GPIO_02
-	   ALE  GPIO_03
-	   R/B  GPIO_04
-	 */
-	/* output select */
-	out_be32((volatile unsigned *)GPIO0_OSRH, in_be32((volatile unsigned *)GPIO0_OSRH) & 0xC0FFFFFF);
-	/* three-state select */
-	out_be32((volatile unsigned *)GPIO0_TSRH, in_be32((volatile unsigned *)GPIO0_TSRH) & 0xC0FFFFFF);
-	/* enable output driver */
-	out_be32((volatile unsigned *)GPIO0_TCR,
-		 in_be32((volatile unsigned *)GPIO0_TCR) | NAND_nCE_GPIO_PIN | NAND_CLE_GPIO_PIN | NAND_ALE_GPIO_PIN);
-#ifdef USE_READY_BUSY_PIN
-	/* three-state select */
-	out_be32((volatile unsigned *)GPIO0_TSRH, in_be32((volatile unsigned *)GPIO0_TSRH) & 0xFF3FFFFF);
-	/* high-impedecence */
-	out_be32((volatile unsigned *)GPIO0_TCR, in_be32((volatile unsigned *)GPIO0_TCR) & (~NAND_RB_GPIO_PIN));
-	/* input select */
-	out_be32((volatile unsigned *)GPIO0_ISR1H,
-		 (in_be32((volatile unsigned *)GPIO0_ISR1H) & 0xFF3FFFFF) | 0x00400000);
-#endif
-
-	/* insert callbacks */
-	this->IO_ADDR_R = ppchameleon_fio_base;
-	this->IO_ADDR_W = ppchameleon_fio_base;
-	this->cmd_ctrl = ppchameleon_hwcontrol;
-#ifdef USE_READY_BUSY_PIN
-	this->dev_ready = ppchameleon_device_ready;
-#endif
-	this->chip_delay = NAND_BIG_DELAY_US;
-	/* ECC mode */
-	this->ecc.mode = NAND_ECC_SOFT;
-
-	/* Scan to find existence of the device (it could not be mounted) */
-	if (nand_scan(ppchameleon_mtd, 1)) {
-		iounmap((void *)ppchameleon_fio_base);
-		ppchameleon_fio_base = NULL;
-		kfree(ppchameleon_mtd);
-		goto nand_evb_init;
-	}
-#ifndef USE_READY_BUSY_PIN
-	/* Adjust delay if necessary */
-	if (ppchameleon_mtd->size == NAND_SMALL_SIZE)
-		this->chip_delay = NAND_SMALL_DELAY_US;
-#endif
-
-#ifdef CONFIG_MTD_PARTITIONS
-	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;
-#endif
-	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);
-	add_mtd_partitions(ppchameleon_mtd, mtd_parts, mtd_parts_nb);
-
- nand_evb_init:
-	/****************************
-	* EVB NAND (always present) *
-	****************************/
-	/* Allocate memory for MTD device structure and private data */
-	ppchameleonevb_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
-	if (!ppchameleonevb_mtd) {
-		printk("Unable to allocate PPChameleonEVB NAND MTD device structure.\n");
-		if (ppchameleon_fio_base)
-			iounmap(ppchameleon_fio_base);
-		return -ENOMEM;
-	}
-
-	/* map physical address */
-	ppchameleonevb_fio_base = ioremap(ppchameleonevb_fio_pbase, SZ_4M);
-	if (!ppchameleonevb_fio_base) {
-		printk("ioremap PPChameleonEVB NAND flash failed\n");
-		kfree(ppchameleonevb_mtd);
-		if (ppchameleon_fio_base)
-			iounmap(ppchameleon_fio_base);
-		return -EIO;
-	}
-
-	/* Get pointer to private data */
-	this = (struct nand_chip *)(&ppchameleonevb_mtd[1]);
-
-	/* Initialize structures */
-	memset(ppchameleonevb_mtd, 0, sizeof(struct mtd_info));
-	memset(this, 0, sizeof(struct nand_chip));
-
-	/* Link the private data with the MTD structure */
-	ppchameleonevb_mtd->priv = this;
-
-	/* Initialize GPIOs */
-	/* Pin mapping for NAND chip */
-	/*
-	   CE   GPIO_14
-	   CLE  GPIO_15
-	   ALE  GPIO_16
-	   R/B  GPIO_31
-	 */
-	/* output select */
-	out_be32((volatile unsigned *)GPIO0_OSRH, in_be32((volatile unsigned *)GPIO0_OSRH) & 0xFFFFFFF0);
-	out_be32((volatile unsigned *)GPIO0_OSRL, in_be32((volatile unsigned *)GPIO0_OSRL) & 0x3FFFFFFF);
-	/* three-state select */
-	out_be32((volatile unsigned *)GPIO0_TSRH, in_be32((volatile unsigned *)GPIO0_TSRH) & 0xFFFFFFF0);
-	out_be32((volatile unsigned *)GPIO0_TSRL, in_be32((volatile unsigned *)GPIO0_TSRL) & 0x3FFFFFFF);
-	/* enable output driver */
-	out_be32((volatile unsigned *)GPIO0_TCR, in_be32((volatile unsigned *)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN |
-		 NAND_EVB_CLE_GPIO_PIN | NAND_EVB_ALE_GPIO_PIN);
-#ifdef USE_READY_BUSY_PIN
-	/* three-state select */
-	out_be32((volatile unsigned *)GPIO0_TSRL, in_be32((volatile unsigned *)GPIO0_TSRL) & 0xFFFFFFFC);
-	/* high-impedecence */
-	out_be32((volatile unsigned *)GPIO0_TCR, in_be32((volatile unsigned *)GPIO0_TCR) & (~NAND_EVB_RB_GPIO_PIN));
-	/* input select */
-	out_be32((volatile unsigned *)GPIO0_ISR1L,
-		 (in_be32((volatile unsigned *)GPIO0_ISR1L) & 0xFFFFFFFC) | 0x00000001);
-#endif
-
-	/* insert callbacks */
-	this->IO_ADDR_R = ppchameleonevb_fio_base;
-	this->IO_ADDR_W = ppchameleonevb_fio_base;
-	this->cmd_ctrl = ppchameleonevb_hwcontrol;
-#ifdef USE_READY_BUSY_PIN
-	this->dev_ready = ppchameleonevb_device_ready;
-#endif
-	this->chip_delay = NAND_SMALL_DELAY_US;
-
-	/* ECC mode */
-	this->ecc.mode = NAND_ECC_SOFT;
-
-	/* Scan to find existence of the device */
-	if (nand_scan(ppchameleonevb_mtd, 1)) {
-		iounmap((void *)ppchameleonevb_fio_base);
-		kfree(ppchameleonevb_mtd);
-		if (ppchameleon_fio_base)
-			iounmap(ppchameleon_fio_base);
-		return -ENXIO;
-	}
-#ifdef CONFIG_MTD_PARTITIONS
-	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;
-#endif
-	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);
-	add_mtd_partitions(ppchameleonevb_mtd, mtd_parts, mtd_parts_nb);
-
-	/* Return happy */
-	return 0;
-}
-
-module_init(ppchameleonevb_init);
-
-/*
- * Clean up routine
- */
-static void __exit ppchameleonevb_cleanup(void)
-{
-	struct nand_chip *this;
-
-	/* Release resources, unregister device(s) */
-	nand_release(ppchameleon_mtd);
-	nand_release(ppchameleonevb_mtd);
-
-	/* Release iomaps */
-	this = (struct nand_chip *) &ppchameleon_mtd[1];
-	iounmap((void *) this->IO_ADDR_R);
-	this = (struct nand_chip *) &ppchameleonevb_mtd[1];
-	iounmap((void *) this->IO_ADDR_R);
-
-	/* Free the MTD device structure */
-	kfree (ppchameleon_mtd);
-	kfree (ppchameleonevb_mtd);
-}
-module_exit(ppchameleonevb_cleanup);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("DAVE Srl <support-ppchameleon at dave-tech.it>");
-MODULE_DESCRIPTION("MTD map driver for DAVE Srl PPChameleonEVB board");
diff --git a/drivers/mtd/nand/toto.c b/drivers/mtd/nand/toto.c
deleted file mode 100644
index f9e2d4a..0000000
--- a/drivers/mtd/nand/toto.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- *  drivers/mtd/nand/toto.c
- *
- *  Copyright (c) 2003 Texas Instruments
- *
- *  Derived from drivers/mtd/autcpu12.c
- *
- *  Copyright (c) 2002 Thomas Gleixner <tgxl at linutronix.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
- *   TI fido board. It supports 32MiB and 64MiB cards
- *
- * $Id: toto.c,v 1.5 2005/11/07 11:14:31 gleixner Exp $
- */
-
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/partitions.h>
-#include <asm/io.h>
-#include <asm/arch/hardware.h>
-#include <asm/sizes.h>
-#include <asm/arch/toto.h>
-#include <asm/arch-omap1510/hardware.h>
-#include <asm/arch/gpio.h>
-
-#define CONFIG_NAND_WORKAROUND 1
-
-/*
- * MTD structure for TOTO board
- */
-static struct mtd_info *toto_mtd = NULL;
-
-static unsigned long toto_io_base = OMAP_FLASH_1_BASE;
-
-/*
- * Define partitions for flash devices
- */
-
-static struct mtd_partition partition_info64M[] = {
-	{ .name =	"toto kernel partition 1",
-	  .offset =	0,
-	  .size	=	2 * SZ_1M },
-	{ .name =	"toto file sys partition 2",
-	  .offset =	2 * SZ_1M,
-	  .size =	14 * SZ_1M },
-	{ .name =	"toto user partition 3",
-	  .offset =	16 * SZ_1M,
-	  .size =	16 * SZ_1M },
-	{ .name =	"toto devboard extra partition 4",
-	  .offset =	32 * SZ_1M,
-	  .size =	32 * SZ_1M },
-};
-
-static struct mtd_partition partition_info32M[] = {
-	{ .name =	"toto kernel partition 1",
-	  .offset =	0,
-	  .size =	2 * SZ_1M },
-	{ .name =	"toto file sys partition 2",
-	  .offset =	2 * SZ_1M,
-	  .size =	14 * SZ_1M },
-	{ .name =	"toto user partition 3",
-	  .offset =	16 * SZ_1M,
-	  .size =	16 * SZ_1M },
-};
-
-#define NUM_PARTITIONS32M 3
-#define NUM_PARTITIONS64M 4
-
-/*
- *	hardware specific access to control-lines
- *
- *	ctrl:
- *	NAND_NCE: bit 0 -> bit 14 (0x4000)
- *	NAND_CLE: bit 1 -> bit 12 (0x1000)
- *	NAND_ALE: bit 2 -> bit 1  (0x0002)
- */
-static void toto_hwcontrol(struct mtd_info *mtd, int cmd,
-			   unsigned int ctrl)
-{
-	struct nand_chip *chip = mtd->priv;
-
-	if (ctrl & NAND_CTRL_CHANGE) {
-		unsigned long bits;
-
-		/* hopefully enough time for tc make proceding write to clear */
-		udelay(1);
-
-		bits = (~ctrl & NAND_NCE) << 14;
-		bits |= (ctrl & NAND_CLE) << 12;
-		bits |= (ctrl & NAND_ALE) >> 1;
-
-#warning Wild guess as gpiosetout() is nowhere defined in the kernel source - tglx
-		gpiosetout(0x5002, bits);
-
-#ifdef CONFIG_NAND_WORKAROUND
-		/* "some" dev boards busted, blue wired to rts2 :( */
-		rts2setout(2, (ctrl & NAND_CLE) << 1);
-#endif
-		/* allow time to ensure gpio state to over take memory write */
-		udelay(1);
-	}
-
-	if (cmd != NAND_CMD_NONE)
-		writeb(cmd, chip->IO_ADDR_W);
-}
-
-/*
- * Main initialization routine
- */
-static int __init toto_init(void)
-{
-	struct nand_chip *this;
-	int err = 0;
-
-	/* Allocate memory for MTD device structure and private data */
-	toto_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
-	if (!toto_mtd) {
-		printk(KERN_WARNING "Unable to allocate toto NAND MTD device structure.\n");
-		err = -ENOMEM;
-		goto out;
-	}
-
-	/* Get pointer to private data */
-	this = (struct nand_chip *)(&toto_mtd[1]);
-
-	/* Initialize structures */
-	memset(toto_mtd, 0, sizeof(struct mtd_info));
-	memset(this, 0, sizeof(struct nand_chip));
-
-	/* Link the private data with the MTD structure */
-	toto_mtd->priv = this;
-	toto_mtd->owner = THIS_MODULE;
-
-	/* Set address of NAND IO lines */
-	this->IO_ADDR_R = toto_io_base;
-	this->IO_ADDR_W = toto_io_base;
-	this->cmd_ctrl = toto_hwcontrol;
-	this->dev_ready = NULL;
-	/* 25 us command delay time */
-	this->chip_delay = 30;
-	this->ecc.mode = NAND_ECC_SOFT;
-
-	/* Scan to find existance of the device */
-	if (nand_scan(toto_mtd, 1)) {
-		err = -ENXIO;
-		goto out_mtd;
-	}
-
-	/* Register the partitions */
-	switch (toto_mtd->size) {
-	case SZ_64M:
-		add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M);
-		break;
-	case SZ_32M:
-		add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M);
-		break;
-	default:{
-			printk(KERN_WARNING "Unsupported Nand device\n");
-			err = -ENXIO;
-			goto out_buf;
-		}
-	}
-
-	gpioreserve(NAND_MASK);	/* claim our gpios */
-	archflashwp(0, 0);	/* open up flash for writing */
-
-	goto out;
-
- out_mtd:
-	kfree(toto_mtd);
- out:
-	return err;
-}
-
-module_init(toto_init);
-
-/*
- * Clean up routine
- */
-static void __exit toto_cleanup(void)
-{
-	/* Release resources, unregister device */
-	nand_release(toto_mtd);
-
-	/* Free the MTD device structure */
-	kfree(toto_mtd);
-
-	/* stop flash writes */
-	archflashwp(0, 1);
-
-	/* release gpios to system */
-	gpiorelease(NAND_MASK);
-}
-
-module_exit(toto_cleanup);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Richard Woodruff <r-woodruff2 at ti.com>");
-MODULE_DESCRIPTION("Glue layer for NAND flash on toto board");



From dwmw2 at infradead.org  Tue Jan  1 11:30:57 2008
From: dwmw2 at infradead.org (David Woodhouse)
Date: Tue, 01 Jan 2008 16:30:57 +0000
Subject: [2.6 patch] remove broken MTD drivers
In-Reply-To: <20080101134839.GN2360@does.not.exist>
References: <20080101134839.GN2360@does.not.exist>
Message-ID: <1199205057.6315.67.camel@shinybook.infradead.org>

On Tue, 2008-01-01 at 15:48 +0200, Adrian Bunk wrote:
> This patch removes two MTD drivers that have been marked as
> BROKEN 19 months ago due to requiring nonexisting header files.
> 
> Signed-off-by: Adrian Bunk <bunk at kernel.org>

Any particular reason you didn't Cc the authors identified in the
drivers you're removing?

-- 
dwmw2



From wd at denx.de  Tue Jan  1 17:58:04 2008
From: wd at denx.de (Wolfgang Denk)
Date: Tue, 01 Jan 2008 23:58:04 +0100
Subject: [2.6 patch] remove broken MTD drivers
In-Reply-To: Your message of "Tue, 01 Jan 2008 15:48:39 +0200."
	<20080101134839.GN2360@does.not.exist>
Message-ID: <20080101225804.F13AA24889@gemini.denx.de>

In message <20080101134839.GN2360 at does.not.exist> you wrote:
> This patch removes two MTD drivers that have been marked as
> BROKEN 19 months ago due to requiring nonexisting header files.
...
>  drivers/mtd/nand/Kconfig          |   12 
>  drivers/mtd/nand/Makefile         |    2 
>  drivers/mtd/nand/ppchameleonevb.c |  439 ------------------------------

It would have been nice if you had put the autors of the files on Cc:

Regarding the PPChameleon NAND support: I discussed this issue with
tglx on 23 June 2006. Thomas promised to fix the driver if I send him
the missing file and eventually needed patches.

I did so on Fri, 23 Jun 2006 23:23:42 +0200.

Thomas, can you please have a look at this?

If you don't have time / resources please let me know so we can submit
the stuff here on the list...

Thanks.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
"More software projects have gone awry for lack of calendar time than
for all other causes combined."
                         - Fred Brooks, Jr., _The Mythical Man Month_


From bunk at kernel.org  Tue Jan  1 18:11:40 2008
From: bunk at kernel.org (Adrian Bunk)
Date: Wed, 2 Jan 2008 01:11:40 +0200
Subject: [2.6 patch] remove broken MTD drivers
In-Reply-To: <1199205057.6315.67.camel@shinybook.infradead.org>
References: <20080101134839.GN2360@does.not.exist>
	<1199205057.6315.67.camel@shinybook.infradead.org>
Message-ID: <20080101231140.GF27566@does.not.exist>

On Tue, Jan 01, 2008 at 04:30:57PM +0000, David Woodhouse wrote:
> On Tue, 2008-01-01 at 15:48 +0200, Adrian Bunk wrote:
> > This patch removes two MTD drivers that have been marked as
> > BROKEN 19 months ago due to requiring nonexisting header files.
> > 
> > Signed-off-by: Adrian Bunk <bunk at kernel.org>
> 
> Any particular reason you didn't Cc the authors identified in the
> drivers you're removing?

The header of ppchameleonevb.c claims it comes from info at wawnet.biz 
which bounces and the header of toto.c contains as only address Thomas'
address (I took the wrong one from the commit, but bounced the email
to him).

> dwmw2

cu
Adrian

-- 

       "Is there not promise of rain?" Ling Tan asked suddenly out
        of the darkness. There had been need of rain for many days.
       "Only a promise," Lao Er said.
                                       Pearl S. Buck - Dragon Seed



From wd at denx.de  Tue Jan  1 19:28:26 2008
From: wd at denx.de (Wolfgang Denk)
Date: Wed, 02 Jan 2008 01:28:26 +0100
Subject: [2.6 patch] remove broken MTD drivers
In-Reply-To: Your message of "Wed, 02 Jan 2008 01:11:40 +0200."
	<20080101231140.GF27566@does.not.exist>
Message-ID: <20080102002826.574C324889@gemini.denx.de>

In message <20080101231140.GF27566 at does.not.exist> you wrote:
>
> The header of ppchameleonevb.c claims it comes from info at wawnet.biz 

Argh. That's indeed ancient code.

So what should I do to fix this? Wait for Thomas' response, or port
patches here?

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
A Chairman was as necessary to a Board planet  as  the  zero  was  in
mathematics, but being a zero had big disadvantages...
                         - Terry Pratchett, _The Dark Side of the Sun_


From bunk at kernel.org  Tue Jan  1 19:37:24 2008
From: bunk at kernel.org (Adrian Bunk)
Date: Wed, 2 Jan 2008 02:37:24 +0200
Subject: [2.6 patch] remove broken MTD drivers
In-Reply-To: <20080102002826.574C324889@gemini.denx.de>
References: <20080101231140.GF27566@does.not.exist>
	<20080102002826.574C324889@gemini.denx.de>
Message-ID: <20080102003724.GL27566@does.not.exist>

On Wed, Jan 02, 2008 at 01:28:26AM +0100, Wolfgang Denk wrote:
> In message <20080101231140.GF27566 at does.not.exist> you wrote:
> >
> > The header of ppchameleonevb.c claims it comes from info at wawnet.biz 
> 
> Argh. That's indeed ancient code.
> 
> So what should I do to fix this? Wait for Thomas' response, or port
> patches here?

I'd say post patches, and I'd expect David to actually be the one who
reviews and incorporates them.

> Best regards,
> 
> Wolfgang Denk

cu
Adrian

-- 

       "Is there not promise of rain?" Ling Tan asked suddenly out
        of the darkness. There had been need of rain for many days.
       "Only a promise," Lao Er said.
                                       Pearl S. Buck - Dragon Seed



From nancydreaming at gmail.com  Tue Jan  1 20:42:29 2008
From: nancydreaming at gmail.com (Nancy)
Date: Wed, 2 Jan 2008 09:42:29 +0800
Subject: Does UBI support MLC nand flash?
Message-ID: <bae050c10801011742s762cd289ta9aae5881e294598@mail.gmail.com>

Sir / Madam,

             Does UBI support MLC nand flash?

             According to the MLC nand spec, It is only allowed write
once per erased
block, moreover, it isn't allowed ramdom write during a block, means
the page number must be increase during the write PED operation.


--
Best Regards,
Nancy


From kmpark at infradead.org  Tue Jan  1 23:45:01 2008
From: kmpark at infradead.org (Kyungmin Park)
Date: Wed, 2 Jan 2008 13:45:01 +0900
Subject: Does UBI support MLC nand flash?
In-Reply-To: <bae050c10801011742s762cd289ta9aae5881e294598@mail.gmail.com>
References: <bae050c10801011742s762cd289ta9aae5881e294598@mail.gmail.com>
Message-ID: <002601c84cfa$7886bc10$1fa9580a@swcenter.sec.samsung.co.kr>

Hi,

I think it can support MLC NAND in the code.
The big differences between the SLC and MLC are NOP (or subpage) and POR handling.

Generally SLC has NOP 4 (old chips have 8) whereas MLC has NOP 1.
In NAND code, it handles with NAND_NO_SUBPAGE_WRITE and NAND_CI_CELLTYPE_MSK.
Umm, who uses the NAND_NO_SUBPAGE_WRITE in code?
Anyway it maybe checks it with the CELLTYPE from 3rd ID data.

And sequential write is also only permitted at large page SLC NAND. It means it's working well on MLC NAND in current UBI code. If
not, it also doesn't work at SLC NAND.

Thank you,
Kyungmin Park

-----Original Message-----
From: linux-mtd-bounces at lists.infradead.org [mailto:linux-mtd-bounces at lists.infradead.org] On Behalf Of Nancy
Sent: Wednesday, January 02, 2008 10:42 AM
To: linux-mtd at lists.infradead.org
Subject: Does UBI support MLC nand flash?

Sir / Madam,

             Does UBI support MLC nand flash?

             According to the MLC nand spec, It is only allowed write
once per erased
block, moreover, it isn't allowed ramdom write during a block, means
the page number must be increase during the write PED operation.


--
Best Regards,
Nancy

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/



From nancydreaming at gmail.com  Wed Jan  2 01:13:07 2008
From: nancydreaming at gmail.com (Nancy)
Date: Wed, 2 Jan 2008 14:13:07 +0800
Subject: Does UBI support MLC nand flash?
In-Reply-To: <002601c84cfa$7886bc10$1fa9580a@swcenter.sec.samsung.co.kr>
References: <bae050c10801011742s762cd289ta9aae5881e294598@mail.gmail.com>
	<002601c84cfa$7886bc10$1fa9580a@swcenter.sec.samsung.co.kr>
Message-ID: <bae050c10801012213p2c7d630r6efcf5c1f77b78df@mail.gmail.com>

Sir,
     I don't know what is NOP, POP stand for? can you explain that?

     I notice mtd-utils "nandwrite.c" does write each page's oob area
twice, write oob(filesystem area) once, and then call "pwrite" to
write pagedata including oob (ecc part). I don't think that will work
right on MLC nand.


--
Best Regards,
Nancy


From nancydreaming at gmail.com  Wed Jan  2 01:19:16 2008
From: nancydreaming at gmail.com (Nancy)
Date: Wed, 2 Jan 2008 14:19:16 +0800
Subject: Does UBI support MLC nand flash?
In-Reply-To: <bae050c10801012213p2c7d630r6efcf5c1f77b78df@mail.gmail.com>
References: <bae050c10801011742s762cd289ta9aae5881e294598@mail.gmail.com>
	<002601c84cfa$7886bc10$1fa9580a@swcenter.sec.samsung.co.kr>
	<bae050c10801012213p2c7d630r6efcf5c1f77b78df@mail.gmail.com>
Message-ID: <bae050c10801012219m71d7415du4379e5b5d5a54560@mail.gmail.com>

oh, forgot to metion UBI.
UBI has two headers for each LED/PED, they are not write at same time.
Is that against MLC nand's no ramdom write and  write only once
permission?

--
Best Regards,
Nancy


From davidb at davidb.org  Wed Jan  2 02:11:14 2008
From: davidb at davidb.org (David Brown)
Date: Tue, 1 Jan 2008 23:11:14 -0800
Subject: Does UBI support MLC nand flash?
In-Reply-To: <bae050c10801012213p2c7d630r6efcf5c1f77b78df@mail.gmail.com>
References: <bae050c10801011742s762cd289ta9aae5881e294598@mail.gmail.com>
	<002601c84cfa$7886bc10$1fa9580a@swcenter.sec.samsung.co.kr>
	<bae050c10801012213p2c7d630r6efcf5c1f77b78df@mail.gmail.com>
Message-ID: <20080102071114.GA9207@old.davidb.org>

On Wed, Jan 02, 2008 at 02:13:07PM +0800, Nancy wrote:

>I notice mtd-utils "nandwrite.c" does write each page's oob area
>twice, write oob(filesystem area) once, and then call "pwrite" to
>write pagedata including oob (ecc part). I don't think that will work
>right on MLC nand.

The underlying driver will have to support cached writes for this to work.
It's listed as a TODO in nand_base.c, at least in the stable kernel.

Dave


From mtd at davidb.org  Wed Jan  2 02:13:06 2008
From: mtd at davidb.org (David Brown)
Date: Tue, 1 Jan 2008 23:13:06 -0800
Subject: Does UBI support MLC nand flash?
In-Reply-To: <bae050c10801012219m71d7415du4379e5b5d5a54560@mail.gmail.com>
References: <bae050c10801011742s762cd289ta9aae5881e294598@mail.gmail.com>
	<002601c84cfa$7886bc10$1fa9580a@swcenter.sec.samsung.co.kr>
	<bae050c10801012213p2c7d630r6efcf5c1f77b78df@mail.gmail.com>
	<bae050c10801012219m71d7415du4379e5b5d5a54560@mail.gmail.com>
Message-ID: <20080102071306.GA10292@old.davidb.org>

On Wed, Jan 02, 2008 at 02:19:16PM +0800, Nancy wrote:
>oh, forgot to metion UBI.
>UBI has two headers for each LED/PED, they are not write at same time.
>Is that against MLC nand's no ramdom write and  write only once
>permission?

Yes.  Perhaps one could be written at the beginning of the block and one
always written at the end of the block.  It wastes more pages that way,
though.

If the second write is only to indicate that the block is invalid, it
_might_ be permissible to write it out of order, since the out of order
write might only corrupt data.  Depending on underlying device
implementation, it might also just not work, though.

Dave


From kmpark at infradead.org  Wed Jan  2 02:23:31 2008
From: kmpark at infradead.org (Kyungmin Park)
Date: Wed, 2 Jan 2008 16:23:31 +0900
Subject: Does UBI support MLC nand flash?
In-Reply-To: <bae050c10801012213p2c7d630r6efcf5c1f77b78df@mail.gmail.com>
References: <bae050c10801011742s762cd289ta9aae5881e294598@mail.gmail.com>
	<002601c84cfa$7886bc10$1fa9580a@swcenter.sec.samsung.co.kr>
	<bae050c10801012213p2c7d630r6efcf5c1f77b78df@mail.gmail.com>
Message-ID: <003c01c84d10$9cb210b0$1fa9580a@swcenter.sec.samsung.co.kr>

Hi,

Refer to previous mail [1,2] related with terminology.

We have to check the flash type & flags such as MTD_OOB_WRITEABLE in mtd-utils too. Or use the mtd_ops to write main and oob
simultaneously if the detected chip is MLC.

Thank you,
Kyungmin Park

1. http://lists.infradead.org/pipermail/linux-mtd/2007-December/020041.html
2. http://git.infradead.org/?p=users/kmpark/onenand-mtd-2.6.git;a=commitdiff;h=4dbecbd80d346f9f6cd5284fb423f5c62bdbc750


-----Original Message-----
From: linux-mtd-bounces at lists.infradead.org [mailto:linux-mtd-bounces at lists.infradead.org] On Behalf Of Nancy
Sent: Wednesday, January 02, 2008 3:13 PM
To: kmpark at infradead.org
Cc: linux-mtd at lists.infradead.org
Subject: Re: Does UBI support MLC nand flash?

Sir,
     I don't know what is NOP, POP stand for? can you explain that?

     I notice mtd-utils "nandwrite.c" does write each page's oob area
twice, write oob(filesystem area) once, and then call "pwrite" to
write pagedata including oob (ecc part). I don't think that will work
right on MLC nand.


--
Best Regards,
Nancy

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/



From mtd at davidb.org  Wed Jan  2 02:27:18 2008
From: mtd at davidb.org (David Brown)
Date: Tue, 1 Jan 2008 23:27:18 -0800
Subject: Does UBI support MLC nand flash?
In-Reply-To: <bae050c10801012213p2c7d630r6efcf5c1f77b78df@mail.gmail.com>
References: <bae050c10801011742s762cd289ta9aae5881e294598@mail.gmail.com>
	<002601c84cfa$7886bc10$1fa9580a@swcenter.sec.samsung.co.kr>
	<bae050c10801012213p2c7d630r6efcf5c1f77b78df@mail.gmail.com>
Message-ID: <20080102072715.GA11408@old.davidb.org>

On Wed, Jan 02, 2008 at 02:13:07PM +0800, Nancy wrote:

>I notice mtd-utils "nandwrite.c" does write each page's oob area
>twice, write oob(filesystem area) once, and then call "pwrite" to
>write pagedata including oob (ecc part). I don't think that will work
>right on MLC nand.

The underlying driver will have to support cached writes for this to work.
It's listed as a TODO in nand_base.c, at least in the stable kernel.

Dave


From nancydreaming at gmail.com  Wed Jan  2 04:36:08 2008
From: nancydreaming at gmail.com (Nancy)
Date: Wed, 2 Jan 2008 17:36:08 +0800
Subject: Does UBI support MLC nand flash?
In-Reply-To: <bae050c10801020133h3b121b2ft47911a0d84921868@mail.gmail.com>
References: <bae050c10801011742s762cd289ta9aae5881e294598@mail.gmail.com>
	<002601c84cfa$7886bc10$1fa9580a@swcenter.sec.samsung.co.kr>
	<bae050c10801012213p2c7d630r6efcf5c1f77b78df@mail.gmail.com>
	<003c01c84d10$9cb210b0$1fa9580a@swcenter.sec.samsung.co.kr>
	<bae050c10801020133h3b121b2ft47911a0d84921868@mail.gmail.com>
Message-ID: <bae050c10801020136s4a6c95a2h9826479f27a75503@mail.gmail.com>

Thank you, Mr. Kyungmin Park
But we do not use JFFS2, if UBI supports MLC nand well, we decide to
use UBIFS instead of current YAFFS2.

We use "nandwrite" for nandflash content's burning. That's more faster
and easiser than do the same job under filesystem support(mount, cp
....)

MTD code change a lot in 2.6 kernel. In old verion of MTD, we added a
MEMWRITEPAGE ioctl to call nand_write_ecc(nand_base.c) whose parameter
"eccbuf" can be offered for fs use. But in the latest version of MTD
code, I can't find a function call meet our needs.

If UBI do not support MLC, we will still use our old one. Faking VFAT
fs info( erase count and virtual block number) must write to oob area,
and ...that's MLC nand, nandwrite.c have to be change.

Oh, MLC nand's badblock tag is  in the last page of earseblock's oob.
some related code have to be changed too.

I write this only for the interface designer reconsider it.

Thanks for all the people who reply me :-)


From nancydreaming at gmail.com  Wed Jan  2 04:37:09 2008
From: nancydreaming at gmail.com (Nancy)
Date: Wed, 2 Jan 2008 17:37:09 +0800
Subject: Does UBI support MLC nand flash?
In-Reply-To: <bae050c10801020136s4a6c95a2h9826479f27a75503@mail.gmail.com>
References: <bae050c10801011742s762cd289ta9aae5881e294598@mail.gmail.com>
	<002601c84cfa$7886bc10$1fa9580a@swcenter.sec.samsung.co.kr>
	<bae050c10801012213p2c7d630r6efcf5c1f77b78df@mail.gmail.com>
	<003c01c84d10$9cb210b0$1fa9580a@swcenter.sec.samsung.co.kr>
	<bae050c10801020133h3b121b2ft47911a0d84921868@mail.gmail.com>
	<bae050c10801020136s4a6c95a2h9826479f27a75503@mail.gmail.com>
Message-ID: <bae050c10801020137t141ceaf7i19ba5297411feb7c@mail.gmail.com>

Thank you, Mr. Kyungmin Park
But we do not use JFFS2, if UBI supports MLC nand well, we decide to
use UBIFS instead of current YAFFS2.

We use "nandwrite" for nandflash content's burning. That's more faster
and easiser than do the same job under filesystem support(mount, cp
....)

MTD code change a lot in 2.6 kernel. In old verion of MTD, we added a
MEMWRITEPAGE ioctl to call nand_write_ecc(nand_base.c) whose parameter
"eccbuf" can be offered for fs use. But in the latest version of MTD
code, I can't find a function call meet our needs.

If UBI do not support MLC, we will still use our old one. Faking VFAT
fs info( erase count and virtual block number) must write to oob area,
and ...that's MLC nand, nandwrite.c have to be change.

Oh, MLC nand's badblock tag is  in the last page of earseblock's oob.
some related code have to be changed too.

I write this only for the interface designer reconsider it.

Thanks for all the people who reply me :-)


From jwboyer at linux.vnet.ibm.com  Wed Jan  2 07:39:45 2008
From: jwboyer at linux.vnet.ibm.com (Josh Boyer)
Date: Wed, 2 Jan 2008 06:39:45 -0600
Subject: Does UBI support MLC nand flash?
In-Reply-To: <bae050c10801012219m71d7415du4379e5b5d5a54560@mail.gmail.com>
References: <bae050c10801011742s762cd289ta9aae5881e294598@mail.gmail.com>
	<002601c84cfa$7886bc10$1fa9580a@swcenter.sec.samsung.co.kr>
	<bae050c10801012213p2c7d630r6efcf5c1f77b78df@mail.gmail.com>
	<bae050c10801012219m71d7415du4379e5b5d5a54560@mail.gmail.com>
Message-ID: <20080102063945.5355d112@zod.rchland.ibm.com>

On Wed, 2 Jan 2008 14:19:16 +0800
Nancy <nancydreaming at gmail.com> wrote:

> oh, forgot to metion UBI.
> UBI has two headers for each LED/PED, they are not write at same time.
> Is that against MLC nand's no ramdom write and  write only once
> permission?

Not to my knowledge.  The second header is written to the second page
in the block if subpage writes aren't supported by the underlying
chip.  That should still work fine for MLC.

josh


From ext-adrian.hunter at nokia.com  Wed Jan  2 08:46:29 2008
From: ext-adrian.hunter at nokia.com (Adrian Hunter)
Date: Wed, 02 Jan 2008 15:46:29 +0200
Subject: Does UBI support MLC nand flash?
In-Reply-To: <bae050c10801011742s762cd289ta9aae5881e294598@mail.gmail.com>
References: <bae050c10801011742s762cd289ta9aae5881e294598@mail.gmail.com>
Message-ID: <477B95B5.2030509@nokia.com>

ext Nancy wrote:
> Sir / Madam,
> 
>              Does UBI support MLC nand flash?
> 
>              According to the MLC nand spec, It is only allowed write
> once per erased
> block, moreover, it isn't allowed ramdom write during a block, means
> the page number must be increase during the write PED operation.
> 
> 
> --
> Best Regards,
> Nancy
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/

As Artem is on holiday, I am replying to this.

UBI (and UBIFS) write sequentially to NAND pages within an eraseblock so there should be no problem with MLC NAND.

However the driver must not set up subpages because UBI will prefer to write subpages if they are available.



From davidb at davidb.org  Wed Jan  2 11:52:28 2008
From: davidb at davidb.org (David Brown)
Date: Wed, 2 Jan 2008 08:52:28 -0800
Subject: Does UBI support MLC nand flash?
In-Reply-To: <20080102063945.5355d112@zod.rchland.ibm.com>
References: <bae050c10801011742s762cd289ta9aae5881e294598@mail.gmail.com>
	<002601c84cfa$7886bc10$1fa9580a@swcenter.sec.samsung.co.kr>
	<bae050c10801012213p2c7d630r6efcf5c1f77b78df@mail.gmail.com>
	<bae050c10801012219m71d7415du4379e5b5d5a54560@mail.gmail.com>
	<20080102063945.5355d112@zod.rchland.ibm.com>
Message-ID: <20080102165228.GA11327@old.davidb.org>

On Wed, Jan 02, 2008 at 06:39:45AM -0600, Josh Boyer wrote:
>On Wed, 2 Jan 2008 14:19:16 +0800
>Nancy <nancydreaming at gmail.com> wrote:
>
>> oh, forgot to metion UBI.
>> UBI has two headers for each LED/PED, they are not write at same time.
>> Is that against MLC nand's no ramdom write and  write only once
>> permission?
>
>Not to my knowledge.  The second header is written to the second page
>in the block if subpage writes aren't supported by the underlying
>chip.  That should still work fine for MLC.

Many MLC devices will not allow you to write to the second page after
having written to the third or subsequent pages.  Would this still work?

Dave


From jwboyer at linux.vnet.ibm.com  Wed Jan  2 12:13:00 2008
From: jwboyer at linux.vnet.ibm.com (Josh Boyer)
Date: Wed, 2 Jan 2008 11:13:00 -0600
Subject: Does UBI support MLC nand flash?
In-Reply-To: <20080102165228.GA11327@old.davidb.org>
References: <bae050c10801011742s762cd289ta9aae5881e294598@mail.gmail.com>
	<002601c84cfa$7886bc10$1fa9580a@swcenter.sec.samsung.co.kr>
	<bae050c10801012213p2c7d630r6efcf5c1f77b78df@mail.gmail.com>
	<bae050c10801012219m71d7415du4379e5b5d5a54560@mail.gmail.com>
	<20080102063945.5355d112@zod.rchland.ibm.com>
	<20080102165228.GA11327@old.davidb.org>
Message-ID: <20080102111300.544ea5cb@zod.rchland.ibm.com>

On Wed, 2 Jan 2008 08:52:28 -0800
David Brown <davidb at davidb.org> wrote:

> On Wed, Jan 02, 2008 at 06:39:45AM -0600, Josh Boyer wrote:
> >On Wed, 2 Jan 2008 14:19:16 +0800
> >Nancy <nancydreaming at gmail.com> wrote:
> >
> >> oh, forgot to metion UBI.
> >> UBI has two headers for each LED/PED, they are not write at same time.
> >> Is that against MLC nand's no ramdom write and  write only once
> >> permission?
> >
> >Not to my knowledge.  The second header is written to the second page
> >in the block if subpage writes aren't supported by the underlying
> >chip.  That should still work fine for MLC.
> 
> Many MLC devices will not allow you to write to the second page after
> having written to the third or subsequent pages.  Would this still work?

Yes... UBI doesn't write actual data to the blocks until both headers
are in place.

josh


From mtd at davidb.org  Wed Jan  2 12:17:28 2008
From: mtd at davidb.org (David Brown)
Date: Wed, 2 Jan 2008 09:17:28 -0800
Subject: Does UBI support MLC nand flash?
In-Reply-To: <20080102111300.544ea5cb@zod.rchland.ibm.com>
References: <bae050c10801011742s762cd289ta9aae5881e294598@mail.gmail.com>
	<002601c84cfa$7886bc10$1fa9580a@swcenter.sec.samsung.co.kr>
	<bae050c10801012213p2c7d630r6efcf5c1f77b78df@mail.gmail.com>
	<bae050c10801012219m71d7415du4379e5b5d5a54560@mail.gmail.com>
	<20080102063945.5355d112@zod.rchland.ibm.com>
	<20080102165228.GA11327@old.davidb.org>
	<20080102111300.544ea5cb@zod.rchland.ibm.com>
Message-ID: <20080102171728.GA13503@old.davidb.org>

On Wed, Jan 02, 2008 at 11:13:00AM -0600, Josh Boyer wrote:
>On Wed, 2 Jan 2008 08:52:28 -0800
>David Brown <davidb at davidb.org> wrote:
>
>> On Wed, Jan 02, 2008 at 06:39:45AM -0600, Josh Boyer wrote:
>> >On Wed, 2 Jan 2008 14:19:16 +0800
>> >Nancy <nancydreaming at gmail.com> wrote:
>> >
>> >> oh, forgot to metion UBI.
>> >> UBI has two headers for each LED/PED, they are not write at same time.
>> >> Is that against MLC nand's no ramdom write and  write only once
>> >> permission?
>> >
>> >Not to my knowledge.  The second header is written to the second page
>> >in the block if subpage writes aren't supported by the underlying
>> >chip.  That should still work fine for MLC.
>> 
>> Many MLC devices will not allow you to write to the second page after
>> having written to the third or subsequent pages.  Would this still work?
>
>Yes... UBI doesn't write actual data to the blocks until both headers
>are in place.

I guess I need to read up more.  I though the second header was written
after the data had been written.  In that case, it would probably be fine.

Dave


From kyungmin.park at samsung.com  Wed Jan  2 19:03:50 2008
From: kyungmin.park at samsung.com (Kyungmin Park)
Date: Thu, 3 Jan 2008 09:03:50 +0900
Subject: [PATCH] [MTD][OneNAND] Multi Level Chip (MLC) OneNAND support
Message-ID: <20080103000350.GA12237@party>

This patch enables the MLC OneNAND support
Now it's basic support. We need to work more.

In MLC, we use the 4KiB BufferRam instead of 2KiB.
With this reason it is changed to read/write data from/to BufferRAM 0 and
we can't use read-while-load.

It passed the nand-tests module and it diffed against the OneNAND MTD tree instead of MTD one.

Any comments are welcome.

Thank you,
Kyungmin Park

Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
---
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 9d00e0b..27c9dcc 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -235,7 +235,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
 		value = onenand_bufferram_address(this, block);
 		this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
 
-		if (ONENAND_IS_2PLANE(this))
+		if (ONENAND_IS_MLC(this) || ONENAND_IS_2PLANE(this))
 			/* It is always BufferRAM0 */
 			ONENAND_SET_BUFFERRAM0(this);
 		else
@@ -257,13 +257,17 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
 
 	if (page != -1) {
 		/* Now we use page size operation */
-		int sectors = 4, count = 4;
+		int sectors = 0, count = 0;
 		int dataram;
 
 		switch (cmd) {
 		case ONENAND_CMD_READ:
 		case ONENAND_CMD_READOOB:
-			dataram = ONENAND_SET_NEXT_BUFFERRAM(this);
+			if (ONENAND_IS_MLC(this))
+				/* It is always BufferRAM0 */
+				dataram = ONENAND_SET_BUFFERRAM0(this);
+			else
+				dataram = ONENAND_SET_NEXT_BUFFERRAM(this);
 			break;
 
 		default:
@@ -849,6 +853,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
 	stats = mtd->ecc_stats;
 
  	/* Read-while-load method */
+	/* Note: We can't use this feature in MLC */
 
  	/* Do first load to bufferRAM */
  	if (read < len) {
@@ -869,7 +874,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
  	while (!ret) {
  		/* If there is more to load then start next load */
  		from += thislen;
- 		if (read + thislen < len) {
+		/* REVISIT: How to handle more fancy both SLC and MLC */
+ 		if (!ONENAND_IS_MLC(this) && read + thislen < len) {
 			this->command(mtd, ONENAND_CMD_READ, from, writesize);
  			/*
  			 * Chip boundary handling in DDP
@@ -901,6 +907,14 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
 			oobcolumn = 0;
 		}
 
+		if (ONENAND_IS_MLC(this) && (read + thislen < len)) {
+			this->command(mtd, ONENAND_CMD_READ, from, writesize);
+ 			ret = this->wait(mtd, FL_READING);
+ 			onenand_update_bufferram(mtd, from, !ret);
+			if (ret == -EBADMSG)
+				ret = 0;
+		}
+
  		/* See if we are done */
  		read += thislen;
  		if (read == len)
@@ -908,16 +922,19 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
  		/* Set up for next read from bufferRAM */
  		if (unlikely(boundary))
  			this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
- 		ONENAND_SET_NEXT_BUFFERRAM(this);
+		if (!ONENAND_IS_MLC(this))
+			ONENAND_SET_NEXT_BUFFERRAM(this);
  		buf += thislen;
 		thislen = min_t(int, writesize, len - read);
  		column = 0;
  		cond_resched();
- 		/* Now wait for load */
- 		ret = this->wait(mtd, FL_READING);
- 		onenand_update_bufferram(mtd, from, !ret);
-		if (ret == -EBADMSG)
-			ret = 0;
+		if (!ONENAND_IS_MLC(this)) {
+ 			/* Now wait for load in SLC */
+			ret = this->wait(mtd, FL_READING);
+			onenand_update_bufferram(mtd, from, !ret);
+			if (ret == -EBADMSG)
+				ret = 0;
+		}
  	}
 
 	/*
@@ -954,7 +971,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
 	size_t len = ops->ooblen;
 	mtd_oob_mode_t mode = ops->mode;
 	u_char *buf = ops->oobbuf;
-	int ret = 0;
+	int ret = 0, readcmd;
 
 	from += ops->ooboffs;
 
@@ -985,13 +1002,15 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
 
 	stats = mtd->ecc_stats;
 
+	readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
+
 	while (read < len) {
 		cond_resched();
 
 		thislen = oobsize - column;
 		thislen = min_t(int, thislen, len);
 
-		this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
+		this->command(mtd, readcmd, from, mtd->oobsize);
 
 		onenand_update_bufferram(mtd, from, 0);
 
@@ -1151,7 +1170,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
 {
 	struct onenand_chip *this = mtd->priv;
 	int read = 0, thislen, column;
-	int ret = 0;
+	int ret = 0, readcmd;
 	size_t len = ops->ooblen;
 	u_char *buf = ops->oobbuf;
 
@@ -1171,13 +1190,15 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
 
 	column = from & (mtd->oobsize - 1);
 
+	readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
+
 	while (read < len) {
 		cond_resched();
 
 		thislen = mtd->oobsize - column;
 		thislen = min_t(int, thislen, len);
 
-		this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
+		this->command(mtd, readcmd, from, mtd->oobsize);
 
 		onenand_update_bufferram(mtd, from, 0);
 
@@ -1218,9 +1239,11 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to
 {
 	struct onenand_chip *this = mtd->priv;
 	u_char *oob_buf = this->oob_buf;
-	int status, i;
+	int status, i, readcmd;
 
-	this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize);
+	readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
+
+	this->command(mtd, readcmd, to, mtd->oobsize);
 	onenand_update_bufferram(mtd, to, 0);
 	status = this->wait(mtd, FL_READING);
 	if (status)
@@ -1471,7 +1494,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
 {
 	struct onenand_chip *this = mtd->priv;
 	int column, ret = 0, oobsize;
-	int written = 0;
+	int written = 0, oobcmd;
 	u_char *oobbuf;
 	size_t len = ops->ooblen;
 	const u_char *buf = ops->oobbuf;
@@ -1484,6 +1507,8 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
 	/* Initialize retlen, in case of early exit */
 	ops->oobretlen = 0;
 
+	WARN_ON_ONCE(ONENAND_IS_MLC(this));
+
 	if (mode == MTD_OOB_AUTO)
 		oobsize = this->ecclayout->oobavail;
 	else
@@ -1513,6 +1538,8 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
 
 	oobbuf = this->oob_buf;
 
+	oobcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB;
+
 	/* Loop until all data write */
 	while (written < len) {
 		int thislen = min_t(int, oobsize, len - written);
@@ -1530,7 +1557,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
 			memcpy(oobbuf + column, buf, thislen);
 		this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
 
-		this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
+		this->command(mtd, oobcmd, to, mtd->oobsize);
 
 		onenand_update_bufferram(mtd, to, 0);
 		if (ONENAND_IS_2PLANE(this)) {
@@ -1999,7 +2026,7 @@ static int onenand_unlock_all(struct mtd_info *mtd)
 		if (ONENAND_IS_DDP(this)) {
 			/* 1st block on another chip */
 			loff_t ofs = this->chipsize >> 1;
-			size_t len = mtd->erasesize;
+			size_t len = this->chipsize >> 1;
 
 			onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
 		}
@@ -2378,6 +2405,9 @@ static void onenand_check_features(struct mtd_info *mtd)
 		break;
 	}
 
+	if (ONENAND_IS_MLC(this))
+		this->options &= ~ONENAND_HAS_2PLANE;
+
 	if (this->options & ONENAND_HAS_CONT_LOCK)
 		printk(KERN_DEBUG "Lock scheme is Continuous Lock\n");
 	if (this->options & ONENAND_HAS_UNLOCK_ALL)
@@ -2482,6 +2512,7 @@ static int onenand_probe(struct mtd_info *mtd)
 	maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
 	dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
 	ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
+	this->technology = this->read_word(this->base + ONENAND_REG_TECHNOLOGY);
 
 	/* Check OneNAND device */
 	if (maf_id != bram_maf_id || dev_id != bram_dev_id)
@@ -2503,6 +2534,10 @@ static int onenand_probe(struct mtd_info *mtd)
 	/* OneNAND page size & block size */
 	/* The data buffer size is equal to page size */
 	mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
+	/* We use the full BufferRAM */
+	if (ONENAND_IS_MLC(this))
+		mtd->writesize <<= 1;
+
 	mtd->oobsize = mtd->writesize >> 5;
 	/* Pages per a block are always 64 in OneNAND */
 	mtd->erasesize = mtd->writesize << 6;
@@ -2571,7 +2606,7 @@ static void onenand_resume(struct mtd_info *mtd)
 int onenand_scan(struct mtd_info *mtd, int maxchips)
 {
 	struct onenand_chip *this = mtd->priv;
-	int i, MLC;
+	int i;
 
 	if (!this->read_word)
 		this->read_word = onenand_readw;
@@ -2627,12 +2662,15 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
 	this->state = FL_READY;
 	init_waitqueue_head(&this->wq);
 	spin_lock_init(&this->chip_lock);
-	MLC = this->read_word(this->base + ONENAND_REG_TECHNOLOGY);
 
 	/*
 	 * Allow subpage writes up to oobsize.
 	 */
 	switch (mtd->oobsize) {
+	case 128:
+		/* REVISIT: Define the onenand_oob_128 */
+		break;
+
 	case 64:
 		this->ecclayout = &onenand_oob_64;
 		mtd->subpage_sft = 2;
@@ -2653,7 +2691,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
 	}
 
 	/* Don't allow the sub-page write in MLC */
-	if (MLC)
+	if (ONENAND_IS_MLC(this))
 		mtd->subpage_sft = 0;
 
 	this->subpagesize = mtd->writesize >> mtd->subpage_sft;
@@ -2674,7 +2712,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
 	/* Fill in remaining MTD driver data */
 	mtd->type = MTD_NANDFLASH;
 	mtd->flags = MTD_CAP_NANDFLASH;
-	if (MLC)
+	if (ONENAND_IS_MLC(this))
 		mtd->flags &= ~MTD_OOB_WRITEABLE;
 	mtd->erase = onenand_erase;
 	mtd->point = NULL;
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index fd0a260..cfc8e88 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -95,6 +95,7 @@ struct onenand_chip {
 	unsigned int		chipsize;
 	unsigned int		device_id;
 	unsigned int		version_id;
+	unsigned int		technology;
 	unsigned int		density_mask;
 	unsigned int		options;
 
@@ -153,6 +154,9 @@ struct onenand_chip {
 #define ONENAND_IS_DDP(this)						\
 	(this->device_id & ONENAND_DEVICE_IS_DDP)
 
+#define ONENAND_IS_MLC(this)						\
+	(this->technology & ONENAND_TECHNOLOGY_IS_MLC)			\
+
 #ifdef CONFIG_MTD_ONENAND_2X_PROGRAM
 #define ONENAND_IS_2PLANE(this)						\
 	(this->options & ONENAND_HAS_2PLANE)
diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h
index d1b310c..2d24a95 100644
--- a/include/linux/mtd/onenand_regs.h
+++ b/include/linux/mtd/onenand_regs.h
@@ -84,6 +84,11 @@
 #define ONENAND_VERSION_PROCESS_SHIFT	(8)
 
 /*
+ * Technology Register F006h (R)
+ */
+#define ONENAND_TECHNOLOGY_IS_MLC	(1 << 0)
+
+/*
  * Start Address 1 F100h (R/W) & Start Address 2 F101h (R/W)
  */
 #define ONENAND_DDP_SHIFT		(15)
@@ -93,7 +98,8 @@
 /*
  * Start Address 8 F107h (R/W)
  */
-#define ONENAND_FPA_MASK		(0x3f)
+/* Note: It's actually 0x3f in case of SLC */
+#define ONENAND_FPA_MASK		(0x7f)
 #define ONENAND_FPA_SHIFT		(2)
 #define ONENAND_FSA_MASK		(0x03)
 
@@ -105,7 +111,8 @@
 #define ONENAND_BSA_BOOTRAM		(0 << 2)
 #define ONENAND_BSA_DATARAM0		(2 << 2)
 #define ONENAND_BSA_DATARAM1		(3 << 2)
-#define ONENAND_BSC_MASK		(0x03)
+/* Note: It's actually 0x03 in case of SLC */
+#define ONENAND_BSC_MASK		(0x07)
 
 /*
  * Command Register F220h (R/W)


From kmpark at infradead.org  Thu Jan  3 01:20:08 2008
From: kmpark at infradead.org (Kyungmin Park)
Date: Thu, 3 Jan 2008 15:20:08 +0900
Subject: [PATCH] [MTD][OneNAND] Multi Level Cell (MLC) OneNAND support
In-Reply-To: <20080103000350.GA12237@party>
References: <20080103000350.GA12237@party>
Message-ID: <003101c84dd0$b20be740$1fa9580a@swcenter.sec.samsung.co.kr>

Sorry to bother you
There's a typo in subject.

It should be "Multi Level Cell (MLC)" :)

BR,
Kyungmin Park



From nancydreaming at gmail.com  Thu Jan  3 02:19:18 2008
From: nancydreaming at gmail.com (Nancy)
Date: Thu, 3 Jan 2008 15:19:18 +0800
Subject: Does UBI support MLC nand flash?
In-Reply-To: <20080102171728.GA13503@old.davidb.org>
References: <bae050c10801011742s762cd289ta9aae5881e294598@mail.gmail.com>
	<002601c84cfa$7886bc10$1fa9580a@swcenter.sec.samsung.co.kr>
	<bae050c10801012213p2c7d630r6efcf5c1f77b78df@mail.gmail.com>
	<bae050c10801012219m71d7415du4379e5b5d5a54560@mail.gmail.com>
	<20080102063945.5355d112@zod.rchland.ibm.com>
	<20080102165228.GA11327@old.davidb.org>
	<20080102111300.544ea5cb@zod.rchland.ibm.com>
	<20080102171728.GA13503@old.davidb.org>
Message-ID: <bae050c10801022319y63929958xe367023262517469@mail.gmail.com>

Thanks a lot everyone, your comment really help me a lot !!!
I never though the technical support of opensource can do this good.
I love here :P

Thanks again :-)

--
Best Regards,
Nancy


From x0081444 at ti.com  Thu Jan  3 08:22:29 2008
From: x0081444 at ti.com (Sameer)
Date: Thu, 3 Jan 2008 18:52:29 +0530
Subject: JFFS2 mount problem on NAND flash
Message-ID: <00dc01c84e0b$b10fab20$ec8818ac@ent.ti.com>

Hi,
I am working on omap based board with 16bit, small page Samsung NAND of size 64MB.
I have enabled hardware ecc functionality in the driver code. To test the functionality I run the
Following tests.
1. When the kernel comes up, >>cat /proc/mtd
	mtd0: 00040000 00020000 "bootloader"
	mtd1: 00020000 00020000 "params"
	mtd2: 00200000 00020000 "kernel"
	mtd3: 03da0000 00020000 "filesystem"
	mtd4: 00080000 00004000 "NAND-X-Loader"
	mtd5: 00080000 00004000 "NAND-U-Boot"
	mtd6: 00040000 00004000 "NAND-U-Boot Environment"
	mtd7: 00400000 00004000 "NAND-Kernel"
	mtd8: 03ac0000 00004000 "NAND-File System"
2. I erase the NAND flash filesystem partition
	./flash_eraseall /dev/mtd8
	This function passes. I have verified the erase functionality using the debugger.
3  mount -t jffs2 /dev/mtdblock8 /mnt/nand. I have enabled the low level jffs2 fs debugging
	Following is the error message
			
	JFFS2: Erase block at 0x00000000 is not formatted. It will be erased
	JFFS2: Erase block at 0x00004000 is not formatted. It will be erased
	JFFS2: Erase block at 0x00008000 is not formatted. It will be erased
	JFFS2: Erase block at 0x0000c000 is not formatted. It will be erased
	JFFS2: Erase block at 0x00010000 is not formatted. It will be erased
	JFFS2: Erase block at 0x00014000 is not formatted. It will be erased
	JFFS2: Erase block at 0x00018000 is not formatted. It will be erased
	JFFS2: Erase block at 0x0001c000 is not formatted. It will be erased
					     -----
						=----
					upto--

	JFFS2: Erase block at 0x03a9c000 is not formatted. It will be erased
	JFFS2: Erase block at 0x03aa0000 is not formatted. It will be erased
	JFFS2: Erase block at 0x03aa4000 is not formatted. It will be erased
	JFFS2: Erase block at 0x03aa8000 is not formatted. It will be erased
	FFS2: Erase block at 0x03aac000 is not formatted. It will be erased
	JFFS2: Erase block at 0x03ab0000 is not formatted. It will be erased
	JFFS2: Erase block at 0x03ab4000 is not formatted. It will be erased
	JFFS2: Erase block at 0x03ab8000 is not formatted. It will be erased
	JFFS2: Erase block at 0x03abc000 is not formatted. It will be erased
	Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes
	mpty_blocks 0, bad_blocks 0, c->nr_blocks 3760
	mount: Mounting /dev/mtdblock8 on /mnt/nand failed: Input/output error

But when I enable the SW_ECC functionalilty I am able to mount the jffs2 fs and perform the fs operations

I am beginner for JFFS2 fs.Could you please let me know what causes this error.


Regards,
-Sameer



From sudeepholla.maillist at gmail.com  Thu Jan  3 08:34:12 2008
From: sudeepholla.maillist at gmail.com (Sudeep K N)
Date: Thu, 3 Jan 2008 19:04:12 +0530
Subject: JFFS2 mount problem on NAND flash
In-Reply-To: <00dc01c84e0b$b10fab20$ec8818ac@ent.ti.com>
References: <00dc01c84e0b$b10fab20$ec8818ac@ent.ti.com>
Message-ID: <366f00c80801030534i30aa3083hb01f00549152b1f6@mail.gmail.com>

Hi,

Try using the -j option with erase:
 ./flash_eraseall -j /dev/mtd8
If it still doesn't work, and its fine with SOFT_ECC, then
there is some problem with spare(oob) only write.

-- 
Regards,
Sudeep

On Jan 3, 2008 6:52 PM, Sameer <x0081444 at ti.com> wrote:
> Hi,
> I am working on omap based board with 16bit, small page Samsung NAND of size 64MB.
> I have enabled hardware ecc functionality in the driver code. To test the functionality I run the
> Following tests.
> 1. When the kernel comes up, >>cat /proc/mtd
>         mtd0: 00040000 00020000 "bootloader"
>         mtd1: 00020000 00020000 "params"
>         mtd2: 00200000 00020000 "kernel"
>         mtd3: 03da0000 00020000 "filesystem"
>         mtd4: 00080000 00004000 "NAND-X-Loader"
>         mtd5: 00080000 00004000 "NAND-U-Boot"
>         mtd6: 00040000 00004000 "NAND-U-Boot Environment"
>         mtd7: 00400000 00004000 "NAND-Kernel"
>         mtd8: 03ac0000 00004000 "NAND-File System"
> 2. I erase the NAND flash filesystem partition
>         ./flash_eraseall /dev/mtd8
>         This function passes. I have verified the erase functionality using the debugger.
> 3  mount -t jffs2 /dev/mtdblock8 /mnt/nand. I have enabled the low level jffs2 fs debugging
>         Following is the error message
>
>         JFFS2: Erase block at 0x00000000 is not formatted. It will be erased
>         JFFS2: Erase block at 0x00004000 is not formatted. It will be erased
>         JFFS2: Erase block at 0x00008000 is not formatted. It will be erased
>         JFFS2: Erase block at 0x0000c000 is not formatted. It will be erased
>         JFFS2: Erase block at 0x00010000 is not formatted. It will be erased
>         JFFS2: Erase block at 0x00014000 is not formatted. It will be erased
>         JFFS2: Erase block at 0x00018000 is not formatted. It will be erased
>         JFFS2: Erase block at 0x0001c000 is not formatted. It will be erased
>                                              -----
>                                                 =----
>                                         upto--
>
>         JFFS2: Erase block at 0x03a9c000 is not formatted. It will be erased
>         JFFS2: Erase block at 0x03aa0000 is not formatted. It will be erased
>         JFFS2: Erase block at 0x03aa4000 is not formatted. It will be erased
>         JFFS2: Erase block at 0x03aa8000 is not formatted. It will be erased
>         FFS2: Erase block at 0x03aac000 is not formatted. It will be erased
>         JFFS2: Erase block at 0x03ab0000 is not formatted. It will be erased
>         JFFS2: Erase block at 0x03ab4000 is not formatted. It will be erased
>         JFFS2: Erase block at 0x03ab8000 is not formatted. It will be erased
>         JFFS2: Erase block at 0x03abc000 is not formatted. It will be erased
>         Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes
>         mpty_blocks 0, bad_blocks 0, c->nr_blocks 3760
>         mount: Mounting /dev/mtdblock8 on /mnt/nand failed: Input/output error
>
> But when I enable the SW_ECC functionalilty I am able to mount the jffs2 fs and perform the fs operations
>
> I am beginner for JFFS2 fs.Could you please let me know what causes this error.
>
>
> Regards,
> -Sameer
>
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>


From arnd at arndb.de  Thu Jan  3 10:05:13 2008
From: arnd at arndb.de (Arnd Bergmann)
Date: Thu, 3 Jan 2008 16:05:13 +0100
Subject: [PATCH 4/5] UBI: introduce attach ioctls
In-Reply-To: <1199364699.7726.34.camel@august>
References: <20071219154137.23264.28116.sendpatchset@golum>
	<1198075329.18962.70.camel@sauron>
	<1199364699.7726.34.camel@august>
Message-ID: <200801031605.14326.arnd@arndb.de>

On Thursday 03 January 2008, Frank Haverkamp wrote:
> > We can autoprobe the VID header offset, unless the MTD device is empty,
> > in which case UBI automatically formats it.
> 
> I do not like auto-probing the VID hdr offset. In my eyes the user
> should have the flexibility to define where his VID-hdr and data start
> e.g. like in our case to have influence on if data is starting on
> subpage- or page-boundaries. I also think that the autoprobe feature
> would add more complexity to the code.

I agree that the user should have the flexibility to set these parameters,
but AFAICS, that is only relevant during initialization (formatting) of
the medium.

However, I find it essential that it's possible to do autoprobing of
existing media, by whatever means.
If you don't want to do it in the kernel, a user space helper might
be useful, preferably one that does not require ioctls, so it can be
done as a shell script.

	Arnd <><


From nancydreaming at gmail.com  Fri Jan  4 04:20:33 2008
From: nancydreaming at gmail.com (Nancy)
Date: Fri, 4 Jan 2008 17:20:33 +0800
Subject: UBIFS: copy file error
Message-ID: <bae050c10801040120u5d2379aak666c76f99443ef7a@mail.gmail.com>

Hi,
   As you can see at last, copy file failed. I use ubifs-olpc-2.6.22 version.
   How can I make it right?

# modprobe nandsim
NAND device: Manufacturer ID: 0x98, Chip ID: 0x39 (Toshiba NAND 128MiB
1,8V 8-bit)
flash size: 128 MiB
page size: 512 bytes
OOB area size: 16 bytes
sector size: 16 KiB
pages number: 262144
pages per sector: 32
bus width: 8
bits in sector size: 14
bits in page size: 9
bits in OOB size: 4
flash size with OOB: 135168 KiB
page address bytes: 4
sector address bytes: 3
options: 0x62
Scanning device for bad blocks
Creating 1 MTD partitions on "NAND 128MiB 1,8V 8-bit":
0x00000000-0x08000000 : "NAND simulator partition 0"
# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00400000 00040000 "NAND BOOT partition"
mtd1: 00400000 00040000 "NAND KERNEL partition"
mtd2: 07800000 00040000 "NAND ROOTFS partition"
mtd3: 08000000 00040000 "NAND DATA1 partition"
mtd4: 10000000 00040000 "NAND DATA2 partition"
mtd5: 20000000 00040000 "NAND VFAT partition"
mtd6: 08000000 00004000 "NAND simulator partition 0"
# modprobe ubi mtd=6
UBI: empty MTD device detected
UBI: create volume table (copy #1)
UBI: create volume table (copy #2)
UBI: attached mtd6 to ubi0
UBI: MTD device name:            "NAND simulator partition 0"
UBI: MTD device size:            128 MiB
UBI: physical eraseblock size:   16384 bytes (16 KiB)
UBI: logical eraseblock size:    15872 bytes
UBI: number of good PEBs:        8192
UBI: number of bad PEBs:         0
UBI: smallest flash I/O unit:    512
UBI: VID header offset:          256 (aligned 256)
UBI: data offset:                512
UBI: max. allowed volumes:       92
UBI: wear-leveling threshold:    4096
UBI: number of internal volumes: 1
UBI: number of user volumes:     0
UBI: available PEBs:             8107
UBI: total number of reserved PEBs: 85
UBI: number of PEBs reserved for bad PEB handling: 81
UBI: max/mean erase counter: 0/0
UBI: background thread "ubi_bgt0d" started, PID 784
# pwd
/home/yrtan/utils
# ./ubimkvol -d 0 -n 0 -N ubifs -s 128MiB
Cannot create volume: No space left on device
  err=-1
# ./ubimkvol -d 0 -n 0 -N ubifs -s 124MiB
Cannot create volume: No space left on device
  err=-1
# ./ubimkvol -d 0 -n 0 -N ubifs -s 123MiB
Cannot create volume: No space left on device
  err=-1
# ./ubimkvol -d 0 -n 0 -N ubifs -s 122MiB
# modprobe ubifs
# mount -t ubifs ubi0:ubifs /mnt/1
UBIFS: default file-system created
UBIFS: mounted UBI device 0, volume 0
UBIFS: minimal I/O unit size:   512 bytes
UBIFS: logical eraseblock size: 15872 bytes (15 KiB)
UBIFS: file system size:        127229952 bytes (124248 KiB, 121 MiB,
8016 LEBs)
UBIFS: journal size:            6396416 bytes (6246 KiB, 6 MiB, 403
LEBs)
UBIFS: data journal heads:      1
UBIFS: default compressor:      LZO
# df
Filesystem           1k-blocks      Used Available Use% Mounted on
tmpfs                    30032        52     29980   0% /dev
ubi0:ubifs               88176        60     88116   0% /mnt/1
# du /root/Documents/ -h
36.9M   /root/Documents
# cp /root/Documents/* /mnt/1
UBIFS: background thread "ubifs_bg_thread0_0" started, PID 832
UBIFS error (pid 832): do_commit: commit failed, error 3
UBIFS warning (pid 832): ubifs_ro_mode: switched to read-only mode
cp: write error: Invalid argument

cp: write error: Invalid argument
cp: write error: Invalid argument
cp: write error: Invalid argument
cp: write error: Invalid argument
# UBIFS error (pid 40): do_writepage: cannot write page 1124 of inode
65, error -22
UBIFS error (pid 40): do_writepage: cannot write page 1125 of inode
65, error -22
UBIFS error (pid 40): do_writepage: cannot write page 1126 of inode
65, error -22
UBIFS error (pid 40): do_writepage: cannot write page 1127 of inode
65, error -22
UBIFS error (pid 40): do_writepage: cannot write page 1128 of inode
65, error -22
UBIFS error (pid 40): do_writepage: cannot write page 1129 of inode
65, error -22
UBIFS error (pid 40): do_writepage: cannot write page 1130 of inode
65, error -22
UBIFS error (pid 40): do_writepage: cannot write page 1131 of inode
65, error -22
UBIFS error (pid 40): do_writepage: cannot write page 1132 of inode
65, error -22
UBIFS error (pid 40): do_writepage: cannot write page 1133 of inode
65, error -22


From x0081444 at ti.com  Fri Jan  4 10:23:05 2008
From: x0081444 at ti.com (Sameer)
Date: Fri, 4 Jan 2008 20:53:05 +0530
Subject: [PATCH] - NAND - Samsung LP nand feature support - nand_base.c upated
Message-ID: <00ed01c84ee5$b4928e40$ec8818ac@ent.ti.com>

Hi,
This patch add the Large page NAND feature support for Samsung nand flash.

Regards,
-Sameer


Signed-off-by: Sameer U <sameersu at ti.com>
---
 drivers/mtd/nand/nand_base.c |    4 ++++
 1 files changed, 4 insertions(+)

Index: linux-omap-git/drivers/mtd/nand/nand_base.c
===================================================================
--- linux-omap-git.orig/drivers/mtd/nand/nand_base.c
+++ linux-omap-git/drivers/mtd/nand/nand_base.c
@@ -2322,6 +2322,10 @@ static struct nand_flash_dev *nand_get_f
	chip->options &= ~NAND_CHIPOPTIONS_MSK;
	chip->options |= type->options & NAND_CHIPOPTIONS_MSK;

+	/* adding feature support for large page samsung nand */
+	if ((*maf_id == NAND_MFR_SAMSUNG) && (mtd->writesize > 512))
+		chip->options |= NAND_SAMSUNG_LP_OPTIONS;
+
	/*
	 * Set chip as a default. Board drivers can override it, if necessary
	 */



From ext-adrian.hunter at nokia.com  Fri Jan  4 10:24:38 2008
From: ext-adrian.hunter at nokia.com (Adrian Hunter)
Date: Fri, 04 Jan 2008 17:24:38 +0200
Subject: UBIFS: copy file error
In-Reply-To: <bae050c10801040120u5d2379aak666c76f99443ef7a@mail.gmail.com>
References: <bae050c10801040120u5d2379aak666c76f99443ef7a@mail.gmail.com>
Message-ID: <477E4FB6.1060000@nokia.com>

ext Nancy wrote:
> Hi,
>    As you can see at last, copy file failed. I use ubifs-olpc-2.6.22 version.
>    How can I make it right?
> 

It may be this bug:

http://git.infradead.org/?p=users/dedekind/ubifs-2.6.git;a=commitdiff;h=313ae7e3fd310930971334cf7f735d272d6e797e

Otherwise try cherry picking the latest patches from:

git://git.infradead.org/users/dedekind/ubifs-2.6.git



From nancydreaming at gmail.com  Fri Jan  4 22:24:45 2008
From: nancydreaming at gmail.com (Nancy)
Date: Sat, 5 Jan 2008 11:24:45 +0800
Subject: UBIFS: copy file error
In-Reply-To: <477E4FB6.1060000@nokia.com>
References: <bae050c10801040120u5d2379aak666c76f99443ef7a@mail.gmail.com>
	<477E4FB6.1060000@nokia.com>
Message-ID: <bae050c10801041924v20b9fdf7m36bcd39a06408a0d@mail.gmail.com>

> It may be this bug:
>
> http://git.infradead.org/?p=users/dedekind/ubifs-2.6.git;a=commitdiff;h=313ae7e3fd310930971334cf7f735d272d6e797e
>
> Otherwise try cherry picking the latest patches from:
>
> git://git.infradead.org/users/dedekind/ubifs-2.6.git
>

That's right !
Thanks a lot   *^_^*

--
Best Wishes,
Nancy


From info at irish.com  Sat Jan  5 09:18:19 2008
From: info at irish.com (The Irish National Lottery Board)
Date: Sat, 5 Jan 2008 09:18:19 -0500 (EST)
Subject: Congratulations!!! Your E-mail Just Won 1,000,
	000.00 Euro (Call Us At +44-70457-46575)
Message-ID: <33303.41.204.224.13.1199542699.squirrel@mail.wadsnet.com>

We are pleased to announce to you the draw of the IRISH LOTTERY PROGRAMME
online Sweepstakes International Program held on 2nd of January, 2008.
Your e-mail address attached to ticket number:56475600545 189 with Serial
number 5369/05 drew the lucky number:1-2-12-28-39-41-15, which
subsequently won the LOTTO RESULTS prize. You have therefore been approved
to claim a total sum of 1,000,000.00 Euro. (One Million Euro) in cash.

In order to file out your claims, you are advised to contact our claim Agent:

Name: Mr. Alton Williams
Tell:+44-70457-46575
     +44-70457-46645
Email: info at altonwilliams.free2all.co.uk

Please the below form for the processing of your claims:

1.FULL NAMES:
2.ADDRESS:
3.SEX:
4.AGE:
5.OCCUPATION:
6.MODE OF REMITTANCE: COURIER/BANK
7.TELEPHONE NUMBER:
8. COUNTRY:

For security reasons, you are advised to keep your winning information
confidential.

Sincerely,

Marry Kelly(Mrs)


Note: This e-mail message passed through the Wadsnet outbound Mail Vault anti-virus/anti-SPAM scanners.


From ezk at cs.sunysb.edu  Sun Jan  6 02:17:32 2008
From: ezk at cs.sunysb.edu (Erez Zadok)
Date: Sun, 6 Jan 2008 02:17:32 -0500
Subject: [PATCH] block2mtd lockdep_init_map warning
Message-ID: <200801060717.m067HW6c030422@agora.fsl.cs.sunysb.edu>

Hi David,

I've reported before a lockdep warning when block2mtd is modloaded, and a
device is initialized, as in

	modprobe block2mtd block2mtd=/dev/loop0

A typical warning looks like this:

BUG: key f88565c0 not in .data!
WARNING: at kernel/lockdep.c:2331 lockdep_init_map()
Pid: 1823, comm: modprobe Not tainted 2.6.24-rc6-unionfs2 #135
 [<c02038c0>] show_trace_log_lvl+0x1a/0x2f
 [<c02042bb>] show_trace+0x12/0x14
 [<c0204a01>] dump_stack+0x6c/0x72
 [<c022edf0>] lockdep_init_map+0x94/0x374
 [<c022e79d>] debug_mutex_init+0x2c/0x3c
 [<c0229bb0>] __mutex_init+0x38/0x40
 [<f885520d>] 0xf885520d
 [<c0226816>] parse_args+0x121/0x1fb
 [<c0237aaf>] sys_init_module+0x10e8/0x1576
 [<c0202836>] sysenter_past_esp+0x5f/0xa5
 =======================

This is a long-standing problem I've seen in several of the latest stable
kernels.  Once lockdep turns itself off, there's no easy way to turn it back
on short of a reboot.

I looked more closely at the mtd code.  I believe the problem is that
lockdep doesn't like a mutex_init to be called from a module_init code path,
possibly because the module's symbols aren't all initialized yet.  (This
could arguably be considered a limitation of lockdep.)

So I tried to defer the call to module_init until it's absolutely needed.  I
couldn't find a clean way to do that via the struct mtd_info ops (there's no
suitable ->init op), so instead I used an int to mark whether the mutex is
initialized or not.  Below is a patch.  It works, but it's not as clean as
it should be: a better way would be to probably add an mtd_info ->init op or
so.

At least with this patch, lockdep doesn't complain any longer, so I can run
a clean set of regression tests w/ unionfs on top of jffs2 and other file
systems.

In lieu of a better fix, is this patch acceptable?

Thanks,
Erez.

------------------------------------------------------------------------------

block2mtd: defer mutex initialization to avoid a lockdep warning

Signed-off-by: Erez Zadok <ezk at cs.sunysb.edu>

diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index be4b994..2c6d3e7 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -32,6 +32,7 @@ struct block2mtd_dev {
 	struct list_head list;
 	struct block_device *blkdev;
 	struct mtd_info mtd;
+	int mutex_initialized;
 	struct mutex write_mutex;
 };
 
@@ -85,6 +86,11 @@ static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
 	size_t len = instr->len;
 	int err;
 
+	if (!dev->mutex_initialized) {
+		mutex_init(&dev->write_mutex);
+		dev->mutex_initialized = 1;
+	}
+
 	instr->state = MTD_ERASING;
 	mutex_lock(&dev->write_mutex);
 	err = _block2mtd_erase(dev, from, len);
@@ -194,6 +200,11 @@ static int block2mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
 	struct block2mtd_dev *dev = mtd->priv;
 	int err;
 
+	if (!dev->mutex_initialized) {
+		mutex_init(&dev->write_mutex);
+		dev->mutex_initialized = 1;
+	}
+
 	if (!len)
 		return 0;
 	if (to >= mtd->size)
@@ -275,8 +286,6 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
 		goto devinit_err;
 	}
 
-	mutex_init(&dev->write_mutex);
-
 	/* Setup the MTD structure */
 	/* make the name contain the block device in */
 	dev->mtd.name = kmalloc(sizeof("block2mtd: ") + strlen(devname),


From joern at logfs.org  Sun Jan  6 08:13:43 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Sun, 6 Jan 2008 14:13:43 +0100
Subject: [PATCH] block2mtd lockdep_init_map warning
In-Reply-To: <200801060717.m067HW6c030422@agora.fsl.cs.sunysb.edu>
References: <200801060717.m067HW6c030422@agora.fsl.cs.sunysb.edu>
Message-ID: <20080106131343.GA3120@lazybastard.org>

Maybe it is not obvious that I maintain this driver and would like to be
kept on Cc:.  Will send a patch to fix that shortly.

On Sun, 6 January 2008 02:17:32 -0500, Erez Zadok wrote:
> 
> Hi David,
> 
> I've reported before a lockdep warning when block2mtd is modloaded, and a
> device is initialized, as in
> 
> 	modprobe block2mtd block2mtd=/dev/loop0
> 
> A typical warning looks like this:
> 
> BUG: key f88565c0 not in .data!
> WARNING: at kernel/lockdep.c:2331 lockdep_init_map()
> Pid: 1823, comm: modprobe Not tainted 2.6.24-rc6-unionfs2 #135
>  [<c02038c0>] show_trace_log_lvl+0x1a/0x2f
>  [<c02042bb>] show_trace+0x12/0x14
>  [<c0204a01>] dump_stack+0x6c/0x72
>  [<c022edf0>] lockdep_init_map+0x94/0x374
>  [<c022e79d>] debug_mutex_init+0x2c/0x3c
>  [<c0229bb0>] __mutex_init+0x38/0x40
>  [<f885520d>] 0xf885520d
>  [<c0226816>] parse_args+0x121/0x1fb
>  [<c0237aaf>] sys_init_module+0x10e8/0x1576
>  [<c0202836>] sysenter_past_esp+0x5f/0xa5
>  =======================
> 
> This is a long-standing problem I've seen in several of the latest stable
> kernels.  Once lockdep turns itself off, there's no easy way to turn it back
> on short of a reboot.
> 
> I looked more closely at the mtd code.  I believe the problem is that
> lockdep doesn't like a mutex_init to be called from a module_init code path,
> possibly because the module's symbols aren't all initialized yet.  (This
> could arguably be considered a limitation of lockdep.)
> 
> So I tried to defer the call to module_init until it's absolutely needed.  I
> couldn't find a clean way to do that via the struct mtd_info ops (there's no
> suitable ->init op), so instead I used an int to mark whether the mutex is
> initialized or not.  Below is a patch.  It works, but it's not as clean as
> it should be: a better way would be to probably add an mtd_info ->init op or
> so.
> 
> At least with this patch, lockdep doesn't complain any longer, so I can run
> a clean set of regression tests w/ unionfs on top of jffs2 and other file
> systems.
> 
> In lieu of a better fix, is this patch acceptable?

Not for me.  I don't mind if you keep such a hack until a proper
solution if found in your private tree.  But it is a horrible solution
to a problem introduced elsewhere.

Ingo, Peter, does either of you actually care about this problem?  In
the last round when I debugged this problem there was a notable lack of
reaction from either of you.

> block2mtd: defer mutex initialization to avoid a lockdep warning
> 
> Signed-off-by: Erez Zadok <ezk at cs.sunysb.edu>
> 
> diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
> index be4b994..2c6d3e7 100644
> --- a/drivers/mtd/devices/block2mtd.c
> +++ b/drivers/mtd/devices/block2mtd.c
> @@ -32,6 +32,7 @@ struct block2mtd_dev {
>  	struct list_head list;
>  	struct block_device *blkdev;
>  	struct mtd_info mtd;
> +	int mutex_initialized;
>  	struct mutex write_mutex;
>  };
>  
> @@ -85,6 +86,11 @@ static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
>  	size_t len = instr->len;
>  	int err;
>  
> +	if (!dev->mutex_initialized) {
> +		mutex_init(&dev->write_mutex);
> +		dev->mutex_initialized = 1;
> +	}
> +
>  	instr->state = MTD_ERASING;
>  	mutex_lock(&dev->write_mutex);
>  	err = _block2mtd_erase(dev, from, len);
> @@ -194,6 +200,11 @@ static int block2mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
>  	struct block2mtd_dev *dev = mtd->priv;
>  	int err;
>  
> +	if (!dev->mutex_initialized) {
> +		mutex_init(&dev->write_mutex);
> +		dev->mutex_initialized = 1;
> +	}
> +
>  	if (!len)
>  		return 0;
>  	if (to >= mtd->size)
> @@ -275,8 +286,6 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
>  		goto devinit_err;
>  	}
>  
> -	mutex_init(&dev->write_mutex);
> -
>  	/* Setup the MTD structure */
>  	/* make the name contain the block device in */
>  	dev->mtd.name = kmalloc(sizeof("block2mtd: ") + strlen(devname),
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/

J?rn

-- 
Joern's library part 13:
http://www.chip-architect.com/


From peterz at infradead.org  Sun Jan  6 08:39:22 2008
From: peterz at infradead.org (Peter Zijlstra)
Date: Sun, 06 Jan 2008 14:39:22 +0100
Subject: [PATCH] block2mtd lockdep_init_map warning
In-Reply-To: <20080106131343.GA3120@lazybastard.org>
References: <200801060717.m067HW6c030422@agora.fsl.cs.sunysb.edu>
	<20080106131343.GA3120@lazybastard.org>
Message-ID: <1199626763.31975.50.camel@lappy>


On Sun, 2008-01-06 at 14:13 +0100, J?rn Engel wrote:

> Ingo, Peter, does either of you actually care about this problem?  In
> the last round when I debugged this problem there was a notable lack of
> reaction from either of you.

Yeah I do, I just know very little about the module stuff and haven't
come around to looking into it.

I agree that Erez's patch is quite horrible.



From joern at lazybastard.org  Sun Jan  6 08:56:01 2008
From: joern at lazybastard.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Sun, 6 Jan 2008 14:56:01 +0100
Subject: [PATCH] Claim maintainership for block2mtd and update email addresses
Message-ID: <20080106135600.GB3120@lazybastard.org>

I have been prime author and maintainer of block2mtd from day one, but
neither MAINTAINERS nor the module source makes this fact clear.  And while
I'm at it, update my email addresses tree-wide, as the old address currently
bounces and change my name to "joern" as unicode will likely continue to
cause trouble until the end of this century.

Signed-off-by: J?rn Engel <joern at lazybastard.org>
---

 MAINTAINERS                     |   10 ++++++++--
 drivers/mtd/devices/block2mtd.c |    4 ++--
 drivers/mtd/devices/phram.c     |    4 ++--
 drivers/mtd/maps/mtx-1_flash.c  |    2 +-
 scripts/checkstack.pl           |    2 +-
 5 files changed, 14 insertions(+), 8 deletions(-)

--- linux-2.6.24-rc3logfs/drivers/mtd/devices/block2mtd.c~block2mtd_maintainer	2007-08-08 19:30:04.000000000 +0200
+++ linux-2.6.24-rc3logfs/drivers/mtd/devices/block2mtd.c	2008-01-06 14:22:57.000000000 +0100
@@ -4,7 +4,7 @@
  * block2mtd.c - create an mtd from a block device
  *
  * Copyright (C) 2001,2002	Simon Evans <spse at secret.org.uk>
- * Copyright (C) 2004-2006	J??rn Engel <joern at wh.fh-wedel.de>
+ * Copyright (C) 2004-2006	Joern Engel <joern at lazybastard.org>
  *
  * Licence: GPL
  */
@@ -485,5 +485,5 @@ module_init(block2mtd_init);
 module_exit(block2mtd_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Simon Evans <spse at secret.org.uk> and others");
+MODULE_AUTHOR("Joern Engel <joern at lazybastard.org>");
 MODULE_DESCRIPTION("Emulate an MTD using a block device");
--- linux-2.6.24-rc3logfs/MAINTAINERS~block2mtd_maintainer	2007-11-30 13:59:51.000000000 +0100
+++ linux-2.6.24-rc3logfs/MAINTAINERS	2008-01-06 14:21:49.000000000 +0100
@@ -835,6 +835,12 @@ L:	linux-kernel at vger.kernel.org
 T:	git kernel.org:/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git
 S:	Maintained
 
+BLOCK2MTD DRIVER
+P:	Joern Engel
+M:	joern at lazybastard.org
+L:	linux-mtd at lists.infradead.org
+S:	Maintained
+
 BLUETOOTH SUBSYSTEM
 P:	Marcel Holtmann
 M:	marcel at holtmann.org
@@ -2985,8 +2991,8 @@ L:	linux-abi-devel at lists.sourceforge.net
 S:	Maintained
 
 PHRAM MTD DRIVER
-P:	J??rn Engel
-M:	joern at wh.fh-wedel.de
+P:	Joern Engel
+M:	joern at lazybastard.org
 L:	linux-mtd at lists.infradead.org
 S:	Maintained
 
--- linux-2.6.24-rc3logfs/drivers/mtd/devices/phram.c~block2mtd_maintainer	2007-08-08 19:30:04.000000000 +0200
+++ linux-2.6.24-rc3logfs/drivers/mtd/devices/phram.c	2008-01-06 14:22:30.000000000 +0100
@@ -2,7 +2,7 @@
  * $Id: phram.c,v 1.16 2005/11/07 11:14:25 gleixner Exp $
  *
  * Copyright (c) ????		Jochen Sch??uble <psionic at psionic.de>
- * Copyright (c) 2003-2004	J??rn Engel <joern at wh.fh-wedel.de>
+ * Copyright (c) 2003-2004	Joern Engel <joern at lazybastard.org>
  *
  * Usage:
  *
@@ -299,5 +299,5 @@ module_init(init_phram);
 module_exit(cleanup_phram);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("J??rn Engel <joern at wh.fh-wedel.de>");
+MODULE_AUTHOR("Joern Engel <joern at lazybastard.org>");
 MODULE_DESCRIPTION("MTD driver for physical RAM");
--- linux-2.6.24-rc3logfs/scripts/checkstack.pl~block2mtd_maintainer	2007-11-15 20:52:00.000000000 +0100
+++ linux-2.6.24-rc3logfs/scripts/checkstack.pl	2008-01-06 14:28:14.000000000 +0100
@@ -2,7 +2,7 @@
 
 #	Check the stack usage of functions
 #
-#	Copyright Joern Engel <joern at wh.fh-wedel.de>
+#	Copyright Joern Engel <joern at lazybastard.org>
 #	Inspired by Linus Torvalds
 #	Original idea maybe from Keith Owens
 #	s390 port and big speedup by Arnd Bergmann <arnd at bergmann-dalldorf.de>
--- linux-2.6.24-rc3logfs/drivers/mtd/maps/mtx-1_flash.c~block2mtd_maintainer	2007-08-08 19:30:04.000000000 +0200
+++ linux-2.6.24-rc3logfs/drivers/mtd/maps/mtx-1_flash.c	2008-01-06 14:28:44.000000000 +0100
@@ -4,7 +4,7 @@
  * $Id: mtx-1_flash.c,v 1.2 2005/11/07 11:14:27 gleixner Exp $
  *
  * (C) 2005 Bruno Randolf <bruno.randolf at 4g-systems.biz>
- * (C) 2005 J??rn Engel <joern at wohnheim.fh-wedel.de>
+ * (C) 2005 Joern Engel <joern at lazybastard.org>
  *
  */
 


From julia at diku.dk  Sun Jan  6 11:50:34 2008
From: julia at diku.dk (Julia Lawall)
Date: Sun, 6 Jan 2008 17:50:34 +0100 (CET)
Subject: [PATCH] fs/jffs2: Add missing call to posix_acl_release
Message-ID: <Pine.LNX.4.64.0801061749490.24950@ask.diku.dk>

From: Julia Lawall <julia at diku.dk>

posix_acl_clone does a memory allocation and sets a reference count, so
posix_acl_release is needed afterwards to free it.


The problem was fixed using the following semantic patch.
(http://www.emn.fr/x-info/coccinelle/)

// <smpl>
@@
type T;
identifier E;
expression E1, E2;
int ret;
statement S;
@@

  T E;
  <+...
(
  E = \(posix_acl_clone\|posix_acl_alloc\|posix_acl_dup\)(...);
  if (E == NULL) S
|
  if ((E = \(posix_acl_clone\|posix_acl_alloc\|posix_acl_dup\)(...)) == NULL) S
)
  ... when != E2 = E
      when strict
(
  posix_acl_release(E);
|
  E1 = E;
|
+ posix_acl_release(E);
  return;
|
+ posix_acl_release(E);
  return ret;
)
  ...+>
// </smpl>

Signed-off-by: Julia Lawall <julia at diku.dk>
---

diff -u -p a/fs/jffs2/acl.c b/fs/jffs2/acl.c
--- a/fs/jffs2/acl.c 2008-01-03 09:49:31.000000000 +0100
+++ b/fs/jffs2/acl.c 2008-01-06 17:38:52.000000000 +0100
@@ -345,8 +345,10 @@ int jffs2_init_acl_pre(struct inode *dir
 		if (!clone)
 			return -ENOMEM;
 		rc = posix_acl_create_masq(clone, (mode_t *)i_mode);
-		if (rc < 0)
+		if (rc < 0) {
+			posix_acl_release(clone);
 			return rc;
+		}
 		if (rc > 0)
 			jffs2_iset_acl(inode, &f->i_acl_access, clone);
 


From shizheng at mail.ustc.edu.cn  Sun Jan  6 14:14:18 2008
From: shizheng at mail.ustc.edu.cn (=?GB2312?B?yrHV/Q==?=)
Date: Mon, 07 Jan 2008 03:14:18 +0800
Subject: why ubimkvol can't recognize /dev/ubi0?
Message-ID: <399646872.11492@ustc.edu.cn>

Hi all,
I wanna have a try of ubifs on nandsim, and do as what the ubifs wiki
tells me
(http://osl.sed.hu/wiki/ubifs/index.php/Download_the_source).

1. compile, install and boot the new kernel(2.6.23)
the configuration option for ubi and nandsim is default turned on as module.


2. make the mtd-utils to produce ubimkvol

3. create a ubi when I got the error
# modprobe nandsim
# modprobe ubi mtd=0
# ls /dev/ubi0 -l
crw-rw---- 1 root root 253, 0 2007-12-25 01:46 /dev/ubi0
# ls /sys/class/ubi -l
drwxr-xr-x 3 root root 0 2007-12-25 01:46 ubi0
-r--r--r-- 1 root root 4096 2007-12-25 01:49 version
# ubimkvol /dev/ubi0 -n 0 -N test -s 20MiB
libubi error: readdir failed on "/sys/class/ubi"
readdir: No such file or directory
ubimkvol error: "/dev/ubi0" is not an UBI device node

it's so strange about the readdir failure, because there is the ubi0
entry in sysfs.

did I miss any step, such as kernel configuration or mtd-tools installation?

Thanks a lot!

best wishes, shizheng



From ezk at cs.sunysb.edu  Sun Jan  6 14:11:47 2008
From: ezk at cs.sunysb.edu (Erez Zadok)
Date: Sun, 6 Jan 2008 14:11:47 -0500
Subject: [PATCH] block2mtd lockdep_init_map warning 
In-Reply-To: Your message of "Sun, 06 Jan 2008 14:13:43 +0100."
	<20080106131343.GA3120@lazybastard.org> 
Message-ID: <200801061911.m06JBldW020012@agora.fsl.cs.sunysb.edu>

In message <20080106131343.GA3120 at lazybastard.org>, =?utf-8?B?SsO2cm4=?= Engel writes:
> Maybe it is not obvious that I maintain this driver and would like to be
> kept on Cc:.  Will send a patch to fix that shortly.

I was looking in MAINTAINERS, and you weren't listed on the main MTD section
as a maintainer.  Perhaps an update?

If you get a patch, I'd love to test it.

> On Sun, 6 January 2008 02:17:32 -0500, Erez Zadok wrote:
[...]
> > In lieu of a better fix, is this patch acceptable?
> 
> Not for me.  I don't mind if you keep such a hack until a proper
> solution if found in your private tree.  But it is a horrible solution
> to a problem introduced elsewhere.

Yup, that's what I figured.  I'll keep this ugly hack but I won't push it to
my unionfs tree on kernel.org.

> Ingo, Peter, does either of you actually care about this problem?  In
> the last round when I debugged this problem there was a notable lack of
> reaction from either of you.

The problem appears to be an interaction of two components--module loading
and lockdep--that's perhaps why it wasn't given enough attention.

I run a lot of regression tests w/ unionfs on top of many different file
systems, and monitoring for all sorts of problems, including lockdep
warnings.  So it's frustrating that each time I get to test w/ jffs2, I get
this lockdep warning, and lockdep shuts down until a reboot.  That kills my
automated testing and masks out possible other lockdep problems (that's why
I wanted to at least have some workaround).  Other lockdep problems I
reported with other subsystems had been fixed within days; this one,
unfortunately, has lingered for a while.  So if a fix can be made in a
reasonable time-frame, I'd really appreciate it.

Thanks,
Erez.


From joern at logfs.org  Sun Jan  6 16:25:42 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Sun, 6 Jan 2008 22:25:42 +0100
Subject: [PATCH] block2mtd lockdep_init_map warning
In-Reply-To: <200801061911.m06JBldW020012@agora.fsl.cs.sunysb.edu>
References: <20080106131343.GA3120@lazybastard.org>
	<200801061911.m06JBldW020012@agora.fsl.cs.sunysb.edu>
Message-ID: <20080106212542.GA5262@lazybastard.org>

On Sun, 6 January 2008 14:11:47 -0500, Erez Zadok wrote:
> 
> The problem appears to be an interaction of two components--module loading
> and lockdep--that's perhaps why it wasn't given enough attention.

Correct.  For modules lockdep depends on initializations done after
module_init has finished.  However block2mtd is an odd sod that can call
into lockdep code during module_init, causing the bug you noticed.

Several solutions are possible.  Modules could get two initcalls, one to
decide whether module load should get aborted, the other run later,
after the remaining module initializations are done.  Or the module
loader could always do the initializations and revoke them later, if
module_init failed.

But I personally am too unfamiliar with the module code to trust my
judgement and have yet to receive feedback.  Even you seem to ignore my
mails and not even Cc: me later on.  I must have done something really
horrible in my last life, it seems.

J?rn

-- 
A quarrel is quickly settled when deserted by one party; there is
no battle unless there be two.
-- Seneca


From marcel at ziswiler.com  Sun Jan  6 19:23:03 2008
From: marcel at ziswiler.com (Marcel Ziswiler)
Date: Mon, 7 Jan 2008 00:23:03 +0000 (UTC)
Subject: [PATCH] basic pxa3 nand controller support
References: <f17812d70712201756h501a80cch8305d40fa479f5cf@mail.gmail.com>
Message-ID: <loom.20080107T001557-159@post.gmane.org>

eric miao <eric.y.miao <at> gmail.com> writes:

> Early feedback is welcome, thanks!

Hi Eric

Overall the patch looks good, just a few comments.

The patch does not apply cleanly unless I remove the spurious newline before
line 1284 resulting in the following error:
patch: **** malformed patch at line 1284: pm_message_t state)

The DRCMR97 register is not defined anywhere, at lest not in 2.6.24-rc6:
drivers/mtd/nand/pxa3xx_nand.c:542: error: ?DRCMR97? undeclared (first use in
this function)

The registers and bit definitions should be moved to pxa-regs.h, not?

I had my troubles getting it to work on a custom PXA320 board. I kinda figured
out what platform data it needs, but still can't seem to get it to work properly:
pxa3xx-nand pxa3xx-nand: failed to detect flash

What kernel does your patch apply to? What CPUs/boards did you try it on? Can
you provide an example platform integration required to make it work?

Cheers

Marcel




From telexwiredept at googlemail.com  Sun Jan  6 21:59:38 2008
From: telexwiredept at googlemail.com (TELEX/ WIRE TRANSFER DEPT CBN.)
Date: Mon,  7 Jan 2008 10:59:38 +0800 (CST)
Subject: LONG OVER DUE CONTRACT PAYMENT.
Message-ID: <20080107025938.1E6B7A5CB0@ms1.wlps.kl.edu.tw>


CENTRAL BANK OF NIGERIA
WIRE TRANSFER DEPARTMENT
MARINA AVENUE-LAGOS
NIGERIA.
E-MAIL: draliu_usman at excite.com
OUR REF: CBN/WTD/AU/03/01/08
ATTN: HONOURABLE CONTRACTOR / NEXT OF KIN CLAIMS.
RE: REMITTANCE OF YOUR CONTRACT SUM WITH THE FEDERAL REPUBLIC OF NIGERIA.
With due respect sir, we sincerely apologize for the delay of the
transfer of your contract sum into your nominated bank account. Several
foreign contractors have gone through several problems receiving their
contract payments from our country.
I sincerely apologize for this problems.Henceforth,We have gone through
your files and documents and I must say they are highly satisfactory
and we have decided to transfer your funds into your account
immediately we hear from you.
To make things clear and to prevent fraudulent activities, we would
advice you to re-send your personal data
1. Names in full: --------------
2. Address: ------------------
3. Nationality: ----------------
4. Age: ----------------------
5. Occupation: ----------------
6. Phone/Fax: -----------------
7. Present Country: ------------
8. Banking details: --------------
9. Contract amount: ------------
And all other relevant documents that approve your claim of this
contract sum.Please we would advice that you contact us on
(draliu_usman at excite.com)so that we could talk this over.
As soon as we receive the aforementioned information, we would commence
with the transfer of your funds into your account immediately.
We are doing this to make sure we erase all terrible names our country
has over the past.
We hope to serve you better.
Regards,
DR ALIU USMAN
MANAGER,
WIRE TRANSFER DEPT.(CBN).






From shizheng at mail.ustc.edu.cn  Mon Jan  7 00:51:39 2008
From: shizheng at mail.ustc.edu.cn (shizheng)
Date: Mon, 07 Jan 2008 13:51:39 +0800
Subject: why ubimkvol can't recognize /dev/ubi0?
In-Reply-To: <399646872.11492@ustc.edu.cn>
References: <399646872.11492@ustc.edu.cn>
Message-ID: <399685257.10363@ustc.edu.cn>

By default nandsim creates device of 8MB.
# cat /proc/mtd
dev:	size	erasesize  name
mtd0:	08000000 00004000  "NAND simulator partition 0"

>
> Vinit Agnihotri wrote:
>> yeah & 1 more...use mtdram instead of nandsim.
>> modprobe mtdram=40960 will create mtd device of size 40MB,
>> besides that you can write small tool for creating & deleting volumes,
>> its simple.
>> you can find ioctl's & structures code in include/mtd/ubi-user.h.
>>
>> --Vinit.
>>
>> On Jan 6, 2008 1:23 PM, Vinit Agnihotri <vinit.agnihotri at gmail.com> wrote:
>>     
>>> You have loaded Nandsim with default, may be theres not enough space
>>> on nandsim to create 20Mib volume,
>>> I guess by default nandsim creates device of 8MB. you can check it by
>>> looking a /proc/mtd.
>>> so try creating volume of smaller size or pass appropriate module
>>> parameters to nandsim module,
>>> do a modinfo nandsim or straight way have look in its code, I assume
>>> that you have proper privileges to run ubimkvol.
>>> still I dont have justification for that strange error, but try this out.
>>>
>>> --Vinit.
>>>
>>>
>>> On Jan 6, 2008 11:14 AM, ?? <shizheng at mail.ustc.edu.cn> wrote:
>>>       
>>>> Hi all,
>>>> I wanna have a try of ubifs on nandsim, and do as what the ubifs wiki
>>>> tells me
>>>> (http://osl.sed.hu/wiki/ubifs/index.php/Download_the_source).
>>>>
>>>> 1. compile, install and boot the new kernel(2.6.23)
>>>> the configuration option for ubi and nandsim is default turned on as module.
>>>>
>>>>
>>>> 2. make the mtd-utils to produce ubimkvol
>>>>
>>>> 3. create a ubi when I got the error
>>>> # modprobe nandsim
>>>> # modprobe ubi mtd=0
>>>> # ls /dev/ubi0 -l
>>>> crw-rw---- 1 root root 253, 0 2007-12-25 01:46 /dev/ubi0
>>>> # ls /sys/class/ubi -l
>>>> drwxr-xr-x 3 root root 0 2007-12-25 01:46 ubi0
>>>> -r--r--r-- 1 root root 4096 2007-12-25 01:49 version
>>>> # ubimkvol /dev/ubi0 -n 0 -N test -s 20MiB
>>>> libubi error: readdir failed on "/sys/class/ubi"
>>>> readdir: No such file or directory
>>>> ubimkvol error: "/dev/ubi0" is not an UBI device node
>>>>
>>>> it's so strange about the readdir failure, because there is the ubi0
>>>> entry in sysfs.
>>>>
>>>> did I miss any step, such as kernel configuration or mtd-tools installation?
>>>>
>>>> Thanks a lot!
>>>>
>>>> best wishes, shizheng
>>>>
>>>>
>>>> ______________________________________________________
>>>> Linux MTD discussion mailing list
>>>> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>>>>
>>>>         
>>>
>>> --
>>> Life is so short. So, follow some rules. Forgive quickly, believe
>>> slowly, love truly, laugh loudly & never avoid anything that makes U
>>> smile.
>>>
>>>       
>>
>>
>>     




From shizheng at mail.ustc.edu.cn  Mon Jan  7 00:59:02 2008
From: shizheng at mail.ustc.edu.cn (shizheng)
Date: Mon, 07 Jan 2008 13:59:02 +0800
Subject: why ubimkvol can't recognize /dev/ubi0?
In-Reply-To: <399685257.10363@ustc.edu.cn>
References: <399685257.10363@ustc.edu.cn>
Message-ID: <399685679.09967@ustc.edu.cn>

>
> By default nandsim creates device of 8MB.
>   
~~~~~~ Sorry, this shold be 128MB :-)
> # cat /proc/mtd
> dev:	size	erasesize  name
> mtd0:	08000000 00004000  "NAND simulator partition 0"
>
> >/
> />/ Vinit Agnihotri wrote:
> />>/ yeah & 1 more...use mtdram instead of nandsim.
> />>/ modprobe mtdram=40960 will create mtd device of size 40MB,
> />>/ besides that you can write small tool for creating & deleting volumes,
> />>/ its simple.
> />>/ you can find ioctl's & structures code in include/mtd/ubi-user.h.
> />>/
> />>/ --Vinit.
> />>/
> />>/ On Jan 6, 2008 1:23 PM, Vinit Agnihotri <vinit.agnihotri at gmail.com <http://lists.infradead.org/mailman/listinfo/linux-mtd>> wrote:
> />>/     
> />>>/ You have loaded Nandsim with default, may be theres not enough space
> />>>/ on nandsim to create 20Mib volume,
> />>>/ I guess by default nandsim creates device of 8MB. you can check it by
> />>>/ looking a /proc/mtd.
> />>>/ so try creating volume of smaller size or pass appropriate module
> />>>/ parameters to nandsim module,
> />>>/ do a modinfo nandsim or straight way have look in its code, I assume
> />>>/ that you have proper privileges to run ubimkvol.
> />>>/ still I dont have justification for that strange error, but try this out.
> />>>/
> />>>/ --Vinit.
> />>>/
> />>>/
> />>>/ On Jan 6, 2008 11:14 AM, ?? <shizheng at mail.ustc.edu.cn <http://lists.infradead.org/mailman/listinfo/linux-mtd>> wrote:
> />>>/       
> />>>>/ Hi all,
> />>>>/ I wanna have a try of ubifs on nandsim, and do as what the ubifs wiki
> />>>>/ tells me
> />>>>/ (http://osl.sed.hu/wiki/ubifs/index.php/Download_the_source).
> />>>>/
> />>>>/ 1. compile, install and boot the new kernel(2.6.23)
> />>>>/ the configuration option for ubi and nandsim is default turned on as module.
> />>>>/
> />>>>/
> />>>>/ 2. make the mtd-utils to produce ubimkvol
> />>>>/
> />>>>/ 3. create a ubi when I got the error
> />>>>/ # modprobe nandsim
> />>>>/ # modprobe ubi mtd=0
> />>>>/ # ls /dev/ubi0 -l
> />>>>/ crw-rw---- 1 root root 253, 0 2007-12-25 01:46 /dev/ubi0
> />>>>/ # ls /sys/class/ubi -l
> />>>>/ drwxr-xr-x 3 root root 0 2007-12-25 01:46 ubi0
> />>>>/ -r--r--r-- 1 root root 4096 2007-12-25 01:49 version
> />>>>/ # ubimkvol /dev/ubi0 -n 0 -N test -s 20MiB
> />>>>/ libubi error: readdir failed on "/sys/class/ubi"
> />>>>/ readdir: No such file or directory
> />>>>/ ubimkvol error: "/dev/ubi0" is not an UBI device node
> />>>>/
> />>>>/ it's so strange about the readdir failure, because there is the ubi0
> />>>>/ entry in sysfs.
> />>>>/
> />>>>/ did I miss any step, such as kernel configuration or mtd-tools installation?
> />>>>/
> />>>>/ Thanks a lot!
> />>>>/
> />>>>/ best wishes, shizheng
> />>>>/
> />>>>/
> />>>>/ ______________________________________________________
> />>>>/ Linux MTD discussion mailing list
> />>>>/ http://lists.infradead.org/mailman/listinfo/linux-mtd/
> />>>>/
> />>>>/         
> />>>/
> />>>/ --
> />>>/ Life is so short. So, follow some rules. Forgive quickly, believe
> />>>/ slowly, love truly, laugh loudly & never avoid anything that makes U
> />>>/ smile.
> />>>/
> />>>/       
> />>/
> />>/
> />>



From ext-adrian.hunter at nokia.com  Mon Jan  7 02:49:25 2008
From: ext-adrian.hunter at nokia.com (Adrian Hunter)
Date: Mon, 07 Jan 2008 09:49:25 +0200
Subject: why ubimkvol can't recognize /dev/ubi0?
In-Reply-To: <399646872.11492@ustc.edu.cn>
References: <399646872.11492@ustc.edu.cn>
Message-ID: <4781D985.6020504@nokia.com>

?? wrote:
> Hi all,
> I wanna have a try of ubifs on nandsim, and do as what the ubifs wiki
> tells me
> (http://osl.sed.hu/wiki/ubifs/index.php/Download_the_source).
> 
> 1. compile, install and boot the new kernel(2.6.23)
> the configuration option for ubi and nandsim is default turned on as module.
> 
> 
> 2. make the mtd-utils to produce ubimkvol
> 
> 3. create a ubi when I got the error
> # modprobe nandsim
> # modprobe ubi mtd=0
> # ls /dev/ubi0 -l
> crw-rw---- 1 root root 253, 0 2007-12-25 01:46 /dev/ubi0
> # ls /sys/class/ubi -l
> drwxr-xr-x 3 root root 0 2007-12-25 01:46 ubi0
> -r--r--r-- 1 root root 4096 2007-12-25 01:49 version
> # ubimkvol /dev/ubi0 -n 0 -N test -s 20MiB
> libubi error: readdir failed on "/sys/class/ubi"
> readdir: No such file or directory
> ubimkvol error: "/dev/ubi0" is not an UBI device node
> 
> it's so strange about the readdir failure, because there is the ubi0
> entry in sysfs.
> 
> did I miss any step, such as kernel configuration or mtd-tools installation?
> 
> Thanks a lot!
> 
> best wishes, shizheng
> 
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/

>From b96f4481662bd7ac247d4d5a25b27f7d8afffb92 Mon Sep 17 00:00:00 2001
From: Adrian Hunter <ext-adrian.hunter at nokia.com>
Date: Mon, 7 Jan 2008 09:47:17 +0200
Subject: ubi-utils: fix bug using readdir

Library functions never reset errno to zero, so if you want
to use its value to check for errors then you must set it to zero
before calling the library function (in this case readdir).

Signed-off-by: Adrian Hunter <ext-adrian.hunter at nokia.com>
---
 ubi-utils/src/libubi.c |   13 +++++++++++--
 1 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/ubi-utils/src/libubi.c b/ubi-utils/src/libubi.c
index 855aa82..be06f70 100644
--- a/ubi-utils/src/libubi.c
+++ b/ubi-utils/src/libubi.c
@@ -872,9 +872,13 @@ int ubi_get_info(libubi_t desc, struct ubi_info *info)
 	}
 
 	info->lowest_dev_num = INT_MAX;
-	while ((dirent = readdir(sysfs_ubi))) {
+	while (1) {
 		int dev_num, ret;
 
+		errno = 0;
+		dirent = readdir(sysfs_ubi);
+		if (!dirent)
+			break;
 		/*
 		 * Make sure this direntry is a directory and not a symlink -
 		 * Linux puts symlinks to UBI volumes on this UBI device to the
@@ -1022,9 +1026,14 @@ int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info)
 		return -1;
 
 	info->lowest_vol_num = INT_MAX;
-	while ((dirent = readdir(sysfs_ubi))) {
+
+	while (1) {
 		int vol_id, ret, devno;
 
+		errno = 0;
+		dirent = readdir(sysfs_ubi);
+		if (!dirent)
+			break;
 		ret = sscanf(dirent->d_name, UBI_VOL_NAME_PATT, &devno, &vol_id);
 		if (ret == 2 && devno == dev_num) {
 			info->vol_count += 1;
-- 
1.4.4.2


From peterz at infradead.org  Mon Jan  7 05:05:26 2008
From: peterz at infradead.org (Peter Zijlstra)
Date: Mon, 07 Jan 2008 11:05:26 +0100
Subject: [PATCH] block2mtd lockdep_init_map warning
In-Reply-To: <200801061911.m06JBldW020012@agora.fsl.cs.sunysb.edu>
References: <200801061911.m06JBldW020012@agora.fsl.cs.sunysb.edu>
Message-ID: <1199700326.7143.10.camel@twins>


On Sun, 2008-01-06 at 14:11 -0500, Erez Zadok wrote:

> > Ingo, Peter, does either of you actually care about this problem?  In
> > the last round when I debugged this problem there was a notable lack of
> > reaction from either of you.
> 
> The problem appears to be an interaction of two components--module loading
> and lockdep--that's perhaps why it wasn't given enough attention.

Would something like this work for people?

Not-Yet-Signed-off-by: Peter Zijlstra <a.p.zijlstra at chello.nl>
---
Index: linux-2.6/include/linux/sched.h
===================================================================
--- linux-2.6.orig/include/linux/sched.h
+++ linux-2.6/include/linux/sched.h
@@ -1160,6 +1160,7 @@ struct task_struct {
 	int lockdep_depth;
 	struct held_lock held_locks[MAX_LOCK_DEPTH];
 	unsigned int lockdep_recursion;
+	struct module *loading_module;
 #endif
 
 /* journalling filesystem info */
Index: linux-2.6/kernel/module.c
===================================================================
--- linux-2.6.orig/kernel/module.c
+++ linux-2.6/kernel/module.c
@@ -2023,6 +2023,9 @@ static struct module *load_module(void _
 		printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
 		       mod->name);
 
+#ifdef CONFIG_LOCKDEP
+	current->loading_module = mod;
+#endif
 	/* Size of section 0 is 0, so this works well if no params */
 	err = parse_args(mod->name, mod->args,
 			 (struct kernel_param *)
@@ -2030,6 +2033,9 @@ static struct module *load_module(void _
 			 sechdrs[setupindex].sh_size
 			 / sizeof(struct kernel_param),
 			 NULL);
+#ifdef CONFIG_LOCKDEP
+	current->loading_module = NULL
+#endif
 	if (err < 0)
 		goto arch_cleanup;
 
@@ -2454,6 +2460,17 @@ int is_module_address(unsigned long addr
 		}
 	}
 
+#ifdef CONFIG_LOCKDEP
+	if (current->loading_module) {
+		mod = current->loading_module;
+		if (within(addr, mod->module_init, mod->init_text_size)
+		    || within(addr, mod->module_core, mod->core_text_size)) {
+			preempt_enable();
+			return 1;
+		}
+	}
+#endif
+
 	preempt_enable();
 
 	return 0;





From joern at logfs.org  Mon Jan  7 05:20:27 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Mon, 7 Jan 2008 11:20:27 +0100
Subject: [PATCH] block2mtd lockdep_init_map warning
In-Reply-To: <1199700326.7143.10.camel@twins>
References: <200801061911.m06JBldW020012@agora.fsl.cs.sunysb.edu>
	<1199700326.7143.10.camel@twins>
Message-ID: <20080107102025.GA5338@lazybastard.org>

On Mon, 7 January 2008 11:05:26 +0100, Peter Zijlstra wrote:
> 
> Would something like this work for people?

Looks a lot better than what I thought of.  However, does the #ifdef
within is_module_address() make sense when afaict lockdep is the only
caller of that function?  Looks as if the whole function should be made
conditional or none of it.

> Not-Yet-Signed-off-by: Peter Zijlstra <a.p.zijlstra at chello.nl>
> ---
> Index: linux-2.6/include/linux/sched.h
> ===================================================================
> --- linux-2.6.orig/include/linux/sched.h
> +++ linux-2.6/include/linux/sched.h
> @@ -1160,6 +1160,7 @@ struct task_struct {
>  	int lockdep_depth;
>  	struct held_lock held_locks[MAX_LOCK_DEPTH];
>  	unsigned int lockdep_recursion;
> +	struct module *loading_module;
>  #endif
>  
>  /* journalling filesystem info */
> Index: linux-2.6/kernel/module.c
> ===================================================================
> --- linux-2.6.orig/kernel/module.c
> +++ linux-2.6/kernel/module.c
> @@ -2023,6 +2023,9 @@ static struct module *load_module(void _
>  		printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
>  		       mod->name);
>  
> +#ifdef CONFIG_LOCKDEP
> +	current->loading_module = mod;
> +#endif
>  	/* Size of section 0 is 0, so this works well if no params */
>  	err = parse_args(mod->name, mod->args,
>  			 (struct kernel_param *)
> @@ -2030,6 +2033,9 @@ static struct module *load_module(void _
>  			 sechdrs[setupindex].sh_size
>  			 / sizeof(struct kernel_param),
>  			 NULL);
> +#ifdef CONFIG_LOCKDEP
> +	current->loading_module = NULL
> +#endif
>  	if (err < 0)
>  		goto arch_cleanup;
>  
> @@ -2454,6 +2460,17 @@ int is_module_address(unsigned long addr
>  		}
>  	}
>  
> +#ifdef CONFIG_LOCKDEP
> +	if (current->loading_module) {
> +		mod = current->loading_module;
> +		if (within(addr, mod->module_init, mod->init_text_size)
> +		    || within(addr, mod->module_core, mod->core_text_size)) {
> +			preempt_enable();
> +			return 1;
> +		}
> +	}
> +#endif
> +
>  	preempt_enable();
>  
>  	return 0;
> 
> 
> 

J?rn

-- 
I don't understand it. Nobody does.
-- Richard P. Feynman


From peterz at infradead.org  Mon Jan  7 05:34:25 2008
From: peterz at infradead.org (Peter Zijlstra)
Date: Mon, 07 Jan 2008 11:34:25 +0100
Subject: [PATCH] block2mtd lockdep_init_map warning
In-Reply-To: <20080107102025.GA5338@lazybastard.org>
References: <200801061911.m06JBldW020012@agora.fsl.cs.sunysb.edu>
	<1199700326.7143.10.camel@twins>
	<20080107102025.GA5338@lazybastard.org>
Message-ID: <1199702065.7143.13.camel@twins>


On Mon, 2008-01-07 at 11:20 +0100, J?rn Engel wrote:
> On Mon, 7 January 2008 11:05:26 +0100, Peter Zijlstra wrote:
> > 
> > Would something like this work for people?
> 
> Looks a lot better than what I thought of.  However, does the #ifdef
> within is_module_address() make sense when afaict lockdep is the only
> caller of that function?  Looks as if the whole function should be made
> conditional or none of it.

Ah, I hadn't bothered to check if there were more users. /me does a (not
so quick) git grep and finds lockdep is indeed the only caller. Sure, we
can move the whole function into the ifdef.




From owain.phillips at siemens.com  Mon Jan  7 07:16:45 2008
From: owain.phillips at siemens.com (Phillips, Owain)
Date: Mon, 07 Jan 2008 12:16:45 +0000
Subject: Flash_eraseall -j and cowardly refusing to mount
Message-ID: <4B760ED6D70BBC4EBFC0AEFDAFB2392A0AEB9FBC@NTHT202E.siemenscomms.co.uk>

Hi linux-mtd at lists.infradead.org,

We just upgraded to mtd-utils-1.0.1 on our 2.6.23 target and I am getting
problems with flash_eraseall -j where the mount fails.

# flash_eraseall -j /dev/mtd11
Erasing 128 Kibyte @ e20000 -- 36 % complete. Cleanmarker written at e20000.
Skipping bad block at 0x00e40000
Erasing 128 Kibyte @ 26a0000 -- 99 % complete. Cleanmarker written at
26a0000.
# mount -t jffs2 /dev/mtdblock11 /mnt
Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes
empty_blocks 0, bad_blocks 1, c->nr_blocks 310
mount: Mounting /dev/mtdblock11 on /mnt failed: Input/output error


If I do a flash_eraseall without the -j option the mount is OK.
Is it OK to revert to just doing this non-jffs2-aware erase; what are
implications/side effects?

If I look at the differences in the filesystems generated via the
flash_eraseall -y and a flash_eraseall followed by a mount the clean marker
appears to be different; is that the problem.

First oob for a flash_erase -j.....

0x000007e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x000007f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
  OOB Data: ff ff 85 19 03 20 08 00 00 00 ff ff ff ff ff ff
  OOB Data: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
  OOB Data: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
  OOB Data: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff

First oob for a flash_erase, followed by jffs2 mount....

0x000007e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x000007f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
  OOB Data: ff ff 85 19 03 20 08 00 00 00 00 00 00 00 ff ff
  OOB Data: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
  OOB Data: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
  OOB Data: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff

Here are details for our device.

# mtd_debug info /dev/mtd11
mtd.type = MTD_NANDFLASH
mtd.flags =
mtd.size = 40632320 (38M)
mtd.erasesize = 131072 (128K)
mtd.oobblock = 2048 (2K)
mtd.oobsize = 64
mtd.ecctype = (unknown ECC type - new MTD API maybe?) regions = 0
#


Any help in pointing out the error of my ways would be greatly appreciated.
Does it look like we cocked up building the mtd utils?

Kind regards,
Owain Phillips
--



From jwboyer at linux.vnet.ibm.com  Mon Jan  7 07:40:51 2008
From: jwboyer at linux.vnet.ibm.com (Josh Boyer)
Date: Mon, 7 Jan 2008 06:40:51 -0600
Subject: Flash_eraseall -j and cowardly refusing to mount
In-Reply-To: <4B760ED6D70BBC4EBFC0AEFDAFB2392A0AEB9FBC@NTHT202E.siemenscomms.co.uk>
References: <4B760ED6D70BBC4EBFC0AEFDAFB2392A0AEB9FBC@NTHT202E.siemenscomms.co.uk>
Message-ID: <20080107064051.457d89a1@zod.rchland.ibm.com>

On Mon, 07 Jan 2008 12:16:45 +0000
"Phillips, Owain" <owain.phillips at siemens.com> wrote:

> Hi linux-mtd at lists.infradead.org,
> 
> We just upgraded to mtd-utils-1.0.1 on our 2.6.23 target and I am getting
> problems with flash_eraseall -j where the mount fails.
> 
> # flash_eraseall -j /dev/mtd11
> Erasing 128 Kibyte @ e20000 -- 36 % complete. Cleanmarker written at e20000.
> Skipping bad block at 0x00e40000
> Erasing 128 Kibyte @ 26a0000 -- 99 % complete. Cleanmarker written at
> 26a0000.
> # mount -t jffs2 /dev/mtdblock11 /mnt
> Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes
> empty_blocks 0, bad_blocks 1, c->nr_blocks 310
> mount: Mounting /dev/mtdblock11 on /mnt failed: Input/output error
> 
> 
> If I do a flash_eraseall without the -j option the mount is OK.
> Is it OK to revert to just doing this non-jffs2-aware erase; what are
> implications/side effects?
> 
> If I look at the differences in the filesystems generated via the
> flash_eraseall -y and a flash_eraseall followed by a mount the clean marker
> appears to be different; is that the problem.
> 
> First oob for a flash_erase -j.....
> 
> 0x000007e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> 0x000007f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>   OOB Data: ff ff 85 19 03 20 08 00 00 00 ff ff ff ff ff ff
>   OOB Data: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>   OOB Data: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>   OOB Data: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> 
> First oob for a flash_erase, followed by jffs2 mount....
> 
> 0x000007e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> 0x000007f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>   OOB Data: ff ff 85 19 03 20 08 00 00 00 00 00 00 00 ff ff
>   OOB Data: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>   OOB Data: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>   OOB Data: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> 
> Here are details for our device.
> 
> # mtd_debug info /dev/mtd11
> mtd.type = MTD_NANDFLASH
> mtd.flags =
> mtd.size = 40632320 (38M)
> mtd.erasesize = 131072 (128K)
> mtd.oobblock = 2048 (2K)
> mtd.oobsize = 64
> mtd.ecctype = (unknown ECC type - new MTD API maybe?) regions = 0
> #
> 
> 
> Any help in pointing out the error of my ways would be greatly appreciated.
> Does it look like we cocked up building the mtd utils?

No.  I think the -j option to flash_eraseall is broken.  It should
either be fixed or removed.

josh


From dwmw2 at infradead.org  Mon Jan  7 10:00:40 2008
From: dwmw2 at infradead.org (David Woodhouse)
Date: Mon, 07 Jan 2008 15:00:40 +0000
Subject: Flash_eraseall -j and cowardly refusing to mount
In-Reply-To: <4B760ED6D70BBC4EBFC0AEFDAFB2392A0AEB9FBC@NTHT202E.siemenscomms.co.uk>
References: <4B760ED6D70BBC4EBFC0AEFDAFB2392A0AEB9FBC@NTHT202E.siemenscomms.co.uk>
Message-ID: <1199718040.27304.12.camel@pmac.infradead.org>

On Mon, 2008-01-07 at 12:16 +0000, Phillips, Owain wrote:
> Hi linux-mtd at lists.infradead.org,
> 
> We just upgraded to mtd-utils-1.0.1 on our 2.6.23 target and I am
> getting problems with flash_eraseall -j where the mount fails.

It ought to be fixed by this:
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=09b3fba5

-- 
dwmw2



From kaigai at ak.jp.nec.com  Mon Jan  7 11:02:57 2008
From: kaigai at ak.jp.nec.com (KaiGai Kohei)
Date: Tue, 08 Jan 2008 01:02:57 +0900
Subject: [PATCH] fs/jffs2: Add missing call to posix_acl_release
In-Reply-To: <Pine.LNX.4.64.0801061749490.24950@ask.diku.dk>
References: <Pine.LNX.4.64.0801061749490.24950@ask.diku.dk>
Message-ID: <47824D31.8040104@ak.jp.nec.com>

Julia Lawall wrote:
> From: Julia Lawall <julia at diku.dk>
> 
> posix_acl_clone does a memory allocation and sets a reference count, so
> posix_acl_release is needed afterwards to free it.
> 
> 
> The problem was fixed using the following semantic patch.
> (http://www.emn.fr/x-info/coccinelle/)
> 
> // <smpl>
> @@
> type T;
> identifier E;
> expression E1, E2;
> int ret;
> statement S;
> @@
> 
>   T E;
>   <+...
> (
>   E = \(posix_acl_clone\|posix_acl_alloc\|posix_acl_dup\)(...);
>   if (E == NULL) S
> |
>   if ((E = \(posix_acl_clone\|posix_acl_alloc\|posix_acl_dup\)(...)) == NULL) S
> )
>   ... when != E2 = E
>       when strict
> (
>   posix_acl_release(E);
> |
>   E1 = E;
> |
> + posix_acl_release(E);
>   return;
> |
> + posix_acl_release(E);
>   return ret;
> )
>   ...+>
> // </smpl>
> 
> Signed-off-by: Julia Lawall <julia at diku.dk>
> ---
> 
> diff -u -p a/fs/jffs2/acl.c b/fs/jffs2/acl.c
> --- a/fs/jffs2/acl.c 2008-01-03 09:49:31.000000000 +0100
> +++ b/fs/jffs2/acl.c 2008-01-06 17:38:52.000000000 +0100
> @@ -345,8 +345,10 @@ int jffs2_init_acl_pre(struct inode *dir
>  		if (!clone)
>  			return -ENOMEM;
>  		rc = posix_acl_create_masq(clone, (mode_t *)i_mode);
> -		if (rc < 0)
> +		if (rc < 0) {
> +			posix_acl_release(clone);
>  			return rc;
> +		}
>  		if (rc > 0)
>  			jffs2_iset_acl(inode, &f->i_acl_access, clone);

Indeed, there was a possibility to cause memory leaking.

Acked-by: KaiGai Kohei <kaigai at ak.jp.nec.com>

-- 
OSS Platform Development Division, NEC
KaiGai Kohei <kaigai at ak.jp.nec.com>



From jhane at mobilygen.com  Mon Jan  7 13:39:19 2008
From: jhane at mobilygen.com (Jeff Hane)
Date: Mon, 07 Jan 2008 10:39:19 -0800
Subject: Flash_eraseall -j and cowardly refusing to mount
In-Reply-To: <1199718040.27304.12.camel@pmac.infradead.org>
References: <4B760ED6D70BBC4EBFC0AEFDAFB2392A0AEB9FBC@NTHT202E.siemenscomms.co.uk>
	<1199718040.27304.12.camel@pmac.infradead.org>
Message-ID: <1199731159.6533.10.camel@qu062.quarc.com>


 But doesn't this only fix the case where you have contiguous 8 bytes to
write the cleanmarker?  flash_eraseall -j uses MTD_PLACE to write the
cleanmarker BUT jffs2 uses MTD_AUTO to read the cleanmarker.
 For example, if your oob area has byte 0 as the bad block indicator and
bytes 8-10 have ecc, there are only 7 consecutive free bytes.
flash_eraseall -j will only write 7 bytes so jffs2 will fail when
mounting the filesystem because it will read 8 bytes.  The 8th byte,
which will be byte 12, will still be FF.
  It seems there should be an ioctl that would allow one to read/write
the oob area using MTD_AUTO???

jeff

On Mon, 2008-01-07 at 15:00 +0000, David Woodhouse wrote:
> On Mon, 2008-01-07 at 12:16 +0000, Phillips, Owain wrote:
> > Hi linux-mtd at lists.infradead.org,
> > 
> > We just upgraded to mtd-utils-1.0.1 on our 2.6.23 target and I am
> > getting problems with flash_eraseall -j where the mount fails.
> 
> It ought to be fixed by this:
> http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=09b3fba5
> 



From lotto at phreego.com  Mon Jan  7 17:40:12 2008
From: lotto at phreego.com (godsent)
Date: Mon, 7 Jan 2008 17:40:12 -0500
Subject: LOAN OFFER APPLY TODAY 
Message-ID: <23c18c27873644178b0404071556852f.lotto@phreego.com>




Attn:

I am a private Loan lender,I offer Loans to individuals,Firms and cooperate bodies at 3% interest rate,loan terms determinant. 
Loan for developing businesses a competitive edge. 
I offer the following kinds of loans 
* Personal Loans (Secure and Unsecured)
* Business Loans (Secure and Unsecured)
* Undergraduate Loans 
* Graduate Loans 
* MBA Education Loans 
* Medical Education Loans 
* Legal Education Loans 
* Study Abroad Loans 
* Consolidation Loan 
* Combination Loan 
* Collateral And Non- Collateral Loans and much more
Loans For Your Business Startup: Loans for Everyone, I offer loans between an amount ranging from ?1,000 to ?500,000, 000. 

You can contact me today and be financially equiped. godsent_loanlender at yahoo.com.sg



From lotto at phreego.com  Mon Jan  7 17:40:10 2008
From: lotto at phreego.com (godsent)
Date: Mon, 7 Jan 2008 17:40:10 -0500
Subject: LOAN OFFER APPLY TODAY 
Message-ID: <c84f667c00234db781ae30bda5ad0dde.lotto@phreego.com>




Attn:

I am a private Loan lender,I offer Loans to individuals,Firms and cooperate bodies at 3% interest rate,loan terms determinant. 
Loan for developing businesses a competitive edge. 
I offer the following kinds of loans 
* Personal Loans (Secure and Unsecured)
* Business Loans (Secure and Unsecured)
* Undergraduate Loans 
* Graduate Loans 
* MBA Education Loans 
* Medical Education Loans 
* Legal Education Loans 
* Study Abroad Loans 
* Consolidation Loan 
* Combination Loan 
* Collateral And Non- Collateral Loans and much more
Loans For Your Business Startup: Loans for Everyone, I offer loans between an amount ranging from ?1,000 to ?500,000, 000. 

You can contact me today and be financially equiped. godsent_loanlender at yahoo.com.sg



From akpm at linux-foundation.org  Mon Jan  7 18:23:00 2008
From: akpm at linux-foundation.org (Andrew Morton)
Date: Mon, 7 Jan 2008 15:23:00 -0800
Subject: [PATCH] Claim maintainership for block2mtd and update email
	addresses
In-Reply-To: <20080106135600.GB3120@lazybastard.org>
References: <20080106135600.GB3120@lazybastard.org>
Message-ID: <20080107152300.2ed7cddb.akpm@linux-foundation.org>

On Sun, 6 Jan 2008 14:56:01 +0100
J__rn Engel <joern at lazybastard.org> wrote:

> - * Copyright (C) 2004-2006	J??rn Engel <joern at wh.fh-wedel.de>
> + * Copyright (C) 2004-2006	Joern Engel <joern at lazybastard.org>

Yup.  Your name comes out like that when sylpheed does its
save-email-to-a-file thing as well and I haven't got around to working out
why, or to reporting it.

In this case it looks like the dud characters came about due to "[MTD] Fix
legacy character sets throughout drivers/mtd, include/linux/mtd".  Which
doesn't look like it fixed anything much really.

Going with the asciified/anglicised/bastardised spelling is a practical
(albeit unhappy) solution.




From joern at logfs.org  Mon Jan  7 20:06:56 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Tue, 8 Jan 2008 02:06:56 +0100
Subject: [PATCH] Claim maintainership for block2mtd and update email
	addresses
In-Reply-To: <20080107152300.2ed7cddb.akpm@linux-foundation.org>
References: <20080106135600.GB3120@lazybastard.org>
	<20080107152300.2ed7cddb.akpm@linux-foundation.org>
Message-ID: <20080108010656.GA10627@lazybastard.org>

On Mon, 7 January 2008 15:23:00 -0800, Andrew Morton wrote:
> On Sun, 6 Jan 2008 14:56:01 +0100
> J__rn Engel <joern at lazybastard.org> wrote:

You found a new one!  That make a round dozen, I believe.
http://logfs.org/logfs/joern

> > - * Copyright (C) 2004-2006	J??rn Engel <joern at wh.fh-wedel.de>
> > + * Copyright (C) 2004-2006	Joern Engel <joern at lazybastard.org>
> 
> Yup.  Your name comes out like that when sylpheed does its
> save-email-to-a-file thing as well and I haven't got around to working out
> why, or to reporting it.
> 
> In this case it looks like the dud characters came about due to "[MTD] Fix
> legacy character sets throughout drivers/mtd, include/linux/mtd".  Which
> doesn't look like it fixed anything much really.
> 
> Going with the asciified/anglicised/bastardised spelling is a practical
> (albeit unhappy) solution.

I'm happy if people spend effort and make unicode work.  Until then I'll
semi-officially change my name to "Joern" and keep collecting unusual
specimens.

J?rn

-- 
Measure. Don't tune for speed until you've measured, and even then
don't unless one part of the code overwhelms the rest.
-- Rob Pike


From rusty at rustcorp.com.au  Mon Jan  7 19:47:00 2008
From: rusty at rustcorp.com.au (Rusty Russell)
Date: Tue, 8 Jan 2008 11:47:00 +1100
Subject: [PATCH] block2mtd lockdep_init_map warning
In-Reply-To: <1199700326.7143.10.camel@twins>
References: <200801061911.m06JBldW020012@agora.fsl.cs.sunysb.edu>
	<1199700326.7143.10.camel@twins>
Message-ID: <200801081147.00701.rusty@rustcorp.com.au>

On Monday 07 January 2008 21:05:26 Peter Zijlstra wrote:
> On Sun, 2008-01-06 at 14:11 -0500, Erez Zadok wrote:
> > > Ingo, Peter, does either of you actually care about this problem?  In
> > > the last round when I debugged this problem there was a notable lack of
> > > reaction from either of you.
> >
> > The problem appears to be an interaction of two components--module
> > loading and lockdep--that's perhaps why it wasn't given enough attention.
>
> Would something like this work for people?

Hi Peter,

    There's nothing wrong with this patch, but I think it papers over a more
general problem: we enter the module (to parse args) while it's not in the
module list.  This also means we won't get a nice oops if it crashes.

    This is untested, but does it solve it for you?

Thanks,
Rusty.

diff -r 68fd1b22db89 kernel/module.c
--- a/kernel/module.c	Mon Jan 07 18:59:50 2008 +1100
+++ b/kernel/module.c	Tue Jan 08 11:46:11 2008 +1100
@@ -2043,6 +2043,11 @@ static struct module *load_module(void _
 		printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
 		       mod->name);
 
+	/* Now sew it into the lists so we can get lockdep and oops
+         * info during argument parsing.  Noone should access us, since
+         * strong_try_module_get() will fail. */
+	stop_machine_run(__link_module, mod, NR_CPUS);
+
 	/* Size of section 0 is 0, so this works well if no params */
 	err = parse_args(mod->name, mod->args,
 			 (struct kernel_param *)
@@ -2051,7 +2056,7 @@ static struct module *load_module(void _
 			 / sizeof(struct kernel_param),
 			 NULL);
 	if (err < 0)
-		goto arch_cleanup;
+		goto unlink;
 
 	err = mod_sysfs_setup(mod,
 			      (struct kernel_param *)
@@ -2059,7 +2064,7 @@ static struct module *load_module(void _
 			      sechdrs[setupindex].sh_size
 			      / sizeof(struct kernel_param));
 	if (err < 0)
-		goto arch_cleanup;
+		goto unlink;
 	add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
 	add_notes_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
 
@@ -2074,7 +2079,8 @@ static struct module *load_module(void _
 	/* Done! */
 	return mod;
 
- arch_cleanup:
+ unlink:
+	stop_machine_run(__unlink_module, mod, NR_CPUS);
 	module_arch_cleanup(mod);
  cleanup:
 	module_unload_free(mod);
@@ -2130,10 +2136,6 @@ sys_init_module(void __user *umod,
 		mutex_unlock(&module_mutex);
 		return PTR_ERR(mod);
 	}
-
-	/* Now sew it into the lists.  They won't access us, since
-           strong_try_module_get() will fail. */
-	stop_machine_run(__link_module, mod, NR_CPUS);
 
 	/* Drop lock so they can recurse */
 	mutex_unlock(&module_mutex);


From sr at denx.de  Tue Jan  8 02:45:57 2008
From: sr at denx.de (Stefan Roese)
Date: Tue, 8 Jan 2008 08:45:57 +0100
Subject: [PATCH 3/4] mtd: Factor out OF partition support from the NOR
	driver.
In-Reply-To: <20071213171552.GB4459@loki.buserror.net>
References: <20071213171552.GB4459@loki.buserror.net>
Message-ID: <200801080845.58016.sr@denx.de>

On Thursday 13 December 2007, Scott Wood wrote:
> Signed-off-by: Scott Wood <scottwood at freescale.com>

Acked-by: Stefan Roese <sr at denx.de>

Best regards,
Stefan


From dwmw2 at infradead.org  Tue Jan  8 02:57:49 2008
From: dwmw2 at infradead.org (David Woodhouse)
Date: Tue, 08 Jan 2008 07:57:49 +0000
Subject: [PATCH 2/4] nand base: Give drivers a chance to do late
	initialization.
In-Reply-To: <20071213171551.GA4459@loki.buserror.net>
References: <20071213171551.GA4459@loki.buserror.net>
Message-ID: <1199779069.4111.379.camel@shinybook.infradead.org>


On Thu, 2007-12-13 at 11:15 -0600, Scott Wood wrote:
> Some nand controllers, such as the Freescale enhanced local bus controller,
> need to do late initialization based on details of the chip that has been
> probed, such as chip size, large/small pages, etc.  A late_init() callback
> method is added to allow this.

Do you really need this so late? Can't it be done between
nand_scan_ident() and nand_scan_tail()? That's why we split nand_scan()
into two in the first place...

-- 
dwmw2



From dwmw2 at infradead.org  Tue Jan  8 03:10:48 2008
From: dwmw2 at infradead.org (David Woodhouse)
Date: Tue, 08 Jan 2008 08:10:48 +0000
Subject: [PATCH 3/4] mtd: Factor out OF partition support from the NOR
	driver.
In-Reply-To: <20071213171552.GB4459@loki.buserror.net>
References: <20071213171552.GB4459@loki.buserror.net>
Message-ID: <1199779848.4111.381.camel@shinybook.infradead.org>

Please adjust for commit 4edaf56e0f8a6f71e3361bf74e3dc835811761e6 and
resend.

-- 
dwmw2



From hcegtvedt at atmel.com  Tue Jan  8 05:27:24 2008
From: hcegtvedt at atmel.com (Hans-Christian Egtvedt)
Date: Tue,  8 Jan 2008 11:27:24 +0100
Subject: [PATCH 1/1] Add fixup for AT49BV6416 devices which needs to swap the
	region info
Message-ID: <11997880443971-git-send-email-hcegtvedt@atmel.com>

This patch adds a fixup for Atmel AT49BV6416 devices which has the erase region
information swapped. The fixup swaps them correct.

Signed-off-by: Hans-Christian Egtvedt <hcegtvedt at atmel.com>
---
 drivers/mtd/chips/cfi_cmdset_0002.c |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 205977b..0b8ad64 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -167,6 +167,18 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
 	}
 }
 
+/* Atmel AT49BV6416 chips have swapped the boot sectors and normal sectors */
+static void fixup_swap_atmel_sector_info(struct mtd_info *mtd, void *param)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	uint32_t erase_region_info_tmp;
+
+	erase_region_info_tmp = cfi->cfiq->EraseRegionInfo[0];
+	cfi->cfiq->EraseRegionInfo[0] = cfi->cfiq->EraseRegionInfo[1];
+	cfi->cfiq->EraseRegionInfo[1] = erase_region_info_tmp;
+}
+
 /* Atmel chips don't use the same PRI format as AMD chips */
 static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
 {
@@ -221,6 +233,7 @@ static void fixup_use_atmel_lock(struct mtd_info *mtd, void *param)
 }
 
 static struct cfi_fixup cfi_fixup_table[] = {
+	{ CFI_MFR_ATMEL, AT49BV6416, fixup_swap_atmel_sector_info, NULL },
 	{ CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
 #ifdef AMD_BOOTLOC_BUG
 	{ CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL },
-- 
1.5.2.5



From scottwood at freescale.com  Tue Jan  8 12:48:09 2008
From: scottwood at freescale.com (Scott Wood)
Date: Tue, 8 Jan 2008 11:48:09 -0600
Subject: [PATCH 2/4] nand base: Give drivers a chance to do late
	initialization.
In-Reply-To: <1199779069.4111.379.camel@shinybook.infradead.org>
References: <20071213171551.GA4459@loki.buserror.net>
	<1199779069.4111.379.camel@shinybook.infradead.org>
Message-ID: <20080108174809.GB5188@loki.buserror.net>

On Tue, Jan 08, 2008 at 07:57:49AM +0000, David Woodhouse wrote:
> 
> On Thu, 2007-12-13 at 11:15 -0600, Scott Wood wrote:
> > Some nand controllers, such as the Freescale enhanced local bus controller,
> > need to do late initialization based on details of the chip that has been
> > probed, such as chip size, large/small pages, etc.  A late_init() callback
> > method is added to allow this.
> 
> Do you really need this so late? Can't it be done between
> nand_scan_ident() and nand_scan_tail()? That's why we split nand_scan()
> into two in the first place...

Yeah, that'd work.  I'll send an updated driver soon.

-Scott


From g.liakhovetski at gmx.de  Tue Jan  8 18:23:24 2008
From: g.liakhovetski at gmx.de (Guennadi Liakhovetski)
Date: Wed, 9 Jan 2008 00:23:24 +0100 (CET)
Subject: [PATCH] Claim maintainership for block2mtd and update email
	addresses
In-Reply-To: <20080108010656.GA10627@lazybastard.org>
References: <20080106135600.GB3120@lazybastard.org>
	<20080107152300.2ed7cddb.akpm@linux-foundation.org>
	<20080108010656.GA10627@lazybastard.org>
Message-ID: <Pine.LNX.4.64.0801090016570.10908@axis700.grange>

On Tue, 8 Jan 2008, J?rn Engel wrote:

> I'm happy if people spend effort and make unicode work.  Until then I'll
> semi-officially change my name to "Joern" and keep collecting unusual
> specimens.

Just wondering - nothing personal at all. What's the official plan for 
this - do we want (when utf8 works) to use utf8 codes for symbols only for 
languages mostly based on ASCII, like iso-8859-15, or for all? Would we, 
for example, then also write Cyrillic names in utf-8 and every other 
alphabet for that matter? Didn't find anything under Documentation about 
that. Maybe we want to document it somewhere? Wasn't C-sources originally 
supposed to be ASCII? So, what we use in sources, what under Documentation 
or in MAINTAINERS may be different matters?

Thanks
Guennadi
---
Guennadi Liakhovetski


From davidb at davidb.org  Tue Jan  8 19:19:31 2008
From: davidb at davidb.org (David Brown)
Date: Tue, 8 Jan 2008 16:19:31 -0800
Subject: [PATCH] Claim maintainership for block2mtd and update email
	addresses
In-Reply-To: <Pine.LNX.4.64.0801090016570.10908@axis700.grange>
References: <20080106135600.GB3120@lazybastard.org>
	<20080107152300.2ed7cddb.akpm@linux-foundation.org>
	<20080108010656.GA10627@lazybastard.org>
	<Pine.LNX.4.64.0801090016570.10908@axis700.grange>
Message-ID: <20080109001931.GA16426@old.davidb.org>

On Wed, Jan 09, 2008 at 12:23:24AM +0100, Guennadi Liakhovetski wrote:

>On Tue, 8 Jan 2008, J?rn Engel wrote:
>
>> I'm happy if people spend effort and make unicode work.  Until then I'll
>> semi-officially change my name to "Joern" and keep collecting unusual
>> specimens.
>
>Just wondering - nothing personal at all. What's the official plan for 
>this - do we want (when utf8 works) to use utf8 codes for symbols only for 
>languages mostly based on ASCII, like iso-8859-15, or for all?

UTF-8 already works fine in git.  There is some support in recent versions
to allow commit messages and users to be specified in other encodings.

I think the issue here is with mailers modifying the encoding of data in
message files.

My reply header should be to J?rn, with a proper 'o' with two dots over it.
By default, my mailer wants to encode the message in iso-8859-1.  If I add
a single unicode character, say '?', then the whole message will get
encoded in UTF-8.

UTF-8 has the advantage of supporting nearly all character sets.  The extra
space needed isn't really an issue for usernames or for comment messages.

Dave


From mtd at davidb.org  Tue Jan  8 19:19:48 2008
From: mtd at davidb.org (David Brown)
Date: Tue, 8 Jan 2008 16:19:48 -0800
Subject: [PATCH] Claim maintainership for block2mtd and update email
	addresses
In-Reply-To: <Pine.LNX.4.64.0801090016570.10908@axis700.grange>
References: <20080106135600.GB3120@lazybastard.org>
	<20080107152300.2ed7cddb.akpm@linux-foundation.org>
	<20080108010656.GA10627@lazybastard.org>
	<Pine.LNX.4.64.0801090016570.10908@axis700.grange>
Message-ID: <20080109001948.GA16644@old.davidb.org>

On Wed, Jan 09, 2008 at 12:23:24AM +0100, Guennadi Liakhovetski wrote:

>On Tue, 8 Jan 2008, J?rn Engel wrote:
>
>> I'm happy if people spend effort and make unicode work.  Until then I'll
>> semi-officially change my name to "Joern" and keep collecting unusual
>> specimens.
>
>Just wondering - nothing personal at all. What's the official plan for 
>this - do we want (when utf8 works) to use utf8 codes for symbols only for 
>languages mostly based on ASCII, like iso-8859-15, or for all?

UTF-8 already works fine in git.  There is some support in recent versions
to allow commit messages and users to be specified in other encodings.

I think the issue here is with mailers modifying the encoding of data in
message files.

My reply header should be to J?rn, with a proper 'o' with two dots over it.
By default, my mailer wants to encode the message in iso-8859-1.  If I add
a single unicode character, say '?', then the whole message will get
encoded in UTF-8.

UTF-8 has the advantage of supporting nearly all character sets.  The extra
space needed isn't really an issue for usernames or for comment messages.

Dave


From gordonfarquharson at gmail.com  Tue Jan  8 23:35:15 2008
From: gordonfarquharson at gmail.com (Gordon Farquharson)
Date: Tue, 8 Jan 2008 21:35:15 -0700
Subject: [PATCH] [MTD] [NOR] Add support for the ST M29W400DB flash chip.
Message-ID: <97a0a9ac0801082035r2dacab1cu40a6bfc4e7fedb1a@mail.gmail.com>

Add support for the ST M29W400DB flash chip.

Signed-off-by: Gordon Farquharson <gordonfarquharson at gmail.com>

---

diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c
index 6405938..0b4f481 100644
--- a/drivers/mtd/chips/jedec_probe.c
+++ b/drivers/mtd/chips/jedec_probe.c
@@ -135,6 +135,7 @@
 #define M29W160DT	0x22C4
 #define M29W160DB	0x2249
 #define M29W040B	0x00E3
+#define M29W400DB	0x00EF
 #define M50FW040	0x002C
 #define M50FW080	0x002D
 #define M50FW016	0x002E
@@ -1498,7 +1499,22 @@ static const struct amd_flash_info jedec_table[] = {
 		.regions	= {
 			ERASEINFO(0x10000,8),
 		}
-        }, {
+	}, {
+		.mfr_id		= MANUFACTURER_ST,
+		.dev_id		= M29W400DB,
+		.name		= "ST M29W400DB",
+		.devtypes	= CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+		.uaddr		= MTD_UADDR_0x0555_0x02AA,
+		.dev_size	= SIZE_512KiB,
+		.cmd_set	= P_ID_AMD_STD,
+		.nr_regions	= 4,
+		.regions	= {
+			ERASEINFO(0x04000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x10000,7)
+		}
+	}, {
 		.mfr_id		= MANUFACTURER_ST,
 		.dev_id		= M50FW040,
 		.name		= "ST M50FW040",

-- 
Gordon Farquharson
GnuPG Key ID: 32D6D676


From daviesmark1984 at yahoo.co.uk  Tue Jan  8 00:08:59 2008
From: daviesmark1984 at yahoo.co.uk (DAVIES MARK)
Date: Tue, 8 Jan 2008 05:08:59 -0000 (GMT)
Subject: Last Reminder Notice
Message-ID: <2232.41.219.210.45.1199768939.squirrel@www.bluelightningmail.com>




THIS IS FOR YOUR ATTENTION

I have not considered this medium as the best manner to approach you on
this issue being that the web has been greatly abused over the recent
years and now unsecured for vital information of importance. This is due
to your non-response to my earlier letter as I urgently wish to alert you
as you have been listed as a possible recipient to the total sum of
?8,600,000.00GBP(Eight million Six hundred thousand British pounds) in the
codicil and last testament of the departed. You have actually been
scheduled because you bear the surname identity with our deceased customer
and therefore give you the position to receive the money he long deposit
only when you are presented as the beneficiary to the legacy. I therefore
reckoned that you work with me for mutual benefit to receive these funds
as you are clearly qualified by your name identity and I shall secure all
the legal papers on your acceptance since I have all the details and since
no one is coming for it. We both know that if nothing is ventured nothing
gained. If this is of appeal to you kindly reply me for more details by
confirming your consent and full support. Please I expect you to provide
me with a confidential telephone for better communication and a physical
address for the procurement of necessary legal documents at the law court
division, all for the release of this sum to you. You to note that time is
of essence as we approach the end of financial year.

Yours faithfully,
Davies Mark.



From tatsam07 at gmail.com  Wed Jan  9 00:00:27 2008
From: tatsam07 at gmail.com (Ramanuj Pandey)
Date: Wed, 09 Jan 2008 10:30:27 +0530
Subject: space shown by df is more than actual used space
Message-ID: <478454EB.9010302@gmail.com>

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi List,
I am new in this field, actually in my target board there is one
partition that is having jffs2 file system, some times after much read
and write the df shows much space used than actual, i tried to read
previous posts and other helps in this list and mail also but was not
able to get the problem fully. Since i am new to this particular field
i want to clear few of my basic doubts like this is the problem of mtd
driver in kernel of mkfs.jffs2 utility.
Please provide me solution or hint of the problem and kindly suggest
some place from where i can get some insight about jffs2 file system and
flashes.
my mkfs.jffs2 utility version is 1.43 and kernel we are using is 2.6.16

Thanks in Advance

Ramanuj
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.4-svn0 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org

iD8DBQFHhFTXq8Ry4Vqy+XkRAhURAJwOOsILaSUA4F2FGrg4wAvxUszX7QCgidKu
ODv1t7SZV26htZGaFwfCx+c=
=y4MZ
-----END PGP SIGNATURE-----


From kyungmin.park at samsung.com  Wed Jan  9 01:37:14 2008
From: kyungmin.park at samsung.com (Kyungmin Park)
Date: Wed, 9 Jan 2008 15:37:14 +0900
Subject: [PATCH][UBIFS] Fix mount oops with wrong name
Message-ID: <20080109063714.GA28810@party>

Also remove white space

/ # mount -t ubifs ubiubifs /tmp
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = c783c000
[00000000] *pgd=8786d031, *pte=00000000, *ppte=00000000
Internal error: Oops: 17 [#1]
Modules linked in: ubifs ubi
CPU: 0    Not tainted  (2.6.23 #15)
PC is at ubi_get_volume_info+0xc/0x84 [ubi]
LR is at ubifs_get_sb+0x4c0/0xfe4 [ubifs]
pc : [<bf0038c8>]    lr : [<bf017f58>]    psr: 60000013
sp : c783bcfc  ip : c783bd10  fp : c783bd0c
r10: bf03dc70  r9 : c7e1d000  r8 : c7e1d37c
r7 : c7e1d374  r6 : c7e1d0a0  r5 : c02b0534  r4 : 00000000
r3 : 00000002  r2 : 00000075  r1 : c7e1d330  r0 : 00000000
Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 00c5387f  Table: 8783c000  DAC: 00000015
Process mount (pid: 283, stack limit = 0xc783a258)
Stack: (0xc783bcfc to 0xc783c000)
Backtrace:
[<bf0038bc>] (ubi_get_volume_info+0x0/0x84 [ubi]) from [<bf017f58>] (ubifs_get_)
 r4:00000000
[<bf017a98>] (ubifs_get_sb+0x0/0xfe4 [ubifs]) from [<c0083c10>] (vfs_kern_mount)
[<c0083bb0>] (vfs_kern_mount+0x0/0xc0) from [<c0083cb8>] (do_kern_mount+0x48/0x)
 r8:c7f4b000 r7:bf03d66c r6:c7899000 r5:c78ee000 r4:00000000
[<c0083c70>] (do_kern_mount+0x0/0xf4) from [<c0099d24>] (do_mount+0x604/0x640)
 r8:00000000 r7:00000000 r6:c7f97000 r5:c78ee000 r4:00000000
[<c0099720>] (do_mount+0x0/0x640) from [<c009a078>] (sys_mount+0xa4/0xec)
[<c0099fd4>] (sys_mount+0x0/0xec) from [<c001ee40>] (ret_fast_syscall+0x0/0x2c)
 r7:00000015 r6:00000000 r5:c0ed0000 r4:00084050
Code: bf012734 e1a0c00d e92dd810 e24cb004 (e5900000)

Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
---
diff --git a/fs/ubifs/build.c b/fs/ubifs/build.c
index 6609e49..82b8f70 100644
--- a/fs/ubifs/build.c
+++ b/fs/ubifs/build.c
@@ -323,7 +323,7 @@ static int alloc_wbufs(struct ubifs_info *c)
 		if (err)
 			return err;
 
-		c->jheads[i].wbuf.sync_callback =  &bud_wbuf_callback;
+		c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback;
 		c->jheads[i].wbuf.jhead = i;
 	}
 
@@ -962,10 +962,12 @@ static int open_ubi(struct ubifs_info *c, const char *name, int mode)
 			c->ubi = ubi_open_volume_nm(dev, ++endptr, mode);
 			if (IS_ERR(c->ubi))
 				return PTR_ERR(c->ubi);
-		} else
-			return -EINVAL;
+		}
 	}
 
+	if (!c->ubi)
+		return -EINVAL;
+
 	ubi_get_volume_info(c->ubi, &c->vi);
 	ubi_get_device_info(c->vi.ubi_num, &c->di);
 	return 0;


From ext-adrian.hunter at nokia.com  Wed Jan  9 02:42:16 2008
From: ext-adrian.hunter at nokia.com (Adrian Hunter)
Date: Wed, 09 Jan 2008 09:42:16 +0200
Subject: [PATCH][UBIFS] Fix mount oops with wrong name
In-Reply-To: <20080109063714.GA28810@party>
References: <20080109063714.GA28810@party>
Message-ID: <47847AD8.5010809@nokia.com>

Kyungmin Park wrote:
> Also remove white space
> 
> / # mount -t ubifs ubiubifs /tmp
> Unable to handle kernel NULL pointer dereference at virtual address 00000000
> pgd = c783c000
> [00000000] *pgd=8786d031, *pte=00000000, *ppte=00000000
> Internal error: Oops: 17 [#1]
> Modules linked in: ubifs ubi
> CPU: 0    Not tainted  (2.6.23 #15)
> PC is at ubi_get_volume_info+0xc/0x84 [ubi]
> LR is at ubifs_get_sb+0x4c0/0xfe4 [ubifs]
> pc : [<bf0038c8>]    lr : [<bf017f58>]    psr: 60000013
> sp : c783bcfc  ip : c783bd10  fp : c783bd0c
> r10: bf03dc70  r9 : c7e1d000  r8 : c7e1d37c
> r7 : c7e1d374  r6 : c7e1d0a0  r5 : c02b0534  r4 : 00000000
> r3 : 00000002  r2 : 00000075  r1 : c7e1d330  r0 : 00000000
> Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
> Control: 00c5387f  Table: 8783c000  DAC: 00000015
> Process mount (pid: 283, stack limit = 0xc783a258)
> Stack: (0xc783bcfc to 0xc783c000)
> Backtrace:
> [<bf0038bc>] (ubi_get_volume_info+0x0/0x84 [ubi]) from [<bf017f58>] (ubifs_get_)
>  r4:00000000
> [<bf017a98>] (ubifs_get_sb+0x0/0xfe4 [ubifs]) from [<c0083c10>] (vfs_kern_mount)
> [<c0083bb0>] (vfs_kern_mount+0x0/0xc0) from [<c0083cb8>] (do_kern_mount+0x48/0x)
>  r8:c7f4b000 r7:bf03d66c r6:c7899000 r5:c78ee000 r4:00000000
> [<c0083c70>] (do_kern_mount+0x0/0xf4) from [<c0099d24>] (do_mount+0x604/0x640)
>  r8:00000000 r7:00000000 r6:c7f97000 r5:c78ee000 r4:00000000
> [<c0099720>] (do_mount+0x0/0x640) from [<c009a078>] (sys_mount+0xa4/0xec)
> [<c0099fd4>] (sys_mount+0x0/0xec) from [<c001ee40>] (ret_fast_syscall+0x0/0x2c)
>  r7:00000015 r6:00000000 r5:c0ed0000 r4:00084050
> Code: bf012734 e1a0c00d e92dd810 e24cb004 (e5900000)
> 
> Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
> ---
> diff --git a/fs/ubifs/build.c b/fs/ubifs/build.c
> index 6609e49..82b8f70 100644
> --- a/fs/ubifs/build.c
> +++ b/fs/ubifs/build.c
> @@ -323,7 +323,7 @@ static int alloc_wbufs(struct ubifs_info *c)
>  		if (err)
>  			return err;
>  
> -		c->jheads[i].wbuf.sync_callback =  &bud_wbuf_callback;
> +		c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback;
>  		c->jheads[i].wbuf.jhead = i;
>  	}
>  
> @@ -962,10 +962,12 @@ static int open_ubi(struct ubifs_info *c, const char *name, int mode)
>  			c->ubi = ubi_open_volume_nm(dev, ++endptr, mode);
>  			if (IS_ERR(c->ubi))
>  				return PTR_ERR(c->ubi);
> -		} else
> -			return -EINVAL;
> +		}
>  	}
>  
> +	if (!c->ubi)
> +		return -EINVAL;
> +
>  	ubi_get_volume_info(c->ubi, &c->vi);
>  	ubi_get_device_info(c->vi.ubi_num, &c->di);
>  	return 0;

Thank you


From r&d2 at dave-tech.it  Wed Jan  9 05:38:08 2008
From: r&d2 at dave-tech.it (llandre)
Date: Wed, 09 Jan 2008 11:38:08 +0100
Subject: NAND bad block detection
Message-ID: <4784A410.9050205@dave-tech.it>

Hi all,

anybody had the chance to read this post

http://article.gmane.org/gmane.linux.drivers.mtd/20150

and is able to clear this issue?




-- 
llandre

DAVE Electronics System House - R&D Department
web:   http://www.dave-tech.it
email: r&d2 at dave-tech.it


From ricard.wanderlof at axis.com  Wed Jan  9 11:30:49 2008
From: ricard.wanderlof at axis.com (Ricard Wanderlof)
Date: Wed, 9 Jan 2008 17:30:49 +0100 (CET)
Subject: mounting "unformatted" nandflash
Message-ID: <Pine.LNX.4.64.0801091138010.22600@lnxricardw.se.axis.com>


Hi all,

Before I start digging into this myself, perhaps someone here has an 
answer.

We are running an embedded system with 128 megs of nand flash 
(large-block). To put it simply, our scenario is that we mount a large 
portion of empty flash as a jffs2 partition. Since the partition is empty, 
there are no [oob] cleanmarkers, and upon mounting, jffs2 scans the 
partition, marks all blocks as needing erasure; this is then ultimately 
controlled by the pdflush kernel task.

The strange thing is that pdflush then takes almost 100% cpu for a minute 
or so to complete. Erasing the whole flash (e.g. using flash_eraseall) 
just takes a few seconds, writing the cleanmarkers should take even less. 
So why is pdflush taking so much time to complete it's task? I've figured 
that it must be the erase/cleanmarker-write process which is the culprit, 
as upon rebooting pdflush exhibits no such behavior when the cleanmarkers 
are in place).

(Yes, in this case we could use flash_eraseall -j (which incidently 
doesn't seem to work but could be easily fixed) to 'format' the partition 
in question. However, for various reasons this isn't practical for us as 
the initial flash write is done using a non-linux tool).

/Ricard
--
Ricard Wolf Wanderl?f                           ricardw(at)axis.com
Axis Communications AB, Lund, Sweden            www.axis.com
Phone +46 46 272 2016                           Fax +46 46 13 61 30


From douglasphilip104 at zipmail.com.br  Wed Jan  9 18:03:12 2008
From: douglasphilip104 at zipmail.com.br (douglasphilip104 at zipmail.com.br)
Date: Thu, 10 Jan 2008 00:03:12 +0100
Subject: =?iso-8859-1?Q?GO=20AND=20SEND=20DELIVERY=20FEE=20TO=20THE=20COMPANY?=
Message-ID: <478470F4000019AF@www.zipmail.com.br>

Attn:Honourable Beneficiary,
 
This is to officially inform you that we have verified your file and found
out why you have not received your fund/draft. It was because you have not
fulfiled the obligations given to you in respect of your overdue fund/draft
payment. Also,You are still dealing with the none officials in the Bank/Courier
and all your attempt to secure the release of your fund/draft failed. I
wish to advise you that such an illegal act should have to stop if you wish
to receive your newly lunched atm card payment. 

I wish to let you know that necessary arrangement has been put in place
to release your fund as your fund was arranged and carefull edited into
ATM card.

This is the latest instruction from Mr. President, Thomas
Yayi Boni/Ministry of Finance Benin Republic. The card center had deposited
your ATM master card with the below delivery
company.Mr.President had mandated to issue out (usd$400,000.00) as part
payment for this fiscal year 2007. You have to stop further contacts with
other person(s) Or Office(s) to avoid any problems in receiving your ATM
master card. 

You will make withdrawals in any part of the world with this ATM master
card but the amount you will withdraw per a day is maximium of(US$1,000
). The amount in the ATM master card is usd$400,000.00.

The only fee that You will send the company is the delivery
charges of usd$95.Therefore, Kindly contact the company and requst them
to give you the informations to send the usd$95. 
and then register for the delivery of your ATM master card to
your address.

Send them the below informations;
1. Your full name..............
2. Your phone and fax number..................
3. Address where you want them to send your ATM master card....
4. Your age and current occupation...............
5. Acopy of your identification card............
6.The delivery Charges usd$95.

Contact person;
Pastor Chris Mba.
E-mail; glocourierbeninofice at yahoo.fr
Note:because of imposters,We hereby issue you a code of conduct
which is (ATM-318) you have to indicate it when contacting the payment center
using it as your Subject. 

Regards.
Hon.Philip Ch.Williams
Chief Auditor To
the president
Benin Republic.






From douglasphilip104 at zipmail.com.br  Wed Jan  9 18:03:11 2008
From: douglasphilip104 at zipmail.com.br (douglasphilip104 at zipmail.com.br)
Date: Thu, 10 Jan 2008 00:03:11 +0100
Subject: =?iso-8859-1?Q?GO=20AND=20SEND=20DELIVERY=20FEE=20TO=20THE=20COMPANY?=
Message-ID: <478470F4000019AE@www.zipmail.com.br>

Attn:Honourable Beneficiary,
 
This is to officially inform you that we have verified your file and found
out why you have not received your fund/draft. It was because you have not
fulfiled the obligations given to you in respect of your overdue fund/draft
payment. Also,You are still dealing with the none officials in the Bank/Courier
and all your attempt to secure the release of your fund/draft failed. I
wish to advise you that such an illegal act should have to stop if you wish
to receive your newly lunched atm card payment. 

I wish to let you know that necessary arrangement has been put in place
to release your fund as your fund was arranged and carefull edited into
ATM card.

This is the latest instruction from Mr. President, Thomas
Yayi Boni/Ministry of Finance Benin Republic. The card center had deposited
your ATM master card with the below delivery
company.Mr.President had mandated to issue out (usd$400,000.00) as part
payment for this fiscal year 2007. You have to stop further contacts with
other person(s) Or Office(s) to avoid any problems in receiving your ATM
master card. 

You will make withdrawals in any part of the world with this ATM master
card but the amount you will withdraw per a day is maximium of(US$1,000
). The amount in the ATM master card is usd$400,000.00.

The only fee that You will send the company is the delivery
charges of usd$95.Therefore, Kindly contact the company and requst them
to give you the informations to send the usd$95. 
and then register for the delivery of your ATM master card to
your address.

Send them the below informations;
1. Your full name..............
2. Your phone and fax number..................
3. Address where you want them to send your ATM master card....
4. Your age and current occupation...............
5. Acopy of your identification card............
6.The delivery Charges usd$95.

Contact person;
Pastor Chris Mba.
E-mail; glocourierbeninofice at yahoo.fr
Note:because of imposters,We hereby issue you a code of conduct
which is (ATM-318) you have to indicate it when contacting the payment center
using it as your Subject. 

Regards.
Hon.Philip Ch.Williams
Chief Auditor To
the president
Benin Republic.






From tur at semihalf.com  Thu Jan 10 04:20:50 2008
From: tur at semihalf.com (Bartlomiej Sieka)
Date: Thu, 10 Jan 2008 10:20:50 +0100
Subject: [PATCH][MTD] Fix incorrect interface code for x16/x32 chips
In-Reply-To: <4755E020.4070702@semihalf.com>
References: <20071126175517.GA1221@frozen.semihalf.com>
	<4755E020.4070702@semihalf.com>
Message-ID: <4785E372.9010409@semihalf.com>

Bartlomiej Sieka wrote:
> Bartlomiej Sieka wrote:
>> According to "Common Flash Memory Interface Publication 100" dated 
>> December 1, 2001, the interface code for x16/x32 chips is 0x0005, 
>> and not 0x0004 used so far.
>> 
>> Signed-off-by: Bartlomiej Sieka <tur at semihalf.com>
> 
> I'd appreciate some feedback on the status of this patch.

Hmm, it's been over a month now since the patch has been posted, and
there haven't been any comments, acceptance/rejection notices, etc. Is
this a wrong list to post this patch? Did I miss some formal requirement
or something? Are people just too busy?

Regards,
Bartlomiej


From joern at logfs.org  Thu Jan 10 06:03:33 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Thu, 10 Jan 2008 12:03:33 +0100
Subject: [PATCH][MTD] Fix incorrect interface code for x16/x32 chips
In-Reply-To: <4785E372.9010409@semihalf.com>
References: <20071126175517.GA1221@frozen.semihalf.com>
	<4755E020.4070702@semihalf.com> <4785E372.9010409@semihalf.com>
Message-ID: <20080110110332.GA26820@lazybastard.org>

On Thu, 10 January 2008 10:20:50 +0100, Bartlomiej Sieka wrote:
> 
> Hmm, it's been over a month now since the patch has been posted, and
> there haven't been any comments, acceptance/rejection notices, etc. Is
> this a wrong list to post this patch? Did I miss some formal requirement
> or something? Are people just too busy?

David tends to be almost constantly busy.  On rare occasions he gets
some free time and merges a large number of patches within one or two
days, then disappears again.

Some people send their patches to Andrew Morton and have him bug David
from time to time.

J?rn

-- 
"Translations are and will always be problematic. They inflict violence
upon two languages." (translation from German)


From rstonehouse at solarflare.com  Thu Jan 10 13:51:13 2008
From: rstonehouse at solarflare.com (Robert Stonehouse)
Date: Thu, 10 Jan 2008 18:51:13 +0000
Subject: [PATCH] [MTD] [RFC] New Solarflare NIC EEPROM/Flash driver
Message-ID: <47866921.40904@solarflare.com>

Hi,

The company I work for (Solarflare Communications) produces a 10Gbit
network adapter and PHYs. We have a network driver (sfc.ko) which we are
currently in the process of submitting to linux-netdev.

One part of this is an MTD driver (sfc_mtd.ko) that gives access to the
EEPROM and flash parts on all our board designs. These should be useful
externally  e.g. programming the flash would be useful for people that want
to flash a PXE image onto the board for network booting.

One unusual aspect is that the MTD driver relies on HW initialisation from
the main network driver (as the registers needed to access the flash and
EEPROM are within a shared PCI BAR). There is a small API (that is named
driverlink in the code) that allows the sfc_mtd driver to detect when a
Solarflare NIC is present and to shutdown when it is removed.

In the last submission that we made to linux-netdev it was requested that
people knowledgeable about MTD drivers look over the code ... so I am sure
  I am in the right place

The thread mentioned was:
     http://marc.info/?l=linux-netdev&m=119825632209357&w=2

The complete network driver is a little too large to post to the list so:
     https://support.solarflare.com/netdev/4/net-2.6.25-sfc-2.2.0038.tgz
And for verification there is:
     https://support.solarflare.com/netdev/4/MD5SUMS

drivers/net/sfc/mtd.c contains the body of the MTD code. As the network
driver uses SPI itself (to read config data from the EEPROM) the MTD driver
uses the same access routines (in falcon.c and spi.h). falcon.c fills in a
struct efx_spi_device which includes function pointers for SPI reads and
writes an well as sizing info and this can be read after a NIC has been
detected, initialised and advertised to driverlink clients.

I would be very interested if anyone has the time to review this.

Many thanks

-- 
Rob Stonehouse


From joern at logfs.org  Thu Jan 10 15:13:09 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Thu, 10 Jan 2008 21:13:09 +0100
Subject: [PATCH] [MTD] [RFC] New Solarflare NIC EEPROM/Flash driver
In-Reply-To: <47866921.40904@solarflare.com>
References: <47866921.40904@solarflare.com>
Message-ID: <20080110201309.GC26820@lazybastard.org>

On Thu, 10 January 2008 18:51:13 +0000, Robert Stonehouse wrote:
> 
> In the last submission that we made to linux-netdev it was requested that
> people knowledgeable about MTD drivers look over the code ... so I am sure
>   I am in the right place

Not quite a review, just a couple of things that stuck out.

  Even if the patch is too large, appending the relevant hunk for the
  mtd driver would have been appreciated.

  The prefix "efx_mtd_" causes me personally some trouble.  By the
  time I have reached the relevant part of the name, my brain has
  already fallen half asleep.  But maybe I'm just overreacting after
  working with in-house code for five years.

  I have no idea why you need eraseregions, if there is just one.
  Kill them?

  How many of the EFX_LOG() statements are still useful?  They may
  have initially helped writing the code, but today they hurt people
  reading the code.
  As a general rule, if you cannot give a good reason why this
  particular log statement is needed in 20s, there usually is none and
  the code can get axed.

  efx_mtd->dead is fun.  Does this still happen with production
  hardware?
  Even if it does, instead of setting the flag and checking it in
  every function, you could replace the operations with
  dead_device_operations that simply return -EIO for every call.

  struct semaphore access_lock; should become a mutex.

Should be enough comments to get things started.

J?rn

-- 
There are two ways of constructing a software design: one way is to make
it so simple that there are obviously no deficiencies, and the other is
to make it so complicated that there are no obvious deficiencies.
-- C. A. R. Hoare


From dwmw2 at infradead.org  Thu Jan 10 17:11:03 2008
From: dwmw2 at infradead.org (David Woodhouse)
Date: Thu, 10 Jan 2008 22:11:03 +0000
Subject: [PATCH][MTD] Fix incorrect interface code for x16/x32 chips
In-Reply-To: <4785E372.9010409@semihalf.com>
References: <20071126175517.GA1221@frozen.semihalf.com>
	<4755E020.4070702@semihalf.com>  <4785E372.9010409@semihalf.com>
Message-ID: <1200003063.2954.4.camel@shinybook.infradead.org>


On Thu, 2008-01-10 at 10:20 +0100, Bartlomiej Sieka wrote:
> Bartlomiej Sieka wrote:
> > Bartlomiej Sieka wrote:
> >> According to "Common Flash Memory Interface Publication 100" dated 
> >> December 1, 2001, the interface code for x16/x32 chips is 0x0005, 
> >> and not 0x0004 used so far.
> >> 
> >> Signed-off-by: Bartlomiej Sieka <tur at semihalf.com>
> > 
> > I'd appreciate some feedback on the status of this patch.
> 
> Hmm, it's been over a month now since the patch has been posted, and
> there haven't been any comments, acceptance/rejection notices, etc. Is
> this a wrong list to post this patch? Did I miss some formal requirement
> or something? Are people just too busy?

Sorry. As J?rn said, I tend to apply patches in bursts. When the merge
window is about to open I try to make sure I catch up. I've applied your
patch now.

Sending it on my girlfriend's birthday and then following up on my
birthday isn't the best way to make sure I pay attention, fwiw :)

-- 
dwmw2



From joern at logfs.org  Thu Jan 10 18:16:45 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Fri, 11 Jan 2008 00:16:45 +0100
Subject: [PATCH] [MTD] [RFC] New Solarflare NIC EEPROM/Flash driver
In-Reply-To: <20080110201309.GC26820@lazybastard.org>
References: <47866921.40904@solarflare.com>
	<20080110201309.GC26820@lazybastard.org>
Message-ID: <20080110231645.GB29847@lazybastard.org>

Editor window was still open on some terminal, so I had a second look:

        /* Free verification buffer */
	kfree(verify_buffer);
  Please kill such non-documentation.  Plain C is readable enough and
  does not need translation in English.  Some of your comments are
  quite useful, because they explain background information.  Do keep
  those.

  efx_mtd_sync() is a function of 29 lines that does... very little.  It
  takes the semaphore and releases it again.  Everything else is pure
  noise.  When reading the function, 90% of the time is wasted on noise.
  So please take a rough brush and sweep out everything you don't need.

  One of my first questions was, why does this driver need 1000 lines?
  And the answer is: it doesn't.  500 sounds like a fair goal.  That
  means 50% of your driver is noise and should get removed.  Which, btw,
  is a fairly good starting point for in-house code.  In my last job,
  75% noise was quite common.
  
  Another interesting metric for in-house code was that while removing
  noise I usually fixed one bug for every 10-20 lines I removed.  Your
  code gives me a significantly better first impression, so I don't
  expect you to find and fix 50 bugs during the cleanup.  But I'd be
  equally surprised if you found none. ;)

J?rn

-- 
Data dominates. If you've chosen the right data structures and organized
things well, the algorithms will almost always be self-evident. Data
structures, not algorithms, are central to programming.
-- Rob Pike


From jsolman33 at yahoo.com  Thu Jan 10 18:38:50 2008
From: jsolman33 at yahoo.com (Jeff S)
Date: Thu, 10 Jan 2008 15:38:50 -0800 (PST)
Subject: JFFS2 determine writing state
Message-ID: <298338.39997.qm@web56002.mail.re3.yahoo.com>

How would one go about checking if JFFS2 is done with a file operation, or all current pending operations?  Is there something in the proc file system or sys file system that allows you to determine the JFFS2 state or something similar.  I need to be able to notify a user that the flash has been written successfully after open, write, and close operations. Thank you.

- Jeff




      ____________________________________________________________________________________
Never miss a thing.  Make Yahoo your home page. 
http://www.yahoo.com/r/hs


From u.luckas at road.de  Fri Jan 11 04:44:41 2008
From: u.luckas at road.de (Uli Luckas)
Date: Fri, 11 Jan 2008 10:44:41 +0100
Subject: [PATCH][CFI] Wrong cache invalidation bug fix
In-Reply-To: <62cbdcd90712130254u64a3ae1eq95b24a4cd2a2f450@mail.gmail.com>
References: <62cbdcd90712030834o28f9126fs841b3b9d46324fb7@mail.gmail.com>
	<62cbdcd90712130248mc82d9cdp781fde10dd73d1b3@mail.gmail.com>
	<62cbdcd90712130254u64a3ae1eq95b24a4cd2a2f450@mail.gmail.com>
Message-ID: <200801111044.43036.u.luckas@road.de>

On Thursday, 13. December 2007, massimo cirillo wrote:
> Hi David,
>
> Could you please apply the patch? It has been tested and acknowledged
> by Nicolas and J?rn.
>
> Description
> This patch fixes improper setting of cache invalidation regions and
> solves the issue of data corrupting.
>
What happend to this patch? As it fixes a grave bug, shouldn't it be pushed 
out for 2.6.24?

regards,
Uli

-- 

------- ROAD ...the handyPC Company - - -  ) ) )

Uli Luckas
Software Development

ROAD GmbH
Bennigsenstr. 14 | 12159 Berlin | Germany
fon: +49 (30) 230069 - 64 | fax: +49 (30) 230069 - 69
url: www.road.de

Amtsgericht Charlottenburg: HRB 96688 B
Managing directors: Hans-Peter Constien, Hubertus von Streit


From dwmw2 at infradead.org  Fri Jan 11 06:03:16 2008
From: dwmw2 at infradead.org (David Woodhouse)
Date: Fri, 11 Jan 2008 11:03:16 +0000
Subject: [PATCH][CFI] Wrong cache invalidation bug fix
In-Reply-To: <Pine.LNX.4.64.0801111042510.20196@pentafluge.infradead.org>
References: <62cbdcd90712030834o28f9126fs841b3b9d46324fb7@mail.gmail.com>
	<alpine.LFD.0.99999.0712031210180.9605@xanadu.home>
	<62cbdcd90712050758h36335aa5q176f1c192f18d6a9@mail.gmail.com>
	<Pine.LNX.4.64.0801111042510.20196@pentafluge.infradead.org>
Message-ID: <1200049397.4839.7.camel@pmac.infradead.org>


On Fri, 2008-01-11 at 10:50 +0000, Alexey Korolev wrote:
> Please include patch from Massimo? It fixes bad dug in CFI driver.

I don't think I've ever received a version of the patch in email which
actually applies. Please remember to save the mail you get back from the
mailing list and try to apply it for yourself to a clean tree. Or better
still, send it to yourself first, _before_ sending it out.

That isn't an excuse for ignoring it for a month -- on that I plead
incompetence.

I've taken the version from Jared's git tree and sent it to Linus.

-- 
dwmw2



From eric.y.miao at gmail.com  Fri Jan 11 06:15:10 2008
From: eric.y.miao at gmail.com (eric miao)
Date: Fri, 11 Jan 2008 19:15:10 +0800
Subject: [PATCH] basic pxa3 nand controller support
In-Reply-To: <loom.20080107T001557-159@post.gmane.org>
References: <f17812d70712201756h501a80cch8305d40fa479f5cf@mail.gmail.com>
	<loom.20080107T001557-159@post.gmane.org>
Message-ID: <f17812d70801110315l545d4a6eu89a0cc775d505278@mail.gmail.com>

On Jan 7, 2008 8:23 AM, Marcel Ziswiler <marcel at ziswiler.com> wrote:
> eric miao <eric.y.miao <at> gmail.com> writes:
>
> > Early feedback is welcome, thanks!
>
> Hi Eric
>
> Overall the patch looks good, just a few comments.
>
> The patch does not apply cleanly unless I remove the spurious newline before
> line 1284 resulting in the following error:
> patch: **** malformed patch at line 1284: pm_message_t state)
>

I might have modified the patch directly, but not sure. Git will
complain but plain
"patch" should work.

> The DRCMR97 register is not defined anywhere, at lest not in 2.6.24-rc6:
> drivers/mtd/nand/pxa3xx_nand.c:542: error: 'DRCMR97' undeclared (first use in
> this function)
>
> The registers and bit definitions should be moved to pxa-regs.h, not?
>

right, but the trend is not to introduce too many DRCMRxx register definitions
into pxa-regs.h, use DRCMR(xx) is more preferred, so you can modify that
to DRCMR(97) please.

> I had my troubles getting it to work on a custom PXA320 board. I kinda figured
> out what platform data it needs, but still can't seem to get it to work properly:
> pxa3xx-nand pxa3xx-nand: failed to detect flash
>

pxa320 may be connected to external NAND flash, which the driver does not
yet support (only those __builtin_xxx are supported for now), sigh, the reason
is a long story

You may let me know the NAND flash type, so I can check with the driver.

> What kernel does your patch apply to? What CPUs/boards did you try it on? Can
> you provide an example platform integration required to make it work?
>

zylonite/pxa{300,310}, both work. Yes, I'll post the remaining patch next week,
hopefully.

> Cheers
>
> Marcel
>
>
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>



-- 
Cheers
- eric


From bhutchings at solarflare.com  Fri Jan 11 07:50:01 2008
From: bhutchings at solarflare.com (Ben Hutchings)
Date: Fri, 11 Jan 2008 12:50:01 +0000
Subject: [PATCH] [MTD] [RFC] New Solarflare NIC EEPROM/Flash driver
In-Reply-To: <20080110201309.GC26820@lazybastard.org>
References: <47866921.40904@solarflare.com>
	<20080110201309.GC26820@lazybastard.org>
Message-ID: <20080111125000.GL3544@solarflare.com>

I didn't originally write this driver, but I was the last person to
make significant changes to it.

J?rn Engel wrote:
> On Thu, 10 January 2008 18:51:13 +0000, Robert Stonehouse wrote:
> > 
> > In the last submission that we made to linux-netdev it was requested that
> > people knowledgeable about MTD drivers look over the code ... so I am sure
> >   I am in the right place
> 
> Not quite a review, just a couple of things that stuck out.
> 
>   Even if the patch is too large, appending the relevant hunk for the
>   mtd driver would have been appreciated.

Sorry about that.  We could have posted just mtd.c, but that would
have been missing the pieces inside the net driver that it depends on.

>   The prefix "efx_mtd_" causes me personally some trouble.  By the
>   time I have reached the relevant part of the name, my brain has
>   already fallen half asleep.  But maybe I'm just overreacting after
>   working with in-house code for five years.
> 
>   I have no idea why you need eraseregions, if there is just one.
>   Kill them?

Earlier versions of this driver supported our first controller and
NICs, EF1/EF1002, which did have multiple regions of flash.  I
simplified the code after this support was removed, but I wasn't aware
that we could avoid specifying eraseregions at all.

>   How many of the EFX_LOG() statements are still useful?  They may
>   have initially helped writing the code, but today they hurt people
>   reading the code.
>   As a general rule, if you cannot give a good reason why this
>   particular log statement is needed in 20s, there usually is none and
>   the code can get axed.

You're right, it is a bit verbose.

>   efx_mtd->dead is fun.  Does this still happen with production
>   hardware?

It shouldn't happen with anything that passed manufacturing tests.
This is playing safe.

>   Even if it does, instead of setting the flag and checking it in
>   every function, you could replace the operations with
>   dead_device_operations that simply return -EIO for every call.
>
>   struct semaphore access_lock; should become a mutex.

Right.  We've tended to be quite conservative in using newer kernel
features, since we also need to support old kernels, but we have a
good backward-compatibility layer now (unifdef'd out of the submitted
code) so this shouldn't be a problem.

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.


From joern at logfs.org  Fri Jan 11 08:24:45 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Fri, 11 Jan 2008 14:24:45 +0100
Subject: [PATCH] [MTD] [RFC] New Solarflare NIC EEPROM/Flash driver
In-Reply-To: <20080111125000.GL3544@solarflare.com>
References: <47866921.40904@solarflare.com>
	<20080110201309.GC26820@lazybastard.org>
	<20080111125000.GL3544@solarflare.com>
Message-ID: <20080111132444.GA1399@lazybastard.org>

On Fri, 11 January 2008 12:50:01 +0000, Ben Hutchings wrote:
> >
> >   The prefix "efx_mtd_" causes me personally some trouble.  By the
> >   time I have reached the relevant part of the name, my brain has
> >   already fallen half asleep.  But maybe I'm just overreacting after
> >   working with in-house code for five years.
> > 
> >   I have no idea why you need eraseregions, if there is just one.
> >   Kill them?
> 
> Earlier versions of this driver supported our first controller and
> NICs, EF1/EF1002, which did have multiple regions of flash.  I
> simplified the code after this support was removed, but I wasn't aware
> that we could avoid specifying eraseregions at all.

Even when eraseregions exist, most code simply ignores them and treats
the complete flash a having a single uniform erasesize.
*greps the source*
The only two users are UBI and mtdchar.  UBI is bogus and mtdchar
exposes it to userspace, where anything could theoretically exist.

Anything else is confined to the CFI code, which you don't use.

> >   efx_mtd->dead is fun.  Does this still happen with production
> >   hardware?
> 
> It shouldn't happen with anything that passed manufacturing tests.
> This is playing safe.

Fair enough.  Then I would prefer the dead_device_operations approach.

> >   Even if it does, instead of setting the flag and checking it in
> >   every function, you could replace the operations with
> >   dead_device_operations that simply return -EIO for every call.
> >
> >   struct semaphore access_lock; should become a mutex.
> 
> Right.  We've tended to be quite conservative in using newer kernel
> features, since we also need to support old kernels, but we have a
> good backward-compatibility layer now (unifdef'd out of the submitted
> code) so this shouldn't be a problem.

Ok.  A straight conversion to a mutex will likely cause trouble with
your reset routine.  Not sure what to do here.

J?rn

-- 
All models are wrong. Some models are useful.
-- George Box


From zql at glomationinc.com  Fri Jan 11 08:47:13 2008
From: zql at glomationinc.com (Zhong Li)
Date: Fri, 11 Jan 2008 08:47:13 -0500
Subject: MTD Make select_chip optional?
Message-ID: <F57D96A984C7417F88EC7A545CE40B46@Saturn>

As the NAND chip capacity grows it seems designs with multiple chips become
less common than single chip.  Looking at the nand_base.c it seems the
select_chip gets called a lot.  Wouldn't it make significant performance
increase if the select_chip call is made optional only for hardware design
with multiple chips?

zl



From jwboyer at gmail.com  Fri Jan 11 08:57:30 2008
From: jwboyer at gmail.com (Josh Boyer)
Date: Fri, 11 Jan 2008 07:57:30 -0600
Subject: JFFS2 determine writing state
In-Reply-To: <298338.39997.qm@web56002.mail.re3.yahoo.com>
References: <298338.39997.qm@web56002.mail.re3.yahoo.com>
Message-ID: <20080111075730.052c821d@zod.rchland.ibm.com>

On Thu, 10 Jan 2008 15:38:50 -0800 (PST)
Jeff S <jsolman33 at yahoo.com> wrote:

> How would one go about checking if JFFS2 is done with a file operation, or all current pending operations?  Is there something in the proc file system or sys file system that allows you to determine the JFFS2 state or something similar.  I need to be able to notify a user that the flash has been written successfully after open, write, and close operations. Thank you.

If you are using regular NOR flash and have the write buffer disabled,
anything you write via the write system call will be written to flash
before it returns.  The open call doesn't cause any writes, and close
is supposed to flush all pending writes before it returns.

There is always fsync or sync as well.

josh


From tur at semihalf.com  Fri Jan 11 10:27:16 2008
From: tur at semihalf.com (Bartlomiej Sieka)
Date: Fri, 11 Jan 2008 16:27:16 +0100
Subject: [PATCH][MTD] Fix incorrect interface code for x16/x32 chips
In-Reply-To: <1200003063.2954.4.camel@shinybook.infradead.org>
References: <20071126175517.GA1221@frozen.semihalf.com>	
	<4755E020.4070702@semihalf.com> <4785E372.9010409@semihalf.com>
	<1200003063.2954.4.camel@shinybook.infradead.org>
Message-ID: <47878AD4.2070204@semihalf.com>

David Woodhouse wrote:
[...]
>>>> According to "Common Flash Memory Interface Publication 100" dated 
>>>> December 1, 2001, the interface code for x16/x32 chips is 0x0005, 
>>>> and not 0x0004 used so far.
>>>>
>>>> Signed-off-by: Bartlomiej Sieka <tur at semihalf.com>
[...]
> Sorry. As J?rn said, I tend to apply patches in bursts. When the merge
> window is about to open I try to make sure I catch up. I've applied your
> patch now.

OK, thanks.

> 
> Sending it on my girlfriend's birthday and then following up on my
> birthday isn't the best way to make sure I pay attention, fwiw :)

Ah, I've marked my calendar now :)

Cheers,
Bartlomiej


From dwmw2 at infradead.org  Fri Jan 11 11:27:53 2008
From: dwmw2 at infradead.org (David Woodhouse)
Date: Fri, 11 Jan 2008 16:27:53 +0000
Subject: MTD Make select_chip optional?
In-Reply-To: <F57D96A984C7417F88EC7A545CE40B46@Saturn>
References: <F57D96A984C7417F88EC7A545CE40B46@Saturn>
Message-ID: <1200068873.4839.27.camel@pmac.infradead.org>


On Fri, 2008-01-11 at 08:47 -0500, Zhong Li wrote:
> As the NAND chip capacity grows it seems designs with multiple chips become
> less common than single chip.  Looking at the nand_base.c it seems the
> select_chip gets called a lot.  Wouldn't it make significant performance
> increase if the select_chip call is made optional only for hardware design
> with multiple chips?

In my experience the answer is likely to be 'no'. Feel free to benchmark
it and prove otherwise....

-- 
dwmw2



From bhutchings at solarflare.com  Fri Jan 11 13:55:51 2008
From: bhutchings at solarflare.com (Ben Hutchings)
Date: Fri, 11 Jan 2008 18:55:51 +0000
Subject: [PATCH] [MTD] [RFC] New Solarflare NIC EEPROM/Flash driver
In-Reply-To: <20080111132444.GA1399@lazybastard.org>
References: <47866921.40904@solarflare.com>
	<20080110201309.GC26820@lazybastard.org>
	<20080111125000.GL3544@solarflare.com>
	<20080111132444.GA1399@lazybastard.org>
Message-ID: <20080111185550.GN3544@solarflare.com>

J?rn Engel wrote:
> > >   efx_mtd->dead is fun.  Does this still happen with production
> > >   hardware?
> > 
> > It shouldn't happen with anything that passed manufacturing tests.
> > This is playing safe.
> 
> Fair enough.  Then I would prefer the dead_device_operations approach.

It turns out that struct efx_mtd_operations is a redundant indirection
layer, but I can introduce a dummy struct efx_spi_device which does
the same thing.

> > >   Even if it does, instead of setting the flag and checking it in
> > >   every function, you could replace the operations with
> > >   dead_device_operations that simply return -EIO for every call.
> > >
> > >   struct semaphore access_lock; should become a mutex.
> > 
> > Right.  We've tended to be quite conservative in using newer kernel
> > features, since we also need to support old kernels, but we have a
> > good backward-compatibility layer now (unifdef'd out of the submitted
> > code) so this shouldn't be a problem.
> 
> Ok.  A straight conversion to a mutex will likely cause trouble with
> your reset routine.  Not sure what to do here.

We can use a mutex if the net driver is guaranteed to call
reset_suspend() and reset_resume() in the same context.  This is
currently true (they are always called in a pair by efx_reset() in
efx.c) but I'm not sure we want to guarantee that.  Unfortunately it
*is* sometimes necessary to reset the controller after it's been
exposed through driverlink, so this is not something we can ignore.

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.


From joern at logfs.org  Fri Jan 11 14:57:26 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Fri, 11 Jan 2008 20:57:26 +0100
Subject: [PATCH] [MTD] [RFC] New Solarflare NIC EEPROM/Flash driver
In-Reply-To: <20080111185550.GN3544@solarflare.com>
References: <47866921.40904@solarflare.com>
	<20080110201309.GC26820@lazybastard.org>
	<20080111125000.GL3544@solarflare.com>
	<20080111132444.GA1399@lazybastard.org>
	<20080111185550.GN3544@solarflare.com>
Message-ID: <20080111195725.GB1399@lazybastard.org>

On Fri, 11 January 2008 18:55:51 +0000, Ben Hutchings wrote:
> 
> It turns out that struct efx_mtd_operations is a redundant indirection
> layer, but I can introduce a dummy struct efx_spi_device which does
> the same thing.

Sounds good.

> > Ok.  A straight conversion to a mutex will likely cause trouble with
> > your reset routine.  Not sure what to do here.
> 
> We can use a mutex if the net driver is guaranteed to call
> reset_suspend() and reset_resume() in the same context.  This is
> currently true (they are always called in a pair by efx_reset() in
> efx.c) but I'm not sure we want to guarantee that.  Unfortunately it
> *is* sometimes necessary to reset the controller after it's been
> exposed through driverlink, so this is not something we can ignore.

I would try to move the lock as far down the callchain as possible.
If you can limit it to the raw bus access, your mtd driver doesn't need
locking at all.

J?rn

-- 
Joern's library part 12:
http://physics.nist.gov/cuu/Units/binary.html


From scottwood at freescale.com  Fri Jan 11 15:49:02 2008
From: scottwood at freescale.com (Scott Wood)
Date: Fri, 11 Jan 2008 14:49:02 -0600
Subject: [RESEND PATCH 1/3] nand base: Don't panic if a controller driver
	does ecc its own way.
Message-ID: <20080111204902.GA11291@loki.buserror.net>

Some hardware, such as the enhanced local bus controller used on some
mpc83xx chips, does ecc transparently when reading and writing data, rather
than providing a generic calculate/correct mechanism that can be exported to
the nand subsystem.

The subsystem should not BUG() when calculate, correct, or hwctl are
missing, if the methods that call them have been overridden.

Signed-off-by: Scott Wood <scottwood at freescale.com>
---
Patch series resent with the right list address.  Was previously sent
to David and the linuxppc-dev list.

 drivers/mtd/nand/nand_base.c |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index e29c1da..85a7283 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2469,8 +2469,12 @@ int nand_scan_tail(struct mtd_info *mtd)
 			chip->ecc.write_oob = nand_write_oob_std;
 
 	case NAND_ECC_HW_SYNDROME:
-		if (!chip->ecc.calculate || !chip->ecc.correct ||
-		    !chip->ecc.hwctl) {
+		if ((!chip->ecc.calculate || !chip->ecc.correct ||
+		     !chip->ecc.hwctl) &&
+		    (!chip->ecc.read_page ||
+		     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");
 			BUG();
-- 
1.5.3.8



From scottwood at freescale.com  Fri Jan 11 15:49:07 2008
From: scottwood at freescale.com (Scott Wood)
Date: Fri, 11 Jan 2008 14:49:07 -0600
Subject: [RESEND PATCH 3/3] Freescale enhanced Local Bus Controller FCM
	NAND support.
Message-ID: <20080111204907.GB11291@loki.buserror.net>

Signed-off-by: Nick Spence <nick.spence at freescale.com>
Signed-off-by: Scott Wood <scottwood at freescale.com>
---
 drivers/mtd/nand/Kconfig         |    9 +
 drivers/mtd/nand/Makefile        |    1 +
 drivers/mtd/nand/fsl_elbc_nand.c | 1243 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 1253 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mtd/nand/fsl_elbc_nand.c

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 0a840d5..4a3c675 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -321,4 +321,13 @@ config MTD_NAND_ORION
 	  No board specific support is done by this driver, each board
 	  must advertise a platform_device for the driver to attach.
 
+config MTD_NAND_FSL_ELBC
+	tristate "NAND support for Freescale eLBC controllers"
+	depends on MTD_NAND && PPC_OF
+	help
+	  Various Freescale chips, including the 8313, include a NAND Flash
+	  Controller Module with built-in hardware ECC capabilities.
+	  Enabling this option will enable you to use this to control
+	  external NAND devices.
+
 endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index e35f5ea..80d575e 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -31,5 +31,6 @@ obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
 obj-$(CONFIG_MTD_ALAUDA)		+= alauda.o
 obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
 obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
+obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
 
 nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
new file mode 100644
index 0000000..2a05bf9
--- /dev/null
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -0,0 +1,1243 @@
+/* Freescale Enhanced Local Bus Controller NAND driver
+ *
+ * Copyright (c) 2006-2007 Freescale Semiconductor
+ *
+ * Authors: Nick Spence <nick.spence at freescale.com>,
+ *          Scott Wood <scottwood at freescale.com>
+ *
+ * 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/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+
+
+#define MAX_BANKS 8
+#define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */
+#define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */
+
+struct elbc_bank {
+	__be32 br;             /**< Base Register  */
+#define BR_BA           0xFFFF8000
+#define BR_BA_SHIFT             15
+#define BR_PS           0x00001800
+#define BR_PS_SHIFT             11
+#define BR_PS_8         0x00000800  /* Port Size 8 bit */
+#define BR_PS_16        0x00001000  /* Port Size 16 bit */
+#define BR_PS_32        0x00001800  /* Port Size 32 bit */
+#define BR_DECC         0x00000600
+#define BR_DECC_SHIFT            9
+#define BR_DECC_OFF     0x00000000  /* HW ECC checking and generation off */
+#define BR_DECC_CHK     0x00000200  /* HW ECC checking on, generation off */
+#define BR_DECC_CHK_GEN 0x00000400  /* HW ECC checking and generation on */
+#define BR_WP           0x00000100
+#define BR_WP_SHIFT              8
+#define BR_MSEL         0x000000E0
+#define BR_MSEL_SHIFT            5
+#define BR_MS_GPCM      0x00000000  /* GPCM */
+#define BR_MS_FCM       0x00000020  /* FCM */
+#define BR_MS_SDRAM     0x00000060  /* SDRAM */
+#define BR_MS_UPMA      0x00000080  /* UPMA */
+#define BR_MS_UPMB      0x000000A0  /* UPMB */
+#define BR_MS_UPMC      0x000000C0  /* UPMC */
+#define BR_V            0x00000001
+#define BR_V_SHIFT               0
+#define BR_RES          ~(BR_BA|BR_PS|BR_DECC|BR_WP|BR_MSEL|BR_V)
+
+	__be32 or;             /**< Base Register  */
+#define OR0 0x5004
+#define OR1 0x500C
+#define OR2 0x5014
+#define OR3 0x501C
+#define OR4 0x5024
+#define OR5 0x502C
+#define OR6 0x5034
+#define OR7 0x503C
+
+#define OR_FCM_AM               0xFFFF8000
+#define OR_FCM_AM_SHIFT                 15
+#define OR_FCM_BCTLD            0x00001000
+#define OR_FCM_BCTLD_SHIFT              12
+#define OR_FCM_PGS              0x00000400
+#define OR_FCM_PGS_SHIFT                10
+#define OR_FCM_CSCT             0x00000200
+#define OR_FCM_CSCT_SHIFT                9
+#define OR_FCM_CST              0x00000100
+#define OR_FCM_CST_SHIFT                 8
+#define OR_FCM_CHT              0x00000080
+#define OR_FCM_CHT_SHIFT                 7
+#define OR_FCM_SCY              0x00000070
+#define OR_FCM_SCY_SHIFT                 4
+#define OR_FCM_SCY_1            0x00000010
+#define OR_FCM_SCY_2            0x00000020
+#define OR_FCM_SCY_3            0x00000030
+#define OR_FCM_SCY_4            0x00000040
+#define OR_FCM_SCY_5            0x00000050
+#define OR_FCM_SCY_6            0x00000060
+#define OR_FCM_SCY_7            0x00000070
+#define OR_FCM_RST              0x00000008
+#define OR_FCM_RST_SHIFT                 3
+#define OR_FCM_TRLX             0x00000004
+#define OR_FCM_TRLX_SHIFT                2
+#define OR_FCM_EHTR             0x00000002
+#define OR_FCM_EHTR_SHIFT                1
+};
+
+struct elbc_regs {
+	struct elbc_bank bank[8];
+	u8 res0[0x28];
+	__be32 mar;             /**< UPM Address Register */
+	u8 res1[0x4];
+	__be32 mamr;            /**< UPMA Mode Register */
+	__be32 mbmr;            /**< UPMB Mode Register */
+	__be32 mcmr;            /**< UPMC Mode Register */
+	u8 res2[0x8];
+	__be32 mrtpr;           /**< Memory Refresh Timer Prescaler Register */
+	__be32 mdr;             /**< UPM Data Register */
+	u8 res3[0x4];
+	__be32 lsor;            /**< Special Operation Initiation Register */
+	__be32 lsdmr;           /**< SDRAM Mode Register */
+	u8 res4[0x8];
+	__be32 lurt;            /**< UPM Refresh Timer */
+	__be32 lsrt;            /**< SDRAM Refresh Timer */
+	u8 res5[0x8];
+	__be32 ltesr;           /**< Transfer Error Status Register */
+#define LTESR_BM   0x80000000
+#define LTESR_FCT  0x40000000
+#define LTESR_PAR  0x20000000
+#define LTESR_WP   0x04000000
+#define LTESR_ATMW 0x00800000
+#define LTESR_ATMR 0x00400000
+#define LTESR_CS   0x00080000
+#define LTESR_CC   0x00000001
+#define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC)
+	__be32 ltedr;           /**< Transfer Error Disable Register */
+	__be32 lteir;           /**< Transfer Error Interrupt Register */
+	__be32 lteatr;          /**< Transfer Error Attributes Register */
+	__be32 ltear;           /**< Transfer Error Address Register */
+	u8 res6[0xC];
+	__be32 lbcr;            /**< Configuration Register */
+#define LBCR_LDIS  0x80000000
+#define LBCR_LDIS_SHIFT    31
+#define LBCR_BCTLC 0x00C00000
+#define LBCR_BCTLC_SHIFT   22
+#define LBCR_AHD   0x00200000
+#define LBCR_LPBSE 0x00020000
+#define LBCR_LPBSE_SHIFT   17
+#define LBCR_EPAR  0x00010000
+#define LBCR_EPAR_SHIFT    16
+#define LBCR_BMT   0x0000FF00
+#define LBCR_BMT_SHIFT      8
+#define LBCR_INIT  0x00040000
+	__be32 lcrr;            /**< Clock Ratio Register */
+#define LCRR_DBYP    0x80000000
+#define LCRR_DBYP_SHIFT      31
+#define LCRR_BUFCMDC 0x30000000
+#define LCRR_BUFCMDC_SHIFT   28
+#define LCRR_ECL     0x03000000
+#define LCRR_ECL_SHIFT       24
+#define LCRR_EADC    0x00030000
+#define LCRR_EADC_SHIFT      16
+#define LCRR_CLKDIV  0x0000000F
+#define LCRR_CLKDIV_SHIFT     0
+	u8 res7[0x8];
+	__be32 fmr;             /**< Flash Mode Register */
+#define FMR_CWTO     0x0000F000
+#define FMR_CWTO_SHIFT       12
+#define FMR_BOOT     0x00000800
+#define FMR_ECCM     0x00000100
+#define FMR_AL       0x00000030
+#define FMR_AL_SHIFT          4
+#define FMR_OP       0x00000003
+#define FMR_OP_SHIFT          0
+	__be32 fir;             /**< Flash Instruction Register */
+#define FIR_OP0      0xF0000000
+#define FIR_OP0_SHIFT        28
+#define FIR_OP1      0x0F000000
+#define FIR_OP1_SHIFT        24
+#define FIR_OP2      0x00F00000
+#define FIR_OP2_SHIFT        20
+#define FIR_OP3      0x000F0000
+#define FIR_OP3_SHIFT        16
+#define FIR_OP4      0x0000F000
+#define FIR_OP4_SHIFT        12
+#define FIR_OP5      0x00000F00
+#define FIR_OP5_SHIFT         8
+#define FIR_OP6      0x000000F0
+#define FIR_OP6_SHIFT         4
+#define FIR_OP7      0x0000000F
+#define FIR_OP7_SHIFT         0
+#define FIR_OP_NOP   0x0	/* No operation and end of sequence */
+#define FIR_OP_CA    0x1        /* Issue current column address */
+#define FIR_OP_PA    0x2        /* Issue current block+page address */
+#define FIR_OP_UA    0x3        /* Issue user defined address */
+#define FIR_OP_CM0   0x4        /* Issue command from FCR[CMD0] */
+#define FIR_OP_CM1   0x5        /* Issue command from FCR[CMD1] */
+#define FIR_OP_CM2   0x6        /* Issue command from FCR[CMD2] */
+#define FIR_OP_CM3   0x7        /* Issue command from FCR[CMD3] */
+#define FIR_OP_WB    0x8        /* Write FBCR bytes from FCM buffer */
+#define FIR_OP_WS    0x9        /* Write 1 or 2 bytes from MDR[AS] */
+#define FIR_OP_RB    0xA        /* Read FBCR bytes to FCM buffer */
+#define FIR_OP_RS    0xB        /* Read 1 or 2 bytes to MDR[AS] */
+#define FIR_OP_CW0   0xC        /* Wait then issue FCR[CMD0] */
+#define FIR_OP_CW1   0xD        /* Wait then issue FCR[CMD1] */
+#define FIR_OP_RBW   0xE        /* Wait then read FBCR bytes */
+#define FIR_OP_RSW   0xE        /* Wait then read 1 or 2 bytes */
+	__be32 fcr;             /**< Flash Command Register */
+#define FCR_CMD0     0xFF000000
+#define FCR_CMD0_SHIFT       24
+#define FCR_CMD1     0x00FF0000
+#define FCR_CMD1_SHIFT       16
+#define FCR_CMD2     0x0000FF00
+#define FCR_CMD2_SHIFT        8
+#define FCR_CMD3     0x000000FF
+#define FCR_CMD3_SHIFT        0
+	__be32 fbar;            /**< Flash Block Address Register */
+#define FBAR_BLK     0x00FFFFFF
+	__be32 fpar;            /**< Flash Page Address Register */
+#define FPAR_SP_PI   0x00007C00
+#define FPAR_SP_PI_SHIFT     10
+#define FPAR_SP_MS   0x00000200
+#define FPAR_SP_CI   0x000001FF
+#define FPAR_SP_CI_SHIFT      0
+#define FPAR_LP_PI   0x0003F000
+#define FPAR_LP_PI_SHIFT     12
+#define FPAR_LP_MS   0x00000800
+#define FPAR_LP_CI   0x000007FF
+#define FPAR_LP_CI_SHIFT      0
+	__be32 fbcr;            /**< Flash Byte Count Register */
+#define FBCR_BC      0x00000FFF
+	u8 res11[0x8];
+	u8 res8[0xF00];
+};
+
+struct fsl_elbc_ctrl;
+
+/* mtd information per set */
+
+struct fsl_elbc_mtd {
+	struct mtd_info mtd;
+	struct nand_chip chip;
+	struct fsl_elbc_ctrl *ctrl;
+
+	struct device *dev;
+	int bank;               /* Chip select bank number           */
+	u8 __iomem *vbase;      /* Chip select base virtual address  */
+	int page_size;          /* NAND page size (0=512, 1=2048)    */
+	unsigned int fmr;       /* FCM Flash Mode Register value     */
+};
+
+/* overview of the fsl elbc controller */
+
+struct fsl_elbc_ctrl {
+	struct nand_hw_control controller;
+	struct fsl_elbc_mtd *chips[MAX_BANKS];
+
+	/* device info */
+	struct device *dev;
+	struct elbc_regs __iomem *regs;
+	int irq;
+	wait_queue_head_t irq_wait;
+	unsigned int irq_status; /* status read from LTESR by irq handler */
+	u8 __iomem *addr;        /* Address of assigned FCM buffer        */
+	unsigned int page;       /* Last page written to / read from      */
+	unsigned int read_bytes; /* Number of bytes read during command   */
+	unsigned int column;     /* Saved column from SEQIN               */
+	unsigned int index;      /* Pointer to next byte to 'read'        */
+	unsigned int status;     /* status read from LTESR after last op  */
+	unsigned int mdr;        /* UPM/FCM Data Register value           */
+	unsigned int use_mdr;    /* Non zero if the MDR is to be set      */
+	unsigned int oob;        /* Non zero if operating on OOB data     */
+	char *oob_poi;           /* Place to write ECC after read back    */
+};
+
+/* These map to the positions used by the FCM hardware ECC generator */
+
+/* Small Page FLASH with FMR[ECCM] = 0 */
+static struct nand_ecclayout fsl_elbc_oob_sp_eccm0 = {
+	.eccbytes = 3,
+	.eccpos = {6, 7, 8},
+	.oobfree = { {0, 5}, {9, 7} },
+	.oobavail = 12,
+};
+
+/* Small Page FLASH with FMR[ECCM] = 1 */
+static struct nand_ecclayout fsl_elbc_oob_sp_eccm1 = {
+	.eccbytes = 3,
+	.eccpos = {8, 9, 10},
+	.oobfree = { {0, 5}, {6, 2}, {11, 5} },
+	.oobavail = 12,
+};
+
+/* Large Page FLASH with FMR[ECCM] = 0 */
+static struct nand_ecclayout fsl_elbc_oob_lp_eccm0 = {
+	.eccbytes = 12,
+	.eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56},
+	.oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} },
+	.oobavail = 48,
+};
+
+/* Large Page FLASH with FMR[ECCM] = 1 */
+static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = {
+	.eccbytes = 12,
+	.eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58},
+	.oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} },
+	.oobavail = 48,
+};
+
+/*=================================*/
+
+/*
+ * Set up the FCM hardware block and page address fields, and the fcm
+ * structure addr field to point to the correct FCM buffer in memory
+ */
+static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+	int buf_num;
+
+	ctrl->page = page_addr;
+
+	out_be32(&lbc->fbar,
+	         page_addr >> (chip->phys_erase_shift - chip->page_shift));
+
+	if (priv->page_size) {
+		out_be32(&lbc->fpar,
+		         ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) |
+		         (oob ? FPAR_LP_MS : 0) | column);
+		buf_num = (page_addr & 1) << 2;
+	} else {
+		out_be32(&lbc->fpar,
+		         ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) |
+		         (oob ? FPAR_SP_MS : 0) | column);
+		buf_num = page_addr & 7;
+	}
+
+	ctrl->addr = priv->vbase + buf_num * 1024;
+	ctrl->index = column;
+
+	/* for OOB data point to the second half of the buffer */
+	if (oob)
+		ctrl->index += priv->page_size ? 2048 : 512;
+
+	dev_vdbg(ctrl->dev, "set_addr: bank=%d, ctrl->addr=0x%p (0x%p), "
+	                    "index %x, pes %d ps %d\n",
+	         buf_num, ctrl->addr, priv->vbase, ctrl->index,
+	         chip->phys_erase_shift, chip->page_shift);
+}
+
+/*
+ * execute FCM command and wait for it to complete
+ */
+static int fsl_elbc_run_command(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+
+	/* Setup the FMR[OP] to execute without write protection */
+	out_be32(&lbc->fmr, priv->fmr | 3);
+	if (ctrl->use_mdr)
+		out_be32(&lbc->mdr, ctrl->mdr);
+
+	dev_vdbg(ctrl->dev,
+	         "fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n",
+	         in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr));
+	dev_vdbg(ctrl->dev,
+	         "fsl_elbc_run_command: fbar=%08x fpar=%08x "
+	         "fbcr=%08x bank=%d\n",
+	         in_be32(&lbc->fbar), in_be32(&lbc->fpar),
+	         in_be32(&lbc->fbcr), priv->bank);
+
+	/* execute special operation */
+	out_be32(&lbc->lsor, priv->bank);
+
+	/* wait for FCM complete flag or timeout */
+	ctrl->irq_status = 0;
+	wait_event_timeout(ctrl->irq_wait, ctrl->irq_status,
+	                   FCM_TIMEOUT_MSECS * HZ/1000);
+	ctrl->status = ctrl->irq_status;
+
+	/* store mdr value in case it was needed */
+	if (ctrl->use_mdr)
+		ctrl->mdr = in_be32(&lbc->mdr);
+
+	ctrl->use_mdr = 0;
+
+	dev_vdbg(ctrl->dev,
+	         "fsl_elbc_run_command: stat=%08x mdr=%08x fmr=%08x\n",
+	         ctrl->status, ctrl->mdr, in_be32(&lbc->fmr));
+
+	/* returns 0 on success otherwise non-zero) */
+	return ctrl->status == LTESR_CC ? 0 : -EIO;
+}
+
+static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
+{
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+
+	if (priv->page_size) {
+		out_be32(&lbc->fir,
+		         (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+		         (FIR_OP_CA  << FIR_OP1_SHIFT) |
+		         (FIR_OP_PA  << FIR_OP2_SHIFT) |
+		         (FIR_OP_CW1 << FIR_OP3_SHIFT) |
+		         (FIR_OP_RBW << FIR_OP4_SHIFT));
+
+		out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
+		                    (NAND_CMD_READSTART << FCR_CMD1_SHIFT));
+	} else {
+		out_be32(&lbc->fir,
+		         (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+		         (FIR_OP_CA  << FIR_OP1_SHIFT) |
+		         (FIR_OP_PA  << FIR_OP2_SHIFT) |
+		         (FIR_OP_RBW << FIR_OP3_SHIFT));
+
+		if (oob)
+			out_be32(&lbc->fcr, NAND_CMD_READOOB << FCR_CMD0_SHIFT);
+		else
+			out_be32(&lbc->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT);
+	}
+}
+
+/* cmdfunc send commands to the FCM */
+static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
+                             int column, int page_addr)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+
+	ctrl->use_mdr = 0;
+
+	/* clear the read buffer */
+	ctrl->read_bytes = 0;
+	if (command != NAND_CMD_PAGEPROG)
+		ctrl->index = 0;
+
+	switch (command) {
+	/* READ0 and READ1 read the entire buffer to use hardware ECC. */
+	case NAND_CMD_READ1:
+		column += 256;
+
+	/* fall-through */
+	case NAND_CMD_READ0:
+		dev_dbg(ctrl->dev,
+		        "fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:"
+		        " 0x%x, column: 0x%x.\n", page_addr, column);
+
+
+		out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */
+		set_addr(mtd, 0, page_addr, 0);
+
+		ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+		ctrl->index += column;
+
+		fsl_elbc_do_read(chip, 0);
+		fsl_elbc_run_command(mtd);
+		return;
+
+	/* READOOB reads only the OOB because no ECC is performed. */
+	case NAND_CMD_READOOB:
+		dev_vdbg(ctrl->dev,
+		         "fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:"
+			 " 0x%x, column: 0x%x.\n", page_addr, column);
+
+		out_be32(&lbc->fbcr, mtd->oobsize - column);
+		set_addr(mtd, column, page_addr, 1);
+
+		ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+
+		fsl_elbc_do_read(chip, 1);
+		fsl_elbc_run_command(mtd);
+		return;
+
+	/* READID must read all 5 possible bytes while CEB is active */
+	case NAND_CMD_READID:
+		dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n");
+
+		out_be32(&lbc->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+		                    (FIR_OP_UA  << FIR_OP1_SHIFT) |
+		                    (FIR_OP_RBW << FIR_OP2_SHIFT));
+		out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT);
+		/* 5 bytes for manuf, device and exts */
+		out_be32(&lbc->fbcr, 5);
+		ctrl->read_bytes = 5;
+		ctrl->use_mdr = 1;
+		ctrl->mdr = 0;
+
+		set_addr(mtd, 0, 0, 0);
+		fsl_elbc_run_command(mtd);
+		return;
+
+	/* ERASE1 stores the block and page address */
+	case NAND_CMD_ERASE1:
+		dev_vdbg(ctrl->dev,
+		         "fsl_elbc_cmdfunc: NAND_CMD_ERASE1, "
+		         "page_addr: 0x%x.\n", page_addr);
+		set_addr(mtd, 0, page_addr, 0);
+		return;
+
+	/* ERASE2 uses the block and page address from ERASE1 */
+	case NAND_CMD_ERASE2:
+		dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
+
+		out_be32(&lbc->fir,
+		         (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+		         (FIR_OP_PA  << FIR_OP1_SHIFT) |
+		         (FIR_OP_CM1 << FIR_OP2_SHIFT));
+
+		out_be32(&lbc->fcr,
+		         (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) |
+		         (NAND_CMD_ERASE2 << FCR_CMD1_SHIFT));
+
+		out_be32(&lbc->fbcr, 0);
+		ctrl->read_bytes = 0;
+
+		fsl_elbc_run_command(mtd);
+		return;
+
+	/* SEQIN sets up the addr buffer and all registers except the length */
+	case NAND_CMD_SEQIN: {
+		__be32 fcr;
+		dev_vdbg(ctrl->dev,
+		         "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, "
+		         "page_addr: 0x%x, column: 0x%x.\n",
+		         page_addr, column);
+
+		ctrl->column = column;
+		ctrl->oob = 0;
+
+		fcr = (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT) |
+		      (NAND_CMD_SEQIN << FCR_CMD2_SHIFT);
+
+		if (priv->page_size) {
+			out_be32(&lbc->fir,
+			         (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+			         (FIR_OP_CA  << FIR_OP1_SHIFT) |
+			         (FIR_OP_PA  << FIR_OP2_SHIFT) |
+			         (FIR_OP_WB  << FIR_OP3_SHIFT) |
+			         (FIR_OP_CW1 << FIR_OP4_SHIFT));
+
+			fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT;
+		} else {
+			out_be32(&lbc->fir,
+			         (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+			         (FIR_OP_CM2 << FIR_OP1_SHIFT) |
+			         (FIR_OP_CA  << FIR_OP2_SHIFT) |
+			         (FIR_OP_PA  << FIR_OP3_SHIFT) |
+			         (FIR_OP_WB  << FIR_OP4_SHIFT) |
+			         (FIR_OP_CW1 << FIR_OP5_SHIFT));
+
+			if (column >= mtd->writesize) {
+				/* OOB area --> READOOB */
+				column -= mtd->writesize;
+				fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT;
+				ctrl->oob = 1;
+			} else if (column < 256) {
+				/* First 256 bytes --> READ0 */
+				fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT;
+			} else {
+				/* Second 256 bytes --> READ1 */
+				fcr |= NAND_CMD_READ1 << FCR_CMD0_SHIFT;
+			}
+		}
+
+		out_be32(&lbc->fcr, fcr);
+		set_addr(mtd, column, page_addr, ctrl->oob);
+		return;
+	}
+
+	/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
+	case NAND_CMD_PAGEPROG: {
+		int full_page;
+		dev_vdbg(ctrl->dev,
+		         "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
+		         "writing %d bytes.\n", ctrl->index);
+
+		/* if the write did not start at 0 or is not a full page
+		 * then set the exact length, otherwise use a full page
+		 * write so the HW generates the ECC.
+		 */
+		if (ctrl->oob || ctrl->column != 0 ||
+		    ctrl->index != mtd->writesize + mtd->oobsize) {
+			out_be32(&lbc->fbcr, ctrl->index);
+			full_page = 0;
+		} 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 && ctrl->oob_poi) {
+			out_be32(&lbc->fbcr, 3);
+			set_addr(mtd, 6, page_addr, 1);
+
+			ctrl->read_bytes = mtd->writesize + 9;
+
+			fsl_elbc_do_read(chip, 1);
+			fsl_elbc_run_command(mtd);
+
+			memcpy_fromio(ctrl->oob_poi + 6,
+			              &ctrl->addr[ctrl->index], 3);
+			ctrl->index += 3;
+		}
+
+		ctrl->oob_poi = NULL;
+		return;
+	}
+
+	/* CMD_STATUS must read the status byte while CEB is active */
+	/* Note - it does not wait for the ready line */
+	case NAND_CMD_STATUS:
+		out_be32(&lbc->fir,
+		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+		         (FIR_OP_RBW << FIR_OP1_SHIFT));
+		out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
+		out_be32(&lbc->fbcr, 1);
+		set_addr(mtd, 0, 0, 0);
+		ctrl->read_bytes = 1;
+
+		fsl_elbc_run_command(mtd);
+
+		/* The chip always seems to report that it is
+		 * write-protected, even when it is not.
+		 */
+		setbits8(ctrl->addr, NAND_STATUS_WP);
+		return;
+
+	/* RESET without waiting for the ready line */
+	case NAND_CMD_RESET:
+		dev_dbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
+		out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT);
+		out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT);
+		fsl_elbc_run_command(mtd);
+		return;
+
+	default:
+		dev_err(ctrl->dev,
+		        "fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n",
+		        command);
+	}
+}
+
+static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
+{
+	/* The hardware does not seem to support multiple
+	 * chips per bank.
+	 */
+}
+
+/*
+ * Write buf to the FCM Controller Data Buffer
+ */
+static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	unsigned int bufsize = mtd->writesize + mtd->oobsize;
+
+	if (len < 0) {
+		dev_err(ctrl->dev, "write_buf of %d bytes", len);
+		ctrl->status = 0;
+		return;
+	}
+
+	if ((unsigned int)len > bufsize - ctrl->index) {
+		dev_err(ctrl->dev,
+		        "write_buf beyond end of buffer "
+		        "(%d requested, %u available)\n",
+		        len, bufsize - ctrl->index);
+		len = bufsize - ctrl->index;
+	}
+
+	memcpy_toio(&ctrl->addr[ctrl->index], buf, len);
+	ctrl->index += len;
+}
+
+/*
+ * read a byte from either the FCM hardware buffer if it has any data left
+ * otherwise issue a command to read a single byte.
+ */
+static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+
+	/* If there are still bytes in the FCM, then use the next byte. */
+	if (ctrl->index < ctrl->read_bytes)
+		return in_8(&ctrl->addr[ctrl->index++]);
+
+	dev_err(ctrl->dev, "read_byte beyond end of buffer\n");
+	return ERR_BYTE;
+}
+
+/*
+ * Read from the FCM Controller Data Buffer
+ */
+static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	int avail;
+
+	if (len < 0)
+		return;
+
+	avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index);
+	memcpy_fromio(buf, &ctrl->addr[ctrl->index], avail);
+	ctrl->index += avail;
+
+	if (len > avail)
+		dev_err(ctrl->dev,
+		        "read_buf beyond end of buffer "
+		        "(%d requested, %d available)\n",
+		        len, avail);
+}
+
+/*
+ * Verify buffer against the FCM Controller Data Buffer
+ */
+static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	int i;
+
+	if (len < 0) {
+		dev_err(ctrl->dev, "write_buf of %d bytes", len);
+		return -EINVAL;
+	}
+
+	if ((unsigned int)len > ctrl->read_bytes - ctrl->index) {
+		dev_err(ctrl->dev,
+		        "verify_buf beyond end of buffer "
+		        "(%d requested, %u available)\n",
+		        len, ctrl->read_bytes - ctrl->index);
+
+		ctrl->index = ctrl->read_bytes;
+		return -EINVAL;
+	}
+
+	for (i = 0; i < len; i++)
+		if (in_8(&ctrl->addr[ctrl->index + i]) != buf[i])
+			break;
+
+	ctrl->index += len;
+	return i == len && ctrl->status == LTESR_CC ? 0 : -EIO;
+}
+
+/* This function is called after Program and Erase Operations to
+ * check for success or failure.
+ */
+static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+
+	if (ctrl->status != LTESR_CC)
+		return NAND_STATUS_FAIL;
+
+	/* Use READ_STATUS command, but wait for the device to be ready */
+	ctrl->use_mdr = 0;
+	out_be32(&lbc->fir,
+	         (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+	         (FIR_OP_RBW << FIR_OP1_SHIFT));
+	out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
+	out_be32(&lbc->fbcr, 1);
+	set_addr(mtd, 0, 0, 0);
+	ctrl->read_bytes = 1;
+
+	fsl_elbc_run_command(mtd);
+
+	if (ctrl->status != LTESR_CC)
+		return NAND_STATUS_FAIL;
+
+	/* The chip always seems to report that it is
+	 * write-protected, even when it is not.
+	 */
+	setbits8(ctrl->addr, NAND_STATUS_WP);
+	return fsl_elbc_read_byte(mtd);
+}
+
+static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+	unsigned int al;
+
+	/* calculate FMR Address Length field */
+	al = 0;
+	if (chip->pagemask & 0xffff0000)
+		al++;
+	if (chip->pagemask & 0xff000000)
+		al++;
+
+	/* add to ECCM mode set in fsl_elbc_init */
+	priv->fmr |= (12 << FMR_CWTO_SHIFT) |  /* Timeout > 12 ms */
+	             (al << FMR_AL_SHIFT);
+
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->numchips = %d\n",
+	        chip->numchips);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chipsize = %ld\n",
+	        chip->chipsize);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
+	        chip->pagemask);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
+	        chip->chip_delay);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
+	        chip->badblockpos);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
+	        chip->chip_shift);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->page_shift = %d\n",
+	        chip->page_shift);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
+	        chip->phys_erase_shift);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecclayout = %p\n",
+	        chip->ecclayout);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
+	        chip->ecc.mode);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
+	        chip->ecc.steps);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
+	        chip->ecc.bytes);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
+	        chip->ecc.total);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.layout = %p\n",
+	        chip->ecc.layout);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->size = %d\n", mtd->size);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
+	        mtd->erasesize);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->writesize = %d\n",
+	        mtd->writesize);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
+	        mtd->oobsize);
+
+	/* adjust Option Register and ECC to match Flash page size */
+	if (mtd->writesize == 512) {
+		priv->page_size = 0;
+		clrbits32(&lbc->bank[priv->bank].or, ~OR_FCM_PGS);
+	} else if (mtd->writesize == 2048) {
+		priv->page_size = 1;
+		setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
+		/* adjust ecc setup if needed */
+		if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
+		    BR_DECC_CHK_GEN) {
+			chip->ecc.size = 512;
+			chip->ecc.layout = (priv->fmr & FMR_ECCM) ?
+			                   &fsl_elbc_oob_lp_eccm1 :
+			                   &fsl_elbc_oob_lp_eccm0;
+			mtd->ecclayout = chip->ecc.layout;
+			mtd->oobavail = chip->ecc.layout->oobavail;
+		}
+	} else {
+		dev_err(ctrl->dev,
+		        "fsl_elbc_init: page size %d is not supported\n",
+		        mtd->writesize);
+		return -1;
+	}
+
+	/* The default u-boot configuration on MPC8313ERDB causes errors;
+	 * more delay is needed.  This should be safe for other boards
+	 * as well.
+	 */
+	setbits32(&lbc->bank[priv->bank].or, 0x70);
+	return 0;
+}
+
+static int fsl_elbc_read_page(struct mtd_info *mtd,
+                              struct nand_chip *chip,
+                              uint8_t *buf)
+{
+	fsl_elbc_read_buf(mtd, buf, mtd->writesize);
+	fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL)
+		mtd->ecc_stats.failed++;
+
+	return 0;
+}
+
+/* ECC will be calculated automatically, and errors will be detected in
+ * waitfunc.
+ */
+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_ctrl *ctrl = priv->ctrl;
+
+	fsl_elbc_write_buf(mtd, buf, mtd->writesize);
+	fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	ctrl->oob_poi = chip->oob_poi;
+}
+
+static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
+{
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+	struct nand_chip *chip = &priv->chip;
+
+	dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank);
+
+	/* Fill in fsl_elbc_mtd structure */
+	priv->mtd.priv = chip;
+	priv->mtd.owner = THIS_MODULE;
+	priv->fmr = 0; /* rest filled in later */
+
+	/* fill in nand_chip structure */
+	/* set up function call table */
+	chip->read_byte = fsl_elbc_read_byte;
+	chip->write_buf = fsl_elbc_write_buf;
+	chip->read_buf = fsl_elbc_read_buf;
+	chip->verify_buf = fsl_elbc_verify_buf;
+	chip->select_chip = fsl_elbc_select_chip;
+	chip->cmdfunc = fsl_elbc_cmdfunc;
+	chip->waitfunc = fsl_elbc_wait;
+
+	/* set up nand options */
+	chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR;
+
+	chip->controller = &ctrl->controller;
+	chip->priv = priv;
+
+	chip->ecc.read_page = fsl_elbc_read_page;
+	chip->ecc.write_page = fsl_elbc_write_page;
+
+	/* If CS Base Register selects full hardware ECC then use it */
+	if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
+	    BR_DECC_CHK_GEN) {
+		chip->ecc.mode = NAND_ECC_HW;
+		/* put in small page settings and adjust later if needed */
+		chip->ecc.layout = (priv->fmr & FMR_ECCM) ?
+				&fsl_elbc_oob_sp_eccm1 : &fsl_elbc_oob_sp_eccm0;
+		chip->ecc.size = 512;
+		chip->ecc.bytes = 3;
+	} else {
+		/* otherwise fall back to default software ECC */
+		chip->ecc.mode = NAND_ECC_SOFT;
+	}
+
+	return 0;
+}
+
+static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
+{
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+
+	nand_release(&priv->mtd);
+
+	if (priv->vbase)
+		iounmap(priv->vbase);
+
+	ctrl->chips[priv->bank] = NULL;
+	kfree(priv);
+
+	return 0;
+}
+
+static int fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl,
+                               struct device_node *node)
+{
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+	struct fsl_elbc_mtd *priv;
+	struct resource res;
+#ifdef CONFIG_MTD_PARTITIONS
+	static const char *part_probe_types[]
+		= { "cmdlinepart", "RedBoot", NULL };
+	struct mtd_partition *parts;
+#endif
+	int ret;
+	int bank;
+
+	/* get, allocate and map the memory resource */
+	ret = of_address_to_resource(node, 0, &res);
+	if (ret) {
+		dev_err(ctrl->dev, "failed to get resource\n");
+		return ret;
+	}
+
+	/* find which chip select it is connected to */
+	for (bank = 0; bank < MAX_BANKS; bank++)
+		if ((in_be32(&lbc->bank[bank].br) & BR_V) &&
+		    (in_be32(&lbc->bank[bank].br) & BR_MSEL) == BR_MS_FCM &&
+		    (in_be32(&lbc->bank[bank].br) &
+		     in_be32(&lbc->bank[bank].or) & BR_BA)
+		     == res.start)
+			break;
+
+	if (bank >= MAX_BANKS) {
+		dev_err(ctrl->dev, "address did not match any chip selects\n");
+		return -ENODEV;
+	}
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	ctrl->chips[bank] = priv;
+	priv->bank = bank;
+	priv->ctrl = ctrl;
+	priv->dev = ctrl->dev;
+
+	priv->vbase = ioremap(res.start, res.end - res.start + 1);
+	if (!priv->vbase) {
+		dev_err(ctrl->dev, "failed to map chip region\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = fsl_elbc_chip_init(priv);
+	if (ret)
+		goto err;
+
+	ret = nand_scan_ident(&priv->mtd, 1);
+	if (ret)
+		goto err;
+
+	ret = fsl_elbc_chip_init_tail(&priv->mtd);
+	if (ret)
+		goto err;
+
+	ret = nand_scan_tail(&priv->mtd);
+	if (ret)
+		goto err;
+
+#ifdef CONFIG_MTD_PARTITIONS
+	/* 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;
+
+#ifdef CONFIG_MTD_OF_PARTS
+	if (ret == 0) {
+		ret = of_mtd_parse_partitions(priv->dev, &priv->mtd,
+		                              node, &parts);
+		if (ret < 0)
+			goto err;
+	}
+#endif
+
+	if (ret > 0)
+		add_mtd_partitions(&priv->mtd, parts, ret);
+	else
+#endif
+		add_mtd_device(&priv->mtd);
+
+	printk(KERN_INFO "eLBC NAND device at 0x%zx, bank %d\n",
+	       res.start, priv->bank);
+	return 0;
+
+err:
+	fsl_elbc_chip_remove(priv);
+	return ret;
+}
+
+static int __devinit fsl_elbc_ctrl_init(struct fsl_elbc_ctrl *ctrl)
+{
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+
+	/* clear event registers */
+	setbits32(&lbc->ltesr, LTESR_NAND_MASK);
+	out_be32(&lbc->lteatr, 0);
+
+	/* Enable interrupts for any detected events */
+	out_be32(&lbc->lteir, LTESR_NAND_MASK);
+
+	ctrl->read_bytes = 0;
+	ctrl->index = 0;
+	ctrl->addr = NULL;
+
+	return 0;
+}
+
+static int __devexit fsl_elbc_ctrl_remove(struct of_device *ofdev)
+{
+	struct fsl_elbc_ctrl *ctrl = dev_get_drvdata(&ofdev->dev);
+	int i;
+
+	for (i = 0; i < MAX_BANKS; i++)
+		if (ctrl->chips[i])
+			fsl_elbc_chip_remove(ctrl->chips[i]);
+
+	if (ctrl->irq)
+		free_irq(ctrl->irq, ctrl);
+
+	if (ctrl->regs)
+		iounmap(ctrl->regs);
+
+	dev_set_drvdata(&ofdev->dev, NULL);
+	kfree(ctrl);
+	return 0;
+}
+
+/* NOTE: This interrupt is also used to report other localbus events,
+ * such as transaction errors on other chipselects.  If we want to
+ * capture those, we'll need to move the IRQ code into a shared
+ * LBC driver.
+ */
+
+static irqreturn_t fsl_elbc_ctrl_irq(int irqno, void *data)
+{
+	struct fsl_elbc_ctrl *ctrl = data;
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+	__be32 status = in_be32(&lbc->ltesr) & LTESR_NAND_MASK;
+
+	if (status) {
+		out_be32(&lbc->ltesr, status);
+		out_be32(&lbc->lteatr, 0);
+
+		ctrl->irq_status = status;
+		smp_wmb();
+		wake_up(&ctrl->irq_wait);
+
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+/* fsl_elbc_ctrl_probe
+ *
+ * called by device layer when it finds a device matching
+ * one our driver can handled. This code allocates all of
+ * the resources needed for the controller only.  The
+ * resources for the NAND banks themselves are allocated
+ * in the chip probe function.
+*/
+
+static int __devinit fsl_elbc_ctrl_probe(struct of_device *ofdev,
+                                         const struct of_device_id *match)
+{
+	struct device_node *child;
+	struct fsl_elbc_ctrl *ctrl;
+	int ret;
+
+	ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
+	if (!ctrl)
+		return -ENOMEM;
+
+	dev_set_drvdata(&ofdev->dev, ctrl);
+
+	spin_lock_init(&ctrl->controller.lock);
+	init_waitqueue_head(&ctrl->controller.wq);
+	init_waitqueue_head(&ctrl->irq_wait);
+
+	ctrl->regs = of_iomap(ofdev->node, 0);
+	if (!ctrl->regs) {
+		dev_err(&ofdev->dev, "failed to get memory region\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	ctrl->irq = of_irq_to_resource(ofdev->node, 0, NULL);
+	if (ctrl->irq == NO_IRQ) {
+		dev_err(&ofdev->dev, "failed to get irq resource\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	ctrl->dev = &ofdev->dev;
+
+	ret = fsl_elbc_ctrl_init(ctrl);
+	if (ret < 0)
+		goto err;
+
+	ret = request_irq(ctrl->irq, fsl_elbc_ctrl_irq, 0, "fsl-elbc", ctrl);
+	if (ret != 0) {
+		dev_err(&ofdev->dev, "failed to install irq (%d)\n",
+		        ctrl->irq);
+		ret = ctrl->irq;
+		goto err;
+	}
+
+	child = NULL;
+	while ((child = of_get_next_child(ofdev->node, child)))
+		if (of_device_is_compatible(child, "fsl,elbc-fcm-nand"))
+			fsl_elbc_chip_probe(ctrl, child);
+
+	return 0;
+
+err:
+	fsl_elbc_ctrl_remove(ofdev);
+	return ret;
+}
+
+static struct of_device_id fsl_elbc_match[] = {
+	{
+		.compatible = "fsl,elbc",
+	},
+	{}
+};
+
+static struct of_platform_driver fsl_elbc_ctrl_driver = {
+	.name	= "fsl-elbc",
+	.match_table = fsl_elbc_match,
+	.probe = fsl_elbc_ctrl_probe,
+	.remove = __devexit_p(fsl_elbc_ctrl_remove),
+};
+
+static int __init fsl_elbc_init(void)
+{
+	return of_register_platform_driver(&fsl_elbc_ctrl_driver);
+}
+
+static void __exit fsl_elbc_exit(void)
+{
+	of_unregister_platform_driver(&fsl_elbc_ctrl_driver);
+}
+
+module_init(fsl_elbc_init);
+module_exit(fsl_elbc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Freescale");
+MODULE_DESCRIPTION("Freescale Enhanced Local Bus Controller MTD NAND driver");
-- 
1.5.3.8


From scottwood at freescale.com  Fri Jan 11 15:55:00 2008
From: scottwood at freescale.com (Scott Wood)
Date: Fri, 11 Jan 2008 14:55:00 -0600
Subject: [RESEND PATCH 2/3] mtd: Factor out OF partition support from the
	NOR driver.
Message-ID: <20080111205500.GA11718@loki.buserror.net>

Signed-off-by: Scott Wood <scottwood at freescale.com>
---
 drivers/mtd/Kconfig            |    8 ++++
 drivers/mtd/Makefile           |    1 +
 drivers/mtd/maps/physmap_of.c  |   89 ++++++++++++----------------------------
 drivers/mtd/ofpart.c           |   70 +++++++++++++++++++++++++++++++
 include/linux/mtd/partitions.h |    9 ++++-
 5 files changed, 114 insertions(+), 63 deletions(-)
 create mode 100644 drivers/mtd/ofpart.c

diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 661eac0..e850334 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -150,6 +150,14 @@ config MTD_AFS_PARTS
 	  for your particular device. It won't happen automatically. The
 	  'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example.
 
+config MTD_OF_PARTS
+	tristate "Flash partition map based on OF description"
+	depends on PPC_OF && MTD_PARTITIONS
+	help
+	  This provides a partition parsing function which derives
+	  the partition map from the children of the flash node,
+	  as described in Documentation/powerpc/booting-without-of.txt.
+
 comment "User Modules And Translation Layers"
 
 config MTD_CHAR
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 7f0b04b..538e33d 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_MTD_CONCAT)	+= mtdconcat.o
 obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
 obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
 obj-$(CONFIG_MTD_AFS_PARTS)	+= afs.o
+obj-$(CONFIG_MTD_OF_PARTS)      += ofpart.o
 
 # 'Users' - code which presents functionality to userspace.
 obj-$(CONFIG_MTD_CHAR)		+= mtdchar.o
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index d4bcd3f..49acd41 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -80,65 +80,6 @@ static int parse_obsolete_partitions(struct of_device *dev,
 
 	return nr_parts;
 }
-
-static int __devinit parse_partitions(struct of_flash *info,
-				      struct of_device *dev)
-{
-	const char *partname;
-	static const char *part_probe_types[]
-		= { "cmdlinepart", "RedBoot", NULL };
-	struct device_node *dp = dev->node, *pp;
-	int nr_parts, i;
-
-	/* First look for RedBoot table or partitions on the command
-	 * line, these take precedence over device tree information */
-	nr_parts = parse_mtd_partitions(info->mtd, part_probe_types,
-					&info->parts, 0);
-	if (nr_parts > 0)
-		return nr_parts;
-
-	/* First count the subnodes */
-	nr_parts = 0;
-	for (pp = of_get_next_child(dp, NULL); pp;
-	     pp = of_get_next_child(dp, pp))
-		nr_parts++;
-
-	if (nr_parts == 0)
-		return parse_obsolete_partitions(dev, info, dp);
-
-	info->parts = kzalloc(nr_parts * sizeof(*info->parts),
-			      GFP_KERNEL);
-	if (!info->parts)
-		return -ENOMEM;
-
-	for (pp = of_get_next_child(dp, NULL), i = 0; pp;
-	     pp = of_get_next_child(dp, pp), i++) {
-		const u32 *reg;
-		int len;
-
-		reg = of_get_property(pp, "reg", &len);
-		if (!reg || (len != 2*sizeof(u32))) {
-			of_node_put(pp);
-			dev_err(&dev->dev, "Invalid 'reg' on %s\n",
-				dp->full_name);
-			kfree(info->parts);
-			info->parts = NULL;
-			return -EINVAL;
-		}
-		info->parts[i].offset = reg[0];
-		info->parts[i].size = reg[1];
-
-		partname = of_get_property(pp, "label", &len);
-		if (!partname)
-			partname = of_get_property(pp, "name", &len);
-		info->parts[i].name = (char *)partname;
-
-		if (of_get_property(pp, "read-only", &len))
-			info->parts[i].mask_flags = MTD_WRITEABLE;
-	}
-
-	return nr_parts;
-}
 #else /* MTD_PARTITIONS */
 #define	OF_FLASH_PARTS(info)		(0)
 #define parse_partitions(info, dev)	(0)
@@ -213,6 +154,10 @@ static struct mtd_info * __devinit obsolete_probe(struct of_device *dev,
 static int __devinit of_flash_probe(struct of_device *dev,
 				    const struct of_device_id *match)
 {
+#ifdef CONFIG_MTD_PARTITIONS
+	static const char *part_probe_types[]
+		= { "cmdlinepart", "RedBoot", NULL };
+#endif
 	struct device_node *dp = dev->node;
 	struct resource res;
 	struct of_flash *info;
@@ -275,13 +220,33 @@ static int __devinit of_flash_probe(struct of_device *dev,
 	}
 	info->mtd->owner = THIS_MODULE;
 
-	err = parse_partitions(info, dev);
+#ifdef CONFIG_MTD_PARTITIONS
+	/* First look for RedBoot table or partitions on the command
+	 * line, these take precedence over device tree information */
+	err = parse_mtd_partitions(info->mtd, part_probe_types,
+	                           &info->parts, 0);
 	if (err < 0)
-		goto err_out;
+		return err;
+
+#ifdef CONFIG_MTD_OF_PARTS
+	if (err == 0) {
+		err = of_mtd_parse_partitions(&dev->dev, info->mtd,
+		                              dp, &info->parts);
+		if (err < 0)
+			return err;
+	}
+#endif
+
+	if (err == 0) {
+		err = parse_obsolete_partitions(dev, info, dp);
+		if (err < 0)
+			return err;
+	}
 
 	if (err > 0)
-		add_mtd_partitions(info->mtd, OF_FLASH_PARTS(info), err);
+		add_mtd_partitions(info->mtd, info->parts, err);
 	else
+#endif
 		add_mtd_device(info->mtd);
 
 	return 0;
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
new file mode 100644
index 0000000..6c562ca
--- /dev/null
+++ b/drivers/mtd/ofpart.c
@@ -0,0 +1,70 @@
+/*
+ * Flash partitions described by the OF (or flattened) device tree
+ *
+ * Copyright (C) 2006 MontaVista Software Inc.
+ * Author: Vitaly Wool <vwool at ru.mvista.com>
+ *
+ * Revised to handle newer style flash binding by:
+ *   Copyright (C) 2007 David Gibson, IBM Corporation.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+int __devinit of_mtd_parse_partitions(struct device *dev,
+                                      struct mtd_info *mtd,
+                                      struct device_node *node,
+                                      struct mtd_partition **pparts)
+{
+	const char *partname;
+	struct device_node *pp;
+	int nr_parts, i;
+
+	/* First count the subnodes */
+	nr_parts = 0;
+	for (pp = node->child; pp; pp = pp->sibling)
+		nr_parts++;
+
+	if (nr_parts == 0)
+		return 0;
+
+	*pparts = kzalloc(nr_parts * sizeof(**pparts), GFP_KERNEL);
+	if (!*pparts)
+		return -ENOMEM;
+
+	for (pp = of_get_next_child(node, NULL), i = 0; pp; 
+	     pp = of_get_next_child(node, pp), i++) {
+		const u32 *reg;
+		int len;
+
+		reg = of_get_property(pp, "reg", &len);
+		if (!reg || (len != 2*sizeof(u32))) {
+			of_node_put(pp);
+			dev_err(dev, "Invalid 'reg' on %s\n", node->full_name);
+			kfree(*pparts);
+			*pparts = NULL;
+			return -EINVAL;
+		}
+		(*pparts)[i].offset = reg[0];
+		(*pparts)[i].size = reg[1];
+
+		partname = of_get_property(pp, "label", &len);
+		if (!partname)
+			partname = of_get_property(pp, "name", &len);
+		(*pparts)[i].name = (char *)partname;
+
+		if (of_get_property(pp, "read-only", &len))
+			(*pparts)[i].mask_flags = MTD_WRITEABLE;
+	}
+
+	return nr_parts;
+}
+EXPORT_SYMBOL(of_mtd_parse_partitions);
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
index da6b3d6..7c37d7e 100644
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -71,5 +71,12 @@ extern int parse_mtd_partitions(struct mtd_info *master, const char **types,
 
 #define put_partition_parser(p) do { module_put((p)->owner); } while(0)
 
-#endif
+struct device;
+struct device_node;
+
+int __devinit of_mtd_parse_partitions(struct device *dev,
+                                      struct mtd_info *mtd,
+                                      struct device_node *node,
+                                      struct mtd_partition **pparts);
 
+#endif
-- 
1.5.3.8



From jamie at shareable.org  Sat Jan 12 05:03:43 2008
From: jamie at shareable.org (Jamie Lokier)
Date: Sat, 12 Jan 2008 10:03:43 +0000
Subject: JFFS2 determine writing state
In-Reply-To: <20080111075730.052c821d@zod.rchland.ibm.com>
References: <298338.39997.qm@web56002.mail.re3.yahoo.com>
	<20080111075730.052c821d@zod.rchland.ibm.com>
Message-ID: <20080112100343.GC1497@shareable.org>

Josh Boyer wrote:
> The open call doesn't cause any writes, and close
> is supposed to flush all pending writes before it returns.

Oh, that's interesting.  So on JFFS2, fsync() is unnecessary before close()?

(On other filesystems it's necessary, of course).

-- Jamie


From jwboyer at gmail.com  Sat Jan 12 15:15:08 2008
From: jwboyer at gmail.com (Josh Boyer)
Date: Sat, 12 Jan 2008 14:15:08 -0600
Subject: JFFS2 determine writing state
In-Reply-To: <20080112100343.GC1497@shareable.org>
References: <298338.39997.qm@web56002.mail.re3.yahoo.com>
	<20080111075730.052c821d@zod.rchland.ibm.com>
	<20080112100343.GC1497@shareable.org>
Message-ID: <20080112141508.22b19686@vader.jdub.homelinux.org>

On Sat, 12 Jan 2008 10:03:43 +0000
Jamie Lokier <jamie at shareable.org> wrote:

> Josh Boyer wrote:
> > The open call doesn't cause any writes, and close
> > is supposed to flush all pending writes before it returns.
> 
> Oh, that's interesting.  So on JFFS2, fsync() is unnecessary before close()?
> 
> (On other filesystems it's necessary, of course).

To be honest, it doesn't really matter if it's necessary or not.
Writing an application to do as little as possible based on implicit
knowledge of the underlying filesystem seems like a really bad idea.
Particularly with the behavior of the filesystem can change based on
which config options you have set (writebuffer, etc).

Write you applications to be portable and cautious and you shouldn't
have a problem.

josh


From jacob at imaginecommunications.com  Sun Jan 13 11:31:20 2008
From: jacob at imaginecommunications.com (Jacob Avraham)
Date: Sun, 13 Jan 2008 18:31:20 +0200
Subject: Redboot FIS entry upgrade from Linux
Message-ID: <FF584854D6FFE547AB2F7515A798AC3A4E3A9955@venus.imagineil.tv>

Hi,

Say I have a zImage or ramdisk image as a file listed in FIS,
which I use to  "fis load" from Redboot.
Now I want to upgrade an image from Linux, so in addition to
writing into the specific mtd partition I need to update the FIS
directory entry checksum value.

Are there any utils to facilitate that?
Or maybe such where not developed because it's not a good idea?

Thanks,

Jacob


From driddoch at solarflare.com  Sun Jan 13 12:19:33 2008
From: driddoch at solarflare.com (David Riddoch)
Date: Sun, 13 Jan 2008 17:19:33 +0000
Subject: [PATCH] [MTD] [RFC] New Solarflare NIC EEPROM/Flash driver
In-Reply-To: <20080111185550.GN3544@solarflare.com>
References: <47866921.40904@solarflare.com>
	<20080110201309.GC26820@lazybastard.org>
	<20080111125000.GL3544@solarflare.com>
	<20080111132444.GA1399@lazybastard.org>
	<20080111185550.GN3544@solarflare.com>
Message-ID: <478A4825.8000006@solarflare.com>

Ben Hutchings wrote:
>>>>   struct semaphore access_lock; should become a mutex.
>>>>         
>>> Right.  We've tended to be quite conservative in using newer kernel
>>> features, since we also need to support old kernels, but we have a
>>> good backward-compatibility layer now (unifdef'd out of the submitted
>>> code) so this shouldn't be a problem.
>>>       
>> Ok.  A straight conversion to a mutex will likely cause trouble with
>> your reset routine.  Not sure what to do here.
>>     
>
> We can use a mutex if the net driver is guaranteed to call
> reset_suspend() and reset_resume() in the same context.  This is
> currently true (they are always called in a pair by efx_reset() in
> efx.c) but I'm not sure we want to guarantee that.
>   
reset_suspend() is documented as being called in a context that permits 
sleeping, and I can't see us ever changing that.  reset_resume() will 
also continue to permit sleeping (although that isn't currently documented).

Cheers,
David

-- 
David Riddoch  +++  Solarflare  +++  driddoch at solarflare.com



From Foster_Brian at emc.com  Sun Jan 13 16:26:02 2008
From: Foster_Brian at emc.com (Foster_Brian at emc.com)
Date: Sun, 13 Jan 2008 16:26:02 -0500
Subject: Redboot FIS entry upgrade from Linux
In-Reply-To: <FF584854D6FFE547AB2F7515A798AC3A4E3A9955@venus.imagineil.tv>
References: <FF584854D6FFE547AB2F7515A798AC3A4E3A9955@venus.imagineil.tv>
Message-ID: <64385436BC51BF448208008A36316D6701B1EB4E@CORPUSMX70B.corp.emc.com>

> -----Original Message-----
> From: linux-mtd-bounces at lists.infradead.org [mailto:linux-mtd-
> bounces at lists.infradead.org] On Behalf Of Jacob Avraham
> Sent: Sunday, January 13, 2008 11:31 AM
> To: linux-mtd at lists.infradead.org
> Subject: Redboot FIS entry upgrade from Linux
> 
> Hi,
> 
> Say I have a zImage or ramdisk image as a file listed in FIS,
> which I use to  "fis load" from Redboot.
> Now I want to upgrade an image from Linux, so in addition to
> writing into the specific mtd partition I need to update the FIS
> directory entry checksum value.
> 
> Are there any utils to facilitate that?
> Or maybe such where not developed because it's not a good idea?
> 
> Thanks,
> 
> Jacob
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/

Perhaps Linux 'fconfig' is what you are looking for:

http://andrzejekiert.ovh.org/software.html.en

Brian



From maryemv at libero.it  Sun Jan 13 17:59:15 2008
From: maryemv at libero.it (Mary Ellaine Manguerra Villanueva)
Date: Sun, 13 Jan 2008 23:59:15 +0100
Subject: Attn From (Miss. Mary Ellaine Villanueva)
Message-ID: <20080113235915.lbd46t0q4y2as04s@webmail.dommel.be>



Miss. Mary Ellaine Manguerra Villanueva
ACCOUNTS OFFICER
BANCO DE ORO UNIVERSAL BANK
PHILIPPINES.

Good Day,
Let me start by introducing myself, I am Miss. Mary Ellaine Manguerra
Villanueva ACCOUNTS OFFICER BANCO DE ORO UNIVERSAL BANK. I am writing you this
letter based on the latest development at my bank, which I will like to bring
to your personal edification. I am writing you this letter with so much joy and
excitement even though my heart goes out to the very powerful and distinguished
gentleman who I was fortunate to have worked for and extremely privileged to
have known for numerous years. I am a top official in charge of client accounts
in BANCO DE ORO UNIVERSAL BANK inside the Philippines.
I am contacting you to be my reliable agent to assist me in receiving $10.2m
into your designated bank account in subsequent investments. This is a
legitimate transaction, and you will be paid 30% for your "Assistance?.
If you are interested, please write back by mail, and provide me with your
confidential telephone number, fax number and I will provide further details
and instructions. Please keep this confidential.
I will assume all responsibilities for this endeavor so you don't have to worry
about any legal ramifications, just what you will do with all that money.  Your
urgent response is highly anticipated so please email me back for more details
on this transaction as soon as possible.
Kind Regards,
Miss. Mary Ellaine Manguerra Villanueva.



From podstavin at dev.rtsoft.ru  Mon Jan 14 00:44:35 2008
From: podstavin at dev.rtsoft.ru (Sergey Podstavin)
Date: Mon, 14 Jan 2008 08:44:35 +0300
Subject: [PATCH][MTD][NAND] PXA300 Zylonite controller support
Message-ID: <1200289475.1727.106.camel@localhost.localdomain>

This is a fixed version for pxa3 nand controller from eric miao, 
working on pxa300 Zylonite

Best wishes,
Sergey Podstavin.

>From 8e078f4fa24f5d3d8e7ee887f135f040dce0580f Mon Sep 17 00:00:00 2001
From: Sergey Podstavin <spodstavin at ru.mvista.com>
Date: Fri, 11 Jan 2008 09:46:30 +0300
Subject: [PATCH] fixed basic pxa3 nand controller support

---
 arch/arm/kernel/head.S                 |    6 +-
 arch/arm/mach-pxa/generic.c            |    6 +
 arch/arm/mach-pxa/pxa3xx.c             |    1 +
 arch/arm/mach-pxa/zylonite.c           |   21 +
 drivers/mtd/nand/Kconfig               |    6 +
 drivers/mtd/nand/Makefile              |    1 +
 drivers/mtd/nand/pxa3xx_nand.c         | 1419
++++++++++++++++++++++++++++++++
 include/asm-arm/arch-pxa/hardware.h    |   30 +-
 include/asm-arm/arch-pxa/pxa-regs.h    |   19 +
 include/asm-arm/arch-pxa/pxa3xx_nand.h |   18 +
 include/asm-arm/arch-pxa/zylonite.h    |  710 ++++++++++++++++
 11 files changed, 2212 insertions(+), 25 deletions(-)
 create mode 100644 drivers/mtd/nand/pxa3xx_nand.c
 create mode 100644 include/asm-arm/arch-pxa/pxa3xx_nand.h

diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 7898cbc..a89c0f2 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -86,9 +86,9 @@ ENTRY(stext)
 	bl	__lookup_processor_type		@ r5=procinfo r9=cpuid
 	movs	r10, r5				@ invalid processor (r5=0)?
 	beq	__error_p			@ yes, error 'p'
-	bl	__lookup_machine_type		@ r5=machinfo
-	movs	r8, r5				@ invalid machine (r5=0)?
-	beq	__error_a			@ yes, error 'a'
+//	bl	__lookup_machine_type		@ r5=machinfo
+//	movs	r8, r5				@ invalid machine (r5=0)?
+//	beq	__error_a			@ yes, error 'a'
 	bl	__vet_atags
 	bl	__create_page_tables
 
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
index 1c34946..4b0f6ea 100644
--- a/arch/arm/mach-pxa/generic.c
+++ b/arch/arm/mach-pxa/generic.c
@@ -195,6 +195,11 @@ static struct map_desc standard_io_desc[]
__initdata = {
 		.pfn		= __phys_to_pfn(0x40000000),
 		.length		= 0x02000000,
 		.type		= MT_DEVICE
+	}, {	/* nand               */
+		.virtual	= 0xf8300000,
+		.pfn		= __phys_to_pfn(0x43100000),
+		.length		= 0x00100000,
+		.type		= MT_DEVICE
 	}, {	/* LCD */
 		.virtual	=  0xf4000000,
 		.pfn		= __phys_to_pfn(0x44000000),
@@ -471,6 +476,7 @@ void __init pxa_set_ficp_info(struct
pxaficp_platform_data *info)
 	pxa_device_ficp.dev.platform_data = info;
 }
 
+
 struct platform_device pxa_device_rtc = {
 	.name		= "sa1100-rtc",
 	.id		= -1,
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index 61d9c9d..4d800c6 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -183,6 +183,7 @@ static struct clk pxa3xx_clks[] = {
 	PXA3xx_CK("LCDCLK", LCD,    &clk_pxa3xx_hsio_ops, &pxa_device_fb.dev),
 	PXA3xx_CK("CAMCLK", CAMERA, &clk_pxa3xx_hsio_ops, NULL),
 
+	PXA3xx_CK("NANDCLK", NAND, &clk_pxa3xx_hsio_ops, NULL),
 	PXA3xx_CKEN("UARTCLK", FFUART, 14857000, 1, &pxa_device_ffuart.dev),
 	PXA3xx_CKEN("UARTCLK", BTUART, 14857000, 1, &pxa_device_btuart.dev),
 	PXA3xx_CKEN("UARTCLK", STUART, 14857000, 1, NULL),
diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
index 743a87b..dc761bd 100644
--- a/arch/arm/mach-pxa/zylonite.c
+++ b/arch/arm/mach-pxa/zylonite.c
@@ -156,6 +156,26 @@ static void __init zylonite_init_lcd(void)
 static inline void zylonite_init_lcd(void) {}
 #endif
 
+static struct resource nand_resources[] = {
+	[0] = {
+		.start	= 0x43100000,
+		.end	= 0x431000ff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= -1,	/* for run-time assignment */
+		.end	= -1,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device nand_device = {
+	.name		= "pxa3xx-nand",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(nand_resources),
+	.resource	= nand_resources,
+};
+
 static void __init zylonite_init(void)
 {
 	/* board-processor specific initialization */
@@ -171,6 +191,7 @@ static void __init zylonite_init(void)
 	platform_device_register(&smc91x_device);
 
 	zylonite_init_lcd();
+	platform_device_register(&nand_device);
 }
 
 MACHINE_START(ZYLONITE, "PXA3xx Platform Development Kit (aka
Zylonite)")
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 246d451..2be073f 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -84,6 +84,12 @@ config MTD_NAND_TS7250
 config MTD_NAND_IDS
 	tristate
 
+config MTD_NAND_PXA3xx
+	tristate "NAND flash support for PXA3xx"
+	depends on MTD_NAND && PXA3xx
+	help
+	  This enables the driver for the NAND flash device on Zylonite board
+
 config MTD_NAND_AU1550
 	tristate "Au1550/1200 NAND support"
 	depends on SOC_AU1200 || SOC_AU1550
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 3ad6c01..ecb7968 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_MTD_NAND_BF5XX)		+= bf5xx_nand.o
 obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB)	+= ppchameleonevb.o
 obj-$(CONFIG_MTD_NAND_S3C2410)		+= s3c2410.o
 obj-$(CONFIG_MTD_NAND_DISKONCHIP)	+= diskonchip.o
+obj-$(CONFIG_MTD_NAND_PXA3xx)		+= pxa3xx_nand.o
 obj-$(CONFIG_MTD_NAND_H1900)		+= h1910.o
 obj-$(CONFIG_MTD_NAND_RTC_FROM4)	+= rtc_from4.o
 obj-$(CONFIG_MTD_NAND_SHARPSL)		+= sharpsl.o
diff --git a/drivers/mtd/nand/pxa3xx_nand.c
b/drivers/mtd/nand/pxa3xx_nand.c
new file mode 100644
index 0000000..74c5460
--- /dev/null
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -0,0 +1,1419 @@
+/*
+ * drivers/mtd/nand/pxa3xx_nand.c
+ *
+ * Copyright (C) 2005 Intel Corporation
+ * Copyright (C) 2006 Marvell International Ltd.
+ *
+ * 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/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa3xx_nand.h>
+
+#define	CHIP_DELAY_TIMEOUT	(2 * HZ/10)
+
+/* registers and bit definitions */
+#define NDCR		(0x00) /* Control register */
+#define NDTR0CS0	(0x04) /* Timing Parameter 0 for CS0 */
+#define NDTR1CS0	(0x0C) /* Timing Parameter 1 for CS0 */
+#define NDSR		(0x14) /* Status Register */
+#define NDPCR		(0x18) /* Page Count Register */
+#define NDBDR0		(0x1C) /* Bad Block Register 0 */
+#define NDBDR1		(0x20) /* Bad Block Register 1 */
+#define NDDB		(0x40) /* Data Buffer */
+#define NDCB0		(0x48) /* Command Buffer0 */
+#define NDCB1		(0x4C) /* Command Buffer1 */
+#define NDCB2		(0x50) /* Command Buffer2 */
+
+#define NDCR_SPARE_EN		(0x1 << 31)
+#define NDCR_ECC_EN		(0x1 << 30)
+#define NDCR_DMA_EN		(0x1 << 29)
+#define NDCR_ND_RUN		(0x1 << 28)
+#define NDCR_DWIDTH_C		(0x1 << 27)
+#define NDCR_DWIDTH_M		(0x1 << 26)
+#define NDCR_PAGE_SZ		(0x1 << 24)
+#define NDCR_NCSX		(0x1 << 23)
+#define NDCR_ND_MODE		(0x3 << 21)
+#define NDCR_NAND_MODE   	(0x0)
+#define NDCR_CLR_PG_CNT		(0x1 << 20)
+#define NDCR_CLR_ECC		(0x1 << 19)
+#define NDCR_RD_ID_CNT_MASK	(0x7 << 16)
+#define NDCR_RD_ID_CNT(x)	(((x) << 16) & NDCR_RD_ID_CNT_MASK)
+
+#define NDCR_RA_START		(0x1 << 15)
+#define NDCR_PG_PER_BLK		(0x1 << 14)
+#define NDCR_ND_ARB_EN		(0x1 << 12)
+
+#define NDSR_MASK		(0xfff)
+#define NDSR_RDY		(0x1 << 11)
+#define NDSR_CS0_PAGED		(0x1 << 10)
+#define NDSR_CS1_PAGED		(0x1 << 9)
+#define NDSR_CS0_CMDD		(0x1 << 8)
+#define NDSR_CS1_CMDD		(0x1 << 7)
+#define NDSR_CS0_BBD		(0x1 << 6)
+#define NDSR_CS1_BBD		(0x1 << 5)
+#define NDSR_DBERR		(0x1 << 4)
+#define NDSR_SBERR		(0x1 << 3)
+#define NDSR_WRDREQ		(0x1 << 2)
+#define NDSR_RDDREQ		(0x1 << 1)
+#define NDSR_WRCMDREQ		(0x1)
+
+#define NDCB0_AUTO_RS		(0x1 << 25)
+#define NDCB0_CSEL		(0x1 << 24)
+#define NDCB0_CMD_TYPE_MASK	(0x7 << 21)
+#define NDCB0_CMD_TYPE(x)	(((x) << 21) & NDCB0_CMD_TYPE_MASK)
+#define NDCB0_NC		(0x1 << 20)
+#define NDCB0_DBC		(0x1 << 19)
+#define NDCB0_ADDR_CYC_MASK	(0x7 << 16)
+#define NDCB0_ADDR_CYC(x)	(((x) << 16) & NDCB0_ADDR_CYC_MASK)
+#define NDCB0_CMD2_MASK		(0xff << 8)
+#define NDCB0_CMD1_MASK		(0xff)
+#define NDCB0_ADDR_CYC_SHIFT	(16)
+
+/* dma-able I/O address for the NAND data and commands */
+#define NDCB0_DMA_ADDR		(0x43100048)
+#define NDDB_DMA_ADDR		(0x43100040)
+
+/* macros for registers read/write */
+#define nand_writel(info, off, val)	\
+	__raw_writel((val), (info)->mmio_base + (off))
+
+#define nand_readl(info, off)		\
+	__raw_readl((info)->mmio_base + (off))
+
+/* error code and state */
+enum {
+	ERR_NONE	= 0,
+	ERR_DMABUSERR	= -1,
+	ERR_SENDCMD	= -2,
+	ERR_DBERR	= -3,
+	ERR_BBERR	= -4,
+	ERR_BUSY	= -5,
+};
+
+enum {
+	STATE_CMD_SEND = 1,
+	STATE_CMD_HANDLE,
+	STATE_DMA_TRANSFER,
+	STATE_DMA_DONE,
+	STATE_READY,
+	STATE_SUSPENDED,
+	STATE_DATA_TRANSFER,
+};
+
+struct pxa3xx_nand_timing {
+	unsigned int	tCH;  /* Enable signal hold time */
+	unsigned int	tCS;  /* Enable signal setup time */
+	unsigned int	tWH;  /* ND_nWE high duration */
+	unsigned int	tWP;  /* ND_nWE pulse time */
+	unsigned int	tRH;  /* ND_nRE high duration */
+	unsigned int	tRP;  /* ND_nRE pulse width */
+	unsigned int	tR;   /* ND_nWE high to ND_nRE low for read */
+	unsigned int	tWHR; /* ND_nWE high to ND_nRE low for status read */
+	unsigned int	tAR;  /* ND_ALE low to ND_nRE low delay */
+};
+
+struct pxa3xx_nand_cmdset {
+	uint16_t	read1;
+	uint16_t	read2;
+	uint16_t	program;
+	uint16_t	read_status;
+	uint16_t	read_id;
+	uint16_t	erase;
+	uint16_t	reset;
+	uint16_t	lock;
+	uint16_t	unlock;
+	uint16_t	lock_status;
+};
+
+struct pxa3xx_nand_flash {
+	struct pxa3xx_nand_timing *timing; /* NAND Flash timing */
+	struct pxa3xx_nand_cmdset *cmdset;
+
+	uint32_t page_per_block;/* Pages per block (PG_PER_BLK) */
+	uint32_t page_size;	/* Page size in bytes (PAGE_SZ) */
+	uint32_t flash_width;	/* Width of Flash memory (DWIDTH_M) */
+	uint32_t dfc_width;	/* Width of flash controller(DWIDTH_C) */
+	uint32_t num_blocks;	/* Number of physical blocks in Flash */
+	uint32_t chip_id;
+
+	/* NOTE: these are automatically calculated, do not define */
+	size_t		oob_size;
+	size_t		read_id_bytes;
+
+	unsigned int	col_addr_cycles;
+	unsigned int	row_addr_cycles;
+};
+
+struct pxa3xx_nand_info {
+	struct nand_chip	nand_chip;
+
+	struct platform_device	 *pdev;
+	struct pxa3xx_nand_flash *flash_info;
+
+	struct clk		*clk;
+	void __iomem		*mmio_base;
+
+	unsigned int 		buf_start;
+	unsigned int		buf_count;
+
+	/* DMA information */
+	unsigned char		*data_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 */
+	unsigned int		state;
+
+	int			use_ecc;	/* use HW ECC ? */
+	int			use_dma;	/* use DMA ? */
+
+	size_t			data_size;	/* data size in FIFO */
+	unsigned int		cur_cmd;
+	int 			retcode;
+	struct completion 	cmd_complete;
+
+	/* generated NDCBx register values */
+	uint32_t		ndcb0;
+	uint32_t		ndcb1;
+	uint32_t		ndcb2;
+};
+
+static int use_dma = 0;
+module_param(use_dma, bool, 0444);
+MODULE_PARM_DESC(use_dma, "enable DMA for data transfering to/from NAND
HW");
+
+static struct pxa3xx_nand_cmdset smallpage_cmdset = {
+	.read1		= 0x0000,
+	.read2		= 0x0050,
+	.program	= 0x1080,
+	.read_status	= 0x0070,
+	.read_id	= 0x0090,
+	.erase		= 0xD060,
+	.reset		= 0x00FF,
+	.lock		= 0x002A,
+	.unlock		= 0x2423,
+	.lock_status	= 0x007A,
+};
+
+static struct pxa3xx_nand_cmdset largepage_cmdset = {
+	.read1		= 0x3000,
+	.read2		= 0x0050,
+	.program	= 0x1080,
+	.read_status	= 0x0070,
+	.read_id	= 0x0090,
+	.erase		= 0xD060,
+	.reset		= 0x00FF,
+	.lock		= 0x002A,
+	.unlock		= 0x2423,
+	.lock_status	= 0x007A,
+};
+
+static struct pxa3xx_nand_timing samsung512MbX16_timing = {
+	.tCH	= 10,
+	.tCS	= 0,
+	.tWH	= 20,
+	.tWP	= 40,
+	.tRH	= 30,
+	.tRP	= 40,
+	.tR	= 11123,
+	.tWHR	= 110,
+	.tAR	= 10,
+};
+
+static struct pxa3xx_nand_flash samsung512MbX16 = {
+	.timing		= &samsung512MbX16_timing,
+	.cmdset		= &smallpage_cmdset,
+	.page_per_block	= 32,
+	.page_size	= 512,
+	.flash_width	= 16,
+	.dfc_width	= 16,
+	.num_blocks	= 4096,
+	.chip_id	= 0x46ec,
+};
+
+static struct pxa3xx_nand_timing micron_timing = {
+	.tCH	= 10,
+	.tCS	= 25,
+	.tWH	= 15,
+	.tWP	= 25,
+	.tRH	= 15,
+	.tRP	= 25,
+	.tR	= 25000,
+	.tWHR	= 60,
+	.tAR	= 10,
+};
+
+static struct pxa3xx_nand_flash micron1GbX8 = {
+	.timing		= &micron_timing,
+	.cmdset		= &largepage_cmdset,
+	.page_per_block	= 64,
+	.page_size	= 2048,
+	.flash_width	= 8,
+	.dfc_width	= 8,
+	.num_blocks	= 1024,
+	.chip_id	= 0xa12c,
+};
+
+static struct pxa3xx_nand_flash micron1GbX16 = {
+	.timing		= &micron_timing,
+	.cmdset		= &largepage_cmdset,
+	.page_per_block	= 64,
+	.page_size	= 2048,
+	.flash_width	= 16,
+	.dfc_width	= 16,
+	.num_blocks	= 1024,
+	.chip_id	= 0xb12c,
+};
+
+static struct pxa3xx_nand_flash *builtin_flash_types[] = {
+	&samsung512MbX16,
+	&micron1GbX8,
+	&micron1GbX16,
+};
+
+#define NDTR0_tCH(c)	(min((c), 7) << 19)
+#define NDTR0_tCS(c)	(min((c), 7) << 16)
+#define NDTR0_tWH(c)	(min((c), 7) << 11)
+#define NDTR0_tWP(c)	(min((c), 7) << 8)
+#define NDTR0_tRH(c)	(min((c), 7) << 3)
+#define NDTR0_tRP(c)	(min((c), 7) << 0)
+
+#define NDTR1_tR(c)	(min((c), 65535) << 16)
+#define NDTR1_tWHR(c)	(min((c), 15) << 4)
+#define NDTR1_tAR(c)	(min((c), 15) << 0)
+
+/* convert nano-seconds to nand flash controller clock cycles */
+#define ns2cycle(ns, clk)	(int)(((ns) * (clk / 1000000) / 1000) + 1)
+
+static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info,
+				   struct pxa3xx_nand_timing *t)
+{
+	unsigned long nand_clk = clk_get_rate(info->clk);
+	uint32_t ndtr0, ndtr1;
+
+	ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) |
+		NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) |
+		NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) |
+		NDTR0_tWP(ns2cycle(t->tWP, nand_clk)) |
+		NDTR0_tRH(ns2cycle(t->tRH, nand_clk)) |
+		NDTR0_tRP(ns2cycle(t->tRP, nand_clk));
+
+	ndtr1 = NDTR1_tR(ns2cycle(t->tR, nand_clk)) |
+		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
+		NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
+
+	nand_writel(info, NDTR0CS0, ndtr0);
+	nand_writel(info, NDTR1CS0, ndtr1);
+}
+
+#define WAIT_EVENT_TIMEOUT	10
+
+static int wait_for_event(struct pxa3xx_nand_info *info, uint32_t
event)
+{
+	int timeout = WAIT_EVENT_TIMEOUT;
+	uint32_t ndsr;
+
+	while (timeout--) {
+		ndsr = nand_readl(info, NDSR) & NDSR_MASK;
+		if (ndsr & event) {
+			nand_writel(info, NDSR, ndsr);
+			return 0;
+		}
+		udelay(10);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info,
+			uint16_t cmd, int column, int page_addr)
+{
+	struct pxa3xx_nand_flash *f = info->flash_info;
+	struct pxa3xx_nand_cmdset *cmdset = f->cmdset;
+
+	/* calculate data size */
+	switch (f->page_size) {
+	case 2048:
+		info->data_size = (info->use_ecc) ? 2088 : 2112;
+		break;
+	case 512:
+		info->data_size = (info->use_ecc) ? 520 : 528;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* generate values for NDCBx registers */
+	info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
+	info->ndcb0 |= NDCB0_ADDR_CYC(f->row_addr_cycles +
f->col_addr_cycles);
+
+	if (f->col_addr_cycles == 2) {
+		/* large block, 2 cycles for column address
+		 * row address starts from 3rd cycle
+		 */
+		info->ndcb1 |= (page_addr << 16) | (column & 0xffff);
+		if (f->row_addr_cycles == 3)
+			info->ndcb2 = (page_addr >> 16) & 0xff;
+	} else
+		/* small block, 1 cycles for column address
+		 * row address starts from 2nd cycle
+		 */
+		info->ndcb1 = (page_addr << 8) | (column & 0xff);
+
+	if (cmd == cmdset->program)
+		info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS;
+
+	info->cur_cmd = cmd;
+	return 0;
+}
+
+static int prepare_erase_cmd(struct pxa3xx_nand_info *info,
+			uint16_t cmd, int page_addr)
+{
+	info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
+	info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3);
+	info->ndcb1 = page_addr;
+
+	info->cur_cmd = cmd;
+	return 0;
+}
+
+static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t
cmd)
+{
+	struct pxa3xx_nand_cmdset *cmdset = info->flash_info->cmdset;
+
+	info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
+
+	if (cmd == cmdset->read_id) {
+		info->ndcb0 |= NDCB0_CMD_TYPE(3);
+		info->data_size = 8;
+	} else if (cmd == cmdset->read_status) {
+		info->ndcb0 |= NDCB0_CMD_TYPE(4);
+		info->data_size = 8;
+	} else if (cmd == cmdset->reset || cmd == cmdset->lock ||
+		   cmd == cmdset->unlock) {
+		info->ndcb0 |= NDCB0_CMD_TYPE(5);
+	} else
+		return -EINVAL;
+
+	info->cur_cmd = cmd;
+	return 0;
+}
+
+static void enable_int(struct pxa3xx_nand_info *info, uint32_t
int_mask)
+{
+	uint32_t ndcr;
+
+	ndcr = nand_readl(info, NDCR);
+	nand_writel(info, NDCR, ndcr & ~int_mask);
+}
+
+static void disable_int(struct pxa3xx_nand_info *info, uint32_t
int_mask)
+{
+	uint32_t ndcr;
+
+	ndcr = nand_readl(info, NDCR);
+	nand_writel(info, NDCR, ndcr | int_mask);
+}
+
+/* NOTE: it is a must to set ND_RUN firstly, then write command buffer
+ * otherwise, it does not work
+ */
+static int write_cmd(struct pxa3xx_nand_info *info)
+{
+	uint32_t ndcr;
+
+	/* clear status bits and run */
+	nand_writel(info, NDSR, NDSR_MASK);
+
+	ndcr = info->reg_ndcr;
+
+	ndcr |= info->use_ecc ? NDCR_ECC_EN : 0;
+	ndcr |= info->use_dma ? NDCR_DMA_EN : 0;
+	ndcr |= NDCR_ND_RUN;
+
+	nand_writel(info, NDCR, ndcr);
+
+	if (wait_for_event(info, NDSR_WRCMDREQ)) {
+		printk(KERN_ERR "timed out writing command\n");
+		return -ETIMEDOUT;
+	}
+
+	nand_writel(info, NDCB0, info->ndcb0);
+	nand_writel(info, NDCB0, info->ndcb1);
+	nand_writel(info, NDCB0, info->ndcb2);
+	return 0;
+}
+
+/* NOTE: {read, write}_fifo_pio() assume the buffer is 4-byte aligned,
+ * and data_size are 4-byte multiples as well
+ */
+static void read_fifo_pio(struct pxa3xx_nand_info *info)
+{
+	uint32_t *buff = (uint32_t *)info->data_buff;
+	int i, data_size = info->data_size;
+
+	BUG_ON((data_size % sizeof(uint32_t)) != 0);
+
+	for (i = 0; i < data_size / sizeof(uint32_t); i++)
+		*buff++ = __raw_readl(info->mmio_base + NDDB);
+}
+
+static void write_fifo_pio(struct pxa3xx_nand_info *info)
+{
+	uint32_t *buff = (uint32_t *)info->data_buff;
+	int i, data_size = info->data_size;
+
+	BUG_ON((data_size % sizeof(uint32_t)) != 0);
+
+	for (i = 0; i < data_size / sizeof(uint32_t); i++)
+		__raw_writel(*buff++, info->mmio_base + NDDB);
+}
+
+static int handle_data_pio(struct pxa3xx_nand_info *info)
+{
+	struct pxa3xx_nand_cmdset *cmdset = info->flash_info->cmdset;
+	int ret, timeout = CHIP_DELAY_TIMEOUT;
+
+	if (info->cur_cmd == cmdset->program) {
+		write_fifo_pio(info);
+
+		enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);
+
+		ret = wait_for_completion_timeout(&info->cmd_complete, timeout);
+		if (!ret) {
+			printk(KERN_ERR "program command time out\n");
+			return -1;
+		}
+	} else
+		read_fifo_pio(info);
+
+	info->state = STATE_READY;
+	return 0;
+}
+
+static void setup_data_dma(struct pxa3xx_nand_info *info)
+{
+	struct pxa3xx_nand_flash * f = info->flash_info;
+	struct pxa_dma_desc *desc = info->data_desc;
+	int dma_len = ALIGN(info->data_size, 32);
+
+	desc->ddadr = DDADR_STOP;
+	desc->dcmd = DCMD_ENDIRQEN | DCMD_WIDTH4 | DCMD_BURST32 | dma_len;
+
+	if (info->cur_cmd == f->cmdset->program) {
+		desc->dsadr = info->data_buff_phys;
+		desc->dtadr = NDDB_DMA_ADDR;
+		desc->dcmd |= DCMD_INCSRCADDR | DCMD_FLOWTRG;
+	} else {
+		desc->dtadr = info->data_buff_phys;
+		desc->dsadr = NDDB_DMA_ADDR;
+		desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC;
+	}
+}
+
+static void start_data_dma(struct pxa3xx_nand_info *info)
+{
+	DRCMR97 = DRCMR_MAPVLD | info->data_dma_ch;
+	DDADR(info->data_dma_ch) = info->data_desc_addr;
+	DCSR(info->data_dma_ch) |= DCSR_RUN;
+}
+
+static void pxa3xx_nand_data_dma_irq(int channel, void *data)
+{
+	struct pxa3xx_nand_info *info = data;
+	struct pxa3xx_nand_flash *f = info->flash_info;
+	uint32_t dcsr, intm;
+
+	dcsr = DCSR(channel);
+	DCSR(channel) = dcsr;
+
+	intm = NDSR_CS0_BBD | NDSR_CS0_CMDD;
+
+	if (dcsr & DCSR_BUSERR) {
+		info->retcode = ERR_DMABUSERR;
+		complete(&info->cmd_complete);
+	}
+
+	if (info->cur_cmd == f->cmdset->program) {
+		info->state = STATE_DMA_DONE;
+		enable_int(info, intm);
+	} else {
+		info->state = STATE_READY;
+		complete(&info->cmd_complete);
+	}
+}
+
+static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
+{
+	unsigned int status, event, intm;
+	struct pxa3xx_nand_info *info = devid;
+
+	intm = NDSR_CS0_BBD | NDSR_CS0_CMDD;
+	event = NDSR_CS0_BBD | NDSR_CS0_CMDD;
+
+	status = nand_readl(info, NDSR);
+
+	if (status & (NDSR_RDDREQ | NDSR_DBERR)) {
+		if (status & NDSR_DBERR)
+			info->retcode = ERR_DBERR;
+
+		disable_int(info, NDSR_RDDREQ | NDSR_DBERR);
+
+		if (info->use_dma) {
+			info->state = STATE_DMA_TRANSFER;
+			start_data_dma(info);
+		} else {
+			info->state = STATE_DATA_TRANSFER;
+			complete(&info->cmd_complete);
+		}
+	} else if (status & NDSR_WRDREQ) {
+		disable_int(info, NDSR_WRDREQ);
+		if (info->use_dma) {
+			info->state = STATE_DMA_TRANSFER;
+			start_data_dma(info);
+		} else {
+			info->state = STATE_DATA_TRANSFER;
+			complete(&info->cmd_complete);
+		}
+	} else if (status & event) {
+		if (status & NDSR_CS0_BBD)
+			info->retcode = ERR_BBERR;
+
+		disable_int(info, intm);
+		info->state = STATE_READY;
+		complete(&info->cmd_complete);
+	}
+	nand_writel(info, NDSR, status);
+	return IRQ_HANDLED;
+}
+
+static int pxa3xx_nand_do_cmd(struct pxa3xx_nand_info *info, uint32_t
event)
+{
+	uint32_t ndcr;
+	int ret, timeout = CHIP_DELAY_TIMEOUT;
+
+	info->state = STATE_CMD_SEND;
+
+	if (write_cmd(info)) {
+		info->retcode = ERR_SENDCMD;
+		goto fail_stop;
+	}
+
+	info->state = STATE_CMD_HANDLE;
+
+	if (info->use_dma)
+		setup_data_dma(info);
+
+	enable_int(info, event);
+
+	ret = wait_for_completion_timeout(&info->cmd_complete, timeout);
+	if (!ret) {
+		printk(KERN_ERR "command execution timed out\n");
+		info->retcode = ERR_SENDCMD;
+		goto fail_stop;
+	}
+
+	if (info->use_dma == 0 && info->data_size > 0)
+		if (handle_data_pio(info))
+			goto fail_stop;
+
+	return 0;
+
+fail_stop:
+	ndcr = nand_readl(info, NDCR);
+	nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN);
+	udelay(10);
+	return -ETIMEDOUT;
+}
+
+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--)
+		if (*buf++ != 0xff)
+			return 0;
+	return 1;
+}
+
+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_flash * flash_info = info->flash_info;
+	struct pxa3xx_nand_cmdset *cmdset = flash_info->cmdset;
+	int ret;
+
+	info->ndcb0 = 0;
+	info->ndcb1 = 0;
+	info->ndcb2 = 0;
+	info->use_dma = 0;
+	info->use_ecc = 0;
+	info->cur_cmd = -1;
+	info->data_size = 0;
+	info->state = STATE_READY;
+
+	init_completion(&info->cmd_complete);
+
+	switch (command) {
+	case NAND_CMD_READOOB:
+		/* disable HW ECC to get all the OOB data */
+		info->use_ecc = 0;
+		info->use_dma = use_dma ? 1 : 0;
+		info->buf_count = mtd->writesize + mtd->oobsize;
+		info->buf_start = mtd->writesize + column;
+
+		if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr))
+			break;
+
+		pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR);
+
+		/* We only are OOB, so if the data has error, does not matter */
+		if (info->retcode == ERR_DBERR)
+			info->retcode = ERR_NONE;
+		break;
+
+	case NAND_CMD_READ0:
+		info->use_ecc = 1;
+		info->use_dma = use_dma ? 1 : 0;
+		info->retcode = ERR_NONE;
+		info->buf_start = column;
+		info->buf_count = mtd->writesize + mtd->oobsize;
+		memset(info->data_buff, 0xFF, info->buf_count);
+
+		if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr))
+			break;
+
+		pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR);
+
+		if (info->retcode == ERR_DBERR) {
+			/* for blank page (all 0xff), HW will calculate its ECC as
+			 * 0, which is different from the ECC information within
+			 * OOB, ignore such double bit errors
+			 */
+			if (is_buf_blank(info->data_buff, mtd->writesize))
+				info->retcode = ERR_NONE;
+		}
+		break;
+	case NAND_CMD_SEQIN:
+		info->buf_start = column;
+		info->buf_count = mtd->writesize + mtd->oobsize;
+		memset(info->data_buff, 0xff, info->buf_count);
+
+		/* save column/page_addr for next CMD_PAGEPROG */
+		info->seqin_column = column;
+		info->seqin_page_addr = page_addr;
+		break;
+	case NAND_CMD_PAGEPROG:
+		info->use_ecc = (info->seqin_column >= mtd->writesize) ? 0 : 1;
+		info->use_dma = use_dma ? 1 : 0;
+
+		if (prepare_read_prog_cmd(info, cmdset->program,
+				info->seqin_column, info->seqin_page_addr))
+			break;
+
+		pxa3xx_nand_do_cmd(info, NDSR_WRDREQ);
+		break;
+	case NAND_CMD_ERASE1:
+		if (prepare_erase_cmd(info, cmdset->erase, page_addr))
+			break;
+
+		pxa3xx_nand_do_cmd(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);
+		break;
+	case NAND_CMD_ERASE2:
+		break;
+	case NAND_CMD_READID:
+		info->use_dma = 0;
+		info->buf_count = flash_info->read_id_bytes;
+		info->buf_start = 0;
+
+		if (prepare_other_cmd(info, cmdset->read_id))
+			break;
+
+		pxa3xx_nand_do_cmd(info, NDSR_RDDREQ);
+		break;
+	case NAND_CMD_STATUS:
+		info->use_dma = 0;
+		info->buf_count = 1;
+		info->buf_start = 0;
+		if (prepare_other_cmd(info, cmdset->read_status))
+			break;
+
+		pxa3xx_nand_do_cmd(info, NDSR_RDDREQ);
+		break;
+	case NAND_CMD_RESET:
+		if (prepare_other_cmd(info, cmdset->reset))
+			break;
+		
+		ret = pxa3xx_nand_do_cmd(info, NDSR_CS0_CMDD);
+		if (ret == 0) {
+			int timeout = 2;
+			uint32_t ndcr;
+
+			while (timeout--) {
+				if (nand_readl(info, NDSR) & NDSR_RDY)
+					break;
+				msleep(10);
+			}
+
+			ndcr = nand_readl(info, NDCR);
+			nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN);
+		}
+		break;
+	default:
+		printk(KERN_ERR "non-supported command.\n");
+		break;
+	}
+
+	if (info->retcode == ERR_DBERR) {
+		printk(KERN_ERR "double bit error @ page %08x\n", page_addr);
+		info->retcode = ERR_NONE;
+	}
+
+	if (info->retcode != ERR_NONE)
+		info->state = STATE_READY;
+}
+
+static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
+{
+	struct pxa3xx_nand_info *info = mtd->priv;
+	char retval = 0xFF;
+
+	if (info->buf_start < info->buf_count)
+		/* Has just send a new command? */
+		retval = info->data_buff[info->buf_start++];
+
+	return retval;
+}
+
+static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)
+{
+	struct pxa3xx_nand_info *info = mtd->priv;
+	u16 retval = 0xFFFF;
+
+	if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) {
+		retval = *((u16 *)(info->data_buff+info->buf_start));
+		info->buf_start += 2;
+	}
+	return retval;
+}
+
+static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf,
int len)
+{
+	struct pxa3xx_nand_info *info = mtd->priv;
+	int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
+
+	memcpy(buf, info->data_buff + info->buf_start, real_len);
+	info->buf_start += real_len;
+}
+
+static void pxa3xx_nand_write_buf(struct mtd_info *mtd,
+		const uint8_t *buf, int len)
+{
+	struct pxa3xx_nand_info *info = mtd->priv;
+	int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
+
+	memcpy(info->data_buff + info->buf_start, buf, real_len);
+	info->buf_start += real_len;
+}
+
+static int pxa3xx_nand_verify_buf(struct mtd_info *mtd,
+		const uint8_t *buf, int len)
+{
+	return 0;
+}
+
+static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+	return;
+}
+
+static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip
*this)
+{
+	struct pxa3xx_nand_info *info = mtd->priv;
+
+	/* pxa3xx_nand_send_command has waited for command complete */
+	if (this->state == FL_WRITING || this->state == FL_ERASING) {
+		if (info->retcode == ERR_NONE)
+			return 0;
+		else {
+			/*
+			 * any error make it return 0x01 which will tell
+			 * the caller the erase and write fail
+			 */
+			return 0x01;
+		}
+	}
+
+	return 0;
+}
+
+static void pxa3xx_nand_ecc_hwctl(struct mtd_info *mtd, int mode)
+{
+	return;
+}
+
+static int pxa3xx_nand_ecc_calculate(struct mtd_info *mtd,
+		const uint8_t *dat, uint8_t *ecc_code)
+{
+	return 0;
+}
+
+static int pxa3xx_nand_ecc_correct(struct mtd_info *mtd,
+		uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc)
+{
+	struct pxa3xx_nand_info *info = mtd->priv;
+	/*
+	 * Any error include ERR_SEND_CMD, ERR_DBERR, ERR_BUSERR, we
+	 * consider it as a ecc error which will tell the caller the
+	 * read fail We have distinguish all the errors, but the
+	 * nand_read_ecc only check this function return value
+	 */
+	if (info->retcode != ERR_NONE)
+		return -1;
+
+	return 0;
+}
+
+static int dfc_readid(struct pxa3xx_nand_info *info, uint32_t *id)
+{
+	struct pxa3xx_nand_flash *f = info->flash_info;
+	struct pxa3xx_nand_cmdset *cmdset = f->cmdset;
+	uint32_t ndcr;
+
+	info->ndcb0 = 0;
+	info->ndcb1 = 0;
+	info->ndcb2 = 0;
+	info->data_size = 0;
+
+	if (prepare_other_cmd(info, cmdset->read_id)) {
+		printk(KERN_ERR "failed to prepare command\n");
+		return -EINVAL;
+	}
+
+	/* Send command */
+	if (write_cmd(info))
+		goto fail_timeout;
+
+	/* Wait for CMDDM(command done successfully) */
+	if (wait_for_event(info, NDSR_RDDREQ))
+		goto fail_timeout;
+
+	read_fifo_pio(info);
+	*id = info->data_buff[0] | (info->data_buff[1] << 8);
+	return 0;
+
+fail_timeout:
+	ndcr = nand_readl(info, NDCR);
+	nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN);
+	udelay(10);
+	return -ETIMEDOUT;
+}
+
+static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
+				    struct pxa3xx_nand_flash *f)
+{
+	struct platform_device *pdev = info->pdev;
+	uint32_t ndcr = 0x00000FFF; /* disable all interrupts */
+
+	if (f->page_size != 2048 && f->page_size != 512)
+		return -EINVAL;
+
+	if (f->flash_width != 16 && f->flash_width != 8)
+		return -EINVAL;
+
+	/* calculate flash information */
+	f->oob_size = (f->page_size == 2048) ? 64 : 16;
+	f->read_id_bytes = (f->page_size == 2048) ? 4 : 2;
+
+	/* calculate addressing information */
+	f->col_addr_cycles = (f->page_size == 2048) ? 2 : 1;
+
+	if (f->num_blocks * f->page_per_block > 65536)
+		f->row_addr_cycles = 3;
+	else
+		f->row_addr_cycles = 2;
+
+	ndcr |= NDCR_ND_ARB_EN;
+	ndcr |= (f->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(f->read_id_bytes);
+	ndcr |= NDCR_SPARE_EN; /* enable spare by default */
+
+	info->reg_ndcr = ndcr;
+
+	pxa3xx_nand_set_timing(info, f->timing);
+	info->flash_info = f;
+	return 0;
+}
+
+static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info)
+{
+	struct pxa3xx_nand_flash *f;
+	uint32_t id;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(builtin_flash_types); i++) {
+
+		f = builtin_flash_types[i];
+
+		if (pxa3xx_nand_config_flash(info, f))
+			continue;
+
+		if (dfc_readid(info, &id))
+			continue;
+
+		if (id == f->chip_id)
+			return 0;
+	}
+
+	return -ENODEV;
+}
+
+/* the maximum possible buffer size for large page with OOB data
+ * is: 2048 + 64 = 2112 bytes, allocate a page here for both the
+ * data buffer and the DMA descriptor
+ */
+#define MAX_BUFF_SIZE	PAGE_SIZE
+
+static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
+{
+	struct platform_device *pdev = info->pdev;
+	int data_desc_offset = MAX_BUFF_SIZE - sizeof(struct pxa_dma_desc);
+
+	if (use_dma == 0) {
+		info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL);
+		if (info->data_buff == NULL)
+			return -ENOMEM;
+		return 0;
+	}
+
+	info->data_buff = dma_alloc_coherent(&pdev->dev, MAX_BUFF_SIZE,
+				&info->data_buff_phys, GFP_KERNEL);
+	if (info->data_buff == NULL) {
+		dev_err(&pdev->dev, "failed to allocate dma buffer\n");
+		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;
+
+	info->data_dma_ch = pxa_request_dma("nand-data", DMA_PRIO_LOW,
+				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,
+				info->data_buff, info->data_buff_phys);
+		return info->data_dma_ch;
+	}
+
+	return 0;
+}
+
+static struct nand_ecclayout hw_smallpage_ecclayout = {
+	.eccbytes = 6,
+	.eccpos = {8, 9, 10, 11, 12, 13 },
+	.oobfree = { {2, 6} }
+};
+
+static struct nand_ecclayout hw_largepage_ecclayout = {
+	.eccbytes = 24,
+	.eccpos = {
+		40, 41, 42, 43, 44, 45, 46, 47,
+		48, 49, 50, 51, 52, 53, 54, 55,
+		56, 57, 58, 59, 60, 61, 62, 63},
+	.oobfree = { {2, 38} }
+};
+
+static void pxa3xx_nand_init_mtd(struct mtd_info *mtd,
+				 struct pxa3xx_nand_info *info)
+{
+	struct pxa3xx_nand_flash *f = info->flash_info;
+	struct nand_chip *this = &info->nand_chip;
+
+	this->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16: 0;
+
+	this->waitfunc		= pxa3xx_nand_waitfunc;
+	this->select_chip	= pxa3xx_nand_select_chip;
+	this->dev_ready		= pxa3xx_nand_dev_ready;
+	this->cmdfunc		= pxa3xx_nand_cmdfunc;
+	this->read_word		= pxa3xx_nand_read_word;
+	this->read_byte		= pxa3xx_nand_read_byte;
+	this->read_buf		= pxa3xx_nand_read_buf;
+	this->write_buf		= pxa3xx_nand_write_buf;
+	this->verify_buf	= pxa3xx_nand_verify_buf;
+
+	this->ecc.mode		= NAND_ECC_HW;
+	this->ecc.hwctl		= pxa3xx_nand_ecc_hwctl;
+	this->ecc.calculate	= pxa3xx_nand_ecc_calculate;
+	this->ecc.correct	= pxa3xx_nand_ecc_correct;
+	this->ecc.size		= f->page_size;
+
+	if (f->page_size == 2048)
+		this->ecc.layout = &hw_largepage_ecclayout;
+	else
+		this->ecc.layout = &hw_smallpage_ecclayout;
+
+	this->chip_delay= 25;
+}
+
+/*
+ * BootRom and XDB will use last 127 block, and they will keep all the
status
+ * of the bootloader and image, so skip the first 2M size and last 2M
size
+ */
+static struct mtd_partition partition_info[] = {
+	{
+		name:		"Bootloader",
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE  /* force read-only */
+	},{
+		name:		"Kernel",
+		size:		0x00200000,
+		mask_flags:	MTD_WRITEABLE  /* force read-only */
+	},{
+		name:		"Filesystem",
+		size:		0x03000000,	/* only mount 48M fs */
+	}, {
+		name:		"MassStorage",
+		size:		0x0, /* It will be set at probe function */
+		offset:		MTDPART_OFS_APPEND /* Append after fs section */
+	}, {
+		name:		"BBT",
+		size:		0x0, /* It will be set at probe function */
+		offset:		MTDPART_OFS_APPEND,/* Append after fs section */
+		mask_flags:	MTD_WRITEABLE  /* force read-only */
+	}
+};
+
+#define		PART_NUM	ARRAY_SIZE(partition_info)
+
+/* MHN_OBM_V2 is related to BBT in MOBM V2
+ * MHN_OBM_V3 is related to BBT in MOBM V3
+ */
+enum {
+	MHN_OBM_NULL = 0,
+	MHN_OBM_V1,
+	MHN_OBM_V2,
+	MHN_OBM_V3,
+	MHN_OBM_INVAL
+} MHN_OBM_TYPE;
+
+static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
+static uint8_t scan_main_bbt_pattern[] = { 'p', 'x', 'a', '1' };
+static uint8_t scan_mirror_bbt_pattern[] = { '0', 'a', 'x', 'p' };
+
+static struct nand_bbt_descr monahans_bbt_default = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+			| NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.maxblocks = 2,
+	.len = 2,
+	.offs = 0,
+	.pattern = scan_ff_pattern,
+};
+
+static struct nand_bbt_descr monahans_bbt_main = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+			| NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.veroffs = 6,
+	.maxblocks = 2,
+        .offs = 2,
+        .len = 4,
+        .pattern = scan_main_bbt_pattern,
+};
+
+static struct nand_bbt_descr monahans_bbt_mirror = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+			| NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.veroffs = 6,
+	.maxblocks = 2,
+        .offs = 2,
+        .len = 4,
+        .pattern = scan_mirror_bbt_pattern,
+};
+
+/*
+ * The relocation table management is different between MOBM V2 and V3.
+ *
+ * MOBM V2 is applied on chips taped out before MhnLV A0.
+ * MOBM V3 is applied on chips taped out after MhnLV A0. It's also
applied
+ * on MhnLV A0.
+ */
+static int calc_obm_ver(void)
+{
+	unsigned int	cpuid;
+	
+	cpuid = read_cpuid(CPUID_ID);
+	/* It's not xscale chip. */
+	if ((cpuid & 0xFFFF0000) != 0x69050000)
+		return MHN_OBM_INVAL;
+	/* It's MhnP Ax */
+	if ((cpuid & 0x0000FFF0) == 0x00006420)
+		return MHN_OBM_V2;
+	/* It's MhnP Bx */
+	if ((cpuid & 0x0000FFF0) == 0x00006820) {
+		if ((cpuid & 0x0F) <= 6)
+			return MHN_OBM_V2;
+		else
+			return MHN_OBM_V3;
+	}
+	/* It's MhnL Ax */
+	if ((cpuid & 0x0000FFF0) == 0x00006880) {
+		if ((cpuid & 0x0F) == 0)
+			return MHN_OBM_V2;
+		else
+			return MHN_OBM_V3;
+	}
+	/* It's MhnLV Ax */
+	if ((cpuid & 0x0000FFF0) == 0x00006890)
+		return MHN_OBM_V3;
+	return MHN_OBM_INVAL;
+}
+static int pxa3xx_nand_probe(struct platform_device *pdev)
+{
+	struct pxa3xx_nand_info *info;
+	struct nand_chip *this;
+	struct mtd_info *mtd;
+	struct resource *res;
+	int ret = 0;
+	int obm;
+
+	mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct
pxa3xx_nand_info),
+			GFP_KERNEL);
+	if (mtd == NULL) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		return -ENOMEM;
+        }
+
+	info = (struct pxa3xx_nand_info *)(&mtd[1]);
+	info->pdev = pdev;
+
+	this = &info->nand_chip;
+	mtd->priv = info;
+
+	info->clk = clk_get(&pdev->dev, "NANDCLK");
+	if (IS_ERR(info->clk)) {
+		dev_err(&pdev->dev, "failed to get nand clock\n");
+		ret = PTR_ERR(info->clk);
+		goto free_mtd;
+	}
+	clk_enable(info->clk);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "no IO memory resource defined\n");
+		ret = -ENODEV;
+		goto fail_put_clk;
+	}
+	res = request_mem_region(res->start, res->end - res->start + 1,
+			pdev->name);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "failed to request memory resource\n");
+		ret = -EBUSY;
+		goto fail_put_clk;
+	}
+	info->mmio_base = ioremap(res->start, res->end - res->start + 1);
+	if (info->mmio_base == NULL) {
+		dev_err(&pdev->dev, "ioremap() failed\n");
+		ret = -ENODEV;
+		goto fail_free_res;
+	}
+	ret = pxa3xx_nand_init_buff(info);
+	if (ret)
+		goto fail_free_io;
+	ret = request_irq(IRQ_NAND, pxa3xx_nand_irq, IRQF_DISABLED,
+				pdev->name, info);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to request IRQ\n");
+		goto free_buf;
+	}
+	ret = pxa3xx_nand_detect_flash(info);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to detect flash\n");
+		ret = -ENODEV;
+		goto fail_free_io;
+	}
+	pxa3xx_nand_init_mtd(mtd, info);
+	platform_set_drvdata(pdev, mtd);
+	if (nand_scan(mtd, 1)) {
+		printk(KERN_ERR "Nand scan failed\n");
+		ret = -ENXIO;
+		goto free_irq;
+	}
+
+	/* There is a potential limitation that no more partition can be
+	 * added between MassStorage and BBT(last block).
+	 *
+	 * The last 127 blocks is reserved for relocation table, they aren't
+	 * statistical data of mtd size and chip size.
+	 *
+	 * BBT partitions contains 4 blocks. Two blocks are used to store
+	 * main descriptor, the other two are used to store mirror descriptor.
+	 */
+
+	/* boot loader partition */
+	obm = calc_obm_ver();
+	if (obm == MHN_OBM_V3) {
+		partition_info[0].size = 0x60000;
+	}else{
+		partition_info[0].size = 0x40000;
+	}
+
+	/* kernel partition */
+	partition_info[1].offset = partition_info[0].offset +
partition_info[0].size;
+
+	/* rootfs partition */
+	partition_info[2].offset = partition_info[1].offset +
partition_info[1].size;
+
+	/* bbt partition */
+	partition_info[PART_NUM - 1].size = (monahans_bbt_main.maxblocks
+					+ monahans_bbt_mirror.maxblocks)
+					<< this->phys_erase_shift;
+	partition_info[PART_NUM - 1].offset = this->chipsize
+					- partition_info[PART_NUM - 1].size;
+
+	/* mass storage partition */
+	partition_info[PART_NUM - 2].offset = partition_info[PART_NUM -
3].offset
+					+ partition_info[PART_NUM - 3].size;
+	partition_info[PART_NUM - 2].size = this->chipsize
+					- partition_info[PART_NUM - 2].offset
+					- partition_info[PART_NUM - 1].size;
+
+	return add_mtd_partitions(mtd, partition_info, PART_NUM);
+free_irq:
+	free_irq(IRQ_NAND, info);
+free_buf:
+	pxa_free_dma(info->data_dma_ch);
+	dma_free_coherent(&pdev->dev, info->data_buff_size,
+			info->data_buff, info->data_buff_phys);
+fail_free_io:
+	iounmap(info->mmio_base);
+fail_free_res:
+	release_mem_region(res->start, res->end - res->start + 1);
+fail_put_clk:
+	clk_put(info->clk);
+free_mtd:
+	kfree(mtd);
+	return ret;
+}
+
+static int pxa3xx_nand_remove(struct platform_device *pdev)
+{
+	struct mtd_info *mtd = platform_get_drvdata(pdev);
+	struct pxa3xx_nand_info *info = mtd->priv;
+
+	platform_set_drvdata(pdev, NULL);
+
+	del_mtd_device(mtd);
+	del_mtd_partitions(mtd);
+	free_irq(IRQ_NAND, info);
+	if (use_dma) {
+		pxa_free_dma(info->data_dma_ch);
+		dma_free_writecombine(&pdev->dev, info->data_buff_size,
+				info->data_buff, info->data_buff_phys);
+	} else
+		kfree(info->data_buff);
+	kfree(mtd);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int pxa3xx_nand_suspend(struct platform_device *pdev,
pm_message_t state)
+{
+	struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev);
+	struct pxa3xx_nand_info *info = mtd->priv;
+
+	if (info->state != STATE_READY) {
+		printk(KERN_ERR "current state is %d\n", info->state);
+		return -EAGAIN;
+	}
+	info->state = STATE_SUSPENDED;
+	/*
+	 * The PM code need read the mobm from NAND.
+	 * So the NAND clock can't be stop here.
+	 * The PM code will cover this.
+	 */
+	/* pxa_set_cken(CKEN_NAND, 0); */
+	return 0;
+}
+
+static int pxa3xx_nand_resume(struct platform_device *pdev)
+{
+	struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev);
+	struct pxa3xx_nand_info *info = mtd->priv;
+	int status;
+
+	if (info->state != STATE_SUSPENDED)
+		printk(KERN_WARNING "Error State after resume back\n");
+
+	info->state = STATE_READY;
+
+	clk_disable(info->clk);
+
+	status = pxa3xx_nand_config_flash(info, info->flash_info);
+	if (status) {
+		dev_err(&pdev->dev, "failed to initialize\n");
+		return -ENXIO;
+	}
+	return 0;
+}
+#else
+#define pxa3xx_nand_suspend	NULL
+#define pxa3xx_nand_resume	NULL
+#endif
+
+static struct platform_driver pxa3xx_nand_driver = {
+	.driver = {
+		.name	= "pxa3xx-nand",
+	},
+	.probe		= pxa3xx_nand_probe,
+	.remove		= pxa3xx_nand_remove,
+	.suspend	= pxa3xx_nand_suspend,
+	.resume		= pxa3xx_nand_resume,
+};
+
+static int __init pxa3xx_nand_init(void)
+{
+	return platform_driver_register(&pxa3xx_nand_driver);
+}
+
+static void __exit pxa3xx_nand_exit(void)
+{
+	platform_driver_unregister(&pxa3xx_nand_driver);
+}
+
+module_init(pxa3xx_nand_init);
+module_exit(pxa3xx_nand_exit);
diff --git a/include/asm-arm/arch-pxa/hardware.h
b/include/asm-arm/arch-pxa/hardware.h
index ab2d963..6e8b6b5 100644
--- a/include/asm-arm/arch-pxa/hardware.h
+++ b/include/asm-arm/arch-pxa/hardware.h
@@ -41,10 +41,12 @@
  */
 #define io_p2v(x) (0xf2000000 + ((x) & 0x01ffffff) + (((x) &
0x1c000000) >> 1))
 #define io_v2p(x) (0x3c000000 + ((x) & 0x01ffffff) + (((x) &
0x0e000000) << 1))
-
+#define io_p2v_2(x)	(((((x) - 0x42000000) & 0xff000000) >> 3) +
0xf8000000\
+ 			+ ((x) & 0x001fffff))
 #ifndef __ASSEMBLY__
 
 # define __REG(x)	(*((volatile u32 *)io_p2v(x)))
+#define __REG_2(x)	(*((volatile u32 *)io_p2v_2(x)))
 
 /* With indexed regs we don't want to feed the index through io_p2v()
    especially if it is a variable, otherwise horrible code will result.
*/
@@ -90,31 +92,19 @@
 #endif
 
 #ifdef CONFIG_CPU_PXA300
-#define __cpu_is_pxa300(id)				\
-	({						\
-		unsigned int _id = (id) >> 4 & 0xfff;	\
-		_id == 0x688;				\
-	 })
+#define __cpu_is_pxa300(id)	(1)
 #else
 #define __cpu_is_pxa300(id)	(0)
 #endif
 
 #ifdef CONFIG_CPU_PXA310
-#define __cpu_is_pxa310(id)				\
-	({						\
-		unsigned int _id = (id) >> 4 & 0xfff;	\
-		_id == 0x689;				\
-	 })
+#define __cpu_is_pxa310(id)	(0)
 #else
 #define __cpu_is_pxa310(id)	(0)
 #endif
 
-#ifdef CONFIG_CPU_PXA320
-#define __cpu_is_pxa320(id)				\
-	({						\
-		unsigned int _id = (id) >> 4 & 0xfff;	\
-		_id == 0x603 || _id == 0x682;		\
-	 })
+#ifdef CONFIG_CPU_PXA320	
+#define __cpu_is_pxa320(id)	(0)
 #else
 #define __cpu_is_pxa320(id)	(0)
 #endif
@@ -166,11 +156,7 @@
 		_id <= 0x2;				\
 	 })
 
-#define __cpu_is_pxa3xx(id)				\
-	({						\
-		unsigned int _id = (id) >> 13 & 0x7;	\
-		_id == 0x3;				\
-	 })
+#define __cpu_is_pxa3xx(id)	(1)
 
 #define cpu_is_pxa2xx()					\
 	({						\
diff --git a/include/asm-arm/arch-pxa/pxa-regs.h
b/include/asm-arm/arch-pxa/pxa-regs.h
index 6b33df6..9f1a32b 100644
--- a/include/asm-arm/arch-pxa/pxa-regs.h
+++ b/include/asm-arm/arch-pxa/pxa-regs.h
@@ -159,6 +159,21 @@
 #define DRCMR68		__REG(0x40001110)  /* Request to Channel Map Register
for Camera FIFO 0 Request */
 #define DRCMR69		__REG(0x40001114)  /* Request to Channel Map Register
for Camera FIFO 1 Request */
 #define DRCMR70		__REG(0x40001118)  /* Request to Channel Map Register
for Camera FIFO 2 Request */
+#define DRCMR71		__REG(0x4000111C)  /* Request to Channel Map Register
for TPM Receive Request */
+#define DRCMR72		__REG(0x40001120)  /* Request to Channel Map Register
for TPM Transmit Request 1 */
+#define DRCMR73		__REG(0x40001124)  /* Request to Channel Map Register
for TPM Transmit Request 2 */
+#define DRCMR74		__REG(0x40001128)  /* Request to Channel Map Register
for DREQ<2> */
+#define DRCMR91		__REG(0x4000116C)  /* Request to Channel Map Register
for USIM 2 Receive Request */
+#define DRCMR92		__REG(0x40001170)  /* Request to Channel Map Register
for USIM 2 Transmit Request */
+#define DRCMR93		__REG(0x40001174)  /* Request to Channel Map Register
for MMC Controller 1 Request */
+#define DRCMR94		__REG(0x40001178)  /* Request to Channel Map Register
for MMC Controller 2 Request */
+#define DRCMR95		__REG(0x4000117C)  /* Request to Channel Map Register
for AC97 Surround Transmit Request */
+#define DRCMR96		__REG(0x40001180)  /* Request to Channel Map Register
for AC97 centre/LFE Transmit Request */
+#define DRCMR97		__REG(0x40001184)  /* Request to Channel Map Register
for NAND interface data transmit & receive Request */
+#define DRCMR98		__REG(0x40001188)  /* Reserved */
+#define DRCMR99		__REG(0x4000118C)  /* Request to Channel Map Register
for NAND interface command transmit Request */
+#define DRCMR100	__REG(0x40001190)  /* Request to Channel Map Register
for MMC Controller 3 Request */
+#define DRCMR101	__REG(0x40001194)  /* Request to Channel Map Register
for MMC Controller 3 Request */
 
 #define DRCMRRXSADR	DRCMR2
 #define DRCMRTXSADR	DRCMR3
@@ -1780,6 +1795,8 @@
 #define OSCC		__REG(0x41300008)  /* Oscillator Configuration Register
*/
 #define CCSR		__REG(0x4130000C)  /* Core Clock Status Register */
 
+#define	CKEN_NAND	4	/* < NAND Flash Controller Clock Enable */
+
 #define CCCR_N_MASK	0x0380		/* Run Mode Frequency to Turbo Mode
Frequency Multiplier */
 #define CCCR_M_MASK	0x0060		/* Memory Frequency to Run Mode Frequency
Multiplier */
 #define CCCR_L_MASK	0x001f		/* Crystal Frequency to Memory Frequency
Multiplier */
@@ -2035,6 +2052,8 @@
 #define MDMRS		__REG(0x48000040)  /* MRS value to be written to SDRAM
*/
 #define BOOT_DEF	__REG(0x48000044)  /* Read-Only Boot-Time Register.
Contains BOOT_SEL and PKG_SEL */
 
+#define MECR_CIT	(1 << 1)	/* Card Is There: 0 -> no card, 1 -> card
inserted */
+
 /*
  * More handy macros for PCMCIA
  *
diff --git a/include/asm-arm/arch-pxa/pxa3xx_nand.h
b/include/asm-arm/arch-pxa/pxa3xx_nand.h
new file mode 100644
index 0000000..81a8937
--- /dev/null
+++ b/include/asm-arm/arch-pxa/pxa3xx_nand.h
@@ -0,0 +1,18 @@
+#ifndef __ASM_ARCH_PXA3XX_NAND_H
+#define __ASM_ARCH_PXA3XX_NAND_H
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+struct pxa3xx_nand_platform_data {
+
+	/* the data flash bus is shared between the Static Memory
+	 * Controller and the Data Flash Controller,  the arbiter
+	 * controls the ownership of the bus
+	 */
+	int	enable_arbiter;
+
+	struct mtd_partition *parts;
+	unsigned int	nr_parts;
+};
+#endif /* __ASM_ARCH_PXA3XX_NAND_H */
diff --git a/include/asm-arm/arch-pxa/zylonite.h
b/include/asm-arm/arch-pxa/zylonite.h
index f58b591..9516f2e 100644
--- a/include/asm-arm/arch-pxa/zylonite.h
+++ b/include/asm-arm/arch-pxa/zylonite.h
@@ -1,5 +1,715 @@
 #ifndef __ASM_ARCH_ZYLONITE_H
 #define __ASM_ARCH_ZYLONITE_H
+#include <asm/arch/mfp.h>
+
+#define MFP_RDY					(MFP_PIN_GPIO0)
+#define MFP_RDY_AF				(MFP_PIN_GPIO0_AF_DF_RDY)
+
+#define MFP_FLASH_NOR_CS_N_GPIO			(MFP_PIN_GPIO1)
+#define MFP_FLASH_NOR_CS_N_GPIO_AF		(MFP_PIN_GPIO1_AF_nCS2)
+
+#define MFP_DEBUG_ETH_CS_N_GPIO			(MFP_PIN_GPIO2)
+#define	MFP_DEBUG_ETH_CS_N_GPIO_AF		(MFP_PIN_GPIO2_AF_nCS3)
+
+#define MFP_MMC_DAT0				(MFP_PIN_GPIO3)
+#define MFP_MMC_DAT0_AF				(MFP_PIN_GPIO3_AF_MM1_DAT0)
+
+#define MFP_MMC_DAT1				(MFP_PIN_GPIO4)
+#define MFP_MMC_DAT1_AF				(MFP_PIN_GPIO4_AF_MM1_DAT1)
+
+#define MFP_MMC_DAT2				(MFP_PIN_GPIO5)
+#define MFP_MMC_DAT2_AF				(MFP_PIN_GPIO5_AF_MM1_DAT2)
+
+#define MFP_MMC_DAT3				(MFP_PIN_GPIO6)
+#define MFP_MMC_DAT3_AF				(MFP_PIN_GPIO6_AF_MM1_DAT3)
+
+#define MFP_MMC_CLK				(MFP_PIN_GPIO7)
+#define MFP_MMC_CLK_AF				(MFP_PIN_GPIO7_AF_MM1_CLK)
+
+#define MFP_MMC_CMD_0				(MFP_PIN_GPIO8)
+#define MFP_MMC_CMD_0_AF			(MFP_PIN_GPIO8_AF_MM1_CMD)
+
+#define MFP_MMC2_DAT0				(MFP_PIN_GPIO9)
+#define MFP_MMC2_DAT0_AF			(MFP_PIN_GPIO9_AF_MM2_DAT0)
+
+#define MFP_MMC2_DAT1				(MFP_PIN_GPIO10)
+#define MFP_MMC2_DAT1_AF			(MFP_PIN_GPIO10_AF_MM2_DAT1)
+
+#define MFP_MMC2_DAT2_CS0			(MFP_PIN_GPIO11)
+#define MFP_MMC2_DAT2_CS0_AF			(MFP_PIN_GPIO11_AF_MM2_DAT2)
+
+#define MFP_MMC2_DAT3_CS1			(MFP_PIN_GPIO12)
+#define MFP_MMC2_DAT3_CS1_AF			(MFP_PIN_GPIO12_AF_MM2_DAT3)
+
+
+#define MFP_MMC2_CLK				(MFP_PIN_GPIO13)
+#define MFP_MMC2_CLK_AF				(MFP_PIN_GPIO13_AF_MM2_CLK)
+
+#define MFP_MMC2_CMD				(MFP_PIN_GPIO14)
+#define MFP_MMC2_CMD_AF				(MFP_PIN_GPIO14_AF_MM2_CMD)
+
+#define MFP_MMC_CMD_1				(MFP_PIN_GPIO15)
+#define MFP_MMC_CMD_1_AF			(MFP_PIN_GPIO15_AF_MM1_CMD)
+
+#define MFP_CIR_ON_PWM				(MFP_PIN_GPIO16)
+#define MFP_CIR_ON_PWM_AF			(MFP_PIN_GPIO16_AF_CIR_OUT)
+
+#define MFP_RSVD_PWM_0				(MFP_PIN_GPIO17)
+#define MFP_RSVD_PWM_0_AF			(MFP_PIN_GPIO17_AF_PWM0_OUT)
+
+#define MFP_RSVD_AC97_SDATA_IN_0		(MFP_PIN_GPIO17)
+#define MFP_RSVD_AC97_SDATA_IN_0_AF
(MFP_PIN_GPIO17_AF_AC97_SDATA_IN_2)
+
+#define MFP_GPIO_EXP_0_N			(MFP_PIN_GPIO18)
+#define MFP_GPIO_EXP_0_N_AF			(MFP_PIN_GPIO18_AF_GPIO_18)
+
+#define MFP_GPIO_EXP_1_N			(MFP_PIN_GPIO19)
+#define MFP_GPIO_EXP_1_N_AF			(MFP_PIN_GPIO19_AF_GPIO_19)
+
+#define MFP_BACKLIGHT_PWM			(MFP_PIN_GPIO20)
+#define MFP_BACKLIGHT_PWM_AF			(MFP_PIN_GPIO20_AF_GPIO_20)
+
+#define MFP_SCL					(MFP_PIN_GPIO21)
+#define MFP_SCL_AF				(MFP_PIN_GPIO21_AF_I2C_SCL)
+
+#define MFP_SDA					(MFP_PIN_GPIO22)
+#define MFP_SDA_AF				(MFP_PIN_GPIO22_AF_I2C_SDA)
+
+#define MFP_AC97_nACRESET			(MFP_PIN_GPIO23)
+#define MFP_AC97_nACRESET_AF			(MFP_PIN_GPIO23_AF_AC97_RESET)
+
+#define MFP_AC97_SYSCLK				(MFP_PIN_GPIO24)
+#define MFP_AC97_SYSCLK_AF			(MFP_PIN_GPIO24_AF_AC97_SYSCLK)
+
+#define MFP_AC97_SDATA_IN_0			(MFP_PIN_GPIO25)
+#define MFP_AC97_SDATA_IN_0_AF			(MFP_PIN_GPIO25_AF_AC97_SDATA_IN_0)
+
+#define MFP_SSP_2_CLK				(MFP_PIN_GPIO25)
+#define MFP_SSP_2_CLK_AF			(MFP_PIN_GPIO25_AF_SSP2_SCLK)
+
+#define MFP_AC97_INT_N_GPIO			(MFP_PIN_GPIO26)
+#define MFP_AC97_INT_N_GPIO_AF			(MFP_PIN_GPIO26_AF_GPIO_26)
+
+#define MFP_SSP_2_FRM				(MFP_PIN_GPIO26)
+#define MFP_SSP_2_FRM_AF			(MFP_PIN_GPIO26_AF_SSP2_FRM)
+
+#define MFP_AC97_SDATA_OUT			(MFP_PIN_GPIO27)
+#define MFP_AC97_SDATA_OUT_AF			(MFP_PIN_GPIO27_AF_AC97_SDATA_OUT)
+
+#define MFP_SSP_2_TXD				(MFP_PIN_GPIO27)
+#define MFP_SSP_2_TXD_AF			(MFP_PIN_GPIO27_AF_SSP2_TXD)
+
+#define MFP_AC97_SYNC				(MFP_PIN_GPIO28)
+#define MFP_AC97_SYNC_AF			(MFP_PIN_GPIO28_AF_AC97_SYNC)
+
+#define MFP_SSP_2_RXD				(MFP_PIN_GPIO28)
+#define MFP_SSP_2_RXD_AF			(MFP_PIN_GPIO28_AF_SSP2_RXD)
+
+#define MFP_AC97_AC97_BITCLK			(MFP_PIN_GPIO29)
+#define MFP_AC97_AC97_BITCLK_AF			(MFP_PIN_GPIO29_AF_AC97_BITCLK)
+
+#define MFP_FFRXD				(MFP_PIN_GPIO30)
+#define MFP_FFRXD_AF				(MFP_PIN_GPIO30_AF_UART1_RXD)
+
+#define MFP_FFTXD				(MFP_PIN_GPIO31)
+#define MFP_FFTXD_AF				(MFP_PIN_GPIO31_AF_UART1_TXD)
+
+#define MFP_FFCTS				(MFP_PIN_GPIO32)
+#define MFP_FFCTS_AF				(MFP_PIN_GPIO32_AF_UART1_CTS)
+
+#define MFP_FFDCD				(MFP_PIN_GPIO33)
+#define MFP_FFDCD_AF				(MFP_PIN_GPIO33_AF_UART1_DCD)
+
+#define MFP_FFDSR				(MFP_PIN_GPIO34)
+#define MFP_FFDSR_AF				(MFP_PIN_GPIO34_AF_UART1_DSR)
+
+#define MFP_FFRI				(MFP_PIN_GPIO35)
+#define MFP_FFRI_AF				(MFP_PIN_GPIO35_AF_UART1_RI)
+
+#define MFP_FFDTR				(MFP_PIN_GPIO36)
+#define MFP_FFDTR_AF				(MFP_PIN_GPIO36_AF_UART1_DTR)
+
+#define MFP_FFRTS				(MFP_PIN_GPIO37)
+#define MFP_FFRTS_AF				(MFP_PIN_GPIO37_AF_UART1_RTS)
+
+#define MFP_U2D_UTM_CLK				(MFP_PIN_GPIO38)
+#define MFP_U2D_UTM_CLK_AF			(MFP_PIN_GPIO38_AF_UTM_CLK)
+
+#define MFP_CIF_DD_0				(MFP_PIN_GPIO39)
+#define MFP_CIF_DD_0_AF				(MFP_PIN_GPIO39_AF_CI_DD_0)
+
+#define MFP_U2D_DATA0				(MFP_PIN_GPIO39)
+#define MFP_U2D_DATA0_AF			(MFP_PIN_GPIO39_AF_UTM_PHYDATA_OUT_0)
+
+#define MFP_CIF_DD_1				(MFP_PIN_GPIO40)
+#define MFP_CIF_DD_1_AF				(MFP_PIN_GPIO40_AF_CI_DD_1)
+
+#define MFP_U2D_DATA1				(MFP_PIN_GPIO40)
+#define MFP_U2D_DATA1_AF			(MFP_PIN_GPIO40_AF_UTM_PHYDATA_OUT_1)
+
+#define MFP_CIF_DD_2				(MFP_PIN_GPIO41)
+#define MFP_CIF_DD_2_AF				(MFP_PIN_GPIO41_AF_CI_DD_2)
+
+#define MFP_U2D_DATA2				(MFP_PIN_GPIO41)
+#define MFP_U2D_DATA2_AF			(MFP_PIN_GPIO41_AF_UTM_PHYDATA_OUT_2)
+
+#define MFP_CIF_DD_3				(MFP_PIN_GPIO42)
+#define MFP_CIF_DD_3_AF				(MFP_PIN_GPIO42_AF_CI_DD_3)
+
+#define MFP_U2D_DATA3				(MFP_PIN_GPIO42)
+#define MFP_U2D_DATA3_AF			(MFP_PIN_GPIO42_AF_UTM_PHYDATA_OUT_3)
+
+#define MFP_CIF_DD_4				(MFP_PIN_GPIO43)
+#define MFP_CIF_DD_4_AF				(MFP_PIN_GPIO43_AF_CI_DD_4)
+
+#define MFP_U2D_DATA4				(MFP_PIN_GPIO43)
+#define MFP_U2D_DATA4_AF			(MFP_PIN_GPIO43_AF_UTM_PHYDATA_OUT_4)
+
+#define MFP_CIF_DD_5				(MFP_PIN_GPIO44)
+#define MFP_CIF_DD_5_AF				(MFP_PIN_GPIO44_AF_CI_DD_5)
+
+#define MFP_U2D_DATA5				(MFP_PIN_GPIO44)
+#define MFP_U2D_DATA5_AF			(MFP_PIN_GPIO44_AF_UTM_PHYDATA_OUT_5)
+
+#define MFP_CIF_DD_6				(MFP_PIN_GPIO45)
+#define MFP_CIF_DD_6_AF				(MFP_PIN_GPIO45_AF_CI_DD_6)
+
+#define MFP_U2D_DATA6				(MFP_PIN_GPIO45)
+#define MFP_U2D_DATA6_AF			(MFP_PIN_GPIO45_AF_UTM_PHYDATA_OUT_6)
+
+#define MFP_CIF_DD_7				(MFP_PIN_GPIO46)
+#define MFP_CIF_DD_7_AF				(MFP_PIN_GPIO46_AF_CI_DD_7)
+
+#define MFP_U2D_DATA7				(MFP_PIN_GPIO46)
+#define MFP_U2D_DATA7_AF			(MFP_PIN_GPIO46_AF_UTM_PHYDATA_OUT_7)
+
+#define MFP_CIF_DD_8				(MFP_PIN_GPIO47)
+#define MFP_CIF_DD_8_AF				(MFP_PIN_GPIO47_AF_CI_DD_8)
+
+#define MFP_U2D_RXACTIVE			(MFP_PIN_GPIO47)
+#define MFP_U2D_RXACTIVE_AF			(MFP_PIN_GPIO47_AF_UTM_RXACTIVE)
+
+#define MFP_CIF_DD_9				(MFP_PIN_GPIO48)
+#define MFP_CIF_DD_9_AF				(MFP_PIN_GPIO48_AF_CI_DD_9)
+
+#define MFP_U2D_RXVALID				(MFP_PIN_GPIO48)
+#define MFP_U2D_RXVALID_AF			(MFP_PIN_GPIO48_AF_UTM_RXVALID)
+
+#define MFP_CIF_MCLK				(MFP_PIN_GPIO49)
+#define MFP_CIF_MCLK_AF				(MFP_PIN_GPIO49_AF_CI_MCLK)
+
+#define MFP_CIF_PCLK				(MFP_PIN_GPIO50)
+#define MFP_CIF_PCLK_AF				(MFP_PIN_GPIO50_AF_CI_PCLK)
+
+#define MFP_U2D_RXERROR				(MFP_PIN_GPIO50)
+#define MFP_U2D_RXERROR_AF			(MFP_PIN_GPIO50_AF_UTM_RXERROR)
+
+#define MFP_CIF_HSYNC				(MFP_PIN_GPIO51)
+#define MFP_CIF_HSYNC_AF			(MFP_PIN_GPIO51_AF_CI_LV)
+
+#define MFP_U2D_OPMODE0				(MFP_PIN_GPIO51)
+#define MFP_U2D_OPMODE0_AF			(MFP_PIN_GPIO51_AF_UTM_OPMODE_PF_0)
+
+#define MFP_CIF_VSYNC				(MFP_PIN_GPIO52)
+#define MFP_CIF_VSYNC_AF			(MFP_PIN_GPIO52_AF_CI_FV)
+
+#define MFP_U2D_TXVALID				(MFP_PIN_GPIO52)
+#define MFP_U2D_TXVALID_AF			(MFP_PIN_GPIO52_AF_TXVALID)
+
+#define MFP_U2D_TXREADY				(MFP_PIN_GPIO53)
+#define MFP_U2D_TXREADY_AF			(MFP_PIN_GPIO53_AF_UTM_TXREADY)
+
+#define MFP_L_DD_0				(MFP_PIN_GPIO54)
+#define MFP_L_DD_0_AF				(MFP_PIN_GPIO54_AF_LCD_LDD_0)
+
+#define MFP_L_LP_DD_0				(MFP_PIN_GPIO54)
+#define MFP_L_LP_DD_0_AF			(MFP_PIN_GPIO54_AF_LCD_LDD_0)
+
+#define MFP_L_DD_1				(MFP_PIN_GPIO55)
+#define MFP_L_DD_1_AF				(MFP_PIN_GPIO55_AF_LCD_LDD_1)
+
+#define MFP_L_LP_DD_1				(MFP_PIN_GPIO55)
+#define MFP_L_LP_DD_1_AF			(MFP_PIN_GPIO55_AF_LCD_LDD_1)
+
+#define MFP_L_DD_2				(MFP_PIN_GPIO56)
+#define MFP_L_DD_2_AF				(MFP_PIN_GPIO56_AF_LCD_LDD_2)
+
+#define MFP_L_LP_DD_2				(MFP_PIN_GPIO56)
+#define MFP_L_LP_DD_2_AF			(MFP_PIN_GPIO56_AF_LCD_LDD_2)
+
+#define MFP_L_DD_3				(MFP_PIN_GPIO57)
+#define MFP_L_DD_3_AF				(MFP_PIN_GPIO57_AF_LCD_LDD_3)
+
+#define MFP_L_LP_DD_3				(MFP_PIN_GPIO57)
+#define MFP_L_LP_DD_3_AF			(MFP_PIN_GPIO57_AF_LCD_LDD_3)
+
+#define MFP_L_DD_4				(MFP_PIN_GPIO58)
+#define MFP_L_DD_4_AF				(MFP_PIN_GPIO58_AF_LCD_LDD_4)
+
+#define MFP_L_LP_DD_4				(MFP_PIN_GPIO58)
+#define MFP_L_LP_DD_4_AF			(MFP_PIN_GPIO58_AF_LCD_LDD_4)
+
+#define MFP_L_DD_5				(MFP_PIN_GPIO59)
+#define MFP_L_DD_5_AF				(MFP_PIN_GPIO59_AF_LCD_LDD_5)
+
+#define MFP_L_LP_DD_5				(MFP_PIN_GPIO59)
+#define MFP_L_LP_DD_5_AF			(MFP_PIN_GPIO59_AF_LCD_LDD_5)
+
+#define MFP_L_DD_6				(MFP_PIN_GPIO60)
+#define MFP_L_DD_6_AF				(MFP_PIN_GPIO60_AF_LCD_LDD_6)
+
+#define MFP_L_LP_DD_6				(MFP_PIN_GPIO60)
+#define MFP_L_LP_DD_6_AF			(MFP_PIN_GPIO60_AF_LCD_LDD_6)
+
+#define MFP_L_DD_7				(MFP_PIN_GPIO61)
+#define MFP_L_DD_7_AF				(MFP_PIN_GPIO61_AF_LCD_LDD_7)
+
+#define MFP_L_LP_DD_7				(MFP_PIN_GPIO61)
+#define MFP_L_LP_DD_7_AF			(MFP_PIN_GPIO61_AF_LCD_LDD_7)
+
+#define MFP_L_DD_8				(MFP_PIN_GPIO62)
+#define MFP_L_DD_8_AF				(MFP_PIN_GPIO62_AF_LCD_LDD_8)
+
+#define MFP_L_LP_DD_8				(MFP_PIN_GPIO62)
+#define MFP_L_LP_DD_8_AF			(MFP_PIN_GPIO62_AF_LCD_LDD_8)
+
+#define MFP_L_DD_9				(MFP_PIN_GPIO63)
+#define MFP_L_DD_9_AF				(MFP_PIN_GPIO63_AF_LCD_LDD_9)
+
+#define MFP_L_LP_DD_9				(MFP_PIN_GPIO63)
+#define MFP_L_LP_DD_9_AF			(MFP_PIN_GPIO63_AF_LCD_LDD_9)
+
+#define MFP_L_DD_10				(MFP_PIN_GPIO64)
+#define MFP_L_DD_10_AF				(MFP_PIN_GPIO64_AF_LCD_LDD_10)
+
+#define MFP_L_LP_DD_10				(MFP_PIN_GPIO64)
+#define MFP_L_LP_DD_10_AF			(MFP_PIN_GPIO64_AF_LCD_LDD_10)
+
+#define MFP_L_DD_11				(MFP_PIN_GPIO65)
+#define MFP_L_DD_11_AF				(MFP_PIN_GPIO65_AF_LCD_LDD_11)
+
+#define MFP_L_LP_DD_11				(MFP_PIN_GPIO65)
+#define MFP_L_LP_DD_11_AF			(MFP_PIN_GPIO65_AF_LCD_LDD_11)
+
+#define MFP_L_DD_12				(MFP_PIN_GPIO66)
+#define MFP_L_DD_12_AF				(MFP_PIN_GPIO66_AF_LCD_LDD_12)
+
+#define MFP_L_LP_DD_12				(MFP_PIN_GPIO66)
+#define MFP_L_LP_DD_12_AF			(MFP_PIN_GPIO66_AF_LCD_LDD_12)
+
+#define MFP_L_DD_13				(MFP_PIN_GPIO67)
+#define MFP_L_DD_13_AF				(MFP_PIN_GPIO67_AF_LCD_LDD_13)
+
+#define MFP_L_LP_DD_13				(MFP_PIN_GPIO67)
+#define MFP_L_LP_DD_13_AF			(MFP_PIN_GPIO67_AF_LCD_LDD_13)
+
+#define MFP_L_DD_14				(MFP_PIN_GPIO68)
+#define MFP_L_DD_14_AF				(MFP_PIN_GPIO68_AF_LCD_LDD_14)
+
+#define MFP_L_LP_DD_14				(MFP_PIN_GPIO68)
+#define MFP_L_LP_DD_14_AF			(MFP_PIN_GPIO68_AF_LCD_LDD_14)
+
+#define MFP_L_DD_15				(MFP_PIN_GPIO69)
+#define MFP_L_DD_15_AF				(MFP_PIN_GPIO69_AF_LCD_LDD_15)
+
+#define MFP_L_LP_DD_15				(MFP_PIN_GPIO69)
+#define MFP_L_LP_DD_15_AF			(MFP_PIN_GPIO69_AF_LCD_LDD_15)
+
+#define MFP_L_DD_16				(MFP_PIN_GPIO70)
+#define MFP_L_DD_16_AF				(MFP_PIN_GPIO70_AF_LCD_LDD_16)
+
+#define MFP_L_LP_DD_16				(MFP_PIN_GPIO70)
+#define MFP_L_LP_DD_16_AF			(MFP_PIN_GPIO70_AF_LCD_LDD_16)
+
+#define MFP_L_DD_17				(MFP_PIN_GPIO71)
+#define MFP_L_DD_17_AF				(MFP_PIN_GPIO71_AF_LCD_LDD_17)
+
+#define MFP_L_LP_DD_17				(MFP_PIN_GPIO71)
+#define MFP_L_LP_DD_17_AF			(MFP_PIN_GPIO71_AF_LCD_LDD_17)
+
+#define MFP_L_FCLK				(MFP_PIN_GPIO72)
+#define MFP_L_FCLK_AF				(MFP_PIN_GPIO72_AF_LCD_L_FCLK)
+
+#define MFP_L_LP_FCLK				(MFP_PIN_GPIO72)
+#define MFP_L_LP_FCLK_AF			(MFP_PIN_GPIO72_AF_LCD_L_FCLK)
+
+#define MFP_L_LCLK				(MFP_PIN_GPIO73)
+#define MFP_L_LCLK_AF				(MFP_PIN_GPIO73_AF_LCD_L_LCLK)
+
+#define MFP_L_LP_LCLK				(MFP_PIN_GPIO73)
+#define MFP_L_LP_LCLK_AF			(MFP_PIN_GPIO73_AF_LCD_L_LCLK)
+
+#define MFP_L_PCLK				(MFP_PIN_GPIO74)
+#define MFP_L_PCLK_AF				(MFP_PIN_GPIO74_AF_LCD_L_PCLK)
+
+#define MFP_L_LP_PCLK				(MFP_PIN_GPIO74)
+#define MFP_L_LP_PCLK_AF			(MFP_PIN_GPIO74_AF_LCD_L_PCLK)
+
+#define MFP_L_BIAS				(MFP_PIN_GPIO75)
+#define MFP_L_BIAS_AF				(MFP_PIN_GPIO75_AF_LCD_L_BIAS)
+
+#define MFP_L_LP_BIAS				(MFP_PIN_GPIO75)
+#define MFP_L_LP_BIAS_AF			(MFP_PIN_GPIO75_AF_LCD_L_BIAS)
+
+#define MFP_L_VSYNC				(MFP_PIN_GPIO76)
+#define MFP_L_VSYNC_AF				(MFP_PIN_GPIO76_AF_LCD_VSYNC)
+
+#define MFP_L_LP_VSYNC				(MFP_PIN_GPIO76)
+#define MFP_L_LP_VSYNC_AF			(MFP_PIN_GPIO76_AF_LCD_VSYNC)
+
+#define MFP_RSVD_MSL1_OB_DAT_0			(MFP_PIN_GPIO77)
+#define MFP_RSVD_MSL1_OB_DAT_0_AF		(MFP_PIN_GPIO77_AF_MSL_OB_DAT0)
+
+#define MFP_RSVD_MSL1_OB_CLK			(MFP_PIN_GPIO78)
+#define MFP_RSVD_MSL1_OB_CLK_AF			(MFP_PIN_GPIO78_AF_MSL_OB_CLK)
+
+#define MFP_RSVD_MSL1_OB_STB			(MFP_PIN_GPIO79)
+#define MFP_RSVD_MSL1_OB_STB_AF			(MFP_PIN_GPIO79_AF_MSL_OB_STB)
+
+#define MFP_RSVD_MSL1_OB_WAIT			(MFP_PIN_GPIO80)
+#define MFP_RSVD_MSL1_OB_WAIT_AF		(MFP_PIN_GPIO80_AF_MSL_OB_WAIT)
+
+#define MFP_RSVD_MSL1_IB_DAT_0			(MFP_PIN_GPIO81)
+#define MFP_RSVD_MSL1_IB_DAT_0_AF		(MFP_PIN_GPIO81_AF_MSL_IB_DAT0)
+
+#define MFP_HOST_WAKEUP_WIFI			(MFP_PIN_GPIO81)
+#define MFP_HOST_WAKEUP_WIFI_AF			(MFP_PIN_GPIO81_AF_GPIO_81)
+
+#define MFP_RSVD_MSL1_IB_CLK			(MFP_PIN_GPIO82)
+#define MFP_RSVD_MSL1_IB_CLK_AF			(MFP_PIN_GPIO82_AF_MSL_IB_CLK)
+
+#define MFP_RSVD_MSL1_IB_STB			(MFP_PIN_GPIO83)
+#define MFP_RSVD_MSL1_IB_STB_AF			(MFP_PIN_GPIO83_AF_MSL_IB_STB)
+
+#define MFP_WIFI_WAKEUP_HOST			(MFP_PIN_GPIO83)
+#define MFP_WIFI_WAKEUP_HOST_AF			(MFP_PIN_GPIO83_AF_UART1_DSR)
+
+#define MFP_RSVD_MSL1_IB_WAIT			(MFP_PIN_GPIO84)
+#define MFP_RSVD_MSL1_IB_WAIT_AF		(MFP_PIN_GPIO84_AF_MSL_IB_WAIT)
+
+#define MFP_RSVD_MSL1_IB_DAT_1			(MFP_PIN_GPIO85)
+#define MFP_RSVD_MSL1_IB_DAT_1_AF		(MFP_PIN_GPIO85_AF_MSL_IB_DAT1)
+
+#define MFP_RSVD_MSL1_IB_DAT_2			(MFP_PIN_GPIO86)
+#define MFP_RSVD_MSL1_IB_DAT_2_AF		(MFP_PIN_GPIO86_AF_MSL_IB_DAT2)
+
+#define MFP_RSVD_MSL1_IB_DAT_3			(MFP_PIN_GPIO87)
+#define MFP_RSVD_MSL1_IB_DAT_3_AF		(MFP_PIN_GPIO87_AF_MSL_IB_DATA3)
+
+#define MFP_RSVD_MSL1_OB_DAT_1			(MFP_PIN_GPIO88)
+#define MFP_RSVD_MSL1_OB_DAT_1_AF		(MFP_PIN_GPIO88_AF_MSL_OB_DAT1)
+
+#define MFP_RSVD_MSL1_OB_DAT_2			(MFP_PIN_GPIO89)
+#define MFP_RSVD_MSL1_OB_DAT_2_AF		(MFP_PIN_GPIO89_AF_MSL_OB_DAT2)
+
+#define MFP_RSVD_MSL1_OB_DAT_3			(MFP_PIN_GPIO90)
+#define MFP_RSVD_MSL1_OB_DAT_3_AF		(MFP_PIN_GPIO90_AF_MSL_OB_DAT3)
+
+#define MFP_SSP_AUDIO_SCLK			(MFP_PIN_GPIO91)
+#define MFP_SSP_AUDIO_SCLK_AF			(MFP_PIN_GPIO91_AF_SSP3_SCLK)
+
+#define MFP_SSP_AUDIO_FRM			(MFP_PIN_GPIO92)
+#define MFP_SSP_AUDIO_FRM_AF			(MFP_PIN_GPIO92_AF_SSP3_FRM)
+
+#define MFP_SSP_AUDIO_TXD			(MFP_PIN_GPIO93)
+#define MFP_SSP_AUDIO_TXD_AF			(MFP_PIN_GPIO93_AF_SSP3_TXD)
+
+#define MFP_SSP_AUDIO_RXD			(MFP_PIN_GPIO94)
+#define MFP_SSP_AUDIO_RXD_AF			(MFP_PIN_GPIO94_AF_SSP3_RXD)
+
+#define MFP_SSP_4_CLK				(MFP_PIN_GPIO95)
+#define MFP_SSP_4_CLK_AF			(MFP_PIN_GPIO95_AF_SSP4_SCLK)
+
+#define MFP_SSP_4_FRM				(MFP_PIN_GPIO96)
+#define MFP_SSP_4_FRM_AF			(MFP_PIN_GPIO96_AF_SSP4_FRM)
+
+#define MFP_SSP_4_TXD				(MFP_PIN_GPIO97)
+#define MFP_SSP_4_TXD_AF			(MFP_PIN_GPIO97_AF_SSP4_TXD)
+
+#define MFP_SSP_4_RXD				(MFP_PIN_GPIO98)
+#define MFP_SSP_4_RXD_AF			(MFP_PIN_GPIO98_AF_SSP4_RXD)
+
+#define MFP_DEBUG_ETH_INT_GPIO			(MFP_PIN_GPIO99)
+#define MFP_DEBUG_ETH_INT_GPIO_AF		(MFP_PIN_GPIO99_AF_GPIO_99)
+
+#define	MFP_U2D_RESET				(MFP_PIN_GPIO100)
+#define	MFP_U2D_RESET_AF			(MFP_PIN_GPIO100_AF_U2D_RESET)
+
+#define MFP_U2D_XCVR_SELECT			(MFP_PIN_GPIO101)
+#define MFP_U2D_XCVR_SELECT_AF
(MFP_PIN_GPIO101_AF_U2D_XCVR_SELECT_PF)
+
+#define MFP_U2D_TERM_SELECT			(MFP_PIN_GPIO102)
+#define MFP_U2D_TERM_SELECT_AF
(MFP_PIN_GPIO102_AF_U2D_TERM_SELECT_PF)
+
+#define MFP_U2D_SUSPENDM_X			(MFP_PIN_GPIO103)
+#define MFP_U2D_SUSPENDM_X_AF			(MFP_PIN_GPIO103_AF_U2D_SUSPENDM_X)
+
+#define MFP_U2D_LINESTATE0			(MFP_PIN_GPIO104)
+#define MFP_U2D_LINESTATE0_AF			(MFP_PIN_GPIO104_AF_UTM_LINESTATE_0)
+
+#define MFP_U2D_LINESTATE1			(MFP_PIN_GPIO105)
+#define MFP_U2D_LINESTATE1_AF			(MFP_PIN_GPIO105_AF_UTM_LINESTATE_1)
+
+#define MFP_OTG_ID				(MFP_PIN_GPIO106)
+#define MFP_OTG_ID_AF				(MFP_PIN_GPIO106_AF_USB_P2_7)
+
+#define MFP_U2D_OPMODE1				(MFP_PIN_GPIO106)
+#define MFP_U2D_OPMODE1_AF			(MFP_PIN_GPIO106_AF_UTM_OPMODE_PF_1)
+
+#define MFP_KP_DKIN_0				(MFP_PIN_GPIO107)
+#define MFP_KP_DKIN_0_AF			(MFP_PIN_GPIO107_AF_KP_DKIN_0)
+
+#define MFP_KP_DKIN_1				(MFP_PIN_GPIO108)
+#define MFP_KP_DKIN_1_AF			(MFP_PIN_GPIO108_AF_KP_DKIN_1)
+
+#define MFP_STD_TXD				(MFP_PIN_GPIO109)
+#define MFP_STD_TXD_AF				(MFP_PIN_GPIO109_AF_UART3_TXD)
+
+#define MFP_STD_RXD				(MFP_PIN_GPIO110)
+#define MFP_STD_RXD_AF				(MFP_PIN_GPIO110_AF_UART3_RXD)
+
+#define MFP_BT_RTS				(MFP_PIN_GPIO111)
+#define MFP_BT_RTS_AF			(MFP_PIN_GPIO111_AF_UART2_RTS)
+
+#define MFP_BT_RXD				(MFP_PIN_GPIO112)
+#define MFP_BT_RXD_AF			(MFP_PIN_GPIO112_AF_UART2_RXD)
+
+#define MFP_BT_TXD				(MFP_PIN_GPIO113)
+#define MFP_BT_TXD_AF			(MFP_PIN_GPIO113_AF_UART2_TXD)
+
+#define MFP_BT_CTS				(MFP_PIN_GPIO114)
+#define MFP_BT_CTS_AF			(MFP_PIN_GPIO114_AF_UART2_CTS)
+
+#define MFP_KP_MKIN_0				(MFP_PIN_GPIO115)
+#define MFP_KP_MKIN_0_AF			(MFP_PIN_GPIO115_AF_KP_MKIN_0)
+
+#define MFP_KP_MKIN_1				(MFP_PIN_GPIO116)
+#define MFP_KP_MKIN_1_AF			(MFP_PIN_GPIO116_AF_KP_MKIN_1)
+
+#define MFP_KP_MKIN_2				(MFP_PIN_GPIO117)
+#define MFP_KP_MKIN_2_AF			(MFP_PIN_GPIO117_AF_KP_MKIN_2)
+
+#define MFP_KP_MKIN_3				(MFP_PIN_GPIO118)
+#define MFP_KP_MKIN_3_AF			(MFP_PIN_GPIO118_AF_KP_MKIN_3)
+
+#define MFP_KP_MKIN_4				(MFP_PIN_GPIO119)
+#define MFP_KP_MKIN_4_AF			(MFP_PIN_GPIO119_AF_KP_MKIN_4)
+
+#define MFP_KP_MKIN_5				(MFP_PIN_GPIO120)
+#define MFP_KP_MKIN_5_AF			(MFP_PIN_GPIO120_AF_KP_MKIN_5)
+
+#define MFP_KP_MKOUT_0				(MFP_PIN_GPIO121)
+#define MFP_KP_MKOUT_0_AF			(MFP_PIN_GPIO121_AF_KP_MKOUT_0)
+
+#define MFP_KP_MKOUT_1				(MFP_PIN_GPIO122)
+#define MFP_KP_MKOUT_1_AF			(MFP_PIN_GPIO122_AF_KP_MKOUT_1)
+
+#define MFP_KP_MKOUT_2				(MFP_PIN_GPIO123)
+#define MFP_KP_MKOUT_2_AF			(MFP_PIN_GPIO123_AF_KP_MKOUT_2)
+
+#define MFP_KP_MKOUT_3				(MFP_PIN_GPIO124)
+#define MFP_KP_MKOUT_3_AF			(MFP_PIN_GPIO124_AF_KP_MKOUT_3)
+
+#define MFP_KP_MKOUT_4				(MFP_PIN_GPIO125)
+#define MFP_KP_MKOUT_4_AF			(MFP_PIN_GPIO125_AF_KP_MKOUT_4)
+
+#define MFP_CAMERA_STROBE_EN_GPIO		(MFP_PIN_GPIO126)
+#define MFP_CAMERA_STROBE_EN_GPIO_AF		(MFP_PIN_GPIO126_AF_GPIO_126)
+
+#define MFP_L_CS				(MFP_PIN_GPIO127)
+#define MFP_L_CS_AF				(MFP_PIN_GPIO127_AF_LCD_nCS)
+
+#define MFP_USBHPEN				(MFP_PIN_GPIO0_2)
+#define MFP_USBHPEN_AF				(MFP_PIN_GPIO0_2_AF_UHC_USBHPEN_MVT)
+
+#define MFP_USBHPWR				(MFP_PIN_GPIO1_2)
+#define MFP_USBHPWR_AF				(MFP_PIN_GPIO1_2_AF_UHC_USBHPWR_MVT)
+
+#define MFP_KP_MKIN_6				(MFP_PIN_GPIO2_2)
+#define MFP_KP_MKIN_6_AF			(MFP_PIN_GPIO2_2_AF_KP_MKIN_6)
+
+#define MFP_KP_MKIN_7				(MFP_PIN_GPIO3_2)
+#define MFP_KP_MKIN_7_AF			(MFP_PIN_GPIO3_2_AF_KP_MKIN_7)
+
+#define MFP_KP_MKOUT_5				(MFP_PIN_GPIO4_2)
+#define MFP_KP_MKOUT_5_AF			(MFP_PIN_GPIO4_2_AF_KP_MK0UT_5)
+
+#define MFP_KP_MKOUT_6				(MFP_PIN_GPIO5_2)
+#define MFP_KP_MKOUT_6_AF			(MFP_PIN_GPIO5_2_AF_KP_MKOUT_6)
+
+#define MFP_KP_MKOUT_7				(MFP_PIN_GPIO6_2)
+#define MFP_KP_MKOUT_7_AF			(MFP_PIN_GPIO6_2_AF_MK_MKOUT_7)
+
+#define MFP_MMC_CD_0_GPIO			(MFP_PIN_GPIO128)
+#define MFP_MMC_CD_0_GPIO_AF			(MFP_PIN_GPIO128_GPIO_128)
+
+#define MFP_MMC_CD_1_GPIO			(MFP_PIN_GPIO129)
+#define MFP_MMC_CD_1_GPIO_AF			(MFP_PIN_GPIO129_GPIO_129)
+
+#define MFP_MMC_WP_0_N_GPIO			(MFP_PIN_GPIO130)
+#define MFP_MMC_WP_0_N_GPIO_AF			(MFP_PIN_GPIO130_GPIO_130)
+
+#define MFP_MMC_WP_1_N_GPIO			(MFP_PIN_GPIO131)
+#define MFP_MMC_WP_1_N_GPIO_AF			(MFP_PIN_GPIO131_GPIO_131)
+
+#define MFP_PHONE_FLIPPED_GPIO			(MFP_PIN_GPIO132)
+#define MFP_PHONE_FLIPPED_GPIO_AF		(MFP_PIN_GPIO132_GPIO_132)
+
+#define MFP_PHONE_CLOSED_GPIO			(MFP_PIN_GPIO133)
+#define MFP_PHONE_CLOSED_GPIO_AF		(MFP_PIN_GPIO133_GPIO_133)
+
+#define MFP_USB2_DETECT				(MFP_PIN_GPIO134)
+#define MFP_USB2_DETECT_AF			(MFP_PIN_GPIO134_GPIO_134)
+
+#define MFP_CFCD_GPIO				(MFP_PIN_GPIO135)
+#define MFP_CFCD_GPIO_AF			(MFP_PIN_GPIO135_GPIO_135)
+
+#define MFP_CAMERA_LIGHT_EN_GPIO		(MFP_PIN_GPIO136)
+#define MFP_CAMERA_LIGHT_EN_GPIO_AF		(MFP_PIN_GPIO136_GPIO_136)
+
+#define MFP_IR_SHDN_N_GPIO			(MFP_PIN_GPIO137)
+#define MFP_IR_SHDN_N_GPIO_AF			(MFP_PIN_GPIO137_GPIO_137)
+
+#define MFP_CIF_HI_PWDN_GPIO			(MFP_PIN_GPIO138)
+#define MFP_CIF_HI_PWDN_GPIO_AF			(MFP_PIN_GPIO138_GPIO_138)
+
+#define MFP_CIF_LO_PWDN_GPIO			(MFP_PIN_GPIO139)
+#define MFP_CIF_LO_PWDN_GPIO_AF			(MFP_PIN_GPIO139_GPIO_139)
+
+#define	MFP_UTMI_TEST_EN			(MFP_PIN_GPIO140)
+#define	MFP_UTMI_TEST_EN_AF			(MFP_PIN_GPIO140_GPIO_140)
+
+#define	MFP_UTMI_SWITCH				(MFP_PIN_GPIO141)
+#define	MFP_UTMI_SWITCH_AF			(MFP_PIN_GPIO141_GPIO_141)
+
+#define	MFP_OTG_EN				(MFP_PIN_GPIO142)
+#define	MFP_OTG_EN_AF				(MFP_PIN_GPIO142_GPIO_142)
+
+#define	MFP_USB_OTG_SR				(MFP_PIN_GPIO143)
+#define	MFP_USB_OTG_SR_AF			(MFP_PIN_GPIO143_GPIO_143)
+
+#define MFP_MWB_BT_CLK_EN_N			(MFP_PIN_GPIO166)
+#define MFP_MWB_BT_CLK_EN_N_AF			(MFP_PIN_GPIO166_GPIO_166)
+
+#define MFP_MWB_BT_RESET			(MFP_PIN_GPIO167)
+#define MFP_MWB_BT_RESET_AF			(MFP_PIN_GPIO167_GPIO_167)
+
+#define MFP_MWB_WL_RESET			(MFP_PIN_GPIO169)
+#define MFP_MWB_WL_RESET_AF			(MFP_PIN_GPIO169_GPIO_169)
+
+#define MFP_ND_CLE				(MFP_PIN_CLE_nOE)
+#define MFP_ND_CLE_AF				(MFP_PIN_DF_CLE_AF_ND_CLE)
+
+#define MFP_DF_ALE				(MFP_PIN_DF_ALE_nWE)
+#define MFP_DF_ALE_AF				(MFP_PIN_DF_ALE_nWE1_AF_ND_ALE)
+
+#define MFP_DF_NCS1				(MFP_PIN_DF_nCS1)
+#define MFP_DF_NCS1_AF				(MFP_PIN_DF_nCS1_AF_DF_nCS1)
+
+#define MFP_DF_SCLK_E				(MFP_PIN_DF_SCLK_E)
+#define MFP_DF_SCLK_E_AF			(MFP_PIN_DF_SCLK_E_AF_DF_SCLK_E)
+
+#define MFP_DF_SCLK_S				(MFP_PIN_DF_SCLK_S)
+#define MFP_DF_SCLK_S_AF			(MFP_PIN_DF_SCLK_S_AF_DF_SCLK_S)
+
+#define MFP_DEBUG_ETH_nBE0			(MFP_PIN_nBE0)
+#define MFP_DEBUG_ETH_nBE0_AF			(MFP_PIN_nBE0_AF_DF_nBE0)
+
+#define MFP_DEBUG_ETH_nBE1			(MFP_PIN_nBE1)
+#define MFP_DEBUG_ETH_nBE1_AF			(MFP_PIN_nBE1_AF_DF_nBE1)
+
+#define MFP_DF_INT_RnB				(MFP_PIN_DF_INT_RnB)
+#define MFP_DF_INT_RnB_AF			(MFP_PIN_DF_INT_RnB_AF_INT_RnB)
+
+#define MFP_nLLA				(MFP_PIN_nLLA)
+#define MFP_nLLA_AF				(MFP_PIN_DF_nLLA_AF_DF_nLLA)
+
+#define MFP_nLUA				(MFP_PIN_nLUA)
+#define MFP_nLUA_AF				(MFP_PIN_DF_nLUA_AF_DF_nLUA)
+
+#define MFP_DF_nWE				(MFP_PIN_DF_nWE)
+#define MFP_DF_nWE_AF				(MFP_PIN_DF_nWE_AF_ND_WE)
+
+#define MFP_DF_nOE				(MFP_PIN_DF_nRE_nOE)
+#define MFP_DF_nOE_AF				(MFP_PIN_DF_nRE_AF_CD_OE)
+
+#define MFP_DF_nRE				(MFP_PIN_DF_nRE)
+#define MFP_DF_nRE_AF				(MFP_PIN_DF_nRE_AF_ND_RE)
+
+#define MFP_RSVD_DF_ADDR0			(MFP_PIN_DF_ADDR0)
+#define MFP_RSVD_DF_ADDR0_AF			(MFP_PIN_DF_ADDR0_AF_DF_ADDR0)
+
+#define MFP_RSVD_DF_ADDR1			(MFP_PIN_DF_ADDR1)
+#define MFP_RSVD_DF_ADDR1_AF			(MFP_PIN_DF_ADDR1_AF_DF_ADDR1)
+
+#define MFP_RSVD_DF_ADDR2			(MFP_PIN_DF_ADDR2)
+#define MFP_RSVD_DF_ADDR2_AF			(MFP_PIN_DF_ADDR2_AF_DF_ADDR2)
+
+#define MFP_RSVD_DF_ADDR3			(MFP_PIN_DF_ADDR3)
+#define MFP_RSVD_DF_ADDR3_AF			(MFP_PIN_DF_ADDR3_AF_DF_ADDR3)
+
+#define MFP_DF_IO_0				(MFP_PIN_DF_IO0)
+#define MFP_DF_IO_0_AF				(MFP_PIN_DF_IO_0_AF_ND)
+
+#define MFP_DF_IO_1				(MFP_PIN_DF_IO1)
+#define MFP_DF_IO_1_AF				(MFP_PIN_DF_IO_1_AF_ND)
+
+#define MFP_DF_IO_2				(MFP_PIN_DF_IO2)
+#define MFP_DF_IO_2_AF				(MFP_PIN_DF_IO_2_AF_ND)
+
+#define MFP_DF_IO_3				(MFP_PIN_DF_IO3)
+#define MFP_DF_IO_3_AF				(MFP_PIN_DF_IO_3_AF_ND)
+
+#define MFP_DF_IO_4				(MFP_PIN_DF_IO4)
+#define MFP_DF_IO_4_AF				(MFP_PIN_DF_IO_4_AF_ND)
+
+#define MFP_DF_IO_5				(MFP_PIN_DF_IO5)
+#define MFP_DF_IO_5_AF				(MFP_PIN_DF_IO_5_AF_ND)
+
+#define MFP_DF_IO_6				(MFP_PIN_DF_IO6)
+#define MFP_DF_IO_6_AF				(MFP_PIN_DF_IO_6_AF_ND)
+
+#define MFP_DF_IO_7				(MFP_PIN_DF_IO7)
+#define MFP_DF_IO_7_AF				(MFP_PIN_DF_IO_7_AF_ND)
+
+#define MFP_DF_IO_8				(MFP_PIN_DF_IO8)
+#define MFP_DF_IO_8_AF				(MFP_PIN_DF_IO_8_AF_ND)
+
+#define MFP_DF_IO_9				(MFP_PIN_DF_IO9)
+#define MFP_DF_IO_9_AF				(MFP_PIN_DF_IO_9_AF_ND)
+
+#define MFP_DF_IO_10				(MFP_PIN_DF_IO10)
+#define MFP_DF_IO_10_AF				(MFP_PIN_DF_IO_10_AF_ND)
+
+#define MFP_DF_IO_11				(MFP_PIN_DF_IO11)
+#define MFP_DF_IO_11_AF				(MFP_PIN_DF_IO_11_AF_ND)
+
+#define MFP_DF_IO_12				(MFP_PIN_DF_IO12)
+#define MFP_DF_IO_12_AF				(MFP_PIN_DF_IO_12_AF_ND)
+
+#define MFP_DF_IO_13				(MFP_PIN_DF_IO13)
+#define MFP_DF_IO_13_AF				(MFP_PIN_DF_IO_13_AF_ND)
+
+#define MFP_DF_IO_14				(MFP_PIN_DF_IO14)
+#define MFP_DF_IO_14_AF				(MFP_PIN_DF_IO_14_AF_ND)
+
+#define MFP_DF_IO_15				(MFP_PIN_DF_IO15)
+#define MFP_DF_IO_15_AF				(MFP_PIN_DF_IO_15_AF_ND)
+
+#define MFP_DF_nADV1				(MFP_PIN_DF_ALE_nWE)
+#define MFP_DF_nADV1_AF				(MFP_PIN_DF_ALE_nWE1_AF_ND_ALE)
+
+#define MFP_DF_NCS0				(MFP_PIN_DF_nCS0)
+#define MFP_DF_NCS0_AF				(MFP_PIN_DF_nCS0_AF_ND_nCS0)
+
+#define MFP_RSVD_DF_NCS1			(MFP_PIN_DF_nCS1)
+#define MFP_RSVD_DF_NCS1_AF			(MFP_PIN_DF_nCS1_AF_ND_nCS1)
+
+#define MFP_SIR_TXD				(MFP_STD_TXD)
+#define MFP_SIR_TXD_AF				(MFP_STD_TXD_AF)
+
+#define MFP_SIR_RXD				(MFP_STD_RXD)
+#define MFP_SIR_RXD_AF				(MFP_STD_RXD_AF)
 
 #define ZYLONITE_ETH_PHYS	0x14000000
 
-- 
1.5.3.7





From naveen_j_s at yahoo.com  Mon Jan 14 02:32:47 2008
From: naveen_j_s at yahoo.com (Naveen Sattigeri)
Date: Sun, 13 Jan 2008 23:32:47 -0800 (PST)
Subject: No subject
Message-ID: <660898.91474.qm@web32812.mail.mud.yahoo.com>

Hi,
I am using Linux kernel 2.4.20-8 as host.For the
target compact nand flash I am using 2.6.10 kernel.I
want the target flash detected as MTD for mounting
JFFS2 file system on it.
Please correct if I am wrong.The kernel 2.6.10 should
be patched for latest NAND mtd drivers.
I have tried the latest patch 2008-January.txt but it
was not successful because probably the patch is for
latest kernel.
Can I get the patch for 2.6.20?
What else I should do to detect the compact flash as
MTD device using a host or using NFS.

Thanking you,



      ____________________________________________________________________________________
Looking for last minute shopping deals?  
Find them fast with Yahoo! Search.  http://tools.search.yahoo.com/newsearch/category.php?category=shopping


From abelyako at googlemail.com  Mon Jan 14 05:23:45 2008
From: abelyako at googlemail.com (Alexander Belyakov)
Date: Mon, 14 Jan 2008 13:23:45 +0300
Subject: [PATCH][JFFS2] Fix garbage collector block search
In-Reply-To: <E1J2Trs-000IFE-00.abelyako-mail-ru@f65.mail.ru>
References: <E1J2Trs-000IFE-00.abelyako-mail-ru@f65.mail.ru>
Message-ID: <fe810cf0801140223yb3a4deehde5b282710619915@mail.gmail.com>

On Dec 12, 2007 6:51 PM, Alexander Belyakov <abelyako at mail.ru> wrote:
> Hello,
>
> The patch checks if erasable_list is empty in jffs2_refile_wbuf_blocks() moving at least one block to that list. So jffs2_find_gc_block() will not fail sometimes with "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?" message.
>
> Signed-off-by: Alexander Belyakov <alexander.belyakov at intel.com>
>
> diff -uNr a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
> --- a/fs/jffs2/wbuf.c   2007-12-03 17:00:16.000000000 +0300
> +++ b/fs/jffs2/wbuf.c   2007-12-11 19:03:03.000000000 +0300
> @@ -115,7 +115,7 @@
>
>                 D1(printk(KERN_DEBUG "Removing eraseblock at 0x%08x from erasable_pending_wbuf_list...\n", jeb->offset));
>                 list_del(this);
> -               if ((jiffies + (n++)) & 127) {
> +               if (((jiffies + (n++)) & 127) && !list_empty(&c->erasable_list)) {
>                         /* Most of the time, we just erase it immediately. Otherwise we
>                            spend ages scanning it on mount, etc. */
>                         D1(printk(KERN_DEBUG "...and adding to erase_pending_list\n"));
>
>

Hello, David.

I've sent this jffs2 fix about month ago. Have you received applicable
patch? It should be applicable -- I've sent it to myself and checked
it before sending out.

Have you any comments on this patch?

Thanks,
Alexander


From yur at emcraft.com  Mon Jan 14 07:57:18 2008
From: yur at emcraft.com (Yuri Tikhonov)
Date: Mon, 14 Jan 2008 15:57:18 +0300
Subject: Block Device Emulation over UBI
Message-ID: <200801141557.18349.yur@emcraft.com>


 Hello all,

 We are about to implement and then maintain a block device driver which is 
intended to work on the top of UBI and provide users with the block-device 
interface to the underlying Flash chips. The goal of this driver is to 
provide users with the possibility to easily organize reliable file storage 
in Flash memory chips (especially NAND Flash) using Flash-unaware 
file-systems like FAT, EXT2/3, etc (UBI is supposed to provide the necessary 
reliability using its features of wear-leveling and bad blocks handling).

 In many cases the ability to have the file-system formatted with, for 
example, FAT is a highly desirable feature of the embedded devices (e.g. for 
exporting the embedded storage via USB link to a Windows-based USB host), so 
we guess our work will be usefull for the embedded world.

 Any suggestions or comments as to possible issues we may run into on this 
road would be very appreciated.

 Regards, Yuri

-- 
Yuri Tikhonov, Senior Software Engineer
Emcraft Systems, www.emcraft.com


From joern at logfs.org  Mon Jan 14 08:28:43 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Mon, 14 Jan 2008 14:28:43 +0100
Subject: [PATCH][JFFS2] Fix garbage collector block search
In-Reply-To: <E1J2Trs-000IFE-00.abelyako-mail-ru@f65.mail.ru>
References: <E1J2Trs-000IFE-00.abelyako-mail-ru@f65.mail.ru>
Message-ID: <20080114132843.GA15710@lazybastard.org>

On Wed, 12 December 2007 18:51:28 +0300, Alexander Belyakov wrote:
> 
> The patch checks if erasable_list is empty in jffs2_refile_wbuf_blocks() moving at least one block to that list. So jffs2_find_gc_block() will not fail sometimes with "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?" message.

If the erasable_list is empty, we push it to the list for someone else
to erase it later instead of doing it now?  Nonsense.

If it makes a difference whether the block is erasable or erase_pending,
we have a bug.  And that bug wants a fix, not a paper bandaid.

> Signed-off-by: Alexander Belyakov <alexander.belyakov at intel.com>
> 
> diff -uNr a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
> --- a/fs/jffs2/wbuf.c	2007-12-03 17:00:16.000000000 +0300
> +++ b/fs/jffs2/wbuf.c	2007-12-11 19:03:03.000000000 +0300
> @@ -115,7 +115,7 @@
>  
>  		D1(printk(KERN_DEBUG "Removing eraseblock at 0x%08x from erasable_pending_wbuf_list...\n", jeb->offset));
>  		list_del(this);
> -		if ((jiffies + (n++)) & 127) {
> +		if (((jiffies + (n++)) & 127) && !list_empty(&c->erasable_list)) {
>  			/* Most of the time, we just erase it immediately. Otherwise we
>  			   spend ages scanning it on mount, etc. */
>  			D1(printk(KERN_DEBUG "...and adding to erase_pending_list\n"));
> 
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
> 

J?rn

-- 
Joern's library part 14:
http://www.sandpile.org/


From jwboyer at gmail.com  Mon Jan 14 08:00:49 2008
From: jwboyer at gmail.com (Josh Boyer)
Date: Mon, 14 Jan 2008 07:00:49 -0600
Subject: 
In-Reply-To: <660898.91474.qm@web32812.mail.mud.yahoo.com>
References: <660898.91474.qm@web32812.mail.mud.yahoo.com>
Message-ID: <20080114070049.12f34137@vader.jdub.homelinux.org>

On Sun, 13 Jan 2008 23:32:47 -0800 (PST)
Naveen Sattigeri <naveen_j_s at yahoo.com> wrote:

> Please correct if I am wrong.The kernel 2.6.10 should
> be patched for latest NAND mtd drivers.
> I have tried the latest patch 2008-January.txt but it
> was not successful because probably the patch is for
> latest kernel.
> Can I get the patch for 2.6.20?

http://linux-mtd.infradead.org/source.html#kernelversions

> What else I should do to detect the compact flash as
> MTD device using a host or using NFS.

You can't.  Compact flash is not real flash, nor does it have an
interface to present the real flash.

http://linux-mtd.infradead.org/faq/jffs2.html#L_stick_jffs2

josh


From vinit.agnihotri at gmail.com  Mon Jan 14 14:46:47 2008
From: vinit.agnihotri at gmail.com (Vinit Agnihotri)
Date: Mon, 14 Jan 2008 11:46:47 -0800
Subject: Block Device Emulation over UBI
In-Reply-To: <200801141557.18349.yur@emcraft.com>
References: <200801141557.18349.yur@emcraft.com>
Message-ID: <9b52d64c0801141146g3b076f74pe2e06b06832219aa@mail.gmail.com>

Few months back I raised same question here &
I got nice replies from Artem.I am not able to found that discussion in my
mail box though :( & even not able to recall much of it.
However Artem said writing block device driver on top of UBI volume is same as
implementing FTL on it, basically its re-inventing the wheel. Probably Artem
can answer you well :-).

--Vinit.


On Jan 14, 2008 4:57 AM, Yuri Tikhonov <yur at emcraft.com> wrote:
>
>  Hello all,
>
>  We are about to implement and then maintain a block device driver which is
> intended to work on the top of UBI and provide users with the block-device
> interface to the underlying Flash chips. The goal of this driver is to
> provide users with the possibility to easily organize reliable file storage
> in Flash memory chips (especially NAND Flash) using Flash-unaware
> file-systems like FAT, EXT2/3, etc (UBI is supposed to provide the necessary
> reliability using its features of wear-leveling and bad blocks handling).
>
>  In many cases the ability to have the file-system formatted with, for
> example, FAT is a highly desirable feature of the embedded devices (e.g. for
> exporting the embedded storage via USB link to a Windows-based USB host), so
> we guess our work will be usefull for the embedded world.
>
>  Any suggestions or comments as to possible issues we may run into on this
> road would be very appreciated.
>
>  Regards, Yuri
>
> --
> Yuri Tikhonov, Senior Software Engineer
> Emcraft Systems, www.emcraft.com
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>



-- 
Life is so short. So, follow some rules. Forgive quickly, believe
slowly, love truly, laugh loudly & never avoid anything that makes U
smile.


From 12o3l at tiscali.nl  Mon Jan 14 19:28:12 2008
From: 12o3l at tiscali.nl (Roel Kluin)
Date: Tue, 15 Jan 2008 01:28:12 +0100
Subject: [MTD] potential division by 0 in cfi_build_cmd() and
	cfi_merge_status()?
Message-ID: <478BFE1C.1090608@tiscali.nl>

Doing some grepping, I stumbled upon this possible error:

in include/linux/mtd/cfi.h, lines 302 and 366, resp. functions
cfi_build_cmd() and cfi_merge_status() there is a division by
cfi_interleave(cfi):

chip_mode = map_bankwidth(map) / cfi_interleave(cfi);

This could be problematic when No CONFIG_MTD_CFI_Ix is selected:
cfi_interleave will triggers BUG(), but when BUG is disabled, the
function returns 0, causing a subsequent division by zero.

When a CONFIG_MTD_CFI_Ix is selected, cfi_interleave(cfi) is either
defined 1 or defined (cfi)->interleave.

cfi is a struct cfi_private pointer, with interleave as an int.

I am not sure whether interleave can ever be 0 in this division when 
CONFIG_MTD_CFI_Ix is set.

shouldn't there be an error exit when cfi_interleave(cfi) evaluates
to 0?

I am not subscribed to this list, so please CC.

Roel


From joern at logfs.org  Mon Jan 14 22:01:03 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Tue, 15 Jan 2008 04:01:03 +0100
Subject: [MTD] potential division by 0 in cfi_build_cmd() and
	cfi_merge_status()?
In-Reply-To: <478BFE1C.1090608@tiscali.nl>
References: <478BFE1C.1090608@tiscali.nl>
Message-ID: <20080115030103.GA19407@lazybastard.org>

On Tue, 15 January 2008 01:28:12 +0100, Roel Kluin wrote:
> 
> Doing some grepping, I stumbled upon this possible error:
> 
> in include/linux/mtd/cfi.h, lines 302 and 366, resp. functions
> cfi_build_cmd() and cfi_merge_status() there is a division by
> cfi_interleave(cfi):
> 
> chip_mode = map_bankwidth(map) / cfi_interleave(cfi);
> 
> This could be problematic when No CONFIG_MTD_CFI_Ix is selected:
> cfi_interleave will triggers BUG(), but when BUG is disabled, the
> function returns 0, causing a subsequent division by zero.
> 
> When a CONFIG_MTD_CFI_Ix is selected, cfi_interleave(cfi) is either
> defined 1 or defined (cfi)->interleave.
> 
> cfi is a struct cfi_private pointer, with interleave as an int.
> 
> I am not sure whether interleave can ever be 0 in this division when 
> CONFIG_MTD_CFI_Ix is set.
> 
> shouldn't there be an error exit when cfi_interleave(cfi) evaluates
> to 0?

I don't think cfi_interleave(cfi) will ever be 0.  But the functions
definitely look a bit large for inlines.  Anyone having both cfi_probe
and jedec_probe will enjoy twice the kernel footprint from them.
Patches to move that code out-of-line are welcome.

J?rn

-- 
Fools ignore complexity.  Pragmatists suffer it.
Some can avoid it.  Geniuses remove it.
-- Perlis's Programming Proverb #58, SIGPLAN Notices, Sept.  1982


From joern at logfs.org  Mon Jan 14 23:10:32 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Tue, 15 Jan 2008 05:10:32 +0100
Subject: [MTD] potential division by 0 in cfi_build_cmd() and
	cfi_merge_status()?
In-Reply-To: <alpine.LFD.1.00.0801142302410.3054@xanadu.home>
References: <478BFE1C.1090608@tiscali.nl>
	<20080115030103.GA19407@lazybastard.org>
	<alpine.LFD.1.00.0801142302410.3054@xanadu.home>
Message-ID: <20080115041025.GB19407@lazybastard.org>

On Mon, 14 January 2008 23:06:13 -0500, Nicolas Pitre wrote:
> On Tue, 15 Jan 2008, J?rn Engel wrote:
> 
> > I don't think cfi_interleave(cfi) will ever be 0.  But the functions
> > definitely look a bit large for inlines.  Anyone having both cfi_probe
> > and jedec_probe will enjoy twice the kernel footprint from them.
> > Patches to move that code out-of-line are welcome.
> 
> Beware.
> 
> The typical use case is for your embedded system to be configured with 
> your flash arrangement and not all possible combinations available under 
> the sun.
> 
> In that case it is most likely that cfi_interleave(cfi) will simplify to 
> a constant, and making this out of line _will_ enlarge your kernel, as 
> well as possibly breaking interaction with a XIP kernel on ARM.
> 
> So please don't push this out of line.

Fair enough.

J?rn

-- 
Joern's library part 13:
http://www.chip-architect.com/


From dedekind at infradead.org  Tue Jan 15 03:08:30 2008
From: dedekind at infradead.org (Artem Bityutskiy)
Date: Tue, 15 Jan 2008 10:08:30 +0200
Subject: why ubimkvol can't recognize /dev/ubi0?
In-Reply-To: <4781D985.6020504@nokia.com>
References: <399646872.11492@ustc.edu.cn>  <4781D985.6020504@nokia.com>
Message-ID: <1200384510.3956.27.camel@sauron>

On Mon, 2008-01-07 at 09:49 +0200, Adrian Hunter wrote:
> From b96f4481662bd7ac247d4d5a25b27f7d8afffb92 Mon Sep 17 00:00:00 2001
> From: Adrian Hunter <ext-adrian.hunter at nokia.com>
> Date: Mon, 7 Jan 2008 09:47:17 +0200
> Subject: ubi-utils: fix bug using readdir
> 
> Library functions never reset errno to zero, so if you want
> to use its value to check for errors then you must set it to zero
> before calling the library function (in this case readdir).
> 
> Signed-off-by: Adrian Hunter <ext-adrian.hunter at nokia.com>

Thanks, committed.

-- 
Best regards,
Artem Bityutskiy (???????? ?????)



From akorolev at infradead.org  Fri Jan 11 05:50:03 2008
From: akorolev at infradead.org (Alexey Korolev)
Date: Fri, 11 Jan 2008 10:50:03 +0000 (GMT)
Subject: [PATCH][CFI] Wrong cache invalidation bug fix
In-Reply-To: <62cbdcd90712050758h36335aa5q176f1c192f18d6a9@mail.gmail.com>
References: <62cbdcd90712030834o28f9126fs841b3b9d46324fb7@mail.gmail.com>
	<alpine.LFD.0.99999.0712031210180.9605@xanadu.home>
	<62cbdcd90712050758h36335aa5q176f1c192f18d6a9@mail.gmail.com>
Message-ID: <Pine.LNX.4.64.0801111042510.20196@pentafluge.infradead.org>

Hi David,

Please include patch from Massimo? It fixes bad dug in CFI driver.

Thanks,
Alexey







Signed-off-by Massimo Cirillo <maxcir at gmail.com> and Giuseppe D'Eliseo
<giuseppedeliseo at gmail.com>
Acked-by: Nicolas Pitre <nico at cam.org> and J?rn Engel <joern at logfs.org>

------
diff -aur a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
--- a/drivers/mtd/chips/cfi_cmdset_0001.c       2007-12-05 10:45:20.000000000 +0100
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c       2007-11-16 19:14:27.000000000 +0100
@@ -1486,9 +1486,12 @@
       int ret, wbufsize, word_gap, words;
       const struct kvec *vec;
       unsigned long vec_seek;
+       unsigned long initial_adr;
+       int initial_len=len;

       wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
       adr += chip->start;
+       initial_adr = adr;
       cmd_adr = adr & ~(wbufsize-1);

       /* Let's determine this according to the interleave only once */
@@ -1501,7 +1504,7 @@
               return ret;
       }

-       XIP_INVAL_CACHED_RANGE(map, adr, len);
+       XIP_INVAL_CACHED_RANGE(map, initial_adr, initial_len);
       ENABLE_VPP(map);
       xip_disable(map, chip, cmd_adr);

@@ -1592,7 +1595,7 @@
       chip->state = FL_WRITING;

       ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr,
-                                  adr, len,
+                                  initial_adr, initial_len,
                                  chip->buffer_write_time);
       if (ret) {
               map_write(map, CMD(0x70), cmd_adr);
---------------

From haver at vnet.ibm.com  Thu Jan  3 07:51:39 2008
From: haver at vnet.ibm.com (Frank Haverkamp)
Date: Thu, 03 Jan 2008 13:51:39 +0100
Subject: [PATCH 4/5] UBI: introduce attach ioctls
In-Reply-To: <1198075329.18962.70.camel@sauron>
References: <20071219154137.23264.28116.sendpatchset@golum>
	<20071219154158.23264.95037.sendpatchset@golum>
	<200712191517.18166.arnd@arndb.de> <1198075329.18962.70.camel@sauron>
Message-ID: <1199364699.7726.34.camel@august>

Hi Arnd and Artem,

On Wed, 2007-12-19 at 16:42 +0200, Artem Bityutskiy wrote:
> On Wed, 2007-12-19 at 15:17 +0100, Arnd Bergmann wrote:
> > > +struct ubi_attach_req {
> > > +       int32_t vid_hdr_offset;
> > > +       int32_t data_offset;
> > >  };
> > 
> > Can you explain why you need to pass vid_hdr_offset /and/ data_offset here?
> > What is the difference between the two?

Data in flash:
EC-hdr | VID-hdr | Data
-------> VID-hdr-offs
-----------------> Data-offset

>  Can't you autoprobe them if you
> > have the device?
> 
> vid_hdr_offset is the offset of the VID header withing an eraseblock.
> data_offs is where the data starts. We want to be able to let users
> select the VID header offset.

> Vs data offset - indeed it is redundant
> and might be dropped because UBI may just assume data starts at the next
> min. I/O unit after the VID header.

Traditionally NAND could only be written only in page-chunks e.g. 2KiB.
Thomas Gleixner introduced that subpages could be written too e.g. 512B.

In our usage example we decided, that we wanted to have the EC-hdr at
offset 0, and the VID-hdr at the end of the last subpage of page 0 in
the NAND-erase block. We wanted the data to start at a page boundary so
that e.g. JFFS2 can use the pagesize as minimum write size and not the
sub-pagesize.

Our layout:
page 0                  | page 1                   | ...
subpage | ... | subpage | subpage | ...  | subpage | ...
EC-hdr  | ... | VID-hdr | Data

Default layout (Artem, correct me if I am wrong):
page 0                          | page 1                   | ...
subpage | ...     | subpage ... | subpage | ...  | subpage | ...
EC-hdr  | VID-hdr | Data

> We can autoprobe the VID header offset, unless the MTD device is empty,
> in which case UBI automatically formats it.

I do not like auto-probing the VID hdr offset. In my eyes the user
should have the flexibility to define where his VID-hdr and data start
e.g. like in our case to have influence on if data is starting on
subpage- or page-boundaries. I also think that the autoprobe feature
would add more complexity to the code.

> > The reason I'm asking is that I'd really like to make this a simple
> > attribute in sysfs, in the mtd object. The question there is what a
> > user would need to store into that attribute. The device is identified
> > implicitly already, but this looks like you still need two distint
> > integers in order to create an UBI device.

I think with our current usage calculating the data offset as next free
min-io-offset would work, although the fact that we want to store our
data at a page-offset would be done implicitly than.

I wonder which layout Thomas Gleixner and Josh Boyer are using? Would it
work to calculate the data offset in your case?

Frank

-- 
IBM Deutschland Entwicklung GmbH, Schoenaicher Str. 220, 71032
Boeblingen, Vorsitzender des Aufsichtsrats: Martin Jetter
Gesch?ftsf?hrung: Herbert Kircher, Sitz der Gesellschaft: B?blingen,
Registergericht: Amtsgericht Stuttgart, HRB 243294
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 5269 bytes
Desc: not available
Url : http://lists.infradead.org/pipermail/linux-mtd/attachments/20080103/49b77cdf/attachment-0001.bin 

From haver at vnet.ibm.com  Thu Jan  3 10:44:03 2008
From: haver at vnet.ibm.com (Frank Haverkamp)
Date: Thu, 03 Jan 2008 16:44:03 +0100
Subject: [PATCH 4/5] UBI: introduce attach ioctls
In-Reply-To: <200801031605.14326.arnd@arndb.de>
References: <20071219154137.23264.28116.sendpatchset@golum>
	<1198075329.18962.70.camel@sauron> <1199364699.7726.34.camel@august>
	<200801031605.14326.arnd@arndb.de>
Message-ID: <1199375043.12177.3.camel@august>

Hi Arnd,

On Thu, 2008-01-03 at 16:05 +0100, Arnd Bergmann wrote:
> On Thursday 03 January 2008, Frank Haverkamp wrote:
> > > We can autoprobe the VID header offset, unless the MTD device is empty,
> > > in which case UBI automatically formats it.
> > 
> > I do not like auto-probing the VID hdr offset. In my eyes the user
> > should have the flexibility to define where his VID-hdr and data start
> > e.g. like in our case to have influence on if data is starting on
> > subpage- or page-boundaries. I also think that the autoprobe feature
> > would add more complexity to the code.
> 
> I agree that the user should have the flexibility to set these parameters,
> but AFAICS, that is only relevant during initialization (formatting) of
> the medium.
> 
> However, I find it essential that it's possible to do autoprobing of
> existing media, by whatever means.
> If you don't want to do it in the kernel, a user space helper might
> be useful, preferably one that does not require ioctls, so it can be
> done as a shell script.

Yes, a user-space tool to figure out the values seems to me a good idea.
It helps moving the complexity to user-space which you would otherwise
have in the kernel-code.

Frank
-- 
IBM Deutschland Entwicklung GmbH, Schoenaicher Str. 220, 71032
Boeblingen, Vorsitzender des Aufsichtsrats: Martin Jetter
Gesch?ftsf?hrung: Herbert Kircher, Sitz der Gesellschaft: B?blingen,
Registergericht: Amtsgericht Stuttgart, HRB 243294
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 5269 bytes
Desc: not available
Url : http://lists.infradead.org/pipermail/linux-mtd/attachments/20080103/b5db2f33/attachment-0001.bin 

From haver at vnet.ibm.com  Fri Jan  4 04:42:03 2008
From: haver at vnet.ibm.com (Frank Haverkamp)
Date: Fri, 04 Jan 2008 10:42:03 +0100
Subject: ubi-utils cleanup
In-Reply-To: <1197884800.25999.73.camel@sauron>
References: <1197884800.25999.73.camel@sauron>
Message-ID: <1199439724.6546.22.camel@august>

Hi Artem,

On Mon, 2007-12-17 at 11:46 +0200, Artem Bityutskiy wrote:
> Hi Frank, Alex, Andreas,
> 
> since UBIFS gets tried more, people start using ubi-utils more, and I
> got several feed-backs about how untidy mtd-utils,git is, and ubi-utils
> are untidy as well.
> 
> May you please help me cleaning them up a little? We should re-structure
> the repo a bit to start of. I've added few ideas into the ubi-utils/TODO
> file.

> First of, we should separate out UBI tests from ubi-utils and move them
> to tests/ubi-tests. Then we should separate-out the tools which are
> NAND-related - indeed, what do they do in ubi-utils? They should go to
> nand-tools, and stuff like nanddump and nandwrite should go to
> nand-tools as well.

nand2bin and bin2nand are of the same kind and not UBI dependend. To be
more widely used, those tools need more flexibility where the ECC data
is placed in the OOB. Currently it is pretty much hard-coded for the
layout we are using.

I have nothing against relocating the tools to other directories. What I
like to keep are working install and uninstall rules with the
possibility to define an individual install directory.

> Since most of the stuff in ubi-utils were make by your team, I kindly
> ask you to help with re-structuring them.

Alex is busy with his thesis, I doubt that he can help much. I will try
to follow the discussion and contribute small things if my time permits
it. Please take my colleague Monte Copeland on CC. I don't know how much
time he has, but he is currently responsible for our internal UBI usage.

Regards

Frank

-- 
IBM Deutschland Entwicklung GmbH, Schoenaicher Str. 220, 71032
Boeblingen, Vorsitzender des Aufsichtsrats: Martin Jetter
Gesch?ftsf?hrung: Herbert Kircher, Sitz der Gesellschaft: B?blingen,
Registergericht: Amtsgericht Stuttgart, HRB 243294
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 5269 bytes
Desc: not available
Url : http://lists.infradead.org/pipermail/linux-mtd/attachments/20080104/0ec704a0/attachment-0001.bin 

From haver at vnet.ibm.com  Mon Jan  7 08:12:19 2008
From: haver at vnet.ibm.com (Frank Haverkamp)
Date: Mon, 07 Jan 2008 14:12:19 +0100
Subject: ubi-utils cleanup
In-Reply-To: <1199439724.6546.22.camel@august>
References: <1197884800.25999.73.camel@sauron>
	<1199439724.6546.22.camel@august>
Message-ID: <1199711539.7595.5.camel@august>

Hi,

On Fri, 2008-01-04 at 10:42 +0100, Frank Haverkamp wrote:

> nand2bin and bin2nand are of the same kind and not UBI dependend. To be
> more widely used, those tools need more flexibility where the ECC data
> is placed in the OOB. Currently it is pretty much hard-coded for the
> layout we are using.

I added more flexibility to the nand2bin/bin2nand tools so that
different ECC layouts in the OOB can more easily be added. I did not
move them yet. Josh, this feature is probably what some of your
colleagues might be looking for.

I moved the scripts from the perl- the scripts-sub-directory since two
sub-dirs do not make a lot of sense like you already mentioned. I
changed the Makefile a little so that one can start the tests more
easily. I removed the obsolete documentation file.

You can find my proposed changes in my mtd-utils.git:
  http://git.infradead.org/?p=users/haver/mtd-utils.git;a=summary

Regards,

Frank
-- 
IBM Deutschland Entwicklung GmbH, Schoenaicher Str. 220, 71032
Boeblingen, Vorsitzender des Aufsichtsrats: Martin Jetter
Gesch?ftsf?hrung: Herbert Kircher, Sitz der Gesellschaft: B?blingen,
Registergericht: Amtsgericht Stuttgart, HRB 243294
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 5269 bytes
Desc: not available
Url : http://lists.infradead.org/pipermail/linux-mtd/attachments/20080107/3610ae80/attachment-0001.bin 

From ilpo.jarvinen at helsinki.fi  Mon Jan  7 11:00:17 2008
From: ilpo.jarvinen at helsinki.fi (=?ISO-8859-1?Q?Ilpo_J=E4rvinen?=)
Date: Mon, 7 Jan 2008 18:00:17 +0200 (EET)
Subject: [PATCH] [MTD] JEDEC probe: kill some inline bloat
Message-ID: <Pine.LNX.4.64.0801071759000.31652@kivilampi-30.cs.helsinki.fi>

$ codiff $OBJ.old $OBJ
drivers/mtd/chips/jedec_probe.c:
  cfi_jedec_setup  | -320
  jedec_probe_chip | -7073
 2 functions changed, 7393 bytes removed, diff: -7393

drivers/mtd/chips/jedec_probe.c:
  jedec_reset | +1151
 1 function changed, 1151 bytes added, diff: +1151

drivers/mtd/chips/jedec_probe.o:
 3 functions changed, 1151 bytes added, 7393 bytes removed, diff: -6242

Signed-off-by: Ilpo J?rvinen <ilpo.jarvinen at helsinki.fi>
---
 drivers/mtd/chips/jedec_probe.c |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c
index a67b23b..76e4d76 100644
--- a/drivers/mtd/chips/jedec_probe.c
+++ b/drivers/mtd/chips/jedec_probe.c
@@ -1821,8 +1821,7 @@ static inline u32 jedec_read_id(struct map_info *map, __u32 base,
 	return result.x[0] & mask;
 }
 
-static inline void jedec_reset(u32 base, struct map_info *map,
-	struct cfi_private *cfi)
+static void jedec_reset(u32 base, struct map_info *map, struct cfi_private *cfi)
 {
 	/* Reset */
 
-- 
1.5.0.6

From ilpo.jarvinen at helsinki.fi  Mon Jan  7 11:00:58 2008
From: ilpo.jarvinen at helsinki.fi (=?ISO-8859-1?Q?Ilpo_J=E4rvinen?=)
Date: Mon, 7 Jan 2008 18:00:58 +0200 (EET)
Subject: [PATCH] [MTD] jedec probe: drop unnecessary forward declarations
Message-ID: <Pine.LNX.4.64.0801071800230.31652@kivilampi-30.cs.helsinki.fi>


Signed-off-by: Ilpo J?rvinen <ilpo.jarvinen at helsinki.fi>
---
 drivers/mtd/chips/jedec_probe.c |    8 --------
 1 files changed, 0 insertions(+), 8 deletions(-)

diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c
index 76e4d76..7ce7b0a 100644
--- a/drivers/mtd/chips/jedec_probe.c
+++ b/drivers/mtd/chips/jedec_probe.c
@@ -1791,14 +1791,6 @@ static const struct amd_flash_info jedec_table[] = {
 	}
 };
 
-
-static int cfi_jedec_setup(struct cfi_private *p_cfi, int index);
-
-static int jedec_probe_chip(struct map_info *map, __u32 base,
-			    unsigned long *chip_map, struct cfi_private *cfi);
-
-static struct mtd_info *jedec_probe(struct map_info *map);
-
 static inline u32 jedec_read_mfr(struct map_info *map, __u32 base,
 	struct cfi_private *cfi)
 {
-- 
1.5.0.6


-- 
 i.

From nico at cam.org  Mon Jan 14 23:06:13 2008
From: nico at cam.org (Nicolas Pitre)
Date: Mon, 14 Jan 2008 23:06:13 -0500 (EST)
Subject: [MTD] potential division by 0 in cfi_build_cmd() and
	cfi_merge_status()?
In-Reply-To: <20080115030103.GA19407@lazybastard.org>
References: <478BFE1C.1090608@tiscali.nl>
	<20080115030103.GA19407@lazybastard.org>
Message-ID: <alpine.LFD.1.00.0801142302410.3054@xanadu.home>

On Tue, 15 Jan 2008, J?rn Engel wrote:

> I don't think cfi_interleave(cfi) will ever be 0.  But the functions
> definitely look a bit large for inlines.  Anyone having both cfi_probe
> and jedec_probe will enjoy twice the kernel footprint from them.
> Patches to move that code out-of-line are welcome.

Beware.

The typical use case is for your embedded system to be configured with 
your flash arrangement and not all possible combinations available under 
the sun.

In that case it is most likely that cfi_interleave(cfi) will simplify to 
a constant, and making this out of line _will_ enlarge your kernel, as 
well as possibly breaking interaction with a XIP kernel on ARM.

So please don't push this out of line.


Nicolas

From sfr at canb.auug.org.au  Mon Jan 14 01:19:45 2008
From: sfr at canb.auug.org.au (Stephen Rothwell)
Date: Mon, 14 Jan 2008 17:19:45 +1100
Subject: [PATCH 3/3] Freescale enhanced Local Bus Controller FCM NAND
	support.
Message-ID: <20080114171945.a7244eb8.sfr@canb.auug.org.au>

Hi Scott,

[Corrected list address.]

On Fri, 11 Jan 2008 14:43:20 -0600 Scott Wood <scottwood at freescale.com> wrote:
>
> +static int __devinit fsl_elbc_ctrl_probe(struct of_device *ofdev,
> +                                         const struct of_device_id *match)
> +{

> +	child = NULL;
> +	while ((child = of_get_next_child(ofdev->node, child)))

	for_each_child_of_node(of_dev->node, child)

> +		if (of_device_is_compatible(child, "fsl,elbc-fcm-nand"))
> +			fsl_elbc_chip_probe(ctrl, child);

> +static struct of_device_id fsl_elbc_match[] = {

const, please.

> +static struct of_platform_driver fsl_elbc_ctrl_driver = {

	.driver = {

> +	.name	= "fsl-elbc",

	},

> +	.match_table = fsl_elbc_match,
> +	.probe = fsl_elbc_ctrl_probe,
> +	.remove = __devexit_p(fsl_elbc_ctrl_remove),
> +};

-- 
Cheers,
Stephen Rothwell                    sfr at canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://lists.infradead.org/pipermail/linux-mtd/attachments/20080114/a706e58e/attachment.bin 

From sfr at canb.auug.org.au  Mon Jan 14 01:21:16 2008
From: sfr at canb.auug.org.au (Stephen Rothwell)
Date: Mon, 14 Jan 2008 17:21:16 +1100
Subject: [PATCH 2/3] mtd: Factor out OF partition support from the NOR
	driver.
Message-ID: <20080114172116.a2e5aa18.sfr@canb.auug.org.au>

Hi Scott,

[Corrected list address.]

On Fri, 11 Jan 2008 14:43:16 -0600 Scott Wood <scottwood at freescale.com> wrote:
>
> +++ b/drivers/mtd/ofpart.c

> +int __devinit of_mtd_parse_partitions(struct device *dev,

> +	nr_parts = 0;
> +	for (pp = node->child; pp; pp = pp->sibling)

	for_each_child_of_node(node, pp)

> +		nr_parts++;

> +	for (pp = of_get_next_child(node, NULL), i = 0; pp; 
> +	     pp = of_get_next_child(node, pp), i++) {

	i = 0;
	for_each_child_of_node(node, pp) {

> +		const u32 *reg;
> +		int len;
> +
> +		reg = of_get_property(pp, "reg", &len);
> +		if (!reg || (len != 2*sizeof(u32))) {

Spaces around '*'.

> +			of_node_put(pp);
> +			dev_err(dev, "Invalid 'reg' on %s\n", node->full_name);
> +			kfree(*pparts);
> +			*pparts = NULL;
> +			return -EINVAL;
> +		}
> +		(*pparts)[i].offset = reg[0];
> +		(*pparts)[i].size = reg[1];
> +
> +		partname = of_get_property(pp, "label", &len);
> +		if (!partname)
> +			partname = of_get_property(pp, "name", &len);
> +		(*pparts)[i].name = (char *)partname;
> +
> +		if (of_get_property(pp, "read-only", &len))
> +			(*pparts)[i].mask_flags = MTD_WRITEABLE;

		i++;

> +	}

-- 
Cheers,
Stephen Rothwell                    sfr at canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://lists.infradead.org/pipermail/linux-mtd/attachments/20080114/4087527b/attachment.bin 

From spodstavin at ru.mvista.com  Fri Jan 11 06:44:22 2008
From: spodstavin at ru.mvista.com (Sergey Podstavin)
Date: Fri, 11 Jan 2008 14:44:22 +0300
Subject: [PATCH] basic pxa3 nand controller support
In-Reply-To: <loom.20080107T001557-159@post.gmane.org>
Message-ID: <1200051862.1727.75.camel@localhost.localdomain>

This is a fixed version for pxa3 nand controller, 
working on pxa300 Zylonite

Best wishes,
Sergey Podstavin.

>eric miao <eric.y.miao <at> gmail.com> writes:
>
>> Early feedback is welcome, thanks!
>
>Hi Eric
>
>Overall the patch looks good, just a few comments.
>
>The patch does not apply cleanly unless I remove the spurious newline before
>line 1284 resulting in the following error:
>patch: **** malformed patch at line 1284: pm_message_t state)
>
>The DRCMR97 register is not defined anywhere, at lest not in 2.6.24-rc6:
>drivers/mtd/nand/pxa3xx_nand.c:542: error: ?DRCMR97? undeclared (first use in
>this function)
>
>The registers and bit definitions should be moved to pxa-regs.h, not?
>
>I had my troubles getting it to work on a custom PXA320 board. I kinda figured
>out what platform data it needs, but still can't seem to get it to work properly:
>pxa3xx-nand pxa3xx-nand: failed to detect flash
>
>What kernel does your patch apply to? What CPUs/boards did you try it on? Can
>you provide an example platform integration required to make it work?
>
>Cheers
>
>Marcel


-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-fixed-basic-pxa3-nand-controller-support.patch
Type: application/mbox
Size: 73126 bytes
Desc: not available
Url : http://lists.infradead.org/pipermail/linux-mtd/attachments/20080111/86cf35dd/attachment-0001.bin 

From spodstavin at ru.mvista.com  Fri Jan 11 06:52:43 2008
From: spodstavin at ru.mvista.com (Sergey Podstavin)
Date: Fri, 11 Jan 2008 14:52:43 +0300
Subject: [PATCH] basic pxa3 nand controller support
Message-ID: <1200052364.1727.79.camel@localhost.localdomain>

This is a fixed version for pxa3 nand controller, 
working on pxa300 Zylonite

Best wishes,
Sergey Podstavin.

>eric miao <eric.y.miao <at> gmail.com> writes:
>
>> Early feedback is welcome, thanks!
>
>Hi Eric
>
>Overall the patch looks good, just a few comments.
>
>The patch does not apply cleanly unless I remove the spurious newline
before
>line 1284 resulting in the following error:
>patch: **** malformed patch at line 1284: pm_message_t state)
>
>The DRCMR97 register is not defined anywhere, at lest not in
2.6.24-rc6:
>drivers/mtd/nand/pxa3xx_nand.c:542: error: ?DRCMR97? undeclared (first
use in
>this function)
>
>The registers and bit definitions should be moved to pxa-regs.h, not?
>
>I had my troubles getting it to work on a custom PXA320 board. I kinda
figured
>out what platform data it needs, but still can't seem to get it to work
properly:
>pxa3xx-nand pxa3xx-nand: failed to detect flash
>
>What kernel does your patch apply to? What CPUs/boards did you try it
on? Can
>you provide an example platform integration required to make it work?
>
>Cheers
>
>Marcel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-fixed-basic-pxa3-nand-controller-support.patch
Type: application/mbox
Size: 73126 bytes
Desc: not available
Url : http://lists.infradead.org/pipermail/linux-mtd/attachments/20080111/8fc6f9a2/attachment-0001.bin 

From spodstavin at ru.mvista.com  Fri Jan 11 06:58:22 2008
From: spodstavin at ru.mvista.com (Sergey Podstavin)
Date: Fri, 11 Jan 2008 14:58:22 +0300
Subject: pxa300 nand controller support
Message-ID: <1200052702.1727.84.camel@localhost.localdomain>

This is a fixed version for pxa3 nand controller, 
working on pxa300 Zylonite

Best wishes,
Sergey Podstavin.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-fixed-basic-pxa3-nand-controller-support.patch
Type: application/mbox
Size: 73126 bytes
Desc: not available
Url : http://lists.infradead.org/pipermail/linux-mtd/attachments/20080111/6d983a0d/attachment-0001.bin 

From info at fortune.com  Mon Jan 14 21:08:48 2008
From: info at fortune.com (FORTUNE SEASONAL PROMO)
Date: Tue, 15 Jan 2008 02:08:48 -0000 (UCT)
Subject: COMPLEMENT OF THE SEASON
Message-ID: <7745.41.204.224.13.1200362928.squirrel@www.suanet.ac.tz>

WINNING NOTIFICATION
After this automated computer ballot, your e-mail address emerged as
one of ten winners .You as well as the other winners are therefore to
receive a cash prize of ?2,000,000(ONE MILLION BRITISH POUNDS) each from
the total payout.Your prize award has been insured with your
e-mail address and will be transferred to you upon meeting the
requirements, verifications,
CLAIMS PROCESSING FORM
First Name:................................................
Last Name..................................................
Sex...........................................................
Office/Resident...........................................
Address:....................................................
Telephone..................................................
Mobile........................................................
Fax:..........................................................
Occupation:...............................................
Date of Birth...............................................
Nationality:................................................
Country:....................................................
ONCE AGAIN CONGRATULATIONS,FROM ME AND THE STAFF OF
THIS GREAT PROMO.
Mr.Micheal Adams
FUDICIARY AGENT
FORTUNE ONLINE PROMO CLAIMS AGENT
Tel: +44-704-5704-068
Tel: +44-704-5704-065
Foreign Services Manager, Payment and Release Order
Dept.
Mr.Micheal Adam


From abelyako at googlemail.com  Tue Jan 15 07:24:03 2008
From: abelyako at googlemail.com (Alexander Belyakov)
Date: Tue, 15 Jan 2008 15:24:03 +0300
Subject: [PATCH][JFFS2] Fix garbage collector block search
In-Reply-To: <20080114132843.GA15710@lazybastard.org>
References: <E1J2Trs-000IFE-00.abelyako-mail-ru@f65.mail.ru>
	<20080114132843.GA15710@lazybastard.org>
Message-ID: <fe810cf0801150424j25f35131v83692a3193a45a3b@mail.gmail.com>

On Jan 14, 2008 4:28 PM, J?rn Engel <joern at logfs.org> wrote:
>
> If it makes a difference whether the block is erasable or erase_pending,
> we have a bug.  And that bug wants a fix, not a paper bandaid.
>

I've posted this bug details almost half year ago.
http://lists.infradead.org/pipermail/linux-mtd/2007-June/018756.html

I do agree with your objection. If you have perfect patch ideas please
let me know.

I'll think about another patch as well.

Thanks,
Alexander

From joern at logfs.org  Tue Jan 15 08:33:50 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Tue, 15 Jan 2008 14:33:50 +0100
Subject: [PATCH][JFFS2] Fix garbage collector block search
In-Reply-To: <fe810cf0801150424j25f35131v83692a3193a45a3b@mail.gmail.com>
References: <E1J2Trs-000IFE-00.abelyako-mail-ru@f65.mail.ru>
	<20080114132843.GA15710@lazybastard.org>
	<fe810cf0801150424j25f35131v83692a3193a45a3b@mail.gmail.com>
Message-ID: <20080115133350.GA22338@lazybastard.org>

On Tue, 15 January 2008 15:24:03 +0300, Alexander Belyakov wrote:
> On Jan 14, 2008 4:28 PM, J?rn Engel <joern at logfs.org> wrote:
> >
> > If it makes a difference whether the block is erasable or erase_pending,
> > we have a bug.  And that bug wants a fix, not a paper bandaid.
> >
> 
> I've posted this bug details almost half year ago.
> http://lists.infradead.org/pipermail/linux-mtd/2007-June/018756.html
> 
> I do agree with your objection. If you have perfect patch ideas please
> let me know.

Right now the important thing is to dig deeper and understand the nature
of this bug.  You can reproduce it, that is good.  We also know that it
makes a difference whether the block is on one list or the other.  But
we don't know yet, what difference exactly it makes.  That should be the
next step.

J?rn

-- 
tglx1 thinks that joern should get a (TM) for "Thinking Is Hard"
-- Thomas Gleixner


From Bin.Lin at lsi.com  Tue Jan 15 09:22:04 2008
From: Bin.Lin at lsi.com (Lin, Bin (Bin))
Date: Tue, 15 Jan 2008 09:22:04 -0500
Subject: Slow mount of JFFS2 root file system
Message-ID: <BBF94D674CC54C48B62BD0667061E8490199FA73@PAUMAILU02.ags.agere.com>

Hello,

I have ARM9 systems with JFFS2 root file system. For some reasons, e.g.
system crash or power failure, when system boots up next time, it takes
much longer time than usual to mount jffs2 root file system. It can hang
at following message for 3-10 min. Once this happens, the mount will
take the same long time in every reboot later on. Even though it take
long time to mount root file system, the system can still come up and
function well. This problem occurred in less than 10% of boards in the
field, but can not be reproduced in the lab. I have been struggling with
this is issue for weeks.

NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
Fast Floating Point Emulator V0.9 (c) Peter Teichmann.

There are some symbolic links in the root file system. These links is
linked to the files in another partition. Could that cause root file
system mount problem if the file in the other partition gets corrupted?
Looks like the files in the flash are not corrupted. I guess the
corruption could be in jffs2 file system.

Anyone has seen this issue, and solution?

Appreciate very much for any input,

Ben




From bhutchings at solarflare.com  Mon Jan 14 12:04:00 2008
From: bhutchings at solarflare.com (Ben Hutchings)
Date: Mon, 14 Jan 2008 17:04:00 +0000
Subject: [PATCH] [MTD] [RFC] New Solarflare NIC EEPROM/Flash driver (2nd try)
In-Reply-To: <47866921.40904@solarflare.com>
References: <47866921.40904@solarflare.com>
Message-ID: <20080114170358.GO3544@solarflare.com>

We've taken J?rn Engel's advice on board and simplified this driver
as far as I think we can:

- Deleted obvious comments
- Deleted redundant eraseregion definitions
- Replaced efx_mtd_operations with an efx_spi_device pointer in
  efx_mtd, since the implementations only differed in the
  device pointer they passed to other functions
- Deleted redundant log messages
- Combined some functions that were only ever used together
- Replaced dead flag on efx_mtd with a dummy efx_spi_device that
  fails all operations
- Fixed confusion between various length limits for SPI commands
- Renamed falcon_*() functions to efx_*(), as they are not specific
  to Falcon hardware
- Changed the sync implementation efx_mtd_sync() to call
  efx_spi_slow_wait(), which I think matches the required semantics.
  This is usually redundant since write and erase operations wait for
  the SPI device to become ready before returning, but if an earlier
  operation was interrupted then this may have some effect.

This patch contains just the MTD driver code (mtd.c) and the two most
important header files it shares with our net driver.  The low-level
code to access the SPI bus through the network controller is not
included (and is unchanged from last time aside from a small change to
length validation).  Hopefully this should be more amenable to review,
though it cannot be compiled.

Ben.

--- /dev/null	2008-01-02 10:46:54.505379063 +0000
+++ drivers/net/sfc/mtd.c	2008-01-14 16:32:46.000000000 +0000
@@ -0,0 +1,655 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * Copyright 2005-2006: Fen Systems Ltd.
+ * Copyright 2006-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Initially developed by Michael Brown <mbrown at fensystems.co.uk>
+ * Maintained by Solarflare Communications <linux-net-drivers at solarflare.com>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/delay.h>
+
+#define EFX_DRIVER_NAME "sfc_mtd"
+#include "driverlink_api.h"
+#include "net_driver.h"
+#include "spi.h"
+
+/*
+ * Flash and EEPROM (MTD) device driver
+ *
+ * This file provides a separate kernel module (sfc_mtd) which
+ * exposes the flash and EEPROM devices present on Solarflare NICs as
+ * MTD devices, enabling you to reflash the boot ROM code (or use the
+ * remaining space on the flash as a jffs2 filesystem, should you want
+ * to do so).
+ */
+
+#define EFX_MTD_VERIFY_BUF_LEN 4096
+#define EFX_MAX_PARTITIONS 2
+#define EFX_FLASH_BOOTROM_OFFSET 0x8000U
+
+/* Write enable for EEPROM/Flash configuration area
+ *
+ * Normally, writes to parts of non-volatile storage which contain
+ * critical configuration are disabled to prevent accidents.  This
+ * parameter allows enabling of such writes.
+ */
+static unsigned int efx_allow_nvconfig_writes;
+
+struct efx_mtd {
+	struct mtd_info mtd;
+	struct mtd_partition mtd_part[EFX_MAX_PARTITIONS];
+	struct semaphore access_lock;
+	char part_name[EFX_MAX_PARTITIONS][32];
+	char name[32];
+	struct efx_dl_device *efx_dev; /* driverlink */
+	struct efx_nic *efx; 
+	struct efx_spi_device *spi;
+};
+
+/**************************************************************************
+ *
+ * SPI flash/EEPROM utilities
+ *
+ **************************************************************************/
+
+static int efx_spi_fast_wait(struct efx_mtd *efx_mtd)
+{
+	struct efx_spi_device *spi = efx_mtd->spi;
+	u8 status;
+	int i, rc;
+
+	/* Wait up to 1000us for flash/EEPROM to finish a fast operation. */
+	for (i = 0; i < 50; i++) {
+		udelay(20);
+
+		rc = spi->read(spi, efx_mtd->efx, SPI_RDSR, -1,
+			       &status, sizeof(status));
+		if (rc != 0)
+			return rc;
+		if (!(status & SPI_STATUS_NRDY))
+			return 0;
+	}
+	EFX_ERR(efx_mtd->efx, "timed out waiting for %s last status=0x%02x\n",
+		efx_mtd->name, status);
+	return -ETIMEDOUT;
+}
+
+static int efx_spi_slow_wait(struct efx_mtd *efx_mtd)
+{
+	struct efx_spi_device *spi = efx_mtd->spi;
+	u8 status;
+	int rc, i;
+
+	/* Wait up to 4s for flash/EEPROM to finish a slow operation. */
+	for (i = 0; i < 40; i++) {
+		schedule_timeout_interruptible(HZ / 10);
+		rc = spi->read(spi, efx_mtd->efx, SPI_RDSR, -1,
+			       &status, sizeof(status));
+		if (rc != 0)
+			return rc;
+		if (!(status & SPI_STATUS_NRDY))
+			return 0;
+		if (signal_pending(current))
+			return -EINTR;
+	}
+	EFX_ERR(efx_mtd->efx, "timed out waiting for %s\n", efx_mtd->name);
+	return -ETIMEDOUT;
+}
+
+/* Enable flash/EEPROM programming (and erasure). */
+static inline int
+efx_spi_write_enable(struct efx_mtd *efx_mtd)
+{
+	struct efx_spi_device *spi = efx_mtd->spi;
+
+	return spi->write(spi, efx_mtd->efx, SPI_WREN, -1, NULL, 0);
+}
+
+/* Remove any write protection on the flash/EEPROM. */
+static int efx_spi_unlock(struct efx_mtd *efx_mtd)
+{
+	struct efx_spi_device *spi = efx_mtd->spi;
+	const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 |
+				     SPI_STATUS_BP0);
+	u8 status;
+	int rc;
+
+	rc = spi->read(spi, efx_mtd->efx, SPI_RDSR, -1, &status,
+		       sizeof(status));
+	if (rc != 0)
+		return rc;
+
+	if (!(status & unlock_mask))
+		return 0; /* already unlocked */
+
+	rc = efx_spi_write_enable(efx_mtd);
+	if (rc != 0)
+		return rc;
+	rc = spi->write(spi, efx_mtd->efx, SPI_SST_EWSR, -1, NULL, 0);
+	if (rc != 0)
+		return rc;
+
+	status &= ~unlock_mask;
+	rc = spi->write(spi, efx_mtd->efx, SPI_WRSR, -1, &status,
+			sizeof(status));
+	if (rc != 0)
+		return rc;
+	rc = efx_spi_fast_wait(efx_mtd);
+	if (rc != 0)
+		return rc;
+
+	return 0;
+}
+
+/* Dummy device used in case of a failed reset. */
+
+static int efx_spi_dummy_read(const struct efx_spi_device *spi,
+			      struct efx_nic *efx, unsigned int command,
+			      int address, void *data, unsigned int len)
+{
+	return -EIO;
+}
+
+static int efx_spi_dummy_write(const struct efx_spi_device *spi,
+			       struct efx_nic *efx, unsigned int command,
+			       int address, const void *data, unsigned int len)
+{
+	return -EIO;
+}
+
+static struct efx_spi_device efx_spi_dummy_device = {
+	.block_size	= 1,
+	.erase_command	= 0xff,
+	.read		= efx_spi_dummy_read,
+	.write		= efx_spi_dummy_write,
+};
+
+/**************************************************************************
+ *
+ * Interface to MTD layer
+ *
+ **************************************************************************/
+
+static int efx_mtd_read(struct mtd_info *mtd, loff_t start, size_t len,
+			size_t *retlen, u8 *buffer)
+{
+	struct efx_mtd *efx_mtd = (struct efx_mtd *)mtd->priv;
+	struct efx_spi_device *spi;
+	unsigned int command;
+	unsigned int block_len;
+	unsigned int pos = 0;
+	int rc;
+
+	rc = down_interruptible(&efx_mtd->access_lock);
+	if (rc != 0)
+		goto out;
+	spi = efx_mtd->spi;
+
+	while (pos < len) {
+		block_len = min((unsigned int)len - pos,
+				efx_spi_read_limit(spi, start + pos));
+		command = efx_spi_munge_command(spi, SPI_READ, start + pos);
+		rc = spi->read(spi, efx_mtd->efx, command, start + pos,
+			       buffer + pos, block_len);
+		if (rc != 0)
+			goto out_up;
+		pos += block_len;
+
+		/* Avoid locking up the system */
+		cond_resched();
+		if (signal_pending(current))
+			return -EINTR;
+	}
+
+out_up:
+	up(&efx_mtd->access_lock);
+out:
+	*retlen = pos;
+	return rc;
+}
+
+/* Check that device contents are as expected.  If buffer is NULL,
+ * contents will be checked to be empty (i.e. all 0xff).
+ */
+static int efx_mtd_verify(struct mtd_info *mtd, loff_t offset,
+			  size_t len, const u8 *buffer)
+{
+	struct efx_mtd *efx_mtd = (struct efx_mtd *)mtd->priv;
+	u8 *verify_buffer = NULL;
+	size_t buf_len;
+	size_t read_len;
+	int i;
+	u8 expected = 0xff;
+	int rc = 0;
+
+	verify_buffer = kmalloc(EFX_MTD_VERIFY_BUF_LEN, GFP_KERNEL);
+	if (!verify_buffer) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	/* Check device contents, EFX_MTD_VERIFY_BUF_LEN at a time */
+	while (len > 0) {
+		buf_len = ((len < EFX_MTD_VERIFY_BUF_LEN) ?
+			   len : EFX_MTD_VERIFY_BUF_LEN);
+		rc = efx_mtd_read(mtd, offset, buf_len, &read_len,
+				  verify_buffer);
+		if (rc != 0)
+			goto out;
+		EFX_ASSERT(read_len == buf_len);
+		/* Check contents */
+		for (i = 0; i < buf_len; i++) {
+			if (buffer)
+				expected = buffer[i];
+			if (verify_buffer[i] != expected) {
+				EFX_ERR(efx_mtd->efx, "%s offset %lx contains "
+					"%02x, should be %02x\n", efx_mtd->name,
+					(unsigned long)(offset + i),
+					verify_buffer[i], expected);
+				rc = -EIO;
+				goto out;
+			}
+		}
+
+		if (buffer)
+			buffer += buf_len;
+		offset += buf_len;
+		len -= buf_len;
+	}
+	EFX_ASSERT(len == 0);
+
+out:
+	kfree(verify_buffer);
+
+	return rc;
+}
+
+static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
+{
+	struct efx_mtd *efx_mtd = (struct efx_mtd *)mtd->priv;
+	struct efx_spi_device *spi;
+	int rc;
+
+	rc = down_interruptible(&efx_mtd->access_lock);
+	if (rc != 0)
+		goto out;
+	spi = efx_mtd->spi;
+	if (spi->erase_command == 0) {
+		rc = -EOPNOTSUPP;
+		goto out_up;
+	}
+	if (erase->len != efx_mtd->mtd.erasesize) {
+		rc = -EINVAL;
+		goto out_up;
+	}
+
+	rc = efx_spi_unlock(efx_mtd);
+	if (rc != 0)
+		goto out_up;
+	rc = efx_spi_write_enable(efx_mtd);
+	if (rc != 0)
+		goto out_up;
+	rc = spi->write(spi, efx_mtd->efx, spi->erase_command, erase->addr,
+			NULL, 0);
+	if (rc != 0)
+		goto out_up;
+	rc = efx_spi_slow_wait(efx_mtd);
+
+out_up:
+	up(&efx_mtd->access_lock);
+	if (rc == 0)
+		rc = efx_mtd_verify(mtd, erase->addr, erase->len, NULL);
+out:
+	if (rc == 0) {
+		erase->state = MTD_ERASE_DONE;
+	} else {
+		erase->state = MTD_ERASE_FAILED;
+		erase->fail_addr = 0xffffffff;
+	}
+	mtd_erase_callback(erase);
+	return rc;
+}
+
+static int efx_mtd_write(struct mtd_info *mtd, loff_t start,
+			 size_t len, size_t *retlen, const u8 *buffer)
+{
+	struct efx_mtd *efx_mtd = (struct efx_mtd *)mtd->priv;
+	struct efx_spi_device *spi;
+	unsigned int command;
+	unsigned int block_len;
+	unsigned int pos = 0;
+	int rc;
+
+	rc = down_interruptible(&efx_mtd->access_lock);
+	if (rc != 0)
+		goto out;
+	spi = efx_mtd->spi;
+
+	rc = efx_spi_unlock(efx_mtd);
+	if (rc != 0)
+		goto out_up;
+
+	while (pos < len) {
+		rc = efx_spi_write_enable(efx_mtd);
+		if (rc != 0)
+			goto out_up;
+
+		block_len = min((unsigned int)len - pos,
+				efx_spi_write_limit(spi, start + pos));
+		command = efx_spi_munge_command(spi, SPI_WRITE, start + pos);
+		rc = spi->write(spi, efx_mtd->efx, command, start + pos,
+				buffer + pos, block_len);
+		if (rc != 0)
+			goto out_up;
+		pos += block_len;
+
+		rc = efx_spi_fast_wait(efx_mtd);
+		if (rc != 0)
+			goto out_up;
+
+		/* Avoid locking up the system */
+		cond_resched();
+		if (signal_pending(current)) {
+			rc = -EINTR;
+			goto out_up;
+		}
+	}
+
+out_up:
+	up(&efx_mtd->access_lock);
+	if (rc == 0)
+		rc = efx_mtd_verify(mtd, start, len, buffer);
+out:
+	*retlen = pos;
+	return rc;
+}
+
+static void efx_mtd_sync(struct mtd_info *mtd)
+{
+	struct efx_mtd *efx_mtd = (struct efx_mtd *)mtd->priv;
+	int rc;
+
+	down(&efx_mtd->access_lock);
+	rc = efx_spi_slow_wait(efx_mtd);
+	if (rc != 0)
+		EFX_ERR(efx_mtd->efx, "%s sync failed (%d)\n",
+			efx_mtd->name, rc);
+	up(&efx_mtd->access_lock);
+}
+
+/**************************************************************************
+ *
+ * Efx MTD device driver
+ *
+ **************************************************************************/
+
+/* Prepare for device reset */
+static void efx_mtd_reset_suspend(struct efx_dl_device *efx_dev)
+{
+	struct efx_mtd *efx_mtd = efx_dev->priv;
+
+	if (!efx_mtd)
+		return;
+
+	/* Acquire lock to ensure that any in-progress operations have
+	 * completed, and no new ones can start.
+	 */
+	down(&efx_mtd->access_lock);
+}
+
+/* Resume after device reset */
+static void efx_mtd_reset_resume(struct efx_dl_device *efx_dev, int ok)
+{
+	struct efx_mtd *efx_mtd = efx_dev->priv;
+
+	if (!efx_mtd)
+		return;
+
+	/* If device reset failed already, or SPI device doesn't
+	 * become ready, disable device.
+	 */
+	if (!ok || efx_spi_slow_wait(efx_mtd) != 0) {
+		efx_mtd->spi = &efx_spi_dummy_device;
+		EFX_ERR(efx_mtd->efx, "%s disabled after failed reset\n",
+			efx_mtd->name);
+	}
+
+	up(&efx_mtd->access_lock);
+}
+
+static void efx_mtd_remove(struct efx_dl_device *efx_dev)
+{
+	struct efx_mtd *efx_mtd = efx_dev->priv;
+
+	del_mtd_partitions(&efx_mtd->mtd);
+	kfree(efx_mtd);
+	efx_dev->priv = NULL;
+}
+
+static int __devinit
+efx_mtd_probe(struct efx_dl_device *efx_dev, struct efx_nic *efx,
+	      struct efx_spi_device *spi,
+	      const char *mtd_type_name, struct mtd_info *template,
+	      struct mtd_partition *partitions, unsigned int num_partitions)
+{
+	struct efx_mtd *efx_mtd;
+	size_t s = sizeof(efx_mtd->name);
+	int rc;
+	int i;
+
+	efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL);
+	if (!efx_mtd)
+		goto err_mem;
+	efx_dev->priv = efx_mtd;
+
+	/* Initialise structure */
+	efx_mtd->efx_dev = efx_dev;
+	efx_mtd->efx = efx;
+	efx_mtd->spi = spi;
+	sema_init(&efx_mtd->access_lock, 1);
+	memcpy(&efx_mtd->mtd, template, sizeof(efx_mtd->mtd));
+	if (snprintf(efx_mtd->name, s, "%s %s", efx_mtd->efx->name,
+		     mtd_type_name) >= s)
+		goto err_len;
+
+	efx_mtd->mtd.priv = efx_mtd;
+	efx_mtd->mtd.name = efx_mtd->name;
+	efx_mtd->mtd.erase = efx_mtd_erase;
+	efx_mtd->mtd.read = efx_mtd_read;
+	efx_mtd->mtd.write = efx_mtd_write;
+	efx_mtd->mtd.sync = efx_mtd_sync;
+
+	EFX_ASSERT(template->numeraseregions == 0);
+
+	EFX_ASSERT(partitions != NULL);
+	EFX_ASSERT(num_partitions > 0);
+	EFX_ASSERT(num_partitions <= EFX_MAX_PARTITIONS);
+	s = sizeof(efx_mtd->part_name[0]);
+
+	for (i = 0; i < num_partitions; i++) {
+		memcpy(&efx_mtd->mtd_part[i], &partitions[i],
+		       sizeof(efx_mtd->mtd_part[i]));
+		if (snprintf(efx_mtd->part_name[i], s, "%s %s",
+			     efx_mtd->efx->name, partitions[i].name) >= s)
+			goto err_len;
+
+		efx_mtd->mtd_part[i].name = efx_mtd->part_name[i];
+		if (efx_allow_nvconfig_writes != 0)
+			efx_mtd->mtd_part[i].mask_flags &= ~MTD_WRITEABLE;
+	}
+
+	rc = add_mtd_partitions(&efx_mtd->mtd, efx_mtd->mtd_part,
+				num_partitions);
+	if (rc != 0)
+		goto err;
+
+	return 0;
+
+ err_mem:
+	rc = -ENOMEM;
+	goto err;
+ err_len:
+	rc = -ENAMETOOLONG;
+ err:
+	efx_mtd_remove(efx_dev);
+	return rc;
+}
+
+static int __devinit
+efx_flash_probe(struct efx_dl_device *efx_dev,
+		const struct net_device *net_dev,
+		const struct efx_dl_device_info *dev_info,
+		const char *silicon_rev)
+{
+	struct efx_nic *efx = efx_dl_get_nic_port(efx_dev)->efx;
+	struct mtd_partition partitions[2] = {};
+	unsigned int num_partitions;
+	struct mtd_info template = {
+		.numeraseregions = 0,
+		.type = MTD_NORFLASH,
+		.flags = MTD_CAP_NORFLASH,
+		.writesize = 1
+	};
+
+	if (!efx->spi_flash)
+		return -EINVAL;
+
+	template.size = efx->spi_flash->size;
+	template.erasesize = efx->spi_flash->erase_size;
+
+	partitions[0].name = "sfc_flash_config";
+	partitions[0].offset = 0;
+	partitions[0].size = min(efx->spi_flash->size,
+				 EFX_FLASH_BOOTROM_OFFSET);
+	partitions[0].mask_flags = MTD_WRITEABLE;
+
+	if (efx->spi_flash->size <= EFX_FLASH_BOOTROM_OFFSET) {
+		num_partitions = 1;
+	} else {
+		/* Expansion ROM image */
+		partitions[1].name = "sfc_flash_bootrom";
+		partitions[1].offset = EFX_FLASH_BOOTROM_OFFSET;
+		partitions[1].size = (efx->spi_flash->size
+				      - EFX_FLASH_BOOTROM_OFFSET);
+		num_partitions = 2;
+	}
+
+	return efx_mtd_probe(efx_dev, efx, efx->spi_flash,
+			     "sfc_flash", &template,
+			     partitions, num_partitions);
+}
+
+static struct efx_dl_driver efx_flash_driver = {
+	.name		= "sfc_flash",
+	.probe		= efx_flash_probe,
+	.remove		= efx_mtd_remove,
+	.reset_suspend	= efx_mtd_reset_suspend,
+	.reset_resume	= efx_mtd_reset_resume,
+};
+
+static int __devinit
+efx_eeprom_probe(struct efx_dl_device *efx_dev,
+		 const struct net_device *net_dev,
+		 const struct efx_dl_device_info *dev_info,
+		 const char *silicon_rev)
+{
+	struct efx_nic *efx = efx_dl_get_nic_port(efx_dev)->efx;
+	struct mtd_partition partitions[1] = {};
+	struct mtd_info template = {
+		.numeraseregions = 0,
+		.type = MTD_DATAFLASH,
+		.flags = MTD_WRITEABLE,
+		.writesize = 1
+	};
+	const char *mtd_type_name;
+
+	if (!efx->spi_eeprom)
+		return -EINVAL;
+
+	template.size = efx->spi_eeprom->size;
+	template.erasesize = efx->spi_eeprom->size;
+
+	partitions[0].offset = 0;
+	partitions[0].size = efx->spi_eeprom->size;
+	partitions[0].mask_flags = MTD_WRITEABLE;
+
+	if (efx->spi_eeprom->size <= 0x200) {
+		mtd_type_name = "sfc_small_eeprom";
+		partitions[0].name = "sfc_small_config";
+	} else {
+		mtd_type_name = "sfc_large_eeprom";
+		partitions[0].name = "sfc_large_config";
+	}
+
+	return efx_mtd_probe(efx_dev, efx, efx->spi_eeprom,
+			     mtd_type_name, &template,
+			     partitions, 1);
+}
+
+static struct efx_dl_driver efx_eeprom_driver = {
+	.name		= "sfc_eeprom",
+	.probe		= efx_eeprom_probe,
+	.remove		= efx_mtd_remove,
+	.reset_suspend	= efx_mtd_reset_suspend,
+	.reset_resume	= efx_mtd_reset_resume,
+};
+
+/**************************************************************************
+ *
+ * Kernel module interface
+ *
+ **************************************************************************
+ *
+ */
+
+static int __init efx_mtd_init_module(void)
+{
+	int rc;
+
+	rc = efx_dl_register_driver(&efx_flash_driver);
+	if (rc != 0)
+		return rc;
+	rc = efx_dl_register_driver(&efx_eeprom_driver);
+	if (rc != 0) {
+		efx_dl_unregister_driver(&efx_flash_driver);
+		return rc;
+	}
+
+	return 0;
+}
+
+static void __exit efx_mtd_exit_module(void)
+{
+	efx_dl_unregister_driver(&efx_eeprom_driver);
+	efx_dl_unregister_driver(&efx_flash_driver);
+}
+
+module_init(efx_mtd_init_module);
+module_exit(efx_mtd_exit_module);
+
+MODULE_AUTHOR("Michael Brown <mbrown at fensystems.co.uk> and "
+	      "Solarflare Communications");
+MODULE_DESCRIPTION("SFC MTD driver");
+MODULE_LICENSE("GPL");
--- /dev/null	2008-01-02 10:46:54.505379063 +0000
+++ drivers/net/sfc/spi.h	2008-01-14 16:32:46.000000000 +0000
@@ -0,0 +1,186 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * Copyright 2005:      Fen Systems Ltd.
+ * Copyright 2006:      Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Initially developed by Michael Brown <mbrown at fensystems.co.uk>
+ * Maintained by Solarflare Communications <linux-net-drivers at solarflare.com>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#ifndef EFX_SPI_H
+#define EFX_SPI_H
+
+#include "net_driver.h"
+
+/**************************************************************************
+ *
+ * Basic SPI command set and bit definitions
+ *
+ *************************************************************************/
+
+/*
+ * Commands common to all known devices.
+ *
+ */
+
+/* Write status register */
+#define SPI_WRSR 0x01
+
+/* Write data to memory array */
+#define SPI_WRITE 0x02
+
+/* Read data from memory array */
+#define SPI_READ 0x03
+
+/* Reset write enable latch */
+#define SPI_WRDI 0x04
+
+/* Read status register */
+#define SPI_RDSR 0x05
+
+/* Set write enable latch */
+#define SPI_WREN 0x06
+
+/* SST: Enable write to status register */
+#define SPI_SST_EWSR 0x50
+
+/*
+ * Status register bits.  Not all bits are supported on all devices.
+ *
+ */
+
+/* Write-protect pin enabled */
+#define SPI_STATUS_WPEN 0x80
+
+/* Block protection bit 2 */
+#define SPI_STATUS_BP2 0x10
+
+/* Block protection bit 1 */
+#define SPI_STATUS_BP1 0x08
+
+/* Block protection bit 0 */
+#define SPI_STATUS_BP0 0x04
+
+/* State of the write enable latch */
+#define SPI_STATUS_WEN 0x02
+
+/* Device busy flag */
+#define SPI_STATUS_NRDY 0x01
+
+/**************************************************************************
+ *
+ * Efx SPI devices
+ *
+ **************************************************************************
+ */
+
+/**
+ * struct efx_spi_device - an Efx SPI (Serial Peripheral Interface) device
+ * @device_id:		Controller's id for the device
+ * @size:		Size (in bytes)
+ * @addr_len:		Number of address bytes in read/write commands
+ * @munge_address:	Flag whether addresses should be munged.
+ *	Some devices with 9-bit addresses (e.g. AT25040A EEPROM)
+ *	use bit 3 of the command byte as address bit A8, rather
+ *	than having a two-byte address.  If this flag is set, then
+ *	commands should be munged in this way.
+ * @erase_command:	Erase command (or 0 if sector erase not needed).
+ * @erase_size:		Erase sector size (in bytes)
+ *	Erase commands affect sectors with this size and alignment.
+ *	This must be a power of two.
+ * @block_size:		Write block size (in bytes).
+ *	Write commands are limited to blocks with this size and alignment.
+ * @read:		Read function for the device
+ * @write:		Write function for the device
+ */
+struct efx_spi_device {
+	int device_id;
+	unsigned int size;
+	unsigned int addr_len;
+	unsigned int munge_address:1;
+	u8 erase_command;
+	unsigned int erase_size;
+	unsigned int block_size;
+	int (*read) (const struct efx_spi_device *spi,
+		     struct efx_nic *efx, unsigned int command,
+		     int address, void *data, unsigned int len);
+	int (*write) (const struct efx_spi_device *spi,
+		      struct efx_nic *efx, unsigned int command,
+		      int address, const void *data, unsigned int len);
+};
+
+/* Maximum length for SPI read or write through Falcon */
+#define FALCON_SPI_MAX_LEN 16U
+
+/**
+ * efx_spi_write_limit - calculate maximum permitted length for write
+ * @spi:		SPI device description
+ * @start:		Starting address
+ *
+ * Return the maximum length for a write starting at the given address
+ * in the device.
+ *
+ * SPI writes must not cross block boundaries.  Devices tend
+ * to wrap addresses at block boundaries; e.g. trying to write 5 bytes
+ * starting at offset 14 with a block size of 16 might write
+ * {14,15,0,1,2} rather than {14,15,16,17,18}.
+ */
+static inline unsigned int
+efx_spi_write_limit(const struct efx_spi_device *spi, unsigned int start)
+{
+	return min(FALCON_SPI_MAX_LEN,
+		   (spi->block_size - (start & (spi->block_size - 1))));
+}
+
+/**
+ * efx_spi_read_limit - calculate maximum permitted length for read
+ * @spi:		SPI device description
+ * @start:		Starting address
+ *
+ * Return the maximum length for a read starting at the given address
+ * in the device.
+ */
+static inline unsigned int
+efx_spi_read_limit(const struct efx_spi_device *spi __attribute__ ((unused)),
+		   unsigned int start __attribute__ ((unused)))
+{
+	return FALCON_SPI_MAX_LEN;
+}
+
+/**
+ * efx_spi_munge_command - adjust command as necessary for given address
+ * @spi:		SPI device description
+ * @command:		Normal SPI command
+ * @address:		Address for command
+ *
+ * Some devices with 9-bit addresses (e.g. AT25040A EEPROM) use bit 3
+ * of the command byte as address bit A8, rather than having a
+ * two-byte address.  This function calculates the appropriate command
+ * byte for the device, taking this munging into account.
+ */
+static inline u8 efx_spi_munge_command(const struct efx_spi_device *spi,
+					    const u8 command,
+					    const unsigned int address)
+{
+	return (command | (((address >> 8) & spi->munge_address) << 3));
+}
+
+#endif /* EFX_SPI_H */
--- /dev/null	2008-01-02 10:46:54.505379063 +0000
+++ drivers/net/sfc/driverlink_api.h	2008-01-14 16:32:46.000000000 +0000
@@ -0,0 +1,594 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * Copyright 2005-2006: Fen Systems Ltd.
+ * Copyright 2005-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Initially developed by Michael Brown <mbrown at fensystems.co.uk>
+ * Maintained by Solarflare Communications <linux-net-drivers at solarflare.com>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#ifndef EFX_DRIVERLINK_API_H
+#define EFX_DRIVERLINK_API_H
+
+#include <linux/list.h> /* for struct list_head */
+
+/**
+ * DOC: Efx driverlink API
+ *
+ * This file must be included by any driver that wishes to attach to
+ * devices claimed by the Solarflare nic driver (sfc). It allows separate
+ * kernel modules to expose other functionality offered by the NIC, with
+ * the sfc driver remaining in overall control.
+ *
+ * Overview:
+ *
+ * Driverlink clients define a &struct efx_dl_driver, and register
+ * this structure with the driverlink layer using
+ * efx_dl_register_driver(), which is exported by the sfc driver.
+ *
+ * The probe() routine of each driverlink client driver is called by
+ * the driverlink layer for each physical port in the system, after
+ * the sfc driver has performed start-of-day hardware initialisation
+ * and self-test. If ports are added or removed via pci hotplug then
+ * the &struct efx_dl_driver probe() or remove() routines are called
+ * as appropriate.
+ *
+ * If the port doesn't provide the necessary hardware resources for a
+ * client, then that client can return failure from its probe()
+ * routine. Information provided to the client driver at probe time
+ * includes
+ *
+ * Each probe() routine is given a unique &struct efx_dl_device per
+ * port, which means it can safely use the @priv member to store any
+ * useful state it needs. The probe routine also has the opportunity
+ * to provide a &struct efx_dl_callbacks via
+ * efx_dl_register_callbacks(), which allows the client to intercept
+ * the sfc driver's operations at strategic points.
+ *
+ * Occasionally, the underlying Efx device may need to be reset to
+ * recover from an error condition.  The client's reset_suspend() and
+ * reset_resume() methods [if provided] will be called to enable the
+ * client to suspend operations and preserve any state before the
+ * reset.  The client can itself request a reset using efx_dl_reset()
+ * or efx_dl_schedule_reset(), should it detect an error condition
+ * necessitating a reset.
+ *
+ * Example:
+ *
+ * The MTD driver (mtd.c) uses the driverlink layer.
+ */
+
+/* Forward declarations */
+struct pci_dev;
+struct net_device;
+struct sk_buff;
+struct efx_dl_device;
+struct efx_dl_device_info;
+
+/*
+ * This is used to guard against the registration of driverlink
+ * clients using an incorrect version of the API.
+ */
+#define EFX_DRIVERLINK_API_VERSION 1
+
+
+/**
+ * struct efx_dl_driver - An Efx driverlink device driver
+ *
+ * This is the analogue of a struct pci_driver for a normal PCI
+ * driver.  Driverlink clients should register themselves using
+ * efx_dl_register_driver() at module initialisation, and deregister
+ * themselves using efx_dl_unregister_driver() at module exit.
+ *
+ * All calls to members of efx_dl_driver are serialised by a single
+ * semaphore, so you are allowed to sleep in these functions. Take care
+ * to not call driverlink methods from within these callbacks, otherwise
+ * a deadlock is possible.
+ *
+ * @name: Name of the driver
+ * @probe: Called when device added
+ * @remove: Called when device removed
+ * @reset_suspend: Called before device is reset
+ * @reset_resume: Called after device is reset
+ */
+struct efx_dl_driver {
+	const char *name;
+
+	/*
+	 * probe - Handle device addition.
+	 * @efx_dev:		Efx driverlink device
+	 * @net_dev:		The net_dev relevent to this port
+	 * @dev_info:		A linked list of device information.
+	 * @silicon_rev:	Silicon revision name.
+	 *
+	 * This will be called after driverlink client registration for
+	 * every port on the system, and for every port that appears
+	 * thereafter via hotplug.
+	 *
+	 * The client may use either @efx_dev->pci_dev, the dev_info linked
+	 * list of available driver information, or the silicon revision
+	 * name to determine if they can support this port. If they can,
+	 * they should return 0 to indicate the probe was successful. Any
+	 * other return code indicates that the probe failed, and the
+	 * @efx_dl_dev will be invalidated.
+	 *
+	 * The client should perform whatever initialisation it
+	 * requires, and store a pointer to its private data in
+	 * @efx_dl_dev->priv (which is not shared between clients).
+	 * It may also wish to hook in a callbacks table using
+	 * efx_dl_register_callbacks().
+	 *
+	 * Return a negative error code or 0 on success.
+	 */
+	int (*probe) (struct efx_dl_device *efx_dl_dev,
+		      const struct net_device *net_dev,
+		      const struct efx_dl_device_info *dev_info,
+		      const char *silicon_rev);
+
+	/*
+	 * remove - Handle device removal.
+	 * @efx_dev:		Efx driverlink device
+	 *
+	 * This will be called at driver exit (or hotplug removal) for
+	 * each registered driverlink client.
+	 *
+	 * The client must ensure that it has finished all operations
+	 * using this device before returning from this method.  If it
+	 * has hooked in a callbacks table using
+	 * efx_dl_register_callbacks(), it must unhook it using
+	 * efx_dl_unregister_callbacks(), and then ensure that all
+	 * callback-triggered operations (e.g. scheduled tasklets)
+	 * have completed before returning.  (It does not need to
+	 * explicitly wait for callback methods to finish executing,
+	 * since efx_dl_unregister_callbacks() will sleep until all
+	 * callbacks have returned anyway.)
+	 *
+	 * Note that the device itself may not have been removed; it
+	 * may be simply that the client is being unloaded
+	 * via efx_dl_unregister_driver(). In this case other clients
+	 * (and the sfc driver itself) will still be using the device,
+	 * so the client cannot assume that the device itself is quiescent.
+	 * In particular, callbacks may continue to be triggered at any
+	 * point until efx_dl_unregister_callbacks() is called.
+	 */
+	void (*remove) (struct efx_dl_device *efx_dev);
+
+	/*
+	 * reset_suspend - Suspend ready for reset.
+	 * @efx_dev:		Efx driverlink device
+	 *
+	 * This method will be called immediately before a hardware
+	 * reset (which may or may not have been initiated by the
+	 * driverlink client).  This client must save any state that it
+	 * will need to restore after the reset, and suspend all
+	 * operations that might access the hardware.  It must not
+	 * return until the client can guarantee to have stopped
+	 * touching the hardware.
+	 *
+	 * It is guaranteed that callbacks will be inactive by the
+	 * time this method is called; the driverlink layer will
+	 * already have prevented new callbacks being made and waited
+	 * for all callbacks functions to return before calling
+	 * reset_suspend().  However, any delayed work scheduled by
+	 * the callback functions (e.g. tasklets) may not yet have
+	 * completed.
+	 *
+	 * This method is allowed to sleep, so waiting on tasklets,
+	 * work queues etc. is permitted.  There will always be a
+	 * corresponding call to the reset_resume() method, so it is
+	 * safe to e.g. down a semaphore within reset_suspend() and up
+	 * it within reset_resume().  (However, you obviously cannot
+	 * do the same with a spinlock).
+	 *
+	 * Note that the reset operation may be being carried out in
+	 * the context of scheduled work, so you cannot use
+	 * flush_scheduled_work() to ensure that any work you may have
+	 * scheduled has completed.
+	 *
+	 * During hardware reset, there is a chance of receiving
+	 * spurious interrupts, so the client's ISR (if any) should be
+	 * unhooked or otherwise disabled.
+	 */
+	void (*reset_suspend) (struct efx_dl_device *efx_dev);
+
+	/*
+	 * reset_resume - Restore after a reset.
+	 * @efx_dev:		Efx driverlink device
+	 * @ok:			Reset success indicator
+	 *
+	 * This method will be called after a hardware reset.  There
+	 * will always have been a corresponding call to the
+	 * reset_suspend() method beforehand.
+	 *
+	 * If @ok is non-zero, the client should restore the state
+	 * that it saved during the call to reset_suspend() and resume
+	 * normal operations.
+	 *
+	 * If @ok is zero, the reset operation has failed and the
+	 * hardware is currently in an unusable state.  In this case,
+	 * the client should release any locks taken out by
+	 * reset_suspend(), but should not take any other action; in
+	 * particular, it must not access the hardware, nor resume
+	 * normal operations.  The hardware is effectively dead at
+	 * this point, and our sole aim is to avoid deadlocking or
+	 * crashing the host.
+	 *
+	 * The driverlink layer will still be locked when
+	 * reset_resume() is called, so the client may not call
+	 * driverlink functions.  In particular, if the reset failed,
+	 * the client must not call efx_dl_unregister_callbacks() at
+	 * this point; it should wait until remove() is called.
+	 */
+	void (*reset_resume) (struct efx_dl_device *efx_dev, int ok);
+
+/* private: */
+	struct list_head node;
+	struct list_head device_list;
+};
+
+/**
+ * DOC: Efx driverlink device information
+ *
+ * Each &struct efx_dl_device makes certain hardware resources visible
+ * to driverlink clients, and they describe which resources are
+ * available by passing a linked list of &struct efx_dl_device_info
+ * into the probe() routine.
+ *
+ * The driverlink client's probe function can iterate through the linked list,
+ * and provided that it understands the resources that are exported, it can
+ * choose to make use of them through an external interface.
+ */
+
+/**
+ * enum efx_dl_device_info_type - Device information identifier.
+ *
+ * Each distinct hardware resource API will have a member in this
+ * enumeration.
+ *
+ * @EFX_DL_FALCON_RESOURCES: Information type is &struct efx_dl_falcon_resources
+ */
+enum efx_dl_device_info_type {
+	/** Falcon resources available for export */
+	EFX_DL_FALCON_RESOURCES = 0,
+};
+
+/**
+ * struct efx_dl_device_info - device information structure
+ * @next: Link to next structure, if any
+ * @type: Type code for this structure
+ *
+ * This structure is embedded in other structures provided by the
+ * driverlink device provider, and implements a linked list of
+ * resources pertinent to a driverlink client.
+ *
+ * Example: &struct efx_dl_falcon_resources
+ */
+struct efx_dl_device_info {
+	struct efx_dl_device_info *next;
+	enum efx_dl_device_info_type type;
+};
+
+/**
+ * enum efx_dl_falcon_resource_flags - Falcon resource information flags.
+ *
+ * Flags that describe hardware variations for the described Falcon based port.
+ *
+ * @EFX_DL_FALCON_DUAL_FUNC: Port is dual-function.
+ *	Certain silicon revisions have two pci functions, and require
+ *	certain hardware resources to be accessed via the secondary
+ *	function. See the discussion of @pci_dev in &struct efx_dl_device
+ *	below.
+ * @EFX_DL_FALCON_USE_MSI: Port is initialised to use MSI/MSI-X interrupts.
+ *	Falcon supports traditional legacy interrupts and MSI/MSI-X
+ *	interrupts. Since the sfc driver supports either, as a run
+ *	time configuration, driverlink drivers need to be aware of which
+ *	one to use for their interrupting resources.
+ */
+enum efx_dl_falcon_resource_flags {
+	EFX_DL_FALCON_DUAL_FUNC = 0x1,
+	EFX_DL_FALCON_USE_MSI = 0x2,
+};
+
+/**
+ * struct efx_dl_falcon_resources - Falcon resource information.
+ *
+ * This structure describes Falcon hardware resources available for
+ * use by a driverlink driver.
+ *
+ * @hdr: Resource linked list header
+ * @biu_lock: Register access lock.
+ *	Some Falcon revisions require register access for configuration
+ *	registers to be serialised between ports and PCI functions.
+ *	The sfc driver will provide the appropriate lock semantics for
+ *	the underlying hardware.
+ * @buffer_table_min: First available buffer table entry
+ * @buffer_table_max: Last available buffer table entry + 1
+ * @evq_timer_min: First available event queue with timer
+ * @evq_timer_max: Last available event queue with timer + 1
+ * @evq_int_min: First available event queue with interrupt
+ * @evq_int_max: Last available event queue with interrupt + 1
+ * @rxq_min: First available RX queue
+ * @rxq_max: Last available RX queue + 1
+ * @txq_min: First available TX queue
+ * @txq_max: Last available TX queue + 1
+ * @flags: Hardware variation flags
+ */
+struct efx_dl_falcon_resources {
+	struct efx_dl_device_info hdr;
+	spinlock_t *biu_lock;
+	unsigned buffer_table_min, buffer_table_max;
+	unsigned evq_timer_min, evq_timer_max;
+	unsigned evq_int_min, evq_int_max;
+	unsigned rxq_min, rxq_max;
+	unsigned txq_min, txq_max;
+	enum efx_dl_falcon_resource_flags flags;
+};
+
+/**
+ * struct efx_dl_device - An Efx driverlink device.
+ *
+ * @pci_dev: Underlying PCI device.
+ *	This is the PCI device used by the sfc driver.  It will
+ *	already have been enabled for bus-mastering DMA etc.
+ * @priv: Driver private data
+ *	Driverlink clients can use this to store a pointer to their
+ *	internal per-device data structure. Each (driver, device)
+ *	tuple has a seperate &struct efx_dl_device, so clients can use
+ *	this @priv field independently.
+ * @driver: Efx driverlink driver for this device
+ */
+struct efx_dl_device {
+	struct pci_dev *pci_dev;
+	void *priv;
+	struct efx_dl_driver *driver;
+};
+
+/**
+ * enum efx_veto - Packet veto request flag.
+ *
+ * This is the return type for the rx_packet() and tx_packet() methods
+ * in &struct efx_dl_callbacks.
+ *
+ * @EFX_ALLOW_PACKET: Packet may be transmitted/received
+ * @EFX_VETO_PACKET: Packet must not be transmitted/received
+ */
+enum efx_veto {
+	EFX_ALLOW_PACKET = 0,
+	EFX_VETO_PACKET = 1,
+};
+
+/**
+ * struct efx_dl_callbacks - Efx callbacks
+ *
+ * These methods can be hooked in to the sfc driver via
+ * efx_dl_register_callbacks().  They allow clients to intercept and/or
+ * modify the behaviour of the sfc driver at predetermined points.
+ *
+ * For efficiency, only one client can hook each callback.
+ *
+ * Since these callbacks are called on packet transmit and reception
+ * paths, clients should avoid acquiring locks or allocating memory.
+ *
+ * @tx_packet: Called when packet is about to be transmitted
+ * @rx_packet: Called when packet is received
+ * @link_change: Called when link status has changed
+ * @request_mtu: Called to request MTU change
+ * @mtu_changed: Called when MTU has been changed
+ * @event: Called when NIC event is not handled by the sfc driver
+ */
+struct efx_dl_callbacks {
+	/*
+	 * tx_packet - Packet about to be transmitted.
+	 * @efx_dev:		Efx driverlink device
+	 * @skb:		Socket buffer containing the packet to be sent
+	 *
+	 * This method is called for every packet about to be
+	 * transmitted.  It allows the client to snoop on traffic sent
+	 * via the kernel queues.
+	 *
+	 * The method may return %EFX_VETO_PACKET in order to prevent
+	 * the sfc driver from transmitting the packet.  The net
+	 * driver will then discard the packet.  If the client wishes
+	 * to retain a reference to the packet data after returning
+	 * %EFX_VETO_PACKET, it must obtain its own copy of the
+	 * packet (e.g. by calling skb_get(), or by copying out the
+	 * packet data to an external buffer).
+	 *
+	 * This method must return quickly, since it will have a
+	 * direct performance impact upon the sfc driver.  It will be
+	 * called with interrupts disabled (and may be called in
+	 * interrupt context), so may not sleep. Since the sfc driver
+	 * may have multiple tx queues, running in parallel, please avoid
+	 * the need for locking if it all possible.
+	 */
+	enum efx_veto (*tx_packet) (struct efx_dl_device *efx_dev,
+				    struct sk_buff *skb);
+
+	/*
+	 * rx_packet - Packet received.
+	 * @efx_dev:		Efx driverlink device
+	 * @pkt_hdr:		Pointer to received packet
+	 * @pkt_len:		Length of received packet
+	 *
+	 * This method is called for every received packet.  It allows
+	 * the client to snoop on traffic received by the kernel
+	 * queues.
+	 *
+	 * The method may return %EFX_VETO_PACKET in order to prevent
+	 * the sfc driver from passing the packet to the kernel.  The net
+	 * driver will then discard the packet.
+	 *
+	 * This method must return quickly, since it will have a
+	 * direct performance impact upon the sfc driver.  It is
+	 * called in tasklet context, so may not sleep.  Note that
+	 * there are per-channel tasklets in the sfc driver, so
+	 * rx_packet() may be called simultaneously on different CPUs
+	 * and must lock appropriately.  The design of the sfc driver
+	 * allows for lockless operation between receive channels, so
+	 * please avoid the need for locking if at all possible.
+	 */
+	enum efx_veto (*rx_packet) (struct efx_dl_device *efx_dev,
+				    const char *pkt_hdr, int pkt_len);
+
+	/*
+	 * link_change - Link status change.
+	 * @efx_dev:		Efx driverlink device
+	 * @link_up:		Link up indicator
+	 *
+	 * This method is called to inform the driverlink client
+	 * whenever the PHY link status changes.  By the time this
+	 * function is called, the MAC has already been reconfigured
+	 * with the new autonegotiation settings from the PHY.
+	 *
+	 * This method is called from tasklet context and may not
+	 * sleep.
+	 */
+	void (*link_change) (struct efx_dl_device *efx_dev, int link_up);
+
+	/*
+	 * request_mtu: Request MTU change.
+	 * @efx_dev:		Efx driverlink device
+	 * @new_mtu:		Requested new MTU
+	 *
+	 * This method is called whenever the user requests an MTU
+	 * change on an interface.  The client may return an error, in
+	 * which case the MTU change request will be denied.  If the
+	 * client returns success, the MAC will be reconfigured with a
+	 * new maxmimum frame length equal to
+	 * EFX_MAX_FRAME_LEN(new_mtu).  The client will be notified
+	 * via the mtu_changed() method once the MAC has been
+	 * reconfigured.
+	 *
+	 * The current MTU for the port can be obtained via
+	 * efx_dl_get_netdev(efx_dl_device)->mtu.
+	 *
+	 * The sfc driver guarantees that no other callback functions
+	 * are in progress when this method is called.  This function
+	 * is called in process context and may sleep.
+	 *
+	 * Return a negative error code or 0 on success.
+	 */
+	int (*request_mtu) (struct efx_dl_device *efx_dev, int new_mtu);
+
+	/*
+	 * mtu_changed - MTU has been changed.
+	 * @efx_dev:		Efx driverlink device
+	 * @mtu:		The new MTU
+	 *
+	 * This method is called once the MAC has been reconfigured
+	 * with a new MTU.  There will have been a preceding call to
+	 * request_mtu().
+	 *
+	 * The sfc driver guarantees that no other callback functions
+	 * are in progress when this method is called.  This function
+	 * is called in process context and may sleep.
+	 */
+	void (*mtu_changed) (struct efx_dl_device *efx_dev, int mtu);
+
+	/*
+	 * event - Event callback.
+	 * @efx_dev:		Efx driverlink device
+	 * @p_event:		Pointer to event
+	 *
+	 * This method is called for each event that is not handled by the
+	 * sfc driver.
+	 */
+	void (*event) (struct efx_dl_device *efx_dev, void *p_event);
+};
+
+/* Include API version number in symbol used for efx_dl_register_driver */
+#define efx_dl_stringify_1(x, y) x ## y
+#define efx_dl_stringify_2(x, y) efx_dl_stringify_1(x, y)
+#define efx_dl_register_driver					\
+	efx_dl_stringify_2(efx_dl_register_driver_api_ver_,	\
+			   EFX_DRIVERLINK_API_VERSION)
+
+extern int efx_dl_register_driver(struct efx_dl_driver *driver);
+
+extern void efx_dl_unregister_driver(struct efx_dl_driver *driver);
+
+extern int efx_dl_register_callbacks(struct efx_dl_device *efx_dev,
+				     struct efx_dl_callbacks *callbacks);
+
+extern void efx_dl_unregister_callbacks(struct efx_dl_device *efx_dev,
+					struct efx_dl_callbacks *callbacks);
+
+extern void efx_dl_schedule_reset(struct efx_dl_device *efx_dev);
+
+/**
+ * efx_dl_for_each_device_info_matching - iterate an efx_dl_device_info list
+ * @_dev_info: Pointer to first &struct efx_dl_device_info
+ * @_type: Type code to look for
+ * @_info_type: Structure type corresponding to type code
+ * @_field: Name of &struct efx_dl_device_info field in the type
+ * @_p: Iterator variable
+ *
+ * Example:
+ *
+ * static int driver_dl_probe(... const struct efx_dl_device_info *dev_info ...)
+ * {
+ *        struct efx_dl_falcon_resources *res;
+ *
+ *        efx_dl_for_each_device_info_matching(dev_info,EFX_DL_FALCON_RESOURCES,
+ *                                             struct efx_dl_falcon_resources,
+ *                                             hdr, res) {
+ *                if (res->flags & EFX_DL_FALCON_DUAL_FUNC) {
+ *                          .....
+ *                }
+ *        }
+ * }
+ */
+#define efx_dl_for_each_device_info_matching(_dev_info, _type, _info_type, \
+						_field, _p);		\
+	for ((_p) = container_of((_dev_info), _info_type, _field);	\
+	     (_p) != NULL;						\
+	     (_p) = container_of((_p)->_field.next, _info_type, _field))\
+		if ((_p)->_field.type != _type)				\
+			continue;					\
+		else
+
+/**
+ * efx_dl_search_device_info - search an efx_dl_device_info list
+ * @_dev_info: Pointer to first &struct efx_dl_device_info
+ * @_type: Type code to look for
+ * @_info_type: Structure type corresponding to type code
+ * @_field: Name of &struct efx_dl_device_info member in this type
+ * @_p: Result variable
+ *
+ * Example:
+ *
+ * static int driver_dl_probe(... const struct efx_dl_device_info *dev_info ...)
+ * {
+ *        struct efx_dl_falcon_resources *res;
+ *
+ *        efx_dl_search_device_info(dev_info, EFX_DL_FALCON_RESOURCES,
+ *                                  struct efx_dl_falcon_resources, hdr, res);
+ *        if (res != NULL) {
+ *                 ....
+ *        }
+ * }
+ */
+#define efx_dl_search_device_info(_dev_info, _type, _info_type, _field, _p) \
+	efx_dl_for_each_device_info_matching((_dev_info), (_type),	    \
+					     (_info_type), (_field), (_p))  \
+	     break;
+
+#endif /* EFX_DRIVERLINK_API_H */
--- END ---

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.


From jamie at shareable.org  Tue Jan 15 09:08:00 2008
From: jamie at shareable.org (Jamie Lokier)
Date: Tue, 15 Jan 2008 14:08:00 +0000
Subject: JFFS2 determine writing state
In-Reply-To: <20080112141508.22b19686@vader.jdub.homelinux.org>
References: <298338.39997.qm@web56002.mail.re3.yahoo.com>
	<20080111075730.052c821d@zod.rchland.ibm.com>
	<20080112100343.GC1497@shareable.org>
	<20080112141508.22b19686@vader.jdub.homelinux.org>
Message-ID: <20080115140759.GE11941@shareable.org>

Josh Boyer wrote:
> On Sat, 12 Jan 2008 10:03:43 +0000 Jamie Lokier <jamie at shareable.org> wrote:
> 
> > Josh Boyer wrote:
> > > The open call doesn't cause any writes, and close
> > > is supposed to flush all pending writes before it returns.
> > 
> > Oh, that's interesting.  So on JFFS2, fsync() is unnecessary
> > before close()?
> > 
> > (On other filesystems it's necessary, of course).
> 
> To be honest, it doesn't really matter if it's necessary or not.
> Writing an application to do as little as possible based on implicit
> knowledge of the underlying filesystem seems like a really bad idea.
> Particularly with the behavior of the filesystem can change based on
> which config options you have set (writebuffer, etc).
> 
> Write you applications to be portable and cautious and you shouldn't
> have a problem.

That's quite reasonable and of course I do call fsync, both on a file
before closing it, and then on its parent directory after renaming a
replacement file into place (just like usual mail software).

But the particular fs behaviour is relevant the other way around: I
have a program which calls open/write/close with small writes
moderately often (because it calls another program which actually
operates on the file).

If JFFS2 commits pending writes on every close, I should change things
to keep the file open between writes so they are coalesced and faster,
when I don't need the individual writes to be committed separately.
When I do need the data committed I can use fsync of course.

In which case, if a program A opens a file on JFFS2, and forks/execs
program B which writes data, then does an implicit close (when it
exits), while B's writes be committed immediately (which isn't wanted)
even though A still has the descriptor open?

Thanks,
-- Jamie


From joern at logfs.org  Tue Jan 15 10:48:31 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Tue, 15 Jan 2008 16:48:31 +0100
Subject: Slow mount of JFFS2 root file system
In-Reply-To: <BBF94D674CC54C48B62BD0667061E8490199FA73@PAUMAILU02.ags.agere.com>
References: <BBF94D674CC54C48B62BD0667061E8490199FA73@PAUMAILU02.ags.agere.com>
Message-ID: <20080115154831.GB22338@lazybastard.org>

On Tue, 15 January 2008 09:22:04 -0500, Lin, Bin (Bin) wrote:
> 
> I have ARM9 systems with JFFS2 root file system. For some reasons, e.g.
> system crash or power failure, when system boots up next time, it takes
> much longer time than usual to mount jffs2 root file system. It can hang
> at following message for 3-10 min. Once this happens, the mount will
> take the same long time in every reboot later on. Even though it take
> long time to mount root file system, the system can still come up and
> function well. This problem occurred in less than 10% of boards in the
> field, but can not be reproduced in the lab. I have been struggling with
> this is issue for weeks.

What stops you from retrieving one such board from the field?  Should be
easy to debug once you have it on your desk.

J?rn

-- 
Prosperity makes friends, adversity tries them.
-- Publilius Syrus


From joern at logfs.org  Tue Jan 15 11:46:13 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Tue, 15 Jan 2008 17:46:13 +0100
Subject: [PATCH] [MTD] [RFC] New Solarflare NIC EEPROM/Flash driver (2nd
	try)
In-Reply-To: <20080114170358.GO3544@solarflare.com>
References: <47866921.40904@solarflare.com>
	<20080114170358.GO3544@solarflare.com>
Message-ID: <20080115164613.GC22338@lazybastard.org>

On Mon, 14 January 2008 17:04:00 +0000, Ben Hutchings wrote:
> 
> This patch contains just the MTD driver code (mtd.c) and the two most
> important header files it shares with our net driver.  The low-level
> code to access the SPI bus through the network controller is not
> included (and is unchanged from last time aside from a small change to
> length validation).  Hopefully this should be more amenable to review,
> though it cannot be compiled.

Hehe.  Maybe next time I can get both?  

Most comments below are fairly generic and can be applied many times
over, both for mtd.c and the rest.

> --- /dev/null	2008-01-02 10:46:54.505379063 +0000
> +++ drivers/net/sfc/mtd.c	2008-01-14 16:32:46.000000000 +0000
> @@ -0,0 +1,655 @@
> +/****************************************************************************
> + * Driver for Solarflare network controllers
> + *           (including support for SFE4001 10GBT NIC)
> + *
> + * Copyright 2005-2006: Fen Systems Ltd.
> + * Copyright 2006-2008: Solarflare Communications Inc,
> + *                      9501 Jeronimo Road, Suite 250,
> + *                      Irvine, CA 92618, USA
> + *
> + * Initially developed by Michael Brown <mbrown at fensystems.co.uk>
> + * Maintained by Solarflare Communications <linux-net-drivers at solarflare.com>
> + *
> + * 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, incorporated herein by reference.
> + *
> + * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
> + ****************************************************************************

Those GPL preambles in every file sure suck.  I guess you cannot
convince your corporate lawyers to remove them.  But at least you can
kill those stars-only lines.

> + */
> +
> +#include <linux/module.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/partitions.h>
> +#include <linux/delay.h>
> +
> +#define EFX_DRIVER_NAME "sfc_mtd"
> +#include "driverlink_api.h"
> +#include "net_driver.h"
> +#include "spi.h"
> +
> +/*
> + * Flash and EEPROM (MTD) device driver
> + *
> + * This file provides a separate kernel module (sfc_mtd) which
> + * exposes the flash and EEPROM devices present on Solarflare NICs as
> + * MTD devices, enabling you to reflash the boot ROM code (or use the
> + * remaining space on the flash as a jffs2 filesystem, should you want
> + * to do so).
> + */
> +
> +#define EFX_MTD_VERIFY_BUF_LEN 4096
> +#define EFX_MAX_PARTITIONS 2
> +#define EFX_FLASH_BOOTROM_OFFSET 0x8000U
> +
> +/* Write enable for EEPROM/Flash configuration area
> + *
> + * Normally, writes to parts of non-volatile storage which contain
> + * critical configuration are disabled to prevent accidents.  This
> + * parameter allows enabling of such writes.
> + */
> +static unsigned int efx_allow_nvconfig_writes;
> +
> +struct efx_mtd {
> +	struct mtd_info mtd;
> +	struct mtd_partition mtd_part[EFX_MAX_PARTITIONS];
> +	struct semaphore access_lock;
> +	char part_name[EFX_MAX_PARTITIONS][32];
> +	char name[32];
> +	struct efx_dl_device *efx_dev; /* driverlink */

Rename to struct efx_driver_link and kill the comment?

> +	struct efx_nic *efx; 
> +	struct efx_spi_device *spi;

Needing three seperate pointers to some struct efc_* is... interesting.
Usually one would be enough and the other two can be derived.

> +};
> +
> +/**************************************************************************
> + *
> + * SPI flash/EEPROM utilities
> + *
> + **************************************************************************/

Is this comment necessary?

> +static int efx_spi_fast_wait(struct efx_mtd *efx_mtd)
> +{
> +	struct efx_spi_device *spi = efx_mtd->spi;
> +	u8 status;
> +	int i, rc;
> +
> +	/* Wait up to 1000us for flash/EEPROM to finish a fast operation. */
> +	for (i = 0; i < 50; i++) {
> +		udelay(20);
> +
> +		rc = spi->read(spi, efx_mtd->efx, SPI_RDSR, -1,
> +			       &status, sizeof(status));
> +		if (rc != 0)

if (rc)

> +			return rc;
> +		if (!(status & SPI_STATUS_NRDY))
> +			return 0;
> +	}
> +	EFX_ERR(efx_mtd->efx, "timed out waiting for %s last status=0x%02x\n",
> +		efx_mtd->name, status);
> +	return -ETIMEDOUT;
> +}
> +
> +static int efx_spi_slow_wait(struct efx_mtd *efx_mtd)
> +{
> +	struct efx_spi_device *spi = efx_mtd->spi;
> +	u8 status;
> +	int rc, i;
> +
> +	/* Wait up to 4s for flash/EEPROM to finish a slow operation. */
> +	for (i = 0; i < 40; i++) {
> +		schedule_timeout_interruptible(HZ / 10);
> +		rc = spi->read(spi, efx_mtd->efx, SPI_RDSR, -1,
> +			       &status, sizeof(status));
> +		if (rc != 0)
> +			return rc;
> +		if (!(status & SPI_STATUS_NRDY))
> +			return 0;
> +		if (signal_pending(current))
> +			return -EINTR;
> +	}
> +	EFX_ERR(efx_mtd->efx, "timed out waiting for %s\n", efx_mtd->name);
> +	return -ETIMEDOUT;
> +}
> +
> +/* Enable flash/EEPROM programming (and erasure). */
> +static inline int

With today's compilers, "inline" is fairly pointless, unless you have
tricky inline assembly.

> +efx_spi_write_enable(struct efx_mtd *efx_mtd)
> +{
> +	struct efx_spi_device *spi = efx_mtd->spi;
> +
> +	return spi->write(spi, efx_mtd->efx, SPI_WREN, -1, NULL, 0);
> +}
> +
> +/* Remove any write protection on the flash/EEPROM. */

Self-evident to flash people.

> +static int efx_spi_unlock(struct efx_mtd *efx_mtd)
> +{
> +	struct efx_spi_device *spi = efx_mtd->spi;
> +	const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 |
> +				     SPI_STATUS_BP0);
> +	u8 status;
> +	int rc;
> +
> +	rc = spi->read(spi, efx_mtd->efx, SPI_RDSR, -1, &status,
> +		       sizeof(status));
> +	if (rc != 0)
> +		return rc;
> +
> +	if (!(status & unlock_mask))
> +		return 0; /* already unlocked */
> +
> +	rc = efx_spi_write_enable(efx_mtd);
> +	if (rc != 0)
> +		return rc;
> +	rc = spi->write(spi, efx_mtd->efx, SPI_SST_EWSR, -1, NULL, 0);
> +	if (rc != 0)
> +		return rc;
> +
> +	status &= ~unlock_mask;
> +	rc = spi->write(spi, efx_mtd->efx, SPI_WRSR, -1, &status,
> +			sizeof(status));
> +	if (rc != 0)
> +		return rc;
> +	rc = efx_spi_fast_wait(efx_mtd);
> +	if (rc != 0)
> +		return rc;
> +
> +	return 0;
> +}
> +
> +/* Dummy device used in case of a failed reset. */
> +
> +static int efx_spi_dummy_read(const struct efx_spi_device *spi,
> +			      struct efx_nic *efx, unsigned int command,
> +			      int address, void *data, unsigned int len)
> +{
> +	return -EIO;
> +}
> +
> +static int efx_spi_dummy_write(const struct efx_spi_device *spi,
> +			       struct efx_nic *efx, unsigned int command,
> +			       int address, const void *data, unsigned int len)
> +{
> +	return -EIO;
> +}
> +
> +static struct efx_spi_device efx_spi_dummy_device = {
> +	.block_size	= 1,
> +	.erase_command	= 0xff,
> +	.read		= efx_spi_dummy_read,
> +	.write		= efx_spi_dummy_write,
> +};
> +
> +/**************************************************************************
> + *
> + * Interface to MTD layer
> + *
> + **************************************************************************/

Kill.

> +static int efx_mtd_read(struct mtd_info *mtd, loff_t start, size_t len,
> +			size_t *retlen, u8 *buffer)
> +{
> +	struct efx_mtd *efx_mtd = (struct efx_mtd *)mtd->priv;
> +	struct efx_spi_device *spi;
> +	unsigned int command;
> +	unsigned int block_len;
> +	unsigned int pos = 0;
> +	int rc;
> +
> +	rc = down_interruptible(&efx_mtd->access_lock);
> +	if (rc != 0)
> +		goto out;
> +	spi = efx_mtd->spi;
> +
> +	while (pos < len) {
> +		block_len = min((unsigned int)len - pos,
> +				efx_spi_read_limit(spi, start + pos));
> +		command = efx_spi_munge_command(spi, SPI_READ, start + pos);
> +		rc = spi->read(spi, efx_mtd->efx, command, start + pos,
> +			       buffer + pos, block_len);
> +		if (rc != 0)
> +			goto out_up;
> +		pos += block_len;
> +
> +		/* Avoid locking up the system */
> +		cond_resched();
> +		if (signal_pending(current))
> +			return -EINTR;
> +	}
> +
> +out_up:
> +	up(&efx_mtd->access_lock);
> +out:
> +	*retlen = pos;
> +	return rc;
> +}
> +
> +/* Check that device contents are as expected.  If buffer is NULL,
> + * contents will be checked to be empty (i.e. all 0xff).
> + */
> +static int efx_mtd_verify(struct mtd_info *mtd, loff_t offset,
> +			  size_t len, const u8 *buffer)
> +{
> +	struct efx_mtd *efx_mtd = (struct efx_mtd *)mtd->priv;

Remove cast.

> +	u8 *verify_buffer = NULL;
> +	size_t buf_len;
> +	size_t read_len;
> +	int i;
> +	u8 expected = 0xff;
> +	int rc = 0;
> +
> +	verify_buffer = kmalloc(EFX_MTD_VERIFY_BUF_LEN, GFP_KERNEL);
> +	if (!verify_buffer) {
> +		rc = -ENOMEM;
> +		goto out;
> +	}
> +
> +	/* Check device contents, EFX_MTD_VERIFY_BUF_LEN at a time */
> +	while (len > 0) {
> +		buf_len = ((len < EFX_MTD_VERIFY_BUF_LEN) ?
> +			   len : EFX_MTD_VERIFY_BUF_LEN);
> +		rc = efx_mtd_read(mtd, offset, buf_len, &read_len,
> +				  verify_buffer);
> +		if (rc != 0)
> +			goto out;
> +		EFX_ASSERT(read_len == buf_len);

You can replace EFX_ASSERT with BUG_ON (with negated condition)
throughout the code.  Duplicating existing kernel infrastructure needs a
very good reason to be accepted.

> +		/* Check contents */
> +		for (i = 0; i < buf_len; i++) {
> +			if (buffer)
> +				expected = buffer[i];
> +			if (verify_buffer[i] != expected) {
> +				EFX_ERR(efx_mtd->efx, "%s offset %lx contains "
> +					"%02x, should be %02x\n", efx_mtd->name,
> +					(unsigned long)(offset + i),
> +					verify_buffer[i], expected);
> +				rc = -EIO;
> +				goto out;
> +			}
> +		}

Home-brewn memcmp?

> +
> +		if (buffer)
> +			buffer += buf_len;
> +		offset += buf_len;
> +		len -= buf_len;
> +	}
> +	EFX_ASSERT(len == 0);
> +
> +out:
> +	kfree(verify_buffer);
> +
> +	return rc;
> +}
> +
> +static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
> +{
> +	struct efx_mtd *efx_mtd = (struct efx_mtd *)mtd->priv;
> +	struct efx_spi_device *spi;
> +	int rc;
> +
> +	rc = down_interruptible(&efx_mtd->access_lock);

What is this semaphore protecting?

> +	if (rc != 0)
> +		goto out;
> +	spi = efx_mtd->spi;
> +	if (spi->erase_command == 0) {
> +		rc = -EOPNOTSUPP;
> +		goto out_up;
> +	}
> +	if (erase->len != efx_mtd->mtd.erasesize) {
> +		rc = -EINVAL;
> +		goto out_up;
> +	}

I bet that none of the above needs such protection.  Please have the
semaphore (and any locks, for that matter) cover the least amount of
code possible.

> +	rc = efx_spi_unlock(efx_mtd);

It appears, as if the semaphore could be dropped here and retaken later.
If so, please do.  And immediatly after that, move the semaphore into
efx_spi_unlock().  Repeat and try to push it as far down the callchain
as possible.

My gut instinct tells me that you can push it through to only protect
the pure bus access and don't need a semaphore in mtd.c at all.  At that
point you can probably replace it with a mutex.  Maybe I am wrong, but
even then please cover the least amount of code possible.  And do
document what the semaphore is protecting.

> +	if (rc != 0)
> +		goto out_up;
> +	rc = efx_spi_write_enable(efx_mtd);
> +	if (rc != 0)
> +		goto out_up;
> +	rc = spi->write(spi, efx_mtd->efx, spi->erase_command, erase->addr,
> +			NULL, 0);
> +	if (rc != 0)
> +		goto out_up;
> +	rc = efx_spi_slow_wait(efx_mtd);
> +
> +out_up:
> +	up(&efx_mtd->access_lock);
> +	if (rc == 0)
> +		rc = efx_mtd_verify(mtd, erase->addr, erase->len, NULL);
> +out:
> +	if (rc == 0) {
> +		erase->state = MTD_ERASE_DONE;
> +	} else {
> +		erase->state = MTD_ERASE_FAILED;
> +		erase->fail_addr = 0xffffffff;

???

> +	}
> +	mtd_erase_callback(erase);
> +	return rc;
> +}
> +
> +static int efx_mtd_write(struct mtd_info *mtd, loff_t start,
> +			 size_t len, size_t *retlen, const u8 *buffer)
> +{
> +	struct efx_mtd *efx_mtd = (struct efx_mtd *)mtd->priv;
> +	struct efx_spi_device *spi;
> +	unsigned int command;
> +	unsigned int block_len;
> +	unsigned int pos = 0;
> +	int rc;
> +
> +	rc = down_interruptible(&efx_mtd->access_lock);
> +	if (rc != 0)
> +		goto out;
> +	spi = efx_mtd->spi;
> +
> +	rc = efx_spi_unlock(efx_mtd);
> +	if (rc != 0)
> +		goto out_up;
> +
> +	while (pos < len) {
> +		rc = efx_spi_write_enable(efx_mtd);
> +		if (rc != 0)
> +			goto out_up;
> +
> +		block_len = min((unsigned int)len - pos,
> +				efx_spi_write_limit(spi, start + pos));
> +		command = efx_spi_munge_command(spi, SPI_WRITE, start + pos);
> +		rc = spi->write(spi, efx_mtd->efx, command, start + pos,
> +				buffer + pos, block_len);
> +		if (rc != 0)
> +			goto out_up;
> +		pos += block_len;
> +
> +		rc = efx_spi_fast_wait(efx_mtd);
> +		if (rc != 0)
> +			goto out_up;
> +
> +		/* Avoid locking up the system */
> +		cond_resched();
> +		if (signal_pending(current)) {
> +			rc = -EINTR;
> +			goto out_up;
> +		}
> +	}
> +
> +out_up:
> +	up(&efx_mtd->access_lock);
> +	if (rc == 0)
> +		rc = efx_mtd_verify(mtd, start, len, buffer);
> +out:
> +	*retlen = pos;
> +	return rc;
> +}
> +
> +static void efx_mtd_sync(struct mtd_info *mtd)
> +{
> +	struct efx_mtd *efx_mtd = (struct efx_mtd *)mtd->priv;
> +	int rc;
> +
> +	down(&efx_mtd->access_lock);
> +	rc = efx_spi_slow_wait(efx_mtd);
> +	if (rc != 0)
> +		EFX_ERR(efx_mtd->efx, "%s sync failed (%d)\n",
> +			efx_mtd->name, rc);

How do you handle -EINTR?

> +	up(&efx_mtd->access_lock);
> +}
> +
> +/**************************************************************************
> + *
> + * Efx MTD device driver
> + *
> + **************************************************************************/

Kill.

> +/* Prepare for device reset */
> +static void efx_mtd_reset_suspend(struct efx_dl_device *efx_dev)
> +{
> +	struct efx_mtd *efx_mtd = efx_dev->priv;
> +
> +	if (!efx_mtd)
> +		return;
> +
> +	/* Acquire lock to ensure that any in-progress operations have
> +	 * completed, and no new ones can start.
> +	 */
> +	down(&efx_mtd->access_lock);
> +}
> +
> +/* Resume after device reset */
> +static void efx_mtd_reset_resume(struct efx_dl_device *efx_dev, int ok)
> +{
> +	struct efx_mtd *efx_mtd = efx_dev->priv;
> +
> +	if (!efx_mtd)
> +		return;
> +
> +	/* If device reset failed already, or SPI device doesn't
> +	 * become ready, disable device.
> +	 */
> +	if (!ok || efx_spi_slow_wait(efx_mtd) != 0) {
> +		efx_mtd->spi = &efx_spi_dummy_device;
> +		EFX_ERR(efx_mtd->efx, "%s disabled after failed reset\n",
> +			efx_mtd->name);
> +	}
> +
> +	up(&efx_mtd->access_lock);
> +}
> +
> +static void efx_mtd_remove(struct efx_dl_device *efx_dev)
> +{
> +	struct efx_mtd *efx_mtd = efx_dev->priv;
> +
> +	del_mtd_partitions(&efx_mtd->mtd);
> +	kfree(efx_mtd);
> +	efx_dev->priv = NULL;
> +}
> +
> +static int __devinit
> +efx_mtd_probe(struct efx_dl_device *efx_dev, struct efx_nic *efx,
> +	      struct efx_spi_device *spi,
> +	      const char *mtd_type_name, struct mtd_info *template,
> +	      struct mtd_partition *partitions, unsigned int num_partitions)
> +{
> +	struct efx_mtd *efx_mtd;
> +	size_t s = sizeof(efx_mtd->name);
> +	int rc;
> +	int i;
> +
> +	efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL);
> +	if (!efx_mtd)
> +		goto err_mem;
> +	efx_dev->priv = efx_mtd;
> +
> +	/* Initialise structure */
> +	efx_mtd->efx_dev = efx_dev;
> +	efx_mtd->efx = efx;
> +	efx_mtd->spi = spi;
> +	sema_init(&efx_mtd->access_lock, 1);
> +	memcpy(&efx_mtd->mtd, template, sizeof(efx_mtd->mtd));

I'm not too fond of this memcpy approach.  In particular because this
function is called probe and does no such thing.

Instead this function could allocate a structure and initialize any
common fields.  Remaining fields would then be initialized in the two
actual probe functions below.

> +	if (snprintf(efx_mtd->name, s, "%s %s", efx_mtd->efx->name,
> +		     mtd_type_name) >= s)
> +		goto err_len;
> +
> +	efx_mtd->mtd.priv = efx_mtd;
> +	efx_mtd->mtd.name = efx_mtd->name;
> +	efx_mtd->mtd.erase = efx_mtd_erase;
> +	efx_mtd->mtd.read = efx_mtd_read;
> +	efx_mtd->mtd.write = efx_mtd_write;
> +	efx_mtd->mtd.sync = efx_mtd_sync;
> +
> +	EFX_ASSERT(template->numeraseregions == 0);
> +
> +	EFX_ASSERT(partitions != NULL);
> +	EFX_ASSERT(num_partitions > 0);
> +	EFX_ASSERT(num_partitions <= EFX_MAX_PARTITIONS);

And I assume most of these assertions are bogus and can be removed.

> +	s = sizeof(efx_mtd->part_name[0]);
> +
> +	for (i = 0; i < num_partitions; i++) {
> +		memcpy(&efx_mtd->mtd_part[i], &partitions[i],
> +		       sizeof(efx_mtd->mtd_part[i]));
> +		if (snprintf(efx_mtd->part_name[i], s, "%s %s",
> +			     efx_mtd->efx->name, partitions[i].name) >= s)
> +			goto err_len;
> +
> +		efx_mtd->mtd_part[i].name = efx_mtd->part_name[i];
> +		if (efx_allow_nvconfig_writes != 0)
> +			efx_mtd->mtd_part[i].mask_flags &= ~MTD_WRITEABLE;
> +	}
> +
> +	rc = add_mtd_partitions(&efx_mtd->mtd, efx_mtd->mtd_part,
> +				num_partitions);
> +	if (rc != 0)
> +		goto err;
> +
> +	return 0;
> +
> + err_mem:
> +	rc = -ENOMEM;
> +	goto err;
> + err_len:
> +	rc = -ENAMETOOLONG;
> + err:
> +	efx_mtd_remove(efx_dev);
> +	return rc;
> +}
> +
> +static int __devinit
> +efx_flash_probe(struct efx_dl_device *efx_dev,
> +		const struct net_device *net_dev,
> +		const struct efx_dl_device_info *dev_info,
> +		const char *silicon_rev)
> +{
> +	struct efx_nic *efx = efx_dl_get_nic_port(efx_dev)->efx;
> +	struct mtd_partition partitions[2] = {};
> +	unsigned int num_partitions;
> +	struct mtd_info template = {
> +		.numeraseregions = 0,
> +		.type = MTD_NORFLASH,
> +		.flags = MTD_CAP_NORFLASH,
> +		.writesize = 1
> +	};
> +
> +	if (!efx->spi_flash)
> +		return -EINVAL;
> +
> +	template.size = efx->spi_flash->size;
> +	template.erasesize = efx->spi_flash->erase_size;
> +
> +	partitions[0].name = "sfc_flash_config";
> +	partitions[0].offset = 0;
> +	partitions[0].size = min(efx->spi_flash->size,
> +				 EFX_FLASH_BOOTROM_OFFSET);
> +	partitions[0].mask_flags = MTD_WRITEABLE;
> +
> +	if (efx->spi_flash->size <= EFX_FLASH_BOOTROM_OFFSET) {
> +		num_partitions = 1;
> +	} else {
> +		/* Expansion ROM image */
> +		partitions[1].name = "sfc_flash_bootrom";
> +		partitions[1].offset = EFX_FLASH_BOOTROM_OFFSET;
> +		partitions[1].size = (efx->spi_flash->size
> +				      - EFX_FLASH_BOOTROM_OFFSET);
> +		num_partitions = 2;
> +	}
> +
> +	return efx_mtd_probe(efx_dev, efx, efx->spi_flash,
> +			     "sfc_flash", &template,
> +			     partitions, num_partitions);
> +}
> +
> +static struct efx_dl_driver efx_flash_driver = {
> +	.name		= "sfc_flash",
> +	.probe		= efx_flash_probe,
> +	.remove		= efx_mtd_remove,
> +	.reset_suspend	= efx_mtd_reset_suspend,
> +	.reset_resume	= efx_mtd_reset_resume,
> +};
> +
> +static int __devinit
> +efx_eeprom_probe(struct efx_dl_device *efx_dev,
> +		 const struct net_device *net_dev,
> +		 const struct efx_dl_device_info *dev_info,
> +		 const char *silicon_rev)
> +{
> +	struct efx_nic *efx = efx_dl_get_nic_port(efx_dev)->efx;
> +	struct mtd_partition partitions[1] = {};
> +	struct mtd_info template = {
> +		.numeraseregions = 0,
> +		.type = MTD_DATAFLASH,
> +		.flags = MTD_WRITEABLE,
> +		.writesize = 1
> +	};
> +	const char *mtd_type_name;
> +
> +	if (!efx->spi_eeprom)
> +		return -EINVAL;
> +
> +	template.size = efx->spi_eeprom->size;
> +	template.erasesize = efx->spi_eeprom->size;
> +
> +	partitions[0].offset = 0;
> +	partitions[0].size = efx->spi_eeprom->size;
> +	partitions[0].mask_flags = MTD_WRITEABLE;
> +
> +	if (efx->spi_eeprom->size <= 0x200) {
> +		mtd_type_name = "sfc_small_eeprom";
> +		partitions[0].name = "sfc_small_config";
> +	} else {
> +		mtd_type_name = "sfc_large_eeprom";
> +		partitions[0].name = "sfc_large_config";
> +	}
> +
> +	return efx_mtd_probe(efx_dev, efx, efx->spi_eeprom,
> +			     mtd_type_name, &template,
> +			     partitions, 1);
> +}
> +
> +static struct efx_dl_driver efx_eeprom_driver = {
> +	.name		= "sfc_eeprom",
> +	.probe		= efx_eeprom_probe,
> +	.remove		= efx_mtd_remove,
> +	.reset_suspend	= efx_mtd_reset_suspend,
> +	.reset_resume	= efx_mtd_reset_resume,
> +};
> +
> +/**************************************************************************
> + *
> + * Kernel module interface
> + *
> + **************************************************************************
> + *
> + */

Kill.

> +static int __init efx_mtd_init_module(void)
> +{
> +	int rc;
> +
> +	rc = efx_dl_register_driver(&efx_flash_driver);
> +	if (rc != 0)
> +		return rc;
> +	rc = efx_dl_register_driver(&efx_eeprom_driver);
> +	if (rc != 0) {
> +		efx_dl_unregister_driver(&efx_flash_driver);
> +		return rc;
> +	}
> +
> +	return 0;
> +}
> +
> +static void __exit efx_mtd_exit_module(void)
> +{
> +	efx_dl_unregister_driver(&efx_eeprom_driver);
> +	efx_dl_unregister_driver(&efx_flash_driver);
> +}
> +
> +module_init(efx_mtd_init_module);
> +module_exit(efx_mtd_exit_module);
> +
> +MODULE_AUTHOR("Michael Brown <mbrown at fensystems.co.uk> and "
> +	      "Solarflare Communications");
> +MODULE_DESCRIPTION("SFC MTD driver");
> +MODULE_LICENSE("GPL");

J?rn

-- 
Linux is more the core point of a concept that surrounds "open source"
which, in turn, is based on a false concept. This concept is that
people actually want to look at source code.
-- Rob Enderle


From joern at logfs.org  Tue Jan 15 11:50:43 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Tue, 15 Jan 2008 17:50:43 +0100
Subject: JFFS2 determine writing state
In-Reply-To: <20080115140759.GE11941@shareable.org>
References: <298338.39997.qm@web56002.mail.re3.yahoo.com>
	<20080111075730.052c821d@zod.rchland.ibm.com>
	<20080112100343.GC1497@shareable.org>
	<20080112141508.22b19686@vader.jdub.homelinux.org>
	<20080115140759.GE11941@shareable.org>
Message-ID: <20080115165043.GD22338@lazybastard.org>

On Tue, 15 January 2008 14:08:00 +0000, Jamie Lokier wrote:
> 
> But the particular fs behaviour is relevant the other way around: I
> have a program which calls open/write/close with small writes
> moderately often (because it calls another program which actually
> operates on the file).
> 
> If JFFS2 commits pending writes on every close, I should change things
> to keep the file open between writes so they are coalesced and faster,
> when I don't need the individual writes to be committed separately.

JFFS2 also commits on every write.  So you need userspace caching if you
want to coalesce things.  fwrite might be enough for that...

> When I do need the data committed I can use fsync of course.

...as long as you also fflush (or fclose) before fsync.

J?rn

-- 
Everything should be made as simple as possible, but not simpler.
-- Albert Einstein


From bhutchings at solarflare.com  Tue Jan 15 12:35:50 2008
From: bhutchings at solarflare.com (Ben Hutchings)
Date: Tue, 15 Jan 2008 17:35:50 +0000
Subject: [PATCH] [MTD] [RFC] New Solarflare NIC EEPROM/Flash driver (2nd
	try)
In-Reply-To: <20080115164613.GC22338@lazybastard.org>
References: <47866921.40904@solarflare.com>
	<20080114170358.GO3544@solarflare.com>
	<20080115164613.GC22338@lazybastard.org>
Message-ID: <20080115173548.GE28547@solarflare.com>

J?rn Engel wrote:
> On Mon, 14 January 2008 17:04:00 +0000, Ben Hutchings wrote:
> > 
> > This patch contains just the MTD driver code (mtd.c) and the two most
> > important header files it shares with our net driver.  The low-level
> > code to access the SPI bus through the network controller is not
> > included (and is unchanged from last time aside from a small change to
> > length validation).  Hopefully this should be more amenable to review,
> > though it cannot be compiled.
> 
> Hehe.  Maybe next time I can get both?  
> 
> Most comments below are fairly generic and can be applied many times
> over, both for mtd.c and the rest.
<snip>
> > +struct efx_mtd {
> > +	struct mtd_info mtd;
> > +	struct mtd_partition mtd_part[EFX_MAX_PARTITIONS];
> > +	struct semaphore access_lock;
> > +	char part_name[EFX_MAX_PARTITIONS][32];
> > +	char name[32];
> > +	struct efx_dl_device *efx_dev; /* driverlink */
> 
> Rename to struct efx_driver_link and kill the comment?

No, there are multiple structures involved in the driverlink API.  But
the "_dl_" in the structure name should be a sufficient clue.

> > +	struct efx_nic *efx; 
> > +	struct efx_spi_device *spi;
> 
> Needing three seperate pointers to some struct efc_* is... interesting.
> Usually one would be enough and the other two can be derived.

The efx_nic pointer can be derived from the efx_dev pointer, though
looking it up requires a function call.  The efx_spi_device pointer is
not redundant, because our NICs usually have 2 SPI devices.

> > +		/* Check contents */
> > +		for (i = 0; i < buf_len; i++) {
> > +			if (buffer)
> > +				expected = buffer[i];
> > +			if (verify_buffer[i] != expected) {
> > +				EFX_ERR(efx_mtd->efx, "%s offset %lx contains "
> > +					"%02x, should be %02x\n", efx_mtd->name,
> > +					(unsigned long)(offset + i),
> > +					verify_buffer[i], expected);
> > +				rc = -EIO;
> > +				goto out;
> > +			}
> > +		}
> 
> Home-brewn memcmp?

:-)  This reports non-matching addresses, and can compare with all-
ones rather than an explicit byte array (if the buffer pointer is NULL)
which we use after an erase.

<snip>
> > +static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
> > +{
> > +	struct efx_mtd *efx_mtd = (struct efx_mtd *)mtd->priv;
> > +	struct efx_spi_device *spi;
> > +	int rc;
> > +
> > +	rc = down_interruptible(&efx_mtd->access_lock);
> 
> What is this semaphore protecting?

It prevents efx_mtd->spi changing underneath us.

<snip> 
> My gut instinct tells me that you can push it through to only protect
> the pure bus access

We already have that for single comamnds, since the net driver reads
the SPI devices.  The access lock is needed to ensure that a sequence
of commands involved in writing is not interrupted, and to exclude a
reset which could interfere with access to the SPI device.

<snip>
> > +out:
> > +	if (rc == 0) {
> > +		erase->state = MTD_ERASE_DONE;
> > +	} else {
> > +		erase->state = MTD_ERASE_FAILED;
> > +		erase->fail_addr = 0xffffffff;
> 
> ???

According to mtd.h:

/* If the erase fails, fail_addr might indicate exactly which block failed.  If
   fail_addr = 0xffffffff, the failure was not at the device level or was not
   specific to any particular block. */

I read that as meaning we must set fail_addr.  Of course it would be
nicer to set it to a meaningful address.

<snip>
> > +static void efx_mtd_sync(struct mtd_info *mtd)
> > +{
> > +	struct efx_mtd *efx_mtd = (struct efx_mtd *)mtd->priv;
> > +	int rc;
> > +
> > +	down(&efx_mtd->access_lock);
> > +	rc = efx_spi_slow_wait(efx_mtd);
> > +	if (rc != 0)
> > +		EFX_ERR(efx_mtd->efx, "%s sync failed (%d)\n",
> > +			efx_mtd->name, rc);
> 
> How do you handle -EINTR?

Obviously it doesn't.  Given that it can't return an error, do you
have any better suggestions?

<snip>
> > +	/* Initialise structure */
> > +	efx_mtd->efx_dev = efx_dev;
> > +	efx_mtd->efx = efx;
> > +	efx_mtd->spi = spi;
> > +	sema_init(&efx_mtd->access_lock, 1);
> > +	memcpy(&efx_mtd->mtd, template, sizeof(efx_mtd->mtd));
> 
> I'm not too fond of this memcpy approach.  In particular because this
> function is called probe and does no such thing.
> 
> Instead this function could allocate a structure and initialize any
> common fields.  Remaining fields would then be initialized in the two
> actual probe functions below.

Right.  The memcpy() is there because the "template" structures used
to be static data.  I replaced them with dynamically generated
structures when adding support for more SPI devices, but didn't follow
through and rework this initialisation.

<snip>
> > +	EFX_ASSERT(template->numeraseregions == 0);
> > +
> > +	EFX_ASSERT(partitions != NULL);
> > +	EFX_ASSERT(num_partitions > 0);
> > +	EFX_ASSERT(num_partitions <= EFX_MAX_PARTITIONS);
> 
> And I assume most of these assertions are bogus and can be removed.

I suppose they are trivially true now.

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.


From bhutchings at solarflare.com  Tue Jan 15 12:57:32 2008
From: bhutchings at solarflare.com (Ben Hutchings)
Date: Tue, 15 Jan 2008 17:57:32 +0000
Subject: [PATCH] [MTD] [RFC] New Solarflare NIC EEPROM/Flash driver (2nd
	try)
In-Reply-To: <20080115164613.GC22338@lazybastard.org>
References: <47866921.40904@solarflare.com>
	<20080114170358.GO3544@solarflare.com>
	<20080115164613.GC22338@lazybastard.org>
Message-ID: <20080115175731.GF28547@solarflare.com>

Something I missed:

J?rn Engel wrote:
<snip>
> You can replace EFX_ASSERT with BUG_ON (with negated condition)
> throughout the code.  Duplicating existing kernel infrastructure needs a
> very good reason to be accepted.
<snip>

Assertions made with EFX_ASSERT() are only checked if EFX_ENABLE_DEBUG
is set, and we don't really want them to be included in a production
build.  Is there a suitable kernel facility for more paranoid checks
that will be disabled by default?

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.


From joern at logfs.org  Tue Jan 15 12:55:53 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Tue, 15 Jan 2008 18:55:53 +0100
Subject: [PATCH] [MTD] [RFC] New Solarflare NIC EEPROM/Flash driver (2nd
	try)
In-Reply-To: <20080115173548.GE28547@solarflare.com>
References: <47866921.40904@solarflare.com>
	<20080114170358.GO3544@solarflare.com>
	<20080115164613.GC22338@lazybastard.org>
	<20080115173548.GE28547@solarflare.com>
Message-ID: <20080115175553.GG22338@lazybastard.org>

On Tue, 15 January 2008 17:35:50 +0000, Ben Hutchings wrote:
> > >
> > > +		/* Check contents */
> > > +		for (i = 0; i < buf_len; i++) {
> > > +			if (buffer)
> > > +				expected = buffer[i];
> > > +			if (verify_buffer[i] != expected) {
> > > +				EFX_ERR(efx_mtd->efx, "%s offset %lx contains "
> > > +					"%02x, should be %02x\n", efx_mtd->name,
> > > +					(unsigned long)(offset + i),
> > > +					verify_buffer[i], expected);
> > > +				rc = -EIO;
> > > +				goto out;
> > > +			}
> > > +		}
> > 
> > Home-brewn memcmp?
> 
> :-)  This reports non-matching addresses, and can compare with all-
> ones rather than an explicit byte array (if the buffer pointer is NULL)
> which we use after an erase.

I have this piece of code for similar purposes.  Notice the first
comment. :)

/*
 * TODO: move to lib/string.c
 */
/**
 * memchr_inv - Find a character in an area of memory.
 * @s: The memory area
 * @c: The byte to search for
 * @n: The size of the area.
 *
 * returns the address of the first character other than @c, or %NULL
 * if the whole buffer contains just @c.
 */
void *memchr_inv(const void *s, int c, size_t n)
{
	const unsigned char *p = s;
	while (n-- != 0) {
		if ((unsigned char)c != *p++) {
			return (void *)(p - 1);
		}
	}
	return NULL;
}

> <snip>
> > > +static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
> > > +{
> > > +	struct efx_mtd *efx_mtd = (struct efx_mtd *)mtd->priv;
> > > +	struct efx_spi_device *spi;
> > > +	int rc;
> > > +
> > > +	rc = down_interruptible(&efx_mtd->access_lock);
> > 
> > What is this semaphore protecting?
> 
> It prevents efx_mtd->spi changing underneath us.
> 
> <snip> 
> > My gut instinct tells me that you can push it through to only protect
> > the pure bus access
> 
> We already have that for single comamnds, since the net driver reads
> the SPI devices.  The access lock is needed to ensure that a sequence
> of commands involved in writing is not interrupted, and to exclude a
> reset which could interfere with access to the SPI device.

Ok.  I will ignore the semaphore from now on.  Rest assured that someone
else will ask about it later.

> <snip>
> > > +out:
> > > +	if (rc == 0) {
> > > +		erase->state = MTD_ERASE_DONE;
> > > +	} else {
> > > +		erase->state = MTD_ERASE_FAILED;
> > > +		erase->fail_addr = 0xffffffff;
> > 
> > ???
> 
> According to mtd.h:
> 
> /* If the erase fails, fail_addr might indicate exactly which block failed.  If
>    fail_addr = 0xffffffff, the failure was not at the device level or was not
>    specific to any particular block. */
> 
> I read that as meaning we must set fail_addr.  Of course it would be
> nicer to set it to a meaningful address.

Hmm.  fail_addr is only used by jffs2 to mark blocks as bad, with
0xffffffff indicating that no block is to blame and nothing should be
marked bad.  Not the nicest interface I have ever seen, but your usage
of it seems proper.

> <snip>
> > > +static void efx_mtd_sync(struct mtd_info *mtd)
> > > +{
> > > +	struct efx_mtd *efx_mtd = (struct efx_mtd *)mtd->priv;
> > > +	int rc;
> > > +
> > > +	down(&efx_mtd->access_lock);
> > > +	rc = efx_spi_slow_wait(efx_mtd);
> > > +	if (rc != 0)
> > > +		EFX_ERR(efx_mtd->efx, "%s sync failed (%d)\n",
> > > +			efx_mtd->name, rc);
> > 
> > How do you handle -EINTR?
> 
> Obviously it doesn't.  Given that it can't return an error, do you
> have any better suggestions?

Can you prevent efx_spi_slow_wait from returning -EINTR?  If you can't,
a BUG_ON() at least makes the problem explicit.  

> Ben Hutchings, Senior Software Engineer, Solarflare Communications
> Not speaking for my employer; that's the marketing department's job.

:)

J?rn

-- 
Data dominates. If you've chosen the right data structures and organized
things well, the algorithms will almost always be self-evident. Data
structures, not algorithms, are central to programming.
-- Rob Pike


From joern at logfs.org  Tue Jan 15 13:28:54 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Tue, 15 Jan 2008 19:28:54 +0100
Subject: [PATCH] [MTD] [RFC] New Solarflare NIC EEPROM/Flash driver (2nd
	try)
In-Reply-To: <20080115175731.GF28547@solarflare.com>
References: <47866921.40904@solarflare.com>
	<20080114170358.GO3544@solarflare.com>
	<20080115164613.GC22338@lazybastard.org>
	<20080115175731.GF28547@solarflare.com>
Message-ID: <20080115182854.GH22338@lazybastard.org>

On Tue, 15 January 2008 17:57:32 +0000, Ben Hutchings wrote:
> J?rn Engel wrote:
> <snip>
> > You can replace EFX_ASSERT with BUG_ON (with negated condition)
> > throughout the code.  Duplicating existing kernel infrastructure needs a
> > very good reason to be accepted.
> <snip>
> 
> Assertions made with EFX_ASSERT() are only checked if EFX_ENABLE_DEBUG
> is set, and we don't really want them to be included in a production
> build.  Is there a suitable kernel facility for more paranoid checks
> that will be disabled by default?

Not that I know of.  Having this once in a generic form might be useful.

J?rn

-- 
I've never met a human being who would want to read 17,000 pages of
documentation, and if there was, I'd kill him to get him out of the
gene pool.
-- Joseph Costello


From jamie at shareable.org  Tue Jan 15 12:35:10 2008
From: jamie at shareable.org (Jamie Lokier)
Date: Tue, 15 Jan 2008 17:35:10 +0000
Subject: JFFS2 determine writing state
In-Reply-To: <20080115165043.GD22338@lazybastard.org>
References: <298338.39997.qm@web56002.mail.re3.yahoo.com>
	<20080111075730.052c821d@zod.rchland.ibm.com>
	<20080112100343.GC1497@shareable.org>
	<20080112141508.22b19686@vader.jdub.homelinux.org>
	<20080115140759.GE11941@shareable.org>
	<20080115165043.GD22338@lazybastard.org>
Message-ID: <20080115173510.GC16677@shareable.org>

J?rn Engel wrote:
> On Tue, 15 January 2008 14:08:00 +0000, Jamie Lokier wrote:
> > But the particular fs behaviour is relevant the other way around: I
> > have a program which calls open/write/close with small writes
> > moderately often (because it calls another program which actually
> > operates on the file).
> > 
> > If JFFS2 commits pending writes on every close, I should change things
> > to keep the file open between writes so they are coalesced and faster,
> > when I don't need the individual writes to be committed separately.
> 
> JFFS2 also commits on every write.  So you need userspace caching if you
> want to coalesce things.  fwrite might be enough for that...

Oh, ok, I thought it at least merged things in the page cache like
most other filesystems.  It seems it's more like O_DSYNC - or more
like O_SYNC (commits metadata changed for every write too)?

Is there a particular advantage, in terms of flash overhead,
compression, or mount/gc times, to writing blocks with a particular
size and alignment, such as 4k size and 4k offset-alignment-in-file?

Also, does LogFS (which I want to try later) have similar
characteristics?

> > When I do need the data committed I can use fsync of course.
> 
> ...as long as you also fflush (or fclose) before fsync.

Sure.  Thanks for your response.

-- Jamie


From joern at logfs.org  Tue Jan 15 14:16:03 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Tue, 15 Jan 2008 20:16:03 +0100
Subject: JFFS2 determine writing state
In-Reply-To: <20080115173510.GC16677@shareable.org>
References: <298338.39997.qm@web56002.mail.re3.yahoo.com>
	<20080111075730.052c821d@zod.rchland.ibm.com>
	<20080112100343.GC1497@shareable.org>
	<20080112141508.22b19686@vader.jdub.homelinux.org>
	<20080115140759.GE11941@shareable.org>
	<20080115165043.GD22338@lazybastard.org>
	<20080115173510.GC16677@shareable.org>
Message-ID: <20080115191603.GJ22338@lazybastard.org>

On Tue, 15 January 2008 17:35:10 +0000, Jamie Lokier wrote:
> 
> Oh, ok, I thought it at least merged things in the page cache like
> most other filesystems.  It seems it's more like O_DSYNC - or more
> like O_SYNC (commits metadata changed for every write too)?

I don't think there is a really good equivalent.  Writes happen
immediatly, but the changes may not become effective immediatly.  In a
way, the worst of both worlds. :)

> Is there a particular advantage, in terms of flash overhead,
> compression, or mount/gc times, to writing blocks with a particular
> size and alignment, such as 4k size and 4k offset-alignment-in-file?

4k size and 4k alignment is best for all the reasons you cited above.

> Also, does LogFS (which I want to try later) have similar
> characteristics?

At the moment, yes.  Most likely I won't get the caching part done
before LCA.

J?rn

-- 
Victory in war is not repetitious.
-- Sun Tzu


From jamie at shareable.org  Tue Jan 15 16:51:44 2008
From: jamie at shareable.org (Jamie Lokier)
Date: Tue, 15 Jan 2008 21:51:44 +0000
Subject: JFFS2 determine writing state
In-Reply-To: <20080115191603.GJ22338@lazybastard.org>
References: <298338.39997.qm@web56002.mail.re3.yahoo.com>
	<20080111075730.052c821d@zod.rchland.ibm.com>
	<20080112100343.GC1497@shareable.org>
	<20080112141508.22b19686@vader.jdub.homelinux.org>
	<20080115140759.GE11941@shareable.org>
	<20080115165043.GD22338@lazybastard.org>
	<20080115173510.GC16677@shareable.org>
	<20080115191603.GJ22338@lazybastard.org>
Message-ID: <20080115215144.GA29037@shareable.org>

J?rn Engel wrote:
> On Tue, 15 January 2008 17:35:10 +0000, Jamie Lokier wrote:
> > 
> > Oh, ok, I thought it at least merged things in the page cache like
> > most other filesystems.  It seems it's more like O_DSYNC - or more
> > like O_SYNC (commits metadata changed for every write too)?
> 
> I don't think there is a really good equivalent.  Writes happen
> immediatly, but the changes may not become effective immediatly.  In a
> way, the worst of both worlds. :)

I'm not sure if I understand what you mean by that.  Let me guess:

Do you mean that MTD write operations are started by write(), but
write() returns before the writes are committed reliably?

If so does fsync/fdatasync/sync_page_range ensure that the preceding
writes are committed reliably?  And does that include fsync on a
directory following an atomic rename (for reliable replacement of a
file)?

> > Also, does LogFS (which I want to try later) have similar
> > characteristics?
> 
> At the moment, yes.  Most likely I won't get the caching part done
> before LCA.

I guess write caching is an interesting beast for such a structured
filesystem.  It would seem like a good opportunity to coalesce some
tree node updates, something applications can't do themselves.
Looking forward to it :-)

-- Jamie


From joern at logfs.org  Tue Jan 15 18:26:13 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Wed, 16 Jan 2008 00:26:13 +0100
Subject: JFFS2 determine writing state
In-Reply-To: <20080115215144.GA29037@shareable.org>
References: <298338.39997.qm@web56002.mail.re3.yahoo.com>
	<20080111075730.052c821d@zod.rchland.ibm.com>
	<20080112100343.GC1497@shareable.org>
	<20080112141508.22b19686@vader.jdub.homelinux.org>
	<20080115140759.GE11941@shareable.org>
	<20080115165043.GD22338@lazybastard.org>
	<20080115173510.GC16677@shareable.org>
	<20080115191603.GJ22338@lazybastard.org>
	<20080115215144.GA29037@shareable.org>
Message-ID: <20080115232613.GA25000@lazybastard.org>

On Tue, 15 January 2008 21:51:44 +0000, Jamie Lokier wrote:
> J?rn Engel wrote:
> > 
> > I don't think there is a really good equivalent.  Writes happen
> > immediatly, but the changes may not become effective immediatly.  In a
> > way, the worst of both worlds. :)
> 
> I'm not sure if I understand what you mean by that.  Let me guess:
> 
> Do you mean that MTD write operations are started by write(), but
> write() returns before the writes are committed reliably?

Yes.  Write() may return before or after reliable commit, depending on
hardware, config options and sheer luck.

> If so does fsync/fdatasync/sync_page_range ensure that the preceding
> writes are committed reliably?

Yes.

> And does that include fsync on a
> directory following an atomic rename (for reliable replacement of a
> file)?

Yes.

> I guess write caching is an interesting beast for such a structured
> filesystem.  It would seem like a good opportunity to coalesce some
> tree node updates, something applications can't do themselves.

That bit is actually done already, modulo some bugs.  Once those bugs
are sorted out, caching actual data is a straight-forward extention.

J?rn

-- 
The wise man seeks everything in himself; the ignorant man tries to get
everything from somebody else.
-- unknown


From scottwood at freescale.com  Tue Jan 15 18:43:06 2008
From: scottwood at freescale.com (Scott Wood)
Date: Tue, 15 Jan 2008 17:43:06 -0600
Subject: [PATCH 2/3] mtd: Factor out OF partition support from the NOR
	driver.
In-Reply-To: <20080114172116.a2e5aa18.sfr@canb.auug.org.au>
References: <20080114172116.a2e5aa18.sfr@canb.auug.org.au>
Message-ID: <478D450A.8060802@freescale.com>

Stephen Rothwell wrote:
>> +	nr_parts = 0;
>> +	for (pp = node->child; pp; pp = pp->sibling)
> 
> 	for_each_child_of_node(node, pp)

"for_each_child_of_node" is only in Paul's tree, but this has to go via mtd.

Plus, I'm just moving the code; it's not new.

-Scott


From scottwood at freescale.com  Tue Jan 15 18:54:47 2008
From: scottwood at freescale.com (Scott Wood)
Date: Tue, 15 Jan 2008 17:54:47 -0600
Subject: [PATCH 2/2] Freescale enhanced Local Bus Controller FCM NAND support.
Message-ID: <20080115235447.GB1666@loki.buserror.net>

Signed-off-by: Nick Spence <nick.spence at freescale.com>
Signed-off-by: Scott Wood <scottwood at freescale.com>
---
 drivers/mtd/nand/Kconfig         |    9 +
 drivers/mtd/nand/Makefile        |    1 +
 drivers/mtd/nand/fsl_elbc_nand.c | 1245 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 1255 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mtd/nand/fsl_elbc_nand.c

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 0a840d5..4a3c675 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -321,4 +321,13 @@ config MTD_NAND_ORION
 	  No board specific support is done by this driver, each board
 	  must advertise a platform_device for the driver to attach.
 
+config MTD_NAND_FSL_ELBC
+	tristate "NAND support for Freescale eLBC controllers"
+	depends on MTD_NAND && PPC_OF
+	help
+	  Various Freescale chips, including the 8313, include a NAND Flash
+	  Controller Module with built-in hardware ECC capabilities.
+	  Enabling this option will enable you to use this to control
+	  external NAND devices.
+
 endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index e35f5ea..80d575e 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -31,5 +31,6 @@ obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
 obj-$(CONFIG_MTD_ALAUDA)		+= alauda.o
 obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
 obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
+obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
 
 nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
new file mode 100644
index 0000000..5a927a1
--- /dev/null
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -0,0 +1,1245 @@
+/* Freescale Enhanced Local Bus Controller NAND driver
+ *
+ * Copyright (c) 2006-2007 Freescale Semiconductor
+ *
+ * Authors: Nick Spence <nick.spence at freescale.com>,
+ *          Scott Wood <scottwood at freescale.com>
+ *
+ * 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/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+
+
+#define MAX_BANKS 8
+#define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */
+#define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */
+
+struct elbc_bank {
+	__be32 br;             /**< Base Register  */
+#define BR_BA           0xFFFF8000
+#define BR_BA_SHIFT             15
+#define BR_PS           0x00001800
+#define BR_PS_SHIFT             11
+#define BR_PS_8         0x00000800  /* Port Size 8 bit */
+#define BR_PS_16        0x00001000  /* Port Size 16 bit */
+#define BR_PS_32        0x00001800  /* Port Size 32 bit */
+#define BR_DECC         0x00000600
+#define BR_DECC_SHIFT            9
+#define BR_DECC_OFF     0x00000000  /* HW ECC checking and generation off */
+#define BR_DECC_CHK     0x00000200  /* HW ECC checking on, generation off */
+#define BR_DECC_CHK_GEN 0x00000400  /* HW ECC checking and generation on */
+#define BR_WP           0x00000100
+#define BR_WP_SHIFT              8
+#define BR_MSEL         0x000000E0
+#define BR_MSEL_SHIFT            5
+#define BR_MS_GPCM      0x00000000  /* GPCM */
+#define BR_MS_FCM       0x00000020  /* FCM */
+#define BR_MS_SDRAM     0x00000060  /* SDRAM */
+#define BR_MS_UPMA      0x00000080  /* UPMA */
+#define BR_MS_UPMB      0x000000A0  /* UPMB */
+#define BR_MS_UPMC      0x000000C0  /* UPMC */
+#define BR_V            0x00000001
+#define BR_V_SHIFT               0
+#define BR_RES          ~(BR_BA|BR_PS|BR_DECC|BR_WP|BR_MSEL|BR_V)
+
+	__be32 or;             /**< Base Register  */
+#define OR0 0x5004
+#define OR1 0x500C
+#define OR2 0x5014
+#define OR3 0x501C
+#define OR4 0x5024
+#define OR5 0x502C
+#define OR6 0x5034
+#define OR7 0x503C
+
+#define OR_FCM_AM               0xFFFF8000
+#define OR_FCM_AM_SHIFT                 15
+#define OR_FCM_BCTLD            0x00001000
+#define OR_FCM_BCTLD_SHIFT              12
+#define OR_FCM_PGS              0x00000400
+#define OR_FCM_PGS_SHIFT                10
+#define OR_FCM_CSCT             0x00000200
+#define OR_FCM_CSCT_SHIFT                9
+#define OR_FCM_CST              0x00000100
+#define OR_FCM_CST_SHIFT                 8
+#define OR_FCM_CHT              0x00000080
+#define OR_FCM_CHT_SHIFT                 7
+#define OR_FCM_SCY              0x00000070
+#define OR_FCM_SCY_SHIFT                 4
+#define OR_FCM_SCY_1            0x00000010
+#define OR_FCM_SCY_2            0x00000020
+#define OR_FCM_SCY_3            0x00000030
+#define OR_FCM_SCY_4            0x00000040
+#define OR_FCM_SCY_5            0x00000050
+#define OR_FCM_SCY_6            0x00000060
+#define OR_FCM_SCY_7            0x00000070
+#define OR_FCM_RST              0x00000008
+#define OR_FCM_RST_SHIFT                 3
+#define OR_FCM_TRLX             0x00000004
+#define OR_FCM_TRLX_SHIFT                2
+#define OR_FCM_EHTR             0x00000002
+#define OR_FCM_EHTR_SHIFT                1
+};
+
+struct elbc_regs {
+	struct elbc_bank bank[8];
+	u8 res0[0x28];
+	__be32 mar;             /**< UPM Address Register */
+	u8 res1[0x4];
+	__be32 mamr;            /**< UPMA Mode Register */
+	__be32 mbmr;            /**< UPMB Mode Register */
+	__be32 mcmr;            /**< UPMC Mode Register */
+	u8 res2[0x8];
+	__be32 mrtpr;           /**< Memory Refresh Timer Prescaler Register */
+	__be32 mdr;             /**< UPM Data Register */
+	u8 res3[0x4];
+	__be32 lsor;            /**< Special Operation Initiation Register */
+	__be32 lsdmr;           /**< SDRAM Mode Register */
+	u8 res4[0x8];
+	__be32 lurt;            /**< UPM Refresh Timer */
+	__be32 lsrt;            /**< SDRAM Refresh Timer */
+	u8 res5[0x8];
+	__be32 ltesr;           /**< Transfer Error Status Register */
+#define LTESR_BM   0x80000000
+#define LTESR_FCT  0x40000000
+#define LTESR_PAR  0x20000000
+#define LTESR_WP   0x04000000
+#define LTESR_ATMW 0x00800000
+#define LTESR_ATMR 0x00400000
+#define LTESR_CS   0x00080000
+#define LTESR_CC   0x00000001
+#define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC)
+	__be32 ltedr;           /**< Transfer Error Disable Register */
+	__be32 lteir;           /**< Transfer Error Interrupt Register */
+	__be32 lteatr;          /**< Transfer Error Attributes Register */
+	__be32 ltear;           /**< Transfer Error Address Register */
+	u8 res6[0xC];
+	__be32 lbcr;            /**< Configuration Register */
+#define LBCR_LDIS  0x80000000
+#define LBCR_LDIS_SHIFT    31
+#define LBCR_BCTLC 0x00C00000
+#define LBCR_BCTLC_SHIFT   22
+#define LBCR_AHD   0x00200000
+#define LBCR_LPBSE 0x00020000
+#define LBCR_LPBSE_SHIFT   17
+#define LBCR_EPAR  0x00010000
+#define LBCR_EPAR_SHIFT    16
+#define LBCR_BMT   0x0000FF00
+#define LBCR_BMT_SHIFT      8
+#define LBCR_INIT  0x00040000
+	__be32 lcrr;            /**< Clock Ratio Register */
+#define LCRR_DBYP    0x80000000
+#define LCRR_DBYP_SHIFT      31
+#define LCRR_BUFCMDC 0x30000000
+#define LCRR_BUFCMDC_SHIFT   28
+#define LCRR_ECL     0x03000000
+#define LCRR_ECL_SHIFT       24
+#define LCRR_EADC    0x00030000
+#define LCRR_EADC_SHIFT      16
+#define LCRR_CLKDIV  0x0000000F
+#define LCRR_CLKDIV_SHIFT     0
+	u8 res7[0x8];
+	__be32 fmr;             /**< Flash Mode Register */
+#define FMR_CWTO     0x0000F000
+#define FMR_CWTO_SHIFT       12
+#define FMR_BOOT     0x00000800
+#define FMR_ECCM     0x00000100
+#define FMR_AL       0x00000030
+#define FMR_AL_SHIFT          4
+#define FMR_OP       0x00000003
+#define FMR_OP_SHIFT          0
+	__be32 fir;             /**< Flash Instruction Register */
+#define FIR_OP0      0xF0000000
+#define FIR_OP0_SHIFT        28
+#define FIR_OP1      0x0F000000
+#define FIR_OP1_SHIFT        24
+#define FIR_OP2      0x00F00000
+#define FIR_OP2_SHIFT        20
+#define FIR_OP3      0x000F0000
+#define FIR_OP3_SHIFT        16
+#define FIR_OP4      0x0000F000
+#define FIR_OP4_SHIFT        12
+#define FIR_OP5      0x00000F00
+#define FIR_OP5_SHIFT         8
+#define FIR_OP6      0x000000F0
+#define FIR_OP6_SHIFT         4
+#define FIR_OP7      0x0000000F
+#define FIR_OP7_SHIFT         0
+#define FIR_OP_NOP   0x0	/* No operation and end of sequence */
+#define FIR_OP_CA    0x1        /* Issue current column address */
+#define FIR_OP_PA    0x2        /* Issue current block+page address */
+#define FIR_OP_UA    0x3        /* Issue user defined address */
+#define FIR_OP_CM0   0x4        /* Issue command from FCR[CMD0] */
+#define FIR_OP_CM1   0x5        /* Issue command from FCR[CMD1] */
+#define FIR_OP_CM2   0x6        /* Issue command from FCR[CMD2] */
+#define FIR_OP_CM3   0x7        /* Issue command from FCR[CMD3] */
+#define FIR_OP_WB    0x8        /* Write FBCR bytes from FCM buffer */
+#define FIR_OP_WS    0x9        /* Write 1 or 2 bytes from MDR[AS] */
+#define FIR_OP_RB    0xA        /* Read FBCR bytes to FCM buffer */
+#define FIR_OP_RS    0xB        /* Read 1 or 2 bytes to MDR[AS] */
+#define FIR_OP_CW0   0xC        /* Wait then issue FCR[CMD0] */
+#define FIR_OP_CW1   0xD        /* Wait then issue FCR[CMD1] */
+#define FIR_OP_RBW   0xE        /* Wait then read FBCR bytes */
+#define FIR_OP_RSW   0xE        /* Wait then read 1 or 2 bytes */
+	__be32 fcr;             /**< Flash Command Register */
+#define FCR_CMD0     0xFF000000
+#define FCR_CMD0_SHIFT       24
+#define FCR_CMD1     0x00FF0000
+#define FCR_CMD1_SHIFT       16
+#define FCR_CMD2     0x0000FF00
+#define FCR_CMD2_SHIFT        8
+#define FCR_CMD3     0x000000FF
+#define FCR_CMD3_SHIFT        0
+	__be32 fbar;            /**< Flash Block Address Register */
+#define FBAR_BLK     0x00FFFFFF
+	__be32 fpar;            /**< Flash Page Address Register */
+#define FPAR_SP_PI   0x00007C00
+#define FPAR_SP_PI_SHIFT     10
+#define FPAR_SP_MS   0x00000200
+#define FPAR_SP_CI   0x000001FF
+#define FPAR_SP_CI_SHIFT      0
+#define FPAR_LP_PI   0x0003F000
+#define FPAR_LP_PI_SHIFT     12
+#define FPAR_LP_MS   0x00000800
+#define FPAR_LP_CI   0x000007FF
+#define FPAR_LP_CI_SHIFT      0
+	__be32 fbcr;            /**< Flash Byte Count Register */
+#define FBCR_BC      0x00000FFF
+	u8 res11[0x8];
+	u8 res8[0xF00];
+};
+
+struct fsl_elbc_ctrl;
+
+/* mtd information per set */
+
+struct fsl_elbc_mtd {
+	struct mtd_info mtd;
+	struct nand_chip chip;
+	struct fsl_elbc_ctrl *ctrl;
+
+	struct device *dev;
+	int bank;               /* Chip select bank number           */
+	u8 __iomem *vbase;      /* Chip select base virtual address  */
+	int page_size;          /* NAND page size (0=512, 1=2048)    */
+	unsigned int fmr;       /* FCM Flash Mode Register value     */
+};
+
+/* overview of the fsl elbc controller */
+
+struct fsl_elbc_ctrl {
+	struct nand_hw_control controller;
+	struct fsl_elbc_mtd *chips[MAX_BANKS];
+
+	/* device info */
+	struct device *dev;
+	struct elbc_regs __iomem *regs;
+	int irq;
+	wait_queue_head_t irq_wait;
+	unsigned int irq_status; /* status read from LTESR by irq handler */
+	u8 __iomem *addr;        /* Address of assigned FCM buffer        */
+	unsigned int page;       /* Last page written to / read from      */
+	unsigned int read_bytes; /* Number of bytes read during command   */
+	unsigned int column;     /* Saved column from SEQIN               */
+	unsigned int index;      /* Pointer to next byte to 'read'        */
+	unsigned int status;     /* status read from LTESR after last op  */
+	unsigned int mdr;        /* UPM/FCM Data Register value           */
+	unsigned int use_mdr;    /* Non zero if the MDR is to be set      */
+	unsigned int oob;        /* Non zero if operating on OOB data     */
+	char *oob_poi;           /* Place to write ECC after read back    */
+};
+
+/* These map to the positions used by the FCM hardware ECC generator */
+
+/* Small Page FLASH with FMR[ECCM] = 0 */
+static struct nand_ecclayout fsl_elbc_oob_sp_eccm0 = {
+	.eccbytes = 3,
+	.eccpos = {6, 7, 8},
+	.oobfree = { {0, 5}, {9, 7} },
+	.oobavail = 12,
+};
+
+/* Small Page FLASH with FMR[ECCM] = 1 */
+static struct nand_ecclayout fsl_elbc_oob_sp_eccm1 = {
+	.eccbytes = 3,
+	.eccpos = {8, 9, 10},
+	.oobfree = { {0, 5}, {6, 2}, {11, 5} },
+	.oobavail = 12,
+};
+
+/* Large Page FLASH with FMR[ECCM] = 0 */
+static struct nand_ecclayout fsl_elbc_oob_lp_eccm0 = {
+	.eccbytes = 12,
+	.eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56},
+	.oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} },
+	.oobavail = 48,
+};
+
+/* Large Page FLASH with FMR[ECCM] = 1 */
+static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = {
+	.eccbytes = 12,
+	.eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58},
+	.oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} },
+	.oobavail = 48,
+};
+
+/*=================================*/
+
+/*
+ * Set up the FCM hardware block and page address fields, and the fcm
+ * structure addr field to point to the correct FCM buffer in memory
+ */
+static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+	int buf_num;
+
+	ctrl->page = page_addr;
+
+	out_be32(&lbc->fbar,
+	         page_addr >> (chip->phys_erase_shift - chip->page_shift));
+
+	if (priv->page_size) {
+		out_be32(&lbc->fpar,
+		         ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) |
+		         (oob ? FPAR_LP_MS : 0) | column);
+		buf_num = (page_addr & 1) << 2;
+	} else {
+		out_be32(&lbc->fpar,
+		         ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) |
+		         (oob ? FPAR_SP_MS : 0) | column);
+		buf_num = page_addr & 7;
+	}
+
+	ctrl->addr = priv->vbase + buf_num * 1024;
+	ctrl->index = column;
+
+	/* for OOB data point to the second half of the buffer */
+	if (oob)
+		ctrl->index += priv->page_size ? 2048 : 512;
+
+	dev_vdbg(ctrl->dev, "set_addr: bank=%d, ctrl->addr=0x%p (0x%p), "
+	                    "index %x, pes %d ps %d\n",
+	         buf_num, ctrl->addr, priv->vbase, ctrl->index,
+	         chip->phys_erase_shift, chip->page_shift);
+}
+
+/*
+ * execute FCM command and wait for it to complete
+ */
+static int fsl_elbc_run_command(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+
+	/* Setup the FMR[OP] to execute without write protection */
+	out_be32(&lbc->fmr, priv->fmr | 3);
+	if (ctrl->use_mdr)
+		out_be32(&lbc->mdr, ctrl->mdr);
+
+	dev_vdbg(ctrl->dev,
+	         "fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n",
+	         in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr));
+	dev_vdbg(ctrl->dev,
+	         "fsl_elbc_run_command: fbar=%08x fpar=%08x "
+	         "fbcr=%08x bank=%d\n",
+	         in_be32(&lbc->fbar), in_be32(&lbc->fpar),
+	         in_be32(&lbc->fbcr), priv->bank);
+
+	/* execute special operation */
+	out_be32(&lbc->lsor, priv->bank);
+
+	/* wait for FCM complete flag or timeout */
+	ctrl->irq_status = 0;
+	wait_event_timeout(ctrl->irq_wait, ctrl->irq_status,
+	                   FCM_TIMEOUT_MSECS * HZ/1000);
+	ctrl->status = ctrl->irq_status;
+
+	/* store mdr value in case it was needed */
+	if (ctrl->use_mdr)
+		ctrl->mdr = in_be32(&lbc->mdr);
+
+	ctrl->use_mdr = 0;
+
+	dev_vdbg(ctrl->dev,
+	         "fsl_elbc_run_command: stat=%08x mdr=%08x fmr=%08x\n",
+	         ctrl->status, ctrl->mdr, in_be32(&lbc->fmr));
+
+	/* returns 0 on success otherwise non-zero) */
+	return ctrl->status == LTESR_CC ? 0 : -EIO;
+}
+
+static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
+{
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+
+	if (priv->page_size) {
+		out_be32(&lbc->fir,
+		         (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+		         (FIR_OP_CA  << FIR_OP1_SHIFT) |
+		         (FIR_OP_PA  << FIR_OP2_SHIFT) |
+		         (FIR_OP_CW1 << FIR_OP3_SHIFT) |
+		         (FIR_OP_RBW << FIR_OP4_SHIFT));
+
+		out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
+		                    (NAND_CMD_READSTART << FCR_CMD1_SHIFT));
+	} else {
+		out_be32(&lbc->fir,
+		         (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+		         (FIR_OP_CA  << FIR_OP1_SHIFT) |
+		         (FIR_OP_PA  << FIR_OP2_SHIFT) |
+		         (FIR_OP_RBW << FIR_OP3_SHIFT));
+
+		if (oob)
+			out_be32(&lbc->fcr, NAND_CMD_READOOB << FCR_CMD0_SHIFT);
+		else
+			out_be32(&lbc->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT);
+	}
+}
+
+/* cmdfunc send commands to the FCM */
+static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
+                             int column, int page_addr)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+
+	ctrl->use_mdr = 0;
+
+	/* clear the read buffer */
+	ctrl->read_bytes = 0;
+	if (command != NAND_CMD_PAGEPROG)
+		ctrl->index = 0;
+
+	switch (command) {
+	/* READ0 and READ1 read the entire buffer to use hardware ECC. */
+	case NAND_CMD_READ1:
+		column += 256;
+
+	/* fall-through */
+	case NAND_CMD_READ0:
+		dev_dbg(ctrl->dev,
+		        "fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:"
+		        " 0x%x, column: 0x%x.\n", page_addr, column);
+
+
+		out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */
+		set_addr(mtd, 0, page_addr, 0);
+
+		ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+		ctrl->index += column;
+
+		fsl_elbc_do_read(chip, 0);
+		fsl_elbc_run_command(mtd);
+		return;
+
+	/* READOOB reads only the OOB because no ECC is performed. */
+	case NAND_CMD_READOOB:
+		dev_vdbg(ctrl->dev,
+		         "fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:"
+			 " 0x%x, column: 0x%x.\n", page_addr, column);
+
+		out_be32(&lbc->fbcr, mtd->oobsize - column);
+		set_addr(mtd, column, page_addr, 1);
+
+		ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+
+		fsl_elbc_do_read(chip, 1);
+		fsl_elbc_run_command(mtd);
+		return;
+
+	/* READID must read all 5 possible bytes while CEB is active */
+	case NAND_CMD_READID:
+		dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n");
+
+		out_be32(&lbc->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+		                    (FIR_OP_UA  << FIR_OP1_SHIFT) |
+		                    (FIR_OP_RBW << FIR_OP2_SHIFT));
+		out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT);
+		/* 5 bytes for manuf, device and exts */
+		out_be32(&lbc->fbcr, 5);
+		ctrl->read_bytes = 5;
+		ctrl->use_mdr = 1;
+		ctrl->mdr = 0;
+
+		set_addr(mtd, 0, 0, 0);
+		fsl_elbc_run_command(mtd);
+		return;
+
+	/* ERASE1 stores the block and page address */
+	case NAND_CMD_ERASE1:
+		dev_vdbg(ctrl->dev,
+		         "fsl_elbc_cmdfunc: NAND_CMD_ERASE1, "
+		         "page_addr: 0x%x.\n", page_addr);
+		set_addr(mtd, 0, page_addr, 0);
+		return;
+
+	/* ERASE2 uses the block and page address from ERASE1 */
+	case NAND_CMD_ERASE2:
+		dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
+
+		out_be32(&lbc->fir,
+		         (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+		         (FIR_OP_PA  << FIR_OP1_SHIFT) |
+		         (FIR_OP_CM1 << FIR_OP2_SHIFT));
+
+		out_be32(&lbc->fcr,
+		         (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) |
+		         (NAND_CMD_ERASE2 << FCR_CMD1_SHIFT));
+
+		out_be32(&lbc->fbcr, 0);
+		ctrl->read_bytes = 0;
+
+		fsl_elbc_run_command(mtd);
+		return;
+
+	/* SEQIN sets up the addr buffer and all registers except the length */
+	case NAND_CMD_SEQIN: {
+		__be32 fcr;
+		dev_vdbg(ctrl->dev,
+		         "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, "
+		         "page_addr: 0x%x, column: 0x%x.\n",
+		         page_addr, column);
+
+		ctrl->column = column;
+		ctrl->oob = 0;
+
+		fcr = (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT) |
+		      (NAND_CMD_SEQIN << FCR_CMD2_SHIFT);
+
+		if (priv->page_size) {
+			out_be32(&lbc->fir,
+			         (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+			         (FIR_OP_CA  << FIR_OP1_SHIFT) |
+			         (FIR_OP_PA  << FIR_OP2_SHIFT) |
+			         (FIR_OP_WB  << FIR_OP3_SHIFT) |
+			         (FIR_OP_CW1 << FIR_OP4_SHIFT));
+
+			fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT;
+		} else {
+			out_be32(&lbc->fir,
+			         (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+			         (FIR_OP_CM2 << FIR_OP1_SHIFT) |
+			         (FIR_OP_CA  << FIR_OP2_SHIFT) |
+			         (FIR_OP_PA  << FIR_OP3_SHIFT) |
+			         (FIR_OP_WB  << FIR_OP4_SHIFT) |
+			         (FIR_OP_CW1 << FIR_OP5_SHIFT));
+
+			if (column >= mtd->writesize) {
+				/* OOB area --> READOOB */
+				column -= mtd->writesize;
+				fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT;
+				ctrl->oob = 1;
+			} else if (column < 256) {
+				/* First 256 bytes --> READ0 */
+				fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT;
+			} else {
+				/* Second 256 bytes --> READ1 */
+				fcr |= NAND_CMD_READ1 << FCR_CMD0_SHIFT;
+			}
+		}
+
+		out_be32(&lbc->fcr, fcr);
+		set_addr(mtd, column, page_addr, ctrl->oob);
+		return;
+	}
+
+	/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
+	case NAND_CMD_PAGEPROG: {
+		int full_page;
+		dev_vdbg(ctrl->dev,
+		         "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
+		         "writing %d bytes.\n", ctrl->index);
+
+		/* if the write did not start at 0 or is not a full page
+		 * then set the exact length, otherwise use a full page
+		 * write so the HW generates the ECC.
+		 */
+		if (ctrl->oob || ctrl->column != 0 ||
+		    ctrl->index != mtd->writesize + mtd->oobsize) {
+			out_be32(&lbc->fbcr, ctrl->index);
+			full_page = 0;
+		} 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 && ctrl->oob_poi) {
+			out_be32(&lbc->fbcr, 3);
+			set_addr(mtd, 6, page_addr, 1);
+
+			ctrl->read_bytes = mtd->writesize + 9;
+
+			fsl_elbc_do_read(chip, 1);
+			fsl_elbc_run_command(mtd);
+
+			memcpy_fromio(ctrl->oob_poi + 6,
+			              &ctrl->addr[ctrl->index], 3);
+			ctrl->index += 3;
+		}
+
+		ctrl->oob_poi = NULL;
+		return;
+	}
+
+	/* CMD_STATUS must read the status byte while CEB is active */
+	/* Note - it does not wait for the ready line */
+	case NAND_CMD_STATUS:
+		out_be32(&lbc->fir,
+		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+		         (FIR_OP_RBW << FIR_OP1_SHIFT));
+		out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
+		out_be32(&lbc->fbcr, 1);
+		set_addr(mtd, 0, 0, 0);
+		ctrl->read_bytes = 1;
+
+		fsl_elbc_run_command(mtd);
+
+		/* The chip always seems to report that it is
+		 * write-protected, even when it is not.
+		 */
+		setbits8(ctrl->addr, NAND_STATUS_WP);
+		return;
+
+	/* RESET without waiting for the ready line */
+	case NAND_CMD_RESET:
+		dev_dbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
+		out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT);
+		out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT);
+		fsl_elbc_run_command(mtd);
+		return;
+
+	default:
+		dev_err(ctrl->dev,
+		        "fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n",
+		        command);
+	}
+}
+
+static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
+{
+	/* The hardware does not seem to support multiple
+	 * chips per bank.
+	 */
+}
+
+/*
+ * Write buf to the FCM Controller Data Buffer
+ */
+static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	unsigned int bufsize = mtd->writesize + mtd->oobsize;
+
+	if (len < 0) {
+		dev_err(ctrl->dev, "write_buf of %d bytes", len);
+		ctrl->status = 0;
+		return;
+	}
+
+	if ((unsigned int)len > bufsize - ctrl->index) {
+		dev_err(ctrl->dev,
+		        "write_buf beyond end of buffer "
+		        "(%d requested, %u available)\n",
+		        len, bufsize - ctrl->index);
+		len = bufsize - ctrl->index;
+	}
+
+	memcpy_toio(&ctrl->addr[ctrl->index], buf, len);
+	ctrl->index += len;
+}
+
+/*
+ * read a byte from either the FCM hardware buffer if it has any data left
+ * otherwise issue a command to read a single byte.
+ */
+static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+
+	/* If there are still bytes in the FCM, then use the next byte. */
+	if (ctrl->index < ctrl->read_bytes)
+		return in_8(&ctrl->addr[ctrl->index++]);
+
+	dev_err(ctrl->dev, "read_byte beyond end of buffer\n");
+	return ERR_BYTE;
+}
+
+/*
+ * Read from the FCM Controller Data Buffer
+ */
+static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	int avail;
+
+	if (len < 0)
+		return;
+
+	avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index);
+	memcpy_fromio(buf, &ctrl->addr[ctrl->index], avail);
+	ctrl->index += avail;
+
+	if (len > avail)
+		dev_err(ctrl->dev,
+		        "read_buf beyond end of buffer "
+		        "(%d requested, %d available)\n",
+		        len, avail);
+}
+
+/*
+ * Verify buffer against the FCM Controller Data Buffer
+ */
+static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	int i;
+
+	if (len < 0) {
+		dev_err(ctrl->dev, "write_buf of %d bytes", len);
+		return -EINVAL;
+	}
+
+	if ((unsigned int)len > ctrl->read_bytes - ctrl->index) {
+		dev_err(ctrl->dev,
+		        "verify_buf beyond end of buffer "
+		        "(%d requested, %u available)\n",
+		        len, ctrl->read_bytes - ctrl->index);
+
+		ctrl->index = ctrl->read_bytes;
+		return -EINVAL;
+	}
+
+	for (i = 0; i < len; i++)
+		if (in_8(&ctrl->addr[ctrl->index + i]) != buf[i])
+			break;
+
+	ctrl->index += len;
+	return i == len && ctrl->status == LTESR_CC ? 0 : -EIO;
+}
+
+/* This function is called after Program and Erase Operations to
+ * check for success or failure.
+ */
+static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+
+	if (ctrl->status != LTESR_CC)
+		return NAND_STATUS_FAIL;
+
+	/* Use READ_STATUS command, but wait for the device to be ready */
+	ctrl->use_mdr = 0;
+	out_be32(&lbc->fir,
+	         (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+	         (FIR_OP_RBW << FIR_OP1_SHIFT));
+	out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
+	out_be32(&lbc->fbcr, 1);
+	set_addr(mtd, 0, 0, 0);
+	ctrl->read_bytes = 1;
+
+	fsl_elbc_run_command(mtd);
+
+	if (ctrl->status != LTESR_CC)
+		return NAND_STATUS_FAIL;
+
+	/* The chip always seems to report that it is
+	 * write-protected, even when it is not.
+	 */
+	setbits8(ctrl->addr, NAND_STATUS_WP);
+	return fsl_elbc_read_byte(mtd);
+}
+
+static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_elbc_mtd *priv = chip->priv;
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+	unsigned int al;
+
+	/* calculate FMR Address Length field */
+	al = 0;
+	if (chip->pagemask & 0xffff0000)
+		al++;
+	if (chip->pagemask & 0xff000000)
+		al++;
+
+	/* add to ECCM mode set in fsl_elbc_init */
+	priv->fmr |= (12 << FMR_CWTO_SHIFT) |  /* Timeout > 12 ms */
+	             (al << FMR_AL_SHIFT);
+
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->numchips = %d\n",
+	        chip->numchips);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chipsize = %ld\n",
+	        chip->chipsize);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
+	        chip->pagemask);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
+	        chip->chip_delay);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
+	        chip->badblockpos);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
+	        chip->chip_shift);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->page_shift = %d\n",
+	        chip->page_shift);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
+	        chip->phys_erase_shift);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecclayout = %p\n",
+	        chip->ecclayout);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
+	        chip->ecc.mode);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
+	        chip->ecc.steps);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
+	        chip->ecc.bytes);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
+	        chip->ecc.total);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.layout = %p\n",
+	        chip->ecc.layout);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->size = %d\n", mtd->size);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
+	        mtd->erasesize);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->writesize = %d\n",
+	        mtd->writesize);
+	dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
+	        mtd->oobsize);
+
+	/* adjust Option Register and ECC to match Flash page size */
+	if (mtd->writesize == 512) {
+		priv->page_size = 0;
+		clrbits32(&lbc->bank[priv->bank].or, ~OR_FCM_PGS);
+	} else if (mtd->writesize == 2048) {
+		priv->page_size = 1;
+		setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
+		/* adjust ecc setup if needed */
+		if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
+		    BR_DECC_CHK_GEN) {
+			chip->ecc.size = 512;
+			chip->ecc.layout = (priv->fmr & FMR_ECCM) ?
+			                   &fsl_elbc_oob_lp_eccm1 :
+			                   &fsl_elbc_oob_lp_eccm0;
+			mtd->ecclayout = chip->ecc.layout;
+			mtd->oobavail = chip->ecc.layout->oobavail;
+		}
+	} else {
+		dev_err(ctrl->dev,
+		        "fsl_elbc_init: page size %d is not supported\n",
+		        mtd->writesize);
+		return -1;
+	}
+
+	/* The default u-boot configuration on MPC8313ERDB causes errors;
+	 * more delay is needed.  This should be safe for other boards
+	 * as well.
+	 */
+	setbits32(&lbc->bank[priv->bank].or, 0x70);
+	return 0;
+}
+
+static int fsl_elbc_read_page(struct mtd_info *mtd,
+                              struct nand_chip *chip,
+                              uint8_t *buf)
+{
+	fsl_elbc_read_buf(mtd, buf, mtd->writesize);
+	fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL)
+		mtd->ecc_stats.failed++;
+
+	return 0;
+}
+
+/* ECC will be calculated automatically, and errors will be detected in
+ * waitfunc.
+ */
+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_ctrl *ctrl = priv->ctrl;
+
+	fsl_elbc_write_buf(mtd, buf, mtd->writesize);
+	fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	ctrl->oob_poi = chip->oob_poi;
+}
+
+static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
+{
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+	struct nand_chip *chip = &priv->chip;
+
+	dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank);
+
+	/* Fill in fsl_elbc_mtd structure */
+	priv->mtd.priv = chip;
+	priv->mtd.owner = THIS_MODULE;
+	priv->fmr = 0; /* rest filled in later */
+
+	/* fill in nand_chip structure */
+	/* set up function call table */
+	chip->read_byte = fsl_elbc_read_byte;
+	chip->write_buf = fsl_elbc_write_buf;
+	chip->read_buf = fsl_elbc_read_buf;
+	chip->verify_buf = fsl_elbc_verify_buf;
+	chip->select_chip = fsl_elbc_select_chip;
+	chip->cmdfunc = fsl_elbc_cmdfunc;
+	chip->waitfunc = fsl_elbc_wait;
+
+	/* set up nand options */
+	chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR;
+
+	chip->controller = &ctrl->controller;
+	chip->priv = priv;
+
+	chip->ecc.read_page = fsl_elbc_read_page;
+	chip->ecc.write_page = fsl_elbc_write_page;
+
+	/* If CS Base Register selects full hardware ECC then use it */
+	if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
+	    BR_DECC_CHK_GEN) {
+		chip->ecc.mode = NAND_ECC_HW;
+		/* put in small page settings and adjust later if needed */
+		chip->ecc.layout = (priv->fmr & FMR_ECCM) ?
+				&fsl_elbc_oob_sp_eccm1 : &fsl_elbc_oob_sp_eccm0;
+		chip->ecc.size = 512;
+		chip->ecc.bytes = 3;
+	} else {
+		/* otherwise fall back to default software ECC */
+		chip->ecc.mode = NAND_ECC_SOFT;
+	}
+
+	return 0;
+}
+
+static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
+{
+	struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+
+	nand_release(&priv->mtd);
+
+	if (priv->vbase)
+		iounmap(priv->vbase);
+
+	ctrl->chips[priv->bank] = NULL;
+	kfree(priv);
+
+	return 0;
+}
+
+static int fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl,
+                               struct device_node *node)
+{
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+	struct fsl_elbc_mtd *priv;
+	struct resource res;
+#ifdef CONFIG_MTD_PARTITIONS
+	static const char *part_probe_types[]
+		= { "cmdlinepart", "RedBoot", NULL };
+	struct mtd_partition *parts;
+#endif
+	int ret;
+	int bank;
+
+	/* get, allocate and map the memory resource */
+	ret = of_address_to_resource(node, 0, &res);
+	if (ret) {
+		dev_err(ctrl->dev, "failed to get resource\n");
+		return ret;
+	}
+
+	/* find which chip select it is connected to */
+	for (bank = 0; bank < MAX_BANKS; bank++)
+		if ((in_be32(&lbc->bank[bank].br) & BR_V) &&
+		    (in_be32(&lbc->bank[bank].br) & BR_MSEL) == BR_MS_FCM &&
+		    (in_be32(&lbc->bank[bank].br) &
+		     in_be32(&lbc->bank[bank].or) & BR_BA)
+		     == res.start)
+			break;
+
+	if (bank >= MAX_BANKS) {
+		dev_err(ctrl->dev, "address did not match any chip selects\n");
+		return -ENODEV;
+	}
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	ctrl->chips[bank] = priv;
+	priv->bank = bank;
+	priv->ctrl = ctrl;
+	priv->dev = ctrl->dev;
+
+	priv->vbase = ioremap(res.start, res.end - res.start + 1);
+	if (!priv->vbase) {
+		dev_err(ctrl->dev, "failed to map chip region\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = fsl_elbc_chip_init(priv);
+	if (ret)
+		goto err;
+
+	ret = nand_scan_ident(&priv->mtd, 1);
+	if (ret)
+		goto err;
+
+	ret = fsl_elbc_chip_init_tail(&priv->mtd);
+	if (ret)
+		goto err;
+
+	ret = nand_scan_tail(&priv->mtd);
+	if (ret)
+		goto err;
+
+#ifdef CONFIG_MTD_PARTITIONS
+	/* 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;
+
+#ifdef CONFIG_MTD_OF_PARTS
+	if (ret == 0) {
+		ret = of_mtd_parse_partitions(priv->dev, &priv->mtd,
+		                              node, &parts);
+		if (ret < 0)
+			goto err;
+	}
+#endif
+
+	if (ret > 0)
+		add_mtd_partitions(&priv->mtd, parts, ret);
+	else
+#endif
+		add_mtd_device(&priv->mtd);
+
+	printk(KERN_INFO "eLBC NAND device at 0x%zx, bank %d\n",
+	       res.start, priv->bank);
+	return 0;
+
+err:
+	fsl_elbc_chip_remove(priv);
+	return ret;
+}
+
+static int __devinit fsl_elbc_ctrl_init(struct fsl_elbc_ctrl *ctrl)
+{
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+
+	/* clear event registers */
+	setbits32(&lbc->ltesr, LTESR_NAND_MASK);
+	out_be32(&lbc->lteatr, 0);
+
+	/* Enable interrupts for any detected events */
+	out_be32(&lbc->lteir, LTESR_NAND_MASK);
+
+	ctrl->read_bytes = 0;
+	ctrl->index = 0;
+	ctrl->addr = NULL;
+
+	return 0;
+}
+
+static int __devexit fsl_elbc_ctrl_remove(struct of_device *ofdev)
+{
+	struct fsl_elbc_ctrl *ctrl = dev_get_drvdata(&ofdev->dev);
+	int i;
+
+	for (i = 0; i < MAX_BANKS; i++)
+		if (ctrl->chips[i])
+			fsl_elbc_chip_remove(ctrl->chips[i]);
+
+	if (ctrl->irq)
+		free_irq(ctrl->irq, ctrl);
+
+	if (ctrl->regs)
+		iounmap(ctrl->regs);
+
+	dev_set_drvdata(&ofdev->dev, NULL);
+	kfree(ctrl);
+	return 0;
+}
+
+/* NOTE: This interrupt is also used to report other localbus events,
+ * such as transaction errors on other chipselects.  If we want to
+ * capture those, we'll need to move the IRQ code into a shared
+ * LBC driver.
+ */
+
+static irqreturn_t fsl_elbc_ctrl_irq(int irqno, void *data)
+{
+	struct fsl_elbc_ctrl *ctrl = data;
+	struct elbc_regs __iomem *lbc = ctrl->regs;
+	__be32 status = in_be32(&lbc->ltesr) & LTESR_NAND_MASK;
+
+	if (status) {
+		out_be32(&lbc->ltesr, status);
+		out_be32(&lbc->lteatr, 0);
+
+		ctrl->irq_status = status;
+		smp_wmb();
+		wake_up(&ctrl->irq_wait);
+
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+/* fsl_elbc_ctrl_probe
+ *
+ * called by device layer when it finds a device matching
+ * one our driver can handled. This code allocates all of
+ * the resources needed for the controller only.  The
+ * resources for the NAND banks themselves are allocated
+ * in the chip probe function.
+*/
+
+static int __devinit fsl_elbc_ctrl_probe(struct of_device *ofdev,
+                                         const struct of_device_id *match)
+{
+	struct device_node *child;
+	struct fsl_elbc_ctrl *ctrl;
+	int ret;
+
+	ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
+	if (!ctrl)
+		return -ENOMEM;
+
+	dev_set_drvdata(&ofdev->dev, ctrl);
+
+	spin_lock_init(&ctrl->controller.lock);
+	init_waitqueue_head(&ctrl->controller.wq);
+	init_waitqueue_head(&ctrl->irq_wait);
+
+	ctrl->regs = of_iomap(ofdev->node, 0);
+	if (!ctrl->regs) {
+		dev_err(&ofdev->dev, "failed to get memory region\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	ctrl->irq = of_irq_to_resource(ofdev->node, 0, NULL);
+	if (ctrl->irq == NO_IRQ) {
+		dev_err(&ofdev->dev, "failed to get irq resource\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	ctrl->dev = &ofdev->dev;
+
+	ret = fsl_elbc_ctrl_init(ctrl);
+	if (ret < 0)
+		goto err;
+
+	ret = request_irq(ctrl->irq, fsl_elbc_ctrl_irq, 0, "fsl-elbc", ctrl);
+	if (ret != 0) {
+		dev_err(&ofdev->dev, "failed to install irq (%d)\n",
+		        ctrl->irq);
+		ret = ctrl->irq;
+		goto err;
+	}
+
+	child = NULL;
+	while ((child = of_get_next_child(ofdev->node, child)))
+		if (of_device_is_compatible(child, "fsl,elbc-fcm-nand"))
+			fsl_elbc_chip_probe(ctrl, child);
+
+	return 0;
+
+err:
+	fsl_elbc_ctrl_remove(ofdev);
+	return ret;
+}
+
+static const struct of_device_id fsl_elbc_match[] = {
+	{
+		.compatible = "fsl,elbc",
+	},
+	{}
+};
+
+static struct of_platform_driver fsl_elbc_ctrl_driver = {
+	.driver = {
+		.name	= "fsl-elbc",
+	},
+	.match_table = fsl_elbc_match,
+	.probe = fsl_elbc_ctrl_probe,
+	.remove = __devexit_p(fsl_elbc_ctrl_remove),
+};
+
+static int __init fsl_elbc_init(void)
+{
+	return of_register_platform_driver(&fsl_elbc_ctrl_driver);
+}
+
+static void __exit fsl_elbc_exit(void)
+{
+	of_unregister_platform_driver(&fsl_elbc_ctrl_driver);
+}
+
+module_init(fsl_elbc_init);
+module_exit(fsl_elbc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Freescale");
+MODULE_DESCRIPTION("Freescale Enhanced Local Bus Controller MTD NAND driver");
-- 
1.5.3.8


From scottwood at freescale.com  Tue Jan 15 18:54:43 2008
From: scottwood at freescale.com (Scott Wood)
Date: Tue, 15 Jan 2008 17:54:43 -0600
Subject: [PATCH 1/2] mtd: Factor out OF partition support from the NOR driver.
Message-ID: <20080115235443.GA1666@loki.buserror.net>

Signed-off-by: Scott Wood <scottwood at freescale.com>
---
 drivers/mtd/Kconfig            |    8 ++++
 drivers/mtd/Makefile           |    1 +
 drivers/mtd/maps/physmap_of.c  |   89 ++++++++++++----------------------------
 drivers/mtd/ofpart.c           |   74 +++++++++++++++++++++++++++++++++
 include/linux/mtd/partitions.h |    9 ++++-
 5 files changed, 118 insertions(+), 63 deletions(-)
 create mode 100644 drivers/mtd/ofpart.c

diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 661eac0..e850334 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -150,6 +150,14 @@ config MTD_AFS_PARTS
 	  for your particular device. It won't happen automatically. The
 	  'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example.
 
+config MTD_OF_PARTS
+	tristate "Flash partition map based on OF description"
+	depends on PPC_OF && MTD_PARTITIONS
+	help
+	  This provides a partition parsing function which derives
+	  the partition map from the children of the flash node,
+	  as described in Documentation/powerpc/booting-without-of.txt.
+
 comment "User Modules And Translation Layers"
 
 config MTD_CHAR
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 7f0b04b..538e33d 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_MTD_CONCAT)	+= mtdconcat.o
 obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
 obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
 obj-$(CONFIG_MTD_AFS_PARTS)	+= afs.o
+obj-$(CONFIG_MTD_OF_PARTS)      += ofpart.o
 
 # 'Users' - code which presents functionality to userspace.
 obj-$(CONFIG_MTD_CHAR)		+= mtdchar.o
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index d4bcd3f..49acd41 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -80,65 +80,6 @@ static int parse_obsolete_partitions(struct of_device *dev,
 
 	return nr_parts;
 }
-
-static int __devinit parse_partitions(struct of_flash *info,
-				      struct of_device *dev)
-{
-	const char *partname;
-	static const char *part_probe_types[]
-		= { "cmdlinepart", "RedBoot", NULL };
-	struct device_node *dp = dev->node, *pp;
-	int nr_parts, i;
-
-	/* First look for RedBoot table or partitions on the command
-	 * line, these take precedence over device tree information */
-	nr_parts = parse_mtd_partitions(info->mtd, part_probe_types,
-					&info->parts, 0);
-	if (nr_parts > 0)
-		return nr_parts;
-
-	/* First count the subnodes */
-	nr_parts = 0;
-	for (pp = of_get_next_child(dp, NULL); pp;
-	     pp = of_get_next_child(dp, pp))
-		nr_parts++;
-
-	if (nr_parts == 0)
-		return parse_obsolete_partitions(dev, info, dp);
-
-	info->parts = kzalloc(nr_parts * sizeof(*info->parts),
-			      GFP_KERNEL);
-	if (!info->parts)
-		return -ENOMEM;
-
-	for (pp = of_get_next_child(dp, NULL), i = 0; pp;
-	     pp = of_get_next_child(dp, pp), i++) {
-		const u32 *reg;
-		int len;
-
-		reg = of_get_property(pp, "reg", &len);
-		if (!reg || (len != 2*sizeof(u32))) {
-			of_node_put(pp);
-			dev_err(&dev->dev, "Invalid 'reg' on %s\n",
-				dp->full_name);
-			kfree(info->parts);
-			info->parts = NULL;
-			return -EINVAL;
-		}
-		info->parts[i].offset = reg[0];
-		info->parts[i].size = reg[1];
-
-		partname = of_get_property(pp, "label", &len);
-		if (!partname)
-			partname = of_get_property(pp, "name", &len);
-		info->parts[i].name = (char *)partname;
-
-		if (of_get_property(pp, "read-only", &len))
-			info->parts[i].mask_flags = MTD_WRITEABLE;
-	}
-
-	return nr_parts;
-}
 #else /* MTD_PARTITIONS */
 #define	OF_FLASH_PARTS(info)		(0)
 #define parse_partitions(info, dev)	(0)
@@ -213,6 +154,10 @@ static struct mtd_info * __devinit obsolete_probe(struct of_device *dev,
 static int __devinit of_flash_probe(struct of_device *dev,
 				    const struct of_device_id *match)
 {
+#ifdef CONFIG_MTD_PARTITIONS
+	static const char *part_probe_types[]
+		= { "cmdlinepart", "RedBoot", NULL };
+#endif
 	struct device_node *dp = dev->node;
 	struct resource res;
 	struct of_flash *info;
@@ -275,13 +220,33 @@ static int __devinit of_flash_probe(struct of_device *dev,
 	}
 	info->mtd->owner = THIS_MODULE;
 
-	err = parse_partitions(info, dev);
+#ifdef CONFIG_MTD_PARTITIONS
+	/* First look for RedBoot table or partitions on the command
+	 * line, these take precedence over device tree information */
+	err = parse_mtd_partitions(info->mtd, part_probe_types,
+	                           &info->parts, 0);
 	if (err < 0)
-		goto err_out;
+		return err;
+
+#ifdef CONFIG_MTD_OF_PARTS
+	if (err == 0) {
+		err = of_mtd_parse_partitions(&dev->dev, info->mtd,
+		                              dp, &info->parts);
+		if (err < 0)
+			return err;
+	}
+#endif
+
+	if (err == 0) {
+		err = parse_obsolete_partitions(dev, info, dp);
+		if (err < 0)
+			return err;
+	}
 
 	if (err > 0)
-		add_mtd_partitions(info->mtd, OF_FLASH_PARTS(info), err);
+		add_mtd_partitions(info->mtd, info->parts, err);
 	else
+#endif
 		add_mtd_device(info->mtd);
 
 	return 0;
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
new file mode 100644
index 0000000..f86e069
--- /dev/null
+++ b/drivers/mtd/ofpart.c
@@ -0,0 +1,74 @@
+/*
+ * Flash partitions described by the OF (or flattened) device tree
+ *
+ * Copyright (C) 2006 MontaVista Software Inc.
+ * Author: Vitaly Wool <vwool at ru.mvista.com>
+ *
+ * Revised to handle newer style flash binding by:
+ *   Copyright (C) 2007 David Gibson, IBM Corporation.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+int __devinit of_mtd_parse_partitions(struct device *dev,
+                                      struct mtd_info *mtd,
+                                      struct device_node *node,
+                                      struct mtd_partition **pparts)
+{
+	const char *partname;
+	struct device_node *pp;
+	int nr_parts, i;
+
+	/* First count the subnodes */
+	pp = NULL;
+	nr_parts = 0;
+	while ((pp = of_get_next_child(node, pp)))
+		nr_parts++;
+
+	if (nr_parts == 0)
+		return 0;
+
+	*pparts = kzalloc(nr_parts * sizeof(**pparts), GFP_KERNEL);
+	if (!*pparts)
+		return -ENOMEM;
+
+	pp = NULL;
+	i = 0;
+	while ((pp = of_get_next_child(node, pp))) {
+		const u32 *reg;
+		int len;
+
+		reg = of_get_property(pp, "reg", &len);
+		if (!reg || (len != 2 * sizeof(u32))) {
+			of_node_put(pp);
+			dev_err(dev, "Invalid 'reg' on %s\n", node->full_name);
+			kfree(*pparts);
+			*pparts = NULL;
+			return -EINVAL;
+		}
+		(*pparts)[i].offset = reg[0];
+		(*pparts)[i].size = reg[1];
+
+		partname = of_get_property(pp, "label", &len);
+		if (!partname)
+			partname = of_get_property(pp, "name", &len);
+		(*pparts)[i].name = (char *)partname;
+
+		if (of_get_property(pp, "read-only", &len))
+			(*pparts)[i].mask_flags = MTD_WRITEABLE;
+
+		i++;
+	}
+
+	return nr_parts;
+}
+EXPORT_SYMBOL(of_mtd_parse_partitions);
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
index da6b3d6..7c37d7e 100644
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -71,5 +71,12 @@ extern int parse_mtd_partitions(struct mtd_info *master, const char **types,
 
 #define put_partition_parser(p) do { module_put((p)->owner); } while(0)
 
-#endif
+struct device;
+struct device_node;
+
+int __devinit of_mtd_parse_partitions(struct device *dev,
+                                      struct mtd_info *mtd,
+                                      struct device_node *node,
+                                      struct mtd_partition **pparts);
 
+#endif
-- 
1.5.3.8



From eric.y.miao at gmail.com  Tue Jan 15 19:52:21 2008
From: eric.y.miao at gmail.com (eric miao)
Date: Wed, 16 Jan 2008 08:52:21 +0800
Subject: [PATCH] basic pxa3 nand controller support
In-Reply-To: <1200051862.1727.75.camel@localhost.localdomain>
References: <loom.20080107T001557-159@post.gmane.org>
	<1200051862.1727.75.camel@localhost.localdomain>
Message-ID: <f17812d70801151652s739fd05eyfc82ab569d8efdd7@mail.gmail.com>

On Jan 11, 2008 7:44 PM, Sergey Podstavin <spodstavin at ru.mvista.com> wrote:
> This is a fixed version for pxa3 nand controller,
> working on pxa300 Zylonite

great, thanks for trying this. It looks like a bunch of things are added back
from previous marvell released packages :-)

1. io mapping is not recommended for peripheral drivers, we instead use
   ioremap() in the nand driver, so it's not a must to map those registers
   when pxa_map_io()

2. as I said, those DRCMRxx macros can be well replaced by DRCMR(xx),
   the original DRCMR(xx) macro has an issue, which is corrected by
   recent patch sent to RMK, and is supposed to be merged in recent
   .24-rc7

3. partition tables should be moved outside of the driver into platform
   code

Apart from the above, could you let me know which modifications you
made this work? You know it's a big patch, and is difficult for line to line
comparison with my original one..., thanks!

>
> Best wishes,
> Sergey Podstavin.
>
>
> >eric miao <eric.y.miao <at> gmail.com> writes:
> >
> >> Early feedback is welcome, thanks!
> >
> >Hi Eric
> >
> >Overall the patch looks good, just a few comments.
> >
> >The patch does not apply cleanly unless I remove the spurious newline before
> >line 1284 resulting in the following error:
> >patch: **** malformed patch at line 1284: pm_message_t state)
> >
> >The DRCMR97 register is not defined anywhere, at lest not in 2.6.24-rc6:
> >drivers/mtd/nand/pxa3xx_nand.c:542: error: 'DRCMR97' undeclared (first use in
> >this function)
> >
> >The registers and bit definitions should be moved to pxa-regs.h, not?
> >
> >I had my troubles getting it to work on a custom PXA320 board. I kinda figured
> >out what platform data it needs, but still can't seem to get it to work properly:
> >pxa3xx-nand pxa3xx-nand: failed to detect flash
> >
> >What kernel does your patch apply to? What CPUs/boards did you try it on? Can
> >you provide an example platform integration required to make it work?
> >
> >Cheers
> >
> >Marcel
>
>
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>
>



-- 
Cheers
- eric


From a.p.zijlstra at chello.nl  Wed Jan 16 03:16:38 2008
From: a.p.zijlstra at chello.nl (Peter Zijlstra)
Date: Wed, 16 Jan 2008 09:16:38 +0100
Subject: [PATCH] block2mtd lockdep_init_map warning
In-Reply-To: <200801081147.00701.rusty@rustcorp.com.au>
References: <200801061911.m06JBldW020012@agora.fsl.cs.sunysb.edu>
	<1199700326.7143.10.camel@twins>
	<200801081147.00701.rusty@rustcorp.com.au>
Message-ID: <1200471398.9535.24.camel@taijtu>


On Tue, 2008-01-08 at 11:47 +1100, Rusty Russell wrote:
> On Monday 07 January 2008 21:05:26 Peter Zijlstra wrote:
> > On Sun, 2008-01-06 at 14:11 -0500, Erez Zadok wrote:
> > > > Ingo, Peter, does either of you actually care about this problem?  In
> > > > the last round when I debugged this problem there was a notable lack of
> > > > reaction from either of you.
> > >
> > > The problem appears to be an interaction of two components--module
> > > loading and lockdep--that's perhaps why it wasn't given enough attention.
> >
> > Would something like this work for people?
> 
> Hi Peter,
> 
>     There's nothing wrong with this patch, but I think it papers over a more
> general problem: we enter the module (to parse args) while it's not in the
> module list.  This also means we won't get a nice oops if it crashes.
> 
>     This is untested, but does it solve it for you?

I think it should, Erez care to give it a spin?

> diff -r 68fd1b22db89 kernel/module.c
> --- a/kernel/module.c	Mon Jan 07 18:59:50 2008 +1100
> +++ b/kernel/module.c	Tue Jan 08 11:46:11 2008 +1100
> @@ -2043,6 +2043,11 @@ static struct module *load_module(void _
>  		printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
>  		       mod->name);
>  
> +	/* Now sew it into the lists so we can get lockdep and oops
> +         * info during argument parsing.  Noone should access us, since
> +         * strong_try_module_get() will fail. */
> +	stop_machine_run(__link_module, mod, NR_CPUS);
> +
>  	/* Size of section 0 is 0, so this works well if no params */
>  	err = parse_args(mod->name, mod->args,
>  			 (struct kernel_param *)
> @@ -2051,7 +2056,7 @@ static struct module *load_module(void _
>  			 / sizeof(struct kernel_param),
>  			 NULL);
>  	if (err < 0)
> -		goto arch_cleanup;
> +		goto unlink;
>  
>  	err = mod_sysfs_setup(mod,
>  			      (struct kernel_param *)
> @@ -2059,7 +2064,7 @@ static struct module *load_module(void _
>  			      sechdrs[setupindex].sh_size
>  			      / sizeof(struct kernel_param));
>  	if (err < 0)
> -		goto arch_cleanup;
> +		goto unlink;
>  	add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
>  	add_notes_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
>  
> @@ -2074,7 +2079,8 @@ static struct module *load_module(void _
>  	/* Done! */
>  	return mod;
>  
> - arch_cleanup:
> + unlink:
> +	stop_machine_run(__unlink_module, mod, NR_CPUS);
>  	module_arch_cleanup(mod);
>   cleanup:
>  	module_unload_free(mod);
> @@ -2130,10 +2136,6 @@ sys_init_module(void __user *umod,
>  		mutex_unlock(&module_mutex);
>  		return PTR_ERR(mod);
>  	}
> -
> -	/* Now sew it into the lists.  They won't access us, since
> -           strong_try_module_get() will fail. */
> -	stop_machine_run(__link_module, mod, NR_CPUS);
>  
>  	/* Drop lock so they can recurse */
>  	mutex_unlock(&module_mutex);



From sfr at canb.auug.org.au  Tue Jan 15 23:41:53 2008
From: sfr at canb.auug.org.au (Stephen Rothwell)
Date: Wed, 16 Jan 2008 15:41:53 +1100
Subject: [PATCH 2/3] mtd: Factor out OF partition support from the NOR
	driver.
In-Reply-To: <478D450A.8060802@freescale.com>
References: <20080114172116.a2e5aa18.sfr@canb.auug.org.au>
	<478D450A.8060802@freescale.com>
Message-ID: <20080116154153.2f6c2ee9.sfr@canb.auug.org.au>

On Tue, 15 Jan 2008 17:43:06 -0600 Scott Wood <scottwood at freescale.com> wrote:
>
> Stephen Rothwell wrote:
> >> +	nr_parts = 0;
> >> +	for (pp = node->child; pp; pp = pp->sibling)
> > 
> > 	for_each_child_of_node(node, pp)
> 
> "for_each_child_of_node" is only in Paul's tree, but this has to go via mtd.
> 
> Plus, I'm just moving the code; it's not new.

OK, we can change it later.

-- 
Cheers,
Stephen Rothwell                    sfr at canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://lists.infradead.org/pipermail/linux-mtd/attachments/20080116/8a92d5bc/attachment-0001.bin 

From dedekind at infradead.org  Wed Jan 16 10:03:36 2008
From: dedekind at infradead.org (Artem Bityutskiy)
Date: Wed, 16 Jan 2008 17:03:36 +0200
Subject: [PATCH] UBI: add auto-resize feature
Message-ID: <20080116150336.16917.1867.sendpatchset@golum>

>From df4d5783bde51db7a213db929252718dbc4381ca Mon Sep 17 00:00:00 2001
From: Artem Bityutskiy <Artem.Bityutskiy at nokia.com>
Date: Wed, 16 Jan 2008 15:44:24 +0200
Subject: [PATCH] UBI: add auto-resize feature

The problem: NAND flashes have different amount of initial bad physical
eraseblocks (marked as bad by the manufacturer). For example, for 256MiB
Samsung OneNAND flash there might be from 0 to 40 bad initial eraseblocks,
which is about 2%. When UBI is used as the base system, one needs to know
the exact amount of good physical eraseblocks, because this number is
needed to create the UBI image which is put to the devices during
production. But this number is not know, which forces us to use the
minimum number of good physical eraseblocks. And UBI additionally
reserves some percentage of physical eraseblocks for bad block handling
(default is 1%), so we have 1-3% of PEBs reserved at the end, depending
on the amount of initial bad PEBs. But it is desired to always have
1% (or more, depending on the configuration).

Solution: this patch adds an "auto-resize" flag to the volume table.
The volume which has the "auto-resize" flag will automatically be re-sized
(enlarged) on the first UBI initialization. UBI clears the flag when
the volume is re-sized. Only one volume may have the "auto-resize" flag.

So, the production UBI image may have one volume with "auto-resize"
flag set, and its size is automatically adjusted on the first boot
of the device.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy at nokia.com>
---
 drivers/mtd/ubi/build.c  |   69 ++++++++++++++++++++++++++++++++++++++++++---
 drivers/mtd/ubi/eba.c    |   15 ----------
 drivers/mtd/ubi/ubi.h    |    6 +++-
 drivers/mtd/ubi/vmt.c    |    2 -
 drivers/mtd/ubi/vtbl.c   |   11 +++++++
 drivers/mtd/ubi/wl.c     |    1 -
 include/mtd/ubi-header.h |   43 +++++++++++++++++++++++++++-
 7 files changed, 121 insertions(+), 26 deletions(-)

diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 8b45735..4e761e9 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -366,9 +366,6 @@ static int uif_init(struct ubi_device *ubi)
 	int i, err;
 	dev_t dev;
 
-	mutex_init(&ubi->volumes_mutex);
-	spin_lock_init(&ubi->volumes_lock);
-
 	sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num);
 
 	/*
@@ -624,6 +621,58 @@ static int io_init(struct ubi_device *ubi)
 }
 
 /**
+ * autoresize - re-size the volume which has the "auto-resize" flag set.
+ * @ubi: UBI device description object
+ * @vol_id: ID of the volume to re-size
+ *
+ * This function re-sizes the volume marked by the @UBI_VTBL_AUTORESIZE_FLG in
+ * the volume table to the largest possible size. See comments in ubi-header.h
+ * for more description of the flag. Returns zero in case of success and a
+ * negative error code in case of failure.
+ */
+static int autoresize(struct ubi_device *ubi, int vol_id)
+{
+	struct ubi_volume_desc desc;
+	struct ubi_volume *vol = ubi->volumes[vol_id];
+	int err, old_reserved_pebs = vol->reserved_pebs;
+
+	/*
+	 * Clear the auto-resize flag in the volume in-memory copy of the
+	 * volume table, and 'ubi_resize_volume()' will propogate this change
+	 * to the flash.
+	 */
+	ubi->vtbl[vol_id].flags &= ~UBI_VTBL_AUTORESIZE_FLG;
+
+	if (ubi->avail_pebs == 0) {
+		struct ubi_vtbl_record vtbl_rec;
+
+		/*
+		 * No avalilable PEBs to re-size the volume, clear the flag on
+		 * flash and exit.
+		 */
+		memcpy(&vtbl_rec, &ubi->vtbl[vol_id],
+		       sizeof(struct ubi_vtbl_record));
+		err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
+		if (err)
+			ubi_err("cannot clean auto-resize flag for volume %d",
+				vol_id);
+	} else {
+		desc.vol = vol;
+		err = ubi_resize_volume(&desc,
+					old_reserved_pebs + ubi->avail_pebs);
+		if (err)
+			ubi_err("cannot auto-resize volume %d", vol_id);
+	}
+
+	if (err)
+		return err;
+
+	ubi_msg("volume %d (\"%s\") re-sized from %d to %d LEBs", vol_id,
+		vol->name, old_reserved_pebs, vol->reserved_pebs);
+	return 0;
+}
+
+/**
  * ubi_attach_mtd_dev - attach an MTD device.
  * @mtd_dev: MTD device description object
  * @ubi_num: number to assign to the new UBI device
@@ -699,6 +748,12 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
 	ubi->mtd = mtd;
 	ubi->ubi_num = ubi_num;
 	ubi->vid_hdr_offset = vid_hdr_offset;
+	ubi->autoresize_vol_id = -1;
+
+	mutex_init(&ubi->buf_mutex);
+	mutex_init(&ubi->ckvol_mutex);
+	mutex_init(&ubi->volumes_mutex);
+	spin_lock_init(&ubi->volumes_lock);
 
 	dbg_msg("attaching mtd%d to ubi%d: VID header offset %d",
 		mtd->index, ubi_num, vid_hdr_offset);
@@ -707,8 +762,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
 	if (err)
 		goto out_free;
 
-	mutex_init(&ubi->buf_mutex);
-	mutex_init(&ubi->ckvol_mutex);
 	ubi->peb_buf1 = vmalloc(ubi->peb_size);
 	if (!ubi->peb_buf1)
 		goto out_free;
@@ -730,6 +783,12 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
 		goto out_free;
 	}
 
+	if (ubi->autoresize_vol_id != -1) {
+		err = autoresize(ubi, ubi->autoresize_vol_id);
+		if (err)
+			goto out_detach;
+	}
+
 	err = uif_init(ubi);
 	if (err)
 		goto out_detach;
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 7c05c6e..1f951e3 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -341,9 +341,6 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
 {
 	int err, pnum, vol_id = vol->vol_id;
 
-	ubi_assert(ubi->ref_count > 0);
-	ubi_assert(vol->ref_count > 0);
-
 	if (ubi->ro_mode)
 		return -EROFS;
 
@@ -392,9 +389,6 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
 	struct ubi_vid_hdr *vid_hdr;
 	uint32_t uninitialized_var(crc);
 
-	ubi_assert(ubi->ref_count > 0);
-	ubi_assert(vol->ref_count > 0);
-
 	err = leb_read_lock(ubi, vol_id, lnum);
 	if (err)
 		return err;
@@ -618,9 +612,6 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
 	int err, pnum, tries = 0, vol_id = vol->vol_id;
 	struct ubi_vid_hdr *vid_hdr;
 
-	ubi_assert(ubi->ref_count > 0);
-	ubi_assert(vol->ref_count > 0);
-
 	if (ubi->ro_mode)
 		return -EROFS;
 
@@ -754,9 +745,6 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
 	struct ubi_vid_hdr *vid_hdr;
 	uint32_t crc;
 
-	ubi_assert(ubi->ref_count > 0);
-	ubi_assert(vol->ref_count > 0);
-
 	if (ubi->ro_mode)
 		return -EROFS;
 
@@ -871,9 +859,6 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
 	struct ubi_vid_hdr *vid_hdr;
 	uint32_t crc;
 
-	ubi_assert(ubi->ref_count > 0);
-	ubi_assert(vol->ref_count > 0);
-
 	if (ubi->ro_mode)
 		return -EROFS;
 
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 90cdcad..a8cdbd0 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -250,9 +250,11 @@ struct ubi_wl_entry;
  * @rsvd_pebs: count of reserved physical eraseblocks
  * @avail_pebs: count of available physical eraseblocks
  * @beb_rsvd_pebs: how many physical eraseblocks are reserved for bad PEB
- * handling
+ *                 handling
  * @beb_rsvd_level: normal level of PEBs reserved for bad PEB handling
  *
+ * @autoresize_vol_id: ID of the volume which has to be auto-resized at the end
+ *                     of UBI ititializetion
  * @vtbl_slots: how many slots are available in the volume table
  * @vtbl_size: size of the volume table in bytes
  * @vtbl: in-RAM volume table copy
@@ -333,12 +335,14 @@ struct ubi_device {
 	int beb_rsvd_pebs;
 	int beb_rsvd_level;
 
+	int autoresize_vol_id;
 	int vtbl_slots;
 	int vtbl_size;
 	struct ubi_vtbl_record *vtbl;
 	struct mutex volumes_mutex;
 
 	int max_ec;
+	/* TODO: mean_ec is not updated run-time, fix */
 	int mean_ec;
 
 	/* EBA unit's stuff */
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index 221ce70..a3ca225 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -497,8 +497,6 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
 
 	dbg_msg("re-size volume %d to from %d to %d PEBs",
 		vol_id, vol->reserved_pebs, reserved_pebs);
-	ubi_assert(desc->mode == UBI_EXCLUSIVE);
-	ubi_assert(vol == ubi->volumes[vol_id]);
 
 	if (vol->vol_type == UBI_STATIC_VOLUME &&
 	    reserved_pebs < vol->used_ebs) {
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index 7a1a8a1..2fd9cf4 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -514,6 +514,17 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
 		vol->name[vol->name_len] = '\0';
 		vol->vol_id = i;
 
+		if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) {
+			/* Auto re-size flag may be set only for one volume */
+			if (ubi->autoresize_vol_id != -1) {
+				ubi_err("more then one auto-resize volume (%d "
+					"and %d)", ubi->autoresize_vol_id, i);
+				return -EINVAL;
+			}
+
+			ubi->autoresize_vol_id = i;
+		}
+
 		ubi_assert(!ubi->volumes[i]);
 		ubi->volumes[i] = vol;
 		ubi->vol_count += 1;
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index bf4c555..c592fd3 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -1303,7 +1303,6 @@ int ubi_wl_flush(struct ubi_device *ubi)
 	 * Make sure all the works which have been done in parallel are
 	 * finished.
 	 */
-	ubi_assert(ubi->ref_count > 0);
 	down_write(&ubi->work_sem);
 	up_write(&ubi->work_sem);
 
diff --git a/include/mtd/ubi-header.h b/include/mtd/ubi-header.h
index 74efa77..69d5d7e 100644
--- a/include/mtd/ubi-header.h
+++ b/include/mtd/ubi-header.h
@@ -58,6 +58,43 @@ enum {
 };
 
 /*
+ * Volume flags used in the volume table record.
+ *
+ * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume
+ *
+ * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume
+ * table. UBI automatically re-sizes the volume which has this flag and makes
+ * the volume to be of largest possible size. This means that if after the
+ * initialization UBI finds out that there are available physical eraseblocks
+ * present on the device, it automatically appends all of them to the volume
+ * (the physical eraseblocks reserved for bad eraseblocks handling and other
+ * reserved physical eraseblocks are not taken). So, if there is a volume with
+ * the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical
+ * eraseblocks will be zero after UBI is loaded, because all of them will be
+ * reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared
+ * after the volume had been initialized.
+ *
+ * The auto-resize feature is useful for device production purposes. For
+ * example, different NAND flash chips may have different amount of initial bad
+ * eraseblocks, depending of particular chip instance. Manufacturers of NAND
+ * chips usually guarantee that the amount of initial bad eraseblocks does not
+ * exceed certain percent, e.g. 2%. When one creates an UBI image which will be
+ * flashed to the end devices in production, he does not know the exact amount
+ * of good physical eraseblocks the NAND chip on the device will have, but this
+ * number is required to calculate the volume sized and put them to the volume
+ * table of the UBI image. In this case, one of the volumes (e.g., the one
+ * which will store the root file system) is marked as "auto-resizable", and
+ * UBI will adjust its size on the first boot if needed.
+ *
+ * Note, first UBI reserves some amount of physical eraseblocks for bad
+ * eraseblock handling, and then re-sizes the volume, not vice-versa. This
+ * means that the pool of reserved physical eraseblocks will always be present.
+ */
+enum {
+	UBI_VTBL_AUTORESIZE_FLG = 0x01,
+};
+
+/*
  * Compatibility constants used by internal volumes.
  *
  * @UBI_COMPAT_DELETE: delete this internal volume before anything is written
@@ -289,7 +326,8 @@ struct ubi_vid_hdr {
  * @upd_marker: if volume update was started but not finished
  * @name_len: volume name length
  * @name: the volume name
- * @padding2: reserved, zeroes
+ * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG)
+ * @padding: reserved, zeroes
  * @crc: a CRC32 checksum of the record
  *
  * The volume table records are stored in the volume table, which is stored in
@@ -324,7 +362,8 @@ struct ubi_vtbl_record {
 	__u8    upd_marker;
 	__be16  name_len;
 	__u8    name[UBI_VOL_NAME_MAX+1];
-	__u8    padding2[24];
+	__u8    flags;
+	__u8    padding[23];
 	__be32  crc;
 } __attribute__ ((packed));
 
-- 
1.5.3.4



From dmcleod at bittware.com  Wed Jan 16 08:57:50 2008
From: dmcleod at bittware.com (DMcLeod)
Date: Wed, 16 Jan 2008 08:57:50 -0500
Subject: JFFS2 access time
Message-ID: <478E0D5E.8070508@bittware.com>

Hi all,

We are using uClinux git 2.6.23. We have 4 2.5MB files sitting in a 
directory on a ~40MB jffs2 partition (on NOR flash). The very first time 
we do an 'ls' in that directory, the response takes literally minutes. 
After the initial delay, any accesses to those files are very 
quick.,,Originally, we started off with the Microtronix 1.4 kernel and 
it did not have this problem. The pre-git version of uClinux-dist had 
this problem but not as severe - it was more like 40 seconds to list the 
contents of that directory.


Thanks in advance,


From c-d.hailfinger.devel.2006 at gmx.net  Wed Jan 16 09:45:20 2008
From: c-d.hailfinger.devel.2006 at gmx.net (Carl-Daniel Hailfinger)
Date: Wed, 16 Jan 2008 15:45:20 +0100
Subject: [PATCH] [MTD] [RESEND] MAPS: add support for Nvidia MCP55 to ck804xrom
Message-ID: <478E1880.2040609@gmx.net>

[PATCH] [MTD] MAPS: add support for Nvidia MCP55 to ck804xrom

This patch extends the existing MAPS driver for the Nvidia CK804 chipset
(ck804xrom.c) to also work on the Nvidia MCP55 chipset. As both chipsets
are rather similar, suporting them both with the same driver is easy.

The patch is not ready for inclusion yet, it needs some codingstyle care
and probably better comments. The indenting is wrong at some points to
keep the diff minimal for a first review. I will post a better version
once I get some comments.

Testers are most welcome! I lack access to the hardware in question and
would appreciate any reports.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006 at gmx.net>

--- linux-mtd/drivers/mtd/maps/ck804xrom.c~	2007-08-01 14:51:00.000000000 +0200
+++ linux-mtd/drivers/mtd/maps/ck804xrom.c	2007-08-01 15:45:25.000000000 +0200
@@ -45,8 +45,9 @@
 	char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
 };
 
-
-/* The 2 bits controlling the window size are often set to allow reading
+/*
+ * The following applies to ck804 only:
+ * The 2 bits controlling the window size are often set to allow reading
  * the BIOS, but too small to allow writing, since the lock registers are
  * 4MiB lower in the address space than the data.
  *
@@ -58,10 +59,17 @@
  * If only the 7 Bit is set, it is a 4MiB window.  Otherwise, a
  * 64KiB window.
  *
+ * The following applies to mcp55 only:
+ * The 15 bits controlling the window size are distributed as follows: 
+ * byte @0x88: bit 0..7
+ * byte @0x8c: bit 8..15
+ * word @0x90: bit 16..30
+ * If all bits are enabled, we have a 16? MiB window
+ * Please set win_size_bits to 0x7fffffff if you actually want to do something
  */
 static uint win_size_bits = 0;
 module_param(win_size_bits, uint, 0);
-MODULE_PARM_DESC(win_size_bits, "ROM window size bits override for 0x88 byte, normally set by BIOS.");
+MODULE_PARM_DESC(win_size_bits, "ROM window size bits override, normally set by BIOS.");
 
 static struct ck804xrom_window ck804xrom_window = {
 	.maps = LIST_HEAD_INIT(ck804xrom_window.maps),
@@ -106,6 +114,7 @@
 {
 	static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
 	u8 byte;
+	u16 word;
 	struct ck804xrom_window *window = &ck804xrom_window;
 	struct ck804xrom_map_info *map = NULL;
 	unsigned long map_top;
@@ -113,6 +122,8 @@
 	/* Remember the pci dev I find the window in */
 	window->pdev = pci_dev_get(pdev);
 
+	switch (ent->driver_data) {
+	case 1:
 	/* Enable the selected rom window.  This is often incorrectly
 	 * set up by the BIOS, and the 4MiB offset for the lock registers
 	 * requires the full 5MiB of window space.
@@ -123,7 +134,6 @@
         pci_read_config_byte(pdev, 0x88, &byte);
         pci_write_config_byte(pdev, 0x88, byte | win_size_bits );
 
-
 	/* Assume the rom window is properly setup, and find it's size */
 	pci_read_config_byte(pdev, 0x88, &byte);
 
@@ -133,6 +143,20 @@
 		window->phys = 0xffc00000; /* 4MiB */
 	else
 		window->phys = 0xffff0000; /* 64KiB */
+	break;
+	case 2:
+	pci_read_config_byte(pdev, 0x88, &byte);
+	pci_write_config_byte(pdev, 0x88, byte | (win_size_bits & 0xff));
+
+	pci_read_config_byte(pdev, 0x8c, &byte);
+	pci_write_config_byte(pdev, 0x8c, byte | ((win_size_bits & 0xff00) >> 8));
+
+	pci_read_config_word(pdev, 0x90, &word);
+	pci_write_config_word(pdev, 0x90, word | ((win_size_bits & 0x7fff0000) >> 16));
+
+	window->phys = 0xff000000; /* 16MiB, hardcoded for now */
+	break;
+	}
 
 	window->size = 0xffffffffUL - window->phys + 1UL;
 
@@ -304,7 +328,23 @@
 
 static struct pci_device_id ck804xrom_pci_tbl[] = {
 	{ PCI_VENDOR_ID_NVIDIA, 0x0051,
-        PCI_ANY_ID, PCI_ANY_ID, }, /* nvidia ck804 */
+        PCI_ANY_ID, PCI_ANY_ID, 1 }, /* nvidia ck804 */
+	{ PCI_VENDOR_ID_NVIDIA, 0x0360,
+        PCI_ANY_ID, PCI_ANY_ID, 2 }, /* nvidia mcp55 */
+	{ PCI_VENDOR_ID_NVIDIA, 0x0361,
+        PCI_ANY_ID, PCI_ANY_ID, 2 }, /* nvidia mcp55 */
+	{ PCI_VENDOR_ID_NVIDIA, 0x0362,
+        PCI_ANY_ID, PCI_ANY_ID, 2 }, /* nvidia mcp55 */
+	{ PCI_VENDOR_ID_NVIDIA, 0x0363,
+        PCI_ANY_ID, PCI_ANY_ID, 2 }, /* nvidia mcp55 */
+	{ PCI_VENDOR_ID_NVIDIA, 0x0364,
+        PCI_ANY_ID, PCI_ANY_ID, 2 }, /* nvidia mcp55 */
+	{ PCI_VENDOR_ID_NVIDIA, 0x0365,
+        PCI_ANY_ID, PCI_ANY_ID, 2 }, /* nvidia mcp55 */
+	{ PCI_VENDOR_ID_NVIDIA, 0x0366,
+        PCI_ANY_ID, PCI_ANY_ID, 2 }, /* nvidia mcp55 */
+	{ PCI_VENDOR_ID_NVIDIA, 0x03607,
+        PCI_ANY_ID, PCI_ANY_ID, 2 }, /* nvidia mcp55 */
 	{ 0, }
 };
 
@@ -332,7 +372,7 @@
 			break;
 	}
 	if (pdev) {
-		retVal = ck804xrom_init_one(pdev, &ck804xrom_pci_tbl[0]);
+		retVal = ck804xrom_init_one(pdev, id);
 		pci_dev_put(pdev);
 		return retVal;
 	}







From dedekind at infradead.org  Wed Jan 16 09:29:46 2008
From: dedekind at infradead.org (Artem Bityutskiy)
Date: Wed, 16 Jan 2008 16:29:46 +0200
Subject: [PATCH] UBI: add auto-resize feature
In-Reply-To: <20080116150336.16917.1867.sendpatchset@golum>
References: <20080116150336.16917.1867.sendpatchset@golum>
Message-ID: <1200493786.3956.41.camel@sauron>

On Wed, 2008-01-16 at 17:03 +0200, Artem Bityutskiy wrote:
> >From df4d5783bde51db7a213db929252718dbc4381ca Mon Sep 17 00:00:00 2001
> From: Artem Bityutskiy <Artem.Bityutskiy at nokia.com>
> Date: Wed, 16 Jan 2008 15:44:24 +0200
> Subject: [PATCH] UBI: add auto-resize feature
> 
> The problem: NAND flashes have different amount of initial bad physical
> eraseblocks (marked as bad by the manufacturer). For example, for 256MiB
> Samsung OneNAND flash there might be from 0 to 40 bad initial eraseblocks,
> which is about 2%. When UBI is used as the base system, one needs to know
> the exact amount of good physical eraseblocks, because this number is
> needed to create the UBI image which is put to the devices during
> production. But this number is not know, which forces us to use the
> minimum number of good physical eraseblocks. And UBI additionally
> reserves some percentage of physical eraseblocks for bad block handling
> (default is 1%), so we have 1-3% of PEBs reserved at the end, depending
> on the amount of initial bad PEBs. But it is desired to always have
> 1% (or more, depending on the configuration).
> 
> Solution: this patch adds an "auto-resize" flag to the volume table.
> The volume which has the "auto-resize" flag will automatically be re-sized
> (enlarged) on the first UBI initialization. UBI clears the flag when
> the volume is re-sized. Only one volume may have the "auto-resize" flag.
> 
> So, the production UBI image may have one volume with "auto-resize"
> flag set, and its size is automatically adjusted on the first boot
> of the device.

Forgot to note that this is backward-compatible.

-- 
Best regards,
Artem Bityutskiy (???????? ?????)



From scottwood at freescale.com  Wed Jan 16 11:36:03 2008
From: scottwood at freescale.com (Scott Wood)
Date: Wed, 16 Jan 2008 10:36:03 -0600
Subject: [PATCH] Fix misparenthesization introduced by commit
	78b65179d08e7e4466ba69d5ede85035a2c96358
Message-ID: <20080116163603.GA4703@loki.buserror.net>

Signed-off-by: Scott Wood <scottwood at freescale.com>
---
 drivers/mtd/nand/nand_base.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 85a7283..971d58c 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2472,9 +2472,9 @@ int nand_scan_tail(struct mtd_info *mtd)
 		if ((!chip->ecc.calculate || !chip->ecc.correct ||
 		     !chip->ecc.hwctl) &&
 		    (!chip->ecc.read_page ||
-		     chip->ecc.read_page == nand_read_page_hwecc) ||
+		     chip->ecc.read_page == nand_read_page_hwecc ||
 		     !chip->ecc.write_page ||
-		     chip->ecc.write_page == nand_write_page_hwecc) {
+		     chip->ecc.write_page == nand_write_page_hwecc)) {
 			printk(KERN_WARNING "No ECC functions supplied, "
 			       "Hardware ECC not possible\n");
 			BUG();
-- 
1.5.3.8


From joern at logfs.org  Wed Jan 16 16:20:54 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Wed, 16 Jan 2008 22:20:54 +0100
Subject: [PATCH] block2mtd lockdep_init_map warning
In-Reply-To: <200801081147.00701.rusty@rustcorp.com.au>
References: <200801061911.m06JBldW020012@agora.fsl.cs.sunysb.edu>
	<1199700326.7143.10.camel@twins>
	<200801081147.00701.rusty@rustcorp.com.au>
Message-ID: <20080116212054.GA891@lazybastard.org>

On Tue, 8 January 2008 11:47:00 +1100, Rusty Russell wrote:
> 
>     There's nothing wrong with this patch, but I think it papers over a more
> general problem: we enter the module (to parse args) while it's not in the
> module list.  This also means we won't get a nice oops if it crashes.
> 
>     This is untested, but does it solve it for you?

Not sure about lockdep, but it makes all the difference for an oops,
forced by explicit BUG() in block2mtd.

Before:
kernel BUG at drivers/mtd/devices/block2mtd.c:382!
invalid opcode: 0000 [#1]
Modules linked in:
CPU:    0
EIP:    0060:[<e0818003>]    Not tainted VLI
EFLAGS: 00000246   (2.6.22 #38)
EIP is at 0xe0818003
eax: dfe8c7da   ebx: dfe8c7d0   ecx: e08185a8   edx: e08185a8
esi: e0818b1c   edi: dfe8c7da   ebp: df95de78   esp: df95de78
ds: 007b   es: 007b   fs: 0000  gs: 0033  ss: 0068
Process insmod (pid: 1076, ti=df95c000 task=df903080 task.ti=df95c000)
Stack: df95dec4 c0125576 00000000 df95de90 fffffff8 e0815932 00000006 00000000 
       e08185a8 e0818b4c 00000283 00000000 0000000b e0818b1c 00000000 dfe8c7dc 
       00000014 e0815b48 00000014 df95dfb0 c01314e4 00000001 00000000 df95df24 
Call Trace:
 [<c0103248>] show_trace_log_lvl+0x1a/0x2f
 [<c01032f8>] show_stack_log_lvl+0x9b/0xa3
 [<c01034be>] show_registers+0x1be/0x290
 [<c010366f>] die+0xdf/0x1a1
 [<c01037ba>] do_trap+0x89/0xa2
 [<c0103b25>] do_invalid_op+0x88/0x92
 [<c0384e82>] error_code+0x6a/0x70
 [<c0125576>] parse_args+0x120/0x1f6
 [<c01314e4>] sys_init_module+0xf76/0x1297
 [<c01023ee>] syscall_call+0x7/0xb
 =======================
Code: <0f> 0b eb fe 55 85 c0 89 e5 53 89 c3 74 31 8b 40 28 e8 ee 3e 93 df 
EIP: [<e0818003>] 0xe0818003 SS:ESP 0068:df95de78

After:
kernel BUG at drivers/mtd/devices/block2mtd.c:382!
invalid opcode: 0000 [#1]
Modules linked in: block2mtd
CPU:    0
EIP:    0060:[<f8820003>]    Not tainted VLI
EFLAGS: 00000246   (2.6.22 #39)
EIP is at block2mtd_setup+0x3/0x7 [block2mtd]
eax: f7da387a   ebx: f7da3870   ecx: f88205a8   edx: f88205a8
esi: f8820b1c   edi: f7da387a   ebp: f788be78   esp: f788be78
ds: 007b   es: 007b   fs: 0000  gs: 0033  ss: 0068
Process insmod (pid: 1072, ti=f788a000 task=c1b22b00 task.ti=f788a000)
Stack: f788bec4 c0125576 00000000 f788be90 fffffff8 f881d932 00000006 00000000 
       f88205a8 f8820b4c 00000283 00000000 0000000b f8820b1c 00000000 f7da387c 
       00000014 f881db48 00000014 f788bfb0 c01314f1 00000001 00000000 f788bf24 
Call Trace:
 [<c0103248>] show_trace_log_lvl+0x1a/0x2f
 [<c01032f8>] show_stack_log_lvl+0x9b/0xa3
 [<c01034be>] show_registers+0x1be/0x290
 [<c010366f>] die+0xdf/0x1a1
 [<c01037ba>] do_trap+0x89/0xa2
 [<c0103b25>] do_invalid_op+0x88/0x92
 [<c0384e92>] error_code+0x6a/0x70
 [<c0125576>] parse_args+0x120/0x1f6
 [<c01314f1>] sys_init_module+0xf83/0x12a4
 [<c01023ee>] syscall_call+0x7/0xb
 =======================
Code: <0f> 0b eb fe 55 85 c0 89 e5 53 89 c3 74 31 8b 40 28 e8 fa be 92 c7 
EIP: [<f8820003>] block2mtd_setup+0x3/0x7 [block2mtd] SS:ESP 0068:f788be78


Patch didn't compile due to function ordering.  Here is an updated version.

Acked-and-tested-by: Joern Engel <joern at lazybastard.org>

diff --git a/kernel/module.c b/kernel/module.c
index c2e3e2e..0397b1e 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1645,6 +1645,17 @@ static inline void add_kallsyms(struct module *mod,
 }
 #endif /* CONFIG_KALLSYMS */
 
+/*
+ * link the module with the whole machine is stopped with interrupts off
+ * - this defends against kallsyms not taking locks
+ */
+static int __link_module(void *_mod)
+{
+	struct module *mod = _mod;
+	list_add(&mod->list, &modules);
+	return 0;
+}
+
 /* Allocate and load the module: note that size of section 0 is always
    zero, and we rely on this for optional sections. */
 static struct module *load_module(void __user *umod,
@@ -2023,6 +2034,11 @@ static struct module *load_module(void __user *umod,
 		printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
 		       mod->name);
 
+	/* Now sew it into the lists so we can get lockdep and oops
+         * info during argument parsing.  Noone should access us, since
+         * strong_try_module_get() will fail. */
+	stop_machine_run(__link_module, mod, NR_CPUS);
+
 	/* Size of section 0 is 0, so this works well if no params */
 	err = parse_args(mod->name, mod->args,
 			 (struct kernel_param *)
@@ -2031,7 +2047,7 @@ static struct module *load_module(void __user *umod,
 			 / sizeof(struct kernel_param),
 			 NULL);
 	if (err < 0)
-		goto arch_cleanup;
+		goto unlink;
 
 	err = mod_sysfs_setup(mod,
 			      (struct kernel_param *)
@@ -2039,7 +2055,7 @@ static struct module *load_module(void __user *umod,
 			      sechdrs[setupindex].sh_size
 			      / sizeof(struct kernel_param));
 	if (err < 0)
-		goto arch_cleanup;
+		goto unlink;
 	add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
 	add_notes_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
 
@@ -2054,7 +2070,8 @@ static struct module *load_module(void __user *umod,
 	/* Done! */
 	return mod;
 
- arch_cleanup:
+ unlink:
+	stop_machine_run(__unlink_module, mod, NR_CPUS);
 	module_arch_cleanup(mod);
  cleanup:
 	module_unload_free(mod);
@@ -2076,17 +2093,6 @@ static struct module *load_module(void __user *umod,
 	goto free_hdr;
 }
 
-/*
- * link the module with the whole machine is stopped with interrupts off
- * - this defends against kallsyms not taking locks
- */
-static int __link_module(void *_mod)
-{
-	struct module *mod = _mod;
-	list_add(&mod->list, &modules);
-	return 0;
-}
-
 /* This is where the real work happens */
 asmlinkage long
 sys_init_module(void __user *umod,
@@ -2111,10 +2117,6 @@ sys_init_module(void __user *umod,
 		return PTR_ERR(mod);
 	}
 
-	/* Now sew it into the lists.  They won't access us, since
-           strong_try_module_get() will fail. */
-	stop_machine_run(__link_module, mod, NR_CPUS);
-
 	/* Drop lock so they can recurse */
 	mutex_unlock(&module_mutex);
 


From dedekind at infradead.org  Thu Jan 17 02:53:51 2008
From: dedekind at infradead.org (Artem Bityutskiy)
Date: Thu, 17 Jan 2008 09:53:51 +0200
Subject: Block Device Emulation over UBI
In-Reply-To: <200801141557.18349.yur@emcraft.com>
References: <200801141557.18349.yur@emcraft.com>
Message-ID: <1200556431.6934.16.camel@sauron>

Hi Yuri,

On Mon, 2008-01-14 at 15:57 +0300, Yuri Tikhonov wrote:
>  We are about to implement and then maintain a block device driver which is 
> intended to work on the top of UBI and provide users with the block-device 
> interface to the underlying Flash chips. The goal of this driver is to 
> provide users with the possibility to easily organize reliable file storage 
> in Flash memory chips (especially NAND Flash) using Flash-unaware 
> file-systems like FAT, EXT2/3, etc (UBI is supposed to provide the necessary 
> reliability using its features of wear-leveling and bad blocks handling).
> 
>  In many cases the ability to have the file-system formatted with, for 
> example, FAT is a highly desirable feature of the embedded devices (e.g. for 
> exporting the embedded storage via USB link to a Windows-based USB host), so 
> we guess our work will be usefull for the embedded world.
> 
>  Any suggestions or comments as to possible issues we may run into on this 
> road would be very appreciated.

You are welcome to implement a block device layer on top of UBI, I'd
call it ubiblk. Here is an idea of a very simple implementation which
belongs to Adrian Hunter.

Every block is mapped to permanent position P = blk_size * blk_number,
which is (P / leb_size):(P % leb_size) in LEB:offset terms. When you
change a block, you use the "atomic LEB change" operation
(ubi_leb_change()) and re-write whole LEB.

While it seems to be very inefficient, it might be not so bad because
Linux elevator should help. Indeed, it re-arranges block change requests
so that they go as consecutively as possible. So the result is that you
write many consecutive blocks which sit at the same LEB at one go in
many cases, not just one block. And we can hope this will be fast
enough, although not necessarily. But it anyway makes sense to try this
out before inventing anything more comprehensive.

Few notes you would also need to do:

1. Implement ubi_get_volume()/ubi_put_volume() interfaces which just
get/put a volume reference and return, thus preventing the volume go
away (e.g., be deleted) while ubiblk is keeping it. Current
open()/close() interfaces do not look quite appropriate.

2. Implement some notification mechanisms for volume re-size - ubiblk
has to be notified when this happens.

3. You might as well also separate gluebi out once you have the above 2
things done and make it a separate ubimtd module, instead of built-in
crap.

HTH.

-- 
Best regards,
Artem Bityutskiy (???????? ?????)



From b.buettner at mkc-gmbh.de  Thu Jan 17 03:42:49 2008
From: b.buettner at mkc-gmbh.de (=?ISO-8859-15?Q?Bernd_B=FCttner?=)
Date: Thu, 17 Jan 2008 09:42:49 +0100
Subject: Cleaning JFFS2 errors
Message-ID: <478F1509.2090001@mkc-gmbh.de>

Hi,
after working some time with the JFFS2 filesystem (on a uclinux-system with a non-mmu freescale processor)
I'm getting errors on every mount like this:

   jffs2_scan_inode(): CRC failed on node at 0x00c999f0: Read 0xffffffff, calculated 0x7621c0c4
   Empty flash at 0x00c99a3c ends at 0x00c99c00
   Empty flash at 0x0134201c ends at 0x01342200
   jffs2_scan_eraseblock(): Node at 0x01d88df8 {0x1985, 0xe001, 0x0000002f) has invalid
     CRC 0x1985e001 (calculated 0x392fe03e)
   JFFS2 notice: (13) read_dnode: node CRC failed on dnode at 0x1341fd4:
     read 0xffffffff, calculated 0xce9c70e9

The kernel is 2.6.19 from the latest uclinux distribution 20070130.

I think these errors are the result of power-loss, misbehaving new drivers and system crashes,
and I suppose they are not critical and will be corrected by jffs2 after some time.

But delivering such systems to customers doesn't look good.

Is there a possibility to force jffs2 to correct these errors at once?

I hope so.

Bernd


From ricard.wanderlof at axis.com  Thu Jan 17 03:47:53 2008
From: ricard.wanderlof at axis.com (Ricard Wanderlof)
Date: Thu, 17 Jan 2008 09:47:53 +0100 (CET)
Subject: JFFS2 access time
In-Reply-To: <478E0D5E.8070508@bittware.com>
References: <478E0D5E.8070508@bittware.com>
Message-ID: <Pine.LNX.4.64.0801170944580.24534@lnxricardw.se.axis.com>


On Wed, 16 Jan 2008, DMcLeod wrote:

> Hi all,
>
> We are using uClinux git 2.6.23. We have 4 2.5MB files sitting in a
> directory on a ~40MB jffs2 partition (on NOR flash). The very first time
> we do an 'ls' in that directory, the response takes literally minutes.
> After the initial delay, any accesses to those files are very

By "the first time" to you mean the first time you boot the board at all, 
or the first time after each boot?

If you download a 10 MB JFFS2 image into a 40 MB partition, then JFFS2 
will upon mounting erase each flash sector in the unused 30 MB area and 
write cleanmarkers to it. This more or less blocks accesses to the flash 
during this time. However, this only occurs the first time the system is 
booted, after that, the partition is completely "JFFS2-formatted" and 
there shouldn't be any further delays.

/Ricard


From jwboyer at gmail.com  Wed Jan 16 19:34:58 2008
From: jwboyer at gmail.com (Josh Boyer)
Date: Wed, 16 Jan 2008 18:34:58 -0600
Subject: JFFS2 access time
In-Reply-To: <478E0D5E.8070508@bittware.com>
References: <478E0D5E.8070508@bittware.com>
Message-ID: <20080116183458.2c997320@zod.rchland.ibm.com>

On Wed, 16 Jan 2008 08:57:50 -0500
DMcLeod <dmcleod at bittware.com> wrote:

> Hi all,
> 
> We are using uClinux git 2.6.23. We have 4 2.5MB files sitting in a 
> directory on a ~40MB jffs2 partition (on NOR flash). The very first time 
> we do an 'ls' in that directory, the response takes literally minutes. 
> After the initial delay, any accesses to those files are very 
> quick.,,

That is normal for large files.  JFFS2 has do the CRC checking on all
the nodes for those large files.  That is a lot of nodes to check.  You
might want to look into using the eraseblock summary feature.

> Originally, we started off with the Microtronix 1.4 kernel and 
> it did not have this problem. The pre-git version of uClinux-dist had 
> this problem but not as severe - it was more like 40 seconds to list the 
> contents of that directory.

I have no idea what those two kernels are, but older JFFS2 used to do
all the CRC checking at mount time.  So mount would be slow and runtime
access would be relatively quick.

josh


From dmcleod at bittware.com  Thu Jan 17 11:06:41 2008
From: dmcleod at bittware.com (DMcLeod)
Date: Thu, 17 Jan 2008 11:06:41 -0500
Subject: JFFS2 access time
In-Reply-To: <20080116183458.2c997320@zod.rchland.ibm.com>
References: <478E0D5E.8070508@bittware.com>
	<20080116183458.2c997320@zod.rchland.ibm.com>
Message-ID: <478F7D11.30606@bittware.com>

Josh Boyer wrote:
> On Wed, 16 Jan 2008 08:57:50 -0500
> DMcLeod <dmcleod at bittware.com> wrote:
>
>   
>> Hi all,
>>
>> We are using uClinux git 2.6.23. We have 4 2.5MB files sitting in a 
>> directory on a ~40MB jffs2 partition (on NOR flash). The very first time 
>> we do an 'ls' in that directory, the response takes literally minutes. 
>> After the initial delay, any accesses to those files are very 
>> quick.,,
>>     
>
> That is normal for large files.  JFFS2 has do the CRC checking on all
> the nodes for those large files.  That is a lot of nodes to check.  You
> might want to look into using the eraseblock summary feature.
>
>   
>> Originally, we started off with the Microtronix 1.4 kernel and 
>> it did not have this problem. The pre-git version of uClinux-dist had 
>> this problem but not as severe - it was more like 40 seconds to list the 
>> contents of that directory.
>>     
> I have no idea what those two kernels are, but older JFFS2 used to do
> all the CRC checking at mount time.  So mount would be slow and runtime
> access would be relatively quick.
>   
The Microtronix kernel is the kernel built by Altera's Quartus 6.1 
suite. By "pre-git" version, we just meant the packaged version from 
nioswiki, rather than getting it from the git server.

At any rate, it turns out that having the verbosity level set to 2 in 
the jffs2 section of menuconfig was our problem. The kernel was so 
dragged down by having to bombard /proc/kmsg with jffs2 printk's that it 
caused the huge delays we were seeing. We set verbosity back to 0 and 
all is well.

Thanks :-)
> josh
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>
>   



From matthieu.castet at parrot.com  Thu Jan 17 11:12:29 2008
From: matthieu.castet at parrot.com (Matthieu CASTET)
Date: Thu, 17 Jan 2008 17:12:29 +0100
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
Message-ID: <478F7E6D.8010300@parrot.com>

Hi,


we have a 240 MB jffs2 partition with summary enabled and no 
compression. We use 2ad8ee713566671875216ebcec64f2eda47bd19d git jffs2 
version 
(http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=2ad8ee713566671875216ebcec64f2eda47bd19d)


On this partition we have several file (less than 1 MB) and a big file 
in the root (200 MB).

The big file is a FAT image that is exported with usb-storage (with usb 
device) or mounted on a loopback device.

After some FAT operations, we manage to get in a situation were the 
jffs2_garbage_collect_pass take 12 minutes.

jffs2_lookup for the big file (triggered with a ls in the root) take 12 
minutes.

If we do a ls without waiting that jffs2_garbage_collect_pass finish, ls 
takes 12 minutes to complete.

We applied the 4 patches starting from "Trigger garbage collection when 
very_dirty_list size becomes excessive" to "Don't count all 'very dirty' 
blocks except in debug mode", but it doesn't change anything.


Why jffs2 take so much time in jffs2_garbage_collect_pass for checking 
the nodes ?
Reading the whole raw flash take about 40s-1min.
Does it read the flash in a random order ?

What does the jffs2_lookup ?
Why it is so long.


What are the alternative ?
Trying yaffs2 ?
Export a smaller file ?

Matthieu


PS : if the big file is moved in a subdirectory, then the ls in the root 
dir is fast, but access to the big file is slow (12 Minutes).


From joern at logfs.org  Thu Jan 17 11:26:01 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Thu, 17 Jan 2008 17:26:01 +0100
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <478F7E6D.8010300@parrot.com>
References: <478F7E6D.8010300@parrot.com>
Message-ID: <20080117162601.GA6677@lazybastard.org>

On Thu, 17 January 2008 17:12:29 +0100, Matthieu CASTET wrote:
> 
> we have a 240 MB jffs2 partition with summary enabled and no 
> compression. We use 2ad8ee713566671875216ebcec64f2eda47bd19d git jffs2 
> version 
> (http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=2ad8ee713566671875216ebcec64f2eda47bd19d)
> 
> 
> On this partition we have several file (less than 1 MB) and a big file 
> in the root (200 MB).
> 
> The big file is a FAT image that is exported with usb-storage (with usb 
> device) or mounted on a loopback device.
> 
> After some FAT operations, we manage to get in a situation were the 
> jffs2_garbage_collect_pass take 12 minutes.
> 
> jffs2_lookup for the big file (triggered with a ls in the root) take 12 
> minutes.
> 
> If we do a ls without waiting that jffs2_garbage_collect_pass finish, ls 
> takes 12 minutes to complete.

Impressive!  JFFS2 may be slow, but it shouldn't be _that_ slow.  Not
sure who cares enough to look at this.  My approach would be to 
$ echo t > /proc/sysrq_trigger
several times during those 12 minutes and take a close look at the code
paths showing up.  Most likely it will spend 99% of the time in one
place.

J?rn

-- 
...one more straw can't possibly matter...
-- Kirby Bakken


From jwboyer at gmail.com  Thu Jan 17 12:43:53 2008
From: jwboyer at gmail.com (Josh Boyer)
Date: Thu, 17 Jan 2008 11:43:53 -0600
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080117162601.GA6677@lazybastard.org>
References: <478F7E6D.8010300@parrot.com>
	<20080117162601.GA6677@lazybastard.org>
Message-ID: <20080117114353.0bc71dac@zod.rchland.ibm.com>

On Thu, 17 Jan 2008 17:26:01 +0100
J?rn Engel <joern at logfs.org> wrote:

> On Thu, 17 January 2008 17:12:29 +0100, Matthieu CASTET wrote:
> > 
> > we have a 240 MB jffs2 partition with summary enabled and no 
> > compression. We use 2ad8ee713566671875216ebcec64f2eda47bd19d git jffs2 
> > version 
> > (http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=2ad8ee713566671875216ebcec64f2eda47bd19d)
> > 
> > 
> > On this partition we have several file (less than 1 MB) and a big file 
> > in the root (200 MB).
> > 
> > The big file is a FAT image that is exported with usb-storage (with usb 
> > device) or mounted on a loopback device.
> > 
> > After some FAT operations, we manage to get in a situation were the 
> > jffs2_garbage_collect_pass take 12 minutes.
> > 
> > jffs2_lookup for the big file (triggered with a ls in the root) take 12 
> > minutes.
> > 
> > If we do a ls without waiting that jffs2_garbage_collect_pass finish, ls 
> > takes 12 minutes to complete.
> 
> Impressive!  JFFS2 may be slow, but it shouldn't be _that_ slow.  Not

How do you know?  A 200MiB file will likely have around 50,000 nodes.
If the summary stuff is incorrect, and since we have no idea what kind
of platform is being used here, it may well be within reason.

> sure who cares enough to look at this.  My approach would be to 
> $ echo t > /proc/sysrq_trigger
> several times during those 12 minutes and take a close look at the code
> paths showing up.  Most likely it will spend 99% of the time in one
> place.

That's sound advice in any case.

josh


From dwmw2 at infradead.org  Thu Jan 17 18:22:21 2008
From: dwmw2 at infradead.org (David Woodhouse)
Date: Fri, 18 Jan 2008 07:22:21 +0800
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080117162601.GA6677@lazybastard.org>
References: <478F7E6D.8010300@parrot.com>
	<20080117162601.GA6677@lazybastard.org>
Message-ID: <1200612141.14882.83.camel@shinybook.infradead.org>


On Thu, 2008-01-17 at 17:26 +0100, J?rn Engel wrote:
> 
> Impressive!  JFFS2 may be slow, but it shouldn't be _that_ slow.  Not
> sure who cares enough to look at this.  My approach would be to 
> $ echo t > /proc/sysrq_trigger
> several times during those 12 minutes and take a close look at the
> code
> paths showing up.  Most likely it will spend 99% of the time in one
> place.

I was going to suggest booting with 'profile=1' and using readprofile,
which is a slightly more reliable way of getting the same information.

-- 
dwmw2



From matthieu.castet at parrot.com  Fri Jan 18 04:39:29 2008
From: matthieu.castet at parrot.com (Matthieu CASTET)
Date: Fri, 18 Jan 2008 10:39:29 +0100
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080117114353.0bc71dac@zod.rchland.ibm.com>
References: <478F7E6D.8010300@parrot.com>	<20080117162601.GA6677@lazybastard.org>
	<20080117114353.0bc71dac@zod.rchland.ibm.com>
Message-ID: <479073D1.5010406@parrot.com>

Josh Boyer wrote:
> On Thu, 17 Jan 2008 17:26:01 +0100
> J?rn Engel <joern at logfs.org> wrote:
> 
>>> If we do a ls without waiting that jffs2_garbage_collect_pass finish, ls 
>>> takes 12 minutes to complete.
>> Impressive!  JFFS2 may be slow, but it shouldn't be _that_ slow.  Not
> 
> How do you know?  A 200MiB file will likely have around 50,000 nodes.
Yes the file got 41324 nodes.
> If the summary stuff is incorrect, and since we have no idea what kind
> of platform is being used here, it may well be within reason.
> 
The summary stuff is correct (I check it with a parser on a dump of the 
image). Also if the summary wasn't correct, only the mount time will grow ?
In my case the mount is ok : less than 5-10s.
The platform used is an arm926 @247 Mhz

Matthieu


From r&d2 at dave-tech.it  Fri Jan 18 05:18:07 2008
From: r&d2 at dave-tech.it (llandre)
Date: Fri, 18 Jan 2008 11:18:07 +0100
Subject: Micron NAND support in linux MTD
Message-ID: <47907CDF.30802@dave-tech.it>

Hi,

I found on MTD mailing list your patch that adds Micron manufacturer ID:
http://article.gmane.org/gmane.linux.drivers.mtd/17694

I'm going to use NAND Micron devices for a new project however I still 
have a doubt about how MTD/JFFS2 handle bad blocks. To detect blocks 
marked as bad it checks the 6th location of OOB area of first page, thus 
it seems it is not able to handle Micron devices properly. In fact these 
devices stores bad block marker in the first location of OOB of first or 
second page (for example see page 50 of MT29F1GxxABB data sheet). Am I 
misreading the datasheet? Could you help me to clear this point?


Thanks in advance,
llandre

DAVE Electronics System House - R&D Department
web:   http://www.dave-tech.it
email: r&d2 at dave-tech.it


From vicky.irobot at gmail.com  Fri Jan 18 07:12:39 2008
From: vicky.irobot at gmail.com (vicky)
Date: Fri, 18 Jan 2008 17:42:39 +0530
Subject: question about node creation /dev/mtd*
Message-ID: <479097B7.9050401@gmail.com>

Hi,

I have enabled mtd in my config. When I boot from the updated kernel I 
find that /dev/mtdblock is not created?

How does the /dev/mtdblock get created? I didn't find this in the 
init/rcs script. I am under an impression that once the mtd is enabled 
in the linux
config file the creation of the corresponding node is taken care in some 
script.

I have a dummy nand driver written and placed in the mtd/nand location.

Please advice.

Vic



From jwboyer at linux.vnet.ibm.com  Fri Jan 18 07:44:32 2008
From: jwboyer at linux.vnet.ibm.com (Josh Boyer)
Date: Fri, 18 Jan 2008 06:44:32 -0600
Subject: question about node creation /dev/mtd*
In-Reply-To: <479097B7.9050401@gmail.com>
References: <479097B7.9050401@gmail.com>
Message-ID: <20080118064432.19233a37@zod.rchland.ibm.com>

On Fri, 18 Jan 2008 17:42:39 +0530
vicky <vicky.irobot at gmail.com> wrote:

> Hi,
> 
> I have enabled mtd in my config. When I boot from the updated kernel I 
> find that /dev/mtdblock is not created?
> 
> How does the /dev/mtdblock get created? I didn't find this in the 
> init/rcs script. I am under an impression that once the mtd is enabled 
> in the linux
> config file the creation of the corresponding node is taken care in some 
> script.

You need to either have udev running, or create it manually yourself
with mknod (which can be done via a script you write). This is, of
course, assuming you have the mtdblock module loaded or compiled into
your kernel.

josh


From jwboyer at gmail.com  Fri Jan 18 07:48:52 2008
From: jwboyer at gmail.com (Josh Boyer)
Date: Fri, 18 Jan 2008 06:48:52 -0600
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <479073D1.5010406@parrot.com>
References: <478F7E6D.8010300@parrot.com>
	<20080117162601.GA6677@lazybastard.org>
	<20080117114353.0bc71dac@zod.rchland.ibm.com>
	<479073D1.5010406@parrot.com>
Message-ID: <20080118064852.026b0c82@zod.rchland.ibm.com>

On Fri, 18 Jan 2008 10:39:29 +0100
Matthieu CASTET <matthieu.castet at parrot.com> wrote:

> Josh Boyer wrote:
> > On Thu, 17 Jan 2008 17:26:01 +0100
> > J?rn Engel <joern at logfs.org> wrote:
> > 
> >>> If we do a ls without waiting that jffs2_garbage_collect_pass finish, ls 
> >>> takes 12 minutes to complete.
> >> Impressive!  JFFS2 may be slow, but it shouldn't be _that_ slow.  Not
> > 
> > How do you know?  A 200MiB file will likely have around 50,000 nodes.
> Yes the file got 41324 nodes.

Wow, I'm surprised I actually got close with my top of the head math :)

> > If the summary stuff is incorrect, and since we have no idea what kind
> > of platform is being used here, it may well be within reason.
> > 
> The summary stuff is correct (I check it with a parser on a dump of the 
> image). Also if the summary wasn't correct, only the mount time will grow ?

Yes, you're correct.

> In my case the mount is ok : less than 5-10s.
> The platform used is an arm926 @247 Mhz

Ok, so running at 247MHz your board has to calculate the CRCs on 41324
nodes before the file can be opened.  I have no idea how long that
should really take, but you're doing about 57 nodes per second if it's
taking 12 minutes.

As J?rn and David suggested, do some profiling to see where it is
spending most of it's time.

josh


From dedekind at infradead.org  Fri Jan 18 07:56:42 2008
From: dedekind at infradead.org (Artem Bityutskiy)
Date: Fri, 18 Jan 2008 14:56:42 +0200
Subject: question about node creation /dev/mtd*
In-Reply-To: <20080118064432.19233a37@zod.rchland.ibm.com>
References: <479097B7.9050401@gmail.com>
	<20080118064432.19233a37@zod.rchland.ibm.com>
Message-ID: <1200661002.6934.23.camel@sauron>

On Fri, 2008-01-18 at 06:44 -0600, Josh Boyer wrote:
> On Fri, 18 Jan 2008 17:42:39 +0530
> vicky <vicky.irobot at gmail.com> wrote:
> 
> > Hi,
> > 
> > I have enabled mtd in my config. When I boot from the updated kernel I 
> > find that /dev/mtdblock is not created?
> > 
> > How does the /dev/mtdblock get created? I didn't find this in the 
> > init/rcs script. I am under an impression that once the mtd is enabled 
> > in the linux
> > config file the creation of the corresponding node is taken care in some 
> > script.
> 
> You need to either have udev running, or create it manually yourself
> with mknod (which can be done via a script you write). This is, of
> course, assuming you have the mtdblock module loaded or compiled into
> your kernel.

udev will not help because MTD is not Linux Device Model-enabled, so
only ancient manual device node creation method may be used. There is a
MAKEDEV script in mtd-utils.git which may help.

-- 
Best regards,
Artem Bityutskiy (???????? ?????)



From jwboyer at linux.vnet.ibm.com  Fri Jan 18 08:14:05 2008
From: jwboyer at linux.vnet.ibm.com (Josh Boyer)
Date: Fri, 18 Jan 2008 07:14:05 -0600
Subject: question about node creation /dev/mtd*
In-Reply-To: <1200661002.6934.23.camel@sauron>
References: <479097B7.9050401@gmail.com>
	<20080118064432.19233a37@zod.rchland.ibm.com>
	<1200661002.6934.23.camel@sauron>
Message-ID: <20080118071405.533c2b45@zod.rchland.ibm.com>

On Fri, 18 Jan 2008 14:56:42 +0200
Artem Bityutskiy <dedekind at infradead.org> wrote:

> On Fri, 2008-01-18 at 06:44 -0600, Josh Boyer wrote:
> > On Fri, 18 Jan 2008 17:42:39 +0530
> > vicky <vicky.irobot at gmail.com> wrote:
> > 
> > > Hi,
> > > 
> > > I have enabled mtd in my config. When I boot from the updated kernel I 
> > > find that /dev/mtdblock is not created?
> > > 
> > > How does the /dev/mtdblock get created? I didn't find this in the 
> > > init/rcs script. I am under an impression that once the mtd is enabled 
> > > in the linux
> > > config file the creation of the corresponding node is taken care in some 
> > > script.
> > 
> > You need to either have udev running, or create it manually yourself
> > with mknod (which can be done via a script you write). This is, of
> > course, assuming you have the mtdblock module loaded or compiled into
> > your kernel.
> 
> udev will not help because MTD is not Linux Device Model-enabled, so
> only ancient manual device node creation method may be used. There is a
> MAKEDEV script in mtd-utils.git which may help.

MTD itself isn't, no.  But I thought mtdblock got some of the sysfs
stuff for free because it hooked into the generic block layer?

It's been a while, I could be mistaken.

josh


From vshrirama at gmail.com  Fri Jan 18 10:45:54 2008
From: vshrirama at gmail.com (Ram)
Date: Fri, 18 Jan 2008 21:15:54 +0530
Subject: Micron NAND support in linux MTD
In-Reply-To: <47907CDF.30802@dave-tech.it>
References: <47907CDF.30802@dave-tech.it>
Message-ID: <8bf247760801180745k6f8337d5p751d91b21bd3728d@mail.gmail.com>

Hi,
   The location of the "bad block indicator" within the spare area
depends on the
    manufacturer. It could vary from chip to chip.

   it could also depend on the page size as well.

   Usually, for a large page size nand, It could be located at the
first byte of the OOB.
   For a small it could be at 6th byte.

  The way you send some commands to the large page size nand device is
somewhat different
  from the small page size nand device. I think you may not be using
the driver for a large page  nand device.

  Most of the stuff (driver) for the large page nand devices is
generic. The way you wait for nand busy changes.

  Check the way your reading the flash information from the chip id
and additional infomation.
  The way youre mtd_info structure is getting initialised. You could
be missing something here.

Hope this helps.

Regards,
sriram




On Jan 18, 2008 3:48 PM, llandre <r&d2 at dave-tech.it> wrote:
> Hi,
>
> I found on MTD mailing list your patch that adds Micron manufacturer ID:
> http://article.gmane.org/gmane.linux.drivers.mtd/17694
>
> I'm going to use NAND Micron devices for a new project however I still
> have a doubt about how MTD/JFFS2 handle bad blocks. To detect blocks
> marked as bad it checks the 6th location of OOB area of first page, thus
> it seems it is not able to handle Micron devices properly. In fact these
> devices stores bad block marker in the first location of OOB of first or
> second page (for example see page 50 of MT29F1GxxABB data sheet). Am I
> misreading the datasheet? Could you help me to clear this point?
>
>
> Thanks in advance,
> llandre
>
> DAVE Electronics System House - R&D Department
> web:   http://www.dave-tech.it
> email: r&d2 at dave-tech.it
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>


From matthieu.castet at parrot.com  Fri Jan 18 11:17:34 2008
From: matthieu.castet at parrot.com (Matthieu CASTET)
Date: Fri, 18 Jan 2008 17:17:34 +0100
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080118064852.026b0c82@zod.rchland.ibm.com>
References: <478F7E6D.8010300@parrot.com>	<20080117162601.GA6677@lazybastard.org>	<20080117114353.0bc71dac@zod.rchland.ibm.com>	<479073D1.5010406@parrot.com>
	<20080118064852.026b0c82@zod.rchland.ibm.com>
Message-ID: <4790D11E.6060201@parrot.com>

Josh Boyer wrote:
> On Fri, 18 Jan 2008 10:39:29 +0100
> Matthieu CASTET <matthieu.castet at parrot.com> wrote:
> 
> 
>> In my case the mount is ok : less than 5-10s.
>> The platform used is an arm926 @247 Mhz
> 
> Ok, so running at 247MHz your board has to calculate the CRCs on 41324
> nodes before the file can be opened.  I have no idea how long that
> should really take, but you're doing about 57 nodes per second if it's
> taking 12 minutes.
> 
> As J?rn and David suggested, do some profiling to see where it is
> spending most of it's time.
> 
I sent a mail, but  because of Message has a suspicious header, the 
message wait  moderator approval.


In summary,
the code spend lot's of time in the rbtree code (7 minutes) and 4 
minutes in jffs2_get_inode_nodes.


Matthieu


  54366 rb_prev                                  543,6600
  28345 rb_next                                  283,4500
   8602 default_idle                              71,6833
  10251 __raw_readsl                              40,0430
  49648 jffs2_get_inode_nodes                     11,8097
    251 s3c2412_nand_devready                      7,8438
   1222 crc32_le                                   4,8492


From abelyako at googlemail.com  Fri Jan 18 11:28:08 2008
From: abelyako at googlemail.com (Alexander Belyakov)
Date: Fri, 18 Jan 2008 19:28:08 +0300
Subject: [PATCH][JFFS2] Fix garbage collector block search
In-Reply-To: <20080115133350.GA22338@lazybastard.org>
References: <E1J2Trs-000IFE-00.abelyako-mail-ru@f65.mail.ru>
	<20080114132843.GA15710@lazybastard.org>
	<fe810cf0801150424j25f35131v83692a3193a45a3b@mail.gmail.com>
	<20080115133350.GA22338@lazybastard.org>
Message-ID: <fe810cf0801180828g7a48b6a1u69e35f832185b5eb@mail.gmail.com>

On 1/15/08, J?rn Engel <joern at logfs.org> wrote:
>
> Right now the important thing is to dig deeper and understand the nature
> of this bug.  You can reproduce it, that is good.  We also know that it
> makes a difference whether the block is on one list or the other.  But
> we don't know yet, what difference exactly it makes.

Question. What is success criteria for jffs2_garbage_collect_pass() execution?

Why asking? In the case described above jffs2_find_gc_block() fails to
find erase block for garbage collection but falling into
jffs2_flush_wbuf_pad(c) which produces amount of erasing blocks. So
jffs2_garbage_collect_pass() sees no single block for garbage
collection, but filesystem still recieves fresh erasing blocks upon
execution.

Is it success or failure? Theoretically.

Thanks,
Alexander

From thraxisp at logicaloutcome.ca  Fri Jan 18 12:20:58 2008
From: thraxisp at logicaloutcome.ca (Glenn Henshaw)
Date: Fri, 18 Jan 2008 12:20:58 -0500
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080117114353.0bc71dac@zod.rchland.ibm.com>
References: <478F7E6D.8010300@parrot.com>
	<20080117162601.GA6677@lazybastard.org>
	<20080117114353.0bc71dac@zod.rchland.ibm.com>
Message-ID: <2B52FCEB-D871-4D9B-81D1-E03F7698AF96@logicaloutcome.ca>


On 17-Jan-08, at 12:43 PM, Josh Boyer wrote:

> On Thu, 17 Jan 2008 17:26:01 +0100
> J?rn Engel <joern at logfs.org> wrote:
>
>> On Thu, 17 January 2008 17:12:29 +0100, Matthieu CASTET wrote:
>>>
>>> we have a 240 MB jffs2 partition with summary enabled and no
>>> compression. We use 2ad8ee713566671875216ebcec64f2eda47bd19d git  
>>> jffs2
>>> version
>>> (http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=2ad8ee713566671875216ebcec64f2eda47bd19d 
>>> )
>>>
>>>
>>> On this partition we have several file (less than 1 MB) and a big  
>>> file
>>> in the root (200 MB).
>>>
>>> The big file is a FAT image that is exported with usb-storage  
>>> (with usb
>>> device) or mounted on a loopback device.
>>>
>>> After some FAT operations, we manage to get in a situation were the
>>> jffs2_garbage_collect_pass take 12 minutes.
>>>
>>> jffs2_lookup for the big file (triggered with a ls in the root)  
>>> take 12
>>> minutes.
>>>
>>> If we do a ls without waiting that jffs2_garbage_collect_pass  
>>> finish, ls
>>> takes 12 minutes to complete.
>>
>> Impressive!  JFFS2 may be slow, but it shouldn't be _that_ slow.  Not
>
> How do you know?  A 200MiB file will likely have around 50,000 nodes.
> If the summary stuff is incorrect, and since we have no idea what kind
> of platform is being used here, it may well be within reason.

   I found a similar problem on an older 2.4.27 based system. We have  
a 64k JFFS2 partition (1024 blocks of 4kbytes). As the file system  
fills up, the time for any operation increases exponentially. When it  
reaches 90% full, it takes minutes to write a file. After a cursory  
inspection, it seems to block doing garbage collection and compressing  
blocks.

   We gave up and limited the capacity to 60% full at the application  
level.

   I'd appreciate any pointer to fix this, as migrating to a 2.6  
kernel is not an option.


-- 
Glenn Henshaw                     Logical Outcome Ltd.
e: thraxisp at logicaloutcome.ca     w: www.logicaloutcome.ca





From jwboyer at gmail.com  Fri Jan 18 12:55:31 2008
From: jwboyer at gmail.com (Josh Boyer)
Date: Fri, 18 Jan 2008 11:55:31 -0600
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <4790D11E.6060201@parrot.com>
References: <478F7E6D.8010300@parrot.com>
	<20080117162601.GA6677@lazybastard.org>
	<20080117114353.0bc71dac@zod.rchland.ibm.com>
	<479073D1.5010406@parrot.com>
	<20080118064852.026b0c82@zod.rchland.ibm.com>
	<4790D11E.6060201@parrot.com>
Message-ID: <20080118115531.2deef9fb@zod.rchland.ibm.com>

On Fri, 18 Jan 2008 17:17:34 +0100
Matthieu CASTET <matthieu.castet at parrot.com> wrote:
 
> I sent a mail, but  because of Message has a suspicious header, the 
> message wait  moderator approval.
> 
> 
> In summary,
> the code spend lot's of time in the rbtree code (7 minutes) and 4 
> minutes in jffs2_get_inode_nodes.
> 
> 
> Matthieu
> 
> 
>   54366 rb_prev                                  543,6600
>   28345 rb_next                                  283,4500
>    8602 default_idle                              71,6833
>   10251 __raw_readsl                              40,0430
>   49648 jffs2_get_inode_nodes                     11,8097
>     251 s3c2412_nand_devready                      7,8438
>    1222 crc32_le                                   4,8492

That seems consistent with JFFS2 doing the CRC checks and constructing
the in-memory representation of your large file.  I suspect the older
list-based in-memory implementation would have taken even longer, but
there could be something amiss with the rb-tree stuff perhaps.

josh


From joern at logfs.org  Fri Jan 18 13:17:44 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Fri, 18 Jan 2008 19:17:44 +0100
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080118115531.2deef9fb@zod.rchland.ibm.com>
References: <478F7E6D.8010300@parrot.com>
	<20080117162601.GA6677@lazybastard.org>
	<20080117114353.0bc71dac@zod.rchland.ibm.com>
	<479073D1.5010406@parrot.com>
	<20080118064852.026b0c82@zod.rchland.ibm.com>
	<4790D11E.6060201@parrot.com>
	<20080118115531.2deef9fb@zod.rchland.ibm.com>
Message-ID: <20080118181744.GA15039@lazybastard.org>

On Fri, 18 January 2008 11:55:31 -0600, Josh Boyer wrote:
> 
> That seems consistent with JFFS2 doing the CRC checks and constructing
> the in-memory representation of your large file.  I suspect the older
> list-based in-memory implementation would have taken even longer, but
> there could be something amiss with the rb-tree stuff perhaps.

There is something conceptually amiss with rb-trees.  Each node
effectively occupies its own cacheline.  With those 40k+ nodes, you
would need a rather sizeable cache with at least 20k cachelines to have
an impact.  Noone does.  So for all practical purposes, every single
lookup will go to main memory.

Maybe it is about time to suggest trying logfs?

J?rn

-- 
People will accept your ideas much more readily if you tell them
that Benjamin Franklin said it first.
-- unknown


From bhutchings at solarflare.com  Fri Jan 18 13:30:28 2008
From: bhutchings at solarflare.com (Ben Hutchings)
Date: Fri, 18 Jan 2008 18:30:28 +0000
Subject: [PATCH] [MTD] [RFC] New Solarflare NIC EEPROM/Flash driver (3rd try)
Message-ID: <20080118183026.GH23117@solarflare.com>

My colleague Robert Stonehouse submitted a new version of the sfc
network driver and accompanying sfc_mtd MTD driver today.  The full
source is at:

https://support.solarflare.com/netdev/5/net-2.6.25-sfc-2.2.0045.patch
https://support.solarflare.com/netdev/5/net-2.6.25-sfc-2.2.0045.tgz

I've included the main source file for the MTD driver below.  We have
made changes that I think answer all the comments from the previous
review:

- Deleted redundant comments, casts, "inline"
- Changed if (rc != 0) to the preferred if (rc)
- Clarified use of access_lock and moved some code out of locked section
  that doesn't need to be in it
- Renamed efx_mtd_probe() to efx_mtd_register(), since it does
  not probe
- Moved structure allocation and device-dependent initialisation out of
  efx_mtd_register()
- Simplified efx_mtd_verify():
  - Replaced large heap buffer with small stack buffer, as this is not
    speed-critical
  - Allowed the caller to specify a repeating pattern, rather than handling
    the erase pattern directly
  - Replaced byte-comparison loop with memcmp()
- Made efx_spi_slow_wait() uninterruptible where EINTR cannot be
  propagated or handled

Some additional fixes:

- Changed probe error code for absent devices to ENODEV
- Changed type and flags for EEPROM to be "RAM" - the EEPROM is randomly
  rewritable and it is certainly not DataFlash

Ben.

--- /dev/null
+++ b/drivers/net/sfc/mtd.c
@@ -0,0 +1,598 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * Copyright 2005-2006: Fen Systems Ltd.
+ * Copyright 2006-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Initially developed by Michael Brown <mbrown at fensystems.co.uk>
+ * Maintained by Solarflare Communications <linux-net-drivers at solarflare.com>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/delay.h>
+
+#define EFX_DRIVER_NAME "sfc_mtd"
+#include "driverlink_api.h"
+#include "net_driver.h"
+#include "spi.h"
+
+/*
+ * Flash and EEPROM (MTD) device driver
+ *
+ * This file provides a separate kernel module (sfc_mtd) which
+ * exposes the flash and EEPROM devices present on Solarflare NICs as
+ * MTD devices, enabling you to reflash the boot ROM code (or use the
+ * remaining space on the flash as a jffs2 filesystem, should you want
+ * to do so).
+ */
+
+#define EFX_MTD_VERIFY_BUF_LEN 16
+#define EFX_MAX_PARTITIONS 2
+#define EFX_FLASH_BOOTROM_OFFSET 0x8000U
+
+/* Write enable for EEPROM/Flash configuration area
+ *
+ * Normally, writes to parts of non-volatile storage which contain
+ * critical configuration are disabled to prevent accidents.  This
+ * parameter allows enabling of such writes.
+ */
+static unsigned int efx_allow_nvconfig_writes;
+
+struct efx_mtd {
+	struct mtd_info mtd;
+	struct mtd_partition part[EFX_MAX_PARTITIONS];
+	char part_name[EFX_MAX_PARTITIONS][32];
+	char name[32];
+	struct efx_dl_device *efx_dev;
+	struct efx_nic *efx;
+	/* This must be held when using *spi; it guards against races
+	 * with device reset and between sequences of dependent
+	 * commands. */
+	struct semaphore access_lock;
+	struct efx_spi_device *spi;
+};
+
+/* SPI utilities */
+
+static int efx_spi_fast_wait(struct efx_mtd *efx_mtd)
+{
+	struct efx_spi_device *spi = efx_mtd->spi;
+	u8 status;
+	int i, rc;
+
+	/* Wait up to 1000us for flash/EEPROM to finish a fast operation. */
+	for (i = 0; i < 50; i++) {
+		udelay(20);
+
+		rc = spi->read(spi, efx_mtd->efx, SPI_RDSR, -1,
+			       &status, sizeof(status));
+		if (rc)
+			return rc;
+		if (!(status & SPI_STATUS_NRDY))
+			return 0;
+	}
+	EFX_ERR(efx_mtd->efx, "timed out waiting for %s last status=0x%02x\n",
+		efx_mtd->name, status);
+	return -ETIMEDOUT;
+}
+
+static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, int uninterruptible)
+{
+	struct efx_spi_device *spi = efx_mtd->spi;
+	u8 status;
+	int rc, i;
+
+	/* Wait up to 4s for flash/EEPROM to finish a slow operation. */
+	for (i = 0; i < 40; i++) {
+		__set_current_state(uninterruptible ?
+				    TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ / 10);
+		rc = spi->read(spi, efx_mtd->efx, SPI_RDSR, -1,
+			       &status, sizeof(status));
+		if (rc)
+			return rc;
+		if (!(status & SPI_STATUS_NRDY))
+			return 0;
+		if (signal_pending(current))
+			return -EINTR;
+	}
+	EFX_ERR(efx_mtd->efx, "timed out waiting for %s\n", efx_mtd->name);
+	return -ETIMEDOUT;
+}
+
+static int
+efx_spi_write_enable(struct efx_mtd *efx_mtd)
+{
+	struct efx_spi_device *spi = efx_mtd->spi;
+
+	return spi->write(spi, efx_mtd->efx, SPI_WREN, -1, NULL, 0);
+}
+
+static int efx_spi_unlock(struct efx_mtd *efx_mtd)
+{
+	struct efx_spi_device *spi = efx_mtd->spi;
+	const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 |
+				     SPI_STATUS_BP0);
+	u8 status;
+	int rc;
+
+	rc = spi->read(spi, efx_mtd->efx, SPI_RDSR, -1, &status,
+		       sizeof(status));
+	if (rc)
+		return rc;
+
+	if (!(status & unlock_mask))
+		return 0; /* already unlocked */
+
+	rc = efx_spi_write_enable(efx_mtd);
+	if (rc)
+		return rc;
+	rc = spi->write(spi, efx_mtd->efx, SPI_SST_EWSR, -1, NULL, 0);
+	if (rc)
+		return rc;
+
+	status &= ~unlock_mask;
+	rc = spi->write(spi, efx_mtd->efx, SPI_WRSR, -1, &status,
+			sizeof(status));
+	if (rc)
+		return rc;
+	rc = efx_spi_fast_wait(efx_mtd);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+/* Dummy device used in case of a failed reset */
+
+static int efx_spi_dummy_read(const struct efx_spi_device *spi,
+			      struct efx_nic *efx, unsigned int command,
+			      int address, void *data, unsigned int len)
+{
+	return -EIO;
+}
+
+static int efx_spi_dummy_write(const struct efx_spi_device *spi,
+			       struct efx_nic *efx, unsigned int command,
+			       int address, const void *data, unsigned int len)
+{
+	return -EIO;
+}
+
+static struct efx_spi_device efx_spi_dummy_device = {
+	.block_size	= 1,
+	.erase_command	= 0xff,
+	.read		= efx_spi_dummy_read,
+	.write		= efx_spi_dummy_write,
+};
+
+/* MTD interface */
+
+static int efx_mtd_read(struct mtd_info *mtd, loff_t start, size_t len,
+			size_t *retlen, u8 *buffer)
+{
+	struct efx_mtd *efx_mtd = mtd->priv;
+	struct efx_spi_device *spi;
+	unsigned int command;
+	unsigned int block_len;
+	unsigned int pos = 0;
+	int rc;
+
+	rc = down_interruptible(&efx_mtd->access_lock);
+	if (rc)
+		goto out;
+	spi = efx_mtd->spi;
+
+	while (pos < len) {
+		block_len = min((unsigned int)len - pos,
+				efx_spi_read_limit(spi, start + pos));
+		command = efx_spi_munge_command(spi, SPI_READ, start + pos);
+		rc = spi->read(spi, efx_mtd->efx, command, start + pos,
+			       buffer + pos, block_len);
+		if (rc)
+			break;
+		pos += block_len;
+
+		/* Avoid locking up the system */
+		cond_resched();
+		if (signal_pending(current)) {
+			rc = -EINTR;
+			break;
+		}
+	}
+
+	up(&efx_mtd->access_lock);
+out:
+	*retlen = pos;
+	return rc;
+}
+
+/* Check that device contents match buffer.  If repeat is true, buffer
+ * contains a pattern of length EFX_MTD_VERIFY_BUF_LEN which the
+ * device contents should match repeatedly.
+ */
+static int efx_mtd_verify(struct mtd_info *mtd, loff_t start,
+			  size_t len, const u8 *buffer, int repeat)
+{
+	u8 verify_buffer[EFX_MTD_VERIFY_BUF_LEN];
+	unsigned int block_len;
+	size_t read_len;
+	unsigned int pos = 0;
+	int rc = 0;
+
+	while (pos < len) {
+		block_len = min(len - pos, sizeof(verify_buffer));
+		rc = efx_mtd_read(mtd, start + pos, block_len, &read_len,
+				  verify_buffer);
+		if (rc)
+			return rc;
+		if (memcmp(repeat ? buffer : buffer + pos, verify_buffer,
+			   block_len))
+			return -EIO;
+		pos += block_len;
+	}
+
+	return 0;
+}
+
+static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
+{
+	struct efx_mtd *efx_mtd = mtd->priv;
+	struct efx_spi_device *spi;
+	u8 empty[EFX_MTD_VERIFY_BUF_LEN];
+	int rc;
+
+	if (erase->len != mtd->erasesize) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = down_interruptible(&efx_mtd->access_lock);
+	if (rc)
+		goto out;
+	spi = efx_mtd->spi;
+	if (spi->erase_command == 0) {
+		rc = -EOPNOTSUPP;
+		goto out_up;
+	}
+
+	rc = efx_spi_unlock(efx_mtd);
+	if (rc)
+		goto out_up;
+	rc = efx_spi_write_enable(efx_mtd);
+	if (rc)
+		goto out_up;
+	rc = spi->write(spi, efx_mtd->efx, spi->erase_command, erase->addr,
+			NULL, 0);
+	if (rc)
+		goto out_up;
+	rc = efx_spi_slow_wait(efx_mtd, 0);
+
+out_up:
+	up(&efx_mtd->access_lock);
+	if (rc)
+		goto out;
+
+	memset(empty, 0xff, sizeof(empty));
+	rc = efx_mtd_verify(mtd, erase->addr, erase->len, empty, 1);
+
+out:
+	if (rc == 0) {
+		erase->state = MTD_ERASE_DONE;
+	} else {
+		erase->state = MTD_ERASE_FAILED;
+		erase->fail_addr = 0xffffffff;
+	}
+	mtd_erase_callback(erase);
+	return rc;
+}
+
+static int efx_mtd_write(struct mtd_info *mtd, loff_t start,
+			 size_t len, size_t *retlen, const u8 *buffer)
+{
+	struct efx_mtd *efx_mtd = mtd->priv;
+	struct efx_spi_device *spi;
+	unsigned int command;
+	unsigned int block_len;
+	unsigned int pos = 0;
+	int rc;
+
+	rc = down_interruptible(&efx_mtd->access_lock);
+	if (rc)
+		goto out;
+	spi = efx_mtd->spi;
+
+	rc = efx_spi_unlock(efx_mtd);
+	if (rc)
+		goto out_up;
+
+	while (pos < len) {
+		rc = efx_spi_write_enable(efx_mtd);
+		if (rc)
+			break;
+
+		block_len = min((unsigned int)len - pos,
+				efx_spi_write_limit(spi, start + pos));
+		command = efx_spi_munge_command(spi, SPI_WRITE, start + pos);
+		rc = spi->write(spi, efx_mtd->efx, command, start + pos,
+				buffer + pos, block_len);
+		if (rc)
+			break;
+		pos += block_len;
+
+		rc = efx_spi_fast_wait(efx_mtd);
+		if (rc)
+			break;
+
+		/* Avoid locking up the system */
+		cond_resched();
+		if (signal_pending(current)) {
+			rc = -EINTR;
+			break;
+		}
+	}
+
+out_up:
+	up(&efx_mtd->access_lock);
+	if (rc == 0)
+		rc = efx_mtd_verify(mtd, start, len, buffer, 0);
+out:
+	*retlen = pos;
+	return rc;
+}
+
+static void efx_mtd_sync(struct mtd_info *mtd)
+{
+	struct efx_mtd *efx_mtd = mtd->priv;
+	int rc;
+
+	down(&efx_mtd->access_lock);
+	rc = efx_spi_slow_wait(efx_mtd, 1);
+	if (rc)
+		EFX_ERR(efx_mtd->efx, "%s sync failed (%d)\n",
+			efx_mtd->name, rc);
+	up(&efx_mtd->access_lock);
+}
+
+/* Driverlink interface */
+
+static void efx_mtd_reset_suspend(struct efx_dl_device *efx_dev)
+{
+	struct efx_mtd *efx_mtd = efx_dev->priv;
+
+	if (!efx_mtd)
+		return;
+
+	/* Acquire lock to ensure that any in-progress operations have
+	 * completed, and no new ones can start.
+	 */
+	down(&efx_mtd->access_lock);
+}
+
+static void efx_mtd_reset_resume(struct efx_dl_device *efx_dev, int ok)
+{
+	struct efx_mtd *efx_mtd = efx_dev->priv;
+
+	if (!efx_mtd)
+		return;
+
+	/* If device reset failed already, or SPI device doesn't
+	 * become ready, disable device.
+	 */
+	if (!ok || efx_spi_slow_wait(efx_mtd, 1) != 0) {
+		efx_mtd->spi = &efx_spi_dummy_device;
+		EFX_ERR(efx_mtd->efx, "%s disabled after failed reset\n",
+			efx_mtd->name);
+	}
+
+	up(&efx_mtd->access_lock);
+}
+
+static void efx_mtd_remove(struct efx_dl_device *efx_dev)
+{
+	struct efx_mtd *efx_mtd = efx_dev->priv;
+
+	del_mtd_partitions(&efx_mtd->mtd);
+	kfree(efx_mtd);
+	efx_dev->priv = NULL;
+}
+
+static __devinit int efx_mtd_register(struct efx_mtd *efx_mtd,
+				      struct efx_dl_device *efx_dev,
+				      struct efx_nic *efx,
+				      struct efx_spi_device *spi,
+				      const char *type_name,
+				      const char **part_type_name,
+				      unsigned int num_parts)
+{
+	int i;
+
+	efx_dev->priv = efx_mtd;
+
+	efx_mtd->efx_dev = efx_dev;
+	efx_mtd->efx = efx;
+	efx_mtd->spi = spi;
+	sema_init(&efx_mtd->access_lock, 1);
+
+	efx_mtd->mtd.size = spi->size;
+	efx_mtd->mtd.erasesize = spi->erase_size;
+	efx_mtd->mtd.writesize = 1;
+	if (snprintf(efx_mtd->name, sizeof(efx_mtd->name),
+		     "%s %s", efx->name, type_name) >=
+	    sizeof(efx_mtd->name))
+		return -ENAMETOOLONG;
+
+	efx_mtd->mtd.priv = efx_mtd;
+	efx_mtd->mtd.name = efx_mtd->name;
+	efx_mtd->mtd.erase = efx_mtd_erase;
+	efx_mtd->mtd.read = efx_mtd_read;
+	efx_mtd->mtd.write = efx_mtd_write;
+	efx_mtd->mtd.sync = efx_mtd_sync;
+
+	for (i = 0; i < num_parts; i++) {
+		efx_mtd->part[i].name = efx_mtd->part_name[i];
+		if (snprintf(efx_mtd->part_name[i],
+			     sizeof(efx_mtd->part_name[i]),
+			     "%s %s", efx->name, part_type_name[i]) >=
+		    sizeof(efx_mtd->part_name[i]))
+			return -ENAMETOOLONG;
+
+		if (efx_allow_nvconfig_writes)
+			efx_mtd->part[i].mask_flags &= ~MTD_WRITEABLE;
+	}
+
+	return add_mtd_partitions(&efx_mtd->mtd, efx_mtd->part, num_parts);
+}
+
+static int __devinit
+efx_flash_probe(struct efx_dl_device *efx_dev,
+		const struct net_device *net_dev,
+		const struct efx_dl_device_info *dev_info,
+		const char *silicon_rev)
+{
+	struct efx_nic *efx = efx_dl_get_nic_port(efx_dev)->efx;
+	struct efx_mtd *efx_mtd;
+	const char *part_type_name[2];
+	unsigned int num_parts;
+	int rc;
+
+	if (!efx->spi_flash)
+		return -ENODEV;
+
+	efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL);
+	if (!efx_mtd)
+		return -ENOMEM;
+
+	efx_mtd->mtd.type = MTD_NORFLASH;
+	efx_mtd->mtd.flags = MTD_CAP_NORFLASH;
+
+	part_type_name[0] = "sfc_flash_config";
+	efx_mtd->part[0].offset = 0;
+	efx_mtd->part[0].size = min(efx->spi_flash->size,
+				    EFX_FLASH_BOOTROM_OFFSET);
+	efx_mtd->part[0].mask_flags = MTD_WRITEABLE;
+
+	if (efx->spi_flash->size <= EFX_FLASH_BOOTROM_OFFSET) {
+		num_parts = 1;
+	} else {
+		part_type_name[1] = "sfc_flash_bootrom";
+		efx_mtd->part[1].offset = EFX_FLASH_BOOTROM_OFFSET;
+		efx_mtd->part[1].size = (efx->spi_flash->size
+					 - EFX_FLASH_BOOTROM_OFFSET);
+		num_parts = 2;
+	}
+
+	rc = efx_mtd_register(efx_mtd, efx_dev, efx, efx->spi_flash,
+			      "sfc_flash", part_type_name, num_parts);
+	if (rc)
+		kfree(efx_mtd);
+	return rc;
+}
+
+static struct efx_dl_driver efx_flash_driver = {
+	.name		= "sfc_flash",
+	.probe		= efx_flash_probe,
+	.remove		= efx_mtd_remove,
+	.reset_suspend	= efx_mtd_reset_suspend,
+	.reset_resume	= efx_mtd_reset_resume,
+};
+
+static int __devinit
+efx_eeprom_probe(struct efx_dl_device *efx_dev,
+		 const struct net_device *net_dev,
+		 const struct efx_dl_device_info *dev_info,
+		 const char *silicon_rev)
+{
+	struct efx_nic *efx = efx_dl_get_nic_port(efx_dev)->efx;
+	struct efx_mtd *efx_mtd;
+	const char *type_name;
+	const char *part_type_name[1];
+	int rc;
+
+	if (!efx->spi_eeprom)
+		return -ENODEV;
+
+	efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL);
+	if (!efx_mtd)
+		return -ENOMEM;
+
+	efx_mtd->mtd.type = MTD_RAM;
+	efx_mtd->mtd.flags = MTD_CAP_RAM;
+
+	efx_mtd->part[0].offset = 0;
+	efx_mtd->part[0].size = efx->spi_eeprom->size;
+	efx_mtd->part[0].mask_flags = MTD_WRITEABLE;
+
+	if (efx->spi_eeprom->size <= 0x200) {
+		type_name = "sfc_small_eeprom";
+		part_type_name[0] = "sfc_small_config";
+	} else {
+		type_name = "sfc_large_eeprom";
+		part_type_name[0] = "sfc_large_config";
+	}
+
+	rc = efx_mtd_register(efx_mtd, efx_dev, efx, efx->spi_eeprom,
+			      type_name, part_type_name, 1);
+	if (rc)
+		kfree(efx_mtd);
+	return rc;
+}
+
+static struct efx_dl_driver efx_eeprom_driver = {
+	.name		= "sfc_eeprom",
+	.probe		= efx_eeprom_probe,
+	.remove		= efx_mtd_remove,
+	.reset_suspend	= efx_mtd_reset_suspend,
+	.reset_resume	= efx_mtd_reset_resume,
+};
+
+/* Kernel module interface */
+
+static int __init efx_mtd_init_module(void)
+{
+	int rc;
+
+	rc = efx_dl_register_driver(&efx_flash_driver);
+	if (rc)
+		return rc;
+	rc = efx_dl_register_driver(&efx_eeprom_driver);
+	if (rc) {
+		efx_dl_unregister_driver(&efx_flash_driver);
+		return rc;
+	}
+
+	return 0;
+}
+
+static void __exit efx_mtd_exit_module(void)
+{
+	efx_dl_unregister_driver(&efx_eeprom_driver);
+	efx_dl_unregister_driver(&efx_flash_driver);
+}
+
+module_init(efx_mtd_init_module);
+module_exit(efx_mtd_exit_module);
+
+MODULE_AUTHOR("Michael Brown <mbrown at fensystems.co.uk> and "
+	      "Solarflare Communications");
+MODULE_DESCRIPTION("SFC MTD driver");
+MODULE_LICENSE("GPL");

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.


From jamie at shareable.org  Fri Jan 18 13:20:46 2008
From: jamie at shareable.org (Jamie Lokier)
Date: Fri, 18 Jan 2008 18:20:46 +0000
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080117162601.GA6677@lazybastard.org>
References: <478F7E6D.8010300@parrot.com>
	<20080117162601.GA6677@lazybastard.org>
Message-ID: <20080118182046.GB21136@shareable.org>

J?rn Engel wrote:
> > If we do a ls without waiting that jffs2_garbage_collect_pass finish, ls 
> > takes 12 minutes to complete.
> 
> Impressive!  JFFS2 may be slow, but it shouldn't be _that_ slow.  Not
> sure who cares enough to look at this.  My approach would be to 
> $ echo t > /proc/sysrq_trigger
> several times during those 12 minutes and take a close look at the code
> paths showing up.  Most likely it will spend 99% of the time in one
> place.

I have seen similar slow GCs with JFFS2 on a 2.4.26-uc0 kernel (which
is very old now), just 1MB size, and of course no summary support.  In
this case it wasn't 12 minutes, but about 1 minute with the GC thread
using 100% CPU.  I saw it a couple of times.  But that's much slower
than erasing and writing the whole 1MB, so it's possible there has
been a GC bug doing excessive flash operations which remains unfixed
for a very long time.

-- Jamie


From jamie at shareable.org  Fri Jan 18 13:39:01 2008
From: jamie at shareable.org (Jamie Lokier)
Date: Fri, 18 Jan 2008 18:39:01 +0000
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <2B52FCEB-D871-4D9B-81D1-E03F7698AF96@logicaloutcome.ca>
References: <478F7E6D.8010300@parrot.com>
	<20080117162601.GA6677@lazybastard.org>
	<20080117114353.0bc71dac@zod.rchland.ibm.com>
	<2B52FCEB-D871-4D9B-81D1-E03F7698AF96@logicaloutcome.ca>
Message-ID: <20080118183900.GC21136@shareable.org>

Glenn Henshaw wrote:
>    I found a similar problem on an older 2.4.27 based system. We have  
> a 64k JFFS2 partition (1024 blocks of 4kbytes). As the file system  
> fills up, the time for any operation increases exponentially. When it  
> reaches 90% full, it takes minutes to write a file. After a cursory  
> inspection, it seems to block doing garbage collection and compressing  
> blocks.
> 
>    We gave up and limited the capacity to 60% full at the application  
> level.
> 
>    I'd appreciate any pointer to fix this, as migrating to a 2.6  
> kernel is not an option.

Yes!  I have exactly the same problem, except I'm using 2.4.26-uc0,
and it's a 1MB partition (16 blocks of 64kbytes).

I am tempted to modify the JFFS2 code to implement a hard limit of 50%
full at the kernel level.

The JFFS2 docs suggest 5 free blocks are enough to ensure GC is
working.  In my experience that does often work, but occasionally
there's a catastrophically long and CPU intensive GC.

-- Jamie


From joern at logfs.org  Fri Jan 18 15:20:24 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Fri, 18 Jan 2008 21:20:24 +0100
Subject: [PATCH] [MTD] [RFC] New Solarflare NIC EEPROM/Flash driver (3rd
	try)
In-Reply-To: <20080118183026.GH23117@solarflare.com>
References: <20080118183026.GH23117@solarflare.com>
Message-ID: <20080118202023.GB15039@lazybastard.org>

On Fri, 18 January 2008 18:30:28 +0000, Ben Hutchings wrote:
> 
> My colleague Robert Stonehouse submitted a new version of the sfc
> network driver and accompanying sfc_mtd MTD driver today.  The full
> source is at:
> 
> https://support.solarflare.com/netdev/5/net-2.6.25-sfc-2.2.0045.patch
> https://support.solarflare.com/netdev/5/net-2.6.25-sfc-2.2.0045.tgz

Cool.

> - Renamed efx_mtd_probe() to efx_mtd_register(), since it does
>   not probe
> - Moved structure allocation and device-dependent initialisation out of
>   efx_mtd_register()

My suggestion for this was actually a bit different, see below.

> - Simplified efx_mtd_verify():
>   - Replaced large heap buffer with small stack buffer, as this is not
>     speed-critical
>   - Allowed the caller to specify a repeating pattern, rather than handling
>     the erase pattern directly
>   - Replaced byte-comparison loop with memcmp()

Interesting solution.  Works for me.  If it makes a difference, you
could increase EFX_MTD_VERIFY_BUF_LEN to maybe 128 or 256.  That should
still be safe on the stack and cut down on function calls.  If it
doesn't make a difference, just leave it.

> - Changed type and flags for EEPROM to be "RAM" - the EEPROM is randomly
>   rewritable and it is certainly not DataFlash

Good.  I forgot to mention it when I saw it.

> +static __devinit int efx_mtd_register(struct efx_mtd *efx_mtd,
> +				      struct efx_dl_device *efx_dev,
> +				      struct efx_nic *efx,
> +				      struct efx_spi_device *spi,
> +				      const char *type_name,
> +				      const char **part_type_name,
> +				      unsigned int num_parts)

The function prototype is a monster.  My idea was to have this function
do the allocation and fill in any generic fields, then hand it over to
the concrete probe functions.  That approach doesn't require seven
parameters and is generally safer.  Something very roughly like the code
below.

If you want to combine the snprintf code, mtd registration, etc.  you
can also add another helper funtion.

static __devinit struct efx_mtd *efx_mtd_alloc( struct efx_spi_device *spi)
{
	struct efx_mtd *efx_mtd;

	efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL);
	if (!efx_mtd)
		return NULL;

	efx_mtd->spi = spi;
	sema_init(&efx_mtd->access_lock, 1);

	efx_mtd->mtd.size = spi->size;
	efx_mtd->mtd.erasesize = spi->erase_size;
	efx_mtd->mtd.writesize = 1;
	efx_mtd->mtd.priv = efx_mtd;

	efx_mtd->mtd.erase = efx_mtd_erase;
	efx_mtd->mtd.read = efx_mtd_read;
	efx_mtd->mtd.write = efx_mtd_write;
	efx_mtd->mtd.sync = efx_mtd_sync;
	return efx_mtd;
}

static int __devinit
efx_flash_probe(struct efx_dl_device *efx_dev,
		const struct net_device *net_dev,
		const struct efx_dl_device_info *dev_info,
		const char *silicon_rev)
{
	struct efx_nic *efx = efx_dl_get_nic_port(efx_dev)->efx;
	struct efx_mtd *efx_mtd;
	const char *part_type_name[2];
	unsigned int num_parts;
	int rc, len;

	if (!efx->spi_flash)
		return -ENODEV;

	efx_mtd = efx_mtd_alloc();
	if (!efx_mtd)
		return -ENOMEM;

	efx_dev->priv = efx_mtd;
	efx_mtd->efx_dev = efx_dev;
	efx_mtd->efx = efx;

	len = snprintf(efx_mtd->name, sizeof(efx_mtd->name), "%s %s", efx->name, "sfc_flash");
	if (len >= sizeof(efx_mtd->name))
		return -ENAMETOOLONG;
	efx_mtd->mtd.name = efx_mtd->name;
	...

J?rn

-- 
But this is not to say that the main benefit of Linux and other GPL
software is lower-cost. Control is the main benefit--cost is secondary.
-- Bruce Perens


From joern at logfs.org  Fri Jan 18 16:00:19 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Fri, 18 Jan 2008 22:00:19 +0100
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080118183900.GC21136@shareable.org>
References: <478F7E6D.8010300@parrot.com>
	<20080117162601.GA6677@lazybastard.org>
	<20080117114353.0bc71dac@zod.rchland.ibm.com>
	<2B52FCEB-D871-4D9B-81D1-E03F7698AF96@logicaloutcome.ca>
	<20080118183900.GC21136@shareable.org>
Message-ID: <20080118210019.GA16849@lazybastard.org>

On Fri, 18 January 2008 18:39:01 +0000, Jamie Lokier wrote:
> 
> Yes!  I have exactly the same problem, except I'm using 2.4.26-uc0,
> and it's a 1MB partition (16 blocks of 64kbytes).
> 
> I am tempted to modify the JFFS2 code to implement a hard limit of 50%
> full at the kernel level.
> 
> The JFFS2 docs suggest 5 free blocks are enough to ensure GC is
> working.  In my experience that does often work, but occasionally
> there's a catastrophically long and CPU intensive GC.

If you want to make GC go berzerk, here's a simple recipe:
1. Fill filesystem 100%.
2. Randomly replace single blocks.

There are two ways to solve this problem:
1. Reserve some amount of free space for GC performance.
2. Write in some non-random fashion.

Solution 2 works even better if the filesystem actually sorts data
very roughly by life expectency.  That requires writing to several
blocks in parallel, i.e. one for long-lived data, one for short-lived
data.  Made an impressive difference in logfs when I implemented that.

And of course academics can write many papers about good heuristics to
predict life expectency.  In fact, they already have.

J?rn

-- 
"Security vulnerabilities are here to stay."
-- Scott Culp, Manager of the Microsoft Security Response Center, 2001


From mattjreimer at gmail.com  Fri Jan 18 19:45:22 2008
From: mattjreimer at gmail.com (Matt Reimer)
Date: Fri, 18 Jan 2008 16:45:22 -0800
Subject: [PATCH] MTD: fix s3c2410 error correction
In-Reply-To: <20080117182634.GX14041@almesberger.net>
References: <20080117182634.GX14041@almesberger.net>
Message-ID: <f383264b0801181645t73bd63f1ua9577309b05e36a9@mail.gmail.com>

On Jan 17, 2008 10:26 AM, Werner Almesberger <werner at openmoko.org> wrote:
> FYI, I've verified the S3C2410 ECC fix
> http://lists.infradead.org/pipermail/linux-mtd/2007-October/019586.html
> on the OpenMoko GTA01 (2410) and GTA02 (2442).
>
> For this, I've written a crude little program to tilt bits in Flash:
> http://svn.openmoko.org/developers/werner/nandtilt/

Great, thanks! That's useful.

Matt


From jamie at shareable.org  Fri Jan 18 19:23:02 2008
From: jamie at shareable.org (Jamie Lokier)
Date: Sat, 19 Jan 2008 00:23:02 +0000
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080118210019.GA16849@lazybastard.org>
References: <478F7E6D.8010300@parrot.com>
	<20080117162601.GA6677@lazybastard.org>
	<20080117114353.0bc71dac@zod.rchland.ibm.com>
	<2B52FCEB-D871-4D9B-81D1-E03F7698AF96@logicaloutcome.ca>
	<20080118183900.GC21136@shareable.org>
	<20080118210019.GA16849@lazybastard.org>
Message-ID: <20080119002302.GA567@shareable.org>

J?rn Engel wrote:
> If you want to make GC go berzerk, here's a simple recipe:
> 1. Fill filesystem 100%.
> 2. Randomly replace single blocks.
> 
> There are two ways to solve this problem:
> 1. Reserve some amount of free space for GC performance.

The real difficulty is that it's not clear how much to reserve for
_reliable_ performance.  We're left guessing based on experience, and
that gives only limited confidence.  The 5 blocks suggested in JFFS2
docs seemed promising, but didn't work out.  Perhaps it does work with
5 blocks, but you have to count all potential metadata overhead and
misalignment overhead when working out how much free "file" data that
translates to?  Really, some of us just want JFFS2 to return -ENOSPC
at _some_ sensible deterministic point before the GC might behave
peculiarly, rather than trying to squeeze as much as possible onto the
partition.

> 2. Write in some non-random fashion.
> 
> Solution 2 works even better if the filesystem actually sorts data
> very roughly by life expectency.  That requires writing to several
> blocks in parallel, i.e. one for long-lived data, one for short-lived
> data.  Made an impressive difference in logfs when I implemented that.

Ah, a bit like generational GC :-)

-- Jamie


From joern at logfs.org  Fri Jan 18 21:38:39 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Sat, 19 Jan 2008 03:38:39 +0100
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080119002302.GA567@shareable.org>
References: <478F7E6D.8010300@parrot.com>
	<20080117162601.GA6677@lazybastard.org>
	<20080117114353.0bc71dac@zod.rchland.ibm.com>
	<2B52FCEB-D871-4D9B-81D1-E03F7698AF96@logicaloutcome.ca>
	<20080118183900.GC21136@shareable.org>
	<20080118210019.GA16849@lazybastard.org>
	<20080119002302.GA567@shareable.org>
Message-ID: <20080119023838.GA17136@lazybastard.org>

On Sat, 19 January 2008 00:23:02 +0000, Jamie Lokier wrote:
> J?rn Engel wrote:
> > 
> > There are two ways to solve this problem:
> > 1. Reserve some amount of free space for GC performance.
> 
> The real difficulty is that it's not clear how much to reserve for
> _reliable_ performance.  We're left guessing based on experience, and
> that gives only limited confidence.  The 5 blocks suggested in JFFS2
> docs seemed promising, but didn't work out.  Perhaps it does work with
> 5 blocks, but you have to count all potential metadata overhead and
> misalignment overhead when working out how much free "file" data that
> translates to?

The five blocks work well enough if your goal is that GC will return
_eventually_.  Now you come along and even want it to return within a
reasonable amount of time.  That is a different problem. ;)

Math is fairly simple.  The worst case is when the write pattern is
completely random and every block contains the same amount of data.  Let
us pick a 99% full filesystem for starters.

In order to write one block worth of data, GC need to move 99 blocks
worth of old data around, before it has freed a full block.  So on
average 99% of all writes handle GC data and only 1% handly the data you
- the user - care about.  If your filesystem is 80% full, 80% of all
writes are GC data and 20% are user data.  Very simple.

Latency is a different problem.  Depending on your design, those 80% or
99% GC writes can happen continuously or in huge batches.

> Really, some of us just want JFFS2 to return -ENOSPC
> at _some_ sensible deterministic point before the GC might behave
> peculiarly, rather than trying to squeeze as much as possible onto the
> partition.

Logfs has a field defined for GC reserve space.  I know the problem and
I care about it.  Although I have to admit that mkfs doesn't allow
setting this field yet.

> > 2. Write in some non-random fashion.
> > 
> > Solution 2 works even better if the filesystem actually sorts data
> > very roughly by life expectency.  That requires writing to several
> > blocks in parallel, i.e. one for long-lived data, one for short-lived
> > data.  Made an impressive difference in logfs when I implemented that.
> 
> Ah, a bit like generational GC :-)

Actually, no.  The different levels of the tree, which JFFS2 doesn't
store on the medium, also happen to have vastly different lifetimes.
Generational GC is the logical next step, which I haven't done yet.

J?rn

-- 
Science is like sex: sometimes something useful comes out,
but that is not the reason we are doing it.
-- Richard Feynman


From office at alphafinancialconsult.co.uk  Wed Jan 16 11:20:07 2008
From: office at alphafinancialconsult.co.uk (ALPHA FINANCIAL CONSULT)
Date: Wed, 16 Jan 2008 17:20:07 +0100
Subject: FUNDS CONSULTATION 2
Message-ID: <E1JFAzn-0006GJ-Rb@da2.joomlahost.it>

                             From: ALPHA FINANCIAL CONSULT.
                                  LONDON, U.K.


We wish to notify you again that you were listed as a beneficiary to the total sum of ?6,000,000.00 GBP (Six Million British Pounds) in the codicil and last testament of the deceased. (Name now withheld since this is our second letter to you). 
We contacted you because you bear the surname identity and therefore can present you as the beneficiary to the inheritance. 

We therefore reckoned that you could receive these funds as you are qualified by your name identity. All the legal papers will be processed upon your acceptance. 
Upon your acceptance of this deal, we request that you kindly forward to us your letter of acceptance, your current telephone and fax numbers and a forwarding address to enable us file necessary LEGAL documents in your name at our high court probate division for the release of the fund in question.

Please contact me ASAP by e-mail and call: +447024058242.  so that we can get this done immediately.

Kind regards,
 
Allen Stone.
Direct Line: +447024058242.
Email: allenstn at mixmail.com






From ezk at cs.sunysb.edu  Sun Jan 20 16:01:35 2008
From: ezk at cs.sunysb.edu (Erez Zadok)
Date: Sun, 20 Jan 2008 16:01:35 -0500
Subject: [PATCH] block2mtd lockdep_init_map warning 
In-Reply-To: Your message of "Wed, 16 Jan 2008 22:20:54 +0100."
	<20080116212054.GA891@lazybastard.org> 
Message-ID: <200801202101.m0KL1Z3w006821@agora.fsl.cs.sunysb.edu>

In message <20080116212054.GA891 at lazybastard.org>, =?utf-8?B?SsO2cm4=?= Engel writes:
[...]
> Patch didn't compile due to function ordering.  Here is an updated version.

Joern/Peter, I've tested this updated patch with v2.6.24-rc8-74-ga7da60f.
It worked fine for me.

Thanks,
Erez.

> Acked-and-tested-by: Joern Engel <joern at lazybastard.org>
> 
> diff --git a/kernel/module.c b/kernel/module.c
> index c2e3e2e..0397b1e 100644
> --- a/kernel/module.c
> +++ b/kernel/module.c
> @@ -1645,6 +1645,17 @@ static inline void add_kallsyms(struct module *mod,
>  }
>  #endif /* CONFIG_KALLSYMS */
>  
> +/*
> + * link the module with the whole machine is stopped with interrupts off
> + * - this defends against kallsyms not taking locks
> + */
> +static int __link_module(void *_mod)
> +{
> +	struct module *mod = _mod;
> +	list_add(&mod->list, &modules);
> +	return 0;
> +}
> +
>  /* Allocate and load the module: note that size of section 0 is always
>     zero, and we rely on this for optional sections. */
>  static struct module *load_module(void __user *umod,
> @@ -2023,6 +2034,11 @@ static struct module *load_module(void __user *umod,
>  		printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
>  		       mod->name);
>  
> +	/* Now sew it into the lists so we can get lockdep and oops
> +         * info during argument parsing.  Noone should access us, since
> +         * strong_try_module_get() will fail. */
> +	stop_machine_run(__link_module, mod, NR_CPUS);
> +
>  	/* Size of section 0 is 0, so this works well if no params */
>  	err = parse_args(mod->name, mod->args,
>  			 (struct kernel_param *)
> @@ -2031,7 +2047,7 @@ static struct module *load_module(void __user *umod,
>  			 / sizeof(struct kernel_param),
>  			 NULL);
>  	if (err < 0)
> -		goto arch_cleanup;
> +		goto unlink;
>  
>  	err = mod_sysfs_setup(mod,
>  			      (struct kernel_param *)
> @@ -2039,7 +2055,7 @@ static struct module *load_module(void __user *umod,
>  			      sechdrs[setupindex].sh_size
>  			      / sizeof(struct kernel_param));
>  	if (err < 0)
> -		goto arch_cleanup;
> +		goto unlink;
>  	add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
>  	add_notes_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
>  
> @@ -2054,7 +2070,8 @@ static struct module *load_module(void __user *umod,
>  	/* Done! */
>  	return mod;
>  
> - arch_cleanup:
> + unlink:
> +	stop_machine_run(__unlink_module, mod, NR_CPUS);
>  	module_arch_cleanup(mod);
>   cleanup:
>  	module_unload_free(mod);
> @@ -2076,17 +2093,6 @@ static struct module *load_module(void __user *umod,
>  	goto free_hdr;
>  }
>  
> -/*
> - * link the module with the whole machine is stopped with interrupts off
> - * - this defends against kallsyms not taking locks
> - */
> -static int __link_module(void *_mod)
> -{
> -	struct module *mod = _mod;
> -	list_add(&mod->list, &modules);
> -	return 0;
> -}
> -
>  /* This is where the real work happens */
>  asmlinkage long
>  sys_init_module(void __user *umod,
> @@ -2111,10 +2117,6 @@ sys_init_module(void __user *umod,
>  		return PTR_ERR(mod);
>  	}
>  
> -	/* Now sew it into the lists.  They won't access us, since
> -           strong_try_module_get() will fail. */
> -	stop_machine_run(__link_module, mod, NR_CPUS);
> -
>  	/* Drop lock so they can recurse */
>  	mutex_unlock(&module_mutex);


From r&d2 at dave-tech.it  Mon Jan 21 04:51:38 2008
From: r&d2 at dave-tech.it (llandre)
Date: Mon, 21 Jan 2008 10:51:38 +0100
Subject: Micron NAND support in linux MTD
In-Reply-To: <8bf247760801180745k6f8337d5p751d91b21bd3728d@mail.gmail.com>
References: <47907CDF.30802@dave-tech.it>
	<8bf247760801180745k6f8337d5p751d91b21bd3728d@mail.gmail.com>
Message-ID: <47946B2A.1030400@dave-tech.it>

Sriram,

IIUC the bad block position is set in function nand_get_flash_type:

	/* Set the bad block position */
	chip->badblockpos = mtd->writesize > 512 ?
		NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;


/*
* Constants for oob configuration
*/
#define NAND_SMALL_BADBLOCK_POS		5
#define NAND_LARGE_BADBLOCK_POS		0

That is two values are defined:
a) 5 for small block devices (6th location)
b) 0 for large block devices (1st location)

So the position is correct with respect to the Micron MT29F1GxxABB 
datasheet.
However I still have a doubt about which page is checked. I'n not sure 
if JFFS2/MTD check first page only. Datasheet says:

"The factory identifies
invalid blocks before shipping by programming data other than FFh (x8) 
or FFFFh (x16) into the first spare location (column address 2,048 for 
x8 devices, or 1,024 for x16 devices) *of the first or second page of 
each bad block*."

so both first and second page should be checked. Do you know what 
JFFS2/MTD do?


-- 
llandre



> Hi,
>    The location of the "bad block indicator" within the spare area
> depends on the
>     manufacturer. It could vary from chip to chip.
> 
>    it could also depend on the page size as well.
> 
>    Usually, for a large page size nand, It could be located at the
> first byte of the OOB.
>    For a small it could be at 6th byte.
> 
>   The way you send some commands to the large page size nand device is
> somewhat different
>   from the small page size nand device. I think you may not be using
> the driver for a large page  nand device.
> 
>   Most of the stuff (driver) for the large page nand devices is
> generic. The way you wait for nand busy changes.
> 
>   Check the way your reading the flash information from the chip id
> and additional infomation.
>   The way youre mtd_info structure is getting initialised. You could
> be missing something here.
> 
> Hope this helps.
> 
> Regards,
> sriram
> 
> 
> 
> 
> On Jan 18, 2008 3:48 PM, llandre <r&d2 at dave-tech.it> wrote:
>> Hi,
>>
>> I found on MTD mailing list your patch that adds Micron manufacturer ID:
>> http://article.gmane.org/gmane.linux.drivers.mtd/17694
>>
>> I'm going to use NAND Micron devices for a new project however I still
>> have a doubt about how MTD/JFFS2 handle bad blocks. To detect blocks
>> marked as bad it checks the 6th location of OOB area of first page, thus
>> it seems it is not able to handle Micron devices properly. In fact these
>> devices stores bad block marker in the first location of OOB of first or
>> second page (for example see page 50 of MT29F1GxxABB data sheet). Am I
>> misreading the datasheet? Could you help me to clear this point?
>>
>>
>> Thanks in advance,
>> llandre
>>
>> DAVE Electronics System House - R&D Department
>> web:   http://www.dave-tech.it
>> email: r&d2 at dave-tech.it
>>
>> ______________________________________________________
>> Linux MTD discussion mailing list
>> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>>
> 
> 



From ricard.wanderlof at axis.com  Mon Jan 21 05:06:40 2008
From: ricard.wanderlof at axis.com (Ricard Wanderlof)
Date: Mon, 21 Jan 2008 11:06:40 +0100 (CET)
Subject: Micron NAND support in linux MTD
In-Reply-To: <47946B2A.1030400@dave-tech.it>
References: <47907CDF.30802@dave-tech.it>
	<8bf247760801180745k6f8337d5p751d91b21bd3728d@mail.gmail.com>
	<47946B2A.1030400@dave-tech.it>
Message-ID: <Pine.LNX.4.64.0801211105440.25733@lnxricardw.se.axis.com>


On Mon, 21 Jan 2008, llandre wrote:

> if JFFS2/MTD check first page only. Datasheet says:
>
> "The factory identifies invalid blocks before shipping by programming 
> data other than FFh (x8) or FFFFh (x16) into the first spare location 
> (column address 2,048 for x8 devices, or 1,024 for x16 devices) *of the 
> first or second page of each bad block*."

The option of programming the second page is probably a last resort in 
case the first page is so bad that it cannot be programmed at all, which I 
would think is most unlikely.

/Ricard


From r&d2 at dave-tech.it  Mon Jan 21 06:21:25 2008
From: r&d2 at dave-tech.it (llandre)
Date: Mon, 21 Jan 2008 12:21:25 +0100
Subject: Micron NAND support in linux MTD
In-Reply-To: <Pine.LNX.4.64.0801211105440.25733@lnxricardw.se.axis.com>
References: <47907CDF.30802@dave-tech.it>
	<8bf247760801180745k6f8337d5p751d91b21bd3728d@mail.gmail.com>
	<47946B2A.1030400@dave-tech.it>
	<Pine.LNX.4.64.0801211105440.25733@lnxricardw.se.axis.com>
Message-ID: <47948035.8040903@dave-tech.it>

>> if JFFS2/MTD check first page only. Datasheet says:
>>
>> "The factory identifies invalid blocks before shipping by programming 
>> data other than FFh (x8) or FFFFh (x16) into the first spare location 
>> (column address 2,048 for x8 devices, or 1,024 for x16 devices) *of 
>> the first or second page of each bad block*."
> 
> The option of programming the second page is probably a last resort in 
> case the first page is so bad that it cannot be programmed at all, which 
> I would think is most unlikely.
I think your point is reasonable. I'd like to hear someone from Samsung 
or Micron to confirm your speculation ...


-- 
llandre

DAVE Electronics System House - R&D Department
web:   http://www.dave.eu
email: r&d2 at dave-tech.it


From ricard.wanderlof at axis.com  Mon Jan 21 06:45:56 2008
From: ricard.wanderlof at axis.com (Ricard Wanderlof)
Date: Mon, 21 Jan 2008 12:45:56 +0100 (CET)
Subject: Micron NAND support in linux MTD
In-Reply-To: <47948035.8040903@dave-tech.it>
References: <47907CDF.30802@dave-tech.it>
	<8bf247760801180745k6f8337d5p751d91b21bd3728d@mail.gmail.com>
	<47946B2A.1030400@dave-tech.it>
	<Pine.LNX.4.64.0801211105440.25733@lnxricardw.se.axis.com>
	<47948035.8040903@dave-tech.it>
Message-ID: <Pine.LNX.4.64.0801211244120.25733@lnxricardw.se.axis.com>


On Mon, 21 Jan 2008, llandre wrote:

>> The option of programming the second page is probably a last resort in case 
>> the first page is so bad that it cannot be programmed at all, which I would 
>> think is most unlikely.
>
> I think your point is reasonable. I'd like to hear someone from Samsung or 
> Micron to confirm your speculation ...

Me too but I think they'd just refer you to the data sheet. I haven't been 
able to get any form of statistics from chip manufacturers like the number 
of bad blocks when the chip is new, or other things that aren't stated in 
the data sheets.

/Ricard


From matthieu.castet at parrot.com  Mon Jan 21 10:57:59 2008
From: matthieu.castet at parrot.com (Matthieu CASTET)
Date: Mon, 21 Jan 2008 16:57:59 +0100
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080118181744.GA15039@lazybastard.org>
References: <478F7E6D.8010300@parrot.com>
	<20080117162601.GA6677@lazybastard.org>
	<20080117114353.0bc71dac@zod.rchland.ibm.com>
	<479073D1.5010406@parrot.com>
	<20080118064852.026b0c82@zod.rchland.ibm.com>
	<4790D11E.6060201@parrot.com>
	<20080118115531.2deef9fb@zod.rchland.ibm.com>
	<20080118181744.GA15039@lazybastard.org>
Message-ID: <4794C107.7070600@parrot.com>

Hi,

J?rn Engel wrote:
> On Fri, 18 January 2008 11:55:31 -0600, Josh Boyer wrote:
>> That seems consistent with JFFS2 doing the CRC checks and constructing
>> the in-memory representation of your large file.  I suspect the older
>> list-based in-memory implementation would have taken even longer, but
>> there could be something amiss with the rb-tree stuff perhaps.
> 
> There is something conceptually amiss with rb-trees.  Each node
> effectively occupies its own cacheline.  With those 40k+ nodes, you
> would need a rather sizeable cache with at least 20k cachelines to have
> an impact.  Noone does.  So for all practical purposes, every single
> lookup will go to main memory.
> 
> Maybe it is about time to suggest trying logfs?
What's the status of logfs on NAND ?

Last time I check, it didn't manage badblock.


Matthieu


From joern at logfs.org  Mon Jan 21 16:25:56 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Mon, 21 Jan 2008 22:25:56 +0100
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <4794C107.7070600@parrot.com>
References: <478F7E6D.8010300@parrot.com>
	<20080117162601.GA6677@lazybastard.org>
	<20080117114353.0bc71dac@zod.rchland.ibm.com>
	<479073D1.5010406@parrot.com>
	<20080118064852.026b0c82@zod.rchland.ibm.com>
	<4790D11E.6060201@parrot.com>
	<20080118115531.2deef9fb@zod.rchland.ibm.com>
	<20080118181744.GA15039@lazybastard.org>
	<4794C107.7070600@parrot.com>
Message-ID: <20080121212555.GA14472@lazybastard.org>

On Mon, 21 January 2008 16:57:59 +0100, Matthieu CASTET wrote:
>
> What's the status of logfs on NAND ?
> 
> Last time I check, it didn't manage badblock.

Is that the only thing stopping you from using logfs?

mklogfs handles bad blocks.  Blocks rotting during lifetime are handled
half-heartedly.  If that is a real problem for you I wouldn't be
surprised if you caught logfs on the wrong foot once or twice.

J?rn

-- 
Joern's library part 10:
http://blogs.msdn.com/David_Gristwood/archive/2004/06/24/164849.aspx


From jwboyer at gmail.com  Mon Jan 21 17:16:12 2008
From: jwboyer at gmail.com (Josh Boyer)
Date: Mon, 21 Jan 2008 16:16:12 -0600
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080121212555.GA14472@lazybastard.org>
References: <478F7E6D.8010300@parrot.com>
	<20080117162601.GA6677@lazybastard.org>
	<20080117114353.0bc71dac@zod.rchland.ibm.com>
	<479073D1.5010406@parrot.com>
	<20080118064852.026b0c82@zod.rchland.ibm.com>
	<4790D11E.6060201@parrot.com>
	<20080118115531.2deef9fb@zod.rchland.ibm.com>
	<20080118181744.GA15039@lazybastard.org>
	<4794C107.7070600@parrot.com>
	<20080121212555.GA14472@lazybastard.org>
Message-ID: <20080121161612.3ca2f093@zod.rchland.ibm.com>

On Mon, 21 Jan 2008 22:25:56 +0100
J?rn Engel <joern at logfs.org> wrote:

> On Mon, 21 January 2008 16:57:59 +0100, Matthieu CASTET wrote:
> >
> > What's the status of logfs on NAND ?
> > 
> > Last time I check, it didn't manage badblock.
> 
> Is that the only thing stopping you from using logfs?
> 
> mklogfs handles bad blocks.  Blocks rotting during lifetime are handled
> half-heartedly.  If that is a real problem for you I wouldn't be
> surprised if you caught logfs on the wrong foot once or twice.

Wait... you're writing a flash filesystem that doesn't really deal with
bad blocks?

josh


From joern at logfs.org  Mon Jan 21 17:29:52 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Mon, 21 Jan 2008 23:29:52 +0100
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080121161612.3ca2f093@zod.rchland.ibm.com>
References: <20080117162601.GA6677@lazybastard.org>
	<20080117114353.0bc71dac@zod.rchland.ibm.com>
	<479073D1.5010406@parrot.com>
	<20080118064852.026b0c82@zod.rchland.ibm.com>
	<4790D11E.6060201@parrot.com>
	<20080118115531.2deef9fb@zod.rchland.ibm.com>
	<20080118181744.GA15039@lazybastard.org>
	<4794C107.7070600@parrot.com>
	<20080121212555.GA14472@lazybastard.org>
	<20080121161612.3ca2f093@zod.rchland.ibm.com>
Message-ID: <20080121222952.GC14472@lazybastard.org>

On Mon, 21 January 2008 16:16:12 -0600, Josh Boyer wrote:
> 
> Wait... you're writing a flash filesystem that doesn't really deal with
> bad blocks?

I never said that.  Like any other new piece of code, logfs has bugs.
Plain and simple.  And having blocks rot underneith you is something I
don't have automated tests for, so don't be surprised to find bugs in
this area.

If you send a patch or a nice test setup or even just a bug report, the
chances of getting those bugs fixed improve.

J?rn

-- 
One of my most productive days was throwing away 1000 lines of code.
-- Ken Thompson.


From thraxisp at logicaloutcome.ca  Mon Jan 21 17:36:45 2008
From: thraxisp at logicaloutcome.ca (Glenn Henshaw)
Date: Mon, 21 Jan 2008 17:36:45 -0500
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080121212555.GA14472@lazybastard.org>
References: <478F7E6D.8010300@parrot.com>
	<20080117162601.GA6677@lazybastard.org>
	<20080117114353.0bc71dac@zod.rchland.ibm.com>
	<479073D1.5010406@parrot.com>
	<20080118064852.026b0c82@zod.rchland.ibm.com>
	<4790D11E.6060201@parrot.com>
	<20080118115531.2deef9fb@zod.rchland.ibm.com>
	<20080118181744.GA15039@lazybastard.org>
	<4794C107.7070600@parrot.com>
	<20080121212555.GA14472@lazybastard.org>
Message-ID: <527F0DC6-BB5F-4C38-94D5-FCC97A8F2FF2@logicaloutcome.ca>


On 21-Jan-08, at 4:25 PM, J?rn Engel wrote:

> On Mon, 21 January 2008 16:57:59 +0100, Matthieu CASTET wrote:
>>
>> What's the status of logfs on NAND ?
>>
>> Last time I check, it didn't manage badblock.
>
> Is that the only thing stopping you from using logfs?
>
> mklogfs handles bad blocks.  Blocks rotting during lifetime are  
> handled
> half-heartedly.  If that is a real problem for you I wouldn't be
> surprised if you caught logfs on the wrong foot once or twice.
>
>

   Has it been ported to a 2.4 kernel? I can't upgrade due to the  
amount of work necessary to rewrite drivers.

-- 
Glenn Henshaw                     Logical Outcome Ltd.
e: thraxisp at logicaloutcome.ca     w: www.logicaloutcome.ca





From eric.y.miao at gmail.com  Mon Jan 21 19:19:40 2008
From: eric.y.miao at gmail.com (eric miao)
Date: Tue, 22 Jan 2008 08:19:40 +0800
Subject: [PATCH] basic pxa3 nand controller support
In-Reply-To: <1200916396.6263.6.camel@localhost.localdomain>
References: <1200916396.6263.6.camel@localhost.localdomain>
Message-ID: <f17812d70801211619u6d2a89bdt19f1b67b1c188470@mail.gmail.com>

Hi Sergey,

Thanks for trying the driver. I guess this is generally OK, but there
are several concerns:

1. we may move to use a consistent OBM version, or at least make
the partition size same across OBM version 2 and 3, and this is the
reason we remove those code in the original patch

2. I wonder if the modification to head.S belongs to this driver

3. recent kernel should include the fix to DRCMR() macro, so we
can use DRCMR(97) safely. and we are slowly moving to use
IORESOURCE_DMA for the purpose of DMA channel assignment,
so one day, we may end up with setting the resource of
pxa3xx_device_nand.

And we may further improve the driver to detect flash by using
the nand generic layer, and eliminate the pxa3xx_nand_flash
structures. I don't have enough time to test this out, will let you
know later.

- eric

On Jan 21, 2008 7:53 PM, Sergey Podstavin <spodstavin at ru.mvista.com> wrote:
> > Date: Wed, 16 Jan 2008 08:52:21 +0800
> > From: "eric miao" <eric.y.miao at gmail.com>
> > Subject: Re: [PATCH] basic pxa3 nand controller support
> > To: spodstavin at ru.mvista.com
> > Cc: linux-mtd at lists.infradead.org
> > Message-ID:
> >       <f17812d70801151652s739fd05eyfc82ab569d8efdd7 at mail.gmail.com>
> > Content-Type: text/plain; charset=UTF-8
> >
> > On Jan 11, 2008 7:44 PM, Sergey Podstavin <spodstavin at ru.mvista.com>
> wrote:
> > > This is a fixed version for pxa3 nand controller,
> > > working on pxa300 Zylonite
> >
> > great, thanks for trying this. It looks like a bunch of things are
> added back
> > from previous marvell released packages :-)
> >
> > 1. io mapping is not recommended for peripheral drivers, we instead
> use
> >    ioremap() in the nand driver, so it's not a must to map those
> registers
> >    when pxa_map_io()
> >
> > 2. as I said, those DRCMRxx macros can be well replaced by DRCMR(xx),
> >    the original DRCMR(xx) macro has an issue, which is corrected by
> >    recent patch sent to RMK, and is supposed to be merged in recent
> >    .24-rc7
> >
> > 3. partition tables should be moved outside of the driver into
> platform
> >    code
> >
> > Apart from the above, could you let me know which modifications you
> > made this work? You know it's a big patch, and is difficult for line
> to line
> > comparison with my original one..., thanks!
> >
>
> This is updated pxa3 nand controller support, io mapping was removed,
> partition tables were moved outside of the driver into platform code,
> some cleanup was done. Changes in head.S were done to boot pxa300
>
> Zylonite.
>
> Best wishes,
> Sergey Podstavin.
>
> Date: Mon, 21 Jan 2008 13:50:42 +0300
> [PATCH] pxa3 nand controller support
> Sergey Podstavin <spodstavin at ru.mvista.com>
>
> ---
>  arch/arm/kernel/head.S                 |    6 +-
>  arch/arm/mach-pxa/pxa3xx.c             |    1 +
>  arch/arm/mach-pxa/zylonite.c           |   61 ++
>  drivers/mtd/nand/Kconfig               |    6 +
>  drivers/mtd/nand/Makefile              |    1 +
>  drivers/mtd/nand/pxa3xx_nand.c         | 1385 ++++++++++++++++++++++++++++++++
>  include/asm-arm/arch-pxa/pxa-regs.h    |    1 +
>  include/asm-arm/arch-pxa/pxa3xx_nand.h |   18 +
>  8 files changed, 1476 insertions(+), 3 deletions(-)
>  create mode 100644 drivers/mtd/nand/pxa3xx_nand.c
>  create mode 100644 include/asm-arm/arch-pxa/pxa3xx_nand.h
>
> diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
> index 7898cbc..a89c0f2 100644
> --- a/arch/arm/kernel/head.S
> +++ b/arch/arm/kernel/head.S
> @@ -86,9 +86,9 @@ ENTRY(stext)
>         bl      __lookup_processor_type         @ r5=procinfo r9=cpuid
>         movs    r10, r5                         @ invalid processor (r5=0)?
>         beq     __error_p                       @ yes, error 'p'
> -       bl      __lookup_machine_type           @ r5=machinfo
> -       movs    r8, r5                          @ invalid machine (r5=0)?
> -       beq     __error_a                       @ yes, error 'a'
> +//     bl      __lookup_machine_type           @ r5=machinfo
> +//     movs    r8, r5                          @ invalid machine (r5=0)?
> +//     beq     __error_a                       @ yes, error 'a'
>         bl      __vet_atags
>         bl      __create_page_tables
>
> diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
> index 61d9c9d..4d800c6 100644
> --- a/arch/arm/mach-pxa/pxa3xx.c
> +++ b/arch/arm/mach-pxa/pxa3xx.c
> @@ -183,6 +183,7 @@ static struct clk pxa3xx_clks[] = {
>         PXA3xx_CK("LCDCLK", LCD,    &clk_pxa3xx_hsio_ops, &pxa_device_fb.dev),
>         PXA3xx_CK("CAMCLK", CAMERA, &clk_pxa3xx_hsio_ops, NULL),
>
> +       PXA3xx_CK("NANDCLK", NAND, &clk_pxa3xx_hsio_ops, NULL),
>         PXA3xx_CKEN("UARTCLK", FFUART, 14857000, 1, &pxa_device_ffuart.dev),
>         PXA3xx_CKEN("UARTCLK", BTUART, 14857000, 1, &pxa_device_btuart.dev),
>         PXA3xx_CKEN("UARTCLK", STUART, 14857000, 1, NULL),
> diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
> index 743a87b..468c773 100644
> --- a/arch/arm/mach-pxa/zylonite.c
> +++ b/arch/arm/mach-pxa/zylonite.c
> @@ -18,6 +18,8 @@
>  #include <linux/interrupt.h>
>  #include <linux/init.h>
>  #include <linux/platform_device.h>
> +#include <linux/mtd/nand.h>
> +#include <linux/mtd/partitions.h>
>
>  #include <asm/mach-types.h>
>  #include <asm/mach/arch.h>
> @@ -25,6 +27,7 @@
>  #include <asm/arch/gpio.h>
>  #include <asm/arch/pxafb.h>
>  #include <asm/arch/zylonite.h>
> +#include <asm/arch/pxa3xx_nand.h>
>
>  #include "generic.h"
>
> @@ -156,6 +159,62 @@ static void __init zylonite_init_lcd(void)
>  static inline void zylonite_init_lcd(void) {}
>  #endif
>
> +struct mtd_partition pxa3xx_mtd_partition_info[] = {
> +       {
> +               name:           "Bootloader",
> +               offset:         0,
> +               mask_flags:     MTD_WRITEABLE  /* force read-only */
> +       },{
> +               name:           "Kernel",
> +               size:           0x00200000,
> +               mask_flags:     MTD_WRITEABLE  /* force read-only */
> +       },{
> +               name:           "Filesystem",
> +               size:           0x03000000,     /* only mount 48M fs */
> +       }, {
> +               name:           "MassStorage",
> +               size:           0x0, /* It will be set at probe function */
> +               offset:         MTDPART_OFS_APPEND /* Append after fs section */
> +       }, {
> +               name:           "BBT",
> +               size:           0x0, /* It will be set at probe function */
> +               offset:         MTDPART_OFS_APPEND,/* Append after fs section */
> +               mask_flags:     MTD_WRITEABLE  /* force read-only */
> +       }
> +};
> +
> +#define                PXA3XX_MTD_PART_NUM     ARRAY_SIZE(pxa3xx_mtd_partition_info)
> +
> +static struct resource nand_resources[] = {
> +       [0] = {
> +               .start  = 0x43100000,
> +               .end    = 0x431000ff,
> +               .flags  = IORESOURCE_MEM,
> +       },
> +       [1] = {
> +               .start  = -1,   /* for run-time assignment */
> +               .end    = -1,
> +               .flags  = IORESOURCE_IRQ,
> +       }
> +};
> +
> +static struct platform_device nand_device = {
> +       .name           = "pxa3xx-nand",
> +       .id             = 0,
> +       .num_resources  = ARRAY_SIZE(nand_resources),
> +       .resource       = nand_resources,
> +};
> +
> +void __init set_pxa_nand_info(struct pxa3xx_nand_platform_data *info)
> +{
> +       nand_device.dev.platform_data = info;
> +}
> +
> +struct pxa3xx_nand_platform_data pxa3xx_nand_data = {
> +       .parts          = pxa3xx_mtd_partition_info,
> +       .nr_parts       = PXA3XX_MTD_PART_NUM,
> +};
> +
>  static void __init zylonite_init(void)
>  {
>         /* board-processor specific initialization */
> @@ -171,6 +230,8 @@ static void __init zylonite_init(void)
>         platform_device_register(&smc91x_device);
>
>         zylonite_init_lcd();
> +       set_pxa_nand_info(&pxa3xx_nand_data);
> +       platform_device_register(&nand_device);
>  }
>
>  MACHINE_START(ZYLONITE, "PXA3xx Platform Development Kit (aka Zylonite)")
> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index 246d451..2be073f 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -84,6 +84,12 @@ config MTD_NAND_TS7250
>  config MTD_NAND_IDS
>         tristate
>
> +config MTD_NAND_PXA3xx
> +       tristate "NAND flash support for PXA3xx"
> +       depends on MTD_NAND && PXA3xx
> +       help
> +         This enables the driver for the NAND flash device on Zylonite board
> +
>  config MTD_NAND_AU1550
>         tristate "Au1550/1200 NAND support"
>         depends on SOC_AU1200 || SOC_AU1550
> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
> index 3ad6c01..ecb7968 100644
> --- a/drivers/mtd/nand/Makefile
> +++ b/drivers/mtd/nand/Makefile
> @@ -17,6 +17,7 @@ obj-$(CONFIG_MTD_NAND_BF5XX)          += bf5xx_nand.o
>  obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB)  += ppchameleonevb.o
>  obj-$(CONFIG_MTD_NAND_S3C2410)         += s3c2410.o
>  obj-$(CONFIG_MTD_NAND_DISKONCHIP)      += diskonchip.o
> +obj-$(CONFIG_MTD_NAND_PXA3xx)          += pxa3xx_nand.o
>  obj-$(CONFIG_MTD_NAND_H1900)           += h1910.o
>  obj-$(CONFIG_MTD_NAND_RTC_FROM4)       += rtc_from4.o
>  obj-$(CONFIG_MTD_NAND_SHARPSL)         += sharpsl.o
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> new file mode 100644
> index 0000000..11bebbf
> --- /dev/null
> +++ b/drivers/mtd/nand/pxa3xx_nand.c
> @@ -0,0 +1,1385 @@
> +/*
> + * drivers/mtd/nand/pxa3xx_nand.c
> + *
> + * Copyright (C) 2005 Intel Corporation
> + * Copyright (C) 2006 Marvell International Ltd.
> + *
> + * 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/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/delay.h>
> +#include <linux/clk.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/nand.h>
> +#include <linux/mtd/partitions.h>
> +#include <asm/io.h>
> +#include <asm/irq.h>
> +#include <asm/dma.h>
> +
> +#include <asm/arch/pxa-regs.h>
> +#include <asm/arch/pxa3xx_nand.h>
> +
> +#define        CHIP_DELAY_TIMEOUT      (2 * HZ/10)
> +
> +/* registers and bit definitions */
> +#define NDCR           (0x00) /* Control register */
> +#define NDTR0CS0       (0x04) /* Timing Parameter 0 for CS0 */
> +#define NDTR1CS0       (0x0C) /* Timing Parameter 1 for CS0 */
> +#define NDSR           (0x14) /* Status Register */
> +#define NDPCR          (0x18) /* Page Count Register */
> +#define NDBDR0         (0x1C) /* Bad Block Register 0 */
> +#define NDBDR1         (0x20) /* Bad Block Register 1 */
> +#define NDDB           (0x40) /* Data Buffer */
> +#define NDCB0          (0x48) /* Command Buffer0 */
> +#define NDCB1          (0x4C) /* Command Buffer1 */
> +#define NDCB2          (0x50) /* Command Buffer2 */
> +
> +#define NDCR_SPARE_EN          (0x1 << 31)
> +#define NDCR_ECC_EN            (0x1 << 30)
> +#define NDCR_DMA_EN            (0x1 << 29)
> +#define NDCR_ND_RUN            (0x1 << 28)
> +#define NDCR_DWIDTH_C          (0x1 << 27)
> +#define NDCR_DWIDTH_M          (0x1 << 26)
> +#define NDCR_PAGE_SZ           (0x1 << 24)
> +#define NDCR_NCSX              (0x1 << 23)
> +#define NDCR_ND_MODE           (0x3 << 21)
> +#define NDCR_NAND_MODE         (0x0)
> +#define NDCR_CLR_PG_CNT                (0x1 << 20)
> +#define NDCR_CLR_ECC           (0x1 << 19)
> +#define NDCR_RD_ID_CNT_MASK    (0x7 << 16)
> +#define NDCR_RD_ID_CNT(x)      (((x) << 16) & NDCR_RD_ID_CNT_MASK)
> +
> +#define NDCR_RA_START          (0x1 << 15)
> +#define NDCR_PG_PER_BLK                (0x1 << 14)
> +#define NDCR_ND_ARB_EN         (0x1 << 12)
> +
> +#define NDSR_MASK              (0xfff)
> +#define NDSR_RDY               (0x1 << 11)
> +#define NDSR_CS0_PAGED         (0x1 << 10)
> +#define NDSR_CS1_PAGED         (0x1 << 9)
> +#define NDSR_CS0_CMDD          (0x1 << 8)
> +#define NDSR_CS1_CMDD          (0x1 << 7)
> +#define NDSR_CS0_BBD           (0x1 << 6)
> +#define NDSR_CS1_BBD           (0x1 << 5)
> +#define NDSR_DBERR             (0x1 << 4)
> +#define NDSR_SBERR             (0x1 << 3)
> +#define NDSR_WRDREQ            (0x1 << 2)
> +#define NDSR_RDDREQ            (0x1 << 1)
> +#define NDSR_WRCMDREQ          (0x1)
> +
> +#define NDCB0_AUTO_RS          (0x1 << 25)
> +#define NDCB0_CSEL             (0x1 << 24)
> +#define NDCB0_CMD_TYPE_MASK    (0x7 << 21)
> +#define NDCB0_CMD_TYPE(x)      (((x) << 21) & NDCB0_CMD_TYPE_MASK)
> +#define NDCB0_NC               (0x1 << 20)
> +#define NDCB0_DBC              (0x1 << 19)
> +#define NDCB0_ADDR_CYC_MASK    (0x7 << 16)
> +#define NDCB0_ADDR_CYC(x)      (((x) << 16) & NDCB0_ADDR_CYC_MASK)
> +#define NDCB0_CMD2_MASK                (0xff << 8)
> +#define NDCB0_CMD1_MASK                (0xff)
> +#define NDCB0_ADDR_CYC_SHIFT   (16)
> +
> +/* dma-able I/O address for the NAND data and commands */
> +#define NDCB0_DMA_ADDR         (0x43100048)
> +#define NDDB_DMA_ADDR          (0x43100040)
> +
> +/* macros for registers read/write */
> +#define nand_writel(info, off, val)    \
> +       __raw_writel((val), (info)->mmio_base + (off))
> +
> +#define nand_readl(info, off)          \
> +       __raw_readl((info)->mmio_base + (off))
> +
> +/* error code and state */
> +enum {
> +       ERR_NONE        = 0,
> +       ERR_DMABUSERR   = -1,
> +       ERR_SENDCMD     = -2,
> +       ERR_DBERR       = -3,
> +       ERR_BBERR       = -4,
> +       ERR_BUSY        = -5,
> +};
> +
> +enum {
> +       STATE_CMD_SEND = 1,
> +       STATE_CMD_HANDLE,
> +       STATE_DMA_TRANSFER,
> +       STATE_DMA_DONE,
> +       STATE_READY,
> +       STATE_SUSPENDED,
> +       STATE_DATA_TRANSFER,
> +};
> +
> +struct pxa3xx_nand_timing {
> +       unsigned int    tCH;  /* Enable signal hold time */
> +       unsigned int    tCS;  /* Enable signal setup time */
> +       unsigned int    tWH;  /* ND_nWE high duration */
> +       unsigned int    tWP;  /* ND_nWE pulse time */
> +       unsigned int    tRH;  /* ND_nRE high duration */
> +       unsigned int    tRP;  /* ND_nRE pulse width */
> +       unsigned int    tR;   /* ND_nWE high to ND_nRE low for read */
> +       unsigned int    tWHR; /* ND_nWE high to ND_nRE low for status read */
> +       unsigned int    tAR;  /* ND_ALE low to ND_nRE low delay */
> +};
> +
> +struct pxa3xx_nand_cmdset {
> +       uint16_t        read1;
> +       uint16_t        read2;
> +       uint16_t        program;
> +       uint16_t        read_status;
> +       uint16_t        read_id;
> +       uint16_t        erase;
> +       uint16_t        reset;
> +       uint16_t        lock;
> +       uint16_t        unlock;
> +       uint16_t        lock_status;
> +};
> +
> +struct pxa3xx_nand_flash {
> +       struct pxa3xx_nand_timing *timing; /* NAND Flash timing */
> +       struct pxa3xx_nand_cmdset *cmdset;
> +
> +       uint32_t page_per_block;/* Pages per block (PG_PER_BLK) */
> +       uint32_t page_size;     /* Page size in bytes (PAGE_SZ) */
> +       uint32_t flash_width;   /* Width of Flash memory (DWIDTH_M) */
> +       uint32_t dfc_width;     /* Width of flash controller(DWIDTH_C) */
> +       uint32_t num_blocks;    /* Number of physical blocks in Flash */
> +       uint32_t chip_id;
> +
> +       /* NOTE: these are automatically calculated, do not define */
> +       size_t          oob_size;
> +       size_t          read_id_bytes;
> +
> +       unsigned int    col_addr_cycles;
> +       unsigned int    row_addr_cycles;
> +};
> +
> +struct pxa3xx_nand_info {
> +       struct nand_chip        nand_chip;
> +
> +       struct platform_device   *pdev;
> +       struct pxa3xx_nand_flash *flash_info;
> +
> +       struct clk              *clk;
> +       void __iomem            *mmio_base;
> +
> +       unsigned int            buf_start;
> +       unsigned int            buf_count;
> +
> +       /* DMA information */
> +       unsigned char           *data_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 */
> +       unsigned int            state;
> +
> +       int                     use_ecc;        /* use HW ECC ? */
> +       int                     use_dma;        /* use DMA ? */
> +
> +       size_t                  data_size;      /* data size in FIFO */
> +       unsigned int            cur_cmd;
> +       int                     retcode;
> +       struct completion       cmd_complete;
> +
> +       /* generated NDCBx register values */
> +       uint32_t                ndcb0;
> +       uint32_t                ndcb1;
> +       uint32_t                ndcb2;
> +};
> +
> +static int use_dma = 0;
> +module_param(use_dma, bool, 0444);
> +MODULE_PARM_DESC(use_dma, "enable DMA for data transfering to/from NAND HW");
> +
> +static struct pxa3xx_nand_cmdset smallpage_cmdset = {
> +       .read1          = 0x0000,
> +       .read2          = 0x0050,
> +       .program        = 0x1080,
> +       .read_status    = 0x0070,
> +       .read_id        = 0x0090,
> +       .erase          = 0xD060,
> +       .reset          = 0x00FF,
> +       .lock           = 0x002A,
> +       .unlock         = 0x2423,
> +       .lock_status    = 0x007A,
> +};
> +
> +static struct pxa3xx_nand_cmdset largepage_cmdset = {
> +       .read1          = 0x3000,
> +       .read2          = 0x0050,
> +       .program        = 0x1080,
> +       .read_status    = 0x0070,
> +       .read_id        = 0x0090,
> +       .erase          = 0xD060,
> +       .reset          = 0x00FF,
> +       .lock           = 0x002A,
> +       .unlock         = 0x2423,
> +       .lock_status    = 0x007A,
> +};
> +
> +static struct pxa3xx_nand_timing samsung512MbX16_timing = {
> +       .tCH    = 10,
> +       .tCS    = 0,
> +       .tWH    = 20,
> +       .tWP    = 40,
> +       .tRH    = 30,
> +       .tRP    = 40,
> +       .tR     = 11123,
> +       .tWHR   = 110,
> +       .tAR    = 10,
> +};
> +
> +static struct pxa3xx_nand_flash samsung512MbX16 = {
> +       .timing         = &samsung512MbX16_timing,
> +       .cmdset         = &smallpage_cmdset,
> +       .page_per_block = 32,
> +       .page_size      = 512,
> +       .flash_width    = 16,
> +       .dfc_width      = 16,
> +       .num_blocks     = 4096,
> +       .chip_id        = 0x46ec,
> +};
> +
> +static struct pxa3xx_nand_timing micron_timing = {
> +       .tCH    = 10,
> +       .tCS    = 25,
> +       .tWH    = 15,
> +       .tWP    = 25,
> +       .tRH    = 15,
> +       .tRP    = 25,
> +       .tR     = 25000,
> +       .tWHR   = 60,
> +       .tAR    = 10,
> +};
> +
> +static struct pxa3xx_nand_flash micron1GbX8 = {
> +       .timing         = &micron_timing,
> +       .cmdset         = &largepage_cmdset,
> +       .page_per_block = 64,
> +       .page_size      = 2048,
> +       .flash_width    = 8,
> +       .dfc_width      = 8,
> +       .num_blocks     = 1024,
> +       .chip_id        = 0xa12c,
> +};
> +
> +static struct pxa3xx_nand_flash micron1GbX16 = {
> +       .timing         = &micron_timing,
> +       .cmdset         = &largepage_cmdset,
> +       .page_per_block = 64,
> +       .page_size      = 2048,
> +       .flash_width    = 16,
> +       .dfc_width      = 16,
> +       .num_blocks     = 1024,
> +       .chip_id        = 0xb12c,
> +};
> +
> +static struct pxa3xx_nand_flash *builtin_flash_types[] = {
> +       &samsung512MbX16,
> +       &micron1GbX8,
> +       &micron1GbX16,
> +};
> +
> +#define NDTR0_tCH(c)   (min((c), 7) << 19)
> +#define NDTR0_tCS(c)   (min((c), 7) << 16)
> +#define NDTR0_tWH(c)   (min((c), 7) << 11)
> +#define NDTR0_tWP(c)   (min((c), 7) << 8)
> +#define NDTR0_tRH(c)   (min((c), 7) << 3)
> +#define NDTR0_tRP(c)   (min((c), 7) << 0)
> +
> +#define NDTR1_tR(c)    (min((c), 65535) << 16)
> +#define NDTR1_tWHR(c)  (min((c), 15) << 4)
> +#define NDTR1_tAR(c)   (min((c), 15) << 0)
> +
> +/* convert nano-seconds to nand flash controller clock cycles */
> +#define ns2cycle(ns, clk)      (int)(((ns) * (clk / 1000000) / 1000) + 1)
> +
> +static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info,
> +                                  struct pxa3xx_nand_timing *t)
> +{
> +       unsigned long nand_clk = clk_get_rate(info->clk);
> +       uint32_t ndtr0, ndtr1;
> +
> +       ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) |
> +               NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) |
> +               NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) |
> +               NDTR0_tWP(ns2cycle(t->tWP, nand_clk)) |
> +               NDTR0_tRH(ns2cycle(t->tRH, nand_clk)) |
> +               NDTR0_tRP(ns2cycle(t->tRP, nand_clk));
> +
> +       ndtr1 = NDTR1_tR(ns2cycle(t->tR, nand_clk)) |
> +               NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
> +               NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
> +
> +       nand_writel(info, NDTR0CS0, ndtr0);
> +       nand_writel(info, NDTR1CS0, ndtr1);
> +}
> +
> +#define WAIT_EVENT_TIMEOUT     10
> +
> +static int wait_for_event(struct pxa3xx_nand_info *info, uint32_t event)
> +{
> +       int timeout = WAIT_EVENT_TIMEOUT;
> +       uint32_t ndsr;
> +
> +       while (timeout--) {
> +               ndsr = nand_readl(info, NDSR) & NDSR_MASK;
> +               if (ndsr & event) {
> +                       nand_writel(info, NDSR, ndsr);
> +                       return 0;
> +               }
> +               udelay(10);
> +       }
> +
> +       return -ETIMEDOUT;
> +}
> +
> +static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info,
> +                       uint16_t cmd, int column, int page_addr)
> +{
> +       struct pxa3xx_nand_flash *f = info->flash_info;
> +       struct pxa3xx_nand_cmdset *cmdset = f->cmdset;
> +
> +       /* calculate data size */
> +       switch (f->page_size) {
> +       case 2048:
> +               info->data_size = (info->use_ecc) ? 2088 : 2112;
> +               break;
> +       case 512:
> +               info->data_size = (info->use_ecc) ? 520 : 528;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       /* generate values for NDCBx registers */
> +       info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
> +       info->ndcb0 |= NDCB0_ADDR_CYC(f->row_addr_cycles + f->col_addr_cycles);
> +
> +       if (f->col_addr_cycles == 2) {
> +               /* large block, 2 cycles for column address
> +                * row address starts from 3rd cycle
> +                */
> +               info->ndcb1 |= (page_addr << 16) | (column & 0xffff);
> +               if (f->row_addr_cycles == 3)
> +                       info->ndcb2 = (page_addr >> 16) & 0xff;
> +       } else
> +               /* small block, 1 cycles for column address
> +                * row address starts from 2nd cycle
> +                */
> +               info->ndcb1 = (page_addr << 8) | (column & 0xff);
> +
> +       if (cmd == cmdset->program)
> +               info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS;
> +
> +       info->cur_cmd = cmd;
> +       return 0;
> +}
> +
> +static int prepare_erase_cmd(struct pxa3xx_nand_info *info,
> +                       uint16_t cmd, int page_addr)
> +{
> +       info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
> +       info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3);
> +       info->ndcb1 = page_addr;
> +
> +       info->cur_cmd = cmd;
> +       return 0;
> +}
> +
> +static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd)
> +{
> +       struct pxa3xx_nand_cmdset *cmdset = info->flash_info->cmdset;
> +
> +       info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
> +
> +       if (cmd == cmdset->read_id) {
> +               info->ndcb0 |= NDCB0_CMD_TYPE(3);
> +               info->data_size = 8;
> +       } else if (cmd == cmdset->read_status) {
> +               info->ndcb0 |= NDCB0_CMD_TYPE(4);
> +               info->data_size = 8;
> +       } else if (cmd == cmdset->reset || cmd == cmdset->lock ||
> +                  cmd == cmdset->unlock) {
> +               info->ndcb0 |= NDCB0_CMD_TYPE(5);
> +       } else
> +               return -EINVAL;
> +
> +       info->cur_cmd = cmd;
> +       return 0;
> +}
> +
> +static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
> +{
> +       uint32_t ndcr;
> +
> +       ndcr = nand_readl(info, NDCR);
> +       nand_writel(info, NDCR, ndcr & ~int_mask);
> +}
> +
> +static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
> +{
> +       uint32_t ndcr;
> +
> +       ndcr = nand_readl(info, NDCR);
> +       nand_writel(info, NDCR, ndcr | int_mask);
> +}
> +
> +/* NOTE: it is a must to set ND_RUN firstly, then write command buffer
> + * otherwise, it does not work
> + */
> +static int write_cmd(struct pxa3xx_nand_info *info)
> +{
> +       uint32_t ndcr;
> +
> +       /* clear status bits and run */
> +       nand_writel(info, NDSR, NDSR_MASK);
> +
> +       ndcr = info->reg_ndcr;
> +
> +       ndcr |= info->use_ecc ? NDCR_ECC_EN : 0;
> +       ndcr |= info->use_dma ? NDCR_DMA_EN : 0;
> +       ndcr |= NDCR_ND_RUN;
> +
> +       nand_writel(info, NDCR, ndcr);
> +
> +       if (wait_for_event(info, NDSR_WRCMDREQ)) {
> +               printk(KERN_ERR "timed out writing command\n");
> +               return -ETIMEDOUT;
> +       }
> +
> +       nand_writel(info, NDCB0, info->ndcb0);
> +       nand_writel(info, NDCB0, info->ndcb1);
> +       nand_writel(info, NDCB0, info->ndcb2);
> +       return 0;
> +}
> +
> +/* NOTE: {read, write}_fifo_pio() assume the buffer is 4-byte aligned,
> + * and data_size are 4-byte multiples as well
> + */
> +static void read_fifo_pio(struct pxa3xx_nand_info *info)
> +{
> +       uint32_t *buff = (uint32_t *)info->data_buff;
> +       int i, data_size = info->data_size;
> +
> +       BUG_ON((data_size % sizeof(uint32_t)) != 0);
> +
> +       for (i = 0; i < data_size / sizeof(uint32_t); i++)
> +               *buff++ = __raw_readl(info->mmio_base + NDDB);
> +}
> +
> +static void write_fifo_pio(struct pxa3xx_nand_info *info)
> +{
> +       uint32_t *buff = (uint32_t *)info->data_buff;
> +       int i, data_size = info->data_size;
> +
> +       BUG_ON((data_size % sizeof(uint32_t)) != 0);
> +
> +       for (i = 0; i < data_size / sizeof(uint32_t); i++)
> +               __raw_writel(*buff++, info->mmio_base + NDDB);
> +}
> +
> +static int handle_data_pio(struct pxa3xx_nand_info *info)
> +{
> +       struct pxa3xx_nand_cmdset *cmdset = info->flash_info->cmdset;
> +       int ret, timeout = CHIP_DELAY_TIMEOUT;
> +
> +       if (info->cur_cmd == cmdset->program) {
> +               write_fifo_pio(info);
> +
> +               enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);
> +
> +               ret = wait_for_completion_timeout(&info->cmd_complete, timeout);
> +               if (!ret) {
> +                       printk(KERN_ERR "program command time out\n");
> +                       return -1;
> +               }
> +       } else
> +               read_fifo_pio(info);
> +
> +       info->state = STATE_READY;
> +       return 0;
> +}
> +
> +static void setup_data_dma(struct pxa3xx_nand_info *info)
> +{
> +       struct pxa3xx_nand_flash * f = info->flash_info;
> +       struct pxa_dma_desc *desc = info->data_desc;
> +       int dma_len = ALIGN(info->data_size, 32);
> +
> +       desc->ddadr = DDADR_STOP;
> +       desc->dcmd = DCMD_ENDIRQEN | DCMD_WIDTH4 | DCMD_BURST32 | dma_len;
> +
> +       if (info->cur_cmd == f->cmdset->program) {
> +               desc->dsadr = info->data_buff_phys;
> +               desc->dtadr = NDDB_DMA_ADDR;
> +               desc->dcmd |= DCMD_INCSRCADDR | DCMD_FLOWTRG;
> +       } else {
> +               desc->dtadr = info->data_buff_phys;
> +               desc->dsadr = NDDB_DMA_ADDR;
> +               desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC;
> +       }
> +}
> +
> +static void start_data_dma(struct pxa3xx_nand_info *info)
> +{
> +       DRCMR97 = DRCMR_MAPVLD | info->data_dma_ch;
> +       DDADR(info->data_dma_ch) = info->data_desc_addr;
> +       DCSR(info->data_dma_ch) |= DCSR_RUN;
> +}
> +
> +static void pxa3xx_nand_data_dma_irq(int channel, void *data)
> +{
> +       struct pxa3xx_nand_info *info = data;
> +       struct pxa3xx_nand_flash *f = info->flash_info;
> +       uint32_t dcsr, intm;
> +
> +       dcsr = DCSR(channel);
> +       DCSR(channel) = dcsr;
> +
> +       intm = NDSR_CS0_BBD | NDSR_CS0_CMDD;
> +
> +       if (dcsr & DCSR_BUSERR) {
> +               info->retcode = ERR_DMABUSERR;
> +               complete(&info->cmd_complete);
> +       }
> +
> +       if (info->cur_cmd == f->cmdset->program) {
> +               info->state = STATE_DMA_DONE;
> +               enable_int(info, intm);
> +       } else {
> +               info->state = STATE_READY;
> +               complete(&info->cmd_complete);
> +       }
> +}
> +
> +static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
> +{
> +       unsigned int status, event, intm;
> +       struct pxa3xx_nand_info *info = devid;
> +
> +       intm = NDSR_CS0_BBD | NDSR_CS0_CMDD;
> +       event = NDSR_CS0_BBD | NDSR_CS0_CMDD;
> +
> +       status = nand_readl(info, NDSR);
> +
> +       if (status & (NDSR_RDDREQ | NDSR_DBERR)) {
> +               if (status & NDSR_DBERR)
> +                       info->retcode = ERR_DBERR;
> +
> +               disable_int(info, NDSR_RDDREQ | NDSR_DBERR);
> +
> +               if (info->use_dma) {
> +                       info->state = STATE_DMA_TRANSFER;
> +                       start_data_dma(info);
> +               } else {
> +                       info->state = STATE_DATA_TRANSFER;
> +                       complete(&info->cmd_complete);
> +               }
> +       } else if (status & NDSR_WRDREQ) {
> +               disable_int(info, NDSR_WRDREQ);
> +               if (info->use_dma) {
> +                       info->state = STATE_DMA_TRANSFER;
> +                       start_data_dma(info);
> +               } else {
> +                       info->state = STATE_DATA_TRANSFER;
> +                       complete(&info->cmd_complete);
> +               }
> +       } else if (status & event) {
> +               if (status & NDSR_CS0_BBD)
> +                       info->retcode = ERR_BBERR;
> +
> +               disable_int(info, intm);
> +               info->state = STATE_READY;
> +               complete(&info->cmd_complete);
> +       }
> +       nand_writel(info, NDSR, status);
> +       return IRQ_HANDLED;
> +}
> +
> +static int pxa3xx_nand_do_cmd(struct pxa3xx_nand_info *info, uint32_t event)
> +{
> +       uint32_t ndcr;
> +       int ret, timeout = CHIP_DELAY_TIMEOUT;
> +
> +       info->state = STATE_CMD_SEND;
> +
> +       if (write_cmd(info)) {
> +               info->retcode = ERR_SENDCMD;
> +               goto fail_stop;
> +       }
> +
> +       info->state = STATE_CMD_HANDLE;
> +
> +       if (info->use_dma)
> +               setup_data_dma(info);
> +
> +       enable_int(info, event);
> +
> +       ret = wait_for_completion_timeout(&info->cmd_complete, timeout);
> +       if (!ret) {
> +               printk(KERN_ERR "command execution timed out\n");
> +               info->retcode = ERR_SENDCMD;
> +               goto fail_stop;
> +       }
> +
> +       if (info->use_dma == 0 && info->data_size > 0)
> +               if (handle_data_pio(info))
> +                       goto fail_stop;
> +
> +       return 0;
> +
> +fail_stop:
> +       ndcr = nand_readl(info, NDCR);
> +       nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN);
> +       udelay(10);
> +       return -ETIMEDOUT;
> +}
> +
> +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--)
> +               if (*buf++ != 0xff)
> +                       return 0;
> +       return 1;
> +}
> +
> +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_flash * flash_info = info->flash_info;
> +       struct pxa3xx_nand_cmdset *cmdset = flash_info->cmdset;
> +       int ret;
> +
> +       info->ndcb0 = 0;
> +       info->ndcb1 = 0;
> +       info->ndcb2 = 0;
> +       info->use_dma = 0;
> +       info->use_ecc = 0;
> +       info->cur_cmd = -1;
> +       info->data_size = 0;
> +       info->state = STATE_READY;
> +
> +       init_completion(&info->cmd_complete);
> +
> +       switch (command) {
> +       case NAND_CMD_READOOB:
> +               /* disable HW ECC to get all the OOB data */
> +               info->use_ecc = 0;
> +               info->use_dma = use_dma ? 1 : 0;
> +               info->buf_count = mtd->writesize + mtd->oobsize;
> +               info->buf_start = mtd->writesize + column;
> +
> +               if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr))
> +                       break;
> +
> +               pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR);
> +
> +               /* We only are OOB, so if the data has error, does not matter */
> +               if (info->retcode == ERR_DBERR)
> +                       info->retcode = ERR_NONE;
> +               break;
> +
> +       case NAND_CMD_READ0:
> +               info->use_ecc = 1;
> +               info->use_dma = use_dma ? 1 : 0;
> +               info->retcode = ERR_NONE;
> +               info->buf_start = column;
> +               info->buf_count = mtd->writesize + mtd->oobsize;
> +               memset(info->data_buff, 0xFF, info->buf_count);
> +
> +               if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr))
> +                       break;
> +
> +               pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR);
> +
> +               if (info->retcode == ERR_DBERR) {
> +                       /* for blank page (all 0xff), HW will calculate its ECC as
> +                        * 0, which is different from the ECC information within
> +                        * OOB, ignore such double bit errors
> +                        */
> +                       if (is_buf_blank(info->data_buff, mtd->writesize))
> +                               info->retcode = ERR_NONE;
> +               }
> +               break;
> +       case NAND_CMD_SEQIN:
> +               info->buf_start = column;
> +               info->buf_count = mtd->writesize + mtd->oobsize;
> +               memset(info->data_buff, 0xff, info->buf_count);
> +
> +               /* save column/page_addr for next CMD_PAGEPROG */
> +               info->seqin_column = column;
> +               info->seqin_page_addr = page_addr;
> +               break;
> +       case NAND_CMD_PAGEPROG:
> +               info->use_ecc = (info->seqin_column >= mtd->writesize) ? 0 : 1;
> +               info->use_dma = use_dma ? 1 : 0;
> +
> +               if (prepare_read_prog_cmd(info, cmdset->program,
> +                               info->seqin_column, info->seqin_page_addr))
> +                       break;
> +
> +               pxa3xx_nand_do_cmd(info, NDSR_WRDREQ);
> +               break;
> +       case NAND_CMD_ERASE1:
> +               if (prepare_erase_cmd(info, cmdset->erase, page_addr))
> +                       break;
> +
> +               pxa3xx_nand_do_cmd(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);
> +               break;
> +       case NAND_CMD_ERASE2:
> +               break;
> +       case NAND_CMD_READID:
> +               info->use_dma = 0;
> +               info->buf_count = flash_info->read_id_bytes;
> +               info->buf_start = 0;
> +
> +               if (prepare_other_cmd(info, cmdset->read_id))
> +                       break;
> +
> +               pxa3xx_nand_do_cmd(info, NDSR_RDDREQ);
> +               break;
> +       case NAND_CMD_STATUS:
> +               info->use_dma = 0;
> +               info->buf_count = 1;
> +               info->buf_start = 0;
> +               if (prepare_other_cmd(info, cmdset->read_status))
> +                       break;
> +
> +               pxa3xx_nand_do_cmd(info, NDSR_RDDREQ);
> +               break;
> +       case NAND_CMD_RESET:
> +               if (prepare_other_cmd(info, cmdset->reset))
> +                       break;
> +
> +               ret = pxa3xx_nand_do_cmd(info, NDSR_CS0_CMDD);
> +               if (ret == 0) {
> +                       int timeout = 2;
> +                       uint32_t ndcr;
> +
> +                       while (timeout--) {
> +                               if (nand_readl(info, NDSR) & NDSR_RDY)
> +                                       break;
> +                               msleep(10);
> +                       }
> +
> +                       ndcr = nand_readl(info, NDCR);
> +                       nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN);
> +               }
> +               break;
> +       default:
> +               printk(KERN_ERR "non-supported command.\n");
> +               break;
> +       }
> +
> +       if (info->retcode == ERR_DBERR) {
> +               printk(KERN_ERR "double bit error @ page %08x\n", page_addr);
> +               info->retcode = ERR_NONE;
> +       }
> +
> +       if (info->retcode != ERR_NONE)
> +               info->state = STATE_READY;
> +}
> +
> +static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
> +{
> +       struct pxa3xx_nand_info *info = mtd->priv;
> +       char retval = 0xFF;
> +
> +       if (info->buf_start < info->buf_count)
> +               /* Has just send a new command? */
> +               retval = info->data_buff[info->buf_start++];
> +
> +       return retval;
> +}
> +
> +static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)
> +{
> +       struct pxa3xx_nand_info *info = mtd->priv;
> +       u16 retval = 0xFFFF;
> +
> +       if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) {
> +               retval = *((u16 *)(info->data_buff+info->buf_start));
> +               info->buf_start += 2;
> +       }
> +       return retval;
> +}
> +
> +static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
> +{
> +       struct pxa3xx_nand_info *info = mtd->priv;
> +       int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
> +
> +       memcpy(buf, info->data_buff + info->buf_start, real_len);
> +       info->buf_start += real_len;
> +}
> +
> +static void pxa3xx_nand_write_buf(struct mtd_info *mtd,
> +               const uint8_t *buf, int len)
> +{
> +       struct pxa3xx_nand_info *info = mtd->priv;
> +       int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
> +
> +       memcpy(info->data_buff + info->buf_start, buf, real_len);
> +       info->buf_start += real_len;
> +}
> +
> +static int pxa3xx_nand_verify_buf(struct mtd_info *mtd,
> +               const uint8_t *buf, int len)
> +{
> +       return 0;
> +}
> +
> +static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip)
> +{
> +       return;
> +}
> +
> +static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
> +{
> +       struct pxa3xx_nand_info *info = mtd->priv;
> +
> +       /* pxa3xx_nand_send_command has waited for command complete */
> +       if (this->state == FL_WRITING || this->state == FL_ERASING) {
> +               if (info->retcode == ERR_NONE)
> +                       return 0;
> +               else {
> +                       /*
> +                        * any error make it return 0x01 which will tell
> +                        * the caller the erase and write fail
> +                        */
> +                       return 0x01;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static void pxa3xx_nand_ecc_hwctl(struct mtd_info *mtd, int mode)
> +{
> +       return;
> +}
> +
> +static int pxa3xx_nand_ecc_calculate(struct mtd_info *mtd,
> +               const uint8_t *dat, uint8_t *ecc_code)
> +{
> +       return 0;
> +}
> +
> +static int pxa3xx_nand_ecc_correct(struct mtd_info *mtd,
> +               uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc)
> +{
> +       struct pxa3xx_nand_info *info = mtd->priv;
> +       /*
> +        * Any error include ERR_SEND_CMD, ERR_DBERR, ERR_BUSERR, we
> +        * consider it as a ecc error which will tell the caller the
> +        * read fail We have distinguish all the errors, but the
> +        * nand_read_ecc only check this function return value
> +        */
> +       if (info->retcode != ERR_NONE)
> +               return -1;
> +
> +       return 0;
> +}
> +
> +static int dfc_readid(struct pxa3xx_nand_info *info, uint32_t *id)
> +{
> +       struct pxa3xx_nand_flash *f = info->flash_info;
> +       struct pxa3xx_nand_cmdset *cmdset = f->cmdset;
> +       uint32_t ndcr;
> +
> +       info->ndcb0 = 0;
> +       info->ndcb1 = 0;
> +       info->ndcb2 = 0;
> +       info->data_size = 0;
> +
> +       if (prepare_other_cmd(info, cmdset->read_id)) {
> +               printk(KERN_ERR "failed to prepare command\n");
> +               return -EINVAL;
> +       }
> +
> +       /* Send command */
> +       if (write_cmd(info))
> +               goto fail_timeout;
> +
> +       /* Wait for CMDDM(command done successfully) */
> +       if (wait_for_event(info, NDSR_RDDREQ))
> +               goto fail_timeout;
> +
> +       read_fifo_pio(info);
> +       *id = info->data_buff[0] | (info->data_buff[1] << 8);
> +       return 0;
> +
> +fail_timeout:
> +       ndcr = nand_readl(info, NDCR);
> +       nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN);
> +       udelay(10);
> +       return -ETIMEDOUT;
> +}
> +
> +static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
> +                                   struct pxa3xx_nand_flash *f)
> +{
> +       uint32_t ndcr = 0x00000FFF; /* disable all interrupts */
> +
> +       if (f->page_size != 2048 && f->page_size != 512)
> +               return -EINVAL;
> +
> +       if (f->flash_width != 16 && f->flash_width != 8)
> +               return -EINVAL;
> +
> +       /* calculate flash information */
> +       f->oob_size = (f->page_size == 2048) ? 64 : 16;
> +       f->read_id_bytes = (f->page_size == 2048) ? 4 : 2;
> +
> +       /* calculate addressing information */
> +       f->col_addr_cycles = (f->page_size == 2048) ? 2 : 1;
> +
> +       if (f->num_blocks * f->page_per_block > 65536)
> +               f->row_addr_cycles = 3;
> +       else
> +               f->row_addr_cycles = 2;
> +
> +       ndcr |= NDCR_ND_ARB_EN;
> +       ndcr |= (f->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(f->read_id_bytes);
> +       ndcr |= NDCR_SPARE_EN; /* enable spare by default */
> +
> +       info->reg_ndcr = ndcr;
> +
> +       pxa3xx_nand_set_timing(info, f->timing);
> +       info->flash_info = f;
> +       return 0;
> +}
> +
> +static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info)
> +{
> +       struct pxa3xx_nand_flash *f;
> +       uint32_t id;
> +       int i;
> +
> +       for (i = 0; i < ARRAY_SIZE(builtin_flash_types); i++) {
> +
> +               f = builtin_flash_types[i];
> +
> +               if (pxa3xx_nand_config_flash(info, f))
> +                       continue;
> +
> +               if (dfc_readid(info, &id))
> +                       continue;
> +
> +               if (id == f->chip_id)
> +                       return 0;
> +       }
> +
> +       return -ENODEV;
> +}
> +
> +/* the maximum possible buffer size for large page with OOB data
> + * is: 2048 + 64 = 2112 bytes, allocate a page here for both the
> + * data buffer and the DMA descriptor
> + */
> +#define MAX_BUFF_SIZE  PAGE_SIZE
> +
> +static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
> +{
> +       struct platform_device *pdev = info->pdev;
> +       int data_desc_offset = MAX_BUFF_SIZE - sizeof(struct pxa_dma_desc);
> +
> +       if (use_dma == 0) {
> +               info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL);
> +               if (info->data_buff == NULL)
> +                       return -ENOMEM;
> +               return 0;
> +       }
> +
> +       info->data_buff = dma_alloc_coherent(&pdev->dev, MAX_BUFF_SIZE,
> +                               &info->data_buff_phys, GFP_KERNEL);
> +       if (info->data_buff == NULL) {
> +               dev_err(&pdev->dev, "failed to allocate dma buffer\n");
> +               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;
> +
> +       info->data_dma_ch = pxa_request_dma("nand-data", DMA_PRIO_LOW,
> +                               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,
> +                               info->data_buff, info->data_buff_phys);
> +               return info->data_dma_ch;
> +       }
> +
> +       return 0;
> +}
> +
> +static struct nand_ecclayout hw_smallpage_ecclayout = {
> +       .eccbytes = 6,
> +       .eccpos = {8, 9, 10, 11, 12, 13 },
> +       .oobfree = { {2, 6} }
> +};
> +
> +static struct nand_ecclayout hw_largepage_ecclayout = {
> +       .eccbytes = 24,
> +       .eccpos = {
> +               40, 41, 42, 43, 44, 45, 46, 47,
> +               48, 49, 50, 51, 52, 53, 54, 55,
> +               56, 57, 58, 59, 60, 61, 62, 63},
> +       .oobfree = { {2, 38} }
> +};
> +
> +static void pxa3xx_nand_init_mtd(struct mtd_info *mtd,
> +                                struct pxa3xx_nand_info *info)
> +{
> +       struct pxa3xx_nand_flash *f = info->flash_info;
> +       struct nand_chip *this = &info->nand_chip;
> +
> +       this->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16: 0;
> +
> +       this->waitfunc          = pxa3xx_nand_waitfunc;
> +       this->select_chip       = pxa3xx_nand_select_chip;
> +       this->dev_ready         = pxa3xx_nand_dev_ready;
> +       this->cmdfunc           = pxa3xx_nand_cmdfunc;
> +       this->read_word         = pxa3xx_nand_read_word;
> +       this->read_byte         = pxa3xx_nand_read_byte;
> +       this->read_buf          = pxa3xx_nand_read_buf;
> +       this->write_buf         = pxa3xx_nand_write_buf;
> +       this->verify_buf        = pxa3xx_nand_verify_buf;
> +
> +       this->ecc.mode          = NAND_ECC_HW;
> +       this->ecc.hwctl         = pxa3xx_nand_ecc_hwctl;
> +       this->ecc.calculate     = pxa3xx_nand_ecc_calculate;
> +       this->ecc.correct       = pxa3xx_nand_ecc_correct;
> +       this->ecc.size          = f->page_size;
> +
> +       if (f->page_size == 2048)
> +               this->ecc.layout = &hw_largepage_ecclayout;
> +       else
> +               this->ecc.layout = &hw_smallpage_ecclayout;
> +
> +       this->chip_delay= 25;
> +}
> +
> +/* MHN_OBM_V2 is related to BBT in MOBM V2
> + * MHN_OBM_V3 is related to BBT in MOBM V3
> + */
> +enum {
> +       MHN_OBM_NULL = 0,
> +       MHN_OBM_V1,
> +       MHN_OBM_V2,
> +       MHN_OBM_V3,
> +       MHN_OBM_INVAL
> +} MHN_OBM_TYPE;
> +
> +static uint8_t scan_main_bbt_pattern[] = { 'p', 'x', 'a', '1' };
> +static uint8_t scan_mirror_bbt_pattern[] = { '0', 'a', 'x', 'p' };
> +
> +static struct nand_bbt_descr monahans_bbt_main = {
> +       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
> +                       | NAND_BBT_2BIT | NAND_BBT_VERSION,
> +       .veroffs = 6,
> +       .maxblocks = 2,
> +        .offs = 2,
> +        .len = 4,
> +        .pattern = scan_main_bbt_pattern,
> +};
> +
> +static struct nand_bbt_descr monahans_bbt_mirror = {
> +       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
> +                       | NAND_BBT_2BIT | NAND_BBT_VERSION,
> +       .veroffs = 6,
> +       .maxblocks = 2,
> +        .offs = 2,
> +        .len = 4,
> +        .pattern = scan_mirror_bbt_pattern,
> +};
> +
> +/*
> + * The relocation table management is different between MOBM V2 and V3.
> + *
> + * MOBM V2 is applied on chips taped out before MhnLV A0.
> + * MOBM V3 is applied on chips taped out after MhnLV A0. It's also applied
> + * on MhnLV A0.
> + */
> +static int calc_obm_ver(void)
> +{
> +       unsigned int    cpuid;
> +
> +       cpuid = read_cpuid(CPUID_ID);
> +       /* It's not xscale chip. */
> +       if ((cpuid & 0xFFFF0000) != 0x69050000)
> +               return MHN_OBM_INVAL;
> +       /* It's MhnP Ax */
> +       if ((cpuid & 0x0000FFF0) == 0x00006420)
> +               return MHN_OBM_V2;
> +       /* It's MhnP Bx */
> +       if ((cpuid & 0x0000FFF0) == 0x00006820) {
> +               if ((cpuid & 0x0F) <= 6)
> +                       return MHN_OBM_V2;
> +               else
> +                       return MHN_OBM_V3;
> +       }
> +       /* It's MhnL Ax */
> +       if ((cpuid & 0x0000FFF0) == 0x00006880) {
> +               if ((cpuid & 0x0F) == 0)
> +                       return MHN_OBM_V2;
> +               else
> +                       return MHN_OBM_V3;
> +       }
> +       /* It's MhnLV Ax */
> +       if ((cpuid & 0x0000FFF0) == 0x00006890)
> +               return MHN_OBM_V3;
> +       return MHN_OBM_INVAL;
> +}
> +static int pxa3xx_nand_probe(struct platform_device *pdev)
> +{
> +       struct pxa3xx_nand_platform_data *pdata;
> +       struct pxa3xx_nand_info *info;
> +       struct nand_chip *this;
> +       struct mtd_info *mtd;
> +       struct resource *res;
> +       int ret = 0;
> +       int obm;
> +
> +       pdata = pdev->dev.platform_data;
> +
> +       if (pdata == NULL) {
> +               dev_err(&pdev->dev, "no platform data defined\n");
> +               return -ENODEV;
> +       }
> +
> +       mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct pxa3xx_nand_info),
> +                       GFP_KERNEL);
> +       if (mtd == NULL) {
> +               dev_err(&pdev->dev, "failed to allocate memory\n");
> +               return -ENOMEM;
> +        }
> +
> +       info = (struct pxa3xx_nand_info *)(&mtd[1]);
> +       info->pdev = pdev;
> +
> +       this = &info->nand_chip;
> +       mtd->priv = info;
> +
> +       info->clk = clk_get(&pdev->dev, "NANDCLK");
> +       if (IS_ERR(info->clk)) {
> +               dev_err(&pdev->dev, "failed to get nand clock\n");
> +               ret = PTR_ERR(info->clk);
> +               goto free_mtd;
> +       }
> +       clk_enable(info->clk);
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (res == NULL) {
> +               dev_err(&pdev->dev, "no IO memory resource defined\n");
> +               ret = -ENODEV;
> +               goto fail_put_clk;
> +       }
> +       res = request_mem_region(res->start, res->end - res->start + 1,
> +                       pdev->name);
> +       if (res == NULL) {
> +               dev_err(&pdev->dev, "failed to request memory resource\n");
> +               ret = -EBUSY;
> +               goto fail_put_clk;
> +       }
> +       info->mmio_base = ioremap(res->start, res->end - res->start + 1);
> +       if (info->mmio_base == NULL) {
> +               dev_err(&pdev->dev, "ioremap() failed\n");
> +               ret = -ENODEV;
> +               goto fail_free_res;
> +       }
> +       ret = pxa3xx_nand_init_buff(info);
> +       if (ret)
> +               goto fail_free_io;
> +       ret = request_irq(IRQ_NAND, pxa3xx_nand_irq, IRQF_DISABLED,
> +                               pdev->name, info);
> +       if (ret < 0) {
> +               dev_err(&pdev->dev, "failed to request IRQ\n");
> +               goto free_buf;
> +       }
> +       ret = pxa3xx_nand_detect_flash(info);
> +       if (ret) {
> +               dev_err(&pdev->dev, "failed to detect flash\n");
> +               ret = -ENODEV;
> +               goto fail_free_io;
> +       }
> +       pxa3xx_nand_init_mtd(mtd, info);
> +       platform_set_drvdata(pdev, mtd);
> +       if (nand_scan(mtd, 1)) {
> +               printk(KERN_ERR "Nand scan failed\n");
> +               ret = -ENXIO;
> +               goto free_irq;
> +       }
> +
> +       /* There is a potential limitation that no more partition can be
> +        * added between MassStorage and BBT(last block).
> +        *
> +        * The last 127 blocks is reserved for relocation table, they aren't
> +        * statistical data of mtd size and chip size.
> +        *
> +        * BBT partitions contains 4 blocks. Two blocks are used to store
> +        * main descriptor, the other two are used to store mirror descriptor.
> +        */
> +
> +       /* boot loader partition */
> +       obm = calc_obm_ver();
> +       if (obm == MHN_OBM_V3) {
> +               pdata->parts[0].size = 0x60000;
> +       }else{
> +               pdata->parts[0].size = 0x40000;
> +       }
> +
> +       /* kernel partition */
> +       pdata->parts[1].offset = pdata->parts[0].offset + pdata->parts[0].size;
> +
> +       /* rootfs partition */
> +       pdata->parts[2].offset = pdata->parts[1].offset + pdata->parts[1].size;
> +
> +       /* bbt partition */
> +       pdata->parts[pdata->nr_parts - 1].size = (monahans_bbt_main.maxblocks
> +                                       + monahans_bbt_mirror.maxblocks)
> +                                       << this->phys_erase_shift;
> +       pdata->parts[pdata->nr_parts - 1].offset = this->chipsize
> +                                       - pdata->parts[pdata->nr_parts - 1].size;
> +
> +       /* mass storage partition */
> +       pdata->parts[pdata->nr_parts - 2].offset = pdata->parts[pdata->nr_parts - 3].offset
> +                                       + pdata->parts[pdata->nr_parts - 3].size;
> +       pdata->parts[pdata->nr_parts - 2].size = this->chipsize
> +                                       - pdata->parts[pdata->nr_parts - 2].offset
> +                                       - pdata->parts[pdata->nr_parts - 1].size;
> +
> +       return add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts);
> +free_irq:
> +       free_irq(IRQ_NAND, info);
> +free_buf:
> +       pxa_free_dma(info->data_dma_ch);
> +       dma_free_coherent(&pdev->dev, info->data_buff_size,
> +                       info->data_buff, info->data_buff_phys);
> +fail_free_io:
> +       iounmap(info->mmio_base);
> +fail_free_res:
> +       release_mem_region(res->start, res->end - res->start + 1);
> +fail_put_clk:
> +       clk_put(info->clk);
> +free_mtd:
> +       kfree(mtd);
> +       return ret;
> +}
> +
> +static int pxa3xx_nand_remove(struct platform_device *pdev)
> +{
> +       struct mtd_info *mtd = platform_get_drvdata(pdev);
> +       struct pxa3xx_nand_info *info = mtd->priv;
> +
> +       platform_set_drvdata(pdev, NULL);
> +
> +       del_mtd_device(mtd);
> +       del_mtd_partitions(mtd);
> +       free_irq(IRQ_NAND, info);
> +       if (use_dma) {
> +               pxa_free_dma(info->data_dma_ch);
> +               dma_free_writecombine(&pdev->dev, info->data_buff_size,
> +                               info->data_buff, info->data_buff_phys);
> +       } else
> +               kfree(info->data_buff);
> +       kfree(mtd);
> +       return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +       struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev);
> +       struct pxa3xx_nand_info *info = mtd->priv;
> +
> +       if (info->state != STATE_READY) {
> +               printk(KERN_ERR "current state is %d\n", info->state);
> +               return -EAGAIN;
> +       }
> +       info->state = STATE_SUSPENDED;
> +       /*
> +        * The PM code need read the mobm from NAND.
> +        * So the NAND clock can't be stop here.
> +        * The PM code will cover this.
> +        */
> +       return 0;
> +}
> +
> +static int pxa3xx_nand_resume(struct platform_device *pdev)
> +{
> +       struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev);
> +       struct pxa3xx_nand_info *info = mtd->priv;
> +       int status;
> +
> +       if (info->state != STATE_SUSPENDED)
> +               printk(KERN_WARNING "Error State after resume back\n");
> +
> +       info->state = STATE_READY;
> +
> +       clk_disable(info->clk);
> +
> +       status = pxa3xx_nand_config_flash(info, info->flash_info);
> +       if (status) {
> +               dev_err(&pdev->dev, "failed to initialize\n");
> +               return -ENXIO;
> +       }
> +       return 0;
> +}
> +#else
> +#define pxa3xx_nand_suspend    NULL
> +#define pxa3xx_nand_resume     NULL
> +#endif
> +
> +static struct platform_driver pxa3xx_nand_driver = {
> +       .driver = {
> +               .name   = "pxa3xx-nand",
> +       },
> +       .probe          = pxa3xx_nand_probe,
> +       .remove         = pxa3xx_nand_remove,
> +       .suspend        = pxa3xx_nand_suspend,
> +       .resume         = pxa3xx_nand_resume,
> +};
> +
> +static int __init pxa3xx_nand_init(void)
> +{
> +       return platform_driver_register(&pxa3xx_nand_driver);
> +}
> +
> +static void __exit pxa3xx_nand_exit(void)
> +{
> +       platform_driver_unregister(&pxa3xx_nand_driver);
> +}
> +
> +module_init(pxa3xx_nand_init);
> +module_exit(pxa3xx_nand_exit);
> diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h
> index 1bd398d..ff9e85f 100644
> --- a/include/asm-arm/arch-pxa/pxa-regs.h
> +++ b/include/asm-arm/arch-pxa/pxa-regs.h
> @@ -159,6 +159,7 @@
>  #define DRCMR68                __REG(0x40001110)  /* Request to Channel Map Register for Camera FIFO 0 Request */
>  #define DRCMR69                __REG(0x40001114)  /* Request to Channel Map Register for Camera FIFO 1 Request */
>  #define DRCMR70                __REG(0x40001118)  /* Request to Channel Map Register for Camera FIFO 2 Request */
> +#define DRCMR97                __REG(0x40001184)  /* Request to Channel Map Register for NAND interface data transmit & receive Request */
>
>  #define DRCMRRXSADR    DRCMR2
>  #define DRCMRTXSADR    DRCMR3
> diff --git a/include/asm-arm/arch-pxa/pxa3xx_nand.h b/include/asm-arm/arch-pxa/pxa3xx_nand.h
> new file mode 100644
> index 0000000..81a8937
> --- /dev/null
> +++ b/include/asm-arm/arch-pxa/pxa3xx_nand.h
> @@ -0,0 +1,18 @@
> +#ifndef __ASM_ARCH_PXA3XX_NAND_H
> +#define __ASM_ARCH_PXA3XX_NAND_H
> +
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/partitions.h>
> +
> +struct pxa3xx_nand_platform_data {
> +
> +       /* the data flash bus is shared between the Static Memory
> +        * Controller and the Data Flash Controller,  the arbiter
> +        * controls the ownership of the bus
> +        */
> +       int     enable_arbiter;
> +
> +       struct mtd_partition *parts;
> +       unsigned int    nr_parts;
> +};
> +#endif /* __ASM_ARCH_PXA3XX_NAND_H */
> --
> 1.5.3.7
>
>
>



-- 
Cheers
- eric


From matthieu.castet at parrot.com  Tue Jan 22 03:57:07 2008
From: matthieu.castet at parrot.com (Matthieu CASTET)
Date: Tue, 22 Jan 2008 09:57:07 +0100
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080121222952.GC14472@lazybastard.org>
References: <20080117162601.GA6677@lazybastard.org>
	<20080117114353.0bc71dac@zod.rchland.ibm.com>
	<479073D1.5010406@parrot.com>
	<20080118064852.026b0c82@zod.rchland.ibm.com>
	<4790D11E.6060201@parrot.com>
	<20080118115531.2deef9fb@zod.rchland.ibm.com>
	<20080118181744.GA15039@lazybastard.org>
	<4794C107.7070600@parrot.com>
	<20080121212555.GA14472@lazybastard.org>
	<20080121161612.3ca2f093@zod.rchland.ibm.com>
	<20080121222952.GC14472@lazybastard.org>
Message-ID: <4795AFE3.506@parrot.com>

J?rn Engel wrote:
> On Mon, 21 January 2008 16:16:12 -0600, Josh Boyer wrote:
>> Wait... you're writing a flash filesystem that doesn't really deal with
>> bad blocks?
> 
> I never said that.  Like any other new piece of code, logfs has bugs.
> Plain and simple.  And having blocks rot underneith you is something I
> don't have automated tests for, so don't be surprised to find bugs in
> this area.
On mtd->read I have see no checking for EBADMSG or EUCLEAN.
There no call to mtd->block_markbad or mtd->block_isbad (it is only 
called in mtd_find_sb).

So I don't see how this can work on NAND flash.


Good test could be to add bad block simulation to nandsim.
There is some patch  for this 
(http://lists.infradead.org/pipermail/linux-mtd/2006-December/017107.html). 
Note they don't simulate bit-flip on read.


Matthieu


From joern at logfs.org  Tue Jan 22 07:03:02 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Tue, 22 Jan 2008 13:03:02 +0100
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <4795AFE3.506@parrot.com>
References: <479073D1.5010406@parrot.com>
	<20080118064852.026b0c82@zod.rchland.ibm.com>
	<4790D11E.6060201@parrot.com>
	<20080118115531.2deef9fb@zod.rchland.ibm.com>
	<20080118181744.GA15039@lazybastard.org>
	<4794C107.7070600@parrot.com>
	<20080121212555.GA14472@lazybastard.org>
	<20080121161612.3ca2f093@zod.rchland.ibm.com>
	<20080121222952.GC14472@lazybastard.org> <4795AFE3.506@parrot.com>
Message-ID: <20080122120300.GA18884@lazybastard.org>

On Tue, 22 January 2008 09:57:07 +0100, Matthieu CASTET wrote:
>
> On mtd->read I have see no checking for EBADMSG or EUCLEAN.

Correct.  The CRC check will barf when uncorrectable errors are
encountered.  Using -EUCLEAN as a trigger to scrub the blocks would be
useful.

> There no call to mtd->block_markbad or mtd->block_isbad (it is only 
> called in mtd_find_sb).

Used to be there and was removed.  mtd->erase() does the same as
mtd->block_isbad().  Calling both would be redundant and a waste of
time.  And logfs has its own bad block table (bad segment table,
actually), so mtd->block_markbad could only be called to play nice with
others after filesystem gets nuked and the flash reused for something
else.  Not all devices define that method.  For a while I carried a
patch that would add a dummy noop call in add_mtd_device (noop call is
faster than a conditional), but dropped it because it just doesn't
matter enough.

> Good test could be to add bad block simulation to nandsim.
> There is some patch  for this 
> (http://lists.infradead.org/pipermail/linux-mtd/2006-December/017107.html). 
> Note they don't simulate bit-flip on read.

Ramtd can simulate bit-flips as well.  A nice test setup needs a bit
more than that, some way to do random, yet repeatable errors.

J?rn

-- 
ticks = jiffies;
while (ticks == jiffies);
ticks = jiffies;
-- /usr/src/linux/init/main.c


From ricard.wanderlof at axis.com  Tue Jan 22 08:24:56 2008
From: ricard.wanderlof at axis.com (Ricard Wanderlof)
Date: Tue, 22 Jan 2008 14:24:56 +0100 (CET)
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080122120300.GA18884@lazybastard.org>
References: <479073D1.5010406@parrot.com>
	<20080118064852.026b0c82@zod.rchland.ibm.com>
	<4790D11E.6060201@parrot.com>
	<20080118115531.2deef9fb@zod.rchland.ibm.com>
	<20080118181744.GA15039@lazybastard.org> <4794C107.7070600@parrot.com>
	<20080121212555.GA14472@lazybastard.org>
	<20080121161612.3ca2f093@zod.rchland.ibm.com>
	<20080121222952.GC14472@lazybastard.org> <4795AFE3.506@parrot.com>
	<20080122120300.GA18884@lazybastard.org>
Message-ID: <Pine.LNX.4.64.0801221419240.25733@lnxricardw.se.axis.com>


> On Tue, 22 Jan 2008, J?rn Engel wrote:
> 
> > On Tue, 22 January 2008 09:57:07 +0100, Matthieu CASTET wrote:
> >
> ... 
> > There no call to mtd->block_markbad or mtd->block_isbad (it is only 
> > called in mtd_find_sb).
> 
> Used to be there and was removed.  mtd->erase() does the same as
> mtd->block_isbad().

How do you mean? mtd->erase() will not erase a bad block, that is true.

However, while it seems that mtd->erase() can mark a block bad if it 
fails, the fact that a block is eraseble without errors does not imply 
that it is good. I've seen NAND flash blocks which have way passed their 
specified number of max write/erase cycles still be successfully erased 
and subsequently written without errors, but the data retention was lousy 
(blocks started to show bit flips after a few thousand reads).

/Ricard
--
Ricard Wolf Wanderl?f                           ricardw(at)axis.com
Axis Communications AB, Lund, Sweden            www.axis.com
Phone +46 46 272 2016                           Fax +46 46 13 61 30


From rgadams at motorola.com  Tue Jan 22 09:15:29 2008
From: rgadams at motorola.com (Adams Richard-W36112)
Date: Tue, 22 Jan 2008 09:15:29 -0500
Subject: problem with 2k page NAND with squashfs
Message-ID: <A2EC06CB0E393B4C8EB220B286B7083E05897213@ct11exm60.ds.mot.com>

 I have an arm-based embedded system running a 2.6.10 kernel. I'm using
a squashfs file system (read only) on the Flash device. The system was
working fine with a 512 byte page Flash part. I started having problems
when I upgraded to a 2048 byte page Flash part. When I mount the squash
file system, it can successfully find the super block, but squashfs
fails (unable to read inode [5ff3:120]) when it try's to finish the
mount. My suspicions are that with the older kernel (2.6.10) it may not
fully support the larger page devices. Is there an achieve of patches
that are applicable for a 2.6.10 kernel? I tried to look through the
mailing list archive, but without a search tool and not knowing what
month I'm looking for the task became tedious.
 
Rick Adams
(858) 404-3091  -- Motorola Office
(858) 775-1136  -- cell phone


From jwboyer at gmail.com  Tue Jan 22 09:49:10 2008
From: jwboyer at gmail.com (Josh Boyer)
Date: Tue, 22 Jan 2008 08:49:10 -0600
Subject: problem with 2k page NAND with squashfs
In-Reply-To: <A2EC06CB0E393B4C8EB220B286B7083E05897213@ct11exm60.ds.mot.com>
References: <A2EC06CB0E393B4C8EB220B286B7083E05897213@ct11exm60.ds.mot.com>
Message-ID: <20080122084910.2939d94a@weaponx>

On Tue, 22 Jan 2008 09:15:29 -0500
"Adams Richard-W36112" <rgadams at motorola.com> wrote:

>  I have an arm-based embedded system running a 2.6.10 kernel. I'm using
> a squashfs file system (read only) on the Flash device. The system was
> working fine with a 512 byte page Flash part. I started having problems
> when I upgraded to a 2048 byte page Flash part. When I mount the squash
> file system, it can successfully find the super block, but squashfs
> fails (unable to read inode [5ff3:120]) when it try's to finish the
> mount. My suspicions are that with the older kernel (2.6.10) it may not
> fully support the larger page devices. Is there an achieve of patches
> that are applicable for a 2.6.10 kernel? I tried to look through the
> mailing list archive, but without a search tool and not knowing what
> month I'm looking for the task became tedious.

http://linux-mtd.infradead.org/source.html#kernelversions

2.6.10 pre-dates git even, so you are likely stuck doing diffs from
kernel tarballs.

josh


From rgadams at motorola.com  Tue Jan 22 09:57:48 2008
From: rgadams at motorola.com (Adams Richard-W36112)
Date: Tue, 22 Jan 2008 09:57:48 -0500
Subject: problem with 2k page NAND with squashfs
In-Reply-To: <20080122084910.2939d94a@weaponx>
References: <A2EC06CB0E393B4C8EB220B286B7083E05897213@ct11exm60.ds.mot.com>
	<20080122084910.2939d94a@weaponx>
Message-ID: <A2EC06CB0E393B4C8EB220B286B7083E05897220@ct11exm60.ds.mot.com>

> On Tue, 22 Jan 2008 09:15:29 -0500
> "Adams Richard-W36112" <rgadams at motorola.com> wrote:
> 
> >  I have an arm-based embedded system running a 2.6.10 kernel. I'm 
> > using a squashfs file system (read only) on the Flash device. The 
> > system was working fine with a 512 byte page Flash part. I started 
> > having problems when I upgraded to a 2048 byte page Flash 
> part. When I 
> > mount the squash file system, it can successfully find the super 
> > block, but squashfs fails (unable to read inode [5ff3:120]) when it 
> > try's to finish the mount. My suspicions are that with the older 
> > kernel (2.6.10) it may not fully support the larger page 
> devices. Is 
> > there an achieve of patches that are applicable for a 
> 2.6.10 kernel? I 
> > tried to look through the mailing list archive, but without 
> a search 
> > tool and not knowing what month I'm looking for the task 
> became tedious.
> 
> http://linux-mtd.infradead.org/source.html#kernelversions
> 
> 2.6.10 pre-dates git even, so you are likely stuck doing 
> diffs from kernel tarballs.
> 
> josh
> 

Before I went through the effort I wanted to check with the list to see
if anyone knows that there is or isn't an issue with the 2k NAND page
size on this vintage kernel.


From joern at logfs.org  Tue Jan 22 10:05:15 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Tue, 22 Jan 2008 16:05:15 +0100
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <Pine.LNX.4.64.0801221419240.25733@lnxricardw.se.axis.com>
References: <4790D11E.6060201@parrot.com>
	<20080118115531.2deef9fb@zod.rchland.ibm.com>
	<20080118181744.GA15039@lazybastard.org>
	<4794C107.7070600@parrot.com>
	<20080121212555.GA14472@lazybastard.org>
	<20080121161612.3ca2f093@zod.rchland.ibm.com>
	<20080121222952.GC14472@lazybastard.org> <4795AFE3.506@parrot.com>
	<20080122120300.GA18884@lazybastard.org>
	<Pine.LNX.4.64.0801221419240.25733@lnxricardw.se.axis.com>
Message-ID: <20080122150514.GD18884@lazybastard.org>

On Tue, 22 January 2008 14:24:56 +0100, Ricard Wanderlof wrote:
> >On Tue, 22 Jan 2008, J?rn Engel wrote:
> >
> >Used to be there and was removed.  mtd->erase() does the same as
> >mtd->block_isbad().
> 
> How do you mean? mtd->erase() will not erase a bad block, that is true.

Exactly.  The only use logfs has for block_isbad() is to skip bad blocks
in the beginning when looking for the superblock.

> However, while it seems that mtd->erase() can mark a block bad if it 
> fails, the fact that a block is eraseble without errors does not imply 
> that it is good. I've seen NAND flash blocks which have way passed their 
> specified number of max write/erase cycles still be successfully erased 
> and subsequently written without errors, but the data retention was lousy 
> (blocks started to show bit flips after a few thousand reads).

I think we are being silly[1].  The question is not whether logfs
handles bad block (it does), but which particular failure case it
doesn't handle well enough.

- Easy: blocks are initially marked bad, erase returns an error.
  Mklogfs erases the complete device once, any bad blocks get stored in
  the bad segment table.  Segments can span multiple eraseblocks, one
  bad block will spoil the complete segment.

- Impossible: data rots without early warning.
  If the device is that bad, you can either have a RAID or replace the
  device.  Nothing the filesystem could or should do about it.

- Moderate: one block continuously spews -EUCLEAN, then becomes
  terminally bad.
  If those are just random bitflips, garbage collection will move the
  data sooner or later.  Logfs does not force GC to happen soon when
  encountering -EUCLEAN, which it should.  Are correctable errors an
  indication of block going bad in the near future?  If yes, I should do
  something about it.

The list probably goes on and on.  And I am sure that I would miss at
least half the interesting cases if I had to create it on my own.  But
if Matthieu or you or anyone else is willing to compose an extensive
list of such failure cases, I will walk through it and try to handle
them one by one.


[1] Silly in the way politicians are talking about freedom and security.
Everyone agrees that both are valuable goals and any policy can be
justified in the name of one or the other.  Ensures heated talkshow
discussions, but otherwise useless.

J?rn

-- 
The story so far:
In the beginning the Universe was created.  This has made a lot
of people very angry and been widely regarded as a bad move.
-- Douglas Adams


From sakoman at gmail.com  Tue Jan 22 13:28:28 2008
From: sakoman at gmail.com (Steve Sakoman)
Date: Tue, 22 Jan 2008 10:28:28 -0800
Subject: CRC errors at linux boot
Message-ID: <5e088bd90801221028q5f6578d2i70a61b1dc333c03a@mail.gmail.com>

The hardware:

PXA270 @ 600 Mhz
256 Mb Strataflash (P30)

The software:

u-boot 1.20
Linux 2.6.21

The issue:

During boot large numbers of CRC error messages are sent to the
console.  They typically are of the form:

   JFFS2 notice: (213) jffs2_get_inode_nodes: Node header CRC failed
at 0x9199dc. {0080,0080,00800080,00800080}

What I think I know:

 Errors have only shown up on a small subset of motherboards, the rest
work flawlessly
 The issue shows up with both buildroot and OpenEmbedded rootfs images
 Reflashing a new image does not cure the problem
 There is no difference in board revision between working and non-working units
 There are no part mis-loads on the failing boards
 Extensive r/w testing with u-boot shows no issues, only linux accesses show it
 Downgrading the cpu clock to 400Mhz does not cure the problem
 Downgrading ram and flash access timings to the most conservative
values does not cure the problem
 The data pattern in the CRC error message is always the same
 The data pattern seems to suggest that the flash part is stuck in
Read Status Register mode
 In Read Status Register mode this bit pattern indicates: "Device is ready"

I saw an old report of exactly this symptom in this thread:

http://lists.infradead.org/pipermail/linux-mtd/2006-May/015429.html

Does anyone have any ideas on how to resolve this?

Thanks!

Steve


From euromillion11111 at peoplepc.com  Tue Jan 22 13:28:25 2008
From: euromillion11111 at peoplepc.com (euromillion11111 at peoplepc.com)
Date: Tue, 22 Jan 2008 10:28:25 -0800 (GMT-08:00)
Subject: Kontaktieren Sie mich
Message-ID: <29472601.1201026505044.JavaMail.root@mswamui-blood.atl.sa.earthlink.net>

Guten Tag,

Auch wenn dieser Brief Sie sicherlich ?berraschen wird, nehmen Sie sich bitte einen Moment Zeit um ihn zu lesen. Es ist sehr wichtig. Ich bin Steve Morgen und ich arbeite bei einer Finanzhaus in den Niederlanden. Ich habe Ihre Adresse durch den International Web Directory Online gefunden. 

 W?hrend unseres letzten Treffens und ?berpr?fung der Bankkontos hat meine Abteilung ein unt?tiges Konto mit einer riesigen Geldsumme, US$ 6,500,000.00(Sechs Million f?nfhundert tausend US Dollar) gefunden, das einem unseren gestorbenen Kunden geh?rt: Herr Williams aus England. Er ist gestorben und hat keine Beg?nstigten hinterlassen. So dass die Fonds auf seinem Konto unt?tig geblieben sind, ohne jeden 
Anspruch oder Aktivit?t f?r einige Zeit schon.


Wegen unseren Finanzhaus vorschriften kann nur ein Ausl?nder als n?chster Verwandten stehen und deshalb habe ich mich entschlossen Sie zu kontaktieren, um mit Ihnen zusammen zu arbeiten um diese unt?tigen Fonds zu reaktivieren. Und so jede negative Entwicklung oder sogar den endg?ltigen Verlust der Fonds abzuwenden. In Namen meiner Kollegen suchen ich Ihre Erlaubnis als n?chster Verwandte unseres verstorbenen Kunden zu stehen, so dass die Fonds freigestellt und auf ihr Konto ?berwiesen werden k?nnen. 

Sie w?rden zum n?chsten Verwandten des Beg?nstigten werden und die Fonds werden in Ihre Verantwortung freigestellt werden. Wir d?rfen mit ausl?ndischen Kontos nicht arbeiten, das k?nnte in der Zeit der ?berweisung auffallen. Ich arbeite noch bei dieser Finanzhaus, das ist der eigentliche 

Grund, dass ich eine zweite Partei oder Person ben?tige, um mit mir zu arbeiten und Anforderungen als n?chster Verwandte zu schicken und auch um ein Bankkonto bereit zu stellen, oder eines bei einer neuen Bank zu er?ffnen, um die unt?tige Fonds zu erhalten.

Am Ende der Transaktion werden Ihnen 40% Prozent zustehen, zur Seite gelegt und 60% werden f?r meine Kollegen und mich sein.
Was ich von Ihnen verlange ist als n?chster Verwandte des Verstorbenen zu stehen. Ich besitze alle notwendigen Dokumente um die Transaktion erfolgreich zu verwirklichen. Weitere Informationen werden Sie so bald ich Ihre positive Antwort bekomme erhalten. Ich schlage Ihnen vor so bald wie m?glich mir zu antworten. 

Wir haben nicht viel Zeit diese ungl?ckliche Situation zu ?ndern und ich bef?rchte, dass ohne Ihre Hilfe alles verloren gehen wird. Wegen der Vertraulichkeit bitte ich Sie mir auf meine privaten Email Adresse mit folgenden Angaben zu antworten: Vollst?ndiger Name, Adresse, Telefon- und Faxnummer.

In Erwartung Ihrer Antwort, verbleibe ich,

 
mit freundlichen Gruessen,

 
Steve Morgan.
stevemorga8 at yahoo.gr


________________________________________
PeoplePC Online
A better way to Internet
http://www.peoplepc.com


From Bin.Lin at lsi.com  Tue Jan 22 22:03:29 2008
From: Bin.Lin at lsi.com (Lin, Bin (Bin))
Date: Tue, 22 Jan 2008 22:03:29 -0500
Subject: Slow mount of JFFS2 root file system
In-Reply-To: <20080115154831.GB22338@lazybastard.org>
References: <BBF94D674CC54C48B62BD0667061E8490199FA73@PAUMAILU02.ags.agere.com>
	<20080115154831.GB22338@lazybastard.org>
Message-ID: <BBF94D674CC54C48B62BD0667061E84901A07FF3@PAUMAILU02.ags.agere.com>

Hi,

I was able to trace down to the location in the code that causes slow root files system mount. When the code scans through medium, most of unused area in the flash (30M of 60M bytes) is scanned as obsolete nodes:

                if (!(je16_to_cpu(node->nodetype) & JFFS2_NODE_ACCURATE)) {
                        /* Wheee. This is an obsoleted node */
                        D2(printk(KERN_DEBUG "Node at 0x%08x is obsolete. Skipping\n", ofs));
                        DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
                        ofs += PAD(je32_to_cpu(node->totlen));
                        continue;
                } 

It takes very long time to scan through all the obsolete 128 byte nodes.
The question is what causes the unused sectors being marked as obsolete? 

Thanks a lot for your reply.
Ben

-----Original Message-----
From: linux-mtd-bounces at lists.infradead.org [mailto:linux-mtd-bounces at lists.infradead.org] On Behalf Of J?rn Engel
Sent: Tuesday, January 15, 2008 10:49 AM
To: Lin, Bin (Bin)
Cc: linux-mtd at lists.infradead.org
Subject: Re: Slow mount of JFFS2 root file system

On Tue, 15 January 2008 09:22:04 -0500, Lin, Bin (Bin) wrote:
> 
> I have ARM9 systems with JFFS2 root file system. For some reasons, e.g.
> system crash or power failure, when system boots up next time, it 
> takes much longer time than usual to mount jffs2 root file system. It 
> can hang at following message for 3-10 min. Once this happens, the 
> mount will take the same long time in every reboot later on. Even 
> though it take long time to mount root file system, the system can 
> still come up and function well. This problem occurred in less than 
> 10% of boards in the field, but can not be reproduced in the lab. I 
> have been struggling with this is issue for weeks.

What stops you from retrieving one such board from the field?  Should be easy to debug once you have it on your desk.

J?rn

--
Prosperity makes friends, adversity tries them.
-- Publilius Syrus

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/


From iqbal at ti.com  Wed Jan 23 00:57:41 2008
From: iqbal at ti.com (iqbal)
Date: Wed, 23 Jan 2008 11:27:41 +0530 (IST)
Subject: mtd unlock issue
Message-ID: <2351.172.24.190.238.1201067861.squirrel@dbdmail.itg.ti.com>


Hello list,

My flash driver unlocks the device inside the probe function for further
writes/programing, due to this my Watchdog reset is causing the kernel to
panic.

The following patch fixed my problem, but I think the fix is some where in the
cfi driver. This patch reads the first sector and make
the flash into read mode.

     /* Unlock the flash device. */
        if (info->mtd->unlock)
                info->mtd->unlock(info->mtd, 0, info->mtd->size);
+       /* HACK by a forcing a dummy read To reset the partition to readable
+        * TODO: a real fix is by fixing unlock function
+        */
+       if (info->mtd->read) {
+               u_char val;
+               size_t len = sizeof(val);
+               info->mtd->read(info->mtd, 0,len,&len, &val);
+       }


If you are aware of this fix pleae let me know how to proceed further and have
a right fix.
I work on the TI OMAP platforms.

Thanks,

Regards
Iqbal






From ricard.wanderlof at axis.com  Wed Jan 23 04:23:55 2008
From: ricard.wanderlof at axis.com (Ricard Wanderlof)
Date: Wed, 23 Jan 2008 10:23:55 +0100 (CET)
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080122150514.GD18884@lazybastard.org>
References: <4790D11E.6060201@parrot.com>
	<20080118115531.2deef9fb@zod.rchland.ibm.com>
	<20080118181744.GA15039@lazybastard.org> <4794C107.7070600@parrot.com>
	<20080121212555.GA14472@lazybastard.org>
	<20080121161612.3ca2f093@zod.rchland.ibm.com>
	<20080121222952.GC14472@lazybastard.org> <4795AFE3.506@parrot.com>
	<20080122120300.GA18884@lazybastard.org>
	<Pine.LNX.4.64.0801221419240.25733@lnxricardw.se.axis.com>
	<20080122150514.GD18884@lazybastard.org>
Message-ID: <Pine.LNX.4.64.0801231014540.25733@lnxricardw.se.axis.com>


On Tue, 22 Jan 2008, J?rn Engel wrote:

> - Moderate: one block continuously spews -EUCLEAN, then becomes
>  terminally bad.
>  If those are just random bitflips, garbage collection will move the
>  data sooner or later.  Logfs does not force GC to happen soon when
>  encountering -EUCLEAN, which it should.  Are correctable errors an
>  indication of block going bad in the near future?  If yes, I should do
>  something about it.

I would say that correctable errors occurring "soon" after writing are an 
indication that the block is going bad. My experience has been that 
extensive reading can cause bitflips (and it probably happens over time 
too), but that for fresh blocks, billions of read operations need to be 
done before a bit flips. For blocks that are nearing their best before 
date, a couple of hundred thousand reads can cause a bit to flip. So if I 
was implementing some sort of 'when is this block considered 
bad'-algorithm, I'd try to keep tabs on how often the block has been 
(read-) accessed in relation to when it was last writen. If this number is 
"low", the block should be considered bad and not used again.

I'm also think that when (if) logfs decides a block is bad, it should mark 
it bad using mtd->block_markbad(). That way, if the flash is rewritten by 
something else than logfs (say during a firmware upgrade), bad blocks can 
be handled in a consistent and startad way.

>The list probably goes on and on.  And I am sure that I would miss at
>least half the interesting cases if I had to create it on my own.  But
>if Matthieu or you or anyone else is willing to compose an extensive
>list of such failure cases, I will walk through it and try to handle
>them one by one.

We ran some tests here on a particular flash chip type to try and 
determine at least some of the failure modes that are related to block 
wear (due to write/erase) and bit decay (due to reading). The end result 
was basically what I tried to describe above, but I can go into more 
detail if you're interested.

/Ricard


From ricard.wanderlof at axis.com  Wed Jan 23 04:27:23 2008
From: ricard.wanderlof at axis.com (Ricard Wanderlof)
Date: Wed, 23 Jan 2008 10:27:23 +0100 (CET)
Subject: problem with 2k page NAND with squashfs
In-Reply-To: <A2EC06CB0E393B4C8EB220B286B7083E05897220@ct11exm60.ds.mot.com>
References: <A2EC06CB0E393B4C8EB220B286B7083E05897213@ct11exm60.ds.mot.com>
	<20080122084910.2939d94a@weaponx>
	<A2EC06CB0E393B4C8EB220B286B7083E05897220@ct11exm60.ds.mot.com>
Message-ID: <Pine.LNX.4.64.0801231024270.25733@lnxricardw.se.axis.com>


On Tue, 22 Jan 2008, Adams Richard-W36112 wrote:

>> On Tue, 22 Jan 2008 09:15:29 -0500
>> "Adams Richard-W36112" <rgadams at motorola.com> wrote:
>>
>>>  I have an arm-based embedded system running a 2.6.10 kernel. I'm
> ...
> Before I went through the effort I wanted to check with the list to see
> if anyone knows that there is or isn't an issue with the 2k NAND page
> size on this vintage kernel.

You could check in drivers/mtd/nand/nand_ids.c and see if your flash chip, 
or indeed any chip with that page size is listed there. Even if it is, 
there could still be a bug of course.

I seem to remember some kernel of similar vintage failing with large-page 
flash chips because the driver tried to kmalloc a buffer the size of a 
block, which failed for chips with 128 KiB blocks, because of limitations 
of the amount of memory that could allocated in one go with kmalloc.

/Ricard
--
Ricard Wolf Wanderl?f                           ricardw(at)axis.com
Axis Communications AB, Lund, Sweden            www.axis.com
Phone +46 46 272 2016                           Fax +46 46 13 61 30


From joern at logfs.org  Wed Jan 23 05:19:15 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Wed, 23 Jan 2008 11:19:15 +0100
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <Pine.LNX.4.64.0801231014540.25733@lnxricardw.se.axis.com>
References: <20080118181744.GA15039@lazybastard.org>
	<4794C107.7070600@parrot.com>
	<20080121212555.GA14472@lazybastard.org>
	<20080121161612.3ca2f093@zod.rchland.ibm.com>
	<20080121222952.GC14472@lazybastard.org> <4795AFE3.506@parrot.com>
	<20080122120300.GA18884@lazybastard.org>
	<Pine.LNX.4.64.0801221419240.25733@lnxricardw.se.axis.com>
	<20080122150514.GD18884@lazybastard.org>
	<Pine.LNX.4.64.0801231014540.25733@lnxricardw.se.axis.com>
Message-ID: <20080123101915.GA24953@lazybastard.org>

On Wed, 23 January 2008 10:23:55 +0100, Ricard Wanderlof wrote:
> On Tue, 22 Jan 2008, J?rn Engel wrote:
> 
> >- Moderate: one block continuously spews -EUCLEAN, then becomes
> > terminally bad.
> > If those are just random bitflips, garbage collection will move the
> > data sooner or later.  Logfs does not force GC to happen soon when
> > encountering -EUCLEAN, which it should.  Are correctable errors an
> > indication of block going bad in the near future?  If yes, I should do
> > something about it.
> 
> I would say that correctable errors occurring "soon" after writing are an 
> indication that the block is going bad. My experience has been that 
> extensive reading can cause bitflips (and it probably happens over time 
> too), but that for fresh blocks, billions of read operations need to be 
> done before a bit flips. For blocks that are nearing their best before 
> date, a couple of hundred thousand reads can cause a bit to flip. So if I 
> was implementing some sort of 'when is this block considered 
> bad'-algorithm, I'd try to keep tabs on how often the block has been 
> (read-) accessed in relation to when it was last writen. If this number is 
> "low", the block should be considered bad and not used again.

That sounds like an impossible strategy.  Causing a write for every read
will significantly increase write pressure, thereby reduce flash
lifetime, reduce performance etc.

What would be possible was a counter for soft/hard errors per physical
block.  On soft error, move data elsewhere and reuse the block, but
increment the error counter.  If the counter increases beyond 17 (or any
other random number), mark the block as bad.  Limit can be an mkfs
option.

> I'm also think that when (if) logfs decides a block is bad, it should mark 
> it bad using mtd->block_markbad(). That way, if the flash is rewritten by 
> something else than logfs (say during a firmware upgrade), bad blocks can 
> be handled in a consistent and startad way.

Maybe I should revive the old patch then.  I don't think it matters much
either way.

> We ran some tests here on a particular flash chip type to try and 
> determine at least some of the failure modes that are related to block 
> wear (due to write/erase) and bit decay (due to reading). The end result 
> was basically what I tried to describe above, but I can go into more 
> detail if you're interested.

I do remember your mail describing the test.  One of the interesting
conclusions is that even awefully worn out block is still good enough to
store short-lived information.  It appears to be a surprisingly robust
strategy to have a high wear-out, as long as you keep the wear
constantly high and replace block contents at a high rate.

J?rn

-- 
You can't tell where a program is going to spend its time. Bottlenecks
occur in surprising places, so don't try to second guess and put in a
speed hack until you've proven that's where the bottleneck is.
-- Rob Pike


From ricard.wanderlof at axis.com  Wed Jan 23 05:41:14 2008
From: ricard.wanderlof at axis.com (Ricard Wanderlof)
Date: Wed, 23 Jan 2008 11:41:14 +0100 (CET)
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080123101915.GA24953@lazybastard.org>
References: <20080118181744.GA15039@lazybastard.org>
	<4794C107.7070600@parrot.com>
	<20080121212555.GA14472@lazybastard.org>
	<20080121161612.3ca2f093@zod.rchland.ibm.com>
	<20080121222952.GC14472@lazybastard.org> <4795AFE3.506@parrot.com>
	<20080122120300.GA18884@lazybastard.org>
	<Pine.LNX.4.64.0801221419240.25733@lnxricardw.se.axis.com>
	<20080122150514.GD18884@lazybastard.org>
	<Pine.LNX.4.64.0801231014540.25733@lnxricardw.se.axis.com>
	<20080123101915.GA24953@lazybastard.org>
Message-ID: <Pine.LNX.4.64.0801231132210.25733@lnxricardw.se.axis.com>


On Wed, 23 Jan 2008, J?rn Engel wrote:

>> I would say that correctable errors occurring "soon" after writing are an
>> indication that the block is going bad. My experience has been that
>> extensive reading can cause bitflips (and it probably happens over time
>> too), but that for fresh blocks, billions of read operations need to be
>> done before a bit flips. For blocks that are nearing their best before
>> date, a couple of hundred thousand reads can cause a bit to flip. So if I
>> was implementing some sort of 'when is this block considered
>> bad'-algorithm, I'd try to keep tabs on how often the block has been
>> (read-) accessed in relation to when it was last writen. If this number is
>> "low", the block should be considered bad and not used again.
>
> That sounds like an impossible strategy.  Causing a write for every read
> will significantly increase write pressure, thereby reduce flash
> lifetime, reduce performance etc.
>
> What would be possible was a counter for soft/hard errors per physical
> block.  On soft error, move data elsewhere and reuse the block, but
> increment the error counter.  If the counter increases beyond 17 (or any
> other random number), mark the block as bad.  Limit can be an mkfs
> option.

Sorry, I didn't express myself clearly. I should have said '...keep tabs 
on how _many_times_ the block has been read accessed in relation to when 
it was last written.' If a page has been read, say, 100 000 times since it 
was last written, and starts to show bit flips, it is a sign that the 
block is wearing out. If it has been read, say, 100 000 000 times since it 
was written and starts showing bit flips, it's probably sufficient just to 
do a garbage collect and rewrite the data (in the same block or 
elsewhere).

The algorithm you suggest also sounds reasonable. Repeatedly occurring bit 
flips (-EUCLEAN) are an indication that the block is wearing out. Probably 
more efficient than logging the number of read accesses somewhere.

One problem may be what to do when the system is powered down. If we don't 
store the error counters in the flash (or some other non-volatile place), 
then each time the system is powered up, all the error counters will be 
reset.

>> We ran some tests here on a particular flash chip type to try and
>> determine at least some of the failure modes that are related to block
>> wear (due to write/erase) and bit decay (due to reading). The end result
>> was basically what I tried to describe above, but I can go into more
>> detail if you're interested.
>
> I do remember your mail describing the test.  One of the interesting
> conclusions is that even awefully worn out block is still good enough to
> store short-lived information.  It appears to be a surprisingly robust
> strategy to have a high wear-out, as long as you keep the wear
> constantly high and replace block contents at a high rate.

You're probably right, but I'm not sure I understand what you mean.

/Ricard
--
Ricard Wolf Wanderl?f                           ricardw(at)axis.com
Axis Communications AB, Lund, Sweden            www.axis.com
Phone +46 46 272 2016                           Fax +46 46 13 61 30


From joern at logfs.org  Wed Jan 23 05:57:13 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Wed, 23 Jan 2008 11:57:13 +0100
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <Pine.LNX.4.64.0801231132210.25733@lnxricardw.se.axis.com>
References: <20080121212555.GA14472@lazybastard.org>
	<20080121161612.3ca2f093@zod.rchland.ibm.com>
	<20080121222952.GC14472@lazybastard.org> <4795AFE3.506@parrot.com>
	<20080122120300.GA18884@lazybastard.org>
	<Pine.LNX.4.64.0801221419240.25733@lnxricardw.se.axis.com>
	<20080122150514.GD18884@lazybastard.org>
	<Pine.LNX.4.64.0801231014540.25733@lnxricardw.se.axis.com>
	<20080123101915.GA24953@lazybastard.org>
	<Pine.LNX.4.64.0801231132210.25733@lnxricardw.se.axis.com>
Message-ID: <20080123105713.GC24953@lazybastard.org>

On Wed, 23 January 2008 11:41:14 +0100, Ricard Wanderlof wrote:
> 
> One problem may be what to do when the system is powered down. If we don't 
> store the error counters in the flash (or some other non-volatile place), 
> then each time the system is powered up, all the error counters will be 
> reset.

Exactly.  If the information we need to detect problems is not stored in
the filesystem, it is useless.  Maybe it would work for a very
specialized system to keep that information in DRAM or NVRAM, but in
general it will get lost.

As a matter of principle logfs does not do any special things for special
systems.  If you have a nice optimization, it has to work for everyone.
If it doesn't, your systems behaves differently from everyone else's
systems.  So whatever bugs you have cannot be reproduced by anyone else.

For example, when the system crashes, some data may get written that
isn't accounted for in the journal.  On reboot/remount that gets
detected and the wasted space is skipped.  Writes continue beyond it.
On hard disks or consumer flash media, it is legal to rewrite the same
location without erase.  But logfs still skips that space and is
deliberately inefficient.

> >I do remember your mail describing the test.  One of the interesting
> >conclusions is that even awefully worn out block is still good enough to
> >store short-lived information.  It appears to be a surprisingly robust
> >strategy to have a high wear-out, as long as you keep the wear
> >constantly high and replace block contents at a high rate.
> 
> You're probably right, but I'm not sure I understand what you mean.

High wearout means short time between two writes.  Which also means few
reads between two writes.

As long as the write rate (wear rate) remains roughly constant, high
wear doesn't seem to cause any problems.  The block's ability to retain
information degrades, but that doesn't matter because it doesn't have to
retain the information for a long time.

J?rn

-- 
Victory in war is not repetitious.
-- Sun Tzu


From ricard.wanderlof at axis.com  Wed Jan 23 06:57:09 2008
From: ricard.wanderlof at axis.com (Ricard Wanderlof)
Date: Wed, 23 Jan 2008 12:57:09 +0100 (CET)
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080123105713.GC24953@lazybastard.org>
References: <20080121212555.GA14472@lazybastard.org>
	<20080121161612.3ca2f093@zod.rchland.ibm.com>
	<20080121222952.GC14472@lazybastard.org>
	<4795AFE3.506@parrot.com> <20080122120300.GA18884@lazybastard.org>
	<Pine.LNX.4.64.0801221419240.25733@lnxricardw.se.axis.com>
	<20080122150514.GD18884@lazybastard.org>
	<Pine.LNX.4.64.0801231014540.25733@lnxricardw.se.axis.com>
	<20080123101915.GA24953@lazybastard.org>
	<Pine.LNX.4.64.0801231132210.25733@lnxricardw.se.axis.com>
	<20080123105713.GC24953@lazybastard.org>
Message-ID: <Pine.LNX.4.64.0801231248400.25733@lnxricardw.se.axis.com>


On Wed, 23 Jan 2008, J?rn Engel wrote:

>> One problem may be what to do when the system is powered down. If we don't
>> store the error counters in the flash (or some other non-volatile place),
>> then each time the system is powered up, all the error counters will be
>> reset.
>
> Exactly.  If the information we need to detect problems is not stored in
> the filesystem, it is useless.  Maybe it would work for a very
> specialized system to keep that information in DRAM or NVRAM, but in
> general it will get lost.
>
> As a matter of principle logfs does not do any special things for special
> systems.  If you have a nice optimization, it has to work for everyone.
> If it doesn't, your systems behaves differently from everyone else's
> systems.  So whatever bugs you have cannot be reproduced by anyone else.

Very true.

Perhaps it's possible to devise something that at least accomplishes part 
of the goal. Such as when writing a new block, also write some statistical 
information such as the number of read accesses since the previous write 
(or power up), or the reason for writing (new data, gc because of 
bitflips, ...) and a write counter. Something of that nature.

> High wearout means short time between two writes.  Which also means few
> reads between two writes.
>
> As long as the write rate (wear rate) remains roughly constant, high
> wear doesn't seem to cause any problems.  The block's ability to retain
> information degrades, but that doesn't matter because it doesn't have to
> retain the information for a long time.

I'd be a bit wary of this with NAND chips some of which have a 100 000 
maximum erase/write cycle specification, though. And I think that 
especially when nearing the maximum value and going beyond it, that there 
is some bit decay occurring over time and not just from reading.

On the other hand, with 100 000 write cycles total, and assuming a product 
lifetime of 3 years, we end up with over 90 permitted write/erase cycles 
per day. Depending on the situation, it might be quite ok to take 
advantage over this.

/Ricard
--
Ricard Wolf Wanderl?f                           ricardw(at)axis.com
Axis Communications AB, Lund, Sweden            www.axis.com
Phone +46 46 272 2016                           Fax +46 46 13 61 30


From joern at logfs.org  Wed Jan 23 08:01:55 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Wed, 23 Jan 2008 14:01:55 +0100
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <Pine.LNX.4.64.0801231248400.25733@lnxricardw.se.axis.com>
References: <20080121222952.GC14472@lazybastard.org> <4795AFE3.506@parrot.com>
	<20080122120300.GA18884@lazybastard.org>
	<Pine.LNX.4.64.0801221419240.25733@lnxricardw.se.axis.com>
	<20080122150514.GD18884@lazybastard.org>
	<Pine.LNX.4.64.0801231014540.25733@lnxricardw.se.axis.com>
	<20080123101915.GA24953@lazybastard.org>
	<Pine.LNX.4.64.0801231132210.25733@lnxricardw.se.axis.com>
	<20080123105713.GC24953@lazybastard.org>
	<Pine.LNX.4.64.0801231248400.25733@lnxricardw.se.axis.com>
Message-ID: <20080123130144.GD24953@lazybastard.org>

On Wed, 23 January 2008 12:57:09 +0100, Ricard Wanderlof wrote:
> 
> Perhaps it's possible to devise something that at least accomplishes part 
> of the goal. Such as when writing a new block, also write some statistical 
> information such as the number of read accesses since the previous write 
> (or power up), or the reason for writing (new data, gc because of 
> bitflips, ...) and a write counter. Something of that nature.

I'm still fairly unconvinced about the read accounting.  We could do
something purely stochastic like accounting _every_ read, but just with
a probability of, say, 1:100,000.  That would still, within statistical
jitter, behave the same for everyone.  But once we depend on the average
mount time of systems, I'm quite unhappy with the solution.

Also, logfs stores a very limited amount of data for each segment (read:
eraseblock).  Currently this is just the erase count, used for wear
leveling and the segment number.  The latter can be used to detect
blocks being moved around by "something", be it an image flasher,
bootloader, FTL or whatever.  There are still 16 bytes of padding in the
structure, so we could add an error counter without breaking the format.

> I'd be a bit wary of this with NAND chips some of which have a 100 000 
> maximum erase/write cycle specification, though. And I think that 
> especially when nearing the maximum value and going beyond it, that there 
> is some bit decay occurring over time and not just from reading.

It doesn't really matter whether the data degrades from a number of
reads or from time passing.  With a constantly high write rate, there is
less time for degradations then with a low write rate.

Problematic would be to have a high write rate for a while, then a very
low write rate that allows data to rot for a long time.  And also this
depends on your numbers being representative for every flash chip. ;)

J?rn

-- 
The only real mistake is the one from which we learn nothing.
-- John Powell


From ricard.wanderlof at axis.com  Wed Jan 23 08:16:12 2008
From: ricard.wanderlof at axis.com (Ricard Wanderlof)
Date: Wed, 23 Jan 2008 14:16:12 +0100 (CET)
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080123130144.GD24953@lazybastard.org>
References: <20080121222952.GC14472@lazybastard.org> <4795AFE3.506@parrot.com>
	<20080122120300.GA18884@lazybastard.org>
	<Pine.LNX.4.64.0801221419240.25733@lnxricardw.se.axis.com>
	<20080122150514.GD18884@lazybastard.org>
	<Pine.LNX.4.64.0801231014540.25733@lnxricardw.se.axis.com>
	<20080123101915.GA24953@lazybastard.org>
	<Pine.LNX.4.64.0801231132210.25733@lnxricardw.se.axis.com>
	<20080123105713.GC24953@lazybastard.org>
	<Pine.LNX.4.64.0801231248400.25733@lnxricardw.se.axis.com>
	<20080123130144.GD24953@lazybastard.org>
Message-ID: <Pine.LNX.4.64.0801231410410.25733@lnxricardw.se.axis.com>


On Wed, 23 Jan 2008, J?rn Engel wrote:

> On Wed, 23 January 2008 12:57:09 +0100, Ricard Wanderlof wrote:
>>
>> Perhaps it's possible to devise something that at least accomplishes part
>> of the goal. Such as when writing a new block, also write some statistical
>> information such as the number of read accesses since the previous write
>> (or power up), or the reason for writing (new data, gc because of
>> bitflips, ...) and a write counter. Something of that nature.
>
> I'm still fairly unconvinced about the read accounting.  We could do
> something purely stochastic like accounting _every_ read, but just with
> a probability of, say, 1:100,000.  That would still, within statistical
> jitter, behave the same for everyone.  But once we depend on the average
> mount time of systems, I'm quite unhappy with the solution.

I think you are right. An error counter should be sufficient to get enough 
statistics to determine if a block has begun to go bad.

>> I'd be a bit wary of this with NAND chips some of which have a 100 000
>> maximum erase/write cycle specification, though. And I think that
>> especially when nearing the maximum value and going beyond it, that there
>> is some bit decay occurring over time and not just from reading.
>
> It doesn't really matter whether the data degrades from a number of
> reads or from time passing.  With a constantly high write rate, there is
> less time for degradations then with a low write rate.

If we have a system that is only used (= powered on) rarely, then any 
degradation from time passing could become significant.

> Problematic would be to have a high write rate for a while, then a very
> low write rate that allows data to rot for a long time.  And also this
> depends on your numbers being representative for every flash chip. ;)

Yes. And the latter is very true. Our tests were only of a certain chip 
type from a certain manufacturer, and of course other chips might behave 
differently.

The only input I have got from chip manufacturers regarding this issue is 
that with inreasing bit densities and decreasing bit cell sizes in the 
future, things like the probability of random bit flips are likely to 
increase. (Somewhere there is a limit when the amount of error correction 
needed to handle this things grows too large to make the chip practically 
useful; say 10 error correction bits per stored bit or whatever).

/Ricard
--
Ricard Wolf Wanderl?f                           ricardw(at)axis.com
Axis Communications AB, Lund, Sweden            www.axis.com
Phone +46 46 272 2016                           Fax +46 46 13 61 30


From joern at logfs.org  Wed Jan 23 09:06:39 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Wed, 23 Jan 2008 15:06:39 +0100
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <Pine.LNX.4.64.0801231410410.25733@lnxricardw.se.axis.com>
References: <20080122120300.GA18884@lazybastard.org>
	<Pine.LNX.4.64.0801221419240.25733@lnxricardw.se.axis.com>
	<20080122150514.GD18884@lazybastard.org>
	<Pine.LNX.4.64.0801231014540.25733@lnxricardw.se.axis.com>
	<20080123101915.GA24953@lazybastard.org>
	<Pine.LNX.4.64.0801231132210.25733@lnxricardw.se.axis.com>
	<20080123105713.GC24953@lazybastard.org>
	<Pine.LNX.4.64.0801231248400.25733@lnxricardw.se.axis.com>
	<20080123130144.GD24953@lazybastard.org>
	<Pine.LNX.4.64.0801231410410.25733@lnxricardw.se.axis.com>
Message-ID: <20080123140639.GE24953@lazybastard.org>

On Wed, 23 January 2008 14:16:12 +0100, Ricard Wanderlof wrote:
> >
> >It doesn't really matter whether the data degrades from a number of
> >reads or from time passing.  With a constantly high write rate, there is
> >less time for degradations then with a low write rate.
> 
> If we have a system that is only used (= powered on) rarely, then any 
> degradation from time passing could become significant.

In that case the write rate wouldn't be _constantly_ high. ;)

> The only input I have got from chip manufacturers regarding this issue is 
> that with inreasing bit densities and decreasing bit cell sizes in the 
> future, things like the probability of random bit flips are likely to 
> increase. (Somewhere there is a limit when the amount of error correction 
> needed to handle this things grows too large to make the chip practically 
> useful; say 10 error correction bits per stored bit or whatever).

If error rates increase, device drivers have to do stronger error
correction.  Quality after error correction has been done should stay
roughly the same.

J?rn

-- 
The cost of changing business rules is much more expensive for software
than for a secretaty.
-- unknown


From ricard.wanderlof at axis.com  Wed Jan 23 09:25:03 2008
From: ricard.wanderlof at axis.com (Ricard Wanderlof)
Date: Wed, 23 Jan 2008 15:25:03 +0100 (CET)
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080123140639.GE24953@lazybastard.org>
References: <20080122120300.GA18884@lazybastard.org>
	<Pine.LNX.4.64.0801221419240.25733@lnxricardw.se.axis.com>
	<20080122150514.GD18884@lazybastard.org>
	<Pine.LNX.4.64.0801231014540.25733@lnxricardw.se.axis.com>
	<20080123101915.GA24953@lazybastard.org>
	<Pine.LNX.4.64.0801231132210.25733@lnxricardw.se.axis.com>
	<20080123105713.GC24953@lazybastard.org>
	<Pine.LNX.4.64.0801231248400.25733@lnxricardw.se.axis.com>
	<20080123130144.GD24953@lazybastard.org>
	<Pine.LNX.4.64.0801231410410.25733@lnxricardw.se.axis.com>
	<20080123140639.GE24953@lazybastard.org>
Message-ID: <Pine.LNX.4.64.0801231517520.15553@lnxricardw.se.axis.com>


On Wed, 23 Jan 2008, J?rn Engel wrote:

>> The only input I have got from chip manufacturers regarding this issue is
>> that with inreasing bit densities and decreasing bit cell sizes in the
>> future, things like the probability of random bit flips are likely to
>> increase. (Somewhere there is a limit when the amount of error correction
>> needed to handle this things grows too large to make the chip practically
>> useful; say 10 error correction bits per stored bit or whatever).
>
> If error rates increase, device drivers have to do stronger error
> correction.  Quality after error correction has been done should stay
> roughly the same.

Yes, true, the first step is to increase the error correction capabilites, 
but there comes a point when there are so many error correction bits 
required per data bit that there is no point of increasing the memory 
size.

Today we have 3 ECC bytes per 256 data bytes in an ordinary nand flash. If 
geometries decrease we might at some point need, say 128 ECC bytes, and 
further down the line perhaps even more ECC bytes than data bytes. It then 
eventually comes to a point of diminishing returns; if the geometries are 
decreased and error rates go up, the increase in number ECC bits might be 
more than the gain in number of data bits. This is far down the line, and 
partly speculative I agree.

/Ricard
--
Ricard Wolf Wanderl?f                           ricardw(at)axis.com
Axis Communications AB, Lund, Sweden            www.axis.com
Phone +46 46 272 2016                           Fax +46 46 13 61 30


From justin_treon at yahoo.com  Wed Jan 23 12:28:13 2008
From: justin_treon at yahoo.com (Justin Treon)
Date: Wed, 23 Jan 2008 09:28:13 -0800 (PST)
Subject: Adding a function pointer to mtd_info struct
Message-ID: <63159.87126.qm@web43145.mail.sp1.yahoo.com>

I am trying to add some new features in my kernel to cfi_cmd_0001.c for a test chip.
 I added a new field to the mtd_info struct in mtd.h and inserted the function
pointer into the mtd->overwrite field I added in cfi_cmd_0001.c, but when I try to
use mtd->overwrite in mtdblock.c the pointer is set to NULL.  

In the mtd_info struct in include/mtd/mtd.h I addded:
	int (*overwrite) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
const u_char *buf);

In cfi_cmd_0001.c I added:
	mtd->overwrite = cfi_intelext_overwrite_buffers;

What file or field do I need to modify to make new function accessible from
mtdblock.c?

Justin Treon



      ____________________________________________________________________________________
Be a better friend, newshound, and 
know-it-all with Yahoo! Mobile.  Try it now.  http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ 




From justin_treon at yahoo.com  Wed Jan 23 19:43:34 2008
From: justin_treon at yahoo.com (Justin Treon)
Date: Wed, 23 Jan 2008 16:43:34 -0800 (PST)
Subject: Adding a function pointer to mtd_info struct
In-Reply-To: <20080123161324.45ea71e3@zod.rchland.ibm.com>
Message-ID: <504404.99599.qm@web43132.mail.sp1.yahoo.com>

> > I am trying to add some new features in my kernel to cfi_cmd_0001.c for a test
> chip.
> >  I added a new field to the mtd_info struct in mtd.h and inserted the function
> > pointer into the mtd->overwrite field I added in cfi_cmd_0001.c, but when I try
> to
> > use mtd->overwrite in mtdblock.c the pointer is set to NULL.  
> > 
> > In the mtd_info struct in include/mtd/mtd.h I addded:
> > 	int (*overwrite) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
> > const u_char *buf);
> > 
> > In cfi_cmd_0001.c I added:
> > 	mtd->overwrite = cfi_intelext_overwrite_buffers;
> > 
> > What file or field do I need to modify to make new function accessible from
> > mtdblock.c?
> 
> Just post a patch of what you did.  It'll be easier to help you.
> 

I figured it out.  I did not realize I had to edit the mtd-parts file as well. Thank
you Josh.

Justin



      ____________________________________________________________________________________
Never miss a thing.  Make Yahoo your home page. 
http://www.yahoo.com/r/hs



From jwboyer at gmail.com  Wed Jan 23 17:13:24 2008
From: jwboyer at gmail.com (Josh Boyer)
Date: Wed, 23 Jan 2008 16:13:24 -0600
Subject: Adding a function pointer to mtd_info struct
In-Reply-To: <63159.87126.qm@web43145.mail.sp1.yahoo.com>
References: <63159.87126.qm@web43145.mail.sp1.yahoo.com>
Message-ID: <20080123161324.45ea71e3@zod.rchland.ibm.com>

On Wed, 23 Jan 2008 09:28:13 -0800 (PST)
Justin Treon <justin_treon at yahoo.com> wrote:

> I am trying to add some new features in my kernel to cfi_cmd_0001.c for a test chip.
>  I added a new field to the mtd_info struct in mtd.h and inserted the function
> pointer into the mtd->overwrite field I added in cfi_cmd_0001.c, but when I try to
> use mtd->overwrite in mtdblock.c the pointer is set to NULL.  
> 
> In the mtd_info struct in include/mtd/mtd.h I addded:
> 	int (*overwrite) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
> const u_char *buf);
> 
> In cfi_cmd_0001.c I added:
> 	mtd->overwrite = cfi_intelext_overwrite_buffers;
> 
> What file or field do I need to modify to make new function accessible from
> mtdblock.c?

Just post a patch of what you did.  It'll be easier to help you.

josh


From nancydreaming at gmail.com  Wed Jan 23 22:13:10 2008
From: nancydreaming at gmail.com (Nancy)
Date: Thu, 24 Jan 2008 11:13:10 +0800
Subject: Is there really need to build Block Device Emulation over UBI?
Message-ID: <bae050c10801231913r43473c02r2d9093a205a00c87@mail.gmail.com>

Hi,
   Is there really need to build Block Device Emulation over UBI? Why
can't use the mtd_blkdev.c and mtdblock.c directly?
   Thanks to gluebi, make UBI and MTD become one. More interesting
thing is,  volume can be treat like a mtd partition. mtdblock.c do not
have wear-leveling and bad block management mechanism but UBI has.
gluebi make all those functions mix together right?
   I have tried, and it work.


From dedekind at infradead.org  Thu Jan 24 02:18:23 2008
From: dedekind at infradead.org (Artem Bityutskiy)
Date: Thu, 24 Jan 2008 09:18:23 +0200
Subject: Is there really need to build Block Device Emulation over UBI?
In-Reply-To: <bae050c10801231913r43473c02r2d9093a205a00c87@mail.gmail.com>
References: <bae050c10801231913r43473c02r2d9093a205a00c87@mail.gmail.com>
Message-ID: <1201159103.6934.36.camel@sauron>

On Thu, 2008-01-24 at 11:13 +0800, Nancy wrote:
> Hi,
>    Is there really need to build Block Device Emulation over UBI? Why
> can't use the mtd_blkdev.c and mtdblock.c directly?
>    Thanks to gluebi, make UBI and MTD become one. More interesting
> thing is,  volume can be treat like a mtd partition. mtdblock.c do not
> have wear-leveling and bad block management mechanism but UBI has.
> gluebi make all those functions mix together right?
>    I have tried, and it work.

The problem with mtdblock is that when it needs to change an eraseblock,
it reads it, erases, then writes new data to it, which would cause data
loss in case of an unclean reboot.

-- 
Best regards,
Artem Bityutskiy (???????? ?????)



From nancydreaming at gmail.com  Thu Jan 24 03:24:52 2008
From: nancydreaming at gmail.com (Nancy)
Date: Thu, 24 Jan 2008 16:24:52 +0800
Subject: Is there really need to build Block Device Emulation over UBI?
In-Reply-To: <1201159103.6934.36.camel@sauron>
References: <bae050c10801231913r43473c02r2d9093a205a00c87@mail.gmail.com>
	<1201159103.6934.36.camel@sauron>
Message-ID: <bae050c10801240024y6bd84a2bj1c5c29037200ab24@mail.gmail.com>

> The problem with mtdblock is that when it needs to change an eraseblock,
> it reads it, erases, then writes new data to it, which would cause data
> loss in case of an unclean reboot.

If I can delay  the erase operation, then it perfect works?  when
change a eraseblock, reads it(from old mapped PEB) , then writes new
data to it(new mapped PEB), finally erase the old mapped PEB.

How about that?


--
Best Wishes,
Nancy


From dedekind at infradead.org  Thu Jan 24 03:45:26 2008
From: dedekind at infradead.org (Artem Bityutskiy)
Date: Thu, 24 Jan 2008 10:45:26 +0200
Subject: Is there really need to build Block Device Emulation over UBI?
In-Reply-To: <bae050c10801240024y6bd84a2bj1c5c29037200ab24@mail.gmail.com>
References: <bae050c10801231913r43473c02r2d9093a205a00c87@mail.gmail.com>
	<1201159103.6934.36.camel@sauron>
	<bae050c10801240024y6bd84a2bj1c5c29037200ab24@mail.gmail.com>
Message-ID: <1201164326.6934.39.camel@sauron>

On Thu, 2008-01-24 at 16:24 +0800, Nancy wrote:
> > The problem with mtdblock is that when it needs to change an eraseblock,
> > it reads it, erases, then writes new data to it, which would cause data
> > loss in case of an unclean reboot.
> 
> If I can delay  the erase operation, then it perfect works?  when
> change a eraseblock, reads it(from old mapped PEB) , then writes new
> data to it(new mapped PEB), finally erase the old mapped PEB.
> 
> How about that?

Yes, this is OK, but mtdblock does not do this. Here I wrote about how
to create a simple FTL layer over UBI:

http://lists.infradead.org/pipermail/linux-mtd/2008-January/020381.html

-- 
Best regards,
Artem Bityutskiy (???????? ?????)



From dedekind at infradead.org  Thu Jan 24 04:37:39 2008
From: dedekind at infradead.org (Artem Bityutskiy)
Date: Thu, 24 Jan 2008 11:37:39 +0200
Subject: Is there really need to build Block Device Emulation over UBI?
In-Reply-To: <bae050c10801231913r43473c02r2d9093a205a00c87@mail.gmail.com>
References: <bae050c10801231913r43473c02r2d9093a205a00c87@mail.gmail.com>
Message-ID: <1201167459.6934.42.camel@sauron>

On Thu, 2008-01-24 at 11:13 +0800, Nancy wrote:
> Hi,
>    Is there really need to build Block Device Emulation over UBI? Why
> can't use the mtd_blkdev.c and mtdblock.c directly?
>    Thanks to gluebi, make UBI and MTD become one. More interesting
> thing is,  volume can be treat like a mtd partition. mtdblock.c do not
> have wear-leveling and bad block management mechanism but UBI has.
> gluebi make all those functions mix together right?
>    I have tried, and it work.

Frankly, I am very busy now and have no time to review so much code.
Please, communicate via the mailing list instead. And please, send
patches instead of whole files.

-- 
Best regards,
Artem Bityutskiy (???????? ?????)



From vicky.irobot at gmail.com  Thu Jan 24 04:42:32 2008
From: vicky.irobot at gmail.com (Max Stirling)
Date: Thu, 24 Jan 2008 04:42:32 -0500
Subject: mtd block readonly low level nand driver cramfs
Message-ID: <47985D88.1060005@gmail.com>

Hi,

This might sound quite basic question. This is the first time I am 
looking into the MTD code so have some really basic questions.

I am trying to mount a read only fs (cramfs) on the flash. Please let me 
know if the following steps are right:

1. Enabled the following in the Kconfig files
    CONFIG_MTD_PARITIONS
    CONFIG_MTD
    CONFIG_MTD_BLOCK_RO
    CONFIG_MTD_NAND
    CONFIG_MTD_NAND_IDS


After booting the compiled kernel I am able to see the mtdblock under 
/proc/devices using 31 Major number.

Now for me to mount the cramfs image that is on the flash I need to 
provide the low level nand driver code. This I need to write but before 
starting that can any one point me to a reference nand driver code that 
is used for read only mount? Which functionality would the MTD require 
to be implemented for mounting a cramfs image which is on the flash.

Would appreciate any pointers to how to get started off with this.

thanks in advance for the reply.

M.S



From ext-adrian.hunter at nokia.com  Thu Jan 24 09:16:40 2008
From: ext-adrian.hunter at nokia.com (Adrian Hunter)
Date: Thu, 24 Jan 2008 16:16:40 +0200
Subject: [PATCH] [MTD] [OneNAND] Do not release chip twice
Message-ID: <47989DC8.5090201@nokia.com>

>From 7adb82278aba483c2211e25e0927bdaa8c8a4363 Mon Sep 17 00:00:00 2001
From: Adrian Hunter <ext-adrian.hunter at nokia.com>
Date: Thu, 24 Jan 2008 12:48:37 +0200
Subject: [MTD] [OneNAND] Do not release chip twice

Signed-off-by: Adrian Hunter <ext-adrian.hunter at nokia.com>
---
 drivers/mtd/onenand/onenand_base.c |    3 ---
 1 files changed, 0 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 1b0b320..92768ea 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -1435,9 +1435,6 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
 		buf += thislen;
 	}
 
-	/* Deselect and wake up anyone waiting on the device */
-	onenand_release_device(mtd);
-
 	ops->retlen = written;
 
 	return ret;
-- 
1.4.4.2


From ext-adrian.hunter at nokia.com  Thu Jan 24 09:17:23 2008
From: ext-adrian.hunter at nokia.com (Adrian Hunter)
Date: Thu, 24 Jan 2008 16:17:23 +0200
Subject: [PATCH] [MTD] [OneNAND] fix call to onenand_verify when writing
	subpages
Message-ID: <47989DF3.5010408@nokia.com>

>From cd14c5e65c47a827da3950022d06502bdf719d3c Mon Sep 17 00:00:00 2001
From: Adrian Hunter <ext-adrian.hunter at nokia.com>
Date: Mon, 21 Jan 2008 17:13:07 +0200
Subject: [MTD] [OneNAND] fix call to onenand_verify when writing subpages

Signed-off-by: Adrian Hunter <ext-adrian.hunter at nokia.com>
---
 drivers/mtd/onenand/onenand_base.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 92768ea..c2bf4ae 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -1419,7 +1419,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
 		}
 
 		/* Only check verify write turn on */
-		ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen);
+		ret = onenand_verify(mtd, buf, to, thislen);
 		if (ret) {
 			printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
 			break;
-- 
1.4.4.2


From dedekind at infradead.org  Thu Jan 24 11:54:53 2008
From: dedekind at infradead.org (Artem Bityutskiy)
Date: Thu, 24 Jan 2008 18:54:53 +0200
Subject: [PATCH] UBI: introduce atomic LEB change ioctl
Message-ID: <20080124165453.30169.40332.sendpatchset@golum>

>From e405cf1dc645e7931df0e47ee7408d5251e2d9d0 Mon Sep 17 00:00:00 2001
From: Artem Bityutskiy <Artem.Bityutskiy at nokia.com>
Date: Thu, 24 Jan 2008 16:15:14 +0200
Subject: [PATCH] UBI: introduce atomic LEB change ioctl

We have to be able to change individual LEBs for utilities like
ubifsck, ubifstune. For example, ubifsck has to be able to fix
errors on the media, ubifstune has to be able to change the
the superblock, hence this ioctl.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy at nokia.com>
---
 include/linux/mtd/ubi.h |   17 ---------------
 include/mtd/ubi-user.h  |   51 +++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 47 insertions(+), 21 deletions(-)

diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h
index c4abe03..f71201d 100644
--- a/include/linux/mtd/ubi.h
+++ b/include/linux/mtd/ubi.h
@@ -26,23 +26,6 @@
 #include <mtd/ubi-user.h>
 
 /*
- * UBI data type hint constants.
- *
- * UBI_LONGTERM: long-term data
- * UBI_SHORTTERM: short-term data
- * UBI_UNKNOWN: data persistence is unknown
- *
- * These constants are used when data is written to UBI volumes in order to
- * help the UBI wear-leveling unit to find more appropriate physical
- * eraseblocks.
- */
-enum {
-	UBI_LONGTERM = 1,
-	UBI_SHORTTERM,
-	UBI_UNKNOWN
-};
-
-/*
  * enum ubi_open_mode - UBI volume open mode constants.
  *
  * UBI_READONLY: read-only mode
diff --git a/include/mtd/ubi-user.h b/include/mtd/ubi-user.h
index 4d184a7..a7421f1 100644
--- a/include/mtd/ubi-user.h
+++ b/include/mtd/ubi-user.h
@@ -63,7 +63,7 @@
  *
  * Volume update should be done via the %UBI_IOCVOLUP IOCTL command of the
  * corresponding UBI volume character device. A pointer to a 64-bit update
- * size should be passed to the IOCTL. After then, UBI expects user to write
+ * size should be passed to the IOCTL. After this, UBI expects user to write
  * this number of bytes to the volume character device. The update is finished
  * when the claimed number of bytes is passed. So, the volume update sequence
  * is something like:
@@ -72,6 +72,15 @@
  * ioctl(fd, UBI_IOCVOLUP, &image_size);
  * write(fd, buf, image_size);
  * close(fd);
+ *
+ * Atomic eraseblock change
+ * ~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * Atomic eraseblock change operation is done via the %UBI_IOCEBCH IOCTL
+ * command of the corresponding UBI volume character device. A pointer to
+ * &struct ubi_leb_change_req has to be passed to the IOCTL. Then the user is
+ * expected to write the requested amount of bytes. This is similar to the
+ * "volume update" IOCTL.
  */
 
 /*
@@ -113,11 +122,30 @@
 #define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t)
 /* An eraseblock erasure command, used for debugging, disabled by default */
 #define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t)
+/* An atomic eraseblock change command */
+#define UBI_IOCEBCH _IOW(UBI_VOL_IOC_MAGIC, 2, int32_t)
 
 /* Maximum MTD device name length supported by UBI */
 #define MAX_UBI_MTD_NAME_LEN 127
 
 /*
+ * UBI data type hint constants.
+ *
+ * UBI_LONGTERM: long-term data
+ * UBI_SHORTTERM: short-term data
+ * UBI_UNKNOWN: data persistence is unknown
+ *
+ * These constants are used when data is written to UBI volumes in order to
+ * help the UBI wear-leveling unit to find more appropriate physical
+ * eraseblocks.
+ */
+enum {
+	UBI_LONGTERM  = 1,
+	UBI_SHORTTERM = 2,
+	UBI_UNKNOWN   = 3,
+};
+
+/*
  * UBI volume type constants.
  *
  * @UBI_DYNAMIC_VOLUME: dynamic volume
@@ -125,7 +153,7 @@
  */
 enum {
 	UBI_DYNAMIC_VOLUME = 3,
-	UBI_STATIC_VOLUME = 4,
+	UBI_STATIC_VOLUME  = 4,
 };
 
 /**
@@ -137,7 +165,7 @@ enum {
  *
  * This data structure is used to specify MTD device UBI has to attach and the
  * parameters it has to use. The number which should be assigned to the new UBI
- * device is passed in @ubi_num. UBI may automatically assing the number if
+ * device is passed in @ubi_num. UBI may automatically assign the number if
  * @UBI_DEV_NUM_AUTO is passed. In this case, the device number is returned in
  * @ubi_num.
  *
@@ -176,7 +204,7 @@ struct ubi_attach_req {
  * @padding2: reserved for future, not used, has to be zeroed
  * @name: volume name
  *
- * This structure is used by userspace programs when creating new volumes. The
+ * This structure is used by user-space programs when creating new volumes. The
  * @used_bytes field is only necessary when creating static volumes.
  *
  * The @alignment field specifies the required alignment of the volume logical
@@ -222,4 +250,19 @@ struct ubi_rsvol_req {
 	int32_t vol_id;
 } __attribute__ ((packed));
 
+/**
+ * struct ubi_leb_change_req - a data structure used in atomic logical
+ *                             eraseblock change requests.
+ * @lnum: logical eraseblock number to change
+ * @bytes: how many bytes will be written to the logical eraseblock
+ * @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN)
+ * @padding: reserved for future, not used, has to be zeroed
+ */
+struct ubi_leb_change_req {
+	int32_t lnum;
+	int32_t bytes;
+	uint8_t dtype;
+	uint8_t padding[7];
+} __attribute__ ((packed));
+
 #endif /* __UBI_USER_H__ */
-- 
1.5.3.4



From jengelh at computergmbh.de  Tue Jan 22 14:49:41 2008
From: jengelh at computergmbh.de (Jan Engelhardt)
Date: Tue, 22 Jan 2008 20:49:41 +0100 (CET)
Subject: [PATCH] [MTD]: constify function pointer tables
In-Reply-To: <54038cd4f87a03884e4f59f8f3697889dfb63c54.1201030614.git.jengelh@computergmbh.de>
References: <54038cd4f87a03884e4f59f8f3697889dfb63c54.1201030614.git.jengelh@computergmbh.de>
Message-ID: <Pine.LNX.4.64.0801222048520.5722@fbirervta.pbzchgretzou.qr>

Signed-off-by: Jan Engelhardt <jengelh at computergmbh.de>
---
 drivers/mtd/ubi/cdev.c |    4 ++--
 drivers/mtd/ubi/ubi.h  |    4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index fe4da1e..05ed76f 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -683,14 +683,14 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
 }
 
 /* UBI character device operations */
-struct file_operations ubi_cdev_operations = {
+const struct file_operations ubi_cdev_operations = {
 	.owner = THIS_MODULE,
 	.ioctl = ubi_cdev_ioctl,
 	.llseek = no_llseek,
 };
 
 /* UBI volume character device operations */
-struct file_operations ubi_vol_cdev_operations = {
+const struct file_operations ubi_vol_cdev_operations = {
 	.owner   = THIS_MODULE,
 	.open    = vol_cdev_open,
 	.release = vol_cdev_release,
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 5e941a6..3a8ab61 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -361,8 +361,8 @@ struct ubi_device {
 #endif
 };
 
-extern struct file_operations ubi_cdev_operations;
-extern struct file_operations ubi_vol_cdev_operations;
+extern const struct file_operations ubi_cdev_operations;
+extern const struct file_operations ubi_vol_cdev_operations;
 extern struct class *ubi_class;
 
 /* vtbl.c */
-- 
1.5.3.4



From matthieu.castet at parrot.com  Fri Jan 18 04:45:16 2008
From: matthieu.castet at parrot.com (Matthieu CASTET)
Date: Fri, 18 Jan 2008 10:45:16 +0100
Subject: Jffs2 and big file = very slow jffs2_garbage_collect_pass
In-Reply-To: <20080117162601.GA6677@lazybastard.org>
References: <478F7E6D.8010300@parrot.com>
	<20080117162601.GA6677@lazybastard.org>
Message-ID: <4790752C.60306@parrot.com>

Hi,

J?rn Engel wrote:
> On Thu, 17 January 2008 17:12:29 +0100, Matthieu CASTET wrote:
>> we have a 240 MB jffs2 partition with summary enabled and no 
>> compression. We use 2ad8ee713566671875216ebcec64f2eda47bd19d git jffs2 
>> version 
>> (http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=2ad8ee713566671875216ebcec64f2eda47bd19d)
>> If we do a ls without waiting that jffs2_garbage_collect_pass finish, ls 
>> takes 12 minutes to complete.
> 
> Impressive!  JFFS2 may be slow, but it shouldn't be _that_ slow.  Not
> sure who cares enough to look at this.  My approach would be to 
> $ echo t > /proc/sysrq_trigger
> several times during those 12 minutes and take a close look at the code
> paths showing up.  Most likely it will spend 99% of the time in one
> place.
I have a jtag debugger that allow me to know where the code take time.
When I mount the partition, thanks to the summary the mount is very 
short (less than 10s).

Then the garbage collector start to check nodes [1]. It spend 12 minutes 
in jffs2_garbage_collect_pass.

Then the system goes idle.

Then if I try to access the file [2]. It take 12 minutes to finish 
jffs2_lookup.

I have attached the result of booting with 'profile=1'. (HZ=200)

The code spend lot's of time in the rbtree code (7 minutes) and 4 
minutes in jffs2_get_inode_nodes.


Matthieu

[1]
#0  rb_next (node=0xc1c76e80) at lib/rbtree.c:325
#1  0xc00c5568 in jffs2_get_inode_nodes (c=0xc0a5a800, f=0xc0a5a200,
     rii=0xc1c19dbc) at fs/jffs2/readinode.c:317
#2  0xc00c59d4 in jffs2_do_read_inode_internal (c=0xc0a5a800, f=0xc0a5a200,
     latest_node=0xc1c19e14) at fs/jffs2/readinode.c:1124
#3  0xc00c63a0 in jffs2_do_crccheck_inode (c=0xc0a5a800, ic=0xc03993c8)
     at fs/jffs2/readinode.c:1379
#4  0xc00c9afc in jffs2_garbage_collect_pass (c=0xc0a5a800)
     at fs/jffs2/gc.c:208
#5  0xc00cc56c in jffs2_garbage_collect_thread (_c=<value optimized out>)
     at fs/jffs2/background.c:138
#6  0xc003766c in sys_waitid (which=19019, pid=20115456, infop=0x4a0e,
     options=-1044275912, ru=0x0) at kernel/exit.c:1634

[2]
#0  0xc00e8c14 in rb_prev (node=<value optimized out>) at lib/rbtree.c:368
#1  0xc00c5624 in jffs2_get_inode_nodes (c=0xc0a5a800, f=0xc1c16ca0,
     rii=0xc0fadbf4) at fs/jffs2/readinode.c:355
#2  0xc00c59d4 in jffs2_do_read_inode_internal (c=0xc0a5a800, f=0xc1c16ca0,
     latest_node=0xc0fadca8) at fs/jffs2/readinode.c:1124
#3  0xc00c6604 in jffs2_do_read_inode (c=0xc0a5a800, f=0xc1c16ca0, ino=165,
     latest_node=0xc0fadca8) at fs/jffs2/readinode.c:1364
#4  0xc00cd5c8 in jffs2_read_inode (inode=0xc1c16cd0) at fs/jffs2/fs.c:247
#5  0xc00c0204 in jffs2_lookup (dir_i=0xc1c16310, target=0xc1c0d0d8,
     nd=<value optimized out>) at include/linux/fs.h:1670
#6  0xc0080100 in do_lookup (nd=0xc0fadf08, name=0xc0fadd8c, 
path=0xc0fadd98)
     at fs/namei.c:494
#7  0xc0081e24 in __link_path_walk (name=0xc085300f "", nd=0xc0fadf08)
     at fs/namei.c:940
#8  0xc008245c in link_path_walk (name=0xc0853000 "/mnt/toto/media",
     nd=0xc0fadf08) at fs/namei.c:1011
#9  0xc00829b0 in do_path_lookup (dfd=<value optimized out>,
     name=0xc0853000 "/mnt/toto/media", flags=<value optimized out>,
     nd=0xc0fadf08) at fs/namei.c:1157
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: profile.txt
Url: http://lists.infradead.org/pipermail/linux-mtd/attachments/20080118/b028ca59/attachment.txt 

From dedekind at infradead.org  Thu Jan 24 11:54:58 2008
From: dedekind at infradead.org (Artem Bityutskiy)
Date: Thu, 24 Jan 2008 18:54:58 +0200
Subject: [PATCH] UBI: implement atomic LEB change ioctl
In-Reply-To: <20080124165453.30169.40332.sendpatchset@golum>
References: <20080124165453.30169.40332.sendpatchset@golum>
Message-ID: <20080124165458.30169.15492.sendpatchset@golum>

>From 7e8210bd9165ba279ddacd0e4fb28891318b9b66 Mon Sep 17 00:00:00 2001
From: Artem Bityutskiy <Artem.Bityutskiy at nokia.com>
Date: Thu, 24 Jan 2008 18:48:21 +0200
Subject: [PATCH] UBI: implement atomic LEB change ioctl

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy at nokia.com>
---
 drivers/mtd/ubi/cdev.c |   72 +++++++++++++++++++++++++++++------
 drivers/mtd/ubi/ubi.h  |   27 +++++++++++--
 drivers/mtd/ubi/upd.c  |   99 ++++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 178 insertions(+), 20 deletions(-)

diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 0c4044d..9d6aae5 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -132,8 +132,15 @@ static int vol_cdev_release(struct inode *inode, struct file *file)
 	if (vol->updating) {
 		ubi_warn("update of volume %d not finished, volume is damaged",
 			 vol->vol_id);
+		ubi_assert(!vol->changing_leb);
 		vol->updating = 0;
 		vfree(vol->upd_buf);
+	} else if (vol->changing_leb) {
+		dbg_msg("only %lld of %lld bytes received for atomic LEB change"
+			" for volume %d:%d, cancel", vol->upd_received,
+			vol->upd_bytes, vol->ubi->ubi_num, vol->vol_id);
+		vol->changing_leb = 0;
+		vfree(vol->upd_buf);
 	}
 
 	ubi_close_volume(desc);
@@ -351,24 +358,32 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
 	struct ubi_volume *vol = desc->vol;
 	struct ubi_device *ubi = vol->ubi;
 
-	if (!vol->updating)
+	if (!vol->updating && !vol->changing_leb)
 		return vol_cdev_direct_write(file, buf, count, offp);
 
-	err = ubi_more_update_data(ubi, vol, buf, count);
+	if (vol->updating)
+		err = ubi_more_update_data(ubi, vol, buf, count);
+	else
+		err = ubi_more_leb_change_data(ubi, vol, buf, count);
+
 	if (err < 0) {
-		ubi_err("cannot write %zd bytes of update data, error %d",
+		ubi_err("cannot accept more %zd bytes of data, error %d",
 			count, err);
 		return err;
 	}
 
 	if (err) {
 		/*
-		 * Update is finished, @err contains number of actually written
-		 * bytes now.
+		 * The operation is finished, @err contains number of actually
+		 * written bytes.
 		 */
 		count = err;
 
-		vol->updating = 0;
+		if (vol->changing_leb) {
+			revoke_exclusive(desc, UBI_READWRITE);
+			return count;
+		}
+
 		err = ubi_check_volume(ubi, vol->vol_id);
 		if (err < 0)
 			return err;
@@ -433,6 +448,43 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
 		break;
 	}
 
+	/* Atomic logical eraseblock change command */
+	case UBI_IOCEBCH:
+	{
+		struct ubi_leb_change_req req;
+
+		err = copy_from_user(&req, argp,
+				     sizeof(struct ubi_leb_change_req));
+		if (err) {
+			err = -EFAULT;
+			break;
+		}
+
+		if (desc->mode == UBI_READONLY ||
+		    vol->vol_type == UBI_STATIC_VOLUME) {
+			err = -EROFS;
+			break;
+		}
+
+		/* Validate the request */
+		err = -EINVAL;
+		if (req.lnum < 0 || req.lnum >= vol->reserved_pebs ||
+		    req.bytes < 0 || req.lnum >= vol->usable_leb_size)
+			break;
+		if (req.dtype != UBI_LONGTERM && req.dtype != UBI_SHORTTERM &&
+		    req.dtype != UBI_UNKNOWN)
+			break;
+
+		err = get_exclusive(desc);
+		if (err < 0)
+			break;
+
+		err = ubi_start_leb_change(ubi, vol, &req);
+		if (req.bytes == 0)
+			revoke_exclusive(desc, UBI_READWRITE);
+		break;
+	}
+
 #ifdef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO
 	/* Logical eraseblock erasure command */
 	case UBI_IOCEBER:
@@ -445,7 +497,8 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
 			break;
 		}
 
-		if (desc->mode == UBI_READONLY) {
+		if (desc->mode == UBI_READONLY ||
+		    vol->vol_type == UBI_STATIC_VOLUME) {
 			err = -EROFS;
 			break;
 		}
@@ -455,11 +508,6 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
 			break;
 		}
 
-		if (vol->vol_type != UBI_DYNAMIC_VOLUME) {
-			err = -EROFS;
-			break;
-		}
-
 		dbg_msg("erase LEB %d:%d", vol->vol_id, lnum);
 		err = ubi_eba_unmap_leb(ubi, vol, lnum);
 		if (err)
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 3a88cf1..4577106 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -158,15 +158,23 @@ struct ubi_volume_desc;
  * @name: volume name
  *
  * @upd_ebs: how many eraseblocks are expected to be updated
- * @upd_bytes: how many bytes are expected to be received
- * @upd_received: how many update bytes were already received
- * @upd_buf: update buffer which is used to collect update data
+ * @ch_lnum: LEB number which is being changing by the atomic LEB change
+ *           operation
+ * @ch_dtype: data persistency type which is being changing by the atomic LEB
+ *            change operation
+ * @upd_bytes: how many bytes are expected to be received for volume update or
+ *             atomic LEB change
+ * @upd_received: how many bytes were already received for volume update or
+ *                atomic LEB change
+ * @upd_buf: update buffer which is used to collect update data or data for
+ *           atomic LEB change
  *
  * @eba_tbl: EBA table of this volume (LEB->PEB mapping)
  * @checked: %1 if this static volume was checked
  * @corrupted: %1 if the volume is corrupted (static volumes only)
  * @upd_marker: %1 if the update marker is set for this volume
  * @updating: %1 if the volume is being updated
+ * @changing_leb: %1 if the atomic LEB change ioctl command is in progress
  *
  * @gluebi_desc: gluebi UBI volume descriptor
  * @gluebi_refcount: reference count of the gluebi MTD device
@@ -202,6 +210,8 @@ struct ubi_volume {
 	char name[UBI_VOL_NAME_MAX+1];
 
 	int upd_ebs;
+	int ch_lnum;
+	int ch_dtype;
 	long long upd_bytes;
 	long long upd_received;
 	void *upd_buf;
@@ -211,9 +221,14 @@ struct ubi_volume {
 	int corrupted:1;
 	int upd_marker:1;
 	int updating:1;
+	int changing_leb:1;
 
 #ifdef CONFIG_MTD_UBI_GLUEBI
-	/* Gluebi-related stuff may be compiled out */
+	/*
+	 * Gluebi-related stuff may be compiled out.
+	 * TODO: this should not be built into UBI but should be a separate
+	 * ubimtd driver which works on top of UBI and emulates MTD devices.
+	 */
 	struct ubi_volume_desc *gluebi_desc;
 	int gluebi_refcount;
 	struct mtd_info gluebi_mtd;
@@ -427,6 +442,10 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
 		     long long bytes);
 int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
 			 const void __user *buf, int count);
+int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
+			 const struct ubi_leb_change_req *req);
+int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol,
+			     const void __user *buf, int count);
 
 /* misc.c */
 int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf, int length);
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index 59c61ab..40f5c0e 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -22,7 +22,8 @@
  */
 
 /*
- * This file contains implementation of the volume update functionality.
+ * This file contains implementation of the volume update and atomic LEB change
+ * functionality.
  *
  * The update operation is based on the per-volume update marker which is
  * stored in the volume table. The update marker is set before the update
@@ -133,6 +134,7 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
 	uint64_t tmp;
 
 	dbg_msg("start update of volume %d, %llu bytes", vol->vol_id, bytes);
+	ubi_assert(!vol->updating && !vol->changing_leb);
 	vol->updating = 1;
 
 	err = set_update_marker(ubi, vol);
@@ -168,6 +170,37 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
 }
 
 /**
+ * ubi_start_leb_change - start atomic LEB change.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ * @req: operation request
+ *
+ * This function starts atomic LEB change operation. Returns zero in case of
+ * success and a negative error code in case of failure.
+ */
+int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
+			 const struct ubi_leb_change_req *req)
+{
+	ubi_assert(!vol->updating && !vol->changing_leb);
+
+	if (req->bytes == 0)
+		return ubi_eba_atomic_leb_change(ubi, vol, req->lnum, NULL, 0,
+						 req->dtype);
+
+	vol->upd_bytes = req->bytes;
+	vol->upd_received = 0;
+	vol->changing_leb = 1;
+	vol->ch_lnum = req->lnum;
+	vol->ch_dtype = req->dtype;
+
+	vol->upd_buf = vmalloc(req->bytes);
+	if (!vol->upd_buf)
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
  * write_leb - write update data.
  * @ubi: UBI device description object
  * @vol: volume description object
@@ -239,9 +272,9 @@ static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
  * @count: how much bytes to write
  *
  * This function writes more data to the volume which is being updated. It may
- * be called arbitrary number of times until all of the update data arrive.
- * This function returns %0 in case of success, number of bytes written during
- * the last call if the whole volume update was successfully finished, and a
+ * be called arbitrary number of times until all the update data arriveis. This
+ * function returns %0 in case of success, number of bytes written during the
+ * last call if the whole volume update has been successfully finished, and a
  * negative error code in case of failure.
  */
 int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
@@ -340,6 +373,7 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
 			return err;
 		err = ubi_wl_flush(ubi);
 		if (err == 0) {
+			vol->updating = 0;
 			err = to_write;
 			vfree(vol->upd_buf);
 		}
@@ -347,3 +381,60 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
 
 	return err;
 }
+
+/**
+ * ubi_more_leb_change_data - accept more data for atomic LEB change.
+ * @vol: volume description object
+ * @buf: write data (user-space memory buffer)
+ * @count: how much bytes to write
+ *
+ * This function accepts more data to the volume which is being under the
+ * "atomic LEB change" operation. It may be called arbitrary number of times
+ * until all data arrives. This function returns %0 in case of success, number
+ * of bytes written during the last call if the whole "atomic LEB change"
+ * operation has been successfully finished, and a negative error code in case
+ * of failure.
+ */
+int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol,
+			     const void __user *buf, int count)
+{
+	int err;
+
+	dbg_msg("write %d of %lld bytes, %lld already passed",
+		count, vol->upd_bytes, vol->upd_received);
+
+	if (ubi->ro_mode)
+		return -EROFS;
+
+	if (vol->upd_received + count > vol->upd_bytes)
+		count = vol->upd_bytes - vol->upd_received;
+
+	err = copy_from_user(vol->upd_buf + vol->upd_received, buf, count);
+	if (err)
+		return -EFAULT;
+
+	if (vol->upd_received + count == vol->upd_bytes) {
+		int l;
+
+		l = ubi_calc_data_len(ubi, buf, vol->upd_bytes);
+		if (l != vol->upd_bytes)
+			dbg_msg("skip last %lld bytes (0xFF)",
+				vol->upd_bytes - l);
+		err = ubi_eba_atomic_leb_change(ubi, vol, vol->ch_lnum,
+						vol->upd_buf, l, UBI_UNKNOWN);
+		if (err)
+			return err;
+	}
+
+	vol->upd_received += count;
+	buf += count;
+
+	ubi_assert(vol->upd_received <= vol->upd_bytes);
+	if (vol->upd_received == vol->upd_bytes) {
+		vol->changing_leb = 0;
+		err = count;
+		vfree(vol->upd_buf);
+	}
+
+	return err;
+}
-- 
1.5.3.4



From vicky.irobot at gmail.com  Fri Jan 18 07:27:02 2008
From: vicky.irobot at gmail.com (vicky)
Date: Fri, 18 Jan 2008 17:57:02 +0530
Subject: question about node creation /dev/mtd*
In-Reply-To: <479097B7.9050401@gmail.com>
References: <479097B7.9050401@gmail.com>
Message-ID: <47909B16.30601@gmail.com>

vicky wrote:
> Hi,
>
> I have enabled mtd in my config. When I boot from the updated kernel I 
> find that /dev/mtdblock is not created?
>
> How does the /dev/mtdblock get created? I didn't find this in the 
> init/rcs script. I am under an impression that once the mtd is enabled 
> in the linux
> config file the creation of the corresponding node is taken care in 
> some script.
>
> I have a dummy nand driver written and placed in the mtd/nand location.
>
> Please advice.
>
> Vic
>
Adding to the email, I enabled the below options in my config file.

CONFIG_MTD=y
CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLKDEVS=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_VERIFY_WRITE=y
CONFIG_MTD_NAND_IDS=y


-------------- next part --------------
A non-text attachment was scrubbed...
Name: vicky_irobot.vcf
Type: text/x-vcard
Size: 91 bytes
Desc: not available
Url : http://lists.infradead.org/pipermail/linux-mtd/attachments/20080118/10a4b4e7/attachment.vcf 

From cem8101 at gmail.com  Thu Jan 24 10:39:36 2008
From: cem8101 at gmail.com (Chase Maupin)
Date: Thu, 24 Jan 2008 09:39:36 -0600
Subject: Error compiling libubi with latest mtd-utils snapshot
Message-ID: <2c8de1360801240739oae8135bg55d829ff75642048@mail.gmail.com>

All,

I downloaded the latest mtd-utils snapshot from
git://git.infradead.org/mtd-utils.git and did a "make clean" followed
by "make".  The snapshot I downloaded was commited Jan 24, 2008 at
11:21 with commit tag e292b5fb39de2c6907ffe751391ae3bbd5603b91.

During the compile I received the following errors:

make -C ./ubi-utils
make[1]: Entering directory
`/home/chase/projects/wiki/mtd-utils.git.new/ubi-utils'
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall src/libubi.c
-c -o libubi.o
In file included from ../include/mtd/ubi-header.h:33,
                 from include/libubi.h:29,
                 from src/libubi.c:34:
/usr/include/asm/byteorder.h:6:2: #warning using private kernel
header; include <endian.h> instead!
In file included from include/libubi.h:29,
                 from src/libubi.c:34:
../include/mtd/ubi-header.h:158: error: syntax error before "__be32"
../include/mtd/ubi-header.h:158: warning: no semicolon at end of struct or union
../include/mtd/ubi-header.h:161: error: syntax error before "ec"
../include/mtd/ubi-header.h:161: warning: type defaults to `int' in
declaration of `ec'
../include/mtd/ubi-header.h:161: warning: data definition has no type
or storage class
../include/mtd/ubi-header.h:162: error: syntax error before "vid_hdr_offset"
../include/mtd/ubi-header.h:162: warning: type defaults to `int' in
declaration of `vid_hdr_offset'
../include/mtd/ubi-header.h:162: warning: data definition has no type
or storage class
../include/mtd/ubi-header.h:163: error: syntax error before "data_offset"
../include/mtd/ubi-header.h:163: warning: type defaults to `int' in
declaration of `data_offset'
../include/mtd/ubi-header.h:163: warning: data definition has no type
or storage class
../include/mtd/ubi-header.h:165: error: syntax error before "hdr_crc"
../include/mtd/ubi-header.h:165: warning: type defaults to `int' in
declaration of `hdr_crc'
../include/mtd/ubi-header.h:165: warning: data definition has no type
or storage class
../include/mtd/ubi-header.h:166: warning: empty declaration
../include/mtd/ubi-header.h:283: error: syntax error before "__be32"
../include/mtd/ubi-header.h:283: warning: no semicolon at end of struct or union
../include/mtd/ubi-header.h:288: error: syntax error before "vol_id"
../include/mtd/ubi-header.h:288: warning: type defaults to `int' in
declaration of `vol_id'
../include/mtd/ubi-header.h:288: warning: data definition has no type
or storage class
../include/mtd/ubi-header.h:289: error: syntax error before "lnum"
../include/mtd/ubi-header.h:289: warning: type defaults to `int' in
declaration of `lnum'
../include/mtd/ubi-header.h:289: warning: data definition has no type
or storage class
../include/mtd/ubi-header.h:290: error: syntax error before "leb_ver"
../include/mtd/ubi-header.h:290: warning: type defaults to `int' in
declaration of `leb_ver'
../include/mtd/ubi-header.h:290: warning: data definition has no type
or storage class
../include/mtd/ubi-header.h:291: error: syntax error before "data_size"
../include/mtd/ubi-header.h:291: warning: type defaults to `int' in
declaration of `data_size'
../include/mtd/ubi-header.h:291: warning: data definition has no type
or storage class
../include/mtd/ubi-header.h:292: error: syntax error before "used_ebs"
../include/mtd/ubi-header.h:292: warning: type defaults to `int' in
declaration of `used_ebs'
../include/mtd/ubi-header.h:292: warning: data definition has no type
or storage class
../include/mtd/ubi-header.h:293: error: syntax error before "data_pad"
../include/mtd/ubi-header.h:293: warning: type defaults to `int' in
declaration of `data_pad'
../include/mtd/ubi-header.h:293: warning: data definition has no type
or storage class
../include/mtd/ubi-header.h:294: error: syntax error before "data_crc"
../include/mtd/ubi-header.h:294: warning: type defaults to `int' in
declaration of `data_crc'
../include/mtd/ubi-header.h:294: warning: data definition has no type
or storage class
../include/mtd/ubi-header.h:295: error: conflicting types for 'padding1'
../include/mtd/ubi-header.h:160: error: previous declaration of
'padding1' was here
../include/mtd/ubi-header.h:296: error: syntax error before "sqnum"
../include/mtd/ubi-header.h:296: warning: type defaults to `int' in
declaration of `sqnum'
../include/mtd/ubi-header.h:296: warning: data definition has no type
or storage class
../include/mtd/ubi-header.h:297: error: conflicting types for 'padding2'
../include/mtd/ubi-header.h:164: error: previous declaration of
'padding2' was here
../include/mtd/ubi-header.h:298: error: syntax error before "hdr_crc"
../include/mtd/ubi-header.h:298: warning: type defaults to `int' in
declaration of `hdr_crc'
../include/mtd/ubi-header.h:298: warning: data definition has no type
or storage class
../include/mtd/ubi-header.h:299: warning: empty declaration
../include/mtd/ubi-header.h:368: error: syntax error before "__be32"
../include/mtd/ubi-header.h:368: warning: no semicolon at end of struct or union
../include/mtd/ubi-header.h:369: warning: type defaults to `int' in
declaration of `alignment'
../include/mtd/ubi-header.h:369: warning: data definition has no type
or storage class
../include/mtd/ubi-header.h:370: error: syntax error before "data_pad"
../include/mtd/ubi-header.h:370: warning: type defaults to `int' in
declaration of `data_pad'
../include/mtd/ubi-header.h:370: warning: data definition has no type
or storage class
../include/mtd/ubi-header.h:373: error: syntax error before "name_len"
../include/mtd/ubi-header.h:373: warning: type defaults to `int' in
declaration of `name_len'
../include/mtd/ubi-header.h:373: warning: data definition has no type
or storage class
../include/mtd/ubi-header.h:377: error: syntax error before "crc"
../include/mtd/ubi-header.h:377: warning: type defaults to `int' in
declaration of `crc'
../include/mtd/ubi-header.h:377: warning: data definition has no type
or storage class
../include/mtd/ubi-header.h:378: warning: empty declaration
make[1]: *** [libubi.o] Error 1
make[1]: Leaving directory
`/home/chase/projects/wiki/mtd-utils.git.new/ubi-utils'
make: *** [all] Error 2


The type __be32 is not defined in my /usr/include directory.  I did
find it define in my kernel tree under include/linux/types.h.  Can
someone give me a pointer on how to get this utility to compile
cleanly?

Thank You,
Chase Maupin


From vapier.adi at gmail.com  Thu Jan 24 16:33:59 2008
From: vapier.adi at gmail.com (Mike Frysinger)
Date: Thu, 24 Jan 2008 16:33:59 -0500
Subject: chip driver for ST PSD4256G6V parts
Message-ID: <8bd0f97a0801241333u6ff94ebav3487baee90b6965c@mail.gmail.com>

we have a driver for the ST PSD4256G6V parts (1) that needs to be
cleaned up a bit and pushed to mainline.  the trouble is that this
part is completely non-standard.  that is to say, it isnt CFI or JEDEC
compatible.  while i'd love to see this part simply disappear, it's
out of our (the software team's) hands, which means we need to support
it.

what makes me sad is the complete lack of any sort of chip-specific
driver in drivers/mtd/chips/ ... so this would need
drivers/mtd/chips/PSD4256G6V.c which is in stark contrast to
everything else.  but i guess it cant be avoided and that's what i
need to submit, right ?

(1): http://www.st.com/stonline/products/literature/ds/8116/psd4256g6v.htm
-mike


From kmpark at infradead.org  Thu Jan 24 18:39:52 2008
From: kmpark at infradead.org (Kyungmin Park)
Date: Fri, 25 Jan 2008 08:39:52 +0900
Subject: [PATCH] [MTD] [OneNAND] Do not release chip twice
In-Reply-To: <47989DC8.5090201@nokia.com>
References: <47989DC8.5090201@nokia.com>
Message-ID: <004b01c85ee2$6f78b2a0$1fa9580a@swcenter.sec.samsung.co.kr>

> From: Adrian Hunter <ext-adrian.hunter at nokia.com>
> Date: Thu, 24 Jan 2008 12:48:37 +0200
> Subject: [MTD] [OneNAND] Do not release chip twice
> 
> Signed-off-by: Adrian Hunter <ext-adrian.hunter at nokia.com>
Ack-off-by: Kyungmin Park <kyungmin.park at samsung.com>



From spodstavin at ru.mvista.com  Fri Jan 25 00:12:09 2008
From: spodstavin at ru.mvista.com (Sergey Podstavin)
Date: Fri, 25 Jan 2008 08:12:09 +0300
Subject: [PATCH] basic pxa3 nand controller support
Message-ID: <1201237929.3292.2.camel@localhost.localdomain>

This is updated pxa3 nand controller support, io mapping was removed,
partition tables were moved outside of the driver into platform code,
some cleanup was done. Changes in head.S were done to boot pxa300
Zylonite.

Best wishes,
Sergey Podstavin.
-------------- next part --------------
Date: Mon, 21 Jan 2008 13:50:42 +0300
[PATCH] pxa3 nand controller support
Sergey Podstavin <spodstavin at ru.mvista.com>

---
 arch/arm/kernel/head.S                 |    6 +-
 arch/arm/mach-pxa/pxa3xx.c             |    1 +
 arch/arm/mach-pxa/zylonite.c           |   61 ++
 drivers/mtd/nand/Kconfig               |    6 +
 drivers/mtd/nand/Makefile              |    1 +
 drivers/mtd/nand/pxa3xx_nand.c         | 1385 ++++++++++++++++++++++++++++++++
 include/asm-arm/arch-pxa/pxa-regs.h    |    1 +
 include/asm-arm/arch-pxa/pxa3xx_nand.h |   18 +
 8 files changed, 1476 insertions(+), 3 deletions(-)
 create mode 100644 drivers/mtd/nand/pxa3xx_nand.c
 create mode 100644 include/asm-arm/arch-pxa/pxa3xx_nand.h

diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 7898cbc..a89c0f2 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -86,9 +86,9 @@ ENTRY(stext)
 	bl	__lookup_processor_type		@ r5=procinfo r9=cpuid
 	movs	r10, r5				@ invalid processor (r5=0)?
 	beq	__error_p			@ yes, error 'p'
-	bl	__lookup_machine_type		@ r5=machinfo
-	movs	r8, r5				@ invalid machine (r5=0)?
-	beq	__error_a			@ yes, error 'a'
+//	bl	__lookup_machine_type		@ r5=machinfo
+//	movs	r8, r5				@ invalid machine (r5=0)?
+//	beq	__error_a			@ yes, error 'a'
 	bl	__vet_atags
 	bl	__create_page_tables
 
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index 61d9c9d..4d800c6 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -183,6 +183,7 @@ static struct clk pxa3xx_clks[] = {
 	PXA3xx_CK("LCDCLK", LCD,    &clk_pxa3xx_hsio_ops, &pxa_device_fb.dev),
 	PXA3xx_CK("CAMCLK", CAMERA, &clk_pxa3xx_hsio_ops, NULL),
 
+	PXA3xx_CK("NANDCLK", NAND, &clk_pxa3xx_hsio_ops, NULL),
 	PXA3xx_CKEN("UARTCLK", FFUART, 14857000, 1, &pxa_device_ffuart.dev),
 	PXA3xx_CKEN("UARTCLK", BTUART, 14857000, 1, &pxa_device_btuart.dev),
 	PXA3xx_CKEN("UARTCLK", STUART, 14857000, 1, NULL),
diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
index 743a87b..468c773 100644
--- a/arch/arm/mach-pxa/zylonite.c
+++ b/arch/arm/mach-pxa/zylonite.c
@@ -18,6 +18,8 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -25,6 +27,7 @@
 #include <asm/arch/gpio.h>
 #include <asm/arch/pxafb.h>
 #include <asm/arch/zylonite.h>
+#include <asm/arch/pxa3xx_nand.h>
 
 #include "generic.h"
 
@@ -156,6 +159,62 @@ static void __init zylonite_init_lcd(void)
 static inline void zylonite_init_lcd(void) {}
 #endif
 
+struct mtd_partition pxa3xx_mtd_partition_info[] = {
+	{
+		name:		"Bootloader",
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE  /* force read-only */
+	},{
+		name:		"Kernel",
+		size:		0x00200000,
+		mask_flags:	MTD_WRITEABLE  /* force read-only */
+	},{
+		name:		"Filesystem",
+		size:		0x03000000,	/* only mount 48M fs */
+	}, {
+		name:		"MassStorage",
+		size:		0x0, /* It will be set at probe function */
+		offset:		MTDPART_OFS_APPEND /* Append after fs section */
+	}, {
+		name:		"BBT",
+		size:		0x0, /* It will be set at probe function */
+		offset:		MTDPART_OFS_APPEND,/* Append after fs section */
+		mask_flags:	MTD_WRITEABLE  /* force read-only */
+	}
+};
+
+#define		PXA3XX_MTD_PART_NUM	ARRAY_SIZE(pxa3xx_mtd_partition_info)
+
+static struct resource nand_resources[] = {
+	[0] = {
+		.start	= 0x43100000,
+		.end	= 0x431000ff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= -1,	/* for run-time assignment */
+		.end	= -1,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device nand_device = {
+	.name		= "pxa3xx-nand",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(nand_resources),
+	.resource	= nand_resources,
+};
+
+void __init set_pxa_nand_info(struct pxa3xx_nand_platform_data *info)
+{
+	nand_device.dev.platform_data = info;
+}
+
+struct pxa3xx_nand_platform_data pxa3xx_nand_data = {
+	.parts		= pxa3xx_mtd_partition_info,
+	.nr_parts	= PXA3XX_MTD_PART_NUM,
+};
+
 static void __init zylonite_init(void)
 {
 	/* board-processor specific initialization */
@@ -171,6 +230,8 @@ static void __init zylonite_init(void)
 	platform_device_register(&smc91x_device);
 
 	zylonite_init_lcd();
+	set_pxa_nand_info(&pxa3xx_nand_data);
+	platform_device_register(&nand_device);
 }
 
 MACHINE_START(ZYLONITE, "PXA3xx Platform Development Kit (aka Zylonite)")
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 246d451..2be073f 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -84,6 +84,12 @@ config MTD_NAND_TS7250
 config MTD_NAND_IDS
 	tristate
 
+config MTD_NAND_PXA3xx
+	tristate "NAND flash support for PXA3xx"
+	depends on MTD_NAND && PXA3xx
+	help
+	  This enables the driver for the NAND flash device on Zylonite board
+
 config MTD_NAND_AU1550
 	tristate "Au1550/1200 NAND support"
 	depends on SOC_AU1200 || SOC_AU1550
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 3ad6c01..ecb7968 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_MTD_NAND_BF5XX)		+= bf5xx_nand.o
 obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB)	+= ppchameleonevb.o
 obj-$(CONFIG_MTD_NAND_S3C2410)		+= s3c2410.o
 obj-$(CONFIG_MTD_NAND_DISKONCHIP)	+= diskonchip.o
+obj-$(CONFIG_MTD_NAND_PXA3xx)		+= pxa3xx_nand.o
 obj-$(CONFIG_MTD_NAND_H1900)		+= h1910.o
 obj-$(CONFIG_MTD_NAND_RTC_FROM4)	+= rtc_from4.o
 obj-$(CONFIG_MTD_NAND_SHARPSL)		+= sharpsl.o
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
new file mode 100644
index 0000000..11bebbf
--- /dev/null
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -0,0 +1,1385 @@
+/*
+ * drivers/mtd/nand/pxa3xx_nand.c
+ *
+ * Copyright (C) 2005 Intel Corporation
+ * Copyright (C) 2006 Marvell International Ltd.
+ *
+ * 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/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa3xx_nand.h>
+
+#define	CHIP_DELAY_TIMEOUT	(2 * HZ/10)
+
+/* registers and bit definitions */
+#define NDCR		(0x00) /* Control register */
+#define NDTR0CS0	(0x04) /* Timing Parameter 0 for CS0 */
+#define NDTR1CS0	(0x0C) /* Timing Parameter 1 for CS0 */
+#define NDSR		(0x14) /* Status Register */
+#define NDPCR		(0x18) /* Page Count Register */
+#define NDBDR0		(0x1C) /* Bad Block Register 0 */
+#define NDBDR1		(0x20) /* Bad Block Register 1 */
+#define NDDB		(0x40) /* Data Buffer */
+#define NDCB0		(0x48) /* Command Buffer0 */
+#define NDCB1		(0x4C) /* Command Buffer1 */
+#define NDCB2		(0x50) /* Command Buffer2 */
+
+#define NDCR_SPARE_EN		(0x1 << 31)
+#define NDCR_ECC_EN		(0x1 << 30)
+#define NDCR_DMA_EN		(0x1 << 29)
+#define NDCR_ND_RUN		(0x1 << 28)
+#define NDCR_DWIDTH_C		(0x1 << 27)
+#define NDCR_DWIDTH_M		(0x1 << 26)
+#define NDCR_PAGE_SZ		(0x1 << 24)
+#define NDCR_NCSX		(0x1 << 23)
+#define NDCR_ND_MODE		(0x3 << 21)
+#define NDCR_NAND_MODE   	(0x0)
+#define NDCR_CLR_PG_CNT		(0x1 << 20)
+#define NDCR_CLR_ECC		(0x1 << 19)
+#define NDCR_RD_ID_CNT_MASK	(0x7 << 16)
+#define NDCR_RD_ID_CNT(x)	(((x) << 16) & NDCR_RD_ID_CNT_MASK)
+
+#define NDCR_RA_START		(0x1 << 15)
+#define NDCR_PG_PER_BLK		(0x1 << 14)
+#define NDCR_ND_ARB_EN		(0x1 << 12)
+
+#define NDSR_MASK		(0xfff)
+#define NDSR_RDY		(0x1 << 11)
+#define NDSR_CS0_PAGED		(0x1 << 10)
+#define NDSR_CS1_PAGED		(0x1 << 9)
+#define NDSR_CS0_CMDD		(0x1 << 8)
+#define NDSR_CS1_CMDD		(0x1 << 7)
+#define NDSR_CS0_BBD		(0x1 << 6)
+#define NDSR_CS1_BBD		(0x1 << 5)
+#define NDSR_DBERR		(0x1 << 4)
+#define NDSR_SBERR		(0x1 << 3)
+#define NDSR_WRDREQ		(0x1 << 2)
+#define NDSR_RDDREQ		(0x1 << 1)
+#define NDSR_WRCMDREQ		(0x1)
+
+#define NDCB0_AUTO_RS		(0x1 << 25)
+#define NDCB0_CSEL		(0x1 << 24)
+#define NDCB0_CMD_TYPE_MASK	(0x7 << 21)
+#define NDCB0_CMD_TYPE(x)	(((x) << 21) & NDCB0_CMD_TYPE_MASK)
+#define NDCB0_NC		(0x1 << 20)
+#define NDCB0_DBC		(0x1 << 19)
+#define NDCB0_ADDR_CYC_MASK	(0x7 << 16)
+#define NDCB0_ADDR_CYC(x)	(((x) << 16) & NDCB0_ADDR_CYC_MASK)
+#define NDCB0_CMD2_MASK		(0xff << 8)
+#define NDCB0_CMD1_MASK		(0xff)
+#define NDCB0_ADDR_CYC_SHIFT	(16)
+
+/* dma-able I/O address for the NAND data and commands */
+#define NDCB0_DMA_ADDR		(0x43100048)
+#define NDDB_DMA_ADDR		(0x43100040)
+
+/* macros for registers read/write */
+#define nand_writel(info, off, val)	\
+	__raw_writel((val), (info)->mmio_base + (off))
+
+#define nand_readl(info, off)		\
+	__raw_readl((info)->mmio_base + (off))
+
+/* error code and state */
+enum {
+	ERR_NONE	= 0,
+	ERR_DMABUSERR	= -1,
+	ERR_SENDCMD	= -2,
+	ERR_DBERR	= -3,
+	ERR_BBERR	= -4,
+	ERR_BUSY	= -5,
+};
+
+enum {
+	STATE_CMD_SEND = 1,
+	STATE_CMD_HANDLE,
+	STATE_DMA_TRANSFER,
+	STATE_DMA_DONE,
+	STATE_READY,
+	STATE_SUSPENDED,
+	STATE_DATA_TRANSFER,
+};
+
+struct pxa3xx_nand_timing {
+	unsigned int	tCH;  /* Enable signal hold time */
+	unsigned int	tCS;  /* Enable signal setup time */
+	unsigned int	tWH;  /* ND_nWE high duration */
+	unsigned int	tWP;  /* ND_nWE pulse time */
+	unsigned int	tRH;  /* ND_nRE high duration */
+	unsigned int	tRP;  /* ND_nRE pulse width */
+	unsigned int	tR;   /* ND_nWE high to ND_nRE low for read */
+	unsigned int	tWHR; /* ND_nWE high to ND_nRE low for status read */
+	unsigned int	tAR;  /* ND_ALE low to ND_nRE low delay */
+};
+
+struct pxa3xx_nand_cmdset {
+	uint16_t	read1;
+	uint16_t	read2;
+	uint16_t	program;
+	uint16_t	read_status;
+	uint16_t	read_id;
+	uint16_t	erase;
+	uint16_t	reset;
+	uint16_t	lock;
+	uint16_t	unlock;
+	uint16_t	lock_status;
+};
+
+struct pxa3xx_nand_flash {
+	struct pxa3xx_nand_timing *timing; /* NAND Flash timing */
+	struct pxa3xx_nand_cmdset *cmdset;
+
+	uint32_t page_per_block;/* Pages per block (PG_PER_BLK) */
+	uint32_t page_size;	/* Page size in bytes (PAGE_SZ) */
+	uint32_t flash_width;	/* Width of Flash memory (DWIDTH_M) */
+	uint32_t dfc_width;	/* Width of flash controller(DWIDTH_C) */
+	uint32_t num_blocks;	/* Number of physical blocks in Flash */
+	uint32_t chip_id;
+
+	/* NOTE: these are automatically calculated, do not define */
+	size_t		oob_size;
+	size_t		read_id_bytes;
+
+	unsigned int	col_addr_cycles;
+	unsigned int	row_addr_cycles;
+};
+
+struct pxa3xx_nand_info {
+	struct nand_chip	nand_chip;
+
+	struct platform_device	 *pdev;
+	struct pxa3xx_nand_flash *flash_info;
+
+	struct clk		*clk;
+	void __iomem		*mmio_base;
+
+	unsigned int 		buf_start;
+	unsigned int		buf_count;
+
+	/* DMA information */
+	unsigned char		*data_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 */
+	unsigned int		state;
+
+	int			use_ecc;	/* use HW ECC ? */
+	int			use_dma;	/* use DMA ? */
+
+	size_t			data_size;	/* data size in FIFO */
+	unsigned int		cur_cmd;
+	int 			retcode;
+	struct completion 	cmd_complete;
+
+	/* generated NDCBx register values */
+	uint32_t		ndcb0;
+	uint32_t		ndcb1;
+	uint32_t		ndcb2;
+};
+
+static int use_dma = 0;
+module_param(use_dma, bool, 0444);
+MODULE_PARM_DESC(use_dma, "enable DMA for data transfering to/from NAND HW");
+
+static struct pxa3xx_nand_cmdset smallpage_cmdset = {
+	.read1		= 0x0000,
+	.read2		= 0x0050,
+	.program	= 0x1080,
+	.read_status	= 0x0070,
+	.read_id	= 0x0090,
+	.erase		= 0xD060,
+	.reset		= 0x00FF,
+	.lock		= 0x002A,
+	.unlock		= 0x2423,
+	.lock_status	= 0x007A,
+};
+
+static struct pxa3xx_nand_cmdset largepage_cmdset = {
+	.read1		= 0x3000,
+	.read2		= 0x0050,
+	.program	= 0x1080,
+	.read_status	= 0x0070,
+	.read_id	= 0x0090,
+	.erase		= 0xD060,
+	.reset		= 0x00FF,
+	.lock		= 0x002A,
+	.unlock		= 0x2423,
+	.lock_status	= 0x007A,
+};
+
+static struct pxa3xx_nand_timing samsung512MbX16_timing = {
+	.tCH	= 10,
+	.tCS	= 0,
+	.tWH	= 20,
+	.tWP	= 40,
+	.tRH	= 30,
+	.tRP	= 40,
+	.tR	= 11123,
+	.tWHR	= 110,
+	.tAR	= 10,
+};
+
+static struct pxa3xx_nand_flash samsung512MbX16 = {
+	.timing		= &samsung512MbX16_timing,
+	.cmdset		= &smallpage_cmdset,
+	.page_per_block	= 32,
+	.page_size	= 512,
+	.flash_width	= 16,
+	.dfc_width	= 16,
+	.num_blocks	= 4096,
+	.chip_id	= 0x46ec,
+};
+
+static struct pxa3xx_nand_timing micron_timing = {
+	.tCH	= 10,
+	.tCS	= 25,
+	.tWH	= 15,
+	.tWP	= 25,
+	.tRH	= 15,
+	.tRP	= 25,
+	.tR	= 25000,
+	.tWHR	= 60,
+	.tAR	= 10,
+};
+
+static struct pxa3xx_nand_flash micron1GbX8 = {
+	.timing		= &micron_timing,
+	.cmdset		= &largepage_cmdset,
+	.page_per_block	= 64,
+	.page_size	= 2048,
+	.flash_width	= 8,
+	.dfc_width	= 8,
+	.num_blocks	= 1024,
+	.chip_id	= 0xa12c,
+};
+
+static struct pxa3xx_nand_flash micron1GbX16 = {
+	.timing		= &micron_timing,
+	.cmdset		= &largepage_cmdset,
+	.page_per_block	= 64,
+	.page_size	= 2048,
+	.flash_width	= 16,
+	.dfc_width	= 16,
+	.num_blocks	= 1024,
+	.chip_id	= 0xb12c,
+};
+
+static struct pxa3xx_nand_flash *builtin_flash_types[] = {
+	&samsung512MbX16,
+	&micron1GbX8,
+	&micron1GbX16,
+};
+
+#define NDTR0_tCH(c)	(min((c), 7) << 19)
+#define NDTR0_tCS(c)	(min((c), 7) << 16)
+#define NDTR0_tWH(c)	(min((c), 7) << 11)
+#define NDTR0_tWP(c)	(min((c), 7) << 8)
+#define NDTR0_tRH(c)	(min((c), 7) << 3)
+#define NDTR0_tRP(c)	(min((c), 7) << 0)
+
+#define NDTR1_tR(c)	(min((c), 65535) << 16)
+#define NDTR1_tWHR(c)	(min((c), 15) << 4)
+#define NDTR1_tAR(c)	(min((c), 15) << 0)
+
+/* convert nano-seconds to nand flash controller clock cycles */
+#define ns2cycle(ns, clk)	(int)(((ns) * (clk / 1000000) / 1000) + 1)
+
+static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info,
+				   struct pxa3xx_nand_timing *t)
+{
+	unsigned long nand_clk = clk_get_rate(info->clk);
+	uint32_t ndtr0, ndtr1;
+
+	ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) |
+		NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) |
+		NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) |
+		NDTR0_tWP(ns2cycle(t->tWP, nand_clk)) |
+		NDTR0_tRH(ns2cycle(t->tRH, nand_clk)) |
+		NDTR0_tRP(ns2cycle(t->tRP, nand_clk));
+
+	ndtr1 = NDTR1_tR(ns2cycle(t->tR, nand_clk)) |
+		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
+		NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
+
+	nand_writel(info, NDTR0CS0, ndtr0);
+	nand_writel(info, NDTR1CS0, ndtr1);
+}
+
+#define WAIT_EVENT_TIMEOUT	10
+
+static int wait_for_event(struct pxa3xx_nand_info *info, uint32_t event)
+{
+	int timeout = WAIT_EVENT_TIMEOUT;
+	uint32_t ndsr;
+
+	while (timeout--) {
+		ndsr = nand_readl(info, NDSR) & NDSR_MASK;
+		if (ndsr & event) {
+			nand_writel(info, NDSR, ndsr);
+			return 0;
+		}
+		udelay(10);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info,
+			uint16_t cmd, int column, int page_addr)
+{
+	struct pxa3xx_nand_flash *f = info->flash_info;
+	struct pxa3xx_nand_cmdset *cmdset = f->cmdset;
+
+	/* calculate data size */
+	switch (f->page_size) {
+	case 2048:
+		info->data_size = (info->use_ecc) ? 2088 : 2112;
+		break;
+	case 512:
+		info->data_size = (info->use_ecc) ? 520 : 528;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* generate values for NDCBx registers */
+	info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
+	info->ndcb0 |= NDCB0_ADDR_CYC(f->row_addr_cycles + f->col_addr_cycles);
+
+	if (f->col_addr_cycles == 2) {
+		/* large block, 2 cycles for column address
+		 * row address starts from 3rd cycle
+		 */
+		info->ndcb1 |= (page_addr << 16) | (column & 0xffff);
+		if (f->row_addr_cycles == 3)
+			info->ndcb2 = (page_addr >> 16) & 0xff;
+	} else
+		/* small block, 1 cycles for column address
+		 * row address starts from 2nd cycle
+		 */
+		info->ndcb1 = (page_addr << 8) | (column & 0xff);
+
+	if (cmd == cmdset->program)
+		info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS;
+
+	info->cur_cmd = cmd;
+	return 0;
+}
+
+static int prepare_erase_cmd(struct pxa3xx_nand_info *info,
+			uint16_t cmd, int page_addr)
+{
+	info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
+	info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3);
+	info->ndcb1 = page_addr;
+
+	info->cur_cmd = cmd;
+	return 0;
+}
+
+static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd)
+{
+	struct pxa3xx_nand_cmdset *cmdset = info->flash_info->cmdset;
+
+	info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
+
+	if (cmd == cmdset->read_id) {
+		info->ndcb0 |= NDCB0_CMD_TYPE(3);
+		info->data_size = 8;
+	} else if (cmd == cmdset->read_status) {
+		info->ndcb0 |= NDCB0_CMD_TYPE(4);
+		info->data_size = 8;
+	} else if (cmd == cmdset->reset || cmd == cmdset->lock ||
+		   cmd == cmdset->unlock) {
+		info->ndcb0 |= NDCB0_CMD_TYPE(5);
+	} else
+		return -EINVAL;
+
+	info->cur_cmd = cmd;
+	return 0;
+}
+
+static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
+{
+	uint32_t ndcr;
+
+	ndcr = nand_readl(info, NDCR);
+	nand_writel(info, NDCR, ndcr & ~int_mask);
+}
+
+static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
+{
+	uint32_t ndcr;
+
+	ndcr = nand_readl(info, NDCR);
+	nand_writel(info, NDCR, ndcr | int_mask);
+}
+
+/* NOTE: it is a must to set ND_RUN firstly, then write command buffer
+ * otherwise, it does not work
+ */
+static int write_cmd(struct pxa3xx_nand_info *info)
+{
+	uint32_t ndcr;
+
+	/* clear status bits and run */
+	nand_writel(info, NDSR, NDSR_MASK);
+
+	ndcr = info->reg_ndcr;
+
+	ndcr |= info->use_ecc ? NDCR_ECC_EN : 0;
+	ndcr |= info->use_dma ? NDCR_DMA_EN : 0;
+	ndcr |= NDCR_ND_RUN;
+
+	nand_writel(info, NDCR, ndcr);
+
+	if (wait_for_event(info, NDSR_WRCMDREQ)) {
+		printk(KERN_ERR "timed out writing command\n");
+		return -ETIMEDOUT;
+	}
+
+	nand_writel(info, NDCB0, info->ndcb0);
+	nand_writel(info, NDCB0, info->ndcb1);
+	nand_writel(info, NDCB0, info->ndcb2);
+	return 0;
+}
+
+/* NOTE: {read, write}_fifo_pio() assume the buffer is 4-byte aligned,
+ * and data_size are 4-byte multiples as well
+ */
+static void read_fifo_pio(struct pxa3xx_nand_info *info)
+{
+	uint32_t *buff = (uint32_t *)info->data_buff;
+	int i, data_size = info->data_size;
+
+	BUG_ON((data_size % sizeof(uint32_t)) != 0);
+
+	for (i = 0; i < data_size / sizeof(uint32_t); i++)
+		*buff++ = __raw_readl(info->mmio_base + NDDB);
+}
+
+static void write_fifo_pio(struct pxa3xx_nand_info *info)
+{
+	uint32_t *buff = (uint32_t *)info->data_buff;
+	int i, data_size = info->data_size;
+
+	BUG_ON((data_size % sizeof(uint32_t)) != 0);
+
+	for (i = 0; i < data_size / sizeof(uint32_t); i++)
+		__raw_writel(*buff++, info->mmio_base + NDDB);
+}
+
+static int handle_data_pio(struct pxa3xx_nand_info *info)
+{
+	struct pxa3xx_nand_cmdset *cmdset = info->flash_info->cmdset;
+	int ret, timeout = CHIP_DELAY_TIMEOUT;
+
+	if (info->cur_cmd == cmdset->program) {
+		write_fifo_pio(info);
+
+		enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);
+
+		ret = wait_for_completion_timeout(&info->cmd_complete, timeout);
+		if (!ret) {
+			printk(KERN_ERR "program command time out\n");
+			return -1;
+		}
+	} else
+		read_fifo_pio(info);
+
+	info->state = STATE_READY;
+	return 0;
+}
+
+static void setup_data_dma(struct pxa3xx_nand_info *info)
+{
+	struct pxa3xx_nand_flash * f = info->flash_info;
+	struct pxa_dma_desc *desc = info->data_desc;
+	int dma_len = ALIGN(info->data_size, 32);
+
+	desc->ddadr = DDADR_STOP;
+	desc->dcmd = DCMD_ENDIRQEN | DCMD_WIDTH4 | DCMD_BURST32 | dma_len;
+
+	if (info->cur_cmd == f->cmdset->program) {
+		desc->dsadr = info->data_buff_phys;
+		desc->dtadr = NDDB_DMA_ADDR;
+		desc->dcmd |= DCMD_INCSRCADDR | DCMD_FLOWTRG;
+	} else {
+		desc->dtadr = info->data_buff_phys;
+		desc->dsadr = NDDB_DMA_ADDR;
+		desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC;
+	}
+}
+
+static void start_data_dma(struct pxa3xx_nand_info *info)
+{
+	DRCMR97 = DRCMR_MAPVLD | info->data_dma_ch;
+	DDADR(info->data_dma_ch) = info->data_desc_addr;
+	DCSR(info->data_dma_ch) |= DCSR_RUN;
+}
+
+static void pxa3xx_nand_data_dma_irq(int channel, void *data)
+{
+	struct pxa3xx_nand_info *info = data;
+	struct pxa3xx_nand_flash *f = info->flash_info;
+	uint32_t dcsr, intm;
+
+	dcsr = DCSR(channel);
+	DCSR(channel) = dcsr;
+
+	intm = NDSR_CS0_BBD | NDSR_CS0_CMDD;
+
+	if (dcsr & DCSR_BUSERR) {
+		info->retcode = ERR_DMABUSERR;
+		complete(&info->cmd_complete);
+	}
+
+	if (info->cur_cmd == f->cmdset->program) {
+		info->state = STATE_DMA_DONE;
+		enable_int(info, intm);
+	} else {
+		info->state = STATE_READY;
+		complete(&info->cmd_complete);
+	}
+}
+
+static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
+{
+	unsigned int status, event, intm;
+	struct pxa3xx_nand_info *info = devid;
+
+	intm = NDSR_CS0_BBD | NDSR_CS0_CMDD;
+	event = NDSR_CS0_BBD | NDSR_CS0_CMDD;
+
+	status = nand_readl(info, NDSR);
+
+	if (status & (NDSR_RDDREQ | NDSR_DBERR)) {
+		if (status & NDSR_DBERR)
+			info->retcode = ERR_DBERR;
+
+		disable_int(info, NDSR_RDDREQ | NDSR_DBERR);
+
+		if (info->use_dma) {
+			info->state = STATE_DMA_TRANSFER;
+			start_data_dma(info);
+		} else {
+			info->state = STATE_DATA_TRANSFER;
+			complete(&info->cmd_complete);
+		}
+	} else if (status & NDSR_WRDREQ) {
+		disable_int(info, NDSR_WRDREQ);
+		if (info->use_dma) {
+			info->state = STATE_DMA_TRANSFER;
+			start_data_dma(info);
+		} else {
+			info->state = STATE_DATA_TRANSFER;
+			complete(&info->cmd_complete);
+		}
+	} else if (status & event) {
+		if (status & NDSR_CS0_BBD)
+			info->retcode = ERR_BBERR;
+
+		disable_int(info, intm);
+		info->state = STATE_READY;
+		complete(&info->cmd_complete);
+	}
+	nand_writel(info, NDSR, status);
+	return IRQ_HANDLED;
+}
+
+static int pxa3xx_nand_do_cmd(struct pxa3xx_nand_info *info, uint32_t event)
+{
+	uint32_t ndcr;
+	int ret, timeout = CHIP_DELAY_TIMEOUT;
+
+	info->state = STATE_CMD_SEND;
+
+	if (write_cmd(info)) {
+		info->retcode = ERR_SENDCMD;
+		goto fail_stop;
+	}
+
+	info->state = STATE_CMD_HANDLE;
+
+	if (info->use_dma)
+		setup_data_dma(info);
+
+	enable_int(info, event);
+
+	ret = wait_for_completion_timeout(&info->cmd_complete, timeout);
+	if (!ret) {
+		printk(KERN_ERR "command execution timed out\n");
+		info->retcode = ERR_SENDCMD;
+		goto fail_stop;
+	}
+
+	if (info->use_dma == 0 && info->data_size > 0)
+		if (handle_data_pio(info))
+			goto fail_stop;
+
+	return 0;
+
+fail_stop:
+	ndcr = nand_readl(info, NDCR);
+	nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN);
+	udelay(10);
+	return -ETIMEDOUT;
+}
+
+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--)
+		if (*buf++ != 0xff)
+			return 0;
+	return 1;
+}
+
+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_flash * flash_info = info->flash_info;
+	struct pxa3xx_nand_cmdset *cmdset = flash_info->cmdset;
+	int ret;
+
+	info->ndcb0 = 0;
+	info->ndcb1 = 0;
+	info->ndcb2 = 0;
+	info->use_dma = 0;
+	info->use_ecc = 0;
+	info->cur_cmd = -1;
+	info->data_size = 0;
+	info->state = STATE_READY;
+
+	init_completion(&info->cmd_complete);
+
+	switch (command) {
+	case NAND_CMD_READOOB:
+		/* disable HW ECC to get all the OOB data */
+		info->use_ecc = 0;
+		info->use_dma = use_dma ? 1 : 0;
+		info->buf_count = mtd->writesize + mtd->oobsize;
+		info->buf_start = mtd->writesize + column;
+
+		if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr))
+			break;
+
+		pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR);
+
+		/* We only are OOB, so if the data has error, does not matter */
+		if (info->retcode == ERR_DBERR)
+			info->retcode = ERR_NONE;
+		break;
+
+	case NAND_CMD_READ0:
+		info->use_ecc = 1;
+		info->use_dma = use_dma ? 1 : 0;
+		info->retcode = ERR_NONE;
+		info->buf_start = column;
+		info->buf_count = mtd->writesize + mtd->oobsize;
+		memset(info->data_buff, 0xFF, info->buf_count);
+
+		if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr))
+			break;
+
+		pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR);
+
+		if (info->retcode == ERR_DBERR) {
+			/* for blank page (all 0xff), HW will calculate its ECC as
+			 * 0, which is different from the ECC information within
+			 * OOB, ignore such double bit errors
+			 */
+			if (is_buf_blank(info->data_buff, mtd->writesize))
+				info->retcode = ERR_NONE;
+		}
+		break;
+	case NAND_CMD_SEQIN:
+		info->buf_start = column;
+		info->buf_count = mtd->writesize + mtd->oobsize;
+		memset(info->data_buff, 0xff, info->buf_count);
+
+		/* save column/page_addr for next CMD_PAGEPROG */
+		info->seqin_column = column;
+		info->seqin_page_addr = page_addr;
+		break;
+	case NAND_CMD_PAGEPROG:
+		info->use_ecc = (info->seqin_column >= mtd->writesize) ? 0 : 1;
+		info->use_dma = use_dma ? 1 : 0;
+
+		if (prepare_read_prog_cmd(info, cmdset->program,
+				info->seqin_column, info->seqin_page_addr))
+			break;
+
+		pxa3xx_nand_do_cmd(info, NDSR_WRDREQ);
+		break;
+	case NAND_CMD_ERASE1:
+		if (prepare_erase_cmd(info, cmdset->erase, page_addr))
+			break;
+
+		pxa3xx_nand_do_cmd(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);
+		break;
+	case NAND_CMD_ERASE2:
+		break;
+	case NAND_CMD_READID:
+		info->use_dma = 0;
+		info->buf_count = flash_info->read_id_bytes;
+		info->buf_start = 0;
+
+		if (prepare_other_cmd(info, cmdset->read_id))
+			break;
+
+		pxa3xx_nand_do_cmd(info, NDSR_RDDREQ);
+		break;
+	case NAND_CMD_STATUS:
+		info->use_dma = 0;
+		info->buf_count = 1;
+		info->buf_start = 0;
+		if (prepare_other_cmd(info, cmdset->read_status))
+			break;
+
+		pxa3xx_nand_do_cmd(info, NDSR_RDDREQ);
+		break;
+	case NAND_CMD_RESET:
+		if (prepare_other_cmd(info, cmdset->reset))
+			break;
+		
+		ret = pxa3xx_nand_do_cmd(info, NDSR_CS0_CMDD);
+		if (ret == 0) {
+			int timeout = 2;
+			uint32_t ndcr;
+
+			while (timeout--) {
+				if (nand_readl(info, NDSR) & NDSR_RDY)
+					break;
+				msleep(10);
+			}
+
+			ndcr = nand_readl(info, NDCR);
+			nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN);
+		}
+		break;
+	default:
+		printk(KERN_ERR "non-supported command.\n");
+		break;
+	}
+
+	if (info->retcode == ERR_DBERR) {
+		printk(KERN_ERR "double bit error @ page %08x\n", page_addr);
+		info->retcode = ERR_NONE;
+	}
+
+	if (info->retcode != ERR_NONE)
+		info->state = STATE_READY;
+}
+
+static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
+{
+	struct pxa3xx_nand_info *info = mtd->priv;
+	char retval = 0xFF;
+
+	if (info->buf_start < info->buf_count)
+		/* Has just send a new command? */
+		retval = info->data_buff[info->buf_start++];
+
+	return retval;
+}
+
+static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)
+{
+	struct pxa3xx_nand_info *info = mtd->priv;
+	u16 retval = 0xFFFF;
+
+	if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) {
+		retval = *((u16 *)(info->data_buff+info->buf_start));
+		info->buf_start += 2;
+	}
+	return retval;
+}
+
+static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct pxa3xx_nand_info *info = mtd->priv;
+	int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
+
+	memcpy(buf, info->data_buff + info->buf_start, real_len);
+	info->buf_start += real_len;
+}
+
+static void pxa3xx_nand_write_buf(struct mtd_info *mtd,
+		const uint8_t *buf, int len)
+{
+	struct pxa3xx_nand_info *info = mtd->priv;
+	int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
+
+	memcpy(info->data_buff + info->buf_start, buf, real_len);
+	info->buf_start += real_len;
+}
+
+static int pxa3xx_nand_verify_buf(struct mtd_info *mtd,
+		const uint8_t *buf, int len)
+{
+	return 0;
+}
+
+static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+	return;
+}
+
+static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
+{
+	struct pxa3xx_nand_info *info = mtd->priv;
+
+	/* pxa3xx_nand_send_command has waited for command complete */
+	if (this->state == FL_WRITING || this->state == FL_ERASING) {
+		if (info->retcode == ERR_NONE)
+			return 0;
+		else {
+			/*
+			 * any error make it return 0x01 which will tell
+			 * the caller the erase and write fail
+			 */
+			return 0x01;
+		}
+	}
+
+	return 0;
+}
+
+static void pxa3xx_nand_ecc_hwctl(struct mtd_info *mtd, int mode)
+{
+	return;
+}
+
+static int pxa3xx_nand_ecc_calculate(struct mtd_info *mtd,
+		const uint8_t *dat, uint8_t *ecc_code)
+{
+	return 0;
+}
+
+static int pxa3xx_nand_ecc_correct(struct mtd_info *mtd,
+		uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc)
+{
+	struct pxa3xx_nand_info *info = mtd->priv;
+	/*
+	 * Any error include ERR_SEND_CMD, ERR_DBERR, ERR_BUSERR, we
+	 * consider it as a ecc error which will tell the caller the
+	 * read fail We have distinguish all the errors, but the
+	 * nand_read_ecc only check this function return value
+	 */
+	if (info->retcode != ERR_NONE)
+		return -1;
+
+	return 0;
+}
+
+static int dfc_readid(struct pxa3xx_nand_info *info, uint32_t *id)
+{
+	struct pxa3xx_nand_flash *f = info->flash_info;
+	struct pxa3xx_nand_cmdset *cmdset = f->cmdset;
+	uint32_t ndcr;
+
+	info->ndcb0 = 0;
+	info->ndcb1 = 0;
+	info->ndcb2 = 0;
+	info->data_size = 0;
+
+	if (prepare_other_cmd(info, cmdset->read_id)) {
+		printk(KERN_ERR "failed to prepare command\n");
+		return -EINVAL;
+	}
+
+	/* Send command */
+	if (write_cmd(info))
+		goto fail_timeout;
+
+	/* Wait for CMDDM(command done successfully) */
+	if (wait_for_event(info, NDSR_RDDREQ))
+		goto fail_timeout;
+
+	read_fifo_pio(info);
+	*id = info->data_buff[0] | (info->data_buff[1] << 8);
+	return 0;
+
+fail_timeout:
+	ndcr = nand_readl(info, NDCR);
+	nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN);
+	udelay(10);
+	return -ETIMEDOUT;
+}
+
+static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
+				    struct pxa3xx_nand_flash *f)
+{
+	uint32_t ndcr = 0x00000FFF; /* disable all interrupts */
+
+	if (f->page_size != 2048 && f->page_size != 512)
+		return -EINVAL;
+
+	if (f->flash_width != 16 && f->flash_width != 8)
+		return -EINVAL;
+
+	/* calculate flash information */
+	f->oob_size = (f->page_size == 2048) ? 64 : 16;
+	f->read_id_bytes = (f->page_size == 2048) ? 4 : 2;
+
+	/* calculate addressing information */
+	f->col_addr_cycles = (f->page_size == 2048) ? 2 : 1;
+
+	if (f->num_blocks * f->page_per_block > 65536)
+		f->row_addr_cycles = 3;
+	else
+		f->row_addr_cycles = 2;
+
+	ndcr |= NDCR_ND_ARB_EN;
+	ndcr |= (f->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(f->read_id_bytes);
+	ndcr |= NDCR_SPARE_EN; /* enable spare by default */
+
+	info->reg_ndcr = ndcr;
+
+	pxa3xx_nand_set_timing(info, f->timing);
+	info->flash_info = f;
+	return 0;
+}
+
+static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info)
+{
+	struct pxa3xx_nand_flash *f;
+	uint32_t id;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(builtin_flash_types); i++) {
+
+		f = builtin_flash_types[i];
+
+		if (pxa3xx_nand_config_flash(info, f))
+			continue;
+
+		if (dfc_readid(info, &id))
+			continue;
+
+		if (id == f->chip_id)
+			return 0;
+	}
+
+	return -ENODEV;
+}
+
+/* the maximum possible buffer size for large page with OOB data
+ * is: 2048 + 64 = 2112 bytes, allocate a page here for both the
+ * data buffer and the DMA descriptor
+ */
+#define MAX_BUFF_SIZE	PAGE_SIZE
+
+static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
+{
+	struct platform_device *pdev = info->pdev;
+	int data_desc_offset = MAX_BUFF_SIZE - sizeof(struct pxa_dma_desc);
+
+	if (use_dma == 0) {
+		info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL);
+		if (info->data_buff == NULL)
+			return -ENOMEM;
+		return 0;
+	}
+
+	info->data_buff = dma_alloc_coherent(&pdev->dev, MAX_BUFF_SIZE,
+				&info->data_buff_phys, GFP_KERNEL);
+	if (info->data_buff == NULL) {
+		dev_err(&pdev->dev, "failed to allocate dma buffer\n");
+		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;
+
+	info->data_dma_ch = pxa_request_dma("nand-data", DMA_PRIO_LOW,
+				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,
+				info->data_buff, info->data_buff_phys);
+		return info->data_dma_ch;
+	}
+
+	return 0;
+}
+
+static struct nand_ecclayout hw_smallpage_ecclayout = {
+	.eccbytes = 6,
+	.eccpos = {8, 9, 10, 11, 12, 13 },
+	.oobfree = { {2, 6} }
+};
+
+static struct nand_ecclayout hw_largepage_ecclayout = {
+	.eccbytes = 24,
+	.eccpos = {
+		40, 41, 42, 43, 44, 45, 46, 47,
+		48, 49, 50, 51, 52, 53, 54, 55,
+		56, 57, 58, 59, 60, 61, 62, 63},
+	.oobfree = { {2, 38} }
+};
+
+static void pxa3xx_nand_init_mtd(struct mtd_info *mtd,
+				 struct pxa3xx_nand_info *info)
+{
+	struct pxa3xx_nand_flash *f = info->flash_info;
+	struct nand_chip *this = &info->nand_chip;
+
+	this->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16: 0;
+
+	this->waitfunc		= pxa3xx_nand_waitfunc;
+	this->select_chip	= pxa3xx_nand_select_chip;
+	this->dev_ready		= pxa3xx_nand_dev_ready;
+	this->cmdfunc		= pxa3xx_nand_cmdfunc;
+	this->read_word		= pxa3xx_nand_read_word;
+	this->read_byte		= pxa3xx_nand_read_byte;
+	this->read_buf		= pxa3xx_nand_read_buf;
+	this->write_buf		= pxa3xx_nand_write_buf;
+	this->verify_buf	= pxa3xx_nand_verify_buf;
+
+	this->ecc.mode		= NAND_ECC_HW;
+	this->ecc.hwctl		= pxa3xx_nand_ecc_hwctl;
+	this->ecc.calculate	= pxa3xx_nand_ecc_calculate;
+	this->ecc.correct	= pxa3xx_nand_ecc_correct;
+	this->ecc.size		= f->page_size;
+
+	if (f->page_size == 2048)
+		this->ecc.layout = &hw_largepage_ecclayout;
+	else
+		this->ecc.layout = &hw_smallpage_ecclayout;
+
+	this->chip_delay= 25;
+}
+
+/* MHN_OBM_V2 is related to BBT in MOBM V2
+ * MHN_OBM_V3 is related to BBT in MOBM V3
+ */
+enum {
+	MHN_OBM_NULL = 0,
+	MHN_OBM_V1,
+	MHN_OBM_V2,
+	MHN_OBM_V3,
+	MHN_OBM_INVAL
+} MHN_OBM_TYPE;
+
+static uint8_t scan_main_bbt_pattern[] = { 'p', 'x', 'a', '1' };
+static uint8_t scan_mirror_bbt_pattern[] = { '0', 'a', 'x', 'p' };
+
+static struct nand_bbt_descr monahans_bbt_main = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+			| NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.veroffs = 6,
+	.maxblocks = 2,
+        .offs = 2,
+        .len = 4,
+        .pattern = scan_main_bbt_pattern,
+};
+
+static struct nand_bbt_descr monahans_bbt_mirror = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+			| NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.veroffs = 6,
+	.maxblocks = 2,
+        .offs = 2,
+        .len = 4,
+        .pattern = scan_mirror_bbt_pattern,
+};
+
+/*
+ * The relocation table management is different between MOBM V2 and V3.
+ *
+ * MOBM V2 is applied on chips taped out before MhnLV A0.
+ * MOBM V3 is applied on chips taped out after MhnLV A0. It's also applied
+ * on MhnLV A0.
+ */
+static int calc_obm_ver(void)
+{
+	unsigned int	cpuid;
+	
+	cpuid = read_cpuid(CPUID_ID);
+	/* It's not xscale chip. */
+	if ((cpuid & 0xFFFF0000) != 0x69050000)
+		return MHN_OBM_INVAL;
+	/* It's MhnP Ax */
+	if ((cpuid & 0x0000FFF0) == 0x00006420)
+		return MHN_OBM_V2;
+	/* It's MhnP Bx */
+	if ((cpuid & 0x0000FFF0) == 0x00006820) {
+		if ((cpuid & 0x0F) <= 6)
+			return MHN_OBM_V2;
+		else
+			return MHN_OBM_V3;
+	}
+	/* It's MhnL Ax */
+	if ((cpuid & 0x0000FFF0) == 0x00006880) {
+		if ((cpuid & 0x0F) == 0)
+			return MHN_OBM_V2;
+		else
+			return MHN_OBM_V3;
+	}
+	/* It's MhnLV Ax */
+	if ((cpuid & 0x0000FFF0) == 0x00006890)
+		return MHN_OBM_V3;
+	return MHN_OBM_INVAL;
+}
+static int pxa3xx_nand_probe(struct platform_device *pdev)
+{
+	struct pxa3xx_nand_platform_data *pdata;
+	struct pxa3xx_nand_info *info;
+	struct nand_chip *this;
+	struct mtd_info *mtd;
+	struct resource *res;
+	int ret = 0;
+	int obm;
+
+	pdata = pdev->dev.platform_data;
+
+	if (pdata == NULL) {
+		dev_err(&pdev->dev, "no platform data defined\n");
+		return -ENODEV;
+	}
+
+	mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct pxa3xx_nand_info),
+			GFP_KERNEL);
+	if (mtd == NULL) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		return -ENOMEM;
+        }
+
+	info = (struct pxa3xx_nand_info *)(&mtd[1]);
+	info->pdev = pdev;
+
+	this = &info->nand_chip;
+	mtd->priv = info;
+
+	info->clk = clk_get(&pdev->dev, "NANDCLK");
+	if (IS_ERR(info->clk)) {
+		dev_err(&pdev->dev, "failed to get nand clock\n");
+		ret = PTR_ERR(info->clk);
+		goto free_mtd;
+	}
+	clk_enable(info->clk);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "no IO memory resource defined\n");
+		ret = -ENODEV;
+		goto fail_put_clk;
+	}
+	res = request_mem_region(res->start, res->end - res->start + 1,
+			pdev->name);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "failed to request memory resource\n");
+		ret = -EBUSY;
+		goto fail_put_clk;
+	}
+	info->mmio_base = ioremap(res->start, res->end - res->start + 1);
+	if (info->mmio_base == NULL) {
+		dev_err(&pdev->dev, "ioremap() failed\n");
+		ret = -ENODEV;
+		goto fail_free_res;
+	}
+	ret = pxa3xx_nand_init_buff(info);
+	if (ret)
+		goto fail_free_io;
+	ret = request_irq(IRQ_NAND, pxa3xx_nand_irq, IRQF_DISABLED,
+				pdev->name, info);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to request IRQ\n");
+		goto free_buf;
+	}
+	ret = pxa3xx_nand_detect_flash(info);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to detect flash\n");
+		ret = -ENODEV;
+		goto fail_free_io;
+	}
+	pxa3xx_nand_init_mtd(mtd, info);
+	platform_set_drvdata(pdev, mtd);
+	if (nand_scan(mtd, 1)) {
+		printk(KERN_ERR "Nand scan failed\n");
+		ret = -ENXIO;
+		goto free_irq;
+	}
+
+	/* There is a potential limitation that no more partition can be
+	 * added between MassStorage and BBT(last block).
+	 *
+	 * The last 127 blocks is reserved for relocation table, they aren't
+	 * statistical data of mtd size and chip size.
+	 *
+	 * BBT partitions contains 4 blocks. Two blocks are used to store
+	 * main descriptor, the other two are used to store mirror descriptor.
+	 */
+
+	/* boot loader partition */
+	obm = calc_obm_ver();
+	if (obm == MHN_OBM_V3) {
+		pdata->parts[0].size = 0x60000;
+	}else{
+		pdata->parts[0].size = 0x40000;
+	}
+
+	/* kernel partition */
+	pdata->parts[1].offset = pdata->parts[0].offset + pdata->parts[0].size;
+
+	/* rootfs partition */
+	pdata->parts[2].offset = pdata->parts[1].offset + pdata->parts[1].size;
+
+	/* bbt partition */
+	pdata->parts[pdata->nr_parts - 1].size = (monahans_bbt_main.maxblocks
+					+ monahans_bbt_mirror.maxblocks)
+					<< this->phys_erase_shift;
+	pdata->parts[pdata->nr_parts - 1].offset = this->chipsize
+					- pdata->parts[pdata->nr_parts - 1].size;
+
+	/* mass storage partition */
+	pdata->parts[pdata->nr_parts - 2].offset = pdata->parts[pdata->nr_parts - 3].offset
+					+ pdata->parts[pdata->nr_parts - 3].size;
+	pdata->parts[pdata->nr_parts - 2].size = this->chipsize
+					- pdata->parts[pdata->nr_parts - 2].offset
+					- pdata->parts[pdata->nr_parts - 1].size;
+
+	return add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts);
+free_irq:
+	free_irq(IRQ_NAND, info);
+free_buf:
+	pxa_free_dma(info->data_dma_ch);
+	dma_free_coherent(&pdev->dev, info->data_buff_size,
+			info->data_buff, info->data_buff_phys);
+fail_free_io:
+	iounmap(info->mmio_base);
+fail_free_res:
+	release_mem_region(res->start, res->end - res->start + 1);
+fail_put_clk:
+	clk_put(info->clk);
+free_mtd:
+	kfree(mtd);
+	return ret;
+}
+
+static int pxa3xx_nand_remove(struct platform_device *pdev)
+{
+	struct mtd_info *mtd = platform_get_drvdata(pdev);
+	struct pxa3xx_nand_info *info = mtd->priv;
+
+	platform_set_drvdata(pdev, NULL);
+
+	del_mtd_device(mtd);
+	del_mtd_partitions(mtd);
+	free_irq(IRQ_NAND, info);
+	if (use_dma) {
+		pxa_free_dma(info->data_dma_ch);
+		dma_free_writecombine(&pdev->dev, info->data_buff_size,
+				info->data_buff, info->data_buff_phys);
+	} else
+		kfree(info->data_buff);
+	kfree(mtd);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev);
+	struct pxa3xx_nand_info *info = mtd->priv;
+
+	if (info->state != STATE_READY) {
+		printk(KERN_ERR "current state is %d\n", info->state);
+		return -EAGAIN;
+	}
+	info->state = STATE_SUSPENDED;
+	/*
+	 * The PM code need read the mobm from NAND.
+	 * So the NAND clock can't be stop here.
+	 * The PM code will cover this.
+	 */
+	return 0;
+}
+
+static int pxa3xx_nand_resume(struct platform_device *pdev)
+{
+	struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev);
+	struct pxa3xx_nand_info *info = mtd->priv;
+	int status;
+
+	if (info->state != STATE_SUSPENDED)
+		printk(KERN_WARNING "Error State after resume back\n");
+
+	info->state = STATE_READY;
+
+	clk_disable(info->clk);
+
+	status = pxa3xx_nand_config_flash(info, info->flash_info);
+	if (status) {
+		dev_err(&pdev->dev, "failed to initialize\n");
+		return -ENXIO;
+	}
+	return 0;
+}
+#else
+#define pxa3xx_nand_suspend	NULL
+#define pxa3xx_nand_resume	NULL
+#endif
+
+static struct platform_driver pxa3xx_nand_driver = {
+	.driver = {
+		.name	= "pxa3xx-nand",
+	},
+	.probe		= pxa3xx_nand_probe,
+	.remove		= pxa3xx_nand_remove,
+	.suspend	= pxa3xx_nand_suspend,
+	.resume		= pxa3xx_nand_resume,
+};
+
+static int __init pxa3xx_nand_init(void)
+{
+	return platform_driver_register(&pxa3xx_nand_driver);
+}
+
+static void __exit pxa3xx_nand_exit(void)
+{
+	platform_driver_unregister(&pxa3xx_nand_driver);
+}
+
+module_init(pxa3xx_nand_init);
+module_exit(pxa3xx_nand_exit);
diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h
index 1bd398d..ff9e85f 100644
--- a/include/asm-arm/arch-pxa/pxa-regs.h
+++ b/include/asm-arm/arch-pxa/pxa-regs.h
@@ -159,6 +159,7 @@
 #define DRCMR68		__REG(0x40001110)  /* Request to Channel Map Register for Camera FIFO 0 Request */
 #define DRCMR69		__REG(0x40001114)  /* Request to Channel Map Register for Camera FIFO 1 Request */
 #define DRCMR70		__REG(0x40001118)  /* Request to Channel Map Register for Camera FIFO 2 Request */
+#define DRCMR97		__REG(0x40001184)  /* Request to Channel Map Register for NAND interface data transmit & receive Request */
 
 #define DRCMRRXSADR	DRCMR2
 #define DRCMRTXSADR	DRCMR3
diff --git a/include/asm-arm/arch-pxa/pxa3xx_nand.h b/include/asm-arm/arch-pxa/pxa3xx_nand.h
new file mode 100644
index 0000000..81a8937
--- /dev/null
+++ b/include/asm-arm/arch-pxa/pxa3xx_nand.h
@@ -0,0 +1,18 @@
+#ifndef __ASM_ARCH_PXA3XX_NAND_H
+#define __ASM_ARCH_PXA3XX_NAND_H
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+struct pxa3xx_nand_platform_data {
+
+	/* the data flash bus is shared between the Static Memory
+	 * Controller and the Data Flash Controller,  the arbiter
+	 * controls the ownership of the bus
+	 */
+	int	enable_arbiter;
+
+	struct mtd_partition *parts;
+	unsigned int	nr_parts;
+};
+#endif /* __ASM_ARCH_PXA3XX_NAND_H */
-- 
1.5.3.7


From dedekind at infradead.org  Fri Jan 25 02:31:14 2008
From: dedekind at infradead.org (Artem Bityutskiy)
Date: Fri, 25 Jan 2008 09:31:14 +0200
Subject: Error compiling libubi with latest mtd-utils snapshot
In-Reply-To: <2c8de1360801240739oae8135bg55d829ff75642048@mail.gmail.com>
References: <2c8de1360801240739oae8135bg55d829ff75642048@mail.gmail.com>
Message-ID: <1201246274.6934.49.camel@sauron>

On Thu, 2008-01-24 at 09:39 -0600, Chase Maupin wrote:
> All,
> 
> I downloaded the latest mtd-utils snapshot from
> git://git.infradead.org/mtd-utils.git and did a "make clean" followed
> by "make".  The snapshot I downloaded was commited Jan 24, 2008 at
> 11:21 with commit tag e292b5fb39de2c6907ffe751391ae3bbd5603b91.
> 
> During the compile I received the following errors:
> 

I've removes all __be32 and the like occurrences from ubi-header.h.
Please, update (git-pull) and try again.

-- 
Best regards,
Artem Bityutskiy (???????? ?????)



From ext-adrian.hunter at nokia.com  Fri Jan 25 04:02:39 2008
From: ext-adrian.hunter at nokia.com (Adrian Hunter)
Date: Fri, 25 Jan 2008 11:02:39 +0200
Subject: [PATCH] [MTD] [OneNAND] Do not release chip twice
In-Reply-To: <004b01c85ee2$6f78b2a0$1fa9580a@swcenter.sec.samsung.co.kr>
References: <47989DC8.5090201@nokia.com>
	<004b01c85ee2$6f78b2a0$1fa9580a@swcenter.sec.samsung.co.kr>
Message-ID: <4799A5AF.9090800@nokia.com>

Kyungmin Park wrote:
>> From: Adrian Hunter <ext-adrian.hunter at nokia.com>
>> Date: Thu, 24 Jan 2008 12:48:37 +0200
>> Subject: [MTD] [OneNAND] Do not release chip twice
>>
>> Signed-off-by: Adrian Hunter <ext-adrian.hunter at nokia.com>
> Ack-off-by: Kyungmin Park <kyungmin.park at samsung.com>
> 

David please apply because the OneNAND driver is broken without this patch


From cem8101 at gmail.com  Fri Jan 25 08:50:10 2008
From: cem8101 at gmail.com (Chase Maupin)
Date: Fri, 25 Jan 2008 07:50:10 -0600
Subject: Error compiling libubi with latest mtd-utils snapshot
In-Reply-To: <1201246274.6934.49.camel@sauron>
References: <2c8de1360801240739oae8135bg55d829ff75642048@mail.gmail.com>
	<1201246274.6934.49.camel@sauron>
Message-ID: <2c8de1360801250550r5a7d1a82h667628b9d1134fec@mail.gmail.com>

Artem,

I downloaded the latest git snapshot and I am seeing the following
results from make and make clean:

Makefile:49: no file name for `-include'
make: Warning: File `Makefile' has modification time 4.1e+03 s in the future
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o ftl_format.o ftl_format.c -g
-Wp,-MD,./.ftl_format.c.dep
gcc -I./include -O2 -Wall  -g -o ftl_format ftl_format.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o flash_erase.o flash_erase.c -g
-Wp,-MD,./.flash_erase.c.dep
gcc -I./include -O2 -Wall  -g -o flash_erase flash_erase.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o crc32.o crc32.c -g -Wp,-MD,./.crc32.c.dep
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o flash_eraseall.o flash_eraseall.c
-g -Wp,-MD,./.flash_eraseall.c.dep
gcc  -o flash_eraseall crc32.o flash_eraseall.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o nanddump.o nanddump.c -g
-Wp,-MD,./.nanddump.c.dep
gcc -I./include -O2 -Wall  -g -o nanddump nanddump.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o doc_loadbios.o doc_loadbios.c -g
-Wp,-MD,./.doc_loadbios.c.dep
gcc -I./include -O2 -Wall  -g -o doc_loadbios doc_loadbios.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o ftl_check.o ftl_check.c -g
-Wp,-MD,./.ftl_check.c.dep
gcc -I./include -O2 -Wall  -g -o ftl_check ftl_check.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o compr_rtime.o compr_rtime.c -g
-Wp,-MD,./.compr_rtime.c.dep
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o mkfs.jffs2.o mkfs.jffs2.c -g
-Wp,-MD,./.mkfs.jffs2.c.dep
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o compr_zlib.o compr_zlib.c -g
-Wp,-MD,./.compr_zlib.c.dep
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o compr_lzo.o compr_lzo.c -g
-Wp,-MD,./.compr_lzo.c.dep
compr_lzo.c: In function `jffs2_lzo_cmpr':
compr_lzo.c:54: warning: passing arg 4 of `lzo1x_999_compress' from
incompatible pointer type
compr_lzo.c: In function `jffs2_lzo_decompress':
compr_lzo.c:74: warning: passing arg 4 of `lzo1x_decompress_safe' from
incompatible pointer type
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o compr.o compr.c -g -Wp,-MD,./.compr.c.dep
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o rbtree.o rbtree.c -g -Wp,-MD,./.rbtree.c.dep
gcc  -o mkfs.jffs2 crc32.o compr_rtime.o mkfs.jffs2.o compr_zlib.o
compr_lzo.o compr.o rbtree.o -lz -llzo2
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o flash_lock.o flash_lock.c -g
-Wp,-MD,./.flash_lock.c.dep
gcc -I./include -O2 -Wall  -g -o flash_lock flash_lock.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o flash_unlock.o flash_unlock.c -g
-Wp,-MD,./.flash_unlock.c.dep
gcc -I./include -O2 -Wall  -g -o flash_unlock flash_unlock.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o flash_info.o flash_info.c -g
-Wp,-MD,./.flash_info.c.dep
gcc -I./include -O2 -Wall  -g -o flash_info flash_info.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o flash_otp_info.o flash_otp_info.c
-g -Wp,-MD,./.flash_otp_info.c.dep
gcc -I./include -O2 -Wall  -g -o flash_otp_info flash_otp_info.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o flash_otp_dump.o flash_otp_dump.c
-g -Wp,-MD,./.flash_otp_dump.c.dep
gcc -I./include -O2 -Wall  -g -o flash_otp_dump flash_otp_dump.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o mtd_debug.o mtd_debug.c -g
-Wp,-MD,./.mtd_debug.c.dep
gcc -I./include -O2 -Wall  -g -o mtd_debug mtd_debug.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o flashcp.o flashcp.c -g
-Wp,-MD,./.flashcp.c.dep
flashcp.c:255:2: warning: #warning "Check for smaller erase regions"
gcc -I./include -O2 -Wall  -g -o flashcp flashcp.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o nandwrite.o nandwrite.c -g
-Wp,-MD,./.nandwrite.c.dep
gcc -I./include -O2 -Wall  -g -o nandwrite nandwrite.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o nandtest.o nandtest.c -g
-Wp,-MD,./.nandtest.c.dep
gcc -I./include -O2 -Wall  -g -o nandtest nandtest.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o jffs2dump.o jffs2dump.c -g
-Wp,-MD,./.jffs2dump.c.dep
gcc  -o jffs2dump jffs2dump.o crc32.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o nftldump.o nftldump.c -g
-Wp,-MD,./.nftldump.c.dep
gcc -I./include -O2 -Wall  -g -o nftldump nftldump.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o nftl_format.o nftl_format.c -g
-Wp,-MD,./.nftl_format.c.dep
gcc -I./include -O2 -Wall  -g -o nftl_format nftl_format.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o docfdisk.o docfdisk.c -g
-Wp,-MD,./.docfdisk.c.dep
docfdisk.c: In function `main':
docfdisk.c:149: warning: 'ip' might be used uninitialized in this function
gcc -I./include -O2 -Wall  -g -o docfdisk docfdisk.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o rfddump.o rfddump.c -g
-Wp,-MD,./.rfddump.c.dep
gcc -I./include -O2 -Wall  -g -o rfddump rfddump.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o rfdformat.o rfdformat.c -g
-Wp,-MD,./.rfdformat.c.dep
gcc -I./include -O2 -Wall  -g -o rfdformat rfdformat.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o serve_image.o serve_image.c -g
-Wp,-MD,./.serve_image.c.dep
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o fec.o fec.c -g -Wp,-MD,./.fec.c.dep
gcc  -o serve_image serve_image.o crc32.o fec.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o recv_image.o recv_image.c -g
-Wp,-MD,./.recv_image.c.dep
recv_image.c: In function `main':
recv_image.c:310: warning: long unsigned int format, uint32_t arg (arg 2)
recv_image.c:310: warning: long unsigned int format, uint32_t arg (arg 3)
recv_image.c:310: warning: long unsigned int format, uint32_t arg (arg 4)
recv_image.c:48: warning: 'image_crc' might be used uninitialized in
this function
recv_image.c:55: warning: 'fec' might be used uninitialized in this function
recv_image.c:58: warning: 'start_seq' might be used uninitialized in
this function
gcc  -o recv_image recv_image.o crc32.o fec.o
mkdir -p .
gcc -I./include -O2 -Wall -g -c -o sumtool.o sumtool.c -g
-Wp,-MD,./.sumtool.c.dep
gcc  -o sumtool sumtool.o crc32.o
make -C ./ubi-utils
make[1]: Entering directory `/home/chase/projects/wiki/mtd-utils.git/ubi-utils'
make[1]: Warning: File `Makefile' has modification time 4.1e+03 s in the future
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall src/libubi.c
-c -o libubi.o
In file included from ../include/mtd/ubi-header.h:34,
                 from include/libubi.h:29,
                 from src/libubi.c:34:
/usr/include/asm/byteorder.h:6:2: #warning using private kernel
header; include <endian.h> instead!
make[1]: *** [libubi.o] Error 1
make[1]: Leaving directory `/home/chase/projects/wiki/mtd-utils.git/ubi-utils'
make: *** [all] Error 2
rm doc_loadbios.o flash_info.o docfdisk.o ftl_check.o rfdformat.o
nandwrite.o mtd_debug.o flash_otp_dump.o nftldump.o flash_lock.o
flash_otp_info.o rfddump.o flash_unlock.o nftl_format.o flashcp.o
flash_erase.o ftl_format.o nandtest.o nanddump.o


I changed line 34 in include/mtd/ubi-header.h from "#include
<asm/byteorder.h>" to "#include <endian.h>" and I see the following
error:

make -C ./ubi-utils
make[1]: Entering directory `/home/chase/projects/wiki/mtd-utils.git/ubi-utils'
make[1]: Warning: File `Makefile' has modification time 4e+03 s in the future
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall src/libubi.c
-c -o libubi.o
ar crv libubi.a libubi.o
a - libubi.o
ranlib libubi.a
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall src/common.c
-c -o common.o
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall
src/ubiupdate.c -c -o ubiupdate.o
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall ubiupdate.o
common.o -L. -lubi -o ubiupdate
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall
src/ubimkvol.c -c -o ubimkvol.o
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall ubimkvol.o
common.o -L. -lubi -o ubimkvol
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall
src/ubirmvol.c -c -o ubirmvol.o
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall ubirmvol.o
common.o -L. -lubi -o ubirmvol
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall
src/ubicrc32.c -c -o ubicrc32.o
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall src/crc32.c
-c -o crc32.o
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall -o ubicrc32
ubicrc32.o crc32.o
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall src/ubinfo.c
-c -o ubinfo.o
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall ubinfo.o
common.o -L. -lubi -o ubinfo
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall
src/ubiattach.c -c -o ubiattach.o
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall ubiattach.o
common.o -L. -lubi -o ubiattach
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall
src/ubidetach.c -c -o ubidetach.o
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall ubidetach.o
common.o -L. -lubi -o ubidetach
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall src/ubinize.c
-c -o ubinize.o
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall
src/libiniparser.c -c -o libiniparser.o
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall
src/dictionary.c -c -o dictionary.o
ar crv libiniparser.a libiniparser.o dictionary.o
a - libiniparser.o
a - dictionary.o
ranlib libiniparser.a
gcc -Iinclude -Isrc -I../include -O2 -Wall -Werror -Wall
src/libubigen.c -c -o libubigen.o
src/libubigen.c: In function `ubigen_create_empty_vtbl':
src/libubigen.c:95: warning: implicit declaration of function `__cpu_to_be32'
src/libubigen.c: In function `ubigen_add_volume':
src/libubigen.c:139: warning: implicit declaration of function `__cpu_to_be16'
src/libubigen.c: In function `init_ec_hdr':
src/libubigen.c:160: warning: implicit declaration of function `__cpu_to_be64'
make[1]: *** [libubigen.o] Error 1
rm ubiupdate.o ubinfo.o ubimkvol.o ubidetach.o ubirmvol.o ubiattach.o
make[1]: Leaving directory `/home/chase/projects/wiki/mtd-utils.git/ubi-utils'
make: *** [all] Error 2
rm doc_loadbios.o flash_info.o docfdisk.o ftl_check.o rfdformat.o
nandwrite.o mtd_debug.o flash_otp_dump.o nftldump.o flash_lock.o
flash_otp_info.o rfddump.o flash_unlock.o nftl_format.o flashcp.o
flash_erase.o ftl_format.o nandtest.o nanddump.o


There still seems to be something wrong here.

Thanks,
Chase Maupin

On 1/25/08, Artem Bityutskiy <dedekind at infradead.org> wrote:
> On Thu, 2008-01-24 at 09:39 -0600, Chase Maupin wrote:
> > All,
> >
> > I downloaded the latest mtd-utils snapshot from
> > git://git.infradead.org/mtd-utils.git and did a "make clean" followed
> > by "make".  The snapshot I downloaded was commited Jan 24, 2008 at
> > 11:21 with commit tag e292b5fb39de2c6907ffe751391ae3bbd5603b91.
> >
> > During the compile I received the following errors:
> >
>
> I've removes all __be32 and the like occurrences from ubi-header.h.
> Please, update (git-pull) and try again.
>
> --
> Best regards,
> Artem Bityutskiy (???????? ?????)
>
>

From dedekind at infradead.org  Fri Jan 25 09:03:41 2008
From: dedekind at infradead.org (Artem Bityutskiy)
Date: Fri, 25 Jan 2008 16:03:41 +0200
Subject: Error compiling libubi with latest mtd-utils snapshot
In-Reply-To: <2c8de1360801250550r5a7d1a82h667628b9d1134fec@mail.gmail.com>
References: <2c8de1360801240739oae8135bg55d829ff75642048@mail.gmail.com>
	<1201246274.6934.49.camel@sauron>
	<2c8de1360801250550r5a7d1a82h667628b9d1134fec@mail.gmail.com>
Message-ID: <1201269821.6934.51.camel@sauron>

On Fri, 2008-01-25 at 07:50 -0600, Chase Maupin wrote:
> Artem,
> 
> I downloaded the latest git snapshot and I am seeing the following
> results from make and make clean:
> 

Should be fixed now, update please.

-- 
Best regards,
Artem Bityutskiy (???????? ?????)



From cem8101 at gmail.com  Fri Jan 25 14:38:52 2008
From: cem8101 at gmail.com (Chase Maupin)
Date: Fri, 25 Jan 2008 13:38:52 -0600
Subject: Error compiling libubi with latest mtd-utils snapshot
In-Reply-To: <1201269821.6934.51.camel@sauron>
References: <2c8de1360801240739oae8135bg55d829ff75642048@mail.gmail.com>
	<1201246274.6934.49.camel@sauron>
	<2c8de1360801250550r5a7d1a82h667628b9d1134fec@mail.gmail.com>
	<1201269821.6934.51.camel@sauron>
Message-ID: <2c8de1360801251138h403206e3g99e222fb6a9944e8@mail.gmail.com>

Artem,

Success.  This is now building without errors.  Thank you for your help.

Chase

On 1/25/08, Artem Bityutskiy <dedekind at infradead.org> wrote:
> On Fri, 2008-01-25 at 07:50 -0600, Chase Maupin wrote:
> > Artem,
> >
> > I downloaded the latest git snapshot and I am seeing the following
> > results from make and make clean:
> >
>
> Should be fixed now, update please.
>
> --
> Best regards,
> Artem Bityutskiy (???????? ?????)
>
>

From jwboyer at linux.vnet.ibm.com  Fri Jan 25 16:28:29 2008
From: jwboyer at linux.vnet.ibm.com (Josh Boyer)
Date: Fri, 25 Jan 2008 15:28:29 -0600
Subject: [PATCH] UBI: introduce atomic LEB change ioctl
In-Reply-To: <20080124165453.30169.40332.sendpatchset@golum>
References: <20080124165453.30169.40332.sendpatchset@golum>
Message-ID: <20080125152829.591def16@zod.rchland.ibm.com>

On Thu, 24 Jan 2008 18:54:53 +0200
Artem Bityutskiy <dedekind at infradead.org> wrote:

> >From e405cf1dc645e7931df0e47ee7408d5251e2d9d0 Mon Sep 17 00:00:00 2001
> From: Artem Bityutskiy <Artem.Bityutskiy at nokia.com>
> Date: Thu, 24 Jan 2008 16:15:14 +0200
> Subject: [PATCH] UBI: introduce atomic LEB change ioctl
> 
> We have to be able to change individual LEBs for utilities like
> ubifsck, ubifstune. For example, ubifsck has to be able to fix
> errors on the media, ubifstune has to be able to change the
> the superblock, hence this ioctl.

Could you explain a bit more?  What exactly does "atomic" mean?

This seems like it's similar to volume update, only on a LEB level
right? If so, could you make volume update just use this or somehow
combine them?

Maybe I've just been away from UBI too long.  It sounds cool, but I
don't fully understand what the intention is.

josh


From mattjreimer at gmail.com  Fri Jan 25 17:07:20 2008
From: mattjreimer at gmail.com (Matt Reimer)
Date: Fri, 25 Jan 2008 14:07:20 -0800
Subject: [PATCH] MTD: fix s3c2410 error correction
In-Reply-To: <20071203152049.GA15000@lazybastard.org>
References: <1192755764-26269-1-git-send-email-mattjreimer@gmail.com>
	<f383264b0711291110k6e61ec29n212be5d4b059833e@mail.gmail.com>
	<20071203152049.GA15000@lazybastard.org>
Message-ID: <f383264b0801251407w861cdbfv72a8111c1ad8d4ef@mail.gmail.com>

On Dec 3, 2007 7:20 AM, J?rn Engel <joern at logfs.org> wrote:
>
> On Thu, 29 November 2007 11:10:41 -0800, Matt Reimer wrote:
> > On Oct 18, 2007 5:02 PM, Matt Reimer <mattjreimer at gmail.com> wrote:
> > > From: Matt Reimer <mreimer at vpop.net>
> > >
> > > The single-bit error correction was, well, incorrect. For determing which
> > > bit to correct it was using P1' P2' P4' P8' instead of P1 P2 P4 P8, and
> > > it was using P16' P32' P64' P128' P256' P512' P1024' P2048' instead of
> > > P16 P32 P64 P128 P256 P512 P1024 P2048.
> >
> > Is there any chance of this getting committed? It has been confirmed
> > to be needed on s3c2440 and s3c2412.
>
> Ok, I'm getting sick of this.  Even though I didn't fully review the
> patch, I'll gladly take the chances of breaking something and
> complaining to Matt afterwards.  Certainly beats ignoring this patch for
> all eternity.

Any takers? Pretty please?

Matt


From nancydreaming at gmail.com  Fri Jan 25 21:24:43 2008
From: nancydreaming at gmail.com (Nancy)
Date: Sat, 26 Jan 2008 10:24:43 +0800
Subject: stupid Q: what's the version of your basic file when you make patches?
Message-ID: <bae050c10801251824r40bdce07k58fd87c2b694df60@mail.gmail.com>

I notice all your patche is short.
I only change code a little,  but the patch based on linux 2.6.22
kernel is large.
How can I make it small like you do ?

What's the version of your basic file when you make patches?


--
Best wishes,
Nancy


From melsondavid at iol.pt  Sat Jan 26 03:54:23 2008
From: melsondavid at iol.pt (melsondavid at iol.pt)
Date: Sat, 26 Jan 2008 08:54:23 +0000 (GMT)
Subject: Hello My Old Friend
Message-ID: <f63fa6ce2b0a.479af53f@iol.pt>

Hello My Old Friend 

I'm happy to inform you about my success in getting those funds transferred under the cooperation of a new partner from paraguay. Presently I'm in Paraguay for investment projects with my own share of the total sum. meanwhile, i didn't forget your past efforts and attempts to assist me in transferring those funds despite that it failed us some how. 

Now contact my secretary in Cotonou Benin his name is Mr Ugo Godwin on email ( ugogodwin1 at o2.pl ) ask him to send you the Cheque of $1.200.000.00 which i kept for your compensation for all the past efforts and attempts to assist me in this matter. I appreciated your efforts at that time very much. so feel free and get in touch with Mr Ugo Godwin and instruct him where to send the amount to you. 

Please do let me know immediately you receive it so that we can share the joy after all the sufferings at that time. in the moment, I'm very busy here because of the investment projects which me and the new partner are having at hand, finally, remember that I had forwarded instruction to Mr Ugo Godwin on your behalf to receive that money, so feel free to get in touch with him on email address ( ugogodwin1 at o2.pl ) he will send the amount to you without any delay. 

Yours Faithfully. 

Melson David From Paraguay

_______________________________________________________________________________________
CORTE AS PRESTACOES de todos os seus creditos.
Conheca UNICO da Capital Mais ou peca uma simulacao on-line.
http://www.iol.pt/correio/rodape.php?dst=0801022



From vitalywool at gmail.com  Sat Jan 26 08:44:47 2008
From: vitalywool at gmail.com (Vitaly Wool)
Date: Sat, 26 Jan 2008 16:44:47 +0300
Subject: [PATCH] basic pxa3 nand controller support
In-Reply-To: <1201237929.3292.2.camel@localhost.localdomain>
References: <1201237929.3292.2.camel@localhost.localdomain>
Message-ID: <acd2a5930801260544n22fae0c9if9a2c5d13d67da81@mail.gmail.com>

FOn Jan 25, 2008 8:12 AM, Sergey Podstavin <spodstavin at ru.mvista.com> wrote:
> This is updated pxa3 nand controller support, io mapping was removed,
> partition tables were moved outside of the driver into platform code,
> some cleanup was done.

<snip>
> @@ -86,9 +86,9 @@ ENTRY(stext)
>         bl      __lookup_processor_type         @ r5=procinfo r9=cpuid
>         movs    r10, r5                         @ invalid processor (r5=0)?
>         beq     __error_p                       @ yes, error 'p'
> -       bl      __lookup_machine_type           @ r5=machinfo
> -       movs    r8, r5                          @ invalid machine (r5=0)?
> -       beq     __error_a                       @ yes, error 'a'
> +//     bl      __lookup_machine_type           @ r5=machinfo
> +//     movs    r8, r5                          @ invalid machine (r5=0)?
> +//     beq     __error_a                       @ yes, error 'a'
>         bl      __vet_atags
>         bl      __create_page_tables

Nice cleanup :P

> +#include <linux/mtd/nand.h>

I wonder if you really need this header.

> +void __init set_pxa_nand_info(struct pxa3xx_nand_platform_data *info)
> +{
> +       nand_device.dev.platform_data = info;
> +}

That doesn't belong to zylonite.c.

> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> new file mode 100644
> index 0000000..11bebbf
> --- /dev/null
> +++ b/drivers/mtd/nand/pxa3xx_nand.c
> @@ -0,0 +1,1385 @@
> +/*
> + * drivers/mtd/nand/pxa3xx_nand.c
> + *
> + * Copyright (C) 2005 Intel Corporation
> + * Copyright (C) 2006 Marvell International Ltd.
> + *
> + * 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/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/delay.h>
> +#include <linux/clk.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/nand.h>
> +#include <linux/mtd/partitions.h>
> +#include <asm/io.h>
> +#include <asm/irq.h>
> +#include <asm/dma.h>
> +
> +#include <asm/arch/pxa-regs.h>
> +#include <asm/arch/pxa3xx_nand.h>
> +
> +#define        CHIP_DELAY_TIMEOUT      (2 * HZ/10)
> +
> +/* registers and bit definitions */
> +#define NDCR           (0x00) /* Control register */
> +#define NDTR0CS0       (0x04) /* Timing Parameter 0 for CS0 */
> +#define NDTR1CS0       (0x0C) /* Timing Parameter 1 for CS0 */
> +#define NDSR           (0x14) /* Status Register */
> +#define NDPCR          (0x18) /* Page Count Register */
> +#define NDBDR0         (0x1C) /* Bad Block Register 0 */
> +#define NDBDR1         (0x20) /* Bad Block Register 1 */
> +#define NDDB           (0x40) /* Data Buffer */
> +#define NDCB0          (0x48) /* Command Buffer0 */
> +#define NDCB1          (0x4C) /* Command Buffer1 */
> +#define NDCB2          (0x50) /* Command Buffer2 */
> +
> +#define NDCR_SPARE_EN          (0x1 << 31)
> +#define NDCR_ECC_EN            (0x1 << 30)
> +#define NDCR_DMA_EN            (0x1 << 29)
> +#define NDCR_ND_RUN            (0x1 << 28)
> +#define NDCR_DWIDTH_C          (0x1 << 27)
> +#define NDCR_DWIDTH_M          (0x1 << 26)
> +#define NDCR_PAGE_SZ           (0x1 << 24)
> +#define NDCR_NCSX              (0x1 << 23)
> +#define NDCR_ND_MODE           (0x3 << 21)
> +#define NDCR_NAND_MODE         (0x0)
> +#define NDCR_CLR_PG_CNT                (0x1 << 20)
> +#define NDCR_CLR_ECC           (0x1 << 19)
> +#define NDCR_RD_ID_CNT_MASK    (0x7 << 16)
> +#define NDCR_RD_ID_CNT(x)      (((x) << 16) & NDCR_RD_ID_CNT_MASK)
> +
> +#define NDCR_RA_START          (0x1 << 15)
> +#define NDCR_PG_PER_BLK                (0x1 << 14)
> +#define NDCR_ND_ARB_EN         (0x1 << 12)
> +
> +#define NDSR_MASK              (0xfff)
> +#define NDSR_RDY               (0x1 << 11)
> +#define NDSR_CS0_PAGED         (0x1 << 10)
> +#define NDSR_CS1_PAGED         (0x1 << 9)
> +#define NDSR_CS0_CMDD          (0x1 << 8)
> +#define NDSR_CS1_CMDD          (0x1 << 7)
> +#define NDSR_CS0_BBD           (0x1 << 6)
> +#define NDSR_CS1_BBD           (0x1 << 5)
> +#define NDSR_DBERR             (0x1 << 4)
> +#define NDSR_SBERR             (0x1 << 3)
> +#define NDSR_WRDREQ            (0x1 << 2)
> +#define NDSR_RDDREQ            (0x1 << 1)
> +#define NDSR_WRCMDREQ          (0x1)
> +
> +#define NDCB0_AUTO_RS          (0x1 << 25)
> +#define NDCB0_CSEL             (0x1 << 24)
> +#define NDCB0_CMD_TYPE_MASK    (0x7 << 21)
> +#define NDCB0_CMD_TYPE(x)      (((x) << 21) & NDCB0_CMD_TYPE_MASK)
> +#define NDCB0_NC               (0x1 << 20)
> +#define NDCB0_DBC              (0x1 << 19)
> +#define NDCB0_ADDR_CYC_MASK    (0x7 << 16)
> +#define NDCB0_ADDR_CYC(x)      (((x) << 16) & NDCB0_ADDR_CYC_MASK)
> +#define NDCB0_CMD2_MASK                (0xff << 8)
> +#define NDCB0_CMD1_MASK                (0xff)
> +#define NDCB0_ADDR_CYC_SHIFT   (16)
> +
> +/* dma-able I/O address for the NAND data and commands */
> +#define NDCB0_DMA_ADDR         (0x43100048)
> +#define NDDB_DMA_ADDR          (0x43100040)
> +
> +/* macros for registers read/write */
> +#define nand_writel(info, off, val)    \
> +       __raw_writel((val), (info)->mmio_base + (off))
> +
> +#define nand_readl(info, off)          \
> +       __raw_readl((info)->mmio_base + (off))
> +
> +/* error code and state */
> +enum {
> +       ERR_NONE        = 0,
> +       ERR_DMABUSERR   = -1,
> +       ERR_SENDCMD     = -2,
> +       ERR_DBERR       = -3,
> +       ERR_BBERR       = -4,
> +       ERR_BUSY        = -5,
> +};
> +
> +enum {
> +       STATE_CMD_SEND = 1,
> +       STATE_CMD_HANDLE,
> +       STATE_DMA_TRANSFER,
> +       STATE_DMA_DONE,
> +       STATE_READY,
> +       STATE_SUSPENDED,
> +       STATE_DATA_TRANSFER,
> +};
> +
> +struct pxa3xx_nand_timing {
> +       unsigned int    tCH;  /* Enable signal hold time */
> +       unsigned int    tCS;  /* Enable signal setup time */
> +       unsigned int    tWH;  /* ND_nWE high duration */
> +       unsigned int    tWP;  /* ND_nWE pulse time */
> +       unsigned int    tRH;  /* ND_nRE high duration */
> +       unsigned int    tRP;  /* ND_nRE pulse width */
> +       unsigned int    tR;   /* ND_nWE high to ND_nRE low for read */
> +       unsigned int    tWHR; /* ND_nWE high to ND_nRE low for status read */
> +       unsigned int    tAR;  /* ND_ALE low to ND_nRE low delay */
> +};
> +
> +struct pxa3xx_nand_cmdset {
> +       uint16_t        read1;
> +       uint16_t        read2;
> +       uint16_t        program;
> +       uint16_t        read_status;
> +       uint16_t        read_id;
> +       uint16_t        erase;
> +       uint16_t        reset;
> +       uint16_t        lock;
> +       uint16_t        unlock;
> +       uint16_t        lock_status;
> +};
> +
> +struct pxa3xx_nand_flash {
> +       struct pxa3xx_nand_timing *timing; /* NAND Flash timing */
> +       struct pxa3xx_nand_cmdset *cmdset;
> +
> +       uint32_t page_per_block;/* Pages per block (PG_PER_BLK) */
> +       uint32_t page_size;     /* Page size in bytes (PAGE_SZ) */
> +       uint32_t flash_width;   /* Width of Flash memory (DWIDTH_M) */
> +       uint32_t dfc_width;     /* Width of flash controller(DWIDTH_C) */
> +       uint32_t num_blocks;    /* Number of physical blocks in Flash */
> +       uint32_t chip_id;
> +
> +       /* NOTE: these are automatically calculated, do not define */
> +       size_t          oob_size;
> +       size_t          read_id_bytes;
> +
> +       unsigned int    col_addr_cycles;
> +       unsigned int    row_addr_cycles;
> +};
> +
> +struct pxa3xx_nand_info {
> +       struct nand_chip        nand_chip;
> +
> +       struct platform_device   *pdev;
> +       struct pxa3xx_nand_flash *flash_info;
> +
> +       struct clk              *clk;
> +       void __iomem            *mmio_base;
> +
> +       unsigned int            buf_start;
> +       unsigned int            buf_count;
> +
> +       /* DMA information */
> +       unsigned char           *data_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 */
> +       unsigned int            state;
> +
> +       int                     use_ecc;        /* use HW ECC ? */
> +       int                     use_dma;        /* use DMA ? */
> +
> +       size_t                  data_size;      /* data size in FIFO */
> +       unsigned int            cur_cmd;
> +       int                     retcode;
> +       struct completion       cmd_complete;
> +
> +       /* generated NDCBx register values */
> +       uint32_t                ndcb0;
> +       uint32_t                ndcb1;
> +       uint32_t                ndcb2;
> +};
> +
> +static int use_dma = 0;
> +module_param(use_dma, bool, 0444);
> +MODULE_PARM_DESC(use_dma, "enable DMA for data transfering to/from NAND HW");
> +
> +static struct pxa3xx_nand_cmdset smallpage_cmdset = {
> +       .read1          = 0x0000,
> +       .read2          = 0x0050,
> +       .program        = 0x1080,
> +       .read_status    = 0x0070,
> +       .read_id        = 0x0090,
> +       .erase          = 0xD060,
> +       .reset          = 0x00FF,
> +       .lock           = 0x002A,
> +       .unlock         = 0x2423,
> +       .lock_status    = 0x007A,
> +};
> +
> +static struct pxa3xx_nand_cmdset largepage_cmdset = {
> +       .read1          = 0x3000,
> +       .read2          = 0x0050,
> +       .program        = 0x1080,
> +       .read_status    = 0x0070,
> +       .read_id        = 0x0090,
> +       .erase          = 0xD060,
> +       .reset          = 0x00FF,
> +       .lock           = 0x002A,
> +       .unlock         = 0x2423,
> +       .lock_status    = 0x007A,
> +};
> +
> +static struct pxa3xx_nand_timing samsung512MbX16_timing = {
> +       .tCH    = 10,
> +       .tCS    = 0,
> +       .tWH    = 20,
> +       .tWP    = 40,
> +       .tRH    = 30,
> +       .tRP    = 40,
> +       .tR     = 11123,
> +       .tWHR   = 110,
> +       .tAR    = 10,
> +};
> +
> +static struct pxa3xx_nand_flash samsung512MbX16 = {
> +       .timing         = &samsung512MbX16_timing,
> +       .cmdset         = &smallpage_cmdset,
> +       .page_per_block = 32,
> +       .page_size      = 512,
> +       .flash_width    = 16,
> +       .dfc_width      = 16,
> +       .num_blocks     = 4096,
> +       .chip_id        = 0x46ec,
> +};
> +
> +static struct pxa3xx_nand_timing micron_timing = {
> +       .tCH    = 10,
> +       .tCS    = 25,
> +       .tWH    = 15,
> +       .tWP    = 25,
> +       .tRH    = 15,
> +       .tRP    = 25,
> +       .tR     = 25000,
> +       .tWHR   = 60,
> +       .tAR    = 10,
> +};
> +
> +static struct pxa3xx_nand_flash micron1GbX8 = {
> +       .timing         = &micron_timing,
> +       .cmdset         = &largepage_cmdset,
> +       .page_per_block = 64,
> +       .page_size      = 2048,
> +       .flash_width    = 8,
> +       .dfc_width      = 8,
> +       .num_blocks     = 1024,
> +       .chip_id        = 0xa12c,
> +};
> +
> +static struct pxa3xx_nand_flash micron1GbX16 = {
> +       .timing         = &micron_timing,
> +       .cmdset         = &largepage_cmdset,
> +       .page_per_block = 64,
> +       .page_size      = 2048,
> +       .flash_width    = 16,
> +       .dfc_width      = 16,
> +       .num_blocks     = 1024,
> +       .chip_id        = 0xb12c,
> +};
> +
> +static struct pxa3xx_nand_flash *builtin_flash_types[] = {
> +       &samsung512MbX16,
> +       &micron1GbX8,
> +       &micron1GbX16,
> +};
> +
> +#define NDTR0_tCH(c)   (min((c), 7) << 19)
> +#define NDTR0_tCS(c)   (min((c), 7) << 16)
> +#define NDTR0_tWH(c)   (min((c), 7) << 11)
> +#define NDTR0_tWP(c)   (min((c), 7) << 8)
> +#define NDTR0_tRH(c)   (min((c), 7) << 3)
> +#define NDTR0_tRP(c)   (min((c), 7) << 0)
> +
> +#define NDTR1_tR(c)    (min((c), 65535) << 16)
> +#define NDTR1_tWHR(c)  (min((c), 15) << 4)
> +#define NDTR1_tAR(c)   (min((c), 15) << 0)
> +
> +/* convert nano-seconds to nand flash controller clock cycles */
> +#define ns2cycle(ns, clk)      (int)(((ns) * (clk / 1000000) / 1000) + 1)
> +
> +static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info,
> +                                  struct pxa3xx_nand_timing *t)
> +{
> +       unsigned long nand_clk = clk_get_rate(info->clk);
> +       uint32_t ndtr0, ndtr1;
> +
> +       ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) |
> +               NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) |
> +               NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) |
> +               NDTR0_tWP(ns2cycle(t->tWP, nand_clk)) |
> +               NDTR0_tRH(ns2cycle(t->tRH, nand_clk)) |
> +               NDTR0_tRP(ns2cycle(t->tRP, nand_clk));
> +
> +       ndtr1 = NDTR1_tR(ns2cycle(t->tR, nand_clk)) |
> +               NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
> +               NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
> +
> +       nand_writel(info, NDTR0CS0, ndtr0);
> +       nand_writel(info, NDTR1CS0, ndtr1);
> +}
> +
> +#define WAIT_EVENT_TIMEOUT     10
> +
> +static int wait_for_event(struct pxa3xx_nand_info *info, uint32_t event)
> +{
> +       int timeout = WAIT_EVENT_TIMEOUT;
> +       uint32_t ndsr;
> +
> +       while (timeout--) {
> +               ndsr = nand_readl(info, NDSR) & NDSR_MASK;
> +               if (ndsr & event) {
> +                       nand_writel(info, NDSR, ndsr);
> +                       return 0;
> +               }
> +               udelay(10);
> +       }
> +
> +       return -ETIMEDOUT;
> +}
> +
> +static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info,
> +                       uint16_t cmd, int column, int page_addr)
> +{
> +       struct pxa3xx_nand_flash *f = info->flash_info;
> +       struct pxa3xx_nand_cmdset *cmdset = f->cmdset;
> +
> +       /* calculate data size */
> +       switch (f->page_size) {
> +       case 2048:
> +               info->data_size = (info->use_ecc) ? 2088 : 2112;
> +               break;
> +       case 512:
> +               info->data_size = (info->use_ecc) ? 520 : 528;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       /* generate values for NDCBx registers */
> +       info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
> +       info->ndcb0 |= NDCB0_ADDR_CYC(f->row_addr_cycles + f->col_addr_cycles);
> +
> +       if (f->col_addr_cycles == 2) {
> +               /* large block, 2 cycles for column address
> +                * row address starts from 3rd cycle
> +                */
> +               info->ndcb1 |= (page_addr << 16) | (column & 0xffff);
> +               if (f->row_addr_cycles == 3)
> +                       info->ndcb2 = (page_addr >> 16) & 0xff;
> +       } else
> +               /* small block, 1 cycles for column address
> +                * row address starts from 2nd cycle
> +                */
> +               info->ndcb1 = (page_addr << 8) | (column & 0xff);
> +
> +       if (cmd == cmdset->program)
> +               info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS;
> +
> +       info->cur_cmd = cmd;
> +       return 0;
> +}
> +
> +static int prepare_erase_cmd(struct pxa3xx_nand_info *info,
> +                       uint16_t cmd, int page_addr)
> +{
> +       info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
> +       info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3);
> +       info->ndcb1 = page_addr;
> +
> +       info->cur_cmd = cmd;
> +       return 0;
> +}
> +
> +static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd)
> +{
> +       struct pxa3xx_nand_cmdset *cmdset = info->flash_info->cmdset;
> +
> +       info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
> +
> +       if (cmd == cmdset->read_id) {
> +               info->ndcb0 |= NDCB0_CMD_TYPE(3);
> +               info->data_size = 8;
> +       } else if (cmd == cmdset->read_status) {
> +               info->ndcb0 |= NDCB0_CMD_TYPE(4);
> +               info->data_size = 8;
> +       } else if (cmd == cmdset->reset || cmd == cmdset->lock ||
> +                  cmd == cmdset->unlock) {
> +               info->ndcb0 |= NDCB0_CMD_TYPE(5);
> +       } else
> +               return -EINVAL;
> +
> +       info->cur_cmd = cmd;
> +       return 0;
> +}
> +
> +static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
> +{
> +       uint32_t ndcr;
> +
> +       ndcr = nand_readl(info, NDCR);
> +       nand_writel(info, NDCR, ndcr & ~int_mask);
> +}
> +
> +static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
> +{
> +       uint32_t ndcr;
> +
> +       ndcr = nand_readl(info, NDCR);
> +       nand_writel(info, NDCR, ndcr | int_mask);
> +}
> +
> +/* NOTE: it is a must to set ND_RUN firstly, then write command buffer
> + * otherwise, it does not work
> + */
> +static int write_cmd(struct pxa3xx_nand_info *info)
> +{
> +       uint32_t ndcr;
> +
> +       /* clear status bits and run */
> +       nand_writel(info, NDSR, NDSR_MASK);
> +
> +       ndcr = info->reg_ndcr;
> +
> +       ndcr |= info->use_ecc ? NDCR_ECC_EN : 0;
> +       ndcr |= info->use_dma ? NDCR_DMA_EN : 0;
> +       ndcr |= NDCR_ND_RUN;
> +
> +       nand_writel(info, NDCR, ndcr);
> +
> +       if (wait_for_event(info, NDSR_WRCMDREQ)) {
> +               printk(KERN_ERR "timed out writing command\n");
> +               return -ETIMEDOUT;
> +       }
> +
> +       nand_writel(info, NDCB0, info->ndcb0);
> +       nand_writel(info, NDCB0, info->ndcb1);
> +       nand_writel(info, NDCB0, info->ndcb2);
> +       return 0;
> +}
> +
> +/* NOTE: {read, write}_fifo_pio() assume the buffer is 4-byte aligned,
> + * and data_size are 4-byte multiples as well
> + */

Why is that? Is it a hardware requirement?
Then, you're checking data_size % 4 but you don't check buffer
alignment. What's the reason for that?

> +static int pxa3xx_nand_do_cmd(struct pxa3xx_nand_info *info, uint32_t event)
> +{
> +       uint32_t ndcr;
> +       int ret, timeout = CHIP_DELAY_TIMEOUT;
> +
> +       info->state = STATE_CMD_SEND;
> +
> +       if (write_cmd(info)) {
> +               info->retcode = ERR_SENDCMD;
> +               goto fail_stop;
> +       }
> +
> +       info->state = STATE_CMD_HANDLE;
> +
> +       if (info->use_dma)
> +               setup_data_dma(info);
> +
> +       enable_int(info, event);

This is unclear to me. It looks like you use PIO NAND interrupt both
for DMA and PIO transfers. Can you please elaborate on that?

> +
> +       ret = wait_for_completion_timeout(&info->cmd_complete, timeout);
> +       if (!ret) {
> +               printk(KERN_ERR "command execution timed out\n");
> +               info->retcode = ERR_SENDCMD;
> +               goto fail_stop;
> +       }
> +
> +       if (info->use_dma == 0 && info->data_size > 0)
> +               if (handle_data_pio(info))
> +                       goto fail_stop;
> +
> +       return 0;
> +
> +fail_stop:
> +       ndcr = nand_readl(info, NDCR);
> +       nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN);
> +       udelay(10);
> +       return -ETIMEDOUT;
> +}
> +
> +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--)
> +               if (*buf++ != 0xff)
> +                       return 0;
> +       return 1;
> +}
> +
> +static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
> +               int column, int page_addr )
<snip>
> +       default:
> +               printk(KERN_ERR "non-supported command.\n");

Is random input really unsupported?

> +
> +       info->data_buff = dma_alloc_coherent(&pdev->dev, MAX_BUFF_SIZE,
> +                               &info->data_buff_phys, GFP_KERNEL);
> +       if (info->data_buff == NULL) {
> +               dev_err(&pdev->dev, "failed to allocate dma buffer\n");
> +               return -ENOMEM;
> +       }

Does this really work with coherent_dma_mask not have been set anywhere?

Thanks,
   Vitaly


From freelotterygame2 at yahoo.co.uk  Sat Jan 26 08:00:46 2008
From: freelotterygame2 at yahoo.co.uk (FREELOTTERYAWARDGAME2008(CONGRATULATIONS YOU HAVE WON))
Date: Sat, 26 Jan 2008 13:00:46 -0000 (UTC)
Subject: CONGRATULATION YOU HAVE WON  =?iso-8859-1?Q?=A31=2C000=2C000.00_GBP?=
Message-ID: <39312.195.166.237.254.1201352446.squirrel@webmail.wananchi.com>

We are pleased to announce to you our Free Lotto which is given away
the sum of ?1,000,000.00 GBP Your email address emerged as one of the
winning email addresses out of an initial database of 300,000 email
addresses.
To claim your prize you are required to contact our
claims officer : Dr.Anthony Halmiton Moore
Address:25 Atlantic Avenue Erlanger
E-mail:payofficer.moore at yahoo.de
Telephone: +447031923486 You are to send to us detials as showed below:
1.FULL NAMES
2.ADDRESS
3.SEX
4.AGE
5.MARITAL STATUS
6.OCCUPATION
7.E-MAIL ADDRESS
8.TELEPHONE NUMBER
9. COUNTRY
Note that you are automatically disqualified if you are below 18 years
of age and illegal dissemination of this mail is highly prohibited.
Your Sincerely,
Mr. Thomas White Online Promotions Manager Uk
Administrative Unit.



From vicky.irobot at gmail.com  Sun Jan 27 03:54:45 2008
From: vicky.irobot at gmail.com (Max Stirling)
Date: Sun, 27 Jan 2008 14:24:45 +0530
Subject: mtd block readonly low level nand driver cramfs
In-Reply-To: <47985D88.1060005@gmail.com>
References: <47985D88.1060005@gmail.com>
Message-ID: <6a61dac20801270054t19e2af20o1211490d104110a9@mail.gmail.com>

I was looking at the chips folder under MTD and the MTD_ROM flag settings.

I got this idea of having this low level driver code under chips with
the MTD_ROM flag set and mounting this for cramfs.

Please comment, especially folks using the RO FS mounted on flash.

MS

On Jan 24, 2008 3:12 PM, Max Stirling <vicky.irobot at gmail.com> wrote:
> Hi,
>
> This might sound quite basic question. This is the first time I am
> looking into the MTD code so have some really basic questions.
>
> I am trying to mount a read only fs (cramfs) on the flash. Please let me
> know if the following steps are right:
>
> 1. Enabled the following in the Kconfig files
>     CONFIG_MTD_PARITIONS
>     CONFIG_MTD
>     CONFIG_MTD_BLOCK_RO
>     CONFIG_MTD_NAND
>     CONFIG_MTD_NAND_IDS
>
>
> After booting the compiled kernel I am able to see the mtdblock under
> /proc/devices using 31 Major number.
>
> Now for me to mount the cramfs image that is on the flash I need to
> provide the low level nand driver code. This I need to write but before
> starting that can any one point me to a reference nand driver code that
> is used for read only mount? Which functionality would the MTD require
> to be implemented for mounting a cramfs image which is on the flash.
>
> Would appreciate any pointers to how to get started off with this.
>
> thanks in advance for the reply.
>
> M.S
>
>


From akpm at linux-foundation.org  Sun Jan 27 05:02:47 2008
From: akpm at linux-foundation.org (Andrew Morton)
Date: Sun, 27 Jan 2008 02:02:47 -0800
Subject: [Bugme-new] [Bug 9829] New: MTD startup lock when using
	multiple nor flash chips
In-Reply-To: <bug-9829-10286@http.bugzilla.kernel.org/>
References: <bug-9829-10286@http.bugzilla.kernel.org/>
Message-ID: <20080127020247.cef86b37.akpm@linux-foundation.org>

> On Sat, 26 Jan 2008 23:33:25 -0800 (PST) bugme-daemon at bugzilla.kernel.org wrote:
> http://bugzilla.kernel.org/show_bug.cgi?id=9829
> 
>            Summary: MTD startup lock when using multiple nor flash chips
>            Product: IO/Storage
>            Version: 2.5
>      KernelVersion: 2.6.24
>           Platform: All
>         OS/Version: Linux
>               Tree: Mainline
>             Status: NEW
>           Severity: blocking
>           Priority: P1
>          Component: Other
>         AssignedTo: io_other at kernel-bugs.osdl.org
>         ReportedBy: davide at elpa.it
> 
> 
> Latest working kernel version: 2.6.17 (not sure)
> Earliest failing kernel version: 2.6.18 (not sure)
> Distribution: kernel only in embedded system
> Hardware Environment: arm9 booting from 2 contiguous flash nor chip (4MB+4MB)
> Software Environment: kernel startup
> Problem Description: startup locks. I found and solved the problem, at line 115
> of drivers/mtd/chips/gen_probe.c (kernel 2.6.24): mapsize value must be
> calculated in bytes, not in long.
> I replaced line 115 from:
> mapsize = (max_chips + BITS_PER_LONG-1) / BITS_PER_LONG;
> to:
> mapsize = sizeof(long) * ( (max_chips + BITS_PER_LONG-1) / BITS_PER_LONG );
> And all worked OK
> Steps to reproduce: boot up the kernel

Thanks.  But we very much prefer patches via email.  Please send the patch
to all the recipients of this email as per
http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt


From kmpark at infradead.org  Sun Jan 27 18:19:44 2008
From: kmpark at infradead.org (Kyungmin Park)
Date: Mon, 28 Jan 2008 08:19:44 +0900
Subject: [PATCH] [MTD] [OneNAND] fix call to onenand_verify when
	writingsubpages
In-Reply-To: <47989DF3.5010408@nokia.com>
References: <47989DF3.5010408@nokia.com>
Message-ID: <009401c8613b$5e62b0f0$1fa9580a@swcenter.sec.samsung.co.kr>

> Signed-off-by: Adrian Hunter <ext-adrian.hunter at nokia.com>
Acked-off-by: Kyungmin Park <kyungmin.park at samsung.com>




From vicky.irobot at gmail.com  Mon Jan 28 02:40:20 2008
From: vicky.irobot at gmail.com (Max Stirling)
Date: Mon, 28 Jan 2008 02:40:20 -0500
Subject: mtd block readonly low level nand driver cramfs
In-Reply-To: <6a61dac20801270054t19e2af20o1211490d104110a9@mail.gmail.com>
References: <47985D88.1060005@gmail.com>
	<6a61dac20801270054t19e2af20o1211490d104110a9@mail.gmail.com>
Message-ID: <479D86E4.30903@gmail.com>

Max Stirling wrote:
> I was looking at the chips folder under MTD and the MTD_ROM flag settings.
>
> I got this idea of having this low level driver code under chips with
> the MTD_ROM flag set and mounting this for cramfs.
>
> Please comment, especially folks using the RO FS mounted on flash.
>
> MS
>
> On Jan 24, 2008 3:12 PM, Max Stirling <vicky.irobot at gmail.com> wrote:
>   
>> Hi,
>>
>> This might sound quite basic question. This is the first time I am
>> looking into the MTD code so have some really basic questions.
>>
>> I am trying to mount a read only fs (cramfs) on the flash. Please let me
>> know if the following steps are right:
>>
>> 1. Enabled the following in the Kconfig files
>>     CONFIG_MTD_PARITIONS
>>     CONFIG_MTD
>>     CONFIG_MTD_BLOCK_RO
>>     CONFIG_MTD_NAND
>>     CONFIG_MTD_NAND_IDS
>>
>>
>> After booting the compiled kernel I am able to see the mtdblock under
>> /proc/devices using 31 Major number.
>>
>> Now for me to mount the cramfs image that is on the flash I need to
>> provide the low level nand driver code. This I need to write but before
>> starting that can any one point me to a reference nand driver code that
>> is used for read only mount? Which functionality would the MTD require
>> to be implemented for mounting a cramfs image which is on the flash.
>>
>> Would appreciate any pointers to how to get started off with this.
>>
>> thanks in advance for the reply.
>>
>> M.S
>>
>>
>>     
When using the cramfs as the fs for the flash and mtdblock_ro enabled. 
Which one should I be calling the user module, the cramfs or the 
mtdblock_ro?




From 12o3l at tiscali.nl  Mon Jan 28 05:48:09 2008
From: 12o3l at tiscali.nl (Roel Kluin)
Date: Mon, 28 Jan 2008 11:48:09 +0100
Subject: [PATCH 1/1][MTD] Test devtype, not definition in flash_probe(),
	drivers/mtd/devices/lart.c
Message-ID: <479DB2E9.2040500@tiscali.nl>

drivers/mtd/devices/lart.c:119:#define FLASH_DEVICE_16mbit_BOTTOM 0x88f488f4
As was, unless "manufacturer != FLASH_MANUFACTURER" this returned true
--
Test devtype, not definition

Signed-off-by: Roel Kluin <12o3l at tiscali.nl>
---
diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c
index 4ea50a1..99fd210 100644
--- a/drivers/mtd/devices/lart.c
+++ b/drivers/mtd/devices/lart.c
@@ -323,7 +323,7 @@ static int flash_probe (void)
    /* put the flash back into command mode */
    write32 (DATA_TO_FLASH (READ_ARRAY),0x00000000);
 
-   return (manufacturer == FLASH_MANUFACTURER && (devtype == FLASH_DEVICE_16mbit_TOP || FLASH_DEVICE_16mbit_BOTTOM));
+   return (manufacturer == FLASH_MANUFACTURER && (devtype == FLASH_DEVICE_16mbit_TOP || devtype == FLASH_DEVICE_16mbit_BOTTOM));
 }
 
 /*


From nancydreaming at gmail.com  Mon Jan 28 09:19:51 2008
From: nancydreaming at gmail.com (Nancy)
Date: Mon, 28 Jan 2008 22:19:51 +0800
Subject: stupid Q: what's the version of your basic file when you make
	patches?
In-Reply-To: <479D858B.5040108@nokia.com>
References: <bae050c10801251824r40bdce07k58fd87c2b694df60@mail.gmail.com>
	<479D858B.5040108@nokia.com>
Message-ID: <bae050c10801280619h9779661ld148cf8bafc2f84c@mail.gmail.com>

Commit the other changes that are in your tree first.
>
> e.g. git-commit -a -s -m "UBIFS: diff between the master branch and the stable-ubifs branch"


Thank you sir!
You are so kind to me!
God bless you!

--
Best wishes,
Nancy


From dedekind at infradead.org  Mon Jan 28 11:22:46 2008
From: dedekind at infradead.org (Artem Bityutskiy)
Date: Mon, 28 Jan 2008 18:22:46 +0200
Subject: [PATCH] UBI: introduce atomic LEB change ioctl
In-Reply-To: <20080125152829.591def16@zod.rchland.ibm.com>
References: <20080124165453.30169.40332.sendpatchset@golum>
	<20080125152829.591def16@zod.rchland.ibm.com>
Message-ID: <1201537366.4262.2.camel@sauron>

On Fri, 2008-01-25 at 15:28 -0600, Josh Boyer wrote:
> Could you explain a bit more?  What exactly does "atomic" mean?
> 
> This seems like it's similar to volume update, only on a LEB level
> right? If so, could you make volume update just use this or somehow
> combine them?
> 
> Maybe I've just been away from UBI too long.  It sounds cool, but I
> don't fully understand what the intention is.

Josh,

I've updated the UBI documentation in order to answer your question. Any
documentation improvements and spelling fixes are welcome.

-- 
Best regards,
Artem Bityutskiy (???????? ?????)



From fuzzoli at comcast.net  Mon Jan 28 23:07:38 2008
From: fuzzoli at comcast.net (Frank)
Date: Mon, 28 Jan 2008 23:07:38 -0500
Subject: Searchable Archives and Using RAM
Message-ID: <479EA68A.2000704@comcast.net>

Hello all,

I just joined the list as I am looking for information on how to set up 
MTD to use 2Mb of battery-backed up RAM as a disk.   This will be on an 
ARM-based SBC that already has MTD NAND drivers loaded.  I think I know 
where I need to start (CONFIG_MTD_MTDRAM, etc), but have not seen any 
how-to's yet.   I found a new book from O'Reilly that'll be out in 
February that looks very promising 
(http://safari.oreilly.com/0136130550/ch10), but I was wondering if 
there are any online resources.

I admit I still need to do some additional searching, and therefore was 
wondering if there is a searchable version of the mailing list archives?

Thanks in advanced,

-Frank
Holland, PA




From msundius at sundius.com  Tue Jan 29 00:48:50 2008
From: msundius at sundius.com (C Michael Sundius)
Date: Mon, 28 Jan 2008 21:48:50 -0800
Subject: trouble looking up files after mount
Message-ID: <dd468eb92fb185c81196168801fe6330@sundius.com>

Hi,

I just started in on a contract that has a JFFS problem. my client is
in the midst of moving to 2.6.10 from 2.4.

They are mounting a jffs file system as root right off the bat with
no initrd, and while it seems to mount OK, no files subsequent
to the mount are found - I get errors indicating it cannot find
the console device and the init program. path_lookup seems
to return ENOENT. I have a BDI debugger and I have seen that
control gets to jffs2_lookup() but it doesn't find any files in the
root directory.

I checked a more recent version of mkfs.jffs2
and it seems to creat the same FS image as what we have
been using (sum gives same results) I think it was version
mtd-utils 1.0.0. my tools didnt'tcompile later versions
easily.

I'm very sure that the endian is not a probelm, I'm using
big throughout.

Here are my questions:
1) Should I really be telling my client to use an initrd? or can
they really get away without it - It was working fine without it
on 2.4. OR should I be telling him to use a more recent version
of linux.
2) Do I need to be using a newer version of mkfs.jffs2?
3) I did not fiddle with any of the advanced compression stuff
in the 2.6 jffs2 configuration.. I'm pretty sure I shouldn't touch
that, rite?
4) Does anyone have some thoughts about where I should be
looking.. it seems as though jffs should be stable enough
to at least read a directory... could it be my old compiler/tools?

thanks for your help...



C Michael Sundius
Solico Group LLC
232 Nevada St
San Francisco, CA 94110
msundius at sundius.com
(415)608-0121
http://www.sundius.com



From kmpark at infradead.org  Tue Jan 29 03:29:03 2008
From: kmpark at infradead.org (Kyungmin Park)
Date: Tue, 29 Jan 2008 17:29:03 +0900
Subject: [GIT PULL] OneNAND updates
Message-ID: <007a01c86251$05ace8b0$1fa9580a@swcenter.sec.samsung.co.kr>

[GIT PULL] OneNAND updates

Please pull git://git.infradead.org/~kmpark/onenand-mtd-2.6

Now I omit the MLC related patches.

Thank you,
Kyungmin Park

[MTD] [OneNAND] Use pre-alloced oob buffer instead of local buffer
[MTD] [OneNAND] Use the u_char instead of char in oobbuf
[MTD] [OneNAND] Check the initial bad block using ONENAND_CTRL_ERROR
[MTD] [OneNAND] Get correct density from device ID
[MTD] [OneNAND] Consolidate OneNAND operation order
[MTD] [OneNAND] fix call to onenand_verify when writing subpages
[MTD] [OneNAND] Do not release chip twice



From kyungmin.park at samsung.com  Tue Jan 29 03:36:30 2008
From: kyungmin.park at samsung.com (Kyungmin Park)
Date: Tue, 29 Jan 2008 17:36:30 +0900
Subject: [PATCH] [JFFS2] JFFS2 doesn't use OOB at MLC NAND/OneNAND
Message-ID: <20080129083630.GA31954@party>

Hi,

It's revised patch from 
http://patchwork.ozlabs.org/linux-mtd/patch?id=15260

Just remove one line
+#define MTD_CAP_MLC_NANDFLASH	(MTD_WRITEABLE)

If you don't any rejct please apply this one.

Any comments are welcome.

Thank you,
Kyungmin Park

Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
---
 fs/jffs2/erase.c      |    1 +
 fs/jffs2/fs.c         |    6 ++++--
 fs/jffs2/os-linux.h   |    2 +-
 include/mtd/mtd-abi.h |    3 ++-
 4 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c
index a1db918..65d7dd7 100644
--- a/fs/jffs2/erase.c
+++ b/fs/jffs2/erase.c
@@ -415,6 +415,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
 	/* Cleanmarker in oob area or no cleanmarker at all ? */
 	if (jffs2_cleanmarker_oob(c) || c->cleanmarker_size == 0) {
 
+		/* We only write cleanmarker in case of SLC NAND */
 		if (jffs2_cleanmarker_oob(c)) {
 			if (jffs2_write_nand_cleanmarker(c, jeb))
 				goto filebad;
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index ee192af..cbeb822 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -656,7 +656,9 @@ void jffs2_gc_release_page(struct jffs2_sb_info *c,
 static int jffs2_flash_setup(struct jffs2_sb_info *c) {
 	int ret = 0;
 
-	if (jffs2_cleanmarker_oob(c)) {
+	if (c->mtd->type == MTD_NANDFLASH) {
+		if (!(c->mtd->flags & MTD_OOB_WRITEABLE))
+			printk(KERN_INFO "JFFS2 doesn't use OOB.\n");
 		/* NAND flash... do setup accordingly */
 		ret = jffs2_nand_flash_setup(c);
 		if (ret)
@@ -689,7 +691,7 @@ static int jffs2_flash_setup(struct jffs2_sb_info *c) {
 
 void jffs2_flash_cleanup(struct jffs2_sb_info *c) {
 
-	if (jffs2_cleanmarker_oob(c)) {
+	if (c->mtd->type == MTD_NANDFLASH) {
 		jffs2_nand_flash_cleanup(c);
 	}
 
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index bf64686..27dd4e8 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -110,7 +110,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
 #define jffs2_can_mark_obsolete(c) (c->mtd->flags & (MTD_BIT_WRITEABLE))
 #endif
 
-#define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH)
+#define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH && (c->mtd->flags & MTD_OOB_WRITEABLE))
 
 #define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf))
 #define jffs2_flash_read_oob(c, ofs, len, retlen, buf) ((c)->mtd->read_oob((c)->mtd, ofs, len, retlen, buf))
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
index f71dac4..5a61074 100644
--- a/include/mtd/mtd-abi.h
+++ b/include/mtd/mtd-abi.h
@@ -30,12 +30,13 @@ struct mtd_oob_buf {
 #define MTD_BIT_WRITEABLE	0x800	/* Single bits can be flipped */
 #define MTD_NO_ERASE		0x1000	/* No erase necessary */
 #define MTD_STUPID_LOCK		0x2000	/* Always locked after reset */
+#define MTD_OOB_WRITEABLE	0x4000	/* Use Out-Of-Band area */
 
 // 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)
+#define MTD_CAP_NANDFLASH	(MTD_WRITEABLE | MTD_OOB_WRITEABLE)
 
 /* ECC byte placement */
 #define MTD_NANDECC_OFF		0	// Switch off ECC (Not recommended)
-- 
1.5.0.6



From rpurdie at rpsys.net  Tue Jan 29 06:27:05 2008
From: rpurdie at rpsys.net (Richard Purdie)
Date: Tue, 29 Jan 2008 11:27:05 +0000
Subject: [PATCH 0/4] mtdoops updates
Message-ID: <1201606025.5017.18.camel@localhost.localdomain>

A series of bugfixes/updates to the mtdoops driver follows, split into
logcial units so its more obvious whats being changed and why.

I've also shared the series as a git branch based on top of the current
mtd-2.6 tree:

git://git.o-hand.com/linux-rpurdie mtdoops-updates

Cheers,

Richard



From rpurdie at rpsys.net  Tue Jan 29 06:27:09 2008
From: rpurdie at rpsys.net (Richard Purdie)
Date: Tue, 29 Jan 2008 11:27:09 +0000
Subject: [PATCH 1/4] mtdoops: Add further error return code checking
Message-ID: <1201606029.5017.20.camel@localhost.localdomain>

Add further error return code checks to the mtdoops driver.

Signed-off-by: Richard Purdie <rpurdie at rpsys.net>
---
 drivers/mtd/mtdoops.c |   41 +++++++++++++++++++++++++++++------------
 1 files changed, 29 insertions(+), 12 deletions(-)

diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 20eaf29..723ca76 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -103,7 +103,7 @@ static int mtdoops_inc_counter(struct mtdoops_context *cxt)
 
 	ret = mtd->read(mtd, cxt->nextpage * OOPS_PAGE_SIZE, 4,
 			&retlen, (u_char *) &count);
-	if ((retlen != 4) || (ret < 0)) {
+	if ((retlen != 4) || ((ret < 0) && (ret != -EUCLEAN))) {
 		printk(KERN_ERR "mtdoops: Read failure at %d (%td of 4 read)"
 				", err %d.\n", cxt->nextpage * OOPS_PAGE_SIZE,
 				retlen, ret);
@@ -136,8 +136,14 @@ static void mtdoops_prepare(struct mtdoops_context *cxt)
 			cxt->nextpage = 0;
 	}
 
-	while (mtd->block_isbad &&
-			mtd->block_isbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE)) {
+	while (mtd->block_isbad) {
+		ret = mtd->block_isbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
+		if (!ret)
+			break;
+		if (ret < 0) {
+			printk(KERN_ERR "mtdoops: block_isbad failed, aborting.\n");
+			return;
+		}
 badblock:
 		printk(KERN_WARNING "mtdoops: Bad block at %08x\n",
 				cxt->nextpage * OOPS_PAGE_SIZE);
@@ -154,15 +160,20 @@ badblock:
 	for (j = 0, ret = -1; (j < 3) && (ret < 0); j++)
 		ret = mtdoops_erase_block(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
 
-	if (ret < 0) {
-		if (mtd->block_markbad)
-			mtd->block_markbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
-		goto badblock;
+	if (ret >= 0) {
+		printk(KERN_DEBUG "mtdoops: Ready %d, %d \n", cxt->nextpage, cxt->nextcount);
+		cxt->ready = 1;
+		return;
 	}
 
-	printk(KERN_DEBUG "mtdoops: Ready %d, %d \n", cxt->nextpage, cxt->nextcount);
-
-	cxt->ready = 1;
+	if (mtd->block_markbad && (ret == -EIO)) {
+		ret = mtd->block_markbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
+		if (ret < 0) {
+			printk(KERN_ERR "mtdoops: block_markbad failed, aborting.\n");
+			return;
+		}
+	}
+	goto badblock;
 }
 
 static void mtdoops_workfunc(struct work_struct *work)
@@ -176,12 +187,18 @@ static void mtdoops_workfunc(struct work_struct *work)
 static int find_next_position(struct mtdoops_context *cxt)
 {
 	struct mtd_info *mtd = cxt->mtd;
-	int page, maxpos = 0;
+	int ret, page, maxpos = 0;
 	u32 count, maxcount = 0xffffffff;
 	size_t retlen;
 
 	for (page = 0; page < cxt->oops_pages; page++) {
-		mtd->read(mtd, page * OOPS_PAGE_SIZE, 4, &retlen, (u_char *) &count);
+		ret = mtd->read(mtd, page * OOPS_PAGE_SIZE, 4, &retlen, (u_char *) &count);
+		if ((retlen != 4) || ((ret < 0) && (ret != -EUCLEAN))) {
+			printk(KERN_ERR "mtdoops: Read failure at %d (%td of 4 read)"
+				", err %d.\n", page * OOPS_PAGE_SIZE, retlen, ret);
+			continue;
+		}
+
 		if (count == 0xffffffff)
 			continue;
 		if (maxcount == 0xffffffff) {
-- 
1.5.2.3




From rpurdie at rpsys.net  Tue Jan 29 06:27:13 2008
From: rpurdie at rpsys.net (Richard Purdie)
Date: Tue, 29 Jan 2008 11:27:13 +0000
Subject: [PATCH 3/4] mtdoops: Ensure sequential write to the buffer
Message-ID: <1201606033.5017.22.camel@localhost.localdomain>

>From a5ef8a78b4214f5efcc7310e71dd1e351672af3f Mon Sep 17 00:00:00 2001
From: Richard Purdie <rpurdie at rpsys.net>
Date: Tue, 29 Jan 2008 10:21:56 +0000
Subject: [PATCH] [MTD] mtdoops: Ensure sequential write to the buffer

Add a spinlock to ensure writes to the mtdoops buffer memory are
sequential and don't race.

Signed-off-by: Richard Purdie <rpurdie at rpsys.net>
---
 drivers/mtd/mtdoops.c |   28 ++++++++++++++++++++++++++++
 1 files changed, 28 insertions(+), 0 deletions(-)

diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 72c434c..1687521 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -28,6 +28,7 @@
 #include <linux/workqueue.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
+#include <linux/spinlock.h>
 #include <linux/mtd/mtd.h>
 
 #define OOPS_PAGE_SIZE 4096
@@ -42,6 +43,9 @@ struct mtdoops_context {
 	int nextcount;
 
 	void *oops_buf;
+
+	/* writecount and disabling ready are spin lock protected */
+	spinlock_t writecount_lock;
 	int ready;
 	int writecount;
 } oops_cxt;
@@ -290,11 +294,22 @@ static void mtdoops_console_sync(void)
 {
 	struct mtdoops_context *cxt = &oops_cxt;
 	struct mtd_info *mtd = cxt->mtd;
+	unsigned long flags;
 
 	if (!cxt->ready || !mtd || cxt->writecount == 0)
 		return;
 
+	/* 
+	 *  Once ready is 0 and we've held the lock no further writes to the 
+	 *  buffer will happen
+	 */
+	spin_lock_irqsave(&cxt->writecount_lock, flags);
+	if (!cxt->ready) {
+		spin_unlock_irqrestore(&cxt->writecount_lock, flags);
+		return;
+	}
 	cxt->ready = 0;
+	spin_unlock_irqrestore(&cxt->writecount_lock, flags);
 
 	schedule_work(&cxt->work_write);
 }
@@ -304,6 +319,7 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count)
 {
 	struct mtdoops_context *cxt = co->data;
 	struct mtd_info *mtd = cxt->mtd;
+	unsigned long flags;
 
 	if (!oops_in_progress) {
 		mtdoops_console_sync();
@@ -313,6 +329,13 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count)
 	if (!cxt->ready || !mtd)
 		return;
 
+	/* Locking on writecount ensures sequential writes to the buffer */
+	spin_lock_irqsave(&cxt->writecount_lock, flags);
+
+	/* Check ready status didn't change whilst waiting for the lock */
+	if (!cxt->ready)
+		return;
+
 	if (cxt->writecount == 0) {
 		u32 *stamp = cxt->oops_buf;
 		*stamp = cxt->nextcount;
@@ -324,6 +347,11 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count)
 
 	memcpy(cxt->oops_buf + cxt->writecount, s, count);
 	cxt->writecount += count;
+
+	spin_unlock_irqrestore(&cxt->writecount_lock, flags);
+
+	if (cxt->writecount == OOPS_PAGE_SIZE)
+		mtdoops_console_sync();
 }
 
 static int __init mtdoops_console_setup(struct console *co, char *options)
-- 
1.5.2.3




From rpurdie at rpsys.net  Tue Jan 29 06:27:14 2008
From: rpurdie at rpsys.net (Richard Purdie)
Date: Tue, 29 Jan 2008 11:27:14 +0000
Subject: [PATCH 4/4] mtdoops: Various minor cleanups
Message-ID: <1201606034.5017.23.camel@localhost.localdomain>

>From b4de341e0ca649104b95eb59024eba1d05b3da42 Mon Sep 17 00:00:00 2001
From: Richard Purdie <rpurdie at rpsys.net>
Date: Tue, 29 Jan 2008 10:25:55 +0000
Subject: [PATCH] [MTD] mtdoops: Various minor cleanups

Various minor cleaups to mtdoops:
  * Don't support the mtd->erasesize < OOPS_PAGE_SIZE case
  * Tweak printks and make the device mtdoops connects to more visible
  * CON_PRINTBUFFER flag is uneeded

Signed-off-by: Richard Purdie <rpurdie at rpsys.net>
---
 drivers/mtd/mtdoops.c |   16 +++++++++-------
 1 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 1687521..34681bc 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -67,10 +67,7 @@ static int mtdoops_erase_block(struct mtd_info *mtd, int offset)
 	erase.mtd = mtd;
 	erase.callback = mtdoops_erase_callback;
 	erase.addr = offset;
-	if (mtd->erasesize < OOPS_PAGE_SIZE)
-		erase.len = OOPS_PAGE_SIZE;
-	else
-		erase.len = mtd->erasesize;
+	erase.len = mtd->erasesize;
 	erase.priv = (u_long)&wait_q;
 
 	set_current_state(TASK_INTERRUPTIBLE);
@@ -271,12 +268,18 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 		return;
 	}
 
+	if (mtd->erasesize < OOPS_PAGE_SIZE) {
+		printk(KERN_ERR "Eraseblock size of MTD partition %d too small\n",
+				mtd->index);
+		return;
+	}
+
 	cxt->mtd = mtd;
 	cxt->oops_pages = mtd->size / OOPS_PAGE_SIZE;
 
 	find_next_position(cxt);
 
-	printk(KERN_DEBUG "mtdoops: Attached to MTD device %d\n", mtd->index);
+	printk(KERN_INFO "mtdoops: Attached to MTD device %d\n", mtd->index);
 }
 
 static void mtdoops_notify_remove(struct mtd_info *mtd)
@@ -377,7 +380,6 @@ static struct console mtdoops_console = {
 	.write		= mtdoops_console_write,
 	.setup		= mtdoops_console_setup,
 	.unblank	= mtdoops_console_sync,
-	.flags		= CON_PRINTBUFFER,
 	.index		= -1,
 	.data		= &oops_cxt,
 };
@@ -390,7 +392,7 @@ static int __init mtdoops_console_init(void)
 	cxt->oops_buf = vmalloc(OOPS_PAGE_SIZE);
 
 	if (!cxt->oops_buf) {
-		printk(KERN_ERR "Failed to allocate oops buffer workspace\n");
+		printk(KERN_ERR "Failed to allocate mtdoops buffer workspace\n");
 		return -ENOMEM;
 	}
 
-- 
1.5.2.3




From rpurdie at rpsys.net  Tue Jan 29 06:27:11 2008
From: rpurdie at rpsys.net (Richard Purdie)
Date: Tue, 29 Jan 2008 11:27:11 +0000
Subject: [PATCH 2/4] mtdoops: Perform write operations in a workqueue
Message-ID: <1201606031.5017.21.camel@localhost.localdomain>

Writing to the flash needs to be done in a workqueue. The console
write functions may be called in any context which can lead to
lockups otherwise.

Signed-off-by: Richard Purdie <rpurdie at rpsys.net>
---
 drivers/mtd/mtdoops.c |   82 +++++++++++++++++++++++++------------------------
 1 files changed, 42 insertions(+), 40 deletions(-)

diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 723ca76..72c434c 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -32,9 +32,10 @@
 
 #define OOPS_PAGE_SIZE 4096
 
-static struct mtdoops_context {
+struct mtdoops_context {
 	int mtd_index;
-	struct work_struct work;
+	struct work_struct work_erase;
+	struct work_struct work_write;
 	struct mtd_info *mtd;
 	int oops_pages;
 	int nextpage;
@@ -87,7 +88,7 @@ static int mtdoops_erase_block(struct mtd_info *mtd, int offset)
 	return 0;
 }
 
-static int mtdoops_inc_counter(struct mtdoops_context *cxt)
+static void mtdoops_inc_counter(struct mtdoops_context *cxt)
 {
 	struct mtd_info *mtd = cxt->mtd;
 	size_t retlen;
@@ -107,21 +108,26 @@ static int mtdoops_inc_counter(struct mtdoops_context *cxt)
 		printk(KERN_ERR "mtdoops: Read failure at %d (%td of 4 read)"
 				", err %d.\n", cxt->nextpage * OOPS_PAGE_SIZE,
 				retlen, ret);
-		return 1;
+		schedule_work(&cxt->work_erase);
+		return;
 	}
 
 	/* See if we need to erase the next block */
-	if (count != 0xffffffff)
-		return 1;
+	if (count != 0xffffffff) {
+		schedule_work(&cxt->work_erase);
+		return;
+	}
 
 	printk(KERN_DEBUG "mtdoops: Ready %d, %d (no erase)\n",
 			cxt->nextpage, cxt->nextcount);
 	cxt->ready = 1;
-	return 0;
 }
 
-static void mtdoops_prepare(struct mtdoops_context *cxt)
+/* Scheduled work - when we can't proceed without erasing a block */
+static void mtdoops_workfunc_erase(struct work_struct *work)
 {
+	struct mtdoops_context *cxt =
+			container_of(work, struct mtdoops_context, work_erase);
 	struct mtd_info *mtd = cxt->mtd;
 	int i = 0, j, ret, mod;
 
@@ -176,15 +182,31 @@ badblock:
 	goto badblock;
 }
 
-static void mtdoops_workfunc(struct work_struct *work)
+static void mtdoops_workfunc_write(struct work_struct *work)
 {
 	struct mtdoops_context *cxt =
-			container_of(work, struct mtdoops_context, work);
+			container_of(work, struct mtdoops_context, work_write);
+	struct mtd_info *mtd = cxt->mtd;
+	size_t retlen;
+	int ret;
 
-	mtdoops_prepare(cxt);
-}
+	if (cxt->writecount < OOPS_PAGE_SIZE)
+		memset(cxt->oops_buf + cxt->writecount, 0xff,
+					OOPS_PAGE_SIZE - cxt->writecount);
+
+	ret = mtd->write(mtd, cxt->nextpage * OOPS_PAGE_SIZE,
+					OOPS_PAGE_SIZE, &retlen, cxt->oops_buf);
+
+	cxt->writecount = 0;
+
+	if ((retlen != OOPS_PAGE_SIZE) || (ret < 0))
+		printk(KERN_ERR "mtdoops: Write failure at %d (%td of %d written), err %d.\n",
+			cxt->nextpage * OOPS_PAGE_SIZE, retlen,	OOPS_PAGE_SIZE, ret);
+
+	mtdoops_inc_counter(cxt);
+}					
 
-static int find_next_position(struct mtdoops_context *cxt)
+static void find_next_position(struct mtdoops_context *cxt)
 {
 	struct mtd_info *mtd = cxt->mtd;
 	int ret, page, maxpos = 0;
@@ -222,20 +244,19 @@ static int find_next_position(struct mtdoops_context *cxt)
 		cxt->ready = 1;
 		printk(KERN_DEBUG "mtdoops: Ready %d, %d (first init)\n",
 				cxt->nextpage, cxt->nextcount);
-		return 0;
+		return;
 	}
 
 	cxt->nextpage = maxpos;
 	cxt->nextcount = maxcount;
 
-	return mtdoops_inc_counter(cxt);
+	mtdoops_inc_counter(cxt);
 }
 
 
 static void mtdoops_notify_add(struct mtd_info *mtd)
 {
 	struct mtdoops_context *cxt = &oops_cxt;
-	int ret;
 
 	if ((mtd->index != cxt->mtd_index) || cxt->mtd_index < 0)
 		return;
@@ -249,9 +270,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
 	cxt->mtd = mtd;
 	cxt->oops_pages = mtd->size / OOPS_PAGE_SIZE;
 
-	ret = find_next_position(cxt);
-	if (ret == 1)
-		mtdoops_prepare(cxt);
+	find_next_position(cxt);
 
 	printk(KERN_DEBUG "mtdoops: Attached to MTD device %d\n", mtd->index);
 }
@@ -271,31 +290,13 @@ static void mtdoops_console_sync(void)
 {
 	struct mtdoops_context *cxt = &oops_cxt;
 	struct mtd_info *mtd = cxt->mtd;
-	size_t retlen;
-	int ret;
 
-	if (!cxt->ready || !mtd)
+	if (!cxt->ready || !mtd || cxt->writecount == 0)
 		return;
 
-	if (cxt->writecount == 0)
-		return;
-
-	if (cxt->writecount < OOPS_PAGE_SIZE)
-		memset(cxt->oops_buf + cxt->writecount, 0xff,
-					OOPS_PAGE_SIZE - cxt->writecount);
-
-	ret = mtd->write(mtd, cxt->nextpage * OOPS_PAGE_SIZE,
-					OOPS_PAGE_SIZE, &retlen, cxt->oops_buf);
 	cxt->ready = 0;
-	cxt->writecount = 0;
-
-	if ((retlen != OOPS_PAGE_SIZE) || (ret < 0))
-		printk(KERN_ERR "mtdoops: Write failure at %d (%td of %d written), err %d.\n",
-			cxt->nextpage * OOPS_PAGE_SIZE, retlen,	OOPS_PAGE_SIZE, ret);
 
-	ret = mtdoops_inc_counter(cxt);
-	if (ret == 1)
-		schedule_work(&cxt->work);
+	schedule_work(&cxt->work_write);
 }
 
 static void
@@ -365,7 +366,8 @@ static int __init mtdoops_console_init(void)
 		return -ENOMEM;
 	}
 
-	INIT_WORK(&cxt->work, mtdoops_workfunc);
+	INIT_WORK(&cxt->work_erase, mtdoops_workfunc_erase);
+	INIT_WORK(&cxt->work_write, mtdoops_workfunc_write);
 
 	register_console(&mtdoops_console);
 	register_mtd_user(&mtdoops_notifier);
-- 
1.5.2.3




From rpurdie at rpsys.net  Tue Jan 29 06:59:24 2008
From: rpurdie at rpsys.net (Richard Purdie)
Date: Tue, 29 Jan 2008 11:59:24 +0000
Subject: [RFC PATCH 1/3]] Add mtd panic_write function pointer
Message-ID: <1201607964.5017.48.camel@localhost.localdomain>

MTDs are well suited for logging critical data and the mtdoops driver
allows kernel panics/oops to be written to flash in a blackbox flight
recorder fashion allowing better debugging and analysis of crashes.

Any kernel oops in user context can be easily handled since the kernel
continues as normal and any queued mtd writes are scheduled. Any kernel
oops in interrupt context results in a panic and the delayed writes will
not be scheduled however. The existing mtd->write function cannot be
called in interrupt context so these messages can never be written to
flash.

This patch adds a panic_write function pointer that drivers can
optionally implement which can be called in interrupt context. It is
only intended to be called when its known the kernel is about to panic
and we need to write to succeed. Since the kernel is not going to be
running for much longer, this function can break locks and delay to
ensure the write succeeds (but not sleep).

Signed-off-by: Richard Purdie <rpurdie at rpsys.net>

---
 drivers/mtd/mtdpart.c   |   17 +++++++++++++++++
 include/linux/mtd/mtd.h |    2 ++
 2 files changed, 19 insertions(+)

Index: kernel-hacking/drivers/mtd/mtdpart.c
===================================================================
--- kernel-hacking.orig/drivers/mtd/mtdpart.c	2007-08-11 10:23:37.000000000 +0100
+++ kernel-hacking/drivers/mtd/mtdpart.c	2008-01-29 10:50:51.000000000 +0000
@@ -151,6 +151,20 @@ static int part_write (struct mtd_info *
 				    len, retlen, buf);
 }
 
+static int part_panic_write (struct mtd_info *mtd, loff_t to, size_t len,
+			size_t *retlen, const u_char *buf)
+{
+	struct mtd_part *part = PART(mtd);
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	if (to >= mtd->size)
+		len = 0;
+	else if (to + len > mtd->size)
+		len = mtd->size - to;
+	return part->master->panic_write (part->master, to + part->offset,
+				    len, retlen, buf);
+}
+
 static int part_write_oob(struct mtd_info *mtd, loff_t to,
 			 struct mtd_oob_ops *ops)
 {
@@ -352,6 +366,9 @@ int add_mtd_partitions(struct mtd_info *
 		slave->mtd.read = part_read;
 		slave->mtd.write = part_write;
 
+		if (master->panic_write)
+			slave->mtd.panic_write = part_panic_write;
+
 		if(master->point && master->unpoint){
 			slave->mtd.point = part_point;
 			slave->mtd.unpoint = part_unpoint;
Index: kernel-hacking/include/linux/mtd/mtd.h
===================================================================
--- kernel-hacking.orig/include/linux/mtd/mtd.h	2007-10-15 13:25:38.000000000 +0100
+++ kernel-hacking/include/linux/mtd/mtd.h	2008-01-29 10:50:51.000000000 +0000
@@ -152,6 +152,8 @@ struct mtd_info {
 	int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
 	int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
 
+	int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
+
 	int (*read_oob) (struct mtd_info *mtd, loff_t from,
 			 struct mtd_oob_ops *ops);
 	int (*write_oob) (struct mtd_info *mtd, loff_t to,



From rpurdie at rpsys.net  Tue Jan 29 06:59:28 2008
From: rpurdie at rpsys.net (Richard Purdie)
Date: Tue, 29 Jan 2008 11:59:28 +0000
Subject: [RFC PATCH 2/3] mtdoops: Use the panic_write function when present
Message-ID: <1201607968.5017.49.camel@localhost.localdomain>

When the MTD provides a panic_write function, use it.

Signed-off-by: Richard Purdie <rpurdie at rpsys.net>

---
 drivers/mtd/mtdoops.c |   26 +++++++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)

Index: kernel-hacking/drivers/mtd/mtdoops.c
===================================================================
--- kernel-hacking.orig/drivers/mtd/mtdoops.c	2008-01-29 11:20:33.000000000 +0000
+++ kernel-hacking/drivers/mtd/mtdoops.c	2008-01-29 11:55:57.000000000 +0000
@@ -28,6 +28,7 @@
 #include <linux/workqueue.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
+#include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/mtd/mtd.h>
 
@@ -183,10 +184,8 @@ badblock:
 	goto badblock;
 }
 
-static void mtdoops_workfunc_write(struct work_struct *work)
+static void mtdoops_write(struct mtdoops_context *cxt, int panic)
 {
-	struct mtdoops_context *cxt =
-			container_of(work, struct mtdoops_context, work_write);
 	struct mtd_info *mtd = cxt->mtd;
 	size_t retlen;
 	int ret;
@@ -195,7 +194,11 @@ static void mtdoops_workfunc_write(struc
 		memset(cxt->oops_buf + cxt->writecount, 0xff,
 					OOPS_PAGE_SIZE - cxt->writecount);
 
-	ret = mtd->write(mtd, cxt->nextpage * OOPS_PAGE_SIZE,
+	if (panic)
+		ret = mtd->panic_write(mtd, cxt->nextpage * OOPS_PAGE_SIZE,
+					OOPS_PAGE_SIZE, &retlen, cxt->oops_buf);
+	else
+		ret = mtd->write(mtd, cxt->nextpage * OOPS_PAGE_SIZE,
 					OOPS_PAGE_SIZE, &retlen, cxt->oops_buf);
 
 	cxt->writecount = 0;
@@ -205,6 +208,15 @@ static void mtdoops_workfunc_write(struc
 			cxt->nextpage * OOPS_PAGE_SIZE, retlen,	OOPS_PAGE_SIZE, ret);
 
 	mtdoops_inc_counter(cxt);
+}
+
+
+static void mtdoops_workfunc_write(struct work_struct *work)
+{
+	struct mtdoops_context *cxt =
+			container_of(work, struct mtdoops_context, work_write);
+
+	mtdoops_write(cxt, 0);
 }					
 
 static void find_next_position(struct mtdoops_context *cxt)
@@ -314,7 +326,11 @@ static void mtdoops_console_sync(void)
 	cxt->ready = 0;
 	spin_unlock_irqrestore(&cxt->writecount_lock, flags);
 
-	schedule_work(&cxt->work_write);
+	if (mtd->panic_write && in_interrupt())
+		/* Interrupt context, we're going to panic so try and log */
+		mtdoops_write(cxt, 1);
+	else
+		schedule_work(&cxt->work_write);
 }
 
 static void



From rpurdie at rpsys.net  Tue Jan 29 06:59:30 2008
From: rpurdie at rpsys.net (Richard Purdie)
Date: Tue, 29 Jan 2008 11:59:30 +0000
Subject: [RFC PATCH 3/3] Add panic_write function to the onenand driver
Message-ID: <1201607970.5017.50.camel@localhost.localdomain>

Implement the panic_write function for the onenand driver. This waits
for any active command to complete/timeout, performs the write, waits
for it to complete and then returns.

Signed-off-by: Richard Purdie <rpurdie at rpsys.net>

---
 drivers/mtd/onenand/onenand_base.c |  102 +++++++++++++++++++++++++++++++++++++
 1 file changed, 102 insertions(+)

Index: kernel-hacking/drivers/mtd/onenand/onenand_base.c
===================================================================
--- kernel-hacking.orig/drivers/mtd/onenand/onenand_base.c	2008-01-29 09:16:55.000000000 +0000
+++ kernel-hacking/drivers/mtd/onenand/onenand_base.c	2008-01-29 10:51:01.000000000 +0000
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
 #include <linux/mtd/mtd.h>
@@ -1285,6 +1286,106 @@ static int onenand_verify(struct mtd_inf
 
 #define NOTALIGNED(x)	((x & (this->subpagesize - 1)) != 0)
 
+static void onenand_panic_wait(struct mtd_info *mtd)
+{
+	struct onenand_chip *this = mtd->priv;
+	unsigned int interrupt;
+	int i;
+	
+	for (i = 0; i < 20; i++) {
+		interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
+		if (interrupt & ONENAND_INT_MASTER)
+			break;
+		udelay(1000);
+	}
+}
+
+
+/**
+ * onenand_panic_write - [MTD Interface] write buffer to FLASH in a panic context
+ * @param mtd		MTD device structure
+ * @param to		offset to write to
+ * @param len		number of bytes to write
+ * @param retlen	pointer to variable to store the number of written bytes
+ * @param buf		the data to write
+ *
+ * Write with ECC
+ */
+static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
+			 size_t *retlen, const u_char *buf)
+{
+	struct onenand_chip *this = mtd->priv;
+	int column, subpage;
+	int written = 0;
+	int ret = 0;
+
+	if (this->state == FL_PM_SUSPENDED)
+		return -EBUSY;
+
+	/* Wait for any existing operation to clear */
+	onenand_panic_wait(mtd);
+
+	DEBUG(MTD_DEBUG_LEVEL3, "onenand_panic_write: to = 0x%08x, len = %i\n",
+	      (unsigned int) to, (int) len);
+
+	/* Initialize retlen, in case of early exit */
+	*retlen = 0;
+
+	/* Do not allow writes past end of device */
+	if (unlikely((to + len) > mtd->size)) {
+		printk(KERN_ERR "onenand_panic_write: Attempt write to past end of device\n");
+		return -EINVAL;
+	}
+
+	/* Reject writes, which are not page aligned */
+        if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) {
+                printk(KERN_ERR "onenand_panic_write: Attempt to write not page aligned data\n");
+                return -EINVAL;
+        }
+
+	column = to & (mtd->writesize - 1);
+
+	/* Loop until all data write */
+	while (written < len) {
+		int thislen = min_t(int, mtd->writesize - column, len - written);
+		u_char *wbuf = (u_char *) buf;
+
+		this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
+
+		/* Partial page write */
+		subpage = thislen < mtd->writesize;
+		if (subpage) {
+			memset(this->page_buf, 0xff, mtd->writesize);
+			memcpy(this->page_buf + column, buf, thislen);
+			wbuf = this->page_buf;
+		}
+
+		this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
+		this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
+
+		this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
+
+		onenand_panic_wait(mtd);
+
+		if (ret) {
+			printk(KERN_ERR "onenand_write_nolock: write filaed %d\n", ret);
+			break;
+		}
+
+		written += thislen;
+
+		if (written == len)
+			break;
+
+		column = 0;
+		to += thislen;
+		buf += thislen;
+	}
+
+	*retlen = written;
+	return ret;
+}
+
 /**
  * onenand_fill_auto_oob - [Internal] oob auto-placement transfer
  * @param mtd		MTD device structure
@@ -2676,6 +2777,7 @@ int onenand_scan(struct mtd_info *mtd, i
 	mtd->write = onenand_write;
 	mtd->read_oob = onenand_read_oob;
 	mtd->write_oob = onenand_write_oob;
+	mtd->panic_write = onenand_panic_write;
 #ifdef CONFIG_MTD_ONENAND_OTP
 	mtd->get_fact_prot_info = onenand_get_fact_prot_info;
 	mtd->read_fact_prot_reg = onenand_read_fact_prot_reg;



From tusharkapse at gmail.com  Tue Jan 29 07:02:55 2008
From: tusharkapse at gmail.com (Tushar Kapse)
Date: Tue, 29 Jan 2008 17:32:55 +0530
Subject: MTD nand device mount problem
Message-ID: <3db60e760801290402p282910dey9891eb9b10c80661@mail.gmail.com>

Hi,
           I am working on the PXA-255 (armV5T) board with 128mb nand support.
To boot the board using MTD nand, I did the following steps:
1. Booted the board using ram filesystem.
2. Using the mtd utility "flash_eraseall" erased the partition /dev/mtd0
    ./flash_eraseall -j /dev/mtd0
3. Using the mtd utility "nandwrite" wrote the jffs2 filesystem image
to /dev/mtd0
   ./nandwrite -jf /dev/mtd0 250kb.jffs2
4. After this to verify, I tried to mount /dev/mtdblock0
    where I have received the following error messages,
end_request: I/O error, dev mtdblock0, sector 262016
printk: 35 messages suppressed.
Buffer I/O error on device mtdblock0, logical block 32752
end_request: I/O error, dev mtdblock0, sector 262016
Buffer I/O error on device mtdblock0, logical block 32752
end_request: I/O error, dev mtdblock0, sector 0
Buffer I/O error on device mtdblock0, logical block 0
end_request: I/O error, dev mtdblock0, sector 0
Buffer I/O error on device mtdblock0, logical block 0
end_request: I/O error, dev mtdblock0, sector 0
Buffer I/O error on device mtdblock0, logical block 0
end_request: I/O error, dev mtdblock0, sector 0

What could be the problem?

Regards,

Tushar Kapse


From anemo at mba.ocn.ne.jp  Tue Jan 29 08:28:22 2008
From: anemo at mba.ocn.ne.jp (Atsushi Nemoto)
Date: Tue, 29 Jan 2008 22:28:22 +0900 (JST)
Subject: [PATCH] at91_nand: Make mtdparts option can override board info
Message-ID: <20080129.222822.59465469.anemo@mba.ocn.ne.jp>

Call parse_mtd_partitions before checking board's partition_info, so
that "mtdparts=" option can override board's default setting.

Signed-off-by: Atsushi Nemoto <anemo at mba.ocn.ne.jp>
---
diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c
index b2a5672..c9fb2ac 100644
--- a/drivers/mtd/nand/at91_nand.c
+++ b/drivers/mtd/nand/at91_nand.c
@@ -156,14 +156,14 @@ static int __init at91_nand_probe(struct platform_device *pdev)
 	}
 
 #ifdef CONFIG_MTD_PARTITIONS
-	if (host->board->partition_info)
-		partitions = host->board->partition_info(mtd->size, &num_partitions);
 #ifdef CONFIG_MTD_CMDLINE_PARTS
-	else {
-		mtd->name = "at91_nand";
-		num_partitions = parse_mtd_partitions(mtd, part_probes, &partitions, 0);
-	}
+	mtd->name = "at91_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 "at91_nand: No parititions defined, or unsupported device.\n");


From anemo at mba.ocn.ne.jp  Tue Jan 29 08:28:37 2008
From: anemo at mba.ocn.ne.jp (Atsushi Nemoto)
Date: Tue, 29 Jan 2008 22:28:37 +0900 (JST)
Subject: [PATCH] at91_nand: Make part_probes[] static
Message-ID: <20080129.222837.126141133.anemo@mba.ocn.ne.jp>

This patch fixes this sparse warning:

linux/drivers/mtd/nand/at91_nand.c:86:12: warning: symbol 'part_probes' was not declared. Should it be static?

Signed-off-by: Atsushi Nemoto <anemo at mba.ocn.ne.jp>
---
diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c
index b2a5672..9adbf2a 100644
--- a/drivers/mtd/nand/at91_nand.c
+++ b/drivers/mtd/nand/at91_nand.c
@@ -83,7 +83,7 @@ static void at91_nand_disable(struct at91_nand_host *host)
 }
 
 #ifdef CONFIG_MTD_PARTITIONS
-const char *part_probes[] = { "cmdlinepart", NULL };
+static const char *part_probes[] = { "cmdlinepart", NULL };
 #endif
 
 /*


From hskinnemoen at atmel.com  Tue Jan 29 13:36:49 2008
From: hskinnemoen at atmel.com (Haavard Skinnemoen)
Date: Tue, 29 Jan 2008 19:36:49 +0100
Subject: [PATCH] MTD: Intel StrataFlash P33 is locked on bootup
Message-ID: <1201631809-32193-1-git-send-email-hskinnemoen@atmel.com>

Add appropriate fixups for all the devices listed in the Intel P33
data sheet.

Thanks to Paolo Santos for reporting this issue and testing the patch.

Signed-off-by: Haavard Skinnemoen <hskinnemoen at atmel.com>
---
 drivers/mtd/chips/cfi_cmdset_0001.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 1707f98..b723af1 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -246,6 +246,12 @@ static struct cfi_fixup cfi_fixup_table[] = {
 	{ CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL },
 	{ CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL },
 	{ MANUFACTURER_INTEL, 0x891c,	      fixup_use_powerup_lock, NULL, },
+	{ MANUFACTURER_INTEL, 0x881d,	      fixup_use_powerup_lock, NULL, },
+	{ MANUFACTURER_INTEL, 0x881e,	      fixup_use_powerup_lock, NULL, },
+	{ MANUFACTURER_INTEL, 0x891f,	      fixup_use_powerup_lock, NULL, },
+	{ MANUFACTURER_INTEL, 0x8820,	      fixup_use_powerup_lock, NULL, },
+	{ MANUFACTURER_INTEL, 0x8821,	      fixup_use_powerup_lock, NULL, },
+	{ MANUFACTURER_INTEL, 0x8922,	      fixup_use_powerup_lock, NULL, },
 	{ 0, 0, NULL, NULL }
 };
 
-- 
1.5.3.8



From joern at logfs.org  Tue Jan 29 17:56:15 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Tue, 29 Jan 2008 23:56:15 +0100
Subject: Searchable Archives and Using RAM
In-Reply-To: <479EA68A.2000704@comcast.net>
References: <479EA68A.2000704@comcast.net>
Message-ID: <20080129225615.GA32157@lazybastard.org>

On Mon, 28 January 2008 23:07:38 -0500, Frank wrote:
> 
> I just joined the list as I am looking for information on how to set up 
> MTD to use 2Mb of battery-backed up RAM as a disk.   This will be on an 
> ARM-based SBC that already has MTD NAND drivers loaded.  I think I know 
> where I need to start (CONFIG_MTD_MTDRAM, etc), but have not seen any 
> how-to's yet.   I found a new book from O'Reilly that'll be out in 
> February that looks very promising 
> (http://safari.oreilly.com/0136130550/ch10), but I was wondering if 
> there are any online resources.

Usually phram is the driver of choice for NVRAM.

J?rn

-- 
Linux is more the core point of a concept that surrounds "open source"
which, in turn, is based on a false concept. This concept is that
people actually want to look at source code.
-- Rob Enderle


From joern at logfs.org  Tue Jan 29 18:07:19 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Wed, 30 Jan 2008 00:07:19 +0100
Subject: [PATCH] [JFFS2] JFFS2 doesn't use OOB at MLC NAND/OneNAND
In-Reply-To: <20080129083630.GA31954@party>
References: <20080129083630.GA31954@party>
Message-ID: <20080129230702.GB32157@lazybastard.org>

On Tue, 29 January 2008 17:36:30 +0900, Kyungmin Park wrote:
> 
> It's revised patch from 
> http://patchwork.ozlabs.org/linux-mtd/patch?id=15260
> 
> Just remove one line
> +#define MTD_CAP_MLC_NANDFLASH	(MTD_WRITEABLE)
> 
> If you don't any rejct please apply this one.

Looks good to me.
Acked-by: Joern Engel <joern at logfs.org>

J?rn

-- 
Schr?dinger's cat is <BLINK>not</BLINK> dead.
-- Illiad


From joern at logfs.org  Tue Jan 29 18:11:04 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Wed, 30 Jan 2008 00:11:04 +0100
Subject: [RFC PATCH 1/3]] Add mtd panic_write function pointer
In-Reply-To: <1201607964.5017.48.camel@localhost.localdomain>
References: <1201607964.5017.48.camel@localhost.localdomain>
Message-ID: <20080129231104.GC32157@lazybastard.org>

On Tue, 29 January 2008 11:59:24 +0000, Richard Purdie wrote:
> 
> MTDs are well suited for logging critical data and the mtdoops driver
> allows kernel panics/oops to be written to flash in a blackbox flight
> recorder fashion allowing better debugging and analysis of crashes.
> 
> Any kernel oops in user context can be easily handled since the kernel
> continues as normal and any queued mtd writes are scheduled. Any kernel
> oops in interrupt context results in a panic and the delayed writes will
> not be scheduled however. The existing mtd->write function cannot be
> called in interrupt context so these messages can never be written to
> flash.
> 
> This patch adds a panic_write function pointer that drivers can
> optionally implement which can be called in interrupt context. It is
> only intended to be called when its known the kernel is about to panic
> and we need to write to succeed. Since the kernel is not going to be
> running for much longer, this function can break locks and delay to
> ensure the write succeeds (but not sleep).

I like the description.  So why is it not part of the patch proper?


J?rn

-- 
Beware of bugs in the above code; I have only proved it correct, but
not tried it.
-- Donald Knuth


From joern at logfs.org  Tue Jan 29 18:17:43 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Wed, 30 Jan 2008 00:17:43 +0100
Subject: [PATCH] at91_nand: Make part_probes[] static
In-Reply-To: <20080129.222837.126141133.anemo@mba.ocn.ne.jp>
References: <20080129.222837.126141133.anemo@mba.ocn.ne.jp>
Message-ID: <20080129231743.GD32157@lazybastard.org>

On Tue, 29 January 2008 22:28:37 +0900, Atsushi Nemoto wrote:
> 
> This patch fixes this sparse warning:
> 
> linux/drivers/mtd/nand/at91_nand.c:86:12: warning: symbol 'part_probes' was not declared. Should it be static?

You cannot fix a warning.  You can only fix code.  Warnings can be and
often are wrong.  This particular is right, so in spite of the
description
Acked-by: Joern Engel <joern at logfs.org>

> Signed-off-by: Atsushi Nemoto <anemo at mba.ocn.ne.jp>
> ---
> diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c
> index b2a5672..9adbf2a 100644
> --- a/drivers/mtd/nand/at91_nand.c
> +++ b/drivers/mtd/nand/at91_nand.c
> @@ -83,7 +83,7 @@ static void at91_nand_disable(struct at91_nand_host *host)
>  }
>  
>  #ifdef CONFIG_MTD_PARTITIONS
> -const char *part_probes[] = { "cmdlinepart", NULL };
> +static const char *part_probes[] = { "cmdlinepart", NULL };
>  #endif
>  
>  /*
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/

J?rn

-- 
Joern's library part 11:
http://www.unicom.com/pw/reply-to-harmful.html


From jaredeh at gmail.com  Tue Jan 29 20:40:55 2008
From: jaredeh at gmail.com (Jared Hulbert)
Date: Tue, 29 Jan 2008 17:40:55 -0800
Subject: [PATCH][CFI] Wrong cache invalidation bug fix
In-Reply-To: <1200049397.4839.7.camel@pmac.infradead.org>
References: <62cbdcd90712030834o28f9126fs841b3b9d46324fb7@mail.gmail.com>
	<alpine.LFD.0.99999.0712031210180.9605@xanadu.home>
	<62cbdcd90712050758h36335aa5q176f1c192f18d6a9@mail.gmail.com>
	<Pine.LNX.4.64.0801111042510.20196@pentafluge.infradead.org>
	<1200049397.4839.7.camel@pmac.infradead.org>
Message-ID: <6934efce0801291740y3609e22cvdd94929499f98eef@mail.gmail.com>

> That isn't an excuse for ignoring it for a month -- on that I plead
> incompetence.
>
> I've taken the version from Jared's git tree and sent it to Linus.

I don't see it anywhere in Linus' or your tree.  Can we make sure it gets in?


From jaredeh at gmail.com  Tue Jan 29 21:13:43 2008
From: jaredeh at gmail.com (Jared Hulbert)
Date: Tue, 29 Jan 2008 18:13:43 -0800
Subject: [PATCH] MTD: Intel StrataFlash P33 is locked on bootup
In-Reply-To: <1201631809-32193-1-git-send-email-hskinnemoen@atmel.com>
References: <1201631809-32193-1-git-send-email-hskinnemoen@atmel.com>
Message-ID: <6934efce0801291813n68b796f5j5f3db1e90eb174a9@mail.gmail.com>

> Add appropriate fixups for all the devices listed in the Intel P33
> data sheet.

Please don't merge this patch.

We worked on a patch that will unlock _all_ intel parts that have this
behavior in a more acceptable way.  It was discussed back in November.

I thought Justin had finished running this through review but I don't
see it now.  So I thought you had Acked this patch Nicolas, I can't
find where.  Was I mistaken?


Anyway I added it to my freshly updated git tree
"git://git.infradead.org/users/jehulber/mtd.git" (with a possibly
unearned Acked-by: Nicolas Pitre)


For visual review only....
__________________________________________________________

From: Justin Treon <justin_treon at yahoo.com>
[MTD] Unlocking all Intel flash that is locked on power up.

Patch for unlocking all Intel flash that has instant locking on power up.
The patch has been tested on Intel M18, P30 and J3D Strata Flash.
  1.    The automatic unlocking can be disabled for a particular partition
         in the map or the command line.
     a. For the bit mask in the map it should look like:
         .mask_flags   = MTD_POWERUP_LOCK,
     b. For the command line parsing it should look like:
         mtdparts=0x80000(bootloader)lk
  2.    This will only unlock parts with instant individual block locking.
         Intel parts with legacy unlocking will not be unlocked.

Signed-off-by: Justin Treon <justin_treon at yahoo.com>
---
drivers/mtd/chips/cfi_cmdset_0001.c |   20 +++++++++++++-------
drivers/mtd/cmdlinepart.c           |    9 ++++++++-
drivers/mtd/mtdcore.c               |    2 +-
include/mtd/mtd-abi.h               |    2 +-
4 files changed, 23 insertions(+), 10 deletions(-)

diff -r c105f44cf785 drivers/mtd/chips/cfi_cmdset_0001.c
--- a/drivers/mtd/chips/cfi_cmdset_0001.c	Thu Nov 08 15:36:57 2007 -0800
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c	Tue Nov 13 22:47:40 2007 -0800
@@ -226,10 +226,16 @@ static void fixup_use_write_buffers(stru
 /*
  * Some chips power-up with all sectors locked by default.
  */
-static void fixup_use_powerup_lock(struct mtd_info *mtd, void *param)
-{
-	printk(KERN_INFO "Using auto-unlock on power-up/resume\n" );
-	mtd->flags |= MTD_STUPID_LOCK;
+static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
+
+	if (cfip->FeatureSupport&32) {
+		printk(KERN_INFO "Using auto-unlock on power-up/resume\n" );
+		mtd->flags |= MTD_POWERUP_LOCK;
+	}
 }

 static struct cfi_fixup cfi_fixup_table[] = {
@@ -244,7 +250,7 @@ static struct cfi_fixup cfi_fixup_table[
 #endif
 	{ CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL },
 	{ CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL },
-	{ MANUFACTURER_INTEL, 0x891c,	      fixup_use_powerup_lock, NULL, },
+	{ MANUFACTURER_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock, NULL, },
 	{ 0, 0, NULL, NULL }
 };

@@ -2273,7 +2279,7 @@ static int cfi_intelext_suspend(struct m
 	struct flchip *chip;
 	int ret = 0;

-	if ((mtd->flags & MTD_STUPID_LOCK)
+	if ((mtd->flags & MTD_POWERUP_LOCK)
 	    && extp && (extp->FeatureSupport & (1 << 5)))
 		cfi_intelext_save_locks(mtd);

@@ -2384,7 +2390,7 @@ static void cfi_intelext_resume(struct m
 		spin_unlock(chip->mutex);
 	}

-	if ((mtd->flags & MTD_STUPID_LOCK)
+	if ((mtd->flags & MTD_POWERUP_LOCK)
 	    && extp && (extp->FeatureSupport & (1 << 5)))
 		cfi_intelext_restore_locks(mtd);
 }
diff -r c105f44cf785 drivers/mtd/cmdlinepart.c
--- a/drivers/mtd/cmdlinepart.c	Thu Nov 08 15:36:57 2007 -0800
+++ b/drivers/mtd/cmdlinepart.c	Thu Nov 15 17:18:11 2007 -0800
@@ -9,7 +9,7 @@
  *
  * mtdparts=<mtddef>[;<mtddef]
  * <mtddef>  := <mtd-id>:<partdef>[,<partdef>]
- * <partdef> := <size>[@offset][<name>][ro]
+ * <partdef> := <size>[@offset][<name>][ro][lk]
  * <mtd-id>  := unique name used in mapping driver/device (mtd->name)
  * <size>    := standard linux memsize OR "-" to denote all remaining space
  * <name>    := '(' NAME ')'
@@ -140,6 +140,13 @@ static struct mtd_partition * newpart(ch
         if (strncmp(s, "ro", 2) == 0)
 	{
 		mask_flags |= MTD_WRITEABLE;
+		s += 2;
+        }
+
+        /* if lk is found do NOT unlock the MTD partition*/
+        if (strncmp(s, "lk", 2) == 0)
+	{
+		mask_flags |= MTD_POWERUP_LOCK;
 		s += 2;
         }

diff -r c105f44cf785 drivers/mtd/mtdcore.c
--- a/drivers/mtd/mtdcore.c	Thu Nov 08 15:36:57 2007 -0800
+++ b/drivers/mtd/mtdcore.c	Tue Nov 13 15:41:00 2007 -0800
@@ -59,7 +59,7 @@ int add_mtd_device(struct mtd_info *mtd)

 			/* Some chips always power up locked. Unlock them now */
 			if ((mtd->flags & MTD_WRITEABLE)
-			    && (mtd->flags & MTD_STUPID_LOCK) && mtd->unlock) {
+			    && (mtd->flags & MTD_POWERUP_LOCK) && mtd->unlock) {
 				if (mtd->unlock(mtd, 0, mtd->size))
 					printk(KERN_WARNING
 					       "%s: unlock failed, "
diff -r c105f44cf785 include/mtd/mtd-abi.h
--- a/include/mtd/mtd-abi.h	Thu Nov 08 15:36:57 2007 -0800
+++ b/include/mtd/mtd-abi.h	Fri Nov 09 10:43:28 2007 -0800
@@ -29,7 +29,7 @@ struct mtd_oob_buf {
 #define MTD_WRITEABLE		0x400	/* Device is writeable */
 #define MTD_BIT_WRITEABLE	0x800	/* Single bits can be flipped */
 #define MTD_NO_ERASE		0x1000	/* No erase necessary */
-#define MTD_STUPID_LOCK		0x2000	/* Always locked after reset */
+#define MTD_POWERUP_LOCK	0x2000	/* Always locked after reset */

 // Some common devices / combinations of capabilities
 #define MTD_CAP_ROM		0


From nico at cam.org  Tue Jan 29 21:32:18 2008
From: nico at cam.org (Nicolas Pitre)
Date: Tue, 29 Jan 2008 21:32:18 -0500 (EST)
Subject: [PATCH] MTD: Intel StrataFlash P33 is locked on bootup
In-Reply-To: <6934efce0801291813n68b796f5j5f3db1e90eb174a9@mail.gmail.com>
References: <1201631809-32193-1-git-send-email-hskinnemoen@atmel.com>
	<6934efce0801291813n68b796f5j5f3db1e90eb174a9@mail.gmail.com>
Message-ID: <alpine.LFD.1.00.0801292127400.22568@xanadu.home>

On Tue, 29 Jan 2008, Jared Hulbert wrote:

> > Add appropriate fixups for all the devices listed in the Intel P33
> > data sheet.
> 
> Please don't merge this patch.
> 
> We worked on a patch that will unlock _all_ intel parts that have this
> behavior in a more acceptable way.  It was discussed back in November.
> 
> I thought Justin had finished running this through review but I don't
> see it now.  So I thought you had Acked this patch Nicolas, I can't
> find where.  Was I mistaken?

I did, but the MTD mailing list has a tendency to require moderator 
aproval for some of my emails.

> Anyway I added it to my freshly updated git tree
> "git://git.infradead.org/users/jehulber/mtd.git" (with a possibly
> unearned Acked-by: Nicolas Pitre)

Please consider it was acked.


Nicolas


From bryan.wu at analog.com  Wed Jan 30 04:18:15 2008
From: bryan.wu at analog.com (Bryan Wu)
Date: Wed, 30 Jan 2008 17:18:15 +0800
Subject: [PATCH 0/3] [MTD/NAND] Blackfin NFC driver updates
Message-ID: <1201684698-26936-1-git-send-email-bryan.wu@analog.com>



From bryan.wu at analog.com  Wed Jan 30 05:02:44 2008
From: bryan.wu at analog.com (Bryan Wu)
Date: Wed, 30 Jan 2008 18:02:44 +0800
Subject: [PATCH 1/1] [MTD/MAPS] Blackfin BF5xx Maps: Handle the case where
	flash memory and ethernet mac/phy are mapped onto the same async bank
Message-ID: <1201687364-32178-1-git-send-email-bryan.wu@analog.com>

The BF533-STAMP does this for example.
All board-specific configuration goes in your board resources file.

Signed-off-by: Mike Frysinger <michael.frysinger at analog.com>
Signed-off-by: Bryan Wu <bryan.wu at analog.com>
---
 drivers/mtd/maps/Kconfig       |   45 ++++++++
 drivers/mtd/maps/Makefile      |    1 +
 drivers/mtd/maps/bf5xx-flash.c |  227 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 273 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mtd/maps/bf5xx-flash.c

diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index a592fc0..5357f04 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -528,6 +528,51 @@ config MTD_PCMCIA_ANONYMOUS
 
 	  If unsure, say N.
 
+config MTD_BF5xx
+	tristate "Blackfin BF533-STAMP Flash Chip Support"
+	depends on BFIN533_STAMP && MTD_CFI
+	select MTD_PARTITIONS
+	help
+	  Map driver which allows for simultaneous utilization of
+	  ethernet and CFI parallel flash.
+
+config BFIN_FLASH_BANK_0
+	hex "EBIU_AMBCTL For Flash (Bank 0)"
+	depends on MTD_BF5xx
+	default 0x7BB0
+	help
+	  For boards that share the async memory bank with both Flash and
+	  the Ethernet, these settings allow you to have EBIU settings just
+	  when the Flash is active.  The other EBIU settings in the main
+	  Blackfin menu will be utilized when the Flash is not active.
+config BFIN_FLASH_BANK_1
+	hex "EBIU_AMBCTL For Flash (Bank 1)"
+	depends on MTD_BF5xx
+	default 0x7BB0
+	help
+	  For boards that share the async memory bank with both Flash and
+	  the Ethernet, these settings allow you to have EBIU settings just
+	  when the Flash is active.  The other EBIU settings in the main
+	  Blackfin menu will be utilized when the Flash is not active.
+config BFIN_FLASH_BANK_2
+	hex "EBIU_AMBCTL For Flash (Bank 2)"
+	depends on MTD_BF5xx
+	default 0x7BB0
+	help
+	  For boards that share the async memory bank with both Flash and
+	  the Ethernet, these settings allow you to have EBIU settings just
+	  when the Flash is active.  The other EBIU settings in the main
+	  Blackfin menu will be utilized when the Flash is not active.
+config BFIN_FLASH_BANK_3
+	hex "EBIU_AMBCTL For Flash (Bank 3)"
+	depends on MTD_BF5xx
+	default 0x7BB0
+	help
+	  For boards that share the async memory bank with both Flash and
+	  the Ethernet, these settings allow you to have EBIU settings just
+	  when the Flash is active.  The other EBIU settings in the main
+	  Blackfin menu will be utilized when the Flash is not active.
+
 config MTD_UCLINUX
 	tristate "Generic uClinux RAM/ROM filesystem support"
 	depends on MTD_PARTITIONS && !MMU
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index 316382a..62eea4f 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -69,3 +69,4 @@ obj-$(CONFIG_MTD_PLATRAM)	+= plat-ram.o
 obj-$(CONFIG_MTD_OMAP_NOR)	+= omap_nor.o
 obj-$(CONFIG_MTD_MTX1)		+= mtx-1_flash.o
 obj-$(CONFIG_MTD_INTEL_VR_NOR)	+= intel_vr_nor.o
+obj-$(CONFIG_MTD_BF5xx)		+= bf5xx-flash.o
diff --git a/drivers/mtd/maps/bf5xx-flash.c b/drivers/mtd/maps/bf5xx-flash.c
new file mode 100644
index 0000000..8c2f897
--- /dev/null
+++ b/drivers/mtd/maps/bf5xx-flash.c
@@ -0,0 +1,227 @@
+/*
+ * drivers/mtd/maps/bf5xx-flash.c
+ *
+ * Handle the case where flash memory and ethernet mac/phy are
+ * mapped onto the same async bank.  The BF533-STAMP does this
+ * for example.  All board-specific configuration goes in your
+ * board resources file.
+ *
+ * Copyright 2000 Nicolas Pitre <nico at cam.org>
+ * Copyright 2005-2008 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#include <asm/blackfin.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+
+#define pr_init(fmt, args...) ({ static const __initdata char __fmt[] = fmt; printk(__fmt, ## args); })
+
+#define DRIVER_NAME "BF5xx-Flash"
+
+#define BFIN_FLASH_AMBCTL0VAL	((CONFIG_BFIN_FLASH_BANK_1 << 16) | CONFIG_BFIN_FLASH_BANK_0)
+#define BFIN_FLASH_AMBCTL1VAL	((CONFIG_BFIN_FLASH_BANK_3 << 16) | CONFIG_BFIN_FLASH_BANK_2)
+
+/* Should add a per-device structure and track this there ... */
+static int enet_flash_pin;
+static struct mtd_info *bf5xx_mtd;
+
+struct flash_save {
+	u32 ambctl0;
+	u32 ambctl1;
+	unsigned long flags;
+};
+
+static void switch_to_flash(struct flash_save *save)
+{
+	local_irq_save(save->flags);
+
+	gpio_set_value(enet_flash_pin, 0);
+	SSYNC();
+
+	save->ambctl0 = bfin_read_EBIU_AMBCTL0();
+	save->ambctl1 = bfin_read_EBIU_AMBCTL1();
+	bfin_write_EBIU_AMBCTL0(BFIN_FLASH_AMBCTL0VAL);
+	bfin_write_EBIU_AMBCTL1(BFIN_FLASH_AMBCTL1VAL);
+	SSYNC();
+}
+
+static void switch_back(struct flash_save *save)
+{
+	bfin_write_EBIU_AMBCTL0(save->ambctl0);
+	bfin_write_EBIU_AMBCTL1(save->ambctl1);
+	SSYNC();
+
+	gpio_set_value(enet_flash_pin, 1);
+
+	local_irq_restore(save->flags);
+}
+
+static map_word bf5xx_read(struct map_info *map, unsigned long ofs)
+{
+	int nValue = 0x0;
+	map_word test;
+	struct flash_save save;
+
+	switch_to_flash(&save);
+	SSYNC();
+	nValue = readw(map->virt + ofs);
+	SSYNC();
+	switch_back(&save);
+
+	test.x[0] = (u16)nValue;
+	return test;
+}
+
+static void bf5xx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	unsigned long i;
+	map_word test;
+
+	if ((unsigned long)to & 0x1) {
+		for (i = 0; i < len / 2 * 2; i += 2) {
+			test = bf5xx_read(map, from + i);
+			put_unaligned(test.x[0], (__le16 *)(to + i));
+		}
+	} else {
+		for (i = 0; i < len / 2 * 2; i += 2) {
+			test = bf5xx_read(map, from + i);
+			*((u16*)(to + i)) = test.x[0];
+		}
+	}
+
+	if (len & 0x1) {
+		test = bf5xx_read(map, from + i);
+		*((u8*)(to + i)) = (u8)test.x[0];
+	}
+}
+
+static void bf5xx_write(struct map_info *map, map_word d1, unsigned long ofs)
+{
+	u16 d;
+	struct flash_save save;
+
+	d = (u16)d1.x[0];
+
+	switch_to_flash(&save);
+
+	SSYNC();
+	writew(d, map->virt + ofs);
+	SSYNC();
+
+	switch_back(&save);
+}
+
+static void bf5xx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	struct flash_save save;
+
+	switch_to_flash(&save);
+
+	memcpy(map->virt + to, from, len);
+
+	switch_back(&save);
+}
+
+static struct map_info bf5xx_map = {
+	.name      = DRIVER_NAME,
+	.read      = bf5xx_read,
+	.copy_from = bf5xx_copy_from,
+	.write     = bf5xx_write,
+	.copy_to   = bf5xx_copy_to,
+};
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
+#endif
+
+static int __init bf5xx_flash_probe(struct platform_device *dev)
+{
+	int ret;
+	struct physmap_flash_data *pdata = dev->dev.platform_data;
+	struct resource *memory = platform_get_resource(dev, IORESOURCE_MEM, 0);
+
+	enet_flash_pin = platform_get_irq(dev, 0);
+
+	bf5xx_map.bankwidth = pdata->width;
+	bf5xx_map.size = memory->end - memory->start + 1;
+	bf5xx_map.virt = (void __iomem *)memory->start;
+	bf5xx_map.phys = memory->start;
+
+	if (gpio_request(enet_flash_pin, DRIVER_NAME)) {
+		pr_init(KERN_ERR DRIVER_NAME ": Failed to request gpio %d\n", enet_flash_pin);
+		return -EBUSY;
+	}
+	gpio_direction_output(enet_flash_pin, 1);
+
+	pr_init(KERN_NOTICE DRIVER_NAME ": probing %d-bit flash bus\n", bf5xx_map.bankwidth * 8);
+	bf5xx_mtd = do_map_probe(memory->name, &bf5xx_map);
+	if (!bf5xx_mtd)
+		return -ENXIO;
+
+#ifdef CONFIG_MTD_PARTITIONS
+	ret = parse_mtd_partitions(bf5xx_mtd, part_probe_types, &pdata->parts, 0);
+	if (ret > 0) {
+		pr_init(KERN_NOTICE DRIVER_NAME ": Using commandline partition definition\n");
+		add_mtd_partitions(bf5xx_mtd, pdata->parts, ret);
+
+	} else if (pdata->nr_parts) {
+		pr_init(KERN_NOTICE DRIVER_NAME ": Using board partition definition\n");
+		add_mtd_partitions(bf5xx_mtd, pdata->parts, pdata->nr_parts);
+
+	} else
+#endif
+	{
+		pr_init(KERN_NOTICE DRIVER_NAME ": no partition info available, registering whole flash at once\n");
+		add_mtd_device(bf5xx_mtd);
+	}
+
+	return 0;
+}
+
+static int __devexit bf5xx_flash_remove(struct platform_device *dev)
+{
+	gpio_free(enet_flash_pin);
+#ifdef CONFIG_MTD_PARTITIONS
+	del_mtd_partitions(bf5xx_mtd);
+#endif
+	map_destroy(bf5xx_mtd);
+	return 0;
+}
+
+static struct platform_driver bf5xx_flash_driver = {
+	.probe		= bf5xx_flash_probe,
+	.remove		= __devexit_p(bf5xx_flash_remove),
+	.driver		= {
+		.name	= DRIVER_NAME,
+	},
+};
+
+static int __init bf5xx_flash_init(void)
+{
+	return platform_driver_register(&bf5xx_flash_driver);
+}
+module_init(bf5xx_flash_init);
+
+static void __exit bf5xx_flash_exit(void)
+{
+	platform_driver_unregister(&bf5xx_flash_driver);
+}
+module_exit(bf5xx_flash_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MTD map driver for Blackfins with flash/ethernet on same async bank");
-- 
1.5.3.4


From rpurdie at rpsys.net  Wed Jan 30 05:03:03 2008
From: rpurdie at rpsys.net (Richard Purdie)
Date: Wed, 30 Jan 2008 10:03:03 +0000
Subject: [RFC PATCH 1/3]] Add mtd panic_write function pointer
In-Reply-To: <20080129231104.GC32157@lazybastard.org>
References: <1201607964.5017.48.camel@localhost.localdomain>
	<20080129231104.GC32157@lazybastard.org>
Message-ID: <1201687383.4668.1.camel@localhost.localdomain>

On Wed, 2008-01-30 at 00:11 +0100, J?rn Engel wrote:
> On Tue, 29 January 2008 11:59:24 +0000, Richard Purdie wrote:
> > 
> > MTDs are well suited for logging critical data and the mtdoops driver
> > allows kernel panics/oops to be written to flash in a blackbox flight
> > recorder fashion allowing better debugging and analysis of crashes.
> > 
> > Any kernel oops in user context can be easily handled since the kernel
> > continues as normal and any queued mtd writes are scheduled. Any kernel
> > oops in interrupt context results in a panic and the delayed writes will
> > not be scheduled however. The existing mtd->write function cannot be
> > called in interrupt context so these messages can never be written to
> > flash.
> > 
> > This patch adds a panic_write function pointer that drivers can
> > optionally implement which can be called in interrupt context. It is
> > only intended to be called when its known the kernel is about to panic
> > and we need to write to succeed. Since the kernel is not going to be
> > running for much longer, this function can break locks and delay to
> > ensure the write succeeds (but not sleep).
> 
> I like the description.  So why is it not part of the patch proper?

You mean add it to mtd.h?

Richard





From bryan.wu at analog.com  Wed Jan 30 05:27:24 2008
From: bryan.wu at analog.com (Bryan Wu)
Date: Wed, 30 Jan 2008 18:27:24 +0800
Subject: [PATCH 1/1] [MTD] chips: add a new INTEL ID to kernel cfi driver.
Message-ID: <1201688844-2318-1-git-send-email-bryan.wu@analog.com>

From: Sonic Zhang <sonic.zhang at analog.com>

Signed-off-by: Sonic Zhang <sonic.zhang at analog.com>
Signed-off-by: Bryan Wu <bryan.wu at analog.com>
---
 drivers/mtd/chips/cfi_cmdset_0001.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 1707f98..a833618 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -246,6 +246,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
 	{ CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL },
 	{ CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL },
 	{ MANUFACTURER_INTEL, 0x891c,	      fixup_use_powerup_lock, NULL, },
+	{ MANUFACTURER_INTEL, 0x891f,	      fixup_use_powerup_lock, NULL, },
 	{ 0, 0, NULL, NULL }
 };
 
-- 
1.5.3.4


From bryan.wu at analog.com  Wed Jan 30 04:18:17 2008
From: bryan.wu at analog.com (Bryan Wu)
Date: Wed, 30 Jan 2008 17:18:17 +0800
Subject: [PATCH 2/3] [MTD/NAND] Blackfin NFC driver: Fix bug - remove wrong
	operation in PM function of the BF54x NFC driver
In-Reply-To: <1201684698-26936-1-git-send-email-bryan.wu@analog.com>
References: <1201684698-26936-1-git-send-email-bryan.wu@analog.com>
Message-ID: <1201684698-26936-3-git-send-email-bryan.wu@analog.com>

There is no suspend/resume operation in NFC driver at all, currently.

Signed-off-by: Bryan Wu <bryan.wu at analog.com>
---
 drivers/mtd/nand/bf5xx_nand.c |    3 ---
 1 files changed, 0 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
index 542850c..2fe9678 100644
--- a/drivers/mtd/nand/bf5xx_nand.c
+++ b/drivers/mtd/nand/bf5xx_nand.c
@@ -760,9 +760,6 @@ static int bf5xx_nand_resume(struct platform_device *dev)
 {
 	struct bf5xx_nand_info *info = platform_get_drvdata(dev);
 
-	if (info)
-		bf5xx_nand_hw_init(info);
-
 	return 0;
 }
 
-- 
1.5.3.4


From bryan.wu at analog.com  Wed Jan 30 04:18:16 2008
From: bryan.wu at analog.com (Bryan Wu)
Date: Wed, 30 Jan 2008 17:18:16 +0800
Subject: [PATCH 1/3] [MTD/NAND] Blackfin NFC driver: Add Blackfin BF52x
	on-chip NAND Flash controller driver support in bf5xx_nand driver
In-Reply-To: <1201684698-26936-1-git-send-email-bryan.wu@analog.com>
References: <1201684698-26936-1-git-send-email-bryan.wu@analog.com>
Message-ID: <1201684698-26936-2-git-send-email-bryan.wu@analog.com>

From: Michael Hennerich <michael.hennerich at analog.com>

Signed-off-by: Michael Hennerich <michael.hennerich at analog.com>
Signed-off-by: Bryan Wu <bryan.wu at analog.com>
---
 drivers/mtd/nand/Kconfig      |    2 +-
 drivers/mtd/nand/bf5xx_nand.c |   20 ++++++++++++++++++--
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 246d451..bf0e9b0 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -93,7 +93,7 @@ config MTD_NAND_AU1550
 
 config MTD_NAND_BF5XX
 	tristate "Blackfin on-chip NAND Flash Controller driver"
-	depends on BF54x && MTD_NAND
+	depends on (BF54x || BF52x) && MTD_NAND
 	help
 	  This enables the Blackfin on-chip NAND flash controller
 
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
index 1657ecd..542850c 100644
--- a/drivers/mtd/nand/bf5xx_nand.c
+++ b/drivers/mtd/nand/bf5xx_nand.c
@@ -74,7 +74,22 @@ static int hardware_ecc = 1;
 static int hardware_ecc;
 #endif
 
-static unsigned short bfin_nfc_pin_req[] = {P_NAND_CE, P_NAND_RB, 0};
+static unsigned short bfin_nfc_pin_req[] =
+	{P_NAND_CE,
+	 P_NAND_RB,
+	 P_NAND_D0,
+	 P_NAND_D1,
+	 P_NAND_D2,
+	 P_NAND_D3,
+	 P_NAND_D4,
+	 P_NAND_D5,
+	 P_NAND_D6,
+	 P_NAND_D7,
+	 P_NAND_WE,
+	 P_NAND_RE,
+	 P_NAND_CLE,
+	 P_NAND_ALE,
+	 0};
 
 /*
  * Data structures for bf5xx nand flash controller driver
@@ -507,12 +522,13 @@ static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info)
 
 	init_completion(&info->dma_completion);
 
+#ifdef CONFIG_BF54x
 	/* Setup DMAC1 channel mux for NFC which shared with SDH */
 	val = bfin_read_DMAC1_PERIMUX();
 	val &= 0xFFFE;
 	bfin_write_DMAC1_PERIMUX(val);
 	SSYNC();
-
+#endif
 	/* Request NFC DMA channel */
 	ret = request_dma(CH_NFC, "BF5XX NFC driver");
 	if (ret < 0) {
-- 
1.5.3.4


From bryan.wu at analog.com  Wed Jan 30 04:18:18 2008
From: bryan.wu at analog.com (Bryan Wu)
Date: Wed, 30 Jan 2008 17:18:18 +0800
Subject: [PATCH 3/3] [MTD/NAND] Blackfin NFC driver: fix ECC caculating bug
	when NAND Flash chip page size is 512 bytes
In-Reply-To: <1201684698-26936-1-git-send-email-bryan.wu@analog.com>
References: <1201684698-26936-1-git-send-email-bryan.wu@analog.com>
Message-ID: <1201684698-26936-4-git-send-email-bryan.wu@analog.com>

Signed-off-by: Bryan Wu <bryan.wu at analog.com>
---
 drivers/mtd/nand/bf5xx_nand.c |   16 ++++++++++------
 1 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
index 2fe9678..7d6ac6a 100644
--- a/drivers/mtd/nand/bf5xx_nand.c
+++ b/drivers/mtd/nand/bf5xx_nand.c
@@ -293,7 +293,6 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd,
 	u16 ecc0, ecc1;
 	u32 code[2];
 	u8 *p;
-	int bytes = 3, i;
 
 	/* first 4 bytes ECC code for 256 page size */
 	ecc0 = bfin_read_NFC_ECC0();
@@ -303,19 +302,24 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd,
 
 	dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]);
 
+	/* first 3 bytes in ecc_code for 256 page size */
+	p = (u8 *) code;
+	memcpy(ecc_code, p, 3);
+
 	/* second 4 bytes ECC code for 512 page size */
 	if (page_size == 512) {
 		ecc0 = bfin_read_NFC_ECC2();
 		ecc1 = bfin_read_NFC_ECC3();
 		code[1] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11);
-		bytes = 6;
+
+		/* second 3 bytes in ecc_code for second 256
+		 * bytes of 512 page size
+		 */
+		p = (u8 *) (code + 1);
+		memcpy((ecc_code + 3), p, 3);
 		dev_dbg(info->device, "returning ecc 0x%08x\n", code[1]);
 	}
 
-	p = (u8 *)code;
-	for (i = 0; i < bytes; i++)
-		ecc_code[i] = p[i];
-
 	return 0;
 }
 
-- 
1.5.3.4


From vicky.irobot at gmail.com  Wed Jan 30 01:37:22 2008
From: vicky.irobot at gmail.com (Max Stirling)
Date: Wed, 30 Jan 2008 01:37:22 -0500
Subject: mtd block readonly low level nand driver cramfs
In-Reply-To: <479D86E4.30903@gmail.com>
References: <47985D88.1060005@gmail.com>
	<6a61dac20801270054t19e2af20o1211490d104110a9@mail.gmail.com>
	<479D86E4.30903@gmail.com>
Message-ID: <47A01B22.9040206@gmail.com>

Max Stirling wrote:
> Max Stirling wrote:
>> I was looking at the chips folder under MTD and the MTD_ROM flag 
>> settings.
>>
>> I got this idea of having this low level driver code under chips with
>> the MTD_ROM flag set and mounting this for cramfs.
>>
>> Please comment, especially folks using the RO FS mounted on flash.
>>
>> MS
>>
>> On Jan 24, 2008 3:12 PM, Max Stirling <vicky.irobot at gmail.com> wrote:
>>  
>>> Hi,
>>>
>>> This might sound quite basic question. This is the first time I am
>>> looking into the MTD code so have some really basic questions.
>>>
>>> I am trying to mount a read only fs (cramfs) on the flash. Please 
>>> let me
>>> know if the following steps are right:
>>>
>>> 1. Enabled the following in the Kconfig files
>>>     CONFIG_MTD_PARITIONS
>>>     CONFIG_MTD
>>>     CONFIG_MTD_BLOCK_RO
>>>     CONFIG_MTD_NAND
>>>     CONFIG_MTD_NAND_IDS
>>>
>>>
>>> After booting the compiled kernel I am able to see the mtdblock under
>>> /proc/devices using 31 Major number.
>>>
>>> Now for me to mount the cramfs image that is on the flash I need to
>>> provide the low level nand driver code. This I need to write but before
>>> starting that can any one point me to a reference nand driver code that
>>> is used for read only mount? Which functionality would the MTD require
>>> to be implemented for mounting a cramfs image which is on the flash.
>>>
>>> Would appreciate any pointers to how to get started off with this.
>>>
>>> thanks in advance for the reply.
>>>
>>> M.S
>>>
>>>
>>>     
> When using the cramfs as the fs for the flash and mtdblock_ro enabled. 
> Which one should I be calling the user module, the cramfs or the 
> mtdblock_ro?
>
>
I have enabled the mtdblock_ro module and written a low lever chip 
driver code. Since I am mounting this as read-only I have set the type 
in mtd_info to MTD_ROM.


When I do a mount using command

# mount -t cramfs /dev/mtdblock mnt_cramfs
.
mtdblock_ro.c mtdblock_readsect
mtdblock_ro.c mtdblock_readsect
mtdblock_ro.c mtdblock_readsect
mtdblock_ro.c mtdblock_readsect
.
mount: Mounting /dev/mtdblock on cramfs failed: Invalid argument.

I created a cramfs image using cramfs utility and written that to flash. 
I tested the cramfs image by mounting on my local machine.

Is there anything that is missing here?

-------------- next part --------------
A non-text attachment was scrubbed...
Name: vicky_irobot.vcf
Type: text/x-vcard
Size: 48 bytes
Desc: not available
Url : http://lists.infradead.org/pipermail/linux-mtd/attachments/20080130/a3a798f0/attachment.vcf 

From will.newton at gmail.com  Wed Jan 30 07:01:08 2008
From: will.newton at gmail.com (Will Newton)
Date: Wed, 30 Jan 2008 12:01:08 +0000
Subject: [PATCH 1/1] [MTD/MAPS] Blackfin BF5xx Maps: Handle the case where
	flash memory and ethernet mac/phy are mapped onto the same async bank
In-Reply-To: <1201687364-32178-1-git-send-email-bryan.wu@analog.com>
References: <1201687364-32178-1-git-send-email-bryan.wu@analog.com>
Message-ID: <87a5b0800801300401o1b0b631dt55cefaeb31b2da22@mail.gmail.com>

On Jan 30, 2008 10:02 AM, Bryan Wu <bryan.wu at analog.com> wrote:

switch_to_flash is calling SSYNC():

> +static void switch_to_flash(struct flash_save *save)
> +{
> +       local_irq_save(save->flags);
> +
> +       gpio_set_value(enet_flash_pin, 0);
> +       SSYNC();
> +
> +       save->ambctl0 = bfin_read_EBIU_AMBCTL0();
> +       save->ambctl1 = bfin_read_EBIU_AMBCTL1();
> +       bfin_write_EBIU_AMBCTL0(BFIN_FLASH_AMBCTL0VAL);
> +       bfin_write_EBIU_AMBCTL1(BFIN_FLASH_AMBCTL1VAL);
> +       SSYNC();
> +}
> +
> +static void switch_back(struct flash_save *save)
> +{
> +       bfin_write_EBIU_AMBCTL0(save->ambctl0);
> +       bfin_write_EBIU_AMBCTL1(save->ambctl1);
> +       SSYNC();
> +
> +       gpio_set_value(enet_flash_pin, 1);
> +
> +       local_irq_restore(save->flags);
> +}
> +
> +static map_word bf5xx_read(struct map_info *map, unsigned long ofs)
> +{
> +       int nValue = 0x0;
> +       map_word test;
> +       struct flash_save save;
> +
> +       switch_to_flash(&save);
> +       SSYNC();

Is it necessary to SSYNC() here as well?

> +       nValue = readw(map->virt + ofs);
> +       SSYNC();
> +       switch_back(&save);
> +
> +       test.x[0] = (u16)nValue;
> +       return test;
> +}
> +
> +static void bf5xx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
> +{
> +       unsigned long i;
> +       map_word test;
> +
> +       if ((unsigned long)to & 0x1) {
> +               for (i = 0; i < len / 2 * 2; i += 2) {
> +                       test = bf5xx_read(map, from + i);
> +                       put_unaligned(test.x[0], (__le16 *)(to + i));
> +               }
> +       } else {
> +               for (i = 0; i < len / 2 * 2; i += 2) {
> +                       test = bf5xx_read(map, from + i);
> +                       *((u16*)(to + i)) = test.x[0];
> +               }
> +       }
> +
> +       if (len & 0x1) {
> +               test = bf5xx_read(map, from + i);
> +               *((u8*)(to + i)) = (u8)test.x[0];
> +       }
> +}
> +
> +static void bf5xx_write(struct map_info *map, map_word d1, unsigned long ofs)
> +{
> +       u16 d;
> +       struct flash_save save;
> +
> +       d = (u16)d1.x[0];
> +
> +       switch_to_flash(&save);
> +
> +       SSYNC();

Also here?

> +       writew(d, map->virt + ofs);
> +       SSYNC();
> +
> +       switch_back(&save);
> +}


From hskinnemoen at atmel.com  Wed Jan 30 07:51:23 2008
From: hskinnemoen at atmel.com (Haavard Skinnemoen)
Date: Wed, 30 Jan 2008 13:51:23 +0100
Subject: [PATCH] MTD: Intel StrataFlash P33 is locked on bootup
In-Reply-To: <6934efce0801291813n68b796f5j5f3db1e90eb174a9@mail.gmail.com>
References: <1201631809-32193-1-git-send-email-hskinnemoen@atmel.com>
	<6934efce0801291813n68b796f5j5f3db1e90eb174a9@mail.gmail.com>
Message-ID: <20080130135123.3021109c@dhcp-252-066.norway.atmel.com>

On Tue, 29 Jan 2008 18:13:43 -0800
"Jared Hulbert" <jaredeh at gmail.com> wrote:

> > Add appropriate fixups for all the devices listed in the Intel P33
> > data sheet.  
> 
> Please don't merge this patch.
> 
> We worked on a patch that will unlock _all_ intel parts that have this
> behavior in a more acceptable way.  It was discussed back in November.

Ok, sounds like a better approach. Please ignore my patch.

Haavard


From hskinnemoen at atmel.com  Wed Jan 30 07:53:50 2008
From: hskinnemoen at atmel.com (Haavard Skinnemoen)
Date: Wed, 30 Jan 2008 13:53:50 +0100
Subject: [PATCH] MTD: Intel StrataFlash P33 is locked on bootup
In-Reply-To: <6934efce0801291813n68b796f5j5f3db1e90eb174a9@mail.gmail.com>
References: <1201631809-32193-1-git-send-email-hskinnemoen@atmel.com>
	<6934efce0801291813n68b796f5j5f3db1e90eb174a9@mail.gmail.com>
Message-ID: <20080130135350.67e95e20@dhcp-252-066.norway.atmel.com>

On Tue, 29 Jan 2008 18:13:43 -0800
"Jared Hulbert" <jaredeh at gmail.com> wrote:

> drivers/mtd/chips/cfi_cmdset_0001.c |   20 +++++++++++++-------
> drivers/mtd/cmdlinepart.c           |    9 ++++++++-
> drivers/mtd/mtdcore.c               |    2 +-
> include/mtd/mtd-abi.h               |    2 +-
> 4 files changed, 23 insertions(+), 10 deletions(-)

Hang on a second though...

> diff -r c105f44cf785 include/mtd/mtd-abi.h
> --- a/include/mtd/mtd-abi.h	Thu Nov 08 15:36:57 2007 -0800
> +++ b/include/mtd/mtd-abi.h	Fri Nov 09 10:43:28 2007 -0800
> @@ -29,7 +29,7 @@ struct mtd_oob_buf {
>  #define MTD_WRITEABLE		0x400	/* Device is writeable */
>  #define MTD_BIT_WRITEABLE	0x800	/* Single bits can be flipped */
>  #define MTD_NO_ERASE		0x1000	/* No erase necessary */
> -#define MTD_STUPID_LOCK		0x2000	/* Always locked after reset */
> +#define MTD_POWERUP_LOCK	0x2000	/* Always locked after reset */
> 
>  // Some common devices / combinations of capabilities
>  #define MTD_CAP_ROM		0

This will break cfi_cmdset_0002.c, which also uses MTD_STUPID_LOCK.

Haavard


From sr at denx.de  Wed Jan 30 08:03:13 2008
From: sr at denx.de (Stefan Roese)
Date: Wed, 30 Jan 2008 14:03:13 +0100
Subject: flash_eraseall reports incorrect percentage
Message-ID: <200801301403.13149.sr@denx.de>

It seems that the flash_eraseall utility doesn't report the correct percentage 
upon completion. After erasing the last sector, the output seems not to get 
updated anymore. This leads to something like this on a partition with only 2 
sectors:

flash_eraseall /dev/mtd6
Erasing 256 Kibyte @ 40000 -- 50 % complete.

I'm just posting this report as a reference. Perhaps somebody has a little 
time to fix it.

Thanks.

Best regards,
Stefan


From b.buettner at mkc-gmbh.de  Wed Jan 30 08:23:00 2008
From: b.buettner at mkc-gmbh.de (=?ISO-8859-1?Q?Bernd_B=FCttner?=)
Date: Wed, 30 Jan 2008 14:23:00 +0100
Subject: Cleaning JFFS2 errors
In-Reply-To: <478F1509.2090001@mkc-gmbh.de>
References: <478F1509.2090001@mkc-gmbh.de>
Message-ID: <47A07A34.6010209@mkc-gmbh.de>

No answer jet.
Does this mean it is a silly question or is there no solution for it?

Bernd


Bernd B?ttner schrieb:
> Hi,
> after working some time with the JFFS2 filesystem (on a uclinux-system with a non-mmu freescale processor)
> I'm getting errors on every mount like this:
> 
>    jffs2_scan_inode(): CRC failed on node at 0x00c999f0: Read 0xffffffff, calculated 0x7621c0c4
>    Empty flash at 0x00c99a3c ends at 0x00c99c00
>    Empty flash at 0x0134201c ends at 0x01342200
>    jffs2_scan_eraseblock(): Node at 0x01d88df8 {0x1985, 0xe001, 0x0000002f) has invalid
>      CRC 0x1985e001 (calculated 0x392fe03e)
>    JFFS2 notice: (13) read_dnode: node CRC failed on dnode at 0x1341fd4:
>      read 0xffffffff, calculated 0xce9c70e9
> 
> The kernel is 2.6.19 from the latest uclinux distribution 20070130.
> 
> I think these errors are the result of power-loss, misbehaving new drivers and system crashes,
> and I suppose they are not critical and will be corrected by jffs2 after some time.
> 
> But delivering such systems to customers doesn't look good.
> 
> Is there a possibility to force jffs2 to correct these errors at once?
> 
> I hope so.
> 
> Bernd
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
> 



From vapier.adi at gmail.com  Wed Jan 30 09:14:30 2008
From: vapier.adi at gmail.com (Mike Frysinger)
Date: Wed, 30 Jan 2008 09:14:30 -0500
Subject: [PATCH 1/1] [MTD/MAPS] Blackfin BF5xx Maps: Handle the case where
	flash memory and ethernet mac/phy are mapped onto the same async bank
In-Reply-To: <87a5b0800801300401o1b0b631dt55cefaeb31b2da22@mail.gmail.com>
References: <1201687364-32178-1-git-send-email-bryan.wu@analog.com>
	<87a5b0800801300401o1b0b631dt55cefaeb31b2da22@mail.gmail.com>
Message-ID: <8bd0f97a0801300614g3f7bce03p668fca354d49761@mail.gmail.com>

On Jan 30, 2008 7:01 AM, Will Newton <will.newton at gmail.com> wrote:
> On Jan 30, 2008 10:02 AM, Bryan Wu <bryan.wu at analog.com> wrote:
>
> switch_to_flash is calling SSYNC():
>
> > +static void switch_to_flash(struct flash_save *save)
> > +{
> > +       local_irq_save(save->flags);
> > +
> > +       gpio_set_value(enet_flash_pin, 0);
> > +       SSYNC();
> > +
> > +       save->ambctl0 = bfin_read_EBIU_AMBCTL0();
> > +       save->ambctl1 = bfin_read_EBIU_AMBCTL1();
> > +       bfin_write_EBIU_AMBCTL0(BFIN_FLASH_AMBCTL0VAL);
> > +       bfin_write_EBIU_AMBCTL1(BFIN_FLASH_AMBCTL1VAL);
> > +       SSYNC();
> > +}
> > +
> > +static void switch_back(struct flash_save *save)
> > +{
> > +       bfin_write_EBIU_AMBCTL0(save->ambctl0);
> > +       bfin_write_EBIU_AMBCTL1(save->ambctl1);
> > +       SSYNC();
> > +
> > +       gpio_set_value(enet_flash_pin, 1);
> > +
> > +       local_irq_restore(save->flags);
> > +}
> > +
> > +static map_word bf5xx_read(struct map_info *map, unsigned long ofs)
> > +{
> > +       int nValue = 0x0;
> > +       map_word test;
> > +       struct flash_save save;
> > +
> > +       switch_to_flash(&save);
> > +       SSYNC();
>
> Is it necessary to SSYNC() here as well?
>
> > +       nValue = readw(map->virt + ofs);
> > +       SSYNC();
> > +       switch_back(&save);
> > +
> > +       test.x[0] = (u16)nValue;
> > +       return test;
> > +}
> > +
> > +static void bf5xx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
> > +{
> > +       unsigned long i;
> > +       map_word test;
> > +
> > +       if ((unsigned long)to & 0x1) {
> > +               for (i = 0; i < len / 2 * 2; i += 2) {
> > +                       test = bf5xx_read(map, from + i);
> > +                       put_unaligned(test.x[0], (__le16 *)(to + i));
> > +               }
> > +       } else {
> > +               for (i = 0; i < len / 2 * 2; i += 2) {
> > +                       test = bf5xx_read(map, from + i);
> > +                       *((u16*)(to + i)) = test.x[0];
> > +               }
> > +       }
> > +
> > +       if (len & 0x1) {
> > +               test = bf5xx_read(map, from + i);
> > +               *((u8*)(to + i)) = (u8)test.x[0];
> > +       }
> > +}
> > +
> > +static void bf5xx_write(struct map_info *map, map_word d1, unsigned long ofs)
> > +{
> > +       u16 d;
> > +       struct flash_save save;
> > +
> > +       d = (u16)d1.x[0];
> > +
> > +       switch_to_flash(&save);
> > +
> > +       SSYNC();
>
> Also here?
>
> > +       writew(d, map->virt + ofs);
> > +       SSYNC();
> > +
> > +       switch_back(&save);
> > +}

thanks ... it should be fixed now
http://blackfin.uclinux.org/gf/project/linux-kernel/scmsvn/?action=browse&path=/&view=rev&root=linux-kernel&revision=4173
-mike


From jaredeh at gmail.com  Wed Jan 30 12:19:54 2008
From: jaredeh at gmail.com (Jared Hulbert)
Date: Wed, 30 Jan 2008 09:19:54 -0800
Subject: [PATCH] MTD: Intel StrataFlash P33 is locked on bootup
In-Reply-To: <20080130135350.67e95e20@dhcp-252-066.norway.atmel.com>
References: <1201631809-32193-1-git-send-email-hskinnemoen@atmel.com>
	<6934efce0801291813n68b796f5j5f3db1e90eb174a9@mail.gmail.com>
	<20080130135350.67e95e20@dhcp-252-066.norway.atmel.com>
Message-ID: <6934efce0801300919v6fdc21f8v68e857301b77ff2e@mail.gmail.com>

> This will break cfi_cmdset_0002.c, which also uses MTD_STUPID_LOCK.

Oh.  That should be fixed ;)  Thanks for catching this.  We need more
inclusive tests.

So if I add this hunk, it should work right?


diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c
b/drivers/mtd/chips/cfi_cmdset_0002.c
index 796bfea..d072e87 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -217,7 +217,7 @@ static void fixup_use_atmel_lock(struct mtd_info
*mtd, void *param)
 {
 	mtd->lock = cfi_atmel_lock;
 	mtd->unlock = cfi_atmel_unlock;
-	mtd->flags |= MTD_STUPID_LOCK;
+	mtd->flags |= MTD_POWERUP_LOCK;
 }


From hskinnemoen at atmel.com  Wed Jan 30 12:22:10 2008
From: hskinnemoen at atmel.com (Haavard Skinnemoen)
Date: Wed, 30 Jan 2008 18:22:10 +0100
Subject: [PATCH] MTD: Intel StrataFlash P33 is locked on bootup
In-Reply-To: <6934efce0801300919v6fdc21f8v68e857301b77ff2e@mail.gmail.com>
References: <1201631809-32193-1-git-send-email-hskinnemoen@atmel.com>
	<6934efce0801291813n68b796f5j5f3db1e90eb174a9@mail.gmail.com>
	<20080130135350.67e95e20@dhcp-252-066.norway.atmel.com>
	<6934efce0801300919v6fdc21f8v68e857301b77ff2e@mail.gmail.com>
Message-ID: <20080130182210.2076ea38@siona>

On Wed, 30 Jan 2008 09:19:54 -0800
"Jared Hulbert" <jaredeh at gmail.com> wrote:

> > This will break cfi_cmdset_0002.c, which also uses MTD_STUPID_LOCK.  
> 
> Oh.  That should be fixed ;)  Thanks for catching this.  We need more
> inclusive tests.
> 
> So if I add this hunk, it should work right?

Yeah, that should do it.

Haavard


From jaredeh at gmail.com  Wed Jan 30 13:25:49 2008
From: jaredeh at gmail.com (Jared Hulbert)
Date: Wed, 30 Jan 2008 10:25:49 -0800
Subject: [PATCH] MTD: Intel StrataFlash P33 is locked on bootup
In-Reply-To: <20080130182210.2076ea38@siona>
References: <1201631809-32193-1-git-send-email-hskinnemoen@atmel.com>
	<6934efce0801291813n68b796f5j5f3db1e90eb174a9@mail.gmail.com>
	<20080130135350.67e95e20@dhcp-252-066.norway.atmel.com>
	<6934efce0801300919v6fdc21f8v68e857301b77ff2e@mail.gmail.com>
	<20080130182210.2076ea38@siona>
Message-ID: <6934efce0801301025s4341bd95k79d1743090098e86@mail.gmail.com>

> > So if I add this hunk, it should work right?
>
> Yeah, that should do it.

The new patch is in "git://git.infradead.org/users/jehulber/mtd.git"

mailer mangled patch follows for reference.
________________________________________

From: Justin Treon <justin_treon at yahoo.com>
[MTD] Unlocking all Intel flash that is locked on power up.

Patch for unlocking all Intel flash that has instant locking on power up.
The patch has been tested on Intel M18, P30 and J3D Strata Flash.
  1.    The automatic unlocking can be disabled for a particular partition
         in the map or the command line.
     a. For the bit mask in the map it should look like:
         .mask_flags   = MTD_POWERUP_LOCK,
     b. For the command line parsing it should look like:
         mtdparts=0x80000(bootloader)lk
  2.    This will only unlock parts with instant individual block locking.
         Intel parts with legacy unlocking will not be unlocked.

Signed-off-by: Justin Treon <justin_treon at yahoo.com>
Signed-off-by: Jared Hulbert <jaredeh at gmail.com>
Acked-by: Nicolas Pitre <nico at cam.org>
---

drivers/mtd/chips/cfi_cmdset_0001.c |   18 ++++++++++++------
drivers/mtd/chips/cfi_cmdset_0002.c |    2 +-
drivers/mtd/cmdlinepart.c           |    9 ++++++++-
drivers/mtd/mtdcore.c               |    2 +-
include/mtd/mtd-abi.h               |    2 +-
5 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c
b/drivers/mtd/chips/cfi_cmdset_0001.c
index 7b44a57..47794d2 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -269,10 +269,16 @@ static void fixup_use_write_buffers(struct
mtd_info *mtd, void *param)
 /*
  * Some chips power-up with all sectors locked by default.
  */
-static void fixup_use_powerup_lock(struct mtd_info *mtd, void *param)
+static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param)
 {
-	printk(KERN_INFO "Using auto-unlock on power-up/resume\n" );
-	mtd->flags |= MTD_STUPID_LOCK;
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
+
+	if (cfip->FeatureSupport&32) {
+		printk(KERN_INFO "Using auto-unlock on power-up/resume\n" );
+		mtd->flags |= MTD_POWERUP_LOCK;
+	}
 }

 static struct cfi_fixup cfi_fixup_table[] = {
@@ -288,7 +294,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
 #endif
 	{ CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL },
 	{ CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL },
-	{ MANUFACTURER_INTEL, 0x891c,	      fixup_use_powerup_lock, NULL, },
+	{ MANUFACTURER_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock, NULL, },
 	{ 0, 0, NULL, NULL }
 };

@@ -2352,7 +2358,7 @@ static int cfi_intelext_suspend(struct mtd_info *mtd)
 	struct flchip *chip;
 	int ret = 0;

-	if ((mtd->flags & MTD_STUPID_LOCK)
+	if ((mtd->flags & MTD_POWERUP_LOCK)
 	    && extp && (extp->FeatureSupport & (1 << 5)))
 		cfi_intelext_save_locks(mtd);

@@ -2463,7 +2469,7 @@ static void cfi_intelext_resume(struct mtd_info *mtd)
 		spin_unlock(chip->mutex);
 	}

-	if ((mtd->flags & MTD_STUPID_LOCK)
+	if ((mtd->flags & MTD_POWERUP_LOCK)
 	    && extp && (extp->FeatureSupport & (1 << 5)))
 		cfi_intelext_restore_locks(mtd);
 }
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c
b/drivers/mtd/chips/cfi_cmdset_0002.c
index 796bfea..d072e87 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -217,7 +217,7 @@ static void fixup_use_atmel_lock(struct mtd_info
*mtd, void *param)
 {
 	mtd->lock = cfi_atmel_lock;
 	mtd->unlock = cfi_atmel_unlock;
-	mtd->flags |= MTD_STUPID_LOCK;
+	mtd->flags |= MTD_POWERUP_LOCK;
 }

 static struct cfi_fixup cfi_fixup_table[] = {
diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c
index 23fab14..b44292a 100644
--- a/drivers/mtd/cmdlinepart.c
+++ b/drivers/mtd/cmdlinepart.c
@@ -9,7 +9,7 @@
  *
  * mtdparts=<mtddef>[;<mtddef]
  * <mtddef>  := <mtd-id>:<partdef>[,<partdef>]
- * <partdef> := <size>[@offset][<name>][ro]
+ * <partdef> := <size>[@offset][<name>][ro][lk]
  * <mtd-id>  := unique name used in mapping driver/device (mtd->name)
  * <size>    := standard linux memsize OR "-" to denote all remaining space
  * <name>    := '(' NAME ')'
@@ -143,6 +143,13 @@ static struct mtd_partition * newpart(char *s,
 		s += 2;
         }

+        /* if lk is found do NOT unlock the MTD partition*/
+        if (strncmp(s, "lk", 2) == 0)
+	{
+		mask_flags |= MTD_POWERUP_LOCK;
+		s += 2;
+        }
+
 	/* test if more partitions are following */
 	if (*s == ',')
 	{
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 6c2645e..f7e7890 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -61,7 +61,7 @@ int add_mtd_device(struct mtd_info *mtd)

 			/* Some chips always power up locked. Unlock them now */
 			if ((mtd->flags & MTD_WRITEABLE)
-			    && (mtd->flags & MTD_STUPID_LOCK) && mtd->unlock) {
+			    && (mtd->flags & MTD_POWERUP_LOCK) && mtd->unlock) {
 				if (mtd->unlock(mtd, 0, mtd->size))
 					printk(KERN_WARNING
 					       "%s: unlock failed, "
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
index f71dac4..615072c 100644
--- a/include/mtd/mtd-abi.h
+++ b/include/mtd/mtd-abi.h
@@ -29,7 +29,7 @@ struct mtd_oob_buf {
 #define MTD_WRITEABLE		0x400	/* Device is writeable */
 #define MTD_BIT_WRITEABLE	0x800	/* Single bits can be flipped */
 #define MTD_NO_ERASE		0x1000	/* No erase necessary */
-#define MTD_STUPID_LOCK		0x2000	/* Always locked after reset */
+#define MTD_POWERUP_LOCK	0x2000	/* Always locked after reset */

 // Some common devices / combinations of capabilities
 #define MTD_CAP_ROM		0


From joern at logfs.org  Wed Jan 30 17:06:31 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Wed, 30 Jan 2008 23:06:31 +0100
Subject: [RFC PATCH 1/3]] Add mtd panic_write function pointer
In-Reply-To: <1201687383.4668.1.camel@localhost.localdomain>
References: <1201607964.5017.48.camel@localhost.localdomain>
	<20080129231104.GC32157@lazybastard.org>
	<1201687383.4668.1.camel@localhost.localdomain>
Message-ID: <20080130220631.GA6786@lazybastard.org>

On Wed, 30 January 2008 10:03:03 +0000, Richard Purdie wrote:
> On Wed, 2008-01-30 at 00:11 +0100, J?rn Engel wrote:
> > 
> > I like the description.  So why is it not part of the patch proper?
> 
> You mean add it to mtd.h?

Yes.  struct mtd_info, like many other kernel interfaces, is nearly
impossible to use without either copying example code or reading the
implementation (aka reverse-engineering the kernel).  We could certainly
do better than that.  And for new additions we should.

J?rn

-- 
To announce that there must be no criticism of the President, or that we
are to stand by the President, right or wrong, is not only unpatriotic
and servile, but is morally treasonable to the American public.
-- Theodore Roosevelt, Kansas City Star, 1918


From joern at logfs.org  Wed Jan 30 18:07:11 2008
From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel)
Date: Thu, 31 Jan 2008 00:07:11 +0100
Subject: Cleaning JFFS2 errors
In-Reply-To: <47A07A34.6010209@mkc-gmbh.de>
References: <478F1509.2090001@mkc-gmbh.de> <47A07A34.6010209@mkc-gmbh.de>
Message-ID: <20080130230711.GB6849@lazybastard.org>

On Wed, 30 January 2008 14:23:00 +0100, Bernd B?ttner wrote:
> 
> No answer jet.
> Does this mean it is a silly question or is there no solution for it?


It's an FAQ.  Most of these are harmless, they simply indicate a power
loss.  They will get cleaned eventually, you cannot force them to get
cleaned, you cannot easily distinguish power loss from data corruption
and you should add this to the FAQ if it's not part of it yet.

J?rn

-- 
Why do musicians compose symphonies and poets write poems?
They do it because life wouldn't have any meaning for them if they didn't.
That's why I draw cartoons.  It's my life.
-- Charles Shultz


From kmpark at infradead.org  Wed Jan 30 21:05:45 2008
From: kmpark at infradead.org (Kyungmin Park)
Date: Thu, 31 Jan 2008 11:05:45 +0900
Subject: [RFC PATCH 3/3] Add panic_write function to the onenand driver
In-Reply-To: <1201607970.5017.50.camel@localhost.localdomain>
References: <1201607970.5017.50.camel@localhost.localdomain>
Message-ID: <003e01c863ad$ce6ef790$1fa9580a@swcenter.sec.samsung.co.kr>

Hi,

> +static void onenand_panic_wait(struct mtd_info *mtd)
> +{
> +	struct onenand_chip *this = mtd->priv;
> +	unsigned int interrupt;
> +	int i;
> +
> +	for (i = 0; i < 20; i++) {
> +		interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
> +		if (interrupt & ONENAND_INT_MASTER)
> +			break;
> +		udelay(1000);
> +	}
> +}

Umm it's waiting with maximum 20msec. how about the increase the index to 20*1000 and use udelay(1).
If we use the busy-waiting, it uses the max 3msec in case of erase.

Anyway I think you don't use the onenand_wait since it has cond_resched(). It's better to use the existing function in case of
panic_write.
Okay try to think what's the better way.

> + */
> +static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
> +			 size_t *retlen, const u_char *buf)
> +{
> +	struct onenand_chip *this = mtd->priv;
> +	int column, subpage;
> +	int written = 0;
> +	int ret = 0;
> +
> +	if (this->state == FL_PM_SUSPENDED)
> +		return -EBUSY;
> +
> +	/* Wait for any existing operation to clear */
> +	onenand_panic_wait(mtd);

Reasonable!

> +
> +		this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
> +		this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
> +
> +		this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
> +
> +		onenand_panic_wait(mtd);

It has to check the return value and update the bufferram. If not, we can read the wrong data later.

Thank you,
Kyungmin Park



From Nagaraj.Venkatapuram at netapp.com  Wed Jan 30 22:07:41 2008
From: Nagaraj.Venkatapuram at netapp.com (Venkatapuram, Nagaraj)
Date: Wed, 30 Jan 2008 19:07:41 -0800
Subject: FW: JFFS2 Utility?
Message-ID: <521D420437D1FD4CA77F1B71E3C4FB8D035D86C1@exsvl03.hq.netapp.com>

Hi, I downloaded mtd-utils-1.1.0 tar ball from the link mentioned below and I did a make. I ran into following compilation errors. Has any body got any insight as to what the problem could be ? Obviously, function definitions are missing and as a result the build is failing.

gcc -I./include -O2 -Wall -g -c -o compr_lzo.o compr_lzo.c -g -Wp,-MD,./.compr_lzo.c.dep
compr_lzo.c:29:23: lzo/lzo1x.h: No such file or directory
compr_lzo.c: In function `jffs2_lzo_cmpr':
compr_lzo.c:54: warning: implicit declaration of function `lzo1x_999_compress'
compr_lzo.c:56: `LZO_E_OK' undeclared (first use in this function)
compr_lzo.c:56: (Each undeclared identifier is reported only once
compr_lzo.c:56: for each function it appears in.)
compr_lzo.c: In function `jffs2_lzo_decompress':
compr_lzo.c:74: warning: implicit declaration of function `lzo1x_decompress_safe'
compr_lzo.c:76: `LZO_E_OK' undeclared (first use in this function)
compr_lzo.c: In function `jffs2_lzo_init':
compr_lzo.c:95: `LZO1X_999_MEM_COMPRESS' undeclared (first use in this function)make: *** [compr_lzo.o] Error 1
rm doc_loadbios.o flash_erase.o mkfs.jffs.o nanddump.o ftl_format.o ftl_check.o

Thanks,
Nagaraj

-----Original Message-----
From: Tallam, Sreenivas 
Sent: Wednesday, January 30, 2008 5:25 PM
To: Venkatapuram, Nagaraj
Subject: FW: JFFS2 Utility?

 Thanks
Sreen

-----Original Message-----
From: Ricard Wanderlof [mailto:ricard.wanderlof at axis.com] 
Sent: Wednesday, December 19, 2007 11:56 PM
To: Tallam, Sreenivas
Cc: linux-mtd at lists.infradead.org
Subject: Re: JFFS2 Utility?


It is not difficult to build from source. A tarball of the source can be found here:

ftp://ftp.infradead.org/pub/mtd-utils/mtd-utils-1.1.0.tar.bz2

Download, unpack, and do 'make' to build them.

/Ricard
--
Ricard Wolf Wanderl?f                           ricardw(at)axis.com
Axis Communications AB, Lund, Sweden            www.axis.com
Phone +46 46 272 2016                           Fax +46 46 13 61 30


From rpurdie at rpsys.net  Thu Jan 31 04:49:15 2008
From: rpurdie at rpsys.net (Richard Purdie)
Date: Thu, 31 Jan 2008 09:49:15 +0000
Subject: [RFC PATCH 1/3]] Add mtd panic_write function pointer
In-Reply-To: <20080130220631.GA6786@lazybastard.org>
References: <1201607964.5017.48.camel@localhost.localdomain>
	<20080129231104.GC32157@lazybastard.org>
	<1201687383.4668.1.camel@localhost.localdomain>
	<20080130220631.GA6786@lazybastard.org>
Message-ID: <1201772955.4996.3.camel@localhost.localdomain>

On Wed, 2008-01-30 at 23:06 +0100, J?rn Engel wrote:
> Yes.  struct mtd_info, like many other kernel interfaces, is nearly
> impossible to use without either copying example code or reading the
> implementation (aka reverse-engineering the kernel).  We could certainly
> do better than that.  And for new additions we should.

Totally agreed, updated patch follows.


MTDs are well suited for logging critical data and the mtdoops driver
allows kernel panics/oops to be written to flash in a blackbox flight
recorder fashion allowing better debugging and analysis of crashes.

Any kernel oops in user context can be easily handled since the kernel
continues as normal and any queued mtd writes are scheduled. Any kernel
oops in interrupt context results in a panic and the delayed writes will
not be scheduled however. The existing mtd->write function cannot be
called in interrupt context so these messages can never be written to
flash.

This patch adds a panic_write function pointer that drivers can
optionally implement which can be called in interrupt context. It is
only intended to be called when its known the kernel is about to panic
and we need to write to succeed. Since the kernel is not going to be
running for much longer, this function can break locks and delay to
ensure the write succeeds (but not sleep).

Signed-off-by: Richard Purdie <rpurdie at rpsys.net>

---
 drivers/mtd/mtdpart.c   |   17 +++++++++++++++++
 include/linux/mtd/mtd.h |    9 +++++++++
 2 files changed, 26 insertions(+)

Index: kernel-hacking/drivers/mtd/mtdpart.c
===================================================================
--- kernel-hacking.orig/drivers/mtd/mtdpart.c	2008-01-31 09:37:23.000000000 +0000
+++ kernel-hacking/drivers/mtd/mtdpart.c	2008-01-31 09:37:28.000000000 +0000
@@ -151,6 +151,20 @@ static int part_write (struct mtd_info *
 				    len, retlen, buf);
 }
 
+static int part_panic_write (struct mtd_info *mtd, loff_t to, size_t len,
+			size_t *retlen, const u_char *buf)
+{
+	struct mtd_part *part = PART(mtd);
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	if (to >= mtd->size)
+		len = 0;
+	else if (to + len > mtd->size)
+		len = mtd->size - to;
+	return part->master->panic_write (part->master, to + part->offset,
+				    len, retlen, buf);
+}
+
 static int part_write_oob(struct mtd_info *mtd, loff_t to,
 			 struct mtd_oob_ops *ops)
 {
@@ -352,6 +366,9 @@ int add_mtd_partitions(struct mtd_info *
 		slave->mtd.read = part_read;
 		slave->mtd.write = part_write;
 
+		if (master->panic_write)
+			slave->mtd.panic_write = part_panic_write;
+
 		if(master->point && master->unpoint){
 			slave->mtd.point = part_point;
 			slave->mtd.unpoint = part_unpoint;
Index: kernel-hacking/include/linux/mtd/mtd.h
===================================================================
--- kernel-hacking.orig/include/linux/mtd/mtd.h	2008-01-31 09:37:23.000000000 +0000
+++ kernel-hacking/include/linux/mtd/mtd.h	2008-01-31 09:44:06.000000000 +0000
@@ -152,6 +152,15 @@ struct mtd_info {
 	int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
 	int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
 
+	/* In blackbox flight recorder like scenarios we want to make successful
+	    writes in interrupt context. panic_write() is only intended to be
+	    called when its known the kernel is about to panic and we need the
+	    write to succeed. Since the kernel is not going to be running for much
+	    longer, this function can break locks and delay to ensure the write
+	    succeeds (but not sleep). */
+
+	int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
+
 	int (*read_oob) (struct mtd_info *mtd, loff_t from,
 			 struct mtd_oob_ops *ops);
 	int (*write_oob) (struct mtd_info *mtd, loff_t to,



From rpurdie at rpsys.net  Thu Jan 31 05:03:34 2008
From: rpurdie at rpsys.net (Richard Purdie)
Date: Thu, 31 Jan 2008 10:03:34 +0000
Subject: [RFC PATCH 3/3] Add panic_write function to the onenand driver
In-Reply-To: <003e01c863ad$ce6ef790$1fa9580a@swcenter.sec.samsung.co.kr>
References: <1201607970.5017.50.camel@localhost.localdomain>
	<003e01c863ad$ce6ef790$1fa9580a@swcenter.sec.samsung.co.kr>
Message-ID: <1201773814.4996.9.camel@localhost.localdomain>

On Thu, 2008-01-31 at 11:05 +0900, Kyungmin Park wrote:
> > +static void onenand_panic_wait(struct mtd_info *mtd)
> > +{
> > +	struct onenand_chip *this = mtd->priv;
> > +	unsigned int interrupt;
> > +	int i;
> > +
> > +	for (i = 0; i < 20; i++) {
> > +		interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
> > +		if (interrupt & ONENAND_INT_MASTER)
> > +			break;
> > +		udelay(1000);
> > +	}
> > +}
> 
> Umm it's waiting with maximum 20msec. how about the increase the index to 20*1000 and use udelay(1).
> If we use the busy-waiting, it uses the max 3msec in case of erase.

I'm ok with changing it to use udelay(10). This function is going to be
rarely called so efficiency isn't a primary concern... 

> Anyway I think you don't use the onenand_wait since it has
> cond_resched(). It's better to use the existing function in case of
> panic_write.
> Okay try to think what's the better way.

Yes, I'm avoiding onenand_wait since we can't schedule in this context.
Other ideas welcome :)

> > + */
> > +static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
> > +			 size_t *retlen, const u_char *buf)
> > +{
> > +	struct onenand_chip *this = mtd->priv;
> > +	int column, subpage;
> > +	int written = 0;
> > +	int ret = 0;
> > +
> > +	if (this->state == FL_PM_SUSPENDED)
> > +		return -EBUSY;
> > +
> > +	/* Wait for any existing operation to clear */
> > +	onenand_panic_wait(mtd);
> 
> Reasonable!
> 
> > +
> > +		this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
> > +		this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
> > +
> > +		this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
> > +
> > +		onenand_panic_wait(mtd);
> 
> It has to check the return value and update the bufferram. If not, we can read the wrong data later.

The key point with panic_write is there is unlikely to be any "later". I
don't mind putting the bufferram update calls back if you're happier
with that though.

Cheers,

Richard




From ext-adrian.hunter at nokia.com  Thu Jan 31 10:21:57 2008
From: ext-adrian.hunter at nokia.com (Adrian Hunter)
Date: Thu, 31 Jan 2008 17:21:57 +0200
Subject: [PATCH][MTD-UTILS] ubi-tools: fix ubinize
Message-ID: <47A1E795.5010407@nokia.com>

ubinize reserves 2 eraseblocks for the volume table at the start of the
output file and then never seeked back to the start of the file.

Signed-off-by: Adrian Hunter <ext-adrian.hunter at nokia.com>
---
 ubi-utils/src/ubinize.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/ubi-utils/src/ubinize.c b/ubi-utils/src/ubinize.c
index 4c3fd97..9660b09 100644
--- a/ubi-utils/src/ubinize.c
+++ b/ubi-utils/src/ubinize.c
@@ -618,6 +618,11 @@ int main(int argc, char * const argv[])
 
 	verbose(args.verbose, "writing layout volume");
 
+	if (fseek(args.fp_out, 0, SEEK_SET) == -1) {
+		errmsg("cannot seek file \"%s\"", args.f_out);
+		goto out_dict;
+	}
+
 	err = ubigen_write_layout_vol(&ui, vtbl, args.fp_out);
 	if (err) {
 		errmsg("cannot write layout volume");
-- 
1.4.4.2


From r&d2 at dave-tech.it  Thu Jan 31 11:54:23 2008
From: r&d2 at dave-tech.it (llandre)
Date: Thu, 31 Jan 2008 17:54:23 +0100
Subject: JFFS2: file contents in case of data CRC error
Message-ID: <47A1FD3F.2020102@dave-tech.it>

I have a JFFS2 partition on 32MByte NAND device.
When reading a specific file - see below for details - JFFS2 reports a 
Data CRC error but function nand_correct_data never returns -1, so I 
assume ECC algorithm is able to correct errors.
However the file is not equal to the original one that has been written 
to NAND. In fact, in the middle of the file, I see a 4-kByte "hole" 
where all bytes are 0.
Anybody can help me about understanding if this is the expected 
behaviour of JFFS2?
Thanks in advance.


bash-2.05# mount -t jffs2 -o ro /dev/mtdblock0 /mnt/nand0
mtdblock_open
ok
bash-2.05# cp -v /mnt/nand0/f.img /tmp/
jffs2_get_inode_nodes(): Data CRC failed on node at 0x01d55544: Read 
0x80b8997f, calculated 0x57f0ea8e
`/mnt/nand0/f.img' -> `/tmp/f.img'

-- 
llandre

DAVE Electronics System House - R&D Department
web:   http://www.dave.eu
email: r&d2 at dave-tech.it


From alexey.korolev at intel.com  Thu Jan 31 14:19:58 2008
From: alexey.korolev at intel.com (Korolev, Alexey)
Date: Thu, 31 Jan 2008 22:19:58 +0300
Subject: JFFS2: file contents in case of data CRC error
In-Reply-To: <47A1FD3F.2020102@dave-tech.it>
References: <47A1FD3F.2020102@dave-tech.it>
Message-ID: <523F3D8D8C97554AA47E53DF1A05466A01880831@nnsmsx411.ccr.corp.intel.com>

Hi 
Could you please give information about how you can get this error? I
need to know use case. 

>I have a JFFS2 partition on 32MByte NAND device.
>When reading a specific file - see below for details - JFFS2 reports a 
>Data CRC error but function nand_correct_data never returns -1, so I 
>assume ECC algorithm is able to correct errors.
>However the file is not equal to the original one that has been written

>to NAND. In fact, in the middle of the file, I see a 4-kByte "hole" 
>where all bytes are 0.

It is Ok. NAND error correction could return that data is correct even
if it is not correct. It finds the issues with guarantee only in case of
1 or 2 bits errors.  

>Anybody can help me about understanding if this is the expected 
>behaviour of JFFS2?
>Thanks in advance.


>bash-2.05# mount -t jffs2 -o ro /dev/mtdblock0 /mnt/nand0
>mtdblock_open
>ok
>bash-2.05# cp -v /mnt/nand0/f.img /tmp/
>jffs2_get_inode_nodes(): Data CRC failed on node at 0x01d55544: Read 
>0x80b8997f, calculated 0x57f0ea8e
>`/mnt/nand0/f.img' -> `/tmp/f.img'

This is a bad error! How obtained you this? What you did before getting
this?

Alexey
--------------------------------------------------------------------
Closed Joint Stock Company Intel A/O
Registered legal address: 125252, Moscow, Russian Federation, 
Chapayevsky Per, 14.

This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.



From nikbansa at cisco.com  Thu Jan 31 14:22:20 2008
From: nikbansa at cisco.com (Nikhil Bansal (nikbansa))
Date: Thu, 31 Jan 2008 11:22:20 -0800
Subject: Jffss2_write_super erasing all the blocks
In-Reply-To: <47A1FD3F.2020102@dave-tech.it>
Message-ID: <ED07EE9DB42A8945877C9794BA15040801A516FF@xmb-sjc-229.amer.cisco.com>

Hi,

I have a question about JFFS2 fs. In my setup, I am running JFFS2 on AMD
Spansion flash (NOR flash). What I noticed was that whenever I erase a
file from my flash, I see that jffs2_write_super function gets called
which in turn calls jffs2_erase_pending_blocks(0) which goes ahead and
deletes all the pending blocks. While this erase is going on super block
is locked and we can not perform any other operation with JFFS2. 

Can someone please explain the logic behind this or if there is
something I am missing here?

Thanks,
Nikhil 

-----Original Message-----
From: linux-mtd-bounces at lists.infradead.org
[mailto:linux-mtd-bounces at lists.infradead.org] On Behalf Of llandre
Sent: Thursday, January 31, 2008 8:54 AM
To: linux-mtd at lists.infradead.org
Subject: JFFS2: file contents in case of data CRC error

I have a JFFS2 partition on 32MByte NAND device.
When reading a specific file - see below for details - JFFS2 reports a
Data CRC error but function nand_correct_data never returns -1, so I
assume ECC algorithm is able to correct errors.
However the file is not equal to the original one that has been written
to NAND. In fact, in the middle of the file, I see a 4-kByte "hole" 
where all bytes are 0.
Anybody can help me about understanding if this is the expected
behaviour of JFFS2?
Thanks in advance.


bash-2.05# mount -t jffs2 -o ro /dev/mtdblock0 /mnt/nand0 mtdblock_open
ok bash-2.05# cp -v /mnt/nand0/f.img /tmp/
jffs2_get_inode_nodes(): Data CRC failed on node at 0x01d55544: Read
0x80b8997f, calculated 0x57f0ea8e `/mnt/nand0/f.img' -> `/tmp/f.img'

--
llandre

DAVE Electronics System House - R&D Department
web:   http://www.dave.eu
email: r&d2 at dave-tech.it

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/


From mattjreimer at gmail.com  Thu Jan 31 14:42:47 2008
From: mattjreimer at gmail.com (Matt Reimer)
Date: Thu, 31 Jan 2008 11:42:47 -0800
Subject: JFFS2: file contents in case of data CRC error
In-Reply-To: <47A1FD3F.2020102@dave-tech.it>
References: <47A1FD3F.2020102@dave-tech.it>
Message-ID: <f383264b0801311142h3cbcbc91pb4e0d3a60fc78f4f@mail.gmail.com>

On Jan 31, 2008 8:54 AM, llandre <r&d2 at dave-tech.it> wrote:
> I have a JFFS2 partition on 32MByte NAND device.
> When reading a specific file - see below for details - JFFS2 reports a
> Data CRC error but function nand_correct_data never returns -1, so I
> assume ECC algorithm is able to correct errors.
> However the file is not equal to the original one that has been written
> to NAND. In fact, in the middle of the file, I see a 4-kByte "hole"
> where all bytes are 0.
> Anybody can help me about understanding if this is the expected
> behaviour of JFFS2?
> Thanks in advance.

I saw exactly this problem on an s3c2440 board back in October. It
turned out that the ECC correction code in the s3c2410 driver was
incorrect in a couple of ways, resulting in corrupt data being passed
up to JFFS2. I'm not sure, but I think what happened from there is
that JFFS2 failed to decompress a block and instead of returning an
error it left the page zeroed. You can use jffs2dump to correlate the
offset reported in the CRC error with the problematic inode. Check the
thread "bit flip" in October 2007.

What platform is this on?

Matt


From jamie at shareable.org  Thu Jan 31 17:57:42 2008
From: jamie at shareable.org (Jamie Lokier)
Date: Thu, 31 Jan 2008 22:57:42 +0000
Subject: JFFS2: file contents in case of data CRC error
In-Reply-To: <f383264b0801311142h3cbcbc91pb4e0d3a60fc78f4f@mail.gmail.com>
References: <47A1FD3F.2020102@dave-tech.it>
	<f383264b0801311142h3cbcbc91pb4e0d3a60fc78f4f@mail.gmail.com>
Message-ID: <20080131225742.GB26188@shareable.org>

Matt Reimer wrote:
> On Jan 31, 2008 8:54 AM, llandre <r&d2 at dave-tech.it> wrote:
> > I have a JFFS2 partition on 32MByte NAND device.
> > When reading a specific file - see below for details - JFFS2 reports a
> > Data CRC error but function nand_correct_data never returns -1, so I
> > assume ECC algorithm is able to correct errors.
> > However the file is not equal to the original one that has been written
> > to NAND. In fact, in the middle of the file, I see a 4-kByte "hole"
> > where all bytes are 0.
> > Anybody can help me about understanding if this is the expected
> > behaviour of JFFS2?
> > Thanks in advance.
> 
> I saw exactly this problem on an s3c2440 board back in October. It
> turned out that the ECC correction code in the s3c2410 driver was
> incorrect in a couple of ways, resulting in corrupt data being passed
> up to JFFS2. I'm not sure, but I think what happened from there is
> that JFFS2 failed to decompress a block and instead of returning an
> error it left the page zeroed. You can use jffs2dump to correlate the
> offset reported in the CRC error with the problematic inode. Check the
> thread "bit flip" in October 2007.

I've seen similar things with cfi_cmdset_0002 on NOR flash, with Linux
2.4.26.  Occasional bit flips on reading flash, resulting in zero
blocks in the read file from JFFS2 - no errors reported to the
application.

I have reason to think our board timings were ever so slightly out of
spec, and haven't seen it in newer board revisions.

-- Jamie


From kmpark at infradead.org  Thu Jan 31 20:30:54 2008
From: kmpark at infradead.org (Kyungmin Park)
Date: Fri, 1 Feb 2008 10:30:54 +0900
Subject: [RFC/REFERENCE PATCH] Use the scatterlist in mtd_blkdevs
Message-ID: <20080201013054.GA14577@party>

Hi,

Now I'm working for CRAMFS optimization for OneNAND.

I try to find optimization point in the cramfs and reduce the memory operation from 3 to 1 in case of uncompressed files (aka XIP files).

In current implementation it has 1 flash read and 2 memory copies.
  Page cache read from flash
  Copy from page cache to local buffer
  Copy local buffer to requested page

In case of uncompressed file, we can issue the requested page to flash directly.

Yes, next access it hits the page cache but forme also requires one more memory copy.

It's working well other devices such as MMC. However it's not in MTD.
Since current mtdblock handles fixed defined blksize and doesn't pass the enough length to optimize the in device level.

Otherwise other flashes, NOR and NAND, OneNAND can optimize the read/write performance if it has beyond page size by read-while-load, cache read, and so on.
Now I added the readsects function pointer with 'len', then OneNAND driver can use the read-while-load feature.

However there's one problem. Each kernel versions the page allocation is some different. Some kernel allocates the page as ascending order we wish, but others descending order. Unfortunately the latest kernel is the latter. So there's no big improvement.

One thing that I said is that we need to new interface to pass buffer with length to optimize in device level.

Any comments are welcome.

Thank you,
Kyungmin Park
---
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 839eed8..51452d7 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/mutex.h>
 #include <linux/kthread.h>
+#include <linux/scatterlist.h>
 #include <asm/uaccess.h>
 
 #include "mtdcore.h"
@@ -32,6 +33,7 @@ struct mtd_blkcore_priv {
 	struct task_struct *thread;
 	struct request_queue *rq;
 	spinlock_t queue_lock;
+	struct scatterlist sg;
 };
 
 static int do_blktrans_request(struct mtd_blktrans_ops *tr,
@@ -54,9 +56,13 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
 
 	switch(rq_data_dir(req)) {
 	case READ:
-		for (; nsect > 0; nsect--, block++, buf += tr->blksize)
-			if (tr->readsect(dev, block, buf))
+		if (tr->readsects) {
+			if (tr->readsects(dev, block, buf, nsect << 9))
 				return 0;
+		} else 
+			for (; nsect > 0; nsect--, block++, buf += tr->blksize)
+				if (tr->readsect(dev, block, buf))
+					return 0;
 		return 1;
 
 	case WRITE:
@@ -74,6 +80,53 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
 	}
 }
 
+static int blk_rq_map_sg_one(struct request_queue *q, struct request *rq,
+		  struct scatterlist *sglist)
+{
+	struct bio_vec *bvec, *bvprv;
+	struct req_iterator iter;
+	struct scatterlist *sg;
+	int nsegs, cluster;
+
+	nsegs = 0;
+	cluster = q->queue_flags & (1 << QUEUE_FLAG_CLUSTER);
+
+	/*
+	 * for each bio in rq
+	 */
+	bvprv = NULL;
+	sg = NULL;
+	rq_for_each_segment(bvec, rq, iter) {
+		int nbytes = bvec->bv_len;
+
+		if (bvprv && cluster) {
+			if (sg->length + nbytes > q->max_segment_size)
+				break;
+
+			if (!BIOVEC_PHYS_MERGEABLE(bvprv, bvec))
+				break;
+			if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bvec))
+				break;
+
+			sg->length += nbytes;
+		} else {
+			if (!sg)
+				sg = sglist;
+			else
+				break;
+
+			sg_set_page(sg, bvec->bv_page, nbytes, bvec->bv_offset);
+			nsegs++;
+		}
+		bvprv = bvec;
+	} /* segments in rq */
+
+	if (sg)
+		__sg_mark_end(sg);
+
+	return nsegs;
+}
+
 static int mtd_blktrans_thread(void *arg)
 {
 	struct mtd_blktrans_ops *tr = arg;
@@ -101,6 +154,16 @@ static int mtd_blktrans_thread(void *arg)
 		dev = req->rq_disk->private_data;
 		tr = dev->tr;
 
+		if (req->current_nr_sectors != req->nr_sectors) {
+			struct scatterlist *sg = &tr->blkcore_priv->sg;
+			int nsg = blk_rq_map_sg_one(req->q, req, sg);
+			if (nsg) {
+				req->current_nr_sectors = sg->length >> 9;
+				if (req->current_nr_sectors > req->nr_sectors)
+					req->current_nr_sectors = req->nr_sectors;
+			}
+		}
+
 		spin_unlock_irq(rq->queue_lock);
 
 		mutex_lock(&dev->lock);
@@ -109,7 +172,11 @@ static int mtd_blktrans_thread(void *arg)
 
 		spin_lock_irq(rq->queue_lock);
 
-		end_request(req, res);
+		if (!end_that_request_chunk(req, res, req->current_nr_sectors << 9)) {
+			add_disk_randomness(req->rq_disk);
+			blkdev_dequeue_request(req);
+			end_that_request_last(req, res);
+		}
 	}
 	spin_unlock_irq(rq->queue_lock);
 
@@ -363,18 +430,14 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
 	if (ret) {
 		printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n",
 		       tr->name, tr->major, ret);
-		kfree(tr->blkcore_priv);
-		mutex_unlock(&mtd_table_mutex);
-		return ret;
+		goto out;
 	}
 	spin_lock_init(&tr->blkcore_priv->queue_lock);
 
 	tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock);
 	if (!tr->blkcore_priv->rq) {
-		unregister_blkdev(tr->major, tr->name);
-		kfree(tr->blkcore_priv);
-		mutex_unlock(&mtd_table_mutex);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto out_rq;
 	}
 
 	tr->blkcore_priv->rq->queuedata = tr;
@@ -384,11 +447,8 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
 	tr->blkcore_priv->thread = kthread_run(mtd_blktrans_thread, tr,
 			"%sd", tr->name);
 	if (IS_ERR(tr->blkcore_priv->thread)) {
-		blk_cleanup_queue(tr->blkcore_priv->rq);
-		unregister_blkdev(tr->major, tr->name);
-		kfree(tr->blkcore_priv);
-		mutex_unlock(&mtd_table_mutex);
-		return PTR_ERR(tr->blkcore_priv->thread);
+		ret = PTR_ERR(tr->blkcore_priv->thread);
+		goto out_thread;
 	}
 
 	INIT_LIST_HEAD(&tr->devs);
@@ -402,6 +462,15 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
 	mutex_unlock(&mtd_table_mutex);
 
 	return 0;
+
+out_thread:
+	blk_cleanup_queue(tr->blkcore_priv->rq);
+out_rq:
+	unregister_blkdev(tr->major, tr->name);
+out:
+	kfree(tr->blkcore_priv);
+	mutex_unlock(&mtd_table_mutex);
+	return ret;
 }
 
 int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr)
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
index 952da30..d771889 100644
--- a/drivers/mtd/mtdblock.c
+++ b/drivers/mtd/mtdblock.c
@@ -245,13 +245,24 @@ static int mtdblock_readsect(struct mtd_blktrans_dev *dev,
 			      unsigned long block, char *buf)
 {
 	struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
-	return do_cached_read(mtdblk, block<<9, 512, buf);
+	struct mtd_blktrans_ops *tr = dev->tr;
+	return do_cached_read(mtdblk, block<<tr->blkshift, tr->blksize, buf);
+}
+
+static int mtdblock_readsects(struct mtd_blktrans_dev *dev,
+				unsigned long block, char *buf, size_t len)
+{
+	/* mtd_blktrans_thread */
+	struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
+	struct mtd_blktrans_ops *tr = dev->tr;
+	return do_cached_read(mtdblk, block<<tr->blkshift, len, buf);
 }
 
 static int mtdblock_writesect(struct mtd_blktrans_dev *dev,
 			      unsigned long block, char *buf)
 {
 	struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
+	struct mtd_blktrans_ops *tr = dev->tr;
 	if (unlikely(!mtdblk->cache_data && mtdblk->cache_size)) {
 		mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize);
 		if (!mtdblk->cache_data)
@@ -261,7 +272,7 @@ static int mtdblock_writesect(struct mtd_blktrans_dev *dev,
 		 * return -EAGAIN sometimes, but why bother?
 		 */
 	}
-	return do_cached_write(mtdblk, block<<9, 512, buf);
+	return do_cached_write(mtdblk, block<<tr->blkshift, tr->blksize, buf);
 }
 
 static int mtdblock_open(struct mtd_blktrans_dev *mbd)
@@ -346,7 +357,7 @@ static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
 	dev->mtd = mtd;
 	dev->devnum = mtd->index;
 
-	dev->size = mtd->size >> 9;
+	dev->size = mtd->size >> tr->blkshift;
 	dev->tr = tr;
 
 	if (!(mtd->flags & MTD_WRITEABLE))
@@ -370,6 +381,7 @@ static struct mtd_blktrans_ops mtdblock_tr = {
 	.flush		= mtdblock_flush,
 	.release	= mtdblock_release,
 	.readsect	= mtdblock_readsect,
+	.readsects	= mtdblock_readsects,
 	.writesect	= mtdblock_writesect,
 	.add_mtd	= mtdblock_add_mtd,
 	.remove_dev	= mtdblock_remove_dev,
diff --git a/include/linux/mtd/blktrans.h b/include/linux/mtd/blktrans.h
index 9a6e2f9..a21f5a9 100644
--- a/include/linux/mtd/blktrans.h
+++ b/include/linux/mtd/blktrans.h
@@ -44,6 +44,10 @@ struct mtd_blktrans_ops {
 	int (*writesect)(struct mtd_blktrans_dev *dev,
 		     unsigned long block, char *buffer);
 
+	/* Multiple reads functions */
+	int (*readsects)(struct mtd_blktrans_dev *dev,
+			unsigned long block, char *buffer, size_t len);
+
 	/* Block layer ioctls */
 	int (*getgeo)(struct mtd_blktrans_dev *dev, struct hd_geometry *geo);
 	int (*flush)(struct mtd_blktrans_dev *dev);


