avr32: upgrade to 2.6.25.6
authorMatteo Croce <rootkit85@yahoo.it>
Thu, 12 Jun 2008 21:13:40 +0000 (21:13 +0000)
committerMatteo Croce <rootkit85@yahoo.it>
Thu, 12 Jun 2008 21:13:40 +0000 (21:13 +0000)
SVN-Revision: 11450

target/linux/avr32/Makefile
target/linux/avr32/config-default
target/linux/avr32/patches/100-git_sync.patch
target/linux/avr32/patches/120-cpufreq_panic.patch [deleted file]

index 5a081f124d312ed0b672885552d4eb2fb3d8eba1..96c5a104b2c9fc923c67a00a424c53a3775c9e61 100644 (file)
@@ -10,7 +10,7 @@ ARCH:=avr32
 BOARD:=avr32
 BOARDNAME:=Atmel AVR32
 FEATURES:=squashfs
-LINUX_VERSION:=2.6.24.7
+LINUX_VERSION:=2.6.25.6
 
 include $(INCLUDE_DIR)/target.mk
 
index ad676449fe709a0d6c8f0e0d493c92d686192022..3fbfb59e89b91b988a1c9d568f17a7fd121a45b1 100644 (file)
@@ -7,10 +7,13 @@ CONFIG_AP700X_16_BIT_SMC=y
 # CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set
 # CONFIG_ARCH_SPARSEMEM_ENABLE is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
-CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_AT32AP700X_WDT=m
 # CONFIG_ATMEL_PWM is not set
 # CONFIG_ATMEL_SSC is not set
-# CONFIG_ATMEL_TCLIB is not set
+CONFIG_ATMEL_TCB_CLKSRC=y
+CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0
+CONFIG_ATMEL_TCLIB=y
 CONFIG_AVR32=y
 CONFIG_BASE_SMALL=0
 CONFIG_BITREVERSE=y
@@ -19,25 +22,38 @@ CONFIG_BOARD_ATNGW100=y
 # CONFIG_BOARD_ATSTK1000 is not set
 # CONFIG_BROADCOM_PHY is not set
 # CONFIG_BT is not set
+CONFIG_CLASSIC_RCU=y
 CONFIG_CPU_AT32AP7000=y
 CONFIG_CPU_AT32AP700X=y
 # CONFIG_CPU_FREQ is not set
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_GF128MUL=m
 # CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_DW_DMAC=y
+# CONFIG_E1000E_ENABLED is not set
 CONFIG_ENTRY_ADDRESS=0x90000000
 # CONFIG_FIXED_PHY is not set
 CONFIG_FS_POSIX_ACL=y
+CONFIG_GENERIC_ALLOCATOR=y
 CONFIG_GENERIC_BUG=y
 CONFIG_GENERIC_CLOCKEVENTS=y
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 CONFIG_GENERIC_GPIO=y
-# CONFIG_GEN_RTC is not set
 # CONFIG_GPIO_DEV is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
 CONFIG_HARDIRQS_SW_RESEND=y
 CONFIG_HAS_DMA=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 # CONFIG_HAVE_ARCH_BOOTMEM_NODE is not set
+CONFIG_HAVE_GPIO_LIB=y
+# CONFIG_HAVE_IDE is not set
+CONFIG_HAVE_KPROBES=y
+# CONFIG_HAVE_KRETPROBES is not set
+CONFIG_HAVE_OPROFILE=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 # CONFIG_I2C_ALGOBIT is not set
@@ -47,14 +63,23 @@ CONFIG_I2C_BOARDINFO=y
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
 # CONFIG_IBM_NEW_EMAC_TAH is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
-# CONFIG_IDE is not set
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LEDS_ALIX is not set
 CONFIG_LEDS_GPIO=y
 CONFIG_LOADER_U_BOOT=y
 CONFIG_LOAD_ADDRESS=0x10000000
+CONFIG_LZO_COMPRESS=m
+CONFIG_LZO_DECOMPRESS=m
 CONFIG_MACB=y
 # CONFIG_MDIO_BITBANG is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_MMC=m
+CONFIG_MMC_ATMELMCI=m
+CONFIG_MMC_BLOCK=m
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
 CONFIG_MTD=y
 # CONFIG_MTD_ABSENT is not set
 CONFIG_MTD_BLKDEVS=y
@@ -104,16 +129,40 @@ CONFIG_MTD_PHYSMAP_START=0x80000000
 # CONFIG_NMI_DEBUGGING is not set
 CONFIG_NO_HZ=y
 # CONFIG_OWNERSHIP_TRACE is not set
-# CONFIG_PATA_AT32 is not set
 CONFIG_PERFORMANCE_COUNTERS=y
 CONFIG_PHYLIB=y
 CONFIG_PHYS_OFFSET=0x10000000
 CONFIG_PLATFORM_AT32AP=y
 # CONFIG_QSEMI_PHY is not set
-# CONFIG_RTC is not set
+# CONFIG_REALTEK_PHY is not set
+CONFIG_RTC_CLASS=m
+CONFIG_RTC_DRV_AT32AP700X=m
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_LIB=m
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_SCHED_HRTICK is not set
 CONFIG_SCSI_WAIT_SCAN=m
+# CONFIG_SDIO_UART is not set
 # CONFIG_SERIAL_8250 is not set
 CONFIG_SERIAL_ATMEL=y
 CONFIG_SERIAL_ATMEL_CONSOLE=y
@@ -122,6 +171,7 @@ CONFIG_SERIAL_ATMEL_PDC=y
 CONFIG_SLABINFO=y
 # CONFIG_SMSC_PHY is not set
 # CONFIG_SND_ATMEL_AC97 is not set
+# CONFIG_SOFT_WATCHDOG is not set
 # CONFIG_SPARSEMEM_STATIC is not set
 # CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
 CONFIG_SPI=y
@@ -133,11 +183,11 @@ CONFIG_SPI_MASTER=y
 CONFIG_SSB_POSSIBLE=y
 CONFIG_SUBARCH_AVR32B=y
 CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_THERMAL is not set
 CONFIG_TICK_ONESHOT=y
 # CONFIG_USB_ARCH_HAS_EHCI is not set
 # CONFIG_USB_ARCH_HAS_HCD is not set
 # CONFIG_USB_ARCH_HAS_OHCI is not set
-# CONFIG_USER_NS is not set
 # CONFIG_VGASTATE is not set
-# CONFIG_WATCHDOG is not set
+CONFIG_VIDEO_V4L2_COMMON=m
 CONFIG_ZONE_DMA_FLAG=0
index 9c2d5ddf42298274997128d5a1f25e69a6247def..a840e45f381d20ea058036747356f7284161d859 100644 (file)
@@ -1,5 +1,423 @@
---- /dev/null
-+++ b/arch/avr32/boards/atngw100/Kconfig
+diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/at91cap9_devices.c avr32-2.6/arch/arm/mach-at91/at91cap9_devices.c
+--- linux-2.6.25.6/arch/arm/mach-at91/at91cap9_devices.c       2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/arm/mach-at91/at91cap9_devices.c    2008-06-12 15:09:38.603815938 +0200
+@@ -278,20 +278,25 @@
+  * -------------------------------------------------------------------- */
+ #if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE)
+-static struct at91_nand_data nand_data;
++static struct atmel_nand_data nand_data;
+ #define NAND_BASE     AT91_CHIPSELECT_3
+ static struct resource nand_resources[] = {
+-      {
++      [0] = {
+               .start  = NAND_BASE,
+               .end    = NAND_BASE + SZ_256M - 1,
+               .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = AT91_BASE_SYS + AT91_ECC,
++              .end    = AT91_BASE_SYS + AT91_ECC + SZ_512 - 1,
++              .flags  = IORESOURCE_MEM,
+       }
+ };
+ static struct platform_device at91cap9_nand_device = {
+-      .name           = "at91_nand",
++      .name           = "atmel_nand",
+       .id             = -1,
+       .dev            = {
+                               .platform_data  = &nand_data,
+@@ -300,7 +305,7 @@
+       .num_resources  = ARRAY_SIZE(nand_resources),
+ };
+-void __init at91_add_device_nand(struct at91_nand_data *data)
++void __init at91_add_device_nand(struct atmel_nand_data *data)
+ {
+       unsigned long csa, mode;
+@@ -341,7 +346,7 @@
+       platform_device_register(&at91cap9_nand_device);
+ }
+ #else
+-void __init at91_add_device_nand(struct at91_nand_data *data) {}
++void __init at91_add_device_nand(struct atmel_nand_data *data) {}
+ #endif
+ /* --------------------------------------------------------------------
+diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/at91rm9200_devices.c avr32-2.6/arch/arm/mach-at91/at91rm9200_devices.c
+--- linux-2.6.25.6/arch/arm/mach-at91/at91rm9200_devices.c     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/arm/mach-at91/at91rm9200_devices.c  2008-06-12 15:09:38.603815938 +0200
+@@ -369,7 +369,7 @@
+  * -------------------------------------------------------------------- */
+ #if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE)
+-static struct at91_nand_data nand_data;
++static struct atmel_nand_data nand_data;
+ #define NAND_BASE     AT91_CHIPSELECT_3
+@@ -382,7 +382,7 @@
+ };
+ static struct platform_device at91rm9200_nand_device = {
+-      .name           = "at91_nand",
++      .name           = "atmel_nand",
+       .id             = -1,
+       .dev            = {
+                               .platform_data  = &nand_data,
+@@ -391,7 +391,7 @@
+       .num_resources  = ARRAY_SIZE(nand_resources),
+ };
+-void __init at91_add_device_nand(struct at91_nand_data *data)
++void __init at91_add_device_nand(struct atmel_nand_data *data)
+ {
+       unsigned int csa;
+@@ -429,7 +429,7 @@
+       platform_device_register(&at91rm9200_nand_device);
+ }
+ #else
+-void __init at91_add_device_nand(struct at91_nand_data *data) {}
++void __init at91_add_device_nand(struct atmel_nand_data *data) {}
+ #endif
+diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/at91sam9260_devices.c avr32-2.6/arch/arm/mach-at91/at91sam9260_devices.c
+--- linux-2.6.25.6/arch/arm/mach-at91/at91sam9260_devices.c    2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/arm/mach-at91/at91sam9260_devices.c 2008-06-12 15:09:38.603815938 +0200
+@@ -283,20 +283,25 @@
+  * -------------------------------------------------------------------- */
+ #if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE)
+-static struct at91_nand_data nand_data;
++static struct atmel_nand_data nand_data;
+ #define NAND_BASE     AT91_CHIPSELECT_3
+ static struct resource nand_resources[] = {
+-      {
++      [0] = {
+               .start  = NAND_BASE,
+               .end    = NAND_BASE + SZ_256M - 1,
+               .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = AT91_BASE_SYS + AT91_ECC,
++              .end    = AT91_BASE_SYS + AT91_ECC + SZ_512 - 1,
++              .flags  = IORESOURCE_MEM,
+       }
+ };
+ static struct platform_device at91sam9260_nand_device = {
+-      .name           = "at91_nand",
++      .name           = "atmel_nand",
+       .id             = -1,
+       .dev            = {
+                               .platform_data  = &nand_data,
+@@ -305,7 +310,7 @@
+       .num_resources  = ARRAY_SIZE(nand_resources),
+ };
+-void __init at91_add_device_nand(struct at91_nand_data *data)
++void __init at91_add_device_nand(struct atmel_nand_data *data)
+ {
+       unsigned long csa, mode;
+@@ -346,7 +351,7 @@
+       platform_device_register(&at91sam9260_nand_device);
+ }
+ #else
+-void __init at91_add_device_nand(struct at91_nand_data *data) {}
++void __init at91_add_device_nand(struct atmel_nand_data *data) {}
+ #endif
+diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/at91sam9261_devices.c avr32-2.6/arch/arm/mach-at91/at91sam9261_devices.c
+--- linux-2.6.25.6/arch/arm/mach-at91/at91sam9261_devices.c    2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/arm/mach-at91/at91sam9261_devices.c 2008-06-12 15:09:38.607815889 +0200
+@@ -199,7 +199,7 @@
+  * -------------------------------------------------------------------- */
+ #if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE)
+-static struct at91_nand_data nand_data;
++static struct atmel_nand_data nand_data;
+ #define NAND_BASE     AT91_CHIPSELECT_3
+@@ -211,8 +211,8 @@
+       }
+ };
+-static struct platform_device at91_nand_device = {
+-      .name           = "at91_nand",
++static struct platform_device atmel_nand_device = {
++      .name           = "atmel_nand",
+       .id             = -1,
+       .dev            = {
+                               .platform_data  = &nand_data,
+@@ -221,7 +221,7 @@
+       .num_resources  = ARRAY_SIZE(nand_resources),
+ };
+-void __init at91_add_device_nand(struct at91_nand_data *data)
++void __init at91_add_device_nand(struct atmel_nand_data *data)
+ {
+       unsigned long csa, mode;
+@@ -262,11 +262,11 @@
+       at91_set_A_periph(AT91_PIN_PC1, 0);             /* NANDWE */
+       nand_data = *data;
+-      platform_device_register(&at91_nand_device);
++      platform_device_register(&atmel_nand_device);
+ }
+ #else
+-void __init at91_add_device_nand(struct at91_nand_data *data) {}
++void __init at91_add_device_nand(struct atmel_nand_data *data) {}
+ #endif
+@@ -539,6 +539,20 @@
+       at91_set_B_periph(AT91_PIN_PB28, 0);    /* LCDD23 */
+ #endif
++#ifdef CONFIG_FB_INTSRAM
++      {
++              void __iomem *fb;
++              struct resource *fb_res = &lcdc_resources[2];
++              size_t fb_len = fb_res->end - fb_res->start + 1;
++
++              fb = ioremap_writecombine(fb_res->start, fb_len);
++              if (fb) {
++                      memset(fb, 0, fb_len);
++                      iounmap(fb, fb_len);
++              }
++      }
++#endif
++
+       lcdc_data = *data;
+       platform_device_register(&at91_lcdc_device);
+ }
+diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/at91sam9263_devices.c avr32-2.6/arch/arm/mach-at91/at91sam9263_devices.c
+--- linux-2.6.25.6/arch/arm/mach-at91/at91sam9263_devices.c    2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/arm/mach-at91/at91sam9263_devices.c 2008-06-12 15:09:38.607815889 +0200
+@@ -353,20 +353,25 @@
+  * -------------------------------------------------------------------- */
+ #if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE)
+-static struct at91_nand_data nand_data;
++static struct atmel_nand_data nand_data;
+ #define NAND_BASE     AT91_CHIPSELECT_3
+ static struct resource nand_resources[] = {
+-      {
++      [0] = {
+               .start  = NAND_BASE,
+               .end    = NAND_BASE + SZ_256M - 1,
+               .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = AT91_BASE_SYS + AT91_ECC0,
++              .end    = AT91_BASE_SYS + AT91_ECC0 + SZ_512 - 1,
++              .flags  = IORESOURCE_MEM,
+       }
+ };
+ static struct platform_device at91sam9263_nand_device = {
+-      .name           = "at91_nand",
++      .name           = "atmel_nand",
+       .id             = -1,
+       .dev            = {
+                               .platform_data  = &nand_data,
+@@ -375,7 +380,7 @@
+       .num_resources  = ARRAY_SIZE(nand_resources),
+ };
+-void __init at91_add_device_nand(struct at91_nand_data *data)
++void __init at91_add_device_nand(struct atmel_nand_data *data)
+ {
+       unsigned long csa, mode;
+@@ -416,7 +421,7 @@
+       platform_device_register(&at91sam9263_nand_device);
+ }
+ #else
+-void __init at91_add_device_nand(struct at91_nand_data *data) {}
++void __init at91_add_device_nand(struct atmel_nand_data *data) {}
+ #endif
+diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/at91sam9rl_devices.c avr32-2.6/arch/arm/mach-at91/at91sam9rl_devices.c
+--- linux-2.6.25.6/arch/arm/mach-at91/at91sam9rl_devices.c     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/arm/mach-at91/at91sam9rl_devices.c  2008-06-12 15:09:38.607815889 +0200
+@@ -100,20 +100,25 @@
+  * -------------------------------------------------------------------- */
+ #if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE)
+-static struct at91_nand_data nand_data;
++static struct atmel_nand_data nand_data;
+ #define NAND_BASE     AT91_CHIPSELECT_3
+ static struct resource nand_resources[] = {
+-      {
++      [0] = {
+               .start  = NAND_BASE,
+               .end    = NAND_BASE + SZ_256M - 1,
+               .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = AT91_BASE_SYS + AT91_ECC,
++              .end    = AT91_BASE_SYS + AT91_ECC + SZ_512 - 1,
++              .flags  = IORESOURCE_MEM,
+       }
+ };
+-static struct platform_device at91_nand_device = {
+-      .name           = "at91_nand",
++static struct platform_device atmel_nand_device = {
++      .name           = "atmel_nand",
+       .id             = -1,
+       .dev            = {
+                               .platform_data  = &nand_data,
+@@ -122,7 +127,7 @@
+       .num_resources  = ARRAY_SIZE(nand_resources),
+ };
+-void __init at91_add_device_nand(struct at91_nand_data *data)
++void __init at91_add_device_nand(struct atmel_nand_data *data)
+ {
+       unsigned long csa;
+@@ -159,11 +164,11 @@
+       at91_set_A_periph(AT91_PIN_PB5, 0);             /* NANDWE */
+       nand_data = *data;
+-      platform_device_register(&at91_nand_device);
++      platform_device_register(&atmel_nand_device);
+ }
+ #else
+-void __init at91_add_device_nand(struct at91_nand_data *data) {}
++void __init at91_add_device_nand(struct atmel_nand_data *data) {}
+ #endif
+@@ -376,6 +381,20 @@
+       at91_set_B_periph(AT91_PIN_PC24, 0);    /* LCDD22 */
+       at91_set_B_periph(AT91_PIN_PC25, 0);    /* LCDD23 */
++#ifdef CONFIG_FB_INTSRAM
++      {
++              void __iomem *fb;
++              struct resource *fb_res = &lcdc_resources[2];
++              size_t fb_len = fb_res->end - fb_res->start + 1;
++
++              fb = ioremap_writecombine(fb_res->start, fb_len);
++              if (fb) {
++                      memset(fb, 0, fb_len);
++                      iounmap(fb, fb_len);
++              }
++      }
++#endif
++
+       lcdc_data = *data;
+       platform_device_register(&at91_lcdc_device);
+ }
+diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/board-cap9adk.c avr32-2.6/arch/arm/mach-at91/board-cap9adk.c
+--- linux-2.6.25.6/arch/arm/mach-at91/board-cap9adk.c  2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/arm/mach-at91/board-cap9adk.c       2008-06-12 15:09:38.607815889 +0200
+@@ -175,7 +175,7 @@
+       return cap9adk_nand_partitions;
+ }
+-static struct at91_nand_data __initdata cap9adk_nand_data = {
++static struct atmel_nand_data __initdata cap9adk_nand_data = {
+       .ale            = 21,
+       .cle            = 22,
+ //    .det_pin        = ... not connected
+diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/board-dk.c avr32-2.6/arch/arm/mach-at91/board-dk.c
+--- linux-2.6.25.6/arch/arm/mach-at91/board-dk.c       2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/arm/mach-at91/board-dk.c    2008-06-12 15:09:38.611815840 +0200
+@@ -151,7 +151,7 @@
+       return dk_nand_partition;
+ }
+-static struct at91_nand_data __initdata dk_nand_data = {
++static struct atmel_nand_data __initdata dk_nand_data = {
+       .ale            = 22,
+       .cle            = 21,
+       .det_pin        = AT91_PIN_PB1,
+diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/board-kb9202.c avr32-2.6/arch/arm/mach-at91/board-kb9202.c
+--- linux-2.6.25.6/arch/arm/mach-at91/board-kb9202.c   2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/arm/mach-at91/board-kb9202.c        2008-06-12 15:09:38.611815840 +0200
+@@ -102,7 +102,7 @@
+       return kb9202_nand_partition;
+ }
+-static struct at91_nand_data __initdata kb9202_nand_data = {
++static struct atmel_nand_data __initdata kb9202_nand_data = {
+       .ale            = 22,
+       .cle            = 21,
+       // .det_pin     = ... not there
+diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/board-sam9260ek.c avr32-2.6/arch/arm/mach-at91/board-sam9260ek.c
+--- linux-2.6.25.6/arch/arm/mach-at91/board-sam9260ek.c        2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/arm/mach-at91/board-sam9260ek.c     2008-06-12 15:09:38.611815840 +0200
+@@ -146,7 +146,7 @@
+       return ek_nand_partition;
+ }
+-static struct at91_nand_data __initdata ek_nand_data = {
++static struct atmel_nand_data __initdata ek_nand_data = {
+       .ale            = 21,
+       .cle            = 22,
+ //    .det_pin        = ... not connected
+diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/board-sam9261ek.c avr32-2.6/arch/arm/mach-at91/board-sam9261ek.c
+--- linux-2.6.25.6/arch/arm/mach-at91/board-sam9261ek.c        2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/arm/mach-at91/board-sam9261ek.c     2008-06-12 15:09:38.611815840 +0200
+@@ -189,7 +189,7 @@
+       return ek_nand_partition;
+ }
+-static struct at91_nand_data __initdata ek_nand_data = {
++static struct atmel_nand_data __initdata ek_nand_data = {
+       .ale            = 22,
+       .cle            = 21,
+ //    .det_pin        = ... not connected
+diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/board-sam9263ek.c avr32-2.6/arch/arm/mach-at91/board-sam9263ek.c
+--- linux-2.6.25.6/arch/arm/mach-at91/board-sam9263ek.c        2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/arm/mach-at91/board-sam9263ek.c     2008-06-12 15:09:38.611815840 +0200
+@@ -192,7 +192,7 @@
+       return ek_nand_partition;
+ }
+-static struct at91_nand_data __initdata ek_nand_data = {
++static struct atmel_nand_data __initdata ek_nand_data = {
+       .ale            = 21,
+       .cle            = 22,
+ //    .det_pin        = ... not connected
+diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/board-sam9rlek.c avr32-2.6/arch/arm/mach-at91/board-sam9rlek.c
+--- linux-2.6.25.6/arch/arm/mach-at91/board-sam9rlek.c 2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/arm/mach-at91/board-sam9rlek.c      2008-06-12 15:09:38.611815840 +0200
+@@ -93,7 +93,7 @@
+       return ek_nand_partition;
+ }
+-static struct at91_nand_data __initdata ek_nand_data = {
++static struct atmel_nand_data __initdata ek_nand_data = {
+       .ale            = 21,
+       .cle            = 22,
+ //    .det_pin        = ... not connected
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/boards/atngw100/Kconfig avr32-2.6/arch/avr32/boards/atngw100/Kconfig
+--- linux-2.6.25.6/arch/avr32/boards/atngw100/Kconfig  1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/arch/avr32/boards/atngw100/Kconfig       2008-06-12 15:09:38.711815728 +0200
 @@ -0,0 +1,12 @@
 +# NGW100 customization
 +
 +
 +        Choose 'Y' here if you're having i2c-related problems and
 +        want to rule out the i2c bus driver.
---- a/arch/avr32/boards/atngw100/setup.c
-+++ b/arch/avr32/boards/atngw100/setup.c
-@@ -20,7 +20,7 @@
- #include <asm/io.h>
- #include <asm/setup.h>
--#include <asm/arch/at32ap7000.h>
-+#include <asm/arch/at32ap700x.h>
- #include <asm/arch/board.h>
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/boards/atngw100/setup.c avr32-2.6/arch/avr32/boards/atngw100/setup.c
+--- linux-2.6.25.6/arch/avr32/boards/atngw100/setup.c  2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/boards/atngw100/setup.c       2008-06-12 15:09:38.711815728 +0200
+@@ -25,6 +25,13 @@
  #include <asm/arch/init.h>
  #include <asm/arch/portmux.h>
-@@ -37,11 +37,16 @@
++/* Oscillator frequencies. These are board-specific */
++unsigned long at32_board_osc_rates[3] = {
++      [0] = 32768,    /* 32.768 kHz on RTC osc */
++      [1] = 20000000, /* 20 MHz on osc0 */
++      [2] = 12000000, /* 12 MHz on osc1 */
++};
++
+ /* Initialized by bootloader-specific startup code. */
+ struct tag *bootloader_tags __initdata;
+@@ -37,11 +44,16 @@
  static struct spi_board_info spi0_board_info[] __initdata = {
        {
                .modalias       = "mtd_dataflash",
  /*
   * The next two functions should go away as the boot loader is
   * supposed to initialize the macb address registers with a valid
-@@ -124,6 +129,7 @@
+@@ -124,6 +136,7 @@
        }
  };
  
  static struct i2c_gpio_platform_data i2c_gpio_data = {
        .sda_pin                = GPIO_PIN_PA(6),
        .scl_pin                = GPIO_PIN_PA(7),
-@@ -139,6 +145,7 @@
+@@ -139,6 +152,7 @@
                .platform_data  = &i2c_gpio_data,
        },
  };
  
  static int __init atngw100_init(void)
  {
-@@ -157,6 +164,7 @@
+@@ -157,6 +171,7 @@
        set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
  
        at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
        at32_add_device_usba(0, NULL);
  
        for (i = 0; i < ARRAY_SIZE(ngw_leds); i++) {
-@@ -165,11 +173,15 @@
+@@ -165,11 +180,15 @@
        }
        platform_device_register(&ngw_gpio_leds);
  
  
        return 0;
  }
---- a/arch/avr32/boards/atstk1000/atstk1000.h
-+++ b/arch/avr32/boards/atstk1000/atstk1000.h
-@@ -12,4 +12,6 @@
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/boards/atstk1000/atstk1002.c avr32-2.6/arch/avr32/boards/atstk1000/atstk1002.c
+--- linux-2.6.25.6/arch/avr32/boards/atstk1000/atstk1002.c     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/boards/atstk1000/atstk1002.c  2008-06-12 15:09:38.711815728 +0200
+@@ -1,7 +1,7 @@
+ /*
+- * ATSTK1002 daughterboard-specific init code
++ * ATSTK1002/ATSTK1006 daughterboard-specific init code
+  *
+- * Copyright (C) 2005-2006 Atmel Corporation
++ * Copyright (C) 2005-2007 Atmel Corporation
+  *
+  * 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
+@@ -28,6 +28,80 @@
  
- extern struct atmel_lcdfb_info atstk1000_lcdc_data;
+ #include "atstk1000.h"
  
-+void atstk1000_setup_j2_leds(void);
++/* Oscillator frequencies. These are board specific */
++unsigned long at32_board_osc_rates[3] = {
++      [0] = 32768,    /* 32.768 kHz on RTC osc */
++      [1] = 20000000, /* 20 MHz on osc0 */
++      [2] = 12000000, /* 12 MHz on osc1 */
++};
 +
- #endif /* __ARCH_AVR32_BOARDS_ATSTK1000_ATSTK1000_H */
---- a/arch/avr32/boards/atstk1000/atstk1002.c
-+++ b/arch/avr32/boards/atstk1000/atstk1002.c
-@@ -11,7 +11,6 @@
- #include <linux/etherdevice.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
--#include <linux/leds.h>
- #include <linux/platform_device.h>
- #include <linux/string.h>
- #include <linux/types.h>
-@@ -22,7 +21,7 @@
- #include <asm/io.h>
- #include <asm/setup.h>
--#include <asm/arch/at32ap7000.h>
-+#include <asm/arch/at32ap700x.h>
- #include <asm/arch/board.h>
- #include <asm/arch/init.h>
- #include <asm/arch/portmux.h>
-@@ -49,18 +48,16 @@
-       },
- };
--#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
--#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
-+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
- static struct at73c213_board_info at73c213_data = {
-       .ssc_id         = 0,
-       .shortname      = "AVR32 STK1000 external DAC",
- };
- #endif
--#endif
--#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
-+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
- static struct spi_board_info spi0_board_info[] __initdata = {
--#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
-+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
-       {
-               /* AT73C213 */
-               .modalias       = "at73c213",
-@@ -80,12 +77,25 @@
- };
- #endif
++/*
++ * The ATSTK1006 daughterboard is very similar to the ATSTK1002. Both
++ * have the AT32AP7000 chip on board; the difference is that the
++ * STK1006 has 128 MB SDRAM (the STK1002 uses the 8 MB SDRAM chip on
++ * the STK1000 motherboard) and 256 MB NAND flash (the STK1002 has
++ * none.)
++ *
++ * The RAM difference is handled by the boot loader, so the only
++ * difference we end up handling here is the NAND flash.
++ */
++#ifdef CONFIG_BOARD_ATSTK1006
++#include <linux/mtd/partitions.h>
++#include <asm/arch/smc.h>
++
++static struct smc_timing nand_timing __initdata = {
++      .ncs_read_setup         = 0,
++      .nrd_setup              = 10,
++      .ncs_write_setup        = 0,
++      .nwe_setup              = 10,
++
++      .ncs_read_pulse         = 30,
++      .nrd_pulse              = 15,
++      .ncs_write_pulse        = 30,
++      .nwe_pulse              = 15,
++
++      .read_cycle             = 30,
++      .write_cycle            = 30,
++
++      .ncs_read_recover       = 0,
++      .nrd_recover            = 15,
++      .ncs_write_recover      = 0,
++      /* WE# high -> RE# low min 60 ns */
++      .nwe_recover            = 50,
++};
++
++static struct smc_config nand_config __initdata = {
++      .bus_width              = 1,
++      .nrd_controlled         = 1,
++      .nwe_controlled         = 1,
++      .nwait_mode             = 0,
++      .byte_write             = 0,
++      .tdf_cycles             = 2,
++      .tdf_mode               = 0,
++};
++
++static struct mtd_partition nand_partitions[] = {
++      {
++              .name           = "main",
++              .offset         = 0x00000000,
++              .size           = MTDPART_SIZ_FULL,
++      },
++};
++
++static struct mtd_partition *nand_part_info(int size, int *num_partitions)
++{
++      *num_partitions = ARRAY_SIZE(nand_partitions);
++      return nand_partitions;
++}
++
++static struct atmel_nand_data atstk1006_nand_data __initdata = {
++      .cle            = 21,
++      .ale            = 22,
++      .rdy_pin        = GPIO_PIN_PB(30),
++      .enable_pin     = GPIO_PIN_PB(29),
++      .partition_info = nand_part_info,
++};
++#endif
  
--#ifdef CONFIG_BOARD_ATSTK1002_SPI1
-+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
- static struct spi_board_info spi1_board_info[] __initdata = { {
-       /* patch in custom entries here */
+ struct eth_addr {
+       u8 addr[6];
+@@ -83,6 +157,19 @@
  } };
  #endif
  
  /*
   * The next two functions should go away as the boot loader is
   * supposed to initialize the macb address registers with a valid
-@@ -141,68 +151,8 @@
-       clk_put(pclk);
- }
--#ifdef CONFIG_BOARD_ATSTK1002_J2_LED
--
--static struct gpio_led stk_j2_led[] = {
--#ifdef CONFIG_BOARD_ATSTK1002_J2_LED8
--#define LEDSTRING "J2 jumpered to LED8"
--      { .name = "led0:amber", .gpio = GPIO_PIN_PB( 8), },
--      { .name = "led1:amber", .gpio = GPIO_PIN_PB( 9), },
--      { .name = "led2:amber", .gpio = GPIO_PIN_PB(10), },
--      { .name = "led3:amber", .gpio = GPIO_PIN_PB(13), },
--      { .name = "led4:amber", .gpio = GPIO_PIN_PB(14), },
--      { .name = "led5:amber", .gpio = GPIO_PIN_PB(15), },
--      { .name = "led6:amber", .gpio = GPIO_PIN_PB(16), },
--      { .name = "led7:amber", .gpio = GPIO_PIN_PB(30),
--                      .default_trigger = "heartbeat", },
--#else /* RGB */
--#define LEDSTRING "J2 jumpered to RGB LEDs"
--      { .name = "r1:red",     .gpio = GPIO_PIN_PB( 8), },
--      { .name = "g1:green",   .gpio = GPIO_PIN_PB(10), },
--      { .name = "b1:blue",    .gpio = GPIO_PIN_PB(14), },
--
--      { .name = "r2:red",     .gpio = GPIO_PIN_PB( 9),
--                      .default_trigger = "heartbeat", },
--      { .name = "g2:green",   .gpio = GPIO_PIN_PB(13), },
--      { .name = "b2:blue",    .gpio = GPIO_PIN_PB(15),
--                      .default_trigger = "heartbeat", },
--      /* PB16, PB30 unused */
--#endif
--};
--
--static struct gpio_led_platform_data stk_j2_led_data = {
--      .num_leds       = ARRAY_SIZE(stk_j2_led),
--      .leds           = stk_j2_led,
--};
--
--static struct platform_device stk_j2_led_dev = {
--      .name           = "leds-gpio",
--      .id             = 2,    /* gpio block J2 */
--      .dev            = {
--              .platform_data  = &stk_j2_led_data,
--      },
--};
--
--static void setup_j2_leds(void)
--{
--      unsigned        i;
--
--      for (i = 0; i < ARRAY_SIZE(stk_j2_led); i++)
--              at32_select_gpio(stk_j2_led[i].gpio, AT32_GPIOF_OUTPUT);
--
--      printk("STK1002: " LEDSTRING "\n");
--      platform_device_register(&stk_j2_led_dev);
--}
--
--#else
--static void setup_j2_leds(void)
--{
--}
--#endif
--
--#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
--#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
--static void __init at73c213_set_clk(struct at73c213_board_info *info)
-+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
-+static void __init atstk1002_setup_extdac(void)
- {
-       struct clk *gclk;
-       struct clk *pll;
-@@ -220,7 +170,7 @@
-       }
-       at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
--      info->dac_clk = gclk;
-+      at73c213_data.dac_clk = gclk;
- err_set_clk:
-       clk_put(pll);
-@@ -229,12 +179,16 @@
- err_gclk:
-       return;
- }
--#endif
--#endif
-+#else
-+static void __init atstk1002_setup_extdac(void)
-+{
-+
-+}
-+#endif /* CONFIG_BOARD_ATSTK1000_EXTDAC */
- void __init setup_board(void)
- {
--#ifdef        CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
-+#ifdef        CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-       at32_map_usart(0, 1);   /* USART 0/B: /dev/ttyS1, IRDA */
- #else
-       at32_map_usart(1, 0);   /* USART 1/A: /dev/ttyS0, DB9 */
-@@ -271,7 +225,7 @@
+@@ -212,6 +299,12 @@
  
        at32_add_system_devices();
  
--#ifdef        CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
-+#ifdef        CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
++#ifdef CONFIG_BOARD_ATSTK1006
++      smc_set_timing(&nand_config, &nand_timing);
++      smc_set_configuration(3, &nand_config);
++      at32_add_device_nand(0, &atstk1006_nand_data);
++#endif
++
+ #ifdef        CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
        at32_add_device_usart(1);
  #else
-       at32_add_device_usart(0);
-@@ -281,12 +235,16 @@
- #ifndef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM
-       set_hw_addr(at32_add_device_eth(0, &eth_data[0]));
- #endif
--#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
-+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
-       at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
- #endif
--#ifdef CONFIG_BOARD_ATSTK1002_SPI1
-+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
+@@ -228,16 +321,30 @@
+ #ifdef CONFIG_BOARD_ATSTK100X_SPI1
        at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
  #endif
 +      at32_add_device_twi(0, NULL, 0);
  #ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
        set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
  #else
-@@ -294,18 +252,23 @@
-                            fbmem_start, fbmem_size);
+       at32_add_device_lcdc(0, &atstk1000_lcdc_data,
+-                           fbmem_start, fbmem_size);
++                           fbmem_start, fbmem_size, 0);
  #endif
        at32_add_device_usba(0, NULL);
--#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
--      at32_add_device_ssc(0, ATMEL_SSC_TX);
 +#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_AC97
 +      at32_add_device_ac97c(0);
 +#else
 +      at32_add_device_abdac(0);
- #endif
--
--      setup_j2_leds();
--
--#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
--#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
--      at73c213_set_clk(&at73c213_data);
-+#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
-+      at32_add_device_ssc(0, ATMEL_SSC_TX);
++#endif
+ #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
+       at32_add_device_ssc(0, ATMEL_SSC_TX);
  #endif
 +      at32_add_device_cf(0, 2, &cf0_data);
 +#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_PSIF
 +      at32_add_device_psif(0);
 +      at32_add_device_psif(1);
++#endif
+       atstk1000_setup_j2_leds();
+       atstk1002_setup_extdac();
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/boards/atstk1000/atstk1003.c avr32-2.6/arch/avr32/boards/atstk1000/atstk1003.c
+--- linux-2.6.25.6/arch/avr32/boards/atstk1000/atstk1003.c     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/boards/atstk1000/atstk1003.c  2008-06-12 15:09:38.711815728 +0200
+@@ -27,6 +27,13 @@
+ #include "atstk1000.h"
++/* Oscillator frequencies. These are board specific */
++unsigned long at32_board_osc_rates[3] = {
++      [0] = 32768,    /* 32.768 kHz on RTC osc */
++      [1] = 20000000, /* 20 MHz on osc0 */
++      [2] = 12000000, /* 12 MHz on osc1 */
++};
++
+ #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
+ static struct at73c213_board_info at73c213_data = {
+       .ssc_id         = 0,
+@@ -59,6 +66,19 @@
+ } };
  #endif
  
-+      atstk1000_setup_j2_leds();
-+      atstk1002_setup_extdac();
++static struct cf_platform_data __initdata cf0_data = {
++#ifdef CONFIG_BOARD_ATSTK1000_CF_HACKS
++      .detect_pin     = CONFIG_BOARD_ATSTK1000_CF_DETECT_PIN,
++      .reset_pin      = CONFIG_BOARD_ATSTK1000_CF_RESET_PIN,
++#else
++      .detect_pin     = GPIO_PIN_NONE,
++      .reset_pin      = GPIO_PIN_NONE,
++#endif
++      .vcc_pin        = GPIO_PIN_NONE,
++      .ready_pin      = GPIO_PIN_PB(27),
++      .cs             = 4,
++};
 +
-       return 0;
- }
- postcore_initcall(atstk1002_init);
---- /dev/null
-+++ b/arch/avr32/boards/atstk1000/atstk1003.c
-@@ -0,0 +1,185 @@
-+/*
-+ * ATSTK1003 daughterboard-specific init code
-+ *
-+ * Copyright (C) 2007 Atmel Corporation
-+ *
-+ * 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/clk.h>
-+#include <linux/err.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/platform_device.h>
-+#include <linux/string.h>
-+#include <linux/types.h>
-+
-+#include <linux/spi/at73c213.h>
-+#include <linux/spi/spi.h>
-+
-+#include <asm/setup.h>
-+
-+#include <asm/arch/at32ap700x.h>
-+#include <asm/arch/board.h>
-+#include <asm/arch/init.h>
-+#include <asm/arch/portmux.h>
-+
-+#include "atstk1000.h"
-+
-+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
-+static struct at73c213_board_info at73c213_data = {
-+      .ssc_id         = 0,
-+      .shortname      = "AVR32 STK1000 external DAC",
-+};
-+#endif
-+
-+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
-+static struct spi_board_info spi0_board_info[] __initdata = {
-+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
-+      {
-+              /* AT73C213 */
-+              .modalias       = "at73c213",
-+              .max_speed_hz   = 200000,
-+              .chip_select    = 0,
-+              .mode           = SPI_MODE_1,
-+              .platform_data  = &at73c213_data,
-+      },
-+#endif
-+      /*
-+       * We can control the LTV350QV LCD panel, but it isn't much
-+       * point since we don't have an LCD controller...
-+       */
-+};
-+#endif
-+
-+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
-+static struct spi_board_info spi1_board_info[] __initdata = { {
-+      /* patch in custom entries here */
-+} };
-+#endif
-+
-+static struct cf_platform_data __initdata cf0_data = {
-+#ifdef CONFIG_BOARD_ATSTK1000_CF_HACKS
-+      .detect_pin     = CONFIG_BOARD_ATSTK1000_CF_DETECT_PIN,
-+      .reset_pin      = CONFIG_BOARD_ATSTK1000_CF_RESET_PIN,
-+#else
-+      .detect_pin     = GPIO_PIN_NONE,
-+      .reset_pin      = GPIO_PIN_NONE,
-+#endif
-+      .vcc_pin        = GPIO_PIN_NONE,
-+      .ready_pin      = GPIO_PIN_PB(27),
-+      .cs             = 4,
-+};
-+
-+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
-+static void __init atstk1003_setup_extdac(void)
-+{
-+      struct clk *gclk;
-+      struct clk *pll;
-+
-+      gclk = clk_get(NULL, "gclk0");
-+      if (IS_ERR(gclk))
-+              goto err_gclk;
-+      pll = clk_get(NULL, "pll0");
-+      if (IS_ERR(pll))
-+              goto err_pll;
-+
-+      if (clk_set_parent(gclk, pll)) {
-+              pr_debug("STK1000: failed to set pll0 as parent for DAC clock\n");
-+              goto err_set_clk;
-+      }
-+
-+      at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
-+      at73c213_data.dac_clk = gclk;
-+
-+err_set_clk:
-+      clk_put(pll);
-+err_pll:
-+      clk_put(gclk);
-+err_gclk:
-+      return;
-+}
-+#else
-+static void __init atstk1003_setup_extdac(void)
-+{
-+
-+}
-+#endif /* CONFIG_BOARD_ATSTK1000_EXTDAC */
-+
-+void __init setup_board(void)
-+{
-+#ifdef        CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-+      at32_map_usart(0, 1);   /* USART 0/B: /dev/ttyS1, IRDA */
-+#else
-+      at32_map_usart(1, 0);   /* USART 1/A: /dev/ttyS0, DB9 */
-+#endif
-+      /* USART 2/unused: expansion connector */
-+      at32_map_usart(3, 2);   /* USART 3/C: /dev/ttyS2, DB9 */
-+
-+      at32_setup_serial_console(0);
-+}
-+
-+static int __init atstk1003_init(void)
-+{
-+      /*
-+       * ATSTK1000 uses 32-bit SDRAM interface. Reserve the
-+       * SDRAM-specific pins so that nobody messes with them.
-+       */
-+      at32_reserve_pin(GPIO_PIN_PE(0));       /* DATA[16]     */
-+      at32_reserve_pin(GPIO_PIN_PE(1));       /* DATA[17]     */
-+      at32_reserve_pin(GPIO_PIN_PE(2));       /* DATA[18]     */
-+      at32_reserve_pin(GPIO_PIN_PE(3));       /* DATA[19]     */
-+      at32_reserve_pin(GPIO_PIN_PE(4));       /* DATA[20]     */
-+      at32_reserve_pin(GPIO_PIN_PE(5));       /* DATA[21]     */
-+      at32_reserve_pin(GPIO_PIN_PE(6));       /* DATA[22]     */
-+      at32_reserve_pin(GPIO_PIN_PE(7));       /* DATA[23]     */
-+      at32_reserve_pin(GPIO_PIN_PE(8));       /* DATA[24]     */
-+      at32_reserve_pin(GPIO_PIN_PE(9));       /* DATA[25]     */
-+      at32_reserve_pin(GPIO_PIN_PE(10));      /* DATA[26]     */
-+      at32_reserve_pin(GPIO_PIN_PE(11));      /* DATA[27]     */
-+      at32_reserve_pin(GPIO_PIN_PE(12));      /* DATA[28]     */
-+      at32_reserve_pin(GPIO_PIN_PE(13));      /* DATA[29]     */
-+      at32_reserve_pin(GPIO_PIN_PE(14));      /* DATA[30]     */
-+      at32_reserve_pin(GPIO_PIN_PE(15));      /* DATA[31]     */
-+      at32_reserve_pin(GPIO_PIN_PE(26));      /* SDCS         */
-+
-+      at32_add_system_devices();
-+
-+#ifdef        CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-+      at32_add_device_usart(1);
-+#else
-+      at32_add_device_usart(0);
-+#endif
-+      at32_add_device_usart(2);
-+
-+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
-+      at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
-+#endif
-+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
-+      at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
-+#endif
-+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+ #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
+ static void __init atstk1003_setup_extdac(void)
+ {
+@@ -147,12 +167,22 @@
+       at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
+ #endif
+ #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+-      at32_add_device_mci(0);
 +      at32_add_device_mci(0, NULL);
-+#endif
-+      at32_add_device_usba(0, NULL);
+ #endif
+       at32_add_device_usba(0, NULL);
 +#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_AC97
 +      at32_add_device_ac97c(0);
 +#else
 +      at32_add_device_abdac(0);
 +#endif
-+#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
-+      at32_add_device_ssc(0, ATMEL_SSC_TX);
-+#endif
+ #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
+       at32_add_device_ssc(0, ATMEL_SSC_TX);
+ #endif
 +      at32_add_device_cf(0, 2, &cf0_data);
 +#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_PSIF
 +      at32_add_device_psif(0);
 +      at32_add_device_psif(1);
 +#endif
-+
-+      atstk1000_setup_j2_leds();
-+      atstk1003_setup_extdac();
-+
-+      return 0;
-+}
-+postcore_initcall(atstk1003_init);
---- /dev/null
-+++ b/arch/avr32/boards/atstk1000/atstk1004.c
-@@ -0,0 +1,156 @@
-+/*
-+ * ATSTK1003 daughterboard-specific init code
-+ *
-+ * Copyright (C) 2007 Atmel Corporation
-+ *
-+ * 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/clk.h>
-+#include <linux/err.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/platform_device.h>
-+#include <linux/string.h>
-+#include <linux/types.h>
-+
-+#include <linux/spi/at73c213.h>
-+#include <linux/spi/spi.h>
-+
-+#include <video/atmel_lcdc.h>
-+
-+#include <asm/setup.h>
-+
-+#include <asm/arch/at32ap700x.h>
-+#include <asm/arch/board.h>
-+#include <asm/arch/init.h>
-+#include <asm/arch/portmux.h>
-+
-+#include "atstk1000.h"
-+
-+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
-+static struct at73c213_board_info at73c213_data = {
-+      .ssc_id         = 0,
-+      .shortname      = "AVR32 STK1000 external DAC",
-+};
-+#endif
-+
-+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
-+static struct spi_board_info spi0_board_info[] __initdata = {
-+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
-+      {
-+              /* AT73C213 */
-+              .modalias       = "at73c213",
-+              .max_speed_hz   = 200000,
-+              .chip_select    = 0,
-+              .mode           = SPI_MODE_1,
-+              .platform_data  = &at73c213_data,
-+      },
-+#endif
-+      {
-+              /* QVGA display */
-+              .modalias       = "ltv350qv",
-+              .max_speed_hz   = 16000000,
-+              .chip_select    = 1,
-+              .mode           = SPI_MODE_3,
-+      },
+       atstk1000_setup_j2_leds();
+       atstk1003_setup_extdac();
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/boards/atstk1000/atstk1004.c avr32-2.6/arch/avr32/boards/atstk1000/atstk1004.c
+--- linux-2.6.25.6/arch/avr32/boards/atstk1000/atstk1004.c     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/boards/atstk1000/atstk1004.c  2008-06-12 15:09:38.715815679 +0200
+@@ -29,6 +29,13 @@
+ #include "atstk1000.h"
++/* Oscillator frequencies. These are board specific */
++unsigned long at32_board_osc_rates[3] = {
++      [0] = 32768,    /* 32.768 kHz on RTC osc */
++      [1] = 20000000, /* 20 MHz on osc0 */
++      [2] = 12000000, /* 12 MHz on osc1 */
 +};
-+#endif
-+
-+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
-+static struct spi_board_info spi1_board_info[] __initdata = { {
-+      /* patch in custom entries here */
-+} };
-+#endif
-+
-+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
-+static void __init atstk1004_setup_extdac(void)
-+{
-+      struct clk *gclk;
-+      struct clk *pll;
-+
-+      gclk = clk_get(NULL, "gclk0");
-+      if (IS_ERR(gclk))
-+              goto err_gclk;
-+      pll = clk_get(NULL, "pll0");
-+      if (IS_ERR(pll))
-+              goto err_pll;
-+
-+      if (clk_set_parent(gclk, pll)) {
-+              pr_debug("STK1000: failed to set pll0 as parent for DAC clock\n");
-+              goto err_set_clk;
-+      }
-+
-+      at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
-+      at73c213_data.dac_clk = gclk;
-+
-+err_set_clk:
-+      clk_put(pll);
-+err_pll:
-+      clk_put(gclk);
-+err_gclk:
-+      return;
-+}
-+#else
-+static void __init atstk1004_setup_extdac(void)
-+{
-+
-+}
-+#endif /* CONFIG_BOARD_ATSTK1000_EXTDAC */
-+
-+void __init setup_board(void)
-+{
-+#ifdef        CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-+      at32_map_usart(0, 1);   /* USART 0/B: /dev/ttyS1, IRDA */
-+#else
-+      at32_map_usart(1, 0);   /* USART 1/A: /dev/ttyS0, DB9 */
-+#endif
-+      /* USART 2/unused: expansion connector */
-+      at32_map_usart(3, 2);   /* USART 3/C: /dev/ttyS2, DB9 */
-+
-+      at32_setup_serial_console(0);
-+}
-+
-+static int __init atstk1004_init(void)
-+{
-+      at32_add_system_devices();
-+
-+#ifdef        CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-+      at32_add_device_usart(1);
-+#else
-+      at32_add_device_usart(0);
-+#endif
-+      at32_add_device_usart(2);
 +
-+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
-+      at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
-+#endif
-+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
-+      at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
-+#endif
-+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+ #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
+ static struct at73c213_board_info at73c213_data = {
+       .ssc_id         = 0,
+@@ -130,14 +137,23 @@
+       at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
+ #endif
+ #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+-      at32_add_device_mci(0);
 +      at32_add_device_mci(0, NULL);
-+#endif
-+      at32_add_device_lcdc(0, &atstk1000_lcdc_data,
-+                           fbmem_start, fbmem_size);
-+      at32_add_device_usba(0, NULL);
+ #endif
+       at32_add_device_lcdc(0, &atstk1000_lcdc_data,
+-                           fbmem_start, fbmem_size);
++                           fbmem_start, fbmem_size, 0);
+       at32_add_device_usba(0, NULL);
 +#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_AC97
 +      at32_add_device_ac97c(0);
 +#else
 +      at32_add_device_abdac(0);
 +#endif
-+#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
-+      at32_add_device_ssc(0, ATMEL_SSC_TX);
-+#endif
+ #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
+       at32_add_device_ssc(0, ATMEL_SSC_TX);
+ #endif
 +#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_PSIF
 +      at32_add_device_psif(0);
 +      at32_add_device_psif(1);
 +#endif
-+
-+      atstk1000_setup_j2_leds();
-+      atstk1004_setup_extdac();
-+
-+      return 0;
-+}
-+postcore_initcall(atstk1004_init);
---- a/arch/avr32/boards/atstk1000/Kconfig
-+++ b/arch/avr32/boards/atstk1000/Kconfig
-@@ -1,34 +1,53 @@
- # STK1000 customization
  
--if BOARD_ATSTK1002
-+if BOARD_ATSTK1000
--config BOARD_ATSTK1002_CUSTOM
--      bool "Non-default STK-1002 jumper settings"
-+choice
-+      prompt "ATSTK1000 CPU daughterboard type"
-+      default BOARD_ATSTK1002
-+
-+config BOARD_ATSTK1002
-+      bool "ATSTK1002"
+       atstk1000_setup_j2_leds();
+       atstk1004_setup_extdac();
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/boards/atstk1000/Kconfig avr32-2.6/arch/avr32/boards/atstk1000/Kconfig
+--- linux-2.6.25.6/arch/avr32/boards/atstk1000/Kconfig 2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/boards/atstk1000/Kconfig      2008-06-12 15:09:38.711815728 +0200
+@@ -18,6 +18,10 @@
+       bool "ATSTK1004"
+       select CPU_AT32AP7002
++config BOARD_ATSTK1006
++      bool "ATSTK1006"
 +      select CPU_AT32AP7000
 +
-+config BOARD_ATSTK1003
-+      bool "ATSTK1003"
-+      select CPU_AT32AP7001
-+
-+config BOARD_ATSTK1004
-+      bool "ATSTK1004"
-+      select CPU_AT32AP7002
-+
-+endchoice
-+
-+
-+config BOARD_ATSTK100X_CUSTOM
-+      bool "Non-default STK1002/STK1003/STK1004 jumper settings"
-       help
-         You will normally leave the jumpers on the CPU card at their
-         default settings.  If you need to use certain peripherals,
-         you will need to change some of those jumpers.
--if BOARD_ATSTK1002_CUSTOM
-+if BOARD_ATSTK100X_CUSTOM
--config BOARD_ATSTK1002_SW1_CUSTOM
-+config BOARD_ATSTK100X_SW1_CUSTOM
-       bool "SW1: use SSC1 (not SPI0)"
-       help
-         This also prevents using the external DAC as an audio interface,
-         and means you can't initialize the on-board QVGA display.
--config BOARD_ATSTK1002_SW2_CUSTOM
-+config BOARD_ATSTK100X_SW2_CUSTOM
-       bool "SW2: use IRDA or TIMER0 (not UART-A, MMC/SD, and PS2-A)"
-       help
-         If you change this you'll want an updated boot loader putting
-         the console on UART-C not UART-A.
--config BOARD_ATSTK1002_SW3_CUSTOM
-+config BOARD_ATSTK100X_SW3_CUSTOM
-       bool "SW3: use TIMER1 (not SSC0 and GCLK)"
-       help
-         This also prevents using the external DAC as an audio interface.
--config BOARD_ATSTK1002_SW4_CUSTOM
-+config BOARD_ATSTK100X_SW4_CUSTOM
-       bool "SW4: use ISI/Camera (not GPIOs, SPI1, and PS2-B)"
-       help
-         To use the camera interface you'll need a custom card (on the
-@@ -36,27 +55,29 @@
- config BOARD_ATSTK1002_SW5_CUSTOM
-       bool "SW5: use MACB1 (not LCDC)"
-+      depends on BOARD_ATSTK1002
- config BOARD_ATSTK1002_SW6_CUSTOM
-       bool "SW6: more GPIOs (not MACB0)"
-+      depends on BOARD_ATSTK1002
- endif # custom
--config BOARD_ATSTK1002_SPI1
-+config BOARD_ATSTK100X_SPI1
-       bool "Configure SPI1 controller"
--      depends on !BOARD_ATSTK1002_SW4_CUSTOM
-+      depends on !BOARD_ATSTK100X_SW4_CUSTOM
-       help
-         All the signals for the second SPI controller are available on
-         GPIO lines and accessed through the J1 jumper block.  Say "y"
-         here to configure that SPI controller.
--config BOARD_ATSTK1002_J2_LED
-+config BOARD_ATSTK1000_J2_LED
-       bool
--      default BOARD_ATSTK1002_J2_LED8 || BOARD_ATSTK1002_J2_RGB
-+      default BOARD_ATSTK1000_J2_LED8 || BOARD_ATSTK1000_J2_RGB
- choice
-       prompt "LEDs connected to J2:"
--      depends on LEDS_GPIO && !BOARD_ATSTK1002_SW4_CUSTOM
-+      depends on LEDS_GPIO && !BOARD_ATSTK100X_SW4_CUSTOM
-       optional
-       help
-         Select this if you have jumpered the J2 jumper block to the
-@@ -64,16 +85,77 @@
-         IDC cable.  A default "heartbeat" trigger is provided, but
-         you can of course override this.
--config BOARD_ATSTK1002_J2_LED8
-+config BOARD_ATSTK1000_J2_LED8
-       bool "LED0..LED7"
-       help
-         Select this if J2 is jumpered to LED0..LED7 amber leds.
+ endchoice
  
--config BOARD_ATSTK1002_J2_RGB
-+config BOARD_ATSTK1000_J2_RGB
-       bool "RGB leds"
-       help
-         Select this if J2 is jumpered to the RGB leds.
  
- endchoice
+@@ -102,4 +106,60 @@
+       depends on !BOARD_ATSTK100X_SW1_CUSTOM && !BOARD_ATSTK100X_SW3_CUSTOM
+       default y
  
--endif # stk 1002
-+config BOARD_ATSTK1000_EXTDAC
-+      bool
-+      depends on !BOARD_ATSTK100X_SW1_CUSTOM && !BOARD_ATSTK100X_SW3_CUSTOM
-+      default y
-+
 +config BOARD_ATSTK100X_ENABLE_AC97
 +      bool "Use AC97C instead of ABDAC"
 +      help
 +        Y if you have level convertion hardware or a PS/2 device capable of
 +        operating on 3.3 volt.
 +
-+endif # stk 1000
---- a/arch/avr32/boards/atstk1000/Makefile
-+++ b/arch/avr32/boards/atstk1000/Makefile
-@@ -1,2 +1,4 @@
- obj-y                         += setup.o flash.o
+ endif # stk 1000
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/boards/atstk1000/Makefile avr32-2.6/arch/avr32/boards/atstk1000/Makefile
+--- linux-2.6.25.6/arch/avr32/boards/atstk1000/Makefile        2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/boards/atstk1000/Makefile     2008-06-12 15:09:38.711815728 +0200
+@@ -2,3 +2,4 @@
  obj-$(CONFIG_BOARD_ATSTK1002) += atstk1002.o
-+obj-$(CONFIG_BOARD_ATSTK1003) += atstk1003.o
-+obj-$(CONFIG_BOARD_ATSTK1004) += atstk1004.o
---- a/arch/avr32/boards/atstk1000/setup.c
-+++ b/arch/avr32/boards/atstk1000/setup.c
-@@ -10,13 +10,17 @@
- #include <linux/bootmem.h>
- #include <linux/fb.h>
- #include <linux/init.h>
-+#include <linux/platform_device.h>
- #include <linux/types.h>
- #include <linux/linkage.h>
- #include <video/atmel_lcdc.h>
- #include <asm/setup.h>
-+
-+#include <asm/arch/at32ap700x.h>
- #include <asm/arch/board.h>
-+#include <asm/arch/portmux.h>
- #include "atstk1000.h"
-@@ -61,3 +65,63 @@
-       .default_monspecs       = &atstk1000_default_monspecs,
-       .guard_time             = 2,
- };
-+
-+#ifdef CONFIG_BOARD_ATSTK1000_J2_LED
-+#include <linux/leds.h>
-+
-+static struct gpio_led stk1000_j2_led[] = {
-+#ifdef CONFIG_BOARD_ATSTK1000_J2_LED8
-+#define LEDSTRING "J2 jumpered to LED8"
-+      { .name = "led0:amber", .gpio = GPIO_PIN_PB( 8), },
-+      { .name = "led1:amber", .gpio = GPIO_PIN_PB( 9), },
-+      { .name = "led2:amber", .gpio = GPIO_PIN_PB(10), },
-+      { .name = "led3:amber", .gpio = GPIO_PIN_PB(13), },
-+      { .name = "led4:amber", .gpio = GPIO_PIN_PB(14), },
-+      { .name = "led5:amber", .gpio = GPIO_PIN_PB(15), },
-+      { .name = "led6:amber", .gpio = GPIO_PIN_PB(16), },
-+      { .name = "led7:amber", .gpio = GPIO_PIN_PB(30),
-+                      .default_trigger = "heartbeat", },
-+#else /* RGB */
-+#define LEDSTRING "J2 jumpered to RGB LEDs"
-+      { .name = "r1:red",     .gpio = GPIO_PIN_PB( 8), },
-+      { .name = "g1:green",   .gpio = GPIO_PIN_PB(10), },
-+      { .name = "b1:blue",    .gpio = GPIO_PIN_PB(14), },
-+
-+      { .name = "r2:red",     .gpio = GPIO_PIN_PB( 9),
-+                      .default_trigger = "heartbeat", },
-+      { .name = "g2:green",   .gpio = GPIO_PIN_PB(13), },
-+      { .name = "b2:blue",    .gpio = GPIO_PIN_PB(15),
-+                      .default_trigger = "heartbeat", },
-+      /* PB16, PB30 unused */
-+#endif
-+};
-+
-+static struct gpio_led_platform_data stk1000_j2_led_data = {
-+      .num_leds       = ARRAY_SIZE(stk1000_j2_led),
-+      .leds           = stk1000_j2_led,
-+};
-+
-+static struct platform_device stk1000_j2_led_dev = {
-+      .name           = "leds-gpio",
-+      .id             = 2,    /* gpio block J2 */
-+      .dev            = {
-+              .platform_data  = &stk1000_j2_led_data,
-+      },
-+};
-+
-+void __init atstk1000_setup_j2_leds(void)
-+{
-+      unsigned        i;
-+
-+      for (i = 0; i < ARRAY_SIZE(stk1000_j2_led); i++)
-+              at32_select_gpio(stk1000_j2_led[i].gpio, AT32_GPIOF_OUTPUT);
-+
-+      printk("STK1000: " LEDSTRING "\n");
-+      platform_device_register(&stk1000_j2_led_dev);
-+}
-+#else /* CONFIG_BOARD_ATSTK1000_J2_LED */
-+void __init atstk1000_setup_j2_leds(void)
-+{
-+
-+}
-+#endif /* CONFIG_BOARD_ATSTK1000_J2_LED */
---- a/arch/avr32/configs/atngw100_defconfig
-+++ b/arch/avr32/configs/atngw100_defconfig
-@@ -1,46 +1,52 @@
+ obj-$(CONFIG_BOARD_ATSTK1003) += atstk1003.o
+ obj-$(CONFIG_BOARD_ATSTK1004) += atstk1004.o
++obj-$(CONFIG_BOARD_ATSTK1006) += atstk1002.o
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/configs/atngw100_defconfig avr32-2.6/arch/avr32/configs/atngw100_defconfig
+--- linux-2.6.25.6/arch/avr32/configs/atngw100_defconfig       2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/configs/atngw100_defconfig    2008-06-12 15:09:38.715815679 +0200
+@@ -1,7 +1,7 @@
  #
  # Automatically generated make config: don't edit
--# Linux kernel version: 2.6.22-rc5
--# Sat Jun 23 15:40:05 2007
-+# Linux kernel version: 2.6.24
-+# Thu Mar  6 12:49:54 2008
+-# Linux kernel version: 2.6.24-rc7
+-# Wed Jan  9 23:20:41 2008
++# Linux kernel version: 2.6.25.4
++# Wed Jun 11 15:23:36 2008
  #
  CONFIG_AVR32=y
  CONFIG_GENERIC_GPIO=y
- CONFIG_GENERIC_HARDIRQS=y
-+CONFIG_STACKTRACE_SUPPORT=y
-+CONFIG_LOCKDEP_SUPPORT=y
-+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
- CONFIG_HARDIRQS_SW_RESEND=y
+@@ -13,10 +13,10 @@
  CONFIG_GENERIC_IRQ_PROBE=y
  CONFIG_RWSEM_GENERIC_SPINLOCK=y
  CONFIG_GENERIC_TIME=y
 +CONFIG_GENERIC_CLOCKEVENTS=y
-+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+ # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
  # CONFIG_ARCH_HAS_ILOG2_U32 is not set
  # CONFIG_ARCH_HAS_ILOG2_U64 is not set
-+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+-CONFIG_ARCH_SUPPORTS_OPROFILE=y
  CONFIG_GENERIC_HWEIGHT=y
  CONFIG_GENERIC_CALIBRATE_DELAY=y
  CONFIG_GENERIC_BUG=y
- CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
- #
--# Code maturity level options
-+# General setup
- #
- CONFIG_EXPERIMENTAL=y
- CONFIG_BROKEN_ON_SMP=y
- CONFIG_INIT_ENV_ARG_LIMIT=32
--
--#
--# General setup
--#
- CONFIG_LOCALVERSION=""
- # CONFIG_LOCALVERSION_AUTO is not set
- CONFIG_SWAP=y
- CONFIG_SYSVIPC=y
--# CONFIG_IPC_NS is not set
- CONFIG_SYSVIPC_SYSCTL=y
- CONFIG_POSIX_MQUEUE=y
+@@ -37,17 +37,15 @@
  CONFIG_BSD_PROCESS_ACCT=y
  CONFIG_BSD_PROCESS_ACCT_V3=y
  # CONFIG_TASKSTATS is not set
--# CONFIG_UTS_NS is not set
-+# CONFIG_USER_NS is not set
-+# CONFIG_PID_NS is not set
+-# CONFIG_USER_NS is not set
+-# CONFIG_PID_NS is not set
  # CONFIG_AUDIT is not set
  # CONFIG_IKCONFIG is not set
  CONFIG_LOG_BUF_SHIFT=14
-+# CONFIG_CGROUPS is not set
-+CONFIG_FAIR_GROUP_SCHED=y
-+CONFIG_FAIR_USER_SCHED=y
-+# CONFIG_FAIR_CGROUP_SCHED is not set
+ # CONFIG_CGROUPS is not set
+-CONFIG_FAIR_GROUP_SCHED=y
+-CONFIG_FAIR_USER_SCHED=y
+-# CONFIG_FAIR_CGROUP_SCHED is not set
++# CONFIG_GROUP_SCHED is not set
  CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
  # CONFIG_RELAY is not set
++# CONFIG_NAMESPACES is not set
  CONFIG_BLK_DEV_INITRD=y
-@@ -61,35 +67,28 @@
+ CONFIG_INITRAMFS_SOURCE=""
+ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+@@ -61,11 +59,13 @@
+ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
++# CONFIG_COMPAT_BRK is not set
+ # CONFIG_BASE_FULL is not set
+ CONFIG_FUTEX=y
  CONFIG_ANON_INODES=y
  CONFIG_EPOLL=y
  CONFIG_SIGNALFD=y
--CONFIG_TIMERFD=y
++CONFIG_TIMERFD=y
  CONFIG_EVENTFD=y
  CONFIG_SHMEM=y
  CONFIG_VM_EVENT_COUNTERS=y
--# CONFIG_SLUB_DEBUG is not set
-+CONFIG_SLUB_DEBUG=y
+@@ -73,6 +73,14 @@
  # CONFIG_SLAB is not set
  CONFIG_SLUB=y
  # CONFIG_SLOB is not set
-+CONFIG_SLABINFO=y
++CONFIG_PROFILING=y
++# CONFIG_MARKERS is not set
++CONFIG_OPROFILE=m
++CONFIG_HAVE_OPROFILE=y
++CONFIG_KPROBES=y
++CONFIG_HAVE_KPROBES=y
++# CONFIG_HAVE_KRETPROBES is not set
++CONFIG_PROC_PAGE_MONITOR=y
+ CONFIG_SLABINFO=y
  CONFIG_RT_MUTEXES=y
  # CONFIG_TINY_SHMEM is not set
- CONFIG_BASE_SMALL=1
--
--#
--# Loadable module support
--#
- CONFIG_MODULES=y
- CONFIG_MODULE_UNLOAD=y
- CONFIG_MODULE_FORCE_UNLOAD=y
- # CONFIG_MODVERSIONS is not set
- # CONFIG_MODULE_SRCVERSION_ALL is not set
- CONFIG_KMOD=y
--
--#
--# Block layer
--#
- CONFIG_BLOCK=y
- # CONFIG_LBD is not set
- # CONFIG_BLK_DEV_IO_TRACE is not set
- # CONFIG_LSF is not set
-+# CONFIG_BLK_DEV_BSG is not set
+@@ -101,10 +109,15 @@
+ CONFIG_DEFAULT_CFQ=y
+ # CONFIG_DEFAULT_NOOP is not set
+ CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_CLASSIC_RCU=y
  
- #
- # IO Schedulers
-@@ -107,21 +106,28 @@
  #
  # System Type and features
  #
  CONFIG_SUBARCH_AVR32B=y
  CONFIG_MMU=y
  CONFIG_PERFORMANCE_COUNTERS=y
- CONFIG_PLATFORM_AT32AP=y
-+CONFIG_CPU_AT32AP700X=y
+@@ -113,6 +126,7 @@
  CONFIG_CPU_AT32AP7000=y
  # CONFIG_BOARD_ATSTK1000 is not set
  CONFIG_BOARD_ATNGW100=y
  CONFIG_LOADER_U_BOOT=y
  
  #
- # Atmel AVR32 AP options
- #
--# CONFIG_AP7000_32_BIT_SMC is not set
--CONFIG_AP7000_16_BIT_SMC=y
--# CONFIG_AP7000_8_BIT_SMC is not set
-+# CONFIG_AP700X_32_BIT_SMC is not set
-+CONFIG_AP700X_16_BIT_SMC=y
-+# CONFIG_AP700X_8_BIT_SMC is not set
+@@ -121,6 +135,7 @@
+ # CONFIG_AP700X_32_BIT_SMC is not set
+ CONFIG_AP700X_16_BIT_SMC=y
+ # CONFIG_AP700X_8_BIT_SMC is not set
 +CONFIG_GPIO_DEV=y
  CONFIG_LOAD_ADDRESS=0x10000000
  CONFIG_ENTRY_ADDRESS=0x90000000
  CONFIG_PHYS_OFFSET=0x10000000
-@@ -141,10 +147,14 @@
- CONFIG_FLATMEM=y
- CONFIG_FLAT_NODE_MEM_MAP=y
- # CONFIG_SPARSEMEM_STATIC is not set
-+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
- CONFIG_SPLIT_PTLOCK_CPUS=4
- # CONFIG_RESOURCES_64BIT is not set
+@@ -146,16 +161,26 @@
  CONFIG_ZONE_DMA_FLAG=0
-+CONFIG_VIRT_TO_BUS=y
+ CONFIG_VIRT_TO_BUS=y
  # CONFIG_OWNERSHIP_TRACE is not set
-+# CONFIG_NMI_DEBUGGING is not set
++CONFIG_NMI_DEBUGGING=y
 +CONFIG_DW_DMAC=y
  # CONFIG_HZ_100 is not set
  CONFIG_HZ_250=y
  # CONFIG_HZ_300 is not set
-@@ -153,13 +163,31 @@
+ # CONFIG_HZ_1000 is not set
+ CONFIG_HZ=250
++# CONFIG_SCHED_HRTICK is not set
  CONFIG_CMDLINE=""
  
  #
--# Bus options
-+# Power management options
- #
--# CONFIG_ARCH_SUPPORTS_MSI is not set
- #
--# PCCARD (PCMCIA/CardBus) support
-+# CPU Frequency scaling
-+#
-+CONFIG_CPU_FREQ=y
-+CONFIG_CPU_FREQ_TABLE=y
-+# CONFIG_CPU_FREQ_DEBUG is not set
-+# CONFIG_CPU_FREQ_STAT is not set
-+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
-+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
-+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
-+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
-+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
-+CONFIG_CPU_FREQ_GOV_USERSPACE=y
-+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
-+CONFIG_CPU_FREQ_AT32AP=y
-+
-+#
-+# Bus options
+ # Power management options
  #
-+# CONFIG_ARCH_SUPPORTS_MSI is not set
- # CONFIG_PCCARD is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_PM=y
++# CONFIG_PM_LEGACY is not set
++# CONFIG_PM_DEBUG is not set
++CONFIG_PM_SLEEP=y
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
  
  #
-@@ -213,6 +241,7 @@
- CONFIG_INET_XFRM_MODE_TRANSPORT=y
- CONFIG_INET_XFRM_MODE_TUNNEL=y
- CONFIG_INET_XFRM_MODE_BEET=y
-+# CONFIG_INET_LRO is not set
- CONFIG_INET_DIAG=y
- CONFIG_INET_TCP_DIAG=y
- # CONFIG_TCP_CONG_ADVANCED is not set
-@@ -240,6 +269,7 @@
+ # CPU Frequency scaling
+@@ -164,9 +189,9 @@
+ CONFIG_CPU_FREQ_TABLE=y
+ # CONFIG_CPU_FREQ_DEBUG is not set
+ # CONFIG_CPU_FREQ_STAT is not set
+-CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+ # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+-# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+ # CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+ # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+@@ -202,6 +227,7 @@
+ CONFIG_XFRM_USER=y
+ # CONFIG_XFRM_SUB_POLICY is not set
+ # CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
+ CONFIG_NET_KEY=y
+ # CONFIG_NET_KEY_MIGRATE is not set
+ CONFIG_INET=y
+@@ -260,82 +286,33 @@
  # CONFIG_NETWORK_SECMARK is not set
  CONFIG_NETFILTER=y
  # CONFIG_NETFILTER_DEBUG is not set
-+CONFIG_BRIDGE_NETFILTER=y
+-CONFIG_BRIDGE_NETFILTER=y
++# CONFIG_NETFILTER_ADVANCED is not set
  
  #
  # Core Netfilter Configuration
-@@ -252,6 +282,7 @@
- # CONFIG_NF_CONNTRACK_EVENTS is not set
- CONFIG_NF_CT_PROTO_GRE=m
- # CONFIG_NF_CT_PROTO_SCTP is not set
-+# CONFIG_NF_CT_PROTO_UDPLITE is not set
- CONFIG_NF_CONNTRACK_AMANDA=m
+ #
+-# CONFIG_NETFILTER_NETLINK is not set
+-CONFIG_NF_CONNTRACK_ENABLED=m
++CONFIG_NETFILTER_NETLINK=m
++CONFIG_NETFILTER_NETLINK_LOG=m
+ CONFIG_NF_CONNTRACK=m
+-CONFIG_NF_CT_ACCT=y
+-CONFIG_NF_CONNTRACK_MARK=y
+-# CONFIG_NF_CONNTRACK_EVENTS is not set
+-CONFIG_NF_CT_PROTO_GRE=m
+-# CONFIG_NF_CT_PROTO_SCTP is not set
+-# CONFIG_NF_CT_PROTO_UDPLITE is not set
+-CONFIG_NF_CONNTRACK_AMANDA=m
  CONFIG_NF_CONNTRACK_FTP=m
- CONFIG_NF_CONNTRACK_H323=m
-@@ -269,9 +300,11 @@
- CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+-CONFIG_NF_CONNTRACK_H323=m
+ CONFIG_NF_CONNTRACK_IRC=m
+-CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+-CONFIG_NF_CONNTRACK_PPTP=m
+-CONFIG_NF_CONNTRACK_SANE=m
+ CONFIG_NF_CONNTRACK_SIP=m
+-CONFIG_NF_CONNTRACK_TFTP=m
++CONFIG_NF_CT_NETLINK=m
+ CONFIG_NETFILTER_XTABLES=y
+-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+-# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
+-# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+ CONFIG_NETFILTER_XT_TARGET_MARK=m
+-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
  CONFIG_NETFILTER_XT_TARGET_NFLOG=m
- # CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
-+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+-# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+-# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
  CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
- CONFIG_NETFILTER_XT_MATCH_COMMENT=m
- CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
- CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+-CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+-CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+-# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
+-CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
  CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
- # CONFIG_NETFILTER_XT_MATCH_DCCP is not set
-@@ -284,6 +317,7 @@
+-# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+-# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+-CONFIG_NETFILTER_XT_MATCH_ESP=m
+-CONFIG_NETFILTER_XT_MATCH_HELPER=m
+-CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+-CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+-CONFIG_NETFILTER_XT_MATCH_MAC=m
  CONFIG_NETFILTER_XT_MATCH_MARK=m
  CONFIG_NETFILTER_XT_MATCH_POLICY=m
- CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
- CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
- CONFIG_NETFILTER_XT_MATCH_QUOTA=m
- CONFIG_NETFILTER_XT_MATCH_REALM=m
-@@ -292,6 +326,8 @@
- CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
- CONFIG_NETFILTER_XT_MATCH_STRING=m
- CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
-+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
- CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+-# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+-CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+-CONFIG_NETFILTER_XT_MATCH_REALM=m
+-# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+ CONFIG_NETFILTER_XT_MATCH_STATE=m
+-CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+-CONFIG_NETFILTER_XT_MATCH_STRING=m
+-CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+-# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+-# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+ #
+ # IP: Netfilter Configuration
+ #
+ CONFIG_NF_CONNTRACK_IPV4=m
+ CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+-# CONFIG_IP_NF_QUEUE is not set
+ CONFIG_IP_NF_IPTABLES=m
+-CONFIG_IP_NF_MATCH_IPRANGE=m
+-CONFIG_IP_NF_MATCH_TOS=m
+-CONFIG_IP_NF_MATCH_RECENT=m
+-CONFIG_IP_NF_MATCH_ECN=m
+-CONFIG_IP_NF_MATCH_AH=m
+-CONFIG_IP_NF_MATCH_TTL=m
+-CONFIG_IP_NF_MATCH_OWNER=m
+-CONFIG_IP_NF_MATCH_ADDRTYPE=m
+ CONFIG_IP_NF_FILTER=m
+ CONFIG_IP_NF_TARGET_REJECT=m
+ CONFIG_IP_NF_TARGET_LOG=m
+@@ -343,54 +320,25 @@
+ CONFIG_NF_NAT=m
+ CONFIG_NF_NAT_NEEDED=y
+ CONFIG_IP_NF_TARGET_MASQUERADE=m
+-CONFIG_IP_NF_TARGET_REDIRECT=m
+-CONFIG_IP_NF_TARGET_NETMAP=m
+-CONFIG_IP_NF_TARGET_SAME=m
+-CONFIG_NF_NAT_SNMP_BASIC=m
+-CONFIG_NF_NAT_PROTO_GRE=m
+ CONFIG_NF_NAT_FTP=m
+ CONFIG_NF_NAT_IRC=m
+-CONFIG_NF_NAT_TFTP=m
+-CONFIG_NF_NAT_AMANDA=m
+-CONFIG_NF_NAT_PPTP=m
+-CONFIG_NF_NAT_H323=m
++# CONFIG_NF_NAT_TFTP is not set
++# CONFIG_NF_NAT_AMANDA is not set
++# CONFIG_NF_NAT_PPTP is not set
++# CONFIG_NF_NAT_H323 is not set
+ CONFIG_NF_NAT_SIP=m
+ CONFIG_IP_NF_MANGLE=m
+-CONFIG_IP_NF_TARGET_TOS=m
+-CONFIG_IP_NF_TARGET_ECN=m
+-CONFIG_IP_NF_TARGET_TTL=m
+-CONFIG_IP_NF_TARGET_CLUSTERIP=m
+-CONFIG_IP_NF_RAW=m
+-CONFIG_IP_NF_ARPTABLES=m
+-CONFIG_IP_NF_ARPFILTER=m
+-CONFIG_IP_NF_ARP_MANGLE=m
  
  #
-@@ -359,13 +395,19 @@
+-# IPv6: Netfilter Configuration (EXPERIMENTAL)
++# IPv6: Netfilter Configuration
+ #
+ CONFIG_NF_CONNTRACK_IPV6=m
+-CONFIG_IP6_NF_QUEUE=m
+ CONFIG_IP6_NF_IPTABLES=m
+-CONFIG_IP6_NF_MATCH_RT=m
+-CONFIG_IP6_NF_MATCH_OPTS=m
+-CONFIG_IP6_NF_MATCH_FRAG=m
+-CONFIG_IP6_NF_MATCH_HL=m
+-CONFIG_IP6_NF_MATCH_OWNER=m
+ CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+-CONFIG_IP6_NF_MATCH_AH=m
+-CONFIG_IP6_NF_MATCH_MH=m
+-CONFIG_IP6_NF_MATCH_EUI64=m
+ CONFIG_IP6_NF_FILTER=m
+ CONFIG_IP6_NF_TARGET_LOG=m
+ CONFIG_IP6_NF_TARGET_REJECT=m
  CONFIG_IP6_NF_MANGLE=m
- CONFIG_IP6_NF_TARGET_HL=m
- CONFIG_IP6_NF_RAW=m
-+
-+#
-+# Bridge: Netfilter Configuration
-+#
-+# CONFIG_BRIDGE_NF_EBTABLES is not set
+-CONFIG_IP6_NF_TARGET_HL=m
+-CONFIG_IP6_NF_RAW=m
+-
+-#
+-# Bridge: Netfilter Configuration
+-#
+-# CONFIG_BRIDGE_NF_EBTABLES is not set
  # CONFIG_IP_DCCP is not set
  # CONFIG_IP_SCTP is not set
  # CONFIG_TIPC is not set
- # CONFIG_ATM is not set
--# CONFIG_BRIDGE is not set
-+CONFIG_BRIDGE=m
- CONFIG_VLAN_8021Q=m
- # CONFIG_DECNET is not set
-+CONFIG_LLC=m
- # CONFIG_LLC2 is not set
- # CONFIG_IPX is not set
- # CONFIG_ATALK is not set
-@@ -373,10 +415,6 @@
- # CONFIG_LAPB is not set
+@@ -407,7 +355,6 @@
  # CONFIG_ECONET is not set
  # CONFIG_WAN_ROUTER is not set
--
--#
--# QoS and/or fair queueing
--#
  # CONFIG_NET_SCHED is not set
- CONFIG_NET_CLS_ROUTE=y
+-CONFIG_NET_CLS_ROUTE=y
  
-@@ -384,6 +422,7 @@
- # Network testing
  #
+ # Network testing
+@@ -415,6 +362,7 @@
  # CONFIG_NET_PKTGEN is not set
-+# CONFIG_NET_TCPPROBE is not set
+ # CONFIG_NET_TCPPROBE is not set
  # CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
  # CONFIG_IRDA is not set
  # CONFIG_BT is not set
-@@ -397,6 +436,7 @@
- # CONFIG_MAC80211 is not set
- # CONFIG_IEEE80211 is not set
- # CONFIG_RFKILL is not set
-+# CONFIG_NET_9P is not set
- #
- # Device Drivers
-@@ -405,16 +445,13 @@
- #
- # Generic Driver Options
- #
-+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
- CONFIG_STANDALONE=y
- # CONFIG_PREVENT_FIRMWARE_BUILD is not set
- # CONFIG_FW_LOADER is not set
- # CONFIG_DEBUG_DRIVER is not set
- # CONFIG_DEBUG_DEVRES is not set
- # CONFIG_SYS_HYPERVISOR is not set
--
--#
--# Connector - unified userspace <-> kernelspace linker
--#
- # CONFIG_CONNECTOR is not set
- CONFIG_MTD=y
- # CONFIG_MTD_DEBUG is not set
-@@ -434,6 +471,7 @@
- # CONFIG_INFTL is not set
- # CONFIG_RFD_FTL is not set
- # CONFIG_SSFDC is not set
-+# CONFIG_MTD_OOPS is not set
- #
- # RAM/ROM/Flash chip drivers
-@@ -493,20 +531,8 @@
- # UBI - Unsorted block images
- #
- # CONFIG_MTD_UBI is not set
--
--#
--# Parallel port support
--#
- # CONFIG_PARPORT is not set
--
--#
--# Plug and Play support
--#
--# CONFIG_PNPACPI is not set
--
--#
--# Block devices
--#
-+CONFIG_BLK_DEV=y
- # CONFIG_BLK_DEV_COW_COMMON is not set
- CONFIG_BLK_DEV_LOOP=m
- # CONFIG_BLK_DEV_CRYPTOLOOP is not set
-@@ -517,11 +543,13 @@
- CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+ # CONFIG_AF_RXRPC is not set
+@@ -531,11 +479,18 @@
+ CONFIG_BLK_DEV_RAM=m
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=4096
+-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
++# CONFIG_BLK_DEV_XIP is not set
  # CONFIG_CDROM_PKTCDVD is not set
  # CONFIG_ATA_OVER_ETH is not set
--
--#
--# Misc devices
--#
--# CONFIG_BLINK is not set
+-# CONFIG_MISC_DEVICES is not set
+-# CONFIG_IDE is not set
 +CONFIG_MISC_DEVICES=y
 +# CONFIG_ATMEL_PWM is not set
 +CONFIG_ATMEL_TCLIB=y
 +CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0
 +# CONFIG_EEPROM_93CX6 is not set
 +# CONFIG_ATMEL_SSC is not set
- # CONFIG_IDE is not set
- #
-@@ -529,30 +557,42 @@
- #
- # CONFIG_RAID_ATTRS is not set
- # CONFIG_SCSI is not set
-+# CONFIG_SCSI_DMA is not set
- # CONFIG_SCSI_NETLINK is not set
- # CONFIG_ATA is not set
--
--#
--# Multi-device support (RAID and LVM)
--#
- # CONFIG_MD is not set
--
--#
--# Network device support
--#
- CONFIG_NETDEVICES=y
-+# CONFIG_NETDEVICES_MULTIQUEUE is not set
- # CONFIG_DUMMY is not set
- # CONFIG_BONDING is not set
-+# CONFIG_MACVLAN is not set
- # CONFIG_EQUALIZER is not set
- CONFIG_TUN=m
--# CONFIG_PHYLIB is not set
-+# CONFIG_VETH is not set
-+CONFIG_PHYLIB=y
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_HAVE_IDE is not set
  
  #
--# Ethernet (10 or 100Mbit)
-+# MII PHY device drivers
- #
-+# CONFIG_MARVELL_PHY is not set
-+# CONFIG_DAVICOM_PHY is not set
-+# CONFIG_QSEMI_PHY is not set
-+# CONFIG_LXT_PHY is not set
-+# CONFIG_CICADA_PHY is not set
-+# CONFIG_VITESSE_PHY is not set
-+# CONFIG_SMSC_PHY is not set
-+# CONFIG_BROADCOM_PHY is not set
-+# CONFIG_ICPLUS_PHY is not set
-+# CONFIG_FIXED_PHY is not set
-+# CONFIG_MDIO_BITBANG is not set
+ # SCSI device support
+@@ -568,11 +523,13 @@
+ # CONFIG_SMSC_PHY is not set
+ # CONFIG_BROADCOM_PHY is not set
+ # CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
+ # CONFIG_FIXED_PHY is not set
+ # CONFIG_MDIO_BITBANG is not set
  CONFIG_NET_ETHERNET=y
--CONFIG_MII=y
-+# CONFIG_MII is not set
+ # CONFIG_MII is not set
  CONFIG_MACB=y
-+# CONFIG_IBM_NEW_EMAC_ZMII is not set
-+# CONFIG_IBM_NEW_EMAC_RGMII is not set
-+# CONFIG_IBM_NEW_EMAC_TAH is not set
-+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
-+# CONFIG_B44 is not set
- # CONFIG_NETDEV_1000 is not set
- # CONFIG_NETDEV_10000 is not set
-@@ -571,21 +611,14 @@
- CONFIG_PPP_BSDCOMP=m
- CONFIG_PPP_MPPE=m
- CONFIG_PPPOE=m
-+# CONFIG_PPPOL2TP is not set
++# CONFIG_ENC28J60 is not set
+ # CONFIG_IBM_NEW_EMAC_ZMII is not set
+ # CONFIG_IBM_NEW_EMAC_RGMII is not set
+ # CONFIG_IBM_NEW_EMAC_TAH is not set
+@@ -599,7 +556,6 @@
+ # CONFIG_PPPOL2TP is not set
  # CONFIG_SLIP is not set
  CONFIG_SLHC=m
- # CONFIG_SHAPER is not set
+-# CONFIG_SHAPER is not set
  # CONFIG_NETCONSOLE is not set
  # CONFIG_NETPOLL is not set
  # CONFIG_NET_POLL_CONTROLLER is not set
--
--#
--# ISDN subsystem
--#
- # CONFIG_ISDN is not set
--
--#
--# Telephony Support
--#
- # CONFIG_PHONE is not set
- #
-@@ -615,28 +648,57 @@
+@@ -633,6 +589,7 @@
  #
  CONFIG_SERIAL_ATMEL=y
  CONFIG_SERIAL_ATMEL_CONSOLE=y
  # CONFIG_SERIAL_ATMEL_TTYAT is not set
  CONFIG_SERIAL_CORE=y
  CONFIG_SERIAL_CORE_CONSOLE=y
- CONFIG_UNIX98_PTYS=y
+@@ -640,8 +597,6 @@
  # CONFIG_LEGACY_PTYS is not set
--
--#
--# IPMI
--#
  # CONFIG_IPMI_HANDLER is not set
--# CONFIG_WATCHDOG is not set
  # CONFIG_HW_RANDOM is not set
- # CONFIG_RTC is not set
- # CONFIG_GEN_RTC is not set
+-# CONFIG_RTC is not set
+-# CONFIG_GEN_RTC is not set
  # CONFIG_R3964 is not set
  # CONFIG_RAW_DRIVER is not set
--
--#
--# TPM devices
--#
  # CONFIG_TCG_TPM is not set
--# CONFIG_I2C is not set
-+CONFIG_I2C=m
-+CONFIG_I2C_BOARDINFO=y
-+CONFIG_I2C_CHARDEV=m
-+
-+#
-+# I2C Algorithms
-+#
-+CONFIG_I2C_ALGOBIT=m
-+# CONFIG_I2C_ALGOPCF is not set
-+# CONFIG_I2C_ALGOPCA is not set
+@@ -659,6 +614,7 @@
+ #
+ # I2C Hardware Bus support
+ #
++CONFIG_I2C_ATMELTWI=m
+ CONFIG_I2C_GPIO=m
+ # CONFIG_I2C_OCORES is not set
+ # CONFIG_I2C_PARPORT_LIGHT is not set
+@@ -669,13 +625,12 @@
+ #
+ # Miscellaneous I2C Chip support
+ #
+-# CONFIG_SENSORS_DS1337 is not set
+-# CONFIG_SENSORS_DS1374 is not set
+ # CONFIG_DS1682 is not set
+ # CONFIG_SENSORS_EEPROM is not set
+ # CONFIG_SENSORS_PCF8574 is not set
+-# CONFIG_SENSORS_PCA9539 is not set
++# CONFIG_PCF8575 is not set
+ # CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_TPS65010 is not set
+ # CONFIG_SENSORS_MAX6875 is not set
+ # CONFIG_SENSORS_TSL2550 is not set
+ # CONFIG_I2C_DEBUG_CORE is not set
+@@ -702,9 +657,27 @@
+ # CONFIG_SPI_AT25 is not set
+ CONFIG_SPI_SPIDEV=m
+ # CONFIG_SPI_TLE62X0 is not set
++CONFIG_HAVE_GPIO_LIB=y
 +
 +#
-+# I2C Hardware Bus support
++# GPIO Support
 +#
-+CONFIG_I2C_ATMELTWI=m
-+CONFIG_I2C_GPIO=m
-+# CONFIG_I2C_OCORES is not set
-+# CONFIG_I2C_PARPORT_LIGHT is not set
-+# CONFIG_I2C_SIMTEC is not set
-+# CONFIG_I2C_TAOS_EVM is not set
-+# CONFIG_I2C_STUB is not set
++# CONFIG_DEBUG_GPIO is not set
 +
 +#
-+# Miscellaneous I2C Chip support
++# I2C GPIO expanders:
 +#
-+# CONFIG_SENSORS_DS1337 is not set
-+# CONFIG_SENSORS_DS1374 is not set
-+# CONFIG_DS1682 is not set
-+# CONFIG_SENSORS_EEPROM is not set
-+# CONFIG_SENSORS_PCF8574 is not set
-+# CONFIG_SENSORS_PCA9539 is not set
-+# CONFIG_SENSORS_PCF8591 is not set
-+# CONFIG_SENSORS_MAX6875 is not set
-+# CONFIG_SENSORS_TSL2550 is not set
-+# CONFIG_I2C_DEBUG_CORE is not set
-+# CONFIG_I2C_DEBUG_ALGO is not set
-+# CONFIG_I2C_DEBUG_BUS is not set
-+# CONFIG_I2C_DEBUG_CHIP is not set
- #
- # SPI support
-@@ -655,13 +717,25 @@
- # SPI Protocol Masters
- #
- # CONFIG_SPI_AT25 is not set
--# CONFIG_SPI_SPIDEV is not set
-+CONFIG_SPI_SPIDEV=m
-+# CONFIG_SPI_TLE62X0 is not set
-+# CONFIG_W1 is not set
-+# CONFIG_POWER_SUPPLY is not set
-+# CONFIG_HWMON is not set
-+CONFIG_WATCHDOG=y
-+# CONFIG_WATCHDOG_NOWAYOUT is not set
- #
--# Dallas's 1-wire bus
-+# Watchdog Device Drivers
- #
--# CONFIG_W1 is not set
--# CONFIG_HWMON is not set
-+# CONFIG_SOFT_WATCHDOG is not set
-+CONFIG_AT32AP700X_WDT=y
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
 +
 +#
-+# Sonics Silicon Backplane
++# SPI GPIO expanders:
 +#
-+CONFIG_SSB_POSSIBLE=y
-+# CONFIG_SSB is not set
- #
- # Multifunction device drivers
-@@ -678,23 +752,21 @@
- #
- # Graphics support
- #
-+# CONFIG_VGASTATE is not set
-+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-+# CONFIG_FB is not set
- # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
- #
- # Display device support
- #
- # CONFIG_DISPLAY_SUPPORT is not set
--# CONFIG_VGASTATE is not set
--# CONFIG_FB is not set
++# CONFIG_GPIO_MCP23S08 is not set
+ # CONFIG_W1 is not set
+ # CONFIG_POWER_SUPPLY is not set
+ # CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
+ CONFIG_WATCHDOG=y
+ # CONFIG_WATCHDOG_NOWAYOUT is not set
  
+@@ -757,10 +730,6 @@
  #
- # Sound
+ # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
  #
- # CONFIG_SOUND is not set
 -
 -#
--# USB support
+-# USB Gadget Support
 -#
-+CONFIG_USB_SUPPORT=y
- # CONFIG_USB_ARCH_HAS_HCD is not set
- # CONFIG_USB_ARCH_HAS_OHCI is not set
- # CONFIG_USB_ARCH_HAS_EHCI is not set
-@@ -706,12 +778,48 @@
+ CONFIG_USB_GADGET=y
+ # CONFIG_USB_GADGET_DEBUG is not set
+ # CONFIG_USB_GADGET_DEBUG_FILES is not set
+@@ -787,21 +756,24 @@
+ # CONFIG_USB_FILE_STORAGE_TEST is not set
+ CONFIG_USB_G_SERIAL=m
+ # CONFIG_USB_MIDI_GADGET is not set
+-CONFIG_MMC=m
++# CONFIG_USB_G_PRINTER is not set
++CONFIG_MMC=y
+ # CONFIG_MMC_DEBUG is not set
+ # CONFIG_MMC_UNSAFE_RESUME is not set
  #
- # USB Gadget Support
+ # MMC/SD Card Drivers
  #
--# CONFIG_USB_GADGET is not set
--# CONFIG_MMC is not set
-+CONFIG_USB_GADGET=y
-+# CONFIG_USB_GADGET_DEBUG is not set
-+# CONFIG_USB_GADGET_DEBUG_FILES is not set
-+CONFIG_USB_GADGET_SELECTED=y
-+# CONFIG_USB_GADGET_AMD5536UDC is not set
-+CONFIG_USB_GADGET_ATMEL_USBA=y
-+CONFIG_USB_ATMEL_USBA=y
-+# CONFIG_USB_GADGET_FSL_USB2 is not set
-+# CONFIG_USB_GADGET_NET2280 is not set
-+# CONFIG_USB_GADGET_PXA2XX is not set
-+# CONFIG_USB_GADGET_M66592 is not set
-+# CONFIG_USB_GADGET_GOKU is not set
-+# CONFIG_USB_GADGET_LH7A40X is not set
-+# CONFIG_USB_GADGET_OMAP is not set
-+# CONFIG_USB_GADGET_S3C2410 is not set
-+# CONFIG_USB_GADGET_AT91 is not set
-+# CONFIG_USB_GADGET_DUMMY_HCD is not set
-+CONFIG_USB_GADGET_DUALSPEED=y
-+CONFIG_USB_ZERO=m
-+CONFIG_USB_ETH=m
-+CONFIG_USB_ETH_RNDIS=y
-+CONFIG_USB_GADGETFS=m
-+CONFIG_USB_FILE_STORAGE=m
-+# CONFIG_USB_FILE_STORAGE_TEST is not set
-+CONFIG_USB_G_SERIAL=m
-+# CONFIG_USB_MIDI_GADGET is not set
-+CONFIG_MMC=y
-+# CONFIG_MMC_DEBUG is not set
-+# CONFIG_MMC_UNSAFE_RESUME is not set
-+
-+#
-+# MMC/SD Card Drivers
-+#
+-CONFIG_MMC_BLOCK=m
 +CONFIG_MMC_BLOCK=y
-+# CONFIG_MMC_BLOCK_BOUNCE is not set
-+# CONFIG_SDIO_UART is not set
+ CONFIG_MMC_BLOCK_BOUNCE=y
+ # CONFIG_SDIO_UART is not set
  
  #
--# LED devices
-+# MMC/SD Host Controller Drivers
+ # MMC/SD Host Controller Drivers
  #
 +CONFIG_MMC_ATMELMCI=y
-+CONFIG_MMC_SPI=m
+ CONFIG_MMC_SPI=m
++# CONFIG_MEMSTICK is not set
  CONFIG_NEW_LEDS=y
  CONFIG_LEDS_CLASS=y
  
-@@ -726,53 +834,71 @@
- CONFIG_LEDS_TRIGGERS=y
- CONFIG_LEDS_TRIGGER_TIMER=y
- CONFIG_LEDS_TRIGGER_HEARTBEAT=y
--
-+CONFIG_RTC_LIB=y
-+CONFIG_RTC_CLASS=y
-+CONFIG_RTC_HCTOSYS=y
-+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
-+# CONFIG_RTC_DEBUG is not set
+@@ -844,19 +816,22 @@
+ # CONFIG_RTC_DRV_PCF8563 is not set
+ # CONFIG_RTC_DRV_PCF8583 is not set
+ # CONFIG_RTC_DRV_M41T80 is not set
++# CONFIG_RTC_DRV_S35390A is not set
  
  #
--# LED drivers
--#
--
--#
--# LED Triggers
--#
--
--#
--# InfiniBand support
-+# RTC interfaces
+ # SPI RTC drivers
  #
-+CONFIG_RTC_INTF_SYSFS=y
-+CONFIG_RTC_INTF_PROC=y
-+CONFIG_RTC_INTF_DEV=y
-+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
-+# CONFIG_RTC_DRV_TEST is not set
- #
--# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-+# I2C RTC drivers
- #
-+# CONFIG_RTC_DRV_DS1307 is not set
-+# CONFIG_RTC_DRV_DS1374 is not set
-+# CONFIG_RTC_DRV_DS1672 is not set
-+# CONFIG_RTC_DRV_MAX6900 is not set
-+# CONFIG_RTC_DRV_RS5C372 is not set
-+# CONFIG_RTC_DRV_ISL1208 is not set
-+# CONFIG_RTC_DRV_X1205 is not set
-+# CONFIG_RTC_DRV_PCF8563 is not set
-+# CONFIG_RTC_DRV_PCF8583 is not set
-+# CONFIG_RTC_DRV_M41T80 is not set
- #
--# Real Time Clock
-+# SPI RTC drivers
- #
--# CONFIG_RTC_CLASS is not set
+-# CONFIG_RTC_DRV_RS5C348 is not set
+ # CONFIG_RTC_DRV_MAX6902 is not set
++# CONFIG_RTC_DRV_R9701 is not set
 +# CONFIG_RTC_DRV_RS5C348 is not set
-+# CONFIG_RTC_DRV_MAX6902 is not set
  
  #
--# DMA Engine support
-+# Platform RTC drivers
+ # Platform RTC drivers
  #
--# CONFIG_DMA_ENGINE is not set
-+# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_DS1511 is not set
+ # CONFIG_RTC_DRV_DS1553 is not set
+-# CONFIG_RTC_DRV_STK17TA8 is not set
+ # CONFIG_RTC_DRV_DS1742 is not set
 +# CONFIG_RTC_DRV_STK17TA8 is not set
-+# CONFIG_RTC_DRV_DS1742 is not set
-+# CONFIG_RTC_DRV_M48T86 is not set
-+# CONFIG_RTC_DRV_M48T59 is not set
-+# CONFIG_RTC_DRV_V3020 is not set
- #
--# DMA Clients
-+# on-CPU RTC drivers
- #
-+CONFIG_RTC_DRV_AT32AP700X=y
- #
--# DMA Devices
-+# Userspace I/O
- #
-+# CONFIG_UIO is not set
+ # CONFIG_RTC_DRV_M48T86 is not set
+ # CONFIG_RTC_DRV_M48T59 is not set
+ # CONFIG_RTC_DRV_V3020 is not set
+@@ -874,25 +849,23 @@
  #
  # File systems
  #
--CONFIG_EXT2_FS=y
-+CONFIG_EXT2_FS=m
+-CONFIG_EXT2_FS=m
++CONFIG_EXT2_FS=y
  # CONFIG_EXT2_FS_XATTR is not set
  # CONFIG_EXT2_FS_XIP is not set
--CONFIG_EXT3_FS=y
-+CONFIG_EXT3_FS=m
+-CONFIG_EXT3_FS=m
++CONFIG_EXT3_FS=y
  # CONFIG_EXT3_FS_XATTR is not set
  # CONFIG_EXT4DEV_FS is not set
--CONFIG_JBD=y
--# CONFIG_JBD_DEBUG is not set
-+CONFIG_JBD=m
+-CONFIG_JBD=m
++CONFIG_JBD=y
  # CONFIG_REISERFS_FS is not set
  # CONFIG_JFS_FS is not set
  # CONFIG_FS_POSIX_ACL is not set
-@@ -781,7 +907,8 @@
+ # CONFIG_XFS_FS is not set
+ # CONFIG_GFS2_FS is not set
  # CONFIG_OCFS2_FS is not set
- # CONFIG_MINIX_FS is not set
- # CONFIG_ROMFS_FS is not set
--# CONFIG_INOTIFY is not set
-+CONFIG_INOTIFY=y
-+CONFIG_INOTIFY_USER=y
+-# CONFIG_MINIX_FS is not set
+-# CONFIG_ROMFS_FS is not set
++# CONFIG_DNOTIFY is not set
+ CONFIG_INOTIFY=y
+ CONFIG_INOTIFY_USER=y
  # CONFIG_QUOTA is not set
- # CONFIG_DNOTIFY is not set
+-# CONFIG_DNOTIFY is not set
  # CONFIG_AUTOFS_FS is not set
-@@ -814,7 +941,6 @@
+ # CONFIG_AUTOFS4_FS is not set
+ CONFIG_FUSE_FS=m
+@@ -923,7 +896,7 @@
  CONFIG_TMPFS=y
  # CONFIG_TMPFS_POSIX_ACL is not set
  # CONFIG_HUGETLB_PAGE is not set
--CONFIG_RAMFS=y
- CONFIG_CONFIGFS_FS=y
+-CONFIG_CONFIGFS_FS=m
++CONFIG_CONFIGFS_FS=y
  
  #
-@@ -830,10 +956,12 @@
- CONFIG_JFFS2_FS=y
- CONFIG_JFFS2_FS_DEBUG=0
- CONFIG_JFFS2_FS_WRITEBUFFER=y
-+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
- # CONFIG_JFFS2_SUMMARY is not set
- # CONFIG_JFFS2_FS_XATTR is not set
- # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
- CONFIG_JFFS2_ZLIB=y
-+# CONFIG_JFFS2_LZO is not set
- CONFIG_JFFS2_RTIME=y
+ # Miscellaneous filesystems
+@@ -948,8 +921,10 @@
  # CONFIG_JFFS2_RUBIN is not set
  # CONFIG_CRAMFS is not set
-@@ -842,19 +970,21 @@
+ # CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
+ # CONFIG_HPFS_FS is not set
  # CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
  # CONFIG_SYSV_FS is not set
  # CONFIG_UFS_FS is not set
--
--#
--# Network File Systems
--#
-+CONFIG_NETWORK_FILESYSTEMS=y
- CONFIG_NFS_FS=y
- CONFIG_NFS_V3=y
- # CONFIG_NFS_V3_ACL is not set
- # CONFIG_NFS_V4 is not set
- # CONFIG_NFS_DIRECTIO is not set
--# CONFIG_NFSD is not set
-+CONFIG_NFSD=m
-+CONFIG_NFSD_V3=y
-+# CONFIG_NFSD_V3_ACL is not set
-+# CONFIG_NFSD_V4 is not set
-+CONFIG_NFSD_TCP=y
- CONFIG_ROOT_NFS=y
- CONFIG_LOCKD=y
- CONFIG_LOCKD_V4=y
-+CONFIG_EXPORTFS=m
- CONFIG_NFS_COMMON=y
- CONFIG_SUNRPC=y
- # CONFIG_SUNRPC_BIND34 is not set
-@@ -871,23 +1001,18 @@
- # CONFIG_NCP_FS is not set
- # CONFIG_CODA_FS is not set
- # CONFIG_AFS_FS is not set
--# CONFIG_9P_FS is not set
- #
- # Partition Types
- #
- # CONFIG_PARTITION_ADVANCED is not set
- CONFIG_MSDOS_PARTITION=y
--
--#
--# Native Language Support
--#
--CONFIG_NLS=y
-+CONFIG_NLS=m
- CONFIG_NLS_DEFAULT="iso8859-1"
--# CONFIG_NLS_CODEPAGE_437 is not set
-+CONFIG_NLS_CODEPAGE_437=m
- # CONFIG_NLS_CODEPAGE_737 is not set
- # CONFIG_NLS_CODEPAGE_775 is not set
--CONFIG_NLS_CODEPAGE_850=y
-+CONFIG_NLS_CODEPAGE_850=m
- # CONFIG_NLS_CODEPAGE_852 is not set
- # CONFIG_NLS_CODEPAGE_855 is not set
- # CONFIG_NLS_CODEPAGE_857 is not set
-@@ -908,7 +1033,7 @@
- # CONFIG_NLS_CODEPAGE_1250 is not set
- # CONFIG_NLS_CODEPAGE_1251 is not set
- # CONFIG_NLS_ASCII is not set
--CONFIG_NLS_ISO8859_1=y
-+CONFIG_NLS_ISO8859_1=m
- # CONFIG_NLS_ISO8859_2 is not set
- # CONFIG_NLS_ISO8859_3 is not set
- # CONFIG_NLS_ISO8859_4 is not set
-@@ -921,18 +1046,19 @@
- # CONFIG_NLS_ISO8859_15 is not set
- # CONFIG_NLS_KOI8_R is not set
+ CONFIG_NETWORK_FILESYSTEMS=y
+@@ -1030,11 +1005,6 @@
  # CONFIG_NLS_KOI8_U is not set
--CONFIG_NLS_UTF8=y
--
--#
--# Distributed Lock Manager
--#
-+CONFIG_NLS_UTF8=m
+ CONFIG_NLS_UTF8=m
  # CONFIG_DLM is not set
-+CONFIG_INSTRUMENTATION=y
-+CONFIG_PROFILING=y
-+CONFIG_OPROFILE=m
-+CONFIG_KPROBES=y
-+# CONFIG_MARKERS is not set
+-CONFIG_INSTRUMENTATION=y
+-CONFIG_PROFILING=y
+-CONFIG_OPROFILE=m
+-CONFIG_KPROBES=y
+-# CONFIG_MARKERS is not set
  
  #
  # Kernel hacking
- #
--CONFIG_TRACE_IRQFLAGS_SUPPORT=y
- # CONFIG_PRINTK_TIME is not set
-+CONFIG_ENABLE_WARN_DEPRECATED=y
- CONFIG_ENABLE_MUST_CHECK=y
- CONFIG_MAGIC_SYSRQ=y
- # CONFIG_UNUSED_SYMBOLS is not set
-@@ -941,12 +1067,17 @@
- CONFIG_DEBUG_KERNEL=y
- # CONFIG_DEBUG_SHIRQ is not set
- CONFIG_DETECT_SOFTLOCKUP=y
-+CONFIG_SCHED_DEBUG=y
+@@ -1053,6 +1023,7 @@
  # CONFIG_SCHEDSTATS is not set
  # CONFIG_TIMER_STATS is not set
-+# CONFIG_SLUB_DEBUG_ON is not set
+ # CONFIG_SLUB_DEBUG_ON is not set
++# CONFIG_SLUB_STATS is not set
  # CONFIG_DEBUG_RT_MUTEXES is not set
  # CONFIG_RT_MUTEX_TESTER is not set
  # CONFIG_DEBUG_SPINLOCK is not set
- # CONFIG_DEBUG_MUTEXES is not set
-+# CONFIG_DEBUG_LOCK_ALLOC is not set
-+# CONFIG_PROVE_LOCKING is not set
-+# CONFIG_LOCK_STAT is not set
- # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
- # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
- # CONFIG_DEBUG_KOBJECT is not set
-@@ -954,21 +1085,21 @@
- # CONFIG_DEBUG_INFO is not set
- # CONFIG_DEBUG_VM is not set
+@@ -1069,9 +1040,10 @@
  # CONFIG_DEBUG_LIST is not set
-+# CONFIG_DEBUG_SG is not set
+ # CONFIG_DEBUG_SG is not set
  CONFIG_FRAME_POINTER=y
- # CONFIG_FORCED_INLINING is not set
-+# CONFIG_BOOT_PRINTK_DELAY is not set
+-# CONFIG_FORCED_INLINING is not set
+ # CONFIG_BOOT_PRINTK_DELAY is not set
  # CONFIG_RCU_TORTURE_TEST is not set
-+# CONFIG_LKDTM is not set
++# CONFIG_KPROBES_SANITY_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
+ # CONFIG_LKDTM is not set
  # CONFIG_FAULT_INJECTION is not set
--# CONFIG_KPROBES is not set
-+# CONFIG_SAMPLES is not set
- #
- # Security options
- #
- # CONFIG_KEYS is not set
- # CONFIG_SECURITY is not set
--
--#
--# Cryptographic options
--#
-+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+ # CONFIG_SAMPLES is not set
+@@ -1084,7 +1056,9 @@
+ # CONFIG_SECURITY_FILE_CAPABILITIES is not set
  CONFIG_CRYPTO=y
  CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_AEAD=y
  CONFIG_CRYPTO_BLKCIPHER=y
-@@ -989,6 +1120,7 @@
- CONFIG_CRYPTO_CBC=y
++# CONFIG_CRYPTO_SEQIV is not set
+ CONFIG_CRYPTO_HASH=y
+ CONFIG_CRYPTO_MANAGER=y
+ CONFIG_CRYPTO_HMAC=y
+@@ -1103,6 +1077,9 @@
  CONFIG_CRYPTO_PCBC=m
  # CONFIG_CRYPTO_LRW is not set
-+# CONFIG_CRYPTO_XTS is not set
+ # CONFIG_CRYPTO_XTS is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_CCM is not set
  # CONFIG_CRYPTO_CRYPTD is not set
  CONFIG_CRYPTO_DES=y
  # CONFIG_CRYPTO_FCRYPT is not set
-@@ -1002,15 +1134,14 @@
- CONFIG_CRYPTO_ARC4=m
+@@ -1117,12 +1094,14 @@
  # CONFIG_CRYPTO_KHAZAD is not set
  # CONFIG_CRYPTO_ANUBIS is not set
-+# CONFIG_CRYPTO_SEED is not set
+ # CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SALSA20 is not set
  CONFIG_CRYPTO_DEFLATE=y
  # CONFIG_CRYPTO_MICHAEL_MIC is not set
  # CONFIG_CRYPTO_CRC32C is not set
  # CONFIG_CRYPTO_CAMELLIA is not set
  # CONFIG_CRYPTO_TEST is not set
--
--#
--# Hardware crypto devices
--#
-+# CONFIG_CRYPTO_AUTHENC is not set
-+CONFIG_CRYPTO_HW=y
+-# CONFIG_CRYPTO_AUTHENC is not set
++CONFIG_CRYPTO_AUTHENC=y
++# CONFIG_CRYPTO_LZO is not set
+ CONFIG_CRYPTO_HW=y
  
  #
- # Library routines
-@@ -1018,8 +1149,9 @@
- CONFIG_BITREVERSE=y
- CONFIG_CRC_CCITT=m
- # CONFIG_CRC16 is not set
--# CONFIG_CRC_ITU_T is not set
-+CONFIG_CRC_ITU_T=m
- CONFIG_CRC32=y
-+CONFIG_CRC7=m
+@@ -1137,10 +1116,7 @@
  # CONFIG_LIBCRC32C is not set
  CONFIG_ZLIB_INFLATE=y
  CONFIG_ZLIB_DEFLATE=y
---- a/arch/avr32/configs/atstk1002_defconfig
-+++ b/arch/avr32/configs/atstk1002_defconfig
-@@ -1,48 +1,49 @@
+-CONFIG_TEXTSEARCH=y
+-CONFIG_TEXTSEARCH_KMP=m
+-CONFIG_TEXTSEARCH_BM=m
+-CONFIG_TEXTSEARCH_FSM=m
++CONFIG_GENERIC_ALLOCATOR=y
+ CONFIG_PLIST=y
+ CONFIG_HAS_IOMEM=y
+ CONFIG_HAS_IOPORT=y
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/configs/atstk1002_defconfig avr32-2.6/arch/avr32/configs/atstk1002_defconfig
+--- linux-2.6.25.6/arch/avr32/configs/atstk1002_defconfig      2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/configs/atstk1002_defconfig   2008-06-12 15:09:38.715815679 +0200
+@@ -1,7 +1,7 @@
  #
  # Automatically generated make config: don't edit
--# Linux kernel version: 2.6.22-rc5
--# Sat Jun 23 15:32:08 2007
-+# Linux kernel version: 2.6.24
-+# Thu Mar  6 12:49:17 2008
+-# Linux kernel version: 2.6.24-rc7
+-# Wed Jan  9 23:07:43 2008
++# Linux kernel version: 2.6.25.4
++# Wed Jun 11 15:29:18 2008
  #
  CONFIG_AVR32=y
  CONFIG_GENERIC_GPIO=y
- CONFIG_GENERIC_HARDIRQS=y
-+CONFIG_STACKTRACE_SUPPORT=y
-+CONFIG_LOCKDEP_SUPPORT=y
-+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
- CONFIG_HARDIRQS_SW_RESEND=y
+@@ -13,10 +13,10 @@
  CONFIG_GENERIC_IRQ_PROBE=y
  CONFIG_RWSEM_GENERIC_SPINLOCK=y
  CONFIG_GENERIC_TIME=y
 +CONFIG_GENERIC_CLOCKEVENTS=y
-+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+ # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
  # CONFIG_ARCH_HAS_ILOG2_U32 is not set
  # CONFIG_ARCH_HAS_ILOG2_U64 is not set
-+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+-CONFIG_ARCH_SUPPORTS_OPROFILE=y
  CONFIG_GENERIC_HWEIGHT=y
  CONFIG_GENERIC_CALIBRATE_DELAY=y
  CONFIG_GENERIC_BUG=y
- CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
- #
--# Code maturity level options
-+# General setup
- #
- CONFIG_EXPERIMENTAL=y
- CONFIG_BROKEN_ON_SMP=y
- CONFIG_INIT_ENV_ARG_LIMIT=32
--
--#
--# General setup
--#
- CONFIG_LOCALVERSION=""
- # CONFIG_LOCALVERSION_AUTO is not set
- CONFIG_SWAP=y
- CONFIG_SYSVIPC=y
--# CONFIG_IPC_NS is not set
- CONFIG_SYSVIPC_SYSCTL=y
+@@ -36,15 +36,15 @@
  CONFIG_POSIX_MQUEUE=y
--CONFIG_BSD_PROCESS_ACCT=y
--CONFIG_BSD_PROCESS_ACCT_V3=y
--CONFIG_TASKSTATS=y
--CONFIG_TASK_DELAY_ACCT=y
--# CONFIG_TASK_XACCT is not set
--# CONFIG_UTS_NS is not set
--CONFIG_AUDIT=y
-+# CONFIG_BSD_PROCESS_ACCT is not set
-+# CONFIG_TASKSTATS is not set
-+# CONFIG_USER_NS is not set
-+# CONFIG_PID_NS is not set
-+# CONFIG_AUDIT is not set
+ # CONFIG_BSD_PROCESS_ACCT is not set
+ # CONFIG_TASKSTATS is not set
+-# CONFIG_USER_NS is not set
+-# CONFIG_PID_NS is not set
+ # CONFIG_AUDIT is not set
  # CONFIG_IKCONFIG is not set
  CONFIG_LOG_BUF_SHIFT=14
-+# CONFIG_CGROUPS is not set
-+# CONFIG_FAIR_GROUP_SCHED is not set
+ # CONFIG_CGROUPS is not set
+-# CONFIG_FAIR_GROUP_SCHED is not set
++# CONFIG_GROUP_SCHED is not set
  CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
  CONFIG_RELAY=y
++# CONFIG_NAMESPACES is not set
  CONFIG_BLK_DEV_INITRD=y
-@@ -63,35 +64,28 @@
+ CONFIG_INITRAMFS_SOURCE=""
+ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+@@ -58,11 +58,13 @@
+ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
++# CONFIG_COMPAT_BRK is not set
+ # CONFIG_BASE_FULL is not set
+ CONFIG_FUTEX=y
  CONFIG_ANON_INODES=y
  CONFIG_EPOLL=y
  CONFIG_SIGNALFD=y
--CONFIG_TIMERFD=y
++CONFIG_TIMERFD=y
  CONFIG_EVENTFD=y
  CONFIG_SHMEM=y
  CONFIG_VM_EVENT_COUNTERS=y
--# CONFIG_SLUB_DEBUG is not set
-+CONFIG_SLUB_DEBUG=y
+@@ -70,6 +72,14 @@
  # CONFIG_SLAB is not set
  CONFIG_SLUB=y
  # CONFIG_SLOB is not set
-+CONFIG_SLABINFO=y
++CONFIG_PROFILING=y
++# CONFIG_MARKERS is not set
++CONFIG_OPROFILE=m
++CONFIG_HAVE_OPROFILE=y
++CONFIG_KPROBES=y
++CONFIG_HAVE_KPROBES=y
++# CONFIG_HAVE_KRETPROBES is not set
++CONFIG_PROC_PAGE_MONITOR=y
+ CONFIG_SLABINFO=y
  CONFIG_RT_MUTEXES=y
  # CONFIG_TINY_SHMEM is not set
- CONFIG_BASE_SMALL=1
--
--#
--# Loadable module support
--#
- CONFIG_MODULES=y
- CONFIG_MODULE_UNLOAD=y
- # CONFIG_MODULE_FORCE_UNLOAD is not set
- # CONFIG_MODVERSIONS is not set
- # CONFIG_MODULE_SRCVERSION_ALL is not set
- # CONFIG_KMOD is not set
--
--#
--# Block layer
--#
- CONFIG_BLOCK=y
- # CONFIG_LBD is not set
- # CONFIG_BLK_DEV_IO_TRACE is not set
- # CONFIG_LSF is not set
-+# CONFIG_BLK_DEV_BSG is not set
- #
- # IO Schedulers
-@@ -99,32 +93,49 @@
- CONFIG_IOSCHED_NOOP=y
- # CONFIG_IOSCHED_AS is not set
- # CONFIG_IOSCHED_DEADLINE is not set
--# CONFIG_IOSCHED_CFQ is not set
-+CONFIG_IOSCHED_CFQ=y
- # CONFIG_DEFAULT_AS is not set
- # CONFIG_DEFAULT_DEADLINE is not set
--# CONFIG_DEFAULT_CFQ is not set
--CONFIG_DEFAULT_NOOP=y
--CONFIG_DEFAULT_IOSCHED="noop"
-+CONFIG_DEFAULT_CFQ=y
-+# CONFIG_DEFAULT_NOOP is not set
-+CONFIG_DEFAULT_IOSCHED="cfq"
+@@ -98,10 +108,15 @@
+ CONFIG_DEFAULT_CFQ=y
+ # CONFIG_DEFAULT_NOOP is not set
+ CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_CLASSIC_RCU=y
  
  #
  # System Type and features
  CONFIG_SUBARCH_AVR32B=y
  CONFIG_MMU=y
  CONFIG_PERFORMANCE_COUNTERS=y
- CONFIG_PLATFORM_AT32AP=y
-+CONFIG_CPU_AT32AP700X=y
- CONFIG_CPU_AT32AP7000=y
--CONFIG_BOARD_ATSTK1002=y
- CONFIG_BOARD_ATSTK1000=y
- # CONFIG_BOARD_ATNGW100 is not set
-+CONFIG_BOARD_ATSTK1002=y
-+# CONFIG_BOARD_ATSTK1003 is not set
-+# CONFIG_BOARD_ATSTK1004 is not set
-+# CONFIG_BOARD_ATSTK100X_CUSTOM is not set
-+# CONFIG_BOARD_ATSTK100X_SPI1 is not set
-+# CONFIG_BOARD_ATSTK1000_J2_LED is not set
-+# CONFIG_BOARD_ATSTK1000_J2_LED8 is not set
-+# CONFIG_BOARD_ATSTK1000_J2_RGB is not set
-+CONFIG_BOARD_ATSTK1000_EXTDAC=y
+@@ -113,12 +128,16 @@
+ CONFIG_BOARD_ATSTK1002=y
+ # CONFIG_BOARD_ATSTK1003 is not set
+ # CONFIG_BOARD_ATSTK1004 is not set
++# CONFIG_BOARD_ATSTK1006 is not set
+ # CONFIG_BOARD_ATSTK100X_CUSTOM is not set
+ # CONFIG_BOARD_ATSTK100X_SPI1 is not set
+ # CONFIG_BOARD_ATSTK1000_J2_LED is not set
+ # CONFIG_BOARD_ATSTK1000_J2_LED8 is not set
+ # CONFIG_BOARD_ATSTK1000_J2_RGB is not set
+ CONFIG_BOARD_ATSTK1000_EXTDAC=y
 +# CONFIG_BOARD_ATSTK100X_ENABLE_AC97 is not set
 +# CONFIG_BOARD_ATSTK1000_CF_HACKS is not set
 +# CONFIG_BOARD_ATSTK100X_ENABLE_PSIF is not set
  CONFIG_LOADER_U_BOOT=y
  
  #
- # Atmel AVR32 AP options
- #
--# CONFIG_AP7000_32_BIT_SMC is not set
--CONFIG_AP7000_16_BIT_SMC=y
--# CONFIG_AP7000_8_BIT_SMC is not set
-+# CONFIG_AP700X_32_BIT_SMC is not set
-+CONFIG_AP700X_16_BIT_SMC=y
-+# CONFIG_AP700X_8_BIT_SMC is not set
+@@ -127,6 +146,7 @@
+ # CONFIG_AP700X_32_BIT_SMC is not set
+ CONFIG_AP700X_16_BIT_SMC=y
+ # CONFIG_AP700X_8_BIT_SMC is not set
 +CONFIG_GPIO_DEV=y
  CONFIG_LOAD_ADDRESS=0x10000000
  CONFIG_ENTRY_ADDRESS=0x90000000
  CONFIG_PHYS_OFFSET=0x10000000
-@@ -144,10 +155,14 @@
- CONFIG_FLATMEM=y
- CONFIG_FLAT_NODE_MEM_MAP=y
- # CONFIG_SPARSEMEM_STATIC is not set
-+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
- CONFIG_SPLIT_PTLOCK_CPUS=4
- # CONFIG_RESOURCES_64BIT is not set
+@@ -152,16 +172,26 @@
  CONFIG_ZONE_DMA_FLAG=0
-+CONFIG_VIRT_TO_BUS=y
+ CONFIG_VIRT_TO_BUS=y
  # CONFIG_OWNERSHIP_TRACE is not set
 +CONFIG_NMI_DEBUGGING=y
 +CONFIG_DW_DMAC=y
  # CONFIG_HZ_100 is not set
  CONFIG_HZ_250=y
  # CONFIG_HZ_300 is not set
-@@ -156,13 +171,31 @@
+ # CONFIG_HZ_1000 is not set
+ CONFIG_HZ=250
++# CONFIG_SCHED_HRTICK is not set
  CONFIG_CMDLINE=""
  
  #
--# Bus options
-+# Power management options
- #
--# CONFIG_ARCH_SUPPORTS_MSI is not set
- #
--# PCCARD (PCMCIA/CardBus) support
-+# CPU Frequency scaling
-+#
-+CONFIG_CPU_FREQ=y
-+CONFIG_CPU_FREQ_TABLE=y
-+# CONFIG_CPU_FREQ_DEBUG is not set
-+# CONFIG_CPU_FREQ_STAT is not set
-+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
-+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
-+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
-+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
-+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
-+CONFIG_CPU_FREQ_GOV_USERSPACE=y
-+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
-+CONFIG_CPU_FREQ_AT32AP=y
-+
-+#
-+# Bus options
+ # Power management options
  #
-+# CONFIG_ARCH_SUPPORTS_MSI is not set
- # CONFIG_PCCARD is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_PM=y
++# CONFIG_PM_LEGACY is not set
++# CONFIG_PM_DEBUG is not set
++CONFIG_PM_SLEEP=y
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
  
  #
-@@ -182,7 +215,12 @@
- CONFIG_PACKET=y
- CONFIG_PACKET_MMAP=y
- CONFIG_UNIX=y
--# CONFIG_NET_KEY is not set
-+CONFIG_XFRM=y
-+CONFIG_XFRM_USER=m
-+# CONFIG_XFRM_SUB_POLICY is not set
-+# CONFIG_XFRM_MIGRATE is not set
-+CONFIG_NET_KEY=m
-+# CONFIG_NET_KEY_MIGRATE is not set
+ # CPU Frequency scaling
+@@ -170,9 +200,9 @@
+ CONFIG_CPU_FREQ_TABLE=y
+ # CONFIG_CPU_FREQ_DEBUG is not set
+ # CONFIG_CPU_FREQ_STAT is not set
+-CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+ # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+-# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+ # CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+ # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+@@ -208,6 +238,7 @@
+ CONFIG_XFRM_USER=m
+ # CONFIG_XFRM_SUB_POLICY is not set
+ # CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
+ CONFIG_NET_KEY=m
+ # CONFIG_NET_KEY_MIGRATE is not set
  CONFIG_INET=y
- # CONFIG_IP_MULTICAST is not set
- # CONFIG_IP_ADVANCED_ROUTER is not set
-@@ -191,36 +229,52 @@
- CONFIG_IP_PNP_DHCP=y
- # CONFIG_IP_PNP_BOOTP is not set
- # CONFIG_IP_PNP_RARP is not set
--# CONFIG_NET_IPIP is not set
--# CONFIG_NET_IPGRE is not set
-+CONFIG_NET_IPIP=m
-+CONFIG_NET_IPGRE=m
- # CONFIG_ARPD is not set
- # CONFIG_SYN_COOKIES is not set
--# CONFIG_INET_AH is not set
--# CONFIG_INET_ESP is not set
-+CONFIG_INET_AH=m
-+CONFIG_INET_ESP=m
- # CONFIG_INET_IPCOMP is not set
- # CONFIG_INET_XFRM_TUNNEL is not set
--# CONFIG_INET_TUNNEL is not set
--# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
--# CONFIG_INET_XFRM_MODE_TUNNEL is not set
--# CONFIG_INET_XFRM_MODE_BEET is not set
-+CONFIG_INET_TUNNEL=m
-+CONFIG_INET_XFRM_MODE_TRANSPORT=m
-+CONFIG_INET_XFRM_MODE_TUNNEL=m
-+CONFIG_INET_XFRM_MODE_BEET=m
-+# CONFIG_INET_LRO is not set
- CONFIG_INET_DIAG=y
- CONFIG_INET_TCP_DIAG=y
- # CONFIG_TCP_CONG_ADVANCED is not set
- CONFIG_TCP_CONG_CUBIC=y
- CONFIG_DEFAULT_TCP_CONG="cubic"
- # CONFIG_TCP_MD5SIG is not set
--# CONFIG_IPV6 is not set
--# CONFIG_INET6_XFRM_TUNNEL is not set
--# CONFIG_INET6_TUNNEL is not set
-+CONFIG_IPV6=m
-+# CONFIG_IPV6_PRIVACY is not set
-+# CONFIG_IPV6_ROUTER_PREF is not set
-+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
-+CONFIG_INET6_AH=m
-+CONFIG_INET6_ESP=m
-+CONFIG_INET6_IPCOMP=m
-+# CONFIG_IPV6_MIP6 is not set
-+CONFIG_INET6_XFRM_TUNNEL=m
-+CONFIG_INET6_TUNNEL=m
-+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
-+CONFIG_INET6_XFRM_MODE_TUNNEL=m
-+CONFIG_INET6_XFRM_MODE_BEET=m
-+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
-+CONFIG_IPV6_SIT=m
-+CONFIG_IPV6_TUNNEL=m
-+# CONFIG_IPV6_MULTIPLE_TABLES is not set
- # CONFIG_NETWORK_SECMARK is not set
- # CONFIG_NETFILTER is not set
- # CONFIG_IP_DCCP is not set
- # CONFIG_IP_SCTP is not set
- # CONFIG_TIPC is not set
- # CONFIG_ATM is not set
--# CONFIG_BRIDGE is not set
-+CONFIG_BRIDGE=m
- # CONFIG_VLAN_8021Q is not set
- # CONFIG_DECNET is not set
-+CONFIG_LLC=m
- # CONFIG_LLC2 is not set
- # CONFIG_IPX is not set
- # CONFIG_ATALK is not set
-@@ -228,16 +282,13 @@
- # CONFIG_LAPB is not set
- # CONFIG_ECONET is not set
- # CONFIG_WAN_ROUTER is not set
--
--#
--# QoS and/or fair queueing
--#
- # CONFIG_NET_SCHED is not set
- #
- # Network testing
- #
+@@ -279,6 +310,7 @@
  # CONFIG_NET_PKTGEN is not set
-+# CONFIG_NET_TCPPROBE is not set
+ # CONFIG_NET_TCPPROBE is not set
  # CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
  # CONFIG_IRDA is not set
  # CONFIG_BT is not set
-@@ -251,6 +302,7 @@
- # CONFIG_MAC80211 is not set
- # CONFIG_IEEE80211 is not set
- # CONFIG_RFKILL is not set
-+# CONFIG_NET_9P is not set
+ # CONFIG_AF_RXRPC is not set
+@@ -395,13 +427,18 @@
+ CONFIG_BLK_DEV_RAM=m
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=4096
+-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
++# CONFIG_BLK_DEV_XIP is not set
+ # CONFIG_CDROM_PKTCDVD is not set
+ # CONFIG_ATA_OVER_ETH is not set
+ CONFIG_MISC_DEVICES=y
++CONFIG_ATMEL_PWM=m
++CONFIG_ATMEL_TCLIB=y
++CONFIG_ATMEL_TCB_CLKSRC=y
++CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0
+ # CONFIG_EEPROM_93CX6 is not set
+ CONFIG_ATMEL_SSC=m
+-# CONFIG_IDE is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_HAVE_IDE is not set
  
  #
- # Device Drivers
-@@ -259,16 +311,13 @@
+ # SCSI device support
+@@ -444,6 +481,7 @@
+ # CONFIG_SCSI_LOWLEVEL is not set
+ CONFIG_ATA=m
+ # CONFIG_ATA_NONSTANDARD is not set
++# CONFIG_SATA_MV is not set
+ CONFIG_PATA_AT32=m
+ # CONFIG_PATA_PLATFORM is not set
+ # CONFIG_MD is not set
+@@ -469,11 +507,13 @@
+ # CONFIG_SMSC_PHY is not set
+ # CONFIG_BROADCOM_PHY is not set
+ # CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
+ # CONFIG_FIXED_PHY is not set
+ # CONFIG_MDIO_BITBANG is not set
+ CONFIG_NET_ETHERNET=y
+ # CONFIG_MII is not set
+ CONFIG_MACB=y
++# CONFIG_ENC28J60 is not set
+ # CONFIG_IBM_NEW_EMAC_ZMII is not set
+ # CONFIG_IBM_NEW_EMAC_RGMII is not set
+ # CONFIG_IBM_NEW_EMAC_TAH is not set
+@@ -500,7 +540,6 @@
+ # CONFIG_PPPOL2TP is not set
+ # CONFIG_SLIP is not set
+ CONFIG_SLHC=m
+-# CONFIG_SHAPER is not set
+ # CONFIG_NETCONSOLE is not set
+ # CONFIG_NETPOLL is not set
+ # CONFIG_NET_POLL_CONTROLLER is not set
+@@ -568,6 +607,7 @@
  #
- # Generic Driver Options
+ CONFIG_SERIAL_ATMEL=y
+ CONFIG_SERIAL_ATMEL_CONSOLE=y
++CONFIG_SERIAL_ATMEL_PDC=y
+ # CONFIG_SERIAL_ATMEL_TTYAT is not set
+ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+@@ -575,8 +615,6 @@
+ # CONFIG_LEGACY_PTYS is not set
+ # CONFIG_IPMI_HANDLER is not set
+ # CONFIG_HW_RANDOM is not set
+-# CONFIG_RTC is not set
+-# CONFIG_GEN_RTC is not set
+ # CONFIG_R3964 is not set
+ # CONFIG_RAW_DRIVER is not set
+ # CONFIG_TCG_TPM is not set
+@@ -594,6 +632,7 @@
  #
-+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
- CONFIG_STANDALONE=y
- # CONFIG_PREVENT_FIRMWARE_BUILD is not set
- # CONFIG_FW_LOADER is not set
- # CONFIG_DEBUG_DRIVER is not set
- # CONFIG_DEBUG_DEVRES is not set
- # CONFIG_SYS_HYPERVISOR is not set
--
--#
--# Connector - unified userspace <-> kernelspace linker
--#
- # CONFIG_CONNECTOR is not set
- CONFIG_MTD=y
- # CONFIG_MTD_DEBUG is not set
-@@ -288,6 +337,7 @@
- # CONFIG_INFTL is not set
- # CONFIG_RFD_FTL is not set
- # CONFIG_SSFDC is not set
-+# CONFIG_MTD_OOPS is not set
- #
- # RAM/ROM/Flash chip drivers
-@@ -327,6 +377,8 @@
+ # I2C Hardware Bus support
  #
- # Self-contained MTD device drivers
++CONFIG_I2C_ATMELTWI=m
+ CONFIG_I2C_GPIO=m
+ # CONFIG_I2C_OCORES is not set
+ # CONFIG_I2C_PARPORT_LIGHT is not set
+@@ -604,13 +643,12 @@
  #
-+CONFIG_MTD_DATAFLASH=m
-+CONFIG_MTD_M25P80=m
- # CONFIG_MTD_SLRAM is not set
- # CONFIG_MTD_PHRAM is not set
- # CONFIG_MTD_MTDRAM is not set
-@@ -345,20 +397,8 @@
- # UBI - Unsorted block images
+ # Miscellaneous I2C Chip support
  #
- # CONFIG_MTD_UBI is not set
--
--#
--# Parallel port support
--#
- # CONFIG_PARPORT is not set
--
--#
--# Plug and Play support
--#
--# CONFIG_PNPACPI is not set
--
--#
--# Block devices
--#
-+CONFIG_BLK_DEV=y
- # CONFIG_BLK_DEV_COW_COMMON is not set
- CONFIG_BLK_DEV_LOOP=m
- # CONFIG_BLK_DEV_CRYPTOLOOP is not set
-@@ -369,42 +409,91 @@
- CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
- # CONFIG_CDROM_PKTCDVD is not set
- # CONFIG_ATA_OVER_ETH is not set
--
--#
--# Misc devices
--#
--# CONFIG_BLINK is not set
-+CONFIG_MISC_DEVICES=y
-+CONFIG_ATMEL_PWM=m
-+CONFIG_ATMEL_TCLIB=y
-+CONFIG_ATMEL_TCB_CLKSRC=y
-+CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0
-+# CONFIG_EEPROM_93CX6 is not set
-+CONFIG_ATMEL_SSC=m
- # CONFIG_IDE is not set
+-# CONFIG_SENSORS_DS1337 is not set
+-# CONFIG_SENSORS_DS1374 is not set
+ # CONFIG_DS1682 is not set
+ # CONFIG_SENSORS_EEPROM is not set
+ # CONFIG_SENSORS_PCF8574 is not set
+-# CONFIG_SENSORS_PCA9539 is not set
++# CONFIG_PCF8575 is not set
+ # CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_TPS65010 is not set
+ # CONFIG_SENSORS_MAX6875 is not set
+ # CONFIG_SENSORS_TSL2550 is not set
+ # CONFIG_I2C_DEBUG_CORE is not set
+@@ -637,9 +675,27 @@
+ # CONFIG_SPI_AT25 is not set
+ CONFIG_SPI_SPIDEV=m
+ # CONFIG_SPI_TLE62X0 is not set
++CONFIG_HAVE_GPIO_LIB=y
++
++#
++# GPIO Support
++#
++# CONFIG_DEBUG_GPIO is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MCP23S08 is not set
+ # CONFIG_W1 is not set
+ # CONFIG_POWER_SUPPLY is not set
+ # CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
+ CONFIG_WATCHDOG=y
+ # CONFIG_WATCHDOG_NOWAYOUT is not set
  
+@@ -732,12 +788,18 @@
  #
- # SCSI device support
+ # Generic devices
  #
- # CONFIG_RAID_ATTRS is not set
--# CONFIG_SCSI is not set
-+CONFIG_SCSI=m
-+CONFIG_SCSI_DMA=y
-+# CONFIG_SCSI_TGT is not set
- # CONFIG_SCSI_NETLINK is not set
--# CONFIG_ATA is not set
-+# CONFIG_SCSI_PROC_FS is not set
++CONFIG_SND_AC97_CODEC=m
+ # CONFIG_SND_DUMMY is not set
+ # CONFIG_SND_MTPAV is not set
+ # CONFIG_SND_SERIAL_U16550 is not set
+ # CONFIG_SND_MPU401 is not set
  
  #
--# Multi-device support (RAID and LVM)
-+# SCSI support type (disk, tape, CD-ROM)
- #
--# CONFIG_MD is not set
-+CONFIG_BLK_DEV_SD=m
-+# CONFIG_CHR_DEV_ST is not set
-+# CONFIG_CHR_DEV_OSST is not set
-+CONFIG_BLK_DEV_SR=m
-+# CONFIG_BLK_DEV_SR_VENDOR is not set
-+# CONFIG_CHR_DEV_SG is not set
-+# CONFIG_CHR_DEV_SCH is not set
-+
++# AVR32 devices
 +#
-+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++CONFIG_SND_ATMEL_AC97=m
++
 +#
-+# CONFIG_SCSI_MULTI_LUN is not set
-+# CONFIG_SCSI_CONSTANTS is not set
-+# CONFIG_SCSI_LOGGING is not set
-+# CONFIG_SCSI_SCAN_ASYNC is not set
-+CONFIG_SCSI_WAIT_SCAN=m
+ # SPI devices
  #
--# Network device support
-+# SCSI Transports
+ CONFIG_SND_AT73C213=m
+@@ -753,9 +815,14 @@
  #
-+# CONFIG_SCSI_SPI_ATTRS is not set
-+# CONFIG_SCSI_FC_ATTRS is not set
-+# CONFIG_SCSI_ISCSI_ATTRS is not set
-+# CONFIG_SCSI_SAS_LIBSAS is not set
-+# CONFIG_SCSI_SRP_ATTRS is not set
-+# CONFIG_SCSI_LOWLEVEL is not set
-+CONFIG_ATA=m
-+# CONFIG_ATA_NONSTANDARD is not set
-+CONFIG_PATA_AT32=m
-+# CONFIG_PATA_PLATFORM is not set
-+# CONFIG_MD is not set
- CONFIG_NETDEVICES=y
--CONFIG_DUMMY=y
-+# CONFIG_NETDEVICES_MULTIQUEUE is not set
-+# CONFIG_DUMMY is not set
- # CONFIG_BONDING is not set
-+# CONFIG_MACVLAN is not set
- # CONFIG_EQUALIZER is not set
- CONFIG_TUN=m
--# CONFIG_PHYLIB is not set
-+# CONFIG_VETH is not set
-+CONFIG_PHYLIB=y
  
  #
--# Ethernet (10 or 100Mbit)
-+# MII PHY device drivers
++# ALSA SoC audio for Freescale SOCs
++#
++
++#
+ # Open Sound System
+ #
+ # CONFIG_SOUND_PRIME is not set
++CONFIG_AC97_BUS=m
+ # CONFIG_HID_SUPPORT is not set
+ CONFIG_USB_SUPPORT=y
+ # CONFIG_USB_ARCH_HAS_HCD is not set
+@@ -765,10 +832,6 @@
+ #
+ # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
  #
-+# CONFIG_MARVELL_PHY is not set
-+# CONFIG_DAVICOM_PHY is not set
-+# CONFIG_QSEMI_PHY is not set
-+# CONFIG_LXT_PHY is not set
-+# CONFIG_CICADA_PHY is not set
-+# CONFIG_VITESSE_PHY is not set
-+# CONFIG_SMSC_PHY is not set
-+# CONFIG_BROADCOM_PHY is not set
-+# CONFIG_ICPLUS_PHY is not set
-+# CONFIG_FIXED_PHY is not set
-+# CONFIG_MDIO_BITBANG is not set
- CONFIG_NET_ETHERNET=y
--CONFIG_MII=y
-+# CONFIG_MII is not set
- CONFIG_MACB=y
-+# CONFIG_IBM_NEW_EMAC_ZMII is not set
-+# CONFIG_IBM_NEW_EMAC_RGMII is not set
-+# CONFIG_IBM_NEW_EMAC_TAH is not set
-+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
-+# CONFIG_B44 is not set
- # CONFIG_NETDEV_1000 is not set
- # CONFIG_NETDEV_10000 is not set
-@@ -423,27 +512,54 @@
- CONFIG_PPP_BSDCOMP=m
- # CONFIG_PPP_MPPE is not set
- # CONFIG_PPPOE is not set
-+# CONFIG_PPPOL2TP is not set
- # CONFIG_SLIP is not set
- CONFIG_SLHC=m
- # CONFIG_SHAPER is not set
- # CONFIG_NETCONSOLE is not set
- # CONFIG_NETPOLL is not set
- # CONFIG_NET_POLL_CONTROLLER is not set
--
--#
--# ISDN subsystem
--#
- # CONFIG_ISDN is not set
 -
 -#
--# Telephony Support
+-# USB Gadget Support
 -#
- # CONFIG_PHONE is not set
+ CONFIG_USB_GADGET=y
+ # CONFIG_USB_GADGET_DEBUG is not set
+ # CONFIG_USB_GADGET_DEBUG_FILES is not set
+@@ -796,27 +859,31 @@
+ # CONFIG_USB_FILE_STORAGE_TEST is not set
+ CONFIG_USB_G_SERIAL=m
+ # CONFIG_USB_MIDI_GADGET is not set
+-CONFIG_MMC=m
++# CONFIG_USB_G_PRINTER is not set
++CONFIG_MMC=y
+ # CONFIG_MMC_DEBUG is not set
+ # CONFIG_MMC_UNSAFE_RESUME is not set
  
  #
- # Input device support
+ # MMC/SD Card Drivers
  #
--# CONFIG_INPUT is not set
-+CONFIG_INPUT=m
-+# CONFIG_INPUT_FF_MEMLESS is not set
-+CONFIG_INPUT_POLLDEV=m
-+
-+#
-+# Userland interfaces
-+#
-+CONFIG_INPUT_MOUSEDEV=m
-+CONFIG_INPUT_MOUSEDEV_PSAUX=y
-+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-+# CONFIG_INPUT_JOYDEV is not set
-+CONFIG_INPUT_EVDEV=m
-+# CONFIG_INPUT_EVBUG is not set
-+
-+#
-+# Input Device Drivers
-+#
-+CONFIG_INPUT_KEYBOARD=y
-+# CONFIG_KEYBOARD_ATKBD is not set
-+# CONFIG_KEYBOARD_SUNKBD is not set
-+# CONFIG_KEYBOARD_LKKBD is not set
-+# CONFIG_KEYBOARD_XTKBD is not set
-+# CONFIG_KEYBOARD_NEWTON is not set
-+# CONFIG_KEYBOARD_STOWAWAY is not set
-+CONFIG_KEYBOARD_GPIO=m
-+CONFIG_INPUT_MOUSE=y
-+# CONFIG_MOUSE_PS2 is not set
-+# CONFIG_MOUSE_SERIAL is not set
-+# CONFIG_MOUSE_VSXXXAA is not set
-+CONFIG_MOUSE_GPIO=m
-+# CONFIG_INPUT_JOYSTICK is not set
-+# CONFIG_INPUT_TABLET is not set
-+# CONFIG_INPUT_TOUCHSCREEN is not set
-+# CONFIG_INPUT_MISC is not set
+-CONFIG_MMC_BLOCK=m
++CONFIG_MMC_BLOCK=y
+ CONFIG_MMC_BLOCK_BOUNCE=y
+ # CONFIG_SDIO_UART is not set
  
  #
- # Hardware I/O ports
-@@ -467,40 +583,94 @@
+ # MMC/SD Host Controller Drivers
  #
- CONFIG_SERIAL_ATMEL=y
- CONFIG_SERIAL_ATMEL_CONSOLE=y
-+CONFIG_SERIAL_ATMEL_PDC=y
- # CONFIG_SERIAL_ATMEL_TTYAT is not set
- CONFIG_SERIAL_CORE=y
- CONFIG_SERIAL_CORE_CONSOLE=y
- CONFIG_UNIX98_PTYS=y
- # CONFIG_LEGACY_PTYS is not set
--
--#
--# IPMI
--#
- # CONFIG_IPMI_HANDLER is not set
--# CONFIG_WATCHDOG is not set
- # CONFIG_HW_RANDOM is not set
- # CONFIG_RTC is not set
- # CONFIG_GEN_RTC is not set
- # CONFIG_R3964 is not set
- # CONFIG_RAW_DRIVER is not set
-+# CONFIG_TCG_TPM is not set
-+CONFIG_I2C=m
-+CONFIG_I2C_BOARDINFO=y
-+CONFIG_I2C_CHARDEV=m
-+
-+#
-+# I2C Algorithms
-+#
-+CONFIG_I2C_ALGOBIT=m
-+# CONFIG_I2C_ALGOPCF is not set
-+# CONFIG_I2C_ALGOPCA is not set
-+
-+#
-+# I2C Hardware Bus support
-+#
-+CONFIG_I2C_ATMELTWI=m
-+CONFIG_I2C_GPIO=m
-+# CONFIG_I2C_OCORES is not set
-+# CONFIG_I2C_PARPORT_LIGHT is not set
-+# CONFIG_I2C_SIMTEC is not set
-+# CONFIG_I2C_TAOS_EVM is not set
-+# CONFIG_I2C_STUB is not set
-+
-+#
-+# Miscellaneous I2C Chip support
-+#
-+# CONFIG_SENSORS_DS1337 is not set
-+# CONFIG_SENSORS_DS1374 is not set
-+# CONFIG_DS1682 is not set
-+# CONFIG_SENSORS_EEPROM is not set
-+# CONFIG_SENSORS_PCF8574 is not set
-+# CONFIG_SENSORS_PCA9539 is not set
-+# CONFIG_SENSORS_PCF8591 is not set
-+# CONFIG_SENSORS_MAX6875 is not set
-+# CONFIG_SENSORS_TSL2550 is not set
-+# CONFIG_I2C_DEBUG_CORE is not set
-+# CONFIG_I2C_DEBUG_ALGO is not set
-+# CONFIG_I2C_DEBUG_BUS is not set
-+# CONFIG_I2C_DEBUG_CHIP is not set
++CONFIG_MMC_ATMELMCI=y
+ CONFIG_MMC_SPI=m
++# CONFIG_MEMSTICK is not set
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=m
  
  #
--# TPM devices
-+# SPI support
+ # LED drivers
  #
--# CONFIG_TCG_TPM is not set
--# CONFIG_I2C is not set
-+CONFIG_SPI=y
-+# CONFIG_SPI_DEBUG is not set
-+CONFIG_SPI_MASTER=y
++CONFIG_LEDS_ATMEL_PWM=m
+ CONFIG_LEDS_GPIO=m
  
  #
--# SPI support
-+# SPI Master Controller Drivers
- #
--# CONFIG_SPI is not set
--# CONFIG_SPI_MASTER is not set
-+CONFIG_SPI_ATMEL=y
-+# CONFIG_SPI_BITBANG is not set
+@@ -853,19 +920,22 @@
+ # CONFIG_RTC_DRV_PCF8563 is not set
+ # CONFIG_RTC_DRV_PCF8583 is not set
+ # CONFIG_RTC_DRV_M41T80 is not set
++# CONFIG_RTC_DRV_S35390A is not set
  
  #
--# Dallas's 1-wire bus
-+# SPI Protocol Masters
+ # SPI RTC drivers
  #
-+# CONFIG_SPI_AT25 is not set
-+CONFIG_SPI_SPIDEV=m
-+# CONFIG_SPI_TLE62X0 is not set
- # CONFIG_W1 is not set
-+# CONFIG_POWER_SUPPLY is not set
- # CONFIG_HWMON is not set
-+CONFIG_WATCHDOG=y
-+# CONFIG_WATCHDOG_NOWAYOUT is not set
-+
-+#
-+# Watchdog Device Drivers
-+#
-+# CONFIG_SOFT_WATCHDOG is not set
-+CONFIG_AT32AP700X_WDT=y
-+
-+#
-+# Sonics Silicon Backplane
-+#
-+CONFIG_SSB_POSSIBLE=y
-+# CONFIG_SSB is not set
+-# CONFIG_RTC_DRV_RS5C348 is not set
+ # CONFIG_RTC_DRV_MAX6902 is not set
++# CONFIG_RTC_DRV_R9701 is not set
++# CONFIG_RTC_DRV_RS5C348 is not set
  
  #
- # Multifunction device drivers
-@@ -517,23 +687,104 @@
+ # Platform RTC drivers
  #
- # Graphics support
- #
--# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-+# CONFIG_VGASTATE is not set
-+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-+CONFIG_FB=y
-+# CONFIG_FIRMWARE_EDID is not set
-+# CONFIG_FB_DDC is not set
-+CONFIG_FB_CFB_FILLRECT=y
-+CONFIG_FB_CFB_COPYAREA=y
-+CONFIG_FB_CFB_IMAGEBLIT=y
-+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
-+# CONFIG_FB_SYS_FILLRECT is not set
-+# CONFIG_FB_SYS_COPYAREA is not set
-+# CONFIG_FB_SYS_IMAGEBLIT is not set
-+# CONFIG_FB_SYS_FOPS is not set
-+CONFIG_FB_DEFERRED_IO=y
-+# CONFIG_FB_SVGALIB is not set
-+# CONFIG_FB_MACMODES is not set
-+# CONFIG_FB_BACKLIGHT is not set
-+# CONFIG_FB_MODE_HELPERS is not set
-+# CONFIG_FB_TILEBLITTING is not set
-+
-+#
-+# Frame buffer hardware drivers
-+#
-+# CONFIG_FB_S1D13XXX is not set
-+CONFIG_FB_ATMEL=y
-+# CONFIG_FB_VIRTUAL is not set
-+CONFIG_BACKLIGHT_LCD_SUPPORT=y
-+CONFIG_LCD_CLASS_DEVICE=y
-+CONFIG_LCD_LTV350QV=y
-+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
- #
- # Display device support
- #
- # CONFIG_DISPLAY_SUPPORT is not set
--# CONFIG_VGASTATE is not set
--# CONFIG_FB is not set
-+# CONFIG_LOGO is not set
- #
- # Sound
- #
--# CONFIG_SOUND is not set
-+CONFIG_SOUND=m
-+
-+#
-+# Advanced Linux Sound Architecture
-+#
-+CONFIG_SND=m
-+CONFIG_SND_TIMER=m
-+CONFIG_SND_PCM=m
-+# CONFIG_SND_SEQUENCER is not set
-+CONFIG_SND_OSSEMUL=y
-+CONFIG_SND_MIXER_OSS=m
-+CONFIG_SND_PCM_OSS=m
-+CONFIG_SND_PCM_OSS_PLUGINS=y
-+# CONFIG_SND_DYNAMIC_MINORS is not set
-+# CONFIG_SND_SUPPORT_OLD_API is not set
-+# CONFIG_SND_VERBOSE_PROCFS is not set
-+# CONFIG_SND_VERBOSE_PRINTK is not set
-+# CONFIG_SND_DEBUG is not set
-+
-+#
-+# Generic devices
-+#
-+CONFIG_SND_AC97_CODEC=m
-+# CONFIG_SND_DUMMY is not set
-+# CONFIG_SND_MTPAV is not set
-+# CONFIG_SND_SERIAL_U16550 is not set
-+# CONFIG_SND_MPU401 is not set
-+
-+#
-+# AVR32 devices
-+#
-+CONFIG_SND_ATMEL_AC97=m
- #
--# USB support
-+# SPI devices
- #
-+CONFIG_SND_AT73C213=m
-+CONFIG_SND_AT73C213_TARGET_BITRATE=48000
-+
-+#
-+# System on Chip audio support
-+#
-+# CONFIG_SND_SOC is not set
-+
-+#
-+# SoC Audio support for SuperH
-+#
-+
-+#
-+# Open Sound System
-+#
-+CONFIG_SOUND_PRIME=m
-+# CONFIG_SOUND_MSNDCLAS is not set
-+# CONFIG_SOUND_MSNDPIN is not set
-+CONFIG_SOUND_AT32_ABDAC=m
-+CONFIG_AC97_BUS=m
-+# CONFIG_HID_SUPPORT is not set
-+CONFIG_USB_SUPPORT=y
- # CONFIG_USB_ARCH_HAS_HCD is not set
- # CONFIG_USB_ARCH_HAS_OHCI is not set
- # CONFIG_USB_ARCH_HAS_EHCI is not set
-@@ -545,63 +796,137 @@
- #
- # USB Gadget Support
- #
--# CONFIG_USB_GADGET is not set
--# CONFIG_MMC is not set
--
--#
--# LED devices
--#
--# CONFIG_NEW_LEDS is not set
-+CONFIG_USB_GADGET=y
-+# CONFIG_USB_GADGET_DEBUG is not set
-+# CONFIG_USB_GADGET_DEBUG_FILES is not set
-+# CONFIG_USB_GADGET_DEBUG_FS is not set
-+CONFIG_USB_GADGET_SELECTED=y
-+# CONFIG_USB_GADGET_AMD5536UDC is not set
-+CONFIG_USB_GADGET_ATMEL_USBA=y
-+CONFIG_USB_ATMEL_USBA=y
-+# CONFIG_USB_GADGET_FSL_USB2 is not set
-+# CONFIG_USB_GADGET_NET2280 is not set
-+# CONFIG_USB_GADGET_PXA2XX is not set
-+# CONFIG_USB_GADGET_M66592 is not set
-+# CONFIG_USB_GADGET_GOKU is not set
-+# CONFIG_USB_GADGET_LH7A40X is not set
-+# CONFIG_USB_GADGET_OMAP is not set
-+# CONFIG_USB_GADGET_S3C2410 is not set
-+# CONFIG_USB_GADGET_AT91 is not set
-+# CONFIG_USB_GADGET_DUMMY_HCD is not set
-+CONFIG_USB_GADGET_DUALSPEED=y
-+CONFIG_USB_ZERO=m
-+CONFIG_USB_ETH=m
-+CONFIG_USB_ETH_RNDIS=y
-+CONFIG_USB_GADGETFS=m
-+CONFIG_USB_FILE_STORAGE=m
-+# CONFIG_USB_FILE_STORAGE_TEST is not set
-+CONFIG_USB_G_SERIAL=m
-+# CONFIG_USB_MIDI_GADGET is not set
-+CONFIG_MMC=y
-+# CONFIG_MMC_DEBUG is not set
-+# CONFIG_MMC_UNSAFE_RESUME is not set
-+
-+#
-+# MMC/SD Card Drivers
-+#
-+CONFIG_MMC_BLOCK=y
-+# CONFIG_MMC_BLOCK_BOUNCE is not set
-+# CONFIG_SDIO_UART is not set
-+
-+#
-+# MMC/SD Host Controller Drivers
-+#
-+CONFIG_MMC_ATMELMCI=y
-+CONFIG_MMC_SPI=m
-+CONFIG_NEW_LEDS=y
-+CONFIG_LEDS_CLASS=m
- #
- # LED drivers
- #
-+CONFIG_LEDS_ATMEL_PWM=m
-+CONFIG_LEDS_GPIO=m
- #
- # LED Triggers
- #
-+CONFIG_LEDS_TRIGGERS=y
-+CONFIG_LEDS_TRIGGER_TIMER=m
-+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
-+CONFIG_RTC_LIB=y
-+CONFIG_RTC_CLASS=y
-+CONFIG_RTC_HCTOSYS=y
-+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
-+# CONFIG_RTC_DEBUG is not set
- #
--# InfiniBand support
-+# RTC interfaces
- #
-+CONFIG_RTC_INTF_SYSFS=y
-+CONFIG_RTC_INTF_PROC=y
-+CONFIG_RTC_INTF_DEV=y
-+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
-+# CONFIG_RTC_DRV_TEST is not set
- #
--# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-+# I2C RTC drivers
- #
-+# CONFIG_RTC_DRV_DS1307 is not set
-+# CONFIG_RTC_DRV_DS1374 is not set
-+# CONFIG_RTC_DRV_DS1672 is not set
-+# CONFIG_RTC_DRV_MAX6900 is not set
-+# CONFIG_RTC_DRV_RS5C372 is not set
-+# CONFIG_RTC_DRV_ISL1208 is not set
-+# CONFIG_RTC_DRV_X1205 is not set
-+# CONFIG_RTC_DRV_PCF8563 is not set
-+# CONFIG_RTC_DRV_PCF8583 is not set
-+# CONFIG_RTC_DRV_M41T80 is not set
- #
--# Real Time Clock
-+# SPI RTC drivers
- #
--# CONFIG_RTC_CLASS is not set
-+# CONFIG_RTC_DRV_RS5C348 is not set
-+# CONFIG_RTC_DRV_MAX6902 is not set
- #
--# DMA Engine support
-+# Platform RTC drivers
- #
--# CONFIG_DMA_ENGINE is not set
-+# CONFIG_RTC_DRV_DS1553 is not set
-+# CONFIG_RTC_DRV_STK17TA8 is not set
-+# CONFIG_RTC_DRV_DS1742 is not set
-+# CONFIG_RTC_DRV_M48T86 is not set
-+# CONFIG_RTC_DRV_M48T59 is not set
-+# CONFIG_RTC_DRV_V3020 is not set
- #
--# DMA Clients
-+# on-CPU RTC drivers
- #
-+CONFIG_RTC_DRV_AT32AP700X=y
- #
--# DMA Devices
-+# Userspace I/O
- #
-+# CONFIG_UIO is not set
++# CONFIG_RTC_DRV_DS1511 is not set
+ # CONFIG_RTC_DRV_DS1553 is not set
+-# CONFIG_RTC_DRV_STK17TA8 is not set
+ # CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
+ # CONFIG_RTC_DRV_M48T86 is not set
+ # CONFIG_RTC_DRV_M48T59 is not set
+ # CONFIG_RTC_DRV_V3020 is not set
+@@ -883,13 +953,13 @@
  #
  # File systems
  #
 +CONFIG_EXT2_FS=y
  # CONFIG_EXT2_FS_XATTR is not set
  # CONFIG_EXT2_FS_XIP is not set
--# CONFIG_EXT3_FS is not set
+-CONFIG_EXT3_FS=m
 +CONFIG_EXT3_FS=y
-+# CONFIG_EXT3_FS_XATTR is not set
+ # CONFIG_EXT3_FS_XATTR is not set
  # CONFIG_EXT4DEV_FS is not set
+-CONFIG_JBD=m
 +CONFIG_JBD=y
-+# CONFIG_JBD_DEBUG is not set
+ # CONFIG_JBD_DEBUG is not set
  # CONFIG_REISERFS_FS is not set
  # CONFIG_JFS_FS is not set
- # CONFIG_FS_POSIX_ACL is not set
+@@ -897,12 +967,10 @@
  # CONFIG_XFS_FS is not set
  # CONFIG_GFS2_FS is not set
  # CONFIG_OCFS2_FS is not set
 -CONFIG_MINIX_FS=m
-+# CONFIG_MINIX_FS is not set
- # CONFIG_ROMFS_FS is not set
+-# CONFIG_ROMFS_FS is not set
++# CONFIG_DNOTIFY is not set
  CONFIG_INOTIFY=y
  CONFIG_INOTIFY_USER=y
-@@ -609,7 +934,7 @@
- # CONFIG_DNOTIFY is not set
+ # CONFIG_QUOTA is not set
+-# CONFIG_DNOTIFY is not set
  # CONFIG_AUTOFS_FS is not set
  # CONFIG_AUTOFS4_FS is not set
--# CONFIG_FUSE_FS is not set
-+CONFIG_FUSE_FS=m
- #
- # CD-ROM/DVD Filesystems
-@@ -637,8 +962,7 @@
+ CONFIG_FUSE_FS=m
+@@ -933,7 +1001,7 @@
  CONFIG_TMPFS=y
  # CONFIG_TMPFS_POSIX_ACL is not set
  # CONFIG_HUGETLB_PAGE is not set
--CONFIG_RAMFS=y
--CONFIG_CONFIGFS_FS=m
+-# CONFIG_CONFIGFS_FS is not set
 +CONFIG_CONFIGFS_FS=y
  
  #
  # Miscellaneous filesystems
-@@ -652,11 +976,12 @@
- # CONFIG_EFS_FS is not set
- CONFIG_JFFS2_FS=y
- CONFIG_JFFS2_FS_DEBUG=0
--CONFIG_JFFS2_FS_WRITEBUFFER=y
-+# CONFIG_JFFS2_FS_WRITEBUFFER is not set
- # CONFIG_JFFS2_SUMMARY is not set
- # CONFIG_JFFS2_FS_XATTR is not set
- # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
- CONFIG_JFFS2_ZLIB=y
-+# CONFIG_JFFS2_LZO is not set
- CONFIG_JFFS2_RTIME=y
+@@ -957,8 +1025,10 @@
  # CONFIG_JFFS2_RUBIN is not set
  # CONFIG_CRAMFS is not set
-@@ -665,10 +990,7 @@
+ # CONFIG_VXFS_FS is not set
++CONFIG_MINIX_FS=m
+ # CONFIG_HPFS_FS is not set
  # CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
  # CONFIG_SYSV_FS is not set
  # CONFIG_UFS_FS is not set
--
--#
--# Network File Systems
--#
-+CONFIG_NETWORK_FILESYSTEMS=y
- CONFIG_NFS_FS=y
- CONFIG_NFS_V3=y
- # CONFIG_NFS_V3_ACL is not set
-@@ -688,17 +1010,12 @@
- # CONFIG_NCP_FS is not set
- # CONFIG_CODA_FS is not set
- # CONFIG_AFS_FS is not set
--# CONFIG_9P_FS is not set
- #
- # Partition Types
- #
- # CONFIG_PARTITION_ADVANCED is not set
- CONFIG_MSDOS_PARTITION=y
--
--#
--# Native Language Support
--#
- CONFIG_NLS=m
- CONFIG_NLS_DEFAULT="iso8859-1"
- CONFIG_NLS_CODEPAGE_437=m
-@@ -739,17 +1056,18 @@
- # CONFIG_NLS_KOI8_R is not set
+ CONFIG_NETWORK_FILESYSTEMS=y
+@@ -1028,11 +1098,6 @@
  # CONFIG_NLS_KOI8_U is not set
  CONFIG_NLS_UTF8=m
--
--#
--# Distributed Lock Manager
--#
  # CONFIG_DLM is not set
-+CONFIG_INSTRUMENTATION=y
-+CONFIG_PROFILING=y
-+CONFIG_OPROFILE=m
-+CONFIG_KPROBES=y
-+# CONFIG_MARKERS is not set
+-CONFIG_INSTRUMENTATION=y
+-CONFIG_PROFILING=y
+-CONFIG_OPROFILE=m
+-CONFIG_KPROBES=y
+-# CONFIG_MARKERS is not set
  
  #
  # Kernel hacking
- #
--CONFIG_TRACE_IRQFLAGS_SUPPORT=y
- # CONFIG_PRINTK_TIME is not set
-+CONFIG_ENABLE_WARN_DEPRECATED=y
- CONFIG_ENABLE_MUST_CHECK=y
- CONFIG_MAGIC_SYSRQ=y
- # CONFIG_UNUSED_SYMBOLS is not set
-@@ -758,12 +1076,17 @@
- CONFIG_DEBUG_KERNEL=y
- # CONFIG_DEBUG_SHIRQ is not set
- CONFIG_DETECT_SOFTLOCKUP=y
-+CONFIG_SCHED_DEBUG=y
+@@ -1051,6 +1116,7 @@
  # CONFIG_SCHEDSTATS is not set
  # CONFIG_TIMER_STATS is not set
-+# CONFIG_SLUB_DEBUG_ON is not set
+ # CONFIG_SLUB_DEBUG_ON is not set
++# CONFIG_SLUB_STATS is not set
  # CONFIG_DEBUG_RT_MUTEXES is not set
  # CONFIG_RT_MUTEX_TESTER is not set
  # CONFIG_DEBUG_SPINLOCK is not set
- # CONFIG_DEBUG_MUTEXES is not set
-+# CONFIG_DEBUG_LOCK_ALLOC is not set
-+# CONFIG_PROVE_LOCKING is not set
-+# CONFIG_LOCK_STAT is not set
- # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
- # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
- # CONFIG_DEBUG_KOBJECT is not set
-@@ -771,22 +1094,63 @@
- # CONFIG_DEBUG_INFO is not set
- # CONFIG_DEBUG_VM is not set
+@@ -1067,9 +1133,10 @@
  # CONFIG_DEBUG_LIST is not set
-+# CONFIG_DEBUG_SG is not set
+ # CONFIG_DEBUG_SG is not set
  CONFIG_FRAME_POINTER=y
- CONFIG_FORCED_INLINING=y
-+# CONFIG_BOOT_PRINTK_DELAY is not set
+-CONFIG_FORCED_INLINING=y
+ # CONFIG_BOOT_PRINTK_DELAY is not set
  # CONFIG_RCU_TORTURE_TEST is not set
-+# CONFIG_LKDTM is not set
++# CONFIG_KPROBES_SANITY_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
+ # CONFIG_LKDTM is not set
  # CONFIG_FAULT_INJECTION is not set
--# CONFIG_KPROBES is not set
-+# CONFIG_SAMPLES is not set
+ # CONFIG_SAMPLES is not set
+@@ -1082,7 +1149,9 @@
+ # CONFIG_SECURITY_FILE_CAPABILITIES is not set
+ CONFIG_CRYPTO=y
+ CONFIG_CRYPTO_ALGAPI=m
++CONFIG_CRYPTO_AEAD=m
+ CONFIG_CRYPTO_BLKCIPHER=m
++# CONFIG_CRYPTO_SEQIV is not set
+ CONFIG_CRYPTO_HASH=m
+ CONFIG_CRYPTO_MANAGER=m
+ CONFIG_CRYPTO_HMAC=m
+@@ -1101,6 +1170,9 @@
+ # CONFIG_CRYPTO_PCBC is not set
+ # CONFIG_CRYPTO_LRW is not set
+ # CONFIG_CRYPTO_XTS is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_CCM is not set
+ # CONFIG_CRYPTO_CRYPTD is not set
+ CONFIG_CRYPTO_DES=m
+ # CONFIG_CRYPTO_FCRYPT is not set
+@@ -1115,12 +1187,14 @@
+ # CONFIG_CRYPTO_KHAZAD is not set
+ # CONFIG_CRYPTO_ANUBIS is not set
+ # CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SALSA20 is not set
+ CONFIG_CRYPTO_DEFLATE=m
+ # CONFIG_CRYPTO_MICHAEL_MIC is not set
+ # CONFIG_CRYPTO_CRC32C is not set
+ # CONFIG_CRYPTO_CAMELLIA is not set
+ # CONFIG_CRYPTO_TEST is not set
+-# CONFIG_CRYPTO_AUTHENC is not set
++CONFIG_CRYPTO_AUTHENC=m
++# CONFIG_CRYPTO_LZO is not set
+ # CONFIG_CRYPTO_HW is not set
  
  #
- # Security options
+@@ -1135,6 +1209,7 @@
+ # CONFIG_LIBCRC32C is not set
+ CONFIG_ZLIB_INFLATE=y
+ CONFIG_ZLIB_DEFLATE=y
++CONFIG_GENERIC_ALLOCATOR=y
+ CONFIG_PLIST=y
+ CONFIG_HAS_IOMEM=y
+ CONFIG_HAS_IOPORT=y
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/configs/atstk1003_defconfig avr32-2.6/arch/avr32/configs/atstk1003_defconfig
+--- linux-2.6.25.6/arch/avr32/configs/atstk1003_defconfig      2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/configs/atstk1003_defconfig   2008-06-12 15:09:38.715815679 +0200
+@@ -1,7 +1,7 @@
  #
- # CONFIG_KEYS is not set
- # CONFIG_SECURITY is not set
--
--#
--# Cryptographic options
--#
--# CONFIG_CRYPTO is not set
-+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
-+CONFIG_CRYPTO=y
-+CONFIG_CRYPTO_ALGAPI=m
-+CONFIG_CRYPTO_BLKCIPHER=m
-+CONFIG_CRYPTO_HASH=m
-+CONFIG_CRYPTO_MANAGER=m
-+CONFIG_CRYPTO_HMAC=m
-+# CONFIG_CRYPTO_XCBC is not set
-+# CONFIG_CRYPTO_NULL is not set
-+# CONFIG_CRYPTO_MD4 is not set
-+CONFIG_CRYPTO_MD5=m
-+CONFIG_CRYPTO_SHA1=m
-+# CONFIG_CRYPTO_SHA256 is not set
-+# CONFIG_CRYPTO_SHA512 is not set
-+# CONFIG_CRYPTO_WP512 is not set
-+# CONFIG_CRYPTO_TGR192 is not set
-+# CONFIG_CRYPTO_GF128MUL is not set
-+# CONFIG_CRYPTO_ECB is not set
-+CONFIG_CRYPTO_CBC=m
-+# CONFIG_CRYPTO_PCBC is not set
-+# CONFIG_CRYPTO_LRW is not set
-+# CONFIG_CRYPTO_XTS is not set
-+# CONFIG_CRYPTO_CRYPTD is not set
-+CONFIG_CRYPTO_DES=m
-+# CONFIG_CRYPTO_FCRYPT is not set
-+# CONFIG_CRYPTO_BLOWFISH is not set
-+# CONFIG_CRYPTO_TWOFISH is not set
-+# CONFIG_CRYPTO_SERPENT is not set
-+# CONFIG_CRYPTO_AES is not set
-+# CONFIG_CRYPTO_CAST5 is not set
-+# CONFIG_CRYPTO_CAST6 is not set
-+# CONFIG_CRYPTO_TEA is not set
-+# CONFIG_CRYPTO_ARC4 is not set
-+# CONFIG_CRYPTO_KHAZAD is not set
-+# CONFIG_CRYPTO_ANUBIS is not set
-+# CONFIG_CRYPTO_SEED is not set
-+CONFIG_CRYPTO_DEFLATE=m
-+# CONFIG_CRYPTO_MICHAEL_MIC is not set
-+# CONFIG_CRYPTO_CRC32C is not set
-+# CONFIG_CRYPTO_CAMELLIA is not set
-+# CONFIG_CRYPTO_TEST is not set
-+# CONFIG_CRYPTO_AUTHENC is not set
-+# CONFIG_CRYPTO_HW is not set
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.24-rc7
+-# Wed Jan  9 22:54:34 2008
++# Linux kernel version: 2.6.25.4
++# Wed Jun 11 15:33:36 2008
+ #
+ CONFIG_AVR32=y
+ CONFIG_GENERIC_GPIO=y
+@@ -13,10 +13,10 @@
+ CONFIG_GENERIC_IRQ_PROBE=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
+ CONFIG_GENERIC_TIME=y
++CONFIG_GENERIC_CLOCKEVENTS=y
+ # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+ # CONFIG_ARCH_HAS_ILOG2_U32 is not set
+ # CONFIG_ARCH_HAS_ILOG2_U64 is not set
+-CONFIG_ARCH_SUPPORTS_OPROFILE=y
+ CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
+ CONFIG_GENERIC_BUG=y
+@@ -39,17 +39,15 @@
+ CONFIG_TASKSTATS=y
+ CONFIG_TASK_DELAY_ACCT=y
+ # CONFIG_TASK_XACCT is not set
+-# CONFIG_USER_NS is not set
+-# CONFIG_PID_NS is not set
+ CONFIG_AUDIT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_LOG_BUF_SHIFT=14
+ # CONFIG_CGROUPS is not set
+-CONFIG_FAIR_GROUP_SCHED=y
+-CONFIG_FAIR_USER_SCHED=y
+-# CONFIG_FAIR_CGROUP_SCHED is not set
++# CONFIG_GROUP_SCHED is not set
+ CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
+ CONFIG_RELAY=y
++# CONFIG_NAMESPACES is not set
+ CONFIG_BLK_DEV_INITRD=y
+ CONFIG_INITRAMFS_SOURCE=""
+ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+@@ -63,11 +61,13 @@
+ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
++# CONFIG_COMPAT_BRK is not set
+ # CONFIG_BASE_FULL is not set
+ CONFIG_FUTEX=y
+ CONFIG_ANON_INODES=y
+ CONFIG_EPOLL=y
+ CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
+ CONFIG_EVENTFD=y
+ CONFIG_SHMEM=y
+ CONFIG_VM_EVENT_COUNTERS=y
+@@ -75,6 +75,14 @@
+ # CONFIG_SLAB is not set
+ CONFIG_SLUB=y
+ # CONFIG_SLOB is not set
++CONFIG_PROFILING=y
++# CONFIG_MARKERS is not set
++CONFIG_OPROFILE=m
++CONFIG_HAVE_OPROFILE=y
++CONFIG_KPROBES=y
++CONFIG_HAVE_KPROBES=y
++# CONFIG_HAVE_KRETPROBES is not set
++CONFIG_PROC_PAGE_MONITOR=y
+ CONFIG_SLABINFO=y
+ CONFIG_RT_MUTEXES=y
+ # CONFIG_TINY_SHMEM is not set
+@@ -103,10 +111,15 @@
+ CONFIG_DEFAULT_CFQ=y
+ # CONFIG_DEFAULT_NOOP is not set
+ CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_CLASSIC_RCU=y
  
  #
- # Library routines
-@@ -794,10 +1158,10 @@
- CONFIG_BITREVERSE=y
- CONFIG_CRC_CCITT=m
- # CONFIG_CRC16 is not set
--# CONFIG_CRC_ITU_T is not set
-+CONFIG_CRC_ITU_T=m
- CONFIG_CRC32=y
-+CONFIG_CRC7=m
- # CONFIG_LIBCRC32C is not set
--CONFIG_AUDIT_GENERIC=y
- CONFIG_ZLIB_INFLATE=y
- CONFIG_ZLIB_DEFLATE=y
- CONFIG_PLIST=y
---- /dev/null
-+++ b/arch/avr32/configs/atstk1003_defconfig
-@@ -0,0 +1,1041 @@
+ # System Type and features
+ #
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+ CONFIG_SUBARCH_AVR32B=y
+ CONFIG_MMU=y
+ CONFIG_PERFORMANCE_COUNTERS=y
+@@ -118,12 +131,16 @@
+ # CONFIG_BOARD_ATSTK1002 is not set
+ CONFIG_BOARD_ATSTK1003=y
+ # CONFIG_BOARD_ATSTK1004 is not set
++# CONFIG_BOARD_ATSTK1006 is not set
+ # CONFIG_BOARD_ATSTK100X_CUSTOM is not set
+ # CONFIG_BOARD_ATSTK100X_SPI1 is not set
+ # CONFIG_BOARD_ATSTK1000_J2_LED is not set
+ # CONFIG_BOARD_ATSTK1000_J2_LED8 is not set
+ # CONFIG_BOARD_ATSTK1000_J2_RGB is not set
+ CONFIG_BOARD_ATSTK1000_EXTDAC=y
++# CONFIG_BOARD_ATSTK100X_ENABLE_AC97 is not set
++# CONFIG_BOARD_ATSTK1000_CF_HACKS is not set
++# CONFIG_BOARD_ATSTK100X_ENABLE_PSIF is not set
+ CONFIG_LOADER_U_BOOT=y
+ #
+@@ -132,6 +149,7 @@
+ # CONFIG_AP700X_32_BIT_SMC is not set
+ CONFIG_AP700X_16_BIT_SMC=y
+ # CONFIG_AP700X_8_BIT_SMC is not set
++CONFIG_GPIO_DEV=y
+ CONFIG_LOAD_ADDRESS=0x10000000
+ CONFIG_ENTRY_ADDRESS=0x90000000
+ CONFIG_PHYS_OFFSET=0x10000000
+@@ -157,16 +175,26 @@
+ CONFIG_ZONE_DMA_FLAG=0
+ CONFIG_VIRT_TO_BUS=y
+ # CONFIG_OWNERSHIP_TRACE is not set
++CONFIG_NMI_DEBUGGING=y
++CONFIG_DW_DMAC=y
+ # CONFIG_HZ_100 is not set
+ CONFIG_HZ_250=y
+ # CONFIG_HZ_300 is not set
+ # CONFIG_HZ_1000 is not set
+ CONFIG_HZ=250
++# CONFIG_SCHED_HRTICK is not set
+ CONFIG_CMDLINE=""
+ #
+ # Power management options
+ #
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_PM=y
++# CONFIG_PM_LEGACY is not set
++# CONFIG_PM_DEBUG is not set
++CONFIG_PM_SLEEP=y
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
+ #
+ # CPU Frequency scaling
+@@ -175,9 +203,9 @@
+ CONFIG_CPU_FREQ_TABLE=y
+ # CONFIG_CPU_FREQ_DEBUG is not set
+ # CONFIG_CPU_FREQ_STAT is not set
+-CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+ # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+-# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+ # CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+ # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+@@ -260,6 +288,7 @@
+ # CONFIG_NET_PKTGEN is not set
+ # CONFIG_NET_TCPPROBE is not set
+ # CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
+ # CONFIG_IRDA is not set
+ # CONFIG_BT is not set
+ # CONFIG_AF_RXRPC is not set
+@@ -376,13 +405,18 @@
+ CONFIG_BLK_DEV_RAM=m
+ CONFIG_BLK_DEV_RAM_COUNT=16
+ CONFIG_BLK_DEV_RAM_SIZE=4096
+-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
++# CONFIG_BLK_DEV_XIP is not set
+ # CONFIG_CDROM_PKTCDVD is not set
+ # CONFIG_ATA_OVER_ETH is not set
+ CONFIG_MISC_DEVICES=y
++CONFIG_ATMEL_PWM=m
++CONFIG_ATMEL_TCLIB=y
++CONFIG_ATMEL_TCB_CLKSRC=y
++CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0
+ # CONFIG_EEPROM_93CX6 is not set
+ CONFIG_ATMEL_SSC=m
+-# CONFIG_IDE is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_HAVE_IDE is not set
+ #
+ # SCSI device support
+@@ -427,6 +461,7 @@
+ # CONFIG_SCSI_DEBUG is not set
+ CONFIG_ATA=m
+ # CONFIG_ATA_NONSTANDARD is not set
++# CONFIG_SATA_MV is not set
+ CONFIG_PATA_AT32=m
+ # CONFIG_PATA_PLATFORM is not set
+ # CONFIG_MD is not set
+@@ -460,7 +495,6 @@
+ # CONFIG_PPPOL2TP is not set
+ # CONFIG_SLIP is not set
+ CONFIG_SLHC=m
+-# CONFIG_SHAPER is not set
+ # CONFIG_NETCONSOLE is not set
+ # CONFIG_NETPOLL is not set
+ # CONFIG_NET_POLL_CONTROLLER is not set
+@@ -528,6 +562,7 @@
+ #
+ CONFIG_SERIAL_ATMEL=y
+ CONFIG_SERIAL_ATMEL_CONSOLE=y
++CONFIG_SERIAL_ATMEL_PDC=y
+ # CONFIG_SERIAL_ATMEL_TTYAT is not set
+ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+@@ -535,8 +570,6 @@
+ # CONFIG_LEGACY_PTYS is not set
+ # CONFIG_IPMI_HANDLER is not set
+ # CONFIG_HW_RANDOM is not set
+-# CONFIG_RTC is not set
+-# CONFIG_GEN_RTC is not set
+ # CONFIG_R3964 is not set
+ # CONFIG_RAW_DRIVER is not set
+ # CONFIG_TCG_TPM is not set
+@@ -554,6 +587,7 @@
+ #
+ # I2C Hardware Bus support
+ #
++CONFIG_I2C_ATMELTWI=m
+ CONFIG_I2C_GPIO=m
+ # CONFIG_I2C_OCORES is not set
+ # CONFIG_I2C_PARPORT_LIGHT is not set
+@@ -564,13 +598,12 @@
+ #
+ # Miscellaneous I2C Chip support
+ #
+-# CONFIG_SENSORS_DS1337 is not set
+-# CONFIG_SENSORS_DS1374 is not set
+ # CONFIG_DS1682 is not set
+ # CONFIG_SENSORS_EEPROM is not set
+ # CONFIG_SENSORS_PCF8574 is not set
+-# CONFIG_SENSORS_PCA9539 is not set
++# CONFIG_PCF8575 is not set
+ # CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_TPS65010 is not set
+ # CONFIG_SENSORS_MAX6875 is not set
+ # CONFIG_SENSORS_TSL2550 is not set
+ # CONFIG_I2C_DEBUG_CORE is not set
+@@ -597,9 +630,27 @@
+ # CONFIG_SPI_AT25 is not set
+ CONFIG_SPI_SPIDEV=m
+ # CONFIG_SPI_TLE62X0 is not set
++CONFIG_HAVE_GPIO_LIB=y
++
 +#
-+# Automatically generated make config: don't edit
-+# Linux kernel version: 2.6.24
-+# Thu Mar  6 12:50:27 2008
++# GPIO Support
 +#
-+CONFIG_AVR32=y
-+CONFIG_GENERIC_GPIO=y
-+CONFIG_GENERIC_HARDIRQS=y
-+CONFIG_STACKTRACE_SUPPORT=y
-+CONFIG_LOCKDEP_SUPPORT=y
-+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-+CONFIG_HARDIRQS_SW_RESEND=y
-+CONFIG_GENERIC_IRQ_PROBE=y
-+CONFIG_RWSEM_GENERIC_SPINLOCK=y
-+CONFIG_GENERIC_TIME=y
-+CONFIG_GENERIC_CLOCKEVENTS=y
-+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
-+CONFIG_ARCH_SUPPORTS_OPROFILE=y
-+CONFIG_GENERIC_HWEIGHT=y
-+CONFIG_GENERIC_CALIBRATE_DELAY=y
-+CONFIG_GENERIC_BUG=y
-+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++# CONFIG_DEBUG_GPIO is not set
 +
 +#
-+# General setup
++# I2C GPIO expanders:
 +#
-+CONFIG_EXPERIMENTAL=y
-+CONFIG_BROKEN_ON_SMP=y
-+CONFIG_INIT_ENV_ARG_LIMIT=32
-+CONFIG_LOCALVERSION=""
-+# CONFIG_LOCALVERSION_AUTO is not set
-+CONFIG_SWAP=y
-+CONFIG_SYSVIPC=y
-+CONFIG_SYSVIPC_SYSCTL=y
-+CONFIG_POSIX_MQUEUE=y
-+CONFIG_BSD_PROCESS_ACCT=y
-+CONFIG_BSD_PROCESS_ACCT_V3=y
-+CONFIG_TASKSTATS=y
-+CONFIG_TASK_DELAY_ACCT=y
-+# CONFIG_TASK_XACCT is not set
-+# CONFIG_USER_NS is not set
-+# CONFIG_PID_NS is not set
-+CONFIG_AUDIT=y
-+# CONFIG_IKCONFIG is not set
-+CONFIG_LOG_BUF_SHIFT=14
-+# CONFIG_CGROUPS is not set
-+CONFIG_FAIR_GROUP_SCHED=y
-+CONFIG_FAIR_USER_SCHED=y
-+# CONFIG_FAIR_CGROUP_SCHED is not set
-+CONFIG_SYSFS_DEPRECATED=y
-+CONFIG_RELAY=y
-+CONFIG_BLK_DEV_INITRD=y
-+CONFIG_INITRAMFS_SOURCE=""
-+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-+CONFIG_SYSCTL=y
-+CONFIG_EMBEDDED=y
-+# CONFIG_SYSCTL_SYSCALL is not set
-+CONFIG_KALLSYMS=y
-+# CONFIG_KALLSYMS_ALL is not set
-+# CONFIG_KALLSYMS_EXTRA_PASS is not set
-+CONFIG_HOTPLUG=y
-+CONFIG_PRINTK=y
-+CONFIG_BUG=y
-+CONFIG_ELF_CORE=y
-+# CONFIG_BASE_FULL is not set
-+CONFIG_FUTEX=y
-+CONFIG_ANON_INODES=y
-+CONFIG_EPOLL=y
-+CONFIG_SIGNALFD=y
-+CONFIG_EVENTFD=y
-+CONFIG_SHMEM=y
-+CONFIG_VM_EVENT_COUNTERS=y
-+# CONFIG_SLUB_DEBUG is not set
-+# CONFIG_SLAB is not set
-+CONFIG_SLUB=y
-+# CONFIG_SLOB is not set
-+CONFIG_SLABINFO=y
-+CONFIG_RT_MUTEXES=y
-+# CONFIG_TINY_SHMEM is not set
-+CONFIG_BASE_SMALL=1
-+CONFIG_MODULES=y
-+CONFIG_MODULE_UNLOAD=y
-+# CONFIG_MODULE_FORCE_UNLOAD is not set
-+# CONFIG_MODVERSIONS is not set
-+# CONFIG_MODULE_SRCVERSION_ALL is not set
-+# CONFIG_KMOD is not set
-+CONFIG_BLOCK=y
-+# CONFIG_LBD is not set
-+# CONFIG_BLK_DEV_IO_TRACE is not set
-+# CONFIG_LSF is not set
-+# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
 +
 +#
-+# IO Schedulers
++# SPI GPIO expanders:
 +#
-+CONFIG_IOSCHED_NOOP=y
-+# CONFIG_IOSCHED_AS is not set
-+# CONFIG_IOSCHED_DEADLINE is not set
-+CONFIG_IOSCHED_CFQ=y
-+# CONFIG_DEFAULT_AS is not set
-+# CONFIG_DEFAULT_DEADLINE is not set
-+CONFIG_DEFAULT_CFQ=y
-+# CONFIG_DEFAULT_NOOP is not set
-+CONFIG_DEFAULT_IOSCHED="cfq"
++# CONFIG_GPIO_MCP23S08 is not set
+ # CONFIG_W1 is not set
+ # CONFIG_POWER_SUPPLY is not set
+ # CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
+ CONFIG_WATCHDOG=y
+ # CONFIG_WATCHDOG_NOWAYOUT is not set
+@@ -665,12 +716,18 @@
+ #
+ # Generic devices
+ #
++CONFIG_SND_AC97_CODEC=m
+ # CONFIG_SND_DUMMY is not set
+ # CONFIG_SND_MTPAV is not set
+ # CONFIG_SND_SERIAL_U16550 is not set
+ # CONFIG_SND_MPU401 is not set
+ #
++# AVR32 devices
++#
++CONFIG_SND_ATMEL_AC97=m
 +
 +#
-+# System Type and features
+ # SPI devices
+ #
+ CONFIG_SND_AT73C213=m
+@@ -686,9 +743,14 @@
+ #
+ #
++# ALSA SoC audio for Freescale SOCs
 +#
-+CONFIG_TICK_ONESHOT=y
-+CONFIG_NO_HZ=y
-+CONFIG_HIGH_RES_TIMERS=y
++
++#
+ # Open Sound System
+ #
+ # CONFIG_SOUND_PRIME is not set
++CONFIG_AC97_BUS=m
+ # CONFIG_HID_SUPPORT is not set
+ CONFIG_USB_SUPPORT=y
+ # CONFIG_USB_ARCH_HAS_HCD is not set
+@@ -698,10 +760,6 @@
+ #
+ # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+ #
+-
+-#
+-# USB Gadget Support
+-#
+ CONFIG_USB_GADGET=y
+ # CONFIG_USB_GADGET_DEBUG is not set
+ # CONFIG_USB_GADGET_DEBUG_FILES is not set
+@@ -729,27 +787,31 @@
+ # CONFIG_USB_FILE_STORAGE_TEST is not set
+ CONFIG_USB_G_SERIAL=m
+ # CONFIG_USB_MIDI_GADGET is not set
+-CONFIG_MMC=m
++# CONFIG_USB_G_PRINTER is not set
++CONFIG_MMC=y
+ # CONFIG_MMC_DEBUG is not set
+ # CONFIG_MMC_UNSAFE_RESUME is not set
+ #
+ # MMC/SD Card Drivers
+ #
+-CONFIG_MMC_BLOCK=m
++CONFIG_MMC_BLOCK=y
+ # CONFIG_MMC_BLOCK_BOUNCE is not set
+ # CONFIG_SDIO_UART is not set
+ #
+ # MMC/SD Host Controller Drivers
+ #
++CONFIG_MMC_ATMELMCI=y
+ CONFIG_MMC_SPI=m
++# CONFIG_MEMSTICK is not set
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+ #
+ # LED drivers
+ #
++CONFIG_LEDS_ATMEL_PWM=m
+ CONFIG_LEDS_GPIO=y
+ #
+@@ -786,19 +848,22 @@
+ # CONFIG_RTC_DRV_PCF8563 is not set
+ # CONFIG_RTC_DRV_PCF8583 is not set
+ # CONFIG_RTC_DRV_M41T80 is not set
++# CONFIG_RTC_DRV_S35390A is not set
+ #
+ # SPI RTC drivers
+ #
+-# CONFIG_RTC_DRV_RS5C348 is not set
+ # CONFIG_RTC_DRV_MAX6902 is not set
++# CONFIG_RTC_DRV_R9701 is not set
++# CONFIG_RTC_DRV_RS5C348 is not set
+ #
+ # Platform RTC drivers
+ #
++# CONFIG_RTC_DRV_DS1511 is not set
+ # CONFIG_RTC_DRV_DS1553 is not set
+-# CONFIG_RTC_DRV_STK17TA8 is not set
+ # CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
+ # CONFIG_RTC_DRV_M48T86 is not set
+ # CONFIG_RTC_DRV_M48T59 is not set
+ # CONFIG_RTC_DRV_V3020 is not set
+@@ -816,13 +881,13 @@
+ #
+ # File systems
+ #
+-CONFIG_EXT2_FS=m
++CONFIG_EXT2_FS=y
+ # CONFIG_EXT2_FS_XATTR is not set
+ # CONFIG_EXT2_FS_XIP is not set
+-CONFIG_EXT3_FS=m
++CONFIG_EXT3_FS=y
+ # CONFIG_EXT3_FS_XATTR is not set
+ # CONFIG_EXT4DEV_FS is not set
+-CONFIG_JBD=m
++CONFIG_JBD=y
+ # CONFIG_JBD_DEBUG is not set
+ # CONFIG_REISERFS_FS is not set
+ # CONFIG_JFS_FS is not set
+@@ -830,12 +895,10 @@
+ # CONFIG_XFS_FS is not set
+ # CONFIG_GFS2_FS is not set
+ # CONFIG_OCFS2_FS is not set
+-# CONFIG_MINIX_FS is not set
+-# CONFIG_ROMFS_FS is not set
++# CONFIG_DNOTIFY is not set
+ CONFIG_INOTIFY=y
+ CONFIG_INOTIFY_USER=y
+ # CONFIG_QUOTA is not set
+-# CONFIG_DNOTIFY is not set
+ # CONFIG_AUTOFS_FS is not set
+ # CONFIG_AUTOFS4_FS is not set
+ CONFIG_FUSE_FS=m
+@@ -866,7 +929,7 @@
+ CONFIG_TMPFS=y
+ # CONFIG_TMPFS_POSIX_ACL is not set
+ # CONFIG_HUGETLB_PAGE is not set
+-CONFIG_CONFIGFS_FS=m
++CONFIG_CONFIGFS_FS=y
+ #
+ # Miscellaneous filesystems
+@@ -891,8 +954,10 @@
+ # CONFIG_JFFS2_RUBIN is not set
+ # CONFIG_CRAMFS is not set
+ # CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
+ # CONFIG_HPFS_FS is not set
+ # CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
+ # CONFIG_SYSV_FS is not set
+ # CONFIG_UFS_FS is not set
+ # CONFIG_NETWORK_FILESYSTEMS is not set
+@@ -943,11 +1008,6 @@
+ # CONFIG_NLS_KOI8_U is not set
+ CONFIG_NLS_UTF8=m
+ # CONFIG_DLM is not set
+-CONFIG_INSTRUMENTATION=y
+-CONFIG_PROFILING=y
+-CONFIG_OPROFILE=m
+-CONFIG_KPROBES=y
+-# CONFIG_MARKERS is not set
+ #
+ # Kernel hacking
+@@ -965,6 +1025,7 @@
+ CONFIG_SCHED_DEBUG=y
+ # CONFIG_SCHEDSTATS is not set
+ # CONFIG_TIMER_STATS is not set
++# CONFIG_SLUB_STATS is not set
+ # CONFIG_DEBUG_RT_MUTEXES is not set
+ # CONFIG_RT_MUTEX_TESTER is not set
+ # CONFIG_DEBUG_SPINLOCK is not set
+@@ -981,9 +1042,10 @@
+ # CONFIG_DEBUG_LIST is not set
+ # CONFIG_DEBUG_SG is not set
+ CONFIG_FRAME_POINTER=y
+-CONFIG_FORCED_INLINING=y
+ # CONFIG_BOOT_PRINTK_DELAY is not set
+ # CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_KPROBES_SANITY_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
+ # CONFIG_LKDTM is not set
+ # CONFIG_FAULT_INJECTION is not set
+ # CONFIG_SAMPLES is not set
+@@ -1009,6 +1071,7 @@
+ CONFIG_AUDIT_GENERIC=y
+ CONFIG_ZLIB_INFLATE=y
+ CONFIG_ZLIB_DEFLATE=y
++CONFIG_GENERIC_ALLOCATOR=y
+ CONFIG_PLIST=y
+ CONFIG_HAS_IOMEM=y
+ CONFIG_HAS_IOPORT=y
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/configs/atstk1004_defconfig avr32-2.6/arch/avr32/configs/atstk1004_defconfig
+--- linux-2.6.25.6/arch/avr32/configs/atstk1004_defconfig      2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/configs/atstk1004_defconfig   2008-06-12 15:09:38.719815350 +0200
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.24-rc7
+-# Wed Jan  9 23:04:20 2008
++# Linux kernel version: 2.6.25.4
++# Wed Jun 11 15:37:49 2008
+ #
+ CONFIG_AVR32=y
+ CONFIG_GENERIC_GPIO=y
+@@ -13,10 +13,10 @@
+ CONFIG_GENERIC_IRQ_PROBE=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
+ CONFIG_GENERIC_TIME=y
++CONFIG_GENERIC_CLOCKEVENTS=y
+ # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+ # CONFIG_ARCH_HAS_ILOG2_U32 is not set
+ # CONFIG_ARCH_HAS_ILOG2_U64 is not set
+-CONFIG_ARCH_SUPPORTS_OPROFILE=y
+ CONFIG_GENERIC_HWEIGHT=y
+ CONFIG_GENERIC_CALIBRATE_DELAY=y
+ CONFIG_GENERIC_BUG=y
+@@ -34,15 +34,15 @@
+ # CONFIG_POSIX_MQUEUE is not set
+ # CONFIG_BSD_PROCESS_ACCT is not set
+ # CONFIG_TASKSTATS is not set
+-# CONFIG_USER_NS is not set
+-# CONFIG_PID_NS is not set
+ # CONFIG_AUDIT is not set
+ # CONFIG_IKCONFIG is not set
+ CONFIG_LOG_BUF_SHIFT=14
+ # CONFIG_CGROUPS is not set
+-# CONFIG_FAIR_GROUP_SCHED is not set
++# CONFIG_GROUP_SCHED is not set
+ CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
+ # CONFIG_RELAY is not set
++# CONFIG_NAMESPACES is not set
+ # CONFIG_BLK_DEV_INITRD is not set
+ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+ CONFIG_SYSCTL=y
+@@ -54,24 +54,37 @@
+ CONFIG_PRINTK=y
+ CONFIG_BUG=y
+ CONFIG_ELF_CORE=y
++# CONFIG_COMPAT_BRK is not set
+ # CONFIG_BASE_FULL is not set
+ # CONFIG_FUTEX is not set
+ # CONFIG_EPOLL is not set
+ # CONFIG_SIGNALFD is not set
++# CONFIG_TIMERFD is not set
+ # CONFIG_EVENTFD is not set
+ CONFIG_SHMEM=y
+ CONFIG_VM_EVENT_COUNTERS=y
+ # CONFIG_SLAB is not set
+ # CONFIG_SLUB is not set
+ CONFIG_SLOB=y
++# CONFIG_PROFILING is not set
++# CONFIG_MARKERS is not set
++CONFIG_HAVE_OPROFILE=y
++CONFIG_HAVE_KPROBES=y
++# CONFIG_HAVE_KRETPROBES is not set
++# CONFIG_PROC_PAGE_MONITOR is not set
+ # CONFIG_TINY_SHMEM is not set
+ CONFIG_BASE_SMALL=1
+ # CONFIG_MODULES is not set
+ # CONFIG_BLOCK is not set
++CONFIG_CLASSIC_RCU=y
+ #
+ # System Type and features
+ #
++# CONFIG_TICK_ONESHOT is not set
++# CONFIG_NO_HZ is not set
++# CONFIG_HIGH_RES_TIMERS is not set
 +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-+CONFIG_SUBARCH_AVR32B=y
-+CONFIG_MMU=y
-+CONFIG_PERFORMANCE_COUNTERS=y
-+CONFIG_PLATFORM_AT32AP=y
-+CONFIG_CPU_AT32AP700X=y
-+CONFIG_CPU_AT32AP7001=y
-+CONFIG_BOARD_ATSTK1000=y
-+# CONFIG_BOARD_ATNGW100 is not set
-+# CONFIG_BOARD_ATSTK1002 is not set
-+CONFIG_BOARD_ATSTK1003=y
-+# CONFIG_BOARD_ATSTK1004 is not set
-+# CONFIG_BOARD_ATSTK100X_CUSTOM is not set
-+# CONFIG_BOARD_ATSTK100X_SPI1 is not set
-+# CONFIG_BOARD_ATSTK1000_J2_LED is not set
-+# CONFIG_BOARD_ATSTK1000_J2_LED8 is not set
-+# CONFIG_BOARD_ATSTK1000_J2_RGB is not set
-+CONFIG_BOARD_ATSTK1000_EXTDAC=y
+ CONFIG_SUBARCH_AVR32B=y
+ CONFIG_MMU=y
+ CONFIG_PERFORMANCE_COUNTERS=y
+@@ -83,10 +96,14 @@
+ # CONFIG_BOARD_ATSTK1002 is not set
+ # CONFIG_BOARD_ATSTK1003 is not set
+ CONFIG_BOARD_ATSTK1004=y
++# CONFIG_BOARD_ATSTK1006 is not set
+ # CONFIG_BOARD_ATSTK100X_CUSTOM is not set
+ # CONFIG_BOARD_ATSTK100X_SPI1 is not set
+ # CONFIG_BOARD_ATSTK1000_J2_LED is not set
+ CONFIG_BOARD_ATSTK1000_EXTDAC=y
 +# CONFIG_BOARD_ATSTK100X_ENABLE_AC97 is not set
 +# CONFIG_BOARD_ATSTK1000_CF_HACKS is not set
 +# CONFIG_BOARD_ATSTK100X_ENABLE_PSIF is not set
-+CONFIG_LOADER_U_BOOT=y
-+
-+#
-+# Atmel AVR32 AP options
-+#
-+# CONFIG_AP700X_32_BIT_SMC is not set
-+CONFIG_AP700X_16_BIT_SMC=y
-+# CONFIG_AP700X_8_BIT_SMC is not set
-+CONFIG_GPIO_DEV=y
-+CONFIG_LOAD_ADDRESS=0x10000000
-+CONFIG_ENTRY_ADDRESS=0x90000000
-+CONFIG_PHYS_OFFSET=0x10000000
-+CONFIG_PREEMPT_NONE=y
-+# CONFIG_PREEMPT_VOLUNTARY is not set
-+# CONFIG_PREEMPT is not set
-+# CONFIG_HAVE_ARCH_BOOTMEM_NODE is not set
-+# CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set
-+# CONFIG_NEED_NODE_MEMMAP_SIZE is not set
-+CONFIG_ARCH_FLATMEM_ENABLE=y
-+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
-+# CONFIG_ARCH_SPARSEMEM_ENABLE is not set
-+CONFIG_SELECT_MEMORY_MODEL=y
-+CONFIG_FLATMEM_MANUAL=y
-+# CONFIG_DISCONTIGMEM_MANUAL is not set
-+# CONFIG_SPARSEMEM_MANUAL is not set
-+CONFIG_FLATMEM=y
-+CONFIG_FLAT_NODE_MEM_MAP=y
-+# CONFIG_SPARSEMEM_STATIC is not set
-+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
-+CONFIG_SPLIT_PTLOCK_CPUS=4
-+# CONFIG_RESOURCES_64BIT is not set
-+CONFIG_ZONE_DMA_FLAG=0
-+CONFIG_VIRT_TO_BUS=y
-+# CONFIG_OWNERSHIP_TRACE is not set
-+CONFIG_NMI_DEBUGGING=y
+ CONFIG_LOADER_U_BOOT=y
+ #
+@@ -95,6 +112,7 @@
+ # CONFIG_AP700X_32_BIT_SMC is not set
+ CONFIG_AP700X_16_BIT_SMC=y
+ # CONFIG_AP700X_8_BIT_SMC is not set
++# CONFIG_GPIO_DEV is not set
+ CONFIG_LOAD_ADDRESS=0x10000000
+ CONFIG_ENTRY_ADDRESS=0x90000000
+ CONFIG_PHYS_OFFSET=0x10000000
+@@ -120,34 +138,26 @@
+ CONFIG_ZONE_DMA_FLAG=0
+ CONFIG_VIRT_TO_BUS=y
+ # CONFIG_OWNERSHIP_TRACE is not set
++# CONFIG_NMI_DEBUGGING is not set
 +CONFIG_DW_DMAC=y
-+# CONFIG_HZ_100 is not set
-+CONFIG_HZ_250=y
-+# CONFIG_HZ_300 is not set
-+# CONFIG_HZ_1000 is not set
-+CONFIG_HZ=250
-+CONFIG_CMDLINE=""
-+
-+#
-+# Power management options
-+#
-+
-+#
-+# CPU Frequency scaling
-+#
-+CONFIG_CPU_FREQ=y
-+CONFIG_CPU_FREQ_TABLE=y
-+# CONFIG_CPU_FREQ_DEBUG is not set
-+# CONFIG_CPU_FREQ_STAT is not set
-+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
-+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
-+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
-+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
-+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
-+CONFIG_CPU_FREQ_GOV_USERSPACE=y
-+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
-+CONFIG_CPU_FREQ_AT32AP=y
+ # CONFIG_HZ_100 is not set
+ CONFIG_HZ_250=y
+ # CONFIG_HZ_300 is not set
+ # CONFIG_HZ_1000 is not set
+ CONFIG_HZ=250
++# CONFIG_SCHED_HRTICK is not set
+ CONFIG_CMDLINE=""
+ #
+ # Power management options
+ #
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++# CONFIG_PM is not set
+ #
+ # CPU Frequency scaling
+ #
+-CONFIG_CPU_FREQ=y
+-CONFIG_CPU_FREQ_TABLE=y
+-# CONFIG_CPU_FREQ_DEBUG is not set
+-# CONFIG_CPU_FREQ_STAT is not set
+-CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+-# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+-# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+-# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+-CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+-# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+-CONFIG_CPU_FREQ_GOV_USERSPACE=y
+-CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+-# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+-CONFIG_CPU_FREQ_AT32AP=y
++# CONFIG_CPU_FREQ is not set
+ #
+ # Bus options
+@@ -222,6 +232,7 @@
+ #
+ # CONFIG_NET_PKTGEN is not set
+ # CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
+ # CONFIG_IRDA is not set
+ # CONFIG_BT is not set
+ # CONFIG_AF_RXRPC is not set
+@@ -321,6 +332,7 @@
+ # CONFIG_MTD_UBI is not set
+ # CONFIG_PARPORT is not set
+ # CONFIG_MISC_DEVICES is not set
++# CONFIG_HAVE_IDE is not set
+ #
+ # SCSI device support
+@@ -358,6 +370,7 @@
+ #
+ CONFIG_SERIAL_ATMEL=y
+ CONFIG_SERIAL_ATMEL_CONSOLE=y
++# CONFIG_SERIAL_ATMEL_PDC is not set
+ # CONFIG_SERIAL_ATMEL_TTYAT is not set
+ CONFIG_SERIAL_CORE=y
+ CONFIG_SERIAL_CORE_CONSOLE=y
+@@ -365,8 +378,6 @@
+ # CONFIG_LEGACY_PTYS is not set
+ # CONFIG_IPMI_HANDLER is not set
+ # CONFIG_HW_RANDOM is not set
+-# CONFIG_RTC is not set
+-# CONFIG_GEN_RTC is not set
+ # CONFIG_R3964 is not set
+ # CONFIG_TCG_TPM is not set
+ # CONFIG_I2C is not set
+@@ -389,9 +400,24 @@
+ # CONFIG_SPI_AT25 is not set
+ # CONFIG_SPI_SPIDEV is not set
+ # CONFIG_SPI_TLE62X0 is not set
++CONFIG_HAVE_GPIO_LIB=y
 +
 +#
-+# Bus options
++# GPIO Support
 +#
-+# CONFIG_ARCH_SUPPORTS_MSI is not set
-+# CONFIG_PCCARD is not set
 +
 +#
-+# Executable file formats
++# I2C GPIO expanders:
 +#
-+CONFIG_BINFMT_ELF=y
-+# CONFIG_BINFMT_MISC is not set
 +
 +#
-+# Networking
-+#
-+CONFIG_NET=y
-+
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MCP23S08 is not set
+ # CONFIG_W1 is not set
+ # CONFIG_POWER_SUPPLY is not set
+ # CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
+ CONFIG_WATCHDOG=y
+ # CONFIG_WATCHDOG_NOWAYOUT is not set
+@@ -471,10 +497,6 @@
+ #
+ # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+ #
+-
+-#
+-# USB Gadget Support
+-#
+ CONFIG_USB_GADGET=y
+ # CONFIG_USB_GADGET_DEBUG_FILES is not set
+ CONFIG_USB_GADGET_SELECTED=y
+@@ -499,7 +521,9 @@
+ # CONFIG_USB_FILE_STORAGE is not set
+ # CONFIG_USB_G_SERIAL is not set
+ # CONFIG_USB_MIDI_GADGET is not set
++# CONFIG_USB_G_PRINTER is not set
+ # CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
+ # CONFIG_NEW_LEDS is not set
+ CONFIG_RTC_LIB=y
+ CONFIG_RTC_CLASS=y
+@@ -519,15 +543,17 @@
+ #
+ # SPI RTC drivers
+ #
+-# CONFIG_RTC_DRV_RS5C348 is not set
+ # CONFIG_RTC_DRV_MAX6902 is not set
++# CONFIG_RTC_DRV_R9701 is not set
++# CONFIG_RTC_DRV_RS5C348 is not set
+ #
+ # Platform RTC drivers
+ #
++# CONFIG_RTC_DRV_DS1511 is not set
+ # CONFIG_RTC_DRV_DS1553 is not set
+-# CONFIG_RTC_DRV_STK17TA8 is not set
+ # CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
+ # CONFIG_RTC_DRV_M48T86 is not set
+ # CONFIG_RTC_DRV_M48T59 is not set
+ # CONFIG_RTC_DRV_V3020 is not set
+@@ -545,9 +571,9 @@
+ #
+ # File systems
+ #
++# CONFIG_DNOTIFY is not set
+ # CONFIG_INOTIFY is not set
+ # CONFIG_QUOTA is not set
+-# CONFIG_DNOTIFY is not set
+ # CONFIG_AUTOFS_FS is not set
+ # CONFIG_AUTOFS4_FS is not set
+ # CONFIG_FUSE_FS is not set
+@@ -580,7 +606,6 @@
+ # CONFIG_NETWORK_FILESYSTEMS is not set
+ # CONFIG_NLS is not set
+ # CONFIG_DLM is not set
+-# CONFIG_INSTRUMENTATION is not set
+ #
+ # Kernel hacking
+@@ -616,6 +641,7 @@
+ # CONFIG_LIBCRC32C is not set
+ CONFIG_ZLIB_INFLATE=y
+ CONFIG_ZLIB_DEFLATE=y
++CONFIG_GENERIC_ALLOCATOR=y
+ CONFIG_HAS_IOMEM=y
+ CONFIG_HAS_IOPORT=y
+ CONFIG_HAS_DMA=y
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/configs/atstk1006_defconfig avr32-2.6/arch/avr32/configs/atstk1006_defconfig
+--- linux-2.6.25.6/arch/avr32/configs/atstk1006_defconfig      1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/arch/avr32/configs/atstk1006_defconfig   2008-06-12 15:09:38.719815350 +0200
+@@ -0,0 +1,1235 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.25.4
++# Wed Jun 11 15:40:45 2008
++#
++CONFIG_AVR32=y
++CONFIG_GENERIC_GPIO=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_TIME=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_ARCH_HAS_ILOG2_U32 is not set
++# CONFIG_ARCH_HAS_ILOG2_U64 is not set
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_GROUP_SCHED is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++CONFIG_RELAY=y
++# CONFIG_NAMESPACES is not set
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_EMBEDDED=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++# CONFIG_COMPAT_BRK is not set
++# CONFIG_BASE_FULL is not set
++CONFIG_FUTEX=y
++CONFIG_ANON_INODES=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_SLUB_DEBUG=y
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++# CONFIG_SLOB is not set
++CONFIG_PROFILING=y
++# CONFIG_MARKERS is not set
++CONFIG_OPROFILE=m
++CONFIG_HAVE_OPROFILE=y
++CONFIG_KPROBES=y
++CONFIG_HAVE_KPROBES=y
++# CONFIG_HAVE_KRETPROBES is not set
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=1
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_KMOD is not set
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF is not set
++# CONFIG_BLK_DEV_BSG is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++# CONFIG_IOSCHED_AS is not set
++# CONFIG_IOSCHED_DEADLINE is not set
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_AS is not set
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_CLASSIC_RCU=y
++
++#
++# System Type and features
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_SUBARCH_AVR32B=y
++CONFIG_MMU=y
++CONFIG_PERFORMANCE_COUNTERS=y
++CONFIG_PLATFORM_AT32AP=y
++CONFIG_CPU_AT32AP700X=y
++CONFIG_CPU_AT32AP7000=y
++CONFIG_BOARD_ATSTK1000=y
++# CONFIG_BOARD_ATNGW100 is not set
++# CONFIG_BOARD_ATSTK1002 is not set
++# CONFIG_BOARD_ATSTK1003 is not set
++# CONFIG_BOARD_ATSTK1004 is not set
++CONFIG_BOARD_ATSTK1006=y
++# CONFIG_BOARD_ATSTK100X_CUSTOM is not set
++# CONFIG_BOARD_ATSTK100X_SPI1 is not set
++# CONFIG_BOARD_ATSTK1000_J2_LED is not set
++# CONFIG_BOARD_ATSTK1000_J2_LED8 is not set
++# CONFIG_BOARD_ATSTK1000_J2_RGB is not set
++CONFIG_BOARD_ATSTK1000_EXTDAC=y
++# CONFIG_BOARD_ATSTK100X_ENABLE_AC97 is not set
++# CONFIG_BOARD_ATSTK1000_CF_HACKS is not set
++# CONFIG_BOARD_ATSTK100X_ENABLE_PSIF is not set
++CONFIG_LOADER_U_BOOT=y
++
++#
++# Atmel AVR32 AP options
++#
++# CONFIG_AP700X_32_BIT_SMC is not set
++CONFIG_AP700X_16_BIT_SMC=y
++# CONFIG_AP700X_8_BIT_SMC is not set
++CONFIG_GPIO_DEV=y
++CONFIG_LOAD_ADDRESS=0x10000000
++CONFIG_ENTRY_ADDRESS=0x90000000
++CONFIG_PHYS_OFFSET=0x10000000
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++# CONFIG_HAVE_ARCH_BOOTMEM_NODE is not set
++# CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set
++# CONFIG_NEED_NODE_MEMMAP_SIZE is not set
++CONFIG_ARCH_FLATMEM_ENABLE=y
++# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
++# CONFIG_ARCH_SPARSEMEM_ENABLE is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++# CONFIG_DISCONTIGMEM_MANUAL is not set
++# CONFIG_SPARSEMEM_MANUAL is not set
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++# CONFIG_SPARSEMEM_STATIC is not set
++# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_OWNERSHIP_TRACE is not set
++CONFIG_NMI_DEBUGGING=y
++CONFIG_DW_DMAC=y
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++# CONFIG_SCHED_HRTICK is not set
++CONFIG_CMDLINE=""
++
++#
++# Power management options
++#
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_PM=y
++# CONFIG_PM_LEGACY is not set
++# CONFIG_PM_DEBUG is not set
++CONFIG_PM_SLEEP=y
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_TABLE=y
++# CONFIG_CPU_FREQ_DEBUG is not set
++# CONFIG_CPU_FREQ_STAT is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++CONFIG_CPU_FREQ_AT32AP=y
++
++#
++# Bus options
++#
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Executable file formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Networking
++#
++CONFIG_NET=y
++
 +#
 +# Networking options
 +#
 +CONFIG_PACKET=y
 +CONFIG_PACKET_MMAP=y
 +CONFIG_UNIX=y
-+# CONFIG_NET_KEY is not set
++CONFIG_XFRM=y
++CONFIG_XFRM_USER=m
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++CONFIG_NET_KEY=m
++# CONFIG_NET_KEY_MIGRATE is not set
 +CONFIG_INET=y
 +# CONFIG_IP_MULTICAST is not set
 +# CONFIG_IP_ADVANCED_ROUTER is not set
 +CONFIG_IP_FIB_HASH=y
-+# CONFIG_IP_PNP is not set
-+# CONFIG_NET_IPIP is not set
-+# CONFIG_NET_IPGRE is not set
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++# CONFIG_IP_PNP_BOOTP is not set
++# CONFIG_IP_PNP_RARP is not set
++CONFIG_NET_IPIP=m
++CONFIG_NET_IPGRE=m
 +# CONFIG_ARPD is not set
 +# CONFIG_SYN_COOKIES is not set
-+# CONFIG_INET_AH is not set
-+# CONFIG_INET_ESP is not set
++CONFIG_INET_AH=m
++CONFIG_INET_ESP=m
 +# CONFIG_INET_IPCOMP is not set
 +# CONFIG_INET_XFRM_TUNNEL is not set
-+# CONFIG_INET_TUNNEL is not set
-+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-+# CONFIG_INET_XFRM_MODE_BEET is not set
++CONFIG_INET_TUNNEL=m
++CONFIG_INET_XFRM_MODE_TRANSPORT=m
++CONFIG_INET_XFRM_MODE_TUNNEL=m
++CONFIG_INET_XFRM_MODE_BEET=m
 +# CONFIG_INET_LRO is not set
-+# CONFIG_INET_DIAG is not set
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
 +# CONFIG_TCP_CONG_ADVANCED is not set
 +CONFIG_TCP_CONG_CUBIC=y
 +CONFIG_DEFAULT_TCP_CONG="cubic"
 +# CONFIG_TCP_MD5SIG is not set
-+# CONFIG_IPV6 is not set
-+# CONFIG_INET6_XFRM_TUNNEL is not set
-+# CONFIG_INET6_TUNNEL is not set
-+# CONFIG_NETWORK_SECMARK is not set
-+# CONFIG_NETFILTER is not set
-+# CONFIG_IP_DCCP is not set
-+# CONFIG_IP_SCTP is not set
-+# CONFIG_TIPC is not set
-+# CONFIG_ATM is not set
-+# CONFIG_BRIDGE is not set
++CONFIG_IPV6=m
++# CONFIG_IPV6_PRIVACY is not set
++# CONFIG_IPV6_ROUTER_PREF is not set
++# CONFIG_IPV6_OPTIMISTIC_DAD is not set
++CONFIG_INET6_AH=m
++CONFIG_INET6_ESP=m
++CONFIG_INET6_IPCOMP=m
++# CONFIG_IPV6_MIP6 is not set
++CONFIG_INET6_XFRM_TUNNEL=m
++CONFIG_INET6_TUNNEL=m
++CONFIG_INET6_XFRM_MODE_TRANSPORT=m
++CONFIG_INET6_XFRM_MODE_TUNNEL=m
++CONFIG_INET6_XFRM_MODE_BEET=m
++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
++CONFIG_IPV6_SIT=m
++CONFIG_IPV6_TUNNEL=m
++# CONFIG_IPV6_MULTIPLE_TABLES is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++CONFIG_BRIDGE=m
 +# CONFIG_VLAN_8021Q is not set
 +# CONFIG_DECNET is not set
++CONFIG_LLC=m
 +# CONFIG_LLC2 is not set
 +# CONFIG_IPX is not set
 +# CONFIG_ATALK is not set
 +# CONFIG_NET_PKTGEN is not set
 +# CONFIG_NET_TCPPROBE is not set
 +# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
 +# CONFIG_IRDA is not set
 +# CONFIG_BT is not set
 +# CONFIG_AF_RXRPC is not set
 +# CONFIG_MTD_DOC2000 is not set
 +# CONFIG_MTD_DOC2001 is not set
 +# CONFIG_MTD_DOC2001PLUS is not set
-+# CONFIG_MTD_NAND is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_VERIFY_WRITE is not set
++# CONFIG_MTD_NAND_ECC_SMC is not set
++# CONFIG_MTD_NAND_MUSEUM_IDS is not set
++CONFIG_MTD_NAND_IDS=y
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++CONFIG_MTD_NAND_ATMEL=y
++CONFIG_MTD_NAND_ATMEL_ECC_HW=y
++# CONFIG_MTD_NAND_ATMEL_ECC_SOFT is not set
++# CONFIG_MTD_NAND_ATMEL_ECC_NONE is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
 +# CONFIG_MTD_ONENAND is not set
 +
 +#
 +# UBI - Unsorted block images
 +#
-+# CONFIG_MTD_UBI is not set
++CONFIG_MTD_UBI=m
++CONFIG_MTD_UBI_WL_THRESHOLD=4096
++CONFIG_MTD_UBI_BEB_RESERVE=1
++CONFIG_MTD_UBI_GLUEBI=y
++
++#
++# UBI debugging options
++#
++# CONFIG_MTD_UBI_DEBUG is not set
 +# CONFIG_PARPORT is not set
 +CONFIG_BLK_DEV=y
 +# CONFIG_BLK_DEV_COW_COMMON is not set
 +CONFIG_BLK_DEV_RAM=m
 +CONFIG_BLK_DEV_RAM_COUNT=16
 +CONFIG_BLK_DEV_RAM_SIZE=4096
-+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
++# CONFIG_BLK_DEV_XIP is not set
 +# CONFIG_CDROM_PKTCDVD is not set
 +# CONFIG_ATA_OVER_ETH is not set
 +CONFIG_MISC_DEVICES=y
 +CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0
 +# CONFIG_EEPROM_93CX6 is not set
 +CONFIG_ATMEL_SSC=m
-+# CONFIG_IDE is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_HAVE_IDE is not set
 +
 +#
 +# SCSI device support
 +# CONFIG_SCSI_ISCSI_ATTRS is not set
 +# CONFIG_SCSI_SAS_LIBSAS is not set
 +# CONFIG_SCSI_SRP_ATTRS is not set
-+CONFIG_SCSI_LOWLEVEL=y
-+# CONFIG_ISCSI_TCP is not set
-+# CONFIG_SCSI_DEBUG is not set
++# CONFIG_SCSI_LOWLEVEL is not set
 +CONFIG_ATA=m
 +# CONFIG_ATA_NONSTANDARD is not set
++# CONFIG_SATA_MV is not set
 +CONFIG_PATA_AT32=m
 +# CONFIG_PATA_PLATFORM is not set
 +# CONFIG_MD is not set
 +# CONFIG_BONDING is not set
 +# CONFIG_MACVLAN is not set
 +# CONFIG_EQUALIZER is not set
-+# CONFIG_TUN is not set
++CONFIG_TUN=m
 +# CONFIG_VETH is not set
-+# CONFIG_NET_ETHERNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++CONFIG_NET_ETHERNET=y
++# CONFIG_MII is not set
++CONFIG_MACB=y
++# CONFIG_ENC28J60 is not set
++# CONFIG_IBM_NEW_EMAC_ZMII is not set
++# CONFIG_IBM_NEW_EMAC_RGMII is not set
++# CONFIG_IBM_NEW_EMAC_TAH is not set
++# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
++# CONFIG_B44 is not set
 +# CONFIG_NETDEV_1000 is not set
 +# CONFIG_NETDEV_10000 is not set
 +
 +# CONFIG_PPPOL2TP is not set
 +# CONFIG_SLIP is not set
 +CONFIG_SLHC=m
-+# CONFIG_SHAPER is not set
 +# CONFIG_NETCONSOLE is not set
 +# CONFIG_NETPOLL is not set
 +# CONFIG_NET_POLL_CONTROLLER is not set
 +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 +# CONFIG_INPUT_JOYDEV is not set
-+# CONFIG_INPUT_EVDEV is not set
++CONFIG_INPUT_EVDEV=m
 +# CONFIG_INPUT_EVBUG is not set
 +
 +#
 +# CONFIG_LEGACY_PTYS is not set
 +# CONFIG_IPMI_HANDLER is not set
 +# CONFIG_HW_RANDOM is not set
-+# CONFIG_RTC is not set
-+# CONFIG_GEN_RTC is not set
 +# CONFIG_R3964 is not set
 +# CONFIG_RAW_DRIVER is not set
 +# CONFIG_TCG_TPM is not set
 +#
 +# Miscellaneous I2C Chip support
 +#
-+# CONFIG_SENSORS_DS1337 is not set
-+# CONFIG_SENSORS_DS1374 is not set
 +# CONFIG_DS1682 is not set
 +# CONFIG_SENSORS_EEPROM is not set
 +# CONFIG_SENSORS_PCF8574 is not set
-+# CONFIG_SENSORS_PCA9539 is not set
++# CONFIG_PCF8575 is not set
 +# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_TPS65010 is not set
 +# CONFIG_SENSORS_MAX6875 is not set
 +# CONFIG_SENSORS_TSL2550 is not set
 +# CONFIG_I2C_DEBUG_CORE is not set
 +# CONFIG_SPI_AT25 is not set
 +CONFIG_SPI_SPIDEV=m
 +# CONFIG_SPI_TLE62X0 is not set
++CONFIG_HAVE_GPIO_LIB=y
++
++#
++# GPIO Support
++#
++# CONFIG_DEBUG_GPIO is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MCP23S08 is not set
 +# CONFIG_W1 is not set
 +# CONFIG_POWER_SUPPLY is not set
 +# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
 +CONFIG_WATCHDOG=y
 +# CONFIG_WATCHDOG_NOWAYOUT is not set
 +
 +#
 +# CONFIG_VGASTATE is not set
 +# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-+# CONFIG_FB is not set
-+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_SYS_FOPS is not set
++CONFIG_FB_DEFERRED_IO=y
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++# CONFIG_FB_MODE_HELPERS is not set
++# CONFIG_FB_TILEBLITTING is not set
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_S1D13XXX is not set
++CONFIG_FB_ATMEL=y
++# CONFIG_FB_VIRTUAL is not set
++CONFIG_BACKLIGHT_LCD_SUPPORT=y
++CONFIG_LCD_CLASS_DEVICE=y
++CONFIG_LCD_LTV350QV=y
++# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
 +
 +#
 +# Display device support
 +#
 +# CONFIG_DISPLAY_SUPPORT is not set
++# CONFIG_LOGO is not set
 +
 +#
 +# Sound
 +CONFIG_SND_PCM_OSS=m
 +CONFIG_SND_PCM_OSS_PLUGINS=y
 +# CONFIG_SND_DYNAMIC_MINORS is not set
-+CONFIG_SND_SUPPORT_OLD_API=y
-+CONFIG_SND_VERBOSE_PROCFS=y
++# CONFIG_SND_SUPPORT_OLD_API is not set
++# CONFIG_SND_VERBOSE_PROCFS is not set
 +# CONFIG_SND_VERBOSE_PRINTK is not set
 +# CONFIG_SND_DEBUG is not set
 +
 +#
 +
 +#
++# ALSA SoC audio for Freescale SOCs
++#
++
++#
 +# Open Sound System
 +#
 +# CONFIG_SOUND_PRIME is not set
 +#
 +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
 +#
-+
-+#
-+# USB Gadget Support
-+#
 +CONFIG_USB_GADGET=y
 +# CONFIG_USB_GADGET_DEBUG is not set
 +# CONFIG_USB_GADGET_DEBUG_FILES is not set
-+CONFIG_USB_GADGET_DEBUG_FS=y
++# CONFIG_USB_GADGET_DEBUG_FS is not set
 +CONFIG_USB_GADGET_SELECTED=y
 +# CONFIG_USB_GADGET_AMD5536UDC is not set
 +CONFIG_USB_GADGET_ATMEL_USBA=y
 +# CONFIG_USB_FILE_STORAGE_TEST is not set
 +CONFIG_USB_G_SERIAL=m
 +# CONFIG_USB_MIDI_GADGET is not set
++# CONFIG_USB_G_PRINTER is not set
 +CONFIG_MMC=y
 +# CONFIG_MMC_DEBUG is not set
 +# CONFIG_MMC_UNSAFE_RESUME is not set
 +# MMC/SD Card Drivers
 +#
 +CONFIG_MMC_BLOCK=y
-+# CONFIG_MMC_BLOCK_BOUNCE is not set
++CONFIG_MMC_BLOCK_BOUNCE=y
 +# CONFIG_SDIO_UART is not set
 +
 +#
 +#
 +CONFIG_MMC_ATMELMCI=y
 +CONFIG_MMC_SPI=m
++# CONFIG_MEMSTICK is not set
 +CONFIG_NEW_LEDS=y
-+CONFIG_LEDS_CLASS=y
++CONFIG_LEDS_CLASS=m
 +
 +#
 +# LED drivers
 +#
 +CONFIG_LEDS_ATMEL_PWM=m
-+CONFIG_LEDS_GPIO=y
++CONFIG_LEDS_GPIO=m
 +
 +#
 +# LED Triggers
 +#
 +CONFIG_LEDS_TRIGGERS=y
-+CONFIG_LEDS_TRIGGER_TIMER=y
-+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
++CONFIG_LEDS_TRIGGER_TIMER=m
++CONFIG_LEDS_TRIGGER_HEARTBEAT=m
 +CONFIG_RTC_LIB=y
 +CONFIG_RTC_CLASS=y
 +CONFIG_RTC_HCTOSYS=y
 +# CONFIG_RTC_DRV_PCF8563 is not set
 +# CONFIG_RTC_DRV_PCF8583 is not set
 +# CONFIG_RTC_DRV_M41T80 is not set
++# CONFIG_RTC_DRV_S35390A is not set
 +
 +#
 +# SPI RTC drivers
 +#
-+# CONFIG_RTC_DRV_RS5C348 is not set
 +# CONFIG_RTC_DRV_MAX6902 is not set
++# CONFIG_RTC_DRV_R9701 is not set
++# CONFIG_RTC_DRV_RS5C348 is not set
 +
 +#
 +# Platform RTC drivers
 +#
++# CONFIG_RTC_DRV_DS1511 is not set
 +# CONFIG_RTC_DRV_DS1553 is not set
-+# CONFIG_RTC_DRV_STK17TA8 is not set
 +# CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
 +# CONFIG_RTC_DRV_M48T86 is not set
 +# CONFIG_RTC_DRV_M48T59 is not set
 +# CONFIG_RTC_DRV_V3020 is not set
 +#
 +# Userspace I/O
 +#
-+CONFIG_UIO=m
++# CONFIG_UIO is not set
 +
 +#
 +# File systems
 +#
-+CONFIG_EXT2_FS=m
++CONFIG_EXT2_FS=y
 +# CONFIG_EXT2_FS_XATTR is not set
 +# CONFIG_EXT2_FS_XIP is not set
-+CONFIG_EXT3_FS=m
++CONFIG_EXT3_FS=y
 +# CONFIG_EXT3_FS_XATTR is not set
 +# CONFIG_EXT4DEV_FS is not set
-+CONFIG_JBD=m
++CONFIG_JBD=y
 +# CONFIG_JBD_DEBUG is not set
 +# CONFIG_REISERFS_FS is not set
 +# CONFIG_JFS_FS is not set
 +# CONFIG_XFS_FS is not set
 +# CONFIG_GFS2_FS is not set
 +# CONFIG_OCFS2_FS is not set
-+# CONFIG_MINIX_FS is not set
-+# CONFIG_ROMFS_FS is not set
++# CONFIG_DNOTIFY is not set
 +CONFIG_INOTIFY=y
 +CONFIG_INOTIFY_USER=y
 +# CONFIG_QUOTA is not set
-+# CONFIG_DNOTIFY is not set
 +# CONFIG_AUTOFS_FS is not set
 +# CONFIG_AUTOFS4_FS is not set
 +CONFIG_FUSE_FS=m
 +# CONFIG_EFS_FS is not set
 +CONFIG_JFFS2_FS=y
 +CONFIG_JFFS2_FS_DEBUG=0
-+CONFIG_JFFS2_FS_WRITEBUFFER=y
-+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
++# CONFIG_JFFS2_FS_WRITEBUFFER is not set
 +# CONFIG_JFFS2_SUMMARY is not set
 +# CONFIG_JFFS2_FS_XATTR is not set
 +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 +# CONFIG_JFFS2_RUBIN is not set
 +# CONFIG_CRAMFS is not set
 +# CONFIG_VXFS_FS is not set
++CONFIG_MINIX_FS=m
 +# CONFIG_HPFS_FS is not set
 +# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
 +# CONFIG_SYSV_FS is not set
 +# CONFIG_UFS_FS is not set
-+# CONFIG_NETWORK_FILESYSTEMS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFS_DIRECTIO is not set
++# CONFIG_NFSD is not set
++CONFIG_ROOT_NFS=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_SUNRPC_BIND34 is not set
++# CONFIG_RPCSEC_GSS_KRB5 is not set
++# CONFIG_RPCSEC_GSS_SPKM3 is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
 +
 +#
 +# Partition Types
 +# CONFIG_NLS_KOI8_U is not set
 +CONFIG_NLS_UTF8=m
 +# CONFIG_DLM is not set
-+CONFIG_INSTRUMENTATION=y
-+CONFIG_PROFILING=y
-+CONFIG_OPROFILE=m
-+CONFIG_KPROBES=y
-+# CONFIG_MARKERS is not set
 +
 +#
 +# Kernel hacking
 +CONFIG_SCHED_DEBUG=y
 +# CONFIG_SCHEDSTATS is not set
 +# CONFIG_TIMER_STATS is not set
++# CONFIG_SLUB_DEBUG_ON is not set
++# CONFIG_SLUB_STATS is not set
 +# CONFIG_DEBUG_RT_MUTEXES is not set
 +# CONFIG_RT_MUTEX_TESTER is not set
 +# CONFIG_DEBUG_SPINLOCK is not set
 +# CONFIG_DEBUG_LIST is not set
 +# CONFIG_DEBUG_SG is not set
 +CONFIG_FRAME_POINTER=y
-+CONFIG_FORCED_INLINING=y
 +# CONFIG_BOOT_PRINTK_DELAY is not set
 +# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_KPROBES_SANITY_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
 +# CONFIG_LKDTM is not set
 +# CONFIG_FAULT_INJECTION is not set
 +# CONFIG_SAMPLES is not set
 +# CONFIG_KEYS is not set
 +# CONFIG_SECURITY is not set
 +# CONFIG_SECURITY_FILE_CAPABILITIES is not set
-+# CONFIG_CRYPTO is not set
++CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ALGAPI=m
++CONFIG_CRYPTO_AEAD=m
++CONFIG_CRYPTO_BLKCIPHER=m
++# CONFIG_CRYPTO_SEQIV is not set
++CONFIG_CRYPTO_HASH=m
++CONFIG_CRYPTO_MANAGER=m
++CONFIG_CRYPTO_HMAC=m
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_MD4 is not set
++CONFIG_CRYPTO_MD5=m
++CONFIG_CRYPTO_SHA1=m
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_WP512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_ECB is not set
++CONFIG_CRYPTO_CBC=m
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_XTS is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++CONFIG_CRYPTO_DES=m
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_ARC4 is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++CONFIG_CRYPTO_DEFLATE=m
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_TEST is not set
++CONFIG_CRYPTO_AUTHENC=m
++# CONFIG_CRYPTO_LZO is not set
++# CONFIG_CRYPTO_HW is not set
 +
 +#
 +# Library routines
 +CONFIG_CRC32=y
 +CONFIG_CRC7=m
 +# CONFIG_LIBCRC32C is not set
-+CONFIG_AUDIT_GENERIC=y
 +CONFIG_ZLIB_INFLATE=y
 +CONFIG_ZLIB_DEFLATE=y
++CONFIG_GENERIC_ALLOCATOR=y
 +CONFIG_PLIST=y
 +CONFIG_HAS_IOMEM=y
 +CONFIG_HAS_IOPORT=y
 +CONFIG_HAS_DMA=y
---- /dev/null
-+++ b/arch/avr32/configs/atstk1004_defconfig
-@@ -0,0 +1,639 @@
-+#
-+# Automatically generated make config: don't edit
-+# Linux kernel version: 2.6.24
-+# Thu Mar  6 12:51:05 2008
-+#
-+CONFIG_AVR32=y
-+CONFIG_GENERIC_GPIO=y
-+CONFIG_GENERIC_HARDIRQS=y
-+CONFIG_STACKTRACE_SUPPORT=y
-+CONFIG_LOCKDEP_SUPPORT=y
-+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-+CONFIG_HARDIRQS_SW_RESEND=y
-+CONFIG_GENERIC_IRQ_PROBE=y
-+CONFIG_RWSEM_GENERIC_SPINLOCK=y
-+CONFIG_GENERIC_TIME=y
-+CONFIG_GENERIC_CLOCKEVENTS=y
-+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
-+CONFIG_ARCH_SUPPORTS_OPROFILE=y
-+CONFIG_GENERIC_HWEIGHT=y
-+CONFIG_GENERIC_CALIBRATE_DELAY=y
-+CONFIG_GENERIC_BUG=y
-+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/drivers/dw-dmac.c avr32-2.6/arch/avr32/drivers/dw-dmac.c
+--- linux-2.6.25.6/arch/avr32/drivers/dw-dmac.c        1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/arch/avr32/drivers/dw-dmac.c     2008-06-12 15:09:38.719815350 +0200
+@@ -0,0 +1,761 @@
++/*
++ * Driver for the Synopsys DesignWare DMA Controller
++ *
++ * Copyright (C) 2005-2006 Atmel Corporation
++ *
++ * 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/clk.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/dmapool.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
 +
-+#
-+# General setup
-+#
-+CONFIG_EXPERIMENTAL=y
-+CONFIG_BROKEN_ON_SMP=y
-+CONFIG_INIT_ENV_ARG_LIMIT=32
-+CONFIG_LOCALVERSION=""
-+# CONFIG_LOCALVERSION_AUTO is not set
-+# CONFIG_SYSVIPC is not set
-+# CONFIG_POSIX_MQUEUE is not set
-+# CONFIG_BSD_PROCESS_ACCT is not set
-+# CONFIG_TASKSTATS is not set
-+# CONFIG_USER_NS is not set
-+# CONFIG_PID_NS is not set
-+# CONFIG_AUDIT is not set
-+# CONFIG_IKCONFIG is not set
-+CONFIG_LOG_BUF_SHIFT=14
-+# CONFIG_CGROUPS is not set
-+# CONFIG_FAIR_GROUP_SCHED is not set
-+CONFIG_SYSFS_DEPRECATED=y
-+# CONFIG_RELAY is not set
-+# CONFIG_BLK_DEV_INITRD is not set
-+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-+CONFIG_SYSCTL=y
-+CONFIG_EMBEDDED=y
-+# CONFIG_SYSCTL_SYSCALL is not set
-+CONFIG_KALLSYMS=y
-+# CONFIG_KALLSYMS_EXTRA_PASS is not set
-+CONFIG_HOTPLUG=y
-+CONFIG_PRINTK=y
-+CONFIG_BUG=y
-+CONFIG_ELF_CORE=y
-+# CONFIG_BASE_FULL is not set
-+# CONFIG_FUTEX is not set
-+# CONFIG_EPOLL is not set
-+# CONFIG_SIGNALFD is not set
-+# CONFIG_EVENTFD is not set
-+CONFIG_SHMEM=y
-+CONFIG_VM_EVENT_COUNTERS=y
-+# CONFIG_SLAB is not set
-+# CONFIG_SLUB is not set
-+CONFIG_SLOB=y
-+# CONFIG_TINY_SHMEM is not set
-+CONFIG_BASE_SMALL=1
-+# CONFIG_MODULES is not set
-+# CONFIG_BLOCK is not set
++#include <asm/dma-controller.h>
++#include <asm/io.h>
 +
-+#
-+# System Type and features
-+#
-+CONFIG_TICK_ONESHOT=y
-+CONFIG_NO_HZ=y
-+CONFIG_HIGH_RES_TIMERS=y
-+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-+CONFIG_SUBARCH_AVR32B=y
-+CONFIG_MMU=y
-+CONFIG_PERFORMANCE_COUNTERS=y
-+CONFIG_PLATFORM_AT32AP=y
-+CONFIG_CPU_AT32AP700X=y
-+CONFIG_CPU_AT32AP7002=y
-+CONFIG_BOARD_ATSTK1000=y
-+# CONFIG_BOARD_ATNGW100 is not set
-+# CONFIG_BOARD_ATSTK1002 is not set
-+# CONFIG_BOARD_ATSTK1003 is not set
-+CONFIG_BOARD_ATSTK1004=y
-+# CONFIG_BOARD_ATSTK100X_CUSTOM is not set
-+# CONFIG_BOARD_ATSTK100X_SPI1 is not set
-+# CONFIG_BOARD_ATSTK1000_J2_LED is not set
-+CONFIG_BOARD_ATSTK1000_EXTDAC=y
-+# CONFIG_BOARD_ATSTK100X_ENABLE_AC97 is not set
-+# CONFIG_BOARD_ATSTK1000_CF_HACKS is not set
-+# CONFIG_BOARD_ATSTK100X_ENABLE_PSIF is not set
-+CONFIG_LOADER_U_BOOT=y
++#include "dw-dmac.h"
 +
-+#
-+# Atmel AVR32 AP options
-+#
-+# CONFIG_AP700X_32_BIT_SMC is not set
-+CONFIG_AP700X_16_BIT_SMC=y
-+# CONFIG_AP700X_8_BIT_SMC is not set
-+# CONFIG_GPIO_DEV is not set
-+CONFIG_LOAD_ADDRESS=0x10000000
-+CONFIG_ENTRY_ADDRESS=0x90000000
-+CONFIG_PHYS_OFFSET=0x10000000
-+CONFIG_PREEMPT_NONE=y
-+# CONFIG_PREEMPT_VOLUNTARY is not set
-+# CONFIG_PREEMPT is not set
-+# CONFIG_HAVE_ARCH_BOOTMEM_NODE is not set
-+# CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set
-+# CONFIG_NEED_NODE_MEMMAP_SIZE is not set
-+CONFIG_ARCH_FLATMEM_ENABLE=y
-+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
-+# CONFIG_ARCH_SPARSEMEM_ENABLE is not set
-+CONFIG_SELECT_MEMORY_MODEL=y
-+CONFIG_FLATMEM_MANUAL=y
-+# CONFIG_DISCONTIGMEM_MANUAL is not set
-+# CONFIG_SPARSEMEM_MANUAL is not set
-+CONFIG_FLATMEM=y
-+CONFIG_FLAT_NODE_MEM_MAP=y
-+# CONFIG_SPARSEMEM_STATIC is not set
-+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
-+CONFIG_SPLIT_PTLOCK_CPUS=4
-+# CONFIG_RESOURCES_64BIT is not set
-+CONFIG_ZONE_DMA_FLAG=0
-+CONFIG_VIRT_TO_BUS=y
-+# CONFIG_OWNERSHIP_TRACE is not set
-+# CONFIG_NMI_DEBUGGING is not set
-+# CONFIG_DW_DMAC is not set
-+# CONFIG_HZ_100 is not set
-+CONFIG_HZ_250=y
-+# CONFIG_HZ_300 is not set
-+# CONFIG_HZ_1000 is not set
-+CONFIG_HZ=250
-+CONFIG_CMDLINE=""
++#define DMAC_NR_CHANNELS 3
++#define DMAC_MAX_BLOCKSIZE 4095
 +
-+#
-+# Power management options
-+#
++enum {
++      CH_STATE_FREE = 0,
++      CH_STATE_ALLOCATED,
++      CH_STATE_BUSY,
++};
 +
-+#
-+# CPU Frequency scaling
-+#
-+CONFIG_CPU_FREQ=y
-+CONFIG_CPU_FREQ_TABLE=y
-+# CONFIG_CPU_FREQ_DEBUG is not set
-+# CONFIG_CPU_FREQ_STAT is not set
-+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
-+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
-+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
-+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
-+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
-+CONFIG_CPU_FREQ_GOV_USERSPACE=y
-+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
-+CONFIG_CPU_FREQ_AT32AP=y
++struct dw_dma_lli {
++      dma_addr_t      sar;
++      dma_addr_t      dar;
++      dma_addr_t      llp;
++      u32             ctllo;
++      u32             ctlhi;
++      u32             sstat;
++      u32             dstat;
++};
 +
-+#
-+# Bus options
-+#
-+# CONFIG_ARCH_SUPPORTS_MSI is not set
-+# CONFIG_PCCARD is not set
++struct dw_dma_block {
++      struct dw_dma_lli *lli_vaddr;
++      dma_addr_t lli_dma_addr;
++};
 +
-+#
-+# Executable file formats
-+#
-+CONFIG_BINFMT_ELF=y
-+# CONFIG_BINFMT_MISC is not set
++struct dw_dma_channel {
++      unsigned int state;
++        int is_cyclic;
++      struct dma_request_sg *req_sg;
++      struct dma_request_cyclic *req_cyclic;
++      unsigned int nr_blocks;
++      int direction;
++      struct dw_dma_block *block;
++};
 +
-+#
-+# Networking
-+#
-+CONFIG_NET=y
++struct dw_dma_controller {
++      spinlock_t lock;
++      void * __iomem  regs;
++      struct dma_pool *lli_pool;
++      struct clk *hclk;
++      struct dma_controller dma;
++      struct dw_dma_channel channel[DMAC_NR_CHANNELS];
++};
++#define to_dw_dmac(dmac) container_of(dmac, struct dw_dma_controller, dma)
 +
-+#
-+# Networking options
-+#
-+CONFIG_PACKET=y
-+CONFIG_PACKET_MMAP=y
-+CONFIG_UNIX=y
-+# CONFIG_NET_KEY is not set
-+CONFIG_INET=y
-+# CONFIG_IP_MULTICAST is not set
-+# CONFIG_IP_ADVANCED_ROUTER is not set
-+CONFIG_IP_FIB_HASH=y
-+# CONFIG_IP_PNP is not set
-+# CONFIG_NET_IPIP is not set
-+# CONFIG_NET_IPGRE is not set
-+# CONFIG_ARPD is not set
-+# CONFIG_SYN_COOKIES is not set
-+# CONFIG_INET_AH is not set
-+# CONFIG_INET_ESP is not set
-+# CONFIG_INET_IPCOMP is not set
-+# CONFIG_INET_XFRM_TUNNEL is not set
-+# CONFIG_INET_TUNNEL is not set
-+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-+# CONFIG_INET_XFRM_MODE_BEET is not set
-+# CONFIG_INET_LRO is not set
-+# CONFIG_INET_DIAG is not set
-+# CONFIG_TCP_CONG_ADVANCED is not set
-+CONFIG_TCP_CONG_CUBIC=y
-+CONFIG_DEFAULT_TCP_CONG="cubic"
-+# CONFIG_TCP_MD5SIG is not set
-+# CONFIG_IPV6 is not set
-+# CONFIG_INET6_XFRM_TUNNEL is not set
-+# CONFIG_INET6_TUNNEL is not set
-+# CONFIG_NETWORK_SECMARK is not set
-+# CONFIG_NETFILTER is not set
-+# CONFIG_IP_DCCP is not set
-+# CONFIG_IP_SCTP is not set
-+# CONFIG_TIPC is not set
-+# CONFIG_ATM is not set
-+# CONFIG_BRIDGE is not set
-+# CONFIG_VLAN_8021Q is not set
-+# CONFIG_DECNET is not set
-+# CONFIG_LLC2 is not set
-+# CONFIG_IPX is not set
-+# CONFIG_ATALK is not set
-+# CONFIG_X25 is not set
-+# CONFIG_LAPB is not set
-+# CONFIG_ECONET is not set
-+# CONFIG_WAN_ROUTER is not set
-+# CONFIG_NET_SCHED is not set
++#define dmac_writel_hi(dmac, reg, value) \
++      __raw_writel((value), (dmac)->regs + DW_DMAC_##reg + 4)
++#define dmac_readl_hi(dmac, reg) \
++      __raw_readl((dmac)->regs + DW_DMAC_##reg + 4)
++#define dmac_writel_lo(dmac, reg, value) \
++      __raw_writel((value), (dmac)->regs + DW_DMAC_##reg)
++#define dmac_readl_lo(dmac, reg) \
++      __raw_readl((dmac)->regs + DW_DMAC_##reg)
++#define dmac_chan_writel_hi(dmac, chan, reg, value) \
++      __raw_writel((value), ((dmac)->regs + 0x58 * (chan) \
++                             + DW_DMAC_CHAN_##reg + 4))
++#define dmac_chan_readl_hi(dmac, chan, reg) \
++      __raw_readl((dmac)->regs + 0x58 * (chan) + DW_DMAC_CHAN_##reg + 4)
++#define dmac_chan_writel_lo(dmac, chan, reg, value) \
++      __raw_writel((value), (dmac)->regs + 0x58 * (chan) + DW_DMAC_CHAN_##reg)
++#define dmac_chan_readl_lo(dmac, chan, reg) \
++      __raw_readl((dmac)->regs + 0x58 * (chan) + DW_DMAC_CHAN_##reg)
++#define set_channel_bit(dmac, reg, chan) \
++      dmac_writel_lo(dmac, reg, (1 << (chan)) | (1 << ((chan) + 8)))
++#define clear_channel_bit(dmac, reg, chan) \
++      dmac_writel_lo(dmac, reg, (0 << (chan)) | (1 << ((chan) + 8)))
 +
-+#
-+# Network testing
-+#
-+# CONFIG_NET_PKTGEN is not set
-+# CONFIG_HAMRADIO is not set
-+# CONFIG_IRDA is not set
-+# CONFIG_BT is not set
-+# CONFIG_AF_RXRPC is not set
++static int dmac_alloc_channel(struct dma_controller *_dmac)
++{
++      struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
++      struct dw_dma_channel *chan;
++      unsigned long flags;
++      int i;
 +
-+#
-+# Wireless
-+#
-+# CONFIG_CFG80211 is not set
-+# CONFIG_WIRELESS_EXT is not set
-+# CONFIG_MAC80211 is not set
-+# CONFIG_IEEE80211 is not set
-+# CONFIG_RFKILL is not set
-+# CONFIG_NET_9P is not set
++      spin_lock_irqsave(&dmac->lock, flags);
++      for (i = 0; i < DMAC_NR_CHANNELS; i++)
++              if (dmac->channel[i].state == CH_STATE_FREE)
++                      break;
 +
-+#
-+# Device Drivers
-+#
++      if (i < DMAC_NR_CHANNELS) {
++              chan = &dmac->channel[i];
++              chan->state = CH_STATE_ALLOCATED;
++      } else {
++              i = -EBUSY;
++      }
 +
-+#
-+# Generic Driver Options
-+#
-+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-+CONFIG_STANDALONE=y
-+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-+# CONFIG_FW_LOADER is not set
-+# CONFIG_SYS_HYPERVISOR is not set
-+# CONFIG_CONNECTOR is not set
-+CONFIG_MTD=y
-+# CONFIG_MTD_DEBUG is not set
-+# CONFIG_MTD_CONCAT is not set
-+CONFIG_MTD_PARTITIONS=y
-+# CONFIG_MTD_REDBOOT_PARTS is not set
-+CONFIG_MTD_CMDLINE_PARTS=y
++      spin_unlock_irqrestore(&dmac->lock, flags);
 +
-+#
-+# User Modules And Translation Layers
-+#
-+CONFIG_MTD_CHAR=y
-+# CONFIG_MTD_OOPS is not set
++      return i;
++}
 +
-+#
-+# RAM/ROM/Flash chip drivers
-+#
-+CONFIG_MTD_CFI=y
-+# CONFIG_MTD_JEDECPROBE is not set
-+CONFIG_MTD_GEN_PROBE=y
-+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
-+CONFIG_MTD_MAP_BANK_WIDTH_1=y
-+CONFIG_MTD_MAP_BANK_WIDTH_2=y
-+CONFIG_MTD_MAP_BANK_WIDTH_4=y
-+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
-+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
-+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
-+CONFIG_MTD_CFI_I1=y
-+CONFIG_MTD_CFI_I2=y
-+# CONFIG_MTD_CFI_I4 is not set
-+# CONFIG_MTD_CFI_I8 is not set
-+# CONFIG_MTD_CFI_INTELEXT is not set
-+CONFIG_MTD_CFI_AMDSTD=y
-+# CONFIG_MTD_CFI_STAA is not set
-+CONFIG_MTD_CFI_UTIL=y
-+# CONFIG_MTD_RAM is not set
-+# CONFIG_MTD_ROM is not set
-+# CONFIG_MTD_ABSENT is not set
++static void dmac_release_channel(struct dma_controller *_dmac, int channel)
++{
++      struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
 +
-+#
-+# Mapping drivers for chip access
-+#
-+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-+CONFIG_MTD_PHYSMAP=y
-+CONFIG_MTD_PHYSMAP_START=0x8000000
-+CONFIG_MTD_PHYSMAP_LEN=0x0
-+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
-+# CONFIG_MTD_PLATRAM is not set
++      BUG_ON(channel >= DMAC_NR_CHANNELS
++             || dmac->channel[channel].state != CH_STATE_ALLOCATED);
 +
-+#
-+# Self-contained MTD device drivers
-+#
-+# CONFIG_MTD_DATAFLASH is not set
-+# CONFIG_MTD_M25P80 is not set
-+# CONFIG_MTD_SLRAM is not set
-+# CONFIG_MTD_PHRAM is not set
-+# CONFIG_MTD_MTDRAM is not set
++      dmac->channel[channel].state = CH_STATE_FREE;
++}
 +
-+#
-+# Disk-On-Chip Device Drivers
-+#
-+# CONFIG_MTD_DOC2000 is not set
-+# CONFIG_MTD_DOC2001 is not set
-+# CONFIG_MTD_DOC2001PLUS is not set
-+# CONFIG_MTD_NAND is not set
-+# CONFIG_MTD_ONENAND is not set
++static struct dw_dma_block *allocate_blocks(struct dw_dma_controller *dmac,
++                                          unsigned int nr_blocks)
++{
++      struct dw_dma_block *block;
++      void *p;
++      unsigned int i;
 +
-+#
-+# UBI - Unsorted block images
-+#
-+# CONFIG_MTD_UBI is not set
-+# CONFIG_PARPORT is not set
-+CONFIG_MISC_DEVICES=y
-+# CONFIG_ATMEL_PWM is not set
-+CONFIG_ATMEL_TCLIB=y
-+CONFIG_ATMEL_TCB_CLKSRC=y
-+CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0
-+# CONFIG_EEPROM_93CX6 is not set
-+# CONFIG_ATMEL_SSC is not set
++      block = kmalloc(nr_blocks * sizeof(*block),
++                      GFP_KERNEL);
++      if (unlikely(!block))
++              return NULL;
 +
-+#
-+# SCSI device support
-+#
-+# CONFIG_SCSI_DMA is not set
-+# CONFIG_SCSI_NETLINK is not set
-+# CONFIG_NETDEVICES is not set
-+# CONFIG_ISDN is not set
-+# CONFIG_PHONE is not set
++      for (i = 0; i < nr_blocks; i++) {
++              p = dma_pool_alloc(dmac->lli_pool, GFP_KERNEL,
++                                 &block[i].lli_dma_addr);
++              block[i].lli_vaddr = p;
++              if (unlikely(!p))
++                      goto fail;
++      }
 +
-+#
-+# Input device support
-+#
-+# CONFIG_INPUT is not set
++      return block;
 +
-+#
-+# Hardware I/O ports
-+#
-+# CONFIG_SERIO is not set
-+# CONFIG_GAMEPORT is not set
++fail:
++      for (i = 0; i < nr_blocks; i++) {
++              if (!block[i].lli_vaddr)
++                      break;
++              dma_pool_free(dmac->lli_pool, block[i].lli_vaddr,
++                            block[i].lli_dma_addr);
++      }
++      kfree(block);
++      return NULL;
++}
 +
-+#
-+# Character devices
-+#
-+# CONFIG_VT is not set
-+# CONFIG_SERIAL_NONSTANDARD is not set
++static void cleanup_channel(struct dw_dma_controller *dmac,
++                          struct dw_dma_channel *chan)
++{
++      unsigned int i;
 +
-+#
-+# Serial drivers
-+#
-+# CONFIG_SERIAL_8250 is not set
++      if (chan->nr_blocks > 1) {
++              for (i = 0; i < chan->nr_blocks; i++)
++                      dma_pool_free(dmac->lli_pool, chan->block[i].lli_vaddr,
++                                    chan->block[i].lli_dma_addr);
++              kfree(chan->block);
++      }
 +
-+#
-+# Non-8250 serial port support
-+#
-+CONFIG_SERIAL_ATMEL=y
-+CONFIG_SERIAL_ATMEL_CONSOLE=y
-+# CONFIG_SERIAL_ATMEL_PDC is not set
-+# CONFIG_SERIAL_ATMEL_TTYAT is not set
-+CONFIG_SERIAL_CORE=y
-+CONFIG_SERIAL_CORE_CONSOLE=y
-+CONFIG_UNIX98_PTYS=y
-+# CONFIG_LEGACY_PTYS is not set
-+# CONFIG_IPMI_HANDLER is not set
-+# CONFIG_HW_RANDOM is not set
-+# CONFIG_RTC is not set
-+# CONFIG_GEN_RTC is not set
-+# CONFIG_R3964 is not set
-+# CONFIG_TCG_TPM is not set
-+# CONFIG_I2C is not set
++      chan->state = CH_STATE_ALLOCATED;
++}
 +
-+#
-+# SPI support
-+#
-+CONFIG_SPI=y
-+CONFIG_SPI_MASTER=y
++static int dmac_prepare_request_sg(struct dma_controller *_dmac,
++                                 struct dma_request_sg *req)
++{
++      struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
++      struct dw_dma_channel *chan;
++      unsigned long ctlhi, ctllo, cfghi, cfglo;
++      unsigned long block_size;
++      unsigned int nr_blocks;
++      int ret, i, direction;
++      unsigned long flags;
 +
-+#
-+# SPI Master Controller Drivers
-+#
-+CONFIG_SPI_ATMEL=y
-+# CONFIG_SPI_BITBANG is not set
++      spin_lock_irqsave(&dmac->lock, flags);
 +
-+#
-+# SPI Protocol Masters
-+#
-+# CONFIG_SPI_AT25 is not set
-+# CONFIG_SPI_SPIDEV is not set
-+# CONFIG_SPI_TLE62X0 is not set
-+# CONFIG_W1 is not set
-+# CONFIG_POWER_SUPPLY is not set
-+# CONFIG_HWMON is not set
-+CONFIG_WATCHDOG=y
-+# CONFIG_WATCHDOG_NOWAYOUT is not set
++      ret = -EINVAL;
++      if (req->req.channel >= DMAC_NR_CHANNELS
++          || dmac->channel[req->req.channel].state != CH_STATE_ALLOCATED
++          || req->block_size > DMAC_MAX_BLOCKSIZE) {
++              spin_unlock_irqrestore(&dmac->lock, flags);
++              return -EINVAL;
++      }
 +
-+#
-+# Watchdog Device Drivers
-+#
-+# CONFIG_SOFT_WATCHDOG is not set
-+CONFIG_AT32AP700X_WDT=y
++      chan = &dmac->channel[req->req.channel];
++      chan->state = CH_STATE_BUSY;
++      chan->req_sg = req;
++      chan->is_cyclic = 0;
 +
-+#
-+# Sonics Silicon Backplane
-+#
-+CONFIG_SSB_POSSIBLE=y
-+# CONFIG_SSB is not set
++      /*
++       * We have marked the channel as busy, so no need to keep the
++       * lock as long as we only touch the channel-specific
++       * registers
++       */
++      spin_unlock_irqrestore(&dmac->lock, flags);
 +
-+#
-+# Multifunction device drivers
-+#
-+# CONFIG_MFD_SM501 is not set
++      /*
++       * There may be limitations in the driver and/or the DMA
++       * controller that prevents us from sending a whole
++       * scatterlist item in one go.  Taking this into account,
++       * calculate the number of block transfers we need to set up.
++       *
++       * FIXME: Let the peripheral driver know about the maximum
++       * block size we support. We really don't want to use a
++       * different block size than what was suggested by the
++       * peripheral.
++       *
++       * Each block will get its own Linked List Item (LLI) below.
++       */
++      block_size = req->block_size;
++      nr_blocks = req->nr_blocks;
++      pr_debug("block_size %lu, nr_blocks %u nr_sg = %u\n",
++               block_size, nr_blocks, req->nr_sg);
 +
-+#
-+# Multimedia devices
-+#
-+# CONFIG_VIDEO_DEV is not set
-+# CONFIG_DVB_CORE is not set
-+# CONFIG_DAB is not set
++      BUG_ON(nr_blocks == 0);
++      chan->nr_blocks = nr_blocks;
 +
-+#
-+# Graphics support
-+#
-+# CONFIG_VGASTATE is not set
-+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-+CONFIG_FB=y
-+# CONFIG_FIRMWARE_EDID is not set
-+# CONFIG_FB_DDC is not set
-+CONFIG_FB_CFB_FILLRECT=y
-+CONFIG_FB_CFB_COPYAREA=y
-+CONFIG_FB_CFB_IMAGEBLIT=y
-+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
-+# CONFIG_FB_SYS_FILLRECT is not set
-+# CONFIG_FB_SYS_COPYAREA is not set
-+# CONFIG_FB_SYS_IMAGEBLIT is not set
-+# CONFIG_FB_SYS_FOPS is not set
-+CONFIG_FB_DEFERRED_IO=y
-+# CONFIG_FB_SVGALIB is not set
-+# CONFIG_FB_MACMODES is not set
-+# CONFIG_FB_BACKLIGHT is not set
-+# CONFIG_FB_MODE_HELPERS is not set
-+# CONFIG_FB_TILEBLITTING is not set
++      ret = -EINVAL;
++      cfglo = cfghi = 0;
++      switch (req->direction) {
++      case DMA_DIR_MEM_TO_PERIPH:
++              direction = DMA_TO_DEVICE;
++              cfghi = req->periph_id << (43 - 32);
++              break;
 +
-+#
-+# Frame buffer hardware drivers
-+#
-+# CONFIG_FB_S1D13XXX is not set
-+CONFIG_FB_ATMEL=y
-+# CONFIG_FB_VIRTUAL is not set
-+CONFIG_BACKLIGHT_LCD_SUPPORT=y
-+CONFIG_LCD_CLASS_DEVICE=y
-+CONFIG_LCD_LTV350QV=y
-+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
++      case DMA_DIR_PERIPH_TO_MEM:
++              direction = DMA_FROM_DEVICE;
++              cfghi = req->periph_id << (39 - 32);
++              break;
++      default:
++              goto out_unclaim_channel;
++      }
 +
-+#
-+# Display device support
-+#
-+# CONFIG_DISPLAY_SUPPORT is not set
-+# CONFIG_LOGO is not set
++        chan->direction = direction;
 +
-+#
-+# Sound
-+#
-+# CONFIG_SOUND is not set
-+CONFIG_USB_SUPPORT=y
-+# CONFIG_USB_ARCH_HAS_HCD is not set
-+# CONFIG_USB_ARCH_HAS_OHCI is not set
-+# CONFIG_USB_ARCH_HAS_EHCI is not set
++      dmac_chan_writel_hi(dmac, req->req.channel, CFG, cfghi);
++      dmac_chan_writel_lo(dmac, req->req.channel, CFG, cfglo);
 +
-+#
-+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
-+#
++      ctlhi = block_size >> req->width;
++      ctllo = ((req->direction << 20)
++               // | (1 << 14) | (1 << 11) // source/dest burst trans len
++               | (req->width << 4) | (req->width << 1)
++               | (1 << 0));            // interrupt enable
 +
-+#
-+# USB Gadget Support
-+#
-+CONFIG_USB_GADGET=y
-+# CONFIG_USB_GADGET_DEBUG_FILES is not set
-+CONFIG_USB_GADGET_SELECTED=y
-+# CONFIG_USB_GADGET_AMD5536UDC is not set
-+CONFIG_USB_GADGET_ATMEL_USBA=y
-+CONFIG_USB_ATMEL_USBA=y
-+# CONFIG_USB_GADGET_FSL_USB2 is not set
-+# CONFIG_USB_GADGET_NET2280 is not set
-+# CONFIG_USB_GADGET_PXA2XX is not set
-+# CONFIG_USB_GADGET_M66592 is not set
-+# CONFIG_USB_GADGET_GOKU is not set
-+# CONFIG_USB_GADGET_LH7A40X is not set
-+# CONFIG_USB_GADGET_OMAP is not set
-+# CONFIG_USB_GADGET_S3C2410 is not set
-+# CONFIG_USB_GADGET_AT91 is not set
-+# CONFIG_USB_GADGET_DUMMY_HCD is not set
-+CONFIG_USB_GADGET_DUALSPEED=y
-+# CONFIG_USB_ZERO is not set
-+CONFIG_USB_ETH=y
-+# CONFIG_USB_ETH_RNDIS is not set
-+# CONFIG_USB_GADGETFS is not set
-+# CONFIG_USB_FILE_STORAGE is not set
-+# CONFIG_USB_G_SERIAL is not set
-+# CONFIG_USB_MIDI_GADGET is not set
-+# CONFIG_MMC is not set
-+# CONFIG_NEW_LEDS is not set
-+CONFIG_RTC_LIB=y
-+CONFIG_RTC_CLASS=y
-+CONFIG_RTC_HCTOSYS=y
-+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
-+# CONFIG_RTC_DEBUG is not set
++      if (nr_blocks == 1) {
++              /* Only one block: No need to use block chaining */
++              if (direction == DMA_TO_DEVICE) {
++                      dmac_chan_writel_lo(dmac, req->req.channel, SAR,
++                                          req->sg->dma_address);
++                      dmac_chan_writel_lo(dmac, req->req.channel, DAR,
++                                          req->data_reg);
++                      ctllo |= 2 << 7; // no dst increment
++              } else {
++                      dmac_chan_writel_lo(dmac, req->req.channel, SAR,
++                                          req->data_reg);
++                      dmac_chan_writel_lo(dmac, req->req.channel, DAR,
++                                          req->sg->dma_address);
++                      ctllo |= 2 << 9; // no src increment
++              }
++              dmac_chan_writel_lo(dmac, req->req.channel, CTL, ctllo);
++              dmac_chan_writel_hi(dmac, req->req.channel, CTL, ctlhi);
++              pr_debug("ctl hi:lo 0x%lx:%lx\n", ctlhi, ctllo);
++      } else {
++              struct dw_dma_lli *lli, *lli_prev = NULL;
++              int j = 0, offset = 0;
 +
-+#
-+# RTC interfaces
-+#
-+CONFIG_RTC_INTF_SYSFS=y
-+# CONFIG_RTC_INTF_PROC is not set
-+CONFIG_RTC_INTF_DEV=y
-+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
-+# CONFIG_RTC_DRV_TEST is not set
++              ret = -ENOMEM;
++              chan->block = allocate_blocks(dmac, nr_blocks);
++              if (!chan->block)
++                      goto out_unclaim_channel;
 +
-+#
-+# SPI RTC drivers
-+#
-+# CONFIG_RTC_DRV_RS5C348 is not set
-+# CONFIG_RTC_DRV_MAX6902 is not set
++              if (direction == DMA_TO_DEVICE)
++                      ctllo |= 1 << 28 | 1 << 27 | 2 << 7;
++              else
++                      ctllo |= 1 << 28 | 1 << 27 | 2 << 9;
 +
-+#
-+# Platform RTC drivers
-+#
-+# CONFIG_RTC_DRV_DS1553 is not set
-+# CONFIG_RTC_DRV_STK17TA8 is not set
-+# CONFIG_RTC_DRV_DS1742 is not set
-+# CONFIG_RTC_DRV_M48T86 is not set
-+# CONFIG_RTC_DRV_M48T59 is not set
-+# CONFIG_RTC_DRV_V3020 is not set
++              /*
++               * Map scatterlist items to blocks. One scatterlist
++               * item may need more than one block for the reasons
++               * mentioned above.
++               */
++              for (i = 0; i < nr_blocks; i++) {
++                      lli = chan->block[i].lli_vaddr;
++                      if (lli_prev) {
++                              lli_prev->llp = chan->block[i].lli_dma_addr;
++                              pr_debug("lli[%d] (0x%p/0x%x): 0x%x 0x%x 0x%x 0x%x 0x%x\n",
++                                       i - 1, chan->block[i - 1].lli_vaddr,
++                                       chan->block[i - 1].lli_dma_addr,
++                                       lli_prev->sar, lli_prev->dar, lli_prev->llp,
++                                       lli_prev->ctllo, lli_prev->ctlhi);
++                      }
++                      lli->llp = 0;
++                      lli->ctllo = ctllo;
++                      lli->ctlhi = ctlhi;
++                      if (direction == DMA_TO_DEVICE) {
++                              lli->sar = req->sg[j].dma_address + offset;
++                              lli->dar = req->data_reg;
++                      } else {
++                              lli->sar = req->data_reg;
++                              lli->dar = req->sg[j].dma_address + offset;
++                      }
++                      lli_prev = lli;
 +
-+#
-+# on-CPU RTC drivers
-+#
-+CONFIG_RTC_DRV_AT32AP700X=y
++                      offset += block_size;
++                      if (offset > req->sg[j].length) {
++                              j++;
++                              offset = 0;
++                      }
++              }
 +
-+#
-+# Userspace I/O
-+#
-+# CONFIG_UIO is not set
++              pr_debug("lli[%d] (0x%p/0x%x): 0x%x 0x%x 0x%x 0x%x 0x%x\n",
++                       i - 1, chan->block[i - 1].lli_vaddr,
++                       chan->block[i - 1].lli_dma_addr, lli_prev->sar,
++                       lli_prev->dar, lli_prev->llp,
++                       lli_prev->ctllo, lli_prev->ctlhi);
 +
-+#
-+# File systems
-+#
-+# CONFIG_INOTIFY is not set
-+# CONFIG_QUOTA is not set
-+# CONFIG_DNOTIFY is not set
-+# CONFIG_AUTOFS_FS is not set
-+# CONFIG_AUTOFS4_FS is not set
-+# CONFIG_FUSE_FS is not set
++              /*
++               * SAR, DAR and CTL are initialized from the LLI. We
++               * only have to enable the LLI bits in CTL.
++               */
++              dmac_chan_writel_hi(dmac, req->req.channel, CTL, 0);
++              dmac_chan_writel_lo(dmac, req->req.channel, LLP,
++                                  chan->block[0].lli_dma_addr);
++              dmac_chan_writel_lo(dmac, req->req.channel, CTL, 1 << 28 | 1 << 27);
++      }
 +
-+#
-+# Pseudo filesystems
-+#
-+CONFIG_PROC_FS=y
-+CONFIG_PROC_KCORE=y
-+CONFIG_PROC_SYSCTL=y
-+CONFIG_SYSFS=y
-+CONFIG_TMPFS=y
-+# CONFIG_TMPFS_POSIX_ACL is not set
-+# CONFIG_HUGETLB_PAGE is not set
-+# CONFIG_CONFIGFS_FS is not set
++      set_channel_bit(dmac, MASK_XFER, req->req.channel);
++      set_channel_bit(dmac, MASK_ERROR, req->req.channel);
++      if (req->req.block_complete)
++              set_channel_bit(dmac, MASK_BLOCK, req->req.channel);
++      else
++              clear_channel_bit(dmac, MASK_BLOCK, req->req.channel);
 +
-+#
-+# Miscellaneous filesystems
-+#
-+CONFIG_JFFS2_FS=y
-+CONFIG_JFFS2_FS_DEBUG=0
-+# CONFIG_JFFS2_FS_WRITEBUFFER is not set
-+# CONFIG_JFFS2_SUMMARY is not set
-+# CONFIG_JFFS2_FS_XATTR is not set
-+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
-+CONFIG_JFFS2_ZLIB=y
-+# CONFIG_JFFS2_LZO is not set
-+CONFIG_JFFS2_RTIME=y
-+# CONFIG_JFFS2_RUBIN is not set
-+# CONFIG_NETWORK_FILESYSTEMS is not set
-+# CONFIG_NLS is not set
-+# CONFIG_DLM is not set
-+# CONFIG_INSTRUMENTATION is not set
++      return 0;
 +
-+#
-+# Kernel hacking
-+#
-+# CONFIG_PRINTK_TIME is not set
-+CONFIG_ENABLE_WARN_DEPRECATED=y
-+CONFIG_ENABLE_MUST_CHECK=y
-+CONFIG_MAGIC_SYSRQ=y
-+# CONFIG_UNUSED_SYMBOLS is not set
-+# CONFIG_DEBUG_FS is not set
-+# CONFIG_HEADERS_CHECK is not set
-+# CONFIG_DEBUG_KERNEL is not set
-+# CONFIG_DEBUG_BUGVERBOSE is not set
-+# CONFIG_SAMPLES is not set
++out_unclaim_channel:
++      chan->state = CH_STATE_ALLOCATED;
++      return ret;
++}
 +
-+#
-+# Security options
-+#
-+# CONFIG_KEYS is not set
-+# CONFIG_SECURITY is not set
-+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
-+# CONFIG_CRYPTO is not set
++static int dmac_prepare_request_cyclic(struct dma_controller *_dmac,
++                                       struct dma_request_cyclic *req)
++{
++      struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
++      struct dw_dma_channel *chan;
++      unsigned long ctlhi, ctllo, cfghi, cfglo;
++      unsigned long block_size;
++      int ret, i, direction;
++      unsigned long flags;
 +
-+#
-+# Library routines
-+#
-+CONFIG_BITREVERSE=y
-+# CONFIG_CRC_CCITT is not set
-+# CONFIG_CRC16 is not set
-+# CONFIG_CRC_ITU_T is not set
-+CONFIG_CRC32=y
-+# CONFIG_CRC7 is not set
-+# CONFIG_LIBCRC32C is not set
-+CONFIG_ZLIB_INFLATE=y
-+CONFIG_ZLIB_DEFLATE=y
-+CONFIG_HAS_IOMEM=y
-+CONFIG_HAS_IOPORT=y
-+CONFIG_HAS_DMA=y
---- /dev/null
-+++ b/arch/avr32/drivers/dw-dmac.c
-@@ -0,0 +1,761 @@
-+/*
-+ * Driver for the Synopsys DesignWare DMA Controller
-+ *
-+ * Copyright (C) 2005-2006 Atmel Corporation
-+ *
-+ * 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/clk.h>
-+#include <linux/device.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dmapool.h>
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
++      spin_lock_irqsave(&dmac->lock, flags);
 +
-+#include <asm/dma-controller.h>
-+#include <asm/io.h>
++        block_size = (req->buffer_size/req->periods) >> req->width;
 +
-+#include "dw-dmac.h"
-+
-+#define DMAC_NR_CHANNELS 3
-+#define DMAC_MAX_BLOCKSIZE 4095
-+
-+enum {
-+      CH_STATE_FREE = 0,
-+      CH_STATE_ALLOCATED,
-+      CH_STATE_BUSY,
-+};
-+
-+struct dw_dma_lli {
-+      dma_addr_t      sar;
-+      dma_addr_t      dar;
-+      dma_addr_t      llp;
-+      u32             ctllo;
-+      u32             ctlhi;
-+      u32             sstat;
-+      u32             dstat;
-+};
-+
-+struct dw_dma_block {
-+      struct dw_dma_lli *lli_vaddr;
-+      dma_addr_t lli_dma_addr;
-+};
-+
-+struct dw_dma_channel {
-+      unsigned int state;
-+        int is_cyclic;
-+      struct dma_request_sg *req_sg;
-+      struct dma_request_cyclic *req_cyclic;
-+      unsigned int nr_blocks;
-+      int direction;
-+      struct dw_dma_block *block;
-+};
-+
-+struct dw_dma_controller {
-+      spinlock_t lock;
-+      void * __iomem  regs;
-+      struct dma_pool *lli_pool;
-+      struct clk *hclk;
-+      struct dma_controller dma;
-+      struct dw_dma_channel channel[DMAC_NR_CHANNELS];
-+};
-+#define to_dw_dmac(dmac) container_of(dmac, struct dw_dma_controller, dma)
-+
-+#define dmac_writel_hi(dmac, reg, value) \
-+      __raw_writel((value), (dmac)->regs + DW_DMAC_##reg + 4)
-+#define dmac_readl_hi(dmac, reg) \
-+      __raw_readl((dmac)->regs + DW_DMAC_##reg + 4)
-+#define dmac_writel_lo(dmac, reg, value) \
-+      __raw_writel((value), (dmac)->regs + DW_DMAC_##reg)
-+#define dmac_readl_lo(dmac, reg) \
-+      __raw_readl((dmac)->regs + DW_DMAC_##reg)
-+#define dmac_chan_writel_hi(dmac, chan, reg, value) \
-+      __raw_writel((value), ((dmac)->regs + 0x58 * (chan) \
-+                             + DW_DMAC_CHAN_##reg + 4))
-+#define dmac_chan_readl_hi(dmac, chan, reg) \
-+      __raw_readl((dmac)->regs + 0x58 * (chan) + DW_DMAC_CHAN_##reg + 4)
-+#define dmac_chan_writel_lo(dmac, chan, reg, value) \
-+      __raw_writel((value), (dmac)->regs + 0x58 * (chan) + DW_DMAC_CHAN_##reg)
-+#define dmac_chan_readl_lo(dmac, chan, reg) \
-+      __raw_readl((dmac)->regs + 0x58 * (chan) + DW_DMAC_CHAN_##reg)
-+#define set_channel_bit(dmac, reg, chan) \
-+      dmac_writel_lo(dmac, reg, (1 << (chan)) | (1 << ((chan) + 8)))
-+#define clear_channel_bit(dmac, reg, chan) \
-+      dmac_writel_lo(dmac, reg, (0 << (chan)) | (1 << ((chan) + 8)))
-+
-+static int dmac_alloc_channel(struct dma_controller *_dmac)
-+{
-+      struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
-+      struct dw_dma_channel *chan;
-+      unsigned long flags;
-+      int i;
-+
-+      spin_lock_irqsave(&dmac->lock, flags);
-+      for (i = 0; i < DMAC_NR_CHANNELS; i++)
-+              if (dmac->channel[i].state == CH_STATE_FREE)
-+                      break;
-+
-+      if (i < DMAC_NR_CHANNELS) {
-+              chan = &dmac->channel[i];
-+              chan->state = CH_STATE_ALLOCATED;
-+      } else {
-+              i = -EBUSY;
-+      }
-+
-+      spin_unlock_irqrestore(&dmac->lock, flags);
-+
-+      return i;
-+}
-+
-+static void dmac_release_channel(struct dma_controller *_dmac, int channel)
-+{
-+      struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
-+
-+      BUG_ON(channel >= DMAC_NR_CHANNELS
-+             || dmac->channel[channel].state != CH_STATE_ALLOCATED);
-+
-+      dmac->channel[channel].state = CH_STATE_FREE;
-+}
-+
-+static struct dw_dma_block *allocate_blocks(struct dw_dma_controller *dmac,
-+                                          unsigned int nr_blocks)
-+{
-+      struct dw_dma_block *block;
-+      void *p;
-+      unsigned int i;
-+
-+      block = kmalloc(nr_blocks * sizeof(*block),
-+                      GFP_KERNEL);
-+      if (unlikely(!block))
-+              return NULL;
-+
-+      for (i = 0; i < nr_blocks; i++) {
-+              p = dma_pool_alloc(dmac->lli_pool, GFP_KERNEL,
-+                                 &block[i].lli_dma_addr);
-+              block[i].lli_vaddr = p;
-+              if (unlikely(!p))
-+                      goto fail;
-+      }
-+
-+      return block;
-+
-+fail:
-+      for (i = 0; i < nr_blocks; i++) {
-+              if (!block[i].lli_vaddr)
-+                      break;
-+              dma_pool_free(dmac->lli_pool, block[i].lli_vaddr,
-+                            block[i].lli_dma_addr);
-+      }
-+      kfree(block);
-+      return NULL;
-+}
-+
-+static void cleanup_channel(struct dw_dma_controller *dmac,
-+                          struct dw_dma_channel *chan)
-+{
-+      unsigned int i;
-+
-+      if (chan->nr_blocks > 1) {
-+              for (i = 0; i < chan->nr_blocks; i++)
-+                      dma_pool_free(dmac->lli_pool, chan->block[i].lli_vaddr,
-+                                    chan->block[i].lli_dma_addr);
-+              kfree(chan->block);
-+      }
-+
-+      chan->state = CH_STATE_ALLOCATED;
-+}
-+
-+static int dmac_prepare_request_sg(struct dma_controller *_dmac,
-+                                 struct dma_request_sg *req)
-+{
-+      struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
-+      struct dw_dma_channel *chan;
-+      unsigned long ctlhi, ctllo, cfghi, cfglo;
-+      unsigned long block_size;
-+      unsigned int nr_blocks;
-+      int ret, i, direction;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&dmac->lock, flags);
-+
-+      ret = -EINVAL;
-+      if (req->req.channel >= DMAC_NR_CHANNELS
-+          || dmac->channel[req->req.channel].state != CH_STATE_ALLOCATED
-+          || req->block_size > DMAC_MAX_BLOCKSIZE) {
-+              spin_unlock_irqrestore(&dmac->lock, flags);
-+              return -EINVAL;
-+      }
++      ret = -EINVAL;
++      if (req->req.channel >= DMAC_NR_CHANNELS
++          || dmac->channel[req->req.channel].state != CH_STATE_ALLOCATED
++            || (req->periods == 0)
++          || block_size > DMAC_MAX_BLOCKSIZE) {
++              spin_unlock_irqrestore(&dmac->lock, flags);
++              return -EINVAL;
++      }
 +
 +      chan = &dmac->channel[req->req.channel];
 +      chan->state = CH_STATE_BUSY;
-+      chan->req_sg = req;
-+      chan->is_cyclic = 0;
++      chan->is_cyclic = 1;
++        chan->req_cyclic = req;
 +
 +      /*
 +       * We have marked the channel as busy, so no need to keep the
 +      spin_unlock_irqrestore(&dmac->lock, flags);
 +
 +      /*
-+       * There may be limitations in the driver and/or the DMA
-+       * controller that prevents us from sending a whole
-+       * scatterlist item in one go.  Taking this into account,
-+       * calculate the number of block transfers we need to set up.
-+       *
-+       * FIXME: Let the peripheral driver know about the maximum
-+       * block size we support. We really don't want to use a
-+       * different block size than what was suggested by the
-+       * peripheral.
-+       *
-+       * Each block will get its own Linked List Item (LLI) below.
++          Setup
 +       */
-+      block_size = req->block_size;
-+      nr_blocks = req->nr_blocks;
-+      pr_debug("block_size %lu, nr_blocks %u nr_sg = %u\n",
-+               block_size, nr_blocks, req->nr_sg);
++      BUG_ON(req->buffer_size % req->periods);
++      /* printk(KERN_INFO "block_size = %lu, periods = %u\n", block_size, req->periods); */
 +
-+      BUG_ON(nr_blocks == 0);
-+      chan->nr_blocks = nr_blocks;
++      chan->nr_blocks = req->periods;
 +
 +      ret = -EINVAL;
 +      cfglo = cfghi = 0;
 +      dmac_chan_writel_hi(dmac, req->req.channel, CFG, cfghi);
 +      dmac_chan_writel_lo(dmac, req->req.channel, CFG, cfglo);
 +
-+      ctlhi = block_size >> req->width;
++      ctlhi = block_size;
 +      ctllo = ((req->direction << 20)
-+               // | (1 << 14) | (1 << 11) // source/dest burst trans len
 +               | (req->width << 4) | (req->width << 1)
 +               | (1 << 0));            // interrupt enable
 +
-+      if (nr_blocks == 1) {
-+              /* Only one block: No need to use block chaining */
-+              if (direction == DMA_TO_DEVICE) {
-+                      dmac_chan_writel_lo(dmac, req->req.channel, SAR,
-+                                          req->sg->dma_address);
-+                      dmac_chan_writel_lo(dmac, req->req.channel, DAR,
-+                                          req->data_reg);
-+                      ctllo |= 2 << 7; // no dst increment
-+              } else {
-+                      dmac_chan_writel_lo(dmac, req->req.channel, SAR,
-+                                          req->data_reg);
-+                      dmac_chan_writel_lo(dmac, req->req.channel, DAR,
-+                                          req->sg->dma_address);
-+                      ctllo |= 2 << 9; // no src increment
-+              }
-+              dmac_chan_writel_lo(dmac, req->req.channel, CTL, ctllo);
-+              dmac_chan_writel_hi(dmac, req->req.channel, CTL, ctlhi);
-+              pr_debug("ctl hi:lo 0x%lx:%lx\n", ctlhi, ctllo);
-+      } else {
-+              struct dw_dma_lli *lli, *lli_prev = NULL;
-+              int j = 0, offset = 0;
++        {
++              struct dw_dma_lli *lli = NULL, *lli_prev = NULL;
 +
 +              ret = -ENOMEM;
-+              chan->block = allocate_blocks(dmac, nr_blocks);
++              chan->block = allocate_blocks(dmac, req->periods);
 +              if (!chan->block)
 +                      goto out_unclaim_channel;
 +
 +                      ctllo |= 1 << 28 | 1 << 27 | 2 << 9;
 +
 +              /*
-+               * Map scatterlist items to blocks. One scatterlist
-+               * item may need more than one block for the reasons
-+               * mentioned above.
++               * Set up a linked list items where each period gets
++               * an item. The linked list item for the last period
++               * points back to the star of the buffer making a
++               * cyclic buffer.
 +               */
-+              for (i = 0; i < nr_blocks; i++) {
++              for (i = 0; i < req->periods; i++) {
 +                      lli = chan->block[i].lli_vaddr;
 +                      if (lli_prev) {
 +                              lli_prev->llp = chan->block[i].lli_dma_addr;
-+                              pr_debug("lli[%d] (0x%p/0x%x): 0x%x 0x%x 0x%x 0x%x 0x%x\n",
-+                                       i - 1, chan->block[i - 1].lli_vaddr,
-+                                       chan->block[i - 1].lli_dma_addr,
-+                                       lli_prev->sar, lli_prev->dar, lli_prev->llp,
-+                                       lli_prev->ctllo, lli_prev->ctlhi);
++                              /* printk(KERN_INFO "lli[%d] (0x%p/0x%x): 0x%x 0x%x 0x%x 0x%x 0x%x\n",
++                                 i - 1, chan->block[i - 1].lli_vaddr,
++                                 chan->block[i - 1].lli_dma_addr,
++                                 lli_prev->sar, lli_prev->dar, lli_prev->llp,
++                                 lli_prev->ctllo, lli_prev->ctlhi);*/
 +                      }
 +                      lli->llp = 0;
 +                      lli->ctllo = ctllo;
 +                      lli->ctlhi = ctlhi;
 +                      if (direction == DMA_TO_DEVICE) {
-+                              lli->sar = req->sg[j].dma_address + offset;
++                              lli->sar = req->buffer_start + i*(block_size << req->width);
 +                              lli->dar = req->data_reg;
 +                      } else {
 +                              lli->sar = req->data_reg;
-+                              lli->dar = req->sg[j].dma_address + offset;
++                              lli->dar = req->buffer_start + i*(block_size << req->width);
 +                      }
 +                      lli_prev = lli;
-+
-+                      offset += block_size;
-+                      if (offset > req->sg[j].length) {
-+                              j++;
-+                              offset = 0;
-+                      }
 +              }
-+
-+              pr_debug("lli[%d] (0x%p/0x%x): 0x%x 0x%x 0x%x 0x%x 0x%x\n",
-+                       i - 1, chan->block[i - 1].lli_vaddr,
-+                       chan->block[i - 1].lli_dma_addr, lli_prev->sar,
-+                       lli_prev->dar, lli_prev->llp,
-+                       lli_prev->ctllo, lli_prev->ctlhi);
-+
-+              /*
-+               * SAR, DAR and CTL are initialized from the LLI. We
-+               * only have to enable the LLI bits in CTL.
-+               */
-+              dmac_chan_writel_hi(dmac, req->req.channel, CTL, 0);
-+              dmac_chan_writel_lo(dmac, req->req.channel, LLP,
-+                                  chan->block[0].lli_dma_addr);
-+              dmac_chan_writel_lo(dmac, req->req.channel, CTL, 1 << 28 | 1 << 27);
-+      }
-+
-+      set_channel_bit(dmac, MASK_XFER, req->req.channel);
-+      set_channel_bit(dmac, MASK_ERROR, req->req.channel);
-+      if (req->req.block_complete)
-+              set_channel_bit(dmac, MASK_BLOCK, req->req.channel);
-+      else
-+              clear_channel_bit(dmac, MASK_BLOCK, req->req.channel);
-+
-+      return 0;
-+
-+out_unclaim_channel:
-+      chan->state = CH_STATE_ALLOCATED;
-+      return ret;
-+}
-+
-+static int dmac_prepare_request_cyclic(struct dma_controller *_dmac,
-+                                       struct dma_request_cyclic *req)
-+{
-+      struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
-+      struct dw_dma_channel *chan;
-+      unsigned long ctlhi, ctllo, cfghi, cfglo;
-+      unsigned long block_size;
-+      int ret, i, direction;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&dmac->lock, flags);
-+
-+        block_size = (req->buffer_size/req->periods) >> req->width;
-+
-+      ret = -EINVAL;
-+      if (req->req.channel >= DMAC_NR_CHANNELS
-+          || dmac->channel[req->req.channel].state != CH_STATE_ALLOCATED
-+            || (req->periods == 0)
-+          || block_size > DMAC_MAX_BLOCKSIZE) {
-+              spin_unlock_irqrestore(&dmac->lock, flags);
-+              return -EINVAL;
-+      }
-+
-+      chan = &dmac->channel[req->req.channel];
-+      chan->state = CH_STATE_BUSY;
-+      chan->is_cyclic = 1;
-+        chan->req_cyclic = req;
-+
-+      /*
-+       * We have marked the channel as busy, so no need to keep the
-+       * lock as long as we only touch the channel-specific
-+       * registers
-+       */
-+      spin_unlock_irqrestore(&dmac->lock, flags);
-+
-+      /*
-+          Setup
-+       */
-+      BUG_ON(req->buffer_size % req->periods);
-+      /* printk(KERN_INFO "block_size = %lu, periods = %u\n", block_size, req->periods); */
-+
-+      chan->nr_blocks = req->periods;
-+
-+      ret = -EINVAL;
-+      cfglo = cfghi = 0;
-+      switch (req->direction) {
-+      case DMA_DIR_MEM_TO_PERIPH:
-+              direction = DMA_TO_DEVICE;
-+              cfghi = req->periph_id << (43 - 32);
-+              break;
-+
-+      case DMA_DIR_PERIPH_TO_MEM:
-+              direction = DMA_FROM_DEVICE;
-+              cfghi = req->periph_id << (39 - 32);
-+              break;
-+      default:
-+              goto out_unclaim_channel;
-+      }
-+
-+        chan->direction = direction;
-+
-+      dmac_chan_writel_hi(dmac, req->req.channel, CFG, cfghi);
-+      dmac_chan_writel_lo(dmac, req->req.channel, CFG, cfglo);
-+
-+      ctlhi = block_size;
-+      ctllo = ((req->direction << 20)
-+               | (req->width << 4) | (req->width << 1)
-+               | (1 << 0));            // interrupt enable
-+
-+        {
-+              struct dw_dma_lli *lli = NULL, *lli_prev = NULL;
-+
-+              ret = -ENOMEM;
-+              chan->block = allocate_blocks(dmac, req->periods);
-+              if (!chan->block)
-+                      goto out_unclaim_channel;
-+
-+              if (direction == DMA_TO_DEVICE)
-+                      ctllo |= 1 << 28 | 1 << 27 | 2 << 7;
-+              else
-+                      ctllo |= 1 << 28 | 1 << 27 | 2 << 9;
-+
-+              /*
-+               * Set up a linked list items where each period gets
-+               * an item. The linked list item for the last period
-+               * points back to the star of the buffer making a
-+               * cyclic buffer.
-+               */
-+              for (i = 0; i < req->periods; i++) {
-+                      lli = chan->block[i].lli_vaddr;
-+                      if (lli_prev) {
-+                              lli_prev->llp = chan->block[i].lli_dma_addr;
-+                              /* printk(KERN_INFO "lli[%d] (0x%p/0x%x): 0x%x 0x%x 0x%x 0x%x 0x%x\n",
-+                                 i - 1, chan->block[i - 1].lli_vaddr,
-+                                 chan->block[i - 1].lli_dma_addr,
-+                                 lli_prev->sar, lli_prev->dar, lli_prev->llp,
-+                                 lli_prev->ctllo, lli_prev->ctlhi);*/
-+                      }
-+                      lli->llp = 0;
-+                      lli->ctllo = ctllo;
-+                      lli->ctlhi = ctlhi;
-+                      if (direction == DMA_TO_DEVICE) {
-+                              lli->sar = req->buffer_start + i*(block_size << req->width);
-+                              lli->dar = req->data_reg;
-+                      } else {
-+                              lli->sar = req->data_reg;
-+                              lli->dar = req->buffer_start + i*(block_size << req->width);
-+                      }
-+                      lli_prev = lli;
-+              }
-+              lli->llp = chan->block[0].lli_dma_addr;
++              lli->llp = chan->block[0].lli_dma_addr;
 +
 +              /*printk(KERN_INFO "lli[%d] (0x%p/0x%x): 0x%x 0x%x 0x%x 0x%x 0x%x\n",
 +                i - 1, chan->block[i - 1].lli_vaddr,
 +MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller driver");
 +MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
 +MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/arch/avr32/drivers/dw-dmac.h
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/drivers/dw-dmac.h avr32-2.6/arch/avr32/drivers/dw-dmac.h
+--- linux-2.6.25.6/arch/avr32/drivers/dw-dmac.h        1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/arch/avr32/drivers/dw-dmac.h     2008-06-12 15:09:38.719815350 +0200
 @@ -0,0 +1,42 @@
 +/*
 + * Driver for the Synopsys DesignWare DMA Controller
 +#define DW_DMAC_CHAN_DSR      0x050
 +
 +#endif /* __AVR32_DW_DMAC_H__ */
---- /dev/null
-+++ b/arch/avr32/drivers/Makefile
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/drivers/Makefile avr32-2.6/arch/avr32/drivers/Makefile
+--- linux-2.6.25.6/arch/avr32/drivers/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/arch/avr32/drivers/Makefile      2008-06-12 15:09:38.719815350 +0200
 @@ -0,0 +1 @@
 +obj-$(CONFIG_DW_DMAC)                 += dw-dmac.o
---- a/arch/avr32/Kconfig
-+++ b/arch/avr32/Kconfig
-@@ -45,6 +45,9 @@
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/Kconfig avr32-2.6/arch/avr32/Kconfig
+--- linux-2.6.25.6/arch/avr32/Kconfig  2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/Kconfig       2008-06-12 15:09:38.711815728 +0200
+@@ -47,6 +47,9 @@
  config GENERIC_TIME
        def_bool y
  
  config RWSEM_XCHGADD_ALGORITHM
        def_bool n
  
-@@ -54,6 +57,9 @@
- config ARCH_HAS_ILOG2_U64
-       def_bool n
-+config ARCH_SUPPORTS_OPROFILE
-+      def_bool y
-+
- config GENERIC_HWEIGHT
-       def_bool y
-@@ -68,6 +74,8 @@
+@@ -70,6 +73,8 @@
  
  menu "System Type and features"
  
  config SUBARCH_AVR32B
        bool
  config MMU
-@@ -81,19 +89,23 @@
+@@ -83,6 +88,7 @@
        select MMU
        select PERFORMANCE_COUNTERS
+       select HAVE_GPIO_LIB
++      select GENERIC_ALLOCATOR
  
--choice
--      prompt "AVR32 CPU type"
--      default CPU_AT32AP7000
-+#
-+# CPU types
-+#
--config CPU_AT32AP7000
--      bool "AT32AP7000"
-+# AP7000 derivatives
-+config CPU_AT32AP700X
-+      bool
-       select PLATFORM_AT32AP
--endchoice
--
--#
--# CPU Daughterboards for ATSTK1000
--config BOARD_ATSTK1002
-+config CPU_AT32AP7000
-+      bool
-+      select CPU_AT32AP700X
-+config CPU_AT32AP7001
-+      bool
-+      select CPU_AT32AP700X
-+config CPU_AT32AP7002
-       bool
-+      select CPU_AT32AP700X
- choice
-       prompt "AVR32 board type"
-@@ -101,15 +113,18 @@
- config BOARD_ATSTK1000
-       bool "ATSTK1000 evaluation board"
--      select BOARD_ATSTK1002 if CPU_AT32AP7000
- config BOARD_ATNGW100
-       bool "ATNGW100 Network Gateway"
-+      select CPU_AT32AP7000
- endchoice
+ #
+ # CPU types
+@@ -117,6 +123,9 @@
  if BOARD_ATSTK1000
  source "arch/avr32/boards/atstk1000/Kconfig"
  endif
  
  choice
        prompt "Boot loader type"
-@@ -123,15 +138,15 @@
- config LOAD_ADDRESS
-       hex
--      default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y
-+      default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP700X=y
- config ENTRY_ADDRESS
-       hex
--      default 0x90000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y
-+      default 0x90000000 if LOADER_U_BOOT=y && CPU_AT32AP700X=y
- config PHYS_OFFSET
-       hex
--      default 0x10000000 if CPU_AT32AP7000=y
-+      default 0x10000000 if CPU_AT32AP700X=y
- source "kernel/Kconfig.preempt"
+@@ -180,6 +189,10 @@
+         be dumped to the console when a Non-Maskable Interrupt
+         happens.
  
-@@ -163,6 +178,20 @@
-         enabling Nexus-compliant debuggers to keep track of the PID of the
-         currently executing task.
-+config NMI_DEBUGGING
-+      bool "NMI Debugging"
-+      default n
-+      help
-+        Say Y here and pass the nmi_debug command-line parameter to
-+        the kernel to turn on NMI debugging. Depending on the value
-+        of the nmi_debug option, various pieces of information will
-+        be dumped to the console when a Non-Maskable Interrupt
-+        happens.
-+
 +config DW_DMAC
 +      tristate "Synopsys DesignWare DMA Controller support"
 +      default y if CPU_AT32AP7000
  # FPU emulation goes here
  
  source "kernel/Kconfig.hz"
-@@ -219,6 +248,8 @@
- source "fs/Kconfig"
-+source "kernel/Kconfig.instrumentation"
-+
- source "arch/avr32/Kconfig.debug"
- source "security/Kconfig"
---- a/arch/avr32/Kconfig.debug
-+++ b/arch/avr32/Kconfig.debug
-@@ -6,14 +6,4 @@
- source "lib/Kconfig.debug"
--config KPROBES
--      bool "Kprobes"
--      depends on DEBUG_KERNEL
--      help
--        Kprobes allows you to trap at almost any kernel address and
--          execute a callback function.  register_kprobe() establishes
--          a probepoint and specifies the callback.  Kprobes is useful
--          for kernel debugging, non-intrusive instrumentation and testing.
--          If in doubt, say "N".
--
- endmenu
---- a/arch/avr32/kernel/cpu.c
-+++ b/arch/avr32/kernel/cpu.c
-@@ -13,6 +13,7 @@
- #include <linux/percpu.h>
- #include <linux/param.h>
- #include <linux/errno.h>
-+#include <linux/clk.h>
- #include <asm/setup.h>
- #include <asm/sysreg.h>
-@@ -187,9 +188,20 @@
- subsys_initcall(topology_init);
+@@ -196,6 +209,11 @@
  
-+struct chip_id_map {
-+      u16     mid;
-+      u16     pn;
-+      const char *name;
-+};
-+
-+static const struct chip_id_map chip_names[] = {
-+      { .mid = 0x1f, .pn = 0x1e82, .name = "AT32AP700x" },
-+};
-+#define NR_CHIP_NAMES ARRAY_SIZE(chip_names)
-+
- static const char *cpu_names[] = {
-       "Morgan",
--      "AP7000",
-+      "AP7",
- };
- #define NR_CPU_NAMES ARRAY_SIZE(cpu_names)
-@@ -206,12 +218,32 @@
-       "MPU"
- };
+ menu "Power management options"
  
-+static const char *cpu_feature_flags[] = {
-+      "rmw", "dsp", "simd", "ocd", "perfctr", "java", "fpu",
-+};
-+
-+static const char *get_chip_name(struct avr32_cpuinfo *cpu)
-+{
-+      unsigned int i;
-+      unsigned int mid = avr32_get_manufacturer_id(cpu);
-+      unsigned int pn = avr32_get_product_number(cpu);
-+
-+      for (i = 0; i < NR_CHIP_NAMES; i++) {
-+              if (chip_names[i].mid == mid && chip_names[i].pn == pn)
-+                      return chip_names[i].name;
-+      }
++config ARCH_SUSPEND_POSSIBLE
++      def_bool y
 +
-+      return "(unknown)";
-+}
++source "kernel/power/Kconfig"
 +
- void __init setup_processor(void)
- {
-       unsigned long config0, config1;
-       unsigned long features;
-       unsigned cpu_id, cpu_rev, arch_id, arch_rev, mmu_type;
-+      unsigned device_id;
-       unsigned tmp;
-+      unsigned i;
-       config0 = sysreg_read(CONFIG0);
-       config1 = sysreg_read(CONFIG1);
-@@ -221,11 +253,14 @@
-       arch_rev = SYSREG_BFEXT(AR, config0);
-       mmu_type = SYSREG_BFEXT(MMUT, config0);
-+      device_id = ocd_read(DID);
-+
-       boot_cpu_data.arch_type = arch_id;
-       boot_cpu_data.cpu_type = cpu_id;
-       boot_cpu_data.arch_revision = arch_rev;
-       boot_cpu_data.cpu_revision = cpu_rev;
-       boot_cpu_data.tlb_config = mmu_type;
-+      boot_cpu_data.device_id = device_id;
-       tmp = SYSREG_BFEXT(ILSZ, config1);
-       if (tmp) {
-@@ -247,41 +282,34 @@
-               return;
-       }
+ menu "CPU Frequency scaling"
  
--      printk ("CPU: %s [%02x] revision %d (%s revision %d)\n",
-+      printk ("CPU: %s chip revision %c\n", get_chip_name(&boot_cpu_data),
-+                      avr32_get_chip_revision(&boot_cpu_data) + 'A');
-+      printk ("CPU: %s [%02x] core revision %d (%s arch revision %d)\n",
-               cpu_names[cpu_id], cpu_id, cpu_rev,
-               arch_names[arch_id], arch_rev);
-       printk ("CPU: MMU configuration: %s\n", mmu_types[mmu_type]);
-       printk ("CPU: features:");
-       features = 0;
--      if (config0 & SYSREG_BIT(CONFIG0_R)) {
-+      if (config0 & SYSREG_BIT(CONFIG0_R))
-               features |= AVR32_FEATURE_RMW;
--              printk(" rmw");
--      }
--      if (config0 & SYSREG_BIT(CONFIG0_D)) {
-+      if (config0 & SYSREG_BIT(CONFIG0_D))
-               features |= AVR32_FEATURE_DSP;
--              printk(" dsp");
--      }
--      if (config0 & SYSREG_BIT(CONFIG0_S)) {
-+      if (config0 & SYSREG_BIT(CONFIG0_S))
-               features |= AVR32_FEATURE_SIMD;
--              printk(" simd");
--      }
--      if (config0 & SYSREG_BIT(CONFIG0_O)) {
-+      if (config0 & SYSREG_BIT(CONFIG0_O))
-               features |= AVR32_FEATURE_OCD;
--              printk(" ocd");
--      }
--      if (config0 & SYSREG_BIT(CONFIG0_P)) {
-+      if (config0 & SYSREG_BIT(CONFIG0_P))
-               features |= AVR32_FEATURE_PCTR;
--              printk(" perfctr");
--      }
--      if (config0 & SYSREG_BIT(CONFIG0_J)) {
-+      if (config0 & SYSREG_BIT(CONFIG0_J))
-               features |= AVR32_FEATURE_JAVA;
--              printk(" java");
--      }
--      if (config0 & SYSREG_BIT(CONFIG0_F)) {
-+      if (config0 & SYSREG_BIT(CONFIG0_F))
-               features |= AVR32_FEATURE_FPU;
--              printk(" fpu");
--      }
-+
-+      for (i = 0; i < ARRAY_SIZE(cpu_feature_flags); i++)
-+              if (features & (1 << i))
-+                      printk(" %s", cpu_feature_flags[i]);
+ source "drivers/cpufreq/Kconfig"
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/kernel/avr32_ksyms.c avr32-2.6/arch/avr32/kernel/avr32_ksyms.c
+--- linux-2.6.25.6/arch/avr32/kernel/avr32_ksyms.c     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/kernel/avr32_ksyms.c  2008-06-12 15:03:55.883815569 +0200
+@@ -29,7 +29,9 @@
+  */
+ EXPORT_SYMBOL(memset);
+ EXPORT_SYMBOL(memcpy);
 +
-       printk("\n");
-       boot_cpu_data.features = features;
- }
-@@ -291,6 +319,8 @@
- {
-       unsigned int icache_size, dcache_size;
-       unsigned int cpu = smp_processor_id();
-+      unsigned int freq;
-+      unsigned int i;
-       icache_size = boot_cpu_data.icache.ways *
-               boot_cpu_data.icache.sets *
-@@ -301,15 +331,21 @@
-       seq_printf(m, "processor\t: %d\n", cpu);
-+      seq_printf(m, "chip type\t: %s revision %c\n",
-+                      get_chip_name(&boot_cpu_data),
-+                      avr32_get_chip_revision(&boot_cpu_data) + 'A');
-       if (boot_cpu_data.arch_type < NR_ARCH_NAMES)
--              seq_printf(m, "cpu family\t: %s revision %d\n",
-+              seq_printf(m, "cpu arch\t: %s revision %d\n",
-                          arch_names[boot_cpu_data.arch_type],
-                          boot_cpu_data.arch_revision);
-       if (boot_cpu_data.cpu_type < NR_CPU_NAMES)
--              seq_printf(m, "cpu type\t: %s revision %d\n",
-+              seq_printf(m, "cpu core\t: %s revision %d\n",
-                          cpu_names[boot_cpu_data.cpu_type],
-                          boot_cpu_data.cpu_revision);
-+      freq = (clk_get_rate(boot_cpu_data.clk) + 500) / 1000;
-+      seq_printf(m, "cpu MHz\t\t: %u.%03u\n", freq / 1000, freq % 1000);
-+
-       seq_printf(m, "i-cache\t\t: %dK (%u ways x %u sets x %u)\n",
-                  icache_size >> 10,
-                  boot_cpu_data.icache.ways,
-@@ -320,7 +356,13 @@
-                  boot_cpu_data.dcache.ways,
-                  boot_cpu_data.dcache.sets,
-                  boot_cpu_data.dcache.linesz);
--      seq_printf(m, "bogomips\t: %lu.%02lu\n",
-+
-+      seq_printf(m, "features\t:");
-+      for (i = 0; i < ARRAY_SIZE(cpu_feature_flags); i++)
-+              if (boot_cpu_data.features & (1 << i))
-+                      seq_printf(m, " %s", cpu_feature_flags[i]);
-+
-+      seq_printf(m, "\nbogomips\t: %lu.%02lu\n",
-                  boot_cpu_data.loops_per_jiffy / (500000/HZ),
-                  (boot_cpu_data.loops_per_jiffy / (5000/HZ)) % 100);
-@@ -343,7 +385,7 @@
- }
+ EXPORT_SYMBOL(clear_page);
++EXPORT_SYMBOL(copy_page);
  
--struct seq_operations cpuinfo_op = {
-+const struct seq_operations cpuinfo_op = {
-       .start  = c_start,
-       .next   = c_next,
-       .stop   = c_stop,
---- /dev/null
-+++ b/arch/avr32/kernel/dma-controller.c
+ /*
+  * Userspace access stuff.
+@@ -41,6 +43,8 @@
+ EXPORT_SYMBOL(__strncpy_from_user);
+ EXPORT_SYMBOL(clear_user);
+ EXPORT_SYMBOL(__clear_user);
++EXPORT_SYMBOL(strnlen_user);
++
+ EXPORT_SYMBOL(csum_partial);
+ EXPORT_SYMBOL(csum_partial_copy_generic);
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/kernel/dma-controller.c avr32-2.6/arch/avr32/kernel/dma-controller.c
+--- linux-2.6.25.6/arch/avr32/kernel/dma-controller.c  1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/arch/avr32/kernel/dma-controller.c       2008-06-12 15:09:38.719815350 +0200
 @@ -0,0 +1,34 @@
 +/*
 + * Preliminary DMA controller framework for AVR32
 +      return NULL;
 +}
 +EXPORT_SYMBOL(find_dma_controller);
---- a/arch/avr32/kernel/entry-avr32b.S
-+++ b/arch/avr32/kernel/entry-avr32b.S
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/kernel/entry-avr32b.S avr32-2.6/arch/avr32/kernel/entry-avr32b.S
+--- linux-2.6.25.6/arch/avr32/kernel/entry-avr32b.S    2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/kernel/entry-avr32b.S 2008-06-12 15:03:55.883815569 +0200
 @@ -741,26 +741,6 @@
  
        .section .irq.text,"ax",@progbits
        .global irq_level0
        .global irq_level1
        .global irq_level2
---- a/arch/avr32/kernel/irq.c
-+++ b/arch/avr32/kernel/irq.c
-@@ -25,6 +25,17 @@
-       printk("unexpected IRQ %u\n", irq);
- }
-+/* May be overridden by platform code */
-+int __weak nmi_enable(void)
-+{
-+      return -ENOSYS;
-+}
-+
-+void __weak nmi_disable(void)
-+{
-+
-+}
-+
- #ifdef CONFIG_PROC_FS
- int show_interrupts(struct seq_file *p, void *v)
- {
---- a/arch/avr32/kernel/kprobes.c
-+++ b/arch/avr32/kernel/kprobes.c
-@@ -48,6 +48,7 @@
- void __kprobes arch_arm_kprobe(struct kprobe *p)
- {
-       pr_debug("arming kprobe at %p\n", p->addr);
-+      ocd_enable(NULL);
-       *p->addr = BREAKPOINT_INSTRUCTION;
-       flush_icache_range((unsigned long)p->addr,
-                          (unsigned long)p->addr + sizeof(kprobe_opcode_t));
-@@ -56,6 +57,7 @@
- void __kprobes arch_disarm_kprobe(struct kprobe *p)
- {
-       pr_debug("disarming kprobe at %p\n", p->addr);
-+      ocd_disable(NULL);
-       *p->addr = p->opcode;
-       flush_icache_range((unsigned long)p->addr,
-                          (unsigned long)p->addr + sizeof(kprobe_opcode_t));
-@@ -260,9 +262,6 @@
- int __init arch_init_kprobes(void)
- {
--      printk("KPROBES: Enabling monitor mode (MM|DBE)...\n");
--      ocd_write(DC, (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT));
--
-       /* TODO: Register kretprobe trampoline */
-       return 0;
- }
---- a/arch/avr32/kernel/Makefile
-+++ b/arch/avr32/kernel/Makefile
-@@ -6,9 +6,11 @@
- obj-$(CONFIG_SUBARCH_AVR32B)  += entry-avr32b.o
- obj-y                         += syscall_table.o syscall-stubs.o irq.o
--obj-y                         += setup.o traps.o semaphore.o ptrace.o
-+obj-y                         += setup.o traps.o semaphore.o ocd.o ptrace.o
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/kernel/Makefile avr32-2.6/arch/avr32/kernel/Makefile
+--- linux-2.6.25.6/arch/avr32/kernel/Makefile  2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/kernel/Makefile       2008-06-12 15:09:38.719815350 +0200
+@@ -9,6 +9,7 @@
+ obj-y                         += setup.o traps.o semaphore.o ocd.o ptrace.o
  obj-y                         += signal.o sys_avr32.o process.o time.o
  obj-y                         += init_task.o switch_to.o cpu.o
 +obj-y                         += dma-controller.o
  obj-$(CONFIG_MODULES)         += module.o avr32_ksyms.o
  obj-$(CONFIG_KPROBES)         += kprobes.o
  obj-$(CONFIG_STACKTRACE)      += stacktrace.o
-+obj-$(CONFIG_NMI_DEBUGGING)   += nmi_debug.o
---- /dev/null
-+++ b/arch/avr32/kernel/nmi_debug.c
-@@ -0,0 +1,82 @@
-+/*
-+ * Copyright (C) 2007 Atmel Corporation
-+ *
-+ * 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/delay.h>
-+#include <linux/kdebug.h>
-+#include <linux/notifier.h>
-+#include <linux/sched.h>
-+
-+#include <asm/irq.h>
-+
-+enum nmi_action {
-+      NMI_SHOW_STATE  = 1 << 0,
-+      NMI_SHOW_REGS   = 1 << 1,
-+      NMI_DIE         = 1 << 2,
-+      NMI_DEBOUNCE    = 1 << 3,
-+};
-+
-+static unsigned long nmi_actions;
-+
-+static int nmi_debug_notify(struct notifier_block *self,
-+              unsigned long val, void *data)
-+{
-+      struct die_args *args = data;
-+
-+      if (likely(val != DIE_NMI))
-+              return NOTIFY_DONE;
-+
-+      if (nmi_actions & NMI_SHOW_STATE)
-+              show_state();
-+      if (nmi_actions & NMI_SHOW_REGS)
-+              show_regs(args->regs);
-+      if (nmi_actions & NMI_DEBOUNCE)
-+              mdelay(10);
-+      if (nmi_actions & NMI_DIE)
-+              return NOTIFY_BAD;
-+
-+      return NOTIFY_OK;
-+}
-+
-+static struct notifier_block nmi_debug_nb = {
-+      .notifier_call = nmi_debug_notify,
-+};
-+
-+static int __init nmi_debug_setup(char *str)
-+{
-+      char *p, *sep;
-+
-+      register_die_notifier(&nmi_debug_nb);
-+      if (nmi_enable()) {
-+              printk(KERN_WARNING "Unable to enable NMI.\n");
-+              return 0;
-+      }
-+
-+      if (*str != '=')
-+              return 0;
-+
-+      for (p = str + 1; *p; p = sep + 1) {
-+              sep = strchr(p, ',');
-+              if (sep)
-+                      *sep = 0;
-+              if (strcmp(p, "state") == 0)
-+                      nmi_actions |= NMI_SHOW_STATE;
-+              else if (strcmp(p, "regs") == 0)
-+                      nmi_actions |= NMI_SHOW_REGS;
-+              else if (strcmp(p, "debounce") == 0)
-+                      nmi_actions |= NMI_DEBOUNCE;
-+              else if (strcmp(p, "die") == 0)
-+                      nmi_actions |= NMI_DIE;
-+              else
-+                      printk(KERN_WARNING "NMI: Unrecognized action `%s'\n",
-+                              p);
-+              if (!sep)
-+                      break;
-+      }
-+
-+      return 0;
-+}
-+__setup("nmi_debug", nmi_debug_setup);
---- /dev/null
-+++ b/arch/avr32/kernel/ocd.c
-@@ -0,0 +1,163 @@
-+/*
-+ * Copyright (C) 2007 Atmel Corporation
-+ *
-+ * 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/init.h>
-+#include <linux/sched.h>
-+#include <linux/spinlock.h>
-+
-+#include <asm/ocd.h>
-+
-+static long ocd_count;
-+static spinlock_t ocd_lock;
-+
-+/**
-+ * ocd_enable - enable on-chip debugging
-+ * @child: task to be debugged
-+ *
-+ * If @child is non-NULL, ocd_enable() first checks if debugging has
-+ * already been enabled for @child, and if it has, does nothing.
-+ *
-+ * If @child is NULL (e.g. when debugging the kernel), or debugging
-+ * has not already been enabled for it, ocd_enable() increments the
-+ * reference count and enables the debugging hardware.
-+ */
-+void ocd_enable(struct task_struct *child)
-+{
-+      u32 dc;
-+
-+      if (child)
-+              pr_debug("ocd_enable: child=%s [%u]\n",
-+                              child->comm, child->pid);
-+      else
-+              pr_debug("ocd_enable (no child)\n");
-+
-+      if (!child || !test_and_set_tsk_thread_flag(child, TIF_DEBUG)) {
-+              spin_lock(&ocd_lock);
-+              ocd_count++;
-+              dc = ocd_read(DC);
-+              dc |= (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT);
-+              ocd_write(DC, dc);
-+              spin_unlock(&ocd_lock);
-+      }
-+}
-+
-+/**
-+ * ocd_disable - disable on-chip debugging
-+ * @child: task that was being debugged, but isn't anymore
-+ *
-+ * If @child is non-NULL, ocd_disable() checks if debugging is enabled
-+ * for @child, and if it isn't, does nothing.
-+ *
-+ * If @child is NULL (e.g. when debugging the kernel), or debugging is
-+ * enabled, ocd_disable() decrements the reference count, and if it
-+ * reaches zero, disables the debugging hardware.
-+ */
-+void ocd_disable(struct task_struct *child)
-+{
-+      u32 dc;
-+
-+      if (!child)
-+              pr_debug("ocd_disable (no child)\n");
-+      else if (test_tsk_thread_flag(child, TIF_DEBUG))
-+              pr_debug("ocd_disable: child=%s [%u]\n",
-+                              child->comm, child->pid);
-+
-+      if (!child || test_and_clear_tsk_thread_flag(child, TIF_DEBUG)) {
-+              spin_lock(&ocd_lock);
-+              ocd_count--;
-+
-+              WARN_ON(ocd_count < 0);
-+
-+              if (ocd_count <= 0) {
-+                      dc = ocd_read(DC);
-+                      dc &= ~((1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT));
-+                      ocd_write(DC, dc);
-+              }
-+              spin_unlock(&ocd_lock);
-+      }
-+}
-+
-+#ifdef CONFIG_DEBUG_FS
-+#include <linux/debugfs.h>
-+#include <linux/module.h>
-+
-+static struct dentry *ocd_debugfs_root;
-+static struct dentry *ocd_debugfs_DC;
-+static struct dentry *ocd_debugfs_DS;
-+static struct dentry *ocd_debugfs_count;
-+
-+static u64 ocd_DC_get(void *data)
-+{
-+      return ocd_read(DC);
-+}
-+static void ocd_DC_set(void *data, u64 val)
-+{
-+      ocd_write(DC, val);
-+}
-+DEFINE_SIMPLE_ATTRIBUTE(fops_DC, ocd_DC_get, ocd_DC_set, "0x%08llx\n");
-+
-+static u64 ocd_DS_get(void *data)
-+{
-+      return ocd_read(DS);
-+}
-+DEFINE_SIMPLE_ATTRIBUTE(fops_DS, ocd_DS_get, NULL, "0x%08llx\n");
-+
-+static u64 ocd_count_get(void *data)
-+{
-+      return ocd_count;
-+}
-+DEFINE_SIMPLE_ATTRIBUTE(fops_count, ocd_count_get, NULL, "%lld\n");
-+
-+static void ocd_debugfs_init(void)
-+{
-+      struct dentry *root;
-+
-+      root = debugfs_create_dir("ocd", NULL);
-+      if (IS_ERR(root) || !root)
-+              goto err_root;
-+      ocd_debugfs_root = root;
-+
-+      ocd_debugfs_DC = debugfs_create_file("DC", S_IRUSR | S_IWUSR,
-+                              root, NULL, &fops_DC);
-+      if (!ocd_debugfs_DC)
-+              goto err_DC;
-+
-+      ocd_debugfs_DS = debugfs_create_file("DS", S_IRUSR, root,
-+                              NULL, &fops_DS);
-+      if (!ocd_debugfs_DS)
-+              goto err_DS;
-+
-+      ocd_debugfs_count = debugfs_create_file("count", S_IRUSR, root,
-+                              NULL, &fops_count);
-+      if (!ocd_debugfs_count)
-+              goto err_count;
-+
-+      return;
-+
-+err_count:
-+      debugfs_remove(ocd_debugfs_DS);
-+err_DS:
-+      debugfs_remove(ocd_debugfs_DC);
-+err_DC:
-+      debugfs_remove(ocd_debugfs_root);
-+err_root:
-+      printk(KERN_WARNING "OCD: Failed to create debugfs entries\n");
-+}
-+#else
-+static inline void ocd_debugfs_init(void)
-+{
-+
-+}
-+#endif
-+
-+static int __init ocd_init(void)
-+{
-+      spin_lock_init(&ocd_lock);
-+      ocd_debugfs_init();
-+      return 0;
-+}
-+arch_initcall(ocd_init);
---- a/arch/avr32/kernel/process.c
-+++ b/arch/avr32/kernel/process.c
-@@ -11,17 +11,18 @@
- #include <linux/fs.h>
- #include <linux/ptrace.h>
- #include <linux/reboot.h>
-+#include <linux/tick.h>
- #include <linux/uaccess.h>
- #include <linux/unistd.h>
- #include <asm/sysreg.h>
- #include <asm/ocd.h>
-+#include <asm/arch/pm.h>
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/kernel/process.c avr32-2.6/arch/avr32/kernel/process.c
+--- linux-2.6.25.6/arch/avr32/kernel/process.c 2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/kernel/process.c      2008-06-12 15:03:55.887814682 +0200
+@@ -18,11 +18,11 @@
+ #include <asm/sysreg.h>
+ #include <asm/ocd.h>
++#include <asm/arch/pm.h>
 +
  void (*pm_power_off)(void) = NULL;
  EXPORT_SYMBOL(pm_power_off);
  /*
   * This file handles the architecture-dependent parts of process handling..
   */
-@@ -30,8 +31,10 @@
- {
-       /* endless idle loop with no priority at all */
-       while (1) {
-+              tick_nohz_stop_sched_tick();
-               while (!need_resched())
-                       cpu_idle_sleep();
-+              tick_nohz_restart_sched_tick();
-               preempt_enable_no_resched();
-               schedule();
-               preempt_disable();
-@@ -103,7 +106,7 @@
-  */
- void exit_thread(void)
- {
--      /* nothing to do */
-+      ocd_disable(current);
- }
- void flush_thread(void)
-@@ -345,6 +348,10 @@
-       p->thread.cpu_context.ksp = (unsigned long)childregs;
-       p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
+@@ -54,6 +54,8 @@
  
-+      clear_tsk_thread_flag(p, TIF_DEBUG);
-+      if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG))
-+              ocd_enable(p);
-+
-       return 0;
- }
---- a/arch/avr32/kernel/ptrace.c
-+++ b/arch/avr32/kernel/ptrace.c
-@@ -58,6 +58,7 @@
+ void machine_power_off(void)
  {
-       clear_tsk_thread_flag(child, TIF_SINGLE_STEP);
-       clear_tsk_thread_flag(child, TIF_BREAKPOINT);
-+      ocd_disable(child);
++      if (pm_power_off)
++              pm_power_off();
  }
  
- /*
-@@ -144,10 +145,6 @@
- {
-       int ret;
--      pr_debug("ptrace: Enabling monitor mode...\n");
--      ocd_write(DC, ocd_read(DC) | (1 << OCD_DC_MM_BIT)
--                      | (1 << OCD_DC_DBE_BIT));
--
-       switch (request) {
-       /* Read the word at location addr in the child process */
-       case PTRACE_PEEKTEXT:
---- a/arch/avr32/kernel/setup.c
-+++ b/arch/avr32/kernel/setup.c
-@@ -273,6 +273,8 @@
+ void machine_restart(char *cmd)
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/kernel/setup.c avr32-2.6/arch/avr32/kernel/setup.c
+--- linux-2.6.25.6/arch/avr32/kernel/setup.c   2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/kernel/setup.c        2008-06-12 15:03:55.887814682 +0200
+@@ -274,6 +274,8 @@
                        printk(KERN_WARNING
                               "Failed to allocate framebuffer memory\n");
                        fbmem_size = 0;
                }
        }
  
---- a/arch/avr32/kernel/signal.c
-+++ b/arch/avr32/kernel/signal.c
-@@ -270,19 +270,12 @@
-       if (!user_mode(regs))
-               return 0;
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/kernel/signal.c avr32-2.6/arch/avr32/kernel/signal.c
+--- linux-2.6.25.6/arch/avr32/kernel/signal.c  2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/kernel/signal.c       2008-06-12 15:09:38.719815350 +0200
+@@ -93,6 +93,9 @@
+       if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
+               goto badframe;
  
--      if (try_to_freeze()) {
--              signr = 0;
--              if (!signal_pending(current))
--                      goto no_signal;
--      }
--
-       if (test_thread_flag(TIF_RESTORE_SIGMASK))
-               oldset = &current->saved_sigmask;
-       else if (!oldset)
-               oldset = &current->blocked;
-       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
--no_signal:
-       if (syscall) {
-               switch (regs->r12) {
-               case -ERESTART_RESTARTBLOCK:
---- a/arch/avr32/kernel/time.c
-+++ b/arch/avr32/kernel/time.c
++      if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)
++              goto badframe;
++
+       pr_debug("Context restored: pc = %08lx, lr = %08lx, sp = %08lx\n",
+                regs->pc, regs->lr, regs->sp);
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/kernel/time.c avr32-2.6/arch/avr32/kernel/time.c
+--- linux-2.6.25.6/arch/avr32/kernel/time.c    2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/kernel/time.c 2008-06-12 15:03:55.887814682 +0200
 @@ -1,16 +1,12 @@
  /*
   * Copyright (C) 2004-2007 Atmel Corporation
 +      comparator.min_delta_ns = clockevent_delta2ns(50, &comparator) + 1;
  
 -static struct sysdev_class timer_class = {
--      set_kset_name("timer"),
+-      .name = "timer",
 -};
 +      sysreg_write(COMPARE, 0);
 +      timer_irqaction.dev_id = &comparator;
  }
 -
 -device_initcall(init_timer_sysfs);
---- a/arch/avr32/kernel/traps.c
-+++ b/arch/avr32/kernel/traps.c
-@@ -9,6 +9,7 @@
- #include <linux/bug.h>
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/lib/io-readsb.S avr32-2.6/arch/avr32/lib/io-readsb.S
+--- linux-2.6.25.6/arch/avr32/lib/io-readsb.S  2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/lib/io-readsb.S       2008-06-12 15:09:38.719815350 +0200
+@@ -41,7 +41,7 @@
+ 2:    sub     r10, -4
+       reteq   r12
+-3:    ld.uh   r8, r12[0]
++3:    ld.ub   r8, r12[0]
+       sub     r10, 1
+       st.b    r11++, r8
+       brne    3b
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/at32ap700x.c avr32-2.6/arch/avr32/mach-at32ap/at32ap700x.c
+--- linux-2.6.25.6/arch/avr32/mach-at32ap/at32ap700x.c 2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/mach-at32ap/at32ap700x.c      2008-06-12 15:09:38.723815860 +0200
+@@ -6,11 +6,13 @@
+  * published by the Free Software Foundation.
+  */
+ #include <linux/clk.h>
++#include <linux/delay.h>
+ #include <linux/fb.h>
  #include <linux/init.h>
- #include <linux/kallsyms.h>
-+#include <linux/kdebug.h>
- #include <linux/module.h>
- #include <linux/notifier.h>
- #include <linux/sched.h>
-@@ -107,9 +108,23 @@
+ #include <linux/platform_device.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/spi/spi.h>
++#include <linux/usb/atmel_usba_udc.h>
  
- asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs)
- {
--      printk(KERN_ALERT "Got Non-Maskable Interrupt, dumping regs\n");
--      show_regs_log_lvl(regs, KERN_ALERT);
--      show_stack_log_lvl(current, regs->sp, regs, KERN_ALERT);
-+      int ret;
-+
-+      nmi_enter();
-+
-+      ret = notify_die(DIE_NMI, "NMI", regs, 0, ecr, SIGINT);
-+      switch (ret) {
-+      case NOTIFY_OK:
-+      case NOTIFY_STOP:
-+              return;
-+      case NOTIFY_BAD:
-+              die("Fatal Non-Maskable Interrupt", regs, SIGINT);
-+      default:
-+              break;
-+      }
-+
-+      printk(KERN_ALERT "Got NMI, but nobody cared. Disabling...\n");
-+      nmi_disable();
- }
+ #include <asm/io.h>
+ #include <asm/irq.h>
+@@ -18,6 +20,7 @@
+ #include <asm/arch/at32ap700x.h>
+ #include <asm/arch/board.h>
+ #include <asm/arch/portmux.h>
++#include <asm/arch/sram.h>
+ #include <video/atmel_lcdc.h>
+@@ -91,25 +94,18 @@
+ static DEFINE_SPINLOCK(pm_lock);
  
- asmlinkage void do_critical_exception(unsigned long ecr, struct pt_regs *regs)
---- a/arch/avr32/mach-at32ap/at32ap7000.c
-+++ /dev/null
-@@ -1,1730 +0,0 @@
--/*
-- * Copyright (C) 2005-2006 Atmel Corporation
-- *
-- * 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/clk.h>
--#include <linux/fb.h>
--#include <linux/init.h>
--#include <linux/platform_device.h>
--#include <linux/dma-mapping.h>
--#include <linux/spi/spi.h>
--
--#include <asm/io.h>
--
--#include <asm/arch/at32ap7000.h>
--#include <asm/arch/board.h>
--#include <asm/arch/portmux.h>
--
--#include <video/atmel_lcdc.h>
--
--#include "clock.h"
--#include "hmatrix.h"
--#include "pio.h"
--#include "pm.h"
--
--
--#define PBMEM(base)                                   \
--      {                                               \
--              .start          = base,                 \
--              .end            = base + 0x3ff,         \
--              .flags          = IORESOURCE_MEM,       \
--      }
--#define IRQ(num)                                      \
--      {                                               \
--              .start          = num,                  \
--              .end            = num,                  \
--              .flags          = IORESOURCE_IRQ,       \
--      }
--#define NAMED_IRQ(num, _name)                         \
--      {                                               \
--              .start          = num,                  \
--              .end            = num,                  \
--              .name           = _name,                \
--              .flags          = IORESOURCE_IRQ,       \
--      }
--
--/* REVISIT these assume *every* device supports DMA, but several
-- * don't ... tc, smc, pio, rtc, watchdog, pwm, ps2, and more.
-- */
--#define DEFINE_DEV(_name, _id)                                        \
--static u64 _name##_id##_dma_mask = DMA_32BIT_MASK;            \
--static struct platform_device _name##_id##_device = {         \
--      .name           = #_name,                               \
--      .id             = _id,                                  \
--      .dev            = {                                     \
--              .dma_mask = &_name##_id##_dma_mask,             \
--              .coherent_dma_mask = DMA_32BIT_MASK,            \
--      },                                                      \
--      .resource       = _name##_id##_resource,                \
--      .num_resources  = ARRAY_SIZE(_name##_id##_resource),    \
--}
--#define DEFINE_DEV_DATA(_name, _id)                           \
--static u64 _name##_id##_dma_mask = DMA_32BIT_MASK;            \
--static struct platform_device _name##_id##_device = {         \
--      .name           = #_name,                               \
--      .id             = _id,                                  \
--      .dev            = {                                     \
--              .dma_mask = &_name##_id##_dma_mask,             \
--              .platform_data  = &_name##_id##_data,           \
--              .coherent_dma_mask = DMA_32BIT_MASK,            \
--      },                                                      \
--      .resource       = _name##_id##_resource,                \
--      .num_resources  = ARRAY_SIZE(_name##_id##_resource),    \
--}
--
--#define select_peripheral(pin, periph, flags)                 \
--      at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)
--
--#define DEV_CLK(_name, devname, bus, _index)                  \
--static struct clk devname##_##_name = {                               \
--      .name           = #_name,                               \
--      .dev            = &devname##_device.dev,                \
--      .parent         = &bus##_clk,                           \
--      .mode           = bus##_clk_mode,                       \
--      .get_rate       = bus##_clk_get_rate,                   \
--      .index          = _index,                               \
--}
--
--static DEFINE_SPINLOCK(pm_lock);
--
 -unsigned long at32ap7000_osc_rates[3] = {
 -      [0] = 32768,
 -      /* FIXME: these are ATSTK1002-specific */
 -      [1] = 20000000,
 -      [2] = 12000000,
 -};
--
--static unsigned long osc_get_rate(struct clk *clk)
--{
++static struct clk osc0;
++static struct clk osc1;
+ static unsigned long osc_get_rate(struct clk *clk)
+ {
 -      return at32ap7000_osc_rates[clk->index];
--}
--
--static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
--{
--      unsigned long div, mul, rate;
--
++      return at32_board_osc_rates[clk->index];
+ }
+ static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
+ {
+       unsigned long div, mul, rate;
 -      if (!(control & PM_BIT(PLLEN)))
 -              return 0;
 -
--      div = PM_BFEXT(PLLDIV, control) + 1;
--      mul = PM_BFEXT(PLLMUL, control) + 1;
--
--      rate = clk->parent->get_rate(clk->parent);
--      rate = (rate + div / 2) / div;
--      rate *= mul;
--
--      return rate;
--}
--
--static unsigned long pll0_get_rate(struct clk *clk)
--{
--      u32 control;
--
--      control = pm_readl(PLL0);
--
--      return pll_get_rate(clk, control);
--}
--
--static unsigned long pll1_get_rate(struct clk *clk)
--{
--      u32 control;
--
--      control = pm_readl(PLL1);
--
--      return pll_get_rate(clk, control);
--}
--
--/*
-- * The AT32AP7000 has five primary clock sources: One 32kHz
-- * oscillator, two crystal oscillators and two PLLs.
-- */
--static struct clk osc32k = {
--      .name           = "osc32k",
--      .get_rate       = osc_get_rate,
--      .users          = 1,
--      .index          = 0,
--};
--static struct clk osc0 = {
--      .name           = "osc0",
--      .get_rate       = osc_get_rate,
--      .users          = 1,
--      .index          = 1,
--};
--static struct clk osc1 = {
--      .name           = "osc1",
--      .get_rate       = osc_get_rate,
--      .index          = 2,
--};
--static struct clk pll0 = {
--      .name           = "pll0",
--      .get_rate       = pll0_get_rate,
--      .parent         = &osc0,
--};
--static struct clk pll1 = {
--      .name           = "pll1",
--      .get_rate       = pll1_get_rate,
--      .parent         = &osc0,
--};
--
--/*
-- * The main clock can be either osc0 or pll0.  The boot loader may
-- * have chosen one for us, so we don't really know which one until we
-- * have a look at the SM.
-- */
--static struct clk *main_clock;
--
--/*
-- * Synchronous clocks are generated from the main clock. The clocks
-- * must satisfy the constraint
-- *   fCPU >= fHSB >= fPB
-- * i.e. each clock must not be faster than its parent.
-- */
--static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift)
--{
--      return main_clock->get_rate(main_clock) >> shift;
--};
--
--static void cpu_clk_mode(struct clk *clk, int enabled)
--{
--      unsigned long flags;
--      u32 mask;
--
--      spin_lock_irqsave(&pm_lock, flags);
--      mask = pm_readl(CPU_MASK);
--      if (enabled)
--              mask |= 1 << clk->index;
--      else
--              mask &= ~(1 << clk->index);
--      pm_writel(CPU_MASK, mask);
--      spin_unlock_irqrestore(&pm_lock, flags);
--}
--
--static unsigned long cpu_clk_get_rate(struct clk *clk)
--{
--      unsigned long cksel, shift = 0;
--
--      cksel = pm_readl(CKSEL);
--      if (cksel & PM_BIT(CPUDIV))
--              shift = PM_BFEXT(CPUSEL, cksel) + 1;
--
--      return bus_clk_get_rate(clk, shift);
--}
--
--static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply)
--{
--      u32 control;
--      unsigned long parent_rate, child_div, actual_rate, div;
--
--      parent_rate = clk->parent->get_rate(clk->parent);
--      control = pm_readl(CKSEL);
--
--      if (control & PM_BIT(HSBDIV))
--              child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1);
--      else
--              child_div = 1;
--
--      if (rate > 3 * (parent_rate / 4) || child_div == 1) {
--              actual_rate = parent_rate;
--              control &= ~PM_BIT(CPUDIV);
--      } else {
--              unsigned int cpusel;
--              div = (parent_rate + rate / 2) / rate;
--              if (div > child_div)
--                      div = child_div;
--              cpusel = (div > 1) ? (fls(div) - 2) : 0;
--              control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control);
--              actual_rate = parent_rate / (1 << (cpusel + 1));
--      }
--
--      pr_debug("clk %s: new rate %lu (actual rate %lu)\n",
--                      clk->name, rate, actual_rate);
--
--      if (apply)
--              pm_writel(CKSEL, control);
--
--      return actual_rate;
--}
--
--static void hsb_clk_mode(struct clk *clk, int enabled)
--{
--      unsigned long flags;
--      u32 mask;
--
--      spin_lock_irqsave(&pm_lock, flags);
--      mask = pm_readl(HSB_MASK);
--      if (enabled)
--              mask |= 1 << clk->index;
--      else
--              mask &= ~(1 << clk->index);
--      pm_writel(HSB_MASK, mask);
--      spin_unlock_irqrestore(&pm_lock, flags);
--}
--
--static unsigned long hsb_clk_get_rate(struct clk *clk)
--{
--      unsigned long cksel, shift = 0;
--
--      cksel = pm_readl(CKSEL);
--      if (cksel & PM_BIT(HSBDIV))
--              shift = PM_BFEXT(HSBSEL, cksel) + 1;
--
--      return bus_clk_get_rate(clk, shift);
--}
--
--static void pba_clk_mode(struct clk *clk, int enabled)
--{
--      unsigned long flags;
--      u32 mask;
--
--      spin_lock_irqsave(&pm_lock, flags);
--      mask = pm_readl(PBA_MASK);
--      if (enabled)
--              mask |= 1 << clk->index;
--      else
--              mask &= ~(1 << clk->index);
--      pm_writel(PBA_MASK, mask);
--      spin_unlock_irqrestore(&pm_lock, flags);
--}
--
--static unsigned long pba_clk_get_rate(struct clk *clk)
--{
--      unsigned long cksel, shift = 0;
--
--      cksel = pm_readl(CKSEL);
--      if (cksel & PM_BIT(PBADIV))
--              shift = PM_BFEXT(PBASEL, cksel) + 1;
--
--      return bus_clk_get_rate(clk, shift);
--}
--
--static void pbb_clk_mode(struct clk *clk, int enabled)
--{
--      unsigned long flags;
--      u32 mask;
--
--      spin_lock_irqsave(&pm_lock, flags);
--      mask = pm_readl(PBB_MASK);
--      if (enabled)
--              mask |= 1 << clk->index;
--      else
--              mask &= ~(1 << clk->index);
--      pm_writel(PBB_MASK, mask);
--      spin_unlock_irqrestore(&pm_lock, flags);
--}
--
--static unsigned long pbb_clk_get_rate(struct clk *clk)
--{
--      unsigned long cksel, shift = 0;
--
--      cksel = pm_readl(CKSEL);
--      if (cksel & PM_BIT(PBBDIV))
--              shift = PM_BFEXT(PBBSEL, cksel) + 1;
--
--      return bus_clk_get_rate(clk, shift);
--}
--
--static struct clk cpu_clk = {
--      .name           = "cpu",
--      .get_rate       = cpu_clk_get_rate,
--      .set_rate       = cpu_clk_set_rate,
--      .users          = 1,
--};
--static struct clk hsb_clk = {
--      .name           = "hsb",
--      .parent         = &cpu_clk,
--      .get_rate       = hsb_clk_get_rate,
--};
--static struct clk pba_clk = {
--      .name           = "pba",
--      .parent         = &hsb_clk,
--      .mode           = hsb_clk_mode,
--      .get_rate       = pba_clk_get_rate,
--      .index          = 1,
--};
--static struct clk pbb_clk = {
--      .name           = "pbb",
--      .parent         = &hsb_clk,
--      .mode           = hsb_clk_mode,
--      .get_rate       = pbb_clk_get_rate,
--      .users          = 1,
--      .index          = 2,
--};
--
--/* --------------------------------------------------------------------
-- *  Generic Clock operations
-- * -------------------------------------------------------------------- */
--
--static void genclk_mode(struct clk *clk, int enabled)
--{
--      u32 control;
--
--      control = pm_readl(GCCTRL(clk->index));
--      if (enabled)
--              control |= PM_BIT(CEN);
--      else
--              control &= ~PM_BIT(CEN);
--      pm_writel(GCCTRL(clk->index), control);
--}
--
--static unsigned long genclk_get_rate(struct clk *clk)
--{
--      u32 control;
--      unsigned long div = 1;
--
--      control = pm_readl(GCCTRL(clk->index));
--      if (control & PM_BIT(DIVEN))
--              div = 2 * (PM_BFEXT(DIV, control) + 1);
--
--      return clk->parent->get_rate(clk->parent) / div;
--}
--
--static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply)
--{
--      u32 control;
--      unsigned long parent_rate, actual_rate, div;
--
--      parent_rate = clk->parent->get_rate(clk->parent);
--      control = pm_readl(GCCTRL(clk->index));
--
--      if (rate > 3 * parent_rate / 4) {
--              actual_rate = parent_rate;
--              control &= ~PM_BIT(DIVEN);
--      } else {
--              div = (parent_rate + rate) / (2 * rate) - 1;
--              control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN);
--              actual_rate = parent_rate / (2 * (div + 1));
--      }
--
--      dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n",
--              clk->name, rate, actual_rate);
--
--      if (apply)
--              pm_writel(GCCTRL(clk->index), control);
--
--      return actual_rate;
--}
--
--int genclk_set_parent(struct clk *clk, struct clk *parent)
--{
--      u32 control;
--
--      dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n",
--              clk->name, parent->name, clk->parent->name);
--
--      control = pm_readl(GCCTRL(clk->index));
--
--      if (parent == &osc1 || parent == &pll1)
--              control |= PM_BIT(OSCSEL);
--      else if (parent == &osc0 || parent == &pll0)
--              control &= ~PM_BIT(OSCSEL);
--      else
--              return -EINVAL;
--
--      if (parent == &pll0 || parent == &pll1)
--              control |= PM_BIT(PLLSEL);
--      else
--              control &= ~PM_BIT(PLLSEL);
--
--      pm_writel(GCCTRL(clk->index), control);
--      clk->parent = parent;
--
--      return 0;
--}
--
--static void __init genclk_init_parent(struct clk *clk)
--{
--      u32 control;
--      struct clk *parent;
--
--      BUG_ON(clk->index > 7);
--
--      control = pm_readl(GCCTRL(clk->index));
--      if (control & PM_BIT(OSCSEL))
--              parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1;
--      else
--              parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0;
--
--      clk->parent = parent;
--}
--
--/* --------------------------------------------------------------------
-- *  System peripherals
-- * -------------------------------------------------------------------- */
--static struct resource at32_pm0_resource[] = {
--      {
--              .start  = 0xfff00000,
--              .end    = 0xfff0007f,
--              .flags  = IORESOURCE_MEM,
--      },
--      IRQ(20),
--};
--
--static struct resource at32ap700x_rtc0_resource[] = {
--      {
--              .start  = 0xfff00080,
--              .end    = 0xfff000af,
--              .flags  = IORESOURCE_MEM,
--      },
--      IRQ(21),
--};
--
--static struct resource at32_wdt0_resource[] = {
--      {
--              .start  = 0xfff000b0,
--              .end    = 0xfff000cf,
--              .flags  = IORESOURCE_MEM,
--      },
--};
--
--static struct resource at32_eic0_resource[] = {
--      {
--              .start  = 0xfff00100,
--              .end    = 0xfff0013f,
--              .flags  = IORESOURCE_MEM,
--      },
--      IRQ(19),
--};
--
--DEFINE_DEV(at32_pm, 0);
--DEFINE_DEV(at32ap700x_rtc, 0);
--DEFINE_DEV(at32_wdt, 0);
--DEFINE_DEV(at32_eic, 0);
--
--/*
-- * Peripheral clock for PM, RTC, WDT and EIC. PM will ensure that this
-- * is always running.
-- */
--static struct clk at32_pm_pclk = {
--      .name           = "pclk",
--      .dev            = &at32_pm0_device.dev,
--      .parent         = &pbb_clk,
--      .mode           = pbb_clk_mode,
--      .get_rate       = pbb_clk_get_rate,
--      .users          = 1,
--      .index          = 0,
--};
--
--static struct resource intc0_resource[] = {
--      PBMEM(0xfff00400),
--};
--struct platform_device at32_intc0_device = {
--      .name           = "intc",
--      .id             = 0,
--      .resource       = intc0_resource,
--      .num_resources  = ARRAY_SIZE(intc0_resource),
--};
--DEV_CLK(pclk, at32_intc0, pbb, 1);
--
--static struct clk ebi_clk = {
--      .name           = "ebi",
--      .parent         = &hsb_clk,
--      .mode           = hsb_clk_mode,
--      .get_rate       = hsb_clk_get_rate,
--      .users          = 1,
--};
--static struct clk hramc_clk = {
--      .name           = "hramc",
--      .parent         = &hsb_clk,
--      .mode           = hsb_clk_mode,
--      .get_rate       = hsb_clk_get_rate,
--      .users          = 1,
--      .index          = 3,
--};
--
--static struct resource smc0_resource[] = {
--      PBMEM(0xfff03400),
--};
--DEFINE_DEV(smc, 0);
--DEV_CLK(pclk, smc0, pbb, 13);
--DEV_CLK(mck, smc0, hsb, 0);
--
--static struct platform_device pdc_device = {
--      .name           = "pdc",
--      .id             = 0,
--};
--DEV_CLK(hclk, pdc, hsb, 4);
--DEV_CLK(pclk, pdc, pba, 16);
--
--static struct clk pico_clk = {
--      .name           = "pico",
--      .parent         = &cpu_clk,
--      .mode           = cpu_clk_mode,
--      .get_rate       = cpu_clk_get_rate,
--      .users          = 1,
--};
--
--static struct resource dmaca0_resource[] = {
--      {
--              .start  = 0xff200000,
--              .end    = 0xff20ffff,
--              .flags  = IORESOURCE_MEM,
--      },
--      IRQ(2),
--};
--DEFINE_DEV(dmaca, 0);
--DEV_CLK(hclk, dmaca0, hsb, 10);
--
--/* --------------------------------------------------------------------
-- * HMATRIX
-- * -------------------------------------------------------------------- */
--
--static struct clk hmatrix_clk = {
--      .name           = "hmatrix_clk",
--      .parent         = &pbb_clk,
--      .mode           = pbb_clk_mode,
--      .get_rate       = pbb_clk_get_rate,
--      .index          = 2,
--      .users          = 1,
--};
--#define HMATRIX_BASE  ((void __iomem *)0xfff00800)
--
--#define hmatrix_readl(reg)                                    \
--      __raw_readl((HMATRIX_BASE) + HMATRIX_##reg)
--#define hmatrix_writel(reg,value)                             \
--      __raw_writel((value), (HMATRIX_BASE) + HMATRIX_##reg)
--
--/*
-- * Set bits in the HMATRIX Special Function Register (SFR) used by the
-- * External Bus Interface (EBI). This can be used to enable special
-- * features like CompactFlash support, NAND Flash support, etc. on
-- * certain chipselects.
-- */
--static inline void set_ebi_sfr_bits(u32 mask)
--{
--      u32 sfr;
--
--      clk_enable(&hmatrix_clk);
--      sfr = hmatrix_readl(SFR4);
--      sfr |= mask;
--      hmatrix_writel(SFR4, sfr);
--      clk_disable(&hmatrix_clk);
--}
--
--/* --------------------------------------------------------------------
+       div = PM_BFEXT(PLLDIV, control) + 1;
+       mul = PM_BFEXT(PLLMUL, control) + 1;
+@@ -120,6 +116,71 @@
+       return rate;
+ }
++static long pll_set_rate(struct clk *clk, unsigned long rate,
++                       u32 *pll_ctrl)
++{
++      unsigned long mul;
++      unsigned long mul_best_fit = 0;
++      unsigned long div;
++      unsigned long div_min;
++      unsigned long div_max;
++      unsigned long div_best_fit = 0;
++      unsigned long base;
++      unsigned long pll_in;
++      unsigned long actual = 0;
++      unsigned long rate_error;
++      unsigned long rate_error_prev = ~0UL;
++      u32 ctrl;
++
++      /* Rate must be between 80 MHz and 200 Mhz. */
++      if (rate < 80000000UL || rate > 200000000UL)
++              return -EINVAL;
++
++      ctrl = PM_BF(PLLOPT, 4);
++      base = clk->parent->get_rate(clk->parent);
++
++      /* PLL input frequency must be between 6 MHz and 32 MHz. */
++      div_min = DIV_ROUND_UP(base, 32000000UL);
++      div_max = base / 6000000UL;
++
++      if (div_max < div_min)
++              return -EINVAL;
++
++      for (div = div_min; div <= div_max; div++) {
++              pll_in = (base + div / 2) / div;
++              mul = (rate + pll_in / 2) / pll_in;
++
++              if (mul == 0)
++                      continue;
++
++              actual = pll_in * mul;
++              rate_error = abs(actual - rate);
++
++              if (rate_error < rate_error_prev) {
++                      mul_best_fit = mul;
++                      div_best_fit = div;
++                      rate_error_prev = rate_error;
++              }
++
++              if (rate_error == 0)
++                      break;
++      }
++
++      if (div_best_fit == 0)
++              return -EINVAL;
++
++      ctrl |= PM_BF(PLLMUL, mul_best_fit - 1);
++      ctrl |= PM_BF(PLLDIV, div_best_fit - 1);
++      ctrl |= PM_BF(PLLCOUNT, 16);
++
++      if (clk->parent == &osc1)
++              ctrl |= PM_BIT(PLLOSC);
++
++      *pll_ctrl = ctrl;
++
++      return actual;
++}
++
+ static unsigned long pll0_get_rate(struct clk *clk)
+ {
+       u32 control;
+@@ -129,6 +190,41 @@
+       return pll_get_rate(clk, control);
+ }
++static void pll1_mode(struct clk *clk, int enabled)
++{
++      unsigned long timeout;
++      u32 status;
++      u32 ctrl;
++
++      ctrl = pm_readl(PLL1);
++
++      if (enabled) {
++              if (!PM_BFEXT(PLLMUL, ctrl) && !PM_BFEXT(PLLDIV, ctrl)) {
++                      pr_debug("clk %s: failed to enable, rate not set\n",
++                                      clk->name);
++                      return;
++              }
++
++              ctrl |= PM_BIT(PLLEN);
++              pm_writel(PLL1, ctrl);
++
++              /* Wait for PLL lock. */
++              for (timeout = 10000; timeout; timeout--) {
++                      status = pm_readl(ISR);
++                      if (status & PM_BIT(LOCK1))
++                              break;
++                      udelay(10);
++              }
++
++              if (!(status & PM_BIT(LOCK1)))
++                      printk(KERN_ERR "clk %s: timeout waiting for lock\n",
++                                      clk->name);
++      } else {
++              ctrl &= ~PM_BIT(PLLEN);
++              pm_writel(PLL1, ctrl);
++      }
++}
++
+ static unsigned long pll1_get_rate(struct clk *clk)
+ {
+       u32 control;
+@@ -138,6 +234,49 @@
+       return pll_get_rate(clk, control);
+ }
++static long pll1_set_rate(struct clk *clk, unsigned long rate, int apply)
++{
++      u32 ctrl = 0;
++      unsigned long actual_rate;
++
++      actual_rate = pll_set_rate(clk, rate, &ctrl);
++
++      if (apply) {
++              if (actual_rate != rate)
++                      return -EINVAL;
++              if (clk->users > 0)
++                      return -EBUSY;
++              pr_debug(KERN_INFO "clk %s: new rate %lu (actual rate %lu)\n",
++                              clk->name, rate, actual_rate);
++              pm_writel(PLL1, ctrl);
++      }
++
++      return actual_rate;
++}
++
++static int pll1_set_parent(struct clk *clk, struct clk *parent)
++{
++      u32 ctrl;
++
++      if (clk->users > 0)
++              return -EBUSY;
++
++      ctrl = pm_readl(PLL1);
++      WARN_ON(ctrl & PM_BIT(PLLEN));
++
++      if (parent == &osc0)
++              ctrl &= ~PM_BIT(PLLOSC);
++      else if (parent == &osc1)
++              ctrl |= PM_BIT(PLLOSC);
++      else
++              return -EINVAL;
++
++      pm_writel(PLL1, ctrl);
++      clk->parent = parent;
++
++      return 0;
++}
++
+ /*
+  * The AT32AP7000 has five primary clock sources: One 32kHz
+  * oscillator, two crystal oscillators and two PLLs.
+@@ -166,7 +305,10 @@
+ };
+ static struct clk pll1 = {
+       .name           = "pll1",
++      .mode           = pll1_mode,
+       .get_rate       = pll1_get_rate,
++      .set_rate       = pll1_set_rate,
++      .set_parent     = pll1_set_parent,
+       .parent         = &osc0,
+ };
+@@ -534,6 +676,14 @@
+       .users          = 1,
+       .index          = 3,
+ };
++static struct clk sdramc_clk = {
++      .name           = "sdramc_clk",
++      .parent         = &pbb_clk,
++      .mode           = pbb_clk_mode,
++      .get_rate       = pbb_clk_get_rate,
++      .users          = 1,
++      .index          = 14,
++};
+ static struct resource smc0_resource[] = {
+       PBMEM(0xfff03400),
+@@ -605,19 +755,32 @@
+ }
+ /* --------------------------------------------------------------------
 - *  System Timer/Counter (TC)
-- * -------------------------------------------------------------------- */
++ *  Timer/Counter (TC)
+  * -------------------------------------------------------------------- */
 -static struct resource at32_systc0_resource[] = {
--      PBMEM(0xfff00c00),
--      IRQ(22),
--};
++
++static struct resource at32_tcb0_resource[] = {
+       PBMEM(0xfff00c00),
+       IRQ(22),
+ };
 -struct platform_device at32_systc0_device = {
 -      .name           = "systc",
--      .id             = 0,
++static struct platform_device at32_tcb0_device = {
++      .name           = "atmel_tcb",
+       .id             = 0,
 -      .resource       = at32_systc0_resource,
 -      .num_resources  = ARRAY_SIZE(at32_systc0_resource),
--};
++      .resource       = at32_tcb0_resource,
++      .num_resources  = ARRAY_SIZE(at32_tcb0_resource),
+ };
 -DEV_CLK(pclk, at32_systc0, pbb, 3);
--
--/* --------------------------------------------------------------------
-- *  PIO
-- * -------------------------------------------------------------------- */
--
--static struct resource pio0_resource[] = {
--      PBMEM(0xffe02800),
--      IRQ(13),
--};
--DEFINE_DEV(pio, 0);
--DEV_CLK(mck, pio0, pba, 10);
--
--static struct resource pio1_resource[] = {
--      PBMEM(0xffe02c00),
--      IRQ(14),
--};
--DEFINE_DEV(pio, 1);
--DEV_CLK(mck, pio1, pba, 11);
--
--static struct resource pio2_resource[] = {
--      PBMEM(0xffe03000),
--      IRQ(15),
--};
--DEFINE_DEV(pio, 2);
--DEV_CLK(mck, pio2, pba, 12);
--
--static struct resource pio3_resource[] = {
--      PBMEM(0xffe03400),
--      IRQ(16),
--};
--DEFINE_DEV(pio, 3);
--DEV_CLK(mck, pio3, pba, 13);
--
--static struct resource pio4_resource[] = {
--      PBMEM(0xffe03800),
--      IRQ(17),
--};
--DEFINE_DEV(pio, 4);
--DEV_CLK(mck, pio4, pba, 14);
--
--void __init at32_add_system_devices(void)
--{
--      platform_device_register(&at32_pm0_device);
--      platform_device_register(&at32_intc0_device);
--      platform_device_register(&at32ap700x_rtc0_device);
--      platform_device_register(&at32_wdt0_device);
--      platform_device_register(&at32_eic0_device);
--      platform_device_register(&smc0_device);
--      platform_device_register(&pdc_device);
--      platform_device_register(&dmaca0_device);
--
++DEV_CLK(t0_clk, at32_tcb0, pbb, 3);
++
++static struct resource at32_tcb1_resource[] = {
++      PBMEM(0xfff01000),
++      IRQ(23),
++};
++static struct platform_device at32_tcb1_device = {
++      .name           = "atmel_tcb",
++      .id             = 1,
++      .resource       = at32_tcb1_resource,
++      .num_resources  = ARRAY_SIZE(at32_tcb1_resource),
++};
++DEV_CLK(t0_clk, at32_tcb1, pbb, 4);
+ /* --------------------------------------------------------------------
+  *  PIO
+@@ -669,7 +832,8 @@
+       platform_device_register(&pdc_device);
+       platform_device_register(&dmaca0_device);
 -      platform_device_register(&at32_systc0_device);
--
--      platform_device_register(&pio0_device);
--      platform_device_register(&pio1_device);
--      platform_device_register(&pio2_device);
--      platform_device_register(&pio3_device);
--      platform_device_register(&pio4_device);
--}
--
--/* --------------------------------------------------------------------
-- *  USART
-- * -------------------------------------------------------------------- */
--
--static struct atmel_uart_data atmel_usart0_data = {
--      .use_dma_tx     = 1,
--      .use_dma_rx     = 1,
--};
--static struct resource atmel_usart0_resource[] = {
--      PBMEM(0xffe00c00),
--      IRQ(6),
--};
--DEFINE_DEV_DATA(atmel_usart, 0);
--DEV_CLK(usart, atmel_usart0, pba, 3);
--
--static struct atmel_uart_data atmel_usart1_data = {
--      .use_dma_tx     = 1,
--      .use_dma_rx     = 1,
--};
--static struct resource atmel_usart1_resource[] = {
--      PBMEM(0xffe01000),
--      IRQ(7),
--};
--DEFINE_DEV_DATA(atmel_usart, 1);
--DEV_CLK(usart, atmel_usart1, pba, 4);
--
--static struct atmel_uart_data atmel_usart2_data = {
--      .use_dma_tx     = 1,
--      .use_dma_rx     = 1,
--};
--static struct resource atmel_usart2_resource[] = {
--      PBMEM(0xffe01400),
--      IRQ(8),
--};
--DEFINE_DEV_DATA(atmel_usart, 2);
--DEV_CLK(usart, atmel_usart2, pba, 5);
--
--static struct atmel_uart_data atmel_usart3_data = {
--      .use_dma_tx     = 1,
--      .use_dma_rx     = 1,
--};
--static struct resource atmel_usart3_resource[] = {
--      PBMEM(0xffe01800),
--      IRQ(9),
--};
--DEFINE_DEV_DATA(atmel_usart, 3);
--DEV_CLK(usart, atmel_usart3, pba, 6);
--
--static inline void configure_usart0_pins(void)
--{
--      select_peripheral(PA(8),  PERIPH_B, 0); /* RXD  */
--      select_peripheral(PA(9),  PERIPH_B, 0); /* TXD  */
--}
--
--static inline void configure_usart1_pins(void)
--{
--      select_peripheral(PA(17), PERIPH_A, 0); /* RXD  */
--      select_peripheral(PA(18), PERIPH_A, 0); /* TXD  */
--}
--
--static inline void configure_usart2_pins(void)
--{
--      select_peripheral(PB(26), PERIPH_B, 0); /* RXD  */
--      select_peripheral(PB(27), PERIPH_B, 0); /* TXD  */
--}
--
--static inline void configure_usart3_pins(void)
--{
--      select_peripheral(PB(18), PERIPH_B, 0); /* RXD  */
--      select_peripheral(PB(17), PERIPH_B, 0); /* TXD  */
--}
--
--static struct platform_device *__initdata at32_usarts[4];
--
--void __init at32_map_usart(unsigned int hw_id, unsigned int line)
--{
--      struct platform_device *pdev;
--
--      switch (hw_id) {
--      case 0:
--              pdev = &atmel_usart0_device;
--              configure_usart0_pins();
--              break;
--      case 1:
--              pdev = &atmel_usart1_device;
--              configure_usart1_pins();
--              break;
--      case 2:
--              pdev = &atmel_usart2_device;
--              configure_usart2_pins();
--              break;
--      case 3:
--              pdev = &atmel_usart3_device;
--              configure_usart3_pins();
--              break;
--      default:
--              return;
--      }
--
--      if (PXSEG(pdev->resource[0].start) == P4SEG) {
--              /* Addresses in the P4 segment are permanently mapped 1:1 */
--              struct atmel_uart_data *data = pdev->dev.platform_data;
--              data->regs = (void __iomem *)pdev->resource[0].start;
--      }
--
--      pdev->id = line;
--      at32_usarts[line] = pdev;
--}
--
--struct platform_device *__init at32_add_device_usart(unsigned int id)
--{
--      platform_device_register(at32_usarts[id]);
--      return at32_usarts[id];
--}
--
--struct platform_device *atmel_default_console_device;
--
--void __init at32_setup_serial_console(unsigned int usart_id)
--{
--      atmel_default_console_device = at32_usarts[usart_id];
--}
--
--/* --------------------------------------------------------------------
-- *  Ethernet
-- * -------------------------------------------------------------------- */
--
--static struct eth_platform_data macb0_data;
--static struct resource macb0_resource[] = {
--      PBMEM(0xfff01800),
--      IRQ(25),
--};
--DEFINE_DEV_DATA(macb, 0);
--DEV_CLK(hclk, macb0, hsb, 8);
--DEV_CLK(pclk, macb0, pbb, 6);
--
--static struct eth_platform_data macb1_data;
--static struct resource macb1_resource[] = {
--      PBMEM(0xfff01c00),
--      IRQ(26),
--};
--DEFINE_DEV_DATA(macb, 1);
--DEV_CLK(hclk, macb1, hsb, 9);
--DEV_CLK(pclk, macb1, pbb, 7);
--
--struct platform_device *__init
--at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
--{
--      struct platform_device *pdev;
--
--      switch (id) {
--      case 0:
--              pdev = &macb0_device;
--
--              select_peripheral(PC(3),  PERIPH_A, 0); /* TXD0 */
--              select_peripheral(PC(4),  PERIPH_A, 0); /* TXD1 */
--              select_peripheral(PC(7),  PERIPH_A, 0); /* TXEN */
--              select_peripheral(PC(8),  PERIPH_A, 0); /* TXCK */
--              select_peripheral(PC(9),  PERIPH_A, 0); /* RXD0 */
--              select_peripheral(PC(10), PERIPH_A, 0); /* RXD1 */
--              select_peripheral(PC(13), PERIPH_A, 0); /* RXER */
--              select_peripheral(PC(15), PERIPH_A, 0); /* RXDV */
--              select_peripheral(PC(16), PERIPH_A, 0); /* MDC  */
--              select_peripheral(PC(17), PERIPH_A, 0); /* MDIO */
--
--              if (!data->is_rmii) {
--                      select_peripheral(PC(0),  PERIPH_A, 0); /* COL  */
--                      select_peripheral(PC(1),  PERIPH_A, 0); /* CRS  */
--                      select_peripheral(PC(2),  PERIPH_A, 0); /* TXER */
--                      select_peripheral(PC(5),  PERIPH_A, 0); /* TXD2 */
--                      select_peripheral(PC(6),  PERIPH_A, 0); /* TXD3 */
--                      select_peripheral(PC(11), PERIPH_A, 0); /* RXD2 */
--                      select_peripheral(PC(12), PERIPH_A, 0); /* RXD3 */
--                      select_peripheral(PC(14), PERIPH_A, 0); /* RXCK */
--                      select_peripheral(PC(18), PERIPH_A, 0); /* SPD  */
--              }
--              break;
--
--      case 1:
--              pdev = &macb1_device;
--
--              select_peripheral(PD(13), PERIPH_B, 0);         /* TXD0 */
--              select_peripheral(PD(14), PERIPH_B, 0);         /* TXD1 */
--              select_peripheral(PD(11), PERIPH_B, 0);         /* TXEN */
--              select_peripheral(PD(12), PERIPH_B, 0);         /* TXCK */
--              select_peripheral(PD(10), PERIPH_B, 0);         /* RXD0 */
--              select_peripheral(PD(6),  PERIPH_B, 0);         /* RXD1 */
--              select_peripheral(PD(5),  PERIPH_B, 0);         /* RXER */
--              select_peripheral(PD(4),  PERIPH_B, 0);         /* RXDV */
--              select_peripheral(PD(3),  PERIPH_B, 0);         /* MDC  */
--              select_peripheral(PD(2),  PERIPH_B, 0);         /* MDIO */
--
--              if (!data->is_rmii) {
--                      select_peripheral(PC(19), PERIPH_B, 0); /* COL  */
--                      select_peripheral(PC(23), PERIPH_B, 0); /* CRS  */
--                      select_peripheral(PC(26), PERIPH_B, 0); /* TXER */
--                      select_peripheral(PC(27), PERIPH_B, 0); /* TXD2 */
--                      select_peripheral(PC(28), PERIPH_B, 0); /* TXD3 */
--                      select_peripheral(PC(29), PERIPH_B, 0); /* RXD2 */
--                      select_peripheral(PC(30), PERIPH_B, 0); /* RXD3 */
--                      select_peripheral(PC(24), PERIPH_B, 0); /* RXCK */
--                      select_peripheral(PD(15), PERIPH_B, 0); /* SPD  */
--              }
--              break;
--
--      default:
--              return NULL;
--      }
--
--      memcpy(pdev->dev.platform_data, data, sizeof(struct eth_platform_data));
--      platform_device_register(pdev);
--
--      return pdev;
--}
--
--/* --------------------------------------------------------------------
-- *  SPI
-- * -------------------------------------------------------------------- */
--static struct resource atmel_spi0_resource[] = {
--      PBMEM(0xffe00000),
--      IRQ(3),
--};
--DEFINE_DEV(atmel_spi, 0);
--DEV_CLK(spi_clk, atmel_spi0, pba, 0);
--
--static struct resource atmel_spi1_resource[] = {
--      PBMEM(0xffe00400),
--      IRQ(4),
--};
--DEFINE_DEV(atmel_spi, 1);
--DEV_CLK(spi_clk, atmel_spi1, pba, 1);
--
--static void __init
--at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b,
--                    unsigned int n, const u8 *pins)
--{
--      unsigned int pin, mode;
--
--      for (; n; n--, b++) {
--              b->bus_num = bus_num;
--              if (b->chip_select >= 4)
--                      continue;
--              pin = (unsigned)b->controller_data;
--              if (!pin) {
--                      pin = pins[b->chip_select];
--                      b->controller_data = (void *)pin;
--              }
--              mode = AT32_GPIOF_OUTPUT;
--              if (!(b->mode & SPI_CS_HIGH))
--                      mode |= AT32_GPIOF_HIGH;
--              at32_select_gpio(pin, mode);
--      }
--}
--
--struct platform_device *__init
--at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
--{
--      /*
--       * Manage the chipselects as GPIOs, normally using the same pins
--       * the SPI controller expects; but boards can use other pins.
--       */
--      static u8 __initdata spi0_pins[] =
--              { GPIO_PIN_PA(3), GPIO_PIN_PA(4),
--                GPIO_PIN_PA(5), GPIO_PIN_PA(20), };
--      static u8 __initdata spi1_pins[] =
--              { GPIO_PIN_PB(2), GPIO_PIN_PB(3),
--                GPIO_PIN_PB(4), GPIO_PIN_PA(27), };
--      struct platform_device *pdev;
--
--      switch (id) {
--      case 0:
--              pdev = &atmel_spi0_device;
--              select_peripheral(PA(0),  PERIPH_A, 0); /* MISO  */
--              select_peripheral(PA(1),  PERIPH_A, 0); /* MOSI  */
--              select_peripheral(PA(2),  PERIPH_A, 0); /* SCK   */
--              at32_spi_setup_slaves(0, b, n, spi0_pins);
--              break;
--
--      case 1:
--              pdev = &atmel_spi1_device;
--              select_peripheral(PB(0),  PERIPH_B, 0); /* MISO  */
--              select_peripheral(PB(1),  PERIPH_B, 0); /* MOSI  */
--              select_peripheral(PB(5),  PERIPH_B, 0); /* SCK   */
--              at32_spi_setup_slaves(1, b, n, spi1_pins);
--              break;
--
--      default:
--              return NULL;
--      }
--
--      spi_register_board_info(b, n);
--      platform_device_register(pdev);
--      return pdev;
--}
--
--/* --------------------------------------------------------------------
-- *  TWI
-- * -------------------------------------------------------------------- */
--static struct resource atmel_twi0_resource[] __initdata = {
--      PBMEM(0xffe00800),
--      IRQ(5),
--};
--static struct clk atmel_twi0_pclk = {
--      .name           = "twi_pclk",
--      .parent         = &pba_clk,
--      .mode           = pba_clk_mode,
--      .get_rate       = pba_clk_get_rate,
--      .index          = 2,
--};
--
++      platform_device_register(&at32_tcb0_device);
++      platform_device_register(&at32_tcb1_device);
+       platform_device_register(&pio0_device);
+       platform_device_register(&pio1_device);
+@@ -679,6 +843,81 @@
+ }
+ /* --------------------------------------------------------------------
++ *  PSIF
++ * -------------------------------------------------------------------- */
++static struct resource atmel_psif0_resource[] __initdata = {
++      {
++              .start  = 0xffe03c00,
++              .end    = 0xffe03cff,
++              .flags  = IORESOURCE_MEM,
++      },
++      IRQ(18),
++};
++static struct clk atmel_psif0_pclk = {
++      .name           = "pclk",
++      .parent         = &pba_clk,
++      .mode           = pba_clk_mode,
++      .get_rate       = pba_clk_get_rate,
++      .index          = 15,
++};
++
++static struct resource atmel_psif1_resource[] __initdata = {
++      {
++              .start  = 0xffe03d00,
++              .end    = 0xffe03dff,
++              .flags  = IORESOURCE_MEM,
++      },
++      IRQ(18),
++};
++static struct clk atmel_psif1_pclk = {
++      .name           = "pclk",
++      .parent         = &pba_clk,
++      .mode           = pba_clk_mode,
++      .get_rate       = pba_clk_get_rate,
++      .index          = 15,
++};
++
++struct platform_device *__init at32_add_device_psif(unsigned int id)
++{
++      struct platform_device *pdev;
++
++      if (!(id == 0 || id == 1))
++              return NULL;
++
++      pdev = platform_device_alloc("atmel_psif", id);
++      if (!pdev)
++              return NULL;
++
++      switch (id) {
++      case 0:
++              if (platform_device_add_resources(pdev, atmel_psif0_resource,
++                                      ARRAY_SIZE(atmel_psif0_resource)))
++                      goto err_add_resources;
++              atmel_psif0_pclk.dev = &pdev->dev;
++              select_peripheral(PA(8), PERIPH_A, 0); /* CLOCK */
++              select_peripheral(PA(9), PERIPH_A, 0); /* DATA  */
++              break;
++      case 1:
++              if (platform_device_add_resources(pdev, atmel_psif1_resource,
++                                      ARRAY_SIZE(atmel_psif1_resource)))
++                      goto err_add_resources;
++              atmel_psif1_pclk.dev = &pdev->dev;
++              select_peripheral(PB(11), PERIPH_A, 0); /* CLOCK */
++              select_peripheral(PB(12), PERIPH_A, 0); /* DATA  */
++              break;
++      default:
++              return NULL;
++      }
++
++      platform_device_add(pdev);
++      return pdev;
++
++err_add_resources:
++      platform_device_put(pdev);
++      return NULL;
++}
++
++/* --------------------------------------------------------------------
+  *  USART
+  * -------------------------------------------------------------------- */
+@@ -989,7 +1228,9 @@
+       .index          = 2,
+ };
 -struct platform_device *__init at32_add_device_twi(unsigned int id)
--{
--      struct platform_device *pdev;
--
--      if (id != 0)
--              return NULL;
--
--      pdev = platform_device_alloc("atmel_twi", id);
--      if (!pdev)
--              return NULL;
--
--      if (platform_device_add_resources(pdev, atmel_twi0_resource,
--                              ARRAY_SIZE(atmel_twi0_resource)))
--              goto err_add_resources;
--
--      select_peripheral(PA(6),  PERIPH_A, 0); /* SDA  */
--      select_peripheral(PA(7),  PERIPH_A, 0); /* SDL  */
--
--      atmel_twi0_pclk.dev = &pdev->dev;
--
--      platform_device_add(pdev);
--      return pdev;
--
--err_add_resources:
--      platform_device_put(pdev);
--      return NULL;
--}
--
--/* --------------------------------------------------------------------
-- * MMC
-- * -------------------------------------------------------------------- */
--static struct resource atmel_mci0_resource[] __initdata = {
--      PBMEM(0xfff02400),
--      IRQ(28),
--};
--static struct clk atmel_mci0_pclk = {
--      .name           = "mci_clk",
--      .parent         = &pbb_clk,
--      .mode           = pbb_clk_mode,
--      .get_rate       = pbb_clk_get_rate,
--      .index          = 9,
--};
--
++struct platform_device *__init at32_add_device_twi(unsigned int id,
++                                                  struct i2c_board_info *b,
++                                                  unsigned int n)
+ {
+       struct platform_device *pdev;
+@@ -1009,6 +1250,9 @@
+       atmel_twi0_pclk.dev = &pdev->dev;
++      if (b)
++              i2c_register_board_info(id, b, n);
++
+       platform_device_add(pdev);
+       return pdev;
+@@ -1032,7 +1276,8 @@
+       .index          = 9,
+ };
 -struct platform_device *__init at32_add_device_mci(unsigned int id)
--{
--      struct platform_device *pdev;
--
--      if (id != 0)
--              return NULL;
--
--      pdev = platform_device_alloc("atmel_mci", id);
--      if (!pdev)
++struct platform_device *__init
++at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
+ {
+       struct platform_device *pdev;
+@@ -1041,11 +1286,15 @@
+       pdev = platform_device_alloc("atmel_mci", id);
+       if (!pdev)
 -              return NULL;
--
--      if (platform_device_add_resources(pdev, atmel_mci0_resource,
--                              ARRAY_SIZE(atmel_mci0_resource)))
++              goto fail;
+       if (platform_device_add_resources(pdev, atmel_mci0_resource,
+                               ARRAY_SIZE(atmel_mci0_resource)))
 -              goto err_add_resources;
--
--      select_peripheral(PA(10), PERIPH_A, 0); /* CLK   */
--      select_peripheral(PA(11), PERIPH_A, 0); /* CMD   */
--      select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */
--      select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */
--      select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */
--      select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */
--
--      atmel_mci0_pclk.dev = &pdev->dev;
--
--      platform_device_add(pdev);
--      return pdev;
--
++              goto fail;
++
++      if (data && platform_device_add_data(pdev, data,
++                              sizeof(struct mci_platform_data)))
++              goto fail;
+       select_peripheral(PA(10), PERIPH_A, 0); /* CLK   */
+       select_peripheral(PA(11), PERIPH_A, 0); /* CMD   */
+@@ -1054,12 +1303,19 @@
+       select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */
+       select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */
++      if (data) {
++              if (data->detect_pin != GPIO_PIN_NONE)
++                      at32_select_gpio(data->detect_pin, 0);
++              if (data->wp_pin != GPIO_PIN_NONE)
++                      at32_select_gpio(data->wp_pin, 0);
++      }
++
+       atmel_mci0_pclk.dev = &pdev->dev;
+       platform_device_add(pdev);
+       return pdev;
 -err_add_resources:
--      platform_device_put(pdev);
--      return NULL;
--}
--
--/* --------------------------------------------------------------------
-- *  LCDC
-- * -------------------------------------------------------------------- */
--static struct atmel_lcdfb_info atmel_lcdfb0_data;
--static struct resource atmel_lcdfb0_resource[] = {
--      {
--              .start          = 0xff000000,
--              .end            = 0xff000fff,
--              .flags          = IORESOURCE_MEM,
--      },
--      IRQ(1),
--      {
--              /* Placeholder for pre-allocated fb memory */
--              .start          = 0x00000000,
--              .end            = 0x00000000,
--              .flags          = 0,
--      },
--};
--DEFINE_DEV_DATA(atmel_lcdfb, 0);
--DEV_CLK(hck1, atmel_lcdfb0, hsb, 7);
--static struct clk atmel_lcdfb0_pixclk = {
--      .name           = "lcdc_clk",
--      .dev            = &atmel_lcdfb0_device.dev,
--      .mode           = genclk_mode,
--      .get_rate       = genclk_get_rate,
--      .set_rate       = genclk_set_rate,
--      .set_parent     = genclk_set_parent,
--      .index          = 7,
--};
--
--struct platform_device *__init
--at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
++fail:
+       platform_device_put(pdev);
+       return NULL;
+ }
+@@ -1097,7 +1353,8 @@
+ struct platform_device *__init
+ at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
 -                   unsigned long fbmem_start, unsigned long fbmem_len)
--{
--      struct platform_device *pdev;
--      struct atmel_lcdfb_info *info;
--      struct fb_monspecs *monspecs;
--      struct fb_videomode *modedb;
--      unsigned int modedb_size;
--
--      /*
--       * Do a deep copy of the fb data, monspecs and modedb. Make
--       * sure all allocations are done before setting up the
--       * portmux.
--       */
--      monspecs = kmemdup(data->default_monspecs,
--                         sizeof(struct fb_monspecs), GFP_KERNEL);
--      if (!monspecs)
--              return NULL;
--
--      modedb_size = sizeof(struct fb_videomode) * monspecs->modedb_len;
--      modedb = kmemdup(monspecs->modedb, modedb_size, GFP_KERNEL);
--      if (!modedb)
--              goto err_dup_modedb;
--      monspecs->modedb = modedb;
--
--      switch (id) {
--      case 0:
--              pdev = &atmel_lcdfb0_device;
++                   unsigned long fbmem_start, unsigned long fbmem_len,
++                   unsigned int pin_config)
+ {
+       struct platform_device *pdev;
+       struct atmel_lcdfb_info *info;
+@@ -1124,37 +1381,77 @@
+       switch (id) {
+       case 0:
+               pdev = &atmel_lcdfb0_device;
 -              select_peripheral(PC(19), PERIPH_A, 0); /* CC     */
 -              select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
 -              select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
 -              select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
 -              select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
 -              select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
--
--              clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
--              clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
--              break;
--
--      default:
--              goto err_invalid_id;
--      }
--
--      if (fbmem_len) {
--              pdev->resource[2].start = fbmem_start;
--              pdev->resource[2].end = fbmem_start + fbmem_len - 1;
--              pdev->resource[2].flags = IORESOURCE_MEM;
--      }
--
--      info = pdev->dev.platform_data;
--      memcpy(info, data, sizeof(struct atmel_lcdfb_info));
--      info->default_monspecs = monspecs;
--
--      platform_device_register(pdev);
--      return pdev;
--
--err_invalid_id:
--      kfree(modedb);
--err_dup_modedb:
--      kfree(monspecs);
--      return NULL;
--}
--
--/* --------------------------------------------------------------------
-- *  SSC
-- * -------------------------------------------------------------------- */
--static struct resource ssc0_resource[] = {
--      PBMEM(0xffe01c00),
--      IRQ(10),
--};
--DEFINE_DEV(ssc, 0);
--DEV_CLK(pclk, ssc0, pba, 7);
--
--static struct resource ssc1_resource[] = {
--      PBMEM(0xffe02000),
--      IRQ(11),
--};
--DEFINE_DEV(ssc, 1);
--DEV_CLK(pclk, ssc1, pba, 8);
--
--static struct resource ssc2_resource[] = {
--      PBMEM(0xffe02400),
--      IRQ(12),
--};
--DEFINE_DEV(ssc, 2);
--DEV_CLK(pclk, ssc2, pba, 9);
--
--struct platform_device *__init
--at32_add_device_ssc(unsigned int id, unsigned int flags)
--{
--      struct platform_device *pdev;
--
--      switch (id) {
--      case 0:
--              pdev = &ssc0_device;
--              if (flags & ATMEL_SSC_RF)
--                      select_peripheral(PA(21), PERIPH_A, 0); /* RF */
--              if (flags & ATMEL_SSC_RK)
--                      select_peripheral(PA(22), PERIPH_A, 0); /* RK */
--              if (flags & ATMEL_SSC_TK)
--                      select_peripheral(PA(23), PERIPH_A, 0); /* TK */
--              if (flags & ATMEL_SSC_TF)
--                      select_peripheral(PA(24), PERIPH_A, 0); /* TF */
--              if (flags & ATMEL_SSC_TD)
--                      select_peripheral(PA(25), PERIPH_A, 0); /* TD */
--              if (flags & ATMEL_SSC_RD)
--                      select_peripheral(PA(26), PERIPH_A, 0); /* RD */
--              break;
--      case 1:
--              pdev = &ssc1_device;
--              if (flags & ATMEL_SSC_RF)
--                      select_peripheral(PA(0), PERIPH_B, 0);  /* RF */
--              if (flags & ATMEL_SSC_RK)
--                      select_peripheral(PA(1), PERIPH_B, 0);  /* RK */
--              if (flags & ATMEL_SSC_TK)
--                      select_peripheral(PA(2), PERIPH_B, 0);  /* TK */
--              if (flags & ATMEL_SSC_TF)
--                      select_peripheral(PA(3), PERIPH_B, 0);  /* TF */
--              if (flags & ATMEL_SSC_TD)
--                      select_peripheral(PA(4), PERIPH_B, 0);  /* TD */
--              if (flags & ATMEL_SSC_RD)
--                      select_peripheral(PA(5), PERIPH_B, 0);  /* RD */
--              break;
--      case 2:
--              pdev = &ssc2_device;
--              if (flags & ATMEL_SSC_TD)
--                      select_peripheral(PB(13), PERIPH_A, 0); /* TD */
--              if (flags & ATMEL_SSC_RD)
--                      select_peripheral(PB(14), PERIPH_A, 0); /* RD */
--              if (flags & ATMEL_SSC_TK)
--                      select_peripheral(PB(15), PERIPH_A, 0); /* TK */
--              if (flags & ATMEL_SSC_TF)
--                      select_peripheral(PB(16), PERIPH_A, 0); /* TF */
--              if (flags & ATMEL_SSC_RF)
--                      select_peripheral(PB(17), PERIPH_A, 0); /* RF */
--              if (flags & ATMEL_SSC_RK)
--                      select_peripheral(PB(18), PERIPH_A, 0); /* RK */
--              break;
--      default:
--              return NULL;
--      }
--
--      platform_device_register(pdev);
--      return pdev;
--}
--
--/* --------------------------------------------------------------------
-- *  USB Device Controller
-- * -------------------------------------------------------------------- */
--static struct resource usba0_resource[] __initdata = {
--      {
--              .start          = 0xff300000,
--              .end            = 0xff3fffff,
--              .flags          = IORESOURCE_MEM,
--      }, {
--              .start          = 0xfff03000,
--              .end            = 0xfff033ff,
--              .flags          = IORESOURCE_MEM,
--      },
--      IRQ(31),
--};
--static struct clk usba0_pclk = {
--      .name           = "pclk",
--      .parent         = &pbb_clk,
--      .mode           = pbb_clk_mode,
--      .get_rate       = pbb_clk_get_rate,
--      .index          = 12,
--};
--static struct clk usba0_hclk = {
--      .name           = "hclk",
--      .parent         = &hsb_clk,
--      .mode           = hsb_clk_mode,
--      .get_rate       = hsb_clk_get_rate,
--      .index          = 6,
--};
--
--struct platform_device *__init
--at32_add_device_usba(unsigned int id, struct usba_platform_data *data)
--{
--      struct platform_device *pdev;
--
--      if (id != 0)
--              return NULL;
--
--      pdev = platform_device_alloc("atmel_usba_udc", 0);
--      if (!pdev)
--              return NULL;
--
--      if (platform_device_add_resources(pdev, usba0_resource,
--                                        ARRAY_SIZE(usba0_resource)))
--              goto out_free_pdev;
--
++
++              switch (pin_config) {
++              case 0:
++                      select_peripheral(PC(19), PERIPH_A, 0); /* CC     */
++                      select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
++                      select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
++                      select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC  */
++                      select_peripheral(PC(23), PERIPH_A, 0); /* DVAL   */
++                      select_peripheral(PC(24), PERIPH_A, 0); /* MODE   */
++                      select_peripheral(PC(25), PERIPH_A, 0); /* PWR    */
++                      select_peripheral(PC(26), PERIPH_A, 0); /* DATA0  */
++                      select_peripheral(PC(27), PERIPH_A, 0); /* DATA1  */
++                      select_peripheral(PC(28), PERIPH_A, 0); /* DATA2  */
++                      select_peripheral(PC(29), PERIPH_A, 0); /* DATA3  */
++                      select_peripheral(PC(30), PERIPH_A, 0); /* DATA4  */
++                      select_peripheral(PC(31), PERIPH_A, 0); /* DATA5  */
++                      select_peripheral(PD(0),  PERIPH_A, 0); /* DATA6  */
++                      select_peripheral(PD(1),  PERIPH_A, 0); /* DATA7  */
++                      select_peripheral(PD(2),  PERIPH_A, 0); /* DATA8  */
++                      select_peripheral(PD(3),  PERIPH_A, 0); /* DATA9  */
++                      select_peripheral(PD(4),  PERIPH_A, 0); /* DATA10 */
++                      select_peripheral(PD(5),  PERIPH_A, 0); /* DATA11 */
++                      select_peripheral(PD(6),  PERIPH_A, 0); /* DATA12 */
++                      select_peripheral(PD(7),  PERIPH_A, 0); /* DATA13 */
++                      select_peripheral(PD(8),  PERIPH_A, 0); /* DATA14 */
++                      select_peripheral(PD(9),  PERIPH_A, 0); /* DATA15 */
++                      select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
++                      select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
++                      select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
++                      select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
++                      select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
++                      select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
++                      select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
++                      select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
++                      break;
++              case 1:
++                      select_peripheral(PE(0),  PERIPH_B, 0); /* CC     */
++                      select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
++                      select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
++                      select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC  */
++                      select_peripheral(PE(1),  PERIPH_B, 0); /* DVAL   */
++                      select_peripheral(PE(2),  PERIPH_B, 0); /* MODE   */
++                      select_peripheral(PC(25), PERIPH_A, 0); /* PWR    */
++                      select_peripheral(PE(3),  PERIPH_B, 0); /* DATA0  */
++                      select_peripheral(PE(4),  PERIPH_B, 0); /* DATA1  */
++                      select_peripheral(PE(5),  PERIPH_B, 0); /* DATA2  */
++                      select_peripheral(PE(6),  PERIPH_B, 0); /* DATA3  */
++                      select_peripheral(PE(7),  PERIPH_B, 0); /* DATA4  */
++                      select_peripheral(PC(31), PERIPH_A, 0); /* DATA5  */
++                      select_peripheral(PD(0),  PERIPH_A, 0); /* DATA6  */
++                      select_peripheral(PD(1),  PERIPH_A, 0); /* DATA7  */
++                      select_peripheral(PE(8),  PERIPH_B, 0); /* DATA8  */
++                      select_peripheral(PE(9),  PERIPH_B, 0); /* DATA9  */
++                      select_peripheral(PE(10), PERIPH_B, 0); /* DATA10 */
++                      select_peripheral(PE(11), PERIPH_B, 0); /* DATA11 */
++                      select_peripheral(PE(12), PERIPH_B, 0); /* DATA12 */
++                      select_peripheral(PD(7),  PERIPH_A, 0); /* DATA13 */
++                      select_peripheral(PD(8),  PERIPH_A, 0); /* DATA14 */
++                      select_peripheral(PD(9),  PERIPH_A, 0); /* DATA15 */
++                      select_peripheral(PE(13), PERIPH_B, 0); /* DATA16 */
++                      select_peripheral(PE(14), PERIPH_B, 0); /* DATA17 */
++                      select_peripheral(PE(15), PERIPH_B, 0); /* DATA18 */
++                      select_peripheral(PE(16), PERIPH_B, 0); /* DATA19 */
++                      select_peripheral(PE(17), PERIPH_B, 0); /* DATA20 */
++                      select_peripheral(PE(18), PERIPH_B, 0); /* DATA21 */
++                      select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
++                      select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
++                      break;
++              default:
++                      goto err_invalid_id;
++              }
+               clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
+               clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
+@@ -1351,9 +1648,39 @@
+       .index          = 6,
+ };
++#define EP(nam, idx, maxpkt, maxbk, dma, isoc)                        \
++      [idx] = {                                               \
++              .name           = nam,                          \
++              .index          = idx,                          \
++              .fifo_size      = maxpkt,                       \
++              .nr_banks       = maxbk,                        \
++              .can_dma        = dma,                          \
++              .can_isoc       = isoc,                         \
++      }
++
++static struct usba_ep_data at32_usba_ep[] __initdata = {
++      EP("ep0",     0,   64, 1, 0, 0),
++      EP("ep1",     1,  512, 2, 1, 1),
++      EP("ep2",     2,  512, 2, 1, 1),
++      EP("ep3-int", 3,   64, 3, 1, 0),
++      EP("ep4-int", 4,   64, 3, 1, 0),
++      EP("ep5",     5, 1024, 3, 1, 1),
++      EP("ep6",     6, 1024, 3, 1, 1),
++};
++
++#undef EP
++
+ struct platform_device *__init
+ at32_add_device_usba(unsigned int id, struct usba_platform_data *data)
+ {
++      /*
++       * pdata doesn't have room for any endpoints, so we need to
++       * append room for the ones we need right after it.
++       */
++      struct {
++              struct usba_platform_data pdata;
++              struct usba_ep_data ep[7];
++      } usba_data;
+       struct platform_device *pdev;
+       if (id != 0)
+@@ -1367,13 +1694,20 @@
+                                         ARRAY_SIZE(usba0_resource)))
+               goto out_free_pdev;
 -      if (data) {
 -              if (platform_device_add_data(pdev, data, sizeof(*data)))
 -                      goto out_free_pdev;
--
++      if (data)
++              usba_data.pdata.vbus_pin = data->vbus_pin;
++      else
++              usba_data.pdata.vbus_pin = -EINVAL;
 -              if (data->vbus_pin != GPIO_PIN_NONE)
 -                      at32_select_gpio(data->vbus_pin, 0);
 -      }
--
--      usba0_pclk.dev = &pdev->dev;
--      usba0_hclk.dev = &pdev->dev;
--
--      platform_device_add(pdev);
--
--      return pdev;
--
--out_free_pdev:
--      platform_device_put(pdev);
--      return NULL;
--}
--
--/* --------------------------------------------------------------------
-- * IDE / CompactFlash
-- * -------------------------------------------------------------------- */
--static struct resource at32_smc_cs4_resource[] __initdata = {
--      {
--              .start  = 0x04000000,
--              .end    = 0x07ffffff,
--              .flags  = IORESOURCE_MEM,
--      },
--      IRQ(~0UL), /* Magic IRQ will be overridden */
--};
--static struct resource at32_smc_cs5_resource[] __initdata = {
--      {
--              .start  = 0x20000000,
--              .end    = 0x23ffffff,
--              .flags  = IORESOURCE_MEM,
--      },
--      IRQ(~0UL), /* Magic IRQ will be overridden */
--};
--
--static int __init at32_init_ide_or_cf(struct platform_device *pdev,
--              unsigned int cs, unsigned int extint)
--{
--      static unsigned int extint_pin_map[4] __initdata = {
--              GPIO_PIN_PB(25),
--              GPIO_PIN_PB(26),
--              GPIO_PIN_PB(27),
--              GPIO_PIN_PB(28),
--      };
--      static bool common_pins_initialized __initdata = false;
--      unsigned int extint_pin;
--      int ret;
--
--      if (extint >= ARRAY_SIZE(extint_pin_map))
--              return -EINVAL;
--      extint_pin = extint_pin_map[extint];
--
--      switch (cs) {
--      case 4:
--              ret = platform_device_add_resources(pdev,
--                              at32_smc_cs4_resource,
--                              ARRAY_SIZE(at32_smc_cs4_resource));
--              if (ret)
--                      return ret;
--
--              select_peripheral(PE(21), PERIPH_A, 0); /* NCS4   -> OE_N  */
--              set_ebi_sfr_bits(HMATRIX_BIT(CS4A));
--              break;
--      case 5:
--              ret = platform_device_add_resources(pdev,
--                              at32_smc_cs5_resource,
--                              ARRAY_SIZE(at32_smc_cs5_resource));
--              if (ret)
--                      return ret;
--
--              select_peripheral(PE(22), PERIPH_A, 0); /* NCS5   -> OE_N  */
--              set_ebi_sfr_bits(HMATRIX_BIT(CS5A));
--              break;
--      default:
--              return -EINVAL;
--      }
--
--      if (!common_pins_initialized) {
--              select_peripheral(PE(19), PERIPH_A, 0); /* CFCE1  -> CS0_N */
--              select_peripheral(PE(20), PERIPH_A, 0); /* CFCE2  -> CS1_N */
--              select_peripheral(PE(23), PERIPH_A, 0); /* CFRNW  -> DIR   */
--              select_peripheral(PE(24), PERIPH_A, 0); /* NWAIT  <- IORDY */
--              common_pins_initialized = true;
--      }
--
--      at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
--
--      pdev->resource[1].start = EIM_IRQ_BASE + extint;
--      pdev->resource[1].end = pdev->resource[1].start;
--
--      return 0;
--}
--
--struct platform_device *__init
--at32_add_device_ide(unsigned int id, unsigned int extint,
--                  struct ide_platform_data *data)
++      data = &usba_data.pdata;
++      data->num_ep = ARRAY_SIZE(at32_usba_ep);
++      memcpy(data->ep, at32_usba_ep, sizeof(at32_usba_ep));
++
++      if (platform_device_add_data(pdev, data, sizeof(usba_data)))
++              goto out_free_pdev;
++
++      if (data->vbus_pin >= 0)
++              at32_select_gpio(data->vbus_pin, 0);
+       usba0_pclk.dev = &pdev->dev;
+       usba0_hclk.dev = &pdev->dev;
+@@ -1526,6 +1860,58 @@
+ #endif
+ /* --------------------------------------------------------------------
++ * NAND Flash / SmartMedia
++ * -------------------------------------------------------------------- */
++static struct resource smc_cs3_resource[] __initdata = {
++      {
++              .start  = 0x0c000000,
++              .end    = 0x0fffffff,
++              .flags  = IORESOURCE_MEM,
++      }, {
++              .start  = 0xfff03c00,
++              .end    = 0xfff03fff,
++              .flags  = IORESOURCE_MEM,
++      },
++};
++
++struct platform_device *__init
++at32_add_device_nand(unsigned int id, struct atmel_nand_data *data)
++{
++      struct platform_device *pdev;
++
++      if (id != 0 || !data)
++              return NULL;
++
++      pdev = platform_device_alloc("atmel_nand", id);
++      if (!pdev)
++              goto fail;
++
++      if (platform_device_add_resources(pdev, smc_cs3_resource,
++                              ARRAY_SIZE(smc_cs3_resource)))
++              goto fail;
++
++      if (platform_device_add_data(pdev, data,
++                              sizeof(struct atmel_nand_data)))
++              goto fail;
++
++      set_ebi_sfr_bits(HMATRIX_BIT(CS3A));
++      if (data->enable_pin)
++              at32_select_gpio(data->enable_pin,
++                              AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
++      if (data->rdy_pin)
++              at32_select_gpio(data->rdy_pin, 0);
++      if (data->det_pin)
++              at32_select_gpio(data->det_pin, 0);
++
++      platform_device_add(pdev);
++      return pdev;
++
++fail:
++      platform_device_put(pdev);
++      return NULL;
++}
++
++/* --------------------------------------------------------------------
+  * AC97C
+  * -------------------------------------------------------------------- */
+ static struct resource atmel_ac97c0_resource[] __initdata = {
+@@ -1683,6 +2069,7 @@
+       &hmatrix_clk,
+       &ebi_clk,
+       &hramc_clk,
++      &sdramc_clk,
+       &smc0_pclk,
+       &smc0_mck,
+       &pdc_hclk,
+@@ -1694,7 +2081,10 @@
+       &pio2_mck,
+       &pio3_mck,
+       &pio4_mck,
+-      &at32_systc0_pclk,
++      &at32_tcb0_t0_clk,
++      &at32_tcb1_t0_clk,
++      &atmel_psif0_pclk,
++      &atmel_psif1_pclk,
+       &atmel_usart0_usart,
+       &atmel_usart1_usart,
+       &atmel_usart2_usart,
+@@ -1730,16 +2120,7 @@
+ };
+ unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
+-void __init at32_portmux_init(void)
 -{
--      struct platform_device *pdev;
--
--      pdev = platform_device_alloc("at32_ide", id);
--      if (!pdev)
--              goto fail;
--
--      if (platform_device_add_data(pdev, data,
--                              sizeof(struct ide_platform_data)))
--              goto fail;
--
--      if (at32_init_ide_or_cf(pdev, data->cs, extint))
--              goto fail;
--
--      platform_device_add(pdev);
--      return pdev;
--
--fail:
--      platform_device_put(pdev);
--      return NULL;
+-      at32_init_pio(&pio0_device);
+-      at32_init_pio(&pio1_device);
+-      at32_init_pio(&pio2_device);
+-      at32_init_pio(&pio3_device);
+-      at32_init_pio(&pio4_device);
 -}
 -
--struct platform_device *__init
--at32_add_device_cf(unsigned int id, unsigned int extint,
--                  struct cf_platform_data *data)
--{
--      struct platform_device *pdev;
--
--      pdev = platform_device_alloc("at32_cf", id);
--      if (!pdev)
--              goto fail;
--
--      if (platform_device_add_data(pdev, data,
--                              sizeof(struct cf_platform_data)))
--              goto fail;
--
--      if (at32_init_ide_or_cf(pdev, data->cs, extint))
--              goto fail;
--
--      if (data->detect_pin != GPIO_PIN_NONE)
--              at32_select_gpio(data->detect_pin, AT32_GPIOF_DEGLITCH);
--      if (data->reset_pin != GPIO_PIN_NONE)
--              at32_select_gpio(data->reset_pin, 0);
--      if (data->vcc_pin != GPIO_PIN_NONE)
--              at32_select_gpio(data->vcc_pin, 0);
--      /* READY is used as extint, so we can't select it as gpio */
--
--      platform_device_add(pdev);
--      return pdev;
+-void __init at32_clock_init(void)
++void __init setup_platform(void)
+ {
+       u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
+       int i;
+@@ -1794,4 +2175,36 @@
+       pm_writel(HSB_MASK, hsb_mask);
+       pm_writel(PBA_MASK, pba_mask);
+       pm_writel(PBB_MASK, pbb_mask);
++
++      /* Initialize the port muxes */
++      at32_init_pio(&pio0_device);
++      at32_init_pio(&pio1_device);
++      at32_init_pio(&pio2_device);
++      at32_init_pio(&pio3_device);
++      at32_init_pio(&pio4_device);
++}
++
++struct gen_pool *sram_pool;
++
++static int __init sram_init(void)
++{
++      struct gen_pool *pool;
++
++      /* 1KiB granularity */
++      pool = gen_pool_create(10, -1);
++      if (!pool)
++              goto fail;
++
++      if (gen_pool_add(pool, 0x24000000, 0x8000, -1))
++              goto err_pool_add;
++
++      sram_pool = pool;
++      return 0;
++
++err_pool_add:
++      gen_pool_destroy(pool);
++fail:
++      pr_err("Failed to create SRAM pool\n");
++      return -ENOMEM;
+ }
++core_initcall(sram_init);
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/at32ap.c avr32-2.6/arch/avr32/mach-at32ap/at32ap.c
+--- linux-2.6.25.6/arch/avr32/mach-at32ap/at32ap.c     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/mach-at32ap/at32ap.c  1970-01-01 01:00:00.000000000 +0100
+@@ -1,56 +0,0 @@
+-/*
+- * Copyright (C) 2006 Atmel Corporation
+- *
+- * 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.
+- */
 -
--fail:
--      platform_device_put(pdev);
--      return NULL;
--}
+-#include <linux/clk.h>
+-#include <linux/err.h>
+-#include <linux/init.h>
+-#include <linux/platform_device.h>
 -
--/* --------------------------------------------------------------------
-- * AC97C
-- * -------------------------------------------------------------------- */
--static struct resource atmel_ac97c0_resource[] __initdata = {
--      PBMEM(0xfff02800),
--      IRQ(29),
--};
--static struct clk atmel_ac97c0_pclk = {
--      .name           = "pclk",
--      .parent         = &pbb_clk,
--      .mode           = pbb_clk_mode,
--      .get_rate       = pbb_clk_get_rate,
--      .index          = 10,
--};
+-#include <asm/arch/init.h>
 -
--struct platform_device *__init at32_add_device_ac97c(unsigned int id)
+-void __init setup_platform(void)
 -{
--      struct platform_device *pdev;
--
--      if (id != 0)
--              return NULL;
--
--      pdev = platform_device_alloc("atmel_ac97c", id);
--      if (!pdev)
--              return NULL;
--
--      if (platform_device_add_resources(pdev, atmel_ac97c0_resource,
--                              ARRAY_SIZE(atmel_ac97c0_resource)))
--              goto err_add_resources;
--
--      select_peripheral(PB(20), PERIPH_B, 0); /* SYNC */
--      select_peripheral(PB(21), PERIPH_B, 0); /* SDO  */
--      select_peripheral(PB(22), PERIPH_B, 0); /* SDI  */
--      select_peripheral(PB(23), PERIPH_B, 0); /* SCLK */
--
--      atmel_ac97c0_pclk.dev = &pdev->dev;
--
--      platform_device_add(pdev);
--      return pdev;
--
--err_add_resources:
--      platform_device_put(pdev);
--      return NULL;
+-      at32_clock_init();
+-      at32_portmux_init();
 -}
 -
--/* --------------------------------------------------------------------
-- * ABDAC
-- * -------------------------------------------------------------------- */
--static struct resource abdac0_resource[] __initdata = {
--      PBMEM(0xfff02000),
--      IRQ(27),
--};
--static struct clk abdac0_pclk = {
--      .name           = "pclk",
--      .parent         = &pbb_clk,
--      .mode           = pbb_clk_mode,
--      .get_rate       = pbb_clk_get_rate,
--      .index          = 8,
--};
--static struct clk abdac0_sample_clk = {
--      .name           = "sample_clk",
--      .mode           = genclk_mode,
--      .get_rate       = genclk_get_rate,
--      .set_rate       = genclk_set_rate,
--      .set_parent     = genclk_set_parent,
--      .index          = 6,
--};
--
--struct platform_device *__init at32_add_device_abdac(unsigned int id)
+-static int __init pdc_probe(struct platform_device *pdev)
 -{
--      struct platform_device *pdev;
--
--      if (id != 0)
--              return NULL;
--
--      pdev = platform_device_alloc("abdac", id);
--      if (!pdev)
--              return NULL;
--
--      if (platform_device_add_resources(pdev, abdac0_resource,
--                              ARRAY_SIZE(abdac0_resource)))
--              goto err_add_resources;
--
--      select_peripheral(PB(20), PERIPH_A, 0); /* DATA1        */
--      select_peripheral(PB(21), PERIPH_A, 0); /* DATA0        */
--      select_peripheral(PB(22), PERIPH_A, 0); /* DATAN1       */
--      select_peripheral(PB(23), PERIPH_A, 0); /* DATAN0       */
+-      struct clk *pclk, *hclk;
 -
--      abdac0_pclk.dev = &pdev->dev;
--      abdac0_sample_clk.dev = &pdev->dev;
+-      pclk = clk_get(&pdev->dev, "pclk");
+-      if (IS_ERR(pclk)) {
+-              dev_err(&pdev->dev, "no pclk defined\n");
+-              return PTR_ERR(pclk);
+-      }
+-      hclk = clk_get(&pdev->dev, "hclk");
+-      if (IS_ERR(hclk)) {
+-              dev_err(&pdev->dev, "no hclk defined\n");
+-              clk_put(pclk);
+-              return PTR_ERR(hclk);
+-      }
 -
--      platform_device_add(pdev);
--      return pdev;
+-      clk_enable(pclk);
+-      clk_enable(hclk);
 -
--err_add_resources:
--      platform_device_put(pdev);
--      return NULL;
+-      dev_info(&pdev->dev, "Atmel Peripheral DMA Controller enabled\n");
+-      return 0;
 -}
 -
--/* --------------------------------------------------------------------
-- *  GCLK
-- * -------------------------------------------------------------------- */
--static struct clk gclk0 = {
--      .name           = "gclk0",
--      .mode           = genclk_mode,
--      .get_rate       = genclk_get_rate,
--      .set_rate       = genclk_set_rate,
--      .set_parent     = genclk_set_parent,
--      .index          = 0,
--};
--static struct clk gclk1 = {
--      .name           = "gclk1",
--      .mode           = genclk_mode,
--      .get_rate       = genclk_get_rate,
--      .set_rate       = genclk_set_rate,
--      .set_parent     = genclk_set_parent,
--      .index          = 1,
--};
--static struct clk gclk2 = {
--      .name           = "gclk2",
--      .mode           = genclk_mode,
--      .get_rate       = genclk_get_rate,
--      .set_rate       = genclk_set_rate,
--      .set_parent     = genclk_set_parent,
--      .index          = 2,
--};
--static struct clk gclk3 = {
--      .name           = "gclk3",
--      .mode           = genclk_mode,
--      .get_rate       = genclk_get_rate,
--      .set_rate       = genclk_set_rate,
--      .set_parent     = genclk_set_parent,
--      .index          = 3,
--};
--static struct clk gclk4 = {
--      .name           = "gclk4",
--      .mode           = genclk_mode,
--      .get_rate       = genclk_get_rate,
--      .set_rate       = genclk_set_rate,
--      .set_parent     = genclk_set_parent,
--      .index          = 4,
--};
--
--struct clk *at32_clock_list[] = {
--      &osc32k,
--      &osc0,
--      &osc1,
--      &pll0,
--      &pll1,
--      &cpu_clk,
--      &hsb_clk,
--      &pba_clk,
--      &pbb_clk,
--      &at32_pm_pclk,
--      &at32_intc0_pclk,
--      &hmatrix_clk,
--      &ebi_clk,
--      &hramc_clk,
--      &smc0_pclk,
--      &smc0_mck,
--      &pdc_hclk,
--      &pdc_pclk,
--      &dmaca0_hclk,
--      &pico_clk,
--      &pio0_mck,
--      &pio1_mck,
--      &pio2_mck,
--      &pio3_mck,
--      &pio4_mck,
--      &at32_systc0_pclk,
--      &atmel_usart0_usart,
--      &atmel_usart1_usart,
--      &atmel_usart2_usart,
--      &atmel_usart3_usart,
--      &macb0_hclk,
--      &macb0_pclk,
--      &macb1_hclk,
--      &macb1_pclk,
--      &atmel_spi0_spi_clk,
--      &atmel_spi1_spi_clk,
--      &atmel_twi0_pclk,
--      &atmel_mci0_pclk,
--      &atmel_lcdfb0_hck1,
--      &atmel_lcdfb0_pixclk,
--      &ssc0_pclk,
--      &ssc1_pclk,
--      &ssc2_pclk,
--      &usba0_hclk,
--      &usba0_pclk,
--      &atmel_ac97c0_pclk,
--      &abdac0_pclk,
--      &abdac0_sample_clk,
--      &gclk0,
--      &gclk1,
--      &gclk2,
--      &gclk3,
--      &gclk4,
+-static struct platform_driver pdc_driver = {
+-      .probe          = pdc_probe,
+-      .driver         = {
+-              .name   = "pdc",
+-      },
 -};
--unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
 -
--void __init at32_portmux_init(void)
+-static int __init pdc_init(void)
 -{
--      at32_init_pio(&pio0_device);
--      at32_init_pio(&pio1_device);
--      at32_init_pio(&pio2_device);
--      at32_init_pio(&pio3_device);
--      at32_init_pio(&pio4_device);
+-      return platform_driver_register(&pdc_driver);
 -}
+-arch_initcall(pdc_init);
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/cpufreq.c avr32-2.6/arch/avr32/mach-at32ap/cpufreq.c
+--- linux-2.6.25.6/arch/avr32/mach-at32ap/cpufreq.c    2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/mach-at32ap/cpufreq.c 2008-06-12 15:03:55.891816030 +0200
+@@ -108,5 +108,4 @@
+ {
+       return cpufreq_register_driver(&at32_driver);
+ }
 -
--void __init at32_clock_init(void)
--{
--      u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
--      int i;
--
--      if (pm_readl(MCCTRL) & PM_BIT(PLLSEL)) {
--              main_clock = &pll0;
--              cpu_clk.parent = &pll0;
--      } else {
--              main_clock = &osc0;
--              cpu_clk.parent = &osc0;
--      }
--
--      if (pm_readl(PLL0) & PM_BIT(PLLOSC))
--              pll0.parent = &osc1;
--      if (pm_readl(PLL1) & PM_BIT(PLLOSC))
--              pll1.parent = &osc1;
--
--      genclk_init_parent(&gclk0);
--      genclk_init_parent(&gclk1);
--      genclk_init_parent(&gclk2);
--      genclk_init_parent(&gclk3);
--      genclk_init_parent(&gclk4);
--      genclk_init_parent(&atmel_lcdfb0_pixclk);
--      genclk_init_parent(&abdac0_sample_clk);
--
--      /*
--       * Turn on all clocks that have at least one user already, and
--       * turn off everything else. We only do this for module
--       * clocks, and even though it isn't particularly pretty to
--       * check the address of the mode function, it should do the
--       * trick...
--       */
--      for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
--              struct clk *clk = at32_clock_list[i];
--
--              if (clk->users == 0)
--                      continue;
--
--              if (clk->mode == &cpu_clk_mode)
--                      cpu_mask |= 1 << clk->index;
--              else if (clk->mode == &hsb_clk_mode)
--                      hsb_mask |= 1 << clk->index;
--              else if (clk->mode == &pba_clk_mode)
--                      pba_mask |= 1 << clk->index;
--              else if (clk->mode == &pbb_clk_mode)
--                      pbb_mask |= 1 << clk->index;
--      }
--
--      pm_writel(CPU_MASK, cpu_mask);
--      pm_writel(HSB_MASK, hsb_mask);
--      pm_writel(PBA_MASK, pba_mask);
--      pm_writel(PBB_MASK, pbb_mask);
--}
---- /dev/null
-+++ b/arch/avr32/mach-at32ap/at32ap700x.c
-@@ -0,0 +1,1944 @@
+-arch_initcall(at32_cpufreq_init);
++late_initcall(at32_cpufreq_init);
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/gpio-dev.c avr32-2.6/arch/avr32/mach-at32ap/gpio-dev.c
+--- linux-2.6.25.6/arch/avr32/mach-at32ap/gpio-dev.c   1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/arch/avr32/mach-at32ap/gpio-dev.c        2008-06-12 15:09:38.723815860 +0200
+@@ -0,0 +1,573 @@
 +/*
-+ * Copyright (C) 2005-2006 Atmel Corporation
++ * GPIO /dev and configfs interface
++ *
++ * Copyright (C) 2006-2007 Atmel Corporation
 + *
 + * 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/clk.h>
-+#include <linux/fb.h>
-+#include <linux/init.h>
-+#include <linux/platform_device.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/spi/spi.h>
-+#include <linux/usb/atmel_usba_udc.h>
-+
-+#include <asm/io.h>
-+#include <asm/irq.h>
++#include <linux/kernel.h>
++#include <linux/configfs.h>
++#include <linux/cdev.h>
++#include <linux/device.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/poll.h>
++#include <linux/uaccess.h>
++#include <linux/wait.h>
 +
-+#include <asm/arch/at32ap700x.h>
-+#include <asm/arch/board.h>
++#include <asm/gpio.h>
 +#include <asm/arch/portmux.h>
 +
-+#include <video/atmel_lcdc.h>
++#define GPIO_DEV_MAX                  8
 +
-+#include "clock.h"
-+#include "hmatrix.h"
-+#include "pio.h"
-+#include "pm.h"
++static struct class *gpio_dev_class;
++static dev_t gpio_devt;
 +
++struct gpio_item {
++      spinlock_t lock;
 +
-+#define PBMEM(base)                                   \
-+      {                                               \
-+              .start          = base,                 \
-+              .end            = base + 0x3ff,         \
-+              .flags          = IORESOURCE_MEM,       \
-+      }
-+#define IRQ(num)                                      \
-+      {                                               \
-+              .start          = num,                  \
-+              .end            = num,                  \
-+              .flags          = IORESOURCE_IRQ,       \
-+      }
-+#define NAMED_IRQ(num, _name)                         \
-+      {                                               \
-+              .start          = num,                  \
-+              .end            = num,                  \
-+              .name           = _name,                \
-+              .flags          = IORESOURCE_IRQ,       \
-+      }
-+
-+/* REVISIT these assume *every* device supports DMA, but several
-+ * don't ... tc, smc, pio, rtc, watchdog, pwm, ps2, and more.
-+ */
-+#define DEFINE_DEV(_name, _id)                                        \
-+static u64 _name##_id##_dma_mask = DMA_32BIT_MASK;            \
-+static struct platform_device _name##_id##_device = {         \
-+      .name           = #_name,                               \
-+      .id             = _id,                                  \
-+      .dev            = {                                     \
-+              .dma_mask = &_name##_id##_dma_mask,             \
-+              .coherent_dma_mask = DMA_32BIT_MASK,            \
-+      },                                                      \
-+      .resource       = _name##_id##_resource,                \
-+      .num_resources  = ARRAY_SIZE(_name##_id##_resource),    \
-+}
-+#define DEFINE_DEV_DATA(_name, _id)                           \
-+static u64 _name##_id##_dma_mask = DMA_32BIT_MASK;            \
-+static struct platform_device _name##_id##_device = {         \
-+      .name           = #_name,                               \
-+      .id             = _id,                                  \
-+      .dev            = {                                     \
-+              .dma_mask = &_name##_id##_dma_mask,             \
-+              .platform_data  = &_name##_id##_data,           \
-+              .coherent_dma_mask = DMA_32BIT_MASK,            \
-+      },                                                      \
-+      .resource       = _name##_id##_resource,                \
-+      .num_resources  = ARRAY_SIZE(_name##_id##_resource),    \
-+}
-+
-+#define select_peripheral(pin, periph, flags)                 \
-+      at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)
-+
-+#define DEV_CLK(_name, devname, bus, _index)                  \
-+static struct clk devname##_##_name = {                               \
-+      .name           = #_name,                               \
-+      .dev            = &devname##_device.dev,                \
-+      .parent         = &bus##_clk,                           \
-+      .mode           = bus##_clk_mode,                       \
-+      .get_rate       = bus##_clk_get_rate,                   \
-+      .index          = _index,                               \
-+}
-+
-+static DEFINE_SPINLOCK(pm_lock);
-+
-+unsigned long at32ap7000_osc_rates[3] = {
-+      [0] = 32768,
-+      /* FIXME: these are ATSTK1002-specific */
-+      [1] = 20000000,
-+      [2] = 12000000,
-+};
++      int enabled;
++      int initialized;
++      int port;
++      u32 pin_mask;
++      u32 oe_mask;
 +
-+static unsigned long osc_get_rate(struct clk *clk)
-+{
-+      return at32ap7000_osc_rates[clk->index];
-+}
++      /* Pin state last time we read it (for blocking reads) */
++      u32 pin_state;
++      int changed;
 +
-+static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
-+{
-+      unsigned long div, mul, rate;
++      wait_queue_head_t change_wq;
++      struct fasync_struct *async_queue;
 +
-+      if (!(control & PM_BIT(PLLEN)))
-+              return 0;
++      int id;
++      struct class_device *gpio_dev;
++      struct cdev char_dev;
++      struct config_item item;
++};
 +
-+      div = PM_BFEXT(PLLDIV, control) + 1;
-+      mul = PM_BFEXT(PLLMUL, control) + 1;
++struct gpio_attribute {
++      struct configfs_attribute attr;
++      ssize_t (*show)(struct gpio_item *, char *);
++      ssize_t (*store)(struct gpio_item *, const char *, size_t);
++};
 +
-+      rate = clk->parent->get_rate(clk->parent);
-+      rate = (rate + div / 2) / div;
-+      rate *= mul;
++static irqreturn_t gpio_dev_interrupt(int irq, void *dev_id)
++{
++      struct gpio_item *gpio = dev_id;
++      u32 old_state, new_state;
 +
-+      return rate;
-+}
++      old_state = gpio->pin_state;
++      new_state = at32_gpio_get_value_multiple(gpio->port, gpio->pin_mask);
++      gpio->pin_state = new_state;
 +
-+static unsigned long pll0_get_rate(struct clk *clk)
-+{
-+      u32 control;
++      if (new_state != old_state) {
++              gpio->changed = 1;
++              wake_up_interruptible(&gpio->change_wq);
 +
-+      control = pm_readl(PLL0);
++              if (gpio->async_queue)
++                      kill_fasync(&gpio->async_queue, SIGIO, POLL_IN);
++      }
 +
-+      return pll_get_rate(clk, control);
++      return IRQ_HANDLED;
 +}
 +
-+static unsigned long pll1_get_rate(struct clk *clk)
++static int gpio_dev_open(struct inode *inode, struct file *file)
 +{
-+      u32 control;
++      struct gpio_item *gpio = container_of(inode->i_cdev,
++                                            struct gpio_item,
++                                            char_dev);
++      unsigned int irq;
++      unsigned int i;
++      int ret;
 +
-+      control = pm_readl(PLL1);
++      nonseekable_open(inode, file);
++      config_item_get(&gpio->item);
++      file->private_data = gpio;
 +
-+      return pll_get_rate(clk, control);
-+}
++      gpio->pin_state = at32_gpio_get_value_multiple(gpio->port,
++                                                     gpio->pin_mask);
++      gpio->changed = 1;
 +
-+/*
-+ * The AT32AP7000 has five primary clock sources: One 32kHz
-+ * oscillator, two crystal oscillators and two PLLs.
-+ */
-+static struct clk osc32k = {
-+      .name           = "osc32k",
-+      .get_rate       = osc_get_rate,
-+      .users          = 1,
-+      .index          = 0,
-+};
-+static struct clk osc0 = {
-+      .name           = "osc0",
-+      .get_rate       = osc_get_rate,
-+      .users          = 1,
-+      .index          = 1,
-+};
-+static struct clk osc1 = {
-+      .name           = "osc1",
-+      .get_rate       = osc_get_rate,
-+      .index          = 2,
-+};
-+static struct clk pll0 = {
-+      .name           = "pll0",
-+      .get_rate       = pll0_get_rate,
-+      .parent         = &osc0,
-+};
-+static struct clk pll1 = {
-+      .name           = "pll1",
-+      .get_rate       = pll1_get_rate,
-+      .parent         = &osc0,
-+};
++      for (i = 0; i < 32; i++) {
++              if (gpio->pin_mask & (1 << i)) {
++                      irq = gpio_to_irq(32 * gpio->port + i);
++                      ret = request_irq(irq, gpio_dev_interrupt, 0,
++                                        "gpio-dev", gpio);
++                      if (ret)
++                              goto err_irq;
++              }
++      }
 +
-+/*
-+ * The main clock can be either osc0 or pll0.  The boot loader may
-+ * have chosen one for us, so we don't really know which one until we
-+ * have a look at the SM.
-+ */
-+static struct clk *main_clock;
++      return 0;
 +
-+/*
-+ * Synchronous clocks are generated from the main clock. The clocks
-+ * must satisfy the constraint
-+ *   fCPU >= fHSB >= fPB
-+ * i.e. each clock must not be faster than its parent.
-+ */
-+static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift)
-+{
-+      return main_clock->get_rate(main_clock) >> shift;
-+};
++err_irq:
++      while (i--) {
++              if (gpio->pin_mask & (1 << i)) {
++                      irq = gpio_to_irq(32 * gpio->port + i);
++                      free_irq(irq, gpio);
++              }
++      }
 +
-+static void cpu_clk_mode(struct clk *clk, int enabled)
-+{
-+      unsigned long flags;
-+      u32 mask;
++      config_item_put(&gpio->item);
 +
-+      spin_lock_irqsave(&pm_lock, flags);
-+      mask = pm_readl(CPU_MASK);
-+      if (enabled)
-+              mask |= 1 << clk->index;
-+      else
-+              mask &= ~(1 << clk->index);
-+      pm_writel(CPU_MASK, mask);
-+      spin_unlock_irqrestore(&pm_lock, flags);
++      return ret;
 +}
 +
-+static unsigned long cpu_clk_get_rate(struct clk *clk)
++static int gpio_dev_fasync(int fd, struct file *file, int mode)
 +{
-+      unsigned long cksel, shift = 0;
-+
-+      cksel = pm_readl(CKSEL);
-+      if (cksel & PM_BIT(CPUDIV))
-+              shift = PM_BFEXT(CPUSEL, cksel) + 1;
++      struct gpio_item *gpio = file->private_data;
 +
-+      return bus_clk_get_rate(clk, shift);
++      return fasync_helper(fd, file, mode, &gpio->async_queue);
 +}
 +
-+static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply)
++static int gpio_dev_release(struct inode *inode, struct file *file)
 +{
-+      u32 control;
-+      unsigned long parent_rate, child_div, actual_rate, div;
-+
-+      parent_rate = clk->parent->get_rate(clk->parent);
-+      control = pm_readl(CKSEL);
++      struct gpio_item *gpio = file->private_data;
++      unsigned int irq;
++      unsigned int i;
 +
-+      if (control & PM_BIT(HSBDIV))
-+              child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1);
-+      else
-+              child_div = 1;
++      gpio_dev_fasync(-1, file, 0);
 +
-+      if (rate > 3 * (parent_rate / 4) || child_div == 1) {
-+              actual_rate = parent_rate;
-+              control &= ~PM_BIT(CPUDIV);
-+      } else {
-+              unsigned int cpusel;
-+              div = (parent_rate + rate / 2) / rate;
-+              if (div > child_div)
-+                      div = child_div;
-+              cpusel = (div > 1) ? (fls(div) - 2) : 0;
-+              control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control);
-+              actual_rate = parent_rate / (1 << (cpusel + 1));
++      for (i = 0; i < 32; i++) {
++              if (gpio->pin_mask & (1 << i)) {
++                      irq = gpio_to_irq(32 * gpio->port + i);
++                      free_irq(irq, gpio);
++              }
 +      }
 +
-+      pr_debug("clk %s: new rate %lu (actual rate %lu)\n",
-+                      clk->name, rate, actual_rate);
-+
-+      if (apply)
-+              pm_writel(CKSEL, control);
++      config_item_put(&gpio->item);
 +
-+      return actual_rate;
++      return 0;
 +}
 +
-+static void hsb_clk_mode(struct clk *clk, int enabled)
++static unsigned int gpio_dev_poll(struct file *file, poll_table *wait)
 +{
-+      unsigned long flags;
-+      u32 mask;
++      struct gpio_item *gpio = file->private_data;
++      unsigned int mask = 0;
 +
-+      spin_lock_irqsave(&pm_lock, flags);
-+      mask = pm_readl(HSB_MASK);
-+      if (enabled)
-+              mask |= 1 << clk->index;
-+      else
-+              mask &= ~(1 << clk->index);
-+      pm_writel(HSB_MASK, mask);
-+      spin_unlock_irqrestore(&pm_lock, flags);
++      poll_wait(file, &gpio->change_wq, wait);
++      if (gpio->changed)
++              mask |= POLLIN | POLLRDNORM;
++
++      return mask;
 +}
 +
-+static unsigned long hsb_clk_get_rate(struct clk *clk)
++static ssize_t gpio_dev_read(struct file *file, char __user *buf,
++                           size_t count, loff_t *offset)
 +{
-+      unsigned long cksel, shift = 0;
++      struct gpio_item *gpio = file->private_data;
++      u32 value;
++
++      spin_lock_irq(&gpio->lock);
++      while (!gpio->changed) {
++              spin_unlock_irq(&gpio->lock);
 +
-+      cksel = pm_readl(CKSEL);
-+      if (cksel & PM_BIT(HSBDIV))
-+              shift = PM_BFEXT(HSBSEL, cksel) + 1;
++              if (file->f_flags & O_NONBLOCK)
++                      return -EAGAIN;
 +
-+      return bus_clk_get_rate(clk, shift);
-+}
++              if (wait_event_interruptible(gpio->change_wq, gpio->changed))
++                      return -ERESTARTSYS;
 +
-+static void pba_clk_mode(struct clk *clk, int enabled)
-+{
-+      unsigned long flags;
-+      u32 mask;
++              spin_lock_irq(&gpio->lock);
++      }
 +
-+      spin_lock_irqsave(&pm_lock, flags);
-+      mask = pm_readl(PBA_MASK);
-+      if (enabled)
-+              mask |= 1 << clk->index;
-+      else
-+              mask &= ~(1 << clk->index);
-+      pm_writel(PBA_MASK, mask);
-+      spin_unlock_irqrestore(&pm_lock, flags);
-+}
++      gpio->changed = 0;
++      value = at32_gpio_get_value_multiple(gpio->port, gpio->pin_mask);
 +
-+static unsigned long pba_clk_get_rate(struct clk *clk)
-+{
-+      unsigned long cksel, shift = 0;
++      spin_unlock_irq(&gpio->lock);
 +
-+      cksel = pm_readl(CKSEL);
-+      if (cksel & PM_BIT(PBADIV))
-+              shift = PM_BFEXT(PBASEL, cksel) + 1;
++      count = min(count, (size_t)4);
++      if (copy_to_user(buf, &value, count))
++              return -EFAULT;
 +
-+      return bus_clk_get_rate(clk, shift);
++      return count;
 +}
 +
-+static void pbb_clk_mode(struct clk *clk, int enabled)
++static ssize_t gpio_dev_write(struct file *file, const char __user *buf,
++                            size_t count, loff_t *offset)
 +{
-+      unsigned long flags;
-+      u32 mask;
++      struct gpio_item *gpio = file->private_data;
++      u32 value = 0;
++      u32 mask = ~0UL;
 +
-+      spin_lock_irqsave(&pm_lock, flags);
-+      mask = pm_readl(PBB_MASK);
-+      if (enabled)
-+              mask |= 1 << clk->index;
-+      else
-+              mask &= ~(1 << clk->index);
-+      pm_writel(PBB_MASK, mask);
-+      spin_unlock_irqrestore(&pm_lock, flags);
-+}
++      count = min(count, (size_t)4);
++      if (copy_from_user(&value, buf, count))
++              return -EFAULT;
 +
-+static unsigned long pbb_clk_get_rate(struct clk *clk)
-+{
-+      unsigned long cksel, shift = 0;
++      /* Assuming big endian */
++      mask <<= (4 - count) * 8;
++      mask &= gpio->pin_mask;
 +
-+      cksel = pm_readl(CKSEL);
-+      if (cksel & PM_BIT(PBBDIV))
-+              shift = PM_BFEXT(PBBSEL, cksel) + 1;
++      at32_gpio_set_value_multiple(gpio->port, value, mask);
 +
-+      return bus_clk_get_rate(clk, shift);
++      return count;
 +}
 +
-+static struct clk cpu_clk = {
-+      .name           = "cpu",
-+      .get_rate       = cpu_clk_get_rate,
-+      .set_rate       = cpu_clk_set_rate,
-+      .users          = 1,
-+};
-+static struct clk hsb_clk = {
-+      .name           = "hsb",
-+      .parent         = &cpu_clk,
-+      .get_rate       = hsb_clk_get_rate,
-+};
-+static struct clk pba_clk = {
-+      .name           = "pba",
-+      .parent         = &hsb_clk,
-+      .mode           = hsb_clk_mode,
-+      .get_rate       = pba_clk_get_rate,
-+      .index          = 1,
-+};
-+static struct clk pbb_clk = {
-+      .name           = "pbb",
-+      .parent         = &hsb_clk,
-+      .mode           = hsb_clk_mode,
-+      .get_rate       = pbb_clk_get_rate,
-+      .users          = 1,
-+      .index          = 2,
++static struct file_operations gpio_dev_fops = {
++      .owner          = THIS_MODULE,
++      .llseek         = no_llseek,
++      .open           = gpio_dev_open,
++      .release        = gpio_dev_release,
++      .fasync         = gpio_dev_fasync,
++      .poll           = gpio_dev_poll,
++      .read           = gpio_dev_read,
++      .write          = gpio_dev_write,
 +};
 +
-+/* --------------------------------------------------------------------
-+ *  Generic Clock operations
-+ * -------------------------------------------------------------------- */
-+
-+static void genclk_mode(struct clk *clk, int enabled)
++static struct gpio_item *to_gpio_item(struct config_item *item)
 +{
-+      u32 control;
-+
-+      control = pm_readl(GCCTRL(clk->index));
-+      if (enabled)
-+              control |= PM_BIT(CEN);
-+      else
-+              control &= ~PM_BIT(CEN);
-+      pm_writel(GCCTRL(clk->index), control);
++      return item ? container_of(item, struct gpio_item, item) : NULL;
 +}
 +
-+static unsigned long genclk_get_rate(struct clk *clk)
++static ssize_t gpio_show_gpio_id(struct gpio_item *gpio, char *page)
 +{
-+      u32 control;
-+      unsigned long div = 1;
-+
-+      control = pm_readl(GCCTRL(clk->index));
-+      if (control & PM_BIT(DIVEN))
-+              div = 2 * (PM_BFEXT(DIV, control) + 1);
-+
-+      return clk->parent->get_rate(clk->parent) / div;
++      return sprintf(page, "%d\n", gpio->port);
 +}
 +
-+static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply)
++static ssize_t gpio_store_gpio_id(struct gpio_item *gpio,
++                                const char *page, size_t count)
 +{
-+      u32 control;
-+      unsigned long parent_rate, actual_rate, div;
++      unsigned long id;
++      char *p = (char *)page;
++      ssize_t ret = -EINVAL;
 +
-+      parent_rate = clk->parent->get_rate(clk->parent);
-+      control = pm_readl(GCCTRL(clk->index));
++      id = simple_strtoul(p, &p, 0);
++      if (!p || (*p && (*p != '\n')))
++              return -EINVAL;
 +
-+      if (rate > 3 * parent_rate / 4) {
-+              actual_rate = parent_rate;
-+              control &= ~PM_BIT(DIVEN);
-+      } else {
-+              div = (parent_rate + rate) / (2 * rate) - 1;
-+              control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN);
-+              actual_rate = parent_rate / (2 * (div + 1));
++      /* Switching PIO is not allowed when live... */
++      spin_lock(&gpio->lock);
++      if (!gpio->enabled) {
++              ret = -ENXIO;
++              if (at32_gpio_port_is_valid(id)) {
++                      gpio->port = id;
++                      ret = count;
++              }
 +      }
++      spin_unlock(&gpio->lock);
 +
-+      dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n",
-+              clk->name, rate, actual_rate);
-+
-+      if (apply)
-+              pm_writel(GCCTRL(clk->index), control);
++      return ret;
++}
 +
-+      return actual_rate;
++static ssize_t gpio_show_pin_mask(struct gpio_item *gpio, char *page)
++{
++      return sprintf(page, "0x%08x\n", gpio->pin_mask);
 +}
 +
-+int genclk_set_parent(struct clk *clk, struct clk *parent)
++static ssize_t gpio_store_pin_mask(struct gpio_item *gpio,
++                                 const char *page, size_t count)
 +{
-+      u32 control;
++      u32 new_mask;
++      char *p = (char *)page;
++      ssize_t ret = -EINVAL;
 +
-+      dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n",
-+              clk->name, parent->name, clk->parent->name);
-+
-+      control = pm_readl(GCCTRL(clk->index));
-+
-+      if (parent == &osc1 || parent == &pll1)
-+              control |= PM_BIT(OSCSEL);
-+      else if (parent == &osc0 || parent == &pll0)
-+              control &= ~PM_BIT(OSCSEL);
-+      else
++      new_mask = simple_strtoul(p, &p, 0);
++      if (!p || (*p && (*p != '\n')))
 +              return -EINVAL;
 +
-+      if (parent == &pll0 || parent == &pll1)
-+              control |= PM_BIT(PLLSEL);
-+      else
-+              control &= ~PM_BIT(PLLSEL);
++      /* Can't update the pin mask while live. */
++      spin_lock(&gpio->lock);
++      if (!gpio->enabled) {
++              gpio->oe_mask &= new_mask;
++              gpio->pin_mask = new_mask;
++              ret = count;
++      }
++      spin_unlock(&gpio->lock);
 +
-+      pm_writel(GCCTRL(clk->index), control);
-+      clk->parent = parent;
++      return ret;
++}
 +
-+      return 0;
++static ssize_t gpio_show_oe_mask(struct gpio_item *gpio, char *page)
++{
++      return sprintf(page, "0x%08x\n", gpio->oe_mask);
 +}
 +
-+static void __init genclk_init_parent(struct clk *clk)
++static ssize_t gpio_store_oe_mask(struct gpio_item *gpio,
++                                const char *page, size_t count)
 +{
-+      u32 control;
-+      struct clk *parent;
++      u32 mask;
++      char *p = (char *)page;
++      ssize_t ret = -EINVAL;
 +
-+      BUG_ON(clk->index > 7);
++      mask = simple_strtoul(p, &p, 0);
++      if (!p || (*p && (*p != '\n')))
++              return -EINVAL;
 +
-+      control = pm_readl(GCCTRL(clk->index));
-+      if (control & PM_BIT(OSCSEL))
-+              parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1;
-+      else
-+              parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0;
++      spin_lock(&gpio->lock);
++      if (!gpio->enabled) {
++              gpio->oe_mask = mask & gpio->pin_mask;
++              ret = count;
++      }
++      spin_unlock(&gpio->lock);
 +
-+      clk->parent = parent;
++      return ret;
 +}
 +
-+/* --------------------------------------------------------------------
-+ *  System peripherals
-+ * -------------------------------------------------------------------- */
-+static struct resource at32_pm0_resource[] = {
-+      {
-+              .start  = 0xfff00000,
-+              .end    = 0xfff0007f,
-+              .flags  = IORESOURCE_MEM,
-+      },
-+      IRQ(20),
-+};
++static ssize_t gpio_show_enabled(struct gpio_item *gpio, char *page)
++{
++      return sprintf(page, "%d\n", gpio->enabled);
++}
 +
-+static struct resource at32ap700x_rtc0_resource[] = {
-+      {
-+              .start  = 0xfff00080,
-+              .end    = 0xfff000af,
-+              .flags  = IORESOURCE_MEM,
-+      },
-+      IRQ(21),
-+};
++static ssize_t gpio_store_enabled(struct gpio_item *gpio,
++                                const char *page, size_t count)
++{
++      char *p = (char *)page;
++      int enabled;
++      int ret;
 +
-+static struct resource at32_wdt0_resource[] = {
-+      {
-+              .start  = 0xfff000b0,
-+              .end    = 0xfff000cf,
-+              .flags  = IORESOURCE_MEM,
-+      },
-+};
++      enabled = simple_strtoul(p, &p, 0);
++      if (!p || (*p && (*p != '\n')))
++              return -EINVAL;
 +
-+static struct resource at32_eic0_resource[] = {
-+      {
-+              .start  = 0xfff00100,
-+              .end    = 0xfff0013f,
-+              .flags  = IORESOURCE_MEM,
-+      },
-+      IRQ(19),
-+};
++      /* make it a boolean value */
++      enabled = !!enabled;
 +
-+DEFINE_DEV(at32_pm, 0);
-+DEFINE_DEV(at32ap700x_rtc, 0);
-+DEFINE_DEV(at32_wdt, 0);
-+DEFINE_DEV(at32_eic, 0);
++      if (gpio->enabled == enabled)
++              /* No change; do nothing. */
++              return count;
 +
-+/*
-+ * Peripheral clock for PM, RTC, WDT and EIC. PM will ensure that this
-+ * is always running.
-+ */
-+static struct clk at32_pm_pclk = {
-+      .name           = "pclk",
-+      .dev            = &at32_pm0_device.dev,
-+      .parent         = &pbb_clk,
-+      .mode           = pbb_clk_mode,
-+      .get_rate       = pbb_clk_get_rate,
-+      .users          = 1,
-+      .index          = 0,
-+};
++      BUG_ON(gpio->id >= GPIO_DEV_MAX);
 +
-+static struct resource intc0_resource[] = {
-+      PBMEM(0xfff00400),
-+};
-+struct platform_device at32_intc0_device = {
-+      .name           = "intc",
-+      .id             = 0,
-+      .resource       = intc0_resource,
-+      .num_resources  = ARRAY_SIZE(intc0_resource),
-+};
-+DEV_CLK(pclk, at32_intc0, pbb, 1);
++      if (!enabled) {
++              class_device_unregister(gpio->gpio_dev);
++              cdev_del(&gpio->char_dev);
++              at32_deselect_pins(gpio->port, gpio->pin_mask);
++              gpio->initialized = 0;
++      } else {
++              if (gpio->port < 0 || !gpio->pin_mask)
++                      return -ENODEV;
++      }
 +
-+static struct clk ebi_clk = {
-+      .name           = "ebi",
-+      .parent         = &hsb_clk,
-+      .mode           = hsb_clk_mode,
-+      .get_rate       = hsb_clk_get_rate,
-+      .users          = 1,
-+};
-+static struct clk hramc_clk = {
-+      .name           = "hramc",
-+      .parent         = &hsb_clk,
-+      .mode           = hsb_clk_mode,
-+      .get_rate       = hsb_clk_get_rate,
-+      .users          = 1,
-+      .index          = 3,
-+};
++      /* Disallow any updates to gpio_id or pin_mask */
++      spin_lock(&gpio->lock);
++      gpio->enabled = enabled;
++      spin_unlock(&gpio->lock);
 +
-+static struct resource smc0_resource[] = {
-+      PBMEM(0xfff03400),
-+};
-+DEFINE_DEV(smc, 0);
-+DEV_CLK(pclk, smc0, pbb, 13);
-+DEV_CLK(mck, smc0, hsb, 0);
++      if (!enabled)
++              return count;
 +
-+static struct platform_device pdc_device = {
-+      .name           = "pdc",
-+      .id             = 0,
-+};
-+DEV_CLK(hclk, pdc, hsb, 4);
-+DEV_CLK(pclk, pdc, pba, 16);
-+
-+static struct clk pico_clk = {
-+      .name           = "pico",
-+      .parent         = &cpu_clk,
-+      .mode           = cpu_clk_mode,
-+      .get_rate       = cpu_clk_get_rate,
-+      .users          = 1,
-+};
++      /* Now, try to allocate the pins */
++      ret = at32_select_gpio_pins(gpio->port, gpio->pin_mask, gpio->oe_mask);
++      if (ret)
++              goto err_alloc_pins;
 +
-+static struct resource dmaca0_resource[] = {
-+      {
-+              .start  = 0xff200000,
-+              .end    = 0xff20ffff,
-+              .flags  = IORESOURCE_MEM,
-+      },
-+      IRQ(2),
-+};
-+DEFINE_DEV(dmaca, 0);
-+DEV_CLK(hclk, dmaca0, hsb, 10);
++      gpio->initialized = 1;
 +
-+/* --------------------------------------------------------------------
-+ * HMATRIX
-+ * -------------------------------------------------------------------- */
++      cdev_init(&gpio->char_dev, &gpio_dev_fops);
++      gpio->char_dev.owner = THIS_MODULE;
++      ret = cdev_add(&gpio->char_dev, MKDEV(MAJOR(gpio_devt), gpio->id), 1);
++      if (ret < 0)
++              goto err_cdev_add;
++      gpio->gpio_dev = class_device_create(gpio_dev_class, NULL,
++                                           MKDEV(MAJOR(gpio_devt), gpio->id),
++                                           NULL,
++                                           "gpio%d", gpio->id);
++      if (IS_ERR(gpio->gpio_dev)) {
++              printk(KERN_ERR "failed to create gpio%d\n", gpio->id);
++              ret = PTR_ERR(gpio->gpio_dev);
++              goto err_class_dev;
++      }
 +
-+static struct clk hmatrix_clk = {
-+      .name           = "hmatrix_clk",
-+      .parent         = &pbb_clk,
-+      .mode           = pbb_clk_mode,
-+      .get_rate       = pbb_clk_get_rate,
-+      .index          = 2,
-+      .users          = 1,
-+};
-+#define HMATRIX_BASE  ((void __iomem *)0xfff00800)
++      printk(KERN_INFO "created gpio%d (port%d/0x%08x) as (%d:%d)\n",
++             gpio->id, gpio->port, gpio->pin_mask,
++             MAJOR(gpio->gpio_dev->devt), MINOR(gpio->gpio_dev->devt));
 +
-+#define hmatrix_readl(reg)                                    \
-+      __raw_readl((HMATRIX_BASE) + HMATRIX_##reg)
-+#define hmatrix_writel(reg,value)                             \
-+      __raw_writel((value), (HMATRIX_BASE) + HMATRIX_##reg)
++      return 0;
 +
-+/*
-+ * Set bits in the HMATRIX Special Function Register (SFR) used by the
-+ * External Bus Interface (EBI). This can be used to enable special
-+ * features like CompactFlash support, NAND Flash support, etc. on
-+ * certain chipselects.
-+ */
-+static inline void set_ebi_sfr_bits(u32 mask)
-+{
-+      u32 sfr;
++err_class_dev:
++      cdev_del(&gpio->char_dev);
++err_cdev_add:
++      at32_deselect_pins(gpio->port, gpio->pin_mask);
++      gpio->initialized = 0;
++err_alloc_pins:
++      spin_lock(&gpio->lock);
++      gpio->enabled = 0;
++      spin_unlock(&gpio->lock);
 +
-+      clk_enable(&hmatrix_clk);
-+      sfr = hmatrix_readl(SFR4);
-+      sfr |= mask;
-+      hmatrix_writel(SFR4, sfr);
-+      clk_disable(&hmatrix_clk);
++      return ret;
 +}
 +
-+/* --------------------------------------------------------------------
-+ *  Timer/Counter (TC)
-+ * -------------------------------------------------------------------- */
-+
-+static struct resource at32_tcb0_resource[] = {
-+      PBMEM(0xfff00c00),
-+      IRQ(22),
-+};
-+static struct platform_device at32_tcb0_device = {
-+      .name           = "atmel_tcb",
-+      .id             = 0,
-+      .resource       = at32_tcb0_resource,
-+      .num_resources  = ARRAY_SIZE(at32_tcb0_resource),
-+};
-+DEV_CLK(t0_clk, at32_tcb0, pbb, 3);
-+
-+static struct resource at32_tcb1_resource[] = {
-+      PBMEM(0xfff01000),
-+      IRQ(23),
++static struct gpio_attribute gpio_item_attr_gpio_id = {
++      .attr = {
++              .ca_owner = THIS_MODULE,
++              .ca_name = "gpio_id",
++              .ca_mode = S_IRUGO | S_IWUSR,
++      },
++      .show = gpio_show_gpio_id,
++      .store = gpio_store_gpio_id,
 +};
-+static struct platform_device at32_tcb1_device = {
-+      .name           = "atmel_tcb",
-+      .id             = 1,
-+      .resource       = at32_tcb1_resource,
-+      .num_resources  = ARRAY_SIZE(at32_tcb1_resource),
++static struct gpio_attribute gpio_item_attr_pin_mask = {
++      .attr = {
++              .ca_owner = THIS_MODULE,
++              .ca_name = "pin_mask",
++              .ca_mode = S_IRUGO | S_IWUSR,
++      },
++      .show = gpio_show_pin_mask,
++      .store = gpio_store_pin_mask,
 +};
-+DEV_CLK(t0_clk, at32_tcb1, pbb, 4);
-+
-+/* --------------------------------------------------------------------
-+ *  PIO
-+ * -------------------------------------------------------------------- */
-+
-+static struct resource pio0_resource[] = {
-+      PBMEM(0xffe02800),
-+      IRQ(13),
++static struct gpio_attribute gpio_item_attr_oe_mask = {
++      .attr = {
++              .ca_owner = THIS_MODULE,
++              .ca_name = "oe_mask",
++              .ca_mode = S_IRUGO | S_IWUSR,
++      },
++      .show = gpio_show_oe_mask,
++      .store = gpio_store_oe_mask,
 +};
-+DEFINE_DEV(pio, 0);
-+DEV_CLK(mck, pio0, pba, 10);
-+
-+static struct resource pio1_resource[] = {
-+      PBMEM(0xffe02c00),
-+      IRQ(14),
++static struct gpio_attribute gpio_item_attr_enabled = {
++      .attr = {
++              .ca_owner = THIS_MODULE,
++              .ca_name = "enabled",
++              .ca_mode = S_IRUGO | S_IWUSR,
++      },
++      .show = gpio_show_enabled,
++      .store = gpio_store_enabled,
 +};
-+DEFINE_DEV(pio, 1);
-+DEV_CLK(mck, pio1, pba, 11);
 +
-+static struct resource pio2_resource[] = {
-+      PBMEM(0xffe03000),
-+      IRQ(15),
++static struct configfs_attribute *gpio_item_attrs[] = {
++      &gpio_item_attr_gpio_id.attr,
++      &gpio_item_attr_pin_mask.attr,
++      &gpio_item_attr_oe_mask.attr,
++      &gpio_item_attr_enabled.attr,
++      NULL,
 +};
-+DEFINE_DEV(pio, 2);
-+DEV_CLK(mck, pio2, pba, 12);
 +
-+static struct resource pio3_resource[] = {
-+      PBMEM(0xffe03400),
-+      IRQ(16),
-+};
-+DEFINE_DEV(pio, 3);
-+DEV_CLK(mck, pio3, pba, 13);
++static ssize_t gpio_show_attr(struct config_item *item,
++                            struct configfs_attribute *attr,
++                            char *page)
++{
++      struct gpio_item *gpio_item = to_gpio_item(item);
++      struct gpio_attribute *gpio_attr
++              = container_of(attr, struct gpio_attribute, attr);
++      ssize_t ret = 0;
 +
-+static struct resource pio4_resource[] = {
-+      PBMEM(0xffe03800),
-+      IRQ(17),
-+};
-+DEFINE_DEV(pio, 4);
-+DEV_CLK(mck, pio4, pba, 14);
++      if (gpio_attr->show)
++              ret = gpio_attr->show(gpio_item, page);
++      return ret;
++}
 +
-+void __init at32_add_system_devices(void)
++static ssize_t gpio_store_attr(struct config_item *item,
++                             struct configfs_attribute *attr,
++                             const char *page, size_t count)
 +{
-+      platform_device_register(&at32_pm0_device);
-+      platform_device_register(&at32_intc0_device);
-+      platform_device_register(&at32ap700x_rtc0_device);
-+      platform_device_register(&at32_wdt0_device);
-+      platform_device_register(&at32_eic0_device);
-+      platform_device_register(&smc0_device);
-+      platform_device_register(&pdc_device);
-+      platform_device_register(&dmaca0_device);
++      struct gpio_item *gpio_item = to_gpio_item(item);
++      struct gpio_attribute *gpio_attr
++              = container_of(attr, struct gpio_attribute, attr);
++      ssize_t ret = -EINVAL;
 +
-+      platform_device_register(&at32_tcb0_device);
-+      platform_device_register(&at32_tcb1_device);
++      if (gpio_attr->store)
++              ret = gpio_attr->store(gpio_item, page, count);
++      return ret;
++}
 +
-+      platform_device_register(&pio0_device);
-+      platform_device_register(&pio1_device);
-+      platform_device_register(&pio2_device);
-+      platform_device_register(&pio3_device);
-+      platform_device_register(&pio4_device);
++static void gpio_release(struct config_item *item)
++{
++      kfree(to_gpio_item(item));
 +}
 +
-+/* --------------------------------------------------------------------
-+ *  PSIF
-+ * -------------------------------------------------------------------- */
-+static struct resource atmel_psif0_resource[] __initdata = {
-+      {
-+              .start  = 0xffe03c00,
-+              .end    = 0xffe03cff,
-+              .flags  = IORESOURCE_MEM,
-+      },
-+      IRQ(18),
-+};
-+static struct clk atmel_psif0_pclk = {
-+      .name           = "pclk",
-+      .parent         = &pba_clk,
-+      .mode           = pba_clk_mode,
-+      .get_rate       = pba_clk_get_rate,
-+      .index          = 15,
++static struct configfs_item_operations gpio_item_ops = {
++      .release                = gpio_release,
++      .show_attribute         = gpio_show_attr,
++      .store_attribute        = gpio_store_attr,
 +};
 +
-+static struct resource atmel_psif1_resource[] __initdata = {
-+      {
-+              .start  = 0xffe03d00,
-+              .end    = 0xffe03dff,
-+              .flags  = IORESOURCE_MEM,
-+      },
-+      IRQ(18),
-+};
-+static struct clk atmel_psif1_pclk = {
-+      .name           = "pclk",
-+      .parent         = &pba_clk,
-+      .mode           = pba_clk_mode,
-+      .get_rate       = pba_clk_get_rate,
-+      .index          = 15,
++static struct config_item_type gpio_item_type = {
++      .ct_item_ops    = &gpio_item_ops,
++      .ct_attrs       = gpio_item_attrs,
++      .ct_owner       = THIS_MODULE,
 +};
 +
-+struct platform_device *__init at32_add_device_psif(unsigned int id)
++static struct config_item *gpio_make_item(struct config_group *group,
++                                        const char *name)
 +{
-+      struct platform_device *pdev;
-+
-+      if (!(id == 0 || id == 1))
-+              return NULL;
++      static int next_id;
++      struct gpio_item *gpio;
 +
-+      pdev = platform_device_alloc("atmel_psif", id);
-+      if (!pdev)
++      if (next_id >= GPIO_DEV_MAX)
 +              return NULL;
 +
-+      switch (id) {
-+      case 0:
-+              if (platform_device_add_resources(pdev, atmel_psif0_resource,
-+                                      ARRAY_SIZE(atmel_psif0_resource)))
-+                      goto err_add_resources;
-+              atmel_psif0_pclk.dev = &pdev->dev;
-+              select_peripheral(PA(8), PERIPH_A, 0); /* CLOCK */
-+              select_peripheral(PA(9), PERIPH_A, 0); /* DATA  */
-+              break;
-+      case 1:
-+              if (platform_device_add_resources(pdev, atmel_psif1_resource,
-+                                      ARRAY_SIZE(atmel_psif1_resource)))
-+                      goto err_add_resources;
-+              atmel_psif1_pclk.dev = &pdev->dev;
-+              select_peripheral(PB(11), PERIPH_A, 0); /* CLOCK */
-+              select_peripheral(PB(12), PERIPH_A, 0); /* DATA  */
-+              break;
-+      default:
++      gpio = kzalloc(sizeof(struct gpio_item), GFP_KERNEL);
++      if (!gpio)
 +              return NULL;
-+      }
 +
-+      platform_device_add(pdev);
-+      return pdev;
++      gpio->id = next_id++;
++      config_item_init_type_name(&gpio->item, name, &gpio_item_type);
++      spin_lock_init(&gpio->lock);
++      init_waitqueue_head(&gpio->change_wq);
 +
-+err_add_resources:
-+      platform_device_put(pdev);
-+      return NULL;
++      return &gpio->item;
 +}
 +
-+/* --------------------------------------------------------------------
-+ *  USART
-+ * -------------------------------------------------------------------- */
++static void gpio_drop_item(struct config_group *group,
++                         struct config_item *item)
++{
++      struct gpio_item *gpio = to_gpio_item(item);
 +
-+static struct atmel_uart_data atmel_usart0_data = {
-+      .use_dma_tx     = 1,
-+      .use_dma_rx     = 1,
-+};
-+static struct resource atmel_usart0_resource[] = {
-+      PBMEM(0xffe00c00),
-+      IRQ(6),
-+};
-+DEFINE_DEV_DATA(atmel_usart, 0);
-+DEV_CLK(usart, atmel_usart0, pba, 3);
++      spin_lock(&gpio->lock);
++      if (gpio->enabled) {
++              class_device_unregister(gpio->gpio_dev);
++              cdev_del(&gpio->char_dev);
++      }
 +
-+static struct atmel_uart_data atmel_usart1_data = {
-+      .use_dma_tx     = 1,
-+      .use_dma_rx     = 1,
-+};
-+static struct resource atmel_usart1_resource[] = {
-+      PBMEM(0xffe01000),
-+      IRQ(7),
-+};
-+DEFINE_DEV_DATA(atmel_usart, 1);
-+DEV_CLK(usart, atmel_usart1, pba, 4);
++      if (gpio->initialized) {
++              at32_deselect_pins(gpio->port, gpio->pin_mask);
++              gpio->initialized = 0;
++              gpio->enabled = 0;
++      }
++      spin_unlock(&gpio->lock);
++}
 +
-+static struct atmel_uart_data atmel_usart2_data = {
-+      .use_dma_tx     = 1,
-+      .use_dma_rx     = 1,
-+};
-+static struct resource atmel_usart2_resource[] = {
-+      PBMEM(0xffe01400),
-+      IRQ(8),
++static struct configfs_group_operations gpio_group_ops = {
++      .make_item      = gpio_make_item,
++      .drop_item      = gpio_drop_item,
 +};
-+DEFINE_DEV_DATA(atmel_usart, 2);
-+DEV_CLK(usart, atmel_usart2, pba, 5);
 +
-+static struct atmel_uart_data atmel_usart3_data = {
-+      .use_dma_tx     = 1,
-+      .use_dma_rx     = 1,
++static struct config_item_type gpio_group_type = {
++      .ct_group_ops   = &gpio_group_ops,
++      .ct_owner       = THIS_MODULE,
 +};
-+static struct resource atmel_usart3_resource[] = {
-+      PBMEM(0xffe01800),
-+      IRQ(9),
++
++static struct configfs_subsystem gpio_subsys = {
++      .su_group = {
++              .cg_item = {
++                       .ci_namebuf = "gpio",
++                       .ci_type = &gpio_group_type,
++               },
++      },
 +};
-+DEFINE_DEV_DATA(atmel_usart, 3);
-+DEV_CLK(usart, atmel_usart3, pba, 6);
 +
-+static inline void configure_usart0_pins(void)
++static int __init gpio_dev_init(void)
 +{
-+      select_peripheral(PA(8),  PERIPH_B, 0); /* RXD  */
-+      select_peripheral(PA(9),  PERIPH_B, 0); /* TXD  */
-+}
++      int err;
 +
-+static inline void configure_usart1_pins(void)
-+{
-+      select_peripheral(PA(17), PERIPH_A, 0); /* RXD  */
-+      select_peripheral(PA(18), PERIPH_A, 0); /* TXD  */
-+}
++      gpio_dev_class = class_create(THIS_MODULE, "gpio-dev");
++      if (IS_ERR(gpio_dev_class)) {
++              err = PTR_ERR(gpio_dev_class);
++              goto err_class_create;
++      }
 +
-+static inline void configure_usart2_pins(void)
-+{
-+      select_peripheral(PB(26), PERIPH_B, 0); /* RXD  */
-+      select_peripheral(PB(27), PERIPH_B, 0); /* TXD  */
-+}
++      err = alloc_chrdev_region(&gpio_devt, 0, GPIO_DEV_MAX, "gpio");
++      if (err < 0)
++              goto err_alloc_chrdev;
++
++      /* Configfs initialization */
++      config_group_init(&gpio_subsys.su_group);
++      mutex_init(&gpio_subsys.su_mutex);
++      err = configfs_register_subsystem(&gpio_subsys);
++      if (err)
++              goto err_register_subsys;
 +
-+static inline void configure_usart3_pins(void)
++      return 0;
++
++err_register_subsys:
++      unregister_chrdev_region(gpio_devt, GPIO_DEV_MAX);
++err_alloc_chrdev:
++      class_destroy(gpio_dev_class);
++err_class_create:
++      printk(KERN_WARNING "Failed to initialize gpio /dev interface\n");
++      return err;
++}
++late_initcall(gpio_dev_init);
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/hsmc.c avr32-2.6/arch/avr32/mach-at32ap/hsmc.c
+--- linux-2.6.25.6/arch/avr32/mach-at32ap/hsmc.c       2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/mach-at32ap/hsmc.c    2008-06-12 15:09:38.723815860 +0200
+@@ -278,4 +278,4 @@
+ {
+       return platform_driver_register(&hsmc_driver);
+ }
+-arch_initcall(hsmc_init);
++core_initcall(hsmc_init);
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/intc.c avr32-2.6/arch/avr32/mach-at32ap/intc.c
+--- linux-2.6.25.6/arch/avr32/mach-at32ap/intc.c       2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/mach-at32ap/intc.c    2008-06-12 15:09:38.723815860 +0200
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2006 Atmel Corporation
++ * Copyright (C) 2006, 2008 Atmel Corporation
+  *
+  * 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
+@@ -12,15 +12,20 @@
+ #include <linux/interrupt.h>
+ #include <linux/irq.h>
+ #include <linux/platform_device.h>
++#include <linux/sysdev.h>
+-#include <asm/intc.h>
+ #include <asm/io.h>
+ #include "intc.h"
+ struct intc {
+-      void __iomem    *regs;
+-      struct irq_chip chip;
++      void __iomem            *regs;
++      struct irq_chip         chip;
++      struct sys_device       sysdev;
++#ifdef CONFIG_PM
++      unsigned long           suspend_ipr;
++      unsigned long           saved_ipr[64];
++#endif
+ };
+ extern struct platform_device at32_intc0_device;
+@@ -137,6 +142,74 @@
+       panic("Interrupt controller initialization failed!\n");
+ }
++#ifdef CONFIG_PM
++void intc_set_suspend_handler(unsigned long offset)
 +{
-+      select_peripheral(PB(18), PERIPH_B, 0); /* RXD  */
-+      select_peripheral(PB(17), PERIPH_B, 0); /* TXD  */
++      intc0.suspend_ipr = offset;
 +}
 +
-+static struct platform_device *__initdata at32_usarts[4];
-+
-+void __init at32_map_usart(unsigned int hw_id, unsigned int line)
++static int intc_suspend(struct sys_device *sdev, pm_message_t state)
 +{
-+      struct platform_device *pdev;
++      struct intc *intc = container_of(sdev, struct intc, sysdev);
++      int i;
 +
-+      switch (hw_id) {
-+      case 0:
-+              pdev = &atmel_usart0_device;
-+              configure_usart0_pins();
-+              break;
-+      case 1:
-+              pdev = &atmel_usart1_device;
-+              configure_usart1_pins();
-+              break;
-+      case 2:
-+              pdev = &atmel_usart2_device;
-+              configure_usart2_pins();
-+              break;
-+      case 3:
-+              pdev = &atmel_usart3_device;
-+              configure_usart3_pins();
-+              break;
-+      default:
-+              return;
++      if (unlikely(!irqs_disabled())) {
++              pr_err("intc_suspend: called with interrupts enabled\n");
++              return -EINVAL;
 +      }
 +
-+      if (PXSEG(pdev->resource[0].start) == P4SEG) {
-+              /* Addresses in the P4 segment are permanently mapped 1:1 */
-+              struct atmel_uart_data *data = pdev->dev.platform_data;
-+              data->regs = (void __iomem *)pdev->resource[0].start;
++      if (unlikely(!intc->suspend_ipr)) {
++              pr_err("intc_suspend: suspend_ipr not initialized\n");
++              return -EINVAL;
++      }
++
++      for (i = 0; i < 64; i++) {
++              intc->saved_ipr[i] = intc_readl(intc, INTPR0 + 4 * i);
++              intc_writel(intc, INTPR0 + 4 * i, intc->suspend_ipr);
 +      }
 +
-+      pdev->id = line;
-+      at32_usarts[line] = pdev;
++      return 0;
 +}
 +
-+struct platform_device *__init at32_add_device_usart(unsigned int id)
++static int intc_resume(struct sys_device *sdev)
 +{
-+      platform_device_register(at32_usarts[id]);
-+      return at32_usarts[id];
-+}
++      struct intc *intc = container_of(sdev, struct intc, sysdev);
++      int i;
 +
-+struct platform_device *atmel_default_console_device;
++      WARN_ON(!irqs_disabled());
 +
-+void __init at32_setup_serial_console(unsigned int usart_id)
-+{
-+      atmel_default_console_device = at32_usarts[usart_id];
-+}
++      for (i = 0; i < 64; i++)
++              intc_writel(intc, INTPR0 + 4 * i, intc->saved_ipr[i]);
 +
-+/* --------------------------------------------------------------------
-+ *  Ethernet
-+ * -------------------------------------------------------------------- */
++      return 0;
++}
++#else
++#define intc_suspend  NULL
++#define intc_resume   NULL
++#endif
 +
-+#ifdef CONFIG_CPU_AT32AP7000
-+static struct eth_platform_data macb0_data;
-+static struct resource macb0_resource[] = {
-+      PBMEM(0xfff01800),
-+      IRQ(25),
-+};
-+DEFINE_DEV_DATA(macb, 0);
-+DEV_CLK(hclk, macb0, hsb, 8);
-+DEV_CLK(pclk, macb0, pbb, 6);
-+
-+static struct eth_platform_data macb1_data;
-+static struct resource macb1_resource[] = {
-+      PBMEM(0xfff01c00),
-+      IRQ(26),
++static struct sysdev_class intc_class = {
++      .name           = "intc",
++      .suspend        = intc_suspend,
++      .resume         = intc_resume,
 +};
-+DEFINE_DEV_DATA(macb, 1);
-+DEV_CLK(hclk, macb1, hsb, 9);
-+DEV_CLK(pclk, macb1, pbb, 7);
 +
-+struct platform_device *__init
-+at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
++static int __init intc_init_sysdev(void)
 +{
-+      struct platform_device *pdev;
++      int ret;
 +
-+      switch (id) {
-+      case 0:
-+              pdev = &macb0_device;
-+
-+              select_peripheral(PC(3),  PERIPH_A, 0); /* TXD0 */
-+              select_peripheral(PC(4),  PERIPH_A, 0); /* TXD1 */
-+              select_peripheral(PC(7),  PERIPH_A, 0); /* TXEN */
-+              select_peripheral(PC(8),  PERIPH_A, 0); /* TXCK */
-+              select_peripheral(PC(9),  PERIPH_A, 0); /* RXD0 */
-+              select_peripheral(PC(10), PERIPH_A, 0); /* RXD1 */
-+              select_peripheral(PC(13), PERIPH_A, 0); /* RXER */
-+              select_peripheral(PC(15), PERIPH_A, 0); /* RXDV */
-+              select_peripheral(PC(16), PERIPH_A, 0); /* MDC  */
-+              select_peripheral(PC(17), PERIPH_A, 0); /* MDIO */
-+
-+              if (!data->is_rmii) {
-+                      select_peripheral(PC(0),  PERIPH_A, 0); /* COL  */
-+                      select_peripheral(PC(1),  PERIPH_A, 0); /* CRS  */
-+                      select_peripheral(PC(2),  PERIPH_A, 0); /* TXER */
-+                      select_peripheral(PC(5),  PERIPH_A, 0); /* TXD2 */
-+                      select_peripheral(PC(6),  PERIPH_A, 0); /* TXD3 */
-+                      select_peripheral(PC(11), PERIPH_A, 0); /* RXD2 */
-+                      select_peripheral(PC(12), PERIPH_A, 0); /* RXD3 */
-+                      select_peripheral(PC(14), PERIPH_A, 0); /* RXCK */
-+                      select_peripheral(PC(18), PERIPH_A, 0); /* SPD  */
-+              }
-+              break;
++      ret = sysdev_class_register(&intc_class);
++      if (ret)
++              return ret;
 +
-+      case 1:
-+              pdev = &macb1_device;
-+
-+              select_peripheral(PD(13), PERIPH_B, 0);         /* TXD0 */
-+              select_peripheral(PD(14), PERIPH_B, 0);         /* TXD1 */
-+              select_peripheral(PD(11), PERIPH_B, 0);         /* TXEN */
-+              select_peripheral(PD(12), PERIPH_B, 0);         /* TXCK */
-+              select_peripheral(PD(10), PERIPH_B, 0);         /* RXD0 */
-+              select_peripheral(PD(6),  PERIPH_B, 0);         /* RXD1 */
-+              select_peripheral(PD(5),  PERIPH_B, 0);         /* RXER */
-+              select_peripheral(PD(4),  PERIPH_B, 0);         /* RXDV */
-+              select_peripheral(PD(3),  PERIPH_B, 0);         /* MDC  */
-+              select_peripheral(PD(2),  PERIPH_B, 0);         /* MDIO */
-+
-+              if (!data->is_rmii) {
-+                      select_peripheral(PC(19), PERIPH_B, 0); /* COL  */
-+                      select_peripheral(PC(23), PERIPH_B, 0); /* CRS  */
-+                      select_peripheral(PC(26), PERIPH_B, 0); /* TXER */
-+                      select_peripheral(PC(27), PERIPH_B, 0); /* TXD2 */
-+                      select_peripheral(PC(28), PERIPH_B, 0); /* TXD3 */
-+                      select_peripheral(PC(29), PERIPH_B, 0); /* RXD2 */
-+                      select_peripheral(PC(30), PERIPH_B, 0); /* RXD3 */
-+                      select_peripheral(PC(24), PERIPH_B, 0); /* RXCK */
-+                      select_peripheral(PD(15), PERIPH_B, 0); /* SPD  */
-+              }
-+              break;
++      intc0.sysdev.id = 0;
++      intc0.sysdev.cls = &intc_class;
++      ret = sysdev_register(&intc0.sysdev);
 +
-+      default:
-+              return NULL;
-+      }
++      return ret;
++}
++device_initcall(intc_init_sysdev);
 +
-+      memcpy(pdev->dev.platform_data, data, sizeof(struct eth_platform_data));
-+      platform_device_register(pdev);
+ unsigned long intc_get_pending(unsigned int group)
+ {
+       return intc_readl(&intc0, INTREQ0 + 4 * group);
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/Kconfig avr32-2.6/arch/avr32/mach-at32ap/Kconfig
+--- linux-2.6.25.6/arch/avr32/mach-at32ap/Kconfig      2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/mach-at32ap/Kconfig   2008-06-12 15:09:38.719815350 +0200
+@@ -26,6 +26,13 @@
+ endchoice
++config GPIO_DEV
++      bool "GPIO /dev interface"
++      select CONFIGFS_FS
++      default n
++      help
++        Say `Y' to enable a /dev interface to the GPIO pins.
 +
-+      return pdev;
-+}
-+#endif
+ endmenu
+ endif # PLATFORM_AT32AP
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/Makefile avr32-2.6/arch/avr32/mach-at32ap/Makefile
+--- linux-2.6.25.6/arch/avr32/mach-at32ap/Makefile     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/mach-at32ap/Makefile  2008-06-12 15:09:38.719815350 +0200
+@@ -1,4 +1,9 @@
+-obj-y                         += at32ap.o clock.o intc.o extint.o pio.o hsmc.o
+-obj-$(CONFIG_CPU_AT32AP700X)  += at32ap700x.o
+-obj-$(CONFIG_CPU_AT32AP700X)  += time-tc.o
++obj-y                         += pdc.o clock.o intc.o extint.o pio.o hsmc.o
++obj-$(CONFIG_CPU_AT32AP700X)  += at32ap700x.o pm-at32ap700x.o
+ obj-$(CONFIG_CPU_FREQ_AT32AP) += cpufreq.o
++obj-$(CONFIG_GPIO_DEV)                += gpio-dev.o
++obj-$(CONFIG_PM)              += pm.o
 +
-+/* --------------------------------------------------------------------
-+ *  SPI
-+ * -------------------------------------------------------------------- */
-+static struct resource atmel_spi0_resource[] = {
-+      PBMEM(0xffe00000),
-+      IRQ(3),
-+};
-+DEFINE_DEV(atmel_spi, 0);
-+DEV_CLK(spi_clk, atmel_spi0, pba, 0);
++ifeq ($(CONFIG_PM_DEBUG),y)
++CFLAGS_pm.o   += -DDEBUG
++endif
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/pdc.c avr32-2.6/arch/avr32/mach-at32ap/pdc.c
+--- linux-2.6.25.6/arch/avr32/mach-at32ap/pdc.c        1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/arch/avr32/mach-at32ap/pdc.c     2008-06-12 15:09:38.723815860 +0200
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2006 Atmel Corporation
++ *
++ * 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.
++ */
 +
-+static struct resource atmel_spi1_resource[] = {
-+      PBMEM(0xffe00400),
-+      IRQ(4),
-+};
-+DEFINE_DEV(atmel_spi, 1);
-+DEV_CLK(spi_clk, atmel_spi1, pba, 1);
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
 +
-+static void __init
-+at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b,
-+                    unsigned int n, const u8 *pins)
++static int __init pdc_probe(struct platform_device *pdev)
 +{
-+      unsigned int pin, mode;
++      struct clk *pclk, *hclk;
 +
-+      for (; n; n--, b++) {
-+              b->bus_num = bus_num;
-+              if (b->chip_select >= 4)
-+                      continue;
-+              pin = (unsigned)b->controller_data;
-+              if (!pin) {
-+                      pin = pins[b->chip_select];
-+                      b->controller_data = (void *)pin;
-+              }
-+              mode = AT32_GPIOF_OUTPUT;
-+              if (!(b->mode & SPI_CS_HIGH))
-+                      mode |= AT32_GPIOF_HIGH;
-+              at32_select_gpio(pin, mode);
-+      }
-+}
-+
-+struct platform_device *__init
-+at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
-+{
-+      /*
-+       * Manage the chipselects as GPIOs, normally using the same pins
-+       * the SPI controller expects; but boards can use other pins.
-+       */
-+      static u8 __initdata spi0_pins[] =
-+              { GPIO_PIN_PA(3), GPIO_PIN_PA(4),
-+                GPIO_PIN_PA(5), GPIO_PIN_PA(20), };
-+      static u8 __initdata spi1_pins[] =
-+              { GPIO_PIN_PB(2), GPIO_PIN_PB(3),
-+                GPIO_PIN_PB(4), GPIO_PIN_PA(27), };
-+      struct platform_device *pdev;
-+
-+      switch (id) {
-+      case 0:
-+              pdev = &atmel_spi0_device;
-+              select_peripheral(PA(0),  PERIPH_A, 0); /* MISO  */
-+              select_peripheral(PA(1),  PERIPH_A, 0); /* MOSI  */
-+              select_peripheral(PA(2),  PERIPH_A, 0); /* SCK   */
-+              at32_spi_setup_slaves(0, b, n, spi0_pins);
-+              break;
-+
-+      case 1:
-+              pdev = &atmel_spi1_device;
-+              select_peripheral(PB(0),  PERIPH_B, 0); /* MISO  */
-+              select_peripheral(PB(1),  PERIPH_B, 0); /* MOSI  */
-+              select_peripheral(PB(5),  PERIPH_B, 0); /* SCK   */
-+              at32_spi_setup_slaves(1, b, n, spi1_pins);
-+              break;
-+
-+      default:
-+              return NULL;
++      pclk = clk_get(&pdev->dev, "pclk");
++      if (IS_ERR(pclk)) {
++              dev_err(&pdev->dev, "no pclk defined\n");
++              return PTR_ERR(pclk);
++      }
++      hclk = clk_get(&pdev->dev, "hclk");
++      if (IS_ERR(hclk)) {
++              dev_err(&pdev->dev, "no hclk defined\n");
++              clk_put(pclk);
++              return PTR_ERR(hclk);
 +      }
 +
-+      spi_register_board_info(b, n);
-+      platform_device_register(pdev);
-+      return pdev;
++      clk_enable(pclk);
++      clk_enable(hclk);
++
++      dev_info(&pdev->dev, "Atmel Peripheral DMA Controller enabled\n");
++      return 0;
 +}
 +
-+/* --------------------------------------------------------------------
-+ *  TWI
-+ * -------------------------------------------------------------------- */
-+static struct resource atmel_twi0_resource[] __initdata = {
-+      PBMEM(0xffe00800),
-+      IRQ(5),
-+};
-+static struct clk atmel_twi0_pclk = {
-+      .name           = "twi_pclk",
-+      .parent         = &pba_clk,
-+      .mode           = pba_clk_mode,
-+      .get_rate       = pba_clk_get_rate,
-+      .index          = 2,
++static struct platform_driver pdc_driver = {
++      .probe          = pdc_probe,
++      .driver         = {
++              .name   = "pdc",
++      },
 +};
 +
-+struct platform_device *__init at32_add_device_twi(unsigned int id,
-+                                                  struct i2c_board_info *b,
-+                                                  unsigned int n)
++static int __init pdc_init(void)
 +{
-+      struct platform_device *pdev;
-+
-+      if (id != 0)
-+              return NULL;
++      return platform_driver_register(&pdc_driver);
++}
++arch_initcall(pdc_init);
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/pio.c avr32-2.6/arch/avr32/mach-at32ap/pio.c
+--- linux-2.6.25.6/arch/avr32/mach-at32ap/pio.c        2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/mach-at32ap/pio.c     2008-06-12 15:09:38.723815860 +0200
+@@ -157,6 +157,82 @@
+       dump_stack();
+ }
++#ifdef CONFIG_GPIO_DEV
 +
-+      pdev = platform_device_alloc("atmel_twi", id);
-+      if (!pdev)
-+              return NULL;
++/* Gang allocators and accessors; used by the GPIO /dev driver */
++int at32_gpio_port_is_valid(unsigned int port)
++{
++      return port < MAX_NR_PIO_DEVICES && pio_dev[port].regs != NULL;
++}
 +
-+      if (platform_device_add_resources(pdev, atmel_twi0_resource,
-+                              ARRAY_SIZE(atmel_twi0_resource)))
-+              goto err_add_resources;
++int at32_select_gpio_pins(unsigned int port, u32 pins, u32 oe_mask)
++{
++      struct pio_device *pio;
++      u32 old, new;
 +
-+      select_peripheral(PA(6),  PERIPH_A, 0); /* SDA  */
-+      select_peripheral(PA(7),  PERIPH_A, 0); /* SDL  */
++      pio = &pio_dev[port];
++      BUG_ON(port > ARRAY_SIZE(pio_dev) || !pio->regs || (oe_mask & ~pins));
 +
-+      atmel_twi0_pclk.dev = &pdev->dev;
++      /* Try to allocate the pins */
++      do {
++              old = pio->pinmux_mask;
++              if (old & pins)
++                      return -EBUSY;
 +
-+      if (b)
-+              i2c_register_board_info(id, b, n);
++              new = old | pins;
++      } while (cmpxchg(&pio->pinmux_mask, old, new) != old);
 +
-+      platform_device_add(pdev);
-+      return pdev;
++      /* That went well, now configure the port */
++      pio_writel(pio, OER, oe_mask);
++      pio_writel(pio, PER, pins);
 +
-+err_add_resources:
-+      platform_device_put(pdev);
-+      return NULL;
++      return 0;
 +}
 +
-+/* --------------------------------------------------------------------
-+ * MMC
-+ * -------------------------------------------------------------------- */
-+static struct resource atmel_mci0_resource[] __initdata = {
-+      PBMEM(0xfff02400),
-+      IRQ(28),
-+};
-+static struct clk atmel_mci0_pclk = {
-+      .name           = "mci_clk",
-+      .parent         = &pbb_clk,
-+      .mode           = pbb_clk_mode,
-+      .get_rate       = pbb_clk_get_rate,
-+      .index          = 9,
-+};
-+
-+struct platform_device *__init
-+at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
++void at32_deselect_pins(unsigned int port, u32 pins)
 +{
-+      struct platform_device *pdev;
-+
-+      if (id != 0)
-+              return NULL;
-+
-+      pdev = platform_device_alloc("atmel_mci", id);
-+      if (!pdev)
-+              goto fail;
-+
-+      if (platform_device_add_resources(pdev, atmel_mci0_resource,
-+                              ARRAY_SIZE(atmel_mci0_resource)))
-+              goto fail;
++      struct pio_device *pio;
++      u32 old, new;
 +
-+      if (data && platform_device_add_data(pdev, data,
-+                              sizeof(struct mci_platform_data)))
-+              goto fail;
++      pio = &pio_dev[port];
++      BUG_ON(port > ARRAY_SIZE(pio_dev) || !pio->regs);
 +
-+      select_peripheral(PA(10), PERIPH_A, 0); /* CLK   */
-+      select_peripheral(PA(11), PERIPH_A, 0); /* CMD   */
-+      select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */
-+      select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */
-+      select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */
-+      select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */
++      /* Return to a "safe" mux configuration */
++      pio_writel(pio, PUER, pins);
++      pio_writel(pio, ODR, pins);
 +
-+      if (data) {
-+              if (data->detect_pin != GPIO_PIN_NONE)
-+                      at32_select_gpio(data->detect_pin, 0);
-+              if (data->wp_pin != GPIO_PIN_NONE)
-+                      at32_select_gpio(data->wp_pin, 0);
-+      }
++      /* Deallocate the pins */
++      do {
++              old = pio->pinmux_mask;
++              new = old & ~pins;
++      } while (cmpxchg(&pio->pinmux_mask, old, new) != old);
++}
 +
-+      atmel_mci0_pclk.dev = &pdev->dev;
++u32 at32_gpio_get_value_multiple(unsigned int port, u32 pins)
++{
++      struct pio_device *pio;
 +
-+      platform_device_add(pdev);
-+      return pdev;
++      pio = &pio_dev[port];
++      BUG_ON(port > ARRAY_SIZE(pio_dev) || !pio->regs);
 +
-+fail:
-+      platform_device_put(pdev);
-+      return NULL;
++      return pio_readl(pio, PDSR) & pins;
 +}
 +
-+/* --------------------------------------------------------------------
-+ *  LCDC
-+ * -------------------------------------------------------------------- */
-+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002)
-+static struct atmel_lcdfb_info atmel_lcdfb0_data;
-+static struct resource atmel_lcdfb0_resource[] = {
-+      {
-+              .start          = 0xff000000,
-+              .end            = 0xff000fff,
-+              .flags          = IORESOURCE_MEM,
-+      },
-+      IRQ(1),
-+      {
-+              /* Placeholder for pre-allocated fb memory */
-+              .start          = 0x00000000,
-+              .end            = 0x00000000,
-+              .flags          = 0,
-+      },
-+};
-+DEFINE_DEV_DATA(atmel_lcdfb, 0);
-+DEV_CLK(hck1, atmel_lcdfb0, hsb, 7);
-+static struct clk atmel_lcdfb0_pixclk = {
-+      .name           = "lcdc_clk",
-+      .dev            = &atmel_lcdfb0_device.dev,
-+      .mode           = genclk_mode,
-+      .get_rate       = genclk_get_rate,
-+      .set_rate       = genclk_set_rate,
-+      .set_parent     = genclk_set_parent,
-+      .index          = 7,
-+};
-+
-+struct platform_device *__init
-+at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
-+                   unsigned long fbmem_start, unsigned long fbmem_len)
++void at32_gpio_set_value_multiple(unsigned int port, u32 value, u32 mask)
 +{
-+      struct platform_device *pdev;
-+      struct atmel_lcdfb_info *info;
-+      struct fb_monspecs *monspecs;
-+      struct fb_videomode *modedb;
-+      unsigned int modedb_size;
++      struct pio_device *pio;
 +
-+      /*
-+       * Do a deep copy of the fb data, monspecs and modedb. Make
-+       * sure all allocations are done before setting up the
-+       * portmux.
-+       */
-+      monspecs = kmemdup(data->default_monspecs,
-+                         sizeof(struct fb_monspecs), GFP_KERNEL);
-+      if (!monspecs)
-+              return NULL;
++      pio = &pio_dev[port];
++      BUG_ON(port > ARRAY_SIZE(pio_dev) || !pio->regs);
 +
-+      modedb_size = sizeof(struct fb_videomode) * monspecs->modedb_len;
-+      modedb = kmemdup(monspecs->modedb, modedb_size, GFP_KERNEL);
-+      if (!modedb)
-+              goto err_dup_modedb;
-+      monspecs->modedb = modedb;
++      /* No atomic updates for now... */
++      pio_writel(pio, CODR, ~value & mask);
++      pio_writel(pio, SODR, value & mask);
++}
 +
-+      switch (id) {
-+      case 0:
-+              pdev = &atmel_lcdfb0_device;
-+              select_peripheral(PC(19), PERIPH_A, 0); /* CC     */
-+              select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
-+              select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
-+              select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC  */
-+              select_peripheral(PC(23), PERIPH_A, 0); /* DVAL   */
-+              select_peripheral(PC(24), PERIPH_A, 0); /* MODE   */
-+              select_peripheral(PC(25), PERIPH_A, 0); /* PWR    */
-+              select_peripheral(PC(26), PERIPH_A, 0); /* DATA0  */
-+              select_peripheral(PC(27), PERIPH_A, 0); /* DATA1  */
-+              select_peripheral(PC(28), PERIPH_A, 0); /* DATA2  */
-+              select_peripheral(PC(29), PERIPH_A, 0); /* DATA3  */
-+              select_peripheral(PC(30), PERIPH_A, 0); /* DATA4  */
-+              select_peripheral(PC(31), PERIPH_A, 0); /* DATA5  */
-+              select_peripheral(PD(0),  PERIPH_A, 0); /* DATA6  */
-+              select_peripheral(PD(1),  PERIPH_A, 0); /* DATA7  */
-+              select_peripheral(PD(2),  PERIPH_A, 0); /* DATA8  */
-+              select_peripheral(PD(3),  PERIPH_A, 0); /* DATA9  */
-+              select_peripheral(PD(4),  PERIPH_A, 0); /* DATA10 */
-+              select_peripheral(PD(5),  PERIPH_A, 0); /* DATA11 */
-+              select_peripheral(PD(6),  PERIPH_A, 0); /* DATA12 */
-+              select_peripheral(PD(7),  PERIPH_A, 0); /* DATA13 */
-+              select_peripheral(PD(8),  PERIPH_A, 0); /* DATA14 */
-+              select_peripheral(PD(9),  PERIPH_A, 0); /* DATA15 */
-+              select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
-+              select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
-+              select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
-+              select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
-+              select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
-+              select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
-+              select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
-+              select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
-+
-+              clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
-+              clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
-+              break;
++#endif /* CONFIG_GPIO_DEV */
 +
-+      default:
-+              goto err_invalid_id;
-+      }
 +
-+      if (fbmem_len) {
-+              pdev->resource[2].start = fbmem_start;
-+              pdev->resource[2].end = fbmem_start + fbmem_len - 1;
-+              pdev->resource[2].flags = IORESOURCE_MEM;
-+      }
+ /*--------------------------------------------------------------------------*/
+ /* GPIO API */
+@@ -318,6 +394,8 @@
+               const char *label;
+               label = gpiochip_is_requested(chip, i);
++              if (!label && (imr & mask))
++                      label = "[irq]";
+               if (!label)
+                       continue;
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/pm-at32ap700x.S avr32-2.6/arch/avr32/mach-at32ap/pm-at32ap700x.S
+--- linux-2.6.25.6/arch/avr32/mach-at32ap/pm-at32ap700x.S      1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/arch/avr32/mach-at32ap/pm-at32ap700x.S   2008-06-12 15:09:38.723815860 +0200
+@@ -0,0 +1,174 @@
++/*
++ * Low-level Power Management code.
++ *
++ * Copyright (C) 2008 Atmel Corporation
++ *
++ * 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 <asm/asm.h>
++#include <asm/asm-offsets.h>
++#include <asm/thread_info.h>
++#include <asm/arch/pm.h>
 +
-+      info = pdev->dev.platform_data;
-+      memcpy(info, data, sizeof(struct atmel_lcdfb_info));
-+      info->default_monspecs = monspecs;
++#include "pm.h"
++#include "sdramc.h"
 +
-+      platform_device_register(pdev);
-+      return pdev;
++/* Same as 0xfff00000 but fits in a 21 bit signed immediate */
++#define PM_BASE       -0x100000
 +
-+err_invalid_id:
-+      kfree(modedb);
-+err_dup_modedb:
-+      kfree(monspecs);
-+      return NULL;
-+}
-+#endif
++      .section .bss, "wa", @nobits
++      .global disable_idle_sleep
++      .type   disable_idle_sleep, @object
++disable_idle_sleep:
++      .int    4
++      .size   disable_idle_sleep, . - disable_idle_sleep
 +
-+/* --------------------------------------------------------------------
-+ *  PWM
-+ * -------------------------------------------------------------------- */
-+static struct resource atmel_pwm0_resource[] __initdata = {
-+      PBMEM(0xfff01400),
-+      IRQ(24),
-+};
-+static struct clk atmel_pwm0_mck = {
-+      .name           = "mck",
-+      .parent         = &pbb_clk,
-+      .mode           = pbb_clk_mode,
-+      .get_rate       = pbb_clk_get_rate,
-+      .index          = 5,
-+};
++      /* Keep this close to the irq handlers */
++      .section .irq.text, "ax", @progbits
 +
-+struct platform_device *__init at32_add_device_pwm(u32 mask)
-+{
-+      struct platform_device *pdev;
++      /*
++       * void cpu_enter_idle(void)
++       *
++       * Put the CPU into "idle" mode, in which it will consume
++       * significantly less power.
++       *
++       * If an interrupt comes along in the window between
++       * unmask_interrupts and the sleep instruction below, the
++       * interrupt code will adjust the return address so that we
++       * never execute the sleep instruction. This is required
++       * because the AP7000 doesn't unmask interrupts when entering
++       * sleep modes; later CPUs may not need this workaround.
++       */
++      .global cpu_enter_idle
++      .type   cpu_enter_idle, @function
++cpu_enter_idle:
++      mask_interrupts
++      get_thread_info r8
++      ld.w    r9, r8[TI_flags]
++      bld     r9, TIF_NEED_RESCHED
++      brcs    .Lret_from_sleep
++      sbr     r9, TIF_CPU_GOING_TO_SLEEP
++      st.w    r8[TI_flags], r9
++      unmask_interrupts
++      sleep   CPU_SLEEP_IDLE
++      .size   cpu_idle_sleep, . - cpu_idle_sleep
 +
-+      if (!mask)
-+              return NULL;
++      /*
++       * Common return path for PM functions that don't run from
++       * SRAM.
++       */
++      .global cpu_idle_skip_sleep
++      .type   cpu_idle_skip_sleep, @function
++cpu_idle_skip_sleep:
++      mask_interrupts
++      ld.w    r9, r8[TI_flags]
++      cbr     r9, TIF_CPU_GOING_TO_SLEEP
++      st.w    r8[TI_flags], r9
++.Lret_from_sleep:
++      unmask_interrupts
++      retal   r12
++      .size   cpu_idle_skip_sleep, . - cpu_idle_skip_sleep
 +
-+      pdev = platform_device_alloc("atmel_pwm", 0);
-+      if (!pdev)
-+              return NULL;
++#ifdef CONFIG_PM
++      .section .init.text, "ax", @progbits
 +
-+      if (platform_device_add_resources(pdev, atmel_pwm0_resource,
-+                              ARRAY_SIZE(atmel_pwm0_resource)))
-+              goto out_free_pdev;
++      .global pm_exception
++      .type   pm_exception, @function
++pm_exception:
++      /*
++       * Exceptions are masked when we switch to this handler, so
++       * we'll only get "unrecoverable" exceptions (offset 0.)
++       */
++      sub     r12, pc, . - .Lpanic_msg
++      lddpc   pc, .Lpanic_addr
++
++      .align  2
++.Lpanic_addr:
++      .long   panic
++.Lpanic_msg:
++      .asciz  "Unrecoverable exception during suspend\n"
++      .size   pm_exception, . - pm_exception
++
++      .global pm_irq0
++      .type   pm_irq0, @function
++pm_irq0:
++      /* Disable interrupts and return after the sleep instruction */
++      mfsr    r9, SYSREG_RSR_INT0
++      mtsr    SYSREG_RAR_INT0, r8
++      sbr     r9, SYSREG_GM_OFFSET
++      mtsr    SYSREG_RSR_INT0, r9
++      rete
 +
-+      if (platform_device_add_data(pdev, &mask, sizeof(mask)))
-+              goto out_free_pdev;
++      /*
++       * void cpu_enter_standby(unsigned long sdramc_base)
++       *
++       * Enter PM_SUSPEND_STANDBY mode. At this point, all drivers
++       * are suspended and interrupts are disabled. Interrupts
++       * marked as 'wakeup' event sources may still come along and
++       * get us out of here.
++       *
++       * The SDRAM will be put into self-refresh mode (which does
++       * not require a clock from the CPU), and the CPU will be put
++       * into "frozen" mode (HSB bus stopped). The SDRAM controller
++       * will automatically bring the SDRAM into normal mode on the
++       * first access, and the power manager will automatically
++       * start the HSB and CPU clocks upon a wakeup event.
++       *
++       * This code uses the same "skip sleep" technique as above.
++       * It is very important that we jump directly to
++       * cpu_after_sleep after the sleep instruction since that's
++       * where we'll end up if the interrupt handler decides that we
++       * need to skip the sleep instruction.
++       */
++      .global pm_standby
++      .type   pm_standby, @function
++pm_standby:
++      /*
++       * interrupts are already masked at this point, and EVBA
++       * points to pm_exception above.
++       */
++      ld.w    r10, r12[SDRAMC_LPR]
++      sub     r8, pc, . - 1f          /* return address for irq handler */
++      mov     r11, SDRAMC_LPR_LPCB_SELF_RFR
++      bfins   r10, r11, 0, 2          /* LPCB <- self Refresh */
++      sync    0                       /* flush write buffer */
++      st.w    r12[SDRAMC_LPR], r11    /* put SDRAM in self-refresh mode */
++      ld.w    r11, r12[SDRAMC_LPR]
++      unmask_interrupts
++      sleep   CPU_SLEEP_FROZEN
++1:    mask_interrupts
++      retal   r12
++      .size   pm_standby, . - pm_standby
 +
-+      if (mask & (1 << 0))
-+              select_peripheral(PA(28), PERIPH_A, 0);
-+      if (mask & (1 << 1))
-+              select_peripheral(PA(29), PERIPH_A, 0);
-+      if (mask & (1 << 2))
-+              select_peripheral(PA(21), PERIPH_B, 0);
-+      if (mask & (1 << 3))
-+              select_peripheral(PA(22), PERIPH_B, 0);
++      .global pm_suspend_to_ram
++      .type   pm_suspend_to_ram, @function
++pm_suspend_to_ram:
++      /*
++       * interrupts are already masked at this point, and EVBA
++       * points to pm_exception above.
++       */
++      mov     r11, 0
++      cache   r11[2], 8               /* clean all dcache lines */
++      sync    0                       /* flush write buffer */
++      ld.w    r10, r12[SDRAMC_LPR]
++      sub     r8, pc, . - 1f          /* return address for irq handler */
++      mov     r11, SDRAMC_LPR_LPCB_SELF_RFR
++      bfins   r10, r11, 0, 2          /* LPCB <- self refresh */
++      st.w    r12[SDRAMC_LPR], r10    /* put SDRAM in self-refresh mode */
++      ld.w    r11, r12[SDRAMC_LPR]
 +
-+      atmel_pwm0_mck.dev = &pdev->dev;
++      unmask_interrupts
++      sleep   CPU_SLEEP_STOP
++1:    mask_interrupts
 +
-+      platform_device_add(pdev);
-+
-+      return pdev;
-+
-+out_free_pdev:
-+      platform_device_put(pdev);
-+      return NULL;
-+}
++      retal   r12
++      .size   pm_suspend_to_ram, . - pm_suspend_to_ram
++
++      .global pm_sram_end
++      .type   pm_sram_end, @function
++pm_sram_end:
++      .size   pm_sram_end, 0
++
++#endif /* CONFIG_PM */
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/pm.c avr32-2.6/arch/avr32/mach-at32ap/pm.c
+--- linux-2.6.25.6/arch/avr32/mach-at32ap/pm.c 1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/arch/avr32/mach-at32ap/pm.c      2008-06-12 15:09:38.723815860 +0200
+@@ -0,0 +1,245 @@
++/*
++ * AVR32 AP Power Management
++ *
++ * Copyright (C) 2008 Atmel Corporation
++ *
++ * 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/io.h>
++#include <linux/suspend.h>
++#include <linux/vmalloc.h>
 +
-+/* --------------------------------------------------------------------
-+ *  SSC
-+ * -------------------------------------------------------------------- */
-+static struct resource ssc0_resource[] = {
-+      PBMEM(0xffe01c00),
-+      IRQ(10),
-+};
-+DEFINE_DEV(ssc, 0);
-+DEV_CLK(pclk, ssc0, pba, 7);
++#include <asm/cacheflush.h>
++#include <asm/sysreg.h>
 +
-+static struct resource ssc1_resource[] = {
-+      PBMEM(0xffe02000),
-+      IRQ(11),
-+};
-+DEFINE_DEV(ssc, 1);
-+DEV_CLK(pclk, ssc1, pba, 8);
++#include <asm/arch/pm.h>
++#include <asm/arch/sram.h>
 +
-+static struct resource ssc2_resource[] = {
-+      PBMEM(0xffe02400),
-+      IRQ(12),
-+};
-+DEFINE_DEV(ssc, 2);
-+DEV_CLK(pclk, ssc2, pba, 9);
++/* FIXME: This is only valid for AP7000 */
++#define SDRAMC_BASE   0xfff03800
 +
-+struct platform_device *__init
-+at32_add_device_ssc(unsigned int id, unsigned int flags)
-+{
-+      struct platform_device *pdev;
++#include "sdramc.h"
 +
-+      switch (id) {
-+      case 0:
-+              pdev = &ssc0_device;
-+              if (flags & ATMEL_SSC_RF)
-+                      select_peripheral(PA(21), PERIPH_A, 0); /* RF */
-+              if (flags & ATMEL_SSC_RK)
-+                      select_peripheral(PA(22), PERIPH_A, 0); /* RK */
-+              if (flags & ATMEL_SSC_TK)
-+                      select_peripheral(PA(23), PERIPH_A, 0); /* TK */
-+              if (flags & ATMEL_SSC_TF)
-+                      select_peripheral(PA(24), PERIPH_A, 0); /* TF */
-+              if (flags & ATMEL_SSC_TD)
-+                      select_peripheral(PA(25), PERIPH_A, 0); /* TD */
-+              if (flags & ATMEL_SSC_RD)
-+                      select_peripheral(PA(26), PERIPH_A, 0); /* RD */
-+              break;
-+      case 1:
-+              pdev = &ssc1_device;
-+              if (flags & ATMEL_SSC_RF)
-+                      select_peripheral(PA(0), PERIPH_B, 0);  /* RF */
-+              if (flags & ATMEL_SSC_RK)
-+                      select_peripheral(PA(1), PERIPH_B, 0);  /* RK */
-+              if (flags & ATMEL_SSC_TK)
-+                      select_peripheral(PA(2), PERIPH_B, 0);  /* TK */
-+              if (flags & ATMEL_SSC_TF)
-+                      select_peripheral(PA(3), PERIPH_B, 0);  /* TF */
-+              if (flags & ATMEL_SSC_TD)
-+                      select_peripheral(PA(4), PERIPH_B, 0);  /* TD */
-+              if (flags & ATMEL_SSC_RD)
-+                      select_peripheral(PA(5), PERIPH_B, 0);  /* RD */
-+              break;
-+      case 2:
-+              pdev = &ssc2_device;
-+              if (flags & ATMEL_SSC_TD)
-+                      select_peripheral(PB(13), PERIPH_A, 0); /* TD */
-+              if (flags & ATMEL_SSC_RD)
-+                      select_peripheral(PB(14), PERIPH_A, 0); /* RD */
-+              if (flags & ATMEL_SSC_TK)
-+                      select_peripheral(PB(15), PERIPH_A, 0); /* TK */
-+              if (flags & ATMEL_SSC_TF)
-+                      select_peripheral(PB(16), PERIPH_A, 0); /* TF */
-+              if (flags & ATMEL_SSC_RF)
-+                      select_peripheral(PB(17), PERIPH_A, 0); /* RF */
-+              if (flags & ATMEL_SSC_RK)
-+                      select_peripheral(PB(18), PERIPH_A, 0); /* RK */
-+              break;
-+      default:
-+              return NULL;
-+      }
++#define SRAM_PAGE_FLAGS       (SYSREG_BIT(TLBELO_D) | SYSREG_BF(SZ, 1)        \
++                              | SYSREG_BF(AP, 3) | SYSREG_BIT(G))
 +
-+      platform_device_register(pdev);
-+      return pdev;
-+}
 +
-+/* --------------------------------------------------------------------
-+ *  USB Device Controller
-+ * -------------------------------------------------------------------- */
-+static struct resource usba0_resource[] __initdata = {
-+      {
-+              .start          = 0xff300000,
-+              .end            = 0xff3fffff,
-+              .flags          = IORESOURCE_MEM,
-+      }, {
-+              .start          = 0xfff03000,
-+              .end            = 0xfff033ff,
-+              .flags          = IORESOURCE_MEM,
-+      },
-+      IRQ(31),
-+};
-+static struct clk usba0_pclk = {
-+      .name           = "pclk",
-+      .parent         = &pbb_clk,
-+      .mode           = pbb_clk_mode,
-+      .get_rate       = pbb_clk_get_rate,
-+      .index          = 12,
-+};
-+static struct clk usba0_hclk = {
-+      .name           = "hclk",
-+      .parent         = &hsb_clk,
-+      .mode           = hsb_clk_mode,
-+      .get_rate       = hsb_clk_get_rate,
-+      .index          = 6,
-+};
++static unsigned long  pm_sram_start;
++static size_t         pm_sram_size;
++static struct vm_struct       *pm_sram_area;
 +
-+#define EP(nam, idx, maxpkt, maxbk, dma, isoc)                        \
-+      [idx] = {                                               \
-+              .name           = nam,                          \
-+              .index          = idx,                          \
-+              .fifo_size      = maxpkt,                       \
-+              .nr_banks       = maxbk,                        \
-+              .can_dma        = dma,                          \
-+              .can_isoc       = isoc,                         \
-+      }
++static void (*avr32_pm_enter_standby)(unsigned long sdramc_base);
++static void (*avr32_pm_enter_str)(unsigned long sdramc_base);
 +
-+static struct usba_ep_data at32_usba_ep[] __initdata = {
-+      EP("ep0",     0,   64, 1, 0, 0),
-+      EP("ep1",     1,  512, 2, 1, 1),
-+      EP("ep2",     2,  512, 2, 1, 1),
-+      EP("ep3-int", 3,   64, 3, 1, 0),
-+      EP("ep4-int", 4,   64, 3, 1, 0),
-+      EP("ep5",     5, 1024, 3, 1, 1),
-+      EP("ep6",     6, 1024, 3, 1, 1),
-+};
++/*
++ * Must be called with interrupts disabled. Exceptions will be masked
++ * on return (i.e. all exceptions will be "unrecoverable".)
++ */
++static void *avr32_pm_map_sram(void)
++{
++      unsigned long   vaddr;
++      unsigned long   page_addr;
++      u32             tlbehi;
++      u32             mmucr;
 +
-+#undef EP
++      vaddr = (unsigned long)pm_sram_area->addr;
++      page_addr = pm_sram_start & PAGE_MASK;
 +
-+struct platform_device *__init
-+at32_add_device_usba(unsigned int id, struct usba_platform_data *data)
-+{
 +      /*
-+       * pdata doesn't have room for any endpoints, so we need to
-+       * append room for the ones we need right after it.
++       * Mask exceptions and grab the first TLB entry. We won't be
++       * needing it while sleeping.
 +       */
-+      struct {
-+              struct usba_platform_data pdata;
-+              struct usba_ep_data ep[7];
-+      } usba_data;
-+      struct platform_device *pdev;
-+
-+      if (id != 0)
-+              return NULL;
-+
-+      pdev = platform_device_alloc("atmel_usba_udc", 0);
-+      if (!pdev)
-+              return NULL;
-+
-+      if (platform_device_add_resources(pdev, usba0_resource,
-+                                        ARRAY_SIZE(usba0_resource)))
-+              goto out_free_pdev;
-+
-+      if (data)
-+              usba_data.pdata.vbus_pin = data->vbus_pin;
-+      else
-+              usba_data.pdata.vbus_pin = -EINVAL;
-+
-+      data = &usba_data.pdata;
-+      data->num_ep = ARRAY_SIZE(at32_usba_ep);
-+      memcpy(data->ep, at32_usba_ep, sizeof(at32_usba_ep));
-+
-+      if (platform_device_add_data(pdev, data, sizeof(usba_data)))
-+              goto out_free_pdev;
-+
-+      if (data->vbus_pin >= 0)
-+              at32_select_gpio(data->vbus_pin, 0);
++      asm volatile("ssrf      %0" : : "i"(SYSREG_EM_OFFSET) : "memory");
 +
-+      usba0_pclk.dev = &pdev->dev;
-+      usba0_hclk.dev = &pdev->dev;
++      mmucr = sysreg_read(MMUCR);
++      tlbehi = sysreg_read(TLBEHI);
++      sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr));
 +
-+      platform_device_add(pdev);
++      tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
++      tlbehi |= vaddr & PAGE_MASK;
++      tlbehi |= SYSREG_BIT(TLBEHI_V);
 +
-+      return pdev;
++      sysreg_write(TLBELO, page_addr | SRAM_PAGE_FLAGS);
++      sysreg_write(TLBEHI, tlbehi);
++      __builtin_tlbw();
 +
-+out_free_pdev:
-+      platform_device_put(pdev);
-+      return NULL;
++      return (void *)(vaddr + pm_sram_start - page_addr);
 +}
 +
-+/* --------------------------------------------------------------------
-+ * IDE / CompactFlash
-+ * -------------------------------------------------------------------- */
-+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7001)
-+static struct resource at32_smc_cs4_resource[] __initdata = {
-+      {
-+              .start  = 0x04000000,
-+              .end    = 0x07ffffff,
-+              .flags  = IORESOURCE_MEM,
-+      },
-+      IRQ(~0UL), /* Magic IRQ will be overridden */
-+};
-+static struct resource at32_smc_cs5_resource[] __initdata = {
-+      {
-+              .start  = 0x20000000,
-+              .end    = 0x23ffffff,
-+              .flags  = IORESOURCE_MEM,
-+      },
-+      IRQ(~0UL), /* Magic IRQ will be overridden */
-+};
-+
-+static int __init at32_init_ide_or_cf(struct platform_device *pdev,
-+              unsigned int cs, unsigned int extint)
++/*
++ * Must be called with interrupts disabled. Exceptions will be
++ * unmasked on return.
++ */
++static void avr32_pm_unmap_sram(void)
 +{
-+      static unsigned int extint_pin_map[4] __initdata = {
-+              GPIO_PIN_PB(25),
-+              GPIO_PIN_PB(26),
-+              GPIO_PIN_PB(27),
-+              GPIO_PIN_PB(28),
-+      };
-+      static bool common_pins_initialized __initdata = false;
-+      unsigned int extint_pin;
-+      int ret;
-+
-+      if (extint >= ARRAY_SIZE(extint_pin_map))
-+              return -EINVAL;
-+      extint_pin = extint_pin_map[extint];
-+
-+      switch (cs) {
-+      case 4:
-+              ret = platform_device_add_resources(pdev,
-+                              at32_smc_cs4_resource,
-+                              ARRAY_SIZE(at32_smc_cs4_resource));
-+              if (ret)
-+                      return ret;
-+
-+              select_peripheral(PE(21), PERIPH_A, 0); /* NCS4   -> OE_N  */
-+              set_ebi_sfr_bits(HMATRIX_BIT(CS4A));
-+              break;
-+      case 5:
-+              ret = platform_device_add_resources(pdev,
-+                              at32_smc_cs5_resource,
-+                              ARRAY_SIZE(at32_smc_cs5_resource));
-+              if (ret)
-+                      return ret;
++      u32     mmucr;
++      u32     tlbehi;
++      u32     tlbarlo;
 +
-+              select_peripheral(PE(22), PERIPH_A, 0); /* NCS5   -> OE_N  */
-+              set_ebi_sfr_bits(HMATRIX_BIT(CS5A));
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
++      /* Going to update TLB entry at index 0 */
++      mmucr = sysreg_read(MMUCR);
++      tlbehi = sysreg_read(TLBEHI);
++      sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr));
 +
-+      if (!common_pins_initialized) {
-+              select_peripheral(PE(19), PERIPH_A, 0); /* CFCE1  -> CS0_N */
-+              select_peripheral(PE(20), PERIPH_A, 0); /* CFCE2  -> CS1_N */
-+              select_peripheral(PE(23), PERIPH_A, 0); /* CFRNW  -> DIR   */
-+              select_peripheral(PE(24), PERIPH_A, 0); /* NWAIT  <- IORDY */
-+              common_pins_initialized = true;
-+      }
++      /* Clear the "valid" bit */
++      tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
++      sysreg_write(TLBEHI, tlbehi);
 +
-+      at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
++      /* Mark it as "not accessed" */
++      tlbarlo = sysreg_read(TLBARLO);
++      sysreg_write(TLBARLO, tlbarlo | 0x80000000U);
 +
-+      pdev->resource[1].start = EIM_IRQ_BASE + extint;
-+      pdev->resource[1].end = pdev->resource[1].start;
++      /* Update the TLB */
++      __builtin_tlbw();
 +
-+      return 0;
++      /* Unmask exceptions */
++      asm volatile("csrf      %0" : : "i"(SYSREG_EM_OFFSET) : "memory");
 +}
 +
-+struct platform_device *__init
-+at32_add_device_ide(unsigned int id, unsigned int extint,
-+                  struct ide_platform_data *data)
++static int avr32_pm_valid_state(suspend_state_t state)
 +{
-+      struct platform_device *pdev;
-+
-+      pdev = platform_device_alloc("at32_ide", id);
-+      if (!pdev)
-+              goto fail;
-+
-+      if (platform_device_add_data(pdev, data,
-+                              sizeof(struct ide_platform_data)))
-+              goto fail;
-+
-+      if (at32_init_ide_or_cf(pdev, data->cs, extint))
-+              goto fail;
-+
-+      platform_device_add(pdev);
-+      return pdev;
++      switch (state) {
++      case PM_SUSPEND_ON:
++      case PM_SUSPEND_STANDBY:
++      case PM_SUSPEND_MEM:
++              return 1;
 +
-+fail:
-+      platform_device_put(pdev);
-+      return NULL;
++      default:
++              return 0;
++      }
 +}
 +
-+struct platform_device *__init
-+at32_add_device_cf(unsigned int id, unsigned int extint,
-+                  struct cf_platform_data *data)
++static int avr32_pm_enter(suspend_state_t state)
 +{
-+      struct platform_device *pdev;
++      u32             lpr_saved;
++      u32             evba_saved;
++      void            *sram;
 +
-+      pdev = platform_device_alloc("at32_cf", id);
-+      if (!pdev)
-+              goto fail;
-+
-+      if (platform_device_add_data(pdev, data,
-+                              sizeof(struct cf_platform_data)))
-+              goto fail;
++      switch (state) {
++      case PM_SUSPEND_STANDBY:
++              sram = avr32_pm_map_sram();
 +
-+      if (at32_init_ide_or_cf(pdev, data->cs, extint))
-+              goto fail;
++              /* Switch to in-sram exception handlers */
++              evba_saved = sysreg_read(EVBA);
++              sysreg_write(EVBA, (unsigned long)sram);
 +
-+      if (data->detect_pin != GPIO_PIN_NONE)
-+              at32_select_gpio(data->detect_pin, AT32_GPIOF_DEGLITCH);
-+      if (data->reset_pin != GPIO_PIN_NONE)
-+              at32_select_gpio(data->reset_pin, 0);
-+      if (data->vcc_pin != GPIO_PIN_NONE)
-+              at32_select_gpio(data->vcc_pin, 0);
-+      /* READY is used as extint, so we can't select it as gpio */
++              /*
++               * Save the LPR register so that we can re-enable
++               * SDRAM Low Power mode on resume.
++               */
++              lpr_saved = sdramc_readl(LPR);
++              pr_debug("%s: Entering standby...\n", __func__);
++              avr32_pm_enter_standby(SDRAMC_BASE);
++              sdramc_writel(LPR, lpr_saved);
 +
-+      platform_device_add(pdev);
-+      return pdev;
++              /* Switch back to regular exception handlers */
++              sysreg_write(EVBA, evba_saved);
 +
-+fail:
-+      platform_device_put(pdev);
-+      return NULL;
-+}
-+#endif
++              avr32_pm_unmap_sram();
++              break;
 +
-+/* --------------------------------------------------------------------
-+ * AC97C
-+ * -------------------------------------------------------------------- */
-+static struct resource atmel_ac97c0_resource[] __initdata = {
-+      PBMEM(0xfff02800),
-+      IRQ(29),
-+};
-+static struct clk atmel_ac97c0_pclk = {
-+      .name           = "pclk",
-+      .parent         = &pbb_clk,
-+      .mode           = pbb_clk_mode,
-+      .get_rate       = pbb_clk_get_rate,
-+      .index          = 10,
-+};
++      case PM_SUSPEND_MEM:
++              sram = avr32_pm_map_sram();
 +
-+struct platform_device *__init at32_add_device_ac97c(unsigned int id)
-+{
-+      struct platform_device *pdev;
++              /* Switch to in-sram exception handlers */
++              evba_saved = sysreg_read(EVBA);
++              sysreg_write(EVBA, (unsigned long)sram);
 +
-+      if (id != 0)
-+              return NULL;
++              /*
++               * Save the LPR register so that we can re-enable
++               * SDRAM Low Power mode on resume.
++               */
++              lpr_saved = sdramc_readl(LPR);
++              pr_debug("%s: Entering suspend-to-ram...\n", __func__);
++              avr32_pm_enter_str(SDRAMC_BASE);
++              sdramc_writel(LPR, lpr_saved);
 +
-+      pdev = platform_device_alloc("atmel_ac97c", id);
-+      if (!pdev)
-+              return NULL;
++              /* Switch back to regular exception handlers */
++              sysreg_write(EVBA, evba_saved);
 +
-+      if (platform_device_add_resources(pdev, atmel_ac97c0_resource,
-+                              ARRAY_SIZE(atmel_ac97c0_resource)))
-+              goto err_add_resources;
++              avr32_pm_unmap_sram();
++              break;
 +
-+      select_peripheral(PB(20), PERIPH_B, 0); /* SYNC */
-+      select_peripheral(PB(21), PERIPH_B, 0); /* SDO  */
-+      select_peripheral(PB(22), PERIPH_B, 0); /* SDI  */
-+      select_peripheral(PB(23), PERIPH_B, 0); /* SCLK */
++      case PM_SUSPEND_ON:
++              pr_debug("%s: Entering idle...\n", __func__);
++              cpu_enter_idle();
++              break;
 +
-+      atmel_ac97c0_pclk.dev = &pdev->dev;
++      default:
++              pr_debug("%s: Invalid suspend state %d\n", __func__, state);
++              goto out;
++      }
 +
-+      platform_device_add(pdev);
-+      return pdev;
++      pr_debug("%s: wakeup\n", __func__);
 +
-+err_add_resources:
-+      platform_device_put(pdev);
-+      return NULL;
++out:
++      return 0;
 +}
 +
-+/* --------------------------------------------------------------------
-+ * ABDAC
-+ * -------------------------------------------------------------------- */
-+static struct resource abdac0_resource[] __initdata = {
-+      PBMEM(0xfff02000),
-+      IRQ(27),
-+};
-+static struct clk abdac0_pclk = {
-+      .name           = "pclk",
-+      .parent         = &pbb_clk,
-+      .mode           = pbb_clk_mode,
-+      .get_rate       = pbb_clk_get_rate,
-+      .index          = 8,
-+};
-+static struct clk abdac0_sample_clk = {
-+      .name           = "sample_clk",
-+      .mode           = genclk_mode,
-+      .get_rate       = genclk_get_rate,
-+      .set_rate       = genclk_set_rate,
-+      .set_parent     = genclk_set_parent,
-+      .index          = 6,
++static struct platform_suspend_ops avr32_pm_ops = {
++      .valid  = avr32_pm_valid_state,
++      .enter  = avr32_pm_enter,
 +};
 +
-+struct platform_device *__init at32_add_device_abdac(unsigned int id)
++static unsigned long avr32_pm_offset(void *symbol)
 +{
-+      struct platform_device *pdev;
++      extern u8 pm_exception[];
 +
-+      if (id != 0)
-+              return NULL;
++      return (unsigned long)symbol - (unsigned long)pm_exception;
++}
 +
-+      pdev = platform_device_alloc("abdac", id);
-+      if (!pdev)
-+              return NULL;
++static int __init avr32_pm_init(void)
++{
++      extern u8 pm_exception[];
++      extern u8 pm_irq0[];
++      extern u8 pm_standby[];
++      extern u8 pm_suspend_to_ram[];
++      extern u8 pm_sram_end[];
++      void *dst;
 +
-+      if (platform_device_add_resources(pdev, abdac0_resource,
-+                              ARRAY_SIZE(abdac0_resource)))
-+              goto err_add_resources;
++      /*
++       * To keep things simple, we depend on not needing more than a
++       * single page.
++       */
++      pm_sram_size = avr32_pm_offset(pm_sram_end);
++      if (pm_sram_size > PAGE_SIZE)
++              goto err;
 +
-+      select_peripheral(PB(20), PERIPH_A, 0); /* DATA1        */
-+      select_peripheral(PB(21), PERIPH_A, 0); /* DATA0        */
-+      select_peripheral(PB(22), PERIPH_A, 0); /* DATAN1       */
-+      select_peripheral(PB(23), PERIPH_A, 0); /* DATAN0       */
++      pm_sram_start = sram_alloc(pm_sram_size);
++      if (!pm_sram_start)
++              goto err_alloc_sram;
 +
-+      abdac0_pclk.dev = &pdev->dev;
-+      abdac0_sample_clk.dev = &pdev->dev;
++      /* Grab a virtual area we can use later on. */
++      pm_sram_area = get_vm_area(pm_sram_size, VM_IOREMAP);
++      if (!pm_sram_area)
++              goto err_vm_area;
++      pm_sram_area->phys_addr = pm_sram_start;
 +
-+      platform_device_add(pdev);
-+      return pdev;
++      local_irq_disable();
++      dst = avr32_pm_map_sram();
++      memcpy(dst, pm_exception, pm_sram_size);
++      flush_dcache_region(dst, pm_sram_size);
++      invalidate_icache_region(dst, pm_sram_size);
++      avr32_pm_unmap_sram();
++      local_irq_enable();
 +
-+err_add_resources:
-+      platform_device_put(pdev);
-+      return NULL;
-+}
++      avr32_pm_enter_standby = dst + avr32_pm_offset(pm_standby);
++      avr32_pm_enter_str = dst + avr32_pm_offset(pm_suspend_to_ram);
++      intc_set_suspend_handler(avr32_pm_offset(pm_irq0));
 +
-+/* --------------------------------------------------------------------
-+ *  GCLK
-+ * -------------------------------------------------------------------- */
-+static struct clk gclk0 = {
-+      .name           = "gclk0",
-+      .mode           = genclk_mode,
-+      .get_rate       = genclk_get_rate,
-+      .set_rate       = genclk_set_rate,
-+      .set_parent     = genclk_set_parent,
-+      .index          = 0,
-+};
-+static struct clk gclk1 = {
-+      .name           = "gclk1",
-+      .mode           = genclk_mode,
-+      .get_rate       = genclk_get_rate,
-+      .set_rate       = genclk_set_rate,
-+      .set_parent     = genclk_set_parent,
-+      .index          = 1,
-+};
-+static struct clk gclk2 = {
-+      .name           = "gclk2",
-+      .mode           = genclk_mode,
-+      .get_rate       = genclk_get_rate,
-+      .set_rate       = genclk_set_rate,
-+      .set_parent     = genclk_set_parent,
-+      .index          = 2,
-+};
-+static struct clk gclk3 = {
-+      .name           = "gclk3",
-+      .mode           = genclk_mode,
-+      .get_rate       = genclk_get_rate,
-+      .set_rate       = genclk_set_rate,
-+      .set_parent     = genclk_set_parent,
-+      .index          = 3,
-+};
-+static struct clk gclk4 = {
-+      .name           = "gclk4",
-+      .mode           = genclk_mode,
-+      .get_rate       = genclk_get_rate,
-+      .set_rate       = genclk_set_rate,
-+      .set_parent     = genclk_set_parent,
-+      .index          = 4,
-+};
++      suspend_set_ops(&avr32_pm_ops);
 +
-+struct clk *at32_clock_list[] = {
-+      &osc32k,
-+      &osc0,
-+      &osc1,
-+      &pll0,
-+      &pll1,
-+      &cpu_clk,
-+      &hsb_clk,
-+      &pba_clk,
-+      &pbb_clk,
-+      &at32_pm_pclk,
-+      &at32_intc0_pclk,
-+      &hmatrix_clk,
-+      &ebi_clk,
-+      &hramc_clk,
-+      &smc0_pclk,
-+      &smc0_mck,
-+      &pdc_hclk,
-+      &pdc_pclk,
-+      &dmaca0_hclk,
-+      &pico_clk,
-+      &pio0_mck,
-+      &pio1_mck,
-+      &pio2_mck,
-+      &pio3_mck,
-+      &pio4_mck,
-+      &at32_tcb0_t0_clk,
-+      &at32_tcb1_t0_clk,
-+      &atmel_psif0_pclk,
-+      &atmel_psif1_pclk,
-+      &atmel_usart0_usart,
-+      &atmel_usart1_usart,
-+      &atmel_usart2_usart,
-+      &atmel_usart3_usart,
-+      &atmel_pwm0_mck,
-+#if defined(CONFIG_CPU_AT32AP7000)
-+      &macb0_hclk,
-+      &macb0_pclk,
-+      &macb1_hclk,
-+      &macb1_pclk,
-+#endif
-+      &atmel_spi0_spi_clk,
-+      &atmel_spi1_spi_clk,
-+      &atmel_twi0_pclk,
-+      &atmel_mci0_pclk,
-+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002)
-+      &atmel_lcdfb0_hck1,
-+      &atmel_lcdfb0_pixclk,
-+#endif
-+      &ssc0_pclk,
-+      &ssc1_pclk,
-+      &ssc2_pclk,
-+      &usba0_hclk,
-+      &usba0_pclk,
-+      &atmel_ac97c0_pclk,
-+      &abdac0_pclk,
-+      &abdac0_sample_clk,
-+      &gclk0,
-+      &gclk1,
-+      &gclk2,
-+      &gclk3,
-+      &gclk4,
-+};
-+unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
++      printk("AVR32 AP Power Management enabled\n");
 +
-+void __init at32_portmux_init(void)
-+{
-+      at32_init_pio(&pio0_device);
-+      at32_init_pio(&pio1_device);
-+      at32_init_pio(&pio2_device);
-+      at32_init_pio(&pio3_device);
-+      at32_init_pio(&pio4_device);
-+}
++      return 0;
 +
-+void __init at32_clock_init(void)
-+{
-+      u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
-+      int i;
++err_vm_area:
++      sram_free(pm_sram_start, pm_sram_size);
++err_alloc_sram:
++err:
++      pr_err("AVR32 Power Management initialization failed\n");
++      return -ENOMEM;
++}
++arch_initcall(avr32_pm_init);
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/sdramc.h avr32-2.6/arch/avr32/mach-at32ap/sdramc.h
+--- linux-2.6.25.6/arch/avr32/mach-at32ap/sdramc.h     1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/arch/avr32/mach-at32ap/sdramc.h  2008-06-12 15:09:38.723815860 +0200
+@@ -0,0 +1,76 @@
++/*
++ * Register definitions for the AT32AP SDRAM Controller
++ *
++ * Copyright (C) 2008 Atmel Corporation
++ *
++ * 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.
++ */
 +
-+      if (pm_readl(MCCTRL) & PM_BIT(PLLSEL)) {
-+              main_clock = &pll0;
-+              cpu_clk.parent = &pll0;
-+      } else {
-+              main_clock = &osc0;
-+              cpu_clk.parent = &osc0;
-+      }
-+
-+      if (pm_readl(PLL0) & PM_BIT(PLLOSC))
-+              pll0.parent = &osc1;
-+      if (pm_readl(PLL1) & PM_BIT(PLLOSC))
-+              pll1.parent = &osc1;
-+
-+      genclk_init_parent(&gclk0);
-+      genclk_init_parent(&gclk1);
-+      genclk_init_parent(&gclk2);
-+      genclk_init_parent(&gclk3);
-+      genclk_init_parent(&gclk4);
-+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002)
-+      genclk_init_parent(&atmel_lcdfb0_pixclk);
-+#endif
-+      genclk_init_parent(&abdac0_sample_clk);
++/* Register offsets */
++#define SDRAMC_MR                     0x0000
++#define SDRAMC_TR                     0x0004
++#define SDRAMC_CR                     0x0008
++#define SDRAMC_HSR                    0x000c
++#define SDRAMC_LPR                    0x0010
++#define SDRAMC_IER                    0x0014
++#define SDRAMC_IDR                    0x0018
++#define SDRAMC_IMR                    0x001c
++#define SDRAMC_ISR                    0x0020
++#define SDRAMC_MDR                    0x0024
++
++/* MR - Mode Register */
++#define SDRAMC_MR_MODE_NORMAL         (  0 <<  0)
++#define SDRAMC_MR_MODE_NOP            (  1 <<  0)
++#define SDRAMC_MR_MODE_BANKS_PRECHARGE        (  2 <<  0)
++#define SDRAMC_MR_MODE_LOAD_MODE      (  3 <<  0)
++#define SDRAMC_MR_MODE_AUTO_REFRESH   (  4 <<  0)
++#define SDRAMC_MR_MODE_EXT_LOAD_MODE  (  5 <<  0)
++#define SDRAMC_MR_MODE_POWER_DOWN     (  6 <<  0)
++
++/* CR - Configuration Register */
++#define SDRAMC_CR_NC_8_BITS           (  0 <<  0)
++#define SDRAMC_CR_NC_9_BITS           (  1 <<  0)
++#define SDRAMC_CR_NC_10_BITS          (  2 <<  0)
++#define SDRAMC_CR_NC_11_BITS          (  3 <<  0)
++#define SDRAMC_CR_NR_11_BITS          (  0 <<  2)
++#define SDRAMC_CR_NR_12_BITS          (  1 <<  2)
++#define SDRAMC_CR_NR_13_BITS          (  2 <<  2)
++#define SDRAMC_CR_NB_2_BANKS          (  0 <<  4)
++#define SDRAMC_CR_NB_4_BANKS          (  1 <<  4)
++#define SDRAMC_CR_CAS(x)              ((x) <<  5)
++#define SDRAMC_CR_DBW_32_BITS         (  0 <<  7)
++#define SDRAMC_CR_DBW_16_BITS         (  1 <<  7)
++#define SDRAMC_CR_TWR(x)              ((x) <<  8)
++#define SDRAMC_CR_TRC(x)              ((x) << 12)
++#define SDRAMC_CR_TRP(x)              ((x) << 16)
++#define SDRAMC_CR_TRCD(x)             ((x) << 20)
++#define SDRAMC_CR_TRAS(x)             ((x) << 24)
++#define SDRAMC_CR_TXSR(x)             ((x) << 28)
++
++/* HSR - High Speed Register */
++#define SDRAMC_HSR_DA                 (  1 <<  0)
++
++/* LPR - Low Power Register */
++#define SDRAMC_LPR_LPCB_INHIBIT               (  0 <<  0)
++#define SDRAMC_LPR_LPCB_SELF_RFR      (  1 <<  0)
++#define SDRAMC_LPR_LPCB_PDOWN         (  2 <<  0)
++#define SDRAMC_LPR_LPCB_DEEP_PDOWN    (  3 <<  0)
++#define SDRAMC_LPR_PASR(x)            ((x) <<  4)
++#define SDRAMC_LPR_TCSR(x)            ((x) <<  8)
++#define SDRAMC_LPR_DS(x)              ((x) << 10)
++#define SDRAMC_LPR_TIMEOUT(x)         ((x) << 12)
++
++/* IER/IDR/IMR/ISR - Interrupt Enable/Disable/Mask/Status Register */
++#define SDRAMC_ISR_RES                        (  1 <<  0)
++
++/* MDR - Memory Device Register */
++#define SDRAMC_MDR_MD_SDRAM           (  0 <<  0)
++#define SDRAMC_MDR_MD_LOW_PWR_SDRAM   (  1 <<  0)
 +
-+      /*
-+       * Turn on all clocks that have at least one user already, and
-+       * turn off everything else. We only do this for module
-+       * clocks, and even though it isn't particularly pretty to
-+       * check the address of the mode function, it should do the
-+       * trick...
-+       */
-+      for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
-+              struct clk *clk = at32_clock_list[i];
-+
-+              if (clk->users == 0)
-+                      continue;
-+
-+              if (clk->mode == &cpu_clk_mode)
-+                      cpu_mask |= 1 << clk->index;
-+              else if (clk->mode == &hsb_clk_mode)
-+                      hsb_mask |= 1 << clk->index;
-+              else if (clk->mode == &pba_clk_mode)
-+                      pba_mask |= 1 << clk->index;
-+              else if (clk->mode == &pbb_clk_mode)
-+                      pbb_mask |= 1 << clk->index;
-+      }
-+
-+      pm_writel(CPU_MASK, cpu_mask);
-+      pm_writel(HSB_MASK, hsb_mask);
-+      pm_writel(PBA_MASK, pba_mask);
-+      pm_writel(PBB_MASK, pbb_mask);
-+}
---- a/arch/avr32/mach-at32ap/extint.c
-+++ b/arch/avr32/mach-at32ap/extint.c
-@@ -26,16 +26,10 @@
- #define EIC_MODE                              0x0014
- #define EIC_EDGE                              0x0018
- #define EIC_LEVEL                             0x001c
--#define EIC_TEST                              0x0020
- #define EIC_NMIC                              0x0024
--/* Bitfields in TEST */
--#define EIC_TESTEN_OFFSET                     31
--#define EIC_TESTEN_SIZE                               1
++/* Register access macros */
++#define sdramc_readl(reg) \
++      __raw_readl((void __iomem __force *)SDRAMC_BASE + SDRAMC_##reg)
++#define sdramc_writel(reg, value) \
++      __raw_writel(value, (void __iomem __force *)SDRAMC_BASE + SDRAMC_##reg)
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/time-tc.c avr32-2.6/arch/avr32/mach-at32ap/time-tc.c
+--- linux-2.6.25.6/arch/avr32/mach-at32ap/time-tc.c    2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/mach-at32ap/time-tc.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,218 +0,0 @@
+-/*
+- * Copyright (C) 2004-2007 Atmel Corporation
+- *
+- * Based on MIPS implementation arch/mips/kernel/time.c
+- *   Copyright 2001 MontaVista Software Inc.
+- *
+- * 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.
+- */
 -
- /* Bitfields in NMIC */
--#define EIC_EN_OFFSET                         0
--#define EIC_EN_SIZE                           1
-+#define EIC_NMIC_ENABLE                               (1 << 0)
- /* Bit manipulation macros */
- #define EIC_BIT(name)                                 \
-@@ -63,6 +57,9 @@
-       unsigned int first_irq;
- };
+-#include <linux/clk.h>
+-#include <linux/clocksource.h>
+-#include <linux/time.h>
+-#include <linux/module.h>
+-#include <linux/interrupt.h>
+-#include <linux/irq.h>
+-#include <linux/kernel_stat.h>
+-#include <linux/errno.h>
+-#include <linux/init.h>
+-#include <linux/profile.h>
+-#include <linux/sysdev.h>
+-#include <linux/err.h>
+-
+-#include <asm/div64.h>
+-#include <asm/sysreg.h>
+-#include <asm/io.h>
+-#include <asm/sections.h>
+-
+-#include <asm/arch/time.h>
+-
+-/* how many counter cycles in a jiffy? */
+-static u32 cycles_per_jiffy;
+-
+-/* the count value for the next timer interrupt */
+-static u32 expirelo;
+-
+-/* the I/O registers of the TC module */
+-static void __iomem *ioregs;
+-
+-cycle_t read_cycle_count(void)
+-{
+-      return (cycle_t)timer_read(ioregs, 0, CV);
+-}
+-
+-struct clocksource clocksource_avr32 = {
+-      .name           = "avr32",
+-      .rating         = 342,
+-      .read           = read_cycle_count,
+-      .mask           = CLOCKSOURCE_MASK(16),
+-      .shift          = 16,
+-      .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+-};
+-
+-static void avr32_timer_ack(void)
+-{
+-      u16 count = expirelo;
+-
+-      /* Ack this timer interrupt and set the next one, use a u16
+-       * variable so it will wrap around correctly */
+-      count += cycles_per_jiffy;
+-      expirelo = count;
+-      timer_write(ioregs, 0, RC, expirelo);
+-
+-      /* Check to see if we have missed any timer interrupts */
+-      count = timer_read(ioregs, 0, CV);
+-      if ((count - expirelo) < 0x7fff) {
+-              expirelo = count + cycles_per_jiffy;
+-              timer_write(ioregs, 0, RC, expirelo);
+-      }
+-}
+-
+-u32 avr32_hpt_read(void)
+-{
+-      return timer_read(ioregs, 0, CV);
+-}
+-
+-static int avr32_timer_calc_div_and_set_jiffies(struct clk *pclk)
+-{
+-      unsigned int cycles_max = (clocksource_avr32.mask + 1) / 2;
+-      unsigned int divs[] = { 4, 8, 16, 32 };
+-      int divs_size = ARRAY_SIZE(divs);
+-      int i = 0;
+-      unsigned long count_hz;
+-      unsigned long shift;
+-      unsigned long mult;
+-      int clock_div = -1;
+-      u64 tmp;
+-
+-      shift = clocksource_avr32.shift;
+-
+-      do {
+-              count_hz = clk_get_rate(pclk) / divs[i];
+-              mult = clocksource_hz2mult(count_hz, shift);
+-              clocksource_avr32.mult = mult;
+-
+-              tmp = TICK_NSEC;
+-              tmp <<= shift;
+-              tmp += mult / 2;
+-              do_div(tmp, mult);
+-
+-              cycles_per_jiffy = tmp;
+-      } while (cycles_per_jiffy > cycles_max && ++i < divs_size);
+-
+-      clock_div = i + 1;
+-
+-      if (clock_div > divs_size) {
+-              pr_debug("timer: could not calculate clock divider\n");
+-              return -EFAULT;
+-      }
+-
+-      /* Set the clock divider */
+-      timer_write(ioregs, 0, CMR, TIMER_BF(CMR_TCCLKS, clock_div));
+-
+-      return 0;
+-}
+-
+-int avr32_hpt_init(unsigned int count)
+-{
+-      struct resource *regs;
+-      struct clk *pclk;
+-      int irq = -1;
+-      int ret = 0;
+-
+-      ret = -ENXIO;
+-
+-      irq = platform_get_irq(&at32_systc0_device, 0);
+-      if (irq < 0) {
+-              pr_debug("timer: could not get irq\n");
+-              goto out_error;
+-      }
+-
+-      pclk = clk_get(&at32_systc0_device.dev, "pclk");
+-      if (IS_ERR(pclk)) {
+-              pr_debug("timer: could not get clk: %ld\n", PTR_ERR(pclk));
+-              goto out_error;
+-      }
+-      clk_enable(pclk);
+-
+-      regs = platform_get_resource(&at32_systc0_device, IORESOURCE_MEM, 0);
+-      if (!regs) {
+-              pr_debug("timer: could not get resource\n");
+-              goto out_error_clk;
+-      }
+-
+-      ioregs = ioremap(regs->start, regs->end - regs->start + 1);
+-      if (!ioregs) {
+-              pr_debug("timer: could not get ioregs\n");
+-              goto out_error_clk;
+-      }
+-
+-      ret = avr32_timer_calc_div_and_set_jiffies(pclk);
+-      if (ret)
+-              goto out_error_io;
+-
+-      ret = setup_irq(irq, &timer_irqaction);
+-      if (ret) {
+-              pr_debug("timer: could not request irq %d: %d\n",
+-                              irq, ret);
+-              goto out_error_io;
+-      }
+-
+-      expirelo = (timer_read(ioregs, 0, CV) / cycles_per_jiffy + 1)
+-              * cycles_per_jiffy;
+-
+-      /* Enable clock and interrupts on RC compare */
+-      timer_write(ioregs, 0, CCR, TIMER_BIT(CCR_CLKEN));
+-      timer_write(ioregs, 0, IER, TIMER_BIT(IER_CPCS));
+-      /* Set cycles to first interrupt */
+-      timer_write(ioregs, 0,  RC, expirelo);
+-
+-      printk(KERN_INFO "timer: AT32AP system timer/counter at 0x%p irq %d\n",
+-                      ioregs, irq);
+-
+-      return 0;
+-
+-out_error_io:
+-      iounmap(ioregs);
+-out_error_clk:
+-      clk_put(pclk);
+-out_error:
+-      return ret;
+-}
+-
+-int avr32_hpt_start(void)
+-{
+-      timer_write(ioregs, 0, CCR, TIMER_BIT(CCR_SWTRG));
+-      return 0;
+-}
+-
+-irqreturn_t timer_interrupt(int irq, void *dev_id)
+-{
+-      unsigned int sr = timer_read(ioregs, 0, SR);
+-
+-      if (sr & TIMER_BIT(SR_CPCS)) {
+-              /* ack timer interrupt and try to set next interrupt */
+-              avr32_timer_ack();
+-
+-              /*
+-               * Call the generic timer interrupt handler
+-               */
+-              write_seqlock(&xtime_lock);
+-              do_timer(1);
+-              write_sequnlock(&xtime_lock);
+-
+-              /*
+-               * In UP mode, we call local_timer_interrupt() to do profiling
+-               * and process accounting.
+-               *
+-               * SMP is not supported yet.
+-               */
+-              local_timer_interrupt(irq, dev_id);
+-
+-              return IRQ_HANDLED;
+-      }
+-
+-      return IRQ_NONE;
+-}
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/Makefile avr32-2.6/arch/avr32/Makefile
+--- linux-2.6.25.6/arch/avr32/Makefile 2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/Makefile      2008-06-12 15:09:38.711815728 +0200
+@@ -32,6 +32,7 @@
+ core-y                                        += arch/avr32/kernel/
+ core-y                                        += arch/avr32/mm/
+ drivers-$(CONFIG_OPROFILE)            += arch/avr32/oprofile/
++drivers-y                             += arch/avr32/drivers/
+ libs-y                                        += arch/avr32/lib/
  
-+static struct eic *nmi_eic;
-+static bool nmi_enabled;
-+
- static void eic_ack_irq(unsigned int irq)
- {
-       struct eic *eic = get_irq_chip_data(irq);
-@@ -133,8 +130,11 @@
-               eic_writel(eic, EDGE, edge);
-               eic_writel(eic, LEVEL, level);
--              if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
-+              if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) {
-                       flow_type |= IRQ_LEVEL;
-+                      __set_irq_handler_unlocked(irq, handle_level_irq);
-+              } else
-+                      __set_irq_handler_unlocked(irq, handle_edge_irq);
-               desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
-               desc->status |= flow_type;
-       }
-@@ -154,9 +154,8 @@
- static void demux_eic_irq(unsigned int irq, struct irq_desc *desc)
- {
-       struct eic *eic = desc->handler_data;
--      struct irq_desc *ext_desc;
-       unsigned long status, pending;
--      unsigned int i, ext_irq;
-+      unsigned int i;
+ archincdir-$(CONFIG_PLATFORM_AT32AP)  := arch-at32ap
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mm/init.c avr32-2.6/arch/avr32/mm/init.c
+--- linux-2.6.25.6/arch/avr32/mm/init.c        2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/mm/init.c     2008-06-12 15:09:38.727815811 +0200
+@@ -11,6 +11,7 @@
+ #include <linux/swap.h>
+ #include <linux/init.h>
+ #include <linux/mmzone.h>
++#include <linux/module.h>
+ #include <linux/bootmem.h>
+ #include <linux/pagemap.h>
+ #include <linux/nodemask.h>
+@@ -28,15 +29,13 @@
+ pgd_t swapper_pg_dir[PTRS_PER_PGD];
  
-       status = eic_readl(eic, ISR);
-       pending = status & eic_readl(eic, IMR);
-@@ -165,15 +164,28 @@
-               i = fls(pending) - 1;
-               pending &= ~(1 << i);
--              ext_irq = i + eic->first_irq;
--              ext_desc = irq_desc + ext_irq;
--              if (ext_desc->status & IRQ_LEVEL)
--                      handle_level_irq(ext_irq, ext_desc);
--              else
--                      handle_edge_irq(ext_irq, ext_desc);
-+              generic_handle_irq(i + eic->first_irq);
-       }
- }
+ struct page *empty_zero_page;
++EXPORT_SYMBOL(empty_zero_page);
  
-+int nmi_enable(void)
-+{
-+      nmi_enabled = true;
-+
-+      if (nmi_eic)
-+              eic_writel(nmi_eic, NMIC, EIC_NMIC_ENABLE);
-+
-+      return 0;
-+}
-+
-+void nmi_disable(void)
-+{
-+      if (nmi_eic)
-+              eic_writel(nmi_eic, NMIC, 0);
-+
-+      nmi_enabled = false;
-+}
-+
- static int __init eic_probe(struct platform_device *pdev)
+ /*
+  * Cache of MMU context last used.
+  */
+ unsigned long mmu_context_cache = NO_CONTEXT;
+-#define START_PFN     (NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT)
+-#define MAX_LOW_PFN   (NODE_DATA(0)->bdata->node_low_pfn)
+-
+ void show_mem(void)
  {
-       struct eic *eic;
-@@ -214,14 +226,13 @@
-       pattern = eic_readl(eic, MODE);
-       nr_irqs = fls(pattern);
--      /* Trigger on falling edge unless overridden by driver */
--      eic_writel(eic, MODE, 0UL);
-+      /* Trigger on low level unless overridden by driver */
-       eic_writel(eic, EDGE, 0UL);
-+      eic_writel(eic, LEVEL, 0UL);
-       eic->chip = &eic_chip;
-       for (i = 0; i < nr_irqs; i++) {
--              /* NOTE the handler we set here is ignored by the demux */
-               set_irq_chip_and_handler(eic->first_irq + i, &eic_chip,
-                                        handle_level_irq);
-               set_irq_chip_data(eic->first_irq + i, eic);
-@@ -230,6 +241,16 @@
-       set_irq_chained_handler(int_irq, demux_eic_irq);
-       set_irq_data(int_irq, eic);
-+      if (pdev->id == 0) {
-+              nmi_eic = eic;
-+              if (nmi_enabled)
-+                      /*
-+                       * Someone tried to enable NMI before we were
-+                       * ready. Do it now.
-+                       */
-+                      nmi_enable();
-+      }
+       int total = 0, reserved = 0, cached = 0;
+diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/oprofile/op_model_avr32.c avr32-2.6/arch/avr32/oprofile/op_model_avr32.c
+--- linux-2.6.25.6/arch/avr32/oprofile/op_model_avr32.c        2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/arch/avr32/oprofile/op_model_avr32.c     2008-06-12 15:03:55.895816260 +0200
+@@ -16,7 +16,6 @@
+ #include <linux/sched.h>
+ #include <linux/types.h>
+-#include <asm/intc.h>
+ #include <asm/sysreg.h>
+ #include <asm/system.h>
+diff --exclude=.git -urN linux-2.6.25.6/Documentation/ABI/stable/sysfs-class-ubi avr32-2.6/Documentation/ABI/stable/sysfs-class-ubi
+--- linux-2.6.25.6/Documentation/ABI/stable/sysfs-class-ubi    1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/Documentation/ABI/stable/sysfs-class-ubi 2008-06-12 15:03:55.427814470 +0200
+@@ -0,0 +1,212 @@
++What:         /sys/class/ubi/
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              The ubi/ class sub-directory belongs to the UBI subsystem and
++              provides general UBI information, per-UBI device information
++              and per-UBI volume information.
++
++What:         /sys/class/ubi/version
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              This file contains version of the latest supported UBI on-media
++              format. Currently it is 1, and there is no plan to change this.
++              However, if in the future UBI needs on-flash format changes
++              which cannot be done in a compatible manner, a new format
++              version will be added. So this is a mechanism for possible
++              future backward-compatible (but forward-incompatible)
++              improvements.
++
++What:         /sys/class/ubiX/
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              The /sys/class/ubi0, /sys/class/ubi1, etc directories describe
++              UBI devices (UBI device 0, 1, etc). They contain general UBI
++              device information and per UBI volume information (each UBI
++              device may have many UBI volumes)
++
++What:         /sys/class/ubi/ubiX/avail_eraseblocks
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Amount of available logical eraseblock. For example, one may
++              create a new UBI volume which has this amount of logical
++              eraseblocks.
++
++What:         /sys/class/ubi/ubiX/bad_peb_count
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Count of bad physical eraseblocks on the underlying MTD device.
++
++What:         /sys/class/ubi/ubiX/bgt_enabled
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Contains ASCII "0\n" if the UBI background thread is disabled,
++              and ASCII "1\n" if it is enabled.
++
++What:         /sys/class/ubi/ubiX/dev
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Major and minor numbers of the character device corresponding
++              to this UBI device (in <major>:<minor> format).
++
++What:         /sys/class/ubi/ubiX/eraseblock_size
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Maximum logical eraseblock size this UBI device may provide. UBI
++              volumes may have smaller logical eraseblock size because of their
++              alignment.
++
++What:         /sys/class/ubi/ubiX/max_ec
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Maximum physical eraseblock erase counter value.
++
++What:         /sys/class/ubi/ubiX/max_vol_count
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Maximum number of volumes which this UBI device may have.
++
++What:         /sys/class/ubi/ubiX/min_io_size
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Minimum input/output unit size. All the I/O may only be done
++              in fractions of the contained number.
++
++What:         /sys/class/ubi/ubiX/mtd_num
++Date:         January 2008
++KernelVersion:        2.6.25
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Number of the underlying MTD device.
++
++What:         /sys/class/ubi/ubiX/reserved_for_bad
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Number of physical eraseblocks reserved for bad block handling.
++
++What:         /sys/class/ubi/ubiX/total_eraseblocks
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Total number of good (not marked as bad) physical eraseblocks on
++              the underlying MTD device.
++
++What:         /sys/class/ubi/ubiX/volumes_count
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Count of volumes on this UBI device.
++
++What:         /sys/class/ubi/ubiX/ubiX_Y/
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              The /sys/class/ubi/ubiX/ubiX_0/, /sys/class/ubi/ubiX/ubiX_1/,
++              etc directories describe UBI volumes on UBI device X (volumes
++              0, 1, etc).
++
++What:         /sys/class/ubi/ubiX/ubiX_Y/alignment
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Volume alignment - the value the logical eraseblock size of
++              this volume has to be aligned on. For example, 2048 means that
++              logical eraseblock size is multiple of 2048. In other words,
++              volume logical eraseblock size is UBI device logical eraseblock
++              size aligned to the alignment value.
++
++What:         /sys/class/ubi/ubiX/ubiX_Y/corrupted
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Contains ASCII "0\n" if the UBI volume is OK, and ASCII "1\n"
++              if it is corrupted (e.g., due to an interrupted volume update).
++
++What:         /sys/class/ubi/ubiX/ubiX_Y/data_bytes
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              The amount of data this volume contains. This value makes sense
++              only for static volumes, and for dynamic volume it equivalent
++              to the total volume size in bytes.
++
++What:         /sys/class/ubi/ubiX/ubiX_Y/dev
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Major and minor numbers of the character device corresponding
++              to this UBI volume (in <major>:<minor> format).
++
++What:         /sys/class/ubi/ubiX/ubiX_Y/name
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Volume name.
++
++What:         /sys/class/ubi/ubiX/ubiX_Y/reserved_ebs
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Count of physical eraseblock reserved for this volume.
++              Equivalent to the volume size in logical eraseblocks.
++
++What:         /sys/class/ubi/ubiX/ubiX_Y/type
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Volume type. Contains ASCII "dynamic\n" for dynamic volumes and
++              "static\n" for static volumes.
++
++What:         /sys/class/ubi/ubiX/ubiX_Y/upd_marker
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Contains ASCII "0\n" if the update marker is not set for this
++              volume, and "1\n" if it is set. The update marker is set when
++              volume update starts, and cleaned when it ends. So the presence
++              of the update marker indicates that the volume is being updated
++              at the moment of the update was interrupted. The later may be
++              checked using the "corrupted" sysfs file.
++
++What:         /sys/class/ubi/ubiX/ubiX_Y/usable_eb_size
++Date:         July 2006
++KernelVersion:        2.6.22
++Contact:      Artem Bityutskiy <dedekind@infradead.org>
++Description:
++              Logical eraseblock size of this volume. Equivalent to logical
++              eraseblock size of the device aligned on the volume alignment
++              value.
+diff --exclude=.git -urN linux-2.6.25.6/Documentation/filesystems/ubifs.txt avr32-2.6/Documentation/filesystems/ubifs.txt
+--- linux-2.6.25.6/Documentation/filesystems/ubifs.txt 1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/Documentation/filesystems/ubifs.txt      2008-06-12 15:09:38.451815572 +0200
+@@ -0,0 +1,163 @@
++Introduction
++=============
++
++UBIFS file-system stands for UBI File System. UBI stands for "Unsorted
++Block Images". UBIFS is a flash file system, which means it is designed
++to work with flash devices. It is important to understand, that UBIFS
++is completely different to any traditional file-system in Linux, like
++Ext2, XFS, JFS, etc. UBIFS represents a separate class of file-systems
++which work with MTD devices, not block devices. The other Linux
++file-system of this class is JFFS2.
++
++To make it more clear, here is a small comparison of MTD devices and
++block devices.
++
++1 MTD devices represent flash devices and they consist of eraseblocks of
++  rather large size, typically about 128KiB. Block devices consist of
++  small blocks, typically 512 bytes.
++2 MTD devices support 3 main operations - read from some offset within an
++  eraseblock, write to some offset within an eraseblock, and erase a whole
++  eraseblock. Block  devices support 2 main operations - read a whole
++  block and write a whole block.
++3 The whole eraseblock has to be erased before it becomes possible to
++  re-write its contents. Blocks may be just re-written.
++4 Eraseblocks become worn out after some number of erase cycles -
++  typically 100K-1G for SLC NAND and NOR flashes, and 1K-10K for MLC
++  NAND flashes. Blocks do not have the wear-out property.
++5 Eraseblocks may become bad (only on NAND flashes) and software should
++  deal with this. Blocks on hard drives typically do not become bad,
++  because hardware has mechanisms to substitute bad blocks, at least in
++  modern LBA disks.
++
++It should be quite obvious why UBIFS is very different to traditional
++file-systems.
++
++UBIFS works on top of UBI. UBI is a separate software layer which may be
++found in drivers/mtd/ubi. UBI is basically a volume management and
++wear-leveling layer. It provides so called UBI volumes which is a higher
++level abstraction than a MTD device. The programming model of UBI devices
++is very similar to MTD devices - they still consist of large eraseblocks,
++they have read/write/erase operations, but UBI devices are devoid of
++limitations like wear and bad blocks (items 4 and 5 in the above list).
++
++In a sense, UBIFS is a next generation of JFFS2 file-system, but it is
++very different and incompatible to JFFS2. The following are the main
++differences.
++
++* JFFS2 works on top of MTD devices, UBIFS depends on UBI and works on
++  top of UBI volumes.
++* JFFS2 does not have on-media index and has to build it while mounting,
++  which requires full media scan. UBIFS maintains the FS indexing
++  information on the flash media and does not require full media scan,
++  so it mounts many times faster than JFFS2.
++* JFFS2 is a write-through file-system, while UBIFS supports write-back,
++  which makes UBIFS much faster on writes.
++
++Similarly to JFFS2, UBIFS supports on-the-flight compression which makes
++it possible to fit quite a lot of data to the flash.
++
++Similarly to JFFS2, UBIFS is tolerant of unclean reboots and power-cuts.
++It does not need stuff like ckfs.ext2. UBIFS automatically replays its
++journal and recovers from crashes, ensuring that the on-flash data
++structures are consistent.
++
++UBIFS scales logarithmically (most of the data structures it uses are
++trees), so the mount time and memory consumption do not linearly depend
++on the flash size, like in case of JFFS2. This is because UBIFS
++maintains the FS index on the flash media. However, UBIFS depends on
++UBI, which scales linearly. So overall UBI/UBIFS stack scales linearly.
++Nevertheless, UBI/UBIFS scales considerably better than JFFS2.
++
++The authors of UBIFS believe, that it is possible to develop UBI2 which
++would scale logarithmically as well. UBI2 would support the same API as UBI,
++but it would be binary incompatible to UBI. So UBIFS would not need to be
++changed to use UBI2
++
++
++Mount options
++=============
++
++(*) == default.
++
++norm_unmount (*)      commit on unmount; the journal is committed
++                      when the file-system is unmounted so that the
++                      next mount does not have to replay the journal
++                      and it becomes very fast;
++fast_unmount          do not commit on unmount; this option makes
++                      unmount faster, but the next mount slower
++                      because of the need to replay the journal.
++
++
++Quick usage instructions
++========================
++
++The UBI volume to mount is specified using "ubiX_Y" or "ubiX:NAME" syntax,
++where "X" is UBI device number, "Y" is UBI volume number, and "NAME" is
++UBI volume name.
++
++Mount volume 0 on UBI device 0 to /mnt/ubifs:
++$ mount -t ubifs ubi0_0 /mnt/ubifs
++
++Mount "rootfs" volume of UBI device 0 to /mnt/ubifs ("rootfs" is volume
++name):
++$ mount -t ubifs ubi0:rootfs /mnt/ubifs
++
++The following is an example of the kernel boot arguments to attach mtd0
++to UBI and mount volume "rootfs":
++ubi.mtd=0 root=ubi0:rootfs rootfstype=ubifs
++
++
++Module Parameters for Debugging
++===============================
++
++When UBIFS has been compiled with debugging enabled, there are 3 module
++parameters that are available to control aspects of testing and debugging.
++The parameters are unsigned integers where each bit controls an option.
++The parameters are:
++
++debug_msgs    Selects which debug messages to display, as follows:
++
++              Message Type                            Flag value
++
++              General messages                        1
++              Journal messages                        2
++              Mount messages                          4
++              Commit messages                         8
++              LEB search messages                     16
++              Budgeting messages                      32
++              Garbage collection messages             64
++              Tree Node Cache (TNC) messages          128
++              LEB properties (lprops) messages        256
++              Input/output messages                   512
++              Log messages                            1024
++              Scan messages                           2048
++              Recovery messages                       4096
++
++debug_chks    Selects extra checks that UBIFS can do while running:
++
++              Check                                   Flag value
++
++              General checks                          1
++              Check Tree Node Cache (TNC)             2
++              Check indexing tree size                4
++              Check orphan area                       8
++              Check old indexing tree                 16
++              Check LEB properties (lprops)           32
++
++debug_tsts    Selects a mode of testing, as follows:
++
++              Test mode                               Flag value
++
++              Force in-the-gaps method                2
++              Failure mode for recovery testing       4
++
++For example, set debug_msgs to 5 to display General messages and Mount
++messages.
++
++
++References
++==========
++
++UBIFS documentation and FAQ/HOWTO at the MTD web site:
++http://www.linux-mtd.infradead.org/doc/ubifs.html
++http://www.linux-mtd.infradead.org/faq/ubifs.html
+diff --exclude=.git -urN linux-2.6.25.6/drivers/char/Kconfig avr32-2.6/drivers/char/Kconfig
+--- linux-2.6.25.6/drivers/char/Kconfig        2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/char/Kconfig     2008-06-12 15:09:40.071816052 +0200
+@@ -706,7 +706,7 @@
+ config RTC
+       tristate "Enhanced Real Time Clock Support"
+-      depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390
++      depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390 && !AVR32
+       ---help---
+         If you say Y here and create a character special file /dev/rtc with
+         major number 10 and minor number 135 using mknod ("man mknod"), you
+@@ -776,7 +776,7 @@
+ config GEN_RTC
+       tristate "Generic /dev/rtc emulation"
+-      depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH
++      depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH && !AVR32
+       ---help---
+         If you say Y here and create a character special file /dev/rtc with
+         major number 10 and minor number 135 using mknod ("man mknod"), you
+diff --exclude=.git -urN linux-2.6.25.6/drivers/char/keyboard.c avr32-2.6/drivers/char/keyboard.c
+--- linux-2.6.25.6/drivers/char/keyboard.c     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/char/keyboard.c  2008-06-12 15:09:40.243816452 +0200
+@@ -1033,7 +1033,8 @@
+ #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
+     defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
+     defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
+-    (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC))
++    (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) ||\
++    defined(CONFIG_AVR32)
+ #define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
+                       ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
+diff --exclude=.git -urN linux-2.6.25.6/drivers/clocksource/Makefile avr32-2.6/drivers/clocksource/Makefile
+--- linux-2.6.25.6/drivers/clocksource/Makefile        2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/clocksource/Makefile     2008-06-12 15:03:58.475816394 +0200
+@@ -1,3 +1,4 @@
++obj-$(CONFIG_ATMEL_TCB_CLKSRC)        += tcb_clksrc.o
+ obj-$(CONFIG_X86_CYCLONE_TIMER)       += cyclone.o
+ obj-$(CONFIG_X86_PM_TIMER)    += acpi_pm.o
+ obj-$(CONFIG_SCx200HR_TIMER)  += scx200_hrt.o
+diff --exclude=.git -urN linux-2.6.25.6/drivers/clocksource/tcb_clksrc.c avr32-2.6/drivers/clocksource/tcb_clksrc.c
+--- linux-2.6.25.6/drivers/clocksource/tcb_clksrc.c    1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/drivers/clocksource/tcb_clksrc.c 2008-06-12 15:03:58.479814669 +0200
+@@ -0,0 +1,302 @@
++#include <linux/init.h>
++#include <linux/clocksource.h>
++#include <linux/clockchips.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/ioport.h>
++#include <linux/io.h>
++#include <linux/platform_device.h>
++#include <linux/atmel_tc.h>
++
 +
-       dev_info(&pdev->dev,
-                "External Interrupt Controller at 0x%p, IRQ %u\n",
-                eic->regs, int_irq);
---- /dev/null
-+++ b/arch/avr32/mach-at32ap/gpio-dev.c
-@@ -0,0 +1,573 @@
 +/*
-+ * GPIO /dev and configfs interface
++ * We're configured to use a specific TC block, one that's not hooked
++ * up to external hardware, to provide a time solution:
 + *
-+ * Copyright (C) 2006-2007 Atmel Corporation
++ *   - Two channels combine to create a free-running 32 bit counter
++ *     with a base rate of 5+ MHz, packaged as a clocksource (with
++ *     resolution better than 200 nsec).
 + *
-+ * 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.
++ *   - The third channel may be used to provide a 16-bit clockevent
++ *     source, used in either periodic or oneshot mode.  This runs
++ *     at 32 KiHZ, and can handle delays of up to two seconds.
++ *
++ * A boot clocksource and clockevent source are also currently needed,
++ * unless the relevant platforms (ARM/AT91, AVR32/AT32) are changed so
++ * this code can be used when init_timers() is called, well before most
++ * devices are set up.  (Some low end AT91 parts, which can run uClinux,
++ * have only the timers in one TC block... they currently don't support
++ * the tclib code, because of that initialization issue.)
++ *
++ * REVISIT behavior during system suspend states... we should disable
++ * all clocks and save the power.  Easily done for clockevent devices,
++ * but clocksources won't necessarily get the needed notifications.
++ * For deeper system sleep states, this will be mandatory...
 + */
-+#include <linux/kernel.h>
-+#include <linux/configfs.h>
-+#include <linux/cdev.h>
-+#include <linux/device.h>
-+#include <linux/fs.h>
-+#include <linux/interrupt.h>
-+#include <linux/module.h>
-+#include <linux/poll.h>
-+#include <linux/uaccess.h>
-+#include <linux/wait.h>
-+
-+#include <asm/gpio.h>
-+#include <asm/arch/portmux.h>
 +
-+#define GPIO_DEV_MAX                  8
-+
-+static struct class *gpio_dev_class;
-+static dev_t gpio_devt;
-+
-+struct gpio_item {
-+      spinlock_t lock;
++static void __iomem *tcaddr;
 +
-+      int enabled;
-+      int initialized;
-+      int port;
-+      u32 pin_mask;
-+      u32 oe_mask;
++static cycle_t tc_get_cycles(void)
++{
++      unsigned long   flags;
++      u32             lower, upper;
 +
-+      /* Pin state last time we read it (for blocking reads) */
-+      u32 pin_state;
-+      int changed;
++      raw_local_irq_save(flags);
++      do {
++              upper = __raw_readl(tcaddr + ATMEL_TC_REG(1, CV));
++              lower = __raw_readl(tcaddr + ATMEL_TC_REG(0, CV));
++      } while (upper != __raw_readl(tcaddr + ATMEL_TC_REG(1, CV)));
 +
-+      wait_queue_head_t change_wq;
-+      struct fasync_struct *async_queue;
++      raw_local_irq_restore(flags);
++      return (upper << 16) | lower;
++}
 +
-+      int id;
-+      struct class_device *gpio_dev;
-+      struct cdev char_dev;
-+      struct config_item item;
++static struct clocksource clksrc = {
++      .name           = "tcb_clksrc",
++      .rating         = 200,
++      .read           = tc_get_cycles,
++      .mask           = CLOCKSOURCE_MASK(32),
++      .shift          = 18,
++      .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 +};
 +
-+struct gpio_attribute {
-+      struct configfs_attribute attr;
-+      ssize_t (*show)(struct gpio_item *, char *);
-+      ssize_t (*store)(struct gpio_item *, const char *, size_t);
++#ifdef CONFIG_GENERIC_CLOCKEVENTS
++
++struct tc_clkevt_device {
++      struct clock_event_device       clkevt;
++      struct clk                      *clk;
++      void __iomem                    *regs;
 +};
 +
-+static irqreturn_t gpio_dev_interrupt(int irq, void *dev_id)
++static struct tc_clkevt_device *to_tc_clkevt(struct clock_event_device *clkevt)
 +{
-+      struct gpio_item *gpio = dev_id;
-+      u32 old_state, new_state;
++      return container_of(clkevt, struct tc_clkevt_device, clkevt);
++}
 +
-+      old_state = gpio->pin_state;
-+      new_state = at32_gpio_get_value_multiple(gpio->port, gpio->pin_mask);
-+      gpio->pin_state = new_state;
++/* For now, we always use the 32K clock ... this optimizes for NO_HZ,
++ * because using one of the divided clocks would usually mean the
++ * tick rate can never be less than several dozen Hz (vs 0.5 Hz).
++ *
++ * A divided clock could be good for high resolution timers, since
++ * 30.5 usec resolution can seem "low".
++ */
++static u32 timer_clock;
 +
-+      if (new_state != old_state) {
-+              gpio->changed = 1;
-+              wake_up_interruptible(&gpio->change_wq);
++static void tc_mode(enum clock_event_mode m, struct clock_event_device *d)
++{
++      struct tc_clkevt_device *tcd = to_tc_clkevt(d);
++      void __iomem            *regs = tcd->regs;
 +
-+              if (gpio->async_queue)
-+                      kill_fasync(&gpio->async_queue, SIGIO, POLL_IN);
++      if (tcd->clkevt.mode == CLOCK_EVT_MODE_PERIODIC
++                      || tcd->clkevt.mode == CLOCK_EVT_MODE_ONESHOT) {
++              __raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR));
++              __raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR));
++              clk_disable(tcd->clk);
 +      }
 +
-+      return IRQ_HANDLED;
-+}
++      switch (m) {
 +
-+static int gpio_dev_open(struct inode *inode, struct file *file)
-+{
-+      struct gpio_item *gpio = container_of(inode->i_cdev,
-+                                            struct gpio_item,
-+                                            char_dev);
-+      unsigned int irq;
-+      unsigned int i;
-+      int ret;
++      /* By not making the gentime core emulate periodic mode on top
++       * of oneshot, we get lower overhead and improved accuracy.
++       */
++      case CLOCK_EVT_MODE_PERIODIC:
++              clk_enable(tcd->clk);
 +
-+      nonseekable_open(inode, file);
-+      config_item_get(&gpio->item);
-+      file->private_data = gpio;
++              /* slow clock, count up to RC, then irq and restart */
++              __raw_writel(timer_clock
++                              | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO,
++                              regs + ATMEL_TC_REG(2, CMR));
++              __raw_writel((32768 + HZ/2) / HZ, tcaddr + ATMEL_TC_REG(2, RC));
 +
-+      gpio->pin_state = at32_gpio_get_value_multiple(gpio->port,
-+                                                     gpio->pin_mask);
-+      gpio->changed = 1;
++              /* Enable clock and interrupts on RC compare */
++              __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
 +
-+      for (i = 0; i < 32; i++) {
-+              if (gpio->pin_mask & (1 << i)) {
-+                      irq = gpio_to_irq(32 * gpio->port + i);
-+                      ret = request_irq(irq, gpio_dev_interrupt, 0,
-+                                        "gpio-dev", gpio);
-+                      if (ret)
-+                              goto err_irq;
-+              }
-+      }
++              /* go go gadget! */
++              __raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG,
++                              regs + ATMEL_TC_REG(2, CCR));
++              break;
 +
-+      return 0;
++      case CLOCK_EVT_MODE_ONESHOT:
++              clk_enable(tcd->clk);
 +
-+err_irq:
-+      while (i--) {
-+              if (gpio->pin_mask & (1 << i)) {
-+                      irq = gpio_to_irq(32 * gpio->port + i);
-+                      free_irq(irq, gpio);
-+              }
-+      }
++              /* slow clock, count up to RC, then irq and stop */
++              __raw_writel(timer_clock | ATMEL_TC_CPCSTOP
++                              | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO,
++                              regs + ATMEL_TC_REG(2, CMR));
++              __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
 +
-+      config_item_put(&gpio->item);
++              /* set_next_event() configures and starts the timer */
++              break;
 +
-+      return ret;
++      default:
++              break;
++      }
 +}
 +
-+static int gpio_dev_fasync(int fd, struct file *file, int mode)
++static int tc_next_event(unsigned long delta, struct clock_event_device *d)
 +{
-+      struct gpio_item *gpio = file->private_data;
++      __raw_writel(delta, tcaddr + ATMEL_TC_REG(2, RC));
 +
-+      return fasync_helper(fd, file, mode, &gpio->async_queue);
++      /* go go gadget! */
++      __raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG,
++                      tcaddr + ATMEL_TC_REG(2, CCR));
++      return 0;
 +}
 +
-+static int gpio_dev_release(struct inode *inode, struct file *file)
-+{
-+      struct gpio_item *gpio = file->private_data;
-+      unsigned int irq;
-+      unsigned int i;
++static struct tc_clkevt_device clkevt = {
++      .clkevt = {
++              .name           = "tc_clkevt",
++              .features       = CLOCK_EVT_FEAT_PERIODIC
++                                      | CLOCK_EVT_FEAT_ONESHOT,
++              .shift          = 32,
++              /* Should be lower than at91rm9200's system timer */
++              .rating         = 125,
++              .cpumask        = CPU_MASK_CPU0,
++              .set_next_event = tc_next_event,
++              .set_mode       = tc_mode,
++      },
++};
 +
-+      gpio_dev_fasync(-1, file, 0);
++static irqreturn_t ch2_irq(int irq, void *handle)
++{
++      struct tc_clkevt_device *dev = handle;
++      unsigned int            sr;
 +
-+      for (i = 0; i < 32; i++) {
-+              if (gpio->pin_mask & (1 << i)) {
-+                      irq = gpio_to_irq(32 * gpio->port + i);
-+                      free_irq(irq, gpio);
-+              }
++      sr = __raw_readl(dev->regs + ATMEL_TC_REG(2, SR));
++      if (sr & ATMEL_TC_CPCS) {
++              dev->clkevt.event_handler(&dev->clkevt);
++              return IRQ_HANDLED;
 +      }
 +
-+      config_item_put(&gpio->item);
-+
-+      return 0;
++      return IRQ_NONE;
 +}
 +
-+static unsigned int gpio_dev_poll(struct file *file, poll_table *wait)
++static struct irqaction tc_irqaction = {
++      .name           = "tc_clkevt",
++      .flags          = IRQF_TIMER | IRQF_DISABLED,
++      .handler        = ch2_irq,
++};
++
++static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
 +{
-+      struct gpio_item *gpio = file->private_data;
-+      unsigned int mask = 0;
++      struct clk *t2_clk = tc->clk[2];
++      int irq = tc->irq[2];
 +
-+      poll_wait(file, &gpio->change_wq, wait);
-+      if (gpio->changed)
-+              mask |= POLLIN | POLLRDNORM;
++      clkevt.regs = tc->regs;
++      clkevt.clk = t2_clk;
++      tc_irqaction.dev_id = &clkevt;
 +
-+      return mask;
++      timer_clock = clk32k_divisor_idx;
++
++      clkevt.clkevt.mult = div_sc(32768, NSEC_PER_SEC, clkevt.clkevt.shift);
++      clkevt.clkevt.max_delta_ns
++              = clockevent_delta2ns(0xffff, &clkevt.clkevt);
++      clkevt.clkevt.min_delta_ns = clockevent_delta2ns(1, &clkevt.clkevt) + 1;
++
++      setup_irq(irq, &tc_irqaction);
++
++      clockevents_register_device(&clkevt.clkevt);
 +}
 +
-+static ssize_t gpio_dev_read(struct file *file, char __user *buf,
-+                           size_t count, loff_t *offset)
++#else /* !CONFIG_GENERIC_CLOCKEVENTS */
++
++static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
 +{
-+      struct gpio_item *gpio = file->private_data;
-+      u32 value;
++      /* NOTHING */
++}
 +
-+      spin_lock_irq(&gpio->lock);
-+      while (!gpio->changed) {
-+              spin_unlock_irq(&gpio->lock);
++#endif
 +
-+              if (file->f_flags & O_NONBLOCK)
-+                      return -EAGAIN;
++static int __init tcb_clksrc_init(void)
++{
++      static char bootinfo[] __initdata
++              = KERN_DEBUG "%s: tc%d at %d.%03d MHz\n";
 +
-+              if (wait_event_interruptible(gpio->change_wq, gpio->changed))
-+                      return -ERESTARTSYS;
++      struct platform_device *pdev;
++      struct atmel_tc *tc;
++      struct clk *t0_clk;
++      u32 rate, divided_rate = 0;
++      int best_divisor_idx = -1;
++      int clk32k_divisor_idx = -1;
++      int i;
 +
-+              spin_lock_irq(&gpio->lock);
++      tc = atmel_tc_alloc(CONFIG_ATMEL_TCB_CLKSRC_BLOCK, clksrc.name);
++      if (!tc) {
++              pr_debug("can't alloc TC for clocksource\n");
++              return -ENODEV;
 +      }
++      tcaddr = tc->regs;
++      pdev = tc->pdev;
 +
-+      gpio->changed = 0;
-+      value = at32_gpio_get_value_multiple(gpio->port, gpio->pin_mask);
++      t0_clk = tc->clk[0];
++      clk_enable(t0_clk);
 +
-+      spin_unlock_irq(&gpio->lock);
++      /* How fast will we be counting?  Pick something over 5 MHz.  */
++      rate = (u32) clk_get_rate(t0_clk);
++      for (i = 0; i < 5; i++) {
++              unsigned divisor = atmel_tc_divisors[i];
++              unsigned tmp;
 +
-+      count = min(count, (size_t)4);
-+      if (copy_to_user(buf, &value, count))
-+              return -EFAULT;
++              /* remember 32 KiHz clock for later */
++              if (!divisor) {
++                      clk32k_divisor_idx = i;
++                      continue;
++              }
 +
-+      return count;
-+}
++              tmp = rate / divisor;
++              pr_debug("TC: %u / %-3u [%d] --> %u\n", rate, divisor, i, tmp);
++              if (best_divisor_idx > 0) {
++                      if (tmp < 5 * 1000 * 1000)
++                              continue;
++              }
++              divided_rate = tmp;
++              best_divisor_idx = i;
++      }
 +
-+static ssize_t gpio_dev_write(struct file *file, const char __user *buf,
-+                            size_t count, loff_t *offset)
-+{
-+      struct gpio_item *gpio = file->private_data;
-+      u32 value = 0;
-+      u32 mask = ~0UL;
++      clksrc.mult = clocksource_hz2mult(divided_rate, clksrc.shift);
 +
-+      count = min(count, (size_t)4);
-+      if (copy_from_user(&value, buf, count))
-+              return -EFAULT;
++      printk(bootinfo, clksrc.name, CONFIG_ATMEL_TCB_CLKSRC_BLOCK,
++                      divided_rate / 1000000,
++                      ((divided_rate + 500000) % 1000000) / 1000);
 +
-+      /* Assuming big endian */
-+      mask <<= (4 - count) * 8;
-+      mask &= gpio->pin_mask;
++      /* tclib will give us three clocks no matter what the
++       * underlying platform supports.
++       */
++      clk_enable(tc->clk[1]);
 +
-+      at32_gpio_set_value_multiple(gpio->port, value, mask);
++      /* channel 0:  waveform mode, input mclk/8, clock TIOA0 on overflow */
++      __raw_writel(best_divisor_idx                   /* likely divide-by-8 */
++                      | ATMEL_TC_WAVE
++                      | ATMEL_TC_WAVESEL_UP           /* free-run */
++                      | ATMEL_TC_ACPA_SET             /* TIOA0 rises at 0 */
++                      | ATMEL_TC_ACPC_CLEAR,          /* (duty cycle 50%) */
++                      tcaddr + ATMEL_TC_REG(0, CMR));
++      __raw_writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA));
++      __raw_writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC));
++      __raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR));      /* no irqs */
++      __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
 +
-+      return count;
-+}
++      /* channel 1:  waveform mode, input TIOA0 */
++      __raw_writel(ATMEL_TC_XC1                       /* input: TIOA0 */
++                      | ATMEL_TC_WAVE
++                      | ATMEL_TC_WAVESEL_UP,          /* free-run */
++                      tcaddr + ATMEL_TC_REG(1, CMR));
++      __raw_writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR));      /* no irqs */
++      __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR));
 +
-+static struct file_operations gpio_dev_fops = {
-+      .owner          = THIS_MODULE,
-+      .llseek         = no_llseek,
-+      .open           = gpio_dev_open,
-+      .release        = gpio_dev_release,
-+      .fasync         = gpio_dev_fasync,
-+      .poll           = gpio_dev_poll,
-+      .read           = gpio_dev_read,
-+      .write          = gpio_dev_write,
-+};
++      /* chain channel 0 to channel 1, then reset all the timers */
++      __raw_writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR);
++      __raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
 +
-+static struct gpio_item *to_gpio_item(struct config_item *item)
-+{
-+      return item ? container_of(item, struct gpio_item, item) : NULL;
-+}
++      /* and away we go! */
++      clocksource_register(&clksrc);
 +
-+static ssize_t gpio_show_gpio_id(struct gpio_item *gpio, char *page)
-+{
-+      return sprintf(page, "%d\n", gpio->port);
++      /* channel 2:  periodic and oneshot timer support */
++      setup_clkevents(tc, clk32k_divisor_idx);
++
++      return 0;
 +}
++arch_initcall(tcb_clksrc_init);
+diff --exclude=.git -urN linux-2.6.25.6/drivers/i2c/busses/i2c-atmeltwi.c avr32-2.6/drivers/i2c/busses/i2c-atmeltwi.c
+--- linux-2.6.25.6/drivers/i2c/busses/i2c-atmeltwi.c   1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/drivers/i2c/busses/i2c-atmeltwi.c        2008-06-12 15:09:40.391816588 +0200
+@@ -0,0 +1,436 @@
++/*
++ * i2c Support for Atmel's Two-Wire Interface (TWI)
++ *
++ * Based on the work of Copyright (C) 2004 Rick Bronson
++ * Converted to 2.6 by Andrew Victor <andrew at sanpeople.com>
++ * Ported to AVR32 and heavily modified by Espen Krangnes
++ * <ekrangnes at atmel.com>
++ *
++ * Copyright (C) 2006 Atmel Corporation
++ *
++ * Borrowed heavily from the original work by:
++ * Copyright (C) 2000 Philip Edelbrock <phil at stimpy.netroedge.com>
++ *
++ * Partialy rewriten by Karel Hojdar <cmkaho at seznam.cz>
++ * bugs removed, interrupt routine markedly rewritten
++ *
++ * 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.
++ */
++#undef VERBOSE_DEBUG
 +
-+static ssize_t gpio_store_gpio_id(struct gpio_item *gpio,
-+                                const char *page, size_t count)
-+{
-+      unsigned long id;
-+      char *p = (char *)page;
-+      ssize_t ret = -EINVAL;
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/i2c.h>
++#include <linux/init.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/completion.h>
++#include <linux/io.h>
 +
-+      id = simple_strtoul(p, &p, 0);
-+      if (!p || (*p && (*p != '\n')))
-+              return -EINVAL;
++#include "i2c-atmeltwi.h"
 +
-+      /* Switching PIO is not allowed when live... */
-+      spin_lock(&gpio->lock);
-+      if (!gpio->enabled) {
-+              ret = -ENXIO;
-+              if (at32_gpio_port_is_valid(id)) {
-+                      gpio->port = id;
-+                      ret = count;
-+              }
-+      }
-+      spin_unlock(&gpio->lock);
++static unsigned int baudrate = 100 * 1000;
++module_param(baudrate, uint, S_IRUGO);
++MODULE_PARM_DESC(baudrate, "The TWI baudrate");
 +
-+      return ret;
-+}
 +
-+static ssize_t gpio_show_pin_mask(struct gpio_item *gpio, char *page)
-+{
-+      return sprintf(page, "0x%08x\n", gpio->pin_mask);
-+}
++struct atmel_twi {
++      void __iomem *regs;
++      struct i2c_adapter adapter;
++      struct clk *pclk;
++      struct completion comp;
++      u32 mask;
++      u8 *buf;
++      u16 len;
++      u16 acks_left;
++      int status;
++      unsigned int irq;
 +
-+static ssize_t gpio_store_pin_mask(struct gpio_item *gpio,
-+                                 const char *page, size_t count)
++};
++#define to_atmel_twi(adap) container_of(adap, struct atmel_twi, adapter)
++
++/*
++ * (Re)Initialize the TWI hardware registers.
++ */
++static int twi_hwinit(struct atmel_twi *twi)
 +{
-+      u32 new_mask;
-+      char *p = (char *)page;
-+      ssize_t ret = -EINVAL;
++      unsigned long cdiv, ckdiv = 0;
 +
-+      new_mask = simple_strtoul(p, &p, 0);
-+      if (!p || (*p && (*p != '\n')))
-+              return -EINVAL;
++      /* REVISIT: wait till SCL is high before resetting; otherwise,
++       * some versions will wedge forever.
++       */
 +
-+      /* Can't update the pin mask while live. */
-+      spin_lock(&gpio->lock);
-+      if (!gpio->enabled) {
-+              gpio->oe_mask &= new_mask;
-+              gpio->pin_mask = new_mask;
-+              ret = count;
-+      }
-+      spin_unlock(&gpio->lock);
-+
-+      return ret;
-+}
-+
-+static ssize_t gpio_show_oe_mask(struct gpio_item *gpio, char *page)
-+{
-+      return sprintf(page, "0x%08x\n", gpio->oe_mask);
-+}
-+
-+static ssize_t gpio_store_oe_mask(struct gpio_item *gpio,
-+                                const char *page, size_t count)
-+{
-+      u32 mask;
-+      char *p = (char *)page;
-+      ssize_t ret = -EINVAL;
++      twi_writel(twi, IDR, ~0UL);
++      twi_writel(twi, CR, TWI_BIT(SWRST));    /*Reset peripheral*/
++      twi_readl(twi, SR);
 +
-+      mask = simple_strtoul(p, &p, 0);
-+      if (!p || (*p && (*p != '\n')))
-+              return -EINVAL;
++      cdiv = (clk_get_rate(twi->pclk) / (2 * baudrate)) - 4;
 +
-+      spin_lock(&gpio->lock);
-+      if (!gpio->enabled) {
-+              gpio->oe_mask = mask & gpio->pin_mask;
-+              ret = count;
++      while (cdiv > 255) {
++              ckdiv++;
++              cdiv = cdiv >> 1;
 +      }
-+      spin_unlock(&gpio->lock);
 +
-+      return ret;
-+}
++      /* REVISIT: there are various errata to consider re CDIV and CHDIV
++       * here, at least on at91 parts.
++       */
 +
-+static ssize_t gpio_show_enabled(struct gpio_item *gpio, char *page)
-+{
-+      return sprintf(page, "%d\n", gpio->enabled);
++      if (ckdiv > 7)
++              return -EINVAL;
++      else
++              twi_writel(twi, CWGR, TWI_BF(CKDIV, ckdiv)
++                              | TWI_BF(CHDIV, cdiv)
++                              | TWI_BF(CLDIV, cdiv));
++      return 0;
 +}
 +
-+static ssize_t gpio_store_enabled(struct gpio_item *gpio,
-+                                const char *page, size_t count)
++/*
++ * Waits for the i2c status register to set the specified bitmask
++ * Returns 0 if timed out ... ~100ms is much longer than the SMBus
++ * limit, but I2C has no limit at all.
++ */
++static int twi_complete(struct atmel_twi *twi, u32 mask)
 +{
-+      char *p = (char *)page;
-+      int enabled;
-+      int ret;
++      int timeout = msecs_to_jiffies(100);
 +
-+      enabled = simple_strtoul(p, &p, 0);
-+      if (!p || (*p && (*p != '\n')))
-+              return -EINVAL;
++      mask |= TWI_BIT(TXCOMP);
++      twi->mask = mask | TWI_BIT(NACK) | TWI_BIT(OVRE);
++      init_completion(&twi->comp);
 +
-+      /* make it a boolean value */
-+      enabled = !!enabled;
++      twi_writel(twi, IER, mask);
 +
-+      if (gpio->enabled == enabled)
-+              /* No change; do nothing. */
-+              return count;
++      if (!wait_for_completion_timeout(&twi->comp, timeout)) {
++              /* RESET TWI interface */
++              twi_writel(twi, CR, TWI_BIT(SWRST));
 +
-+      BUG_ON(gpio->id >= GPIO_DEV_MAX);
++              /* Reinitialize TWI */
++              twi_hwinit(twi);
 +
-+      if (!enabled) {
-+              class_device_unregister(gpio->gpio_dev);
-+              cdev_del(&gpio->char_dev);
-+              at32_deselect_pins(gpio->port, gpio->pin_mask);
-+              gpio->initialized = 0;
-+      } else {
-+              if (gpio->port < 0 || !gpio->pin_mask)
-+                      return -ENODEV;
++              return -ETIMEDOUT;
 +      }
++      return 0;
++}
 +
-+      /* Disallow any updates to gpio_id or pin_mask */
-+      spin_lock(&gpio->lock);
-+      gpio->enabled = enabled;
-+      spin_unlock(&gpio->lock);
++/*
++ * Generic i2c master transfer entrypoint.
++ */
++static int twi_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num)
++{
++      struct atmel_twi *twi = to_atmel_twi(adap);
++      int i;
 +
-+      if (!enabled)
-+              return count;
++      dev_dbg(&adap->dev, "twi_xfer: processing %d messages:\n", num);
 +
-+      /* Now, try to allocate the pins */
-+      ret = at32_select_gpio_pins(gpio->port, gpio->pin_mask, gpio->oe_mask);
-+      if (ret)
-+              goto err_alloc_pins;
++      twi->status = 0;
++      for (i = 0; i < num; i++, pmsg++) {
++              twi->len = pmsg->len;
++              twi->buf = pmsg->buf;
++              twi->acks_left = pmsg->len;
++              twi_writel(twi, MMR, TWI_BF(DADR, pmsg->addr) |
++                      (pmsg->flags & I2C_M_RD ? TWI_BIT(MREAD) : 0));
++              twi_writel(twi, IADR, TWI_BF(IADR, pmsg->addr));
 +
-+      gpio->initialized = 1;
++              dev_dbg(&adap->dev,
++                      "#%d: %s %d byte%s %s dev 0x%02x\n",
++                      i,
++                      pmsg->flags & I2C_M_RD ? "reading" : "writing",
++                      pmsg->len,
++                      pmsg->len > 1 ? "s" : "",
++                      pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr);
 +
-+      cdev_init(&gpio->char_dev, &gpio_dev_fops);
-+      gpio->char_dev.owner = THIS_MODULE;
-+      ret = cdev_add(&gpio->char_dev, MKDEV(MAJOR(gpio_devt), gpio->id), 1);
-+      if (ret < 0)
-+              goto err_cdev_add;
-+      gpio->gpio_dev = class_device_create(gpio_dev_class, NULL,
-+                                           MKDEV(MAJOR(gpio_devt), gpio->id),
-+                                           NULL,
-+                                           "gpio%d", gpio->id);
-+      if (IS_ERR(gpio->gpio_dev)) {
-+              printk(KERN_ERR "failed to create gpio%d\n", gpio->id);
-+              ret = PTR_ERR(gpio->gpio_dev);
-+              goto err_class_dev;
-+      }
++              /* enable */
++              twi_writel(twi, CR, TWI_BIT(MSEN));
 +
-+      printk(KERN_INFO "created gpio%d (port%d/0x%08x) as (%d:%d)\n",
-+             gpio->id, gpio->port, gpio->pin_mask,
-+             MAJOR(gpio->gpio_dev->devt), MINOR(gpio->gpio_dev->devt));
++              if (pmsg->flags & I2C_M_RD) {
++                      /* cleanup after previous RX overruns */
++                      while (twi_readl(twi, SR) & TWI_BIT(RXRDY))
++                              twi_readl(twi, RHR);
 +
-+      return 0;
++                      if (twi->len == 1)
++                              twi_writel(twi, CR,
++                                      TWI_BIT(START) | TWI_BIT(STOP));
++                      else
++                              twi_writel(twi, CR, TWI_BIT(START));
 +
-+err_class_dev:
-+      cdev_del(&gpio->char_dev);
-+err_cdev_add:
-+      at32_deselect_pins(gpio->port, gpio->pin_mask);
-+      gpio->initialized = 0;
-+err_alloc_pins:
-+      spin_lock(&gpio->lock);
-+      gpio->enabled = 0;
-+      spin_unlock(&gpio->lock);
++                      if (twi_complete(twi, TWI_BIT(RXRDY)) == -ETIMEDOUT) {
++                              dev_dbg(&adap->dev, "RX[%d] timeout. "
++                                      "Stopped with %d bytes left\n",
++                                      i, twi->acks_left);
++                              return -ETIMEDOUT;
++                      }
++              } else {
++                      twi_writel(twi, THR, twi->buf[0]);
++                      twi->acks_left--;
++                      /* REVISIT: some chips don't start automagically:
++                       * twi_writel(twi, CR, TWI_BIT(START));
++                       */
++                      if (twi_complete(twi, TWI_BIT(TXRDY)) == -ETIMEDOUT) {
++                              dev_dbg(&adap->dev, "TX[%d] timeout. "
++                                      "Stopped with %d bytes left\n",
++                                      i, twi->acks_left);
++                              return -ETIMEDOUT;
++                      }
++                      /* REVISIT: an erratum workaround may be needed here;
++                       * see sam9261 "STOP not generated" (START either).
++                       */
++              }
 +
-+      return ret;
-+}
++              /* Disable TWI interface */
++              twi_writel(twi, CR, TWI_BIT(MSDIS));
 +
-+static struct gpio_attribute gpio_item_attr_gpio_id = {
-+      .attr = {
-+              .ca_owner = THIS_MODULE,
-+              .ca_name = "gpio_id",
-+              .ca_mode = S_IRUGO | S_IWUSR,
-+      },
-+      .show = gpio_show_gpio_id,
-+      .store = gpio_store_gpio_id,
-+};
-+static struct gpio_attribute gpio_item_attr_pin_mask = {
-+      .attr = {
-+              .ca_owner = THIS_MODULE,
-+              .ca_name = "pin_mask",
-+              .ca_mode = S_IRUGO | S_IWUSR,
-+      },
-+      .show = gpio_show_pin_mask,
-+      .store = gpio_store_pin_mask,
-+};
-+static struct gpio_attribute gpio_item_attr_oe_mask = {
-+      .attr = {
-+              .ca_owner = THIS_MODULE,
-+              .ca_name = "oe_mask",
-+              .ca_mode = S_IRUGO | S_IWUSR,
-+      },
-+      .show = gpio_show_oe_mask,
-+      .store = gpio_store_oe_mask,
-+};
-+static struct gpio_attribute gpio_item_attr_enabled = {
-+      .attr = {
-+              .ca_owner = THIS_MODULE,
-+              .ca_name = "enabled",
-+              .ca_mode = S_IRUGO | S_IWUSR,
-+      },
-+      .show = gpio_show_enabled,
-+      .store = gpio_store_enabled,
-+};
++              if (twi->status)
++                      return twi->status;
 +
-+static struct configfs_attribute *gpio_item_attrs[] = {
-+      &gpio_item_attr_gpio_id.attr,
-+      &gpio_item_attr_pin_mask.attr,
-+      &gpio_item_attr_oe_mask.attr,
-+      &gpio_item_attr_enabled.attr,
-+      NULL,
-+};
++              /* WARNING:  This driver lies about properly supporting
++               * repeated start, or it would *ALWAYS* return here.  It
++               * has issued a STOP.  Continuing is a false claim -- that
++               * a second (or third, etc.) message is part of the same
++               * "combined" (no STOPs between parts) message.
++               */
 +
-+static ssize_t gpio_show_attr(struct config_item *item,
-+                            struct configfs_attribute *attr,
-+                            char *page)
-+{
-+      struct gpio_item *gpio_item = to_gpio_item(item);
-+      struct gpio_attribute *gpio_attr
-+              = container_of(attr, struct gpio_attribute, attr);
-+      ssize_t ret = 0;
++      } /* end cur msg */
 +
-+      if (gpio_attr->show)
-+              ret = gpio_attr->show(gpio_item, page);
-+      return ret;
++      return i;
 +}
 +
-+static ssize_t gpio_store_attr(struct config_item *item,
-+                             struct configfs_attribute *attr,
-+                             const char *page, size_t count)
-+{
-+      struct gpio_item *gpio_item = to_gpio_item(item);
-+      struct gpio_attribute *gpio_attr
-+              = container_of(attr, struct gpio_attribute, attr);
-+      ssize_t ret = -EINVAL;
 +
-+      if (gpio_attr->store)
-+              ret = gpio_attr->store(gpio_item, page, count);
-+      return ret;
-+}
-+
-+static void gpio_release(struct config_item *item)
-+{
-+      kfree(to_gpio_item(item));
-+}
-+
-+static struct configfs_item_operations gpio_item_ops = {
-+      .release                = gpio_release,
-+      .show_attribute         = gpio_show_attr,
-+      .store_attribute        = gpio_store_attr,
-+};
-+
-+static struct config_item_type gpio_item_type = {
-+      .ct_item_ops    = &gpio_item_ops,
-+      .ct_attrs       = gpio_item_attrs,
-+      .ct_owner       = THIS_MODULE,
-+};
-+
-+static struct config_item *gpio_make_item(struct config_group *group,
-+                                        const char *name)
++static irqreturn_t twi_interrupt(int irq, void *dev_id)
 +{
-+      static int next_id;
-+      struct gpio_item *gpio;
++      struct atmel_twi *twi = dev_id;
++      int status = twi_readl(twi, SR);
 +
-+      if (next_id >= GPIO_DEV_MAX)
-+              return NULL;
++      /* Save state for later debug prints */
++      int old_status = status;
 +
-+      gpio = kzalloc(sizeof(struct gpio_item), GFP_KERNEL);
-+      if (!gpio)
-+              return NULL;
++      if (twi->mask & status) {
 +
-+      gpio->id = next_id++;
-+      config_item_init_type_name(&gpio->item, name, &gpio_item_type);
-+      spin_lock_init(&gpio->lock);
-+      init_waitqueue_head(&gpio->change_wq);
++              status &= twi->mask;
 +
-+      return &gpio->item;
-+}
++              if (status & TWI_BIT(RXRDY)) {
++                      if ((status & TWI_BIT(OVRE)) && twi->acks_left) {
++                              /* Note weakness in fault reporting model:
++                               * we can't say "the first N of these data
++                               * bytes are valid".
++                               */
++                              dev_err(&twi->adapter.dev,
++                                      "OVERRUN RX! %04x, lost %d\n",
++                                      old_status, twi->acks_left);
++                              twi->acks_left = 0;
++                              twi_writel(twi, CR, TWI_BIT(STOP));
++                              twi->status = -EOVERFLOW;
++                      } else if (twi->acks_left > 0) {
++                              twi->buf[twi->len - twi->acks_left] =
++                                      twi_readl(twi, RHR);
++                              twi->acks_left--;
++                      }
++                      if (status & TWI_BIT(TXCOMP))
++                              goto done;
++                      if (twi->acks_left == 1)
++                              twi_writel(twi, CR, TWI_BIT(STOP));
 +
-+static void gpio_drop_item(struct config_group *group,
-+                         struct config_item *item)
-+{
-+      struct gpio_item *gpio = to_gpio_item(item);
++              } else if (status & (TWI_BIT(NACK) | TWI_BIT(TXCOMP))) {
++                      goto done;
 +
-+      spin_lock(&gpio->lock);
-+      if (gpio->enabled) {
-+              class_device_unregister(gpio->gpio_dev);
-+              cdev_del(&gpio->char_dev);
-+      }
++              } else if (status & TWI_BIT(TXRDY)) {
++                      if (twi->acks_left > 0) {
++                              twi_writel(twi, THR,
++                                      twi->buf[twi->len - twi->acks_left]);
++                              twi->acks_left--;
++                      } else
++                              twi_writel(twi, CR, TWI_BIT(STOP));
++              }
 +
-+      if (gpio->initialized) {
-+              at32_deselect_pins(gpio->port, gpio->pin_mask);
-+              gpio->initialized = 0;
-+              gpio->enabled = 0;
++              if (twi->acks_left == 0)
++                      twi_writel(twi, IDR, ~TWI_BIT(TXCOMP));
 +      }
-+      spin_unlock(&gpio->lock);
-+}
-+
-+static struct configfs_group_operations gpio_group_ops = {
-+      .make_item      = gpio_make_item,
-+      .drop_item      = gpio_drop_item,
-+};
 +
-+static struct config_item_type gpio_group_type = {
-+      .ct_group_ops   = &gpio_group_ops,
-+      .ct_owner       = THIS_MODULE,
-+};
++      /* enabling this message helps trigger overruns/underruns ... */
++      dev_vdbg(&twi->adapter.dev,
++              "ISR: SR 0x%04X, mask 0x%04X, acks %i\n",
++              old_status,
++              twi->acks_left ? twi->mask : TWI_BIT(TXCOMP),
++              twi->acks_left);
 +
-+static struct configfs_subsystem gpio_subsys = {
-+      .su_group = {
-+              .cg_item = {
-+                       .ci_namebuf = "gpio",
-+                       .ci_type = &gpio_group_type,
-+               },
-+      },
-+};
++      return IRQ_HANDLED;
 +
-+static int __init gpio_dev_init(void)
-+{
-+      int err;
++done:
++      /* Note weak fault reporting model:  we can't report how many
++       * bytes we sent before the NAK, or let upper layers choose
++       * whether to continue.  The I2C stack doesn't allow that...
++       */
++      if (status & TWI_BIT(NACK)) {
++              dev_dbg(&twi->adapter.dev, "NACK received! %d to go\n",
++                      twi->acks_left);
++              twi->status = -EPIPE;
 +
-+      gpio_dev_class = class_create(THIS_MODULE, "gpio-dev");
-+      if (IS_ERR(gpio_dev_class)) {
-+              err = PTR_ERR(gpio_dev_class);
-+              goto err_class_create;
++      /* TX underrun morphs automagically into a premature STOP;
++       * we'll probably observe UVRE even when it's not documented.
++       */
++      } else if (twi->acks_left && (twi->mask & TWI_BIT(TXRDY))) {
++              dev_err(&twi->adapter.dev, "UNDERRUN TX!  %04x, %d to go\n",
++                      old_status, twi->acks_left);
++              twi->status = -ENOSR;
 +      }
 +
-+      err = alloc_chrdev_region(&gpio_devt, 0, GPIO_DEV_MAX, "gpio");
-+      if (err < 0)
-+              goto err_alloc_chrdev;
-+
-+      /* Configfs initialization */
-+      config_group_init(&gpio_subsys.su_group);
-+      mutex_init(&gpio_subsys.su_mutex);
-+      err = configfs_register_subsystem(&gpio_subsys);
-+      if (err)
-+              goto err_register_subsys;
++      twi_writel(twi, IDR, ~0UL);
++      complete(&twi->comp);
 +
-+      return 0;
++      dev_dbg(&twi->adapter.dev, "ISR: SR 0x%04X, acks %i --> %d\n",
++              old_status, twi->acks_left, twi->status);
 +
-+err_register_subsys:
-+      unregister_chrdev_region(gpio_devt, GPIO_DEV_MAX);
-+err_alloc_chrdev:
-+      class_destroy(gpio_dev_class);
-+err_class_create:
-+      printk(KERN_WARNING "Failed to initialize gpio /dev interface\n");
-+      return err;
++      return IRQ_HANDLED;
 +}
-+late_initcall(gpio_dev_init);
---- a/arch/avr32/mach-at32ap/intc.c
-+++ b/arch/avr32/mach-at32ap/intc.c
-@@ -13,7 +13,6 @@
- #include <linux/irq.h>
- #include <linux/platform_device.h>
--#include <asm/intc.h>
- #include <asm/io.h>
- #include "intc.h"
---- a/arch/avr32/mach-at32ap/Kconfig
-+++ b/arch/avr32/mach-at32ap/Kconfig
-@@ -3,9 +3,9 @@
- menu "Atmel AVR32 AP options"
- choice
--      prompt "AT32AP7000 static memory bus width"
--      depends on CPU_AT32AP7000
--      default AP7000_16_BIT_SMC
-+      prompt "AT32AP700x static memory bus width"
-+      depends on CPU_AT32AP700X
-+      default AP700X_16_BIT_SMC
-       help
-         Define the width of the AP7000 external static memory interface.
-         This is used to determine how to mangle the address and/or data
-@@ -15,17 +15,24 @@
-         width for all chip selects, excluding the flash (which is using
-         raw access and is thus not affected by any of this.)
--config AP7000_32_BIT_SMC
-+config AP700X_32_BIT_SMC
-       bool "32 bit"
--config AP7000_16_BIT_SMC
-+config AP700X_16_BIT_SMC
-       bool "16 bit"
--config AP7000_8_BIT_SMC
-+config AP700X_8_BIT_SMC
-       bool "8 bit"
- endchoice
-+config GPIO_DEV
-+      bool "GPIO /dev interface"
-+      select CONFIGFS_FS
-+      default n
-+      help
-+        Say `Y' to enable a /dev interface to the GPIO pins.
 +
- endmenu
- endif # PLATFORM_AT32AP
---- a/arch/avr32/mach-at32ap/Makefile
-+++ b/arch/avr32/mach-at32ap/Makefile
-@@ -1,4 +1,4 @@
- obj-y                         += at32ap.o clock.o intc.o extint.o pio.o hsmc.o
--obj-$(CONFIG_CPU_AT32AP7000)  += at32ap7000.o
--obj-$(CONFIG_CPU_AT32AP7000)  += time-tc.o
-+obj-$(CONFIG_CPU_AT32AP700X)  += at32ap700x.o pm-at32ap700x.o
- obj-$(CONFIG_CPU_FREQ_AT32AP) += cpufreq.o
-+obj-$(CONFIG_GPIO_DEV)                += gpio-dev.o
---- a/arch/avr32/mach-at32ap/pio.c
-+++ b/arch/avr32/mach-at32ap/pio.c
-@@ -162,6 +162,82 @@
-       dump_stack();
- }
-+#ifdef CONFIG_GPIO_DEV
 +
-+/* Gang allocators and accessors; used by the GPIO /dev driver */
-+int at32_gpio_port_is_valid(unsigned int port)
++/*
++ * Return list of supported functionality.
++ *
++ * NOTE:  see warning above about repeated starts; this driver is falsely
++ * claiming to support "combined" transfers.  The mid-message STOPs mean
++ * some slaves will never work with this driver.  (Use i2c-gpio...)
++ */
++static u32 twi_func(struct i2c_adapter *adapter)
 +{
-+      return port < MAX_NR_PIO_DEVICES && pio_dev[port].regs != NULL;
++      return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL)
++              & ~I2C_FUNC_SMBUS_QUICK;
 +}
 +
-+int at32_select_gpio_pins(unsigned int port, u32 pins, u32 oe_mask)
++static struct i2c_algorithm twi_algorithm = {
++      .master_xfer    = twi_xfer,
++      .functionality  = twi_func,
++};
++
++/*
++ * Main initialization routine.
++ */
++static int __init twi_probe(struct platform_device *pdev)
 +{
-+      struct pio_device *pio;
-+      u32 old, new;
++      struct atmel_twi *twi;
++      struct resource *regs;
++      struct clk *pclk;
++      struct i2c_adapter *adapter;
++      int rc, irq;
 +
-+      pio = &pio_dev[port];
-+      BUG_ON(port > ARRAY_SIZE(pio_dev) || !pio->regs || (oe_mask & ~pins));
++      regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (!regs)
++              return -ENXIO;
 +
-+      /* Try to allocate the pins */
-+      do {
-+              old = pio->pinmux_mask;
-+              if (old & pins)
-+                      return -EBUSY;
++      pclk = clk_get(&pdev->dev, "twi_pclk");
++      if (IS_ERR(pclk))
++              return PTR_ERR(pclk);
++      clk_enable(pclk);
 +
-+              new = old | pins;
-+      } while (cmpxchg(&pio->pinmux_mask, old, new) != old);
++      rc = -ENOMEM;
++      twi = kzalloc(sizeof(struct atmel_twi), GFP_KERNEL);
++      if (!twi) {
++              dev_dbg(&pdev->dev, "can't allocate interface!\n");
++              goto err_alloc_twi;
++      }
 +
-+      /* That went well, now configure the port */
-+      pio_writel(pio, OER, oe_mask);
-+      pio_writel(pio, PER, pins);
++      twi->pclk = pclk;
++      twi->regs = ioremap(regs->start, regs->end - regs->start + 1);
++      if (!twi->regs)
++              goto err_ioremap;
 +
-+      return 0;
-+}
++      irq = platform_get_irq(pdev, 0);
++      rc = request_irq(irq, twi_interrupt, 0, "twi", twi);
++      if (rc) {
++              dev_dbg(&pdev->dev, "can't bind irq!\n");
++              goto err_irq;
++      }
++      twi->irq = irq;
 +
-+void at32_deselect_pins(unsigned int port, u32 pins)
-+{
-+      struct pio_device *pio;
-+      u32 old, new;
++      rc = twi_hwinit(twi);
++      if (rc) {
++              dev_err(&pdev->dev, "Unable to set baudrate\n");
++              goto err_hw_init;
++      }
 +
-+      pio = &pio_dev[port];
-+      BUG_ON(port > ARRAY_SIZE(pio_dev) || !pio->regs);
++      adapter = &twi->adapter;
++      sprintf(adapter->name, "TWI");
++      adapter->algo = &twi_algorithm;
++      adapter->class = I2C_CLASS_ALL;
++      adapter->nr = pdev->id;
++      adapter->dev.parent = &pdev->dev;
 +
-+      /* Return to a "safe" mux configuration */
-+      pio_writel(pio, PUER, pins);
-+      pio_writel(pio, ODR, pins);
++      platform_set_drvdata(pdev, twi);
 +
-+      /* Deallocate the pins */
-+      do {
-+              old = pio->pinmux_mask;
-+              new = old & ~pins;
-+      } while (cmpxchg(&pio->pinmux_mask, old, new) != old);
-+}
++      rc = i2c_add_numbered_adapter(adapter);
++      if (rc) {
++              dev_dbg(&pdev->dev, "Adapter %s registration failed\n",
++                      adapter->name);
++              goto err_register;
++      }
 +
-+u32 at32_gpio_get_value_multiple(unsigned int port, u32 pins)
-+{
-+      struct pio_device *pio;
++      dev_info(&pdev->dev,
++              "Atmel TWI/I2C adapter (baudrate %dk) at 0x%08lx.\n",
++               baudrate/1000, (unsigned long)regs->start);
 +
-+      pio = &pio_dev[port];
-+      BUG_ON(port > ARRAY_SIZE(pio_dev) || !pio->regs);
++      return 0;
 +
-+      return pio_readl(pio, PDSR) & pins;
++
++err_register:
++      platform_set_drvdata(pdev, NULL);
++
++err_hw_init:
++      free_irq(irq, twi);
++
++err_irq:
++      iounmap(twi->regs);
++
++err_ioremap:
++      kfree(twi);
++
++err_alloc_twi:
++      clk_disable(pclk);
++      clk_put(pclk);
++
++      return rc;
 +}
 +
-+void at32_gpio_set_value_multiple(unsigned int port, u32 value, u32 mask)
++static int __exit twi_remove(struct platform_device *pdev)
 +{
-+      struct pio_device *pio;
++      struct atmel_twi *twi = platform_get_drvdata(pdev);
++      int res;
 +
-+      pio = &pio_dev[port];
-+      BUG_ON(port > ARRAY_SIZE(pio_dev) || !pio->regs);
++      platform_set_drvdata(pdev, NULL);
++      res = i2c_del_adapter(&twi->adapter);
++      twi_writel(twi, CR, TWI_BIT(MSDIS));
++      iounmap(twi->regs);
++      clk_disable(twi->pclk);
++      clk_put(twi->pclk);
++      free_irq(twi->irq, twi);
++      kfree(twi);
 +
-+      /* No atomic updates for now... */
-+      pio_writel(pio, CODR, ~value & mask);
-+      pio_writel(pio, SODR, value & mask);
++      return res;
 +}
 +
-+#endif /* CONFIG_GPIO_DEV */
++static struct platform_driver twi_driver = {
++      .remove         = __exit_p(twi_remove),
++      .driver         = {
++              .name   = "atmel_twi",
++              .owner  = THIS_MODULE,
++      },
++};
++
++static int __init atmel_twi_init(void)
++{
++      return platform_driver_probe(&twi_driver, twi_probe);
++}
++
++static void __exit atmel_twi_exit(void)
++{
++      platform_driver_unregister(&twi_driver);
++}
 +
++module_init(atmel_twi_init);
++module_exit(atmel_twi_exit);
 +
- /*--------------------------------------------------------------------------*/
- /* GPIO API */
---- /dev/null
-+++ b/arch/avr32/mach-at32ap/pm-at32ap700x.S
-@@ -0,0 +1,66 @@
++MODULE_AUTHOR("Espen Krangnes");
++MODULE_DESCRIPTION("I2C driver for Atmel TWI");
++MODULE_LICENSE("GPL");
+diff --exclude=.git -urN linux-2.6.25.6/drivers/i2c/busses/i2c-atmeltwi.h avr32-2.6/drivers/i2c/busses/i2c-atmeltwi.h
+--- linux-2.6.25.6/drivers/i2c/busses/i2c-atmeltwi.h   1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/drivers/i2c/busses/i2c-atmeltwi.h        2008-06-12 15:09:40.391816588 +0200
+@@ -0,0 +1,117 @@
 +/*
-+ * Low-level Power Management code.
-+ *
-+ * Copyright (C) 2008 Atmel Corporation
-+ *
-+ * 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.
++ * Register definitions for the Atmel Two-Wire Interface
 + */
-+#include <asm/asm.h>
-+#include <asm/asm-offsets.h>
-+#include <asm/thread_info.h>
-+#include <asm/arch/pm.h>
 +
-+      .section .bss, "wa", @nobits
-+      .global disable_idle_sleep
-+      .type   disable_idle_sleep, @object
-+disable_idle_sleep:
-+      .int    4
-+      .size   disable_idle_sleep, . - disable_idle_sleep
++#ifndef __ATMELTWI_H__
++#define __ATMELTWI_H__
 +
-+      /* Keep this close to the irq handlers */
-+      .section .irq.text, "ax", @progbits
++/* TWI register offsets */
++#define TWI_CR                                        0x0000
++#define TWI_MMR                                       0x0004
++#define TWI_SMR                                       0x0008
++#define TWI_IADR                              0x000c
++#define TWI_CWGR                              0x0010
++#define TWI_SR                                        0x0020
++#define TWI_IER                                       0x0024
++#define TWI_IDR                                       0x0028
++#define TWI_IMR                                       0x002c
++#define TWI_RHR                                       0x0030
++#define TWI_THR                                       0x0034
 +
-+      /*
-+       * void cpu_enter_idle(void)
-+       *
-+       * Put the CPU into "idle" mode, in which it will consume
-+       * significantly less power.
-+       *
-+       * If an interrupt comes along in the window between
-+       * unmask_interrupts and the sleep instruction below, the
-+       * interrupt code will adjust the return address so that we
-+       * never execute the sleep instruction. This is required
-+       * because the AP7000 doesn't unmask interrupts when entering
-+       * sleep modes; later CPUs may not need this workaround.
-+       */
-+      .global cpu_enter_idle
-+      .type   cpu_enter_idle, @function
-+cpu_enter_idle:
-+      mask_interrupts
-+      get_thread_info r8
-+      ld.w    r9, r8[TI_flags]
-+      bld     r9, TIF_NEED_RESCHED
-+      brcs    .Lret_from_sleep
-+      sbr     r9, TIF_CPU_GOING_TO_SLEEP
-+      st.w    r8[TI_flags], r9
-+      unmask_interrupts
-+      sleep   CPU_SLEEP_IDLE
-+      .size   cpu_idle_sleep, . - cpu_idle_sleep
++/* Bitfields in CR */
++#define TWI_START_OFFSET                      0
++#define TWI_START_SIZE                                1
++#define TWI_STOP_OFFSET                               1
++#define TWI_STOP_SIZE                         1
++#define TWI_MSEN_OFFSET                               2
++#define TWI_MSEN_SIZE                         1
++#define TWI_MSDIS_OFFSET                      3
++#define TWI_MSDIS_SIZE                                1
++#define TWI_SVEN_OFFSET                               4
++#define TWI_SVEN_SIZE                         1
++#define TWI_SVDIS_OFFSET                      5
++#define TWI_SVDIS_SIZE                                1
++#define TWI_SWRST_OFFSET                      7
++#define TWI_SWRST_SIZE                                1
 +
-+      /*
-+       * Common return path for PM functions that don't run from
-+       * SRAM.
-+       */
-+      .global cpu_idle_skip_sleep
-+      .type   cpu_idle_skip_sleep, @function
-+cpu_idle_skip_sleep:
-+      mask_interrupts
-+      ld.w    r9, r8[TI_flags]
-+      cbr     r9, TIF_CPU_GOING_TO_SLEEP
-+      st.w    r8[TI_flags], r9
-+.Lret_from_sleep:
-+      unmask_interrupts
-+      retal   r12
-+      .size   cpu_idle_skip_sleep, . - cpu_idle_skip_sleep
---- a/arch/avr32/mach-at32ap/time-tc.c
-+++ /dev/null
-@@ -1,218 +0,0 @@
--/*
-- * Copyright (C) 2004-2007 Atmel Corporation
-- *
-- * Based on MIPS implementation arch/mips/kernel/time.c
-- *   Copyright 2001 MontaVista Software Inc.
-- *
-- * 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/clk.h>
--#include <linux/clocksource.h>
--#include <linux/time.h>
--#include <linux/module.h>
--#include <linux/interrupt.h>
--#include <linux/irq.h>
--#include <linux/kernel_stat.h>
--#include <linux/errno.h>
--#include <linux/init.h>
--#include <linux/profile.h>
--#include <linux/sysdev.h>
--#include <linux/err.h>
--
--#include <asm/div64.h>
--#include <asm/sysreg.h>
--#include <asm/io.h>
--#include <asm/sections.h>
--
--#include <asm/arch/time.h>
--
--/* how many counter cycles in a jiffy? */
--static u32 cycles_per_jiffy;
--
--/* the count value for the next timer interrupt */
--static u32 expirelo;
--
--/* the I/O registers of the TC module */
--static void __iomem *ioregs;
--
--cycle_t read_cycle_count(void)
--{
--      return (cycle_t)timer_read(ioregs, 0, CV);
--}
--
--struct clocksource clocksource_avr32 = {
--      .name           = "avr32",
--      .rating         = 342,
--      .read           = read_cycle_count,
--      .mask           = CLOCKSOURCE_MASK(16),
--      .shift          = 16,
--      .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
--};
--
--static void avr32_timer_ack(void)
--{
--      u16 count = expirelo;
--
--      /* Ack this timer interrupt and set the next one, use a u16
--       * variable so it will wrap around correctly */
--      count += cycles_per_jiffy;
--      expirelo = count;
--      timer_write(ioregs, 0, RC, expirelo);
--
--      /* Check to see if we have missed any timer interrupts */
--      count = timer_read(ioregs, 0, CV);
--      if ((count - expirelo) < 0x7fff) {
--              expirelo = count + cycles_per_jiffy;
--              timer_write(ioregs, 0, RC, expirelo);
--      }
--}
--
--u32 avr32_hpt_read(void)
--{
--      return timer_read(ioregs, 0, CV);
--}
--
--static int avr32_timer_calc_div_and_set_jiffies(struct clk *pclk)
--{
--      unsigned int cycles_max = (clocksource_avr32.mask + 1) / 2;
--      unsigned int divs[] = { 4, 8, 16, 32 };
--      int divs_size = ARRAY_SIZE(divs);
--      int i = 0;
--      unsigned long count_hz;
--      unsigned long shift;
--      unsigned long mult;
--      int clock_div = -1;
--      u64 tmp;
--
--      shift = clocksource_avr32.shift;
--
--      do {
--              count_hz = clk_get_rate(pclk) / divs[i];
--              mult = clocksource_hz2mult(count_hz, shift);
--              clocksource_avr32.mult = mult;
--
--              tmp = TICK_NSEC;
--              tmp <<= shift;
--              tmp += mult / 2;
--              do_div(tmp, mult);
--
--              cycles_per_jiffy = tmp;
--      } while (cycles_per_jiffy > cycles_max && ++i < divs_size);
--
--      clock_div = i + 1;
--
--      if (clock_div > divs_size) {
--              pr_debug("timer: could not calculate clock divider\n");
--              return -EFAULT;
--      }
--
--      /* Set the clock divider */
--      timer_write(ioregs, 0, CMR, TIMER_BF(CMR_TCCLKS, clock_div));
--
--      return 0;
--}
--
--int avr32_hpt_init(unsigned int count)
--{
--      struct resource *regs;
--      struct clk *pclk;
--      int irq = -1;
--      int ret = 0;
--
--      ret = -ENXIO;
--
--      irq = platform_get_irq(&at32_systc0_device, 0);
--      if (irq < 0) {
--              pr_debug("timer: could not get irq\n");
--              goto out_error;
--      }
--
--      pclk = clk_get(&at32_systc0_device.dev, "pclk");
--      if (IS_ERR(pclk)) {
--              pr_debug("timer: could not get clk: %ld\n", PTR_ERR(pclk));
--              goto out_error;
--      }
--      clk_enable(pclk);
--
--      regs = platform_get_resource(&at32_systc0_device, IORESOURCE_MEM, 0);
--      if (!regs) {
--              pr_debug("timer: could not get resource\n");
--              goto out_error_clk;
--      }
--
--      ioregs = ioremap(regs->start, regs->end - regs->start + 1);
--      if (!ioregs) {
--              pr_debug("timer: could not get ioregs\n");
--              goto out_error_clk;
--      }
--
--      ret = avr32_timer_calc_div_and_set_jiffies(pclk);
--      if (ret)
--              goto out_error_io;
--
--      ret = setup_irq(irq, &timer_irqaction);
--      if (ret) {
--              pr_debug("timer: could not request irq %d: %d\n",
--                              irq, ret);
--              goto out_error_io;
--      }
--
--      expirelo = (timer_read(ioregs, 0, CV) / cycles_per_jiffy + 1)
--              * cycles_per_jiffy;
--
--      /* Enable clock and interrupts on RC compare */
--      timer_write(ioregs, 0, CCR, TIMER_BIT(CCR_CLKEN));
--      timer_write(ioregs, 0, IER, TIMER_BIT(IER_CPCS));
--      /* Set cycles to first interrupt */
--      timer_write(ioregs, 0,  RC, expirelo);
--
--      printk(KERN_INFO "timer: AT32AP system timer/counter at 0x%p irq %d\n",
--                      ioregs, irq);
--
--      return 0;
--
--out_error_io:
--      iounmap(ioregs);
--out_error_clk:
--      clk_put(pclk);
--out_error:
--      return ret;
--}
--
--int avr32_hpt_start(void)
--{
--      timer_write(ioregs, 0, CCR, TIMER_BIT(CCR_SWTRG));
--      return 0;
--}
--
--irqreturn_t timer_interrupt(int irq, void *dev_id)
--{
--      unsigned int sr = timer_read(ioregs, 0, SR);
--
--      if (sr & TIMER_BIT(SR_CPCS)) {
--              /* ack timer interrupt and try to set next interrupt */
--              avr32_timer_ack();
--
--              /*
--               * Call the generic timer interrupt handler
--               */
--              write_seqlock(&xtime_lock);
--              do_timer(1);
--              write_sequnlock(&xtime_lock);
--
--              /*
--               * In UP mode, we call local_timer_interrupt() to do profiling
--               * and process accounting.
--               *
--               * SMP is not supported yet.
--               */
--              local_timer_interrupt(irq, dev_id);
--
--              return IRQ_HANDLED;
--      }
--
--      return IRQ_NONE;
--}
---- a/arch/avr32/Makefile
-+++ b/arch/avr32/Makefile
-@@ -16,7 +16,7 @@
- CFLAGS_MODULE += -mno-relax
- LDFLAGS_vmlinux       += --relax
--cpuflags-$(CONFIG_CPU_AT32AP7000)     += -mcpu=ap7000
-+cpuflags-$(CONFIG_PLATFORM_AT32AP)    += -march=ap
- KBUILD_CFLAGS += $(cpuflags-y)
- KBUILD_AFLAGS += $(cpuflags-y)
-@@ -31,6 +31,8 @@
- core-$(CONFIG_LOADER_U_BOOT)          += arch/avr32/boot/u-boot/
- core-y                                        += arch/avr32/kernel/
- core-y                                        += arch/avr32/mm/
-+drivers-$(CONFIG_OPROFILE)            += arch/avr32/oprofile/
-+drivers-y                             += arch/avr32/drivers/
- libs-y                                        += arch/avr32/lib/
++/* Bitfields in MMR */
++#define TWI_IADRSZ_OFFSET                     8
++#define TWI_IADRSZ_SIZE                               2
++#define TWI_MREAD_OFFSET                      12
++#define TWI_MREAD_SIZE                                1
++#define TWI_DADR_OFFSET                               16
++#define TWI_DADR_SIZE                         7
++
++/* Bitfields in SMR */
++#define TWI_SADR_OFFSET                               16
++#define TWI_SADR_SIZE                         7
++
++/* Bitfields in IADR */
++#define TWI_IADR_OFFSET                               0
++#define TWI_IADR_SIZE                         24
++
++/* Bitfields in CWGR */
++#define TWI_CLDIV_OFFSET                      0
++#define TWI_CLDIV_SIZE                                8
++#define TWI_CHDIV_OFFSET                      8
++#define TWI_CHDIV_SIZE                                8
++#define TWI_CKDIV_OFFSET                      16
++#define TWI_CKDIV_SIZE                                3
++
++/* Bitfields in SR */
++#define TWI_TXCOMP_OFFSET                     0
++#define TWI_TXCOMP_SIZE                               1
++#define TWI_RXRDY_OFFSET                      1
++#define TWI_RXRDY_SIZE                                1
++#define TWI_TXRDY_OFFSET                      2
++#define TWI_TXRDY_SIZE                                1
++#define TWI_SVDIR_OFFSET                      3
++#define TWI_SVDIR_SIZE                                1
++#define TWI_SVACC_OFFSET                      4
++#define TWI_SVACC_SIZE                                1
++#define TWI_GCACC_OFFSET                      5
++#define TWI_GCACC_SIZE                                1
++#define TWI_OVRE_OFFSET                               6
++#define TWI_OVRE_SIZE                         1
++#define TWI_UNRE_OFFSET                               7
++#define TWI_UNRE_SIZE                         1
++#define TWI_NACK_OFFSET                               8
++#define TWI_NACK_SIZE                         1
++#define TWI_ARBLST_OFFSET                     9
++#define TWI_ARBLST_SIZE                               1
++
++/* Bitfields in RHR */
++#define TWI_RXDATA_OFFSET                     0
++#define TWI_RXDATA_SIZE                               8
++
++/* Bitfields in THR */
++#define TWI_TXDATA_OFFSET                     0
++#define TWI_TXDATA_SIZE                               8
++
++/* Constants for IADRSZ */
++#define TWI_IADRSZ_NO_ADDR                    0
++#define TWI_IADRSZ_ONE_BYTE                   1
++#define TWI_IADRSZ_TWO_BYTES                  2
++#define TWI_IADRSZ_THREE_BYTES                        3
++
++/* Bit manipulation macros */
++#define TWI_BIT(name)                                 \
++      (1 << TWI_##name##_OFFSET)
++#define TWI_BF(name, value)                           \
++      (((value) & ((1 << TWI_##name##_SIZE) - 1))     \
++       << TWI_##name##_OFFSET)
++#define TWI_BFEXT(name, value)                                \
++      (((value) >> TWI_##name##_OFFSET)               \
++       & ((1 << TWI_##name##_SIZE) - 1))
++#define TWI_BFINS(name, value, old)                   \
++      (((old) & ~(((1 << TWI_##name##_SIZE) - 1)      \
++                  << TWI_##name##_OFFSET))            \
++       | TWI_BF(name, (value)))
++
++/* Register access macros */
++#define twi_readl(port, reg)                          \
++      __raw_readl((port)->regs + TWI_##reg)
++#define twi_writel(port, reg, value)                  \
++      __raw_writel((value), (port)->regs + TWI_##reg)
++
++#endif /* __ATMELTWI_H__ */
+diff --exclude=.git -urN linux-2.6.25.6/drivers/i2c/busses/Kconfig avr32-2.6/drivers/i2c/busses/Kconfig
+--- linux-2.6.25.6/drivers/i2c/busses/Kconfig  2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/i2c/busses/Kconfig       2008-06-12 15:09:40.383816128 +0200
+@@ -88,6 +88,14 @@
+         to support combined I2C messages.  Use the i2c-gpio driver
+         unless your system can cope with those limitations.
  
- archincdir-$(CONFIG_PLATFORM_AT32AP)  := arch-at32ap
---- a/arch/avr32/mm/dma-coherent.c
-+++ b/arch/avr32/mm/dma-coherent.c
-@@ -41,6 +41,13 @@
-       struct page *page, *free, *end;
-       int order;
-+      /* Following is a work-around (a.k.a. hack) to prevent pages
-+       * with __GFP_COMP being passed to split_page() which cannot
-+       * handle them.  The real problem is that this flag probably
-+       * should be 0 on AVR32 as it is not supported on this
-+       * platform--see CONFIG_HUGETLB_PAGE. */
-+      gfp &= ~(__GFP_COMP);
-+
-       size = PAGE_ALIGN(size);
-       order = get_order(size);
---- a/arch/avr32/mm/fault.c
-+++ b/arch/avr32/mm/fault.c
-@@ -189,6 +189,8 @@
-       page = sysreg_read(PTBR);
-       printk(KERN_ALERT "ptbr = %08lx", page);
-+      if (address >= TASK_SIZE)
-+              page = (unsigned long)swapper_pg_dir;
-       if (page) {
-               page = ((unsigned long *)page)[address >> 22];
-               printk(" pgd = %08lx", page);
---- a/arch/avr32/mm/tlb.c
-+++ b/arch/avr32/mm/tlb.c
-@@ -348,7 +348,7 @@
-       return 0;
- }
++config I2C_ATMELTWI
++      tristate "Atmel Two-Wire Interface (TWI)"
++      depends on I2C && (ARCH_AT91 || PLATFORM_AT32AP)
++      help
++        Atmel on-chip TWI controller. Say Y if you have an AT32 or
++        AT91-based device and want to use its built-in TWI
++        functionality.
++
+ config I2C_AU1550
+       tristate "Au1550/Au1200 SMBus interface"
+       depends on SOC_AU1550 || SOC_AU1200
+diff --exclude=.git -urN linux-2.6.25.6/drivers/i2c/busses/Makefile avr32-2.6/drivers/i2c/busses/Makefile
+--- linux-2.6.25.6/drivers/i2c/busses/Makefile 2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/i2c/busses/Makefile      2008-06-12 15:09:40.383816128 +0200
+@@ -52,6 +52,7 @@
+ obj-$(CONFIG_I2C_VOODOO3)     += i2c-voodoo3.o
+ obj-$(CONFIG_SCx200_ACB)      += scx200_acb.o
+ obj-$(CONFIG_SCx200_I2C)      += scx200_i2c.o
++obj-$(CONFIG_I2C_ATMELTWI)    += i2c-atmeltwi.o
  
--static struct seq_operations tlb_ops = {
-+static const struct seq_operations tlb_ops = {
-       .start          = tlb_start,
-       .next           = tlb_next,
-       .stop           = tlb_stop,
---- /dev/null
-+++ b/arch/avr32/oprofile/Makefile
-@@ -0,0 +1,8 @@
-+obj-$(CONFIG_OPROFILE) += oprofile.o
-+
-+oprofile-y            := $(addprefix ../../../drivers/oprofile/,      \
-+                              oprof.o cpu_buffer.o buffer_sync.o      \
-+                              event_buffer.o oprofile_files.o         \
-+                              oprofilefs.o oprofile_stats.o           \
-+                              timer_int.o)
-+oprofile-y            += op_model_avr32.o
---- /dev/null
-+++ b/arch/avr32/oprofile/op_model_avr32.c
-@@ -0,0 +1,234 @@
+ ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
+ EXTRA_CFLAGS += -DDEBUG
+diff --exclude=.git -urN linux-2.6.25.6/drivers/input/serio/at32psif.c avr32-2.6/drivers/input/serio/at32psif.c
+--- linux-2.6.25.6/drivers/input/serio/at32psif.c      1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/drivers/input/serio/at32psif.c   2008-06-12 15:09:40.619816021 +0200
+@@ -0,0 +1,351 @@
++/*
++ * Copyright (C) 2007 Atmel Corporation
++ *
++ * Driver for the AT32AP700X PS/2 controller (PSIF).
++ *
++ * 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/kernel.h>
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/init.h>
++#include <linux/serio.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/clk.h>
++#include <linux/platform_device.h>
++
++#include "at32psif.h"
++
++#define PSIF_BUF_SIZE         16
++
++#define ring_is_empty(_psif)  (_psif->head == _psif->tail)
++#define ring_next_head(_psif) ((_psif->head + 1) & (PSIF_BUF_SIZE - 1))
++#define ring_next_tail(_psif) ((_psif->tail + 1) & (PSIF_BUF_SIZE - 1))
++
++struct psif {
++      struct platform_device  *pdev;
++      struct clk              *pclk;
++      struct serio            *io;
++      struct timer_list       tx_timer;
++      void __iomem            *regs;
++      unsigned int            irq;
++      unsigned int            open;
++      /* Prevent concurrent writes to circular buffer. */
++      spinlock_t              lock;
++      unsigned int            head;
++      unsigned int            tail;
++      unsigned char           buffer[PSIF_BUF_SIZE];
++};
++
++static irqreturn_t psif_interrupt(int irq, void *_ptr)
++{
++      struct psif *psif = _ptr;
++      int retval = IRQ_NONE;
++      unsigned int io_flags = 0;
++      unsigned long status;
++
++      status = psif_readl(psif, SR);
++
++      if (status & PSIF_BIT(RXRDY)) {
++              unsigned char val = (unsigned char) psif_readl(psif, RHR);
++
++              if (status & PSIF_BIT(PARITY))
++                      io_flags |= SERIO_PARITY;
++              if (status & PSIF_BIT(OVRUN))
++                      dev_err(&psif->pdev->dev, "overrun read error\n");
++
++              serio_interrupt(psif->io, val, io_flags);
++
++              retval = IRQ_HANDLED;
++      }
++
++      spin_lock(&psif->lock);
++
++      if (status & PSIF_BIT(TXEMPTY)) {
++              if (status & PSIF_BIT(NACK))
++                      dev_err(&psif->pdev->dev, "NACK error\n");
++
++              psif_writel(psif, IDR, PSIF_BIT(TXEMPTY));
++
++              if (!ring_is_empty(psif))
++                      mod_timer(&psif->tx_timer,
++                                      jiffies + msecs_to_jiffies(1));
++
++              retval = IRQ_HANDLED;
++      }
++
++      spin_unlock(&psif->lock);
++
++      return retval;
++}
++
++static void psif_transmit_data(unsigned long data)
++{
++      struct psif *psif = (struct psif *)data;
++      unsigned long flags;
++
++      spin_lock_irqsave(&psif->lock, flags);
++
++      psif_writel(psif, THR, psif->buffer[psif->tail]);
++      psif->tail = ring_next_tail(psif);
++
++      if (!ring_is_empty(psif))
++              psif_writel(psif, IER, PSIF_BIT(TXEMPTY));
++
++      spin_unlock_irqrestore(&psif->lock, flags);
++}
++
++static int psif_write(struct serio *io, unsigned char val)
++{
++      struct psif *psif = io->port_data;
++      unsigned long flags;
++      unsigned int head;
++
++      spin_lock_irqsave(&psif->lock, flags);
++
++      head = ring_next_head(psif);
++
++      if (head != psif->tail) {
++              psif->buffer[psif->head] = val;
++              psif->head = head;
++      } else {
++              dev_err(&psif->pdev->dev, "underrun write error\n");
++      }
++
++      spin_unlock_irqrestore(&psif->lock, flags);
++
++      /* Make sure TXEMPTY interrupt is enabled. */
++      psif_writel(psif, IER, PSIF_BIT(TXEMPTY));
++
++      return 0;
++}
++
++static int psif_open(struct serio *io)
++{
++      struct psif *psif = io->port_data;
++      int retval;
++
++      retval = clk_enable(psif->pclk);
++      if (retval)
++              goto out;
++
++      psif_writel(psif, CR, PSIF_BIT(CR_TXEN) | PSIF_BIT(CR_RXEN));
++      psif_writel(psif, IER, PSIF_BIT(RXRDY));
++
++      psif->open = 1;
++out:
++      return retval;
++}
++
++static void psif_close(struct serio *io)
++{
++      struct psif *psif = io->port_data;
++
++      psif->open = 0;
++
++      psif_writel(psif, IDR, ~0UL);
++      psif_writel(psif, CR, PSIF_BIT(CR_TXDIS) | PSIF_BIT(CR_RXDIS));
++
++      clk_disable(psif->pclk);
++}
++
++static void psif_set_prescaler(struct psif *psif)
++{
++      unsigned long prscv;
++      unsigned long rate = clk_get_rate(psif->pclk);
++
++      /* PRSCV = Pulse length (100 us) * PSIF module frequency. */
++      prscv = 100 * (rate / 1000000UL);
++
++      if (prscv > ((1<<PSIF_PSR_PRSCV_SIZE) - 1)) {
++              prscv = (1<<PSIF_PSR_PRSCV_SIZE) - 1;
++              dev_dbg(&psif->pdev->dev, "pclk too fast, "
++                              "prescaler set to max\n");
++      }
++
++      clk_enable(psif->pclk);
++      psif_writel(psif, PSR, prscv);
++      clk_disable(psif->pclk);
++}
++
++static int __init psif_probe(struct platform_device *pdev)
++{
++      struct resource *regs;
++      struct psif *psif;
++      struct serio *io;
++      struct clk *pclk;
++      int irq;
++      int ret;
++
++      psif = kzalloc(sizeof(struct psif), GFP_KERNEL);
++      if (!psif) {
++              dev_dbg(&pdev->dev, "out of memory\n");
++              ret = -ENOMEM;
++              goto out;
++      }
++      psif->pdev = pdev;
++
++      io = kzalloc(sizeof(struct serio), GFP_KERNEL);
++      if (!io) {
++              dev_dbg(&pdev->dev, "out of memory\n");
++              ret = -ENOMEM;
++              goto out_free_psif;
++      }
++      psif->io = io;
++
++      regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (!regs) {
++              dev_dbg(&pdev->dev, "no mmio resources defined\n");
++              ret = -ENOMEM;
++              goto out_free_io;
++      }
++
++      psif->regs = ioremap(regs->start, regs->end - regs->start + 1);
++      if (!psif->regs) {
++              ret = -ENOMEM;
++              dev_dbg(&pdev->dev, "could not map I/O memory\n");
++              goto out_free_io;
++      }
++
++      pclk = clk_get(&pdev->dev, "pclk");
++      if (IS_ERR(pclk)) {
++              dev_dbg(&pdev->dev, "could not get peripheral clock\n");
++              ret = PTR_ERR(pclk);
++              goto out_iounmap;
++      }
++      psif->pclk = pclk;
++
++      /* Reset the PSIF to enter at a known state. */
++      ret = clk_enable(pclk);
++      if (ret) {
++              dev_dbg(&pdev->dev, "could not enable pclk\n");
++              goto out_put_clk;
++      }
++      psif_writel(psif, CR, PSIF_BIT(CR_SWRST));
++      clk_disable(pclk);
++
++      setup_timer(&psif->tx_timer, psif_transmit_data, (unsigned long)psif);
++
++      irq = platform_get_irq(pdev, 0);
++      if (irq < 0) {
++              dev_dbg(&pdev->dev, "could not get irq\n");
++              ret = -ENXIO;
++              goto out_put_clk;
++      }
++      ret = request_irq(irq, psif_interrupt, IRQF_SHARED, "at32psif", psif);
++      if (ret) {
++              dev_dbg(&pdev->dev, "could not request irq %d\n", irq);
++              goto out_put_clk;
++      }
++      psif->irq = irq;
++
++      io->id.type     = SERIO_8042;
++      io->write       = psif_write;
++      io->open        = psif_open;
++      io->close       = psif_close;
++      strlcpy(io->name, pdev->dev.bus_id, sizeof(io->name));
++      strlcpy(io->phys, pdev->dev.bus_id, sizeof(io->phys));
++      io->port_data   = psif;
++      io->dev.parent  = &pdev->dev;
++
++      psif_set_prescaler(psif);
++
++      spin_lock_init(&psif->lock);
++      serio_register_port(psif->io);
++      platform_set_drvdata(pdev, psif);
++
++      dev_info(&pdev->dev, "Atmel AVR32 PSIF PS/2 driver on 0x%08x irq %d\n",
++                      (int)psif->regs, psif->irq);
++
++      return 0;
++
++out_put_clk:
++      clk_put(psif->pclk);
++out_iounmap:
++      iounmap(psif->regs);
++out_free_io:
++      kfree(io);
++out_free_psif:
++      kfree(psif);
++out:
++      return ret;
++}
++
++static int __exit psif_remove(struct platform_device *pdev)
++{
++      struct psif *psif = platform_get_drvdata(pdev);
++
++      psif_writel(psif, IDR, ~0UL);
++      psif_writel(psif, CR, PSIF_BIT(CR_TXDIS) | PSIF_BIT(CR_RXDIS));
++
++      serio_unregister_port(psif->io);
++      iounmap(psif->regs);
++      free_irq(psif->irq, psif);
++      clk_put(psif->pclk);
++      kfree(psif);
++
++      platform_set_drvdata(pdev, NULL);
++
++      return 0;
++}
++
++#ifdef CONFIG_PM
++static int psif_suspend(struct platform_device *pdev, pm_message_t state)
++{
++      struct psif *psif = platform_get_drvdata(pdev);
++
++      if (psif->open) {
++              psif_writel(psif, CR, PSIF_BIT(CR_RXDIS) | PSIF_BIT(CR_TXDIS));
++              clk_disable(psif->pclk);
++      }
++
++      return 0;
++}
++
++static int psif_resume(struct platform_device *pdev)
++{
++      struct psif *psif = platform_get_drvdata(pdev);
++
++      if (psif->open) {
++              clk_enable(psif->pclk);
++              psif_set_prescaler(psif);
++              psif_writel(psif, CR, PSIF_BIT(CR_RXEN) | PSIF_BIT(CR_TXEN));
++      }
++
++      return 0;
++}
++#else
++#define psif_suspend  NULL
++#define psif_resume   NULL
++#endif
++
++static struct platform_driver psif_driver = {
++      .remove         = __exit_p(psif_remove),
++      .driver         = {
++              .name   = "atmel_psif",
++      },
++      .suspend        = psif_suspend,
++      .resume         = psif_resume,
++};
++
++static int __init psif_init(void)
++{
++      return platform_driver_probe(&psif_driver, psif_probe);
++}
++
++static void __exit psif_exit(void)
++{
++      platform_driver_unregister(&psif_driver);
++}
++
++module_init(psif_init);
++module_exit(psif_exit);
++
++MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
++MODULE_DESCRIPTION("Atmel AVR32 PSIF PS/2 driver");
++MODULE_LICENSE("GPL");
+diff --exclude=.git -urN linux-2.6.25.6/drivers/input/serio/at32psif.h avr32-2.6/drivers/input/serio/at32psif.h
+--- linux-2.6.25.6/drivers/input/serio/at32psif.h      1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/drivers/input/serio/at32psif.h   2008-06-12 15:09:40.619816021 +0200
+@@ -0,0 +1,82 @@
++/*
++ * Copyright (C) 2007 Atmel Corporation
++ *
++ * Driver for the AT32AP700X PS/2 controller (PSIF).
++ *
++ * 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.
++ */
++
++#ifndef _AT32PSIF_H
++#define _AT32PSIF_H
++
++/* PSIF register offsets */
++#define PSIF_CR                               0x00
++#define PSIF_RHR                      0x04
++#define PSIF_THR                      0x08
++#define PSIF_SR                               0x10
++#define PSIF_IER                      0x14
++#define PSIF_IDR                      0x18
++#define PSIF_IMR                      0x1c
++#define PSIF_PSR                      0x24
++
++/* Bitfields in control register. */
++#define PSIF_CR_RXDIS_OFFSET          1
++#define PSIF_CR_RXDIS_SIZE            1
++#define PSIF_CR_RXEN_OFFSET           0
++#define PSIF_CR_RXEN_SIZE             1
++#define PSIF_CR_SWRST_OFFSET          15
++#define PSIF_CR_SWRST_SIZE            1
++#define PSIF_CR_TXDIS_OFFSET          9
++#define PSIF_CR_TXDIS_SIZE            1
++#define PSIF_CR_TXEN_OFFSET           8
++#define PSIF_CR_TXEN_SIZE             1
++
++/* Bitfields in interrupt disable, enable, mask and status register. */
++#define PSIF_NACK_OFFSET              8
++#define PSIF_NACK_SIZE                        1
++#define PSIF_OVRUN_OFFSET             5
++#define PSIF_OVRUN_SIZE                       1
++#define PSIF_PARITY_OFFSET            9
++#define PSIF_PARITY_SIZE              1
++#define PSIF_RXRDY_OFFSET             4
++#define PSIF_RXRDY_SIZE                       1
++#define PSIF_TXEMPTY_OFFSET           1
++#define PSIF_TXEMPTY_SIZE             1
++#define PSIF_TXRDY_OFFSET             0
++#define PSIF_TXRDY_SIZE                       1
++
++/* Bitfields in prescale register. */
++#define PSIF_PSR_PRSCV_OFFSET         0
++#define PSIF_PSR_PRSCV_SIZE           12
++
++/* Bitfields in receive hold register. */
++#define PSIF_RHR_RXDATA_OFFSET                0
++#define PSIF_RHR_RXDATA_SIZE          8
++
++/* Bitfields in transmit hold register. */
++#define PSIF_THR_TXDATA_OFFSET                0
++#define PSIF_THR_TXDATA_SIZE          8
++
++/* Bit manipulation macros */
++#define PSIF_BIT(name)                                        \
++      (1 << PSIF_##name##_OFFSET)
++#define PSIF_BF(name, value)                          \
++      (((value) & ((1 << PSIF_##name##_SIZE) - 1))    \
++       << PSIF_##name##_OFFSET)
++#define PSIF_BFEXT(name, value)\
++      (((value) >> PSIF_##name##_OFFSET)              \
++       & ((1 << PSIF_##name##_SIZE) - 1))
++#define PSIF_BFINS(name, value, old)                  \
++      (((old) & ~(((1 << PSIF_##name##_SIZE) - 1)     \
++                  << PSIF_##name##_OFFSET))           \
++       | PSIF_BF(name, value))
++
++/* Register access macros */
++#define psif_readl(port, reg)                         \
++      __raw_readl((port)->regs + PSIF_##reg)
++#define psif_writel(port, reg, value)                 \
++      __raw_writel((value), (port)->regs + PSIF_##reg)
++
++#endif /* _AT32PSIF_H */
+diff --exclude=.git -urN linux-2.6.25.6/drivers/input/serio/Kconfig avr32-2.6/drivers/input/serio/Kconfig
+--- linux-2.6.25.6/drivers/input/serio/Kconfig 2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/input/serio/Kconfig      2008-06-12 15:09:40.615815791 +0200
+@@ -88,6 +88,17 @@
+         To compile this driver as a module, choose M here: the
+         module will be called rpckbd.
++config SERIO_AT32PSIF
++      tristate "AVR32 PSIF PS/2 keyboard and mouse controller"
++      depends on AVR32
++      default n
++      help
++        Say Y here if you want to use the PSIF peripheral on AVR32 devices
++        and connect a PS/2 keyboard and/or mouse to it.
++
++        To compile this driver as a module, choose M here: the module will
++        be called at32psif.
++
+ config SERIO_AMBAKMI
+       tristate "AMBA KMI keyboard controller"
+       depends on ARM_AMBA
+diff --exclude=.git -urN linux-2.6.25.6/drivers/input/serio/Makefile avr32-2.6/drivers/input/serio/Makefile
+--- linux-2.6.25.6/drivers/input/serio/Makefile        2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/input/serio/Makefile     2008-06-12 15:03:58.919815686 +0200
+@@ -12,6 +12,7 @@
+ obj-$(CONFIG_SERIO_RPCKBD)    += rpckbd.o
+ obj-$(CONFIG_SERIO_SA1111)    += sa1111ps2.o
+ obj-$(CONFIG_SERIO_AMBAKMI)   += ambakmi.o
++obj-$(CONFIG_SERIO_AT32PSIF)  += at32psif.o
+ obj-$(CONFIG_SERIO_Q40KBD)    += q40kbd.o
+ obj-$(CONFIG_SERIO_GSCPS2)    += gscps2.o
+ obj-$(CONFIG_HP_SDC)          += hp_sdc.o
+diff --exclude=.git -urN linux-2.6.25.6/drivers/misc/atmel_tclib.c avr32-2.6/drivers/misc/atmel_tclib.c
+--- linux-2.6.25.6/drivers/misc/atmel_tclib.c  1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/drivers/misc/atmel_tclib.c       2008-06-12 15:03:59.515815344 +0200
+@@ -0,0 +1,161 @@
++#include <linux/atmel_tc.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++
++/* Number of bytes to reserve for the iomem resource */
++#define ATMEL_TC_IOMEM_SIZE   256
++
++
++/*
++ * This is a thin library to solve the problem of how to portably allocate
++ * one of the TC blocks.  For simplicity, it doesn't currently expect to
++ * share individual timers between different drivers.
++ */
++
++#if defined(CONFIG_AVR32)
++/* AVR32 has these divide PBB */
++const u8 atmel_tc_divisors[5] = { 0, 4, 8, 16, 32, };
++EXPORT_SYMBOL(atmel_tc_divisors);
++
++#elif defined(CONFIG_ARCH_AT91)
++/* AT91 has these divide MCK */
++const u8 atmel_tc_divisors[5] = { 2, 8, 32, 128, 0, };
++EXPORT_SYMBOL(atmel_tc_divisors);
++
++#endif
++
++static DEFINE_SPINLOCK(tc_list_lock);
++static LIST_HEAD(tc_list);
++
++/**
++ * atmel_tc_alloc - allocate a specified TC block
++ * @block: which block to allocate
++ * @name: name to be associated with the iomem resource
++ *
++ * Caller allocates a block.  If it is available, a pointer to a
++ * pre-initialized struct atmel_tc is returned. The caller can access
++ * the registers directly through the "regs" field.
++ */
++struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name)
++{
++      struct atmel_tc         *tc;
++      struct platform_device  *pdev = NULL;
++      struct resource         *r;
++
++      spin_lock(&tc_list_lock);
++      list_for_each_entry(tc, &tc_list, node) {
++              if (tc->pdev->id == block) {
++                      pdev = tc->pdev;
++                      break;
++              }
++      }
++
++      if (!pdev || tc->iomem)
++              goto fail;
++
++      r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      r = request_mem_region(r->start, ATMEL_TC_IOMEM_SIZE, name);
++      if (!r)
++              goto fail;
++
++      tc->regs = ioremap(r->start, ATMEL_TC_IOMEM_SIZE);
++      if (!tc->regs)
++              goto fail_ioremap;
++
++      tc->iomem = r;
++
++out:
++      spin_unlock(&tc_list_lock);
++      return tc;
++
++fail_ioremap:
++      release_resource(r);
++fail:
++      tc = NULL;
++      goto out;
++}
++EXPORT_SYMBOL_GPL(atmel_tc_alloc);
++
++/**
++ * atmel_tc_free - release a specified TC block
++ * @tc: Timer/counter block that was returned by atmel_tc_alloc()
++ *
++ * This reverses the effect of atmel_tc_alloc(), unmapping the I/O
++ * registers, invalidating the resource returned by that routine and
++ * making the TC available to other drivers.
++ */
++void atmel_tc_free(struct atmel_tc *tc)
++{
++      spin_lock(&tc_list_lock);
++      if (tc->regs) {
++              iounmap(tc->regs);
++              release_resource(tc->iomem);
++              tc->regs = NULL;
++              tc->iomem = NULL;
++      }
++      spin_unlock(&tc_list_lock);
++}
++EXPORT_SYMBOL_GPL(atmel_tc_free);
++
++static int __init tc_probe(struct platform_device *pdev)
++{
++      struct atmel_tc *tc;
++      struct clk      *clk;
++      int             irq;
++
++      if (!platform_get_resource(pdev, IORESOURCE_MEM, 0))
++              return -EINVAL;
++
++      irq = platform_get_irq(pdev, 0);
++      if (irq < 0)
++              return -EINVAL;
++
++      tc = kzalloc(sizeof(struct atmel_tc), GFP_KERNEL);
++      if (!tc)
++              return -ENOMEM;
++
++      tc->pdev = pdev;
++
++      clk = clk_get(&pdev->dev, "t0_clk");
++      if (IS_ERR(clk)) {
++              kfree(tc);
++              return -EINVAL;
++      }
++
++      tc->clk[0] = clk;
++      tc->clk[1] = clk_get(&pdev->dev, "t1_clk");
++      if (IS_ERR(tc->clk[1]))
++              tc->clk[1] = clk;
++      tc->clk[2] = clk_get(&pdev->dev, "t2_clk");
++      if (IS_ERR(tc->clk[2]))
++              tc->clk[2] = clk;
++
++      tc->irq[0] = irq;
++      tc->irq[1] = platform_get_irq(pdev, 1);
++      if (tc->irq[1] < 0)
++              tc->irq[1] = irq;
++      tc->irq[2] = platform_get_irq(pdev, 2);
++      if (tc->irq[2] < 0)
++              tc->irq[2] = irq;
++
++      spin_lock(&tc_list_lock);
++      list_add_tail(&tc->node, &tc_list);
++      spin_unlock(&tc_list_lock);
++
++      return 0;
++}
++
++static struct platform_driver tc_driver = {
++      .driver.name    = "atmel_tcb",
++};
++
++static int __init tc_init(void)
++{
++      return platform_driver_probe(&tc_driver, tc_probe);
++}
++arch_initcall(tc_init);
+diff --exclude=.git -urN linux-2.6.25.6/drivers/misc/Kconfig avr32-2.6/drivers/misc/Kconfig
+--- linux-2.6.25.6/drivers/misc/Kconfig        2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/misc/Kconfig     2008-06-12 15:09:41.067816939 +0200
+@@ -22,6 +22,39 @@
+         purposes including software controlled power-efficent backlights
+         on LCD displays, motor control, and waveform generation.
++config ATMEL_TCLIB
++      bool "Atmel AT32/AT91 Timer/Counter Library"
++      depends on (AVR32 || ARCH_AT91)
++      help
++        Select this if you want a library to allocate the Timer/Counter
++        blocks found on many Atmel processors.  This facilitates using
++        these blocks by different drivers despite processor differences.
++
++config ATMEL_TCB_CLKSRC
++      bool "TC Block Clocksource"
++      depends on ATMEL_TCLIB && GENERIC_TIME
++      default y
++      help
++        Select this to get a high precision clocksource based on a
++        TC block with a 5+ MHz base clock rate.  Two timer channels
++        are combined to make a single 32-bit timer.
++
++        When GENERIC_CLOCKEVENTS is defined, the third timer channel
++        may be used as a clock event device supporting oneshot mode
++        (delays of up to two seconds) based on the 32 KiHz clock.
++
++config ATMEL_TCB_CLKSRC_BLOCK
++      int
++      depends on ATMEL_TCB_CLKSRC
++      prompt "TC Block" if ARCH_AT91RM9200 || ARCH_AT91SAM9260 || CPU_AT32AP700X
++      default 0
++      range 0 1
++      help
++        Some chips provide more than one TC block, so you have the
++        choice of which one to use for the clock framework.  The other
++        TC can be used for other purposes, such as PWM generation and
++        interval timing.
++
+ config IBM_ASM
+       tristate "Device driver for IBM RSA service processor"
+       depends on X86 && PCI && INPUT && EXPERIMENTAL
+diff --exclude=.git -urN linux-2.6.25.6/drivers/misc/Makefile avr32-2.6/drivers/misc/Makefile
+--- linux-2.6.25.6/drivers/misc/Makefile       2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/misc/Makefile    2008-06-12 15:09:41.067816939 +0200
+@@ -10,6 +10,7 @@
+ obj-$(CONFIG_ASUS_LAPTOP)     += asus-laptop.o
+ obj-$(CONFIG_ATMEL_PWM)               += atmel_pwm.o
+ obj-$(CONFIG_ATMEL_SSC)               += atmel-ssc.o
++obj-$(CONFIG_ATMEL_TCLIB)     += atmel_tclib.o
+ obj-$(CONFIG_TC1100_WMI)      += tc1100-wmi.o
+ obj-$(CONFIG_LKDTM)           += lkdtm.o
+ obj-$(CONFIG_TIFM_CORE)               += tifm_core.o
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mmc/host/atmel-mci.c avr32-2.6/drivers/mmc/host/atmel-mci.c
+--- linux-2.6.25.6/drivers/mmc/host/atmel-mci.c        1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/drivers/mmc/host/atmel-mci.c     2008-06-12 15:09:41.083816184 +0200
+@@ -0,0 +1,1220 @@
++/*
++ * Atmel MultiMedia Card Interface driver
++ *
++ * Copyright (C) 2004-2006 Atmel Corporation
++ *
++ * 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/blkdev.h>
++#include <linux/clk.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <linux/mmc/host.h>
++
++#include <asm/dma-controller.h>
++#include <asm/io.h>
++#include <asm/arch/board.h>
++#include <asm/arch/gpio.h>
++
++#include "atmel-mci.h"
++
++#define DRIVER_NAME "atmel_mci"
++
++#define MCI_DATA_ERROR_FLAGS  (MCI_BIT(DCRCE) | MCI_BIT(DTOE) |       \
++                               MCI_BIT(OVRE) | MCI_BIT(UNRE))
++
++enum {
++      EVENT_CMD_COMPLETE = 0,
++      EVENT_DATA_COMPLETE,
++      EVENT_DATA_ERROR,
++      EVENT_STOP_SENT,
++      EVENT_STOP_COMPLETE,
++      EVENT_DMA_COMPLETE,
++      EVENT_DMA_ERROR,
++};
++
++struct atmel_mci_dma {
++      struct dma_request_sg   req;
++      unsigned short          rx_periph_id;
++      unsigned short          tx_periph_id;
++};
++
++struct atmel_mci {
++      struct mmc_host         *mmc;
++      void __iomem            *regs;
++      struct atmel_mci_dma    dma;
++
++      struct mmc_request      *mrq;
++      struct mmc_command      *cmd;
++      struct mmc_data         *data;
++
++      u32                     cmd_status;
++      u32                     data_status;
++      u32                     stop_status;
++      u32                     stop_cmdr;
++
++      struct tasklet_struct   tasklet;
++      unsigned long           pending_events;
++      unsigned long           completed_events;
++
++      int                     present;
++      int                     detect_pin;
++      int                     wp_pin;
++
++      /* For detect pin debouncing */
++      struct timer_list       detect_timer;
++
++      unsigned long           bus_hz;
++      unsigned long           mapbase;
++      struct clk              *mck;
++      struct platform_device  *pdev;
++
++#ifdef CONFIG_DEBUG_FS
++      struct dentry           *debugfs_root;
++      struct dentry           *debugfs_regs;
++      struct dentry           *debugfs_req;
++      struct dentry           *debugfs_pending_events;
++      struct dentry           *debugfs_completed_events;
++#endif
++};
++
++/* Those printks take an awful lot of time... */
++#ifndef DEBUG
++static unsigned int fmax = 15000000U;
++#else
++static unsigned int fmax = 1000000U;
++#endif
++module_param(fmax, uint, 0444);
++MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
++
++/* Test bit macros for completed events */
++#define mci_cmd_is_complete(host)                     \
++      test_bit(EVENT_CMD_COMPLETE, &host->completed_events)
++#define mci_data_is_complete(host)                    \
++      test_bit(EVENT_DATA_COMPLETE, &host->completed_events)
++#define mci_data_error_is_complete(host)              \
++      test_bit(EVENT_DATA_ERROR, &host->completed_events)
++#define mci_stop_sent_is_complete(host)                       \
++      test_bit(EVENT_STOP_SENT, &host->completed_events)
++#define mci_stop_is_complete(host)                    \
++      test_bit(EVENT_STOP_COMPLETE, &host->completed_events)
++#define mci_dma_is_complete(host)                     \
++      test_bit(EVENT_DMA_COMPLETE, &host->completed_events)
++#define mci_dma_error_is_complete(host)                       \
++      test_bit(EVENT_DMA_ERROR, &host->completed_events)
++
++/* Test and clear bit macros for pending events */
++#define mci_clear_cmd_is_pending(host)                        \
++      test_and_clear_bit(EVENT_CMD_COMPLETE, &host->pending_events)
++#define mci_clear_data_is_pending(host)                       \
++      test_and_clear_bit(EVENT_DATA_COMPLETE, &host->pending_events)
++#define mci_clear_data_error_is_pending(host)         \
++      test_and_clear_bit(EVENT_DATA_ERROR, &host->pending_events)
++#define mci_clear_stop_sent_is_pending(host)          \
++      test_and_clear_bit(EVENT_STOP_SENT, &host->pending_events)
++#define mci_clear_stop_is_pending(host)                       \
++      test_and_clear_bit(EVENT_STOP_COMPLETE, &host->pending_events)
++#define mci_clear_dma_error_is_pending(host)          \
++      test_and_clear_bit(EVENT_DMA_ERROR, &host->pending_events)
++
++/* Test and set bit macros for completed events */
++#define mci_set_cmd_is_completed(host)                        \
++      test_and_set_bit(EVENT_CMD_COMPLETE, &host->completed_events)
++#define mci_set_data_is_completed(host)                       \
++      test_and_set_bit(EVENT_DATA_COMPLETE, &host->completed_events)
++#define mci_set_data_error_is_completed(host)         \
++      test_and_set_bit(EVENT_DATA_ERROR, &host->completed_events)
++#define mci_set_stop_sent_is_completed(host)          \
++      test_and_set_bit(EVENT_STOP_SENT, &host->completed_events)
++#define mci_set_stop_is_completed(host)                       \
++      test_and_set_bit(EVENT_STOP_COMPLETE, &host->completed_events)
++#define mci_set_dma_error_is_completed(host)          \
++      test_and_set_bit(EVENT_DMA_ERROR, &host->completed_events)
++
++/* Set bit macros for completed events */
++#define mci_set_cmd_complete(host)                    \
++      set_bit(EVENT_CMD_COMPLETE, &host->completed_events)
++#define mci_set_data_complete(host)                   \
++      set_bit(EVENT_DATA_COMPLETE, &host->completed_events)
++#define mci_set_data_error_complete(host)             \
++      set_bit(EVENT_DATA_ERROR, &host->completed_events)
++#define mci_set_stop_sent_complete(host)              \
++      set_bit(EVENT_STOP_SENT, &host->completed_events)
++#define mci_set_stop_complete(host)                   \
++      set_bit(EVENT_STOP_COMPLETE, &host->completed_events)
++#define mci_set_dma_complete(host)                    \
++      set_bit(EVENT_DMA_COMPLETE, &host->completed_events)
++#define mci_set_dma_error_complete(host)              \
++      set_bit(EVENT_DMA_ERROR, &host->completed_events)
++
++/* Set bit macros for pending events */
++#define mci_set_cmd_pending(host)                     \
++      set_bit(EVENT_CMD_COMPLETE, &host->pending_events)
++#define mci_set_data_pending(host)                    \
++      set_bit(EVENT_DATA_COMPLETE, &host->pending_events)
++#define mci_set_data_error_pending(host)              \
++      set_bit(EVENT_DATA_ERROR, &host->pending_events)
++#define mci_set_stop_sent_pending(host)                       \
++      set_bit(EVENT_STOP_SENT, &host->pending_events)
++#define mci_set_stop_pending(host)                    \
++      set_bit(EVENT_STOP_COMPLETE, &host->pending_events)
++#define mci_set_dma_error_pending(host)                       \
++      set_bit(EVENT_DMA_ERROR, &host->pending_events)
++
++/* Clear bit macros for pending events */
++#define mci_clear_cmd_pending(host)                   \
++      clear_bit(EVENT_CMD_COMPLETE, &host->pending_events)
++#define mci_clear_data_pending(host)                  \
++      clear_bit(EVENT_DATA_COMPLETE, &host->pending_events)
++#define mci_clear_data_error_pending(host)            \
++      clear_bit(EVENT_DATA_ERROR, &host->pending_events)
++#define mci_clear_stop_sent_pending(host)             \
++      clear_bit(EVENT_STOP_SENT, &host->pending_events)
++#define mci_clear_stop_pending(host)                  \
++      clear_bit(EVENT_STOP_COMPLETE, &host->pending_events)
++#define mci_clear_dma_error_pending(host)             \
++      clear_bit(EVENT_DMA_ERROR, &host->pending_events)
++
++
++#ifdef CONFIG_DEBUG_FS
++#include <linux/debugfs.h>
++
++#define DBG_REQ_BUF_SIZE      (4096 - sizeof(unsigned int))
++
++struct req_dbg_data {
++      unsigned int nbytes;
++      char str[DBG_REQ_BUF_SIZE];
++};
++
++static int req_dbg_open(struct inode *inode, struct file *file)
++{
++      struct atmel_mci *host;
++      struct mmc_request *mrq;
++      struct mmc_command *cmd, *stop;
++      struct mmc_data *data;
++      struct req_dbg_data *priv;
++      char *str;
++      unsigned long n = 0;
++
++      priv = kzalloc(DBG_REQ_BUF_SIZE, GFP_KERNEL);
++      if (!priv)
++              return -ENOMEM;
++      str = priv->str;
++
++      mutex_lock(&inode->i_mutex);
++      host = inode->i_private;
++
++      spin_lock_irq(&host->mmc->lock);
++      mrq = host->mrq;
++      if (mrq) {
++              cmd = mrq->cmd;
++              data = mrq->data;
++              stop = mrq->stop;
++              n = snprintf(str, DBG_REQ_BUF_SIZE,
++                           "CMD%u(0x%x) %x %x %x %x %x (err %u)\n",
++                           cmd->opcode, cmd->arg, cmd->flags,
++                           cmd->resp[0], cmd->resp[1], cmd->resp[2],
++                           cmd->resp[3], cmd->error);
++              if (n < DBG_REQ_BUF_SIZE && data)
++                      n += snprintf(str + n, DBG_REQ_BUF_SIZE - n,
++                                    "DATA %u * %u (%u) %x (err %u)\n",
++                                    data->blocks, data->blksz,
++                                    data->bytes_xfered, data->flags,
++                                    data->error);
++              if (n < DBG_REQ_BUF_SIZE && stop)
++                      n += snprintf(str + n, DBG_REQ_BUF_SIZE - n,
++                                    "CMD%u(0x%x) %x %x %x %x %x (err %u)\n",
++                                    stop->opcode, stop->arg, stop->flags,
++                                    stop->resp[0], stop->resp[1],
++                                    stop->resp[2], stop->resp[3],
++                                    stop->error);
++      }
++      spin_unlock_irq(&host->mmc->lock);
++      mutex_unlock(&inode->i_mutex);
++
++      priv->nbytes = min(n, DBG_REQ_BUF_SIZE);
++      file->private_data = priv;
++
++      return 0;
++}
++
++static ssize_t req_dbg_read(struct file *file, char __user *buf,
++                          size_t nbytes, loff_t *ppos)
++{
++      struct req_dbg_data *priv = file->private_data;
++
++      return simple_read_from_buffer(buf, nbytes, ppos,
++                                     priv->str, priv->nbytes);
++}
++
++static int req_dbg_release(struct inode *inode, struct file *file)
++{
++      kfree(file->private_data);
++      return 0;
++}
++
++static const struct file_operations req_dbg_fops = {
++      .owner          = THIS_MODULE,
++      .open           = req_dbg_open,
++      .llseek         = no_llseek,
++      .read           = req_dbg_read,
++      .release        = req_dbg_release,
++};
++
++static int regs_dbg_open(struct inode *inode, struct file *file)
++{
++      struct atmel_mci *host;
++      unsigned int i;
++      u32 *data;
++      int ret = -ENOMEM;
++
++      mutex_lock(&inode->i_mutex);
++      host = inode->i_private;
++      data = kmalloc(inode->i_size, GFP_KERNEL);
++      if (!data)
++              goto out;
++
++      spin_lock_irq(&host->mmc->lock);
++      for (i = 0; i < inode->i_size / 4; i++)
++              data[i] = __raw_readl(host->regs + i * 4);
++      spin_unlock_irq(&host->mmc->lock);
++
++      file->private_data = data;
++      ret = 0;
++
++out:
++      mutex_unlock(&inode->i_mutex);
++
++      return ret;
++}
++
++static ssize_t regs_dbg_read(struct file *file, char __user *buf,
++                           size_t nbytes, loff_t *ppos)
++{
++      struct inode *inode = file->f_dentry->d_inode;
++      int ret;
++
++      mutex_lock(&inode->i_mutex);
++      ret = simple_read_from_buffer(buf, nbytes, ppos,
++                                    file->private_data,
++                                    file->f_dentry->d_inode->i_size);
++      mutex_unlock(&inode->i_mutex);
++
++      return ret;
++}
++
++static int regs_dbg_release(struct inode *inode, struct file *file)
++{
++      kfree(file->private_data);
++      return 0;
++}
++
++static const struct file_operations regs_dbg_fops = {
++      .owner          = THIS_MODULE,
++      .open           = regs_dbg_open,
++      .llseek         = generic_file_llseek,
++      .read           = regs_dbg_read,
++      .release        = regs_dbg_release,
++};
++
++static void atmci_init_debugfs(struct atmel_mci *host)
++{
++      struct mmc_host *mmc;
++      struct dentry *root, *regs;
++      struct resource *res;
++
++      mmc = host->mmc;
++      root = debugfs_create_dir(mmc_hostname(mmc), NULL);
++      if (IS_ERR(root) || !root)
++              goto err_root;
++      host->debugfs_root = root;
++
++      regs = debugfs_create_file("regs", 0400, root, host, &regs_dbg_fops);
++      if (!regs)
++              goto err_regs;
++
++      res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0);
++      regs->d_inode->i_size = res->end - res->start + 1;
++      host->debugfs_regs = regs;
++
++      host->debugfs_req = debugfs_create_file("req", 0400, root,
++                                              host, &req_dbg_fops);
++      if (!host->debugfs_req)
++              goto err_req;
++
++      host->debugfs_pending_events
++              = debugfs_create_u32("pending_events", 0400, root,
++                                   (u32 *)&host->pending_events);
++      if (!host->debugfs_pending_events)
++              goto err_pending_events;
++
++      host->debugfs_completed_events
++              = debugfs_create_u32("completed_events", 0400, root,
++                                   (u32 *)&host->completed_events);
++      if (!host->debugfs_completed_events)
++              goto err_completed_events;
++
++      return;
++
++err_completed_events:
++      debugfs_remove(host->debugfs_pending_events);
++err_pending_events:
++      debugfs_remove(host->debugfs_req);
++err_req:
++      debugfs_remove(host->debugfs_regs);
++err_regs:
++      debugfs_remove(host->debugfs_root);
++err_root:
++      host->debugfs_root = NULL;
++      dev_err(&host->pdev->dev,
++              "failed to initialize debugfs for %s\n",
++              mmc_hostname(mmc));
++}
++
++static void atmci_cleanup_debugfs(struct atmel_mci *host)
++{
++      if (host->debugfs_root) {
++              debugfs_remove(host->debugfs_completed_events);
++              debugfs_remove(host->debugfs_pending_events);
++              debugfs_remove(host->debugfs_req);
++              debugfs_remove(host->debugfs_regs);
++              debugfs_remove(host->debugfs_root);
++              host->debugfs_root = NULL;
++      }
++}
++#else
++static inline void atmci_init_debugfs(struct atmel_mci *host)
++{
++
++}
++
++static inline void atmci_cleanup_debugfs(struct atmel_mci *host)
++{
++
++}
++#endif /* CONFIG_DEBUG_FS */
++
++static inline unsigned int ns_to_clocks(struct atmel_mci *host,
++                                      unsigned int ns)
++{
++      return (ns * (host->bus_hz / 1000000) + 999) / 1000;
++}
++
++static void atmci_set_timeout(struct atmel_mci *host,
++                            struct mmc_data *data)
++{
++      static unsigned dtomul_to_shift[] = {
++              0, 4, 7, 8, 10, 12, 16, 20
++      };
++      unsigned timeout;
++      unsigned dtocyc, dtomul;
++
++      timeout = ns_to_clocks(host, data->timeout_ns) + data->timeout_clks;
++
++      for (dtomul = 0; dtomul < 8; dtomul++) {
++              unsigned shift = dtomul_to_shift[dtomul];
++              dtocyc = (timeout + (1 << shift) - 1) >> shift;
++              if (dtocyc < 15)
++                      break;
++      }
++
++      if (dtomul >= 8) {
++              dtomul = 7;
++              dtocyc = 15;
++      }
++
++      dev_dbg(&host->mmc->class_dev, "setting timeout to %u cycles\n",
++                      dtocyc << dtomul_to_shift[dtomul]);
++      mci_writel(host, DTOR, (MCI_BF(DTOMUL, dtomul)
++                              | MCI_BF(DTOCYC, dtocyc)));
++}
++
++/*
++ * Return mask with command flags to be enabled for this command.
++ */
++static u32 atmci_prepare_command(struct mmc_host *mmc,
++                               struct mmc_command *cmd)
++{
++      u32 cmdr;
++
++      cmd->error = 0;
++
++      cmdr = MCI_BF(CMDNB, cmd->opcode);
++
++      if (cmd->flags & MMC_RSP_PRESENT) {
++              if (cmd->flags & MMC_RSP_136)
++                      cmdr |= MCI_BF(RSPTYP, MCI_RSPTYP_136_BIT);
++              else
++                      cmdr |= MCI_BF(RSPTYP, MCI_RSPTYP_48_BIT);
++      }
++
++      /*
++       * This should really be MAXLAT_5 for CMD2 and ACMD41, but
++       * it's too difficult to determine whether this is an ACMD or
++       * not. Better make it 64.
++       */
++      cmdr |= MCI_BIT(MAXLAT);
++
++      if (mmc->ios.bus_mode == MMC_BUSMODE_OPENDRAIN)
++              cmdr |= MCI_BIT(OPDCMD);
++
++      dev_dbg(&mmc->class_dev,
++              "cmd: op %02x arg %08x flags %08x, cmdflags %08lx\n",
++              cmd->opcode, cmd->arg, cmd->flags, (unsigned long)cmdr);
++
++      return cmdr;
++}
++
++static void atmci_start_command(struct atmel_mci *host,
++                              struct mmc_command *cmd,
++                              u32 cmd_flags)
++{
++      WARN_ON(host->cmd);
++      host->cmd = cmd;
++
++      mci_writel(host, ARGR, cmd->arg);
++      mci_writel(host, CMDR, cmd_flags);
++
++      if (cmd->data)
++              dma_start_request(host->dma.req.req.dmac,
++                                host->dma.req.req.channel);
++}
++
++/*
++ * Returns a mask of flags to be set in the command register when the
++ * command to start the transfer is to be sent.
++ */
++static u32 atmci_prepare_data(struct mmc_host *mmc, struct mmc_data *data)
++{
++      struct atmel_mci *host = mmc_priv(mmc);
++      u32 cmd_flags;
++
++      WARN_ON(host->data);
++      host->data = data;
++
++      atmci_set_timeout(host, data);
++      mci_writel(host, BLKR, (MCI_BF(BCNT, data->blocks)
++                              | MCI_BF(BLKLEN, data->blksz)));
++      host->dma.req.block_size = data->blksz;
++      host->dma.req.nr_blocks = data->blocks;
++
++      cmd_flags = MCI_BF(TRCMD, MCI_TRCMD_START_TRANS);
++      if (data->flags & MMC_DATA_STREAM)
++              cmd_flags |= MCI_BF(TRTYP, MCI_TRTYP_STREAM);
++      else if (data->blocks > 1)
++              cmd_flags |= MCI_BF(TRTYP, MCI_TRTYP_MULTI_BLOCK);
++      else
++              cmd_flags |= MCI_BF(TRTYP, MCI_TRTYP_BLOCK);
++
++      if (data->flags & MMC_DATA_READ) {
++              cmd_flags |= MCI_BIT(TRDIR);
++              host->dma.req.nr_sg
++                      = dma_map_sg(&host->pdev->dev, data->sg,
++                                   data->sg_len, DMA_FROM_DEVICE);
++              host->dma.req.periph_id = host->dma.rx_periph_id;
++              host->dma.req.direction = DMA_DIR_PERIPH_TO_MEM;
++              host->dma.req.data_reg = host->mapbase + MCI_RDR;
++      } else {
++              host->dma.req.nr_sg
++                      = dma_map_sg(&host->pdev->dev, data->sg,
++                                   data->sg_len, DMA_TO_DEVICE);
++              host->dma.req.periph_id = host->dma.tx_periph_id;
++              host->dma.req.direction = DMA_DIR_MEM_TO_PERIPH;
++              host->dma.req.data_reg = host->mapbase + MCI_TDR;
++      }
++      host->dma.req.sg = data->sg;
++
++      dma_prepare_request_sg(host->dma.req.req.dmac, &host->dma.req);
++
++      return cmd_flags;
++}
++
++static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
++{
++      struct atmel_mci *host = mmc_priv(mmc);
++      struct mmc_data *data = mrq->data;
++      u32 iflags;
++      u32 cmdflags = 0;
++
++      iflags = mci_readl(host, IMR);
++      if (iflags)
++              dev_warn(&mmc->class_dev, "WARNING: IMR=0x%08x\n",
++                              mci_readl(host, IMR));
++
++      WARN_ON(host->mrq != NULL);
++
++      /*
++       * We may "know" the card is gone even though there's still an
++       * electrical connection. If so, we really need to communicate
++       * this to the MMC core since there won't be any more
++       * interrupts as the card is completely removed. Otherwise,
++       * the MMC core might believe the card is still there even
++       * though the card was just removed very slowly.
++       */
++      if (!host->present) {
++              mrq->cmd->error = -ENOMEDIUM;
++              mmc_request_done(mmc, mrq);
++              return;
++      }
++
++      host->mrq = mrq;
++      host->pending_events = 0;
++      host->completed_events = 0;
++
++      iflags = MCI_BIT(CMDRDY);
++      cmdflags = atmci_prepare_command(mmc, mrq->cmd);
++
++      if (mrq->stop) {
++              WARN_ON(!data);
++
++              host->stop_cmdr = atmci_prepare_command(mmc, mrq->stop);
++              host->stop_cmdr |= MCI_BF(TRCMD, MCI_TRCMD_STOP_TRANS);
++              if (!(data->flags & MMC_DATA_WRITE))
++                      host->stop_cmdr |= MCI_BIT(TRDIR);
++              if (data->flags & MMC_DATA_STREAM)
++                      host->stop_cmdr |= MCI_BF(TRTYP, MCI_TRTYP_STREAM);
++              else
++                      host->stop_cmdr |= MCI_BF(TRTYP, MCI_TRTYP_MULTI_BLOCK);
++      }
++      if (data) {
++              cmdflags |= atmci_prepare_data(mmc, data);
++              iflags |= MCI_DATA_ERROR_FLAGS;
++      }
++
++      atmci_start_command(host, mrq->cmd, cmdflags);
++      mci_writel(host, IER, iflags);
++}
++
++static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
++{
++      struct atmel_mci *host = mmc_priv(mmc);
++      u32 mr;
++
++      if (ios->clock) {
++              u32 clkdiv;
++
++              /* Set clock rate */
++              clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * ios->clock) - 1;
++              if (clkdiv > 255) {
++                      dev_warn(&mmc->class_dev,
++                              "clock %u too slow; using %lu\n",
++                              ios->clock, host->bus_hz / (2 * 256));
++                      clkdiv = 255;
++              }
++
++              mr = mci_readl(host, MR);
++              mr = MCI_BFINS(CLKDIV, clkdiv, mr)
++                      | MCI_BIT(WRPROOF) | MCI_BIT(RDPROOF);
++              mci_writel(host, MR, mr);
++
++              /* Enable the MCI controller */
++              mci_writel(host, CR, MCI_BIT(MCIEN));
++      } else {
++              /* Disable the MCI controller */
++              mci_writel(host, CR, MCI_BIT(MCIDIS));
++      }
++
++      switch (ios->bus_width) {
++      case MMC_BUS_WIDTH_1:
++              mci_writel(host, SDCR, 0);
++              break;
++      case MMC_BUS_WIDTH_4:
++              mci_writel(host, SDCR, MCI_BIT(SDCBUS));
++              break;
++      }
++
++      switch (ios->power_mode) {
++      case MMC_POWER_ON:
++              /* Send init sequence (74 clock cycles) */
++              mci_writel(host, IDR, ~0UL);
++              mci_writel(host, CMDR, MCI_BF(SPCMD, MCI_SPCMD_INIT_CMD));
++              while (!(mci_readl(host, SR) & MCI_BIT(CMDRDY)))
++                      cpu_relax();
++              break;
++      default:
++              /*
++               * TODO: None of the currently available AVR32-based
++               * boards allow MMC power to be turned off. Implement
++               * power control when this can be tested properly.
++               */
++              break;
++      }
++}
++
++static int atmci_get_ro(struct mmc_host *mmc)
++{
++      int read_only = 0;
++      struct atmel_mci *host = mmc_priv(mmc);
++
++      if (host->wp_pin >= 0) {
++              read_only = gpio_get_value(host->wp_pin);
++              dev_dbg(&mmc->class_dev, "card is %s\n",
++                              read_only ? "read-only" : "read-write");
++      } else {
++              dev_dbg(&mmc->class_dev,
++                      "no pin for checking read-only switch."
++                      " Assuming write-enable.\n");
++      }
++
++      return read_only;
++}
++
++static struct mmc_host_ops atmci_ops = {
++      .request        = atmci_request,
++      .set_ios        = atmci_set_ios,
++      .get_ro         = atmci_get_ro,
++};
++
++static void atmci_request_end(struct mmc_host *mmc, struct mmc_request *mrq)
++{
++      struct atmel_mci *host = mmc_priv(mmc);
++
++      WARN_ON(host->cmd || host->data);
++      host->mrq = NULL;
++
++      mmc_request_done(mmc, mrq);
++}
++
++static void send_stop_cmd(struct mmc_host *mmc, struct mmc_data *data,
++                        u32 flags)
++{
++      struct atmel_mci *host = mmc_priv(mmc);
++
++      atmci_start_command(host, data->stop, host->stop_cmdr | flags);
++      mci_writel(host, IER, MCI_BIT(CMDRDY));
++}
++
++static void atmci_data_complete(struct atmel_mci *host, struct mmc_data *data)
++{
++      host->data = NULL;
++      dma_unmap_sg(&host->pdev->dev, data->sg, host->dma.req.nr_sg,
++                   ((data->flags & MMC_DATA_WRITE)
++                    ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
++
++      /*
++       * Data might complete before command for very short transfers
++       * (like READ_SCR)
++       */
++      if (mci_cmd_is_complete(host)
++          && (!data->stop || mci_stop_is_complete(host)))
++              atmci_request_end(host->mmc, data->mrq);
++}
++
++static void atmci_command_complete(struct atmel_mci *host,
++                      struct mmc_command *cmd, u32 status)
++{
++      if (status & MCI_BIT(RTOE))
++              cmd->error = -ETIMEDOUT;
++      else if ((cmd->flags & MMC_RSP_CRC)
++                      && (status & MCI_BIT(RCRCE)))
++              cmd->error = -EILSEQ;
++      else if (status & (MCI_BIT(RINDE) | MCI_BIT(RDIRE) | MCI_BIT(RENDE)))
++              cmd->error = -EIO;
++
++      if (cmd->error) {
++              dev_dbg(&host->mmc->class_dev,
++                              "command error: op=0x%x status=0x%08x\n",
++                              cmd->opcode, status);
++
++              if (cmd->data) {
++                      dma_stop_request(host->dma.req.req.dmac,
++                                      host->dma.req.req.channel);
++                      mci_writel(host, IDR, MCI_BIT(NOTBUSY)
++                                      | MCI_DATA_ERROR_FLAGS);
++                      host->data = NULL;
++              }
++      }
++}
++
++static void atmci_detect_change(unsigned long data)
++{
++      struct atmel_mci *host = (struct atmel_mci *)data;
++      struct mmc_request *mrq = host->mrq;
++      int present;
++
++      /*
++       * atmci_remove() sets detect_pin to -1 before freeing the
++       * interrupt. We must not re-enable the interrupt if it has
++       * been freed.
++       */
++      smp_rmb();
++      if (host->detect_pin < 0)
++              return;
++
++      enable_irq(gpio_to_irq(host->detect_pin));
++      present = !gpio_get_value(host->detect_pin);
++
++      dev_vdbg(&host->pdev->dev, "detect change: %d (was %d)\n",
++                      present, host->present);
++
++      if (present != host->present) {
++              dev_dbg(&host->mmc->class_dev, "card %s\n",
++                      present ? "inserted" : "removed");
++              host->present = present;
++
++              /* Reset controller if card is gone */
++              if (!present) {
++                      mci_writel(host, CR, MCI_BIT(SWRST));
++                      mci_writel(host, IDR, ~0UL);
++                      mci_writel(host, CR, MCI_BIT(MCIEN));
++              }
++
++              /* Clean up queue if present */
++              if (mrq) {
++                      if (!mci_cmd_is_complete(host))
++                              mrq->cmd->error = -ENOMEDIUM;
++                      if (mrq->data && !mci_data_is_complete(host)
++                          && !mci_data_error_is_complete(host)) {
++                              dma_stop_request(host->dma.req.req.dmac,
++                                              host->dma.req.req.channel);
++                              host->data->error = -ENOMEDIUM;
++                              atmci_data_complete(host, host->data);
++                      }
++                      if (mrq->stop && !mci_stop_is_complete(host))
++                              mrq->stop->error = -ENOMEDIUM;
++
++                      host->cmd = NULL;
++                      atmci_request_end(host->mmc, mrq);
++              }
++
++              mmc_detect_change(host->mmc, 0);
++      }
++}
++
++static void atmci_tasklet_func(unsigned long priv)
++{
++      struct mmc_host *mmc = (struct mmc_host *)priv;
++      struct atmel_mci *host = mmc_priv(mmc);
++      struct mmc_request *mrq = host->mrq;
++      struct mmc_data *data = host->data;
++
++      dev_vdbg(&mmc->class_dev,
++              "tasklet: pending/completed/mask %lx/%lx/%x\n",
++               host->pending_events, host->completed_events,
++               mci_readl(host, IMR));
++
++      if (mci_clear_cmd_is_pending(host)) {
++              mci_set_cmd_complete(host);
++              atmci_command_complete(host, mrq->cmd, host->cmd_status);
++              if (!host->data || mci_data_is_complete(host)
++                  || mci_data_error_is_complete(host))
++                      atmci_request_end(mmc, mrq);
++      }
++      if (mci_clear_stop_is_pending(host)) {
++              mci_set_stop_complete(host);
++              atmci_command_complete(host, mrq->stop, host->stop_status);
++              if (mci_data_is_complete(host)
++                  || mci_data_error_is_complete(host))
++                      atmci_request_end(mmc, mrq);
++      }
++      if (mci_clear_dma_error_is_pending(host)) {
++              mci_set_dma_error_complete(host);
++              mci_clear_data_pending(host);
++
++              /* DMA controller got bus error => invalid address */
++              data->error = -EIO;
++
++              dev_dbg(&mmc->class_dev, "dma error after %u bytes xfered\n",
++                              host->data->bytes_xfered);
++
++              if (data->stop
++                  && !mci_set_stop_sent_is_completed(host))
++                      /* TODO: Check if card is still present */
++                      send_stop_cmd(host->mmc, data, 0);
++
++              atmci_data_complete(host, data);
++      }
++      if (mci_clear_data_error_is_pending(host)) {
++              u32 status = host->data_status;
++
++              mci_set_data_error_complete(host);
++              mci_clear_data_pending(host);
++
++              dma_stop_request(host->dma.req.req.dmac,
++                               host->dma.req.req.channel);
++
++              if (status & MCI_BIT(DCRCE)) {
++                      dev_dbg(&mmc->class_dev, "data CRC error\n");
++                      data->error = -EILSEQ;
++              } else if (status & MCI_BIT(DTOE)) {
++                      dev_dbg(&mmc->class_dev, "data timeout error\n");
++                      data->error = -ETIMEDOUT;
++              } else {
++                      dev_dbg(&mmc->class_dev, "data FIFO error\n");
++                      data->error = -EIO;
++              }
++              dev_dbg(&mmc->class_dev, "bytes xfered: %u\n",
++                              data->bytes_xfered);
++
++              if (data->stop
++                  && !mci_set_stop_sent_is_completed(host))
++                      /* TODO: Check if card is still present */
++                      send_stop_cmd(host->mmc, data, 0);
++
++              atmci_data_complete(host, data);
++      }
++      if (mci_clear_data_is_pending(host)) {
++              mci_set_data_complete(host);
++              data->bytes_xfered = data->blocks * data->blksz;
++              atmci_data_complete(host, data);
++      }
++}
++
++static void atmci_cmd_interrupt(struct mmc_host *mmc, u32 status)
++{
++      struct atmel_mci *host = mmc_priv(mmc);
++      struct mmc_command *cmd = host->cmd;
++
++      /*
++       * Read the response now so that we're free to send a new
++       * command immediately.
++       */
++      cmd->resp[0] = mci_readl(host, RSPR);
++      cmd->resp[1] = mci_readl(host, RSPR);
++      cmd->resp[2] = mci_readl(host, RSPR);
++      cmd->resp[3] = mci_readl(host, RSPR);
++
++      mci_writel(host, IDR, MCI_BIT(CMDRDY));
++      host->cmd = NULL;
++
++      if (mci_stop_sent_is_complete(host)) {
++              host->stop_status = status;
++              mci_set_stop_pending(host);
++      } else {
++              struct mmc_request *mrq = host->mrq;
++
++              if (mrq->stop && mci_dma_is_complete(host)
++                              && !mci_set_stop_sent_is_completed(host))
++                      send_stop_cmd(host->mmc, mrq->data, 0);
++              host->cmd_status = status;
++              mci_set_cmd_pending(host);
++      }
++
++      tasklet_schedule(&host->tasklet);
++}
++
++static void atmci_xfer_complete(struct dma_request *_req)
++{
++      struct dma_request_sg *req = to_dma_request_sg(_req);
++      struct atmel_mci_dma *dma;
++      struct atmel_mci *host;
++      struct mmc_data *data;
++
++      dma = container_of(req, struct atmel_mci_dma, req);
++      host = container_of(dma, struct atmel_mci, dma);
++      data = host->data;
++
++      /*
++       * This callback may be called before we see the CMDRDY
++       * interrupt under heavy irq load (possibly caused by other
++       * drivers) or when interrupts are disabled for a long time.
++       */
++      mci_set_dma_complete(host);
++      if (data->stop && mci_cmd_is_complete(host)
++                      && !mci_set_stop_sent_is_completed(host))
++              send_stop_cmd(host->mmc, data, 0);
++
++      /*
++       * Regardless of what the documentation says, we have to wait
++       * for NOTBUSY even after block read operations.
++       *
++       * When the DMA transfer is complete, the controller may still
++       * be reading the CRC from the card, i.e. the data transfer is
++       * still in progress and we haven't seen all the potential
++       * error bits yet.
++       */
++      mci_writel(host, IER, MCI_BIT(NOTBUSY));
++}
++
++static void atmci_dma_error(struct dma_request *_req)
++{
++      struct dma_request_sg *req = to_dma_request_sg(_req);
++      struct atmel_mci_dma *dma;
++      struct atmel_mci *host;
++
++      dma = container_of(req, struct atmel_mci_dma, req);
++      host = container_of(dma, struct atmel_mci, dma);
++
++      mci_writel(host, IDR, (MCI_BIT(NOTBUSY)
++                             | MCI_DATA_ERROR_FLAGS));
++
++      mci_set_dma_error_pending(host);
++      tasklet_schedule(&host->tasklet);
++}
++
++static irqreturn_t atmci_interrupt(int irq, void *dev_id)
++{
++      struct mmc_host *mmc = dev_id;
++      struct atmel_mci *host = mmc_priv(mmc);
++      u32 status, mask, pending;
++
++      spin_lock(&mmc->lock);
++
++      status = mci_readl(host, SR);
++      mask = mci_readl(host, IMR);
++      pending = status & mask;
++
++      do {
++              if (pending & MCI_DATA_ERROR_FLAGS) {
++                      mci_writel(host, IDR, (MCI_BIT(NOTBUSY)
++                                             | MCI_DATA_ERROR_FLAGS));
++                      host->data_status = status;
++                      mci_set_data_error_pending(host);
++                      tasklet_schedule(&host->tasklet);
++                      break;
++              }
++              if (pending & MCI_BIT(CMDRDY))
++                      atmci_cmd_interrupt(mmc, status);
++              if (pending & MCI_BIT(NOTBUSY)) {
++                      mci_writel(host, IDR, (MCI_BIT(NOTBUSY)
++                                             | MCI_DATA_ERROR_FLAGS));
++                      mci_set_data_pending(host);
++                      tasklet_schedule(&host->tasklet);
++              }
++
++              status = mci_readl(host, SR);
++              mask = mci_readl(host, IMR);
++              pending = status & mask;
++      } while (pending);
++
++      spin_unlock(&mmc->lock);
++
++      return IRQ_HANDLED;
++}
++
++static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
++{
++      struct mmc_host *mmc = dev_id;
++      struct atmel_mci *host = mmc_priv(mmc);
++
++      /*
++       * Disable interrupts until the pin has stabilized and check
++       * the state then. Use mod_timer() since we may be in the
++       * middle of the timer routine when this interrupt triggers.
++       */
++      disable_irq_nosync(irq);
++      mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(20));
++
++      return IRQ_HANDLED;
++}
++
++static int __devinit atmci_probe(struct platform_device *pdev)
++{
++      struct mci_platform_data *board;
++      struct atmel_mci *host;
++      struct mmc_host *mmc;
++      struct resource *regs;
++      int irq;
++      int ret;
++
++      regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (!regs)
++              return -ENXIO;
++      irq = platform_get_irq(pdev, 0);
++      if (irq < 0)
++              return irq;
++
++      board = pdev->dev.platform_data;
++
++      mmc = mmc_alloc_host(sizeof(struct atmel_mci), &pdev->dev);
++      if (!mmc)
++              return -ENOMEM;
++
++      host = mmc_priv(mmc);
++      host->pdev = pdev;
++      host->mmc = mmc;
++      if (board) {
++              host->detect_pin = board->detect_pin;
++              host->wp_pin = board->wp_pin;
++      } else {
++              host->detect_pin = -1;
++              host->wp_pin = -1;
++      }
++
++      host->mck = clk_get(&pdev->dev, "mci_clk");
++      if (IS_ERR(host->mck)) {
++              ret = PTR_ERR(host->mck);
++              goto out_free_host;
++      }
++      clk_enable(host->mck);
++
++      ret = -ENOMEM;
++      host->regs = ioremap(regs->start, regs->end - regs->start + 1);
++      if (!host->regs)
++              goto out_disable_clk;
++
++      host->bus_hz = clk_get_rate(host->mck);
++      host->mapbase = regs->start;
++
++      mmc->ops = &atmci_ops;
++      mmc->f_min = (host->bus_hz + 511) / 512;
++      mmc->f_max = min((unsigned int)(host->bus_hz / 2), fmax);
++      mmc->ocr_avail  = MMC_VDD_32_33 | MMC_VDD_33_34;
++      mmc->caps |= MMC_CAP_4_BIT_DATA;
++
++      tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)mmc);
++
++      ret = request_irq(irq, atmci_interrupt, 0, "mmci", mmc);
++      if (ret)
++              goto out_unmap;
++
++      /* Assume card is present if we don't have a detect pin */
++      host->present = 1;
++      if (host->detect_pin >= 0) {
++              if (gpio_request(host->detect_pin, "mmc_detect")) {
++                      dev_dbg(&mmc->class_dev, "no detect pin available\n");
++                      host->detect_pin = -1;
++              } else {
++                      host->present = !gpio_get_value(host->detect_pin);
++              }
++      }
++      if (host->wp_pin >= 0) {
++              if (gpio_request(host->wp_pin, "mmc_wp")) {
++                      dev_dbg(&mmc->class_dev, "no WP pin available\n");
++                      host->wp_pin = -1;
++              }
++      }
++
++      /* TODO: Get this information from platform data */
++      ret = -ENOMEM;
++      host->dma.req.req.dmac = find_dma_controller(0);
++      if (!host->dma.req.req.dmac) {
++              dev_dbg(&mmc->class_dev, "no DMA controller available\n");
++              goto out_free_irq;
++      }
++      ret = dma_alloc_channel(host->dma.req.req.dmac);
++      if (ret < 0) {
++              dev_dbg(&mmc->class_dev, "unable to allocate DMA channel\n");
++              goto out_free_irq;
++      }
++      host->dma.req.req.channel = ret;
++      host->dma.req.width = DMA_WIDTH_32BIT;
++      host->dma.req.req.xfer_complete = atmci_xfer_complete;
++      host->dma.req.req.block_complete = NULL; // atmci_block_complete;
++      host->dma.req.req.error = atmci_dma_error;
++      host->dma.rx_periph_id = 0;
++      host->dma.tx_periph_id = 1;
++
++      mci_writel(host, CR, MCI_BIT(SWRST));
++      mci_writel(host, IDR, ~0UL);
++
++      platform_set_drvdata(pdev, host);
++
++      mmc_add_host(mmc);
++
++      if (host->detect_pin >= 0) {
++              setup_timer(&host->detect_timer, atmci_detect_change,
++                              (unsigned long)host);
++
++              ret = request_irq(gpio_to_irq(host->detect_pin),
++                                atmci_detect_interrupt,
++                                IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
++                                DRIVER_NAME, mmc);
++              if (ret) {
++                      dev_dbg(&mmc->class_dev,
++                              "could not request IRQ %d for detect pin\n",
++                              gpio_to_irq(host->detect_pin));
++                      gpio_free(host->detect_pin);
++                      host->detect_pin = -1;
++              }
++      }
++
++      dev_info(&mmc->class_dev, "Atmel MCI controller at 0x%08lx irq %d\n",
++                      host->mapbase, irq);
++
++      atmci_init_debugfs(host);
++
++      return 0;
++
++out_free_irq:
++      if (host->detect_pin >= 0)
++              gpio_free(host->detect_pin);
++      if (host->wp_pin >= 0)
++              gpio_free(host->wp_pin);
++      free_irq(irq, mmc);
++out_unmap:
++      iounmap(host->regs);
++out_disable_clk:
++      clk_disable(host->mck);
++      clk_put(host->mck);
++out_free_host:
++      mmc_free_host(mmc);
++      return ret;
++}
++
++static int __devexit atmci_remove(struct platform_device *pdev)
++{
++      struct atmel_mci *host = platform_get_drvdata(pdev);
++
++      platform_set_drvdata(pdev, NULL);
++
++      if (host) {
++              atmci_cleanup_debugfs(host);
++
++              if (host->detect_pin >= 0) {
++                      int pin = host->detect_pin;
++
++                      /* Make sure our timer doesn't enable the interrupt */
++                      host->detect_pin = -1;
++                      smp_wmb();
++
++                      free_irq(gpio_to_irq(pin), host->mmc);
++                      del_timer_sync(&host->detect_timer);
++                      cancel_delayed_work(&host->mmc->detect);
++                      gpio_free(pin);
++              }
++
++              mmc_remove_host(host->mmc);
++
++              mci_writel(host, IDR, ~0UL);
++              mci_writel(host, CR, MCI_BIT(MCIDIS));
++              mci_readl(host, SR);
++
++              dma_release_channel(host->dma.req.req.dmac,
++                                  host->dma.req.req.channel);
++
++              if (host->wp_pin >= 0)
++                      gpio_free(host->wp_pin);
++
++              free_irq(platform_get_irq(pdev, 0), host->mmc);
++              iounmap(host->regs);
++
++              clk_disable(host->mck);
++              clk_put(host->mck);
++
++              mmc_free_host(host->mmc);
++      }
++      return 0;
++}
++
++static struct platform_driver atmci_driver = {
++      .probe          = atmci_probe,
++      .remove         = __devexit_p(atmci_remove),
++      .driver         = {
++              .name           = DRIVER_NAME,
++      },
++};
++
++static int __init atmci_init(void)
++{
++      return platform_driver_register(&atmci_driver);
++}
++
++static void __exit atmci_exit(void)
++{
++      platform_driver_unregister(&atmci_driver);
++}
++
++module_init(atmci_init);
++module_exit(atmci_exit);
++
++MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver");
++MODULE_LICENSE("GPL");
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mmc/host/atmel-mci.h avr32-2.6/drivers/mmc/host/atmel-mci.h
+--- linux-2.6.25.6/drivers/mmc/host/atmel-mci.h        1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/drivers/mmc/host/atmel-mci.h     2008-06-12 15:09:41.083816184 +0200
+@@ -0,0 +1,192 @@
++/*
++ * Atmel MultiMedia Card Interface driver
++ *
++ * Copyright (C) 2004-2006 Atmel Corporation
++ *
++ * 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.
++ */
++#ifndef __DRIVERS_MMC_ATMEL_MCI_H__
++#define __DRIVERS_MMC_ATMEL_MCI_H__
++
++/* MCI register offsets */
++#define MCI_CR                                        0x0000
++#define MCI_MR                                        0x0004
++#define MCI_DTOR                              0x0008
++#define MCI_SDCR                              0x000c
++#define MCI_ARGR                              0x0010
++#define MCI_CMDR                              0x0014
++#define MCI_BLKR                              0x0018
++#define MCI_RSPR                              0x0020
++#define MCI_RSPR1                             0x0024
++#define MCI_RSPR2                             0x0028
++#define MCI_RSPR3                             0x002c
++#define MCI_RDR                                       0x0030
++#define MCI_TDR                                       0x0034
++#define MCI_SR                                        0x0040
++#define MCI_IER                                       0x0044
++#define MCI_IDR                                       0x0048
++#define MCI_IMR                                       0x004c
++
++/* Bitfields in CR */
++#define MCI_MCIEN_OFFSET                      0
++#define MCI_MCIEN_SIZE                                1
++#define MCI_MCIDIS_OFFSET                     1
++#define MCI_MCIDIS_SIZE                               1
++#define MCI_PWSEN_OFFSET                      2
++#define MCI_PWSEN_SIZE                                1
++#define MCI_PWSDIS_OFFSET                     3
++#define MCI_PWSDIS_SIZE                               1
++#define MCI_SWRST_OFFSET                      7
++#define MCI_SWRST_SIZE                                1
++
++/* Bitfields in MR */
++#define MCI_CLKDIV_OFFSET                     0
++#define MCI_CLKDIV_SIZE                               8
++#define MCI_PWSDIV_OFFSET                     8
++#define MCI_PWSDIV_SIZE                               3
++#define MCI_RDPROOF_OFFSET                    11
++#define MCI_RDPROOF_SIZE                      1
++#define MCI_WRPROOF_OFFSET                    12
++#define MCI_WRPROOF_SIZE                      1
++#define MCI_DMAPADV_OFFSET                    14
++#define MCI_DMAPADV_SIZE                      1
++#define MCI_BLKLEN_OFFSET                     16
++#define MCI_BLKLEN_SIZE                               16
++
++/* Bitfields in DTOR */
++#define MCI_DTOCYC_OFFSET                     0
++#define MCI_DTOCYC_SIZE                               4
++#define MCI_DTOMUL_OFFSET                     4
++#define MCI_DTOMUL_SIZE                               3
++
++/* Bitfields in SDCR */
++#define MCI_SDCSEL_OFFSET                     0
++#define MCI_SDCSEL_SIZE                               4
++#define MCI_SDCBUS_OFFSET                     7
++#define MCI_SDCBUS_SIZE                               1
++
++/* Bitfields in ARGR */
++#define MCI_ARG_OFFSET                                0
++#define MCI_ARG_SIZE                          32
++
++/* Bitfields in CMDR */
++#define MCI_CMDNB_OFFSET                      0
++#define MCI_CMDNB_SIZE                                6
++#define MCI_RSPTYP_OFFSET                     6
++#define MCI_RSPTYP_SIZE                               2
++#define MCI_SPCMD_OFFSET                      8
++#define MCI_SPCMD_SIZE                                3
++#define MCI_OPDCMD_OFFSET                     11
++#define MCI_OPDCMD_SIZE                               1
++#define MCI_MAXLAT_OFFSET                     12
++#define MCI_MAXLAT_SIZE                               1
++#define MCI_TRCMD_OFFSET                      16
++#define MCI_TRCMD_SIZE                                2
++#define MCI_TRDIR_OFFSET                      18
++#define MCI_TRDIR_SIZE                                1
++#define MCI_TRTYP_OFFSET                      19
++#define MCI_TRTYP_SIZE                                2
++
++/* Bitfields in BLKR */
++#define MCI_BCNT_OFFSET                               0
++#define MCI_BCNT_SIZE                         16
++
++/* Bitfields in RSPRn */
++#define MCI_RSP_OFFSET                                0
++#define MCI_RSP_SIZE                          32
++
++/* Bitfields in SR/IER/IDR/IMR */
++#define MCI_CMDRDY_OFFSET                     0
++#define MCI_CMDRDY_SIZE                               1
++#define MCI_RXRDY_OFFSET                      1
++#define MCI_RXRDY_SIZE                                1
++#define MCI_TXRDY_OFFSET                      2
++#define MCI_TXRDY_SIZE                                1
++#define MCI_BLKE_OFFSET                               3
++#define MCI_BLKE_SIZE                         1
++#define MCI_DTIP_OFFSET                               4
++#define MCI_DTIP_SIZE                         1
++#define MCI_NOTBUSY_OFFSET                    5
++#define MCI_NOTBUSY_SIZE                      1
++#define MCI_ENDRX_OFFSET                      6
++#define MCI_ENDRX_SIZE                                1
++#define MCI_ENDTX_OFFSET                      7
++#define MCI_ENDTX_SIZE                                1
++#define MCI_RXBUFF_OFFSET                     14
++#define MCI_RXBUFF_SIZE                               1
++#define MCI_TXBUFE_OFFSET                     15
++#define MCI_TXBUFE_SIZE                               1
++#define MCI_RINDE_OFFSET                      16
++#define MCI_RINDE_SIZE                                1
++#define MCI_RDIRE_OFFSET                      17
++#define MCI_RDIRE_SIZE                                1
++#define MCI_RCRCE_OFFSET                      18
++#define MCI_RCRCE_SIZE                                1
++#define MCI_RENDE_OFFSET                      19
++#define MCI_RENDE_SIZE                                1
++#define MCI_RTOE_OFFSET                               20
++#define MCI_RTOE_SIZE                         1
++#define MCI_DCRCE_OFFSET                      21
++#define MCI_DCRCE_SIZE                                1
++#define MCI_DTOE_OFFSET                               22
++#define MCI_DTOE_SIZE                         1
++#define MCI_OVRE_OFFSET                               30
++#define MCI_OVRE_SIZE                         1
++#define MCI_UNRE_OFFSET                               31
++#define MCI_UNRE_SIZE                         1
++
++/* Constants for DTOMUL */
++#define MCI_DTOMUL_1_CYCLE                    0
++#define MCI_DTOMUL_16_CYCLES                  1
++#define MCI_DTOMUL_128_CYCLES                 2
++#define MCI_DTOMUL_256_CYCLES                 3
++#define MCI_DTOMUL_1024_CYCLES                        4
++#define MCI_DTOMUL_4096_CYCLES                        5
++#define MCI_DTOMUL_65536_CYCLES                       6
++#define MCI_DTOMUL_1048576_CYCLES             7
++
++/* Constants for RSPTYP */
++#define MCI_RSPTYP_NO_RESP                    0
++#define MCI_RSPTYP_48_BIT                     1
++#define MCI_RSPTYP_136_BIT                    2
++
++/* Constants for SPCMD */
++#define MCI_SPCMD_NO_SPEC_CMD                 0
++#define MCI_SPCMD_INIT_CMD                    1
++#define MCI_SPCMD_SYNC_CMD                    2
++#define MCI_SPCMD_INT_CMD                     4
++#define MCI_SPCMD_INT_RESP                    5
++
++/* Constants for TRCMD */
++#define MCI_TRCMD_NO_TRANS                    0
++#define MCI_TRCMD_START_TRANS                 1
++#define MCI_TRCMD_STOP_TRANS                  2
++
++/* Constants for TRTYP */
++#define MCI_TRTYP_BLOCK                               0
++#define MCI_TRTYP_MULTI_BLOCK                 1
++#define MCI_TRTYP_STREAM                      2
++
++/* Bit manipulation macros */
++#define MCI_BIT(name)                                 \
++      (1 << MCI_##name##_OFFSET)
++#define MCI_BF(name,value)                            \
++      (((value) & ((1 << MCI_##name##_SIZE) - 1))     \
++       << MCI_##name##_OFFSET)
++#define MCI_BFEXT(name,value)                         \
++      (((value) >> MCI_##name##_OFFSET)               \
++       & ((1 << MCI_##name##_SIZE) - 1))
++#define MCI_BFINS(name,value,old)                     \
++      (((old) & ~(((1 << MCI_##name##_SIZE) - 1)      \
++                  << MCI_##name##_OFFSET))            \
++       | MCI_BF(name,value))
++
++/* Register access macros */
++#define mci_readl(port,reg)                           \
++      __raw_readl((port)->regs + MCI_##reg)
++#define mci_writel(port,reg,value)                    \
++      __raw_writel((value), (port)->regs + MCI_##reg)
++
++#endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mmc/host/Kconfig avr32-2.6/drivers/mmc/host/Kconfig
+--- linux-2.6.25.6/drivers/mmc/host/Kconfig    2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mmc/host/Kconfig 2008-06-12 15:09:41.083816184 +0200
+@@ -91,6 +91,16 @@
+         If unsure, say N.
++config MMC_ATMELMCI
++      tristate "Atmel Multimedia Card Interface support"
++      depends on AVR32 && MMC
++      help
++        This selects the Atmel Multimedia Card Interface. If you have
++        a AT91 (ARM) or AT32 (AVR32) platform with a Multimedia Card
++        slot, say Y or M here.
++
++        If unsure, say N.
++
+ config MMC_IMX
+       tristate "Motorola i.MX Multimedia Card Interface support"
+       depends on ARCH_IMX
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mmc/host/Makefile avr32-2.6/drivers/mmc/host/Makefile
+--- linux-2.6.25.6/drivers/mmc/host/Makefile   2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mmc/host/Makefile        2008-06-12 15:09:41.083816184 +0200
+@@ -15,6 +15,7 @@
+ obj-$(CONFIG_MMC_AU1X)                += au1xmmc.o
+ obj-$(CONFIG_MMC_OMAP)                += omap.o
+ obj-$(CONFIG_MMC_AT91)                += at91_mci.o
++obj-$(CONFIG_MMC_ATMELMCI)    += atmel-mci.o
+ obj-$(CONFIG_MMC_TIFM_SD)     += tifm_sd.o
+ obj-$(CONFIG_MMC_SPI)         += mmc_spi.o
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/at91_nand.c avr32-2.6/drivers/mtd/nand/at91_nand.c
+--- linux-2.6.25.6/drivers/mtd/nand/at91_nand.c        2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/nand/at91_nand.c     1970-01-01 01:00:00.000000000 +0100
+@@ -1,236 +0,0 @@
+-/*
+- * drivers/mtd/nand/at91_nand.c
+- *
+- *  Copyright (C) 2003 Rick Bronson
+- *
+- *  Derived from drivers/mtd/nand/autcpu12.c
+- *     Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
+- *
+- *  Derived from drivers/mtd/spia.c
+- *     Copyright (C) 2000 Steven J. Hill (sjhill@cotw.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.
+- *
+- */
+-
+-#include <linux/slab.h>
+-#include <linux/module.h>
+-#include <linux/platform_device.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/nand.h>
+-#include <linux/mtd/partitions.h>
+-
+-#include <asm/io.h>
+-#include <asm/sizes.h>
+-
+-#include <asm/hardware.h>
+-#include <asm/arch/board.h>
+-#include <asm/arch/gpio.h>
+-
+-struct at91_nand_host {
+-      struct nand_chip        nand_chip;
+-      struct mtd_info         mtd;
+-      void __iomem            *io_base;
+-      struct at91_nand_data   *board;
+-};
+-
+-/*
+- * Hardware specific access to control-lines
+- */
+-static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+-{
+-      struct nand_chip *nand_chip = mtd->priv;
+-      struct at91_nand_host *host = nand_chip->priv;
+-
+-      if (cmd == NAND_CMD_NONE)
+-              return;
+-
+-      if (ctrl & NAND_CLE)
+-              writeb(cmd, host->io_base + (1 << host->board->cle));
+-      else
+-              writeb(cmd, host->io_base + (1 << host->board->ale));
+-}
+-
+-/*
+- * Read the Device Ready pin.
+- */
+-static int at91_nand_device_ready(struct mtd_info *mtd)
+-{
+-      struct nand_chip *nand_chip = mtd->priv;
+-      struct at91_nand_host *host = nand_chip->priv;
+-
+-      return at91_get_gpio_value(host->board->rdy_pin);
+-}
+-
+-/*
+- * Enable NAND.
+- */
+-static void at91_nand_enable(struct at91_nand_host *host)
+-{
+-      if (host->board->enable_pin)
+-              at91_set_gpio_value(host->board->enable_pin, 0);
+-}
+-
+-/*
+- * Disable NAND.
+- */
+-static void at91_nand_disable(struct at91_nand_host *host)
+-{
+-      if (host->board->enable_pin)
+-              at91_set_gpio_value(host->board->enable_pin, 1);
+-}
+-
+-#ifdef CONFIG_MTD_PARTITIONS
+-const char *part_probes[] = { "cmdlinepart", NULL };
+-#endif
+-
+-/*
+- * Probe for the NAND device.
+- */
+-static int __init at91_nand_probe(struct platform_device *pdev)
+-{
+-      struct at91_nand_host *host;
+-      struct mtd_info *mtd;
+-      struct nand_chip *nand_chip;
+-      int res;
+-
+-#ifdef CONFIG_MTD_PARTITIONS
+-      struct mtd_partition *partitions = NULL;
+-      int num_partitions = 0;
+-#endif
+-
+-      /* Allocate memory for the device structure (and zero it) */
+-      host = kzalloc(sizeof(struct at91_nand_host), GFP_KERNEL);
+-      if (!host) {
+-              printk(KERN_ERR "at91_nand: failed to allocate device structure.\n");
+-              return -ENOMEM;
+-      }
+-
+-      host->io_base = ioremap(pdev->resource[0].start,
+-                              pdev->resource[0].end - pdev->resource[0].start + 1);
+-      if (host->io_base == NULL) {
+-              printk(KERN_ERR "at91_nand: ioremap failed\n");
+-              kfree(host);
+-              return -EIO;
+-      }
+-
+-      mtd = &host->mtd;
+-      nand_chip = &host->nand_chip;
+-      host->board = pdev->dev.platform_data;
+-
+-      nand_chip->priv = host;         /* link the private data structures */
+-      mtd->priv = nand_chip;
+-      mtd->owner = THIS_MODULE;
+-
+-      /* Set address of NAND IO lines */
+-      nand_chip->IO_ADDR_R = host->io_base;
+-      nand_chip->IO_ADDR_W = host->io_base;
+-      nand_chip->cmd_ctrl = at91_nand_cmd_ctrl;
+-
+-      if (host->board->rdy_pin)
+-              nand_chip->dev_ready = at91_nand_device_ready;
+-
+-      nand_chip->ecc.mode = NAND_ECC_SOFT;    /* enable ECC */
+-      nand_chip->chip_delay = 20;             /* 20us command delay time */
+-
+-      if (host->board->bus_width_16)          /* 16-bit bus width */
+-              nand_chip->options |= NAND_BUSWIDTH_16;
+-
+-      platform_set_drvdata(pdev, host);
+-      at91_nand_enable(host);
+-
+-      if (host->board->det_pin) {
+-              if (at91_get_gpio_value(host->board->det_pin)) {
+-                      printk ("No SmartMedia card inserted.\n");
+-                      res = ENXIO;
+-                      goto out;
+-              }
+-      }
+-
+-      /* Scan to find existance of the device */
+-      if (nand_scan(mtd, 1)) {
+-              res = -ENXIO;
+-              goto out;
+-      }
+-
+-#ifdef CONFIG_MTD_PARTITIONS
+-#ifdef CONFIG_MTD_CMDLINE_PARTS
+-      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");
+-              res = ENXIO;
+-              goto release;
+-      }
+-
+-      res = add_mtd_partitions(mtd, partitions, num_partitions);
+-#else
+-      res = add_mtd_device(mtd);
+-#endif
+-
+-      if (!res)
+-              return res;
+-
+-release:
+-      nand_release(mtd);
+-out:
+-      at91_nand_disable(host);
+-      platform_set_drvdata(pdev, NULL);
+-      iounmap(host->io_base);
+-      kfree(host);
+-      return res;
+-}
+-
+-/*
+- * Remove a NAND device.
+- */
+-static int __devexit at91_nand_remove(struct platform_device *pdev)
+-{
+-      struct at91_nand_host *host = platform_get_drvdata(pdev);
+-      struct mtd_info *mtd = &host->mtd;
+-
+-      nand_release(mtd);
+-
+-      at91_nand_disable(host);
+-
+-      iounmap(host->io_base);
+-      kfree(host);
+-
+-      return 0;
+-}
+-
+-static struct platform_driver at91_nand_driver = {
+-      .probe          = at91_nand_probe,
+-      .remove         = at91_nand_remove,
+-      .driver         = {
+-              .name   = "at91_nand",
+-              .owner  = THIS_MODULE,
+-      },
+-};
+-
+-static int __init at91_nand_init(void)
+-{
+-      return platform_driver_register(&at91_nand_driver);
+-}
+-
+-
+-static void __exit at91_nand_exit(void)
+-{
+-      platform_driver_unregister(&at91_nand_driver);
+-}
+-
+-
+-module_init(at91_nand_init);
+-module_exit(at91_nand_exit);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Rick Bronson");
+-MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200");
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/atmel_nand.c avr32-2.6/drivers/mtd/nand/atmel_nand.c
+--- linux-2.6.25.6/drivers/mtd/nand/atmel_nand.c       1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/drivers/mtd/nand/atmel_nand.c    2008-06-12 15:09:41.107815889 +0200
+@@ -0,0 +1,650 @@
++/*
++ *  Copyright (C) 2003 Rick Bronson
++ *
++ *  Derived from drivers/mtd/nand/autcpu12.c
++ *     Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
++ *
++ *  Derived from drivers/mtd/spia.c
++ *     Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
++ *
++ *
++ *  Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
++ *     Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright (C) 2007
++ *
++ *     Derived from Das U-Boot source code
++ *                    (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
++ *     (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
++ *
++ *
++ * 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/slab.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
++
++#include <linux/gpio.h>
++#include <linux/io.h>
++
++#include <asm/arch/board.h>
++#include <asm/arch/cpu.h>
++
++#ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW
++#define hard_ecc      1
++#else
++#define hard_ecc      0
++#endif
++
++#ifdef CONFIG_MTD_NAND_ATMEL_ECC_NONE
++#define no_ecc                1
++#else
++#define no_ecc                0
++#endif
++
++/* Register access macros */
++#define ecc_readl(add, reg)                           \
++      __raw_readl(add + ATMEL_ECC_##reg)
++#define ecc_writel(add, reg, value)                   \
++      __raw_writel((value), add + ATMEL_ECC_##reg)
++
++#include "atmel_nand_ecc.h"   /* Hardware ECC registers */
++
++/* oob layout for large page size
++ * bad block info is on bytes 0 and 1
++ * the bytes have to be consecutives to avoid
++ * several NAND_CMD_RNDOUT during read
++ */
++static struct nand_ecclayout atmel_oobinfo_large = {
++      .eccbytes = 4,
++      .eccpos = {60, 61, 62, 63},
++      .oobfree = {
++              {2, 58}
++      },
++};
++
++/* oob layout for small page size
++ * bad block info is on bytes 4 and 5
++ * the bytes have to be consecutives to avoid
++ * several NAND_CMD_RNDOUT during read
++ */
++static struct nand_ecclayout atmel_oobinfo_small = {
++      .eccbytes = 4,
++      .eccpos = {0, 1, 2, 3},
++      .oobfree = {
++              {6, 10}
++      },
++};
++
++struct atmel_nand_host {
++      struct nand_chip        nand_chip;
++      struct mtd_info         mtd;
++      void __iomem            *io_base;
++      struct atmel_nand_data  *board;
++      struct device           *dev;
++      void __iomem            *ecc;
++};
++
++/*
++ * Enable NAND.
++ */
++static void atmel_nand_enable(struct atmel_nand_host *host)
++{
++      if (host->board->enable_pin)
++              gpio_set_value(host->board->enable_pin, 0);
++}
++
++/*
++ * Disable NAND.
++ */
++static void atmel_nand_disable(struct atmel_nand_host *host)
++{
++      if (host->board->enable_pin)
++              gpio_set_value(host->board->enable_pin, 1);
++}
++
++/*
++ * Hardware specific access to control-lines
++ */
++static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
++{
++      struct nand_chip *nand_chip = mtd->priv;
++      struct atmel_nand_host *host = nand_chip->priv;
++
++      if (ctrl & NAND_CTRL_CHANGE) {
++              if (ctrl & NAND_NCE)
++                      atmel_nand_enable(host);
++              else
++                      atmel_nand_disable(host);
++      }
++      if (cmd == NAND_CMD_NONE)
++              return;
++
++      if (ctrl & NAND_CLE)
++              writeb(cmd, host->io_base + (1 << host->board->cle));
++      else
++              writeb(cmd, host->io_base + (1 << host->board->ale));
++}
++
++/*
++ * Read the Device Ready pin.
++ */
++static int atmel_nand_device_ready(struct mtd_info *mtd)
++{
++      struct nand_chip *nand_chip = mtd->priv;
++      struct atmel_nand_host *host = nand_chip->priv;
++
++      return gpio_get_value(host->board->rdy_pin);
++}
++
++/*
++ * Minimal-overhead PIO for data access.
++ */
++static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len)
++{
++      struct nand_chip        *nand_chip = mtd->priv;
++
++      __raw_readsb(nand_chip->IO_ADDR_R, buf, len);
++}
++
++static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len)
++{
++      struct nand_chip        *nand_chip = mtd->priv;
++
++      __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2);
++}
++
++static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
++{
++      struct nand_chip        *nand_chip = mtd->priv;
++
++      __raw_writesb(nand_chip->IO_ADDR_W, buf, len);
++}
++
++static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len)
++{
++      struct nand_chip        *nand_chip = mtd->priv;
++
++      __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2);
++}
++
++/*
++ * write oob for small pages
++ */
++static int atmel_nand_write_oob_512(struct mtd_info *mtd,
++              struct nand_chip *chip, int page)
++{
++      int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
++      int eccsize = chip->ecc.size, length = mtd->oobsize;
++      int len, pos, status = 0;
++      const uint8_t *bufpoi = chip->oob_poi;
++
++      pos = eccsize + chunk;
++
++      chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page);
++      len = min_t(int, length, chunk);
++      chip->write_buf(mtd, bufpoi, len);
++      bufpoi += len;
++      length -= len;
++      if (length > 0)
++              chip->write_buf(mtd, bufpoi, length);
++
++      chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++      status = chip->waitfunc(mtd, chip);
++
++      return status & NAND_STATUS_FAIL ? -EIO : 0;
++
++}
++
++/*
++ * read oob for small pages
++ */
++static int atmel_nand_read_oob_512(struct mtd_info *mtd,
++              struct nand_chip *chip, int page, int sndcmd)
++{
++      if (sndcmd) {
++              chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
++              sndcmd = 0;
++      }
++      chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++      return sndcmd;
++}
++
++/*
++ * Calculate HW ECC
++ *
++ * function called after a write
++ *
++ * mtd:        MTD block structure
++ * dat:        raw data (unused)
++ * ecc_code:   buffer for ECC
++ */
++static int atmel_nand_calculate(struct mtd_info *mtd,
++              const u_char *dat, unsigned char *ecc_code)
++{
++      struct nand_chip *nand_chip = mtd->priv;
++      struct atmel_nand_host *host = nand_chip->priv;
++      uint32_t *eccpos = nand_chip->ecc.layout->eccpos;
++      unsigned int ecc_value;
++
++      /* get the first 2 ECC bytes */
++      ecc_value = ecc_readl(host->ecc, PR);
++
++      ecc_code[eccpos[0]] = ecc_value & 0xFF;
++      ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF;
++
++      /* get the last 2 ECC bytes */
++      ecc_value = ecc_readl(host->ecc, NPR) & ATMEL_ECC_NPARITY;
++
++      ecc_code[eccpos[2]] = ecc_value & 0xFF;
++      ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF;
++
++      return 0;
++}
++
++/*
++ * HW ECC read page function
++ *
++ * mtd:        mtd info structure
++ * chip:       nand chip info structure
++ * buf:        buffer to store read data
++ */
++static int atmel_nand_read_page(struct mtd_info *mtd,
++              struct nand_chip *chip, uint8_t *buf)
++{
++      int eccsize = chip->ecc.size;
++      int eccbytes = chip->ecc.bytes;
++      uint32_t *eccpos = chip->ecc.layout->eccpos;
++      uint8_t *p = buf;
++      uint8_t *oob = chip->oob_poi;
++      uint8_t *ecc_pos;
++      int stat;
++
++      /*
++       * Errata: ALE is incorrectly wired up to the ECC controller
++       * on the AP7000, so it will include the address cycles in the
++       * ECC calculation.
++       *
++       * Workaround: Reset the parity registers before reading the
++       * actual data.
++       */
++      if (cpu_is_at32ap7000()) {
++              struct atmel_nand_host *host = chip->priv;
++              ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
++      }
++
++      /* read the page */
++      chip->read_buf(mtd, p, eccsize);
++
++      /* move to ECC position if needed */
++      if (eccpos[0] != 0) {
++              /* This only works on large pages
++               * because the ECC controller waits for
++               * NAND_CMD_RNDOUTSTART after the
++               * NAND_CMD_RNDOUT.
++               * anyway, for small pages, the eccpos[0] == 0
++               */
++              chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
++                              mtd->writesize + eccpos[0], -1);
++      }
++
++      /* the ECC controller needs to read the ECC just after the data */
++      ecc_pos = oob + eccpos[0];
++      chip->read_buf(mtd, ecc_pos, eccbytes);
++
++      /* check if there's an error */
++      stat = chip->ecc.correct(mtd, p, oob, NULL);
++
++      if (stat < 0)
++              mtd->ecc_stats.failed++;
++      else
++              mtd->ecc_stats.corrected += stat;
++
++      /* get back to oob start (end of page) */
++      chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
++
++      /* read the oob */
++      chip->read_buf(mtd, oob, mtd->oobsize);
++
++      return 0;
++}
++
++/*
++ * HW ECC Correction
++ *
++ * function called after a read
++ *
++ * mtd:        MTD block structure
++ * dat:        raw data read from the chip
++ * read_ecc:   ECC from the chip (unused)
++ * isnull:     unused
++ *
++ * Detect and correct a 1 bit error for a page
++ */
++static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
++              u_char *read_ecc, u_char *isnull)
++{
++      struct nand_chip *nand_chip = mtd->priv;
++      struct atmel_nand_host *host = nand_chip->priv;
++      unsigned int ecc_status;
++      unsigned int ecc_word, ecc_bit;
++
++      /* get the status from the Status Register */
++      ecc_status = ecc_readl(host->ecc, SR);
++
++      /* if there's no error */
++      if (likely(!(ecc_status & ATMEL_ECC_RECERR)))
++              return 0;
++
++      /* get error bit offset (4 bits) */
++      ecc_bit = ecc_readl(host->ecc, PR) & ATMEL_ECC_BITADDR;
++      /* get word address (12 bits) */
++      ecc_word = ecc_readl(host->ecc, PR) & ATMEL_ECC_WORDADDR;
++      ecc_word >>= 4;
++
++      /* if there are multiple errors */
++      if (ecc_status & ATMEL_ECC_MULERR) {
++              /* check if it is a freshly erased block
++               * (filled with 0xff) */
++              if ((ecc_bit == ATMEL_ECC_BITADDR)
++                              && (ecc_word == (ATMEL_ECC_WORDADDR >> 4))) {
++                      /* the block has just been erased, return OK */
++                      return 0;
++              }
++              /* it doesn't seems to be a freshly
++               * erased block.
++               * We can't correct so many errors */
++              dev_dbg(host->dev, "atmel_nand : multiple errors detected."
++                              " Unable to correct.\n");
++              return -EIO;
++      }
++
++      /* if there's a single bit error : we can correct it */
++      if (ecc_status & ATMEL_ECC_ECCERR) {
++              /* there's nothing much to do here.
++               * the bit error is on the ECC itself.
++               */
++              dev_dbg(host->dev, "atmel_nand : one bit error on ECC code."
++                              " Nothing to correct\n");
++              return 0;
++      }
++
++      dev_dbg(host->dev, "atmel_nand : one bit error on data."
++                      " (word offset in the page :"
++                      " 0x%x bit offset : 0x%x)\n",
++                      ecc_word, ecc_bit);
++      /* correct the error */
++      if (nand_chip->options & NAND_BUSWIDTH_16) {
++              /* 16 bits words */
++              ((unsigned short *) dat)[ecc_word] ^= (1 << ecc_bit);
++      } else {
++              /* 8 bits words */
++              dat[ecc_word] ^= (1 << ecc_bit);
++      }
++      dev_dbg(host->dev, "atmel_nand : error corrected\n");
++      return 1;
++}
++
++/*
++ * Enable HW ECC : unused on most chips
++ */
++static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
++{
++      if (cpu_is_at32ap7000()) {
++              struct nand_chip *nand_chip = mtd->priv;
++              struct atmel_nand_host *host = nand_chip->priv;
++              ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
++      }
++}
++
++#ifdef CONFIG_MTD_PARTITIONS
++static const char *part_probes[] = { "cmdlinepart", NULL };
++#endif
++
++/*
++ * Probe for the NAND device.
++ */
++static int __init atmel_nand_probe(struct platform_device *pdev)
++{
++      struct atmel_nand_host *host;
++      struct mtd_info *mtd;
++      struct nand_chip *nand_chip;
++      struct resource *regs;
++      struct resource *mem;
++      int res;
++
++#ifdef CONFIG_MTD_PARTITIONS
++      struct mtd_partition *partitions = NULL;
++      int num_partitions = 0;
++#endif
++
++      mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (!mem) {
++              printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n");
++              return -ENXIO;
++      }
++
++      /* Allocate memory for the device structure (and zero it) */
++      host = kzalloc(sizeof(struct atmel_nand_host), GFP_KERNEL);
++      if (!host) {
++              printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n");
++              return -ENOMEM;
++      }
++
++      host->io_base = ioremap(mem->start, mem->end - mem->start + 1);
++      if (host->io_base == NULL) {
++              printk(KERN_ERR "atmel_nand: ioremap failed\n");
++              res = -EIO;
++              goto err_nand_ioremap;
++      }
++
++      mtd = &host->mtd;
++      nand_chip = &host->nand_chip;
++      host->board = pdev->dev.platform_data;
++      host->dev = &pdev->dev;
++
++      nand_chip->priv = host;         /* link the private data structures */
++      mtd->priv = nand_chip;
++      mtd->owner = THIS_MODULE;
++
++      /* Set address of NAND IO lines */
++      nand_chip->IO_ADDR_R = host->io_base;
++      nand_chip->IO_ADDR_W = host->io_base;
++      nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
++
++      if (host->board->rdy_pin)
++              nand_chip->dev_ready = atmel_nand_device_ready;
++
++      regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++      if (!regs && hard_ecc) {
++              printk(KERN_ERR "atmel_nand: can't get I/O resource "
++                              "regs\nFalling back on software ECC\n");
++      }
++
++      nand_chip->ecc.mode = NAND_ECC_SOFT;    /* enable ECC */
++      if (no_ecc)
++              nand_chip->ecc.mode = NAND_ECC_NONE;
++      if (hard_ecc && regs) {
++              host->ecc = ioremap(regs->start, regs->end - regs->start + 1);
++              if (host->ecc == NULL) {
++                      printk(KERN_ERR "atmel_nand: ioremap failed\n");
++                      res = -EIO;
++                      goto err_ecc_ioremap;
++              }
++              nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME;
++              nand_chip->ecc.calculate = atmel_nand_calculate;
++              nand_chip->ecc.correct = atmel_nand_correct;
++              nand_chip->ecc.hwctl = atmel_nand_hwctl;
++              nand_chip->ecc.read_page = atmel_nand_read_page;
++              nand_chip->ecc.bytes = 4;
++              nand_chip->ecc.prepad = 0;
++              nand_chip->ecc.postpad = 0;
++      }
++
++      nand_chip->chip_delay = 20;             /* 20us command delay time */
++
++      if (host->board->bus_width_16) {        /* 16-bit bus width */
++              nand_chip->options |= NAND_BUSWIDTH_16;
++              nand_chip->read_buf = atmel_read_buf16;
++              nand_chip->write_buf = atmel_write_buf16;
++      } else {
++              nand_chip->read_buf = atmel_read_buf;
++              nand_chip->write_buf = atmel_write_buf;
++      }
++
++      platform_set_drvdata(pdev, host);
++      atmel_nand_enable(host);
++
++      if (host->board->det_pin) {
++              if (gpio_get_value(host->board->det_pin)) {
++                      printk("No SmartMedia card inserted.\n");
++                      res = ENXIO;
++                      goto err_no_card;
++              }
++      }
++
++      /* first scan to find the device and get the page size */
++      if (nand_scan_ident(mtd, 1)) {
++              res = -ENXIO;
++              goto err_scan_ident;
++      }
++
++      if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) {
++              /* ECC is calculated for the whole page (1 step) */
++              nand_chip->ecc.size = mtd->writesize;
++
++              /* set ECC page size and oob layout */
++              switch (mtd->writesize) {
++              case 512:
++                      nand_chip->ecc.layout = &atmel_oobinfo_small;
++                      nand_chip->ecc.read_oob = atmel_nand_read_oob_512;
++                      nand_chip->ecc.write_oob = atmel_nand_write_oob_512;
++                      ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
++                      break;
++              case 1024:
++                      nand_chip->ecc.layout = &atmel_oobinfo_large;
++                      ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056);
++                      break;
++              case 2048:
++                      nand_chip->ecc.layout = &atmel_oobinfo_large;
++                      ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112);
++                      break;
++              case 4096:
++                      nand_chip->ecc.layout = &atmel_oobinfo_large;
++                      ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224);
++                      break;
++              default:
++                      /* page size not handled by HW ECC */
++                      /* switching back to soft ECC */
++                      nand_chip->ecc.mode = NAND_ECC_SOFT;
++                      nand_chip->ecc.calculate = NULL;
++                      nand_chip->ecc.correct = NULL;
++                      nand_chip->ecc.hwctl = NULL;
++                      nand_chip->ecc.read_page = NULL;
++                      nand_chip->ecc.postpad = 0;
++                      nand_chip->ecc.prepad = 0;
++                      nand_chip->ecc.bytes = 0;
++                      break;
++              }
++      }
++
++      /* second phase scan */
++      if (nand_scan_tail(mtd)) {
++              res = -ENXIO;
++              goto err_scan_tail;
++      }
++
++#ifdef CONFIG_MTD_PARTITIONS
++#ifdef CONFIG_MTD_CMDLINE_PARTS
++      mtd->name = "atmel_nand";
++      num_partitions = parse_mtd_partitions(mtd, part_probes,
++                                            &partitions, 0);
++#endif
++      if (num_partitions <= 0 && host->board->partition_info)
++              partitions = host->board->partition_info(mtd->size,
++                                                       &num_partitions);
++
++      if ((!partitions) || (num_partitions == 0)) {
++              printk(KERN_ERR "atmel_nand: No parititions defined, or unsupported device.\n");
++              res = ENXIO;
++              goto err_no_partitions;
++      }
++
++      res = add_mtd_partitions(mtd, partitions, num_partitions);
++#else
++      res = add_mtd_device(mtd);
++#endif
++
++      if (!res)
++              return res;
++
++#ifdef CONFIG_MTD_PARTITIONS
++err_no_partitions:
++#endif
++      nand_release(mtd);
++err_scan_tail:
++err_scan_ident:
++err_no_card:
++      atmel_nand_disable(host);
++      platform_set_drvdata(pdev, NULL);
++      if (host->ecc)
++              iounmap(host->ecc);
++err_ecc_ioremap:
++      iounmap(host->io_base);
++err_nand_ioremap:
++      kfree(host);
++      return res;
++}
++
++/*
++ * Remove a NAND device.
++ */
++static int __exit atmel_nand_remove(struct platform_device *pdev)
++{
++      struct atmel_nand_host *host = platform_get_drvdata(pdev);
++      struct mtd_info *mtd = &host->mtd;
++
++      nand_release(mtd);
++
++      atmel_nand_disable(host);
++
++      if (host->ecc)
++              iounmap(host->ecc);
++      iounmap(host->io_base);
++      kfree(host);
++
++      return 0;
++}
++
++static struct platform_driver atmel_nand_driver = {
++      .remove         = __exit_p(atmel_nand_remove),
++      .driver         = {
++              .name   = "atmel_nand",
++              .owner  = THIS_MODULE,
++      },
++};
++
++static int __init atmel_nand_init(void)
++{
++      return platform_driver_probe(&atmel_nand_driver, atmel_nand_probe);
++}
++
++
++static void __exit atmel_nand_exit(void)
++{
++      platform_driver_unregister(&atmel_nand_driver);
++}
++
++
++module_init(atmel_nand_init);
++module_exit(atmel_nand_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Rick Bronson");
++MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91 / AVR32");
++MODULE_ALIAS("platform:atmel_nand");
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/atmel_nand_ecc.h avr32-2.6/drivers/mtd/nand/atmel_nand_ecc.h
+--- linux-2.6.25.6/drivers/mtd/nand/atmel_nand_ecc.h   1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/drivers/mtd/nand/atmel_nand_ecc.h        2008-06-12 15:09:41.111815840 +0200
+@@ -0,0 +1,36 @@
++/*
++ * Error Corrected Code Controller (ECC) - System peripherals regsters.
++ * Based on AT91SAM9260 datasheet revision B.
++ *
++ * 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.
++ */
++
++#ifndef ATMEL_NAND_ECC_H
++#define ATMEL_NAND_ECC_H
++
++#define ATMEL_ECC_CR          0x00                    /* Control register */
++#define               ATMEL_ECC_RST           (1 << 0)                /* Reset parity */
++
++#define ATMEL_ECC_MR          0x04                    /* Mode register */
++#define               ATMEL_ECC_PAGESIZE      (3 << 0)                /* Page Size */
++#define                       ATMEL_ECC_PAGESIZE_528          (0)
++#define                       ATMEL_ECC_PAGESIZE_1056         (1)
++#define                       ATMEL_ECC_PAGESIZE_2112         (2)
++#define                       ATMEL_ECC_PAGESIZE_4224         (3)
++
++#define ATMEL_ECC_SR          0x08                    /* Status register */
++#define               ATMEL_ECC_RECERR                (1 << 0)                /* Recoverable Error */
++#define               ATMEL_ECC_ECCERR                (1 << 1)                /* ECC Single Bit Error */
++#define               ATMEL_ECC_MULERR                (1 << 2)                /* Multiple Errors */
++
++#define ATMEL_ECC_PR          0x0c                    /* Parity register */
++#define               ATMEL_ECC_BITADDR       (0xf << 0)              /* Bit Error Address */
++#define               ATMEL_ECC_WORDADDR      (0xfff << 4)            /* Word Error Address */
++
++#define ATMEL_ECC_NPR         0x10                    /* NParity register */
++#define               ATMEL_ECC_NPARITY       (0xffff << 0)           /* NParity */
++
++#endif
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/bf5xx_nand.c avr32-2.6/drivers/mtd/nand/bf5xx_nand.c
+--- linux-2.6.25.6/drivers/mtd/nand/bf5xx_nand.c       2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/nand/bf5xx_nand.c    2008-06-12 15:09:41.111815840 +0200
+@@ -803,3 +803,4 @@
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR(DRV_AUTHOR);
+ MODULE_DESCRIPTION(DRV_DESC);
++MODULE_ALIAS("platform:" DRV_NAME);
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/Kconfig avr32-2.6/drivers/mtd/nand/Kconfig
+--- linux-2.6.25.6/drivers/mtd/nand/Kconfig    2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/nand/Kconfig 2008-06-12 15:09:41.107815889 +0200
+@@ -272,12 +272,54 @@
+         If you say "m", the module will be called "cs553x_nand.ko".
+-config MTD_NAND_AT91
+-      bool "Support for NAND Flash / SmartMedia on AT91"
+-      depends on ARCH_AT91
++config MTD_NAND_ATMEL
++      bool "Support for NAND Flash / SmartMedia on AT91 and AVR32"
++      depends on ARCH_AT91 || AVR32
+       help
+         Enables support for NAND Flash / Smart Media Card interface
+-        on Atmel AT91 processors.
++        on Atmel AT91 and AVR32 processors.
++choice
++      prompt "ECC management for NAND Flash / SmartMedia on AT91 / AVR32"
++      depends on MTD_NAND_ATMEL
++
++config MTD_NAND_ATMEL_ECC_HW
++      bool "Hardware ECC"
++      depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 || AVR32
++      help
++        Use hardware ECC instead of software ECC when the chip
++        supports it.
++
++        The hardware ECC controller is capable of single bit error
++        correction and 2-bit random detection per page.
++
++        NB : hardware and software ECC schemes are incompatible.
++        If you switch from one to another, you'll have to erase your
++        mtd partition.
++
++        If unsure, say Y
++
++config MTD_NAND_ATMEL_ECC_SOFT
++      bool "Software ECC"
++      help
++        Use software ECC.
++
++        NB : hardware and software ECC schemes are incompatible.
++        If you switch from one to another, you'll have to erase your
++        mtd partition.
++
++config MTD_NAND_ATMEL_ECC_NONE
++      bool "No ECC (testing only, DANGEROUS)"
++      depends on DEBUG_KERNEL
++      help
++        No ECC will be used.
++        It's not a good idea and it should be reserved for testing
++        purpose only.
++
++        If unsure, say N
++
++        endchoice
++
++endchoice
+ config MTD_NAND_CM_X270
+       tristate "Support for NAND Flash on CM-X270 modules"
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/Makefile avr32-2.6/drivers/mtd/nand/Makefile
+--- linux-2.6.25.6/drivers/mtd/nand/Makefile   2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/nand/Makefile        2008-06-12 15:09:41.107815889 +0200
+@@ -24,7 +24,7 @@
+ obj-$(CONFIG_MTD_NAND_NANDSIM)                += nandsim.o
+ obj-$(CONFIG_MTD_NAND_CS553X)         += cs553x_nand.o
+ obj-$(CONFIG_MTD_NAND_NDFC)           += ndfc.o
+-obj-$(CONFIG_MTD_NAND_AT91)           += at91_nand.o
++obj-$(CONFIG_MTD_NAND_ATMEL)          += atmel_nand.o
+ obj-$(CONFIG_MTD_NAND_CM_X270)                += cmx270_nand.o
+ obj-$(CONFIG_MTD_NAND_BASLER_EXCITE)  += excite_nandflash.o
+ obj-$(CONFIG_MTD_NAND_PLATFORM)               += plat_nand.o
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/ndfc.c avr32-2.6/drivers/mtd/nand/ndfc.c
+--- linux-2.6.25.6/drivers/mtd/nand/ndfc.c     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/nand/ndfc.c  2008-06-12 15:03:59.579815954 +0200
+@@ -317,3 +317,5 @@
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
+ MODULE_DESCRIPTION("Platform driver for NDFC");
++MODULE_ALIAS("platform:ndfc-chip");
++MODULE_ALIAS("platform:ndfc-nand");
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/orion_nand.c avr32-2.6/drivers/mtd/nand/orion_nand.c
+--- linux-2.6.25.6/drivers/mtd/nand/orion_nand.c       2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/nand/orion_nand.c    2008-06-12 15:09:41.115816070 +0200
+@@ -169,3 +169,4 @@
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Tzachi Perelstein");
+ MODULE_DESCRIPTION("NAND glue for Orion platforms");
++MODULE_ALIAS("platform:orion_nand");
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/plat_nand.c avr32-2.6/drivers/mtd/nand/plat_nand.c
+--- linux-2.6.25.6/drivers/mtd/nand/plat_nand.c        2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/nand/plat_nand.c     2008-06-12 15:09:41.115816070 +0200
+@@ -150,3 +150,4 @@
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Vitaly Wool");
+ MODULE_DESCRIPTION("Simple generic NAND driver");
++MODULE_ALIAS("platform:gen_nand");
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/s3c2410.c avr32-2.6/drivers/mtd/nand/s3c2410.c
+--- linux-2.6.25.6/drivers/mtd/nand/s3c2410.c  2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/nand/s3c2410.c       2008-06-12 15:09:41.115816070 +0200
+@@ -927,3 +927,6 @@
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+ MODULE_DESCRIPTION("S3C24XX MTD NAND driver");
++MODULE_ALIAS("platform:s3c2410-nand");
++MODULE_ALIAS("platform:s3c2412-nand");
++MODULE_ALIAS("platform:s3c2440-nand");
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/build.c avr32-2.6/drivers/mtd/ubi/build.c
+--- linux-2.6.25.6/drivers/mtd/ubi/build.c     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/ubi/build.c  2008-06-12 15:09:41.119815462 +0200
+@@ -355,15 +355,34 @@
+ }
+ /**
++ * free_user_volumes - free all user volumes.
++ * @ubi: UBI device description object
++ *
++ * Normally the volumes are freed at the release function of the volume device
++ * objects. However, on error paths the volumes have to be freed before the
++ * device objects have been initialized.
++ */
++static void free_user_volumes(struct ubi_device *ubi)
++{
++      int i;
++
++      for (i = 0; i < ubi->vtbl_slots; i++)
++              if (ubi->volumes[i]) {
++                      kfree(ubi->volumes[i]->eba_tbl);
++                      kfree(ubi->volumes[i]);
++              }
++}
++
++/**
+  * uif_init - initialize user interfaces for an UBI device.
+  * @ubi: UBI device description object
+  *
+  * This function returns zero in case of success and a negative error code in
+- * case of failure.
++ * case of failure. Note, this function destroys all volumes if it failes.
+  */
+ static int uif_init(struct ubi_device *ubi)
+ {
+-      int i, err;
++      int i, err, do_free = 0;
+       dev_t dev;
+       sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num);
+@@ -410,10 +429,13 @@
+ out_volumes:
+       kill_volumes(ubi);
++      do_free = 0;
+ out_sysfs:
+       ubi_sysfs_close(ubi);
+       cdev_del(&ubi->cdev);
+ out_unreg:
++      if (do_free)
++              free_user_volumes(ubi);
+       unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1);
+       ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err);
+       return err;
+@@ -422,6 +444,10 @@
+ /**
+  * uif_close - close user interfaces for an UBI device.
+  * @ubi: UBI device description object
++ *
++ * Note, since this function un-registers UBI volume device objects (@vol->dev),
++ * the memory allocated voe the volumes is freed as well (in the release
++ * function).
+  */
+ static void uif_close(struct ubi_device *ubi)
+ {
+@@ -432,6 +458,21 @@
+ }
+ /**
++ * free_internal_volumes - free internal volumes.
++ * @ubi: UBI device description object
++ */
++static void free_internal_volumes(struct ubi_device *ubi)
++{
++      int i;
++
++      for (i = ubi->vtbl_slots;
++           i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
++              kfree(ubi->volumes[i]->eba_tbl);
++              kfree(ubi->volumes[i]);
++      }
++}
++
++/**
+  * attach_by_scanning - attach an MTD device using scanning method.
+  * @ubi: UBI device descriptor
+  *
+@@ -475,6 +516,7 @@
+ out_wl:
+       ubi_wl_close(ubi);
+ out_vtbl:
++      free_internal_volumes(ubi);
+       vfree(ubi->vtbl);
+ out_si:
+       ubi_scan_destroy_si(si);
+@@ -530,7 +572,11 @@
+       ubi->min_io_size = ubi->mtd->writesize;
+       ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
+-      /* Make sure minimal I/O unit is power of 2 */
++      /*
++       * Make sure minimal I/O unit is power of 2. Note, there is no
++       * fundamental reason for this assumption. It is just an optimization
++       * which allows us to avoid costly division operations.
++       */
+       if (!is_power_of_2(ubi->min_io_size)) {
+               ubi_err("min. I/O unit (%d) is not power of 2",
+                       ubi->min_io_size);
+@@ -581,7 +627,7 @@
+       if (ubi->vid_hdr_offset < UBI_EC_HDR_SIZE ||
+           ubi->leb_start < ubi->vid_hdr_offset + UBI_VID_HDR_SIZE ||
+           ubi->leb_start > ubi->peb_size - UBI_VID_HDR_SIZE ||
+-          ubi->leb_start % ubi->min_io_size) {
++          ubi->leb_start & (ubi->min_io_size - 1)) {
+               ubi_err("bad VID header (%d) or data offsets (%d)",
+                       ubi->vid_hdr_offset, ubi->leb_start);
+               return -EINVAL;
+@@ -606,8 +652,16 @@
+               ubi->ro_mode = 1;
+       }
+-      dbg_msg("leb_size         %d", ubi->leb_size);
+-      dbg_msg("ro_mode          %d", ubi->ro_mode);
++      ubi_msg("physical eraseblock size:   %d bytes (%d KiB)",
++              ubi->peb_size, ubi->peb_size >> 10);
++      ubi_msg("logical eraseblock size:    %d bytes", ubi->leb_size);
++      ubi_msg("smallest flash I/O unit:    %d", ubi->min_io_size);
++      if (ubi->hdrs_min_io_size != ubi->min_io_size)
++              ubi_msg("sub-page size:              %d",
++                      ubi->hdrs_min_io_size);
++      ubi_msg("VID header offset:          %d (aligned %d)",
++              ubi->vid_hdr_offset, ubi->vid_hdr_aloffset);
++      ubi_msg("data offset:                %d", ubi->leb_start);
+       /*
+        * Note, ideally, we have to initialize ubi->bad_peb_count here. But
+@@ -638,7 +692,7 @@
+       /*
+        * Clear the auto-resize flag in the volume in-memory copy of the
+-       * volume table, and 'ubi_resize_volume()' will propogate this change
++       * volume table, and 'ubi_resize_volume()' will propagate this change
+        * to the flash.
+        */
+       ubi->vtbl[vol_id].flags &= ~UBI_VTBL_AUTORESIZE_FLG;
+@@ -647,7 +701,7 @@
+               struct ubi_vtbl_record vtbl_rec;
+               /*
+-               * No avalilable PEBs to re-size the volume, clear the flag on
++               * No available PEBs to re-size the volume, clear the flag on
+                * flash and exit.
+                */
+               memcpy(&vtbl_rec, &ubi->vtbl[vol_id],
+@@ -680,7 +734,7 @@
+  *
+  * This function attaches MTD device @mtd_dev to UBI and assign @ubi_num number
+  * to the newly created UBI device, unless @ubi_num is %UBI_DEV_NUM_AUTO, in
+- * which case this function finds a vacant device nubert and assings it
++ * which case this function finds a vacant device number and assigns it
+  * automatically. Returns the new UBI device number in case of success and a
+  * negative error code in case of failure.
+  *
+@@ -690,7 +744,7 @@
+ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
+ {
+       struct ubi_device *ubi;
+-      int i, err;
++      int i, err, do_free = 1;
+       /*
+        * Check if we already have the same MTD device attached.
+@@ -755,8 +809,7 @@
+       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);
++      ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num);
+       err = io_init(ubi);
+       if (err)
+@@ -791,7 +844,7 @@
+       err = uif_init(ubi);
+       if (err)
+-              goto out_detach;
++              goto out_nofree;
+       ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
+       if (IS_ERR(ubi->bgt_thread)) {
+@@ -804,15 +857,8 @@
+       ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num);
+       ubi_msg("MTD device name:            \"%s\"", mtd->name);
+       ubi_msg("MTD device size:            %llu MiB", ubi->flash_size >> 20);
+-      ubi_msg("physical eraseblock size:   %d bytes (%d KiB)",
+-              ubi->peb_size, ubi->peb_size >> 10);
+-      ubi_msg("logical eraseblock size:    %d bytes", ubi->leb_size);
+       ubi_msg("number of good PEBs:        %d", ubi->good_peb_count);
+       ubi_msg("number of bad PEBs:         %d", ubi->bad_peb_count);
+-      ubi_msg("smallest flash I/O unit:    %d", ubi->min_io_size);
+-      ubi_msg("VID header offset:          %d (aligned %d)",
+-              ubi->vid_hdr_offset, ubi->vid_hdr_aloffset);
+-      ubi_msg("data offset:                %d", ubi->leb_start);
+       ubi_msg("max. allowed volumes:       %d", ubi->vtbl_slots);
+       ubi_msg("wear-leveling threshold:    %d", CONFIG_MTD_UBI_WL_THRESHOLD);
+       ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT);
+@@ -835,9 +881,13 @@
+ out_uif:
+       uif_close(ubi);
++out_nofree:
++      do_free = 0;
+ out_detach:
+-      ubi_eba_close(ubi);
+       ubi_wl_close(ubi);
++      if (do_free)
++              free_user_volumes(ubi);
++      free_internal_volumes(ubi);
+       vfree(ubi->vtbl);
+ out_free:
+       vfree(ubi->peb_buf1);
+@@ -899,8 +949,8 @@
+               kthread_stop(ubi->bgt_thread);
+       uif_close(ubi);
+-      ubi_eba_close(ubi);
+       ubi_wl_close(ubi);
++      free_internal_volumes(ubi);
+       vfree(ubi->vtbl);
+       put_mtd_device(ubi->mtd);
+       vfree(ubi->peb_buf1);
+@@ -950,8 +1000,7 @@
+       BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
+       if (mtd_devs > UBI_MAX_DEVICES) {
+-              printk(KERN_ERR "UBI error: too many MTD devices, "
+-                     "maximum is %d\n", UBI_MAX_DEVICES);
++              ubi_err("too many MTD devices, maximum is %d", UBI_MAX_DEVICES);
+               return -EINVAL;
+       }
+@@ -959,25 +1008,25 @@
+       ubi_class = class_create(THIS_MODULE, UBI_NAME_STR);
+       if (IS_ERR(ubi_class)) {
+               err = PTR_ERR(ubi_class);
+-              printk(KERN_ERR "UBI error: cannot create UBI class\n");
++              ubi_err("cannot create UBI class");
+               goto out;
+       }
+       err = class_create_file(ubi_class, &ubi_version);
+       if (err) {
+-              printk(KERN_ERR "UBI error: cannot create sysfs file\n");
++              ubi_err("cannot create sysfs file");
+               goto out_class;
+       }
+       err = misc_register(&ubi_ctrl_cdev);
+       if (err) {
+-              printk(KERN_ERR "UBI error: cannot register device\n");
++              ubi_err("cannot register device");
+               goto out_version;
+       }
+       ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
+-                                              sizeof(struct ubi_wl_entry),
+-                                              0, 0, NULL);
++                                            sizeof(struct ubi_wl_entry),
++                                            0, 0, NULL);
+       if (!ubi_wl_entry_slab)
+               goto out_dev_unreg;
+@@ -1000,8 +1049,7 @@
+               mutex_unlock(&ubi_devices_mutex);
+               if (err < 0) {
+                       put_mtd_device(mtd);
+-                      printk(KERN_ERR "UBI error: cannot attach mtd%d\n",
+-                             mtd->index);
++                      ubi_err("cannot attach mtd%d", mtd->index);
+                       goto out_detach;
+               }
+       }
+@@ -1023,7 +1071,7 @@
+ out_class:
+       class_destroy(ubi_class);
+ out:
+-      printk(KERN_ERR "UBI error: cannot initialize UBI, error %d\n", err);
++      ubi_err("UBI error: cannot initialize UBI, error %d", err);
+       return err;
+ }
+ module_init(ubi_init);
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/cdev.c avr32-2.6/drivers/mtd/ubi/cdev.c
+--- linux-2.6.25.6/drivers/mtd/ubi/cdev.c      2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/ubi/cdev.c   2008-06-12 15:09:41.119815462 +0200
+@@ -290,7 +290,7 @@
+       off = do_div(tmp, vol->usable_leb_size);
+       lnum = tmp;
+-      if (off % ubi->min_io_size) {
++      if (off & (ubi->min_io_size - 1)) {
+               dbg_err("unaligned position");
+               return -EINVAL;
+       }
+@@ -299,7 +299,7 @@
+               count_save = count = vol->used_bytes - *offp;
+       /* We can write only in fractions of the minimum I/O unit */
+-      if (count % ubi->min_io_size) {
++      if (count & (ubi->min_io_size - 1)) {
+               dbg_err("unaligned write length");
+               return -EINVAL;
+       }
+@@ -559,7 +559,7 @@
+       if (req->alignment > ubi->leb_size)
+               goto bad;
+-      n = req->alignment % ubi->min_io_size;
++      n = req->alignment & (ubi->min_io_size - 1);
+       if (req->alignment != 1 && n)
+               goto bad;
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/debug.h avr32-2.6/drivers/mtd/ubi/debug.h
+--- linux-2.6.25.6/drivers/mtd/ubi/debug.h     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/ubi/debug.h  2008-06-12 15:09:41.123815692 +0200
+@@ -99,8 +99,10 @@
+ #ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD
+ /* Initialization and build messages */
+ #define dbg_bld(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
++#define UBI_IO_DEBUG 1
+ #else
+ #define dbg_bld(fmt, ...) ({})
++#define UBI_IO_DEBUG 0
+ #endif
+ #ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_BITFLIPS
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/eba.c avr32-2.6/drivers/mtd/ubi/eba.c
+--- linux-2.6.25.6/drivers/mtd/ubi/eba.c       2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/ubi/eba.c    2008-06-12 15:09:41.123815692 +0200
+@@ -752,7 +752,7 @@
+               /* If this is the last LEB @len may be unaligned */
+               len = ALIGN(data_size, ubi->min_io_size);
+       else
+-              ubi_assert(len % ubi->min_io_size == 0);
++              ubi_assert(!(len & (ubi->min_io_size - 1)));
+       vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
+       if (!vid_hdr)
+@@ -1233,20 +1233,3 @@
+       }
+       return err;
+ }
+-
+-/**
+- * ubi_eba_close - close EBA unit.
+- * @ubi: UBI device description object
+- */
+-void ubi_eba_close(const struct ubi_device *ubi)
+-{
+-      int i, num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT;
+-
+-      dbg_eba("close EBA unit");
+-
+-      for (i = 0; i < num_volumes; i++) {
+-              if (!ubi->volumes[i])
+-                      continue;
+-              kfree(ubi->volumes[i]->eba_tbl);
+-      }
+-}
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/gluebi.c avr32-2.6/drivers/mtd/ubi/gluebi.c
+--- linux-2.6.25.6/drivers/mtd/ubi/gluebi.c    2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/ubi/gluebi.c 2008-06-12 15:03:59.587815297 +0200
+@@ -291,11 +291,12 @@
+       /*
+        * In case of dynamic volume, MTD device size is just volume size. In
+        * case of a static volume the size is equivalent to the amount of data
+-       * bytes, which is zero at this moment and will be changed after volume
+-       * update.
++       * bytes.
+        */
+       if (vol->vol_type == UBI_DYNAMIC_VOLUME)
+               mtd->size = vol->usable_leb_size * vol->reserved_pebs;
++      else
++              mtd->size = vol->used_bytes;
+       if (add_mtd_device(mtd)) {
+               ubi_err("cannot not add MTD device\n");
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/io.c avr32-2.6/drivers/mtd/ubi/io.c
+--- linux-2.6.25.6/drivers/mtd/ubi/io.c        2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/ubi/io.c     2008-06-12 15:03:59.587815297 +0200
+@@ -631,6 +631,8 @@
+       dbg_io("read EC header from PEB %d", pnum);
+       ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
++      if (UBI_IO_DEBUG)
++              verbose = 1;
+       err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE);
+       if (err) {
+@@ -904,6 +906,8 @@
+       dbg_io("read VID header from PEB %d", pnum);
+       ubi_assert(pnum >= 0 &&  pnum < ubi->peb_count);
++      if (UBI_IO_DEBUG)
++              verbose = 1;
+       p = (char *)vid_hdr - ubi->vid_hdr_shift;
+       err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/kapi.c avr32-2.6/drivers/mtd/ubi/kapi.c
+--- linux-2.6.25.6/drivers/mtd/ubi/kapi.c      2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/ubi/kapi.c   2008-06-12 15:09:41.123815692 +0200
+@@ -397,8 +397,8 @@
+               return -EROFS;
+       if (lnum < 0 || lnum >= vol->reserved_pebs || offset < 0 || len < 0 ||
+-          offset + len > vol->usable_leb_size || offset % ubi->min_io_size ||
+-          len % ubi->min_io_size)
++          offset + len > vol->usable_leb_size ||
++          offset & (ubi->min_io_size - 1) || len & (ubi->min_io_size - 1))
+               return -EINVAL;
+       if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
+@@ -447,7 +447,7 @@
+               return -EROFS;
+       if (lnum < 0 || lnum >= vol->reserved_pebs || len < 0 ||
+-          len > vol->usable_leb_size || len % ubi->min_io_size)
++          len > vol->usable_leb_size || len & (ubi->min_io_size - 1))
+               return -EINVAL;
+       if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/Kconfig avr32-2.6/drivers/mtd/ubi/Kconfig
+--- linux-2.6.25.6/drivers/mtd/ubi/Kconfig     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/ubi/Kconfig  2008-06-12 15:03:59.583815905 +0200
+@@ -24,8 +24,13 @@
+         erase counter value and the lowest erase counter value of eraseblocks
+         of UBI devices. When this threshold is exceeded, UBI starts performing
+         wear leveling by means of moving data from eraseblock with low erase
+-        counter to eraseblocks with high erase counter. Leave the default
+-        value if unsure.
++        counter to eraseblocks with high erase counter.
++
++        The default value should be OK for SLC NAND flashes, NOR flashes and
++        other flashes which have eraseblock life-cycle 100000 or more.
++        However, in case of MLC NAND flashes which typically have eraseblock
++        life-cycle less then 10000, the threshold should be lessened (e.g.,
++        to 128 or 256, although it does not have to be power of 2).
+ config MTD_UBI_BEB_RESERVE
+       int "Percentage of reserved eraseblocks for bad eraseblocks handling"
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/misc.c avr32-2.6/drivers/mtd/ubi/misc.c
+--- linux-2.6.25.6/drivers/mtd/ubi/misc.c      2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/ubi/misc.c   2008-06-12 15:09:41.123815692 +0200
+@@ -37,7 +37,7 @@
+ {
+       int i;
+-      ubi_assert(length % ubi->min_io_size == 0);
++      ubi_assert(!(length & (ubi->min_io_size - 1)));
+       for (i = length - 1; i >= 0; i--)
+               if (((const uint8_t *)buf)[i] != 0xFF)
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/scan.c avr32-2.6/drivers/mtd/ubi/scan.c
+--- linux-2.6.25.6/drivers/mtd/ubi/scan.c      2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/ubi/scan.c   2008-06-12 15:03:59.587815297 +0200
+@@ -42,6 +42,7 @@
+ #include <linux/err.h>
+ #include <linux/crc32.h>
++#include <asm/div64.h>
+ #include "ubi.h"
+ #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+@@ -92,27 +93,6 @@
+ }
+ /**
+- * commit_to_mean_value - commit intermediate results to the final mean erase
+- * counter value.
+- * @si: scanning information
+- *
+- * This is a helper function which calculates partial mean erase counter mean
+- * value and adds it to the resulting mean value. As we can work only in
+- * integer arithmetic and we want to calculate the mean value of erase counter
+- * accurately, we first sum erase counter values in @si->ec_sum variable and
+- * count these components in @si->ec_count. If this temporary @si->ec_sum is
+- * going to overflow, we calculate the partial mean value
+- * (@si->ec_sum/@si->ec_count) and add it to @si->mean_ec.
+- */
+-static void commit_to_mean_value(struct ubi_scan_info *si)
+-{
+-      si->ec_sum /= si->ec_count;
+-      if (si->ec_sum % si->ec_count >= si->ec_count / 2)
+-              si->mean_ec += 1;
+-      si->mean_ec += si->ec_sum;
+-}
+-
+-/**
+  * validate_vid_hdr - check that volume identifier header is correct and
+  * consistent.
+  * @vid_hdr: the volume identifier header to check
+@@ -901,15 +881,8 @@
+ adjust_mean_ec:
+       if (!ec_corr) {
+-              if (si->ec_sum + ec < ec) {
+-                      commit_to_mean_value(si);
+-                      si->ec_sum = 0;
+-                      si->ec_count = 0;
+-              } else {
+-                      si->ec_sum += ec;
+-                      si->ec_count += 1;
+-              }
+-
++              si->ec_sum += ec;
++              si->ec_count += 1;
+               if (ec > si->max_ec)
+                       si->max_ec = ec;
+               if (ec < si->min_ec)
+@@ -965,9 +938,11 @@
+       dbg_msg("scanning is finished");
+-      /* Finish mean erase counter calculations */
+-      if (si->ec_count)
+-              commit_to_mean_value(si);
++      /* Calculate mean erase counter */
++      if (si->ec_count) {
++              do_div(si->ec_sum, si->ec_count);
++              si->mean_ec = si->ec_sum;
++      }
+       if (si->is_empty)
+               ubi_msg("empty MTD device detected");
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/scan.h avr32-2.6/drivers/mtd/ubi/scan.h
+--- linux-2.6.25.6/drivers/mtd/ubi/scan.h      2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/ubi/scan.h   2008-06-12 15:03:59.587815297 +0200
+@@ -124,7 +124,7 @@
+       int max_ec;
+       unsigned long long max_sqnum;
+       int mean_ec;
+-      int ec_sum;
++      uint64_t ec_sum;
+       int ec_count;
+ };
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/ubi.h avr32-2.6/drivers/mtd/ubi/ubi.h
+--- linux-2.6.25.6/drivers/mtd/ubi/ubi.h       2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/ubi/ubi.h    2008-06-12 15:09:41.123815692 +0200
+@@ -37,10 +37,9 @@
+ #include <linux/string.h>
+ #include <linux/vmalloc.h>
+ #include <linux/mtd/mtd.h>
+-
+-#include <mtd/ubi-header.h>
+ #include <linux/mtd/ubi.h>
++#include "ubi-media.h"
+ #include "scan.h"
+ #include "debug.h"
+@@ -478,7 +477,6 @@
+ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
+                    struct ubi_vid_hdr *vid_hdr);
+ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si);
+-void ubi_eba_close(const struct ubi_device *ubi);
+ /* wl.c */
+ int ubi_wl_get_peb(struct ubi_device *ubi, int dtype);
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/ubi-media.h avr32-2.6/drivers/mtd/ubi/ubi-media.h
+--- linux-2.6.25.6/drivers/mtd/ubi/ubi-media.h 1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/drivers/mtd/ubi/ubi-media.h      2008-06-12 15:03:59.587815297 +0200
+@@ -0,0 +1,372 @@
++/*
++ * Copyright (c) International Business Machines Corp., 2006
++ *
++ * 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
++ *
++ * Authors: Artem Bityutskiy (Битюцкий Артём)
++ *          Thomas Gleixner
++ *          Frank Haverkamp
++ *          Oliver Lohmann
++ *          Andreas Arnez
++ */
++
++/*
++ * This file defines the layout of UBI headers and all the other UBI on-flash
++ * data structures.
++ */
++
++#ifndef __UBI_MEDIA_H__
++#define __UBI_MEDIA_H__
++
++#include <asm/byteorder.h>
++
++/* The version of UBI images supported by this implementation */
++#define UBI_VERSION 1
++
++/* The highest erase counter value supported by this implementation */
++#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF
++
++/* The initial CRC32 value used when calculating CRC checksums */
++#define UBI_CRC32_INIT 0xFFFFFFFFU
++
++/* Erase counter header magic number (ASCII "UBI#") */
++#define UBI_EC_HDR_MAGIC  0x55424923
++/* Volume identifier header magic number (ASCII "UBI!") */
++#define UBI_VID_HDR_MAGIC 0x55424921
++
++/*
++ * Volume type constants used in the volume identifier header.
++ *
++ * @UBI_VID_DYNAMIC: dynamic volume
++ * @UBI_VID_STATIC: static volume
++ */
++enum {
++      UBI_VID_DYNAMIC = 1,
++      UBI_VID_STATIC  = 2
++};
++
++/*
++ * 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
++ * to the flash
++ * @UBI_COMPAT_RO: attach this device in read-only mode
++ * @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its
++ * physical eraseblocks, don't allow the wear-leveling unit to move them
++ * @UBI_COMPAT_REJECT: reject this UBI image
++ */
++enum {
++      UBI_COMPAT_DELETE   = 1,
++      UBI_COMPAT_RO       = 2,
++      UBI_COMPAT_PRESERVE = 4,
++      UBI_COMPAT_REJECT   = 5
++};
++
++/* Sizes of UBI headers */
++#define UBI_EC_HDR_SIZE  sizeof(struct ubi_ec_hdr)
++#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr)
++
++/* Sizes of UBI headers without the ending CRC */
++#define UBI_EC_HDR_SIZE_CRC  (UBI_EC_HDR_SIZE  - sizeof(__be32))
++#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(__be32))
++
++/**
++ * struct ubi_ec_hdr - UBI erase counter header.
++ * @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC)
++ * @version: version of UBI implementation which is supposed to accept this
++ * UBI image
++ * @padding1: reserved for future, zeroes
++ * @ec: the erase counter
++ * @vid_hdr_offset: where the VID header starts
++ * @data_offset: where the user data start
++ * @padding2: reserved for future, zeroes
++ * @hdr_crc: erase counter header CRC checksum
++ *
++ * The erase counter header takes 64 bytes and has a plenty of unused space for
++ * future usage. The unused fields are zeroed. The @version field is used to
++ * indicate the version of UBI implementation which is supposed to be able to
++ * work with this UBI image. If @version is greater then the current UBI
++ * version, the image is rejected. This may be useful in future if something
++ * is changed radically. This field is duplicated in the volume identifier
++ * header.
++ *
++ * The @vid_hdr_offset and @data_offset fields contain the offset of the the
++ * volume identifier header and user data, relative to the beginning of the
++ * physical eraseblock. These values have to be the same for all physical
++ * eraseblocks.
++ */
++struct ubi_ec_hdr {
++      __be32  magic;
++      __u8    version;
++      __u8    padding1[3];
++      __be64  ec; /* Warning: the current limit is 31-bit anyway! */
++      __be32  vid_hdr_offset;
++      __be32  data_offset;
++      __u8    padding2[36];
++      __be32  hdr_crc;
++} __attribute__ ((packed));
++
++/**
++ * struct ubi_vid_hdr - on-flash UBI volume identifier header.
++ * @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC)
++ * @version: UBI implementation version which is supposed to accept this UBI
++ * image (%UBI_VERSION)
++ * @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC)
++ * @copy_flag: if this logical eraseblock was copied from another physical
++ * eraseblock (for wear-leveling reasons)
++ * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE,
++ * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
++ * @vol_id: ID of this volume
++ * @lnum: logical eraseblock number
++ * @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be
++ * removed, kept only for not breaking older UBI users)
++ * @data_size: how many bytes of data this logical eraseblock contains
++ * @used_ebs: total number of used logical eraseblocks in this volume
++ * @data_pad: how many bytes at the end of this physical eraseblock are not
++ * used
++ * @data_crc: CRC checksum of the data stored in this logical eraseblock
++ * @padding1: reserved for future, zeroes
++ * @sqnum: sequence number
++ * @padding2: reserved for future, zeroes
++ * @hdr_crc: volume identifier header CRC checksum
++ *
++ * The @sqnum is the value of the global sequence counter at the time when this
++ * VID header was created. The global sequence counter is incremented each time
++ * UBI writes a new VID header to the flash, i.e. when it maps a logical
++ * eraseblock to a new physical eraseblock. The global sequence counter is an
++ * unsigned 64-bit integer and we assume it never overflows. The @sqnum
++ * (sequence number) is used to distinguish between older and newer versions of
++ * logical eraseblocks.
++ *
++ * There are 2 situations when there may be more then one physical eraseblock
++ * corresponding to the same logical eraseblock, i.e., having the same @vol_id
++ * and @lnum values in the volume identifier header. Suppose we have a logical
++ * eraseblock L and it is mapped to the physical eraseblock P.
++ *
++ * 1. Because UBI may erase physical eraseblocks asynchronously, the following
++ * situation is possible: L is asynchronously erased, so P is scheduled for
++ * erasure, then L is written to,i.e. mapped to another physical eraseblock P1,
++ * so P1 is written to, then an unclean reboot happens. Result - there are 2
++ * physical eraseblocks P and P1 corresponding to the same logical eraseblock
++ * L. But P1 has greater sequence number, so UBI picks P1 when it attaches the
++ * flash.
++ *
++ * 2. From time to time UBI moves logical eraseblocks to other physical
++ * eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P
++ * to P1, and an unclean reboot happens before P is physically erased, there
++ * are two physical eraseblocks P and P1 corresponding to L and UBI has to
++ * select one of them when the flash is attached. The @sqnum field says which
++ * PEB is the original (obviously P will have lower @sqnum) and the copy. But
++ * it is not enough to select the physical eraseblock with the higher sequence
++ * number, because the unclean reboot could have happen in the middle of the
++ * copying process, so the data in P is corrupted. It is also not enough to
++ * just select the physical eraseblock with lower sequence number, because the
++ * data there may be old (consider a case if more data was added to P1 after
++ * the copying). Moreover, the unclean reboot may happen when the erasure of P
++ * was just started, so it result in unstable P, which is "mostly" OK, but
++ * still has unstable bits.
++ *
++ * UBI uses the @copy_flag field to indicate that this logical eraseblock is a
++ * copy. UBI also calculates data CRC when the data is moved and stores it at
++ * the @data_crc field of the copy (P1). So when UBI needs to pick one physical
++ * eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is
++ * examined. If it is cleared, the situation* is simple and the newer one is
++ * picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC
++ * checksum is correct, this physical eraseblock is selected (P1). Otherwise
++ * the older one (P) is selected.
++ *
++ * Note, there is an obsolete @leb_ver field which was used instead of @sqnum
++ * in the past. But it is not used anymore and we keep it in order to be able
++ * to deal with old UBI images. It will be removed at some point.
++ *
++ * There are 2 sorts of volumes in UBI: user volumes and internal volumes.
++ * Internal volumes are not seen from outside and are used for various internal
++ * UBI purposes. In this implementation there is only one internal volume - the
++ * layout volume. Internal volumes are the main mechanism of UBI extensions.
++ * For example, in future one may introduce a journal internal volume. Internal
++ * volumes have their own reserved range of IDs.
++ *
++ * The @compat field is only used for internal volumes and contains the "degree
++ * of their compatibility". It is always zero for user volumes. This field
++ * provides a mechanism to introduce UBI extensions and to be still compatible
++ * with older UBI binaries. For example, if someone introduced a journal in
++ * future, he would probably use %UBI_COMPAT_DELETE compatibility for the
++ * journal volume.  And in this case, older UBI binaries, which know nothing
++ * about the journal volume, would just delete this volume and work perfectly
++ * fine. This is similar to what Ext2fs does when it is fed by an Ext3fs image
++ * - it just ignores the Ext3fs journal.
++ *
++ * The @data_crc field contains the CRC checksum of the contents of the logical
++ * eraseblock if this is a static volume. In case of dynamic volumes, it does
++ * not contain the CRC checksum as a rule. The only exception is when the
++ * data of the physical eraseblock was moved by the wear-leveling unit, then
++ * the wear-leveling unit calculates the data CRC and stores it in the
++ * @data_crc field. And of course, the @copy_flag is %in this case.
++ *
++ * The @data_size field is used only for static volumes because UBI has to know
++ * how many bytes of data are stored in this eraseblock. For dynamic volumes,
++ * this field usually contains zero. The only exception is when the data of the
++ * physical eraseblock was moved to another physical eraseblock for
++ * wear-leveling reasons. In this case, UBI calculates CRC checksum of the
++ * contents and uses both @data_crc and @data_size fields. In this case, the
++ * @data_size field contains data size.
++ *
++ * The @used_ebs field is used only for static volumes and indicates how many
++ * eraseblocks the data of the volume takes. For dynamic volumes this field is
++ * not used and always contains zero.
++ *
++ * The @data_pad is calculated when volumes are created using the alignment
++ * parameter. So, effectively, the @data_pad field reduces the size of logical
++ * eraseblocks of this volume. This is very handy when one uses block-oriented
++ * software (say, cramfs) on top of the UBI volume.
++ */
++struct ubi_vid_hdr {
++      __be32  magic;
++      __u8    version;
++      __u8    vol_type;
++      __u8    copy_flag;
++      __u8    compat;
++      __be32  vol_id;
++      __be32  lnum;
++      __be32  leb_ver; /* obsolete, to be removed, don't use */
++      __be32  data_size;
++      __be32  used_ebs;
++      __be32  data_pad;
++      __be32  data_crc;
++      __u8    padding1[4];
++      __be64  sqnum;
++      __u8    padding2[12];
++      __be32  hdr_crc;
++} __attribute__ ((packed));
++
++/* Internal UBI volumes count */
++#define UBI_INT_VOL_COUNT 1
++
++/*
++ * Starting ID of internal volumes. There is reserved room for 4096 internal
++ * volumes.
++ */
++#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096)
++
++/* The layout volume contains the volume table */
++
++#define UBI_LAYOUT_VOLUME_ID     UBI_INTERNAL_VOL_START
++#define UBI_LAYOUT_VOLUME_TYPE   UBI_VID_DYNAMIC
++#define UBI_LAYOUT_VOLUME_ALIGN  1
++#define UBI_LAYOUT_VOLUME_EBS    2
++#define UBI_LAYOUT_VOLUME_NAME   "layout volume"
++#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT
++
++/* The maximum number of volumes per one UBI device */
++#define UBI_MAX_VOLUMES 128
++
++/* The maximum volume name length */
++#define UBI_VOL_NAME_MAX 127
++
++/* Size of the volume table record */
++#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
++
++/* Size of the volume table record without the ending CRC */
++#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(__be32))
++
++/**
++ * struct ubi_vtbl_record - a record in the volume table.
++ * @reserved_pebs: how many physical eraseblocks are reserved for this volume
++ * @alignment: volume alignment
++ * @data_pad: how many bytes are unused at the end of the each physical
++ * eraseblock to satisfy the requested alignment
++ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
++ * @upd_marker: if volume update was started but not finished
++ * @name_len: volume name length
++ * @name: the volume name
++ * @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
++ * the layout volume. The layout volume consists of 2 logical eraseblock, each
++ * of which contains a copy of the volume table (i.e., the volume table is
++ * duplicated). The volume table is an array of &struct ubi_vtbl_record
++ * objects indexed by the volume ID.
++ *
++ * If the size of the logical eraseblock is large enough to fit
++ * %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES
++ * records. Otherwise, it contains as many records as it can fit (i.e., size of
++ * logical eraseblock divided by sizeof(struct ubi_vtbl_record)).
++ *
++ * The @upd_marker flag is used to implement volume update. It is set to %1
++ * before update and set to %0 after the update. So if the update operation was
++ * interrupted, UBI knows that the volume is corrupted.
++ *
++ * The @alignment field is specified when the volume is created and cannot be
++ * later changed. It may be useful, for example, when a block-oriented file
++ * system works on top of UBI. The @data_pad field is calculated using the
++ * logical eraseblock size and @alignment. The alignment must be multiple to the
++ * minimal flash I/O unit. If @alignment is 1, all the available space of
++ * the physical eraseblocks is used.
++ *
++ * Empty records contain all zeroes and the CRC checksum of those zeroes.
++ */
++struct ubi_vtbl_record {
++      __be32  reserved_pebs;
++      __be32  alignment;
++      __be32  data_pad;
++      __u8    vol_type;
++      __u8    upd_marker;
++      __be16  name_len;
++      __u8    name[UBI_VOL_NAME_MAX+1];
++      __u8    flags;
++      __u8    padding[23];
++      __be32  crc;
++} __attribute__ ((packed));
++
++#endif /* !__UBI_MEDIA_H__ */
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/upd.c avr32-2.6/drivers/mtd/ubi/upd.c
+--- linux-2.6.25.6/drivers/mtd/ubi/upd.c       2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/ubi/upd.c    2008-06-12 15:09:41.123815692 +0200
+@@ -237,10 +237,10 @@
+       int err;
+       if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
+-              len = ALIGN(len, ubi->min_io_size);
+-              memset(buf + len, 0xFF, len - len);
++              int l = ALIGN(len, ubi->min_io_size);
+-              len = ubi_calc_data_len(ubi, buf, len);
++              memset(buf + len, 0xFF, l - len);
++              len = ubi_calc_data_len(ubi, buf, l);
+               if (len == 0) {
+                       dbg_msg("all %d bytes contain 0xFF - skip", len);
+                       return 0;
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/vmt.c avr32-2.6/drivers/mtd/ubi/vmt.c
+--- linux-2.6.25.6/drivers/mtd/ubi/vmt.c       2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/ubi/vmt.c    2008-06-12 15:09:41.123815692 +0200
+@@ -127,6 +127,7 @@
+ {
+       struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);
++      kfree(vol->eba_tbl);
+       kfree(vol);
+ }
+@@ -201,7 +202,7 @@
+  */
+ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
+ {
+-      int i, err, vol_id = req->vol_id, dont_free = 0;
++      int i, err, vol_id = req->vol_id, do_free = 1;
+       struct ubi_volume *vol;
+       struct ubi_vtbl_record vtbl_rec;
+       uint64_t bytes;
+@@ -365,14 +366,14 @@
+ out_sysfs:
+       /*
+-       * We have registered our device, we should not free the volume*
++       * We have registered our device, we should not free the volume
+        * description object in this function in case of an error - it is
+        * freed by the release function.
+        *
+        * Get device reference to prevent the release function from being
+        * called just after sysfs has been closed.
+        */
+-      dont_free = 1;
++      do_free = 0;
+       get_device(&vol->dev);
+       volume_sysfs_close(vol);
+ out_gluebi:
+@@ -382,17 +383,18 @@
+ out_cdev:
+       cdev_del(&vol->cdev);
+ out_mapping:
+-      kfree(vol->eba_tbl);
++      if (do_free)
++              kfree(vol->eba_tbl);
+ out_acc:
+       spin_lock(&ubi->volumes_lock);
+       ubi->rsvd_pebs -= vol->reserved_pebs;
+       ubi->avail_pebs += vol->reserved_pebs;
+ out_unlock:
+       spin_unlock(&ubi->volumes_lock);
+-      if (dont_free)
+-              put_device(&vol->dev);
+-      else
++      if (do_free)
+               kfree(vol);
++      else
++              put_device(&vol->dev);
+       ubi_err("cannot create volume %d, error %d", vol_id, err);
+       return err;
+ }
+@@ -445,8 +447,6 @@
+                       goto out_err;
+       }
+-      kfree(vol->eba_tbl);
+-      vol->eba_tbl = NULL;
+       cdev_del(&vol->cdev);
+       volume_sysfs_close(vol);
+@@ -727,7 +727,7 @@
+               goto fail;
+       }
+-      n = vol->alignment % ubi->min_io_size;
++      n = vol->alignment & (ubi->min_io_size - 1);
+       if (vol->alignment != 1 && n) {
+               ubi_err("alignment is not multiple of min I/O unit");
+               goto fail;
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/vtbl.c avr32-2.6/drivers/mtd/ubi/vtbl.c
+--- linux-2.6.25.6/drivers/mtd/ubi/vtbl.c      2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/ubi/vtbl.c   2008-06-12 15:09:41.127815922 +0200
+@@ -127,7 +127,7 @@
+                     const struct ubi_vtbl_record *vtbl)
+ {
+       int i, n, reserved_pebs, alignment, data_pad, vol_type, name_len;
+-      int upd_marker;
++      int upd_marker, err;
+       uint32_t crc;
+       const char *name;
+@@ -153,7 +153,7 @@
+               if (reserved_pebs == 0) {
+                       if (memcmp(&vtbl[i], &empty_vtbl_record,
+                                               UBI_VTBL_RECORD_SIZE)) {
+-                              dbg_err("bad empty record");
++                              err = 2;
+                               goto bad;
+                       }
+                       continue;
+@@ -161,56 +161,57 @@
+               if (reserved_pebs < 0 || alignment < 0 || data_pad < 0 ||
+                   name_len < 0) {
+-                      dbg_err("negative values");
++                      err = 3;
+                       goto bad;
+               }
+               if (alignment > ubi->leb_size || alignment == 0) {
+-                      dbg_err("bad alignment");
++                      err = 4;
+                       goto bad;
+               }
+-              n = alignment % ubi->min_io_size;
++              n = alignment & (ubi->min_io_size - 1);
+               if (alignment != 1 && n) {
+-                      dbg_err("alignment is not multiple of min I/O unit");
++                      err = 5;
+                       goto bad;
+               }
+               n = ubi->leb_size % alignment;
+               if (data_pad != n) {
+                       dbg_err("bad data_pad, has to be %d", n);
++                      err = 6;
+                       goto bad;
+               }
+               if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) {
+-                      dbg_err("bad vol_type");
++                      err = 7;
+                       goto bad;
+               }
+               if (upd_marker != 0 && upd_marker != 1) {
+-                      dbg_err("bad upd_marker");
++                      err = 8;
+                       goto bad;
+               }
+               if (reserved_pebs > ubi->good_peb_count) {
+                       dbg_err("too large reserved_pebs, good PEBs %d",
+                               ubi->good_peb_count);
++                      err = 9;
+                       goto bad;
+               }
+               if (name_len > UBI_VOL_NAME_MAX) {
+-                      dbg_err("too long volume name, max %d",
+-                              UBI_VOL_NAME_MAX);
++                      err = 10;
+                       goto bad;
+               }
+               if (name[0] == '\0') {
+-                      dbg_err("NULL volume name");
++                      err = 11;
+                       goto bad;
+               }
+               if (name_len != strnlen(name, name_len + 1)) {
+-                      dbg_err("bad name_len");
++                      err = 12;
+                       goto bad;
+               }
+       }
+@@ -235,7 +236,7 @@
+       return 0;
+ bad:
+-      ubi_err("volume table check failed, record %d", i);
++      ubi_err("volume table check failed: record %d, error %d", i, err);
+       ubi_dbg_dump_vtbl_record(&vtbl[i], i);
+       return -EINVAL;
+ }
+@@ -384,7 +385,16 @@
+               err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
+                                      ubi->vtbl_size);
+               if (err == UBI_IO_BITFLIPS || err == -EBADMSG)
+-                      /* Scrub the PEB later */
++                      /*
++                       * Scrub the PEB later. Note, -EBADMSG indicates an
++                       * uncorrectable ECC error, but we have our own CRC and
++                       * the data will be checked later. If the data is OK,
++                       * the PEB will be scrubbed (because we set
++                       * seb->scrub). If the data is not OK, the contents of
++                       * the PEB will be recovered from the second copy, and
++                       * seb->scrub will be cleared in
++                       * 'ubi_scan_add_used()'.
++                       */
+                       seb->scrub = 1;
+               else if (err)
+                       goto out_free;
+@@ -620,30 +630,32 @@
+ static int check_sv(const struct ubi_volume *vol,
+                   const struct ubi_scan_volume *sv)
+ {
++      int err;
++
+       if (sv->highest_lnum >= vol->reserved_pebs) {
+-              dbg_err("bad highest_lnum");
++              err = 1;
+               goto bad;
+       }
+       if (sv->leb_count > vol->reserved_pebs) {
+-              dbg_err("bad leb_count");
++              err = 2;
+               goto bad;
+       }
+       if (sv->vol_type != vol->vol_type) {
+-              dbg_err("bad vol_type");
++              err = 3;
+               goto bad;
+       }
+       if (sv->used_ebs > vol->reserved_pebs) {
+-              dbg_err("bad used_ebs");
++              err = 4;
+               goto bad;
+       }
+       if (sv->data_pad != vol->data_pad) {
+-              dbg_err("bad data_pad");
++              err = 5;
+               goto bad;
+       }
+       return 0;
+ bad:
+-      ubi_err("bad scanning information");
++      ubi_err("bad scanning information, error %d", err);
+       ubi_dbg_dump_sv(sv);
+       ubi_dbg_dump_vol_info(vol);
+       return -EINVAL;
+@@ -672,14 +684,13 @@
+               return -EINVAL;
+       }
+-      if (si->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT&&
++      if (si->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT &&
+           si->highest_vol_id < UBI_INTERNAL_VOL_START) {
+               ubi_err("too large volume ID %d found by scanning",
+                       si->highest_vol_id);
+               return -EINVAL;
+       }
+-
+       for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
+               cond_resched();
+diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/wl.c avr32-2.6/drivers/mtd/ubi/wl.c
+--- linux-2.6.25.6/drivers/mtd/ubi/wl.c        2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/mtd/ubi/wl.c     2008-06-12 15:09:41.127815922 +0200
+@@ -1368,7 +1368,7 @@
+               int err;
+               if (kthread_should_stop())
+-                      goto out;
++                      break;
+               if (try_to_freeze())
+                       continue;
+@@ -1403,7 +1403,6 @@
+               cond_resched();
+       }
+-out:
+       dbg_wl("background thread \"%s\" is killed", ubi->bgt_name);
+       return 0;
+ }
+diff --exclude=.git -urN linux-2.6.25.6/drivers/net/macb.c avr32-2.6/drivers/net/macb.c
+--- linux-2.6.25.6/drivers/net/macb.c  2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/net/macb.c       2008-06-12 15:09:41.343816061 +0200
+@@ -1277,8 +1277,45 @@
+       return 0;
+ }
++#ifdef CONFIG_PM
++static int macb_suspend(struct platform_device *pdev, pm_message_t state)
++{
++      struct net_device *netdev = platform_get_drvdata(pdev);
++      struct macb *bp = netdev_priv(netdev);
++
++      netif_device_detach(netdev);
++
++#ifndef CONFIG_ARCH_AT91
++      clk_disable(bp->hclk);
++#endif
++      clk_disable(bp->pclk);
++
++      return 0;
++}
++
++static int macb_resume(struct platform_device *pdev)
++{
++      struct net_device *netdev = platform_get_drvdata(pdev);
++      struct macb *bp = netdev_priv(netdev);
++
++      clk_enable(bp->pclk);
++#ifndef CONFIG_ARCH_AT91
++      clk_enable(bp->hclk);
++#endif
++
++      netif_device_attach(netdev);
++
++      return 0;
++}
++#else
++#define macb_suspend  NULL
++#define macb_resume   NULL
++#endif
++
+ static struct platform_driver macb_driver = {
+       .remove         = __exit_p(macb_remove),
++      .suspend        = macb_suspend,
++      .resume         = macb_resume,
+       .driver         = {
+               .name           = "macb",
+       },
+diff --exclude=.git -urN linux-2.6.25.6/drivers/parport/Kconfig avr32-2.6/drivers/parport/Kconfig
+--- linux-2.6.25.6/drivers/parport/Kconfig     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/parport/Kconfig  2008-06-12 15:04:01.310815768 +0200
+@@ -36,7 +36,7 @@
+ config PARPORT_PC
+       tristate "PC-style hardware"
+       depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && \
+-              (!M68K || ISA) && !MN10300
++              (!M68K || ISA) && !MN10300 && !AVR32
+       ---help---
+         You should say Y here if you have a PC-style parallel port. All
+         IBM PC compatible computers and some Alphas have PC-style
+diff --exclude=.git -urN linux-2.6.25.6/drivers/pcmcia/at32_cf.c avr32-2.6/drivers/pcmcia/at32_cf.c
+--- linux-2.6.25.6/drivers/pcmcia/at32_cf.c    1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/drivers/pcmcia/at32_cf.c 2008-06-12 15:09:42.047816626 +0200
+@@ -0,0 +1,533 @@
++/*
++ * Driver for AVR32 Static Memory Controller: CompactFlash support
++ *
++ * Copyright (C) 2006 Atmel Norway
++ *
++ * 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.
++ *
++ * The full GNU General Public License is included in this
++ * distribution in the file called COPYING.
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/err.h>
++#include <linux/clk.h>
++#include <linux/dma-mapping.h>
++
++#include <pcmcia/ss.h>
++
++#include <asm/gpio.h>
++#include <asm/io.h>
++#include <asm/arch/board.h>
++
++#include <asm/arch/smc.h>
++
++struct at32_cf_socket {
++      struct pcmcia_socket    socket;
++      int                     detect_pin;
++      int                     reset_pin;
++      int                     vcc_pin;
++      int                     ready_pin;
++      struct resource         res_attr;
++      struct resource         res_mem;
++      struct resource         res_io;
++      struct smc_config       smc;
++      unsigned int            irq;
++      unsigned int            cf_cs;
++      socket_state_t          state;
++      unsigned                present:1;
++};
++#define to_at32_cf(sock) container_of(sock, struct at32_cf_socket, socket)
++
++/*
++ * We have the following memory layout relative to the base address:
++ *
++ *   Alt IDE Mode:      00e0 0000 -> 00ff ffff
++ *   True IDE Mode:     00c0 0000 -> 00df ffff
++ *   I/O memory:        0080 0000 -> 00bf ffff
++ *   Common memory:     0040 0000 -> 007f ffff
++ *   Attribute memory:  0000 0000 -> 003f ffff
++ */
++#define CF_ATTR_OFFSET        0x00000000
++#define CF_MEM_OFFSET 0x00400000
++#define CF_IO_OFFSET  0x00800000
++#define CF_RES_SIZE   4096
++
++#ifdef DEBUG
++
++static int pc_debug;
++module_param(pc_debug, int, 0644);
++
++static void at32_cf_debug(struct at32_cf_socket *cf, const char *func,
++                        int level, const char *fmt, ...)
++{
++      va_list args;
++
++      if (pc_debug > level) {
++              printk(KERN_DEBUG "at32_cf/%u: %s: ", cf->cf_cs, func);
++              va_start(args, fmt);
++              vprintk(fmt, args);
++              va_end(args);
++      }
++}
++
++#define debug(cf, lvl, fmt, arg...)                   \
++      at32_cf_debug(cf, __func__, lvl, fmt, ##arg)
++
++#else
++#define debug(cf, lvl, fmt, arg...) do { } while (0)
++#endif
++
++static inline int at32_cf_present(struct at32_cf_socket *cf)
++{
++      int present = 1;
++
++      /* If we don't have a detect pin, assume the card is present */
++      if (cf->detect_pin >= 0)
++              present = !gpio_get_value(cf->detect_pin);
++
++      return present;
++}
++
++static irqreturn_t at32_cf_irq(int irq, void *dev_id)
++{
++      struct at32_cf_socket *cf = dev_id;
++      unsigned int present;
++
++      present = at32_cf_present(cf);
++      if (present != cf->present) {
++              cf->present = present;
++              debug(cf, 3, "card %s\n", present ? "present" : "gone");
++              pcmcia_parse_events(&cf->socket, SS_DETECT);
++      }
++
++      return IRQ_HANDLED;
++}
++
++static int at32_cf_get_status(struct pcmcia_socket *sock, u_int *value)
++{
++      struct at32_cf_socket *cf;
++      u_int status = 0;
++
++      cf = container_of(sock, struct at32_cf_socket, socket);
++
++      if (at32_cf_present(cf)) {
++              /* NOTE: gpio on AP7xxx is 3.3V */
++              status = SS_DETECT | SS_3VCARD;
++              if (cf->ready_pin < 0 || gpio_get_value(cf->ready_pin))
++                      status |= SS_READY;
++              if (cf->vcc_pin < 0 || gpio_get_value(cf->vcc_pin))
++                      status |= SS_POWERON;
++      }
++
++      *value = status;
++      return 0;
++}
++
++static int at32_cf_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
++{
++      struct at32_cf_socket *cf = container_of(sock, struct at32_cf_socket, socket);
++
++      debug(cf, 2, "mask: %s%s%s%s%s%sflags: %s%s%s%s%s%sVcc %d Vpp %d irq %d\n",
++                      (state->csc_mask==0)?"<NONE> ":"",
++                      (state->csc_mask&SS_DETECT)?"DETECT ":"",
++                      (state->csc_mask&SS_READY)?"READY ":"",
++                      (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"",
++                      (state->csc_mask&SS_BATWARN)?"BATWARN ":"",
++                      (state->csc_mask&SS_STSCHG)?"STSCHG ":"",
++                      (state->flags==0)?"<NONE> ":"",
++                      (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"",
++                      (state->flags&SS_IOCARD)?"IOCARD ":"",
++                      (state->flags&SS_RESET)?"RESET ":"",
++                      (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"",
++                      (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"",
++                      state->Vcc, state->Vpp, state->io_irq);
++
++      /*
++       * TODO: Allow boards to override this in case they have level
++       * converters.
++       */
++      switch (state->Vcc) {
++      case 0:
++              if (cf->vcc_pin >= 0)
++                      gpio_set_value(cf->vcc_pin, 0);
++              break;
++      case 33:
++              if (cf->vcc_pin >= 0)
++                      gpio_set_value(cf->vcc_pin, 1);
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      if (cf->reset_pin >= 0)
++              gpio_set_value(cf->reset_pin, state->flags & SS_RESET);
++
++      cf->state = *state;
++
++      return 0;
++}
++
++static int at32_cf_socket_init(struct pcmcia_socket *sock)
++{
++      debug(to_at32_cf(sock), 2, "called\n");
++
++      return 0;
++}
++
++static int at32_cf_suspend(struct pcmcia_socket *sock)
++{
++      debug(to_at32_cf(sock), 2, "called\n");
++
++      at32_cf_set_socket(sock, &dead_socket);
++
++      return 0;
++}
++
++static int at32_cf_set_io_map(struct pcmcia_socket *sock,
++                            struct pccard_io_map *map)
++{
++      struct at32_cf_socket *cf = container_of(sock, struct at32_cf_socket, socket);
++      int retval;
++
++      debug(cf, 2, "map %u  speed %u start 0x%08x stop 0x%08x\n",
++              map->map, map->speed, map->start, map->stop);
++      debug(cf, 2, "flags: %s%s%s%s%s%s%s%s\n",
++              (map->flags == 0) ? "<NONE>":"",
++              (map->flags & MAP_ACTIVE) ? "ACTIVE " : "",
++              (map->flags & MAP_16BIT) ? "16BIT " : "",
++              (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "",
++              (map->flags & MAP_0WS) ? "0WS " : "",
++              (map->flags & MAP_WRPROT) ? "WRPROT " : "",
++              (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "",
++              (map->flags & MAP_PREFETCH) ? "PREFETCH " : "");
++
++      map->flags &= MAP_ACTIVE | MAP_16BIT | MAP_USE_WAIT;
++
++      if (map->flags & MAP_16BIT)
++              cf->smc.bus_width = 2;
++      else
++              cf->smc.bus_width = 1;
++
++      if (map->flags & MAP_USE_WAIT)
++              cf->smc.nwait_mode = 3;
++      else
++              cf->smc.nwait_mode = 0;
++
++      retval = smc_set_configuration(cf->cf_cs, &cf->smc);
++      if (retval) {
++              printk(KERN_ERR "at32_cf: could not set up SMC for I/O\n");
++              return retval;
++      }
++
++      map->start = cf->socket.io_offset;
++      map->stop = map->start + CF_RES_SIZE - 1;
++
++      return 0;
++}
++
++static int
++at32_cf_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map)
++{
++      struct at32_cf_socket *cf;
++      struct resource *res;
++      int retval;
++
++      cf = container_of(sock, struct at32_cf_socket, socket);
++
++      debug(cf, 2, "map %u speed %u card_start %08x\n",
++              map->map, map->speed, map->card_start);
++      debug(cf, 2, "flags: %s%s%s%s%s%s%s%s\n",
++              (map->flags==0)?"<NONE>":"",
++              (map->flags&MAP_ACTIVE)?"ACTIVE ":"",
++              (map->flags&MAP_16BIT)?"16BIT ":"",
++              (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"",
++              (map->flags&MAP_0WS)?"0WS ":"",
++              (map->flags&MAP_WRPROT)?"WRPROT ":"",
++              (map->flags&MAP_ATTRIB)?"ATTRIB ":"",
++              (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"");
++
++      if (map->card_start)
++              return -EINVAL;
++
++      map->flags &= MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT | MAP_USE_WAIT;
++
++      if (map->flags & MAP_ATTRIB) {
++              res = &cf->res_attr;
++
++              /* Linksys WCF12 seems to use WAIT when reading CIS */
++              map->flags |= MAP_USE_WAIT;
++      } else {
++              res = &cf->res_mem;
++      }
++
++      if (map->flags & MAP_USE_WAIT)
++              cf->smc.nwait_mode = 3;
++      else
++              cf->smc.nwait_mode = 0;
++
++      retval = smc_set_configuration(cf->cf_cs, &cf->smc);
++      if (retval) {
++              printk(KERN_ERR "at32_cf: could not set up SMC for mem\n");
++              return retval;
++      }
++
++      map->static_start = res->start;
++
++      return 0;
++}
++
++static struct pccard_operations at32_cf_ops = {
++      .init                   = at32_cf_socket_init,
++      .suspend                = at32_cf_suspend,
++      .get_status             = at32_cf_get_status,
++      .set_socket             = at32_cf_set_socket,
++      .set_io_map             = at32_cf_set_io_map,
++      .set_mem_map            = at32_cf_set_mem_map,
++};
++
++static int __init request_pin(struct platform_device *pdev,
++                            unsigned int pin, const char *name)
++{
++      if (gpio_request(pin, name)) {
++              dev_warn(&pdev->dev, "failed to request %s pin\n", name);
++              return -1;
++      }
++
++      return pin;
++}
++
++static struct smc_timing at32_cf_timing __initdata = {
++      .ncs_read_setup         = 30,
++      .nrd_setup              = 100,
++      .ncs_write_setup        = 30,
++      .nwe_setup              = 100,
++
++      .ncs_read_pulse         = 360,
++      .nrd_pulse              = 290,
++      .ncs_write_pulse        = 360,
++      .nwe_pulse              = 290,
++
++      .read_cycle             = 420,
++      .write_cycle            = 420,
++};
++
++static int __init at32_cf_probe(struct platform_device *pdev)
++{
++      struct at32_cf_socket   *cf;
++      struct cf_platform_data *board = pdev->dev.platform_data;
++      struct resource         *res_skt;
++      int                     irq;
++      int                     ret;
++
++      dev_dbg(&pdev->dev, "probe");
++
++      if (!board)
++              return -ENXIO;
++
++      res_skt = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (!res_skt)
++              return -ENXIO;
++
++      irq = platform_get_irq(pdev, 0);
++      if (irq < 0)
++              return irq;
++
++      cf = kzalloc(sizeof(struct at32_cf_socket), GFP_KERNEL);
++      if (!cf)
++              return -ENOMEM;
++
++      cf->detect_pin = -1;
++      cf->reset_pin = -1;
++      cf->vcc_pin = -1;
++      cf->ready_pin = -1;
++      cf->cf_cs = board->cs;
++
++      if (board->detect_pin != GPIO_PIN_NONE)
++              cf->detect_pin = request_pin(pdev, board->detect_pin,
++                                           "cf_detect");
++      if (board->reset_pin != GPIO_PIN_NONE)
++              cf->reset_pin = request_pin(pdev, board->reset_pin,
++                                          "cf_reset");
++      if (board->vcc_pin != GPIO_PIN_NONE)
++              cf->vcc_pin = request_pin(pdev, board->vcc_pin,
++                                        "cf_vcc");
++      if (board->ready_pin != GPIO_PIN_NONE)
++              /* READY is also used for irq through EIM */
++              cf->ready_pin = board->ready_pin;
++
++      debug(cf, 2, "pins: detect=%d reset=%d vcc=%d\n",
++            cf->detect_pin, cf->reset_pin, cf->vcc_pin);
++
++      cf->socket.pci_irq = irq;
++      cf->socket.ops = &at32_cf_ops;
++      cf->socket.resource_ops = &pccard_static_ops;
++      cf->socket.dev.parent = &pdev->dev;
++      cf->socket.owner = THIS_MODULE;
++      cf->socket.features =
++              SS_CAP_MEM_ALIGN | SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
++      cf->socket.map_size = CF_RES_SIZE;
++
++      cf->res_attr.start = res_skt->start + CF_ATTR_OFFSET;
++      cf->res_attr.end = cf->res_attr.start + CF_RES_SIZE - 1;
++      cf->res_attr.name = "attribute";
++      cf->res_attr.flags = IORESOURCE_MEM;
++      ret = request_resource(res_skt, &cf->res_attr);
++      if (ret)
++              goto err_request_res_attr;
++
++      cf->res_mem.start = res_skt->start + CF_MEM_OFFSET;
++      cf->res_mem.end = cf->res_mem.start + CF_RES_SIZE - 1;
++      cf->res_mem.name = "memory";
++      cf->res_mem.flags = IORESOURCE_MEM;
++      ret = request_resource(res_skt, &cf->res_mem);
++      if (ret)
++              goto err_request_res_mem;
++
++      cf->res_io.start = res_skt->start + CF_IO_OFFSET;
++      cf->res_io.end = cf->res_io.start + CF_RES_SIZE - 1;
++      cf->res_io.name = "io";
++      cf->res_io.flags = IORESOURCE_MEM;
++      ret = request_resource(res_skt, &cf->res_io);
++      if (ret)
++              goto err_request_res_io;
++
++      cf->socket.io_offset = cf->res_io.start;
++
++      if (cf->detect_pin >= 0) {
++              ret = request_irq(gpio_to_irq(cf->detect_pin), at32_cf_irq,
++                                IRQF_SHARED, "cf_detect", cf);
++              if (ret) {
++                      debug(cf, 1,
++                            "failed to request cf_detect interrupt\n");
++                      goto err_detect_irq;
++              }
++      }
++
++      cf->present = at32_cf_present(cf);
++
++      /* Setup SMC timings */
++      smc_set_timing(&cf->smc, &at32_cf_timing);
++
++      cf->smc.bus_width = 2;
++      cf->smc.nrd_controlled = 1;
++      cf->smc.nwe_controlled = 1;
++      cf->smc.nwait_mode = 0;
++      cf->smc.byte_write = 0;
++      cf->smc.tdf_cycles = 8;
++      cf->smc.tdf_mode = 0;
++
++      ret = smc_set_configuration(cf->cf_cs, &cf->smc);
++      if (ret) {
++              debug(cf, 1, "failed to configure SMC\n", ret);
++              goto err_smc;
++      }
++
++      ret = pcmcia_register_socket(&cf->socket);
++      if (ret) {
++              debug(cf, 1, "failed to register socket: %d\n", ret);
++              goto err_register_socket;
++      }
++
++      if (cf->reset_pin >= 0)
++              gpio_direction_output(cf->reset_pin, 0);
++
++      platform_set_drvdata(pdev, cf);
++
++      dev_info(&pdev->dev, "Atmel SMC CF interface at 0x%08lx\n",
++               (unsigned long)res_skt->start);
++
++      return 0;
++
++err_register_socket:
++err_smc:
++      if (cf->detect_pin >= 0)
++              free_irq(gpio_to_irq(cf->detect_pin), cf);
++err_detect_irq:
++      release_resource(&cf->res_io);
++err_request_res_io:
++      release_resource(&cf->res_mem);
++err_request_res_mem:
++      release_resource(&cf->res_attr);
++err_request_res_attr:
++      if (cf->vcc_pin >= 0)
++              gpio_free(cf->vcc_pin);
++      if (cf->reset_pin >= 0)
++              gpio_free(cf->reset_pin);
++      if (cf->detect_pin >= 0)
++              gpio_free(cf->detect_pin);
++      kfree(cf);
++
++      return ret;
++}
++
++static int __exit at32_cf_remove(struct platform_device *pdev)
++{
++      struct at32_cf_socket *cf = platform_get_drvdata(pdev);
++
++      pcmcia_unregister_socket(&cf->socket);
++      if (cf->detect_pin >= 0) {
++              free_irq(gpio_to_irq(cf->detect_pin), cf);
++              gpio_free(cf->detect_pin);
++      }
++      if (cf->vcc_pin >= 0)
++              gpio_free(cf->vcc_pin);
++      if (cf->reset_pin >= 0)
++              gpio_free(cf->reset_pin);
++
++      release_resource(&cf->res_io);
++      release_resource(&cf->res_mem);
++      release_resource(&cf->res_attr);
++      kfree(cf);
++      platform_set_drvdata(pdev, NULL);
++
++      return 0;
++}
++
++static struct platform_driver at32_cf_driver = {
++      .remove         = __exit_p(at32_cf_remove),
++      .driver         = {
++              .name   = "at32_cf",
++              .owner  = THIS_MODULE,
++      },
++};
++
++static int __init at32_cf_init(void)
++{
++      int ret;
++
++      ret = platform_driver_probe(&at32_cf_driver, at32_cf_probe);
++      if (ret)
++              printk(KERN_ERR "at32_cf: probe failed: %d\n", ret);
++      return ret;
++}
++
++static void __exit at32_cf_exit(void)
++{
++      platform_driver_unregister(&at32_cf_driver);
++}
++
++module_init(at32_cf_init);
++module_exit(at32_cf_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Driver for SMC PCMCIA interface");
++MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
+diff --exclude=.git -urN linux-2.6.25.6/drivers/pcmcia/Kconfig avr32-2.6/drivers/pcmcia/Kconfig
+--- linux-2.6.25.6/drivers/pcmcia/Kconfig      2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/pcmcia/Kconfig   2008-06-12 15:09:42.047816626 +0200
+@@ -277,6 +277,13 @@
+         Say Y here to support the CompactFlash controller on the
+         PA Semi Electra eval board.
++config AT32_CF
++      tristate "AT32AP CompactFlash Controller"
++      depends on PCMCIA && AVR32 && PLATFORM_AT32AP
++      help
++        Say Y here to support the CompactFlash controller on AT32 chips.
++        Or choose M to compile the driver as a module named "at32_cf".
++
+ config PCCARD_NONSTATIC
+       tristate
+diff --exclude=.git -urN linux-2.6.25.6/drivers/pcmcia/Makefile avr32-2.6/drivers/pcmcia/Makefile
+--- linux-2.6.25.6/drivers/pcmcia/Makefile     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/pcmcia/Makefile  2008-06-12 15:09:42.047816626 +0200
+@@ -38,6 +38,7 @@
+ obj-$(CONFIG_OMAP_CF)                         += omap_cf.o
+ obj-$(CONFIG_AT91_CF)                         += at91_cf.o
+ obj-$(CONFIG_ELECTRA_CF)                      += electra_cf.o
++obj-$(CONFIG_AT32_CF)                         += at32_cf.o
+ sa11xx_core-y                                 += soc_common.o sa11xx_base.o
+ pxa2xx_core-y                                 += soc_common.o pxa2xx_base.o
+diff --exclude=.git -urN linux-2.6.25.6/drivers/serial/atmel_serial.c avr32-2.6/drivers/serial/atmel_serial.c
+--- linux-2.6.25.6/drivers/serial/atmel_serial.c       2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/serial/atmel_serial.c    2008-06-12 15:09:42.514816054 +0200
+@@ -1440,6 +1440,15 @@
+ };
+ #ifdef CONFIG_PM
++static bool atmel_serial_clk_will_stop(void)
++{
++#ifdef CONFIG_ARCH_AT91
++      return at91_suspend_entering_slow_clock();
++#else
++      return false;
++#endif
++}
++
+ static int atmel_serial_suspend(struct platform_device *pdev,
+                               pm_message_t state)
+ {
+@@ -1447,7 +1456,7 @@
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       if (device_may_wakeup(&pdev->dev)
+-          && !at91_suspend_entering_slow_clock())
++          && !atmel_serial_clk_will_stop())
+               enable_irq_wake(port->irq);
+       else {
+               uart_suspend_port(&atmel_uart, port);
+diff --exclude=.git -urN linux-2.6.25.6/drivers/spi/atmel_spi.c avr32-2.6/drivers/spi/atmel_spi.c
+--- linux-2.6.25.6/drivers/spi/atmel_spi.c     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/spi/atmel_spi.c  2008-06-12 15:09:42.542815989 +0200
+@@ -51,9 +51,7 @@
+       u8                      stopping;
+       struct list_head        queue;
+       struct spi_transfer     *current_transfer;
+-      unsigned long           current_remaining_bytes;
+-      struct spi_transfer     *next_transfer;
+-      unsigned long           next_remaining_bytes;
++      unsigned long           remaining_bytes;
+       void                    *buffer;
+       dma_addr_t              buffer_dma;
+@@ -133,48 +131,6 @@
+               gpio_set_value(gpio, !active);
+ }
+-static inline int atmel_spi_xfer_is_last(struct spi_message *msg,
+-                                      struct spi_transfer *xfer)
+-{
+-      return msg->transfers.prev == &xfer->transfer_list;
+-}
+-
+-static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer)
+-{
+-      return xfer->delay_usecs == 0 && !xfer->cs_change;
+-}
+-
+-static void atmel_spi_next_xfer_data(struct spi_master *master,
+-                              struct spi_transfer *xfer,
+-                              dma_addr_t *tx_dma,
+-                              dma_addr_t *rx_dma,
+-                              u32 *plen)
+-{
+-      struct atmel_spi        *as = spi_master_get_devdata(master);
+-      u32                     len = *plen;
+-
+-      /* use scratch buffer only when rx or tx data is unspecified */
+-      if (xfer->rx_buf)
+-              *rx_dma = xfer->rx_dma + xfer->len - len;
+-      else {
+-              *rx_dma = as->buffer_dma;
+-              if (len > BUFFER_SIZE)
+-                      len = BUFFER_SIZE;
+-      }
+-      if (xfer->tx_buf)
+-              *tx_dma = xfer->tx_dma + xfer->len - len;
+-      else {
+-              *tx_dma = as->buffer_dma;
+-              if (len > BUFFER_SIZE)
+-                      len = BUFFER_SIZE;
+-              memset(as->buffer, 0, len);
+-              dma_sync_single_for_device(&as->pdev->dev,
+-                              as->buffer_dma, len, DMA_TO_DEVICE);
+-      }
+-
+-      *plen = len;
+-}
+-
+ /*
+  * Submit next transfer for DMA.
+  * lock is held, spi irq is blocked
+@@ -184,78 +140,53 @@
+ {
+       struct atmel_spi        *as = spi_master_get_devdata(master);
+       struct spi_transfer     *xfer;
+-      u32                     len, remaining, total;
++      u32                     len;
+       dma_addr_t              tx_dma, rx_dma;
+-      if (!as->current_transfer)
+-              xfer = list_entry(msg->transfers.next,
+-                              struct spi_transfer, transfer_list);
+-      else if (!as->next_transfer)
+-              xfer = list_entry(as->current_transfer->transfer_list.next,
+-                              struct spi_transfer, transfer_list);
+-      else
+-              xfer = NULL;
+-
+-      if (xfer) {
+-              len = xfer->len;
+-              atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
+-              remaining = xfer->len - len;
+-
+-              spi_writel(as, RPR, rx_dma);
+-              spi_writel(as, TPR, tx_dma);
+-
+-              if (msg->spi->bits_per_word > 8)
+-                      len >>= 1;
+-              spi_writel(as, RCR, len);
+-              spi_writel(as, TCR, len);
+-
+-              dev_dbg(&msg->spi->dev,
+-                      "  start xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+-                      xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
+-                      xfer->rx_buf, xfer->rx_dma);
+-      } else {
+-              xfer = as->next_transfer;
+-              remaining = as->next_remaining_bytes;
++      xfer = as->current_transfer;
++      if (!xfer || as->remaining_bytes == 0) {
++              if (xfer)
++                      xfer = list_entry(xfer->transfer_list.next,
++                                      struct spi_transfer, transfer_list);
++              else
++                      xfer = list_entry(msg->transfers.next,
++                                      struct spi_transfer, transfer_list);
++              as->remaining_bytes = xfer->len;
++              as->current_transfer = xfer;
+       }
+-      as->current_transfer = xfer;
+-      as->current_remaining_bytes = remaining;
+-
+-      if (remaining > 0)
+-              len = remaining;
+-      else if (!atmel_spi_xfer_is_last(msg, xfer)
+-                      && atmel_spi_xfer_can_be_chained(xfer)) {
+-              xfer = list_entry(xfer->transfer_list.next,
+-                              struct spi_transfer, transfer_list);
+-              len = xfer->len;
+-      } else
+-              xfer = NULL;
++      len = as->remaining_bytes;
+-      as->next_transfer = xfer;
++      tx_dma = xfer->tx_dma + xfer->len - len;
++      rx_dma = xfer->rx_dma + xfer->len - len;
+-      if (xfer) {
+-              total = len;
+-              atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
+-              as->next_remaining_bytes = total - len;
+-
+-              spi_writel(as, RNPR, rx_dma);
+-              spi_writel(as, TNPR, tx_dma);
+-
+-              if (msg->spi->bits_per_word > 8)
+-                      len >>= 1;
+-              spi_writel(as, RNCR, len);
+-              spi_writel(as, TNCR, len);
+-
+-              dev_dbg(&msg->spi->dev,
+-                      "  next xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+-                      xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
+-                      xfer->rx_buf, xfer->rx_dma);
+-      } else {
+-              spi_writel(as, RNCR, 0);
+-              spi_writel(as, TNCR, 0);
++      /* use scratch buffer only when rx or tx data is unspecified */
++      if (!xfer->rx_buf) {
++              rx_dma = as->buffer_dma;
++              if (len > BUFFER_SIZE)
++                      len = BUFFER_SIZE;
+       }
++      if (!xfer->tx_buf) {
++              tx_dma = as->buffer_dma;
++              if (len > BUFFER_SIZE)
++                      len = BUFFER_SIZE;
++              memset(as->buffer, 0, len);
++              dma_sync_single_for_device(&as->pdev->dev,
++                              as->buffer_dma, len, DMA_TO_DEVICE);
++      }
++
++      spi_writel(as, RPR, rx_dma);
++      spi_writel(as, TPR, tx_dma);
+-      /* REVISIT: We're waiting for ENDRX before we start the next
++      as->remaining_bytes -= len;
++      if (msg->spi->bits_per_word > 8)
++              len >>= 1;
++
++      /* REVISIT: when xfer->delay_usecs == 0, the PDC "next transfer"
++       * mechanism might help avoid the IRQ latency between transfers
++       * (and improve the nCS0 errata handling on at91rm9200 chips)
++       *
++       * We're also waiting for ENDRX before we start the next
+        * transfer because we need to handle some difficult timing
+        * issues otherwise. If we wait for ENDTX in one transfer and
+        * then starts waiting for ENDRX in the next, it's difficult
+@@ -265,7 +196,17 @@
+        *
+        * It should be doable, though. Just not now...
+        */
++      spi_writel(as, TNCR, 0);
++      spi_writel(as, RNCR, 0);
+       spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES));
++
++      dev_dbg(&msg->spi->dev,
++              "  start xfer %p: len %u tx %p/%08x rx %p/%08x imr %03x\n",
++              xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
++              xfer->rx_buf, xfer->rx_dma, spi_readl(as, IMR));
++
++      spi_writel(as, RCR, len);
++      spi_writel(as, TCR, len);
+       spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
+ }
+@@ -363,7 +304,6 @@
+       spin_lock(&as->lock);
+       as->current_transfer = NULL;
+-      as->next_transfer = NULL;
+       /* continue if needed */
+       if (list_empty(&as->queue) || as->stopping)
+@@ -447,7 +387,7 @@
+               spi_writel(as, IDR, pending);
+-              if (as->current_remaining_bytes == 0) {
++              if (as->remaining_bytes == 0) {
+                       msg->actual_length += xfer->len;
+                       if (!msg->is_dma_mapped)
+@@ -457,7 +397,7 @@
+                       if (xfer->delay_usecs)
+                               udelay(xfer->delay_usecs);
+-                      if (atmel_spi_xfer_is_last(msg, xfer)) {
++                      if (msg->transfers.prev == &xfer->transfer_list) {
+                               /* report completed message */
+                               atmel_spi_msg_done(master, as, msg, 0,
+                                               xfer->cs_change);
+diff --exclude=.git -urN linux-2.6.25.6/drivers/usb/gadget/atmel_usba_udc.c avr32-2.6/drivers/usb/gadget/atmel_usba_udc.c
+--- linux-2.6.25.6/drivers/usb/gadget/atmel_usba_udc.c 2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/usb/gadget/atmel_usba_udc.c      2008-06-12 15:09:42.586816287 +0200
+@@ -18,6 +18,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/usb/ch9.h>
+ #include <linux/usb/gadget.h>
++#include <linux/usb/atmel_usba_udc.h>
+ #include <linux/delay.h>
+ #include <asm/gpio.h>
+@@ -27,6 +28,7 @@
+ static struct usba_udc the_udc;
++static struct usba_ep *usba_ep;
+ #ifdef CONFIG_USB_GADGET_DEBUG_FS
+ #include <linux/debugfs.h>
+@@ -324,53 +326,28 @@
+       return 1;
+ }
+-static void copy_to_fifo(void __iomem *fifo, const void *buf, int len)
+-{
+-      unsigned long tmp;
++#if defined(CONFIG_AVR32)
+-      DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len);
+-      for (; len > 0; len -= 4, buf += 4, fifo += 4) {
+-              tmp = *(unsigned long *)buf;
+-              if (len >= 4) {
+-                      DBG(DBG_FIFO, "  -> %08lx\n", tmp);
+-                      __raw_writel(tmp, fifo);
+-              } else {
+-                      do {
+-                              DBG(DBG_FIFO, "  -> %02lx\n", tmp >> 24);
+-                              __raw_writeb(tmp >> 24, fifo);
+-                              fifo++;
+-                              tmp <<= 8;
+-                      } while (--len);
+-                      break;
+-              }
+-      }
++static void toggle_bias(int is_on)
++{
+ }
+-static void copy_from_fifo(void *buf, void __iomem *fifo, int len)
++#elif defined(CONFIG_ARCH_AT91)
++
++#include <asm/arch/at91_pmc.h>
++
++static void toggle_bias(int is_on)
+ {
+-      union {
+-              unsigned long *w;
+-              unsigned char *b;
+-      } p;
+-      unsigned long tmp;
+-
+-      DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len);
+-      for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) {
+-              if (len >= 4) {
+-                      tmp = __raw_readl(fifo);
+-                      *p.w = tmp;
+-                      DBG(DBG_FIFO, "  -> %08lx\n", tmp);
+-              } else {
+-                      do {
+-                              tmp = __raw_readb(fifo);
+-                              *p.b = tmp;
+-                              DBG(DBG_FIFO, " -> %02lx\n", tmp);
+-                              fifo++, p.b++;
+-                      } while (--len);
+-              }
+-      }
++      unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR);
++
++      if (is_on)
++              at91_sys_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
++      else
++              at91_sys_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
+ }
++#endif /* CONFIG_ARCH_AT91 */
++
+ static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
+ {
+       unsigned int transaction_len;
+@@ -387,7 +364,7 @@
+               ep->ep.name, req, transaction_len,
+               req->last_transaction ? ", done" : "");
+-      copy_to_fifo(ep->fifo, req->req.buf + req->req.actual, transaction_len);
++      memcpy_toio(ep->fifo, req->req.buf + req->req.actual, transaction_len);
+       usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+       req->req.actual += transaction_len;
+ }
+@@ -476,7 +453,7 @@
+                       bytecount = req->req.length - req->req.actual;
+               }
+-              copy_from_fifo(req->req.buf + req->req.actual,
++              memcpy_fromio(req->req.buf + req->req.actual,
+                               ep->fifo, bytecount);
+               req->req.actual += bytecount;
+@@ -1029,33 +1006,6 @@
+       .set_selfpowered        = usba_udc_set_selfpowered,
+ };
+-#define EP(nam, idx, maxpkt, maxbk, dma, isoc)                        \
+-{                                                             \
+-      .ep     = {                                             \
+-              .ops            = &usba_ep_ops,                 \
+-              .name           = nam,                          \
+-              .maxpacket      = maxpkt,                       \
+-      },                                                      \
+-      .udc            = &the_udc,                             \
+-      .queue          = LIST_HEAD_INIT(usba_ep[idx].queue),   \
+-      .fifo_size      = maxpkt,                               \
+-      .nr_banks       = maxbk,                                \
+-      .index          = idx,                                  \
+-      .can_dma        = dma,                                  \
+-      .can_isoc       = isoc,                                 \
+-}
+-
+-static struct usba_ep usba_ep[] = {
+-      EP("ep0", 0, 64, 1, 0, 0),
+-      EP("ep1in-bulk", 1, 512, 2, 1, 1),
+-      EP("ep2out-bulk", 2, 512, 2, 1, 1),
+-      EP("ep3in-int", 3, 64, 3, 1, 0),
+-      EP("ep4out-int", 4, 64, 3, 1, 0),
+-      EP("ep5in-iso", 5, 1024, 3, 1, 1),
+-      EP("ep6out-iso", 6, 1024, 3, 1, 1),
+-};
+-#undef EP
+-
+ static struct usb_endpoint_descriptor usba_ep0_desc = {
+       .bLength = USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType = USB_DT_ENDPOINT,
+@@ -1074,7 +1024,6 @@
+ static struct usba_udc the_udc = {
+       .gadget = {
+               .ops            = &usba_udc_ops,
+-              .ep0            = &usba_ep[0].ep,
+               .ep_list        = LIST_HEAD_INIT(the_udc.gadget.ep_list),
+               .is_dualspeed   = 1,
+               .name           = "atmel_usba_udc",
+@@ -1231,7 +1180,7 @@
+               } else {
+                       usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+                       usba_writel(udc, TST, USBA_TST_PKT_MODE);
+-                      copy_to_fifo(ep->fifo, test_packet_buffer,
++                      memcpy_toio(ep->fifo, test_packet_buffer,
+                                       sizeof(test_packet_buffer));
+                       usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+                       dev_info(dev, "Entering Test_Packet mode...\n");
+@@ -1530,13 +1479,13 @@
+               DBG(DBG_HW, "Packet length: %u\n", pkt_len);
+               if (pkt_len != sizeof(crq)) {
+                       pr_warning("udc: Invalid packet length %u "
+-                              "(expected %lu)\n", pkt_len, sizeof(crq));
++                              "(expected %zu)\n", pkt_len, sizeof(crq));
+                       set_protocol_stall(udc, ep);
+                       return;
+               }
+               DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo);
+-              copy_from_fifo(crq.data, ep->fifo, sizeof(crq));
++              memcpy_fromio(crq.data, ep->fifo, sizeof(crq));
+               /* Free up one bank in the FIFO so that we can
+                * generate or receive a reply right away. */
+@@ -1688,6 +1637,7 @@
+       DBG(DBG_INT, "irq, status=%#08x\n", status);
+       if (status & USBA_DET_SUSPEND) {
++              toggle_bias(0);
+               usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
+               DBG(DBG_BUS, "Suspend detected\n");
+               if (udc->gadget.speed != USB_SPEED_UNKNOWN
+@@ -1699,6 +1649,7 @@
+       }
+       if (status & USBA_WAKE_UP) {
++              toggle_bias(1);
+               usba_writel(udc, INT_CLR, USBA_WAKE_UP);
+               DBG(DBG_BUS, "Wake Up CPU detected\n");
+       }
+@@ -1792,12 +1743,14 @@
+       vbus = gpio_get_value(udc->vbus_pin);
+       if (vbus != udc->vbus_prev) {
+               if (vbus) {
+-                      usba_writel(udc, CTRL, USBA_EN_USBA);
++                      toggle_bias(1);
++                      usba_writel(udc, CTRL, USBA_ENABLE_MASK);
+                       usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+               } else {
+                       udc->gadget.speed = USB_SPEED_UNKNOWN;
+                       reset_all_endpoints(udc);
+-                      usba_writel(udc, CTRL, 0);
++                      toggle_bias(0);
++                      usba_writel(udc, CTRL, USBA_DISABLE_MASK);
+                       spin_unlock(&udc->lock);
+                       udc->driver->disconnect(&udc->gadget);
+                       spin_lock(&udc->lock);
+@@ -1850,7 +1803,8 @@
+       /* If Vbus is present, enable the controller and wait for reset */
+       spin_lock_irqsave(&udc->lock, flags);
+       if (vbus_is_present(udc) && udc->vbus_prev == 0) {
+-              usba_writel(udc, CTRL, USBA_EN_USBA);
++              toggle_bias(1);
++              usba_writel(udc, CTRL, USBA_ENABLE_MASK);
+               usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+       }
+       spin_unlock_irqrestore(&udc->lock, flags);
+@@ -1883,7 +1837,8 @@
+       spin_unlock_irqrestore(&udc->lock, flags);
+       /* This will also disable the DP pullup */
+-      usba_writel(udc, CTRL, 0);
++      toggle_bias(0);
++      usba_writel(udc, CTRL, USBA_DISABLE_MASK);
+       driver->unbind(&udc->gadget);
+       udc->gadget.dev.driver = NULL;
+@@ -1908,7 +1863,7 @@
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID);
+       fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID);
+-      if (!regs || !fifo)
++      if (!regs || !fifo || !pdata)
+               return -ENXIO;
+       irq = platform_get_irq(pdev, 0);
+@@ -1953,19 +1908,48 @@
+       /* Make sure we start from a clean slate */
+       clk_enable(pclk);
+-      usba_writel(udc, CTRL, 0);
++      toggle_bias(0);
++      usba_writel(udc, CTRL, USBA_DISABLE_MASK);
+       clk_disable(pclk);
++      usba_ep = kmalloc(sizeof(struct usba_ep) * pdata->num_ep,
++                        GFP_KERNEL);
++      if (!usba_ep)
++              goto err_alloc_ep;
++
++      the_udc.gadget.ep0 = &usba_ep[0].ep;
++
+       INIT_LIST_HEAD(&usba_ep[0].ep.ep_list);
+       usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0);
+       usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0);
+       usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0);
+-      for (i = 1; i < ARRAY_SIZE(usba_ep); i++) {
++      usba_ep[0].ep.ops = &usba_ep_ops;
++      usba_ep[0].ep.name = pdata->ep[0].name;
++      usba_ep[0].ep.maxpacket = pdata->ep[0].fifo_size;
++      usba_ep[0].udc = &the_udc;
++      INIT_LIST_HEAD(&usba_ep[0].queue);
++      usba_ep[0].fifo_size = pdata->ep[0].fifo_size;
++      usba_ep[0].nr_banks = pdata->ep[0].nr_banks;
++      usba_ep[0].index = pdata->ep[0].index;
++      usba_ep[0].can_dma = pdata->ep[0].can_dma;
++      usba_ep[0].can_isoc = pdata->ep[0].can_isoc;
++
++      for (i = 1; i < pdata->num_ep; i++) {
+               struct usba_ep *ep = &usba_ep[i];
+               ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
+               ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
+               ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
++              ep->ep.ops = &usba_ep_ops;
++              ep->ep.name = pdata->ep[i].name;
++              ep->ep.maxpacket = pdata->ep[i].fifo_size;
++              ep->udc = &the_udc;
++              INIT_LIST_HEAD(&ep->queue);
++              ep->fifo_size = pdata->ep[i].fifo_size;
++              ep->nr_banks = pdata->ep[i].nr_banks;
++              ep->index = pdata->ep[i].index;
++              ep->can_dma = pdata->ep[i].can_dma;
++              ep->can_isoc = pdata->ep[i].can_isoc;
+               list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+       }
+@@ -1984,7 +1968,7 @@
+               goto err_device_add;
+       }
+-      if (pdata && pdata->vbus_pin != GPIO_PIN_NONE) {
++      if (pdata->vbus_pin >= 0) {
+               if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
+                       udc->vbus_pin = pdata->vbus_pin;
+@@ -2004,7 +1988,7 @@
+       }
+       usba_init_debugfs(udc);
+-      for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
++      for (i = 1; i < pdata->num_ep; i++)
+               usba_ep_init_debugfs(udc, &usba_ep[i]);
+       return 0;
+@@ -2012,6 +1996,8 @@
+ err_device_add:
+       free_irq(irq, udc);
+ err_request_irq:
++      kfree(usba_ep);
++err_alloc_ep:
+       iounmap(udc->fifo);
+ err_map_fifo:
+       iounmap(udc->regs);
+@@ -2029,10 +2015,11 @@
+ {
+       struct usba_udc *udc;
+       int i;
++      struct usba_platform_data *pdata = pdev->dev.platform_data;
+       udc = platform_get_drvdata(pdev);
+-      for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
++      for (i = 1; i < pdata->num_ep; i++)
+               usba_ep_cleanup_debugfs(&usba_ep[i]);
+       usba_cleanup_debugfs(udc);
+@@ -2040,6 +2027,7 @@
+               gpio_free(udc->vbus_pin);
+       free_irq(udc->irq, udc);
++      kfree(usba_ep);
+       iounmap(udc->fifo);
+       iounmap(udc->regs);
+       clk_put(udc->hclk);
+diff --exclude=.git -urN linux-2.6.25.6/drivers/usb/gadget/atmel_usba_udc.h avr32-2.6/drivers/usb/gadget/atmel_usba_udc.h
+--- linux-2.6.25.6/drivers/usb/gadget/atmel_usba_udc.h 2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/usb/gadget/atmel_usba_udc.h      2008-06-12 15:04:02.443815949 +0200
+@@ -41,6 +41,15 @@
+ #define USBA_EN_USBA                          (1 <<  8)
+ #define USBA_DETACH                           (1 <<  9)
+ #define USBA_REMOTE_WAKE_UP                   (1 << 10)
++#define USBA_PULLD_DIS                                (1 << 11)
++
++#if defined(CONFIG_AVR32)
++#define USBA_ENABLE_MASK                      USBA_EN_USBA
++#define USBA_DISABLE_MASK                     0
++#elif defined(CONFIG_ARCH_AT91)
++#define USBA_ENABLE_MASK                      (USBA_EN_USBA | USBA_PULLD_DIS)
++#define USBA_DISABLE_MASK                     USBA_DETACH
++#endif /* CONFIG_ARCH_AT91 */
+ /* Bitfields in FNUM */
+ #define USBA_MICRO_FRAME_NUM_OFFSET           0
+diff --exclude=.git -urN linux-2.6.25.6/drivers/usb/gadget/Kconfig avr32-2.6/drivers/usb/gadget/Kconfig
+--- linux-2.6.25.6/drivers/usb/gadget/Kconfig  2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/usb/gadget/Kconfig       2008-06-12 15:09:42.582816057 +0200
+@@ -118,10 +118,10 @@
+ config USB_GADGET_ATMEL_USBA
+       boolean "Atmel USBA"
+       select USB_GADGET_DUALSPEED
+-      depends on AVR32
++      depends on AVR32 || ARCH_AT91CAP9
+       help
+         USBA is the integrated high-speed USB Device controller on
+-        the AT32AP700x processors from Atmel.
++        the AT32AP700x and AT91CAP9 processors from Atmel.
+ config USB_ATMEL_USBA
+       tristate
+diff --exclude=.git -urN linux-2.6.25.6/drivers/video/atmel_lcdfb.c avr32-2.6/drivers/video/atmel_lcdfb.c
+--- linux-2.6.25.6/drivers/video/atmel_lcdfb.c 2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/drivers/video/atmel_lcdfb.c      2008-06-12 15:09:43.343816340 +0200
+@@ -38,7 +38,9 @@
+ #endif
+ #if defined(CONFIG_ARCH_AT91)
+-#define       ATMEL_LCDFB_FBINFO_DEFAULT      FBINFO_DEFAULT
++#define       ATMEL_LCDFB_FBINFO_DEFAULT      (FBINFO_DEFAULT \
++                                       | FBINFO_PARTIAL_PAN_OK \
++                                       | FBINFO_HWACCEL_YPAN)
+ static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+                                       struct fb_var_screeninfo *var)
+@@ -176,7 +178,7 @@
+       .type           = FB_TYPE_PACKED_PIXELS,
+       .visual         = FB_VISUAL_TRUECOLOR,
+       .xpanstep       = 0,
+-      .ypanstep       = 0,
++      .ypanstep       = 1,
+       .ywrapstep      = 0,
+       .accel          = FB_ACCEL_NONE,
+ };
+@@ -250,6 +252,8 @@
+               return -ENOMEM;
+       }
++      memset(info->screen_base, 0, info->fix.smem_len);
++
+       return 0;
+ }
+@@ -634,7 +638,6 @@
+       struct fb_info *info = sinfo->info;
+       int ret = 0;
+-      memset_io(info->screen_base, 0, info->fix.smem_len);
+       info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
+       dev_info(info->device,
+@@ -764,6 +767,11 @@
+               info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+               if (!info->screen_base)
+                       goto release_intmem;
++
++              /*
++               * Don't clear the framebuffer -- someone may have set
++               * up a splash image.
++               */
+       } else {
+               /* alocate memory buffer */
+               ret = atmel_lcdfb_alloc_video_memory(sinfo);
+diff --exclude=.git -urN linux-2.6.25.6/fs/fs-writeback.c avr32-2.6/fs/fs-writeback.c
+--- linux-2.6.25.6/fs/fs-writeback.c   2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/fs/fs-writeback.c        2008-06-12 15:09:44.531816544 +0200
+@@ -385,8 +385,6 @@
+  * WB_SYNC_HOLD is a hack for sys_sync(): reattach the inode to sb->s_dirty so
+  * that it can be located for waiting on in __writeback_single_inode().
+  *
+- * Called under inode_lock.
+- *
+  * If `bdi' is non-zero then we're being asked to writeback a specific queue.
+  * This function assumes that the blockdev superblock's inodes are backed by
+  * a variety of queues, so all inodes are searched.  For other superblocks,
+@@ -402,11 +400,12 @@
+  * on the writer throttling path, and we get decent balancing between many
+  * throttled threads: we don't want them all piling up on inode_sync_wait.
+  */
+-static void
+-sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc)
++void generic_sync_sb_inodes(struct super_block *sb,
++                              struct writeback_control *wbc)
+ {
+       const unsigned long start = jiffies;    /* livelock avoidance */
++      spin_lock(&inode_lock);
+       if (!wbc->for_kupdate || list_empty(&sb->s_io))
+               queue_io(sb, wbc->older_than_this);
+@@ -485,8 +484,16 @@
+               if (!list_empty(&sb->s_more_io))
+                       wbc->more_io = 1;
+       }
++      spin_unlock(&inode_lock);
+       return;         /* Leave any unwritten inodes on s_io */
+ }
++EXPORT_SYMBOL_GPL(generic_sync_sb_inodes);
++
++static void sync_sb_inodes(struct super_block *sb,
++                              struct writeback_control *wbc)
++{
++      generic_sync_sb_inodes(sb, wbc);
++}
+ /*
+  * Start writeback of dirty pagecache data against all unlocked inodes.
+@@ -526,11 +533,8 @@
+                        * be unmounted by the time it is released.
+                        */
+                       if (down_read_trylock(&sb->s_umount)) {
+-                              if (sb->s_root) {
+-                                      spin_lock(&inode_lock);
++                              if (sb->s_root)
+                                       sync_sb_inodes(sb, wbc);
+-                                      spin_unlock(&inode_lock);
+-                              }
+                               up_read(&sb->s_umount);
+                       }
+                       spin_lock(&sb_lock);
+@@ -568,9 +572,7 @@
+                       (inodes_stat.nr_inodes - inodes_stat.nr_unused) +
+                       nr_dirty + nr_unstable;
+       wbc.nr_to_write += wbc.nr_to_write / 2;         /* Bit more for luck */
+-      spin_lock(&inode_lock);
+       sync_sb_inodes(sb, &wbc);
+-      spin_unlock(&inode_lock);
+ }
+ /*
+diff --exclude=.git -urN linux-2.6.25.6/fs/Kconfig avr32-2.6/fs/Kconfig
+--- linux-2.6.25.6/fs/Kconfig  2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/fs/Kconfig       2008-06-12 15:09:43.915816293 +0200
+@@ -1347,6 +1347,9 @@
+ endchoice
++# UBIFS File system configuration
++source "fs/ubifs/Kconfig"
++
+ config CRAMFS
+       tristate "Compressed ROM file system support (cramfs)"
+       depends on BLOCK
+diff --exclude=.git -urN linux-2.6.25.6/fs/Makefile avr32-2.6/fs/Makefile
+--- linux-2.6.25.6/fs/Makefile 2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/fs/Makefile      2008-06-12 15:09:43.915816293 +0200
+@@ -100,6 +100,7 @@
+ obj-$(CONFIG_UFS_FS)          += ufs/
+ obj-$(CONFIG_EFS_FS)          += efs/
+ obj-$(CONFIG_JFFS2_FS)                += jffs2/
++obj-$(CONFIG_UBIFS_FS)                += ubifs/
+ obj-$(CONFIG_AFFS_FS)         += affs/
+ obj-$(CONFIG_ROMFS_FS)                += romfs/
+ obj-$(CONFIG_QNX4FS_FS)               += qnx4/
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/budget.c avr32-2.6/fs/ubifs/budget.c
+--- linux-2.6.25.6/fs/ubifs/budget.c   1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/budget.c        2008-06-12 15:09:45.311815896 +0200
+@@ -0,0 +1,863 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Adrian Hunter
++ *          Artem Bityutskiy (Битюцкий Артём)
++ */
++
++/*
++ * This file implements the budgeting unit which is responsible for UBIFS space
++ * management.
++ *
++ * Factors such as compression, wasted space at the ends of LEBs, space in other
++ * journal heads, the effect of updates on the index, and so on, make it
++ * impossible to accurately predict the amount of space needed. Consequently
++ * approximations are used.
++ */
++
++#include "ubifs.h"
++#include <linux/writeback.h>
++#include <asm/div64.h>
++
++/*
++ * When pessimistic budget calculations say that there is no enough space,
++ * UBIFS starts writing back dirty inodes and pages, doing garbage collection,
++ * or committing. The below constants define maximum number of times UBIFS
++ * repeats the operations.
++ */
++#define MAX_SHRINK_RETRIES 8
++#define MAX_GC_RETRIES     4
++#define MAX_CMT_RETRIES    2
++#define MAX_NOSPC_RETRIES  1
++
++/*
++ * The below constant defines amount of dirty pages which should be written
++ * back at when trying to shrink the liability.
++ */
++#define NR_TO_WRITE 16
++
++/**
++ * struct retries_info - information about re-tries while making free space.
++ * @prev_liability: previous liability
++ * @shrink_cnt: how many times the liability was shrinked
++ * @shrink_retries: count of liability shrink re-tries (increased when
++ *                  liability does not shrink)
++ * @try_gc: GC should be tried first
++ * @gc_retries: how many times GC was run
++ * @cmt_retries: how many times commit has been done
++ * @nospc_retries: how many times GC returned %-ENOSPC
++ *
++ * Since we consider budgeting to be the fast-path, and this structure has to
++ * be allocated on stack and zeroed out, we make it smaller using bit-fields.
++ */
++struct retries_info {
++      long long prev_liability;
++      unsigned int shrink_cnt;
++      unsigned int shrink_retries:5;
++      unsigned int try_gc:1;
++      unsigned int gc_retries:4;
++      unsigned int cmt_retries:3;
++      unsigned int nospc_retries:1;
++};
++
++/**
++ * shrink_liability - write-back some dirty pages/inodes.
++ * @c: UBIFS file-system description object
++ * @nr_to_write: how many dirty pages to write-back
++ *
++ * This function shrinks UBIFS liability by means of writing back some amount
++ * of dirty inodes and their pages. Returns the amount of pages which were
++ * written back. The returned value does not include dirty inodes which were
++ * synchronized.
++ *
++ * Note, this function synchronizes even VFS inodes which are locked
++ * (@i_mutex) by the caller of the budgeting function, because write-back does
++ * not touch @i_mutex.
++ */
++static int shrink_liability(struct ubifs_info *c, int nr_to_write)
++{
++      struct writeback_control wbc = {
++              .sync_mode   = WB_SYNC_NONE,
++              .range_end   = LLONG_MAX,
++              .nr_to_write = nr_to_write,
++      };
++
++      generic_sync_sb_inodes(c->vfs_sb, &wbc);
++      dbg_budg("%ld pages were written back", nr_to_write - wbc.nr_to_write);
++      return nr_to_write - wbc.nr_to_write;
++}
++
++
++/**
++ * run_gc - run garbage collector.
++ * @c: UBIFS file-system description object
++ *
++ * This function runs garbage collector to make some more free space. Returns
++ * zero if a free LEB has been produced, %-EAGAIN if commit is required, and a
++ * negative error code in case of failure.
++ */
++static int run_gc(struct ubifs_info *c)
++{
++      int err, lnum;
++
++      /* Make some free space by garbage-collecting dirty space */
++      down_read(&c->commit_sem);
++      lnum = ubifs_garbage_collect(c, 1);
++      up_read(&c->commit_sem);
++      if (lnum < 0)
++              return lnum;
++
++      /* GC freed one LEB, return it to lprops */
++      dbg_budg("GC freed LEB %d", lnum);
++      err = ubifs_return_leb(c, lnum);
++      if (err)
++              return err;
++
++      return 0;
++}
++
++/**
++ * make_free_space - make more free space on the file-system.
++ * @c: UBIFS file-system description object
++ * @ri: information about previous invocations of this function
++ *
++ * This function is called when an operation cannot be budgeted because there
++ * is supposedly no free space. But in most cases there is some free space:
++ *   o budgeting is pessimistic, so it always budgets more then it is actually
++ *     needed, so shrinking the liability is one way to make free space - the
++ *     cached data will take less space then it was budgeted for;
++ *   o GC may turn some dark space into free space (budgeting treats dark space
++ *     as not available);
++ *   o commit may free some LEB, i.e., turn freeable LEBs into free LEBs.
++ *
++ * So this function tries to do the above. Returns %-EAGAIN if some free space
++ * was presumably made and the caller has to re-try budgeting the operation.
++ * Returns %-ENOSPC if it couldn't do more free space, and other negative error
++ * codes on failures.
++ */
++static int make_free_space(struct ubifs_info *c, struct retries_info *ri)
++{
++      int err;
++
++      /*
++       * If we have some dirty pages and inodes (liability), try to write
++       * them back unless this was tried too many times without effect
++       * already.
++       */
++      if (ri->shrink_retries < MAX_SHRINK_RETRIES && !ri->try_gc) {
++              long long liability;
++
++              spin_lock(&c->space_lock);
++              liability = c->budg_idx_growth + c->budg_data_growth +
++                          c->budg_dd_growth;
++              spin_unlock(&c->space_lock);
++
++              if (ri->prev_liability >= liability) {
++                      /* Liability does not shrink, next time try GC then */
++                      ri->shrink_retries += 1;
++                      if (ri->gc_retries < MAX_GC_RETRIES)
++                              ri->try_gc = 1;
++                      dbg_budg("liability did not shrink: retries %d of %d",
++                               ri->shrink_retries, MAX_SHRINK_RETRIES);
++              }
++
++              dbg_budg("force write-back (count %d)", ri->shrink_cnt);
++              shrink_liability(c, NR_TO_WRITE + ri->shrink_cnt);
++
++              ri->prev_liability = liability;
++              ri->shrink_cnt += 1;
++              return -EAGAIN;
++      }
++
++      /*
++       * Try to run garbage collector unless it was already tried too many
++       * times.
++       */
++      if (ri->gc_retries < MAX_GC_RETRIES) {
++              ri->gc_retries += 1;
++              dbg_budg("run GC, retries %d of %d",
++                       ri->gc_retries, MAX_GC_RETRIES);
++
++              ri->try_gc = 0;
++              err = run_gc(c);
++              if (!err)
++                      return -EAGAIN;
++
++              if (err == -EAGAIN) {
++                      dbg_budg("GC asked to commit");
++                      err = ubifs_run_commit(c);
++                      if (err)
++                              return err;
++                      return -EAGAIN;
++              }
++
++              if (err != -ENOSPC)
++                      return err;
++
++              /*
++               * GC could not make any progress. If this is the first time,
++               * then it makes sense to try to commit, because it might make
++               * some dirty space.
++               */
++              dbg_budg("GC returned -ENOSPC, retries %d",
++                       ri->nospc_retries);
++              if (ri->nospc_retries >= MAX_NOSPC_RETRIES)
++                      return err;
++              ri->nospc_retries += 1;
++      }
++
++      /* Neither GC nor write-back helped, try to commit */
++      if (ri->cmt_retries < MAX_CMT_RETRIES) {
++              ri->cmt_retries += 1;
++              dbg_budg("run commit, retries %d of %d",
++                       ri->cmt_retries, MAX_CMT_RETRIES);
++              err = ubifs_run_commit(c);
++              if (err)
++                      return err;
++              return -EAGAIN;
++      }
++
++      return -ENOSPC;
++}
++
++/**
++ * ubifs_calc_min_idx_lebs - calculate amount of eraseblocks for the index.
++ * @c: UBIFS file-system description object
++ *
++ * This function calculates and returns the number of eraseblocks which should
++ * be kept for index usage.
++ */
++int ubifs_calc_min_idx_lebs(struct ubifs_info *c)
++{
++      int ret;
++      uint64_t idx_size;
++
++      idx_size = c->old_idx_sz + c->budg_idx_growth + c->budg_uncommitted_idx;
++
++      /* And make sure we have twice the index size of space reserved */
++      idx_size <<= 1;
++
++      /*
++       * We do not maintain 'old_idx_size' as 'old_idx_lebs'/'old_idx_bytes'
++       * pair, nor similarly the two variables for the new index size, so we
++       * have to do this costly 64-bit division on fast-path.
++       */
++      if (do_div(idx_size, c->leb_size - c->max_idx_node_sz))
++              ret = idx_size + 1;
++      else
++              ret = idx_size;
++      /*
++       * The index head is not available for the in-the-gaps method, so add an
++       * extra LEB to compensate.
++       */
++      ret += 1;
++      /*
++       * At present the index needs at least 2 LEBs: one for the index head
++       * and one for in-the-gaps method (which currently does not cater for
++       * the index head and so excludes it from consideration).
++       */
++      if (ret < 2)
++              ret = 2;
++      return ret;
++}
++
++/**
++ * ubifs_calc_available - calculate available FS space.
++ * @c: UBIFS file-system description object
++ *
++ * This function calculates and returns amount of FS space available for use.
++ */
++long long ubifs_calc_available(const struct ubifs_info *c)
++{
++      long long available, subtract_lebs;
++
++      /*
++       * Force the amount available to the total size reported if the used
++       * space is zero.
++       */
++      if (c->lst.total_used <= UBIFS_INO_NODE_SZ &&
++          c->budg_data_growth + c->budg_dd_growth == 0) {
++              /* Do the same calculation as for c->block_cnt */
++              available = c->main_lebs - 2;
++              available *= c->leb_size - c->dark_wm;
++              return available;
++      }
++
++      available = c->main_bytes - c->lst.total_used;
++
++      /*
++       * Now 'available' contains theoretically available flash space
++       * assuming there is no index, so we have to subtract the space which
++       * is reserved for the index.
++       */
++      subtract_lebs = c->min_idx_lebs;
++
++      /* Take into account that GC reserves one LEB for its own needs */
++      subtract_lebs += 1;
++
++      /*
++       * The GC journal head LEB is not really accessible. And since
++       * different write types go to different heads, we may count only on
++       * one head's space.
++       */
++      subtract_lebs += c->jhead_cnt - 1;
++
++      /* We also reserve one LEB for deletions, which bypass budgeting */
++      subtract_lebs += 1;
++
++      available -= subtract_lebs * c->leb_size;
++
++      /* Subtract the dead space which is not available for use */
++      available -= c->lst.total_dead;
++
++      /*
++       * Subtract dark space, which might or might not be usable - it depends
++       * on the data which we have on the media and which will be written. If
++       * this is a lot of uncompressed or not-compressible data, the dark
++       * space cannot be used.
++       */
++      available -= c->lst.total_dark;
++
++      /*
++       * However, there is more dark space. The index may be bigger than
++       * min_idx_lebs. Those extra LEBs are assumed to be available, but
++       * their dark space is not included in total_dark, so it is subtracted
++       * here.
++       */
++      if (c->lst.idx_lebs > c->min_idx_lebs) {
++              subtract_lebs = c->lst.idx_lebs - c->min_idx_lebs;
++              available -= subtract_lebs * c->dark_wm;
++      }
++
++      /* The calculations are rough and may end up with a negative number */
++      return available > 0 ? available : 0;
++}
++
++/**
++ * rp_can_write - check whether the user is allowed to write.
++ * @c: UBIFS file-system description object
++ * @avail: available space on FS
++ *
++ * UBIFS has so-called "reserved pool" which is flash space reserved
++ * for the superuser and for uses whose UID/GID is recorded in UBIFS superblock.
++ * This function checks whether current user is allowed to write
++ * to the file-system - it returns %1 if there is plenty of space or the user
++ * is eligible to use the reserved pool and %0 otherwise.
++ */
++static int rp_can_write(struct ubifs_info *c, long long avail)
++{
++      if (avail > c->rp_size || current->fsuid == c->rp_uid ||
++          capable(CAP_SYS_RESOURCE) ||
++          (c->rp_gid != 0 && in_group_p(c->rp_gid)))
++              return 1;
++
++      return 0;
++}
++
++/**
++ * do_budget_space - reserve flash space for index and data growth.
++ * @c: UBIFS file-system description object
++ *
++ * This function makes sure UBIFS has enough free eraseblocks for index growth
++ * and data.
++ *
++ * When budgeting index space, UBIFS reserves twice as more LEBs as the index
++ * would take if it was consolidated and written to the flash. This guarantees
++ * that the "in-the-gaps" commit method always succeeds and UBIFS will always
++ * be able to commit dirty index. So this function basically adds amount of
++ * budgeted index space to the size of the current index, multiplies this by 2,
++ * and makes sure this does not exceed the amount of free eraseblocks.
++ *
++ * Notes about @c->min_idx_lebs and @c->lst.idx_lebs variables:
++ * o @c->lst.idx_lebs is the number of LEBs the index currently uses. It might
++ *    be large, because UBIFS does not do any index consolidation as long as
++ *    there is free space. IOW, the index may take a lot of LEBs, but the LEBs
++ *    will contain a lot of dirt.
++ * o @c->min_idx_lebs is the the index presumably takes. IOW, the index may be
++ *   consolidated to take up to @c->min_idx_lebs LEBs.
++ *
++ * This function returns zero in case of success, and %-ENOSPC in case of
++ * failure.
++ */
++static int do_budget_space(struct ubifs_info *c)
++{
++      long long outstanding, available;
++      int lebs, rsvd_idx_lebs, min_idx_lebs;
++
++      /* First budget index space */
++      min_idx_lebs = ubifs_calc_min_idx_lebs(c);
++
++      /* Now 'min_idx_lebs' contains number of LEBs to reserve */
++      if (min_idx_lebs > c->lst.idx_lebs)
++              rsvd_idx_lebs = min_idx_lebs - c->lst.idx_lebs;
++      else
++              rsvd_idx_lebs = 0;
++
++      /*
++       * The number of LEBs that are available to be used by the index is:
++       *
++       *    @c->lst.empty_lebs + @c->freeable_cnt + @c->idx_gc_cnt -
++       *    @c->lst.taken_empty_lebs
++       *
++       * @empty_lebs are available because they are empty. @freeable_cnt are
++       * available because they contain only free and dirty space and the
++       * index allocation always occurs after wbufs are synch'ed.
++       * @idx_gc_cnt are available because they are index LEBs that have been
++       * garbage collected (including trivial GC) and are awaiting the commit
++       * before they can be unmapped - note that the in-the-gaps method will
++       * grab these if it needs them. @taken_empty_lebs are empty_lebs that
++       * have already been allocated for some purpose (also includes those
++       * LEBs on the @idx_gc list).
++       *
++       * Note, @taken_empty_lebs may temporarily be higher by one because of
++       * the way we serialize LEB allocations and budgeting. See a comment in
++       * 'ubifs_find_free_space()'.
++       */
++      lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
++             c->lst.taken_empty_lebs;
++      if (unlikely(rsvd_idx_lebs > lebs)) {
++              dbg_budg("out of indexing space: min_idx_lebs %d (old %d), "
++                       "rsvd_idx_lebs %d", min_idx_lebs, c->min_idx_lebs,
++                       rsvd_idx_lebs);
++              return -ENOSPC;
++      }
++
++      available = ubifs_calc_available(c);
++      outstanding = c->budg_data_growth + c->budg_dd_growth;
++
++      if (unlikely(available < outstanding)) {
++              dbg_budg("out of data space: available %lld, outstanding %lld",
++                       available, outstanding);
++              return -ENOSPC;
++      }
++
++      if (!rp_can_write(c, available - outstanding))
++              return -ENOSPC;
++
++      c->min_idx_lebs = min_idx_lebs;
++      return 0;
++}
++
++/**
++ * calc_idx_growth - calculate approximate index growth from budgeting request.
++ * @c: UBIFS file-system description object
++ * @req: budgeting request
++ *
++ * For now we assume each new node adds one znode. But this is rather poor
++ * approximation, though.
++ */
++static int calc_idx_growth(const struct ubifs_info *c,
++                         const struct ubifs_budget_req *req)
++{
++      int znodes;
++
++      znodes = req->new_ino + (req->new_page << UBIFS_BLOCKS_PER_PAGE_SHIFT) +
++               req->new_dent;
++      return znodes * c->max_idx_node_sz;
++}
++
++/**
++ * calc_data_growth - calculate approximate amount of new data from budgeting
++ * request.
++ * @c: UBIFS file-system description object
++ * @req: budgeting request
++ */
++static int calc_data_growth(const struct ubifs_info *c,
++                          const struct ubifs_budget_req *req)
++{
++      int data_growth;
++
++      data_growth = req->new_ino  ? c->inode_budget : 0;
++      if (req->new_page)
++              data_growth += c->page_budget;
++      if (req->new_dent)
++              data_growth += c->dent_budget;
++      data_growth += req->new_ino_d;
++
++      return data_growth;
++}
++
++/**
++ * calc_dd_growth - calculate approximate amount of data which makes other data
++ * dirty from budgeting request.
++ * @c: UBIFS file-system description object
++ * @req: budgeting request
++ */
++static int calc_dd_growth(const struct ubifs_info *c,
++                        const struct ubifs_budget_req *req)
++{
++      int dd_growth;
++
++      dd_growth = req->dirtied_page ? c->page_budget : 0;
++
++      if (req->dirtied_ino)
++              dd_growth += c->inode_budget << (req->dirtied_ino - 1);
++      if (req->mod_dent)
++              dd_growth += c->dent_budget;
++      dd_growth += req->dirtied_ino_d;
++
++      return dd_growth;
++}
++
++/**
++ * ubifs_budget_space - ensure there is enough space to complete an operation.
++ * @c: UBIFS file-system description object
++ * @req: budget request
++ *
++ * This function allocates budget for an operation. It uses pessimistic
++ * approximation of how much flash space the operation needs. The goal of this
++ * function is to make sure UBIFS always has flash space to flush all dirty
++ * pages, dirty inodes, and dirty znodes (liability). This function may force
++ * commit, garbage-collection or write-back. Returns zero in case of success,
++ * %-ENOSPC if there is no free space and other negative error codes in case of
++ * failures.
++ */
++int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req)
++{
++      int uninitialized_var(cmt_retries), uninitialized_var(wb_retries);
++      int err, idx_growth, data_growth, dd_growth;
++      struct retries_info ri;
++
++      data_growth = calc_data_growth(c, req);
++      dd_growth = calc_dd_growth(c, req);
++      if (!data_growth && !dd_growth)
++              return 0;
++      idx_growth = calc_idx_growth(c, req);
++      memset(&ri, 0, sizeof(struct retries_info));
++
++again:
++      spin_lock(&c->space_lock);
++      ubifs_assert(c->budg_idx_growth >= 0);
++      ubifs_assert(c->budg_data_growth >= 0);
++      ubifs_assert(c->budg_dd_growth >= 0);
++
++      c->budg_idx_growth += idx_growth;
++      c->budg_data_growth += data_growth;
++      c->budg_dd_growth += dd_growth;
++
++      err = do_budget_space(c);
++      if (unlikely(err)) {
++              /* Restore the old values */
++              c->budg_idx_growth -= idx_growth;
++              c->budg_data_growth -= data_growth;
++              c->budg_dd_growth -= dd_growth;
++              spin_unlock(&c->space_lock);
++
++              goto make_space;
++      }
++
++      req->idx_growth = idx_growth;
++      req->data_growth = data_growth;
++      req->dd_growth = dd_growth;
++      spin_unlock(&c->space_lock);
++
++      return 0;
++
++make_space:
++      err = make_free_space(c, &ri);
++      if (err == -EAGAIN) {
++              dbg_budg("try again");
++              cond_resched();
++              goto again;
++      } else if (err == -ENOSPC)
++              dbg_budg("FS is full, -ENOSPC");
++      else
++              ubifs_err("cannot budget space, error %d", err);
++
++      return err;
++}
++
++/**
++ * ubifs_release_budget - release budgeted free space.
++ * @c: UBIFS file-system description object
++ * @req: budget request
++ *
++ * This function releases the space budgeted by 'ubifs_budget_space()'. Note,
++ * since the index changes (which were budgeted for in @req->idx_growth) will
++ * only be written to the media on commit, this function moves the index budget
++ * from @c->budg_idx_growth to @c->budg_uncommitted_idx. The latter will be
++ * zeroed by the commit operation.
++ */
++void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req)
++{
++      if (!req->data_growth && !req->dd_growth)
++              return;
++
++      if (req->idx_growth == -1)
++              req->idx_growth = calc_idx_growth(c, req);
++
++      spin_lock(&c->space_lock);
++      c->budg_idx_growth -= req->idx_growth;
++      c->budg_uncommitted_idx += req->idx_growth;
++      c->budg_data_growth -= req->data_growth;
++      c->budg_dd_growth -= req->dd_growth;
++      c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
++
++      ubifs_assert(c->budg_idx_growth >= 0);
++      ubifs_assert(c->budg_data_growth >= 0);
++      ubifs_assert(c->min_idx_lebs < c->main_lebs);
++      spin_unlock(&c->space_lock);
++}
++
++/**
++ * ubifs_convert_page_budget - convert budget of a new page.
++ * @c: UBIFS file-system description object
++ *
++ * This function converts budget which was allocated for a new page of data to
++ * the budget of changing an existing page of data. The latter is not larger
++ * then the former, so this function only does simple re-calculation and does
++ * not involve any write-back.
++ */
++void ubifs_convert_page_budget(struct ubifs_info *c)
++{
++      spin_lock(&c->space_lock);
++      /* Release the index growth reservation */
++      c->budg_idx_growth -= c->max_idx_node_sz << UBIFS_BLOCKS_PER_PAGE_SHIFT;
++      /* Release the data growth reservation */
++      c->budg_data_growth -= c->page_budget;
++      /* Increase the dirty data growth reservation instead */
++      c->budg_dd_growth += c->page_budget;
++      /* And re-calculate the indexing space reservation */
++      c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
++      spin_unlock(&c->space_lock);
++}
++
++/**
++ * ubifs_budget_inode_op - budget an operation on inode.
++ * @c: UBIFS file-system description object
++ * @inode: VFS inode which will be made dirty by the operation
++ * @req: budget request of the operation
++ *
++ * This function is called to get budget for an operation which changes an
++ * inode. The inode may be in dirty or clean state. The former means there is
++ * no need to allocate the budget as it has already been allocated before. The
++ * latter means that the inode change budget has to be allocated.
++ *
++ * The caller has to pass the inode which is going to be changed. This function
++ * acquires budget the for as described in @req plus the budget for changing
++ * the inode dirty, if needed. Returns zero in case of success, %-ENOSPC if
++ * there is no more flash space, and other negative error codes in case of
++ * failure.
++ *
++ * Note, upon exit, this function leaves the inode locked, and the
++ * 'ubifs_release_ino_dirty()' or 'ubifs_release_ino_clean()' function has to
++ * be called to unlock it.
++ */
++int ubifs_budget_inode_op(struct ubifs_info *c, struct inode *inode,
++                            struct ubifs_budget_req *req)
++{
++      struct ubifs_inode *ui = ubifs_inode(inode);
++      int err, old = req->dirtied_ino;
++
++      ubifs_assert(req->dirtied_ino <= 3);
++      ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 3);
++
++again:
++      /*
++       * If the inode is clean, it will be dirtied by this operation and we
++       * have to budget for this.
++       */
++      req->dirtied_ino += !ui->dirty;
++      if (req->dirtied_ino > old)
++              req->dirtied_ino_d += ui->data_len;
++
++      /*
++       * Note, if the budget request does not actually request anything
++       * (i.e., @req contains only zeroes), 'ubifs_budget_space()' will
++       * return almost straight away.
++       */
++      err = ubifs_budget_space(c, req);
++      if (unlikely(err))
++              return err;
++
++      mutex_lock(&ui->budg_mutex);
++
++      if (req->dirtied_ino != old + !ui->dirty) {
++              /* The inode has probably been written back meanwhile */
++              ubifs_release_budget(c, req);
++              mutex_unlock(&ui->budg_mutex);
++              req->dirtied_ino = old;
++              req->dirtied_ino_d -= ui->data_len;
++              goto again;
++      }
++
++      UBIFS_DBG(ui->budgeted = 1);
++      return 0;
++}
++
++/**
++ * ubifs_release_ino_dirty - release budget of a "dirtying" operation.
++ * @c: UBIFS file-system description object
++ * @inode: VFS inode the operation worked on
++ * @req: budget to release
++ *
++ * This function has to be called at the end of VFS operations which acquired
++ * budget via 'ubifs_budget_inode_op()'. It assumes that the inode has been
++ * marked as dirty and will be synchronized later by write-back, so it does not
++ * release the budget of the inode.
++ *
++ * Note, this function also avoids releasing page budgets which are released
++ * separately.
++ */
++void ubifs_release_ino_dirty(struct ubifs_info *c, struct inode *inode,
++                              struct ubifs_budget_req *req)
++{
++      ubifs_assert(req->dirtied_ino <= 4);
++      ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 4);
++      ubifs_assert(req->idx_growth >= 0);
++      ubifs_assert(req->data_growth >= 0);
++      ubifs_assert(req->dd_growth >= 0);
++
++      if (req->dirtied_ino) {
++              req->dd_growth -= c->inode_budget;
++              req->dd_growth -= req->dirtied_ino_d;
++      }
++
++      if (req->dirtied_page) {
++              req->dd_growth -= c->page_budget;
++              ubifs_assert(req->new_page == 0);
++      } else if (req->new_page) {
++              req->idx_growth -=
++                      c->max_idx_node_sz << UBIFS_BLOCKS_PER_PAGE_SHIFT;
++              req->data_growth -= c->page_budget;
++              ubifs_assert(req->dirtied_page == 0);
++      }
++
++      ubifs_assert(req->dd_growth >= 0);
++      ubifs_release_budget(c, req);
++      mutex_unlock(&ubifs_inode(inode)->budg_mutex);
++}
++
++/**
++ * ubifs_cancel_ino_op - cancel budget of an operation on inode.
++ * @c: UBIFS file-system description object
++ * @inode: VFS inode the operation worked on
++ * @req: budget to release
++ *
++ * This function has to be called if the operation failed and whole budget has
++ * to be released, including the budget for inode which would had been
++ * dirtied. It is important not to mark the inode dirty before calling this
++ * function.
++ */
++void ubifs_cancel_ino_op(struct ubifs_info *c, struct inode *inode,
++                       struct ubifs_budget_req *req)
++{
++      ubifs_assert(req->dirtied_ino <= 4);
++      ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 4);
++      ubifs_assert(req->idx_growth >= 0);
++      ubifs_assert(req->data_growth >= 0);
++      ubifs_assert(req->dd_growth >= 0);
++
++      ubifs_release_budget(c, req);
++      mutex_unlock(&ubifs_inode(inode)->budg_mutex);
++}
++
++/**
++ * ubifs_release_ino_clean - release budget of a "cleaning" operation.
++ * @c: UBIFS file-system description object
++ * @inode: VFS inode the operation worked on
++ * @req: budget to release
++ *
++ * This function has to be called at the end of VFS operations which acquired
++ * budget via 'ubifs_budget_inode_op()'. It assumed the operation synchronized
++ * the inode, so it marks the inode clean, unlocks it and releases whole budget.
++ *
++ * Note, this function also avoids releasing page budgets which are released
++ * separately.
++ */
++void ubifs_release_ino_clean(struct ubifs_info *c, struct inode *inode,
++                           struct ubifs_budget_req *req)
++{
++      struct ubifs_inode *ui = ubifs_inode(inode);
++
++      ubifs_assert(req->dirtied_ino <= 4);
++      ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 4);
++      ubifs_assert(req->idx_growth >= 0);
++      ubifs_assert(req->data_growth >= 0);
++      ubifs_assert(req->dd_growth >= 0);
++      ubifs_assert(!req->dirtied_page);
++      ubifs_assert(!req->new_page);
++      UBIFS_DBG(ui->budgeted = 0);
++
++      ubifs_release_budget(c, req);
++      if (ui->dirty) {
++              ui->dirty = 0;
++              /*
++               * Note, VFS still treats the inode as dirty and
++               * 'ubifs_write_inode()' will be called, but it'll do nothing
++               * because @ui->dirty is %0.
++               */
++              atomic_long_dec(&c->dirty_ino_cnt);
++      }
++      mutex_unlock(&ubifs_inode(inode)->budg_mutex);
++}
++
++/**
++ * ubifs_release_new_page_budget - release budget of a new page.
++ * @c: UBIFS file-system description object
++ *
++ * This is a helper function which releases budget corresponding to the budget
++ * of one new page of data.
++ */
++void ubifs_release_new_page_budget(struct ubifs_info *c)
++{
++      struct ubifs_budget_req req = { .new_page = 1,
++                                      .idx_growth = -1,
++                                      .data_growth = c->page_budget };
++
++      ubifs_release_budget(c, &req);
++}
++
++/**
++ * ubifs_budg_get_free_space - return amount of free space.
++ * @c: UBIFS file-system description object
++ *
++ * This function returns amount of free space on the file-system.
++ */
++long long ubifs_budg_get_free_space(struct ubifs_info *c)
++{
++      int min_idx_lebs, rsvd_idx_lebs;
++      long long available, outstanding, free;
++
++      /* Do exactly the same calculations as in 'do_budget_space()' */
++      spin_lock(&c->space_lock);
++      min_idx_lebs = ubifs_calc_min_idx_lebs(c);
++
++      if (min_idx_lebs > c->lst.idx_lebs)
++              rsvd_idx_lebs = min_idx_lebs - c->lst.idx_lebs;
++      else
++              rsvd_idx_lebs = 0;
++
++      if (rsvd_idx_lebs > c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt
++                              - c->lst.taken_empty_lebs) {
++              spin_unlock(&c->space_lock);
++              return 0;
++      }
++
++      c->min_idx_lebs = min_idx_lebs;
++      available = ubifs_calc_available(c);
++      outstanding = c->budg_data_growth + c->budg_dd_growth;
++      spin_unlock(&c->space_lock);
++
++      if (available > outstanding)
++              free = ubifs_reported_space(c, available - outstanding);
++      else
++              free = 0;
++
++      return free;
++}
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/commit.c avr32-2.6/fs/ubifs/commit.c
+--- linux-2.6.25.6/fs/ubifs/commit.c   1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/commit.c        2008-06-12 15:09:45.311815896 +0200
+@@ -0,0 +1,677 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Adrian Hunter
++ *          Artem Bityutskiy (Битюцкий Артём)
++ */
++
++/*
++ * This file implements functions that manage the running of the commit process.
++ * Each affected module has its own functions to accomplish their part in the
++ * commit and those functions are called here.
++ *
++ * The commit is the process whereby all updates to the index and LEB properties
++ * are written out together and the journal becomes empty. This keeps the
++ * file system consistent - at all times the state can be recreated by reading
++ * the index and LEB properties and then replaying the journal.
++ *
++ * The commit is split into two parts named "commit start" and "commit end".
++ * During commit start, the commit process has exclusive access to the journal
++ * by holding the commit semaphore down for writing. As few I/O operations as
++ * possible are performed during commit start, instead the nodes that are to be
++ * written are merely identified. During commit end, the commit semaphore is no
++ * longer held and the journal is again in operation, allowing users to continue
++ * to use the file system while the bulk of the commit I/O is performed. The
++ * purpose of this two-step approach is to prevent the commit from causing any
++ * latency blips. Note that in any case, the commit does not prevent lookups
++ * (as permitted by the TNC mutex), or access to VFS data structures e.g. page
++ * cache.
++ */
++
++#include <linux/freezer.h>
++#include <linux/kthread.h>
++#include "ubifs.h"
++
++/**
++ * do_commit - commit the journal.
++ * @c: UBIFS file-system description object
++ *
++ * This function implements UBIFS commit. It has to be called with commit lock
++ * locked. Returns zero in case of success and a negative error code in case of
++ * failure.
++ */
++static int do_commit(struct ubifs_info *c)
++{
++      int err, new_ltail_lnum, old_ltail_lnum, i;
++      struct ubifs_zbranch zroot;
++      struct ubifs_lp_stats lst;
++
++      dbg_cmt("start");
++      if (c->ro_media) {
++              err = -EROFS;
++              goto out_up;
++      }
++
++      /* Sync all write buffers (necessary for recovery) */
++      for (i = 0; i < c->jhead_cnt; i++) {
++              err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
++              if (err)
++                      goto out_up;
++      }
++
++      err = ubifs_gc_start_commit(c);
++      if (err)
++              goto out_up;
++      err = dbg_check_lprops(c);
++      if (err)
++              goto out_up;
++      err = ubifs_log_start_commit(c, &new_ltail_lnum);
++      if (err)
++              goto out_up;
++      err = ubifs_tnc_start_commit(c, &zroot);
++      if (err)
++              goto out_up;
++      err = ubifs_lpt_start_commit(c);
++      if (err)
++              goto out_up;
++      err = ubifs_orphan_start_commit(c);
++      if (err)
++              goto out_up;
++
++      ubifs_get_lp_stats(c, &lst);
++
++      up_write(&c->commit_sem);
++
++      err = ubifs_tnc_end_commit(c);
++      if (err)
++              goto out;
++      err = ubifs_lpt_end_commit(c);
++      if (err)
++              goto out;
++      err = ubifs_orphan_end_commit(c);
++      if (err)
++              goto out;
++      old_ltail_lnum = c->ltail_lnum;
++      err = ubifs_log_end_commit(c, new_ltail_lnum);
++      if (err)
++              goto out;
++      err = dbg_check_old_index(c, &zroot);
++      if (err)
++              goto out;
++
++      mutex_lock(&c->mst_mutex);
++      c->mst_node->cmt_no      = cpu_to_le64(++c->cmt_no);
++      c->mst_node->log_lnum    = cpu_to_le32(new_ltail_lnum);
++      c->mst_node->root_lnum   = cpu_to_le32(zroot.lnum);
++      c->mst_node->root_offs   = cpu_to_le32(zroot.offs);
++      c->mst_node->root_len    = cpu_to_le32(zroot.len);
++      c->mst_node->ihead_lnum  = cpu_to_le32(c->ihead_lnum);
++      c->mst_node->ihead_offs  = cpu_to_le32(c->ihead_offs);
++      c->mst_node->index_size  = cpu_to_le64(c->old_idx_sz);
++      c->mst_node->lpt_lnum    = cpu_to_le32(c->lpt_lnum);
++      c->mst_node->lpt_offs    = cpu_to_le32(c->lpt_offs);
++      c->mst_node->nhead_lnum  = cpu_to_le32(c->nhead_lnum);
++      c->mst_node->nhead_offs  = cpu_to_le32(c->nhead_offs);
++      c->mst_node->ltab_lnum   = cpu_to_le32(c->ltab_lnum);
++      c->mst_node->ltab_offs   = cpu_to_le32(c->ltab_offs);
++      c->mst_node->lsave_lnum  = cpu_to_le32(c->lsave_lnum);
++      c->mst_node->lsave_offs  = cpu_to_le32(c->lsave_offs);
++      c->mst_node->lscan_lnum  = cpu_to_le32(c->lscan_lnum);
++      c->mst_node->empty_lebs  = cpu_to_le32(lst.empty_lebs);
++      c->mst_node->idx_lebs    = cpu_to_le32(lst.idx_lebs);
++      c->mst_node->total_free  = cpu_to_le64(lst.total_free);
++      c->mst_node->total_dirty = cpu_to_le64(lst.total_dirty);
++      c->mst_node->total_used  = cpu_to_le64(lst.total_used);
++      c->mst_node->total_dead  = cpu_to_le64(lst.total_dead);
++      c->mst_node->total_dark  = cpu_to_le64(lst.total_dark);
++      if (c->no_orphs)
++              c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS);
++      else
++              c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_NO_ORPHS);
++      err = ubifs_write_master(c);
++      mutex_unlock(&c->mst_mutex);
++      if (err)
++              goto out;
++
++      err = ubifs_log_post_commit(c, old_ltail_lnum);
++      if (err)
++              goto out;
++      err = ubifs_gc_end_commit(c);
++      if (err)
++              goto out;
++      err = ubifs_lpt_post_commit(c);
++      if (err)
++              goto out;
++
++      spin_lock(&c->cs_lock);
++      c->cmt_state = COMMIT_RESTING;
++      wake_up(&c->cmt_wq);
++      dbg_cmt("commit end");
++      spin_unlock(&c->cs_lock);
++
++      return 0;
++
++out_up:
++      up_write(&c->commit_sem);
++out:
++      ubifs_err("commit failed, error %d", err);
++      spin_lock(&c->cs_lock);
++      c->cmt_state = COMMIT_BROKEN;
++      wake_up(&c->cmt_wq);
++      spin_unlock(&c->cs_lock);
++      ubifs_ro_mode(c, err);
++      return err;
++}
++
++/**
++ * run_bg_commit - run background commit if it is needed.
++ * @c: UBIFS file-system description object
++ *
++ * This function runs background commit if it is needed. Returns zero in case
++ * of success and a negative error code in case of failure.
++ */
++static int run_bg_commit(struct ubifs_info *c)
++{
++      spin_lock(&c->cs_lock);
++      /*
++       * Run background commit only if background commit was requested or if
++       * commit is required.
++       */
++      if (c->cmt_state != COMMIT_BACKGROUND &&
++          c->cmt_state != COMMIT_REQUIRED)
++              goto out;
++      spin_unlock(&c->cs_lock);
++
++      down_write(&c->commit_sem);
++      spin_lock(&c->cs_lock);
++      if (c->cmt_state == COMMIT_REQUIRED)
++              c->cmt_state = COMMIT_RUNNING_REQUIRED;
++      else if (c->cmt_state == COMMIT_BACKGROUND)
++              c->cmt_state = COMMIT_RUNNING_BACKGROUND;
++      else
++              goto out_cmt_unlock;
++      spin_unlock(&c->cs_lock);
++
++      return do_commit(c);
++
++out_cmt_unlock:
++      up_write(&c->commit_sem);
++out:
++      spin_unlock(&c->cs_lock);
++      return 0;
++}
++
++/**
++ * ubifs_bg_thread - UBIFS background thread function.
++ * @info: points to the file-system description object
++ *
++ * This function implements various file-system background activities:
++ * o when a write-buffer timer expires it synchronizes the appropriate
++ *   write-buffer;
++ * o when the journal is about to be full, it starts in-advance commit.
++ *
++ * Note, other stuff like background garbage collection may be added here in
++ * future.
++ */
++int ubifs_bg_thread(void *info)
++{
++      int err;
++      struct ubifs_info *c = info;
++
++      ubifs_msg("background thread \"%s\" started, PID %d",
++                c->bgt_name, current->pid);
++      set_freezable();
++
++      while (1) {
++              if (kthread_should_stop())
++                      break;
++
++              if (try_to_freeze())
++                      continue;
++
++              set_current_state(TASK_INTERRUPTIBLE);
++              /* Check if there is something to do */
++              if (!c->need_bgt) {
++                      /*
++                       * Nothing prevents us from going sleep now and
++                       * be never woken up and block the task which
++                       * could wait in 'kthread_stop()' forever.
++                       */
++                      if (kthread_should_stop())
++                              break;
++                      schedule();
++                      continue;
++              } else
++                      __set_current_state(TASK_RUNNING);
++
++              c->need_bgt = 0;
++              err = ubifs_bg_wbufs_sync(c);
++              if (err)
++                      ubifs_ro_mode(c, err);
++
++              run_bg_commit(c);
++              cond_resched();
++      }
++
++      dbg_msg("background thread \"%s\" stops", c->bgt_name);
++      return 0;
++}
++
++/**
++ * ubifs_commit_required - set commit state to "required".
++ * @c: UBIFS file-system description object
++ *
++ * This function is called if a commit is required but cannot be done from the
++ * calling function, so it is just flagged instead.
++ */
++void ubifs_commit_required(struct ubifs_info *c)
++{
++      spin_lock(&c->cs_lock);
++      switch (c->cmt_state) {
++      case COMMIT_RESTING:
++      case COMMIT_BACKGROUND:
++              dbg_cmt("old: %s, new: %s", dbg_cstate(c->cmt_state),
++                      dbg_cstate(COMMIT_REQUIRED));
++              c->cmt_state = COMMIT_REQUIRED;
++              break;
++      case COMMIT_RUNNING_BACKGROUND:
++              dbg_cmt("old: %s, new: %s", dbg_cstate(c->cmt_state),
++                      dbg_cstate(COMMIT_RUNNING_REQUIRED));
++              c->cmt_state = COMMIT_RUNNING_REQUIRED;
++              break;
++      case COMMIT_REQUIRED:
++      case COMMIT_RUNNING_REQUIRED:
++      case COMMIT_BROKEN:
++              break;
++      }
++      spin_unlock(&c->cs_lock);
++}
++
++/**
++ * ubifs_request_bg_commit - notify the background thread to do a commit.
++ * @c: UBIFS file-system description object
++ *
++ * This function is called if the journal is full enough to make a commit
++ * worthwhile, so background thread is kicked to start it.
++ */
++void ubifs_request_bg_commit(struct ubifs_info *c)
++{
++      spin_lock(&c->cs_lock);
++      if (c->cmt_state == COMMIT_RESTING) {
++              dbg_cmt("old: %s, new: %s", dbg_cstate(c->cmt_state),
++                      dbg_cstate(COMMIT_BACKGROUND));
++              c->cmt_state = COMMIT_BACKGROUND;
++              spin_unlock(&c->cs_lock);
++              ubifs_wake_up_bgt(c);
++      } else
++              spin_unlock(&c->cs_lock);
++}
++
++/**
++ * wait_for_commit - wait for commit.
++ * @c: UBIFS file-system description object
++ *
++ * This function sleeps until the commit operation is no longer running.
++ */
++static int wait_for_commit(struct ubifs_info *c)
++{
++      dbg_cmt("pid %d goes sleep", current->pid);
++
++      /*
++       * The following sleeps if the condition is false, and will be woken
++       * when the commit ends. It is possible, although very unlikely, that we
++       * will wake up and see the subsequent commit running, rather than the
++       * one we were waiting for, and go back to sleep.  However, we will be
++       * woken again, so there is no danger of sleeping forever.
++       */
++      wait_event(c->cmt_wq, c->cmt_state != COMMIT_RUNNING_BACKGROUND &&
++                            c->cmt_state != COMMIT_RUNNING_REQUIRED);
++      dbg_cmt("commit finished, pid %d woke up", current->pid);
++      return 0;
++}
++
++/**
++ * ubifs_run_commit - run or wait for commit.
++ * @c: UBIFS file-system description object
++ *
++ * This function runs commit and returns zero in case of success and a negative
++ * error code in case of failure.
++ */
++int ubifs_run_commit(struct ubifs_info *c)
++{
++      int err = 0;
++
++      spin_lock(&c->cs_lock);
++      if (c->cmt_state == COMMIT_BROKEN) {
++              err = -EINVAL;
++              goto out;
++      }
++
++      if (c->cmt_state == COMMIT_RUNNING_BACKGROUND)
++              /*
++               * We set the commit state to 'running required' to indicate
++               * that we want it to complete as quickly as possible.
++               */
++              c->cmt_state = COMMIT_RUNNING_REQUIRED;
++
++      if (c->cmt_state == COMMIT_RUNNING_REQUIRED) {
++              spin_unlock(&c->cs_lock);
++              return wait_for_commit(c);
++      }
++      spin_unlock(&c->cs_lock);
++
++      /* Ok, the commit is indeed needed */
++
++      down_write(&c->commit_sem);
++      spin_lock(&c->cs_lock);
++      /*
++       * Since we unlocked 'c->cs_lock', the state may have changed, so
++       * re-check it.
++       */
++      if (c->cmt_state == COMMIT_BROKEN) {
++              err = -EINVAL;
++              goto out_cmt_unlock;
++      }
++
++      if (c->cmt_state == COMMIT_RUNNING_BACKGROUND)
++              c->cmt_state = COMMIT_RUNNING_REQUIRED;
++
++      if (c->cmt_state == COMMIT_RUNNING_REQUIRED) {
++              up_write(&c->commit_sem);
++              spin_unlock(&c->cs_lock);
++              return wait_for_commit(c);
++      }
++      c->cmt_state = COMMIT_RUNNING_REQUIRED;
++      spin_unlock(&c->cs_lock);
++
++      err = do_commit(c);
++      return err;
++
++out_cmt_unlock:
++      up_write(&c->commit_sem);
++out:
++      spin_unlock(&c->cs_lock);
++      return err;
++}
++
++/**
++ * ubifs_gc_should_commit - determine if it is time for GC to run commit.
++ * @c: UBIFS file-system description object
++ *
++ * This function is called by garbage collection to determine if commit should
++ * be run. If commit state is @COMMIT_BACKGROUND, which means that the journal
++ * is full enough to start commit, this function returns true. It is not
++ * absolutely necessary to commit yet, but it feels like this should be better
++ * then to keep doing GC. This function returns %1 if GC has to initiate commit
++ * and %0 if not.
++ */
++int ubifs_gc_should_commit(struct ubifs_info *c)
++{
++      int ret = 0;
++
++      spin_lock(&c->cs_lock);
++      if (c->cmt_state == COMMIT_BACKGROUND) {
++              dbg_cmt("commit required now");
++              c->cmt_state = COMMIT_REQUIRED;
++      } else
++              dbg_cmt("commit not requested");
++      if (c->cmt_state == COMMIT_REQUIRED)
++              ret = 1;
++      spin_unlock(&c->cs_lock);
++      return ret;
++}
++
++#ifdef CONFIG_UBIFS_FS_DEBUG
++
++/**
++ * struct idx_node - hold index nodes during index tree traversal.
++ * @list: list
++ * @iip: index in parent (slot number of this indexing node in the parent
++ *       indexing node)
++ * @upper_key: all keys in this indexing node have to be less or equivalent to
++ *             this key
++ * @idx: index node (8-byte aligned because all node structures must be 8-byte
++ *       aligned)
++ */
++struct idx_node {
++      struct list_head list;
++      int iip;
++      union ubifs_key upper_key;
++      struct ubifs_idx_node idx __attribute__((aligned(8)));
++};
++
++/**
++ * dbg_old_index_check_init - get information for the next old index check.
++ * @c: UBIFS file-system description object
++ * @zroot: root of the index
++ *
++ * This function records information about the index that will be needed for the
++ * next old index check i.e. 'dbg_check_old_index()'.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++int dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot)
++{
++      struct ubifs_idx_node *idx;
++      int lnum, offs, len, err = 0;
++
++      c->old_zroot = *zroot;
++
++      lnum = c->old_zroot.lnum;
++      offs = c->old_zroot.offs;
++      len = c->old_zroot.len;
++
++      idx = kmalloc(c->max_idx_node_sz, GFP_NOFS);
++      if (!idx)
++              return -ENOMEM;
++
++      err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs);
++      if (err)
++              goto out;
++
++      c->old_zroot_level = le16_to_cpu(idx->level);
++      c->old_zroot_sqnum = le64_to_cpu(idx->ch.sqnum);
++out:
++      kfree(idx);
++      return err;
++}
++
++/**
++ * dbg_check_old_index - check the old copy of the index.
++ * @c: UBIFS file-system description object
++ * @zroot: root of the new index
++ *
++ * In order to be able to recover from an unclean unmount, a complete copy of
++ * the index must exist on flash. This is the "old" index. The commit process
++ * must write the "new" index to flash without overwriting or destroying any
++ * part of the old index. This function is run at commit end in order to check
++ * that the old index does indeed exist completely intact.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot)
++{
++      int lnum, offs, len, err = 0, uninitialized_var(last_level), child_cnt;
++      int first = 1, iip;
++      union ubifs_key lower_key, upper_key, l_key, u_key;
++      unsigned long long uninitialized_var(last_sqnum);
++      struct ubifs_idx_node *idx;
++      struct list_head list;
++      struct idx_node *i;
++      size_t sz;
++
++      if (!(ubifs_chk_flags & UBIFS_CHK_OLD_IDX))
++              goto out;
++
++      INIT_LIST_HEAD(&list);
++
++      sz = sizeof(struct idx_node) + ubifs_idx_node_sz(c, c->fanout) -
++           UBIFS_IDX_NODE_SZ;
++
++      /* Start at the old zroot */
++      lnum = c->old_zroot.lnum;
++      offs = c->old_zroot.offs;
++      len = c->old_zroot.len;
++      iip = 0;
++
++      /*
++       * Traverse the index tree preorder depth-first i.e. do a node and then
++       * its subtrees from left to right.
++       */
++      while (1) {
++              struct ubifs_branch *br;
++
++              /* Get the next index node */
++              i = kmalloc(sz, GFP_NOFS);
++              if (!i) {
++                      err = -ENOMEM;
++                      goto out_free;
++              }
++              i->iip = iip;
++              /* Keep the index nodes on our path in a linked list */
++              list_add_tail(&i->list, &list);
++              /* Read the index node */
++              idx = &i->idx;
++              err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs);
++              if (err)
++                      goto out_free;
++              /* Validate index node */
++              child_cnt = le16_to_cpu(idx->child_cnt);
++              if (child_cnt < 1 || child_cnt > c->fanout) {
++                      err = 1;
++                      goto out_dump;
++              }
++              if (first) {
++                      first = 0;
++                      /* Check root level and sqnum */
++                      if (le16_to_cpu(idx->level) != c->old_zroot_level) {
++                              err = 2;
++                              goto out_dump;
++                      }
++                      if (le64_to_cpu(idx->ch.sqnum) != c->old_zroot_sqnum) {
++                              err = 3;
++                              goto out_dump;
++                      }
++                      /* Set last values as though root had a parent */
++                      last_level = le16_to_cpu(idx->level) + 1;
++                      last_sqnum = le64_to_cpu(idx->ch.sqnum) + 1;
++                      key_read(c, ubifs_idx_key(c, idx), &lower_key);
++                      highest_ino_key(c, &upper_key, INUM_WATERMARK);
++              }
++              key_copy(c, &upper_key, &i->upper_key);
++              if (le16_to_cpu(idx->level) != last_level - 1) {
++                      err = 3;
++                      goto out_dump;
++              }
++              /*
++               * The index is always written bottom up hence a child's sqnum
++               * is always less than the parents.
++               */
++              if (le64_to_cpu(idx->ch.sqnum) >= last_sqnum) {
++                      err = 4;
++                      goto out_dump;
++              }
++              /* Check key range */
++              key_read(c, ubifs_idx_key(c, idx), &l_key);
++              br = ubifs_idx_branch(c, idx, child_cnt - 1);
++              key_read(c, &br->key, &u_key);
++              if (keys_cmp(c, &lower_key, &l_key) > 0) {
++                      err = 5;
++                      goto out_dump;
++              }
++              if (keys_cmp(c, &upper_key, &u_key) < 0) {
++                      err = 6;
++                      goto out_dump;
++              }
++              if (keys_cmp(c, &upper_key, &u_key) == 0)
++                      if (!is_hash_key(c, &u_key)) {
++                              err = 7;
++                              goto out_dump;
++                      }
++              /* Go to next index node */
++              if (le16_to_cpu(idx->level) == 0) {
++                      /* At the bottom, so go up until can go right */
++                      while (1) {
++                              /* Drop the bottom of the list */
++                              list_del(&i->list);
++                              kfree(i);
++                              /* No more list means we are done */
++                              if (list_empty(&list))
++                                      goto out;
++                              /* Look at the new bottom */
++                              i = list_entry(list.prev, struct idx_node,
++                                             list);
++                              idx = &i->idx;
++                              /* Can we go right */
++                              if (iip + 1 < le16_to_cpu(idx->child_cnt)) {
++                                      iip = iip + 1;
++                                      break;
++                              } else
++                                      /* Nope, so go up again */
++                                      iip = i->iip;
++                      }
++              } else
++                      /* Go down left */
++                      iip = 0;
++              /*
++               * We have the parent in 'idx' and now we set up for reading the
++               * child pointed to by slot 'iip'.
++               */
++              last_level = le16_to_cpu(idx->level);
++              last_sqnum = le64_to_cpu(idx->ch.sqnum);
++              br = ubifs_idx_branch(c, idx, iip);
++              lnum = le32_to_cpu(br->lnum);
++              offs = le32_to_cpu(br->offs);
++              len = le32_to_cpu(br->len);
++              key_read(c, &br->key, &lower_key);
++              if (iip + 1 < le16_to_cpu(idx->child_cnt)) {
++                      br = ubifs_idx_branch(c, idx, iip + 1);
++                      key_read(c, &br->key, &upper_key);
++              } else
++                      key_copy(c, &i->upper_key, &upper_key);
++      }
++out:
++      err = dbg_old_index_check_init(c, zroot);
++      if (err)
++              goto out_free;
++
++      return 0;
++
++out_dump:
++      dbg_err("dumping index node (iip=%d)", i->iip);
++      dbg_dump_node(c, idx);
++      list_del(&i->list);
++      kfree(i);
++      if (!list_empty(&list)) {
++              i = list_entry(list.prev, struct idx_node, list);
++              dbg_err("dumping parent index node");
++              dbg_dump_node(c, &i->idx);
++      }
++out_free:
++      while (!list_empty(&list)) {
++              i = list_entry(list.next, struct idx_node, list);
++              list_del(&i->list);
++              kfree(i);
++      }
++      ubifs_err("failed, error %d", err);
++      if (err > 0)
++              err = -EINVAL;
++      return err;
++}
++
++#endif /* CONFIG_UBIFS_FS_DEBUG */
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/compress.c avr32-2.6/fs/ubifs/compress.c
+--- linux-2.6.25.6/fs/ubifs/compress.c 1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/compress.c      2008-06-12 15:09:45.315815846 +0200
+@@ -0,0 +1,253 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ * Copyright (C) 2006, 2007 University of Szeged, Hungary
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Adrian Hunter
++ *          Artem Bityutskiy (Битюцкий Артём)
++ *          Zoltan Sogor
++ */
++
++/*
++ * This file provides a single place to access to compression and
++ * decompression.
++ */
++
++#include <linux/crypto.h>
++#include "ubifs.h"
++
++/* Fake description object for the "none" compressor */
++static struct ubifs_compressor none_compr = {
++      .compr_type = UBIFS_COMPR_NONE,
++      .name = "no compression",
++      .capi_name = "",
++};
++
++#ifdef CONFIG_UBIFS_FS_LZO
++static DEFINE_MUTEX(lzo_mutex);
++
++static struct ubifs_compressor lzo_compr = {
++      .compr_type = UBIFS_COMPR_LZO,
++      .comp_mutex = &lzo_mutex,
++      .name = "LZO",
++      .capi_name = "lzo",
++};
++#else
++static struct ubifs_compressor lzo_compr = {
++      .compr_type = UBIFS_COMPR_LZO,
++      .name = "LZO",
++};
++#endif
++
++#ifdef CONFIG_UBIFS_FS_ZLIB
++static DEFINE_MUTEX(deflate_mutex);
++static DEFINE_MUTEX(inflate_mutex);
++
++static struct ubifs_compressor zlib_compr = {
++      .compr_type = UBIFS_COMPR_ZLIB,
++      .comp_mutex = &deflate_mutex,
++      .decomp_mutex = &inflate_mutex,
++      .name = "zlib",
++      .capi_name = "deflate",
++};
++#else
++static struct ubifs_compressor zlib_compr = {
++      .compr_type = UBIFS_COMPR_ZLIB,
++      .name = "zlib",
++};
++#endif
++
++/* All UBIFS compressors */
++struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
++
++/**
++ * ubifs_compress - compress data.
++ * @in_buf: data to compress
++ * @in_len: length of the data to compress
++ * @out_buf: output buffer where compressed data should be stored
++ * @out_len: output buffer length is returned here
++ * @compr_type: type of compression to use on enter, actually used compression
++ *              type on exit
++ *
++ * This function compresses input buffer @in_buf of length @in_len and stores
++ * the result in the output buffer @out_buf and the resulting length in
++ * @out_len. If the input buffer does not compress, it is just copied to the
++ * @out_buf. The same happens if @compr_type is %UBIFS_COMPR_NONE or if
++ * compression error occurred.
++ *
++ * Note, if the input buffer was not compressed, it is copied to the output
++ * buffer and %UBIFS_COMPR_NONE is returned in @compr_type.
++ *
++ * This functions returns %0 on success or a negative error code on failure.
++ */
++void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len,
++                  int *compr_type)
++{
++      int err;
++      struct ubifs_compressor *compr = ubifs_compressors[*compr_type];
++
++      if (*compr_type == UBIFS_COMPR_NONE)
++              goto no_compr;
++
++      /* If the input data is small, do not even try to compress it */
++      if (in_len < UBIFS_MIN_COMPR_LEN)
++              goto no_compr;
++
++      if (compr->comp_mutex)
++              mutex_lock(compr->comp_mutex);
++      err = crypto_comp_compress(compr->cc, in_buf, in_len, out_buf,
++                                 out_len);
++      if (compr->comp_mutex)
++              mutex_unlock(compr->comp_mutex);
++      if (unlikely(err)) {
++              ubifs_warn("cannot compress %d bytes, compressor %s, "
++                         "error %d, leave data uncompressed",
++                         in_len, compr->name, err);
++               goto no_compr;
++      }
++
++      /*
++       * Presently, we just require that compression results in less data,
++       * rather than any defined minimum compression ratio or amount.
++       */
++      if (ALIGN(*out_len, 8) >= ALIGN(in_len, 8))
++              goto no_compr;
++
++      return;
++
++no_compr:
++      memcpy(out_buf, in_buf, in_len);
++      *out_len = in_len;
++      *compr_type = UBIFS_COMPR_NONE;
++}
++
++/**
++ * ubifs_decompress - decompress data.
++ * @in_buf: data to decompress
++ * @in_len: length of the data to decompress
++ * @out_buf: output buffer where decompressed data should
++ * @out_len: output length is returned here
++ * @compr_type: type of compression
++ *
++ * This function decompresses data from buffer @in_buf into buffer @out_buf.
++ * The length of the uncompressed data is returned in @out_len. This functions
++ * returns %0 on success or a negative error code on failure.
++ */
++int ubifs_decompress(const void *in_buf, int in_len, void *out_buf,
++                   int *out_len, int compr_type)
++{
++      int err;
++      struct ubifs_compressor *compr;
++
++      if (unlikely(compr_type < 0 || compr_type >= UBIFS_COMPR_TYPES_CNT)) {
++              ubifs_err("invalid compression type %d", compr_type);
++              return -EINVAL;
++      }
++
++      compr = ubifs_compressors[compr_type];
++
++      if (unlikely(!compr->capi_name)) {
++              ubifs_err("%s compression is not compiled in", compr->name);
++              return -EINVAL;
++      }
++
++      if (compr_type == UBIFS_COMPR_NONE) {
++              memcpy(out_buf, in_buf, in_len);
++              *out_len = in_len;
++              return 0;
++      }
++
++      if (compr->decomp_mutex)
++              mutex_lock(compr->decomp_mutex);
++      err = crypto_comp_decompress(compr->cc, in_buf, in_len, out_buf,
++                                   out_len);
++      if (compr->decomp_mutex)
++              mutex_unlock(compr->decomp_mutex);
++      if (err)
++              ubifs_err("cannot decompress %d bytes, compressor %s, "
++                        "error %d", in_len, compr->name, err);
++
++      return err;
++}
++
++/**
++ * compr_init - initialize a compressor.
++ * @compr: compressor description object
++ *
++ * This function initializes the requested compressor and returns zero in case
++ * of success or a negative error code in case of failure.
++ */
++static int __init compr_init(struct ubifs_compressor *compr)
++{
++      if (compr->capi_name) {
++              compr->cc = crypto_alloc_comp(compr->capi_name, 0, 0);
++              if (IS_ERR(compr->cc)) {
++                      ubifs_err("cannot initialize compressor %s, error %ld",
++                                compr->name, PTR_ERR(compr->cc));
++                      return PTR_ERR(compr->cc);
++              }
++      }
++
++      ubifs_compressors[compr->compr_type] = compr;
++      return 0;
++}
++
++/**
++ * compr_exit - de-initialize a compressor.
++ * @compr: compressor description object
++ */
++static void compr_exit(struct ubifs_compressor *compr)
++{
++      if (compr->capi_name)
++              crypto_free_comp(compr->cc);
++      return;
++}
++
++/**
++ * ubifs_compressors_init - initialize UBIFS compressors.
++ *
++ * This function initializes the compressor which were compiled in. Returns
++ * zero in case of success and a negative error code in case of failure.
++ */
++int __init ubifs_compressors_init(void)
++{
++      int err;
++
++      err = compr_init(&lzo_compr);
++      if (err)
++              return err;
++
++      err = compr_init(&zlib_compr);
++      if (err)
++              goto out_lzo;
++
++      ubifs_compressors[UBIFS_COMPR_NONE] = &none_compr;
++      return 0;
++
++out_lzo:
++      compr_exit(&lzo_compr);
++      return err;
++}
++
++/**
++ * ubifs_compressors_exit - de-initialize UBIFS compressors.
++ */
++void __exit ubifs_compressors_exit(void)
++{
++      compr_exit(&lzo_compr);
++      compr_exit(&zlib_compr);
++}
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/debug.c avr32-2.6/fs/ubifs/debug.c
+--- linux-2.6.25.6/fs/ubifs/debug.c    1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/debug.c 2008-06-12 15:09:45.315815846 +0200
+@@ -0,0 +1,2210 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Artem Bityutskiy (Битюцкий Артём)
++ *          Adrian Hunter
++ */
++
++/*
++ * This file implements most of the debugging stuff which is compiled in only
++ * when it is enabled. But some debugging check functions are implemented in
++ * corresponding subsystem, just because they are closely related and utilize
++ * various local functions of those subsystems.
++ */
++
++#define UBIFS_DBG_PRESERVE_UBI
++
++#include "ubifs.h"
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++
++#ifdef CONFIG_UBIFS_FS_DEBUG
++
++DEFINE_SPINLOCK(dbg_lock);
++
++static char dbg_key_buf0[128];
++static char dbg_key_buf1[128];
++
++unsigned int ubifs_msg_flags = UBIFS_MSG_FLAGS_DEFAULT;
++unsigned int ubifs_chk_flags = UBIFS_CHK_FLAGS_DEFAULT;
++unsigned int ubifs_tst_flags;
++
++module_param_named(debug_msgs, ubifs_msg_flags, uint, S_IRUGO | S_IWUSR);
++module_param_named(debug_chks, ubifs_chk_flags, uint, S_IRUGO | S_IWUSR);
++module_param_named(debug_tsts, ubifs_tst_flags, uint, S_IRUGO | S_IWUSR);
++
++MODULE_PARM_DESC(debug_msgs, "Debug message type flags");
++MODULE_PARM_DESC(debug_chks, "Debug check flags");
++MODULE_PARM_DESC(debug_tsts, "Debug special test flags");
++
++static const char *get_key_fmt(int fmt)
++{
++      switch (fmt) {
++      case UBIFS_SIMPLE_KEY_FMT:
++              return "simple";
++      default:
++              return "unknown/invalid format";
++      }
++}
++
++static const char *get_key_hash(int hash)
++{
++      switch (hash) {
++      case UBIFS_KEY_HASH_R5:
++              return "R5";
++      case UBIFS_KEY_HASH_TEST:
++              return "test";
++      default:
++              return "unknown/invalid name hash";
++      }
++}
++
++static const char *get_key_type(int type)
++{
++      switch (type) {
++      case UBIFS_INO_KEY:
++              return "inode";
++      case UBIFS_DENT_KEY:
++              return "direntry";
++      case UBIFS_XENT_KEY:
++              return "xentry";
++      case UBIFS_DATA_KEY:
++              return "data";
++      case UBIFS_TRUN_KEY:
++              return "truncate";
++      default:
++              return "unknown/invalid key";
++      }
++}
++
++static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key,
++                      char *buffer)
++{
++      char *p = buffer;
++      int type = key_type(c, key);
++
++      if (c->key_fmt == UBIFS_SIMPLE_KEY_FMT) {
++              switch (type) {
++              case UBIFS_INO_KEY:
++                      sprintf(p, "(%lu, %s)", key_inum(c, key),
++                             get_key_type(type));
++                      break;
++              case UBIFS_DENT_KEY:
++              case UBIFS_XENT_KEY:
++                      sprintf(p, "(%lu, %s, %#08x)", key_inum(c, key),
++                              get_key_type(type), key_hash(c, key));
++                      break;
++              case UBIFS_DATA_KEY:
++                      sprintf(p, "(%lu, %s, %u)", key_inum(c, key),
++                              get_key_type(type), key_block(c, key));
++                      break;
++              case UBIFS_TRUN_KEY:
++                      sprintf(p, "(%lu, %s)",
++                              key_inum(c, key), get_key_type(type));
++                      break;
++              default:
++                      sprintf(p, "(bad key type: %#08x, %#08x)",
++                              key->u32[0], key->u32[1]);
++              }
++      } else
++              sprintf(p, "bad key format %d", c->key_fmt);
++}
++
++const char *dbg_key_str0(const struct ubifs_info *c, const union ubifs_key *key)
++{
++      /* dbg_lock must be held */
++      sprintf_key(c, key, dbg_key_buf0);
++      return dbg_key_buf0;
++}
++
++const char *dbg_key_str1(const struct ubifs_info *c, const union ubifs_key *key)
++{
++      /* dbg_lock must be held */
++      sprintf_key(c, key, dbg_key_buf1);
++      return dbg_key_buf1;
++}
++
++const char *dbg_ntype(int type)
++{
++      switch (type) {
++      case UBIFS_PAD_NODE:
++              return "padding node";
++      case UBIFS_SB_NODE:
++              return "superblock node";
++      case UBIFS_MST_NODE:
++              return "master node";
++      case UBIFS_REF_NODE:
++              return "reference node";
++      case UBIFS_INO_NODE:
++              return "inode node";
++      case UBIFS_DENT_NODE:
++              return "direntry node";
++      case UBIFS_XENT_NODE:
++              return "xentry node";
++      case UBIFS_DATA_NODE:
++              return "data node";
++      case UBIFS_TRUN_NODE:
++              return "truncate node";
++      case UBIFS_IDX_NODE:
++              return "indexing node";
++      case UBIFS_CS_NODE:
++              return "commit start node";
++      case UBIFS_ORPH_NODE:
++              return "orphan node";
++      default:
++              return "unknown node";
++      }
++}
++
++static const char *dbg_gtype(int type)
++{
++      switch (type) {
++      case UBIFS_NO_NODE_GROUP:
++              return "no node group";
++      case UBIFS_IN_NODE_GROUP:
++              return "in node group";
++      case UBIFS_LAST_OF_NODE_GROUP:
++              return "last of node group";
++      default:
++              return "unknown";
++      }
++}
++
++const char *dbg_cstate(int cmt_state)
++{
++      switch (cmt_state) {
++      case COMMIT_RESTING:
++              return "commit resting";
++      case COMMIT_BACKGROUND:
++              return "background commit requested";
++      case COMMIT_REQUIRED:
++              return "commit required";
++      case COMMIT_RUNNING_BACKGROUND:
++              return "BACKGROUND commit running";
++      case COMMIT_RUNNING_REQUIRED:
++              return "commit running and required";
++      case COMMIT_BROKEN:
++              return "broken commit";
++      default:
++              return "unknown commit state";
++      }
++}
++
++static void dump_ch(const struct ubifs_ch *ch)
++{
++      printk(KERN_DEBUG "\tmagic          %#x\n", le32_to_cpu(ch->magic));
++      printk(KERN_DEBUG "\tcrc            %#x\n", le32_to_cpu(ch->crc));
++      printk(KERN_DEBUG "\tnode_type      %d (%s)\n", ch->node_type,
++             dbg_ntype(ch->node_type));
++      printk(KERN_DEBUG "\tgroup_type     %d (%s)\n", ch->group_type,
++             dbg_gtype(ch->group_type));
++      printk(KERN_DEBUG "\tsqnum          %llu\n",
++             (unsigned long long)le64_to_cpu(ch->sqnum));
++      printk(KERN_DEBUG "\tlen            %u\n", le32_to_cpu(ch->len));
++}
++
++void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode)
++{
++      const struct ubifs_inode *ui = ubifs_inode(inode);
++
++      printk(KERN_DEBUG "inode      %lu\n", inode->i_ino);
++      printk(KERN_DEBUG "size       %llu\n",
++             (unsigned long long)i_size_read(inode));
++      printk(KERN_DEBUG "nlink      %u\n", inode->i_nlink);
++      printk(KERN_DEBUG "uid        %u\n", (unsigned int)inode->i_uid);
++      printk(KERN_DEBUG "gid        %u\n", (unsigned int)inode->i_gid);
++      printk(KERN_DEBUG "atime      %u.%u\n",
++             (unsigned int)inode->i_atime.tv_sec,
++             (unsigned int)inode->i_atime.tv_nsec);
++      printk(KERN_DEBUG "mtime      %u.%u\n",
++             (unsigned int)inode->i_mtime.tv_sec,
++             (unsigned int)inode->i_mtime.tv_nsec);
++      printk(KERN_DEBUG "ctime       %u.%u\n",
++             (unsigned int)inode->i_ctime.tv_sec,
++             (unsigned int)inode->i_ctime.tv_nsec);
++      printk(KERN_DEBUG "creat_sqnum %llu\n", ui->creat_sqnum);
++      printk(KERN_DEBUG "xattr_size  %lld\n", ui->xattr_size);
++      printk(KERN_DEBUG "xattr_cnt   %d\n", ui->xattr_cnt);
++      printk(KERN_DEBUG "xattr_names %d\n", ui->xattr_names);
++      printk(KERN_DEBUG "dirty       %u\n", ui->dirty);
++      printk(KERN_DEBUG "xattr       %u\n", ui->xattr);
++      printk(KERN_DEBUG "flags       %d\n", ui->flags);
++      printk(KERN_DEBUG "compr_type  %d\n", ui->compr_type);
++      printk(KERN_DEBUG "data_len    %d\n", ui->data_len);
++}
++
++void dbg_dump_node(const struct ubifs_info *c, const void *node)
++{
++      int i, n;
++      union ubifs_key key;
++      const struct ubifs_ch *ch = node;
++
++      if (dbg_failure_mode)
++              return;
++
++      /* If the magic is incorrect, just hexdump the first bytes */
++      if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC) {
++              printk(KERN_DEBUG "Not a node, first %zu bytes:", UBIFS_CH_SZ);
++              print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
++                             (void *)node, UBIFS_CH_SZ, 1);
++              return;
++      }
++
++      spin_lock(&dbg_lock);
++      dump_ch(node);
++
++      switch (ch->node_type) {
++      case UBIFS_PAD_NODE:
++      {
++              const struct ubifs_pad_node *pad = node;
++
++              printk(KERN_DEBUG "\tpad_len        %u\n",
++                     le32_to_cpu(pad->pad_len));
++              break;
++      }
++      case UBIFS_SB_NODE:
++      {
++              const struct ubifs_sb_node *sup = node;
++              unsigned int sup_flags = le32_to_cpu(sup->flags);
++
++              printk(KERN_DEBUG "\tkey_hash       %d (%s)\n",
++                     (int)sup->key_hash, get_key_hash(sup->key_hash));
++              printk(KERN_DEBUG "\tkey_fmt        %d (%s)\n",
++                     (int)sup->key_fmt, get_key_fmt(sup->key_fmt));
++              printk(KERN_DEBUG "\tflags          %#x\n", sup_flags);
++              printk(KERN_DEBUG "\t  big_lpt      %u\n",
++                     !!(sup_flags & UBIFS_FLG_BIGLPT));
++              printk(KERN_DEBUG "\tmin_io_size    %u\n",
++                     le32_to_cpu(sup->min_io_size));
++              printk(KERN_DEBUG "\tleb_size       %u\n",
++                     le32_to_cpu(sup->leb_size));
++              printk(KERN_DEBUG "\tleb_cnt        %u\n",
++                     le32_to_cpu(sup->leb_cnt));
++              printk(KERN_DEBUG "\tmax_leb_cnt    %u\n",
++                     le32_to_cpu(sup->max_leb_cnt));
++              printk(KERN_DEBUG "\tmax_bud_bytes  %llu\n",
++                     (unsigned long long)le64_to_cpu(sup->max_bud_bytes));
++              printk(KERN_DEBUG "\tlog_lebs       %u\n",
++                     le32_to_cpu(sup->log_lebs));
++              printk(KERN_DEBUG "\tlpt_lebs       %u\n",
++                     le32_to_cpu(sup->lpt_lebs));
++              printk(KERN_DEBUG "\torph_lebs      %u\n",
++                     le32_to_cpu(sup->orph_lebs));
++              printk(KERN_DEBUG "\tjhead_cnt      %u\n",
++                     le32_to_cpu(sup->jhead_cnt));
++              printk(KERN_DEBUG "\tfanout         %u\n",
++                     le32_to_cpu(sup->fanout));
++              printk(KERN_DEBUG "\tlsave_cnt      %u\n",
++                     le32_to_cpu(sup->lsave_cnt));
++              printk(KERN_DEBUG "\tdefault_compr  %u\n",
++                     (int)le16_to_cpu(sup->default_compr));
++              printk(KERN_DEBUG "\trp_size        %llu\n",
++                     (unsigned long long)le64_to_cpu(sup->rp_size));
++              printk(KERN_DEBUG "\trp_uid         %u\n",
++                     le32_to_cpu(sup->rp_uid));
++              printk(KERN_DEBUG "\trp_gid         %u\n",
++                     le32_to_cpu(sup->rp_gid));
++              printk(KERN_DEBUG "\tfmt_version    %u\n",
++                     le32_to_cpu(sup->fmt_version));
++              printk(KERN_DEBUG "\ttime_gran      %u\n",
++                     le32_to_cpu(sup->time_gran));
++              printk(KERN_DEBUG "\tUUID           %02X%02X%02X%02X-%02X%02X"
++                     "-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
++                     sup->uuid[0], sup->uuid[1], sup->uuid[2], sup->uuid[3],
++                     sup->uuid[4], sup->uuid[5], sup->uuid[6], sup->uuid[7],
++                     sup->uuid[8], sup->uuid[9], sup->uuid[10], sup->uuid[11],
++                     sup->uuid[12], sup->uuid[13], sup->uuid[14],
++                     sup->uuid[15]);
++              break;
++      }
++      case UBIFS_MST_NODE:
++      {
++              const struct ubifs_mst_node *mst = node;
++
++              printk(KERN_DEBUG "\thighest_inum   %llu\n",
++                     (unsigned long long)le64_to_cpu(mst->highest_inum));
++              printk(KERN_DEBUG "\tcommit number  %llu\n",
++                     (unsigned long long)le64_to_cpu(mst->cmt_no));
++              printk(KERN_DEBUG "\tflags          %#x\n",
++                     le32_to_cpu(mst->flags));
++              printk(KERN_DEBUG "\tlog_lnum       %u\n",
++                     le32_to_cpu(mst->log_lnum));
++              printk(KERN_DEBUG "\troot_lnum      %u\n",
++                     le32_to_cpu(mst->root_lnum));
++              printk(KERN_DEBUG "\troot_offs      %u\n",
++                     le32_to_cpu(mst->root_offs));
++              printk(KERN_DEBUG "\troot_len       %u\n",
++                     le32_to_cpu(mst->root_len));
++              printk(KERN_DEBUG "\tgc_lnum        %u\n",
++                     le32_to_cpu(mst->gc_lnum));
++              printk(KERN_DEBUG "\tihead_lnum     %u\n",
++                     le32_to_cpu(mst->ihead_lnum));
++              printk(KERN_DEBUG "\tihead_offs     %u\n",
++                     le32_to_cpu(mst->ihead_offs));
++              printk(KERN_DEBUG "\tindex_size     %u\n",
++                     le32_to_cpu(mst->index_size));
++              printk(KERN_DEBUG "\tlpt_lnum       %u\n",
++                     le32_to_cpu(mst->lpt_lnum));
++              printk(KERN_DEBUG "\tlpt_offs       %u\n",
++                     le32_to_cpu(mst->lpt_offs));
++              printk(KERN_DEBUG "\tnhead_lnum     %u\n",
++                     le32_to_cpu(mst->nhead_lnum));
++              printk(KERN_DEBUG "\tnhead_offs     %u\n",
++                     le32_to_cpu(mst->nhead_offs));
++              printk(KERN_DEBUG "\tltab_lnum      %u\n",
++                     le32_to_cpu(mst->ltab_lnum));
++              printk(KERN_DEBUG "\tltab_offs      %u\n",
++                     le32_to_cpu(mst->ltab_offs));
++              printk(KERN_DEBUG "\tlsave_lnum     %u\n",
++                     le32_to_cpu(mst->lsave_lnum));
++              printk(KERN_DEBUG "\tlsave_offs     %u\n",
++                     le32_to_cpu(mst->lsave_offs));
++              printk(KERN_DEBUG "\tlscan_lnum     %u\n",
++                     le32_to_cpu(mst->lscan_lnum));
++              printk(KERN_DEBUG "\tleb_cnt        %u\n",
++                     le32_to_cpu(mst->leb_cnt));
++              printk(KERN_DEBUG "\tempty_lebs     %u\n",
++                     le32_to_cpu(mst->empty_lebs));
++              printk(KERN_DEBUG "\tidx_lebs       %u\n",
++                     le32_to_cpu(mst->idx_lebs));
++              printk(KERN_DEBUG "\ttotal_free     %llu\n",
++                     (unsigned long long)le64_to_cpu(mst->total_free));
++              printk(KERN_DEBUG "\ttotal_dirty    %llu\n",
++                     (unsigned long long)le64_to_cpu(mst->total_dirty));
++              printk(KERN_DEBUG "\ttotal_used     %llu\n",
++                     (unsigned long long)le64_to_cpu(mst->total_used));
++              printk(KERN_DEBUG "\ttotal_dead     %llu\n",
++                     (unsigned long long)le64_to_cpu(mst->total_dead));
++              printk(KERN_DEBUG "\ttotal_dark     %llu\n",
++                     (unsigned long long)le64_to_cpu(mst->total_dark));
++              break;
++      }
++      case UBIFS_REF_NODE:
++      {
++              const struct ubifs_ref_node *ref = node;
++
++              printk(KERN_DEBUG "\tlnum           %u\n",
++                     le32_to_cpu(ref->lnum));
++              printk(KERN_DEBUG "\toffs           %u\n",
++                     le32_to_cpu(ref->offs));
++              printk(KERN_DEBUG "\tjhead          %u\n",
++                     le32_to_cpu(ref->jhead));
++              break;
++      }
++      case UBIFS_INO_NODE:
++      {
++              const struct ubifs_ino_node *ino = node;
++
++              key_read(c, &ino->key, &key);
++              printk(KERN_DEBUG "\tkey            %s\n", DBGKEY(&key));
++              printk(KERN_DEBUG "\tcreat_sqnum    %llu\n",
++                     (unsigned long long)le64_to_cpu(ino->creat_sqnum));
++              printk(KERN_DEBUG "\tsize           %llu\n",
++                     (unsigned long long)le64_to_cpu(ino->size));
++              printk(KERN_DEBUG "\tnlink          %u\n",
++                     le32_to_cpu(ino->nlink));
++              printk(KERN_DEBUG "\tatime          %lld.%u\n",
++                     (long long)le64_to_cpu(ino->atime_sec),
++                     le32_to_cpu(ino->atime_nsec));
++              printk(KERN_DEBUG "\tmtime          %lld.%u\n",
++                     (long long)le64_to_cpu(ino->mtime_sec),
++                     le32_to_cpu(ino->mtime_nsec));
++              printk(KERN_DEBUG "\tctime          %lld.%u\n",
++                     (long long)le64_to_cpu(ino->ctime_sec),
++                     le32_to_cpu(ino->ctime_nsec));
++              printk(KERN_DEBUG "\tuid            %u\n",
++                     le32_to_cpu(ino->uid));
++              printk(KERN_DEBUG "\tgid            %u\n",
++                     le32_to_cpu(ino->gid));
++              printk(KERN_DEBUG "\tmode           %u\n",
++                     le32_to_cpu(ino->mode));
++              printk(KERN_DEBUG "\tflags          %#x\n",
++                     le32_to_cpu(ino->flags));
++              printk(KERN_DEBUG "\txattr_cnt      %u\n",
++                     le32_to_cpu(ino->xattr_cnt));
++              printk(KERN_DEBUG "\txattr_size     %llu\n",
++                     (unsigned long long)le64_to_cpu(ino->xattr_size));
++              printk(KERN_DEBUG "\txattr_names    %u\n",
++                     le32_to_cpu(ino->xattr_names));
++              printk(KERN_DEBUG "\tcompr_type     %#x\n",
++                     (int)le16_to_cpu(ino->compr_type));
++              printk(KERN_DEBUG "\tdata len       %u\n",
++                     le32_to_cpu(ino->data_len));
++              break;
++      }
++      case UBIFS_DENT_NODE:
++      case UBIFS_XENT_NODE:
++      {
++              const struct ubifs_dent_node *dent = node;
++              int nlen = le16_to_cpu(dent->nlen);
++
++              key_read(c, &dent->key, &key);
++              printk(KERN_DEBUG "\tkey            %s\n", DBGKEY(&key));
++              printk(KERN_DEBUG "\tinum           %llu\n",
++                     (unsigned long long)le64_to_cpu(dent->inum));
++              printk(KERN_DEBUG "\ttype           %d\n", (int)dent->type);
++              printk(KERN_DEBUG "\tnlen           %d\n", nlen);
++              printk(KERN_DEBUG "\tname           ");
++
++              if (nlen > UBIFS_MAX_NLEN)
++                      printk(KERN_DEBUG "(bad name length, not printing, "
++                                        "bad or corrupted node)");
++              else {
++                      for (i = 0; i < nlen && dent->name[i]; i++)
++                              printk("%c", dent->name[i]);
++              }
++              printk("\n");
++
++              break;
++      }
++      case UBIFS_DATA_NODE:
++      {
++              const struct ubifs_data_node *dn = node;
++              int dlen = le32_to_cpu(ch->len) - UBIFS_DATA_NODE_SZ;
++
++              key_read(c, &dn->key, &key);
++              printk(KERN_DEBUG "\tkey            %s\n", DBGKEY(&key));
++              printk(KERN_DEBUG "\tsize           %u\n",
++                     le32_to_cpu(dn->size));
++              printk(KERN_DEBUG "\tcompr_typ      %d\n",
++                     (int)le16_to_cpu(dn->compr_type));
++              printk(KERN_DEBUG "\tdata size      %d\n",
++                     dlen);
++              printk(KERN_DEBUG "\tdata:\n");
++              print_hex_dump(KERN_DEBUG, "\t", DUMP_PREFIX_OFFSET, 32, 1,
++                             (void *)&dn->data, dlen, 0);
++              break;
++      }
++      case UBIFS_TRUN_NODE:
++      {
++              const struct ubifs_trun_node *trun = node;
++
++              printk(KERN_DEBUG "\tinum           %u\n",
++                     le32_to_cpu(trun->inum));
++              printk(KERN_DEBUG "\told_size       %llu\n",
++                     (unsigned long long)le64_to_cpu(trun->old_size));
++              printk(KERN_DEBUG "\tnew_size       %llu\n",
++                     (unsigned long long)le64_to_cpu(trun->new_size));
++              break;
++      }
++      case UBIFS_IDX_NODE:
++      {
++              const struct ubifs_idx_node *idx = node;
++
++              n = le16_to_cpu(idx->child_cnt);
++              printk(KERN_DEBUG "\tchild_cnt      %d\n", n);
++              printk(KERN_DEBUG "\tlevel          %d\n",
++                     (int)le16_to_cpu(idx->level));
++              printk(KERN_DEBUG "\tBranches:\n");
++
++              for (i = 0; i < n && i < c->fanout - 1; i++) {
++                      const struct ubifs_branch *br;
++
++                      br = ubifs_idx_branch(c, idx, i);
++                      key_read(c, &br->key, &key);
++                      printk(KERN_DEBUG "\t%d: LEB %d:%d len %d key %s\n",
++                             i, le32_to_cpu(br->lnum), le32_to_cpu(br->offs),
++                             le32_to_cpu(br->len), DBGKEY(&key));
++              }
++              break;
++      }
++      case UBIFS_CS_NODE:
++              break;
++      case UBIFS_ORPH_NODE:
++      {
++              const struct ubifs_orph_node *orph = node;
++
++              printk(KERN_DEBUG "\tcommit number  %llu\n",
++                     (unsigned long long)
++                              le64_to_cpu(orph->cmt_no) & LLONG_MAX);
++              printk(KERN_DEBUG "\tlast node flag %llu\n",
++                     (unsigned long long)(le64_to_cpu(orph->cmt_no)) >> 63);
++              n = (le32_to_cpu(ch->len) - UBIFS_ORPH_NODE_SZ) >> 3;
++              printk(KERN_DEBUG "\t%d orphan inode numbers:\n", n);
++              for (i = 0; i < n; i++)
++                      printk(KERN_DEBUG "\t  ino %llu\n",
++                             le64_to_cpu(orph->inos[i]));
++              break;
++      }
++      default:
++              printk(KERN_DEBUG "node type %d was not recognized\n",
++                     (int)ch->node_type);
++      }
++      spin_unlock(&dbg_lock);
++}
++
++void dbg_dump_budget_req(const struct ubifs_budget_req *req)
++{
++      spin_lock(&dbg_lock);
++      printk(KERN_DEBUG "Budgeting request: new_ino %d, dirtied_ino %d\n",
++             req->new_ino, req->dirtied_ino);
++      printk(KERN_DEBUG "\tnew_ino_d   %d, dirtied_ino_d %d\n",
++             req->new_ino_d, req->dirtied_ino_d);
++      printk(KERN_DEBUG "\tnew_page    %d, dirtied_page %d\n",
++             req->new_page, req->dirtied_page);
++      printk(KERN_DEBUG "\tnew_dent    %d, mod_dent     %d\n",
++             req->new_dent, req->mod_dent);
++      printk(KERN_DEBUG "\tidx_growth  %d\n", req->idx_growth);
++      printk(KERN_DEBUG "\tdata_growth %d dd_growth     %d\n",
++             req->data_growth, req->dd_growth);
++      spin_unlock(&dbg_lock);
++}
++
++void dbg_dump_lstats(const struct ubifs_lp_stats *lst)
++{
++      spin_lock(&dbg_lock);
++      printk(KERN_DEBUG "Lprops statistics: empty_lebs %d, idx_lebs  %d\n",
++             lst->empty_lebs, lst->idx_lebs);
++      printk(KERN_DEBUG "\ttaken_empty_lebs %d, total_free %lld, "
++             "total_dirty %lld\n", lst->taken_empty_lebs, lst->total_free,
++             lst->total_dirty);
++      printk(KERN_DEBUG "\ttotal_used %lld, total_dark %lld, "
++             "total_dead %lld\n", lst->total_used, lst->total_dark,
++             lst->total_dead);
++      spin_unlock(&dbg_lock);
++}
++
++void dbg_dump_budg(struct ubifs_info *c)
++{
++      int i;
++      struct rb_node *rb;
++      struct ubifs_bud *bud;
++      struct ubifs_gced_idx_leb *idx_gc;
++
++      spin_lock(&dbg_lock);
++      printk(KERN_DEBUG "Budgeting info: budg_data_growth %lld, "
++             "budg_dd_growth %lld, budg_idx_growth %lld\n",
++             c->budg_data_growth, c->budg_dd_growth, c->budg_idx_growth);
++      printk(KERN_DEBUG "\tdata budget sum %lld, total budget sum %lld, "
++             "freeable_cnt %d\n", c->budg_data_growth + c->budg_dd_growth,
++             c->budg_data_growth + c->budg_dd_growth + c->budg_idx_growth,
++             c->freeable_cnt);
++      printk(KERN_DEBUG "\tmin_idx_lebs %d, old_idx_sz %lld, "
++             "calc_idx_sz %lld, idx_gc_cnt %d\n", c->min_idx_lebs,
++             c->old_idx_sz, c->calc_idx_sz, c->idx_gc_cnt);
++      printk(KERN_DEBUG "\tdirty_pg_cnt %ld, dirty_ino_cnt %ld, "
++             "dirty_zn_cnt %ld, clean_zn_cnt %ld\n",
++             atomic_long_read(&c->dirty_pg_cnt),
++             atomic_long_read(&c->dirty_ino_cnt),
++             atomic_long_read(&c->dirty_zn_cnt),
++             atomic_long_read(&c->clean_zn_cnt));
++      printk(KERN_DEBUG "\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n",
++             c->dark_wm, c->dead_wm, c->max_idx_node_sz);
++      printk(KERN_DEBUG "\tgc_lnum %d, ihead_lnum %d\n",
++             c->gc_lnum, c->ihead_lnum);
++      for (i = 0; i < c->jhead_cnt; i++)
++              printk(KERN_DEBUG "\tjhead %d\t LEB %d\n",
++                     c->jheads[i].wbuf.jhead, c->jheads[i].wbuf.lnum);
++      for (rb = rb_first(&c->buds); rb; rb = rb_next(rb)) {
++              bud = rb_entry(rb, struct ubifs_bud, rb);
++              printk(KERN_DEBUG "\tbud LEB %d\n", bud->lnum);
++      }
++      list_for_each_entry(bud, &c->old_buds, list)
++              printk(KERN_DEBUG "\told bud LEB %d\n", bud->lnum);
++      list_for_each_entry(idx_gc, &c->idx_gc, list)
++              printk(KERN_DEBUG "\tGC'ed idx LEB %d unmap %d\n",
++                     idx_gc->lnum, idx_gc->unmap);
++      printk(KERN_DEBUG "\tcommit state %d\n", c->cmt_state);
++      spin_unlock(&dbg_lock);
++}
++
++void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
++{
++      printk(KERN_DEBUG "LEB %d lprops: free %d, dirty %d (used %d), "
++             "flags %#x\n", lp->lnum, lp->free, lp->dirty,
++             c->leb_size - lp->free - lp->dirty, lp->flags);
++}
++
++void dbg_dump_lprops(struct ubifs_info *c)
++{
++      int lnum, err;
++      struct ubifs_lprops lp;
++      struct ubifs_lp_stats lst;
++
++      printk(KERN_DEBUG "Dumping LEB properties\n");
++      ubifs_get_lp_stats(c, &lst);
++      dbg_dump_lstats(&lst);
++
++      for (lnum = c->main_first; lnum < c->leb_cnt; lnum++) {
++              err = ubifs_read_one_lp(c, lnum, &lp);
++              if (err)
++                      ubifs_err("cannot read lprops for LEB %d", lnum);
++
++              dbg_dump_lprop(c, &lp);
++      }
++}
++
++void dbg_dump_leb(const struct ubifs_info *c, int lnum)
++{
++      struct ubifs_scan_leb *sleb;
++      struct ubifs_scan_node *snod;
++
++      if (dbg_failure_mode)
++              return;
++
++      printk(KERN_DEBUG "Dumping LEB %d\n", lnum);
++
++      sleb = ubifs_scan(c, lnum, 0, c->dbg_buf);
++      if (IS_ERR(sleb)) {
++              ubifs_err("scan error %d", (int)PTR_ERR(sleb));
++              return;
++      }
++
++      printk(KERN_DEBUG "LEB %d has %d nodes ending at %d\n", lnum,
++             sleb->nodes_cnt, sleb->endpt);
++
++      list_for_each_entry(snod, &sleb->nodes, list) {
++              cond_resched();
++              printk(KERN_DEBUG "Dumping node at LEB %d:%d len %d\n", lnum,
++                     snod->offs, snod->len);
++              dbg_dump_node(c, snod->node);
++      }
++
++      ubifs_scan_destroy(sleb);
++      return;
++}
++
++void dbg_dump_znode(const struct ubifs_info *c,
++                  const struct ubifs_znode *znode)
++{
++      int n;
++      const struct ubifs_zbranch *zbr;
++
++      spin_lock(&dbg_lock);
++      if (znode->parent)
++              zbr = &znode->parent->zbranch[znode->iip];
++      else
++              zbr = &c->zroot;
++
++      printk(KERN_DEBUG "znode %p, LEB %d:%d len %d parent %p iip %d level %d"
++             " child_cnt %d flags %lx\n", znode, zbr->lnum, zbr->offs,
++             zbr->len, znode->parent, znode->iip, znode->level,
++             znode->child_cnt, znode->flags);
++
++      if (znode->child_cnt <= 0 || znode->child_cnt > c->fanout) {
++              spin_unlock(&dbg_lock);
++              return;
++      }
++
++      printk(KERN_DEBUG "zbranches:\n");
++      for (n = 0; n < znode->child_cnt; n++) {
++              zbr = &znode->zbranch[n];
++              if (znode->level > 0)
++                      printk(KERN_DEBUG "\t%d: znode %p LEB %d:%d len %d key "
++                                        "%s\n", n, zbr->znode, zbr->lnum,
++                                        zbr->offs, zbr->len,
++                                        DBGKEY(&zbr->key));
++              else
++                      printk(KERN_DEBUG "\t%d: LNC %p LEB %d:%d len %d key "
++                                        "%s\n", n, zbr->znode, zbr->lnum,
++                                        zbr->offs, zbr->len,
++                                        DBGKEY(&zbr->key));
++      }
++      spin_unlock(&dbg_lock);
++}
++
++void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat)
++{
++      int i;
++
++      printk(KERN_DEBUG "Dumping heap cat %d (%d elements)\n",
++             cat, heap->cnt);
++      for (i = 0; i < heap->cnt; i++) {
++              struct ubifs_lprops *lprops = heap->arr[i];
++
++              printk(KERN_DEBUG "\t%d. LEB %d hpos %d free %d dirty %d "
++                     "flags %d\n", i, lprops->lnum, lprops->hpos,
++                     lprops->free, lprops->dirty, lprops->flags);
++      }
++}
++
++void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
++                  struct ubifs_nnode *parent, int iip)
++{
++      int i;
++
++      printk(KERN_DEBUG "Dumping pnode:\n");
++      printk(KERN_DEBUG "\taddress %zx parent %zx cnext %zx\n",
++             (size_t)pnode, (size_t)parent, (size_t)pnode->cnext);
++      printk(KERN_DEBUG "\tflags %lu iip %d level %d num %d\n",
++             pnode->flags, iip, pnode->level, pnode->num);
++      for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
++              struct ubifs_lprops *lp = &pnode->lprops[i];
++
++              printk(KERN_DEBUG "\t%d: free %d dirty %d flags %d lnum %d\n",
++                     i, lp->free, lp->dirty, lp->flags, lp->lnum);
++      }
++}
++
++void dbg_dump_tnc(struct ubifs_info *c)
++{
++      struct ubifs_znode *znode;
++      int level;
++
++      printk(KERN_DEBUG "\n");
++      printk(KERN_DEBUG "Dumping the TNC tree\n");
++      znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL);
++      level = znode->level;
++      printk(KERN_DEBUG "== Level %d ==\n", level);
++      while (znode) {
++              if (level != znode->level) {
++                      level = znode->level;
++                      printk(KERN_DEBUG "== Level %d ==\n", level);
++              }
++              dbg_dump_znode(c, znode);
++              znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode);
++      }
++
++      printk(KERN_DEBUG "\n");
++}
++
++static int dump_znode(struct ubifs_info *c, struct ubifs_znode *znode,
++                    void *priv)
++{
++      dbg_dump_znode(c, znode);
++      return 0;
++}
++
++/**
++ * dbg_dump_index - dump the on-flash index.
++ * @c: UBIFS file-system description object
++ *
++ * This function dumps whole UBIFS indexing B-tree, unlike 'dbg_dump_tnc()'
++ * which dumps only in-memory znodes and does not read znodes which from flash.
++ */
++void dbg_dump_index(struct ubifs_info *c)
++{
++      dbg_walk_index(c, NULL, dump_znode, NULL);
++}
++
++/*
++ * dbg_check_dir - check directory inode size and link count.
++ * @c: UBIFS file-system description object
++ * @dir: the directory to calculate size for
++ * @size: the result is returned here
++ *
++ * This function makes sure that directory size and link count are correct.
++ * Returns zero in case of success and a negative error code in case of
++ * failure.
++ *
++ * Note, it is good idea to make sure the @dir->i_mutex is locked before
++ * calling this function.
++ */
++int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir)
++{
++      unsigned int nlink = 2;
++      union ubifs_key key;
++      struct ubifs_dent_node *dent, *pdent = NULL;
++      struct qstr nm = { .name = NULL };
++      loff_t size = UBIFS_INO_NODE_SZ;
++
++      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++              return 0;
++
++      if (!S_ISDIR(dir->i_mode))
++              return 0;
++
++      lowest_dent_key(c, &key, dir->i_ino);
++      while (1) {
++              int err;
++
++              dent = ubifs_tnc_next_ent(c, &key, &nm);
++              if (IS_ERR(dent)) {
++                      err = PTR_ERR(dent);
++                      if (err == -ENOENT)
++                              break;
++                      return err;
++              }
++
++              nm.name = dent->name;
++              nm.len = le16_to_cpu(dent->nlen);
++              size += CALC_DENT_SIZE(nm.len);
++              if (dent->type == UBIFS_ITYPE_DIR)
++                      nlink += 1;
++              kfree(pdent);
++              pdent = dent;
++              key_read(c, &dent->key, &key);
++      }
++      kfree(pdent);
++
++      if (i_size_read(dir) != size) {
++              ubifs_err("directory inode %lu has size %llu, "
++                        "but calculated size is %llu", dir->i_ino,
++                        (unsigned long long)i_size_read(dir),
++                        (unsigned long long)size);
++              dump_stack();
++              return -EINVAL;
++      }
++      if (dir->i_nlink != nlink) {
++              ubifs_err("directory inode %lu has nlink %u, but calculated "
++                        "nlink is %u", dir->i_ino, dir->i_nlink, nlink);
++              dump_stack();
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
++/**
++ * dbg_check_key_order - make sure that colliding keys are properly ordered.
++ * @c: UBIFS file-system description object
++ * @zbr1: first zbranch
++ * @zbr1: following zbranch
++ *
++ * In UBIFS indexing B-tree colliding keys has to be sorted in binary order of
++ * names of the direntries/xentries which are referred by the keys. This
++ * function reads direntries/xentries referred by @zbr1 and @zbr2 and makes
++ * sure the name of direntry/xentry referred by @zbr1 is less than
++ * direntry/xentry referred by @zbr2. Returns zero if this is true, %1 if not,
++ * and a negative error code in case of failure.
++ */
++static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
++                             struct ubifs_zbranch *zbr2)
++{
++      int err, nlen1, nlen2, cmp;
++      struct ubifs_dent_node *dent1, *dent2;
++      union ubifs_key key;
++
++      ubifs_assert(!keys_cmp(c, &zbr1->key, &zbr2->key));
++      dent1 = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
++      if (!dent1)
++              return -ENOMEM;
++      dent2 = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
++      if (!dent2) {
++              err = -ENOMEM;
++              goto out_free;
++      }
++
++      err = ubifs_tnc_read_node(c, zbr1, dent1);
++      if (err)
++              goto out_free;
++      err = ubifs_validate_entry(c, dent1);
++      if (err)
++              goto out_free;
++
++      err = ubifs_tnc_read_node(c, zbr2, dent2);
++      if (err)
++              goto out_free;
++      err = ubifs_validate_entry(c, dent2);
++      if (err)
++              goto out_free;
++
++      /* Make sure node keys are the same as in zbranch */
++      err = 1;
++      key_read(c, &dent1->key, &key);
++      if (keys_cmp(c, &zbr1->key, &key)) {
++              dbg_err("1st entry at %d:%d has key %s", zbr1->lnum,
++                      zbr1->offs, DBGKEY(&key));
++              dbg_err("but it should have key %s according to tnc",
++                      DBGKEY(&zbr1->key));
++                      dbg_dump_node(c, dent1);
++                      goto out_free;
++      }
++
++      key_read(c, &dent2->key, &key);
++      if (keys_cmp(c, &zbr2->key, &key)) {
++              dbg_err("2nd entry at %d:%d has key %s", zbr1->lnum,
++                      zbr1->offs, DBGKEY(&key));
++              dbg_err("but it should have key %s according to tnc",
++                      DBGKEY(&zbr2->key));
++                      dbg_dump_node(c, dent2);
++                      goto out_free;
++      }
++
++      nlen1 = le16_to_cpu(dent1->nlen);
++      nlen2 = le16_to_cpu(dent2->nlen);
++
++      cmp = memcmp(dent1->name, dent2->name, min_t(int, nlen1, nlen2));
++      if (cmp < 0 || (cmp == 0 && nlen1 < nlen2)) {
++              err = 0;
++              goto out_free;
++      }
++      if (cmp == 0 && nlen1 == nlen2)
++              dbg_err("2 xent/dent nodes with the same name");
++      else
++              dbg_err("bad order of colliding key %s",
++                      DBGKEY(&key));
++
++      dbg_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs);
++      dbg_dump_node(c, dent1);
++      dbg_msg("second node at %d:%d\n", zbr2->lnum, zbr2->offs);
++      dbg_dump_node(c, dent2);
++
++out_free:
++      kfree(dent2);
++      kfree(dent1);
++      return err;
++}
++
++/**
++ * dbg_check_znode - check if znode is all right.
++ * @c: UBIFS file-system description object
++ * @zbr: zbranch which points to this znode
++ *
++ * This function makes sure that znode referred to by @zbr is all right.
++ * Returns zero if it is, and %-EINVAL if it is not.
++ */
++static int dbg_check_znode(struct ubifs_info *c, struct ubifs_zbranch *zbr)
++{
++      struct ubifs_znode *znode = zbr->znode;
++      struct ubifs_znode *zp = znode->parent;
++      int n, err, cmp;
++
++      if (znode->child_cnt <= 0 || znode->child_cnt > c->fanout) {
++              err = 1;
++              goto out;
++      }
++      if (znode->level < 0) {
++              err = 2;
++              goto out;
++      }
++      if (znode->iip < 0 || znode->iip >= c->fanout) {
++              err = 3;
++              goto out;
++      }
++
++      if (zbr->len == 0)
++              /* Only dirty zbranch may have no on-flash nodes */
++              if (!ubifs_zn_dirty(znode)) {
++                      err = 4;
++                      goto out;
++              }
++
++      if (ubifs_zn_dirty(znode)) {
++              /*
++               * If znode is dirty, its parent has to be dirty as well. The
++               * order of the operation is important, so we have to have
++               * memory barriers.
++               */
++              smp_mb();
++              if (zp && !ubifs_zn_dirty(zp)) {
++                      /*
++                       * The dirty flag is atomic and is cleared outside the
++                       * TNC mutex, so znode's dirty flag may now have
++                       * been cleared. The child is always cleared before the
++                       * parent, so we just need to check again.
++                       */
++                      smp_mb();
++                      if (ubifs_zn_dirty(znode)) {
++                              err = 5;
++                              goto out;
++                      }
++              }
++      }
++
++      if (zp) {
++              const union ubifs_key *min, *max;
++
++              if (znode->level != zp->level - 1) {
++                      err = 6;
++                      goto out;
++              }
++
++              /* Make sure the 'parent' pointer in our znode is correct */
++              err = ubifs_search_zbranch(c, zp, &zbr->key, &n);
++              if (!err) {
++                      /* This zbranch does not exist in the parent */
++                      err = 7;
++                      goto out;
++              }
++
++              if (znode->iip >= zp->child_cnt) {
++                      err = 8;
++                      goto out;
++              }
++
++              if (znode->iip != n) {
++                      /* This may happen only in case of collisions */
++                      if (keys_cmp(c, &zp->zbranch[n].key,
++                                   &zp->zbranch[znode->iip].key)) {
++                              err = 9;
++                              goto out;
++                      }
++                      n = znode->iip;
++              }
++
++              /*
++               * Make sure that the first key in our znode is greater than or
++               * equal to the key in the pointing zbranch.
++               */
++              min = &zbr->key;
++              cmp = keys_cmp(c, min, &znode->zbranch[0].key);
++              if (cmp == 1) {
++                      err = 10;
++                      goto out;
++              }
++
++              if (n + 1 < zp->child_cnt) {
++                      max = &zp->zbranch[n + 1].key;
++
++                      /*
++                       * Make sure the last key in our znode is less or
++                       * equivalent than the the key in zbranch which goes
++                       * after our pointing zbranch.
++                       */
++                      cmp = keys_cmp(c, max,
++                              &znode->zbranch[znode->child_cnt - 1].key);
++                      if (cmp == -1) {
++                              err = 11;
++                              goto out;
++                      }
++              }
++      } else {
++              /* This may only be root znode */
++              if (zbr != &c->zroot) {
++                      err = 12;
++                      goto out;
++              }
++      }
++
++      /*
++       * Make sure that next key is greater or equivalent then the previous
++       * one.
++       */
++      for (n = 1; n < znode->child_cnt; n++) {
++              cmp = keys_cmp(c, &znode->zbranch[n - 1].key,
++                             &znode->zbranch[n].key);
++              if (cmp > 0) {
++                      err = 13;
++                      goto out;
++              }
++              if (cmp == 0) {
++                      /* This can only be keys with colliding hash */
++                      if (!is_hash_key(c, &znode->zbranch[n].key)) {
++                              err = 14;
++                              goto out;
++                      }
++
++                      if (znode->level != 0 || c->replaying)
++                              continue;
++
++                      /*
++                       * Colliding keys should follow binary order of
++                       * corresponding xentry/dentry names.
++                       */
++                      err = dbg_check_key_order(c, &znode->zbranch[n - 1],
++                                                &znode->zbranch[n]);
++                      if (err < 0)
++                              return err;
++                      if (err) {
++                              err = 15;
++                              goto out;
++                      }
++              }
++      }
++
++      for (n = 0; n < znode->child_cnt; n++) {
++              if (!znode->zbranch[n].znode &&
++                  (znode->zbranch[n].lnum == 0 ||
++                   znode->zbranch[n].len == 0)) {
++                      err = 16;
++                      goto out;
++              }
++
++              if (znode->zbranch[n].lnum != 0 &&
++                  znode->zbranch[n].len == 0) {
++                      err = 17;
++                      goto out;
++              }
++
++              if (znode->zbranch[n].lnum == 0 &&
++                  znode->zbranch[n].len != 0) {
++                      err = 18;
++                      goto out;
++              }
++
++              if (znode->zbranch[n].lnum == 0 &&
++                  znode->zbranch[n].offs != 0) {
++                      err = 19;
++                      goto out;
++              }
++
++              if (znode->level != 0 && znode->zbranch[n].znode)
++                      if (znode->zbranch[n].znode->parent != znode) {
++                              err = 20;
++                              goto out;
++                      }
++      }
++
++      return 0;
++
++out:
++      ubifs_err("failed, error %d", err);
++      ubifs_msg("dump of the znode");
++      dbg_dump_znode(c, znode);
++      if (zp) {
++              ubifs_msg("dump of the parent znode");
++              dbg_dump_znode(c, zp);
++      }
++      dump_stack();
++      return -EINVAL;
++}
++
++/**
++ * dbg_check_tnc - check TNC tree.
++ * @c: UBIFS file-system description object
++ * @extra: do extra checks that are possible at start commit
++ *
++ * This function traverses whole TNC tree and checks every znode. Returns zero
++ * if everything is all right and %-EINVAL if something is wrong with TNC.
++ */
++int dbg_check_tnc(struct ubifs_info *c, int extra)
++{
++      struct ubifs_znode *znode;
++      long clean_cnt = 0, dirty_cnt = 0;
++      int err, last;
++
++      if (!(ubifs_chk_flags & UBIFS_CHK_TNC))
++              return 0;
++
++      ubifs_assert(mutex_is_locked(&c->tnc_mutex));
++      if (!c->zroot.znode)
++              return 0;
++
++      znode = ubifs_tnc_postorder_first(c->zroot.znode);
++      while (1) {
++              struct ubifs_znode *prev;
++              struct ubifs_zbranch *zbr;
++
++              if (!znode->parent)
++                      zbr = &c->zroot;
++              else
++                      zbr = &znode->parent->zbranch[znode->iip];
++
++              err = dbg_check_znode(c, zbr);
++              if (err)
++                      return err;
++
++              if (extra) {
++                      if (ubifs_zn_dirty(znode))
++                              dirty_cnt += 1;
++                      else
++                              clean_cnt += 1;
++              }
++
++              prev = znode;
++              znode = ubifs_tnc_postorder_next(znode);
++              if (!znode)
++                      break;
++
++              /*
++               * If the last key of this znode is equivalent to the first key
++               * of the next znode (collision), then check order of the keys.
++               */
++              last = prev->child_cnt - 1;
++              if (prev->level == 0 && znode->level == 0 && !c->replaying &&
++                  !keys_cmp(c, &prev->zbranch[last].key,
++                            &znode->zbranch[0].key)) {
++                      err = dbg_check_key_order(c, &prev->zbranch[last],
++                                                &znode->zbranch[0]);
++                      if (err < 0)
++                              return err;
++                      if (err) {
++                              ubifs_msg("first znode");
++                              dbg_dump_znode(c, prev);
++                              ubifs_msg("second znode");
++                              dbg_dump_znode(c, znode);
++                              return -EINVAL;
++                      }
++              }
++      }
++
++      if (extra) {
++              if (clean_cnt != atomic_long_read(&c->clean_zn_cnt)) {
++                      ubifs_err("incorrect clean_zn_cnt %ld, calculated %ld",
++                                atomic_long_read(&c->clean_zn_cnt),
++                                clean_cnt);
++                      return -EINVAL;
++              }
++              if (dirty_cnt != atomic_long_read(&c->dirty_zn_cnt)) {
++                      ubifs_err("incorrect dirty_zn_cnt %ld, calculated %ld",
++                                atomic_long_read(&c->dirty_zn_cnt),
++                                dirty_cnt);
++                      return -EINVAL;
++              }
++      }
++
++      return 0;
++}
++
++/**
++ * dbg_walk_index - walk the on-flash index.
++ * @c: UBIFS file-system description object
++ * @leaf_cb: called for each leaf node
++ * @znode_cb: called for each indexing node
++ * @priv: private date which is passed to callbacks
++ *
++ * This function walks the UBIFS index and calls the @leaf_cb for each leaf
++ * node and @znode_cb for each indexing node. Returns zero in case of success
++ * and a negative error code in case of failure.
++ *
++ * It would be better if this function removed every znode it pulled to into
++ * the TNC, so that the behavior more closely matched the non-debugging
++ * behavior.
++ */
++int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb,
++                 dbg_znode_callback znode_cb, void *priv)
++{
++      int err;
++      struct ubifs_zbranch *zbr;
++      struct ubifs_znode *znode, *child;
++
++      mutex_lock(&c->tnc_mutex);
++      /* If the root indexing node is not in TNC - pull it */
++      if (!c->zroot.znode) {
++              c->zroot.znode = ubifs_load_znode(c, &c->zroot, NULL, 0);
++              if (IS_ERR(c->zroot.znode)) {
++                      err = PTR_ERR(c->zroot.znode);
++                      c->zroot.znode = NULL;
++                      goto out_unlock;
++              }
++      }
++
++      /*
++       * We are going to traverse the indexing tree in the postorder manner.
++       * Go down and find the leftmost indexing node where we are going to
++       * start from.
++       */
++      znode = c->zroot.znode;
++      while (znode->level > 0) {
++              zbr = &znode->zbranch[0];
++              child = zbr->znode;
++              if (!child) {
++                      child = ubifs_load_znode(c, zbr, znode, 0);
++                      if (IS_ERR(child)) {
++                              err = PTR_ERR(child);
++                              goto out_unlock;
++                      }
++                      zbr->znode = child;
++              }
++
++              znode = child;
++      }
++
++      /* Iterate over all indexing nodes */
++      while (1) {
++              int idx;
++
++              cond_resched();
++
++              if (znode_cb) {
++                      err = znode_cb(c, znode, priv);
++                      if (err) {
++                              ubifs_err("znode checking function returned "
++                                        "error %d", err);
++                              dbg_dump_znode(c, znode);
++                              goto out_dump;
++                      }
++              }
++              if (leaf_cb && znode->level == 0) {
++                      for (idx = 0; idx < znode->child_cnt; idx++) {
++                              zbr = &znode->zbranch[idx];
++                              err = leaf_cb(c, zbr, priv);
++                              if (err) {
++                                      ubifs_err("leaf checking function "
++                                                "returned error %d, for leaf "
++                                                "at LEB %d:%d",
++                                                err, zbr->lnum, zbr->offs);
++                                      goto out_dump;
++                              }
++                      }
++              }
++
++              if (!znode->parent)
++                      break;
++
++              idx = znode->iip + 1;
++              znode = znode->parent;
++              if (idx < znode->child_cnt) {
++                      /* Switch to the next index in the parent */
++                      zbr = &znode->zbranch[idx];
++                      child = zbr->znode;
++                      if (!child) {
++                              child = ubifs_load_znode(c, zbr, znode, idx);
++                              if (IS_ERR(child)) {
++                                      err = PTR_ERR(child);
++                                      goto out_unlock;
++                              }
++                              zbr->znode = child;
++                      }
++                      znode = child;
++              } else
++                      /*
++                       * This is the last child, switch to the parent and
++                       * continue.
++                       */
++                      continue;
++
++              /* Go to the lowest leftmost znode in the new sub-tree */
++              while (znode->level > 0) {
++                      zbr = &znode->zbranch[0];
++                      child = zbr->znode;
++                      if (!child) {
++                              child = ubifs_load_znode(c, zbr, znode, 0);
++                              if (IS_ERR(child)) {
++                                      err = PTR_ERR(child);
++                                      goto out_unlock;
++                              }
++                              zbr->znode = child;
++                      }
++                      znode = child;
++              }
++      }
++
++      mutex_unlock(&c->tnc_mutex);
++      return 0;
++
++out_dump:
++      if (znode->parent)
++              zbr = &znode->parent->zbranch[znode->iip];
++      else
++              zbr = &c->zroot;
++      ubifs_msg("dump of znode at LEB %d:%d", zbr->lnum, zbr->offs);
++      dbg_dump_znode(c, znode);
++out_unlock:
++      mutex_unlock(&c->tnc_mutex);
++      return err;
++}
++
++/**
++ * add_size - add znode size to partially calculated index size.
++ * @c: UBIFS file-system description object
++ * @znode: znode to add size for
++ * @priv: partially calculated index size
++ *
++ * This is a helper function for 'dbg_check_idx_size()' which is called for
++ * every indexing node and adds its size to the 'long long' variable pointed to
++ * by @priv.
++ */
++static int add_size(struct ubifs_info *c, struct ubifs_znode *znode, void *priv)
++{
++      long long *idx_size = priv;
++      int add;
++
++      add = ubifs_idx_node_sz(c, znode->child_cnt);
++      add = ALIGN(add, 8);
++      *idx_size += add;
++      return 0;
++}
++
++/**
++ * dbg_check_idx_size - check index size.
++ * @c: UBIFS file-system description object
++ * @idx_size: size to check
++ *
++ * This function walks the UBIFS index, calculates its size and checks that the
++ * size is equivalent to @idx_size. Returns zero in case of success and a
++ * negative error code in case of failure.
++ */
++int dbg_check_idx_size(struct ubifs_info *c, long long idx_size)
++{
++      int err;
++      long long calc = 0;
++
++      if (!(ubifs_chk_flags & UBIFS_CHK_IDX_SZ))
++              return 0;
++
++      err = dbg_walk_index(c, NULL, add_size, &calc);
++      if (err) {
++              ubifs_err("error %d while walking the index", err);
++              return err;
++      }
++
++      if (calc != idx_size) {
++              ubifs_err("index size check failed: calculated size is %lld, "
++                        "should be %lld", calc, idx_size);
++              dump_stack();
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
++/**
++ * fsck_inode - information about an inode used when checking the file-system.
++ * @rb: link in the RB-tree of inodes
++ * @inum: inode number
++ * @mode: inode type, permissions, etc
++ * @nlink: inode link count
++ * @xatt_cnt: count of extended attributes
++ * @references: how many directory/xattr entries refer this inode (calculated
++ *              while walking the index)
++ * @calc_cnt: for directory inode count of child directories, for regular files
++ *            count of extended attributes
++ * @size: inode size (read from on-flash inode)
++ * @xattr_sz: summary size of all extended attributes (read from on-flash
++ *            inode)
++ * @calc_sz: for directories calculated directory size, for regular files
++ *           calculated summary size of all extended attributes
++ */
++struct fsck_inode {
++      struct rb_node rb;
++      ino_t inum;
++      umode_t mode;
++      int nlink;
++      int xattr_cnt;
++      int references;
++      int calc_cnt;
++      long long size;
++      long long xattr_sz;
++      long long calc_sz;
++};
++
++/**
++ * fsck_data - private FS checking information.
++ * @inodes: RB-tree of all inodes (contains @struct fsck_inode objects)
++ */
++struct fsck_data {
++      struct rb_root inodes;
++};
++
++/**
++ * add_inode - add inode information to RB-tree of inodes.
++ * @c: UBIFS file-system description object
++ * @fsckd: FS checking information
++ * @ino: raw UBIFS inode to add
++ *
++ * This is a helper function for 'check_leaf()' which adds information about
++ * inode @ino to the RB-tree of inodes. Returns inode information pointer in
++ * case of success and a negative error code in case of failure.
++ */
++static struct fsck_inode *add_inode(struct ubifs_info *c,
++                                  struct fsck_data *fsckd,
++                                  struct ubifs_ino_node *ino)
++{
++      struct rb_node **p, *parent = NULL;
++      struct fsck_inode *fscki;
++      ino_t inum = key_inum_flash(c, &ino->key);
++
++      p = &fsckd->inodes.rb_node;
++      while (*p) {
++              parent = *p;
++              fscki = rb_entry(parent, struct fsck_inode, rb);
++              if (inum < fscki->inum)
++                      p = &(*p)->rb_left;
++              else if (inum > fscki->inum)
++                      p = &(*p)->rb_right;
++              else
++                      return fscki;
++      }
++
++      fscki = kzalloc(sizeof(struct fsck_inode), GFP_NOFS);
++      if (!fscki)
++              return ERR_PTR(-ENOMEM);
++
++      fscki->inum = inum;
++      fscki->nlink = le32_to_cpu(ino->nlink);
++      fscki->size = le64_to_cpu(ino->size);
++      fscki->xattr_cnt = le32_to_cpu(ino->xattr_cnt);
++      fscki->xattr_sz = le64_to_cpu(ino->xattr_size);
++      fscki->mode = le32_to_cpu(ino->mode);
++      if (S_ISDIR(fscki->mode)) {
++              fscki->calc_sz = UBIFS_INO_NODE_SZ;
++              fscki->calc_cnt = 2;
++      }
++      rb_link_node(&fscki->rb, parent, p);
++      rb_insert_color(&fscki->rb, &fsckd->inodes);
++      return fscki;
++}
++
++/**
++ * search_inode - search inode in the RB-tree of inodes.
++ * @fsckd: FS checking information
++ * @inum: inode number to search
++ *
++ * This is a helper function for 'check_leaf()' which searches inode @inum in
++ * the RB-tree of inodes and returns an inode information pointer or %NULL if
++ * the inode was not found.
++ */
++static struct fsck_inode *search_inode(struct fsck_data *fsckd, ino_t inum)
++{
++      struct rb_node *p;
++      struct fsck_inode *fscki;
++
++      p = fsckd->inodes.rb_node;
++      while (p) {
++              fscki = rb_entry(p, struct fsck_inode, rb);
++              if (inum < fscki->inum)
++                      p = p->rb_left;
++              else if (inum > fscki->inum)
++                      p = p->rb_right;
++              else
++                      return fscki;
++      }
++      return NULL;
++}
++
++/**
++ * read_add_inode - read inode node and add it to RB-tree of inodes.
++ * @c: UBIFS file-system description object
++ * @fsckd: FS checking information
++ * @inum: inode number to read
++ *
++ * This is a helper function for 'check_leaf()' which finds inode node @inum in
++ * the index, reads it, and adds it to the RB-tree of inodes. Returns inode
++ * information pointer in case of success and a negative error code in case of
++ * failure.
++ */
++static struct fsck_inode *read_add_inode(struct ubifs_info *c,
++                                       struct fsck_data *fsckd, ino_t inum)
++{
++      int n, err;
++      union ubifs_key key;
++      struct ubifs_znode *znode;
++      struct ubifs_zbranch *zbr;
++      struct ubifs_ino_node *ino;
++      struct fsck_inode *fscki;
++
++      fscki = search_inode(fsckd, inum);
++      if (fscki)
++              return fscki;
++
++      ino_key_init(c, &key, inum);
++      err = ubifs_lookup_level0(c, &key, &znode, &n);
++      if (!err) {
++              ubifs_err("inode %lu not found in index", inum);
++              return ERR_PTR(-ENOENT);
++      } else if (err < 0) {
++              ubifs_err("error %d while looking up inode %lu", err, inum);
++              return ERR_PTR(err);
++      }
++
++      zbr = &znode->zbranch[n];
++      if (zbr->len < UBIFS_INO_NODE_SZ) {
++              ubifs_err("bad node %lu node length %d", inum, zbr->len);
++              return ERR_PTR(-EINVAL);
++      }
++
++      ino = kmalloc(zbr->len, GFP_NOFS);
++      if (!ino)
++              return ERR_PTR(-ENOMEM);
++
++      err = ubifs_tnc_read_node(c, zbr, ino);
++      if (err) {
++              ubifs_err("cannot read inode node at LEB %d:%d, error %d",
++                        zbr->lnum, zbr->offs, err);
++              kfree(ino);
++              return ERR_PTR(err);
++      }
++
++      fscki = add_inode(c, fsckd, ino);
++      kfree(ino);
++      if (IS_ERR(fscki)) {
++              ubifs_err("error %ld while adding inode %lu node",
++                        PTR_ERR(fscki), inum);
++              return fscki;
++      }
++
++      return fscki;
++}
++
++/**
++ * check_leaf - check leaf node.
++ * @c: UBIFS file-system description object
++ * @zbr: zbranch of the leaf node to check
++ * @priv: FS checking information
++ *
++ * This is a helper function for 'dbg_check_filesystem()' which is called for
++ * every single leaf node while walking the indexing tree. It checks that the
++ * leaf node referred from the indexing tree exists, has correct CRC, and does
++ * some other basic validation. This function is also responsible for building
++ * an RB-tree of inodes - it adds all inodes into the RB-tree. It also
++ * calculates reference count, size, etc for each inode in order to later
++ * compare them to the information stored inside the inodes and detect possible
++ * inconsistencies. Returns zero in case of success and a negative error code
++ * in case of failure.
++ */
++static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr,
++                    void *priv)
++{
++      ino_t inum;
++      void *node;
++      int err, type = key_type(c, &zbr->key);
++      struct fsck_inode *fscki;
++
++      if (zbr->len < UBIFS_CH_SZ) {
++              ubifs_err("bad leaf length %d (LEB %d:%d)",
++                        zbr->len, zbr->lnum, zbr->offs);
++              return -EINVAL;
++      }
++
++      node = kmalloc(zbr->len, GFP_NOFS);
++      if (!node)
++              return -ENOMEM;
++
++      err = ubifs_tnc_read_node(c, zbr, node);
++      if (err) {
++              ubifs_err("cannot read leaf node at LEB %d:%d, error %d",
++                        zbr->lnum, zbr->offs, err);
++              goto out_free;
++      }
++
++      /* If this is an inode node, add it to RB-tree of inodes */
++      if (type == UBIFS_INO_KEY) {
++              fscki = add_inode(c, priv, node);
++              if (IS_ERR(fscki)) {
++                      err = PTR_ERR(fscki);
++                      ubifs_err("error %d while adding inode node", err);
++                      goto out_dump;
++              }
++              goto out;
++      }
++
++      if (type != UBIFS_DENT_KEY && type != UBIFS_XENT_KEY &&
++          type != UBIFS_DATA_KEY) {
++              ubifs_err("unexpected node type %d at LEB %d:%d",
++                        type, zbr->lnum, zbr->offs);
++              err = -EINVAL;
++              goto out_free;
++      }
++
++      if (type == UBIFS_DATA_KEY) {
++              long long blk_offs;
++              struct ubifs_data_node *dn = node;
++
++              /*
++               * Search the inode node this data node belongs to and insert
++               * it to the RB-tree of inodes.
++               */
++              inum = key_inum_flash(c, &dn->key);
++              fscki = read_add_inode(c, priv, inum);
++              if (IS_ERR(fscki)) {
++                      err = PTR_ERR(fscki);
++                      ubifs_err("error %d while processing data node and "
++                                "trying to find inode node %lu", err, inum);
++                      goto out_dump;
++              }
++
++              /* Make sure the data node is within inode size */
++              blk_offs = (key_block_flash(c, &dn->key) << UBIFS_BLOCK_SHIFT);
++              blk_offs += le32_to_cpu(dn->size);
++              if (blk_offs > fscki->size) {
++                      ubifs_err("data node at LEB %d:%d is not within inode "
++                                "size %lld", zbr->lnum, zbr->offs, fscki->size);
++                      err = -EINVAL;
++                      goto out_dump;
++              }
++      } else {
++              int nlen;
++              struct ubifs_dent_node *dent = node;
++              struct fsck_inode *fscki1;
++
++              err = ubifs_validate_entry(c, dent);
++              if (err)
++                      goto out_dump;
++
++              /*
++               * Search the inode node this entry refers to and the parent
++               * inode node and insert them to the RB-tree of inodes.
++               */
++              inum = le64_to_cpu(dent->inum);
++              fscki = read_add_inode(c, priv, inum);
++              if (IS_ERR(fscki)) {
++                      err = PTR_ERR(fscki);
++                      ubifs_err("error %d while processing entry node and "
++                                "trying to find inode node %lu", err, inum);
++                      goto out_dump;
++              }
++
++              /* Count how many direntries or xentries refers this inode */
++              fscki->references += 1;
++
++              inum = key_inum_flash(c, &dent->key);
++              fscki1 = read_add_inode(c, priv, inum);
++              if (IS_ERR(fscki1)) {
++                      err = PTR_ERR(fscki);
++                      ubifs_err("error %d while processing entry node and "
++                                "trying to find parent inode node %lu",
++                                err, inum);
++                      goto out_dump;
++              }
++
++              nlen = le16_to_cpu(dent->nlen);
++              if (type == UBIFS_XENT_KEY) {
++                      fscki1->calc_cnt += 1;
++                      fscki1->calc_sz += CALC_DENT_SIZE(nlen);
++                      fscki1->calc_sz += CALC_XATTR_BYTES(fscki->size);
++              } else {
++                      fscki1->calc_sz += CALC_DENT_SIZE(nlen);
++                      if (dent->type == UBIFS_ITYPE_DIR)
++                              fscki1->calc_cnt += 1;
++              }
++      }
++
++out:
++      kfree(node);
++      return 0;
++
++out_dump:
++      ubifs_msg("dump of node at LEB %d:%d", zbr->lnum, zbr->offs);
++      dbg_dump_node(c, node);
++out_free:
++      kfree(node);
++      return err;
++}
++
++/**
++ * free_inodes - free RB-tree of inodes.
++ * @fsckd: FS checking information
++ */
++static void free_inodes(struct fsck_data *fsckd)
++{
++      struct rb_node *this = fsckd->inodes.rb_node;
++      struct fsck_inode *fscki;
++
++      while (this) {
++              if (this->rb_left)
++                      this = this->rb_left;
++              else if (this->rb_right)
++                      this = this->rb_right;
++              else {
++                      fscki = rb_entry(this, struct fsck_inode, rb);
++                      this = rb_parent(this);
++                      if (this) {
++                              if (this->rb_left == &fscki->rb)
++                                      this->rb_left = NULL;
++                              else
++                                      this->rb_right = NULL;
++                      }
++                      kfree(fscki);
++              }
++      }
++}
++
++/**
++ * check_inodes - checks all inodes.
++ * @c: UBIFS file-system description object
++ * @fsckd: FS checking information
++ *
++ * This is a helper function for 'dbg_check_filesystem()' which walks the
++ * RB-tree of inodes after the index scan has been finished, and checks that
++ * inode nlink, size, etc are correct. Returns zero if inodes are fine,
++ * %-EINVAL if not, and a negative error code in case of failure.
++ */
++static int check_inodes(struct ubifs_info *c, struct fsck_data *fsckd)
++{
++      int n, err;
++      union ubifs_key key;
++      struct ubifs_znode *znode;
++      struct ubifs_zbranch *zbr;
++      struct ubifs_ino_node *ino;
++      struct fsck_inode *fscki;
++      struct rb_node *this = rb_first(&fsckd->inodes);
++
++      while (this) {
++              fscki = rb_entry(this, struct fsck_inode, rb);
++              this = rb_next(this);
++
++              if (S_ISDIR(fscki->mode)) {
++                      /*
++                       * Directories have to have exactly one reference (they
++                       * cannot have hardlinks), although root inode is an
++                       * exception.
++                       */
++                      if (fscki->inum != UBIFS_ROOT_INO &&
++                          fscki->references != 1) {
++                              ubifs_err("directory inode %lu has %d "
++                                        "direntries which refer it, but "
++                                        "should be 1", fscki->inum,
++                                        fscki->references);
++                              goto out_dump;
++                      }
++                      if (fscki->inum == UBIFS_ROOT_INO &&
++                          fscki->references != 0) {
++                              ubifs_err("root inode %lu has non-zero (%d) "
++                                        "direntries which refer it",
++                                        fscki->inum, fscki->references);
++                              goto out_dump;
++                      }
++                      if (fscki->calc_sz != fscki->size) {
++                              ubifs_err("directory inode %lu size is %lld, "
++                                        "but calculated size is %lld",
++                                        fscki->inum, fscki->size,
++                                        fscki->calc_sz);
++                              goto out_dump;
++                      }
++                      if (fscki->calc_cnt != fscki->nlink) {
++                              ubifs_err("directory inode %lu nlink is %d, "
++                                        "but calculated nlink is %d",
++                                        fscki->inum, fscki->nlink,
++                                        fscki->calc_cnt);
++                              goto out_dump;
++                      }
++              } else {
++                      if (fscki->references != fscki->nlink) {
++                              ubifs_err("inode %lu nlink is %d, but "
++                                        "calculated nlink is %d", fscki->inum,
++                                        fscki->nlink, fscki->references);
++                              goto out_dump;
++                      }
++                      if (fscki->xattr_sz != fscki->calc_sz) {
++                              ubifs_err("inode %lu has xattr size %lld, but "
++                                        "calculated size is %lld",
++                                        fscki->inum, fscki->xattr_sz,
++                                        fscki->calc_sz);
++                              goto out_dump;
++                      }
++                      if (fscki->xattr_cnt != fscki->calc_cnt) {
++                              ubifs_err("inode %lu has %d xattrs, but "
++                                        "calculated count is %d", fscki->inum,
++                                        fscki->xattr_cnt, fscki->calc_cnt);
++                              goto out_dump;
++                      }
++              }
++      }
++
++      return 0;
++
++out_dump:
++      /* Read the bad inode and dump it */
++      ino_key_init(c, &key, fscki->inum);
++      err = ubifs_lookup_level0(c, &key, &znode, &n);
++      if (!err) {
++              ubifs_err("inode %lu not found in index", fscki->inum);
++              return -ENOENT;
++      } else if (err < 0) {
++              ubifs_err("error %d while looking up inode %lu",
++                        err, fscki->inum);
++              return err;
++      }
++
++      zbr = &znode->zbranch[n];
++      ino = kmalloc(zbr->len, GFP_NOFS);
++      if (!ino)
++              return -ENOMEM;
++
++      err = ubifs_tnc_read_node(c, zbr, ino);
++      if (err) {
++              ubifs_err("cannot read inode node at LEB %d:%d, error %d",
++                        zbr->lnum, zbr->offs, err);
++              kfree(ino);
++              return err;
++      }
++
++      ubifs_msg("dump of the inode %lu sitting in LEB %d:%d",
++                fscki->inum, zbr->lnum, zbr->offs);
++      dbg_dump_node(c, ino);
++      kfree(ino);
++      return -EINVAL;
++}
++
++/**
++ * dbg_check_filesystem - check the file-system.
++ * @c: UBIFS file-system description object
++ *
++ * This function checks the file system, namely:
++ * o makes sure that all leaf nodes exist and their CRCs are correct;
++ * o makes sure inode nlink, size, xattr size/count are correct (for all
++ *   inodes).
++ *
++ * The function reads whole indexing tree and all nodes, so it is pretty
++ * heavy-weight. Returns zero if the file-system is consistent, %-EINVAL if
++ * not, and a negative error code in case of failure.
++ */
++int dbg_check_filesystem(struct ubifs_info *c)
++{
++      int err;
++      struct fsck_data fsckd;
++
++      if (!(ubifs_chk_flags & UBIFS_CHK_FS))
++              return 0;
++
++      fsckd.inodes = RB_ROOT;
++      err = dbg_walk_index(c, check_leaf, NULL, &fsckd);
++      if (err)
++              goto out_free;
++
++      err = check_inodes(c, &fsckd);
++      if (err)
++              goto out_free;
++
++      free_inodes(&fsckd);
++      return 0;
++
++out_free:
++      ubifs_err("file-system check failed with error %d", err);
++      dump_stack();
++      free_inodes(&fsckd);
++      return err;
++}
++
++static int invocation_cnt;
++
++int dbg_force_in_the_gaps(void)
++{
++      if (!dbg_force_in_the_gaps_enabled)
++              return 0;
++      /* Force in-the-gaps every 8th commit */
++      return !((invocation_cnt++) & 0x7);
++}
++
++/* Failure mode for recovery testing */
++
++#define chance(n, d) (simple_rand() <= (n) * 32768LL / (d))
++
++struct failure_mode_info {
++      struct list_head list;
++      struct ubifs_info *c;
++};
++
++static LIST_HEAD(fmi_list);
++static DEFINE_SPINLOCK(fmi_lock);
++
++static unsigned int next;
++
++static int simple_rand(void)
++{
++      if (next == 0)
++              next = current->pid;
++      next = next * 1103515245 + 12345;
++      return (next >> 16) & 32767;
++}
++
++void dbg_failure_mode_registration(struct ubifs_info *c)
++{
++      struct failure_mode_info *fmi;
++
++      fmi = kmalloc(sizeof(struct failure_mode_info), GFP_NOFS);
++      if (!fmi) {
++              dbg_err("Failed to register failure mode - no memory");
++              return;
++      }
++      fmi->c = c;
++      spin_lock(&fmi_lock);
++      list_add_tail(&fmi->list, &fmi_list);
++      spin_unlock(&fmi_lock);
++}
++
++void dbg_failure_mode_deregistration(struct ubifs_info *c)
++{
++      struct failure_mode_info *fmi, *tmp;
++
++      spin_lock(&fmi_lock);
++      list_for_each_entry_safe(fmi, tmp, &fmi_list, list)
++              if (fmi->c == c) {
++                      list_del(&fmi->list);
++                      kfree(fmi);
++              }
++      spin_unlock(&fmi_lock);
++}
++
++static struct ubifs_info *dbg_find_info(struct ubi_volume_desc *desc)
++{
++      struct failure_mode_info *fmi;
++
++      spin_lock(&fmi_lock);
++      list_for_each_entry(fmi, &fmi_list, list)
++              if (fmi->c->ubi == desc) {
++                      struct ubifs_info *c = fmi->c;
++
++                      spin_unlock(&fmi_lock);
++                      return c;
++              }
++      spin_unlock(&fmi_lock);
++      return NULL;
++}
++
++static int in_failure_mode(struct ubi_volume_desc *desc)
++{
++      struct ubifs_info *c = dbg_find_info(desc);
++
++      if (c)
++              return c->failure_mode;
++      return 0;
++}
++
++static int do_fail(struct ubi_volume_desc *desc, int lnum, int write)
++{
++      struct ubifs_info *c = dbg_find_info(desc);
++
++      if (!c || !dbg_failure_mode)
++              return 0;
++      if (c->failure_mode)
++              return 1;
++      if (!c->fail_cnt) {
++              /* First call - decide delay to failure */
++              if (chance(1, 2)) {
++                      unsigned int delay = 1 << (simple_rand() >> 11);
++
++                      if (chance(1, 2)) {
++                              c->fail_delay = 1;
++                              c->fail_timeout = jiffies +
++                                                msecs_to_jiffies(delay);
++                              dbg_rcvry("failing after %ums", delay);
++                      } else {
++                              c->fail_delay = 2;
++                              c->fail_cnt_max = delay;
++                              dbg_rcvry("failing after %u calls", delay);
++                      }
++              }
++              c->fail_cnt += 1;
++      }
++      /* Determine if failure delay has expired */
++      if (c->fail_delay == 1) {
++              if (time_before(jiffies, c->fail_timeout))
++                      return 0;
++      } else if (c->fail_delay == 2)
++              if (c->fail_cnt++ < c->fail_cnt_max)
++                      return 0;
++      if (lnum == UBIFS_SB_LNUM) {
++              if (write) {
++                      if (chance(1, 2))
++                              return 0;
++              } else if (chance(19, 20))
++                      return 0;
++              dbg_rcvry("failing in super block LEB %d", lnum);
++      } else if (lnum == UBIFS_MST_LNUM || lnum == UBIFS_MST_LNUM + 1) {
++              if (chance(19, 20))
++                      return 0;
++              dbg_rcvry("failing in master LEB %d", lnum);
++      } else if (lnum >= UBIFS_LOG_LNUM && lnum <= c->log_last) {
++              if (write) {
++                      if (chance(99, 100))
++                              return 0;
++              } else if (chance(399, 400))
++                      return 0;
++              dbg_rcvry("failing in log LEB %d", lnum);
++      } else if (lnum >= c->lpt_first && lnum <= c->lpt_last) {
++              if (write) {
++                      if (chance(7, 8))
++                              return 0;
++              } else if (chance(19, 20))
++                      return 0;
++              dbg_rcvry("failing in LPT LEB %d", lnum);
++      } else if (lnum >= c->orph_first && lnum <= c->orph_last) {
++              if (write) {
++                      if (chance(1, 2))
++                              return 0;
++              } else if (chance(9, 10))
++                      return 0;
++              dbg_rcvry("failing in orphan LEB %d", lnum);
++      } else if (lnum == c->ihead_lnum) {
++              if (chance(99, 100))
++                      return 0;
++              dbg_rcvry("failing in index head LEB %d", lnum);
++      } else if (c->jheads && lnum == c->jheads[GCHD].wbuf.lnum) {
++              if (chance(9, 10))
++                      return 0;
++              dbg_rcvry("failing in GC head LEB %d", lnum);
++      } else if (write && !RB_EMPTY_ROOT(&c->buds) &&
++                 !ubifs_search_bud(c, lnum)) {
++              if (chance(19, 20))
++                      return 0;
++              dbg_rcvry("failing in non-bud LEB %d", lnum);
++      } else if (c->cmt_state == COMMIT_RUNNING_BACKGROUND ||
++                 c->cmt_state == COMMIT_RUNNING_REQUIRED) {
++              if (chance(999, 1000))
++                      return 0;
++              dbg_rcvry("failing in bud LEB %d commit running", lnum);
++      } else {
++              if (chance(9999, 10000))
++                      return 0;
++              dbg_rcvry("failing in bud LEB %d commit not running", lnum);
++      }
++      ubifs_err("*** SETTING FAILURE MODE ON (LEB %d) ***", lnum);
++      c->failure_mode = 1;
++      dump_stack();
++      return 1;
++}
++
++static void cut_data(const void *buf, int len)
++{
++      int flen, i;
++      unsigned char *p = (void *)buf;
++
++      flen = (len * (long long)simple_rand()) >> 15;
++      for (i = flen; i < len; i++)
++              p[i] = 0xff;
++}
++
++int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
++               int len, int check)
++{
++      if (in_failure_mode(desc))
++              return -EIO;
++      return ubi_leb_read(desc, lnum, buf, offset, len, check);
++}
++
++int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
++                int offset, int len, int dtype)
++{
++      int err;
++
++      if (in_failure_mode(desc))
++              return -EIO;
++      if (do_fail(desc, lnum, 1))
++              cut_data(buf, len);
++      err = ubi_leb_write(desc, lnum, buf, offset, len, dtype);
++      if (err)
++              return err;
++      if (in_failure_mode(desc))
++              return -EIO;
++      return 0;
++}
++
++int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
++                 int len, int dtype)
++{
++      int err;
++
++      if (do_fail(desc, lnum, 1))
++              return -EIO;
++      err = ubi_leb_change(desc, lnum, buf, len, dtype);
++      if (err)
++              return err;
++      if (do_fail(desc, lnum, 1))
++              return -EIO;
++      return 0;
++}
++
++int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum)
++{
++      int err;
++
++      if (do_fail(desc, lnum, 0))
++              return -EIO;
++      err = ubi_leb_erase(desc, lnum);
++      if (err)
++              return err;
++      if (do_fail(desc, lnum, 0))
++              return -EIO;
++      return 0;
++}
++
++int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum)
++{
++      int err;
++
++      if (do_fail(desc, lnum, 0))
++              return -EIO;
++      err = ubi_leb_unmap(desc, lnum);
++      if (err)
++              return err;
++      if (do_fail(desc, lnum, 0))
++              return -EIO;
++      return 0;
++}
++
++int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum)
++{
++      if (in_failure_mode(desc))
++              return -EIO;
++      return ubi_is_mapped(desc, lnum);
++}
++
++#endif /* CONFIG_UBIFS_FS_DEBUG */
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/debug.h avr32-2.6/fs/ubifs/debug.h
+--- linux-2.6.25.6/fs/ubifs/debug.h    1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/debug.h 2008-06-12 15:09:45.315815846 +0200
+@@ -0,0 +1,396 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Artem Bityutskiy (Битюцкий Артём)
++ *          Adrian Hunter
++ */
++
++#ifndef __UBIFS_DEBUG_H__
++#define __UBIFS_DEBUG_H__
++
++#ifdef CONFIG_UBIFS_FS_DEBUG
++
++#define UBIFS_DBG(op) op
++
++#define ubifs_assert(expr)  do {                                               \
++      if (unlikely(!(expr))) {                                               \
++              printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \
++                     __func__, __LINE__, current->pid);                      \
++              dbg_dump_stack();                                              \
++      }                                                                      \
++} while (0)
++
++#define ubifs_assert_cmt_locked(c) do {                                        \
++      if (unlikely(down_write_trylock(&(c)->commit_sem))) {                  \
++              up_write(&(c)->commit_sem);                                    \
++              printk(KERN_CRIT "commit lock is not locked!\n");              \
++              ubifs_assert(0);                                               \
++      }                                                                      \
++} while (0)
++
++#define dbg_dump_stack() do {                                                  \
++      if (!dbg_failure_mode)                                                 \
++              dump_stack();                                                  \
++} while (0)
++
++/* Generic debugging messages */
++#define dbg_msg(fmt, ...) do {                                                 \
++      spin_lock(&dbg_lock);                                                  \
++      printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", current->pid,   \
++             __func__, ##__VA_ARGS__);                                       \
++      spin_unlock(&dbg_lock);                                                \
++} while (0)
++
++#define dbg_do_msg(typ, fmt, ...) do {                                         \
++      if (ubifs_msg_flags & typ)                                             \
++              dbg_msg(fmt, ##__VA_ARGS__);                                   \
++} while (0)
++
++#define dbg_err(fmt, ...) do {                                                 \
++      spin_lock(&dbg_lock);                                                  \
++      ubifs_err(fmt, ##__VA_ARGS__);                                         \
++      spin_unlock(&dbg_lock);                                                \
++} while (0)
++
++const char *dbg_key_str0(const struct ubifs_info *c,
++                       const union ubifs_key *key);
++const char *dbg_key_str1(const struct ubifs_info *c,
++                       const union ubifs_key *key);
++
++/*
++ * DBGKEY macros require dbg_lock to be held, which it is in the dbg message
++ * macros.
++ */
++#define DBGKEY(key) dbg_key_str0(c, (key))
++#define DBGKEY1(key) dbg_key_str1(c, (key))
++
++/* General messages */
++#define dbg_gen(fmt, ...)        dbg_do_msg(UBIFS_MSG_GEN, fmt, ##__VA_ARGS__)
++
++/* Additional journal messages */
++#define dbg_jnl(fmt, ...)        dbg_do_msg(UBIFS_MSG_JNL, fmt, ##__VA_ARGS__)
++
++/* Additional TNC messages */
++#define dbg_tnc(fmt, ...)        dbg_do_msg(UBIFS_MSG_TNC, fmt, ##__VA_ARGS__)
++
++/* Additional lprops messages */
++#define dbg_lp(fmt, ...)         dbg_do_msg(UBIFS_MSG_LP, fmt, ##__VA_ARGS__)
++
++/* Additional LEB find messages */
++#define dbg_find(fmt, ...)       dbg_do_msg(UBIFS_MSG_FIND, fmt, ##__VA_ARGS__)
++
++/* Additional mount messages */
++#define dbg_mnt(fmt, ...)        dbg_do_msg(UBIFS_MSG_MNT, fmt, ##__VA_ARGS__)
++
++/* Additional I/O messages */
++#define dbg_io(fmt, ...)         dbg_do_msg(UBIFS_MSG_IO, fmt, ##__VA_ARGS__)
++
++/* Additional commit messages */
++#define dbg_cmt(fmt, ...)        dbg_do_msg(UBIFS_MSG_CMT, fmt, ##__VA_ARGS__)
++
++/* Additional budgeting messages */
++#define dbg_budg(fmt, ...)       dbg_do_msg(UBIFS_MSG_BUDG, fmt, ##__VA_ARGS__)
++
++/* Additional log messages */
++#define dbg_log(fmt, ...)        dbg_do_msg(UBIFS_MSG_LOG, fmt, ##__VA_ARGS__)
++
++/* Additional gc messages */
++#define dbg_gc(fmt, ...)         dbg_do_msg(UBIFS_MSG_GC, fmt, ##__VA_ARGS__)
++
++/* Additional scan messages */
++#define dbg_scan(fmt, ...)       dbg_do_msg(UBIFS_MSG_SCAN, fmt, ##__VA_ARGS__)
++
++/* Additional recovery messages */
++#define dbg_rcvry(fmt, ...)      dbg_do_msg(UBIFS_MSG_RCVRY, fmt, ##__VA_ARGS__)
++
++/*
++ * Debugging message type flags (must match msg_type_names in debug.c).
++ *
++ * UBIFS_MSG_GEN: general messages
++ * UBIFS_MSG_JNL: journal messages
++ * UBIFS_MSG_MNT: mount messages
++ * UBIFS_MSG_CMT: commit messages
++ * UBIFS_MSG_FIND: LEB find messages
++ * UBIFS_MSG_BUDG: budgeting messages
++ * UBIFS_MSG_GC: garbage collection messages
++ * UBIFS_MSG_TNC: TNC messages
++ * UBIFS_MSG_LP: lprops messages
++ * UBIFS_MSG_IO: I/O messages
++ * UBIFS_MSG_LOG: log messages
++ * UBIFS_MSG_SCAN: scan messages
++ * UBIFS_MSG_RCVRY: recovery messages
++ */
++enum {
++      UBIFS_MSG_GEN   = 0x1,
++      UBIFS_MSG_JNL   = 0x2,
++      UBIFS_MSG_MNT   = 0x4,
++      UBIFS_MSG_CMT   = 0x8,
++      UBIFS_MSG_FIND  = 0x10,
++      UBIFS_MSG_BUDG  = 0x20,
++      UBIFS_MSG_GC    = 0x40,
++      UBIFS_MSG_TNC   = 0x80,
++      UBIFS_MSG_LP    = 0x100,
++      UBIFS_MSG_IO    = 0x200,
++      UBIFS_MSG_LOG   = 0x400,
++      UBIFS_MSG_SCAN  = 0x800,
++      UBIFS_MSG_RCVRY = 0x1000,
++};
++
++/* Debugging message type flags for each default debug message level */
++#define UBIFS_MSG_LVL_0 0
++#define UBIFS_MSG_LVL_1 0x1
++#define UBIFS_MSG_LVL_2 0x7f
++#define UBIFS_MSG_LVL_3 0xffff
++
++/*
++ * Debugging check flags (must match chk_names in debug.c).
++ *
++ * UBIFS_CHK_GEN: general checks
++ * UBIFS_CHK_TNC: check TNC
++ * UBIFS_CHK_IDX_SZ: check index size
++ * UBIFS_CHK_ORPH: check orphans
++ * UBIFS_CHK_OLD_IDX: check the old index
++ * UBIFS_CHK_LPROPS: check lprops
++ * UBIFS_CHK_FS: check the file-system
++ */
++enum {
++      UBIFS_CHK_GEN     = 0x1,
++      UBIFS_CHK_TNC     = 0x2,
++      UBIFS_CHK_IDX_SZ  = 0x4,
++      UBIFS_CHK_ORPH    = 0x8,
++      UBIFS_CHK_OLD_IDX = 0x10,
++      UBIFS_CHK_LPROPS  = 0x20,
++      UBIFS_CHK_FS      = 0x40,
++};
++
++/*
++ * Special testing flags (must match tst_names in debug.c).
++ *
++ * UBIFS_TST_FORCE_IN_THE_GAPS: force the use of in-the-gaps method
++ * UBIFS_TST_RCVRY: failure mode for recovery testing
++ */
++enum {
++      UBIFS_TST_FORCE_IN_THE_GAPS = 0x2,
++      UBIFS_TST_RCVRY             = 0x4,
++};
++
++#if CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 1
++#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_1
++#elif CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 2
++#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_2
++#elif CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 3
++#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_3
++#else
++#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_0
++#endif
++
++#ifdef CONFIG_UBIFS_FS_DEBUG_CHKS
++#define UBIFS_CHK_FLAGS_DEFAULT 0xffffffff
++#else
++#define UBIFS_CHK_FLAGS_DEFAULT 0
++#endif
++
++extern spinlock_t dbg_lock;
++
++extern unsigned int ubifs_msg_flags;
++extern unsigned int ubifs_chk_flags;
++extern unsigned int ubifs_tst_flags;
++
++/* Dump functions */
++
++const char *dbg_ntype(int type);
++const char *dbg_cstate(int cmt_state);
++const char *dbg_get_key_dump(const struct ubifs_info *c,
++                           const union ubifs_key *key);
++void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode);
++void dbg_dump_node(const struct ubifs_info *c, const void *node);
++void dbg_dump_budget_req(const struct ubifs_budget_req *req);
++void dbg_dump_lstats(const struct ubifs_lp_stats *lst);
++void dbg_dump_budg(struct ubifs_info *c);
++void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp);
++void dbg_dump_lprops(struct ubifs_info *c);
++void dbg_dump_leb(const struct ubifs_info *c, int lnum);
++void dbg_dump_znode(const struct ubifs_info *c,
++                  const struct ubifs_znode *znode);
++void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat);
++void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
++                  struct ubifs_nnode *parent, int iip);
++void dbg_dump_tnc(struct ubifs_info *c);
++void dbg_dump_index(struct ubifs_info *c);
++
++/* Checking helper functions */
++
++typedef int (*dbg_leaf_callback)(struct ubifs_info *c,
++                               struct ubifs_zbranch *zbr, void *priv);
++typedef int (*dbg_znode_callback)(struct ubifs_info *c,
++                                struct ubifs_znode *znode, void *priv);
++
++int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb,
++                 dbg_znode_callback znode_cb, void *priv);
++
++/* Checking functions */
++
++int dbg_check_lprops(struct ubifs_info *c);
++
++int dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot);
++int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot);
++
++int dbg_check_cats(struct ubifs_info *c);
++
++int dbg_check_ltab(struct ubifs_info *c);
++
++int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir);
++
++int dbg_check_tnc(struct ubifs_info *c, int extra);
++
++int dbg_check_idx_size(struct ubifs_info *c, long long idx_size);
++
++int dbg_check_filesystem(struct ubifs_info *c);
++
++void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
++                  int add_pos);
++
++int dbg_check_lprops(struct ubifs_info *c);
++int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
++                      int row, int col);
++
++/* Force the use of in-the-gaps method for testing */
++
++#define dbg_force_in_the_gaps_enabled \
++      (ubifs_tst_flags & UBIFS_TST_FORCE_IN_THE_GAPS)
++
++int dbg_force_in_the_gaps(void);
++
++/* Failure mode for recovery testing */
++
++#define dbg_failure_mode (ubifs_tst_flags & UBIFS_TST_RCVRY)
++
++void dbg_failure_mode_registration(struct ubifs_info *c);
++void dbg_failure_mode_deregistration(struct ubifs_info *c);
++
++#ifndef UBIFS_DBG_PRESERVE_UBI
++
++#define ubi_leb_read   dbg_leb_read
++#define ubi_leb_write  dbg_leb_write
++#define ubi_leb_change dbg_leb_change
++#define ubi_leb_erase  dbg_leb_erase
++#define ubi_leb_unmap  dbg_leb_unmap
++#define ubi_is_mapped  dbg_is_mapped
++
++#endif
++
++int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
++               int len, int check);
++int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
++                int offset, int len, int dtype);
++int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
++                 int len, int dtype);
++int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum);
++int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum);
++int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum);
++
++static inline int dbg_read(struct ubi_volume_desc *desc, int lnum, char *buf,
++                         int offset, int len)
++{
++      return dbg_leb_read(desc, lnum, buf, offset, len, 0);
++}
++
++static inline int dbg_write(struct ubi_volume_desc *desc, int lnum,
++                          const void *buf, int offset, int len)
++{
++      return dbg_leb_write(desc, lnum, buf, offset, len, UBI_UNKNOWN);
++}
++
++static inline int dbg_change(struct ubi_volume_desc *desc, int lnum,
++                                  const void *buf, int len)
++{
++      return dbg_leb_change(desc, lnum, buf, len, UBI_UNKNOWN);
++}
++
++#else /* !CONFIG_UBIFS_FS_DEBUG */
++
++#define UBIFS_DBG(op)
++#define ubifs_assert(expr)                         ({})
++#define ubifs_assert_cmt_locked(c)
++#define dbg_dump_stack()
++#define dbg_err(fmt, ...)                          ({})
++#define dbg_msg(fmt, ...)                          ({})
++#define dbg_key(c, key, fmt, ...)                  ({})
++
++#define dbg_gen(fmt, ...)                          ({})
++#define dbg_jnl(fmt, ...)                          ({})
++#define dbg_tnc(fmt, ...)                          ({})
++#define dbg_lp(fmt, ...)                           ({})
++#define dbg_find(fmt, ...)                         ({})
++#define dbg_mnt(fmt, ...)                          ({})
++#define dbg_io(fmt, ...)                           ({})
++#define dbg_cmt(fmt, ...)                          ({})
++#define dbg_budg(fmt, ...)                         ({})
++#define dbg_log(fmt, ...)                          ({})
++#define dbg_gc(fmt, ...)                           ({})
++#define dbg_scan(fmt, ...)                         ({})
++#define dbg_rcvry(fmt, ...)                        ({})
++
++#define dbg_ntype(type)                            ""
++#define dbg_cstate(cmt_state)                      ""
++#define dbg_get_key_dump(c, key)                   ({})
++#define dbg_dump_inode(c, inode)                   ({})
++#define dbg_dump_node(c, node)                     ({})
++#define dbg_dump_budget_req(req)                   ({})
++#define dbg_dump_lstats(lst)                       ({})
++#define dbg_dump_budg(c)                           ({})
++#define dbg_dump_lprop(c, lp)                      ({})
++#define dbg_dump_lprops(c)                         ({})
++#define dbg_dump_leb(c, lnum)                      ({})
++#define dbg_dump_znode(c, znode)                   ({})
++#define dbg_dump_heap(c, heap, cat)                ({})
++#define dbg_dump_pnode(c, pnode, parent, iip)      ({})
++#define dbg_dump_tnc(c)                            ({})
++#define dbg_dump_index(c)                          ({})
++
++#define dbg_walk_index(c, leaf_cb, znode_cb, priv) 0
++
++#define dbg_old_index_check_init(c, zroot)         0
++#define dbg_check_old_index(c, zroot)              0
++
++#define dbg_check_cats(c)                          0
++
++#define dbg_check_ltab(c)                          0
++
++#define dbg_check_dir_size(c, dir)                 0
++
++#define dbg_check_tnc(c, x)                        0
++
++#define dbg_check_idx_size(c, idx_size)            0
++#define dbg_check_filesystem(c)                    0
++
++#define dbg_check_heap(c, heap, cat, add_pos)      ({})
++
++#define dbg_check_lprops(c)                        0
++#define dbg_check_lpt_nodes(c, cnode, row, col)    0
++
++#define dbg_force_in_the_gaps_enabled              0
++#define dbg_force_in_the_gaps()                    0
++
++#define dbg_failure_mode                           0
++#define dbg_failure_mode_registration(c)           ({})
++#define dbg_failure_mode_deregistration(c)         ({})
++
++#endif /* !CONFIG_UBIFS_FS_DEBUG */
++
++#endif /* !__UBIFS_DEBUG_H__ */
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/dir.c avr32-2.6/fs/ubifs/dir.c
+--- linux-2.6.25.6/fs/ubifs/dir.c      1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/dir.c   2008-06-12 15:09:45.364399968 +0200
+@@ -0,0 +1,1017 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ * Copyright (C) 2006, 2007 University of Szeged, Hungary
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Artem Bityutskiy (Битюцкий Артём)
++ *          Adrian Hunter
++ *          Zoltan Sogor
++ */
++
++/*
++ * This file implements directory operations.
++ *
++ * All FS operations in this file allocate budget before writing anything to the
++ * media. If they fail to allocate it, the error is returned. The only
++ * exceptions are 'ubifs_unlink()' and 'ubifs_rmdir()' which keep working even
++ * if they unable to allocate the budget, because deletion %-ENOSPC failure is
++ * not what users are usually ready to get. UBIFS budgeting subsystem has some
++ * space reserved for these purposes.
++ *
++ * All operations in this file change the parent inode, e.g., 'ubifs_link()'
++ * changes ctime and nlink of the parent inode. The parent inode is written to
++ * the media straight away - it is not marked as dirty and there is no
++ * write-back for it. This was done to simplify file-system recovery which
++ * would otherwise be very difficult to do. So instead of marking the parent
++ * inode dirty, the operations mark it clean.
++ */
++
++#include "ubifs.h"
++
++/*
++ * Provide backing_dev_info in order to disable readahead. For UBIFS, I/O is
++ * not deferred, it is done immediately in readpage, which means the user would
++ * have to wait not just for their own I/O but the readahead I/O as well i.e.
++ * completely pointless.
++ */
++struct backing_dev_info ubifs_backing_dev_info = {
++      .ra_pages       = 0, /* Set to zero to disable readahead */
++      .state          = 0,
++      .capabilities   = BDI_CAP_MAP_COPY,
++      .unplug_io_fn   = default_unplug_io_fn,
++};
++
++/**
++ * inherit_flags - inherit flags of the parent inode.
++ * @dir: parent inode
++ * @mode: new inode mode flags
++ *
++ * This is a helper function for 'ubifs_new_inode()' which inherits flag of the
++ * parent directory inode @dir. UBIFS inodes inherit the following flags:
++ * o %UBIFS_COMPR_FL, which is useful to switch compression on/of on
++ *   sub-directory basis;
++ * o %UBIFS_SYNC_FL - useful for the same reasons;
++ * o %UBIFS_DIRSYNC_FL - similar, but relevant only to directories.
++ *
++ * This function returns the inherited flags.
++ */
++static int inherit_flags(const struct inode *dir, int mode)
++{
++      int flags;
++      const struct ubifs_inode *ui = ubifs_inode(dir);
++
++      if (!S_ISDIR(dir->i_mode))
++              /*
++               * The parent is not a directory, which means that an extended
++               * attribute inode is being created. No flags.
++               */
++              return 0;
++
++      flags = ui->flags & (UBIFS_COMPR_FL | UBIFS_SYNC_FL | UBIFS_DIRSYNC_FL);
++      if (!S_ISDIR(mode))
++              /* The "DIRSYNC" flag only applies to directories */
++              flags &= ~UBIFS_DIRSYNC_FL;
++
++      return flags;
++}
++
++/**
++ * ubifs_new_inode - allocate new UBIFS inode object.
++ * @c: UBIFS file-system description object
++ * @dir: parent directory inode
++ * @mode: inode mode flags
++ *
++ * This function finds an unused inode number, allocates new inode and
++ * initializes it. Returns new inode in case of success and an error code in
++ * case of failure.
++ */
++struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
++                            int mode)
++{
++      struct inode *inode;
++      struct ubifs_inode *ui;
++
++      inode = new_inode(c->vfs_sb);
++      if (!inode)
++              return ERR_PTR(-ENOMEM);
++
++      /*
++       * Set 'S_NOCMTIME' to prevent VFS form updating [mc]time of inodes and
++       * marking them dirty in file write path (see 'file_update_time()').
++       * UBIFS has to fully control "clean <-> dirty" transitions of inodes
++       * to make budgeting work.
++       */
++      inode->i_flags |= (S_NOCMTIME);
++
++      inode->i_uid = current->fsuid;
++      if (dir->i_mode & S_ISGID) {
++              inode->i_gid = dir->i_gid;
++              if (S_ISDIR(mode))
++                      mode |= S_ISGID;
++      } else
++              inode->i_gid = current->fsgid;
++      inode->i_mode = mode;
++      inode->i_mtime = inode->i_atime = inode->i_ctime =
++                       ubifs_current_time(inode);
++      inode->i_mapping->nrpages = 0;
++      /* Disable readahead */
++      inode->i_mapping->backing_dev_info = &ubifs_backing_dev_info;
++
++      switch (mode & S_IFMT) {
++      case S_IFREG:
++              inode->i_mapping->a_ops = &ubifs_file_address_operations;
++              inode->i_op = &ubifs_file_inode_operations;
++              inode->i_fop = &ubifs_file_operations;
++              break;
++      case S_IFDIR:
++              inode->i_op  = &ubifs_dir_inode_operations;
++              inode->i_fop = &ubifs_dir_operations;
++              inode->i_size = UBIFS_INO_NODE_SZ;
++              break;
++      case S_IFLNK:
++              inode->i_op = &ubifs_symlink_inode_operations;
++              break;
++      case S_IFSOCK:
++      case S_IFIFO:
++      case S_IFBLK:
++      case S_IFCHR:
++              inode->i_op  = &ubifs_file_inode_operations;
++              break;
++      default:
++              BUG();
++      }
++
++      ui = ubifs_inode(inode);
++      ui->flags = inherit_flags(dir, mode);
++      ubifs_set_inode_flags(inode);
++
++      if (S_ISREG(mode))
++              ui->compr_type = c->default_compr;
++      else
++              ui->compr_type = UBIFS_COMPR_NONE;
++
++      spin_lock(&c->cnt_lock);
++      /* Inode number overflow is currently not supported */
++      if (c->highest_inum >= INUM_WARN_WATERMARK) {
++              if (c->highest_inum >= INUM_WATERMARK) {
++                      spin_unlock(&c->cnt_lock);
++                      ubifs_err("out of inode numbers");
++                      make_bad_inode(inode);
++                      iput(inode);
++                      return ERR_PTR(-EINVAL);
++              }
++              ubifs_warn("running out of inode numbers (current %lu, max %d)",
++                         c->highest_inum, INUM_WATERMARK);
++      }
++
++      inode->i_ino = ++c->highest_inum;
++      inode->i_generation = ++c->vfs_gen;
++      /*
++       * The creation sequence number remains with this inode for its
++       * lifetime. All nodes for this inode have a greater sequence number,
++       * and so it is possible to distinguish obsolete nodes belonging to a
++       * previous incarnation of the same inode number - for example, for the
++       * purpose of rebuilding the index.
++       */
++      ui->creat_sqnum = ++c->max_sqnum;
++      spin_unlock(&c->cnt_lock);
++
++      return inode;
++}
++
++#ifdef CONFIG_UBIFS_FS_DEBUG
++
++static int dbg_check_name(struct ubifs_dent_node *dent, struct qstr *nm)
++{
++      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++              return 0;
++      if (le16_to_cpu(dent->nlen) != nm->len)
++              return -EINVAL;
++      if (memcmp(dent->name, nm->name, nm->len))
++              return -EINVAL;
++      return 0;
++}
++
++#else
++
++#define dbg_check_name(dent, nm) 0
++
++#endif
++
++static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
++                                 struct nameidata *nd)
++{
++      int err;
++      union ubifs_key key;
++      struct inode *inode = NULL;
++      struct ubifs_dent_node *dent;
++      struct ubifs_info *c = dir->i_sb->s_fs_info;
++
++      dbg_gen("'%.*s' in dir ino %lu",
++              dentry->d_name.len, dentry->d_name.name, dir->i_ino);
++
++      if (dentry->d_name.len > UBIFS_MAX_NLEN)
++              return ERR_PTR(-ENAMETOOLONG);
++
++      dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
++      if (!dent)
++              return ERR_PTR(-ENOMEM);
++
++      dent_key_init(c, &key, dir->i_ino, &dentry->d_name);
++
++      err = ubifs_tnc_lookup_nm(c, &key, dent, &dentry->d_name);
++      if (err) {
++              if (err == -ENOENT) {
++                      dbg_gen("not found");
++                      goto done;
++              }
++              goto out;
++      }
++
++      if (dbg_check_name(dent, &dentry->d_name)) {
++              err = -EINVAL;
++              goto out;
++      }
++
++      inode = ubifs_iget(dir->i_sb, le64_to_cpu(dent->inum));
++      if (IS_ERR(inode)) {
++              /*
++               * This should not happen. Probably the file-system needs
++               * checking.
++               */
++              err = PTR_ERR(inode);
++              ubifs_err("dead directory entry '%.*s', error %d",
++                        dentry->d_name.len, dentry->d_name.name, err);
++              ubifs_ro_mode(c, err);
++              goto out;
++      }
++
++done:
++      kfree(dent);
++      /*
++       * Note, d_splice_alias() would be required instead if we supported
++       * NFS.
++       */
++      d_add(dentry, inode);
++      return NULL;
++
++out:
++      kfree(dent);
++      return ERR_PTR(err);
++}
++
++static int ubifs_create(struct inode *dir, struct dentry *dentry, int mode,
++                      struct nameidata *nd)
++{
++      struct inode *inode;
++      struct ubifs_info *c = dir->i_sb->s_fs_info;
++      struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 };
++      int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len);
++
++      dbg_gen("dent '%.*s', mode %#x in dir ino %lu",
++              dentry->d_name.len, dentry->d_name.name, mode, dir->i_ino);
++
++      inode = ubifs_new_inode(c, dir, mode);
++      if (IS_ERR(inode))
++              return PTR_ERR(inode);
++
++      err = ubifs_budget_inode_op(c, dir, &req);
++      if (err)
++              goto out;
++
++      dir->i_size += sz_change;
++
++      err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0,
++                             IS_DIRSYNC(dir), 0);
++      if (err)
++              goto out_budg;
++
++      insert_inode_hash(inode);
++      d_instantiate(dentry, inode);
++      ubifs_release_ino_clean(c, dir, &req);
++      return 0;
++
++out_budg:
++      dir->i_size -= sz_change;
++      ubifs_cancel_ino_op(c, dir, &req);
++      ubifs_err("cannot create regular file, error %d", err);
++out:
++      make_bad_inode(inode);
++      iput(inode);
++      return err;
++}
++
++/**
++ * vfs_dent_type - get VFS directory entry type.
++ * @type: UBIFS directory entry type
++ *
++ * This function converts UBIFS directory entry type into VFS directory entry
++ * type.
++ */
++static unsigned int vfs_dent_type(uint8_t type)
++{
++      switch (type) {
++      case UBIFS_ITYPE_REG:
++              return DT_REG;
++      case UBIFS_ITYPE_DIR:
++              return DT_DIR;
++      case UBIFS_ITYPE_LNK:
++              return DT_LNK;
++      case UBIFS_ITYPE_BLK:
++              return DT_BLK;
++      case UBIFS_ITYPE_CHR:
++              return DT_CHR;
++      case UBIFS_ITYPE_FIFO:
++              return DT_FIFO;
++      case UBIFS_ITYPE_SOCK:
++              return DT_SOCK;
++      default:
++              BUG();
++      }
++      return 0;
++}
++
++/*
++ * The classical Unix view for directory is that it is a linear array of
++ * (name, inode number) entries. Linux/VFS assumes this model as well.
++ * Particularly, 'readdir()' call wants us to return a directory entry offset
++ * which later may be used to continue 'readdir()'ing the directory or to
++ * 'seek()' to that specific direntry. Obviously UBIFS does not really fit this
++ * model because directory entries are identified by keys, which may collide.
++ *
++ * UBIFS uses directory entry hash value for directory offsets, so
++ * 'seekdir()'/'telldir()' may not always work because of possible key
++ * collisions. But UBIFS guarantees that consecutive 'readdir()' calls work
++ * properly by means of saving full directory entry name in the private field
++ * of the file description object.
++ *
++ * This means that UBIFS cannot support NFS which requires full
++ * 'seekdir()'/'telldir()' support.
++ */
++static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
++{
++      int err, over = 0;
++      struct qstr nm;
++      union ubifs_key key;
++      struct ubifs_dent_node *dent;
++      struct inode *dir = file->f_path.dentry->d_inode;
++      struct ubifs_info *c = dir->i_sb->s_fs_info;
++
++      dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
++
++      if (file->f_pos > UBIFS_S_KEY_HASH_MASK || file->f_pos == 2)
++              /*
++               * The directory was seek'ed to a senseless position or there
++               * are no more entries.
++               */
++              return 0;
++
++      /* File positions 0 and 1 correspond to "." and ".." */
++      if (file->f_pos == 0) {
++              ubifs_assert(!file->private_data);
++              over = filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR);
++              if (over)
++                      return 0;
++              file->f_pos = 1;
++      }
++
++      if (file->f_pos == 1) {
++              ubifs_assert(!file->private_data);
++              over = filldir(dirent, "..", 2, 1,
++                             parent_ino(file->f_path.dentry), DT_DIR);
++              if (over)
++                      return 0;
++
++              /* Find the first entry in TNC and save it */
++              lowest_dent_key(c, &key, dir->i_ino);
++              nm.name = NULL;
++              dent = ubifs_tnc_next_ent(c, &key, &nm);
++              if (IS_ERR(dent)) {
++                      err = PTR_ERR(dent);
++                      goto out;
++              }
++
++              file->f_pos = key_hash_flash(c, &dent->key);
++              file->private_data = dent;
++      }
++
++      dent = file->private_data;
++      if (!dent) {
++              /*
++               * The directory was seek'ed to and is now readdir'ed.
++               * Find the entry corresponding to @file->f_pos or the
++               * closest one.
++               */
++              dent_key_init_hash(c, &key, dir->i_ino, file->f_pos);
++              nm.name = NULL;
++              dent = ubifs_tnc_next_ent(c, &key, &nm);
++              if (IS_ERR(dent)) {
++                      err = PTR_ERR(dent);
++                      goto out;
++              }
++              file->f_pos = key_hash_flash(c, &dent->key);
++              file->private_data = dent;
++      }
++
++      while (1) {
++              dbg_gen("feed '%s', ino %llu, new f_pos %#x",
++                      dent->name, le64_to_cpu(dent->inum),
++                      key_hash_flash(c, &dent->key));
++              ubifs_assert(dent->ch.sqnum > ubifs_inode(dir)->creat_sqnum);
++
++              nm.len = le16_to_cpu(dent->nlen);
++              over = filldir(dirent, dent->name, nm.len, file->f_pos,
++                             le64_to_cpu(dent->inum),
++                             vfs_dent_type(dent->type));
++              if (over)
++                      return 0;
++
++              /* Switch to the next entry */
++              key_read(c, &dent->key, &key);
++              nm.name = dent->name;
++              dent = ubifs_tnc_next_ent(c, &key, &nm);
++              if (IS_ERR(dent)) {
++                      err = PTR_ERR(dent);
++                      goto out;
++              }
++
++              kfree(file->private_data);
++              file->f_pos = key_hash_flash(c, &dent->key);
++              file->private_data = dent;
++              cond_resched();
++      }
++
++out:
++      if (err != -ENOENT) {
++              ubifs_err("cannot find next direntry, error %d", err);
++              return err;
++      }
++
++      kfree(file->private_data);
++      file->private_data = NULL;
++      file->f_pos = 2;
++      return 0;
++}
++
++/* If a directory is seeked, we have to free saved readdir() state */
++loff_t ubifs_dir_llseek(struct file *file, loff_t offset, int origin)
++{
++      kfree(file->private_data);
++      file->private_data = NULL;
++      return generic_file_llseek(file, offset, origin);
++}
++
++/* Free saved readdir() state when the directory is closed */
++static int ubifs_dir_release(struct inode *dir, struct file *file)
++{
++      kfree(file->private_data);
++      file->private_data = NULL;
++      return 0;
++}
++
++static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
++                    struct dentry *dentry)
++{
++      struct ubifs_info *c = dir->i_sb->s_fs_info;
++      struct inode *inode = old_dentry->d_inode;
++      struct ubifs_inode *ui = ubifs_inode(inode);
++      struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 1,
++                                      .dirtied_ino_d = ui->data_len };
++      int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len);
++
++      dbg_gen("dent '%.*s' to ino %lu (nlink %d) in dir ino %lu",
++              dentry->d_name.len, dentry->d_name.name, inode->i_ino,
++              inode->i_nlink, dir->i_ino);
++
++      err = ubifs_budget_inode_op(c, dir, &req);
++      if (err)
++              return err;
++
++      inc_nlink(inode);
++      dir->i_size += sz_change;
++      inode->i_ctime = dir->i_mtime = dir->i_ctime =
++                       ubifs_current_time(inode);
++
++      err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0,
++                             IS_DIRSYNC(dir), 0);
++      if (err)
++              goto out_budg;
++
++      atomic_inc(&inode->i_count);
++      d_instantiate(dentry, inode);
++      ubifs_release_ino_clean(c, dir, &req);
++      return 0;
++
++out_budg:
++      dir->i_size -= sz_change;
++      ubifs_cancel_ino_op(c, dir, &req);
++      drop_nlink(inode);
++      iput(inode);
++      return err;
++}
++
++static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
++{
++      struct ubifs_info *c = dir->i_sb->s_fs_info;
++      struct inode *inode = dentry->d_inode;
++      struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 1 };
++      int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
++      int err, budgeted = 1;
++
++      dbg_gen("dent '%.*s' from ino %lu (nlink %d) in dir ino %lu",
++              dentry->d_name.len, dentry->d_name.name, inode->i_ino,
++              inode->i_nlink, dir->i_ino);
++
++      err = ubifs_budget_inode_op(c, dir, &req);
++      if (err) {
++              if (err != -ENOSPC)
++                      return err;
++              err = 0;
++              budgeted = 0;
++      }
++
++      dir->i_size -= sz_change;
++      dir->i_mtime = dir->i_ctime = ubifs_current_time(dir);
++
++      inode->i_ctime = dir->i_ctime;
++      drop_nlink(inode);
++
++      err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1,
++                             IS_DIRSYNC(dir), 0);
++      if (err)
++              goto out_budg;
++
++      if (budgeted)
++              ubifs_release_ino_clean(c, dir, &req);
++
++      return 0;
++
++out_budg:
++      dir->i_size += sz_change;
++      inc_nlink(inode);
++      if (budgeted)
++              ubifs_cancel_ino_op(c, dir, &req);
++      return err;
++}
++
++/**
++ * check_dir_empty - check if a directory is empty or not.
++ * @c: UBIFS file-system description object
++ * @dir: VFS inode object of the directory to check
++ *
++ * This function checks if directory @dir is empty. Returns zero if the
++ * directory is empty, %-ENOTEMPTY if it is not, and other negative error codes
++ * in case of of errors.
++ */
++static int check_dir_empty(struct ubifs_info *c, struct inode *dir)
++{
++      struct qstr nm = { .name = NULL };
++      struct ubifs_dent_node *dent;
++      union ubifs_key key;
++      int err;
++
++      lowest_dent_key(c, &key, dir->i_ino);
++      dent = ubifs_tnc_next_ent(c, &key, &nm);
++      if (IS_ERR(dent)) {
++              err = PTR_ERR(dent);
++              if (err == -ENOENT)
++                      err = 0;
++      } else {
++              kfree(dent);
++              err = -ENOTEMPTY;
++      }
++
++      return err;
++}
++
++static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
++{
++      struct ubifs_info *c = dir->i_sb->s_fs_info;
++      struct inode *inode = dentry->d_inode;
++      struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 1 };
++      int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
++      int err, budgeted = 0;
++
++      dbg_gen("directory '%.*s', ino %lu in dir ino %lu", dentry->d_name.len,
++              dentry->d_name.name, inode->i_ino, dir->i_ino);
++
++      err = check_dir_empty(c, dentry->d_inode);
++      if (err)
++              return err;
++
++      budgeted = 1;
++      err = ubifs_budget_inode_op(c, dir, &req);
++      if (err) {
++              if (err != -ENOSPC)
++                      return err;
++              budgeted = 0;
++      }
++
++      dir->i_size -= sz_change;
++      dir->i_mtime = dir->i_ctime = ubifs_current_time(dir);
++      drop_nlink(dir);
++
++      inode->i_size = 0;
++      inode->i_ctime = dir->i_ctime;
++      clear_nlink(inode);
++
++      err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1,
++                             IS_DIRSYNC(dir), 0);
++      if (err)
++              goto out_budg;
++
++      if (budgeted)
++              ubifs_release_ino_clean(c, dir, &req);
++
++      return 0;
++
++out_budg:
++      dir->i_size += sz_change;
++      inc_nlink(dir);
++      inc_nlink(inode);
++      inc_nlink(inode);
++      if (budgeted)
++              ubifs_cancel_ino_op(c, dir, &req);
++      return err;
++}
++
++static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++{
++      struct inode *inode;
++      struct ubifs_info *c = dir->i_sb->s_fs_info;
++      struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 };
++      int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len);
++
++      dbg_gen("dent '%.*s', mode %#x in dir ino %lu",
++              dentry->d_name.len, dentry->d_name.name, mode, dir->i_ino);
++
++      err = ubifs_budget_inode_op(c, dir, &req);
++      if (err)
++              return err;
++
++      inode = ubifs_new_inode(c, dir, S_IFDIR | mode);
++      if (IS_ERR(inode)) {
++              err = PTR_ERR(inode);
++              goto out_budg;
++      }
++
++      insert_inode_hash(inode);
++      inc_nlink(inode);
++
++      dir->i_mtime = dir->i_ctime = ubifs_current_time(dir);
++      dir->i_size += sz_change;
++      inc_nlink(dir);
++
++      err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0,
++                             IS_DIRSYNC(dir), 0);
++      if (err) {
++              ubifs_err("cannot create directory, error %d", err);
++              goto out_inode;
++      }
++
++      d_instantiate(dentry, inode);
++      ubifs_release_ino_clean(c, dir, &req);
++      return 0;
++
++out_inode:
++      dir->i_size -= sz_change;
++      drop_nlink(dir);
++      make_bad_inode(inode);
++      iput(inode);
++out_budg:
++      ubifs_cancel_ino_op(c, dir, &req);
++      return err;
++}
++
++static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
++                     int mode, dev_t rdev)
++{
++      struct inode *inode;
++      struct ubifs_info *c = dir->i_sb->s_fs_info;
++      struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 };
++      union ubifs_dev_desc *dev = NULL;
++      int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
++      int err, devlen = 0;
++
++      dbg_gen("dent '%.*s' in dir ino %lu",
++              dentry->d_name.len, dentry->d_name.name, dir->i_ino);
++
++      if (!new_valid_dev(rdev))
++              return -EINVAL;
++
++      if (S_ISBLK(mode) || S_ISCHR(mode)) {
++              dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS);
++              if (!dev)
++                      return -ENOMEM;
++              devlen = ubifs_encode_dev(dev, rdev);
++      }
++
++      err = ubifs_budget_inode_op(c, dir, &req);
++      if (err) {
++              kfree(dev);
++              return err;
++      }
++
++      inode = ubifs_new_inode(c, dir, mode);
++      if (IS_ERR(inode)) {
++              kfree(dev);
++              err = PTR_ERR(inode);
++              goto out_budg;
++      }
++
++      init_special_inode(inode, inode->i_mode, rdev);
++
++      inode->i_size = devlen;
++      ubifs_inode(inode)->data = dev;
++      ubifs_inode(inode)->data_len = devlen;
++
++      dir->i_size += sz_change;
++
++      err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0,
++                             IS_DIRSYNC(dir), 0);
++      if (err)
++              goto out_inode;
++
++      insert_inode_hash(inode);
++      d_instantiate(dentry, inode);
++      ubifs_release_ino_clean(c, dir, &req);
++      return 0;
++
++out_inode:
++      dir->i_size -= sz_change;
++      make_bad_inode(inode);
++      iput(inode);
++out_budg:
++      ubifs_cancel_ino_op(c, dir, &req);
++      return err;
++}
++
++static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
++                       const char *symname)
++{
++      struct inode *inode;
++      struct ubifs_inode *ui;
++      struct ubifs_info *c = dir->i_sb->s_fs_info;
++      int err, len = strlen(symname);
++      int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
++      struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
++                                      .new_ino_d = len };
++
++      dbg_gen("dent '%.*s', target '%s' in dir ino %lu", dentry->d_name.len,
++              dentry->d_name.name, symname, dir->i_ino);
++
++      if (len > UBIFS_MAX_INO_DATA)
++              return -ENAMETOOLONG;
++
++      err = ubifs_budget_inode_op(c, dir, &req);
++      if (err)
++              return err;
++
++      inode = ubifs_new_inode(c, dir, S_IFLNK | S_IRWXUGO);
++      if (IS_ERR(inode)) {
++              err = PTR_ERR(inode);
++              goto out_budg;
++      }
++
++      ui = ubifs_inode(inode);
++      ui->data = kmalloc(len + 1, GFP_NOFS);
++      if (!ui->data) {
++              err = -ENOMEM;
++              goto out_inode;
++      }
++
++      memcpy(ui->data, symname, len);
++      ((char *)ui->data)[len] = '\0';
++      /*
++       * The terminating zero byte is not written to the flash media and it
++       * is put just to make later in-memory string processing simpler. Thus,
++       * data length is @len, not @len + %1.
++       */
++      ui->data_len = len;
++      inode->i_size = len;
++
++      dir->i_size += sz_change;
++
++      err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0,
++                             IS_DIRSYNC(dir), 0);
++      if (err)
++              goto out_dir;
++
++      insert_inode_hash(inode);
++      d_instantiate(dentry, inode);
++      ubifs_release_ino_clean(c, dir, &req);
++      return 0;
++
++out_dir:
++      dir->i_size -= sz_change;
++out_inode:
++      make_bad_inode(inode);
++      iput(inode);
++out_budg:
++      ubifs_cancel_ino_op(c, dir, &req);
++      return err;
++}
++
++static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
++                      struct inode *new_dir, struct dentry *new_dentry)
++{
++      struct ubifs_info *c = old_dir->i_sb->s_fs_info;
++      struct inode *old_inode = old_dentry->d_inode;
++      struct inode *new_inode = new_dentry->d_inode;
++      int err, move = (new_dir != old_dir);
++      int is_dir = S_ISDIR(old_inode->i_mode);
++      int unlink = !!new_inode;
++      int dirsync = (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir));
++      int new_sz = CALC_DENT_SIZE(new_dentry->d_name.len);
++      int old_sz = CALC_DENT_SIZE(old_dentry->d_name.len);
++      struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1 };
++      struct timespec time = ubifs_current_time(old_dir);
++
++      dbg_gen("dent '%.*s' ino %lu in dir ino %lu to dent '%.*s' in "
++              "dir ino %lu", old_dentry->d_name.len, old_dentry->d_name.name,
++              old_inode->i_ino, old_dir->i_ino, new_dentry->d_name.len,
++              new_dentry->d_name.name, new_dir->i_ino);
++
++      if (unlink && is_dir) {
++              err = check_dir_empty(c, new_inode);
++              if (err)
++                      return err;
++      }
++
++      if (move) {
++              req.dirtied_ino = 1;
++              if (unlink) {
++                      req.dirtied_ino += 2;
++                      req.dirtied_ino_d = ubifs_inode(new_inode)->data_len;
++              }
++      }
++
++      /*
++       * Note, rename may write @new_dir inode if the directory entry is
++       * moved there. And if the @new_dir is dirty, we do not bother to make
++       * it clean. It could be done, but requires extra coding which does not
++       * seem to be really worth it.
++       */
++      err = ubifs_budget_inode_op(c, old_dir, &req);
++      if (err)
++              return err;
++
++      /*
++       * Like most other Unix systems, set the ctime for inodes on a
++       * rename.
++       */
++      old_inode->i_ctime = time;
++
++      /*
++       * If we moved a directory to another parent directory, decrement
++       * 'i_nlink' of the old parent. Also, update 'i_size' of the old parent
++       * as well as its [mc]time.
++       */
++      if (is_dir && move)
++              drop_nlink(old_dir);
++      old_dir->i_size -= old_sz;
++      old_dir->i_mtime = old_dir->i_ctime = time;
++      new_dir->i_mtime = new_dir->i_ctime = time;
++
++      /*
++       * If we moved a directory object to new directory, parent's 'i_nlink'
++       * should be adjusted.
++       */
++      if (move && is_dir)
++              inc_nlink(new_dir);
++
++      /*
++       * And finally, if we unlinked a direntry which happened to have the
++       * same name as the moved direntry, we have to decrement 'i_nlink' of
++       * the unlinked inode and change its ctime.
++       */
++      if (unlink) {
++              /*
++               * Directories cannot have hard-links, so if this is a
++               * directory, decrement its 'i_nlink' twice because an empty
++               * directory has 'i_nlink' 2.
++               */
++              if (is_dir)
++                      drop_nlink(new_inode);
++              new_inode->i_ctime = time;
++              drop_nlink(new_inode);
++      } else
++              new_dir->i_size += new_sz;
++
++      err = ubifs_jnl_rename(c, old_dir, old_dentry, new_dir, new_dentry,
++                             dirsync);
++      if (err)
++              goto out_inode;
++
++      ubifs_release_ino_clean(c, old_dir, &req);
++      return 0;
++
++out_inode:
++      if (unlink) {
++              if (is_dir)
++                      inc_nlink(new_inode);
++              inc_nlink(new_inode);
++      } else
++              new_dir->i_size -= new_sz;
++      old_dir->i_size += old_sz;
++      if (is_dir && move) {
++              drop_nlink(new_dir);
++              inc_nlink(old_dir);
++      }
++      ubifs_cancel_ino_op(c, old_dir, &req);
++      return err;
++}
++
++int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
++                struct kstat *stat)
++{
++      struct inode *inode = dentry->d_inode;
++      loff_t size;
++
++      stat->dev = inode->i_sb->s_dev;
++      stat->ino = inode->i_ino;
++      stat->mode = inode->i_mode;
++      stat->nlink = inode->i_nlink;
++      stat->uid = inode->i_uid;
++      stat->gid = inode->i_gid;
++      stat->rdev = inode->i_rdev;
++      stat->atime = inode->i_atime;
++      stat->mtime = inode->i_mtime;
++      stat->ctime = inode->i_ctime;
++      stat->blksize = UBIFS_BLOCK_SIZE;
++      stat->size = i_size_read(inode);
++
++      spin_lock(&inode->i_lock);
++      size = ubifs_inode(inode)->xattr_size;
++      spin_unlock(&inode->i_lock);
++
++      /*
++       * Unfortunately, the 'stat()' system call was designed for block
++       * device based file systems, and it is not appropriate for UBIFS,
++       * because UBIFS does not have notion of "block". For example, it is
++       * difficult to tell how many block a directory takes - it actually
++       * takes less than 300 bytes, but we have to round it to block size,
++       * which introduces large mistake. This makes utilities like 'du' to
++       * report completely senseless numbers. This is the reason why UBIFS
++       * goes the same way as JFFS2 - it reports zero blocks for everything
++       * but regular files, which makes more sense than reporting completely
++       * wrong sizes.
++       */
++      if (S_ISREG(inode->i_mode))
++              size += stat->size;
++
++      size = ALIGN(size, UBIFS_BLOCK_SIZE);
++      /*
++       * Note, user-space expects 512-byte blocks count irrespectively of what
++       * was reported in @stat->size.
++       */
++      stat->blocks = size >> 9;
++
++      return 0;
++}
++
++struct inode_operations ubifs_dir_inode_operations = {
++      .lookup      = ubifs_lookup,
++      .create      = ubifs_create,
++      .link        = ubifs_link,
++      .symlink     = ubifs_symlink,
++      .unlink      = ubifs_unlink,
++      .mkdir       = ubifs_mkdir,
++      .rmdir       = ubifs_rmdir,
++      .mknod       = ubifs_mknod,
++      .rename      = ubifs_rename,
++      .setattr     = ubifs_setattr,
++      .getattr     = ubifs_getattr,
++#ifdef CONFIG_UBIFS_FS_XATTR
++      .setxattr    = ubifs_setxattr,
++      .getxattr    = ubifs_getxattr,
++      .listxattr   = ubifs_listxattr,
++      .removexattr = ubifs_removexattr,
++#endif
++};
++
++struct file_operations ubifs_dir_operations = {
++      .llseek         = ubifs_dir_llseek,
++      .release        = ubifs_dir_release,
++      .read           = generic_read_dir,
++      .readdir        = ubifs_readdir,
++      .fsync          = ubifs_fsync,
++      .unlocked_ioctl = ubifs_ioctl,
++#ifdef CONFIG_COMPAT
++      .compat_ioctl   = ubifs_compat_ioctl,
++#endif
++};
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/file.c avr32-2.6/fs/ubifs/file.c
+--- linux-2.6.25.6/fs/ubifs/file.c     1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/file.c  2008-06-12 15:09:45.364399968 +0200
+@@ -0,0 +1,960 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Artem Bityutskiy (Битюцкий Артём)
++ *          Adrian Hunter
++ */
++
++/*
++ * This file implements VFS file and inode operations of regular files, device
++ * nodes and symlinks as well as address space operations.
++ *
++ * UBIFS uses 2 page flags: PG_private and PG_checked. PG_private is set if the
++ * page is dirty and is used for budgeting purposes - dirty pages should not be
++ * budgeted. The PG_checked flag is set if full budgeting is required for the
++ * page e.g., when it corresponds to a file hole or it is just beyond the file
++ * size. The budgeting is done in 'ubifs_write_begin()', because it is OK to
++ * fail in this function, and the budget is released in 'ubifs_write_end()'. So
++ * the PG_private and PG_checked flags carry the information about how the page
++ * was budgeted, to make it possible to release the budget properly.
++ *
++ * A thing to keep in mind: inode's 'i_mutex' is locked in most VFS operations
++ * we implement. However, this is not true for '->writepage()', which might be
++ * called with 'i_mutex' unlocked. For example, when pdflush is performing
++ * write-back, it calls 'writepage()' with unlocked 'i_mutex', although the
++ * inode has 'I_LOCK' flag in this case. At "normal" work-paths 'i_mutex' is
++ * locked in '->writepage', e.g. in "sys_write -> alloc_pages -> direct reclaim
++ * path'. So, in '->writepage()' we are only guaranteed that the page is
++ * locked.
++ *
++ * Similarly, 'i_mutex' does not have to be locked in readpage(), e.g.,
++ * readahead path does not have it locked ("sys_read -> generic_file_aio_read
++ * -> ondemand_readahead -> readpage"). In case of readahead, 'I_LOCK' flag is
++ * not set as well.
++ *
++ * This, for example means that there might be 2 concurrent '->writepage()'
++ * calls for the same inode, but different inode dirty pages.
++ */
++
++#include "ubifs.h"
++#include <linux/mount.h>
++
++static int read_block(struct inode *inode, void *addr, unsigned int block,
++                    struct ubifs_data_node *dn)
++{
++      struct ubifs_info *c = inode->i_sb->s_fs_info;
++      int err, len, out_len;
++      union ubifs_key key;
++      unsigned int dlen;
++
++      data_key_init(c, &key, inode->i_ino, block);
++      err = ubifs_tnc_lookup(c, &key, dn);
++      if (err) {
++              if (err == -ENOENT)
++                      /* Not found, so it must be a hole */
++                      memset(addr, 0, UBIFS_BLOCK_SIZE);
++              return err;
++      }
++
++      ubifs_assert(dn->ch.sqnum > ubifs_inode(inode)->creat_sqnum);
++
++      len = le32_to_cpu(dn->size);
++      if (len <= 0 || len > UBIFS_BLOCK_SIZE)
++              goto dump;
++
++      dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
++      out_len = UBIFS_BLOCK_SIZE;
++      err = ubifs_decompress(&dn->data, dlen, addr, &out_len,
++                             le16_to_cpu(dn->compr_type));
++      if (err || len != out_len)
++              goto dump;
++
++      /*
++       * Data length can be less than a full block, even for blocks that are
++       * not the last in the file (e.g., as a result of making a hole and
++       * appending data). Ensure that the remainder is zeroed out.
++       */
++      if (len < UBIFS_BLOCK_SIZE)
++              memset(addr + len, 0, UBIFS_BLOCK_SIZE - len);
++
++      return 0;
++
++dump:
++      ubifs_err("bad data node (block %u, inode %lu)",
++                block, inode->i_ino);
++      dbg_dump_node(c, dn);
++      return -EINVAL;
++}
++
++static int do_readpage(struct page *page)
++{
++      void *addr;
++      int err = 0, i;
++      unsigned int block, beyond;
++      struct ubifs_data_node *dn;
++      struct inode *inode = page->mapping->host;
++      loff_t i_size = i_size_read(inode);
++
++      dbg_gen("ino %lu, pg %lu, i_size %lld, flags %#lx",
++              inode->i_ino, page->index, i_size, page->flags);
++      ubifs_assert(!PageChecked(page));
++      ubifs_assert(!PagePrivate(page));
++
++      addr = kmap(page);
++
++      block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
++      beyond = (i_size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
++      if (block >= beyond) {
++              /* Reading beyond inode */
++              SetPageChecked(page);
++              memset(addr, 0, PAGE_CACHE_SIZE);
++              goto out;
++      }
++
++      dn = kmalloc(UBIFS_MAX_DATA_NODE_SZ, GFP_NOFS);
++      if (!dn) {
++              err = -ENOMEM;
++              goto error;
++      }
++
++      i = 0;
++      while (1) {
++              int ret;
++
++              if (block >= beyond) {
++                      /* Reading beyond inode */
++                      err = -ENOENT;
++                      memset(addr, 0, UBIFS_BLOCK_SIZE);
++              } else {
++                      ret = read_block(inode, addr, block, dn);
++                      if (ret) {
++                              err = ret;
++                              if (err != -ENOENT)
++                                      break;
++                      }
++              }
++              if (++i >= UBIFS_BLOCKS_PER_PAGE)
++                      break;
++              block += 1;
++              addr += UBIFS_BLOCK_SIZE;
++      }
++      if (err) {
++              if (err == -ENOENT) {
++                      /* Not found, so it must be a hole */
++                      SetPageChecked(page);
++                      dbg_gen("hole");
++                      goto out_free;
++              }
++              ubifs_err("cannot read page %lu of inode %lu, error %d",
++                        page->index, inode->i_ino, err);
++              goto error;
++      }
++
++out_free:
++      kfree(dn);
++out:
++      SetPageUptodate(page);
++      ClearPageError(page);
++      flush_dcache_page(page);
++      kunmap(page);
++      return 0;
++
++error:
++      kfree(dn);
++      ClearPageUptodate(page);
++      SetPageError(page);
++      flush_dcache_page(page);
++      kunmap(page);
++      return err;
++}
++
++static int ubifs_write_begin(struct file *file, struct address_space *mapping,
++                           loff_t pos, unsigned len, unsigned flags,
++                           struct page **pagep, void **fsdata)
++{
++      struct inode *inode = mapping->host;
++      struct ubifs_info *c = inode->i_sb->s_fs_info;
++      pgoff_t index = pos >> PAGE_CACHE_SHIFT;
++      struct ubifs_budget_req req = { .new_page = 1 };
++      loff_t i_size =  i_size_read(inode);
++      int uninitialized_var(err);
++      struct page *page;
++
++      ubifs_assert(!(inode->i_sb->s_flags & MS_RDONLY));
++
++      if (unlikely(c->ro_media))
++              return -EROFS;
++
++      /*
++       * We are about to have a page of data written and we have to budget for
++       * this. The very important point here is that we have to budget before
++       * locking the page, because budgeting may force write-back, which
++       * would wait on locked pages and deadlock if we had the page locked.
++       *
++       * At this point we do not know anything about the page of data we are
++       * going to change, so assume the biggest budget (i.e., assume that
++       * this is a new page of data and it does not override an older page of
++       * data in the inode). Later the budget will be amended if this is not
++       * true.
++       */
++      if (pos + len > i_size)
++              /*
++               * We are writing beyond the file which means we are going to
++               * change inode size and make the inode dirty. And in turn,
++               * this means we have to budget for making the inode dirty.
++               *
++               * Note, if the inode is already dirty,
++               * 'ubifs_budget_inode_op()' will not allocate any budget,
++               * but will just lock the @budg_mutex of the inode to prevent
++               * it from becoming clean before we have changed its size,
++               * which is going to happen in 'ubifs_write_end()'.
++               */
++              err = ubifs_budget_inode_op(c, inode, &req);
++      else
++              /*
++               * The inode is not going to be marked as dirty by this write
++               * operation, do not budget for this.
++               */
++              err = ubifs_budget_space(c, &req);
++      if (unlikely(err))
++              return err;
++
++      page = __grab_cache_page(mapping, index);
++      if (unlikely(!page)) {
++              err = -ENOMEM;
++              goto out_release;
++      }
++
++      if (!PageUptodate(page)) {
++              /*
++               * The page is not loaded from the flash and has to be loaded
++               * unless we are writing all of it.
++               */
++              if (!(pos & PAGE_CACHE_MASK) && len == PAGE_CACHE_SIZE)
++                      /*
++                       * Set the PG_checked flag to make the further code
++                       * assume the page is new.
++                       */
++                      SetPageChecked(page);
++              else {
++                      err = do_readpage(page);
++                      if (err)
++                              goto out_unlock;
++              }
++
++              SetPageUptodate(page);
++              ClearPageError(page);
++      }
++
++      if (PagePrivate(page))
++              /*
++               * The page is dirty, which means it was budgeted twice:
++               *   o first time the budget was allocated by the task which
++               *     made the page dirty and set the PG_private flag;
++               *   o and then we budgeted for it for the second time at the
++               *     very beginning of this function.
++               *
++               * So what we have to do is to release the page budget we
++               * allocated.
++               *
++               * Note, the page write operation may change the inode length,
++               * which makes it dirty and means the budget should be
++               * allocated. This was done above in the "pos + len > i_size"
++               * case. If this was done, we do not free the the inode budget,
++               * because we cannot as we are really going to mark it dirty in
++               * the 'ubifs_write_end()' function.
++               */
++              ubifs_release_new_page_budget(c);
++      else if (!PageChecked(page))
++              /*
++               * The page is not new, which means we are changing the page
++               * which already exists on the media. This means that changing
++               * the page does not make the amount of indexing information
++               * larger, and this part of the budget which we have already
++               * acquired may be released.
++               */
++              ubifs_convert_page_budget(c);
++
++      *pagep = page;
++      return 0;
++
++out_unlock:
++      unlock_page(page);
++      page_cache_release(page);
++out_release:
++      if (pos + len > i_size)
++              ubifs_cancel_ino_op(c, inode, &req);
++      else
++              ubifs_release_budget(c, &req);
++      return err;
++}
++
++static int ubifs_write_end(struct file *file, struct address_space *mapping,
++                         loff_t pos, unsigned len, unsigned copied,
++                         struct page *page, void *fsdata)
++{
++      struct inode *inode = mapping->host;
++      struct ubifs_inode *ui = ubifs_inode(inode);
++      struct ubifs_info *c = inode->i_sb->s_fs_info;
++      loff_t i_size =  i_size_read(inode);
++
++      dbg_gen("ino %lu, pos %llu, pg %lu, len %u, copied %d, i_size %lld",
++              inode->i_ino, pos, page->index, len, copied, i_size);
++
++      if (unlikely(copied < len && len == PAGE_CACHE_SIZE)) {
++              /*
++               * VFS copied less data to the page that it intended and
++               * declared in its '->write_begin()' call via the @len
++               * argument. If the page was not up-to-date, and @len was
++               * @PAGE_CACHE_SIZE, the 'ubifs_write_begin()' function did
++               * not load it from the media (for optimization reasons). This
++               * means that part of the page contains garbage. So read the
++               * page now.
++               */
++              dbg_gen("copied %d instead of %d, read page and repeat",
++                      copied, len);
++
++              if (pos + len > i_size)
++                      /* See a comment below about this hacky unlock */
++                      mutex_unlock(&ui->budg_mutex);
++
++              copied = do_readpage(page);
++
++              /*
++               * Return 0 to force VFS to repeat the whole operation, or the
++               * error code if 'do_readpage()' failed.
++               */
++              goto out;
++      }
++
++      if (!PagePrivate(page)) {
++              SetPagePrivate(page);
++              atomic_long_inc(&c->dirty_pg_cnt);
++              __set_page_dirty_nobuffers(page);
++      }
++
++      if (pos + len > i_size) {
++              i_size_write(inode, pos + len);
++
++              /*
++               * Note, we do not set @I_DIRTY_PAGES (which means that the
++               * inode has dirty pages), this has been done in
++               * '__set_page_dirty_nobuffers()'.
++               */
++              mark_inode_dirty_sync(inode);
++
++              /*
++               * The inode has been marked dirty, unlock it. This is a bit
++               * hacky because normally we would have to call
++               * 'ubifs_release_ino_dirty()'. But we know there is nothing
++               * to release because page's budget will be released in
++               * 'ubifs_write_page()' and inode's budget will be released in
++               * 'ubifs_write_inode()', so just unlock the inode here for
++               * optimization.
++               */
++              mutex_unlock(&ui->budg_mutex);
++      }
++
++out:
++      unlock_page(page);
++      page_cache_release(page);
++      return copied;
++}
++
++static int ubifs_readpage(struct file *file, struct page *page)
++{
++      do_readpage(page);
++      unlock_page(page);
++      return 0;
++}
++
++/**
++ * release_existing_page_budget - release budget of an existing page.
++ * @c: UBIFS file-system description object
++ *
++ * This is a helper function which releases budget corresponding to the budget
++ * of changing one one page of data which already exists on the flash media.
++ *
++ * This function was not moved to "budget.c" because there is only one user.
++ */
++static void release_existing_page_budget(struct ubifs_info *c)
++{
++      struct ubifs_budget_req req = { .dd_growth = c->page_budget};
++
++      ubifs_release_budget(c, &req);
++}
++
++static int do_writepage(struct page *page, int len)
++{
++      int err = 0, i, blen;
++      unsigned int block;
++      void *addr;
++      union ubifs_key key;
++      struct inode *inode = page->mapping->host;
++      struct ubifs_info *c = inode->i_sb->s_fs_info;
++
++      /* Update radix tree tags */
++      set_page_writeback(page);
++
++      addr = kmap(page);
++
++      block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
++      i = 0;
++      while (len) {
++              blen = min_t(int, len, UBIFS_BLOCK_SIZE);
++              data_key_init(c, &key, inode->i_ino, block);
++              err = ubifs_jnl_write_data(c, inode, &key, addr, blen);
++              if (err)
++                      break;
++              if (++i >= UBIFS_BLOCKS_PER_PAGE)
++                      break;
++              block += 1;
++              addr += blen;
++              len -= blen;
++      }
++      if (err) {
++              SetPageError(page);
++              ubifs_err("cannot write page %lu of inode %lu, error %d",
++                        page->index, inode->i_ino, err);
++              ubifs_ro_mode(c, err);
++      }
++
++      ubifs_assert(PagePrivate(page));
++      if (PageChecked(page))
++              ubifs_release_new_page_budget(c);
++      else
++              release_existing_page_budget(c);
++
++      atomic_long_dec(&c->dirty_pg_cnt);
++      ClearPagePrivate(page);
++      ClearPageChecked(page);
++
++      kunmap(page);
++      unlock_page(page);
++      end_page_writeback(page);
++
++      return err;
++}
++
++static int ubifs_writepage(struct page *page, struct writeback_control *wbc)
++{
++      struct inode *inode = page->mapping->host;
++      loff_t i_size =  i_size_read(inode);
++      pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
++      int len;
++      void *kaddr;
++
++      dbg_gen("ino %lu, pg %lu, pg flags %#lx",
++              inode->i_ino, page->index, page->flags);
++      ubifs_assert(PagePrivate(page));
++
++      /* Is the page fully inside i_size? */
++      if (page->index < end_index)
++              return do_writepage(page, PAGE_CACHE_SIZE);
++
++      /* Is the page fully outside i_size? (truncate in progress) */
++      len = i_size & (PAGE_CACHE_SIZE - 1);
++      if (page->index >= end_index + 1 || !len) {
++              unlock_page(page);
++              return 0;
++      }
++
++      /*
++       * The page straddles i_size. It must be zeroed out on each and every
++       * writepage invocation because it may be mmapped. "A file is mapped
++       * in multiples of the page size. For a file that is not a multiple of
++       * the page size, the remaining memory is zeroed when mapped, and
++       * writes to that region are not written out to the file."
++       */
++      kaddr = kmap_atomic(page, KM_USER0);
++      memset(kaddr + len, 0, PAGE_CACHE_SIZE - len);
++      flush_dcache_page(page);
++      kunmap_atomic(kaddr, KM_USER0);
++
++      return do_writepage(page, len);
++}
++
++static int ubifs_trunc(struct inode *inode, loff_t new_size)
++{
++      loff_t old_size;
++      int err;
++
++      dbg_gen("ino %lu, size %lld -> %lld",
++              inode->i_ino, inode->i_size, new_size);
++      old_size = inode->i_size;
++
++      err = vmtruncate(inode, new_size);
++      if (err)
++              return err;
++
++      if (new_size < old_size) {
++              struct ubifs_info *c = inode->i_sb->s_fs_info;
++              int offset = new_size & (UBIFS_BLOCK_SIZE - 1);
++
++              if (offset) {
++                      pgoff_t index = new_size >> PAGE_CACHE_SHIFT;
++                      struct page *page;
++
++                      page = find_lock_page(inode->i_mapping, index);
++                      if (page) {
++                              if (PageDirty(page)) {
++                                      ubifs_assert(PagePrivate(page));
++
++                                      clear_page_dirty_for_io(page);
++                                      if (UBIFS_BLOCKS_PER_PAGE_SHIFT)
++                                              offset = new_size &
++                                                       (PAGE_CACHE_SIZE - 1);
++                                      err = do_writepage(page, offset);
++                                      page_cache_release(page);
++                                      if (err)
++                                              return err;
++                                      /*
++                                       * We could now tell ubifs_jnl_truncate
++                                       * not to read the last block.
++                                       */
++                              } else {
++                                      /*
++                                       * We could 'kmap()' the page and
++                                       * pass the data to ubifs_jnl_truncate
++                                       * to save it from having to read it.
++                                       */
++                                      unlock_page(page);
++                                      page_cache_release(page);
++                              }
++                      }
++              }
++              err = ubifs_jnl_truncate(c, inode->i_ino, old_size, new_size);
++              if (err)
++                      return err;
++      }
++
++      return 0;
++}
++
++int ubifs_setattr(struct dentry *dentry, struct iattr *attr)
++{
++      unsigned int ia_valid = attr->ia_valid;
++      struct inode *inode = dentry->d_inode;
++      struct ubifs_info *c = inode->i_sb->s_fs_info;
++      struct ubifs_budget_req req;
++      int truncation, err = 0;
++
++      dbg_gen("ino %lu, ia_valid %#x", inode->i_ino, ia_valid);
++      err = inode_change_ok(inode, attr);
++      if (err)
++              return err;
++
++      memset(&req, 0, sizeof(struct ubifs_budget_req));
++
++      /*
++       * If this is truncation, and we do not truncate on a block boundary,
++       * budget for changing one data block, because the last block will be
++       * re-written.
++       */
++      truncation = (ia_valid & ATTR_SIZE) && attr->ia_size != inode->i_size;
++      if (truncation && attr->ia_size < inode->i_size &&
++          (attr->ia_size & (UBIFS_BLOCK_SIZE - 1)))
++              req.dirtied_page = 1;
++
++      err = ubifs_budget_inode_op(c, inode, &req);
++      if (err)
++              return err;
++
++      if (truncation) {
++              err = ubifs_trunc(inode, attr->ia_size);
++              if (err) {
++                      ubifs_cancel_ino_op(c, inode, &req);
++                      return err;
++              }
++
++              inode->i_mtime = inode->i_ctime = ubifs_current_time(inode);
++      }
++
++      if (ia_valid & ATTR_UID)
++              inode->i_uid = attr->ia_uid;
++      if (ia_valid & ATTR_GID)
++              inode->i_gid = attr->ia_gid;
++      if (ia_valid & ATTR_ATIME)
++              inode->i_atime = timespec_trunc(attr->ia_atime,
++                                              inode->i_sb->s_time_gran);
++      if (ia_valid & ATTR_MTIME)
++              inode->i_mtime = timespec_trunc(attr->ia_mtime,
++                                              inode->i_sb->s_time_gran);
++      if (ia_valid & ATTR_CTIME)
++              inode->i_ctime = timespec_trunc(attr->ia_ctime,
++                                              inode->i_sb->s_time_gran);
++      if (ia_valid & ATTR_MODE) {
++              umode_t mode = attr->ia_mode;
++
++              if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
++                      mode &= ~S_ISGID;
++              inode->i_mode = mode;
++      }
++
++      mark_inode_dirty_sync(inode);
++      ubifs_release_ino_dirty(c, inode, &req);
++
++      if (req.dirtied_page) {
++              /*
++               * Truncation code does not make the reenacted page dirty, it
++               * just changes it on journal level, so we have to release page
++               * change budget.
++               */
++              memset(&req, 0, sizeof(struct ubifs_budget_req));
++              req.dd_growth = c->page_budget;
++              ubifs_release_budget(c, &req);
++      }
++
++      if (IS_SYNC(inode))
++              err = write_inode_now(inode, 1);
++
++      return err;
++}
++
++static void ubifs_invalidatepage(struct page *page, unsigned long offset)
++{
++      struct inode *inode = page->mapping->host;
++      struct ubifs_info *c = inode->i_sb->s_fs_info;
++      struct ubifs_budget_req req;
++
++      ubifs_assert(PagePrivate(page));
++      if (offset)
++              /* Partial page remains dirty */
++              return;
++
++      memset(&req, 0, sizeof(struct ubifs_budget_req));
++      if (PageChecked(page)) {
++              req.new_page = 1;
++              req.idx_growth = -1;
++              req.data_growth = c->page_budget;
++      } else
++              req.dd_growth = c->page_budget;
++      ubifs_release_budget(c, &req);
++
++      atomic_long_dec(&c->dirty_pg_cnt);
++      ClearPagePrivate(page);
++      ClearPageChecked(page);
++}
++
++static void *ubifs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++      struct ubifs_inode *ui = ubifs_inode(dentry->d_inode);
++
++      nd_set_link(nd, ui->data);
++      return NULL;
++}
++
++int ubifs_fsync(struct file *file, struct dentry *dentry, int datasync)
++{
++      struct inode *inode = dentry->d_inode;
++      struct ubifs_info *c = inode->i_sb->s_fs_info;
++      int err;
++
++      dbg_gen("syncing inode %lu", inode->i_ino);
++
++      /* Synchronize the inode and dirty pages */
++      err = write_inode_now(inode, 1);
++      if (err)
++              return err;
++
++      /*
++       * Some data related to this inode may still sit in a write-buffer.
++       * Flush them.
++       */
++      err = ubifs_sync_wbufs_by_inodes(c, &inode, 1);
++      if (err)
++              return err;
++
++      return 0;
++}
++
++/**
++ * mctime_update_needed - check if mtime or ctime update is needed.
++ * @inode: the inode to do the check for
++ * @now: current time
++ *
++ * This helper function checks if the inode mtime/ctime should be updated or
++ * not. If current values of the time-stamps are within the UBIFS inode time
++ * granularity, they are not updated. This is an optimization.
++ */
++static inline int mctime_update_needed(const struct inode *inode,
++                                     const struct timespec *now)
++{
++      if (!timespec_equal(&inode->i_mtime, now) ||
++          !timespec_equal(&inode->i_ctime, now))
++              return 1;
++      return 0;
++}
++
++/**
++ * update_ctime - update mtime and ctime of an inode.
++ * @c: UBIFS file-system description object
++ * @inode: inode to update
++ *
++ * This function updates mtime and ctime of the inode if it is not equivalent to
++ * current time. Returns zero in case of success and a negative error code in
++ * case of failure.
++ */
++static int update_mctime(struct ubifs_info *c, struct inode *inode)
++{
++      struct timespec now = ubifs_current_time(inode);
++
++      if (mctime_update_needed(inode, &now)) {
++              struct ubifs_budget_req req;
++              int err;
++
++              memset(&req, 0, sizeof(struct ubifs_budget_req));
++              err = ubifs_budget_inode_op(c, inode, &req);
++              if (err)
++                      return err;
++
++              inode->i_mtime = inode->i_ctime = now;
++              mark_inode_dirty_sync(inode);
++              mutex_unlock(&ubifs_inode(inode)->budg_mutex);
++      }
++
++      return 0;
++}
++
++static ssize_t ubifs_write(struct file *file, const char __user *buf,
++                         size_t len, loff_t *ppos)
++{
++      int err;
++      ssize_t ret;
++      struct inode *inode = file->f_mapping->host;
++      struct ubifs_info *c = inode->i_sb->s_fs_info;
++
++      err = update_mctime(c, inode);
++      if (err)
++              return err;
++
++      ret = do_sync_write(file, buf, len, ppos);
++      if (ret < 0)
++              return ret;
++
++      if (ret > 0 && IS_SYNC(inode)) {
++              err = ubifs_sync_wbufs_by_inodes(c, &inode, 1);
++              if (err)
++                      return err;
++      }
++
++      return ret;
++}
++
++static ssize_t ubifs_aio_write(struct kiocb *iocb, const struct iovec *iov,
++                             unsigned long nr_segs, loff_t pos)
++{
++      int err;
++      ssize_t ret;
++      struct inode *inode = iocb->ki_filp->f_mapping->host;
++      struct ubifs_info *c = inode->i_sb->s_fs_info;
++
++      err = update_mctime(c, inode);
++      if (err)
++              return err;
++
++      ret = generic_file_aio_write(iocb, iov, nr_segs, pos);
++      if (ret < 0)
++              return ret;
++
++      if (ret > 0 && IS_SYNC(inode)) {
++              err = ubifs_sync_wbufs_by_inodes(c, &inode, 1);
++              if (err)
++                      return err;
++      }
++
++      return ret;
++}
++
++static int ubifs_set_page_dirty(struct page *page)
++{
++      int ret;
++
++      ret = __set_page_dirty_nobuffers(page);
++      /*
++       * An attempt to dirty a page without budgeting for it - should not
++       * happen.
++       */
++      ubifs_assert(ret == 0);
++      return ret;
++}
++
++static int ubifs_releasepage(struct page *page, gfp_t unused_gfp_flags)
++{
++      /*
++       * An attempt to release a dirty page without budgeting for it - should
++       * not happen.
++       */
++      if (PageWriteback(page))
++              return 0;
++      ubifs_assert(PagePrivate(page));
++      ubifs_assert(0);
++      ClearPagePrivate(page);
++      ClearPageChecked(page);
++      return 1;
++}
++
++/*
++ * mmap()d file has taken write protection fault and is being made
++ * writable. UBIFS must ensure page is budgeted for.
++ */
++static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
++{
++      struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
++      struct ubifs_info *c = inode->i_sb->s_fs_info;
++      struct timespec now = ubifs_current_time(inode);
++      struct ubifs_budget_req req = { .new_page = 1 };
++      int err, update_time;
++
++      dbg_gen("ino %lu, pg %lu, i_size %lld", inode->i_ino, page->index,
++              i_size_read(inode));
++      ubifs_assert(!(inode->i_sb->s_flags & MS_RDONLY));
++
++      if (unlikely(c->ro_media))
++              return -EROFS;
++
++      /*
++       * We have not locked @page so far so we may budget for changing the
++       * page. Note, we cannot do this after we locked the page, because
++       * budgeting may cause write-back which would cause deadlock.
++       *
++       * At the moment we do not know whether the page is dirty or not, so we
++       * assume that it is not and budget for a new page. We could look at
++       * the @PG_private flag and figure this out, but we may race with write
++       * back and the page state may change by the time we lock it, so this
++       * would need additional care. We do not bother with this at the
++       * moment, although it might be good idea to do. Instead, we allocate
++       * budget for a new page and amend it later on if the page was in fact
++       * dirty.
++       *
++       * The budgeting-related logic of this function is similar to what we
++       * do in 'ubifs_write_begin()' and 'ubifs_write_end()'. Glance there
++       * for more comments.
++       */
++      if (mctime_update_needed(inode, &now)) {
++              /*
++               * We have to change inode time stamp which requires extra
++               * budgeting.
++               */
++              update_time = 1;
++              err = ubifs_budget_inode_op(c, inode, &req);
++      } else {
++              update_time = 0;
++              err = ubifs_budget_space(c, &req);
++      }
++      if (unlikely(err)) {
++              if (err == -ENOSPC)
++                      ubifs_warn("out of space for mmapped file "
++                                 "(inode number %lu)", inode->i_ino);
++              return err;
++      }
++
++      lock_page(page);
++      if (unlikely(page->mapping != inode->i_mapping ||
++                   page_offset(page) > i_size_read(inode))) {
++              /* Page got truncated out from underneath us */
++              err = -EINVAL;
++              goto out_unlock;
++      }
++
++      if (PagePrivate(page))
++              ubifs_release_new_page_budget(c);
++      else {
++              if (!PageChecked(page))
++                      ubifs_convert_page_budget(c);
++              SetPagePrivate(page);
++              atomic_long_inc(&c->dirty_pg_cnt);
++              __set_page_dirty_nobuffers(page);
++      }
++
++      if (update_time) {
++              inode->i_mtime = inode->i_ctime = now;
++              mark_inode_dirty_sync(inode);
++              mutex_unlock(&ubifs_inode(inode)->budg_mutex);
++      }
++
++      unlock_page(page);
++      return 0;
++
++out_unlock:
++      unlock_page(page);
++      if (update_time)
++              ubifs_cancel_ino_op(c, inode, &req);
++      else
++              ubifs_release_budget(c, &req);
++      return err;
++}
++
++struct vm_operations_struct ubifs_file_vm_ops = {
++      .fault        = filemap_fault,
++      .page_mkwrite = ubifs_vm_page_mkwrite,
++};
++
++static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
++{
++      int err;
++
++      /* 'generic_file_mmap()' takes care of NOMMU case */
++      err = generic_file_mmap(file, vma);
++      if (err)
++              return err;
++      vma->vm_ops = &ubifs_file_vm_ops;
++      return 0;
++}
++
++struct address_space_operations ubifs_file_address_operations = {
++      .readpage       = ubifs_readpage,
++      .writepage      = ubifs_writepage,
++      .write_begin    = ubifs_write_begin,
++      .write_end      = ubifs_write_end,
++      .invalidatepage = ubifs_invalidatepage,
++      .set_page_dirty = ubifs_set_page_dirty,
++      .releasepage    = ubifs_releasepage,
++};
++
++struct inode_operations ubifs_file_inode_operations = {
++      .setattr     = ubifs_setattr,
++      .getattr     = ubifs_getattr,
++#ifdef CONFIG_UBIFS_FS_XATTR
++      .setxattr    = ubifs_setxattr,
++      .getxattr    = ubifs_getxattr,
++      .listxattr   = ubifs_listxattr,
++      .removexattr = ubifs_removexattr,
++#endif
++};
++
++struct inode_operations ubifs_symlink_inode_operations = {
++      .readlink    = generic_readlink,
++      .follow_link = ubifs_follow_link,
++      .setattr     = ubifs_setattr,
++      .getattr     = ubifs_getattr,
++};
++
++struct file_operations ubifs_file_operations = {
++      .llseek         = generic_file_llseek,
++      .read           = do_sync_read,
++      .write          = ubifs_write,
++      .aio_read       = generic_file_aio_read,
++      .aio_write      = ubifs_aio_write,
++      .mmap           = ubifs_file_mmap,
++      .fsync          = ubifs_fsync,
++      .unlocked_ioctl = ubifs_ioctl,
++#ifdef CONFIG_COMPAT
++      .compat_ioctl   = ubifs_compat_ioctl,
++#endif
++};
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/find.c avr32-2.6/fs/ubifs/find.c
+--- linux-2.6.25.6/fs/ubifs/find.c     1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/find.c  2008-06-12 15:09:45.364399968 +0200
+@@ -0,0 +1,977 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Artem Bityutskiy (Битюцкий Артём)
++ *          Adrian Hunter
++ */
++
++/*
++ * This file contains functions for finding LEBs for various purposes e.g.
++ * garbage collection. In general, lprops category heaps and lists are used
++ * for fast access, falling back on scanning the LPT as a last resort.
++ */
++
++#include <linux/sort.h>
++#include "ubifs.h"
++
++/**
++ * struct scan_data - data provided to scan callback functions
++ * @min_space: minimum number of bytes for which to scan
++ * @pick_free: whether it is OK to scan for empty LEBs
++ * @lnum: LEB number found is returned here
++ * @exclude_index: whether to exclude index LEBs
++ */
++struct scan_data {
++      int min_space;
++      int pick_free;
++      int lnum;
++      int exclude_index;
++};
++
++/**
++ * valuable - determine whether LEB properties are valuable.
++ * @c: the UBIFS file-system description object
++ * @lprops: LEB properties
++ *
++ * This function return %1 if the LEB properties should be added to the LEB
++ * properties tree in memory. Otherwise %0 is returned.
++ */
++static int valuable(struct ubifs_info *c, const struct ubifs_lprops *lprops)
++{
++      int n, cat = lprops->flags & LPROPS_CAT_MASK;
++      struct ubifs_lpt_heap *heap;
++
++      switch (cat) {
++      case LPROPS_DIRTY:
++      case LPROPS_DIRTY_IDX:
++      case LPROPS_FREE:
++              heap = &c->lpt_heap[cat - 1];
++              if (heap->cnt < heap->max_cnt)
++                      return 1;
++              if (lprops->free + lprops->dirty >= c->dark_wm)
++                      return 1;
++              return 0;
++      case LPROPS_EMPTY:
++              n = c->lst.empty_lebs + c->freeable_cnt -
++                  c->lst.taken_empty_lebs;
++              if (n < c->lsave_cnt)
++                      return 1;
++              return 0;
++      case LPROPS_FREEABLE:
++              return 1;
++      case LPROPS_FRDI_IDX:
++              return 1;
++      }
++      return 0;
++}
++
++/**
++ * scan_for_dirty_cb - dirty space scan callback.
++ * @c: the UBIFS file-system description object
++ * @lprops: LEB properties to scan
++ * @in_tree: whether the LEB properties are in main memory
++ * @data: information passed to and from the caller of the scan
++ *
++ * This function returns a code that indicates whether the scan should continue
++ * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree
++ * in main memory (%LPT_SCAN_ADD), or whether the scan should stop
++ * (%LPT_SCAN_STOP).
++ */
++static int scan_for_dirty_cb(struct ubifs_info *c,
++                           const struct ubifs_lprops *lprops, int in_tree,
++                           struct scan_data *data)
++{
++      int ret = LPT_SCAN_CONTINUE;
++
++      /* Exclude LEBs that are currently in use */
++      if (lprops->flags & LPROPS_TAKEN)
++              return LPT_SCAN_CONTINUE;
++      /* Determine whether to add these LEB properties to the tree */
++      if (!in_tree && valuable(c, lprops))
++              ret |= LPT_SCAN_ADD;
++      /* Exclude LEBs with too little space */
++      if (lprops->free + lprops->dirty < data->min_space)
++              return ret;
++      /* If specified, exclude index LEBs */
++      if (data->exclude_index && lprops->flags & LPROPS_INDEX)
++              return ret;
++      /* If specified, exclude empty or freeable LEBs */
++      if (lprops->free + lprops->dirty == c->leb_size) {
++              if (!data->pick_free)
++                      return ret;
++      /* Exclude LEBs with too little dirty space (unless it is empty) */
++      } else if (lprops->dirty < c->dead_wm)
++              return ret;
++      /* Finally we found space */
++      data->lnum = lprops->lnum;
++      return LPT_SCAN_ADD | LPT_SCAN_STOP;
++}
++
++/**
++ * scan_for_dirty - find a data LEB with free space.
++ * @c: the UBIFS file-system description object
++ * @min_space: minimum amount free plus dirty space the returned LEB has to
++ *             have
++ * @pick_free: if it is OK to return a free or freeable LEB
++ * @exclude_index: whether to exclude index LEBs
++ *
++ * This function returns a pointer to the LEB properties found or a negative
++ * error code.
++ */
++static const struct ubifs_lprops *scan_for_dirty(struct ubifs_info *c,
++                                               int min_space, int pick_free,
++                                               int exclude_index)
++{
++      const struct ubifs_lprops *lprops;
++      struct ubifs_lpt_heap *heap;
++      struct scan_data data;
++      int err, i;
++
++      /* There may be an LEB with enough dirty space on the free heap */
++      heap = &c->lpt_heap[LPROPS_FREE - 1];
++      for (i = 0; i < heap->cnt; i++) {
++              lprops = heap->arr[i];
++              if (lprops->free + lprops->dirty < min_space)
++                      continue;
++              if (lprops->dirty < c->dead_wm)
++                      continue;
++              return lprops;
++      }
++      /*
++       * A LEB may have fallen off of the bottom of the dirty heap, and ended
++       * up as uncategorized even though it has enough dirty space for us now,
++       * so check the uncategorized list. N.B. neither empty nor freeable LEBs
++       * can end up as uncategorized because they are kept on lists not
++       * finite-sized heaps.
++       */
++      list_for_each_entry(lprops, &c->uncat_list, list) {
++              if (lprops->flags & LPROPS_TAKEN)
++                      continue;
++              if (lprops->free + lprops->dirty < min_space)
++                      continue;
++              if (exclude_index && (lprops->flags & LPROPS_INDEX))
++                      continue;
++              if (lprops->dirty < c->dead_wm)
++                      continue;
++              return lprops;
++      }
++      /* We have looked everywhere in main memory, now scan the flash */
++      if (c->pnodes_have >= c->pnode_cnt)
++              /* All pnodes are in memory, so skip scan */
++              return ERR_PTR(-ENOSPC);
++      data.min_space = min_space;
++      data.pick_free = pick_free;
++      data.lnum = -1;
++      data.exclude_index = exclude_index;
++      err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum,
++                                  (ubifs_lpt_scan_callback)scan_for_dirty_cb,
++                                  &data);
++      if (err)
++              return ERR_PTR(err);
++      ubifs_assert(data.lnum >= c->main_first && data.lnum < c->leb_cnt);
++      c->lscan_lnum = data.lnum;
++      lprops = ubifs_lpt_lookup_dirty(c, data.lnum);
++      if (IS_ERR(lprops))
++              return lprops;
++      ubifs_assert(lprops->lnum == data.lnum);
++      ubifs_assert(lprops->free + lprops->dirty >= min_space);
++      ubifs_assert(lprops->dirty >= c->dead_wm ||
++                   (pick_free &&
++                    lprops->free + lprops->dirty == c->leb_size));
++      ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
++      ubifs_assert(!(lprops->flags & LPROPS_INDEX));
++      return lprops;
++}
++
++/**
++ * ubifs_find_dirty_leb - find a dirty LEB for the Garbage Collector.
++ * @c: the UBIFS file-system description object
++ * @ret_lp: LEB properties are returned here on exit
++ * @min_space: minimum amount free plus dirty space the returned LEB has to
++ *             have
++ * @pick_free: controls whether it is OK to pick empty or index LEBs
++ *
++ * This function tries to find a dirty logical eraseblock which has at least
++ * @min_space free and dirty space. It prefers to take an LEB from the dirty or
++ * dirty index heap, and it falls-back to LPT scanning if the heaps are empty
++ * or do not have an LEB which satisfies the @min_space criteria.
++ *
++ * Note:
++ *   o LEBs which have less than dead watermark of dirty space are never picked
++ *   by this function;
++ *
++ * Returns zero and the LEB properties of
++ * found dirty LEB in case of success, %-ENOSPC if no dirty LEB was found and a
++ * negative error code in case of other failures. The returned LEB is marked as
++ * "taken".
++ *
++ * The additional @pick_free argument controls if this function has to return a
++ * free or freeable LEB if one is present. For example, GC must to set it to %1,
++ * when called from the journal space reservation function, because the
++ * appearance of free space may coincide with the loss of enough dirty space
++ * for GC to succeed anyway.
++ *
++ * In contrast, if the Garbage Collector is called from budgeting, it should
++ * just make free space, not return LEBs which are already free or freeable.
++ *
++ * In addition @pick_free is set to %2 by the recovery process in order to
++ * recover gc_lnum in which case an index LEB must not be returned.
++ */
++int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
++                       int min_space, int pick_free)
++{
++      int err = 0, sum, exclude_index = pick_free == 2 ? 1 : 0;
++      const struct ubifs_lprops *lp = NULL, *idx_lp = NULL;
++      struct ubifs_lpt_heap *heap, *idx_heap;
++
++      ubifs_get_lprops(c);
++
++      if (pick_free) {
++              int lebs, rsvd_idx_lebs = 0;
++
++              spin_lock(&c->space_lock);
++              lebs = c->lst.empty_lebs;
++              lebs += c->freeable_cnt - c->lst.taken_empty_lebs;
++
++              /*
++               * Note, the index may consume more LEBs than have been reserved
++               * for it. It is OK because it might be consolidated by GC.
++               * But if the index takes fewer LEBs than it is reserved for it,
++               * this function must avoid picking those reserved LEBs.
++               */
++              if (c->min_idx_lebs >= c->lst.idx_lebs) {
++                      rsvd_idx_lebs = c->min_idx_lebs -  c->lst.idx_lebs;
++                      exclude_index = 1;
++              }
++              spin_unlock(&c->space_lock);
++
++              /* Check if there are enough free LEBs for the index */
++              if (rsvd_idx_lebs < lebs) {
++                      /* OK, try to find an empty LEB */
++                      lp = ubifs_fast_find_empty(c);
++                      if (lp)
++                              goto found;
++
++                      /* Or a freeable LEB */
++                      lp = ubifs_fast_find_freeable(c);
++                      if (lp)
++                              goto found;
++              } else
++                      /*
++                       * We cannot pick free/freeable LEBs in the below code.
++                       */
++                      pick_free = 0;
++      } else {
++              spin_lock(&c->space_lock);
++              exclude_index = (c->min_idx_lebs >= c->lst.idx_lebs);
++              spin_unlock(&c->space_lock);
++      }
++
++      /* Look on the dirty and dirty index heaps */
++      heap = &c->lpt_heap[LPROPS_DIRTY - 1];
++      idx_heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1];
++
++      if (idx_heap->cnt && !exclude_index) {
++              idx_lp = idx_heap->arr[0];
++              sum = idx_lp->free + idx_lp->dirty;
++              /*
++               * Since we reserve twice as more space for the index than it
++               * actually takes, it does not make sense to pick indexing LEBs
++               * with less than half LEB of dirty space.
++               */
++              if (sum < min_space || sum < c->half_leb_size)
++                      idx_lp = NULL;
++      }
++
++      if (heap->cnt) {
++              lp = heap->arr[0];
++              if (lp->dirty + lp->free < min_space)
++                      lp = NULL;
++      }
++
++      /* Pick the LEB with most space */
++      if (idx_lp && lp) {
++              if (idx_lp->free + idx_lp->dirty >= lp->free + lp->dirty)
++                      lp = idx_lp;
++      } else if (idx_lp && !lp)
++              lp = idx_lp;
++
++      if (lp) {
++              ubifs_assert(lp->dirty >= c->dead_wm);
++              goto found;
++      }
++
++      /* Did not find a dirty LEB on the dirty heaps, have to scan */
++      dbg_find("scanning LPT for a dirty LEB");
++      lp = scan_for_dirty(c, min_space, pick_free, exclude_index);
++      if (IS_ERR(lp)) {
++              err = PTR_ERR(lp);
++              goto out;
++      }
++      ubifs_assert(lp->dirty >= c->dead_wm ||
++                   (pick_free && lp->free + lp->dirty == c->leb_size));
++
++found:
++      dbg_find("found LEB %d, free %d, dirty %d, flags %#x",
++               lp->lnum, lp->free, lp->dirty, lp->flags);
++
++      lp = ubifs_change_lp(c, lp, LPROPS_NC, LPROPS_NC,
++                           lp->flags | LPROPS_TAKEN, 0);
++      if (IS_ERR(lp)) {
++              err = PTR_ERR(lp);
++              goto out;
++      }
++
++      memcpy(ret_lp, lp, sizeof(struct ubifs_lprops));
++
++out:
++      ubifs_release_lprops(c);
++      return err;
++}
++
++/**
++ * scan_for_free_cb - free space scan callback.
++ * @c: the UBIFS file-system description object
++ * @lprops: LEB properties to scan
++ * @in_tree: whether the LEB properties are in main memory
++ * @data: information passed to and from the caller of the scan
++ *
++ * This function returns a code that indicates whether the scan should continue
++ * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree
++ * in main memory (%LPT_SCAN_ADD), or whether the scan should stop
++ * (%LPT_SCAN_STOP).
++ */
++static int scan_for_free_cb(struct ubifs_info *c,
++                          const struct ubifs_lprops *lprops, int in_tree,
++                          struct scan_data *data)
++{
++      int ret = LPT_SCAN_CONTINUE;
++
++      /* Exclude LEBs that are currently in use */
++      if (lprops->flags & LPROPS_TAKEN)
++              return LPT_SCAN_CONTINUE;
++      /* Determine whether to add these LEB properties to the tree */
++      if (!in_tree && valuable(c, lprops))
++              ret |= LPT_SCAN_ADD;
++      /* Exclude index LEBs */
++      if (lprops->flags & LPROPS_INDEX)
++              return ret;
++      /* Exclude LEBs with too little space */
++      if (lprops->free < data->min_space)
++              return ret;
++      /* If specified, exclude empty LEBs */
++      if (!data->pick_free && lprops->free == c->leb_size)
++              return ret;
++      /*
++       * LEBs that have only free and dirty space must not be allocated
++       * because they may have been unmapped already or they may have data
++       * that is obsolete only because of nodes that are still sitting in a
++       * wbuf.
++       */
++      if (lprops->free + lprops->dirty == c->leb_size && lprops->dirty > 0)
++              return ret;
++      /* Finally we found space */
++      data->lnum = lprops->lnum;
++      return LPT_SCAN_ADD | LPT_SCAN_STOP;
++}
++
++/**
++ * do_find_free_space - find a data LEB with free space.
++ * @c: the UBIFS file-system description object
++ * @min_space: minimum amount of free space required
++ * @pick_free: whether it is OK to scan for empty LEBs
++ * @squeeze: whether to try to find space in a non-empty LEB first
++ *
++ * This function returns a pointer to the LEB properties found or a negative
++ * error code.
++ */
++static
++const struct ubifs_lprops *do_find_free_space(struct ubifs_info *c,
++                                            int min_space, int pick_free,
++                                            int squeeze)
++{
++      const struct ubifs_lprops *lprops;
++      struct ubifs_lpt_heap *heap;
++      struct scan_data data;
++      int err, i;
++
++      if (squeeze) {
++              lprops = ubifs_fast_find_free(c);
++              if (lprops && lprops->free >= min_space)
++                      return lprops;
++      }
++      if (pick_free) {
++              lprops = ubifs_fast_find_empty(c);
++              if (lprops)
++                      return lprops;
++      }
++      if (!squeeze) {
++              lprops = ubifs_fast_find_free(c);
++              if (lprops && lprops->free >= min_space)
++                      return lprops;
++      }
++      /* There may be an LEB with enough free space on the dirty heap */
++      heap = &c->lpt_heap[LPROPS_DIRTY - 1];
++      for (i = 0; i < heap->cnt; i++) {
++              lprops = heap->arr[i];
++              if (lprops->free >= min_space)
++                      return lprops;
++      }
++      /*
++       * A LEB may have fallen off of the bottom of the free heap, and ended
++       * up as uncategorized even though it has enough free space for us now,
++       * so check the uncategorized list. N.B. neither empty nor freeable LEBs
++       * can end up as uncategorized because they are kept on lists not
++       * finite-sized heaps.
++       */
++      list_for_each_entry(lprops, &c->uncat_list, list) {
++              if (lprops->flags & LPROPS_TAKEN)
++                      continue;
++              if (lprops->flags & LPROPS_INDEX)
++                      continue;
++              if (lprops->free >= min_space)
++                      return lprops;
++      }
++      /* We have looked everywhere in main memory, now scan the flash */
++      if (c->pnodes_have >= c->pnode_cnt)
++              /* All pnodes are in memory, so skip scan */
++              return ERR_PTR(-ENOSPC);
++      data.min_space = min_space;
++      data.pick_free = pick_free;
++      data.lnum = -1;
++      err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum,
++                                  (ubifs_lpt_scan_callback)scan_for_free_cb,
++                                  &data);
++      if (err)
++              return ERR_PTR(err);
++      ubifs_assert(data.lnum >= c->main_first && data.lnum < c->leb_cnt);
++      c->lscan_lnum = data.lnum;
++      lprops = ubifs_lpt_lookup_dirty(c, data.lnum);
++      if (IS_ERR(lprops))
++              return lprops;
++      ubifs_assert(lprops->lnum == data.lnum);
++      ubifs_assert(lprops->free >= min_space);
++      ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
++      ubifs_assert(!(lprops->flags & LPROPS_INDEX));
++      return lprops;
++}
++
++/**
++ * ubifs_find_free_space - find a data LEB with free space.
++ * @c: the UBIFS file-system description object
++ * @min_space: minimum amount of required free space
++ * @free: contains amount of free space in the LEB on exit
++ * @squeeze: whether to try to find space in a non-empty LEB first
++ *
++ * This function looks for an LEB with at least @min_space bytes of free space.
++ * It tries to find an empty LEB if possible. If no empty LEBs are available,
++ * this function searches for a non-empty data LEB. The returned LEB is marked
++ * as "taken".
++ *
++ * This function returns found LEB number in case of success, %-ENOSPC if it
++ * failed to find a LEB with @min_space bytes of free space and other a negative
++ * error codes in case of failure.
++ */
++int ubifs_find_free_space(struct ubifs_info *c, int min_space, int *free,
++                        int squeeze)
++{
++      const struct ubifs_lprops *lprops;
++      int lebs, rsvd_idx_lebs, pick_free = 0, err, lnum, flags;
++
++      dbg_find("min_space %d", min_space);
++      ubifs_assert(min_space > 0 && min_space <= c->dark_wm);
++
++      ubifs_get_lprops(c);
++
++      /* Check if there are enough empty LEBs for commit */
++      spin_lock(&c->space_lock);
++      if (c->min_idx_lebs > c->lst.idx_lebs)
++              rsvd_idx_lebs = c->min_idx_lebs -  c->lst.idx_lebs;
++      else
++              rsvd_idx_lebs = 0;
++      lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
++             c->lst.taken_empty_lebs;
++      ubifs_assert(lebs + c->lst.idx_lebs >= c->min_idx_lebs);
++      if (rsvd_idx_lebs < lebs)
++              /*
++               * OK to allocate an empty LEB, but we still don't want to go
++               * looking for one if there aren't any.
++               */
++              if (c->lst.empty_lebs - c->lst.taken_empty_lebs > 0) {
++                      pick_free = 1;
++                      /*
++                       * Because we release the space lock, we must account
++                       * for this allocation here. After the LEB properties
++                       * flags have been updated, we subtract one. Note, the
++                       * result of this is that lprops also decreases
++                       * @taken_empty_lebs in 'ubifs_change_lp()', so it is
++                       * off by one for a short period of time which may
++                       * introduce a small disturbance to budgeting
++                       * calculations, but this is harmless because at the
++                       * worst case this would make the budgeting subsystem
++                       * be more pessimistic than needed.
++                       *
++                       * Fundamentally, this is about serialization of the
++                       * budgeting and lprops subsystems. We could make the
++                       * @space_lock a mutex and avoid dropping it before
++                       * calling 'ubifs_change_lp()', but mutex is more
++                       * heavy-weight, and we want budgeting to be as fast as
++                       * possible.
++                       */
++                      c->lst.taken_empty_lebs += 1;
++              }
++      spin_unlock(&c->space_lock);
++
++      lprops = do_find_free_space(c, min_space, pick_free, squeeze);
++      if (IS_ERR(lprops)) {
++              err = PTR_ERR(lprops);
++              goto out;
++      }
++
++      lnum = lprops->lnum;
++      flags = lprops->flags | LPROPS_TAKEN;
++
++      lprops = ubifs_change_lp(c, lprops, LPROPS_NC, LPROPS_NC, flags, 0);
++      if (IS_ERR(lprops)) {
++              err = PTR_ERR(lprops);
++              goto out;
++      }
++
++      if (pick_free) {
++              spin_lock(&c->space_lock);
++              c->lst.taken_empty_lebs -= 1;
++              spin_unlock(&c->space_lock);
++      }
++
++      *free = lprops->free;
++      ubifs_release_lprops(c);
++
++      if (*free == c->leb_size) {
++              /*
++               * Ensure that empty LEBs have been unmapped. They may not have
++               * been, for example, because of an unclean unmount.  Also
++               * LEBs that were freeable LEBs (free + dirty == leb_size) will
++               * not have been unmapped.
++               */
++              err = ubifs_leb_unmap(c, lnum);
++              if (err)
++                      return err;
++      }
++
++      dbg_find("found LEB %d, free %d", lnum, *free);
++      ubifs_assert(*free >= min_space);
++      return lnum;
++
++out:
++      if (pick_free) {
++              spin_lock(&c->space_lock);
++              c->lst.taken_empty_lebs -= 1;
++              spin_unlock(&c->space_lock);
++      }
++      ubifs_release_lprops(c);
++      return err;
++}
++
++/**
++ * scan_for_idx_cb - callback used by the scan for a free LEB for the index.
++ * @c: the UBIFS file-system description object
++ * @lprops: LEB properties to scan
++ * @in_tree: whether the LEB properties are in main memory
++ * @data: information passed to and from the caller of the scan
++ *
++ * This function returns a code that indicates whether the scan should continue
++ * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree
++ * in main memory (%LPT_SCAN_ADD), or whether the scan should stop
++ * (%LPT_SCAN_STOP).
++ */
++static int scan_for_idx_cb(struct ubifs_info *c,
++                         const struct ubifs_lprops *lprops, int in_tree,
++                         struct scan_data *data)
++{
++      int ret = LPT_SCAN_CONTINUE;
++
++      /* Exclude LEBs that are currently in use */
++      if (lprops->flags & LPROPS_TAKEN)
++              return LPT_SCAN_CONTINUE;
++      /* Determine whether to add these LEB properties to the tree */
++      if (!in_tree && valuable(c, lprops))
++              ret |= LPT_SCAN_ADD;
++      /* Exclude index LEBS */
++      if (lprops->flags & LPROPS_INDEX)
++              return ret;
++      /* Exclude LEBs that cannot be made empty */
++      if (lprops->free + lprops->dirty != c->leb_size)
++              return ret;
++      /*
++       * We are allocating for the index so it is safe to allocate LEBs with
++       * only free and dirty space, because write buffers are sync'd at commit
++       * start.
++       */
++      data->lnum = lprops->lnum;
++      return LPT_SCAN_ADD | LPT_SCAN_STOP;
++}
++
++/**
++ * scan_for_leb_for_idx - scan for a free LEB for the index.
++ * @c: the UBIFS file-system description object
++ */
++static const struct ubifs_lprops *scan_for_leb_for_idx(struct ubifs_info *c)
++{
++      struct ubifs_lprops *lprops;
++      struct scan_data data;
++      int err;
++
++      data.lnum = -1;
++      err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum,
++                                  (ubifs_lpt_scan_callback)scan_for_idx_cb,
++                                  &data);
++      if (err)
++              return ERR_PTR(err);
++      ubifs_assert(data.lnum >= c->main_first && data.lnum < c->leb_cnt);
++      c->lscan_lnum = data.lnum;
++      lprops = ubifs_lpt_lookup_dirty(c, data.lnum);
++      if (IS_ERR(lprops))
++              return lprops;
++      ubifs_assert(lprops->lnum == data.lnum);
++      ubifs_assert(lprops->free + lprops->dirty == c->leb_size);
++      ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
++      ubifs_assert(!(lprops->flags & LPROPS_INDEX));
++      return lprops;
++}
++
++/**
++ * ubifs_find_free_leb_for_idx - find a free LEB for the index.
++ * @c: the UBIFS file-system description object
++ *
++ * This function looks for a free LEB and returns that LEB number. The returned
++ * LEB is marked as "taken", "index".
++ *
++ * Only empty LEBs are allocated. This is for two reasons. First, the commit
++ * calculates the number of LEBs to allocate based on the assumption that they
++ * will be empty. Secondly, free space at the end of an index LEB is not
++ * guaranteed to be empty because it may have been used by the in-the-gaps
++ * method prior to an unclean unmount.
++ *
++ * If no LEB is found %-ENOSPC is returned. For other failures another negative
++ * error code is returned.
++ */
++int ubifs_find_free_leb_for_idx(struct ubifs_info *c)
++{
++      const struct ubifs_lprops *lprops;
++      int lnum = -1, err, flags;
++
++      ubifs_get_lprops(c);
++
++      lprops = ubifs_fast_find_empty(c);
++      if (!lprops) {
++              lprops = ubifs_fast_find_freeable(c);
++              if (!lprops) {
++                      ubifs_assert(c->freeable_cnt == 0);
++                      if (c->lst.empty_lebs - c->lst.taken_empty_lebs > 0) {
++                              lprops = scan_for_leb_for_idx(c);
++                              if (IS_ERR(lprops)) {
++                                      err = PTR_ERR(lprops);
++                                      goto out;
++                              }
++                      }
++              }
++      }
++
++      if (!lprops) {
++              err = -ENOSPC;
++              goto out;
++      }
++
++      lnum = lprops->lnum;
++
++      dbg_find("found LEB %d, free %d, dirty %d, flags %#x",
++               lnum, lprops->free, lprops->dirty, lprops->flags);
++
++      flags = lprops->flags | LPROPS_TAKEN | LPROPS_INDEX;
++      lprops = ubifs_change_lp(c, lprops, c->leb_size, 0, flags, 0);
++      if (IS_ERR(lprops)) {
++              err = PTR_ERR(lprops);
++              goto out;
++      }
++
++      ubifs_release_lprops(c);
++
++      /*
++       * Ensure that empty LEBs have been unmapped. They may not have been,
++       * for example, because of an unclean unmount. Also LEBs that were
++       * freeable LEBs (free + dirty == leb_size) will not have been unmapped.
++       */
++      err = ubifs_leb_unmap(c, lnum);
++      if (err) {
++              ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
++                                  LPROPS_TAKEN | LPROPS_INDEX, 0);
++              return err;
++      }
++
++      return lnum;
++
++out:
++      ubifs_release_lprops(c);
++      return err;
++}
++
++static int cmp_dirty_idx(const struct ubifs_lprops **a,
++                       const struct ubifs_lprops **b)
++{
++      const struct ubifs_lprops *lpa = *a;
++      const struct ubifs_lprops *lpb = *b;
++
++      return lpa->dirty + lpa->free - lpb->dirty - lpb->free;
++}
++
++static void swap_dirty_idx(struct ubifs_lprops **a, struct ubifs_lprops **b,
++                         int size)
++{
++      struct ubifs_lprops *t = *a;
++
++      *a = *b;
++      *b = t;
++}
++
++/**
++ * ubifs_save_dirty_idx_lnums - save an array of the most dirty index LEB nos.
++ * @c: the UBIFS file-system description object
++ *
++ * This function is called each commit to create an array of LEB numbers of
++ * dirty index LEBs sorted in order of dirty and free space.  This is used by
++ * the in-the-gaps method of TNC commit.
++ */
++int ubifs_save_dirty_idx_lnums(struct ubifs_info *c)
++{
++      int i;
++
++      ubifs_get_lprops(c);
++      /* Copy the LPROPS_DIRTY_IDX heap */
++      c->dirty_idx.cnt = c->lpt_heap[LPROPS_DIRTY_IDX - 1].cnt;
++      memcpy(c->dirty_idx.arr, c->lpt_heap[LPROPS_DIRTY_IDX - 1].arr,
++             sizeof(void *) * c->dirty_idx.cnt);
++      /* Sort it so that the dirtiest is now at the end */
++      sort(c->dirty_idx.arr, c->dirty_idx.cnt, sizeof(void *),
++           (int (*)(const void *, const void *))cmp_dirty_idx,
++           (void (*)(void *, void *, int))swap_dirty_idx);
++      dbg_find("found %d dirty index LEBs", c->dirty_idx.cnt);
++      if (c->dirty_idx.cnt)
++              dbg_find("dirtiest index LEB is %d with dirty %d and free %d",
++                       c->dirty_idx.arr[c->dirty_idx.cnt - 1]->lnum,
++                       c->dirty_idx.arr[c->dirty_idx.cnt - 1]->dirty,
++                       c->dirty_idx.arr[c->dirty_idx.cnt - 1]->free);
++      /* Replace the lprops pointers with LEB numbers */
++      for (i = 0; i < c->dirty_idx.cnt; i++)
++              c->dirty_idx.arr[i] = (void *)(size_t)c->dirty_idx.arr[i]->lnum;
++      ubifs_release_lprops(c);
++      return 0;
++}
++
++/**
++ * scan_dirty_idx_cb - callback used by the scan for a dirty index LEB.
++ * @c: the UBIFS file-system description object
++ * @lprops: LEB properties to scan
++ * @in_tree: whether the LEB properties are in main memory
++ * @data: information passed to and from the caller of the scan
++ *
++ * This function returns a code that indicates whether the scan should continue
++ * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree
++ * in main memory (%LPT_SCAN_ADD), or whether the scan should stop
++ * (%LPT_SCAN_STOP).
++ */
++static int scan_dirty_idx_cb(struct ubifs_info *c,
++                         const struct ubifs_lprops *lprops, int in_tree,
++                         struct scan_data *data)
++{
++      int ret = LPT_SCAN_CONTINUE;
++
++      /* Exclude LEBs that are currently in use */
++      if (lprops->flags & LPROPS_TAKEN)
++              return LPT_SCAN_CONTINUE;
++      /* Determine whether to add these LEB properties to the tree */
++      if (!in_tree && valuable(c, lprops))
++              ret |= LPT_SCAN_ADD;
++      /* Exclude non-index LEBs */
++      if (!(lprops->flags & LPROPS_INDEX))
++              return ret;
++      /* Exclude LEBs with too little space */
++      if (lprops->free + lprops->dirty < c->min_idx_node_sz)
++              return ret;
++      /* Finally we found space */
++      data->lnum = lprops->lnum;
++      return LPT_SCAN_ADD | LPT_SCAN_STOP;
++}
++
++/**
++ * find_dirty_idx_leb - find a dirty index LEB.
++ * @c: the UBIFS file-system description object
++ *
++ * This function returns LEB number upon success and a negative error code upon
++ * failure.  In particular, -ENOSPC is returned if a dirty index LEB is not
++ * found.
++ *
++ * Note that this function scans the entire LPT but it is called very rarely.
++ */
++static int find_dirty_idx_leb(struct ubifs_info *c)
++{
++      const struct ubifs_lprops *lprops;
++      struct ubifs_lpt_heap *heap;
++      struct scan_data data;
++      int err, i, ret;
++
++      /* Check all structures in memory first */
++      data.lnum = -1;
++      heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1];
++      for (i = 0; i < heap->cnt; i++) {
++              lprops = heap->arr[i];
++              ret = scan_dirty_idx_cb(c, lprops, 1, &data);
++              if (ret & LPT_SCAN_STOP)
++                      goto found;
++      }
++      list_for_each_entry(lprops, &c->frdi_idx_list, list) {
++              ret = scan_dirty_idx_cb(c, lprops, 1, &data);
++              if (ret & LPT_SCAN_STOP)
++                      goto found;
++      }
++      list_for_each_entry(lprops, &c->uncat_list, list) {
++              ret = scan_dirty_idx_cb(c, lprops, 1, &data);
++              if (ret & LPT_SCAN_STOP)
++                      goto found;
++      }
++      if (c->pnodes_have >= c->pnode_cnt)
++              /* All pnodes are in memory, so skip scan */
++              return -ENOSPC;
++      err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum,
++                                  (ubifs_lpt_scan_callback)scan_dirty_idx_cb,
++                                  &data);
++      if (err)
++              return err;
++found:
++      ubifs_assert(data.lnum >= c->main_first && data.lnum < c->leb_cnt);
++      c->lscan_lnum = data.lnum;
++      lprops = ubifs_lpt_lookup_dirty(c, data.lnum);
++      if (IS_ERR(lprops))
++              return PTR_ERR(lprops);
++      ubifs_assert(lprops->lnum == data.lnum);
++      ubifs_assert(lprops->free + lprops->dirty >= c->min_idx_node_sz);
++      ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
++      ubifs_assert((lprops->flags & LPROPS_INDEX));
++
++      dbg_find("found dirty LEB %d, free %d, dirty %d, flags %#x",
++               lprops->lnum, lprops->free, lprops->dirty, lprops->flags);
++
++      lprops = ubifs_change_lp(c, lprops, LPROPS_NC, LPROPS_NC,
++                               lprops->flags | LPROPS_TAKEN, 0);
++      if (IS_ERR(lprops))
++              return PTR_ERR(lprops);
++
++      return lprops->lnum;
++}
++
++/**
++ * get_idx_gc_leb - try to get a LEB number from trivial GC.
++ * @c: the UBIFS file-system description object
++ */
++static int get_idx_gc_leb(struct ubifs_info *c)
++{
++      const struct ubifs_lprops *lp;
++      int err, lnum;
++
++      err = ubifs_get_idx_gc_leb(c);
++      if (err < 0)
++              return err;
++      lnum = err;
++      /*
++       * The LEB was due to be unmapped after the commit but
++       * it is needed now for this commit.
++       */
++      lp = ubifs_lpt_lookup_dirty(c, lnum);
++      if (unlikely(IS_ERR(lp)))
++              return PTR_ERR(lp);
++      lp = ubifs_change_lp(c, lp, LPROPS_NC, LPROPS_NC,
++                           lp->flags | LPROPS_INDEX, -1);
++      if (unlikely(IS_ERR(lp)))
++              return PTR_ERR(lp);
++      dbg_find("LEB %d, dirty %d and free %d flags %#x",
++               lp->lnum, lp->dirty, lp->free, lp->flags);
++      return lnum;
++}
++
++/**
++ * find_dirtiest_idx_leb - find dirtiest index LEB from dirtiest array.
++ * @c: the UBIFS file-system description object
++ */
++static int find_dirtiest_idx_leb(struct ubifs_info *c)
++{
++      const struct ubifs_lprops *lp;
++      int lnum;
++
++      while (1) {
++              if (!c->dirty_idx.cnt)
++                      return -ENOSPC;
++              /* The lprops pointers were replaced by LEB numbers */
++              lnum = (size_t)c->dirty_idx.arr[--c->dirty_idx.cnt];
++              lp = ubifs_lpt_lookup(c, lnum);
++              if (IS_ERR(lp))
++                      return PTR_ERR(lp);
++              if ((lp->flags & LPROPS_TAKEN) || !(lp->flags & LPROPS_INDEX))
++                      continue;
++              lp = ubifs_change_lp(c, lp, LPROPS_NC, LPROPS_NC,
++                                   lp->flags | LPROPS_TAKEN, 0);
++              if (IS_ERR(lp))
++                      return PTR_ERR(lp);
++              break;
++      }
++      dbg_find("LEB %d, dirty %d and free %d flags %#x", lp->lnum, lp->dirty,
++               lp->free, lp->flags);
++      ubifs_assert(lp->flags | LPROPS_TAKEN);
++      ubifs_assert(lp->flags | LPROPS_INDEX);
++      return lnum;
++}
++
++/**
++ * ubifs_find_dirty_idx_leb - try to find dirtiest index LEB as at last commit.
++ * @c: the UBIFS file-system description object
++ *
++ * This function attempts to find an untaken index LEB with the most free and
++ * dirty space that can be used without overwriting index nodes that were in the
++ * last index committed.
++ */
++int ubifs_find_dirty_idx_leb(struct ubifs_info *c)
++{
++      int err;
++
++      ubifs_get_lprops(c);
++
++      /*
++       * We made an array of the dirtiest index LEB numbers as at the start of
++       * last commit.  Try that array first.
++       */
++      err = find_dirtiest_idx_leb(c);
++
++      /* Next try scanning the entire LPT */
++      if (err == -ENOSPC)
++              err = find_dirty_idx_leb(c);
++
++      /* Finally take any index LEBs awaiting trivial GC */
++      if (err == -ENOSPC)
++              err = get_idx_gc_leb(c);
++
++      ubifs_release_lprops(c);
++      return err;
++}
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/gc.c avr32-2.6/fs/ubifs/gc.c
+--- linux-2.6.25.6/fs/ubifs/gc.c       1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/gc.c    2008-06-12 15:09:45.367815766 +0200
+@@ -0,0 +1,762 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Adrian Hunter
++ *          Artem Bityutskiy (Битюцкий Артём)
++ */
++
++/*
++ * This file implements garbage collection. The procedure for garbage collection
++ * is different depending on whether a LEB as an index LEB (contains index
++ * nodes) or not. For non-index LEBs, garbage collection finds a LEB which
++ * contains a lot of dirty space (obsolete nodes), and copies the non-obsolete
++ * nodes to the journal, at which point the garbage-collected LEB is free to be
++ * reused. For index LEBs, garbage collection marks the non-obsolete index nodes
++ * dirty in the TNC, and after the next commit, the garbage-collected LEB is
++ * to be reused. Garbage collection will cause the number of dirty index nodes
++ * to grow, however sufficient space is reserved for the index to ensure the
++ * commit will never run out of space.
++ */
++
++#include <linux/pagemap.h>
++#include "ubifs.h"
++
++/*
++ * GC tries to optimize the way it fit nodes to available space, and it sorts
++ * nodes a little. The below constants are watermarks which define "large",
++ * "medium", and "small" nodes.
++ */
++#define MEDIUM_NODE_WM (UBIFS_BLOCK_SIZE / 4)
++#define SMALL_NODE_WM  UBIFS_MAX_DENT_NODE_SZ
++
++/*
++ * GC may need to move more then one LEB to make progress. The below constants
++ * define "soft" and "hard" limits on the number of LEBs the garbage collector
++ * may move.
++ */
++#define SOFT_LEBS_LIMIT 4
++#define HARD_LEBS_LIMIT 32
++
++/**
++ * switch_gc_head - switch the garbage collection journal head.
++ * @c: UBIFS file-system description object
++ * @buf: buffer to write
++ * @len: length of the buffer to write
++ * @lnum: LEB number written is returned here
++ * @offs: offset written is returned here
++ *
++ * This function switch the GC head to the next LEB which is reserved in
++ * @c->gc_lnum. Returns %0 in case of success, %-EAGAIN if commit is required,
++ * and other negative error code in case of failures.
++ */
++static int switch_gc_head(struct ubifs_info *c)
++{
++      int err, gc_lnum = c->gc_lnum;
++      struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
++
++      ubifs_assert(gc_lnum != -1);
++      dbg_gc("switch GC head from LEB %d:%d to LEB %d (waste %d bytes)",
++             wbuf->lnum, wbuf->offs + wbuf->used, gc_lnum,
++             c->leb_size - wbuf->offs - wbuf->used);
++
++      err = ubifs_wbuf_sync_nolock(wbuf);
++      if (err)
++              return err;
++
++      /*
++       * The GC write-buffer was synchronized, we may safely unmap
++       * 'c->gc_lnum'.
++       */
++      err = ubifs_leb_unmap(c, gc_lnum);
++      if (err)
++              return err;
++
++      err = ubifs_add_bud_to_log(c, GCHD, gc_lnum, 0);
++      if (err)
++              return err;
++
++      c->gc_lnum = -1;
++      err = ubifs_wbuf_seek_nolock(wbuf, gc_lnum, 0, UBI_LONGTERM);
++      return err;
++}
++
++/**
++ * move_nodes - move nodes.
++ * @c: UBIFS file-system description object
++ * @sleb: describes nodes to move
++ *
++ * This function moves valid nodes from data LEB described by @sleb to the GC
++ * journal head. The obsolete nodes are dropped.
++ *
++ * When moving nodes we have to deal with classical bin-packing problem: the
++ * space in the current GC journal head LEB and in @c->gc_lnum are the "bins",
++ * where the nodes in the @sleb->nodes list are the elements which should be
++ * fit optimally to the bins. This function uses the "first fit decreasing"
++ * strategy, although it does not really sort the nodes but just split them on
++ * 3 classes - large, medium, and small, so they are roughly sorted.
++ *
++ * This function returns zero in case of success, %-EAGAIN if commit is
++ * required, and other negative error codes in case of other failures.
++ */
++static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb)
++{
++      struct ubifs_scan_node *snod, *tmp;
++      struct list_head large, medium, small;
++      struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
++      int avail, err, min = INT_MAX;
++
++      INIT_LIST_HEAD(&large);
++      INIT_LIST_HEAD(&medium);
++      INIT_LIST_HEAD(&small);
++
++      list_for_each_entry_safe(snod, tmp, &sleb->nodes, list) {
++              struct list_head *lst;
++
++              ubifs_assert(snod->type != UBIFS_IDX_NODE);
++              ubifs_assert(snod->type != UBIFS_REF_NODE);
++              ubifs_assert(snod->type != UBIFS_CS_NODE);
++
++              err = ubifs_tnc_has_node(c, &snod->key, 0, sleb->lnum,
++                                       snod->offs, 0);
++              if (err < 0)
++                      goto out;
++
++              lst = &snod->list;
++              list_del(lst);
++              if (!err) {
++                      /* The node is obsolete, remove it from the list */
++                      kfree(snod);
++                      continue;
++              }
++
++              /*
++               * Sort the list of nodes so that large nodes go first, and
++               * small nodes go last.
++               */
++              if (snod->len > MEDIUM_NODE_WM)
++                      list_add(lst, &large);
++              else if (snod->len > SMALL_NODE_WM)
++                      list_add(lst, &medium);
++              else
++                      list_add(lst, &small);
++
++              /* And find the smallest node */
++              if (snod->len < min)
++                      min = snod->len;
++      }
++
++      /*
++       * Join the tree lists so that we'd have one roughly sorted list
++       * ('large' will be the head of the joined list).
++       */
++      list_splice(&medium, large.prev);
++      list_splice(&small, large.prev);
++
++      if (wbuf->lnum == -1) {
++              /*
++               * The GC journal head is not set, because it is the first GC
++               * invocation since mount.
++               */
++              err = switch_gc_head(c);
++              if (err)
++                      goto out;
++      }
++
++      /* Write nodes to their new location. Use the first-fit strategy */
++      while (1) {
++              avail = c->leb_size - wbuf->offs - wbuf->used;
++              list_for_each_entry_safe(snod, tmp, &large, list) {
++                      int new_lnum, new_offs;
++
++                      if (avail < min)
++                              break;
++
++                      if (snod->len > avail)
++                              /* This node does not fit */
++                              continue;
++
++                      cond_resched();
++
++                      new_lnum = wbuf->lnum;
++                      new_offs = wbuf->offs + wbuf->used;
++                              err = ubifs_wbuf_write_nolock(wbuf, snod->node,
++                                                    snod->len);
++
++                      err = ubifs_tnc_replace(c, &snod->key, sleb->lnum,
++                                              snod->offs, new_lnum, new_offs,
++                                              snod->len);
++                      if (err)
++                              goto out;
++
++                      avail = c->leb_size - wbuf->offs - wbuf->used;
++                      list_del(&snod->list);
++                      kfree(snod);
++              }
++
++              if (list_empty(&large))
++                      break;
++
++              /*
++               * Waste the rest of the space in the LEB and switch to the
++               * next LEB.
++               */
++              err = switch_gc_head(c);
++              if (err)
++                      goto out;
++      }
++
++      return 0;
++
++out:
++      list_for_each_entry_safe(snod, tmp, &large, list) {
++              list_del(&snod->list);
++              kfree(snod);
++      }
++      return err;
++}
++
++/**
++ * gc_sync_wbufs - sync write-buffers for GC.
++ * @c: UBIFS file-system description object
++ *
++ * We must guarantee that obsoleting nodes are on flash. Unfortunately they may
++ * be in a write-buffer instead. That is, a node could be written to a
++ * write-buffer, obsoleting another node in a LEB that is GC'd. If that LEB is
++ * erased before the write-buffer is sync'd and then there is an unclean
++ * unmount, then an existing node is lost. To avoid this, we sync all
++ * write-buffers.
++ *
++ * This function returns %0 on success or a negative error code on failure.
++ */
++static int gc_sync_wbufs(struct ubifs_info *c)
++{
++      int err, i;
++
++      for (i = 0; i < c->jhead_cnt; i++) {
++              if (i == GCHD)
++                      continue;
++              err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
++              if (err)
++                      return err;
++      }
++      return 0;
++}
++
++/**
++ * ubifs_garbage_collect_leb - garbage-collect a logical eraseblock.
++ * @c: UBIFS file-system description object
++ * @lp: describes the LEB to garbage collect
++ *
++ * This function garbage-collects an LEB and returns one of the @LEB_FREED,
++ * @LEB_RETAINED, etc positive codes in case of success, %-EAGAIN if commit is
++ * required, and other negative error codes in case of failures.
++ */
++int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp)
++{
++      struct ubifs_scan_leb *sleb;
++      struct ubifs_scan_node *snod;
++      struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
++      int err = 0, lnum = lp->lnum;
++
++      ubifs_assert(c->gc_lnum != -1 || wbuf->offs + wbuf->used == 0 ||
++                   c->need_recovery);
++      ubifs_assert(c->gc_lnum != lnum);
++      ubifs_assert(wbuf->lnum != lnum);
++
++      /*
++       * We scan the entire LEB even though we only really need to scan up to
++       * (c->leb_size - lp->free).
++       */
++      sleb = ubifs_scan(c, lnum, 0, c->sbuf);
++      if (IS_ERR(sleb))
++              return PTR_ERR(sleb);
++
++      ubifs_assert(!list_empty(&sleb->nodes));
++      snod = list_entry(sleb->nodes.next, struct ubifs_scan_node, list);
++
++      if (snod->type == UBIFS_IDX_NODE) {
++              struct ubifs_gced_idx_leb *idx_gc;
++
++              dbg_gc("indexing LEB %d (free %d, dirty %d)",
++                     lnum, lp->free, lp->dirty);
++              list_for_each_entry(snod, &sleb->nodes, list) {
++                      struct ubifs_idx_node *idx = snod->node;
++                      int level = le16_to_cpu(idx->level);
++
++                      ubifs_assert(snod->type == UBIFS_IDX_NODE);
++                      key_read(c, ubifs_idx_key(c, idx), &snod->key);
++                      err = ubifs_dirty_idx_node(c, &snod->key, level, lnum,
++                                                 snod->offs);
++                      if (err)
++                              goto out;
++              }
++
++              idx_gc = kmalloc(sizeof(struct ubifs_gced_idx_leb), GFP_NOFS);
++              if (!idx_gc) {
++                      err = -ENOMEM;
++                      goto out;
++              }
++
++              idx_gc->lnum = lnum;
++              idx_gc->unmap = 0;
++              list_add(&idx_gc->list, &c->idx_gc);
++
++              /*
++               * Don't release the LEB until after the next commit, because
++               * it may contain date which is needed for recovery. So
++               * although we freed this LEB, it will become usable only after
++               * the commit.
++               */
++              err = ubifs_change_one_lp(c, lnum, c->leb_size, 0, 0,
++                                        LPROPS_INDEX, 1);
++              if (err)
++                      goto out;
++              err = LEB_FREED_IDX;
++      } else {
++              dbg_gc("data LEB %d (free %d, dirty %d)",
++                     lnum, lp->free, lp->dirty);
++
++              err = move_nodes(c, sleb);
++              if (err)
++                      goto out;
++
++              err = gc_sync_wbufs(c);
++              if (err)
++                      goto out;
++
++              err = ubifs_change_one_lp(c, lnum, c->leb_size, 0, 0, 0, 0);
++              if (err)
++                      goto out;
++
++              if (c->gc_lnum == -1) {
++                      c->gc_lnum = lnum;
++                      err = LEB_RETAINED;
++              } else {
++                      err = ubifs_wbuf_sync_nolock(wbuf);
++                      if (err)
++                              goto out;
++
++                      err = ubifs_leb_unmap(c, lnum);
++                      if (err)
++                              goto out;
++
++                      err = LEB_FREED;
++              }
++      }
++
++out:
++      ubifs_scan_destroy(sleb);
++      return err;
++}
++
++/**
++ * ubifs_garbage_collect - UBIFS garbage collector.
++ * @c: UBIFS file-system description object
++ * @anyway: do GC even if there are free LEBs
++ *
++ * This function does out-of-place garbage collection. The return codes are:
++ *   o positive LEB number if the LEB has been freed and may be used;
++ *   o %-EAGAIN if the caller has to run commit;
++ *   o %-ENOSPC if GC failed to make any progress;
++ *   o other negative error codes in case of other errors.
++ *
++ * Garbage collector writes data to the journal when GC'ing data LEBs, and just
++ * marking indexing nodes dirty when GC'ing indexing LEBs. Thus, at some point
++ * commit may be required. But commit cannot be run from inside GC, because the
++ * caller might be holding the commit lock, so %-EAGAIN is returned instead;
++ * And this error code means that the caller has to run commit, and re-run GC
++ * if there is still no free space.
++ *
++ * There are many reasons why this function may return %-EAGAIN:
++ * o the log is full and there is no space to write an LEB reference for
++ *   @c->gc_lnum;
++ * o the journal is too large and exceeds size limitations;
++ * o GC moved indexing LEBs, but they can be used only after the commit;
++ * o the shrinker fails to find clean znodes to free and requests the commit;
++ * o etc.
++ *
++ * Note, if the file-system is close to be full, this function may return
++ * %-EAGAIN infinitely, so the caller has to limit amount of re-invocations of
++ * the function. E.g., this happens if the limits on the journal size are too
++ * tough and GC writes too much to the journal before an LEB is freed. This
++ * might also mean that the journal is too large, and the TNC becomes to big,
++ * so that the shrinker is constantly called, finds not clean znodes to free,
++ * and requests commit. Well, this may also happen if the journal is all right,
++ * but another kernel process consumes too much memory. Anyway, infinite
++ * %-EAGAIN may happen, but in some extreme/misconfiguration cases.
++ */
++int ubifs_garbage_collect(struct ubifs_info *c, int anyway)
++{
++      int i, err, ret, min_space = c->dead_wm;
++      struct ubifs_lprops lp;
++      struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
++
++      ubifs_assert_cmt_locked(c);
++
++      if (ubifs_gc_should_commit(c))
++              return -EAGAIN;
++
++      mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
++      /* We expect the write-buffer to be empty on entry */
++      ubifs_assert(!wbuf->used);
++
++      for (i = 0; ; i++) {
++              int space_before = c->leb_size - wbuf->offs - wbuf->used;
++              int space_after;
++
++              cond_resched();
++
++              /* Give the commit an opportunity to run */
++              if (ubifs_gc_should_commit(c)) {
++                      ret = -EAGAIN;
++                      break;
++              }
++
++              if (i > SOFT_LEBS_LIMIT && !list_empty(&c->idx_gc)) {
++                      /*
++                       * We've done enough iterations. Indexing LEBs were
++                       * moved and will be available after the commit.
++                       */
++                      dbg_gc("soft limit, some index LEBs GC'ed, -EAGAIN");
++                      ubifs_commit_required(c);
++                      ret = -EAGAIN;
++                      break;
++              }
++
++              if (i > HARD_LEBS_LIMIT) {
++                      /*
++                       * We've moved too many LEBs and have not made
++                       * progress, give up.
++                       */
++                      dbg_gc("hard limit, -ENOSPC");
++                      ret = -ENOSPC;
++                      break;
++              }
++
++              /*
++               * Empty and freeable LEBs can turn up while we waited for
++               * the wbuf lock, or while we have been running GC. In that
++               * case, we should just return one of those instead of
++               * continuing to GC dirty LEBs. Hence we request
++               * 'ubifs_find_dirty_leb()' to return an empty LEB if it can.
++               */
++              ret = ubifs_find_dirty_leb(c, &lp, min_space, anyway ? 0 : 1);
++              if (ret) {
++                      if (ret == -ENOSPC)
++                              dbg_gc("no more dirty LEBs");
++                      break;
++              }
++
++              dbg_gc("found LEB %d: free %d, dirty %d, sum %d "
++                     "(min. space %d)", lp.lnum, lp.free, lp.dirty,
++                     lp.free + lp.dirty, min_space);
++
++              if (lp.free + lp.dirty == c->leb_size) {
++                      /* An empty LEB was returned */
++                      dbg_gc("LEB %d is free, return it", lp.lnum);
++                      /*
++                       * ubifs_find_dirty_leb() doesn't return freeable index
++                       * LEBs.
++                       */
++                      ubifs_assert(!(lp.flags & LPROPS_INDEX));
++                      if (lp.free != c->leb_size) {
++                              /*
++                               * Write buffers must be sync'd before
++                               * unmapping freeable LEBs, because one of them
++                               * may contain data which obsoletes something
++                               * in 'lp.pnum'.
++                               */
++                              ret = gc_sync_wbufs(c);
++                              if (ret)
++                                      goto out;
++                              ret = ubifs_change_one_lp(c, lp.lnum,
++                                                        c->leb_size, 0, 0, 0,
++                                                        0);
++                              if (ret)
++                                      goto out;
++                      }
++                      ret = ubifs_leb_unmap(c, lp.lnum);
++                      if (ret)
++                              goto out;
++                      ret = lp.lnum;
++                      break;
++              }
++
++              space_before = c->leb_size - wbuf->offs - wbuf->used;
++              if (wbuf->lnum == -1)
++                      space_before = 0;
++
++              ret = ubifs_garbage_collect_leb(c, &lp);
++              if (ret < 0) {
++                      if (ret == -EAGAIN || ret == -ENOSPC) {
++                              /*
++                               * These codes are not errors, so we have to
++                               * return the LEB to lprops. But if the
++                               * 'ubifs_return_leb()' function fails, its
++                               * failure code is propagated to the caller
++                               * instead of the original '-EAGAIN' or
++                               * '-ENOSPC'.
++                               */
++                              err = ubifs_return_leb(c, lp.lnum);
++                              if (err)
++                                      ret = err;
++                              break;
++                      }
++                      goto out;
++              }
++
++              if (ret == LEB_FREED) {
++                      /* An LEB has been freed and is ready for use */
++                      dbg_gc("LEB %d freed, return", lp.lnum);
++                      ret = lp.lnum;
++                      break;
++              }
++
++              if (ret == LEB_FREED_IDX) {
++                      /*
++                       * This was an indexing LEB and it cannot be
++                       * immediately used. And instead of requesting the
++                       * commit straight away, we try to garbage collect some
++                       * more.
++                       */
++                      dbg_gc("indexing LEB %d freed, continue", lp.lnum);
++                      continue;
++              }
++
++              ubifs_assert(ret == LEB_RETAINED);
++              space_after = c->leb_size - wbuf->offs - wbuf->used;
++              dbg_gc("LEB %d retained, freed %d bytes", lp.lnum,
++                     space_after - space_before);
++
++              if (space_after > space_before) {
++                      /* GC makes progress, keep working */
++                      min_space >>= 1;
++                      if (min_space < c->dead_wm)
++                              min_space = c->dead_wm;
++                      continue;
++              }
++
++              dbg_gc("did not make progress");
++
++              /*
++               * GC moved an LEB bud have not done any progress. This means
++               * that the previous GC head LEB contained too few free space
++               * and the LEB which was GC'ed contained only large nodes which
++               * did not fit that space.
++               *
++               * We can do 2 things:
++               * 1. pick another LEB in a hope it'll contain a small node
++               *    which will fit the space we have at the end of current GC
++               *    head LEB, but there is no guarantee, so we try this out
++               *    unless we have already been working for too long;
++               * 2. request an LEB with more dirty space, which will force
++               *    'ubifs_find_dirty_leb()' to start scanning the lprops
++               *    table, instead of just picking one from the heap
++               *    (previously it already picked the dirtiest LEB).
++               */
++              if (i < SOFT_LEBS_LIMIT) {
++                      dbg_gc("try again");
++                      continue;
++              }
++
++              min_space <<= 1;
++              if (min_space > c->dark_wm)
++                      min_space = c->dark_wm;
++              dbg_gc("set min. space to %d", min_space);
++      }
++
++      if (ret == -ENOSPC && !list_empty(&c->idx_gc)) {
++              dbg_gc("no space, some index LEBs GC'ed, -EAGAIN");
++              ubifs_commit_required(c);
++              ret = -EAGAIN;
++      }
++
++      err = ubifs_wbuf_sync_nolock(wbuf);
++      if (!err)
++              err = ubifs_leb_unmap(c, c->gc_lnum);
++      if (err)
++              ret = err;
++      mutex_unlock(&wbuf->io_mutex);
++      return ret;
++
++out:
++      ubifs_assert(ret < 0);
++      ubifs_assert(ret != -ENOSPC && ret != -EAGAIN);
++      ubifs_wbuf_sync_nolock(wbuf);
++      mutex_unlock(&wbuf->io_mutex);
++      ubifs_return_leb(c, lp.lnum);
++      return ret;
++}
++
++/**
++ * ubifs_gc_start_commit - garbage collection at start of commit.
++ * @c: UBIFS file-system description object
++ *
++ * If a LEB has only dirty and free space, then we may safely unmap it and make
++ * it free.  Note, we cannot do this with indexing LEBs because dirty space may
++ * correspond index nodes that are required for recovery.  In that case, the
++ * LEB cannot be unmapped until after the next commit.
++ *
++ * This function returns %0 upon success and a negative error code upon failure.
++ */
++int ubifs_gc_start_commit(struct ubifs_info *c)
++{
++      struct ubifs_gced_idx_leb *idx_gc;
++      const struct ubifs_lprops *lp;
++      int err = 0, flags;
++
++      ubifs_get_lprops(c);
++
++      /*
++       * Unmap (non-index) freeable LEBs. Note that recovery requires that all
++       * wbufs are sync'd before this, which is done in 'do_commit()'.
++       */
++      while (1) {
++              lp = ubifs_fast_find_freeable(c);
++              if (unlikely(IS_ERR(lp))) {
++                      err = PTR_ERR(lp);
++                      goto out;
++              }
++              if (!lp)
++                      break;
++              ubifs_assert(!(lp->flags & LPROPS_TAKEN));
++              ubifs_assert(!(lp->flags & LPROPS_INDEX));
++              err = ubifs_leb_unmap(c, lp->lnum);
++              if (err)
++                      goto out;
++              lp = ubifs_change_lp(c, lp, c->leb_size, 0, lp->flags, 0);
++              if (unlikely(IS_ERR(lp))) {
++                      err = PTR_ERR(lp);
++                      goto out;
++              }
++              ubifs_assert(!(lp->flags & LPROPS_TAKEN));
++              ubifs_assert(!(lp->flags & LPROPS_INDEX));
++      }
++
++      /* Mark GC'd index LEBs OK to unmap after this commit finishes */
++      list_for_each_entry(idx_gc, &c->idx_gc, list)
++              idx_gc->unmap = 1;
++
++      /* Record index freeable LEBs for unmapping after commit */
++      while (1) {
++              lp = ubifs_fast_find_frdi_idx(c);
++              if (unlikely(IS_ERR(lp))) {
++                      err = PTR_ERR(lp);
++                      goto out;
++              }
++              if (!lp)
++                      break;
++              idx_gc = kmalloc(sizeof(struct ubifs_gced_idx_leb), GFP_NOFS);
++              if (!idx_gc) {
++                      err = -ENOMEM;
++                      goto out;
++              }
++              ubifs_assert(!(lp->flags & LPROPS_TAKEN));
++              ubifs_assert(lp->flags & LPROPS_INDEX);
++              /* Don't release the LEB until after the next commit */
++              flags = (lp->flags | LPROPS_TAKEN) ^ LPROPS_INDEX;
++              lp = ubifs_change_lp(c, lp, c->leb_size, 0, flags, 1);
++              if (unlikely(IS_ERR(lp))) {
++                      err = PTR_ERR(lp);
++                      kfree(idx_gc);
++                      goto out;
++              }
++              ubifs_assert(lp->flags & LPROPS_TAKEN);
++              ubifs_assert(!(lp->flags & LPROPS_INDEX));
++              idx_gc->lnum = lp->lnum;
++              idx_gc->unmap = 1;
++              list_add(&idx_gc->list, &c->idx_gc);
++      }
++out:
++      ubifs_release_lprops(c);
++      return err;
++}
++
++/**
++ * ubifs_gc_end_commit - garbage collection at end of commit.
++ * @c: UBIFS file-system description object
++ *
++ * This function completes out-of-place garbage collection of index LEBs.
++ */
++int ubifs_gc_end_commit(struct ubifs_info *c)
++{
++      struct ubifs_gced_idx_leb *idx_gc, *tmp;
++      struct ubifs_wbuf *wbuf;
++      int err = 0;
++
++      wbuf = &c->jheads[GCHD].wbuf;
++      mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
++      list_for_each_entry_safe(idx_gc, tmp, &c->idx_gc, list)
++              if (idx_gc->unmap) {
++                      dbg_gc("LEB %d", idx_gc->lnum);
++                      err = ubifs_leb_unmap(c, idx_gc->lnum);
++                      if (err)
++                              goto out;
++                      err = ubifs_change_one_lp(c, idx_gc->lnum, LPROPS_NC,
++                                        LPROPS_NC, 0, LPROPS_TAKEN, -1);
++                      if (err)
++                              goto out;
++                      list_del(&idx_gc->list);
++                      kfree(idx_gc);
++              }
++out:
++      mutex_unlock(&wbuf->io_mutex);
++      return err;
++}
++
++/**
++ * ubifs_destroy_idx_gc - destroy idx_gc list.
++ * @c: UBIFS file-system description object
++ *
++ * This function destroys the idx_gc list. It is called when unmounting or
++ * remounting read-only so locks are not needed.
++ */
++void ubifs_destroy_idx_gc(struct ubifs_info *c)
++{
++      while (!list_empty(&c->idx_gc)) {
++              struct ubifs_gced_idx_leb *idx_gc;
++
++              idx_gc = list_entry(c->idx_gc.next, struct ubifs_gced_idx_leb,
++                                  list);
++              c->idx_gc_cnt -= 1;
++              list_del(&idx_gc->list);
++              kfree(idx_gc);
++      }
++
++}
++
++/**
++ * ubifs_get_idx_gc_leb - get a LEB from GC'd index LEB list.
++ * @c: UBIFS file-system description object
++ *
++ * Called during start commit so locks are not needed.
++ */
++int ubifs_get_idx_gc_leb(struct ubifs_info *c)
++{
++      struct ubifs_gced_idx_leb *idx_gc;
++      int lnum;
++
++      if (list_empty(&c->idx_gc))
++              return -ENOSPC;
++      idx_gc = list_entry(c->idx_gc.next, struct ubifs_gced_idx_leb, list);
++      lnum = idx_gc->lnum;
++      /* c->idx_gc_cnt is updated by the caller when lprops are updated */
++      list_del(&idx_gc->list);
++      kfree(idx_gc);
++      return lnum;
++}
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/io.c avr32-2.6/fs/ubifs/io.c
+--- linux-2.6.25.6/fs/ubifs/io.c       1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/io.c    2008-06-12 15:09:45.367815766 +0200
+@@ -0,0 +1,921 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ * Copyright (C) 2006, 2007 University of Szeged, Hungary
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Artem Bityutskiy (Битюцкий Артём)
++ *          Adrian Hunter
++ *          Zoltan Sogor
++ */
++
++/*
++ * This file implements UBIFS I/O subsystem which provides various I/O-related
++ * helper functions (reading/writing/checking/validating nodes) and implements
++ * write-buffering support. Write buffers help to save space which otherwise
++ * would have been wasted for padding to the nearest minimal I/O unit boundary.
++ * Instead, data first goes to the write-buffer and is flushed when the
++ * buffer is full or when it is not used for some time (by timer). This is
++ * similarto the mechanism is used by JFFS2.
++ *
++ * Write-buffers are defined by 'struct ubifs_wbuf' objects and protected by
++ * mutexes defined inside these objects. Since sometimes upper-level code
++ * has to lock the write-buffer (e.g. journal space reservation code), many
++ * functions related to write-buffers have "nolock" suffix which means that the
++ * caller has to lock the write-buffer before calling this function.
++ *
++ * UBIFS stores nodes at 64 bit-aligned addresses. If the node length is not
++ * aligned, UBIFS starts the next node from the aligned address, and the padded
++ * bytes may contain any rubbish. In other words, UBIFS does not put padding
++ * bytes in those small gaps. Common headers of nodes store real node lengths,
++ * not aligned lengths. Indexing nodes also store real lengths in branches.
++ *
++ * UBIFS uses padding when it pads to the next min. I/O unit. In this case it
++ * uses padding nodes or padding bytes, if the padding node does not fit.
++ *
++ * All UBIFS nodes are protected by CRC checksums and UBIFS checks all nodes
++ * every time they are read from the flash media.
++ */
++
++#include <linux/crc32.h>
++#include "ubifs.h"
++
++/**
++ * ubifs_check_node - check node.
++ * @c: UBIFS file-system description object
++ * @buf: node to check
++ * @lnum: logical eraseblock number
++ * @offs: offset within the logical eraseblock
++ * @quiet: print no messages
++ *
++ * This function checks node magic number and CRC checksum. This function also
++ * validates node length to prevent UBIFS from becoming crazy when an attacker
++ * feeds it a file-system image with incorrect nodes. For example, too large
++ * node length in the common header could cause UBIFS to read memory outside of
++ * allocated buffer when checking the CRC checksum.
++ *
++ * This function returns zero in case of success %-EUCLEAN in case of bad CRC
++ * or magic.
++ */
++int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
++                   int offs, int quiet)
++{
++      int err = -EINVAL, type, node_len;
++      uint32_t crc, node_crc, magic;
++      const struct ubifs_ch *ch = buf;
++
++      ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
++      ubifs_assert(!(offs & 7) && offs < c->leb_size);
++
++      magic = le32_to_cpu(ch->magic);
++      if (magic != UBIFS_NODE_MAGIC) {
++              if (!quiet)
++                      ubifs_err("bad magic %#08x, expected %#08x",
++                                magic, UBIFS_NODE_MAGIC);
++              err = -EUCLEAN;
++              goto out;
++      }
++
++      type = ch->node_type;
++      if (type < 0 || type >= UBIFS_NODE_TYPES_CNT) {
++              if (!quiet)
++                      ubifs_err("bad node type %d", type);
++              goto out;
++      }
++
++      node_len = le32_to_cpu(ch->len);
++      if (node_len + offs > c->leb_size)
++              goto out_len;
++
++      if (c->ranges[type].max_len == 0) {
++              if (node_len != c->ranges[type].len)
++                      goto out_len;
++      } else if (node_len < c->ranges[type].min_len ||
++                 node_len > c->ranges[type].max_len)
++              goto out_len;
++
++      crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
++      node_crc = le32_to_cpu(ch->crc);
++      if (crc != node_crc) {
++              if (!quiet)
++                      ubifs_err("bad CRC: calculated %#08x, read %#08x",
++                                crc, node_crc);
++              err = -EUCLEAN;
++              goto out;
++      }
++
++      return 0;
++
++out_len:
++      if (!quiet)
++              ubifs_err("bad node length %d", node_len);
++out:
++      if (!quiet) {
++              ubifs_err("bad node at LEB %d:%d", lnum, offs);
++              dbg_dump_node(c, buf);
++              dbg_dump_stack();
++      }
++      return err;
++}
++
++/**
++ * ubifs_pad - pad flash space.
++ * @c: UBIFS file-system description object
++ * @buf: buffer to put padding to
++ * @pad: how many bytes to pad
++ *
++ * The flash media obliges us to write only in chunks of %c->min_io_size and
++ * when we have to write less data we add padding node to the write-buffer and
++ * pad it to the next minimal I/O unit's boundary. Padding nodes help when the
++ * media is being scanned. If the amount of wasted space is not enough to fit a
++ * padding node which takes %UBIFS_PAD_NODE_SZ bytes, we write padding bytes
++ * pattern (%UBIFS_PADDING_BYTE).
++ *
++ * Padding nodes are also used to fill gaps when the "commit-in-gaps" method is
++ * used.
++ */
++void ubifs_pad(const struct ubifs_info *c, void *buf, int pad)
++{
++      uint32_t crc;
++
++      ubifs_assert(pad >= 0 && !(pad & 7));
++
++      if (pad >= UBIFS_PAD_NODE_SZ) {
++              struct ubifs_ch *ch = buf;
++              struct ubifs_pad_node *pad_node = buf;
++
++              ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC);
++              ch->node_type = UBIFS_PAD_NODE;
++              ch->group_type = UBIFS_NO_NODE_GROUP;
++              ch->padding[0] = ch->padding[1] = 0;
++              ch->sqnum = 0;
++              ch->len = cpu_to_le32(UBIFS_PAD_NODE_SZ);
++              pad -= UBIFS_PAD_NODE_SZ;
++              pad_node->pad_len = cpu_to_le32(pad);
++              crc = crc32(UBIFS_CRC32_INIT, buf + 8, UBIFS_PAD_NODE_SZ - 8);
++              ch->crc = cpu_to_le32(crc);
++              memset(buf + UBIFS_PAD_NODE_SZ, 0, pad);
++      } else if (pad > 0)
++              /* Too little space, padding node won't fit */
++              memset(buf, UBIFS_PADDING_BYTE, pad);
++}
++
++/**
++ * next_sqnum - get next sequence number.
++ * @c: UBIFS file-system description object
++ */
++static unsigned long long next_sqnum(struct ubifs_info *c)
++{
++      unsigned long long sqnum;
++
++      spin_lock(&c->cnt_lock);
++      sqnum = ++c->max_sqnum;
++      spin_unlock(&c->cnt_lock);
++
++      if (unlikely(sqnum >= SQNUM_WARN_WATERMARK)) {
++              if (sqnum >= SQNUM_WATERMARK) {
++                      ubifs_err("sequence number overflow %llu, end of life",
++                                sqnum);
++                      ubifs_ro_mode(c, -EINVAL);
++              }
++              ubifs_warn("running out of sequence numbers, end of life soon");
++      }
++
++      return sqnum;
++}
++
++/**
++ * ubifs_prepare_node - prepare node to be written to flash.
++ * @c: UBIFS file-system description object
++ * @node: the node to pad
++ * @len: node length
++ * @pad: if the buffer has to be padded
++ *
++ * This function prepares node at @node to be written to the media - it
++ * calculates node CRC, fills the common header, and adds proper padding up to
++ * the next minimum I/O unit if @pad is not zero.
++ */
++void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad)
++{
++      uint32_t crc;
++      struct ubifs_ch *ch = node;
++      unsigned long long sqnum = next_sqnum(c);
++
++      ubifs_assert(len >= UBIFS_CH_SZ);
++
++      ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC);
++      ch->len = cpu_to_le32(len);
++      ch->group_type = UBIFS_NO_NODE_GROUP;
++      ch->sqnum = cpu_to_le64(sqnum);
++      ch->padding[0] = ch->padding[1] = 0;
++      crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8);
++      ch->crc = cpu_to_le32(crc);
++
++      if (pad) {
++              len = ALIGN(len, 8);
++              pad = ALIGN(len, c->min_io_size) - len;
++              ubifs_pad(c, node + len, pad);
++      }
++}
++
++/**
++ * ubifs_prep_grp_node - prepare node of a group to be written to flash.
++ * @c: UBIFS file-system description object
++ * @node: the node to pad
++ * @len: node length
++ * @last: indicates the last node of the group
++ *
++ * This function prepares node at @node to be written to the media - it
++ * calculates node CRC and fills the common header.
++ */
++void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last)
++{
++      uint32_t crc;
++      struct ubifs_ch *ch = node;
++      unsigned long long sqnum = next_sqnum(c);
++
++      ubifs_assert(len >= UBIFS_CH_SZ);
++
++      ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC);
++      ch->len = cpu_to_le32(len);
++      if (last)
++              ch->group_type = UBIFS_LAST_OF_NODE_GROUP;
++      else
++              ch->group_type = UBIFS_IN_NODE_GROUP;
++      ch->sqnum = cpu_to_le64(sqnum);
++      ch->padding[0] = ch->padding[1] = 0;
++      crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8);
++      ch->crc = cpu_to_le32(crc);
++}
++
++/**
++ * wbuf_timer_callback - write-buffer timer callback function.
++ * @data: timer data (write-buffer descriptor)
++ *
++ * This function is called when the write-buffer timer expires.
++ */
++static void wbuf_timer_callback_nolock(unsigned long data)
++{
++      struct ubifs_wbuf *wbuf = (struct ubifs_wbuf *)data;
++
++      wbuf->need_sync = 1;
++      wbuf->c->need_wbuf_sync = 1;
++      ubifs_wake_up_bgt(wbuf->c);
++}
++
++/**
++ * new_wbuf_timer - start new write-buffer timer.
++ * @wbuf: write-buffer descriptor
++ */
++static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
++{
++      ubifs_assert(!timer_pending(&wbuf->timer));
++
++      if (!wbuf->timeout)
++              return;
++
++      wbuf->timer.expires = jiffies + wbuf->timeout;
++      add_timer(&wbuf->timer);
++}
++
++/**
++ * cancel_wbuf_timer - cancel write-buffer timer.
++ * @wbuf: write-buffer descriptor
++ */
++static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
++{
++      /*
++       * If the syncer is waiting for the lock (from the background thread's
++       * context) and another task is changing write-buffer then the syncing
++       * should be canceled.
++       */
++      wbuf->need_sync = 0;
++      del_timer(&wbuf->timer);
++}
++
++/**
++ * ubifs_wbuf_sync_nolock - synchronize write-buffer.
++ * @wbuf: write-buffer to synchronize
++ *
++ * This function synchronizes write-buffer @buf and returns zero in case of
++ * success or a negative error code in case of failure.
++ */
++int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
++{
++      struct ubifs_info *c = wbuf->c;
++      int err, dirt;
++
++      cancel_wbuf_timer_nolock(wbuf);
++      if (!wbuf->used || wbuf->lnum == -1)
++              /* Write-buffer is empty or not seeked */
++              return 0;
++
++      dbg_io("LEB %d:%d, %d bytes",
++             wbuf->lnum, wbuf->offs, wbuf->used);
++      ubifs_assert(!(c->vfs_sb->s_flags & MS_RDONLY));
++      ubifs_assert(!(wbuf->avail & 7));
++      ubifs_assert(wbuf->offs + c->min_io_size <= c->leb_size);
++
++      if (c->ro_media)
++              return -EROFS;
++
++      ubifs_pad(c, wbuf->buf + wbuf->used, wbuf->avail);
++      err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
++                          c->min_io_size, wbuf->dtype);
++      if (err) {
++              ubifs_err("cannot write %d bytes to LEB %d:%d",
++                        c->min_io_size, wbuf->lnum, wbuf->offs);
++              dbg_dump_stack();
++              return err;
++      }
++
++      dirt = wbuf->avail;
++
++      spin_lock(&wbuf->lock);
++      wbuf->offs += c->min_io_size;
++      wbuf->avail = c->min_io_size;
++      wbuf->used = 0;
++      wbuf->next_ino = 0;
++      spin_unlock(&wbuf->lock);
++
++      if (wbuf->sync_callback)
++              err = wbuf->sync_callback(c, wbuf->lnum,
++                                        c->leb_size - wbuf->offs, dirt);
++      return err;
++}
++
++/**
++ * ubifs_wbuf_seek_nolock - seek write-buffer.
++ * @wbuf: write-buffer
++ * @lnum: logical eraseblock number to seek to
++ * @offs: logical eraseblock offset to seek to
++ * @dtype: data type
++ *
++ * This function targets the write buffer to logical eraseblock @lnum:@offs.
++ * The write-buffer is synchronized if it is not empty. Returns zero in case of
++ * success and a negative error code in case of failure.
++ */
++int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
++                         int dtype)
++{
++      const struct ubifs_info *c = wbuf->c;
++
++      dbg_io("LEB %d:%d", lnum, offs);
++      ubifs_assert(lnum >= 0 && lnum < c->leb_cnt);
++      ubifs_assert(offs >= 0 && offs <= c->leb_size);
++      ubifs_assert(offs % c->min_io_size == 0 && !(offs & 7));
++      ubifs_assert(lnum != wbuf->lnum);
++
++      if (wbuf->used > 0) {
++              int err = ubifs_wbuf_sync_nolock(wbuf);
++
++              if (err)
++                      return err;
++      }
++
++      spin_lock(&wbuf->lock);
++      wbuf->lnum = lnum;
++      wbuf->offs = offs;
++      wbuf->avail = c->min_io_size;
++      wbuf->used = 0;
++      spin_unlock(&wbuf->lock);
++      wbuf->dtype = dtype;
++
++      return 0;
++}
++
++/**
++ * ubifs_bg_wbufs_sync - synchronize write-buffers.
++ * @c: UBIFS file-system description object
++ *
++ * This function is called by background thread to synchronize write-buffers.
++ * Returns zero in case of success and a negative error code in case of
++ * failure.
++ */
++int ubifs_bg_wbufs_sync(struct ubifs_info *c)
++{
++      int err, i;
++
++      if (!c->need_wbuf_sync)
++              return 0;
++      c->need_wbuf_sync = 0;
++
++      if (c->ro_media) {
++              err = -EROFS;
++              goto out_timers;
++      }
++
++      dbg_io("synchronize");
++      for (i = 0; i < c->jhead_cnt; i++) {
++              struct ubifs_wbuf *wbuf = &c->jheads[i].wbuf;
++
++              cond_resched();
++
++              /*
++               * If the mutex is locked then wbuf is being changed, so
++               * synchronization is not necessary.
++               */
++              if (mutex_is_locked(&wbuf->io_mutex))
++                      continue;
++
++              mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
++              if (!wbuf->need_sync) {
++                      mutex_unlock(&wbuf->io_mutex);
++                      continue;
++              }
++
++              err = ubifs_wbuf_sync_nolock(wbuf);
++              mutex_unlock(&wbuf->io_mutex);
++              if (err) {
++                      ubifs_err("cannot sync write-buffer, error %d", err);
++                      ubifs_ro_mode(c, err);
++                      goto out_timers;
++              }
++      }
++
++      return 0;
++
++out_timers:
++      /* Cancel all timers to prevent repeated errors */
++      for (i = 0; i < c->jhead_cnt; i++) {
++              struct ubifs_wbuf *wbuf = &c->jheads[i].wbuf;
++
++              mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
++              cancel_wbuf_timer_nolock(wbuf);
++              mutex_unlock(&wbuf->io_mutex);
++      }
++      return err;
++}
++
++/**
++ * ubifs_wbuf_write_nolock - write data to flash via write-buffer.
++ * @wbuf: write-buffer
++ * @buf: node to write
++ * @len: node length
++ *
++ * This function writes data to flash via write-buffer @wbuf. This means that
++ * the last piece of the node won't reach the flash media immediately if it
++ * does not take whole minimal I/O unit. Instead, the node will sit in RAM
++ * until the write-buffer is synchronized (e.g., by timer).
++ *
++ * This function returns zero in case of success and a negative error code in
++ * case of failure. If the node cannot be written because there is no more
++ * space in this logical eraseblock, %-ENOSPC is returned.
++ */
++int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
++{
++      struct ubifs_info *c = wbuf->c;
++      int err, written, n, aligned_len = ALIGN(len, 8), offs;
++
++      dbg_io("%d bytes (%s) to wbuf at LEB %d:%d", len,
++             dbg_ntype(((struct ubifs_ch *)buf)->node_type), wbuf->lnum,
++             wbuf->offs + wbuf->used);
++      ubifs_assert(len > 0 && wbuf->lnum >= 0 && wbuf->lnum < c->leb_cnt);
++      ubifs_assert(wbuf->offs >= 0 && wbuf->offs % c->min_io_size == 0);
++      ubifs_assert(!(wbuf->offs & 7) && wbuf->offs <= c->leb_size);
++      ubifs_assert(wbuf->avail > 0 && wbuf->avail <= c->min_io_size);
++      ubifs_assert(mutex_is_locked(&wbuf->io_mutex));
++
++      if (c->leb_size - wbuf->offs - wbuf->used < aligned_len) {
++              err = -ENOSPC;
++              goto out;
++      }
++
++      cancel_wbuf_timer_nolock(wbuf);
++
++      if (c->ro_media)
++              return -EROFS;
++
++      if (aligned_len <= wbuf->avail) {
++              /*
++               * The node is not very large and fits entirely within
++               * write-buffer.
++               */
++              memcpy(wbuf->buf + wbuf->used, buf, len);
++
++              if (aligned_len == wbuf->avail) {
++                      dbg_io("flush wbuf to LEB %d:%d", wbuf->lnum,
++                              wbuf->offs);
++                      err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf,
++                                          wbuf->offs, c->min_io_size,
++                                          wbuf->dtype);
++                      if (err)
++                              goto out;
++
++                      spin_lock(&wbuf->lock);
++                      wbuf->offs += c->min_io_size;
++                      wbuf->avail = c->min_io_size;
++                      wbuf->used = 0;
++                      wbuf->next_ino = 0;
++                      spin_unlock(&wbuf->lock);
++              } else {
++                      spin_lock(&wbuf->lock);
++                      wbuf->avail -= aligned_len;
++                      wbuf->used += aligned_len;
++                      spin_unlock(&wbuf->lock);
++              }
++
++              goto exit;
++      }
++
++      /*
++       * The node is large enough and does not fit entirely within current
++       * minimal I/O unit. We have to fill and flush write-buffer and switch
++       * to the next min. I/O unit.
++       */
++      dbg_io("flush wbuf to LEB %d:%d", wbuf->lnum, wbuf->offs);
++      memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
++      err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
++                          c->min_io_size, wbuf->dtype);
++      if (err)
++              goto out;
++
++      offs = wbuf->offs + c->min_io_size;
++      len -= wbuf->avail;
++      aligned_len -= wbuf->avail;
++      written = wbuf->avail;
++
++      /*
++       * The remaining data may take more whole min. I/O units, so write the
++       * remains multiple to min. I/O unit size directly to the flash media.
++       * We align node length to 8-byte boundary because we anyway flash wbuf
++       * if the remaining space is less than 8 bytes.
++       */
++      n = aligned_len >> c->min_io_shift;
++      if (n) {
++              n <<= c->min_io_shift;
++              dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum, offs);
++              err = ubi_leb_write(c->ubi, wbuf->lnum, buf + written, offs, n,
++                                  wbuf->dtype);
++              if (err)
++                      goto out;
++              offs += n;
++              aligned_len -= n;
++              len -= n;
++              written += n;
++      }
++
++      spin_lock(&wbuf->lock);
++      if (aligned_len)
++              /*
++               * And now we have what's left and what does not take whole
++               * min. I/O unit, so write it to the write-buffer and we are
++               * done.
++               */
++              memcpy(wbuf->buf, buf + written, len);
++
++      wbuf->offs = offs;
++      wbuf->used = aligned_len;
++      wbuf->avail = c->min_io_size - aligned_len;
++      wbuf->next_ino = 0;
++      spin_unlock(&wbuf->lock);
++
++exit:
++      if (wbuf->sync_callback) {
++              int free = c->leb_size - wbuf->offs - wbuf->used;
++
++              err = wbuf->sync_callback(c, wbuf->lnum, free, 0);
++              if (err)
++                      goto out;
++      }
++
++      if (wbuf->used)
++              new_wbuf_timer_nolock(wbuf);
++
++      return 0;
++
++out:
++      ubifs_err("cannot write %d bytes to LEB %d:%d, error %d",
++                len, wbuf->lnum, wbuf->offs, err);
++      dbg_dump_node(c, buf);
++      dbg_dump_stack();
++      dbg_dump_leb(c, wbuf->lnum);
++      return err;
++}
++
++/**
++ * ubifs_write_node - write node to the media.
++ * @c: UBIFS file-system description object
++ * @buf: the node to write
++ * @len: node length
++ * @lnum: logical eraseblock number
++ * @offs: offset within the logical eraseblock
++ * @dtype: node life-time hint (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN)
++ *
++ * This function automatically fills node magic number, assigns sequence
++ * number, and calculates node CRC checksum. The length of the @buf buffer has
++ * to be aligned to the minimal I/O unit size. This function automatically
++ * appends padding node and padding bytes if needed. Returns zero in case of
++ * success and a negative error code in case of failure.
++ */
++int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
++                   int offs, int dtype)
++{
++      int err, buf_len = ALIGN(len, c->min_io_size);
++
++      dbg_io("LEB %d:%d, %s, length %d (aligned %d)",
++             lnum, offs, dbg_ntype(((struct ubifs_ch *)buf)->node_type), len,
++             buf_len);
++      ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
++      ubifs_assert(offs % c->min_io_size == 0 && offs < c->leb_size);
++
++      if (c->ro_media)
++              return -EROFS;
++
++      ubifs_prepare_node(c, buf, len, 1);
++      err = ubi_leb_write(c->ubi, lnum, buf, offs, buf_len, dtype);
++      if (err) {
++              ubifs_err("cannot write %d bytes to LEB %d:%d, error %d",
++                        buf_len, lnum, offs, err);
++              dbg_dump_node(c, buf);
++              dbg_dump_stack();
++      }
++
++      return err;
++}
++
++/**
++ * ubifs_read_node_wbuf - read node from the media or write-buffer.
++ * @wbuf: wbuf to check for un-written data
++ * @buf: buffer to read to
++ * @type: node type
++ * @len: node length
++ * @lnum: logical eraseblock number
++ * @offs: offset within the logical eraseblock
++ *
++ * This function reads a node of known type and length, checks it and stores
++ * in @buf. If the node partially or fully sits in the write-buffer, this
++ * function takes data from the buffer, otherwise it reads the flash media.
++ * Returns zero in case of success, %-EUCLEAN if CRC mismatched and a negative
++ * error code in case of failure.
++ */
++int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
++                       int lnum, int offs)
++{
++      const struct ubifs_info *c = wbuf->c;
++      int err, rlen, overlap;
++      struct ubifs_ch *ch = buf;
++
++      dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len);
++      ubifs_assert(wbuf && lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
++      ubifs_assert(!(offs & 7) && offs < c->leb_size);
++      ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT);
++
++      spin_lock(&wbuf->lock);
++      overlap = (lnum == wbuf->lnum && offs + len > wbuf->offs);
++      if (!overlap) {
++              /* We may safely unlock the write-buffer and read the data */
++              spin_unlock(&wbuf->lock);
++              return ubifs_read_node(c, buf, type, len, lnum, offs);
++      }
++
++      /* Don't read under wbuf */
++      rlen = wbuf->offs - offs;
++      if (rlen < 0)
++              rlen = 0;
++
++      /* Copy the rest from the write-buffer */
++      memcpy(buf + rlen, wbuf->buf + offs + rlen - wbuf->offs, len - rlen);
++      spin_unlock(&wbuf->lock);
++
++      if (rlen > 0) {
++              /* Read everything that goes before write-buffer */
++              err = ubi_read(c->ubi, lnum, buf, offs, rlen);
++              if (err && err != -EBADMSG) {
++                      ubifs_err("failed to read node %d from LEB %d:%d, "
++                                "error %d", type, lnum, offs, err);
++                      dbg_dump_stack();
++                      return err;
++              }
++      }
++
++      err = ubifs_check_node(c, buf, lnum, offs, 0);
++      if (err) {
++              ubifs_err("expected node type %d", type);
++              return err;
++      }
++
++      if (type != ch->node_type) {
++              ubifs_err("bad node type (%d but expected %d)",
++                        ch->node_type, type);
++              goto out;
++      }
++
++      rlen = le32_to_cpu(ch->len);
++      if (rlen != len) {
++              ubifs_err("bad node length %d, expected %d", rlen, len);
++              goto out;
++      }
++
++      return 0;
++
++out:
++      ubifs_err("bad node at LEB %d:%d", lnum, offs);
++      dbg_dump_node(c, buf);
++      dbg_dump_stack();
++      return -EINVAL;
++}
++
++/**
++ * ubifs_read_node - read node.
++ * @c: UBIFS file-system description object
++ * @buf: buffer to read to
++ * @type: node type
++ * @len: node length (not aligned)
++ * @lnum: logical eraseblock number
++ * @offs: offset within the logical eraseblock
++ *
++ * This function reads a node of known type and and length, checks it and
++ * stores in @buf. Returns zero in case of success, %-EUCLEAN if CRC mismatched
++ * and a negative error code in case of failure.
++ */
++int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
++                  int lnum, int offs)
++{
++      int err, l;
++      struct ubifs_ch *ch = buf;
++
++      dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len);
++      ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
++      ubifs_assert(len >= UBIFS_CH_SZ && offs + len <= c->leb_size);
++      ubifs_assert(!(offs & 7) && offs < c->leb_size);
++      ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT);
++
++      err = ubi_read(c->ubi, lnum, buf, offs, len);
++      if (err && err != -EBADMSG) {
++              ubifs_err("cannot read node %d from LEB %d:%d, error %d",
++                        type, lnum, offs, err);
++              return err;
++      }
++
++      err = ubifs_check_node(c, buf, lnum, offs, 0);
++      if (err) {
++              ubifs_err("expected node type %d", type);
++              return err;
++      }
++
++      if (type != ch->node_type) {
++              ubifs_err("bad node type (%d but expected %d)",
++                        ch->node_type, type);
++              goto out;
++      }
++
++      l = le32_to_cpu(ch->len);
++      if (l != len) {
++              ubifs_err("bad node length %d, expected %d", l, len);
++              goto out;
++      }
++
++      return 0;
++
++out:
++      ubifs_err("bad node at LEB %d:%d", lnum, offs);
++      dbg_dump_node(c, buf);
++      dbg_dump_stack();
++      return -EINVAL;
++}
++
++/**
++ * ubifs_wbuf_init - initialize write-buffer.
++ * @c: UBIFS file-system description object
++ * @wbuf: write-buffer to initialize
++ *
++ * This function initializes write buffer. Returns zero in case of success
++ * %-ENOMEM in case of failure.
++ */
++int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
++{
++      size_t size;
++
++      wbuf->buf = kmalloc(c->min_io_size, GFP_KERNEL);
++      if (!wbuf->buf)
++              return -ENOMEM;
++
++      size = (c->min_io_size / UBIFS_CH_SZ + 1) * sizeof(ino_t);
++      wbuf->inodes = kmalloc(size, GFP_KERNEL);
++      if (!wbuf->inodes) {
++              kfree(wbuf->buf);
++              wbuf->buf = NULL;
++              return -ENOMEM;
++      }
++
++      wbuf->used = 0;
++      wbuf->lnum = wbuf->offs = -1;
++      wbuf->avail = c->min_io_size;
++      wbuf->dtype = UBI_UNKNOWN;
++      wbuf->sync_callback = NULL;
++      mutex_init(&wbuf->io_mutex);
++      spin_lock_init(&wbuf->lock);
++
++      wbuf->c = c;
++      init_timer(&wbuf->timer);
++      wbuf->timer.function = wbuf_timer_callback_nolock;
++      wbuf->timer.data = (unsigned long)wbuf;
++      wbuf->timeout = DEFAULT_WBUF_TIMEOUT;
++      wbuf->next_ino = 0;
++
++      return 0;
++}
++
++/**
++ * ubifs_wbuf_add_ino_nolock - add an inode number into the wbuf inode array.
++ * @wbuf: the write-buffer whereto add
++ * @inum: the inode number
++ *
++ * This function adds an inode number to the inode array of the write-buffer.
++ */
++void ubifs_wbuf_add_ino_nolock(struct ubifs_wbuf *wbuf, ino_t inum)
++{
++      if (!wbuf->buf)
++              /* NOR flash or something similar */
++              return;
++
++      spin_lock(&wbuf->lock);
++      if (wbuf->used)
++              wbuf->inodes[wbuf->next_ino++] = inum;
++      spin_unlock(&wbuf->lock);
++}
++
++/**
++ * wbuf_has_ino - returns if the wbuf contains data from the inode.
++ * @wbuf: the write-buffer
++ * @inum: the inode number
++ *
++ * This function returns with %1 if the write-buffer contains some data from the
++ * given inode otherwise it returns with %0.
++ */
++static int wbuf_has_ino(struct ubifs_wbuf *wbuf, ino_t inum)
++{
++      int i, ret = 0;
++
++      spin_lock(&wbuf->lock);
++      for (i = 0; i < wbuf->next_ino; i++)
++              if (inum == wbuf->inodes[i]) {
++                      ret = 1;
++                      break;
++              }
++      spin_unlock(&wbuf->lock);
++
++      return ret;
++}
++
++/**
++ * ubifs_sync_wbufs_by_inodes - synchronize write-buffers which have data.
++ * belonging to specified inodes.
++ * @c: UBIFS file-system description object
++ * @inodes: array of inodes
++ * @count: number of elements in @inodes
++ *
++ * This function synchronizes write-buffers which contain nodes belonging to
++ * any inode specified in @inodes array. Returns zero in case of success and a
++ * negative error code in case of failure.
++ */
++int ubifs_sync_wbufs_by_inodes(struct ubifs_info *c,
++                             struct inode * const *inodes, int count)
++{
++      int i, j, err = 0;
++
++      ubifs_assert(count);
++
++      for (i = 0; i < c->jhead_cnt; i++) {
++              struct ubifs_wbuf *wbuf = &c->jheads[i].wbuf;
++
++              if (i == GCHD)
++                      /*
++                       * GC head is special, do not look at it. Even if the
++                       * head contains something related to this inode, it is
++                       * a _copy_ of corresponding on-flash node which sits
++                       * somewhere else.
++                       */
++                      continue;
++
++              for (j = 0; j < count && !err; j++)
++                      if (wbuf_has_ino(wbuf, inodes[j]->i_ino)) {
++                              mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
++                              if (wbuf_has_ino(wbuf, inodes[j]->i_ino))
++                                      err = ubifs_wbuf_sync_nolock(wbuf);
++                              mutex_unlock(&wbuf->io_mutex);
++                              break;
++                      }
++
++              if (err) {
++                      ubifs_ro_mode(c, err);
++                      break;
++              }
++      }
++
++      return err;
++}
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/ioctl.c avr32-2.6/fs/ubifs/ioctl.c
+--- linux-2.6.25.6/fs/ubifs/ioctl.c    1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/ioctl.c 2008-06-12 15:09:45.367815766 +0200
+@@ -0,0 +1,204 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ * Copyright (C) 2006, 2007 University of Szeged, Hungary
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Zoltan Sogor
++ *          Artem Bityutskiy (Битюцкий Артём)
++ *          Adrian Hunter
++ */
++
++/* This file implements EXT2-compatible extended attribute ioctl() calls */
++
++#include <linux/compat.h>
++#include <linux/smp_lock.h>
++#include "ubifs.h"
++
++/**
++ * ubifs_set_inode_flags - set VFS inode flags.
++ * @inode: VFS inode to set flags for
++ *
++ * This function propagates flags from UBIFS inode object to VFS inode object.
++ */
++void ubifs_set_inode_flags(struct inode *inode)
++{
++      unsigned int flags = ubifs_inode(inode)->flags;
++
++      inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE | S_DIRSYNC);
++      if (flags & UBIFS_SYNC_FL)
++              inode->i_flags |= S_SYNC;
++      if (flags & UBIFS_APPEND_FL)
++              inode->i_flags |= S_APPEND;
++      if (flags & UBIFS_IMMUTABLE_FL)
++              inode->i_flags |= S_IMMUTABLE;
++      if (flags & UBIFS_DIRSYNC_FL)
++              inode->i_flags |= S_DIRSYNC;
++}
++
++/*
++ * ioctl2ubifs - convert ioctl inode flags to UBIFS inode flags.
++ * @ioctl_flags: flags to convert
++ *
++ * This function convert ioctl flags (@FS_COMPR_FL, etc) to UBIFS inode flags
++ * (@UBIFS_COMPR_FL, etc).
++ */
++static int ioctl2ubifs(int ioctl_flags)
++{
++      int ubifs_flags = 0;
++
++      if (ioctl_flags & FS_COMPR_FL)
++              ubifs_flags |= UBIFS_COMPR_FL;
++      if (ioctl_flags & FS_SYNC_FL)
++              ubifs_flags |= UBIFS_SYNC_FL;
++      if (ioctl_flags & FS_APPEND_FL)
++              ubifs_flags |= UBIFS_APPEND_FL;
++      if (ioctl_flags & FS_IMMUTABLE_FL)
++              ubifs_flags |= UBIFS_IMMUTABLE_FL;
++      if (ioctl_flags & FS_DIRSYNC_FL)
++              ubifs_flags |= UBIFS_DIRSYNC_FL;
++
++      return ubifs_flags;
++}
++
++/*
++ * ubifs2ioctl - convert UBIFS inode flags to ioctl inode flags.
++ * @ubifs_flags: flags to convert
++ *
++ * This function convert UBIFS (@UBIFS_COMPR_FL, etc) to ioctl flags
++ * (@FS_COMPR_FL, etc).
++ */
++static int ubifs2ioctl(int ubifs_flags)
++{
++      int ioctl_flags = 0;
++
++      if (ubifs_flags & UBIFS_COMPR_FL)
++              ioctl_flags |= FS_COMPR_FL;
++      if (ubifs_flags & UBIFS_SYNC_FL)
++              ioctl_flags |= FS_SYNC_FL;
++      if (ubifs_flags & UBIFS_APPEND_FL)
++              ioctl_flags |= FS_APPEND_FL;
++      if (ubifs_flags & UBIFS_IMMUTABLE_FL)
++              ioctl_flags |= FS_IMMUTABLE_FL;
++      if (ubifs_flags & UBIFS_DIRSYNC_FL)
++              ioctl_flags |= FS_DIRSYNC_FL;
++
++      return ioctl_flags;
++}
++
++static int setflags(struct inode *inode, int flags)
++{
++      struct ubifs_inode *ui = ubifs_inode(inode);
++      struct ubifs_info *c = inode->i_sb->s_fs_info;
++      struct ubifs_budget_req req;
++      int oldflags, err;
++
++      mutex_lock(&inode->i_mutex);
++
++      memset(&req, 0 , sizeof(struct ubifs_budget_req));
++      err = ubifs_budget_inode_op(c, inode, &req);
++      if (err)
++              goto out;
++
++      /*
++       * The IMMUTABLE and APPEND_ONLY flags can only be changed by
++       * the relevant capability.
++       */
++      oldflags = ubifs2ioctl(ui->flags);
++      if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) {
++              if (!capable(CAP_LINUX_IMMUTABLE)) {
++                      err = -EPERM;
++                      goto out_budg;
++              }
++      }
++
++      ui->flags = ioctl2ubifs(flags);
++      ubifs_set_inode_flags(inode);
++
++      inode->i_ctime = ubifs_current_time(inode);
++      mark_inode_dirty_sync(inode);
++
++      ubifs_release_ino_dirty(c, inode, &req);
++
++      if (IS_SYNC(inode))
++              err = write_inode_now(inode, 1);
++
++      mutex_unlock(&inode->i_mutex);
++      return err;
++
++out_budg:
++      ubifs_cancel_ino_op(c, inode, &req);
++out:
++      ubifs_err("can't modify inode %lu attributes", inode->i_ino);
++      mutex_unlock(&inode->i_mutex);
++      return err;
++}
++
++long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++      int flags;
++      struct inode *inode = file->f_path.dentry->d_inode;
++
++      switch (cmd) {
++      case FS_IOC_GETFLAGS:
++              flags = ubifs2ioctl(ubifs_inode(inode)->flags);
++
++              return put_user(flags, (int __user *) arg);
++
++      case FS_IOC_SETFLAGS: {
++              if (IS_RDONLY(inode))
++                      return -EROFS;
++
++              if (!is_owner_or_cap(inode))
++                      return -EACCES;
++
++              if (get_user(flags, (int __user *) arg))
++                      return -EFAULT;
++
++              if (!S_ISDIR(inode->i_mode))
++                      flags &= ~FS_DIRSYNC_FL;
++
++              return setflags(inode, flags);
++      }
++
++      default:
++              return -ENOTTY;
++      }
++}
++
++#ifdef CONFIG_COMPAT
++long ubifs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++      int err;
++
++      switch (cmd) {
++      case FS_IOC32_GETFLAGS:
++              cmd = FS_IOC_GETFLAGS;
++              break;
++      case FS_IOC32_SETFLAGS:
++              cmd = FS_IOC_SETFLAGS;
++              break;
++      default:
++              return -ENOIOCTLCMD;
++      }
++
++      lock_kernel();
++      err = ubifs_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
++      unlock_kernel();
++
++      return err;
++}
++#endif
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/journal.c avr32-2.6/fs/ubifs/journal.c
+--- linux-2.6.25.6/fs/ubifs/journal.c  1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/journal.c       2008-06-12 15:09:45.367815766 +0200
+@@ -0,0 +1,1286 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Artem Bityutskiy (Битюцкий Артём)
++ *          Adrian Hunter
++ */
++
++/*
++ * This file implements UBIFS journal.
++ *
++ * The journal consists of 2 parts - the log and bud LEBs. The log has fixed
++ * length and position, while a bud logical eraseblock is any LEB in the main
++ * area. Buds contain file system data - data nodes, inode nodes, etc. The log
++ * contains only references to buds and some other stuff like commit
++ * start node. The idea is that when we commit the journal, we do
++ * not copy the data, the buds just become indexed. Since after the commit the
++ * nodes in bud eraseblocks become leaf nodes of the file system index tree, we
++ * use term "bud". Analogy is obvious, bud eraseblocks contain nodes which will
++ * become leafs in the future.
++ *
++ * The journal is multi-headed because we want to write data to the journal as
++ * optimally as possible. It is nice to have nodes belonging to the same inode
++ * in one LEB, so we may write data owned by different inodes to different
++ * journal heads, although at present only one data head is used.
++ *
++ * For recovery reasons, the base head contains all inode nodes, all directory
++ * entry nodes and all truncate nodes.  This means that the other heads contain
++ * only data nodes.
++ *
++ * Bud LEBs may be half-indexed. For example, if the bud was not full at the
++ * time of commit, the bud is retained to continue to be used in the journal,
++ * even though the "front" of the LEB is now indexed. In that case, the log
++ * reference contains the offset where the bud starts for the purposes of the
++ * journal.
++ *
++ * The journal size has to be limited, because the larger is the journal, the
++ * longer it takes to mount UBIFS (scanning the journal) and the more memory it
++ * takes (indexing in the TNC).
++ *
++ * Note, all the journal write operations like 'ubifs_jnl_update()' here, which
++ * write multiple UBIFS nodes to the journal at one go, are atomic with respect
++ * to unclean reboots. Should the unclean reboot happen, the recovery code drops
++ * all the nodes.
++ */
++
++#include "ubifs.h"
++
++/**
++ * zero_ino_node_unused - zero out unused fields of an on-flash inode node.
++ * @ino: the inode to zero out
++ */
++static inline void zero_ino_node_unused(struct ubifs_ino_node *ino)
++{
++      memset(ino->padding, 0, 26);
++}
++
++/**
++ * zero_dent_node_unused - zero out unused fields of an on-flash directory
++ *                         entry node.
++ * @ino: the directory entry to zero out
++ */
++static inline void zero_dent_node_unused(struct ubifs_dent_node *dent)
++{
++      dent->padding1 = 0;
++      memset(dent->padding2, 0, 4);
++}
++
++/**
++ * zero_data_node_unused - zero out unused fields of an on-flash data node.
++ * @ino: the data node to zero out
++ */
++static inline void zero_data_node_unused(struct ubifs_data_node *data)
++{
++      memset(data->padding, 0, 2);
++}
++
++/**
++ * zero_trun_node_unused - zero out unused fields of an on-flash truncation
++ *                         node.
++ * @ino: the truncation node to zero out
++ */
++static inline void zero_trun_node_unused(struct ubifs_trun_node *trun)
++{
++      memset(trun->padding, 0, 12);
++}
++
++/**
++ * reserve_space - reserve space in the journal.
++ * @c: UBIFS file-system description object
++ * @jhead: journal head number
++ * @len: node length
++ *
++ * This function reserves space in journal head @head. If the reservation
++ * succeeded, the journal head stays locked and later has to be unlocked using
++ * 'release_head()'. 'write_node()' and 'write_head()' functions also unlock
++ * it. Returns zero in case of success, %-EAGAIN if commit has to be done, and
++ * other negative error codes in case of other failures.
++ */
++static int reserve_space(struct ubifs_info *c, int jhead, int len)
++{
++      int err = 0, err1, retries = 0, avail, lnum, offs, free, squeeze;
++      struct ubifs_wbuf *wbuf = &c->jheads[jhead].wbuf;
++
++      /*
++       * Typically, the base head has smaller nodes written to it, so it is
++       * better to try to allocate space at the ends of eraseblocks. This is
++       * what the squeeze parameter does.
++       */
++      squeeze = (jhead == BASEHD);
++again:
++      mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
++      avail = c->leb_size - wbuf->offs - wbuf->used;
++
++      if (wbuf->lnum != -1 && avail >= len)
++              return 0;
++
++      /*
++       * Write buffer wasn't seek'ed or there is no enough space - look for an
++       * LEB with some empty space.
++       */
++      lnum = ubifs_find_free_space(c, len, &free, squeeze);
++      if (lnum >= 0) {
++              /* Found an LEB, add it to the journal head */
++              offs = c->leb_size - free;
++              err = ubifs_add_bud_to_log(c, jhead, lnum, offs);
++              if (err)
++                      goto out_return;
++              /* A new bud was successfully allocated and added to the log */
++              goto out;
++      }
++
++      err = lnum;
++      if (err != -ENOSPC)
++              goto out_unlock;
++
++      /*
++       * No free space, we have to run garbage collector to make
++       * some. But the write-buffer mutex has to be unlocked because
++       * GC have to sync write buffers, which may lead a deadlock.
++       */
++      dbg_jnl("no free space  jhead %d, run GC", jhead);
++      mutex_unlock(&wbuf->io_mutex);
++
++      lnum = ubifs_garbage_collect(c, 0);
++      if (lnum < 0) {
++              err = lnum;
++              if (err != -ENOSPC)
++                      return err;
++
++              /*
++               * GC could not make a free LEB. But someone else may
++               * have allocated new bud for this journal head,
++               * because we dropped the 'io_mutex', so try once
++               * again.
++               */
++              dbg_jnl("GC couldn't make a free LEB for jhead %d", jhead);
++              if (retries++ < 2) {
++                      dbg_jnl("retry (%d)", retries);
++                      goto again;
++              }
++
++              dbg_jnl("return -ENOSPC");
++              return err;
++      }
++
++      mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
++      dbg_jnl("got LEB %d for jhead %d", lnum, jhead);
++      avail = c->leb_size - wbuf->offs - wbuf->used;
++
++      if (wbuf->lnum != -1 && avail >= len) {
++              /*
++               * Someone else has switched the journal head and we have
++               * enough space now. This happens when more then one process is
++               * trying to write to the same journal head at the same time.
++               */
++              dbg_jnl("return LEB %d back, already have LEB %d:%d",
++                      lnum, wbuf->lnum, wbuf->offs + wbuf->used);
++              err = ubifs_return_leb(c, lnum);
++              if (err)
++                      goto out_unlock;
++              return 0;
++      }
++
++      err = ubifs_add_bud_to_log(c, jhead, lnum, 0);
++      if (err)
++              goto out_return;
++      offs = 0;
++
++out:
++      err = ubifs_wbuf_seek_nolock(wbuf, lnum, offs, UBI_SHORTTERM);
++      if (err)
++              goto out_unlock;
++
++      return 0;
++
++out_unlock:
++      mutex_unlock(&wbuf->io_mutex);
++      return err;
++
++out_return:
++      /* An error occurred and the LEB has to be returned to lprops */
++      ubifs_assert(err < 0);
++      err1 = ubifs_return_leb(c, lnum);
++      if (err1 && err == -EAGAIN)
++              /*
++               * Return original error code 'err' only if it is not
++               * '-EAGAIN', which is not really an error. Otherwise, return
++               * the error code of 'ubifs_return_leb()'.
++               */
++              err = err1;
++      mutex_unlock(&wbuf->io_mutex);
++      return err;
++}
++
++/**
++ * write_node - write node to a journal head.
++ * @c: UBIFS file-system description object
++ * @jhead: journal head
++ * @node: node to write
++ * @len: node length
++ * @lnum: LEB number written is returned here
++ * @offs: offset written is returned here
++ *
++ * This function writes a node to reserved space of journal head @jhead.
++ * Returns zero in case of success and a negative error code in case of
++ * failure.
++ */
++static int write_node(struct ubifs_info *c, int jhead, void *node, int len,
++                    int *lnum, int *offs)
++{
++      struct ubifs_wbuf *wbuf = &c->jheads[jhead].wbuf;
++
++      ubifs_assert(jhead != GCHD);
++
++      *lnum = c->jheads[jhead].wbuf.lnum;
++      *offs = c->jheads[jhead].wbuf.offs + c->jheads[jhead].wbuf.used;
++
++      dbg_jnl("jhead %d, LEB %d:%d, len %d", jhead, *lnum, *offs, len);
++      ubifs_prepare_node(c, node, len, 0);
++
++      return ubifs_wbuf_write_nolock(wbuf, node, len);
++}
++
++/**
++ * write_head - write data to a journal head.
++ * @c: UBIFS file-system description object
++ * @jhead: journal head
++ * @buf: buffer to write
++ * @len: length to write
++ * @lnum: LEB number written is returned here
++ * @offs: offset written is returned here
++ * @sync: non-zero if the write-buffer has to by synchronized
++ *
++ * This function is the same as 'write_node()' but it does not assume the
++ * buffer it is writing is a node, so it does not prepare it (which means
++ * initializing common header and calculating CRC).
++ */
++static int write_head(struct ubifs_info *c, int jhead, void *buf, int len,
++                    int *lnum, int *offs, int sync)
++{
++      int err;
++      struct ubifs_wbuf *wbuf = &c->jheads[jhead].wbuf;
++
++      ubifs_assert(jhead != GCHD);
++
++      *lnum = c->jheads[jhead].wbuf.lnum;
++      *offs = c->jheads[jhead].wbuf.offs + c->jheads[jhead].wbuf.used;
++      dbg_jnl("jhead %d, LEB %d:%d, len %d", jhead, *lnum, *offs, len);
++
++      err = ubifs_wbuf_write_nolock(wbuf, buf, len);
++      if (err)
++              return err;
++      if (sync)
++              err = ubifs_wbuf_sync_nolock(wbuf);
++      return err;
++}
++
++/**
++ * make_reservation - reserve journal space.
++ * @c: UBIFS file-system description object
++ * @jhead: journal head
++ * @len: how many bytes to reserve
++ *
++ * This function makes space reservation in journal head @jhead. The function
++ * takes the commit lock and locks the journal head, and the caller has to
++ * unlock the head and finish the reservation with 'finish_reservation()'.
++ * Returns zero in case of success and a negative error code in case of
++ * failure.
++ *
++ * Note, the journal head may be unlocked as soon as the data is written, while
++ * the commit lock has to be released after the data has been added to the
++ * TNC.
++ */
++static int make_reservation(struct ubifs_info *c, int jhead, int len)
++{
++      int err, cmt_retries = 0, nospc_retries = 0;
++
++      ubifs_assert(len <= c->dark_wm);
++
++again:
++      down_read(&c->commit_sem);
++      err = reserve_space(c, jhead, len);
++      if (!err)
++              return 0;
++      up_read(&c->commit_sem);
++
++      if (err == -ENOSPC) {
++              /*
++               * GC could not make any progress. We should try to commit
++               * once because it could make some dirty space and GC would
++               * make progress, so make the error -EAGAIN so that the below
++               * will commit and re-try.
++               */
++              if (nospc_retries++ < 2) {
++                      dbg_jnl("no space, retry");
++                      err = -EAGAIN;
++              }
++
++              /*
++               * This means that the budgeting is incorrect. We always have
++               * to be able to write to the media, because all operations are
++               * budgeted. Deletions are not budgeted, though, but we reserve
++               * an extra LEB for them.
++               */
++      }
++
++      if (err != -EAGAIN)
++              goto out;
++
++      /*
++       * -EAGAIN means that the journal is full or too large, or the above
++       * code wants to do one commit. Do this and re-try.
++       */
++      if (cmt_retries > 128) {
++              /*
++               * This should not happen unless the journal size limitations
++               * are too tough.
++               */
++              ubifs_err("stuck in space allocation");
++              err = -ENOSPC;
++              goto out;
++      } else if (cmt_retries > 32)
++              ubifs_warn("too many space allocation re-tries (%d)",
++                         cmt_retries);
++
++      dbg_jnl("-EAGAIN, commit and retry (retried %d times)",
++              cmt_retries);
++      cmt_retries += 1;
++
++      err = ubifs_run_commit(c);
++      if (err)
++              return err;
++      goto again;
++
++out:
++      ubifs_err("cannot reserve %d bytes in jhead %d, error %d",
++                len, jhead, err);
++      if (err == -ENOSPC) {
++              /* This are some budgeting problems, print useful information */
++              down_write(&c->commit_sem);
++              spin_lock(&c->space_lock);
++              dbg_dump_stack();
++              dbg_dump_budg(c);
++              spin_unlock(&c->space_lock);
++              dbg_dump_lprops(c);
++              cmt_retries = dbg_check_lprops(c);
++              up_write(&c->commit_sem);
++      }
++
++      return err;
++}
++
++/**
++ * release_head - release a journal head.
++ * @c: UBIFS file-system description object
++ * @jhead: journal head
++ *
++ * This function releases journal head @jhead which was locked by
++ * the 'make_reservation()' function. It has to be called after each successful
++ * 'make_reservation()' invocation.
++ */
++static inline void release_head(struct ubifs_info *c, int jhead)
++{
++      mutex_unlock(&c->jheads[jhead].wbuf.io_mutex);
++}
++
++/**
++ * finish_reservation - finish a reservation.
++ * @c: UBIFS file-system description object
++ *
++ * This function finishes journal space reservation. It must be called after
++ * 'make_reservation()'.
++ */
++static void finish_reservation(struct ubifs_info *c)
++{
++      up_read(&c->commit_sem);
++}
++
++/**
++ * get_dent_type - translate VFS inode mode to UBIFS directory entry type.
++ * @mode: inode mode
++ */
++static int get_dent_type(int mode)
++{
++      switch (mode & S_IFMT) {
++      case S_IFREG:
++              return UBIFS_ITYPE_REG;
++      case S_IFDIR:
++              return UBIFS_ITYPE_DIR;
++      case S_IFLNK:
++              return UBIFS_ITYPE_LNK;
++      case S_IFBLK:
++              return UBIFS_ITYPE_BLK;
++      case S_IFCHR:
++              return UBIFS_ITYPE_CHR;
++      case S_IFIFO:
++              return UBIFS_ITYPE_FIFO;
++      case S_IFSOCK:
++              return UBIFS_ITYPE_SOCK;
++      default:
++              BUG();
++      }
++      return 0;
++}
++
++/**
++ * pack_inode - pack an inode node.
++ * @c: UBIFS file-system description object
++ * @ino: buffer in which to pack inode node
++ * @inode: inode to pack
++ * @last: indicates the last node of the group
++ * @last_reference: non-zero if this is a deletion inode
++ */
++static void pack_inode(struct ubifs_info *c, struct ubifs_ino_node *ino,
++                     const struct inode *inode, int last, int last_reference)
++{
++      int data_len = 0;
++      struct ubifs_inode *ui = ubifs_inode(inode);
++
++      ino->ch.node_type = UBIFS_INO_NODE;
++      ino_key_init_flash(c, &ino->key, inode->i_ino);
++      ino->creat_sqnum = cpu_to_le64(ui->creat_sqnum);
++      ino->size  = cpu_to_le64(i_size_read(inode));
++      ino->nlink = cpu_to_le32(inode->i_nlink);
++      ino->atime_sec  = cpu_to_le64(inode->i_atime.tv_sec);
++      ino->atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec);
++      ino->ctime_sec  = cpu_to_le64(inode->i_ctime.tv_sec);
++      ino->ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
++      ino->mtime_sec  = cpu_to_le64(inode->i_mtime.tv_sec);
++      ino->mtime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec);
++      ino->uid   = cpu_to_le32(inode->i_uid);
++      ino->gid   = cpu_to_le32(inode->i_gid);
++      ino->mode  = cpu_to_le32(inode->i_mode);
++      ino->flags = cpu_to_le32(ui->flags);
++      ino->compr_type  = cpu_to_le16(ui->compr_type);
++      ino->xattr_cnt   = cpu_to_le32(ui->xattr_cnt);
++      ino->xattr_size  = cpu_to_le64(ui->xattr_size);
++      ino->xattr_names = cpu_to_le32(ui->xattr_names);
++      ino->data_len    = cpu_to_le32(ui->data_len);
++      zero_ino_node_unused(ino);
++
++      /*
++       * Drop the attached data if this is a deletion inode, the data is not
++       * needed anymore.
++       */
++      if (!last_reference) {
++              memcpy(ino->data, ui->data, ui->data_len);
++              data_len = ui->data_len;
++      }
++
++      ubifs_prep_grp_node(c, ino, UBIFS_INO_NODE_SZ + data_len, last);
++}
++
++/**
++ * ubifs_jnl_update - update inode.
++ * @c: UBIFS file-system description object
++ * @dir: parent inode or host inode in case of extended attributes
++ * @nm: directory entry name
++ * @inode: inode
++ * @deletion: indicates a directory entry deletion i.e unlink or rmdir
++ * @sync: non-zero if the write-buffer has to be synchronized
++ * @xent: non-zero if the directory entry is an extended attribute entry
++ *
++ * This function updates an inode by writing a directory entry (or extended
++ * attribute entry), the inode itself, and the parent directory inode (or the
++ * host inode) to the journal.
++ *
++ * The function writes the host inode @dir last, which is important in case of
++ * extended attributes. Indeed, then we guarantee that if the host inode gets
++ * synchronized, and the write-buffer it sits in gets flushed, the extended
++ * attribute inode gets flushed too. And this is exactly what the user expects -
++ * synchronizing the host inode synchronizes its extended attributes.
++ * Similarly, this guarantees that if @dir is synchronized, its directory entry
++ * corresponding to @nm gets synchronized too.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
++                   const struct qstr *nm, const struct inode *inode,
++                   int deletion, int sync, int xent)
++{
++      int err, dlen, ilen, len, lnum, ino_offs, dent_offs;
++      int aligned_dlen, aligned_ilen;
++      int last_reference = !!(deletion && inode->i_nlink == 0);
++      struct ubifs_dent_node *dent;
++      struct ubifs_ino_node *ino;
++      union ubifs_key dent_key, ino_key;
++
++      dbg_jnl("ino %lu, dent '%.*s', data len %d in dir ino %lu",
++              inode->i_ino, nm->len, nm->name, ubifs_inode(inode)->data_len,
++              dir->i_ino);
++      ubifs_assert(ubifs_inode(dir)->data_len == 0);
++
++      dlen = UBIFS_DENT_NODE_SZ + nm->len + 1;
++      ilen = UBIFS_INO_NODE_SZ;
++
++      /*
++       * If the last reference to the inode is being deleted, then there is no
++       * need to attach and write inode data, it is being deleted anyway.
++       */
++      if (!last_reference)
++              ilen += ubifs_inode(inode)->data_len;
++
++      aligned_dlen = ALIGN(dlen, 8);
++      aligned_ilen = ALIGN(ilen, 8);
++
++      len = aligned_dlen + aligned_ilen + UBIFS_INO_NODE_SZ;
++
++      dent = kmalloc(len, GFP_NOFS);
++      if (!dent)
++              return -ENOMEM;
++
++      /* Make reservation before allocating sequence numbers */
++      err = make_reservation(c, BASEHD, len);
++      if (err)
++              goto out_free;
++
++      if (!xent) {
++              dent->ch.node_type = UBIFS_DENT_NODE;
++              dent_key_init(c, &dent_key, dir->i_ino, nm);
++      } else {
++              dent->ch.node_type = UBIFS_XENT_NODE;
++              xent_key_init(c, &dent_key, dir->i_ino, nm);
++      }
++
++      key_write(c, &dent_key, dent->key);
++      dent->inum = deletion ? 0 : cpu_to_le64(inode->i_ino);
++      dent->type = get_dent_type(inode->i_mode);
++      dent->nlen = cpu_to_le16(nm->len);
++      memcpy(dent->name, nm->name, nm->len);
++      dent->name[nm->len] = '\0';
++      zero_dent_node_unused(dent);
++      ubifs_prep_grp_node(c, dent, dlen, 0);
++
++      ino = (void *)dent + aligned_dlen;
++      pack_inode(c, ino, inode, 0, last_reference);
++
++      ino = (void *)ino + aligned_ilen;
++      pack_inode(c, ino, dir, 1, 0);
++
++      if (last_reference) {
++              err = ubifs_add_orphan(c, inode->i_ino);
++              if (err) {
++                      release_head(c, BASEHD);
++                      goto out_finish;
++              }
++      }
++
++      err = write_head(c, BASEHD, dent, len, &lnum, &dent_offs, sync);
++      if (!sync && !err) {
++              struct ubifs_wbuf *wbuf = &c->jheads[BASEHD].wbuf;
++
++              ubifs_wbuf_add_ino_nolock(wbuf, inode->i_ino);
++              ubifs_wbuf_add_ino_nolock(wbuf, dir->i_ino);
++      }
++      release_head(c, BASEHD);
++      kfree(dent);
++      if (err)
++              goto out_ro;
++
++      if (deletion) {
++              err = ubifs_tnc_remove_nm(c, &dent_key, nm);
++              if (err)
++                      goto out_ro;
++              err = ubifs_add_dirt(c, lnum, dlen);
++      } else
++              err = ubifs_tnc_add_nm(c, &dent_key, lnum, dent_offs, dlen, nm);
++      if (err)
++              goto out_ro;
++
++      /*
++       * Note, we do not remove the inode from TNC even if the last reference
++       * to it has just been deleted, because the inode may still be opened.
++       * Instead, the inode has been added to orphan lists and the orphan
++       * subsystem will take further care about it.
++       */
++      ino_key_init(c, &ino_key, inode->i_ino);
++      ino_offs = dent_offs + aligned_dlen;
++      err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, ilen);
++      if (err)
++              goto out_ro;
++
++      ino_key_init(c, &ino_key, dir->i_ino);
++      ino_offs += aligned_ilen;
++      err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, UBIFS_INO_NODE_SZ);
++      if (err)
++              goto out_ro;
++
++      finish_reservation(c);
++      return 0;
++
++out_finish:
++      finish_reservation(c);
++out_free:
++      kfree(dent);
++      return err;
++
++out_ro:
++      ubifs_ro_mode(c, err);
++      if (last_reference)
++              ubifs_delete_orphan(c, inode->i_ino);
++      finish_reservation(c);
++      return err;
++}
++
++/**
++ * ubifs_jnl_write_data - write a data node to the journal.
++ * @c: UBIFS file-system description object
++ * @inode: inode the data node belongs to
++ * @key: node key
++ * @buf: buffer to write
++ * @len: data length (must not exceed %UBIFS_BLOCK_SIZE)
++ *
++ * This function writes a data node to the journal. Returns %0 if the data node
++ * was successfully written, and a negative error code in case of failure.
++ */
++int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
++                       const union ubifs_key *key, const void *buf, int len)
++{
++      int err, lnum, offs, compr_type, out_len;
++      int dlen = UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR;
++      const struct ubifs_inode *ui = ubifs_inode(inode);
++      struct ubifs_data_node *data;
++
++      dbg_jnl("ino %lu, blk %u, len %d, key %s", key_inum(c, key),
++              key_block(c, key), len, DBGKEY(key));
++      ubifs_assert(len <= UBIFS_BLOCK_SIZE);
++
++      data = kmalloc(dlen, GFP_NOFS);
++      if (!data)
++              return -ENOMEM;
++
++      data->ch.node_type = UBIFS_DATA_NODE;
++      key_write(c, key, &data->key);
++      data->size = cpu_to_le32(len);
++      zero_data_node_unused(data);
++
++      if (!(ui->flags && UBIFS_COMPR_FL))
++              /* Compression is disabled for this inode */
++              compr_type = UBIFS_COMPR_NONE;
++      else
++              compr_type = ui->compr_type;
++
++      out_len = dlen - UBIFS_DATA_NODE_SZ;
++      ubifs_compress(buf, len, &data->data, &out_len, &compr_type);
++      ubifs_assert(out_len <= UBIFS_BLOCK_SIZE);
++
++      dlen = UBIFS_DATA_NODE_SZ + out_len;
++      data->compr_type = cpu_to_le16(compr_type);
++
++      /* Make reservation before allocating sequence numbers */
++      err = make_reservation(c, DATAHD, dlen);
++      if (err)
++              goto out_free;
++
++      err = write_node(c, DATAHD, data, dlen, &lnum, &offs);
++      if (!err)
++              ubifs_wbuf_add_ino_nolock(&c->jheads[DATAHD].wbuf,
++                                        key_inum(c, key));
++      release_head(c, DATAHD);
++      if (err)
++              goto out_ro;
++
++      err = ubifs_tnc_add(c, key, lnum, offs, dlen);
++      if (err)
++              goto out_ro;
++
++      finish_reservation(c);
++      kfree(data);
++      return 0;
++
++out_ro:
++      ubifs_ro_mode(c, err);
++      finish_reservation(c);
++out_free:
++      kfree(data);
++      return err;
++}
++
++/**
++ * ubifs_jnl_write_inode - flush inode to the journal.
++ * @c: UBIFS file-system description object
++ * @inode: inode to flush
++ * @last_reference: inode has been deleted
++ * @sync: non-zero if the write-buffer has to be synchronized
++ *
++ * This function writes inode @inode to the journal (to the base head). Returns
++ * zero in case of success and a negative error code in case of failure.
++ */
++int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode,
++                        int last_reference, int sync)
++{
++      int err, len, lnum, offs;
++      struct ubifs_ino_node *ino;
++      struct ubifs_inode *ui = ubifs_inode(inode);
++
++      dbg_jnl("ino %lu%s", inode->i_ino,
++              last_reference ? " (last reference)" : "");
++      if (last_reference)
++              ubifs_assert(inode->i_nlink == 0);
++
++      /* If the inode is deleted, do not write the attached data */
++      len = UBIFS_INO_NODE_SZ;
++      if (!last_reference)
++              len += ui->data_len;
++      ino = kmalloc(len, GFP_NOFS);
++      if (!ino)
++              return -ENOMEM;
++
++      /* Make reservation before allocating sequence numbers */
++      err = make_reservation(c, BASEHD, len);
++      if (err)
++              goto out_free;
++
++      pack_inode(c, ino, inode, 1, last_reference);
++
++      err = write_head(c, BASEHD, ino, len, &lnum, &offs, sync);
++      if (!sync && !err)
++              ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf,
++                                        inode->i_ino);
++      release_head(c, BASEHD);
++      if (err)
++              goto out_ro;
++
++      if (last_reference) {
++              err = ubifs_tnc_remove_ino(c, inode->i_ino);
++              if (err)
++                      goto out_ro;
++              ubifs_delete_orphan(c, inode->i_ino);
++              err = ubifs_add_dirt(c, lnum, len);
++      } else {
++              union ubifs_key key;
++
++              ino_key_init(c, &key, inode->i_ino);
++              err = ubifs_tnc_add(c, &key, lnum, offs, len);
++      }
++      if (err)
++              goto out_ro;
++
++      finish_reservation(c);
++      kfree(ino);
++      return 0;
++
++out_ro:
++      ubifs_ro_mode(c, err);
++      finish_reservation(c);
++out_free:
++      kfree(ino);
++      return err;
++}
++
++/**
++ * ubifs_jnl_rename - rename a directory entry.
++ * @c: UBIFS file-system description object
++ * @old_dir: parent inode of directory entry to rename
++ * @old_dentry: directory entry to rename
++ * @new_dir: parent inode of directory entry to rename
++ * @new_dentry: new directory entry (or directory entry to replace)
++ * @sync: non-zero if the write-buffer has to be synchronized
++ *
++ * Returns zero in case of success and a negative error code in case of failure.
++ */
++int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
++                   const struct dentry *old_dentry,
++                   const struct inode *new_dir,
++                   const struct dentry *new_dentry, int sync)
++{
++      const struct inode *old_inode = old_dentry->d_inode;
++      const struct inode *new_inode = new_dentry->d_inode;
++      int err, dlen1, dlen2, ilen, lnum, offs, len;
++      int aligned_dlen1, aligned_dlen2, plen = UBIFS_INO_NODE_SZ;
++      int last_reference = !!(new_inode && new_inode->i_nlink == 0);
++      struct ubifs_dent_node *dent, *dent2;
++      void *p;
++      union ubifs_key key;
++
++      dbg_jnl("dent '%.*s' in dir ino %lu to dent '%.*s' in dir ino %lu",
++              old_dentry->d_name.len, old_dentry->d_name.name,
++              old_dir->i_ino, new_dentry->d_name.len,
++              new_dentry->d_name.name, new_dir->i_ino);
++
++      ubifs_assert(ubifs_inode(old_dir)->data_len == 0);
++      ubifs_assert(ubifs_inode(new_dir)->data_len == 0);
++
++      dlen1 = UBIFS_DENT_NODE_SZ + new_dentry->d_name.len + 1;
++      dlen2 = UBIFS_DENT_NODE_SZ + old_dentry->d_name.len + 1;
++      if (new_inode) {
++              ilen = UBIFS_INO_NODE_SZ;
++              if (!last_reference)
++                      ilen += ubifs_inode(new_inode)->data_len;
++      } else
++              ilen = 0;
++
++      aligned_dlen1 = ALIGN(dlen1, 8);
++      aligned_dlen2 = ALIGN(dlen2, 8);
++
++      len = aligned_dlen1 + aligned_dlen2 + ALIGN(ilen, 8) + ALIGN(plen, 8);
++      if (old_dir != new_dir)
++              len += plen;
++
++      dent = kmalloc(len, GFP_NOFS);
++      if (!dent)
++              return -ENOMEM;
++
++      /* Make reservation before allocating sequence numbers */
++      err = make_reservation(c, BASEHD, len);
++      if (err)
++              goto out_free;
++
++      /* Make new dent */
++      dent->ch.node_type = UBIFS_DENT_NODE;
++      dent_key_init_flash(c, &dent->key, new_dir->i_ino, &new_dentry->d_name);
++      dent->inum = cpu_to_le64(old_inode->i_ino);
++      dent->type = get_dent_type(old_inode->i_mode);
++      dent->nlen = cpu_to_le16(new_dentry->d_name.len);
++      memcpy(dent->name, new_dentry->d_name.name, new_dentry->d_name.len);
++      dent->name[new_dentry->d_name.len] = '\0';
++      zero_dent_node_unused(dent);
++      ubifs_prep_grp_node(c, dent, dlen1, 0);
++
++      dent2 = (void *)dent + aligned_dlen1;
++
++      /* Make deletion dent */
++      dent2->ch.node_type = UBIFS_DENT_NODE;
++      dent_key_init_flash(c, &dent2->key, old_dir->i_ino,
++                          &old_dentry->d_name);
++      dent2->inum = 0;
++      dent2->type = DT_UNKNOWN;
++      dent2->nlen = cpu_to_le16(old_dentry->d_name.len);
++      memcpy(dent2->name, old_dentry->d_name.name, old_dentry->d_name.len);
++      dent2->name[old_dentry->d_name.len] = '\0';
++      zero_dent_node_unused(dent2);
++      ubifs_prep_grp_node(c, dent2, dlen2, 0);
++
++      p = (void *)dent2 + aligned_dlen2;
++      if (new_inode) {
++              pack_inode(c, p, new_inode, 0, last_reference);
++              p += ALIGN(ilen, 8);
++      }
++
++      if (old_dir == new_dir)
++              pack_inode(c, p, old_dir, 1, 0);
++      else {
++              pack_inode(c, p, old_dir, 0, 0);
++              p += ALIGN(plen, 8);
++              pack_inode(c, p, new_dir, 1, 0);
++      }
++
++      if (last_reference) {
++              err = ubifs_add_orphan(c, new_inode->i_ino);
++              if (err) {
++                      release_head(c, BASEHD);
++                      goto out_finish;
++              }
++      }
++
++      err = write_head(c, BASEHD, dent, len, &lnum, &offs, sync);
++      if (!sync && !err) {
++              struct ubifs_wbuf *wbuf = &c->jheads[BASEHD].wbuf;
++
++              ubifs_wbuf_add_ino_nolock(wbuf, new_dir->i_ino);
++              ubifs_wbuf_add_ino_nolock(wbuf, old_dir->i_ino);
++              if (new_inode)
++                      ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf,
++                                                new_inode->i_ino);
++      }
++      release_head(c, BASEHD);
++      if (err)
++              goto out_ro;
++
++      dent_key_init(c, &key, new_dir->i_ino, &new_dentry->d_name);
++      err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, &new_dentry->d_name);
++      if (err)
++              goto out_ro;
++
++      err = ubifs_add_dirt(c, lnum, dlen2);
++      if (err)
++              goto out_ro;
++
++      dent_key_init(c, &key, old_dir->i_ino, &old_dentry->d_name);
++      err = ubifs_tnc_remove_nm(c, &key, &old_dentry->d_name);
++      if (err)
++              goto out_ro;
++
++      offs += aligned_dlen1 + aligned_dlen2;
++      if (new_inode) {
++              ino_key_init(c, &key, new_inode->i_ino);
++              err = ubifs_tnc_add(c, &key, lnum, offs, ilen);
++              if (err)
++                      goto out_ro;
++              offs += ALIGN(ilen, 8);
++      }
++
++      ino_key_init(c, &key, old_dir->i_ino);
++      err = ubifs_tnc_add(c, &key, lnum, offs, plen);
++      if (err)
++              goto out_ro;
++
++      if (old_dir != new_dir) {
++              offs += ALIGN(plen, 8);
++              ino_key_init(c, &key, new_dir->i_ino);
++              err = ubifs_tnc_add(c, &key, lnum, offs, plen);
++              if (err)
++                      goto out_ro;
++      }
++
++      finish_reservation(c);
++      kfree(dent);
++      return 0;
++
++out_ro:
++      ubifs_ro_mode(c, err);
++      if (last_reference)
++              ubifs_delete_orphan(c, new_inode->i_ino);
++out_finish:
++      finish_reservation(c);
++out_free:
++      kfree(dent);
++      return err;
++}
++
++/**
++ * recomp_data_node - re-compress a truncated data node.
++ * @dn: data node to re-compress
++ * @new_len: new length
++ *
++ * This function is used when an inode is truncated and the last data node of
++ * the inode has to be re-compressed and re-written.
++ */
++static int recomp_data_node(struct ubifs_data_node *dn, int *new_len)
++{
++      void *buf;
++      int err, len, compr_type, out_len;
++
++      out_len = le32_to_cpu(dn->size);
++      buf = kmalloc(out_len * WORST_COMPR_FACTOR, GFP_NOFS);
++      if (!buf)
++              return -ENOMEM;
++
++      len = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
++      compr_type = le16_to_cpu(dn->compr_type);
++      err = ubifs_decompress(&dn->data, len, buf, &out_len, compr_type);
++      if (err)
++              goto out;
++
++      ubifs_compress(buf, *new_len, &dn->data, &out_len, &compr_type);
++      ubifs_assert(out_len <= UBIFS_BLOCK_SIZE);
++      dn->compr_type = cpu_to_le16(compr_type);
++      dn->size = cpu_to_le32(*new_len);
++      *new_len = UBIFS_DATA_NODE_SZ + out_len;
++out:
++      kfree(buf);
++      return err;
++}
++
++/**
++ * ubifs_jnl_truncate - update the journal for a truncation.
++ * @c: UBIFS file-system description object
++ * @inum: inode number of inode being truncated
++ * @old_size: old size
++ * @new_size: new size
++ *
++ * When the size of a file decreases due to truncation, a truncation node is
++ * written, the journal tree is updated, and the last data block is re-written
++ * if it has been affected.
++ *
++ * This function returns %0 in the case of success, and a negative error code in
++ * case of failure.
++ */
++int ubifs_jnl_truncate(struct ubifs_info *c, ino_t inum,
++                     loff_t old_size, loff_t new_size)
++{
++      union ubifs_key key, to_key;
++      struct ubifs_trun_node *trun;
++      struct ubifs_data_node *uninitialized_var(dn);
++      int err, dlen, len, lnum, offs, bit, sz;
++      unsigned int blk;
++
++      dbg_jnl("ino %lu, size %lld -> %lld", inum, old_size, new_size);
++
++      sz = UBIFS_TRUN_NODE_SZ + UBIFS_MAX_DATA_NODE_SZ * WORST_COMPR_FACTOR;
++      trun = kmalloc(sz, GFP_NOFS);
++      if (!trun)
++              return -ENOMEM;
++
++      trun->ch.node_type = UBIFS_TRUN_NODE;
++      trun->inum = cpu_to_le32(inum);
++      trun->old_size = cpu_to_le64(old_size);
++      trun->new_size = cpu_to_le64(new_size);
++      zero_trun_node_unused(trun);
++
++      dlen = new_size & (UBIFS_BLOCK_SIZE - 1);
++
++      if (dlen) {
++              /* Get last data block so it can be truncated */
++              dn = (void *)trun + ALIGN(UBIFS_TRUN_NODE_SZ, 8);
++              blk = new_size / UBIFS_BLOCK_SIZE;
++              data_key_init(c, &key, inum, blk);
++              dbg_jnl("last block key %s", DBGKEY(&key));
++              err = ubifs_tnc_lookup(c, &key, dn);
++              if (err == -ENOENT)
++                      dlen = 0; /* Not found (so it is a hole) */
++              else if (err)
++                      goto out_free;
++              else {
++                      if (le32_to_cpu(dn->size) <= dlen)
++                              dlen = 0; /* Nothing to do */
++                      else {
++                              int compr_type = le16_to_cpu(dn->compr_type);
++
++                              if (compr_type != UBIFS_COMPR_NONE) {
++                                      err = recomp_data_node(dn, &dlen);
++                                      if (err)
++                                              goto out_free;
++                              } else {
++                                      dn->size = cpu_to_le32(dlen);
++                                      dlen += UBIFS_DATA_NODE_SZ;
++                              }
++                              zero_data_node_unused(dn);
++                      }
++              }
++      }
++
++      if (dlen)
++              len = ALIGN(UBIFS_TRUN_NODE_SZ, 8) + dlen;
++      else
++              len = UBIFS_TRUN_NODE_SZ;
++
++      /* Must make reservation before allocating sequence numbers */
++      err = make_reservation(c, BASEHD, len);
++      if (err)
++              goto out_free;
++
++      ubifs_prepare_node(c, trun, UBIFS_TRUN_NODE_SZ, 0);
++      if (dlen)
++              ubifs_prepare_node(c, dn, dlen, 0);
++
++      err = write_head(c, BASEHD, trun, len, &lnum, &offs, 0);
++      if (!err)
++              ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, inum);
++      release_head(c, BASEHD);
++      if (err)
++              goto out_ro;
++
++      if (dlen) {
++              offs += ALIGN(UBIFS_TRUN_NODE_SZ, 8);
++              err = ubifs_tnc_add(c, &key, lnum, offs, dlen);
++              if (err)
++                      goto out_ro;
++      }
++
++      err = ubifs_add_dirt(c, lnum, UBIFS_TRUN_NODE_SZ);
++      if (err)
++              goto out_ro;
++
++      bit = new_size & (UBIFS_BLOCK_SIZE - 1);
++
++      blk = new_size / UBIFS_BLOCK_SIZE + (bit ? 1 : 0);
++      data_key_init(c, &key, inum, blk);
++
++      bit = old_size & (UBIFS_BLOCK_SIZE - 1);
++
++      blk = old_size / UBIFS_BLOCK_SIZE - (bit ? 0: 1);
++      data_key_init(c, &to_key, inum, blk);
++
++      err = ubifs_tnc_remove_range(c, &key, &to_key);
++      if (err)
++              goto out_ro;
++
++      finish_reservation(c);
++      kfree(trun);
++      return 0;
++
++out_ro:
++      ubifs_ro_mode(c, err);
++      finish_reservation(c);
++out_free:
++      kfree(trun);
++      return err;
++}
++
++#ifdef CONFIG_UBIFS_FS_XATTR
++
++int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
++                         const struct inode *inode, const struct qstr *nm,
++                         int sync)
++{
++      int err, xlen, hlen, len, lnum, xent_offs, aligned_xlen;
++      struct ubifs_dent_node *xent;
++      struct ubifs_ino_node *ino;
++      union ubifs_key xent_key, key1, key2;
++
++      dbg_jnl("host %lu, xattr ino %lu, name '%s', data len %d",
++              host->i_ino, inode->i_ino, nm->name,
++              ubifs_inode(inode)->data_len);
++      ubifs_assert(inode->i_nlink == 0);
++
++      /*
++       * Since we are deleting the inode, we do not bother to attach any data
++       * to it and assume its length is %UBIFS_INO_NODE_SZ.
++       */
++      xlen = UBIFS_DENT_NODE_SZ + nm->len + 1;
++      aligned_xlen = ALIGN(xlen, 8);
++      hlen = ubifs_inode(host)->data_len + UBIFS_INO_NODE_SZ;
++      len = aligned_xlen + UBIFS_INO_NODE_SZ + ALIGN(hlen, 8);
++
++      xent = kmalloc(len, GFP_NOFS);
++      if (!xent)
++              return -ENOMEM;
++
++      /* Make reservation before allocating sequence numbers */
++      err = make_reservation(c, BASEHD, len);
++      if (err) {
++              kfree(xent);
++              return err;
++      }
++
++      xent->ch.node_type = UBIFS_XENT_NODE;
++      xent_key_init(c, &xent_key, host->i_ino, nm);
++      key_write(c, &xent_key, xent->key);
++      xent->inum = 0;
++      xent->type = get_dent_type(inode->i_mode);
++      xent->nlen = cpu_to_le16(nm->len);
++      memcpy(xent->name, nm->name, nm->len);
++      xent->name[nm->len] = '\0';
++      zero_dent_node_unused(xent);
++      ubifs_prep_grp_node(c, xent, xlen, 0);
++
++      ino = (void *)xent + aligned_xlen;
++      pack_inode(c, ino, inode, 0, 1);
++
++      ino = (void *)ino + UBIFS_INO_NODE_SZ;
++      pack_inode(c, ino, host, 1, 0);
++
++      err = write_head(c, BASEHD, xent, len, &lnum, &xent_offs, sync);
++      if (!sync && !err)
++              ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, host->i_ino);
++      release_head(c, BASEHD);
++      kfree(xent);
++      if (err)
++              goto out_ro;
++
++      /* Remove the extended attribute entry from TNC */
++      err = ubifs_tnc_remove_nm(c, &xent_key, nm);
++      if (err)
++              goto out_ro;
++      err = ubifs_add_dirt(c, lnum, xlen);
++      if (err)
++              goto out_ro;
++
++      /*
++       * Remove all nodes belonging to the extended attribute inode from TNC.
++       * Well, there actually must be only one node - the inode itself.
++       */
++      lowest_ino_key(c, &key1, inode->i_ino);
++      highest_ino_key(c, &key2, inode->i_ino);
++      err = ubifs_tnc_remove_range(c, &key1, &key2);
++      if (err)
++              goto out_ro;
++      err = ubifs_add_dirt(c, lnum, UBIFS_INO_NODE_SZ);
++      if (err)
++              goto out_ro;
++
++      /* And update TNC with the new host inode position */
++      ino_key_init(c, &key1, host->i_ino);
++      err = ubifs_tnc_add(c, &key1, lnum, xent_offs + len - hlen, hlen);
++      if (err)
++              goto out_ro;
++
++      finish_reservation(c);
++      return 0;
++
++out_ro:
++      ubifs_ro_mode(c, err);
++      finish_reservation(c);
++      return err;
++}
++
++/**
++ * ubifs_jnl_write_2_inodes - write 2 inodes to the journal.
++ * @c: UBIFS file-system description object
++ * @inode1: first inode to write
++ * @inode2: second inode to write
++ * @sync: non-zero if the write-buffer has to be synchronized
++ *
++ * This function writes 2 inodes @inode1 and @inode2 to the journal (to the
++ * base head - first @inode1, then @inode2). Returns zero in case of success
++ * and a negative error code in case of failure.
++ */
++int ubifs_jnl_write_2_inodes(struct ubifs_info *c, const struct inode *inode1,
++                           const struct inode *inode2, int sync)
++{
++      int err, len1, len2, aligned_len, aligned_len1, lnum, offs;
++      struct ubifs_ino_node *ino;
++      union ubifs_key key;
++
++      dbg_jnl("ino %lu, ino %lu", inode1->i_ino, inode2->i_ino);
++      ubifs_assert(inode1->i_nlink > 0);
++      ubifs_assert(inode2->i_nlink > 0);
++
++      len1 = UBIFS_INO_NODE_SZ + ubifs_inode(inode1)->data_len;
++      len2 = UBIFS_INO_NODE_SZ + ubifs_inode(inode2)->data_len;
++      aligned_len1 = ALIGN(len1, 8);
++      aligned_len = aligned_len1 + ALIGN(len2, 8);
++
++      ino = kmalloc(aligned_len, GFP_NOFS);
++      if (!ino)
++              return -ENOMEM;
++
++      /* Make reservation before allocating sequence numbers */
++      err = make_reservation(c, BASEHD, aligned_len);
++      if (err)
++              goto out_free;
++
++      pack_inode(c, ino, inode1, 0, 0);
++      pack_inode(c, (void *)ino + aligned_len1, inode2, 1, 0);
++
++      err = write_head(c, BASEHD, ino, aligned_len, &lnum, &offs, 0);
++      if (!sync && !err) {
++              struct ubifs_wbuf *wbuf = &c->jheads[BASEHD].wbuf;
++
++              ubifs_wbuf_add_ino_nolock(wbuf, inode1->i_ino);
++              ubifs_wbuf_add_ino_nolock(wbuf, inode2->i_ino);
++      }
++      release_head(c, BASEHD);
++      if (err)
++              goto out_ro;
++
++      ino_key_init(c, &key, inode1->i_ino);
++      err = ubifs_tnc_add(c, &key, lnum, offs, len1);
++      if (err)
++              goto out_ro;
++
++      ino_key_init(c, &key, inode2->i_ino);
++      err = ubifs_tnc_add(c, &key, lnum, offs + aligned_len1, len2);
++      if (err)
++              goto out_ro;
++
++      finish_reservation(c);
++      kfree(ino);
++      return 0;
++
++out_ro:
++      ubifs_ro_mode(c, err);
++      finish_reservation(c);
++out_free:
++      kfree(ino);
++      return err;
++}
++
++#endif /* CONFIG_UBIFS_FS_XATTR */
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/Kconfig avr32-2.6/fs/ubifs/Kconfig
+--- linux-2.6.25.6/fs/ubifs/Kconfig    1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/Kconfig 2008-06-12 15:09:45.311815896 +0200
+@@ -0,0 +1,72 @@
++config UBIFS_FS
++      tristate "UBIFS file system support"
++      select CRC16
++      select CRC32
++      select CRYPTO if UBIFS_FS_ADVANCED_COMPR
++      select CRYPTO if UBIFS_FS_LZO
++      select CRYPTO if UBIFS_FS_ZLIB
++      select CRYPTO_LZO if UBIFS_FS_LZO
++      select CRYPTO_DEFLATE if UBIFS_FS_ZLIB
++      depends on MTD_UBI
++      help
++        UBIFS is a file system for flash devices which works on top of UBI.
++
++config UBIFS_FS_XATTR
++      bool "Extended attributes support"
++      depends on UBIFS_FS
++      help
++        This option enables support of extended attributes.
++
++config UBIFS_FS_ADVANCED_COMPR
++      bool "Advanced compression options"
++      depends on UBIFS_FS
++      help
++        This option allows to explicitly choose which compressions, if any,
++        are enabled in UBIFS. Removing compressors means inbility to read
++        existing file systems.
++
++        If unsure, say 'N'.
++
++config UBIFS_FS_LZO
++      bool "LZO compression support" if UBIFS_FS_ADVANCED_COMPR
++      depends on UBIFS_FS
++      default y
++      help
++         LZO compressor is generally faster then zlib but compresses worse.
++         Say 'Y' if unsure.
++
++config UBIFS_FS_ZLIB
++      bool "ZLIB compression support" if UBIFS_FS_ADVANCED_COMPR
++      depends on UBIFS_FS
++      default y
++      help
++        Zlib copresses better then LZO but it is slower. Say 'Y' if unsure.
++
++# Debugging-related stuff
++config UBIFS_FS_DEBUG
++      bool "Enable debugging"
++      depends on UBIFS_FS
++      select DEBUG_FS
++      select KALLSYMS_ALL
++      help
++        This option enables UBIFS debugging.
++
++config UBIFS_FS_DEBUG_MSG_LVL
++      int "Default message level (0 = no extra messages, 3 = lots)"
++      depends on UBIFS_FS_DEBUG
++      default "0"
++      help
++        This controls the amount of debugging messages produced by UBIFS.
++        If reporting bugs, please try to have available a full dump of the
++        messages at level 1 while the misbehaviour was occurring. Level 2
++        may become necessary if level 1 messages were not enough to find the
++        bug. Generally Level 3 should be avoided.
++
++config UBIFS_FS_DEBUG_CHKS
++      bool "Enable extra checks"
++      depends on UBIFS_FS_DEBUG
++      help
++        If extra checks are enabled UBIFS will check the consistency of its
++        internal data structures during operation. However, UBIFS performance
++        is dramatically slower when this option is selected especially if the
++        file system is large.
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/key.h avr32-2.6/fs/ubifs/key.h
+--- linux-2.6.25.6/fs/ubifs/key.h      1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/key.h   2008-06-12 15:09:45.367815766 +0200
+@@ -0,0 +1,533 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Artem Bityutskiy (Битюцкий Артём)
++ *          Adrian Hunter
++ */
++
++/*
++ * This header contains various key-related definitions and helper function.
++ * UBIFS allows several key schemes, so we access key fields only via these
++ * helpers. At the moment only one key scheme is supported.
++ *
++ * Simple key scheme
++ * ~~~~~~~~~~~~~~~~~
++ *
++ * Keys are 64-bits long. First 32-bits are inode number (parent inode number
++ * in case of direntry key). Next 3 bits are node type. The last 29 bits are
++ * 4KiB offset in case of inode node, and direntry hash in case of a direntry
++ * node. We use "r5" hash borrowed from reiserfs.
++ */
++
++#ifndef __UBIFS_KEY_H__
++#define __UBIFS_KEY_H__
++
++/**
++ * key_r5_hash - R5 hash function (borrowed from reiserfs).
++ * @s: direntry name
++ * @len: name length
++ */
++static inline uint32_t key_r5_hash(const char *s, int len)
++{
++      uint32_t a = 0;
++      const signed char *str = (const signed char *)s;
++
++      while (*str) {
++              a += *str << 4;
++              a += *str >> 4;
++              a *= 11;
++              str++;
++      }
++
++      a &= UBIFS_S_KEY_HASH_MASK;
++
++      /*
++       * We use hash values as offset in directories, so values %0 and %1 are
++       * reserved for "." and "..". %2 is reserved for "end of readdir"
++       * marker.
++       */
++      if (unlikely(a >= 0 && a <= 2))
++              a += 3;
++      return a;
++}
++
++/**
++ * key_test_hash - testing hash function.
++ * @str: direntry name
++ * @len: name length
++ */
++static inline uint32_t key_test_hash(const char *str, int len)
++{
++      uint32_t a = 0;
++
++      len = min_t(uint32_t, len, 4);
++      memcpy(&a, str, len);
++      a &= UBIFS_S_KEY_HASH_MASK;
++      if (unlikely(a >= 0 && a <= 2))
++              a += 3;
++      return a;
++}
++
++/**
++ * ino_key_init - initialize inode key.
++ * @c: UBIFS file-system description object
++ * @key: key to initialize
++ * @inum: inode number
++ */
++static inline void ino_key_init(const struct ubifs_info *c,
++                              union ubifs_key *key, ino_t inum)
++{
++      key->u32[0] = inum;
++      key->u32[1] = UBIFS_INO_KEY << UBIFS_S_KEY_BLOCK_BITS;
++}
++
++/**
++ * ino_key_init_flash - initialize on-flash inode key.
++ * @c: UBIFS file-system description object
++ * @k: key to initialize
++ * @inum: inode number
++ */
++static inline void ino_key_init_flash(const struct ubifs_info *c, void *k,
++                                    ino_t inum)
++{
++      union ubifs_key *key = k;
++
++      key->j32[0] = cpu_to_le32(inum);
++      key->j32[1] = cpu_to_le32(UBIFS_INO_KEY << UBIFS_S_KEY_BLOCK_BITS);
++      memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8);
++}
++
++/**
++ * lowest_ino_key - get the lowest possible inode key.
++ * @c: UBIFS file-system description object
++ * @key: key to initialize
++ * @inum: inode number
++ */
++static inline void lowest_ino_key(const struct ubifs_info *c,
++                              union ubifs_key *key, ino_t inum)
++{
++      key->u32[0] = inum;
++      key->u32[1] = 0;
++}
++
++/**
++ * highest_ino_key - get the highest possible inode key.
++ * @c: UBIFS file-system description object
++ * @key: key to initialize
++ * @inum: inode number
++ */
++static inline void highest_ino_key(const struct ubifs_info *c,
++                              union ubifs_key *key, ino_t inum)
++{
++      key->u32[0] = inum;
++      key->u32[1] = 0xffffffff;
++}
++
++/**
++ * dent_key_init - initialize directory entry key.
++ * @c: UBIFS file-system description object
++ * @key: key to initialize
++ * @inum: parent inode number
++ * @nm: direntry name and length
++ */
++static inline void dent_key_init(const struct ubifs_info *c,
++                               union ubifs_key *key, ino_t inum,
++                               const struct qstr *nm)
++{
++      uint32_t hash = c->key_hash(nm->name, nm->len);
++
++      ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
++      key->u32[0] = inum;
++      key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS);
++}
++
++/**
++ * dent_key_init_hash - initialize directory entry key without re-calculating
++ *                      hash function.
++ * @c: UBIFS file-system description object
++ * @key: key to initialize
++ * @inum: parent inode number
++ * @hash: direntry name hash
++ */
++static inline void dent_key_init_hash(const struct ubifs_info *c,
++                                    union ubifs_key *key, ino_t inum,
++                                    uint32_t hash)
++{
++      ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
++      key->u32[0] = inum;
++      key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS);
++}
++
++/**
++ * dent_key_init_flash - initialize on-flash directory entry key.
++ * @c: UBIFS file-system description object
++ * @k: key to initialize
++ * @inum: parent inode number
++ * @nm: direntry name and length
++ */
++static inline void dent_key_init_flash(const struct ubifs_info *c, void *k,
++                                     ino_t inum, const struct qstr *nm)
++{
++      union ubifs_key *key = k;
++      uint32_t hash = c->key_hash(nm->name, nm->len);
++
++      ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
++      key->j32[0] = cpu_to_le32(inum);
++      key->j32[1] = cpu_to_le32(hash |
++                                (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS));
++      memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8);
++}
++
++/**
++ * lowest_dent_key - get the lowest possible directory entry key.
++ * @c: UBIFS file-system description object
++ * @key: where to store the lowest key
++ * @inum: parent inode number
++ */
++static inline void lowest_dent_key(const struct ubifs_info *c,
++                                 union ubifs_key *key, ino_t inum)
++{
++      key->u32[0] = inum;
++      key->u32[1] = UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS;
++}
++
++/**
++ * xent_key_init - initialize extended attribute entry key.
++ * @c: UBIFS file-system description object
++ * @key: key to initialize
++ * @inum: host inode number
++ * @nm: extended attribute entry name and length
++ */
++static inline void xent_key_init(const struct ubifs_info *c,
++                               union ubifs_key *key, ino_t inum,
++                               const struct qstr *nm)
++{
++      uint32_t hash = c->key_hash(nm->name, nm->len);
++
++      ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
++      key->u32[0] = inum;
++      key->u32[1] = hash | (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS);
++}
++
++/**
++ * xent_key_init_hash - initialize extended attribute entry key without
++ *                      re-calculating hash function.
++ * @c: UBIFS file-system description object
++ * @key: key to initialize
++ * @inum: host inode number
++ * @hash: extended attribute entry name hash
++ */
++static inline void xent_key_init_hash(const struct ubifs_info *c,
++                                    union ubifs_key *key, ino_t inum,
++                                    uint32_t hash)
++{
++      ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
++      key->u32[0] = inum;
++      key->u32[1] = hash | (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS);
++}
++
++/**
++ * xent_key_init_flash - initialize on-flash extended attribute entry key.
++ * @c: UBIFS file-system description object
++ * @k: key to initialize
++ * @inum: host inode number
++ * @nm: extended attribute entry name and length
++ */
++static inline void xent_key_init_flash(const struct ubifs_info *c, void *k,
++                                     ino_t inum, const struct qstr *nm)
++{
++      union ubifs_key *key = k;
++      uint32_t hash = c->key_hash(nm->name, nm->len);
++
++      ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
++      key->j32[0] = cpu_to_le32(inum);
++      key->j32[1] = cpu_to_le32(hash |
++                                (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS));
++      memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8);
++}
++
++/**
++ * lowest_xent_key - get the lowest possible extended attribute entry key.
++ * @c: UBIFS file-system description object
++ * @key: where to store the lowest key
++ * @inum: host inode number
++ */
++static inline void lowest_xent_key(const struct ubifs_info *c,
++                                 union ubifs_key *key, ino_t inum)
++{
++      key->u32[0] = inum;
++      key->u32[1] = UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS;
++}
++
++/**
++ * data_key_init - initialize data key.
++ * @c: UBIFS file-system description object
++ * @key: key to initialize
++ * @inum: inode number
++ * @block: block number
++ */
++static inline void data_key_init(const struct ubifs_info *c,
++                               union ubifs_key *key, ino_t inum,
++                               unsigned int block)
++{
++      ubifs_assert(!(block & ~UBIFS_S_KEY_BLOCK_MASK));
++      key->u32[0] = inum;
++      key->u32[1] = block | (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS);
++}
++
++/**
++ * data_key_init_flash - initialize on-flash data key.
++ * @c: UBIFS file-system description object
++ * @k: key to initialize
++ * @inum: inode number
++ * @block: block number
++ */
++static inline void data_key_init_flash(const struct ubifs_info *c, void *k,
++                                     ino_t inum, unsigned int block)
++{
++      union ubifs_key *key = k;
++
++      ubifs_assert(!(block & ~UBIFS_S_KEY_BLOCK_MASK));
++      key->j32[0] = cpu_to_le32(inum);
++      key->j32[1] = cpu_to_le32(block |
++                                (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS));
++      memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8);
++}
++
++/**
++ * trun_key_init - initialize truncation node key.
++ * @c: UBIFS file-system description object
++ * @key: key to initialize
++ * @inum: inode number
++ *
++ * Note, UBIFS does not have truncation keys on the media and this function is
++ * only used for purposes of replay.
++ */
++static inline void trun_key_init(const struct ubifs_info *c,
++                               union ubifs_key *key, ino_t inum)
++{
++      key->u32[0] = inum;
++      key->u32[1] = UBIFS_TRUN_KEY << UBIFS_S_KEY_BLOCK_BITS;
++}
++
++/**
++ * key_type - get key type.
++ * @c: UBIFS file-system description object
++ * @key: key to get type of
++ */
++static inline int key_type(const struct ubifs_info *c,
++                         const union ubifs_key *key)
++{
++      return key->u32[1] >> UBIFS_S_KEY_BLOCK_BITS;
++}
++
++/**
++ * key_type_flash - get type of a on-flash formatted key.
++ * @c: UBIFS file-system description object
++ * @k: key to get type of
++ */
++static inline int key_type_flash(const struct ubifs_info *c, const void *k)
++{
++      const union ubifs_key *key = k;
++
++      return le32_to_cpu(key->u32[1]) >> UBIFS_S_KEY_BLOCK_BITS;
++}
++
++/**
++ * key_inum - fetch inode number from key.
++ * @c: UBIFS file-system description object
++ * @k: key to fetch inode number from
++ */
++static inline ino_t key_inum(const struct ubifs_info *c, const void *k)
++{
++      const union ubifs_key *key = k;
++
++      return key->u32[0];
++}
++
++/**
++ * key_inum_flash - fetch inode number from an on-flash formatted key.
++ * @c: UBIFS file-system description object
++ * @k: key to fetch inode number from
++ */
++static inline ino_t key_inum_flash(const struct ubifs_info *c, const void *k)
++{
++      const union ubifs_key *key = k;
++
++      return le32_to_cpu(key->j32[0]);
++}
++
++/**
++ * key_hash - get directory entry hash.
++ * @c: UBIFS file-system description object
++ * @key: the key to get hash from
++ */
++static inline int key_hash(const struct ubifs_info *c,
++                         const union ubifs_key *key)
++{
++      return key->u32[1] & UBIFS_S_KEY_HASH_MASK;
++}
++
++/**
++ * key_hash_flash - get directory entry hash from an on-flash formatted key.
++ * @c: UBIFS file-system description object
++ * @k: the key to get hash from
++ */
++static inline int key_hash_flash(const struct ubifs_info *c, const void *k)
++{
++      const union ubifs_key *key = k;
++
++      return le32_to_cpu(key->j32[1]) & UBIFS_S_KEY_HASH_MASK;
++}
++
++/**
++ * key_block - get data block number.
++ * @c: UBIFS file-system description object
++ * @key: the key to get the block number from
++ */
++static inline unsigned int key_block(const struct ubifs_info *c,
++                                   const union ubifs_key *key)
++{
++      return key->u32[1] & UBIFS_S_KEY_BLOCK_MASK;
++}
++
++/**
++ * key_block_flash - get data block number from an on-flash formatted key.
++ * @c: UBIFS file-system description object
++ * @k: the key to get the block number from
++ */
++static inline unsigned int key_block_flash(const struct ubifs_info *c,
++                                         const void *k)
++{
++      const union ubifs_key *key = k;
++
++      return le32_to_cpu(key->u32[1]) & UBIFS_S_KEY_BLOCK_MASK;
++}
++
++/**
++ * key_read - transform a key to in-memory format.
++ * @c: UBIFS file-system description object
++ * @from: the key to transform
++ * @to: the key to store the result
++ */
++static inline void key_read(const struct ubifs_info *c, const void *from,
++                          union ubifs_key *to)
++{
++      const union ubifs_key *f = from;
++
++      to->u32[0] = le32_to_cpu(f->j32[0]);
++      to->u32[1] = le32_to_cpu(f->j32[1]);
++}
++
++/**
++ * key_write - transform a key from in-memory format.
++ * @c: UBIFS file-system description object
++ * @from: the key to transform
++ * @to: the key to store the result
++ */
++static inline void key_write(const struct ubifs_info *c,
++                           const union ubifs_key *from, void *to)
++{
++      union ubifs_key *t = to;
++
++      t->j32[0] = cpu_to_le32(from->u32[0]);
++      t->j32[1] = cpu_to_le32(from->u32[1]);
++      memset(to + 8, 0, UBIFS_MAX_KEY_LEN - 8);
++}
++
++/**
++ * key_write_idx - transform a key from in-memory format for the index.
++ * @c: UBIFS file-system description object
++ * @from: the key to transform
++ * @to: the key to store the result
++ */
++static inline void key_write_idx(const struct ubifs_info *c,
++                               const union ubifs_key *from, void *to)
++{
++      union ubifs_key *t = to;
++
++      t->j32[0] = cpu_to_le32(from->u32[0]);
++      t->j32[1] = cpu_to_le32(from->u32[1]);
++}
++
++/**
++ * key_copy - copy a key.
++ * @c: UBIFS file-system description object
++ * @from: the key to copy from
++ * @to: the key to copy to
++ */
++static inline void key_copy(const struct ubifs_info *c,
++                          const union ubifs_key *from, union ubifs_key *to)
++{
++      to->u64[0] = from->u64[0];
++}
++
++/**
++ * keys_cmp - compare keys.
++ * @c: UBIFS file-system description object
++ * @key1: the first key to compare
++ * @key2: the second key to compare
++ *
++ * This function compares 2 keys and returns %-1 if @key1 is less than
++ * @key2, 0 if the keys are equivalent and %1 if @key1 is greater than @key2.
++ */
++static inline int keys_cmp(const struct ubifs_info *c,
++                         const union ubifs_key *key1,
++                         const union ubifs_key *key2)
++{
++      if (key1->u32[0] < key2->u32[0])
++              return -1;
++      if (key1->u32[0] > key2->u32[0])
++              return 1;
++      if (key1->u32[1] < key2->u32[1])
++              return -1;
++      if (key1->u32[1] > key2->u32[1])
++              return 1;
++
++      return 0;
++}
++
++/**
++ * is_hash_key - is a key vulnerable to hash collisions.
++ * @c: UBIFS file-system description object
++ * @key: key
++ *
++ * This function returns %1 if @key is a hashed key or %0 otherwise.
++ */
++static inline int is_hash_key(const struct ubifs_info *c,
++                            const union ubifs_key *key)
++{
++      int type = key_type(c, key);
++
++      return type == UBIFS_DENT_KEY || type == UBIFS_XENT_KEY;
++}
++
++/**
++ * key_max_inode_size - get maximum file size allowed by current key format.
++ * @c: UBIFS file-system description object
++ */
++static inline unsigned long long key_max_inode_size(const struct ubifs_info *c)
++{
++      switch (c->key_fmt) {
++      case UBIFS_SIMPLE_KEY_FMT:
++              return (1ULL << UBIFS_S_KEY_BLOCK_BITS) * UBIFS_BLOCK_SIZE;
++      default:
++              return 0;
++      }
++}
++#endif /* !__UBIFS_KEY_H__ */
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/log.c avr32-2.6/fs/ubifs/log.c
+--- linux-2.6.25.6/fs/ubifs/log.c      1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/log.c   2008-06-12 15:09:45.367815766 +0200
+@@ -0,0 +1,799 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Artem Bityutskiy (Битюцкий Артём)
++ *          Adrian Hunter
++ */
++
++/*
++ * This file is a part of UBIFS journal implementation and contains various
++ * functions which manipulate the log. The log is a fixed area on the flash
++ * which does not contain any data but refers to buds. The log is a part of the
++ * journal.
++ */
++
++#include "ubifs.h"
++
++#ifdef CONFIG_UBIFS_FS_DEBUG
++static int dbg_check_bud_bytes(struct ubifs_info *c);
++#else
++#define dbg_check_bud_bytes(c) 0
++#endif
++
++/**
++ * ubifs_search_bud - search bud LEB.
++ * @c: UBIFS file-system description object
++ * @lnum: logical eraseblock number to search
++ *
++ * This function searches bud LEB @lnum. Returns bud description object in case
++ * of success and %NULL if there is no bud with this LEB number.
++ */
++struct ubifs_bud *ubifs_search_bud(struct ubifs_info *c, int lnum)
++{
++      struct rb_node *p;
++      struct ubifs_bud *bud;
++
++      spin_lock(&c->buds_lock);
++      p = c->buds.rb_node;
++      while (p) {
++              bud = rb_entry(p, struct ubifs_bud, rb);
++              if (lnum < bud->lnum)
++                      p = p->rb_left;
++              else if (lnum > bud->lnum)
++                      p = p->rb_right;
++              else {
++                      spin_unlock(&c->buds_lock);
++                      return bud;
++              }
++      }
++      spin_unlock(&c->buds_lock);
++      return NULL;
++}
++
++/**
++ * ubifs_get_wbuf - get the wbuf associated with a LEB, if there is one.
++ * @c: UBIFS file-system description object
++ * @lnum: logical eraseblock number to search
++ *
++ * This functions returns the wbuf for @lnum or %NULL if there is not one.
++ */
++struct ubifs_wbuf *ubifs_get_wbuf(struct ubifs_info *c, int lnum)
++{
++      struct rb_node *p;
++      struct ubifs_bud *bud;
++      int jhead;
++
++      if (!c->jheads)
++              return NULL;
++
++      spin_lock(&c->buds_lock);
++      p = c->buds.rb_node;
++      while (p) {
++              bud = rb_entry(p, struct ubifs_bud, rb);
++              if (lnum < bud->lnum)
++                      p = p->rb_left;
++              else if (lnum > bud->lnum)
++                      p = p->rb_right;
++              else {
++                      jhead = bud->jhead;
++                      spin_unlock(&c->buds_lock);
++                      return &c->jheads[jhead].wbuf;
++              }
++      }
++      spin_unlock(&c->buds_lock);
++      return NULL;
++}
++
++/**
++ * next_log_lnum - switch to the next log LEB.
++ * @c: UBIFS file-system description object
++ * @lnum: current log LEB
++ */
++static inline int next_log_lnum(const struct ubifs_info *c, int lnum)
++{
++      lnum += 1;
++      if (lnum > c->log_last)
++              lnum = UBIFS_LOG_LNUM;
++
++      return lnum;
++}
++
++/**
++ * empty_log_bytes - calculate amount of empty space in the log.
++ * @c: UBIFS file-system description object
++ */
++static inline long long empty_log_bytes(const struct ubifs_info *c)
++{
++      long long h, t;
++
++      h = c->lhead_lnum * c->leb_size + c->lhead_offs;
++      t = c->ltail_lnum * c->leb_size;
++
++      if (h >= t)
++              return c->log_bytes - h + t;
++      else
++              return t - h;
++}
++
++/**
++ * ubifs_add_bud - add bud LEB to the tree of buds and its journal head list.
++ * @c: UBIFS file-system description object
++ * @bud: the bud to add
++ */
++void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud)
++{
++      struct rb_node **p, *parent = NULL;
++      struct ubifs_bud *b;
++      struct ubifs_jhead *jhead;
++
++      spin_lock(&c->buds_lock);
++      p = &c->buds.rb_node;
++      while (*p) {
++              parent = *p;
++              b = rb_entry(parent, struct ubifs_bud, rb);
++              ubifs_assert(bud->lnum != b->lnum);
++              if (bud->lnum < b->lnum)
++                      p = &(*p)->rb_left;
++              else
++                      p = &(*p)->rb_right;
++      }
++
++      rb_link_node(&bud->rb, parent, p);
++      rb_insert_color(&bud->rb, &c->buds);
++      if (c->jheads) {
++              jhead = &c->jheads[bud->jhead];
++              list_add_tail(&bud->list, &jhead->buds_list);
++      } else
++              ubifs_assert(c->replaying && (c->vfs_sb->s_flags & MS_RDONLY));
++
++      /*
++       * Note, although this is a new bud, we anyway account this space now,
++       * before any data has been written to it, because this is about to
++       * guarantee fixed mount time, and this bud will anyway be read and
++       * scanned.
++       */
++      c->bud_bytes += c->leb_size - bud->start;
++
++      dbg_log("LEB %d:%d, jhead %d, bud_bytes %lld", bud->lnum,
++              bud->start, bud->jhead, c->bud_bytes);
++      spin_unlock(&c->buds_lock);
++}
++
++/**
++ * ubifs_create_buds_lists - create journal head buds lists for remount rw.
++ * @c: UBIFS file-system description object
++ */
++void ubifs_create_buds_lists(struct ubifs_info *c)
++{
++      struct rb_node *p;
++
++      spin_lock(&c->buds_lock);
++      p = rb_first(&c->buds);
++      while (p) {
++              struct ubifs_bud *bud = rb_entry(p, struct ubifs_bud, rb);
++              struct ubifs_jhead *jhead = &c->jheads[bud->jhead];
++
++              list_add_tail(&bud->list, &jhead->buds_list);
++              p = rb_next(p);
++      }
++      spin_unlock(&c->buds_lock);
++}
++
++/**
++ * ubifs_add_bud_to_log - add a new bud to the log.
++ * @c: UBIFS file-system description object
++ * @jhead: journal head the bud belongs to
++ * @lnum: LEB number of the bud
++ * @offs: starting offset of the bud
++ *
++ * This function writes reference node for the new bud LEB @lnum it to the log,
++ * and adds it to the buds tress. It also makes sure that log size does not
++ * exceed the 'c->max_bud_bytes' limit. Returns zero in case of success,
++ * %-EAGAIN if commit is required, and a negative error codes in case of
++ * failure.
++ */
++int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
++{
++      int err;
++      struct ubifs_bud *bud;
++      struct ubifs_ref_node *ref;
++
++      bud = kmalloc(sizeof(struct ubifs_bud), GFP_NOFS);
++      if (!bud)
++              return -ENOMEM;
++      ref = kzalloc(c->ref_node_alsz, GFP_NOFS);
++      if (!ref) {
++              kfree(bud);
++              return -ENOMEM;
++      }
++
++      mutex_lock(&c->log_mutex);
++      /* Make sure we have enough space in the log */
++      if (empty_log_bytes(c) - c->ref_node_alsz < c->min_log_bytes) {
++              dbg_log("not enough log space - %lld, required %d",
++                      empty_log_bytes(c), c->min_log_bytes);
++              ubifs_commit_required(c);
++              err = -EAGAIN;
++              goto out_unlock;
++      }
++
++      /*
++       * Make sure the the amount of space in buds will not exceed
++       * 'c->max_bud_bytes' limit, because we want to guarantee mount time
++       * limits.
++       *
++       * It is not necessary to hold @c->buds_lock when reading @c->bud_bytes
++       * because we are holding @c->log_mutex. All @c->bud_bytes take place
++       * when both @c->log_mutex and @c->bud_bytes are locked.
++       */
++      if (c->bud_bytes + c->leb_size - offs > c->max_bud_bytes) {
++              dbg_log("bud bytes %lld (%lld max), require commit",
++                      c->bud_bytes, c->max_bud_bytes);
++              ubifs_commit_required(c);
++              err = -EAGAIN;
++              goto out_unlock;
++      }
++
++      /*
++       * If the journal is full enough - start background commit. Note, it is
++       * OK to read 'c->cmt_state' without spinlock because integer reads
++       * are atomic in the kernel.
++       */
++      if (c->bud_bytes >= c->bg_bud_bytes &&
++          c->cmt_state == COMMIT_RESTING) {
++              dbg_log("bud bytes %lld (%lld max), initiate BG commit",
++                      c->bud_bytes, c->max_bud_bytes);
++              ubifs_request_bg_commit(c);
++      }
++
++      bud->lnum = lnum;
++      bud->start = offs;
++      bud->jhead = jhead;
++
++      ref->ch.node_type = UBIFS_REF_NODE;
++      ref->lnum = cpu_to_le32(bud->lnum);
++      ref->offs = cpu_to_le32(bud->start);
++      ref->jhead = cpu_to_le32(jhead);
++
++      if (c->lhead_offs > c->leb_size - c->ref_node_alsz) {
++              c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
++              c->lhead_offs = 0;
++      }
++
++      if (c->lhead_offs == 0) {
++              /* Must ensure next log LEB has been unmapped */
++              err = ubifs_leb_unmap(c, c->lhead_lnum);
++              if (err)
++                      goto out_unlock;
++      }
++
++      if (bud->start == 0) {
++              /*
++               * Before writing the LEB reference which refers an empty LEB
++               * to the log, we have to make sure it is mapped, because
++               * otherwise we'd risk to refer an LEB with garbage in case of
++               * an unclean reboot, because the target LEB might have been
++               * unmapped, but not yet physically erased.
++               */
++              err = ubi_leb_map(c->ubi, bud->lnum, UBI_SHORTTERM);
++              if (err)
++                      goto out_unlock;
++      }
++
++      dbg_log("write ref LEB %d:%d",
++              c->lhead_lnum, c->lhead_offs);
++      err = ubifs_write_node(c, ref, UBIFS_REF_NODE_SZ, c->lhead_lnum,
++                             c->lhead_offs, UBI_SHORTTERM);
++      c->lhead_offs += c->ref_node_alsz;
++      if (err)
++              goto out_unlock;
++
++      ubifs_add_bud(c, bud);
++
++      mutex_unlock(&c->log_mutex);
++      kfree(ref);
++      return 0;
++
++out_unlock:
++      mutex_unlock(&c->log_mutex);
++      kfree(ref);
++      kfree(bud);
++      return err;
++}
++
++/**
++ * remove_buds - remove used buds.
++ * @c: UBIFS file-system description object
++ *
++ * This function removes use buds from the buds tree. It does not remove the
++ * buds which are pointed to by journal heads.
++ */
++static void remove_buds(struct ubifs_info *c)
++{
++      struct rb_node *p;
++
++      ubifs_assert(list_empty(&c->old_buds));
++      c->cmt_bud_bytes = 0;
++      spin_lock(&c->buds_lock);
++      p = rb_first(&c->buds);
++      while (p) {
++              struct rb_node *p1 = p;
++              struct ubifs_bud *bud;
++              struct ubifs_wbuf *wbuf;
++
++              p = rb_next(p);
++              bud = rb_entry(p1, struct ubifs_bud, rb);
++              wbuf = &c->jheads[bud->jhead].wbuf;
++
++              if (wbuf->lnum == bud->lnum) {
++                      /*
++                       * Do not remove buds which are pointed to by journal
++                       * heads (non-closed buds).
++                       */
++                      c->cmt_bud_bytes += wbuf->offs - bud->start;
++                      dbg_log("preserve %d:%d, jhead %d, bud bytes %d, "
++                              "cmt_bud_bytes %lld", bud->lnum, bud->start,
++                              bud->jhead, wbuf->offs - bud->start,
++                              c->cmt_bud_bytes);
++                      bud->start = wbuf->offs;
++              } else {
++                      c->cmt_bud_bytes += c->leb_size - bud->start;
++                      dbg_log("remove %d:%d, jhead %d, bud bytes %d, "
++                              "cmt_bud_bytes %lld", bud->lnum, bud->start,
++                              bud->jhead, c->leb_size - bud->start,
++                              c->cmt_bud_bytes);
++                      rb_erase(p1, &c->buds);
++                      list_del(&bud->list);
++                      /*
++                       * If the commit does not finish, the recovery will need
++                       * to replay the journal, in which case the old buds
++                       * must be unchanged. Do not release them until post
++                       * commit i.e. do not allow them to be garbage
++                       * collected.
++                       */
++                      list_add(&bud->list, &c->old_buds);
++              }
++      }
++      spin_unlock(&c->buds_lock);
++}
++
++/**
++ * ubifs_log_start_commit - start commit.
++ * @c: UBIFS file-system description object
++ * @ltail_lnum: return new log tail LEB number
++ *
++ * The commit operation starts with writing "commit start" node to the log and
++ * reference nodes for all journal heads which will define new journal after
++ * the commit has been finished. The commit start and reference nodes are
++ * written in one go to the nearest empty log LEB (hence, when commit is
++ * finished UBIFS may safely unmap all the previous log LEBs). This function
++ * returns zero in case of success and a negative error code in case of
++ * failure.
++ */
++int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
++{
++      void *buf;
++      struct ubifs_cs_node *cs;
++      struct ubifs_ref_node *ref;
++      int err, i, max_len, len;
++
++      err = dbg_check_bud_bytes(c);
++      if (err)
++              return err;
++
++      max_len = UBIFS_CS_NODE_SZ + c->jhead_cnt * UBIFS_REF_NODE_SZ;
++      max_len = ALIGN(max_len, c->min_io_size);
++      buf = cs = kmalloc(max_len, GFP_NOFS);
++      if (!buf)
++              return -ENOMEM;
++
++      cs->ch.node_type = UBIFS_CS_NODE;
++      cs->cmt_no = cpu_to_le64(c->cmt_no + 1);
++      ubifs_prepare_node(c, cs, UBIFS_CS_NODE_SZ, 0);
++
++      /*
++       * Note, we do not lock 'c->log_mutex' because this is the commit start
++       * phase and we are exclusively using the log. And we do not lock
++       * write-buffer because nobody can write to the file-system at this
++       * phase.
++       */
++
++      len = UBIFS_CS_NODE_SZ;
++      for (i = 0; i < c->jhead_cnt; i++) {
++              int lnum = c->jheads[i].wbuf.lnum;
++              int offs = c->jheads[i].wbuf.offs;
++
++              if (lnum == -1 || offs == c->leb_size)
++                      continue;
++
++              dbg_log("add ref to LEB %d:%d for jhead %d", lnum, offs, i);
++              ref = buf + len;
++              ref->ch.node_type = UBIFS_REF_NODE;
++              ref->lnum = cpu_to_le32(lnum);
++              ref->offs = cpu_to_le32(offs);
++              ref->jhead = cpu_to_le32(i);
++
++              ubifs_prepare_node(c, ref, UBIFS_REF_NODE_SZ, 0);
++              len += UBIFS_REF_NODE_SZ;
++      }
++
++      ubifs_pad(c, buf + len, ALIGN(len, c->min_io_size) - len);
++
++      /* Switch to the next log LEB */
++      if (c->lhead_offs) {
++              c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
++              c->lhead_offs = 0;
++      }
++
++      if (c->lhead_offs == 0) {
++              /* Must ensure next LEB has been unmapped */
++              err = ubifs_leb_unmap(c, c->lhead_lnum);
++              if (err)
++                      goto out;
++      }
++
++      len = ALIGN(len, c->min_io_size);
++      dbg_log("writing commit start at LEB %d:0, len %d", c->lhead_lnum, len);
++      err = ubifs_leb_write(c, c->lhead_lnum, cs, 0, len, UBI_SHORTTERM);
++      if (err)
++              goto out;
++
++      *ltail_lnum = c->lhead_lnum;
++
++      c->lhead_offs += len;
++      if (c->lhead_offs == c->leb_size) {
++              c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
++              c->lhead_offs = 0;
++      }
++
++      remove_buds(c);
++
++      /*
++       * We have started the commit and now users may use the rest of the log
++       * for new writes.
++       */
++      c->min_log_bytes = 0;
++
++out:
++      kfree(buf);
++      return err;
++}
++
++/**
++ * ubifs_log_end_commit - end commit.
++ * @c: UBIFS file-system description object
++ * @ltail_lnum: new log tail LEB number
++ *
++ * This function is called on when the commit operation was finished. It
++ * moves log tail to new position and unmaps LEBs which contain obsolete data.
++ * Returns zero in case of success and a negative error code in case of
++ * failure.
++ */
++int ubifs_log_end_commit(struct ubifs_info *c, int ltail_lnum)
++{
++      int err;
++
++      /*
++       * At this phase we have to lock 'c->log_mutex' because UBIFS allows FS
++       * writes during commit. Its only short "commit" start phase when
++       * writers are blocked.
++       */
++      mutex_lock(&c->log_mutex);
++
++      dbg_log("old tail was LEB %d:0, new tail is LEB %d:0",
++              c->ltail_lnum, ltail_lnum);
++
++      c->ltail_lnum = ltail_lnum;
++      /*
++       * The commit is finished and from now on it must be guaranteed that
++       * there is always enough space for the next commit.
++       */
++      c->min_log_bytes = c->leb_size;
++
++      spin_lock(&c->buds_lock);
++      c->bud_bytes -= c->cmt_bud_bytes;
++      spin_unlock(&c->buds_lock);
++
++      err = dbg_check_bud_bytes(c);
++
++      mutex_unlock(&c->log_mutex);
++      return err;
++}
++
++/**
++ * ubifs_log_post_commit - things to do after commit is completed.
++ * @c: UBIFS file-system description object
++ * @old_ltail_lnum: old log tail LEB number
++ *
++ * Release buds only after commit is completed, because they must be unchanged
++ * if recovery is needed.
++ *
++ * Unmap log LEBs only after commit is completed, because they may be needed for
++ * recovery.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum)
++{
++      int lnum, err = 0;
++
++      while (!list_empty(&c->old_buds)) {
++              struct ubifs_bud *bud;
++
++              bud = list_entry(c->old_buds.next, struct ubifs_bud, list);
++              err = ubifs_return_leb(c, bud->lnum);
++              if (err)
++                      return err;
++              list_del(&bud->list);
++              kfree(bud);
++      }
++      mutex_lock(&c->log_mutex);
++      for (lnum = old_ltail_lnum; lnum != c->ltail_lnum;
++           lnum = next_log_lnum(c, lnum)) {
++              dbg_log("unmap log LEB %d", lnum);
++              err = ubifs_leb_unmap(c, lnum);
++              if (err)
++                      goto out;
++      }
++out:
++      mutex_unlock(&c->log_mutex);
++      return err;
++}
++
++/**
++ * struct done_ref - references that have been done.
++ * @rb: rb-tree node
++ * @lnum: LEB number
++ */
++struct done_ref {
++      struct rb_node rb;
++      int lnum;
++};
++
++/**
++ * done_already - determine if a reference has been done already.
++ * @done_tree: rb-tree to store references that have been done
++ * @lnum: LEB number of reference
++ *
++ * This function returns %1 if the reference has been done, %0 if not, otherwise
++ * a negative error code is returned.
++ */
++static int done_already(struct rb_root *done_tree, int lnum)
++{
++      struct rb_node **p = &done_tree->rb_node, *parent = NULL;
++      struct done_ref *dr;
++
++      while (*p) {
++              parent = *p;
++              dr = rb_entry(parent, struct done_ref, rb);
++              if (lnum < dr->lnum)
++                      p = &(*p)->rb_left;
++              else if (lnum > dr->lnum)
++                      p = &(*p)->rb_right;
++              else
++                      return 1;
++      }
++
++      dr = kzalloc(sizeof(struct done_ref), GFP_NOFS);
++      if (!dr)
++              return -ENOMEM;
++
++      dr->lnum = lnum;
++
++      rb_link_node(&dr->rb, parent, p);
++      rb_insert_color(&dr->rb, done_tree);
++
++      return 0;
++}
++
++/**
++ * destroy_done_tree - destroy the done tree.
++ * @done_tree: done tree to destroy
++ */
++static void destroy_done_tree(struct rb_root *done_tree)
++{
++      struct rb_node *this = done_tree->rb_node;
++      struct done_ref *dr;
++
++      while (this) {
++              if (this->rb_left) {
++                      this = this->rb_left;
++                      continue;
++              } else if (this->rb_right) {
++                      this = this->rb_right;
++                      continue;
++              }
++              dr = rb_entry(this, struct done_ref, rb);
++              this = rb_parent(this);
++              if (this) {
++                      if (this->rb_left == &dr->rb)
++                              this->rb_left = NULL;
++                      else
++                              this->rb_right = NULL;
++              }
++              kfree(dr);
++      }
++}
++
++/**
++ * add_node - add a node to the consolidated log.
++ * @c: UBIFS file-system description object
++ * @buf: buffer to which to add
++ * @lnum: LEB number to which to write is passed and returned here
++ * @offs: offset to where to write is passed and returned here
++ * @node: node to add
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int add_node(struct ubifs_info *c, void *buf, int *lnum, int *offs,
++                  void *node)
++{
++      struct ubifs_ch *ch = node;
++      int len = le32_to_cpu(ch->len), remains = c->leb_size - *offs;
++
++      if (len > remains) {
++              int sz = ALIGN(*offs, c->min_io_size), err;
++
++              ubifs_pad(c, buf + *offs, sz - *offs);
++              err = ubi_leb_change(c->ubi, *lnum, buf, sz, UBI_SHORTTERM);
++              if (err)
++                      return err;
++              *lnum = next_log_lnum(c, *lnum);
++              *offs = 0;
++      }
++      memcpy(buf + *offs, node, len);
++      *offs += ALIGN(len, 8);
++      return 0;
++}
++
++/**
++ * ubifs_consolidate_log - consolidate the log.
++ * @c: UBIFS file-system description object
++ *
++ * Repeated failed commits could cause the log to be full, but at least 1 LEB is
++ * needed for commit. This function rewrites the reference nodes in the log
++ * omitting duplicates, and failed CS nodes, and leaving no gaps.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++int ubifs_consolidate_log(struct ubifs_info *c)
++{
++      struct ubifs_scan_leb *sleb;
++      struct ubifs_scan_node *snod;
++      struct rb_root done_tree = RB_ROOT;
++      int lnum, err, first = 1, write_lnum, offs = 0;
++      void *buf;
++
++      dbg_rcvry("log tail LEB %d, log head LEB %d", c->ltail_lnum,
++                c->lhead_lnum);
++      buf = vmalloc(c->leb_size);
++      if (!buf)
++              return -ENOMEM;
++      lnum = c->ltail_lnum;
++      write_lnum = lnum;
++      while (1) {
++              sleb = ubifs_scan(c, lnum, 0, c->sbuf);
++              if (IS_ERR(sleb)) {
++                      err = PTR_ERR(sleb);
++                      goto out_free;
++              }
++              list_for_each_entry(snod, &sleb->nodes, list) {
++                      switch (snod->type) {
++                      case UBIFS_REF_NODE: {
++                              struct ubifs_ref_node *ref = snod->node;
++                              int ref_lnum = le32_to_cpu(ref->lnum);
++
++                              err = done_already(&done_tree, ref_lnum);
++                              if (err < 0)
++                                      goto out_scan;
++                              if (err != 1) {
++                                      err = add_node(c, buf, &write_lnum,
++                                                     &offs, snod->node);
++                                      if (err)
++                                              goto out_scan;
++                              }
++                              break;
++                      }
++                      case UBIFS_CS_NODE:
++                              if (!first)
++                                      break;
++                              err = add_node(c, buf, &write_lnum, &offs,
++                                             snod->node);
++                              if (err)
++                                      goto out_scan;
++                              first = 0;
++                              break;
++                      }
++              }
++              ubifs_scan_destroy(sleb);
++              if (lnum == c->lhead_lnum)
++                      break;
++              lnum = next_log_lnum(c, lnum);
++      }
++      if (offs) {
++              int sz = ALIGN(offs, c->min_io_size);
++
++              ubifs_pad(c, buf + offs, sz - offs);
++              err = ubi_leb_change(c->ubi, write_lnum, buf, sz,
++                                   UBI_SHORTTERM);
++              if (err)
++                      goto out_free;
++              offs = ALIGN(offs, c->min_io_size);
++      }
++      destroy_done_tree(&done_tree);
++      vfree(buf);
++      if (write_lnum == c->lhead_lnum) {
++              ubifs_err("log is too full");
++              return -EINVAL;
++      }
++      /* Unmap remaining LEBs */
++      lnum = write_lnum;
++      do {
++              lnum = next_log_lnum(c, lnum);
++              err = ubifs_leb_unmap(c, lnum);
++              if (err)
++                      return err;
++      } while (lnum != c->lhead_lnum);
++      c->lhead_lnum = write_lnum;
++      c->lhead_offs = offs;
++      dbg_rcvry("new log head at %d:%d", c->lhead_lnum, c->lhead_offs);
++      return 0;
++
++out_scan:
++      ubifs_scan_destroy(sleb);
++out_free:
++      destroy_done_tree(&done_tree);
++      vfree(buf);
++      return err;
++}
++
++#ifdef CONFIG_UBIFS_FS_DEBUG
++
++/**
++ * dbg_check_bud_bytes - make sure bud bytes calculation are all right.
++ * @c: UBIFS file-system description object
++ *
++ * This function makes sure the amount of flash space used by closed buds
++ * ('c->bud_bytes' is correct). Returns zero in case of success and %-EINVAL in
++ * case of failure.
++ */
++static int dbg_check_bud_bytes(struct ubifs_info *c)
++{
++      int i, err = 0;
++      struct ubifs_bud *bud;
++      long long bud_bytes = 0;
++
++      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++              return 0;
++
++      spin_lock(&c->buds_lock);
++      for (i = 0; i < c->jhead_cnt; i++)
++              list_for_each_entry(bud, &c->jheads[i].buds_list, list)
++                      bud_bytes += c->leb_size - bud->start;
++
++      if (c->bud_bytes != bud_bytes) {
++              ubifs_err("bad bud_bytes %lld, calculated %lld",
++                        c->bud_bytes, bud_bytes);
++              err = -EINVAL;
++      }
++      spin_unlock(&c->buds_lock);
++
++      return err;
++}
++
++#endif /* CONFIG_UBIFS_FS_DEBUG */
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/lprops.c avr32-2.6/fs/ubifs/lprops.c
+--- linux-2.6.25.6/fs/ubifs/lprops.c   1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/lprops.c        2008-06-12 15:09:45.371816276 +0200
+@@ -0,0 +1,1355 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Adrian Hunter
++ *          Artem Bityutskiy (Битюцкий Артём)
++ */
++
++/*
++ * This file implements the functions that access LEB properties and their
++ * categories. LEBs are categorized based on the needs of UBIFS, and the
++ * categories are stored as either heaps or lists to provide a fast way of
++ * finding a LEB in a particular category. For example, UBIFS may need to find
++ * an empty LEB for the journal, or a very dirty LEB for garbage collection.
++ */
++
++#include "ubifs.h"
++
++/**
++ * get_heap_comp_val - get the LEB properties value for heap comparisons.
++ * @lprops: LEB properties
++ * @cat: LEB category
++ */
++static int get_heap_comp_val(struct ubifs_lprops *lprops, int cat)
++{
++      switch (cat) {
++      case LPROPS_FREE:
++              return lprops->free;
++      case LPROPS_DIRTY_IDX:
++              return lprops->free + lprops->dirty;
++      default:
++              return lprops->dirty;
++      }
++}
++
++/**
++ * move_up_lpt_heap - move a new heap entry up as far as possible.
++ * @c: UBIFS file-system description object
++ * @heap: LEB category heap
++ * @lprops: LEB properties to move
++ * @cat: LEB category
++ *
++ * New entries to a heap are added at the bottom and then moved up until the
++ * parent's value is greater.  In the case of LPT's category heaps, the value
++ * is either the amount of free space or the amount of dirty space, depending
++ * on the category.
++ */
++static void move_up_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,
++                           struct ubifs_lprops *lprops, int cat)
++{
++      int val1, val2, hpos;
++
++      hpos = lprops->hpos;
++      if (!hpos)
++              return; /* Already top of the heap */
++      val1 = get_heap_comp_val(lprops, cat);
++      /* Compare to parent and, if greater, move up the heap */
++      do {
++              int ppos = (hpos - 1) / 2;
++
++              val2 = get_heap_comp_val(heap->arr[ppos], cat);
++              if (val2 >= val1)
++                      return;
++              /* Greater than parent so move up */
++              heap->arr[ppos]->hpos = hpos;
++              heap->arr[hpos] = heap->arr[ppos];
++              heap->arr[ppos] = lprops;
++              lprops->hpos = ppos;
++              hpos = ppos;
++      } while (hpos);
++}
++
++/**
++ * adjust_lpt_heap - move a changed heap entry up or down the heap.
++ * @c: UBIFS file-system description object
++ * @heap: LEB category heap
++ * @lprops: LEB properties to move
++ * @hpos: heap position of @lprops
++ * @cat: LEB category
++ *
++ * Changed entries in a heap are moved up or down until the parent's value is
++ * greater.  In the case of LPT's category heaps, the value is either the amount
++ * of free space or the amount of dirty space, depending on the category.
++ */
++static void adjust_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,
++                          struct ubifs_lprops *lprops, int hpos, int cat)
++{
++      int val1, val2, val3, cpos;
++
++      val1 = get_heap_comp_val(lprops, cat);
++      /* Compare to parent and, if greater than parent, move up the heap */
++      if (hpos) {
++              int ppos = (hpos - 1) / 2;
++
++              val2 = get_heap_comp_val(heap->arr[ppos], cat);
++              if (val1 > val2) {
++                      /* Greater than parent so move up */
++                      while (1) {
++                              heap->arr[ppos]->hpos = hpos;
++                              heap->arr[hpos] = heap->arr[ppos];
++                              heap->arr[ppos] = lprops;
++                              lprops->hpos = ppos;
++                              hpos = ppos;
++                              if (!hpos)
++                                      return;
++                              ppos = (hpos - 1) / 2;
++                              val2 = get_heap_comp_val(heap->arr[ppos], cat);
++                              if (val1 <= val2)
++                                      return;
++                              /* Still greater than parent so keep going */
++                      }
++              }
++      }
++      /* Not greater than parent, so compare to children */
++      while (1) {
++              /* Compare to left child */
++              cpos = hpos * 2 + 1;
++              if (cpos >= heap->cnt)
++                      return;
++              val2 = get_heap_comp_val(heap->arr[cpos], cat);
++              if (val1 < val2) {
++                      /* Less than left child, so promote biggest child */
++                      if (cpos + 1 < heap->cnt) {
++                              val3 = get_heap_comp_val(heap->arr[cpos + 1],
++                                                       cat);
++                              if (val3 > val2)
++                                      cpos += 1; /* Right child is bigger */
++                      }
++                      heap->arr[cpos]->hpos = hpos;
++                      heap->arr[hpos] = heap->arr[cpos];
++                      heap->arr[cpos] = lprops;
++                      lprops->hpos = cpos;
++                      hpos = cpos;
++                      continue;
++              }
++              /* Compare to right child */
++              cpos += 1;
++              if (cpos >= heap->cnt)
++                      return;
++              val3 = get_heap_comp_val(heap->arr[cpos], cat);
++              if (val1 < val3) {
++                      /* Less than right child, so promote right child */
++                      heap->arr[cpos]->hpos = hpos;
++                      heap->arr[hpos] = heap->arr[cpos];
++                      heap->arr[cpos] = lprops;
++                      lprops->hpos = cpos;
++                      hpos = cpos;
++                      continue;
++              }
++              return;
++      }
++}
++
++/**
++ * add_to_lpt_heap - add LEB properties to a LEB category heap.
++ * @c: UBIFS file-system description object
++ * @lprops: LEB properties to add
++ * @cat: LEB category
++ *
++ * This function returns %1 if @lprops is added to the heap for LEB category
++ * @cat, otherwise %0 is returned because the heap is full.
++ */
++static int add_to_lpt_heap(struct ubifs_info *c, struct ubifs_lprops *lprops,
++                         int cat)
++{
++      struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
++
++      if (heap->cnt >= heap->max_cnt) {
++              const int b = LPT_HEAP_SZ / 2 - 1;
++              int cpos, val1, val2;
++
++              /* Compare to some other LEB on the bottom of heap */
++              /* Pick a position kind of randomly */
++              cpos = (((size_t)lprops >> 4) & b) + b;
++              ubifs_assert(cpos >= b);
++              ubifs_assert(cpos < LPT_HEAP_SZ);
++              ubifs_assert(cpos < heap->cnt);
++
++              val1 = get_heap_comp_val(lprops, cat);
++              val2 = get_heap_comp_val(heap->arr[cpos], cat);
++              if (val1 > val2) {
++                      struct ubifs_lprops *lp;
++
++                      lp = heap->arr[cpos];
++                      lp->flags &= ~LPROPS_CAT_MASK;
++                      lp->flags |= LPROPS_UNCAT;
++                      list_add(&lp->list, &c->uncat_list);
++                      lprops->hpos = cpos;
++                      heap->arr[cpos] = lprops;
++                      move_up_lpt_heap(c, heap, lprops, cat);
++                      dbg_check_heap(c, heap, cat, lprops->hpos);
++                      return 1; /* Added to heap */
++              }
++              dbg_check_heap(c, heap, cat, -1);
++              return 0; /* Not added to heap */
++      } else {
++              lprops->hpos = heap->cnt++;
++              heap->arr[lprops->hpos] = lprops;
++              move_up_lpt_heap(c, heap, lprops, cat);
++              dbg_check_heap(c, heap, cat, lprops->hpos);
++              return 1; /* Added to heap */
++      }
++}
++
++/**
++ * remove_from_lpt_heap - remove LEB properties from a LEB category heap.
++ * @c: UBIFS file-system description object
++ * @lprops: LEB properties to remove
++ * @cat: LEB category
++ */
++static void remove_from_lpt_heap(struct ubifs_info *c,
++                               struct ubifs_lprops *lprops, int cat)
++{
++      struct ubifs_lpt_heap *heap;
++      int hpos = lprops->hpos;
++
++      heap = &c->lpt_heap[cat - 1];
++      ubifs_assert(hpos >= 0 && hpos < heap->cnt);
++      ubifs_assert(heap->arr[hpos] == lprops);
++      heap->cnt -= 1;
++      if (hpos < heap->cnt) {
++              heap->arr[hpos] = heap->arr[heap->cnt];
++              heap->arr[hpos]->hpos = hpos;
++              adjust_lpt_heap(c, heap, heap->arr[hpos], hpos, cat);
++      }
++      dbg_check_heap(c, heap, cat, -1);
++}
++
++/**
++ * lpt_heap_replace - replace lprops in a category heap.
++ * @c: UBIFS file-system description object
++ * @old_lprops: LEB properties to replace
++ * @new_lprops: LEB properties with which to replace
++ * @cat: LEB category
++ *
++ * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode)
++ * and the lprops that the pnode contains.  When that happens, references in
++ * the category heaps to those lprops must be updated to point to the new
++ * lprops.  This function does that.
++ */
++static void lpt_heap_replace(struct ubifs_info *c,
++                           struct ubifs_lprops *old_lprops,
++                           struct ubifs_lprops *new_lprops, int cat)
++{
++      struct ubifs_lpt_heap *heap;
++      int hpos = new_lprops->hpos;
++
++      heap = &c->lpt_heap[cat - 1];
++      heap->arr[hpos] = new_lprops;
++}
++
++/**
++ * ubifs_add_to_cat - add LEB properties to a category list or heap.
++ * @c: UBIFS file-system description object
++ * @lprops: LEB properties to add
++ * @cat: LEB category to which to add
++ *
++ * LEB properties are categorized to enable fast find operations.
++ */
++void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops,
++                    int cat)
++{
++      switch (cat) {
++      case LPROPS_DIRTY:
++      case LPROPS_DIRTY_IDX:
++      case LPROPS_FREE:
++              if (add_to_lpt_heap(c, lprops, cat))
++                      break;
++              /* No more room on heap so make it uncategorized */
++              cat = LPROPS_UNCAT;
++              /* Fall through */
++      case LPROPS_UNCAT:
++              list_add(&lprops->list, &c->uncat_list);
++              break;
++      case LPROPS_EMPTY:
++              list_add(&lprops->list, &c->empty_list);
++              break;
++      case LPROPS_FREEABLE:
++              list_add(&lprops->list, &c->freeable_list);
++              c->freeable_cnt += 1;
++              break;
++      case LPROPS_FRDI_IDX:
++              list_add(&lprops->list, &c->frdi_idx_list);
++              break;
++      default:
++              ubifs_assert(0);
++      }
++      lprops->flags &= ~LPROPS_CAT_MASK;
++      lprops->flags |= cat;
++}
++
++/**
++ * ubifs_remove_from_cat - remove LEB properties from a category list or heap.
++ * @c: UBIFS file-system description object
++ * @lprops: LEB properties to remove
++ * @cat: LEB category from which to remove
++ *
++ * LEB properties are categorized to enable fast find operations.
++ */
++static void ubifs_remove_from_cat(struct ubifs_info *c,
++                                struct ubifs_lprops *lprops, int cat)
++{
++      switch (cat) {
++      case LPROPS_DIRTY:
++      case LPROPS_DIRTY_IDX:
++      case LPROPS_FREE:
++              remove_from_lpt_heap(c, lprops, cat);
++              break;
++      case LPROPS_FREEABLE:
++              c->freeable_cnt -= 1;
++              ubifs_assert(c->freeable_cnt >= 0);
++              /* Fall through */
++      case LPROPS_UNCAT:
++      case LPROPS_EMPTY:
++      case LPROPS_FRDI_IDX:
++              ubifs_assert(!list_empty(&lprops->list));
++              list_del(&lprops->list);
++              break;
++      default:
++              ubifs_assert(0);
++      }
++}
++
++/**
++ * ubifs_replace_cat - replace lprops in a category list or heap.
++ * @c: UBIFS file-system description object
++ * @old_lprops: LEB properties to replace
++ * @new_lprops: LEB properties with which to replace
++ *
++ * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode)
++ * and the lprops that the pnode contains. When that happens, references in
++ * category lists and heaps must be replaced. This function does that.
++ */
++void ubifs_replace_cat(struct ubifs_info *c, struct ubifs_lprops *old_lprops,
++                     struct ubifs_lprops *new_lprops)
++{
++      int cat;
++
++      cat = new_lprops->flags & LPROPS_CAT_MASK;
++      switch (cat) {
++      case LPROPS_DIRTY:
++      case LPROPS_DIRTY_IDX:
++      case LPROPS_FREE:
++              lpt_heap_replace(c, old_lprops, new_lprops, cat);
++              break;
++      case LPROPS_UNCAT:
++      case LPROPS_EMPTY:
++      case LPROPS_FREEABLE:
++      case LPROPS_FRDI_IDX:
++              list_replace(&old_lprops->list, &new_lprops->list);
++              break;
++      default:
++              ubifs_assert(0);
++      }
++}
++
++/**
++ * ubifs_ensure_cat - ensure LEB properties are categorized.
++ * @c: UBIFS file-system description object
++ * @lprops: LEB properties
++ *
++ * A LEB may have fallen off of the bottom of a heap, and ended up as
++ * uncategorized even though it has enough space for us now. If that is the case
++ * this function will put the LEB back onto a heap.
++ */
++void ubifs_ensure_cat(struct ubifs_info *c, struct ubifs_lprops *lprops)
++{
++      int cat = lprops->flags & LPROPS_CAT_MASK;
++
++      if (cat != LPROPS_UNCAT)
++              return;
++      cat = ubifs_categorize_lprops(c, lprops);
++      if (cat == LPROPS_UNCAT)
++              return;
++      ubifs_remove_from_cat(c, lprops, LPROPS_UNCAT);
++      ubifs_add_to_cat(c, lprops, cat);
++}
++
++/**
++ * ubifs_categorize_lprops - categorize LEB properties.
++ * @c: UBIFS file-system description object
++ * @lprops: LEB properties to categorize
++ *
++ * LEB properties are categorized to enable fast find operations. This function
++ * returns the LEB category to which the LEB properties belong. Note however
++ * that if the LEB category is stored as a heap and the heap is full, the
++ * LEB properties may have their category changed to %LPROPS_UNCAT.
++ */
++int ubifs_categorize_lprops(const struct ubifs_info *c,
++                          const struct ubifs_lprops *lprops)
++{
++      if (lprops->flags & LPROPS_TAKEN)
++              return LPROPS_UNCAT;
++
++      if (lprops->free == c->leb_size) {
++              ubifs_assert(!(lprops->flags & LPROPS_INDEX));
++              return LPROPS_EMPTY;
++      }
++
++      if (lprops->free + lprops->dirty == c->leb_size) {
++              if (lprops->flags & LPROPS_INDEX)
++                      return LPROPS_FRDI_IDX;
++              else
++                      return LPROPS_FREEABLE;
++      }
++
++      if (lprops->flags & LPROPS_INDEX) {
++              if (lprops->dirty + lprops->free >= c->min_idx_node_sz)
++                      return LPROPS_DIRTY_IDX;
++      } else {
++              if (lprops->dirty >= c->dead_wm &&
++                  lprops->dirty > lprops->free)
++                      return LPROPS_DIRTY;
++              if (lprops->free > 0)
++                      return LPROPS_FREE;
++      }
++
++      return LPROPS_UNCAT;
++}
++
++/**
++ * change_category - change LEB properties category.
++ * @c: UBIFS file-system description object
++ * @lprops: LEB properties to recategorize
++ *
++ * LEB properties are categorized to enable fast find operations. When the LEB
++ * properties change they must be recategorized.
++ */
++static void change_category(struct ubifs_info *c, struct ubifs_lprops *lprops)
++{
++      int old_cat = lprops->flags & LPROPS_CAT_MASK;
++      int new_cat = ubifs_categorize_lprops(c, lprops);
++
++      if (old_cat == new_cat) {
++              struct ubifs_lpt_heap *heap = &c->lpt_heap[new_cat - 1];
++
++              /* lprops on a heap now must be moved up or down */
++              if (new_cat < 1 || new_cat > LPROPS_HEAP_CNT)
++                      return; /* Not on a heap */
++              heap = &c->lpt_heap[new_cat - 1];
++              adjust_lpt_heap(c, heap, lprops, lprops->hpos, new_cat);
++      } else {
++              ubifs_remove_from_cat(c, lprops, old_cat);
++              ubifs_add_to_cat(c, lprops, new_cat);
++      }
++}
++
++/**
++ * ubifs_get_lprops - get reference to LEB properties.
++ * @c: the UBIFS file-system description object
++ *
++ * This function locks lprops. Lprops have to be unlocked by
++ * 'ubifs_release_lprops()'.
++ */
++void ubifs_get_lprops(struct ubifs_info *c)
++{
++      mutex_lock(&c->lp_mutex);
++}
++
++/**
++ * calc_dark - calculate LEB dark space size.
++ * @c: the UBIFS file-system description object
++ * @spc: amount of free and dirty space in the LEB
++ *
++ * This function calculates amount of dark space in an LEB which has @spc bytes
++ * of free and dirty space. Returns the calculations result.
++ *
++ * Dark space is the space which is not always usable - it depends on which
++ * nodes are written in which order. E.g., if an LEB has only 512 free bytes,
++ * it is dark space, because it cannot fit a large data node. So UBIFS cannot
++ * count on this LEB and treat these 512 bytes as usable because it is not true
++ * if, for example, only big chunks of uncompressible data will be written to
++ * the FS.
++ */
++static int calc_dark(struct ubifs_info *c, int spc)
++{
++      ubifs_assert(!(spc & 7));
++
++      if (spc < c->dark_wm)
++              return spc;
++
++      /*
++       * If we have slightly more space then the dark space watermark, we can
++       * anyway safely assume it we'll be able to write a node of the
++       * smallest size there.
++       */
++      if (spc - c->dark_wm < MIN_WRITE_SZ)
++              return spc - MIN_WRITE_SZ;
++
++      return c->dark_wm;
++}
++
++/**
++ * is_lprops_dirty - determine if LEB properties are dirty.
++ * @c: the UBIFS file-system description object
++ * @lprops: LEB properties to test
++ */
++static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops)
++{
++      struct ubifs_pnode *pnode;
++      int pos;
++
++      pos = (lprops->lnum - c->main_first) & (UBIFS_LPT_FANOUT - 1);
++      pnode = (struct ubifs_pnode *)container_of(lprops - pos,
++                                                 struct ubifs_pnode,
++                                                 lprops[0]);
++      return !test_bit(COW_ZNODE, &pnode->flags) &&
++             test_bit(DIRTY_CNODE, &pnode->flags);
++}
++
++/**
++ * ubifs_change_lp - change LEB properties.
++ * @c: the UBIFS file-system description object
++ * @lp: LEB properties to change
++ * @free: new free space amount
++ * @dirty: new dirty space amount
++ * @flags: new flags
++ * @idx_gc_cnt: change to the count of idx_gc list
++ *
++ * This function changes LEB properties. This function does not change a LEB
++ * property (@free, @dirty or @flag) if the value passed is %LPROPS_NC.
++ *
++ * This function returns a pointer to the updated LEB properties on success
++ * and a negative error code on failure. N.B. the LEB properties may have had to
++ * be copied (due to COW) and consequently the pointer returned may not be the
++ * same as the pointer passed.
++ */
++const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
++                                         const struct ubifs_lprops *lp,
++                                         int free, int dirty, int flags,
++                                         int idx_gc_cnt)
++{
++      /*
++       * This is the only function that is allowed to change lprops, so we
++       * discard the const qualifier.
++       */
++      struct ubifs_lprops *lprops = (struct ubifs_lprops *)lp;
++
++      dbg_lp("LEB %d, free %d, dirty %d, flags %d",
++             lprops->lnum, free, dirty, flags);
++
++      ubifs_assert(mutex_is_locked(&c->lp_mutex));
++      ubifs_assert(c->lst.empty_lebs >= 0 &&
++                   c->lst.empty_lebs <= c->main_lebs);
++      ubifs_assert(c->freeable_cnt >= 0);
++      ubifs_assert(c->freeable_cnt <= c->main_lebs);
++      ubifs_assert(c->lst.taken_empty_lebs >= 0);
++      ubifs_assert(c->lst.taken_empty_lebs <= c->lst.empty_lebs);
++      ubifs_assert(!(c->lst.total_free & 7) && !(c->lst.total_dirty & 7));
++      ubifs_assert(!(c->lst.total_dead & 7) && !(c->lst.total_dark & 7));
++      ubifs_assert(!(c->lst.total_used & 7));
++      ubifs_assert(free == LPROPS_NC || free >= 0);
++      ubifs_assert(dirty == LPROPS_NC || dirty >= 0);
++
++      if (!is_lprops_dirty(c, lprops)) {
++              lprops = ubifs_lpt_lookup_dirty(c, lprops->lnum);
++              if (IS_ERR(lprops))
++                      return lprops;
++      } else
++              ubifs_assert(lprops == ubifs_lpt_lookup_dirty(c, lprops->lnum));
++
++      ubifs_assert(!(lprops->free & 7) && !(lprops->dirty & 7));
++
++      spin_lock(&c->space_lock);
++
++      if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size)
++              c->lst.taken_empty_lebs -= 1;
++
++      if (!(lprops->flags & LPROPS_INDEX)) {
++              int old_spc;
++
++              old_spc = lprops->free + lprops->dirty;
++              if (old_spc < c->dead_wm)
++                      c->lst.total_dead -= old_spc;
++              else
++                      c->lst.total_dark -= calc_dark(c, old_spc);
++
++              c->lst.total_used -= c->leb_size - old_spc;
++      }
++
++      if (free != LPROPS_NC) {
++              free = ALIGN(free, 8);
++              c->lst.total_free += free - lprops->free;
++
++              /* Increase or decrease empty LEBs counter if needed */
++              if (free == c->leb_size) {
++                      if (lprops->free != c->leb_size)
++                              c->lst.empty_lebs += 1;
++              } else if (lprops->free == c->leb_size)
++                      c->lst.empty_lebs -= 1;
++              lprops->free = free;
++      }
++
++      if (dirty != LPROPS_NC) {
++              dirty = ALIGN(dirty, 8);
++              c->lst.total_dirty += dirty - lprops->dirty;
++              lprops->dirty = dirty;
++      }
++
++      if (flags != LPROPS_NC) {
++              /* Take care about indexing LEBs counter if needed */
++              if ((lprops->flags & LPROPS_INDEX)) {
++                      if (!(flags & LPROPS_INDEX))
++                              c->lst.idx_lebs -= 1;
++              } else if (flags & LPROPS_INDEX)
++                      c->lst.idx_lebs += 1;
++              lprops->flags = flags;
++      }
++
++      if (!(lprops->flags & LPROPS_INDEX)) {
++              int new_spc;
++
++              new_spc = lprops->free + lprops->dirty;
++              if (new_spc < c->dead_wm)
++                      c->lst.total_dead += new_spc;
++              else
++                      c->lst.total_dark += calc_dark(c, new_spc);
++
++              c->lst.total_used += c->leb_size - new_spc;
++      }
++
++      if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size)
++              c->lst.taken_empty_lebs += 1;
++
++      change_category(c, lprops);
++
++      c->idx_gc_cnt += idx_gc_cnt;
++
++      spin_unlock(&c->space_lock);
++
++      return lprops;
++}
++
++/**
++ * ubifs_release_lprops - release lprops lock.
++ * @c: the UBIFS file-system description object
++ *
++ * This function has to be called after each 'ubifs_get_lprops()' call to
++ * unlock lprops.
++ */
++void ubifs_release_lprops(struct ubifs_info *c)
++{
++      ubifs_assert(mutex_is_locked(&c->lp_mutex));
++      ubifs_assert(c->lst.empty_lebs >= 0 &&
++                   c->lst.empty_lebs <= c->main_lebs);
++
++      mutex_unlock(&c->lp_mutex);
++}
++
++/**
++ * ubifs_get_lp_stats - get lprops statistics.
++ * @c: UBIFS file-system description object
++ * @st: return statistics
++ */
++void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *st)
++{
++      spin_lock(&c->space_lock);
++      memcpy(st, &c->lst, sizeof(struct ubifs_lp_stats));
++      spin_unlock(&c->space_lock);
++}
++
++/**
++ * ubifs_change_one_lp - change LEB properties.
++ * @c: the UBIFS file-system description object
++ * @lnum: LEB to change properties for
++ * @free: amount of free space
++ * @dirty: amount of dirty space
++ * @flags_set: flags to set
++ * @flags_clean: flags to clean
++ * @idx_gc_cnt: change to the count of idx_gc list
++ *
++ * This function changes properties of LEB @lnum. It is a helper wrapper over
++ * 'ubifs_change_lp()' which hides lprops get/release. The arguments are the
++ * same as in case of 'ubifs_change_lp()'. Returns zero in case of success and
++ * a negative error code in case of failure.
++ */
++int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
++                      int flags_set, int flags_clean, int idx_gc_cnt)
++{
++      int err = 0, flags;
++      const struct ubifs_lprops *lp;
++
++      ubifs_get_lprops(c);
++
++      lp = ubifs_lpt_lookup_dirty(c, lnum);
++      if (IS_ERR(lp)) {
++              err = PTR_ERR(lp);
++              goto out;
++      }
++
++      flags = (lp->flags | flags_set) & ~flags_clean;
++      lp = ubifs_change_lp(c, lp, free, dirty, flags, idx_gc_cnt);
++      if (IS_ERR(lp))
++              err = PTR_ERR(lp);
++
++out:
++      ubifs_release_lprops(c);
++      return err;
++}
++
++/**
++ * ubifs_update_one_lp - update LEB properties.
++ * @c: the UBIFS file-system description object
++ * @lnum: LEB to change properties for
++ * @free: amount of free space
++ * @dirty: amount of dirty space to add
++ * @flags_set: flags to set
++ * @flags_clean: flags to clean
++ *
++ * This function is the same as 'ubifs_change_one_lp()' but @dirty is added to
++ * current dirty space, not substitutes it.
++ */
++int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
++                      int flags_set, int flags_clean)
++{
++      int err = 0, flags;
++      const struct ubifs_lprops *lp;
++
++      ubifs_get_lprops(c);
++
++      lp = ubifs_lpt_lookup_dirty(c, lnum);
++      if (IS_ERR(lp)) {
++              err = PTR_ERR(lp);
++              goto out;
++      }
++
++      flags = (lp->flags | flags_set) & ~flags_clean;
++      lp = ubifs_change_lp(c, lp, free, lp->dirty + dirty, flags, 0);
++      if (IS_ERR(lp))
++              err = PTR_ERR(lp);
++
++out:
++      ubifs_release_lprops(c);
++      return err;
++}
++
++/**
++ * ubifs_read_one_lp - read LEB properties.
++ * @c: the UBIFS file-system description object
++ * @lnum: LEB to read properties for
++ * @lp: where to store read properties
++ *
++ * This helper function reads properties of a LEB @lnum and stores them in @lp.
++ * Returns zero in case of success and a negative error code in case of
++ * failure.
++ */
++int ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp)
++{
++      int err = 0;
++      const struct ubifs_lprops *lpp;
++
++      ubifs_get_lprops(c);
++
++      lpp = ubifs_lpt_lookup(c, lnum);
++      if (IS_ERR(lpp)) {
++              err = PTR_ERR(lpp);
++              goto out;
++      }
++
++      memcpy(lp, lpp, sizeof(struct ubifs_lprops));
++
++out:
++      ubifs_release_lprops(c);
++      return err;
++}
++
++/**
++ * ubifs_fast_find_free - try to find a LEB with free space quickly.
++ * @c: the UBIFS file-system description object
++ *
++ * This function returns LEB properties for a LEB with free space or %NULL if
++ * the function is unable to find a LEB quickly.
++ */
++const struct ubifs_lprops *ubifs_fast_find_free(struct ubifs_info *c)
++{
++      struct ubifs_lprops *lprops;
++      struct ubifs_lpt_heap *heap;
++
++      ubifs_assert(mutex_is_locked(&c->lp_mutex));
++
++      heap = &c->lpt_heap[LPROPS_FREE - 1];
++      if (heap->cnt == 0)
++              return NULL;
++
++      lprops = heap->arr[0];
++      ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
++      ubifs_assert(!(lprops->flags & LPROPS_INDEX));
++      return lprops;
++}
++
++/**
++ * ubifs_fast_find_empty - try to find an empty LEB quickly.
++ * @c: the UBIFS file-system description object
++ *
++ * This function returns LEB properties for an empty LEB or %NULL if the
++ * function is unable to find an empty LEB quickly.
++ */
++const struct ubifs_lprops *ubifs_fast_find_empty(struct ubifs_info *c)
++{
++      struct ubifs_lprops *lprops;
++
++      ubifs_assert(mutex_is_locked(&c->lp_mutex));
++
++      if (list_empty(&c->empty_list))
++              return NULL;
++
++      lprops = list_entry(c->empty_list.next, struct ubifs_lprops, list);
++      ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
++      ubifs_assert(!(lprops->flags & LPROPS_INDEX));
++      ubifs_assert(lprops->free == c->leb_size);
++      return lprops;
++}
++
++/**
++ * ubifs_fast_find_freeable - try to find a freeable LEB quickly.
++ * @c: the UBIFS file-system description object
++ *
++ * This function returns LEB properties for a freeable LEB or %NULL if the
++ * function is unable to find a freeable LEB quickly.
++ */
++const struct ubifs_lprops *ubifs_fast_find_freeable(struct ubifs_info *c)
++{
++      struct ubifs_lprops *lprops;
++
++      ubifs_assert(mutex_is_locked(&c->lp_mutex));
++
++      if (list_empty(&c->freeable_list))
++              return NULL;
++
++      lprops = list_entry(c->freeable_list.next, struct ubifs_lprops, list);
++      ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
++      ubifs_assert(!(lprops->flags & LPROPS_INDEX));
++      ubifs_assert(lprops->free + lprops->dirty == c->leb_size);
++      ubifs_assert(c->freeable_cnt > 0);
++      return lprops;
++}
++
++/**
++ * ubifs_fast_find_frdi_idx - try to find a freeable index LEB quickly.
++ * @c: the UBIFS file-system description object
++ *
++ * This function returns LEB properties for a freeable index LEB or %NULL if the
++ * function is unable to find a freeable index LEB quickly.
++ */
++const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c)
++{
++      struct ubifs_lprops *lprops;
++
++      ubifs_assert(mutex_is_locked(&c->lp_mutex));
++
++      if (list_empty(&c->frdi_idx_list))
++              return NULL;
++
++      lprops = list_entry(c->frdi_idx_list.next, struct ubifs_lprops, list);
++      ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
++      ubifs_assert((lprops->flags & LPROPS_INDEX));
++      ubifs_assert(lprops->free + lprops->dirty == c->leb_size);
++      return lprops;
++}
++
++#ifdef CONFIG_UBIFS_FS_DEBUG
++
++/**
++ * dbg_check_cats - check category heaps and lists.
++ * @c: UBIFS file-system description object
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++int dbg_check_cats(struct ubifs_info *c)
++{
++      struct ubifs_lprops *lprops;
++      struct list_head *pos;
++      int i, cat;
++
++      if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS)))
++              return 0;
++
++      list_for_each_entry(lprops, &c->empty_list, list) {
++              if (lprops->free != c->leb_size) {
++                      ubifs_err("non-empty LEB %d on empty list "
++                                "(free %d dirty %d flags %d)", lprops->lnum,
++                                lprops->free, lprops->dirty, lprops->flags);
++                      return -EINVAL;
++              }
++              if (lprops->flags & LPROPS_TAKEN) {
++                      ubifs_err("taken LEB %d on empty list "
++                                "(free %d dirty %d flags %d)", lprops->lnum,
++                                lprops->free, lprops->dirty, lprops->flags);
++                      return -EINVAL;
++              }
++      }
++
++      i = 0;
++      list_for_each_entry(lprops, &c->freeable_list, list) {
++              if (lprops->free + lprops->dirty != c->leb_size) {
++                      ubifs_err("non-freeable LEB %d on freeable list "
++                                "(free %d dirty %d flags %d)", lprops->lnum,
++                                lprops->free, lprops->dirty, lprops->flags);
++                      return -EINVAL;
++              }
++              if (lprops->flags & LPROPS_TAKEN) {
++                      ubifs_err("taken LEB %d on freeable list "
++                                "(free %d dirty %d flags %d)", lprops->lnum,
++                                lprops->free, lprops->dirty, lprops->flags);
++                      return -EINVAL;
++              }
++              i += 1;
++      }
++      if (i != c->freeable_cnt) {
++              ubifs_err("freeable list count %d expected %d", i,
++                        c->freeable_cnt);
++              return -EINVAL;
++      }
++
++      i = 0;
++      list_for_each(pos, &c->idx_gc)
++              i += 1;
++      if (i != c->idx_gc_cnt) {
++              ubifs_err("idx_gc list count %d expected %d", i,
++                        c->idx_gc_cnt);
++              return -EINVAL;
++      }
++
++      list_for_each_entry(lprops, &c->frdi_idx_list, list) {
++              if (lprops->free + lprops->dirty != c->leb_size) {
++                      ubifs_err("non-freeable LEB %d on frdi_idx list "
++                                "(free %d dirty %d flags %d)", lprops->lnum,
++                                lprops->free, lprops->dirty, lprops->flags);
++                      return -EINVAL;
++              }
++              if (lprops->flags & LPROPS_TAKEN) {
++                      ubifs_err("taken LEB %d on frdi_idx list "
++                                "(free %d dirty %d flags %d)", lprops->lnum,
++                                lprops->free, lprops->dirty, lprops->flags);
++                      return -EINVAL;
++              }
++              if (!(lprops->flags & LPROPS_INDEX)) {
++                      ubifs_err("non-index LEB %d on frdi_idx list "
++                                "(free %d dirty %d flags %d)", lprops->lnum,
++                                lprops->free, lprops->dirty, lprops->flags);
++                      return -EINVAL;
++              }
++      }
++
++      for (cat = 1; cat <= LPROPS_HEAP_CNT; cat++) {
++              struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
++
++              for (i = 0; i < heap->cnt; i++) {
++                      lprops = heap->arr[i];
++                      if (!lprops) {
++                              ubifs_err("null ptr in LPT heap cat %d", cat);
++                              return -EINVAL;
++                      }
++                      if (lprops->hpos != i) {
++                              ubifs_err("bad ptr in LPT heap cat %d", cat);
++                              return -EINVAL;
++                      }
++                      if (lprops->flags & LPROPS_TAKEN) {
++                              ubifs_err("taken LEB in LPT heap cat %d", cat);
++                              return -EINVAL;
++                      }
++              }
++      }
++
++      return 0;
++}
++
++void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
++                  int add_pos)
++{
++      int i = 0, j, err = 0;
++
++      if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS)))
++              return;
++
++      for (i = 0; i < heap->cnt; i++) {
++              struct ubifs_lprops *lprops = heap->arr[i];
++              struct ubifs_lprops *lp;
++
++              if (i != add_pos)
++                      if ((lprops->flags & LPROPS_CAT_MASK) != cat) {
++                              err = 1;
++                              goto out;
++                      }
++              if (lprops->hpos != i) {
++                      err = 2;
++                      goto out;
++              }
++              lp = ubifs_lpt_lookup(c, lprops->lnum);
++              if (IS_ERR(lp)) {
++                      err = 3;
++                      goto out;
++              }
++              if (lprops != lp) {
++                      dbg_msg("lprops %zx lp %zx lprops->lnum %d lp->lnum %d",
++                              (size_t)lprops, (size_t)lp, lprops->lnum,
++                              lp->lnum);
++                      err = 4;
++                      goto out;
++              }
++              for (j = 0; j < i; j++) {
++                      lp = heap->arr[j];
++                      if (lp == lprops) {
++                              err = 5;
++                              goto out;
++                      }
++                      if (lp->lnum == lprops->lnum) {
++                              err = 6;
++                              goto out;
++                      }
++              }
++      }
++out:
++      if (err) {
++              dbg_msg("failed cat %d hpos %d err %d", cat, i, err);
++              dbg_dump_stack();
++              dbg_dump_heap(c, heap, cat);
++      }
++}
++
++/**
++ * struct scan_check_data - data provided to scan callback function.
++ * @lst: LEB properties statistics
++ * @err: error code
++ */
++struct scan_check_data {
++      struct ubifs_lp_stats lst;
++      int err;
++};
++
++/**
++ * scan_check_cb - scan callback.
++ * @c: the UBIFS file-system description object
++ * @lp: LEB properties to scan
++ * @in_tree: whether the LEB properties are in main memory
++ * @data: information passed to and from the caller of the scan
++ *
++ * This function returns a code that indicates whether the scan should continue
++ * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree
++ * in main memory (%LPT_SCAN_ADD), or whether the scan should stop
++ * (%LPT_SCAN_STOP).
++ */
++static int scan_check_cb(struct ubifs_info *c,
++                       const struct ubifs_lprops *lp, int in_tree,
++                       struct scan_check_data *data)
++{
++      struct ubifs_scan_leb *sleb;
++      struct ubifs_scan_node *snod;
++      struct ubifs_lp_stats *lst = &data->lst;
++      int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty;
++
++      cat = lp->flags & LPROPS_CAT_MASK;
++      if (cat != LPROPS_UNCAT) {
++              cat = ubifs_categorize_lprops(c, lp);
++              if (cat != (lp->flags & LPROPS_CAT_MASK)) {
++                      ubifs_err("bad LEB category %d expected %d",
++                                (lp->flags & LPROPS_CAT_MASK), cat);
++                      goto out;
++              }
++      }
++
++      /* Check lp is on its category list (if it has one) */
++      if (in_tree) {
++              struct list_head *list = NULL;
++
++              switch (cat) {
++              case LPROPS_EMPTY:
++                      list = &c->empty_list;
++                      break;
++              case LPROPS_FREEABLE:
++                      list = &c->freeable_list;
++                      break;
++              case LPROPS_FRDI_IDX:
++                      list = &c->frdi_idx_list;
++                      break;
++              case LPROPS_UNCAT:
++                      list = &c->uncat_list;
++                      break;
++              }
++              if (list) {
++                      struct ubifs_lprops *lprops;
++                      int found = 0;
++
++                      list_for_each_entry(lprops, list, list) {
++                              if (lprops == lp) {
++                                      found = 1;
++                                      break;
++                              }
++                      }
++                      if (!found) {
++                              ubifs_err("bad LPT list (category %d)", cat);
++                              goto out;
++                      }
++              }
++      }
++
++      /* Check lp is on its category heap (if it has one) */
++      if (in_tree && cat > 0 && cat <= LPROPS_HEAP_CNT) {
++              struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
++
++              if ((lp->hpos != -1 && heap->arr[lp->hpos]->lnum != lnum) ||
++                  lp != heap->arr[lp->hpos]) {
++                      ubifs_err("bad LPT heap (category %d)", cat);
++                      goto out;
++              }
++      }
++
++      sleb = ubifs_scan(c, lnum, 0, c->dbg_buf);
++      if (IS_ERR(sleb)) {
++              /*
++               * After an unclean unmount, empty and freeable LEBs
++               * may contain garbage.
++               */
++              if (lp->free == c->leb_size) {
++                      ubifs_err("scan errors were in empty LEB "
++                                "- continuing checking");
++                      lst->empty_lebs += 1;
++                      lst->total_free += c->leb_size;
++                      lst->total_dark += calc_dark(c, c->leb_size);
++                      return LPT_SCAN_CONTINUE;
++              }
++
++              if (lp->free + lp->dirty == c->leb_size &&
++                  !(lp->flags & LPROPS_INDEX)) {
++                      ubifs_err("scan errors were in freeable LEB "
++                                "- continuing checking");
++                      lst->total_free  += lp->free;
++                      lst->total_dirty += lp->dirty;
++                      lst->total_dark  +=  calc_dark(c, c->leb_size);
++                      return LPT_SCAN_CONTINUE;
++              }
++              data->err = PTR_ERR(sleb);
++              return LPT_SCAN_STOP;
++      }
++
++      is_idx = -1;
++      list_for_each_entry(snod, &sleb->nodes, list) {
++              int found, level = 0;
++
++              cond_resched();
++
++              if (is_idx == -1)
++                      is_idx = (snod->type == UBIFS_IDX_NODE) ? 1 : 0;
++
++              if (is_idx && snod->type != UBIFS_IDX_NODE) {
++                      ubifs_err("indexing node in data LEB %d:%d",
++                                lnum, snod->offs);
++                      goto out_destroy;
++              }
++
++              if (snod->type == UBIFS_IDX_NODE) {
++                      struct ubifs_idx_node *idx = snod->node;
++
++                      key_read(c, ubifs_idx_key(c, idx), &snod->key);
++                      level = le16_to_cpu(idx->level);
++              }
++
++              found = ubifs_tnc_has_node(c, &snod->key, level, lnum,
++                                         snod->offs, is_idx);
++              if (found) {
++                      if (found < 0)
++                              goto out_destroy;
++                      used += ALIGN(snod->len, 8);
++              }
++      }
++
++      free = c->leb_size - sleb->endpt;
++      dirty = sleb->endpt - used;
++
++      if (free > c->leb_size || free < 0 || dirty > c->leb_size ||
++          dirty < 0) {
++              ubifs_err("bad calculated accounting for LEB %d: "
++                        "free %d, dirty %d", lnum, free, dirty);
++              goto out_destroy;
++      }
++
++      if (lp->free + lp->dirty == c->leb_size &&
++          free + dirty == c->leb_size)
++              if ((is_idx && !(lp->flags & LPROPS_INDEX)) ||
++                  (!is_idx && free == c->leb_size)) {
++                      /*
++                       * Empty or freeable LEBs could contain index
++                       * nodes from an uncompleted commit due to an
++                       * unclean unmount. Or they could be empty for
++                       * the same reason.
++                       */
++                      free = lp->free;
++                      dirty = lp->dirty;
++                      is_idx = 0;
++                  }
++
++      if (is_idx && lp->free + lp->dirty == free + dirty &&
++          lnum != c->ihead_lnum) {
++              /*
++               * After an unclean unmount, an index LEB could have a different
++               * amount of free space than the value recorded by lprops. That
++               * is because the in-the-gaps method may use free space or
++               * create free space (as a side-effect of using ubi_leb_change
++               * and not writing the whole LEB). The incorrect free space
++               * value is not a problem because the index is only ever
++               * allocated empty LEBs, so there will never be an attempt to
++               * write to the free space at the end of an index LEB - except
++               * by the in-the-gaps method for which it is not a problem.
++               */
++              free = lp->free;
++              dirty = lp->dirty;
++      }
++
++      if (lp->free != free || lp->dirty != dirty)
++              goto out_print;
++
++      if (is_idx && !(lp->flags & LPROPS_INDEX)) {
++              if (free == c->leb_size)
++                      /* Free but not unmapped LEB, it's fine */
++                      is_idx = 0;
++              else {
++                      ubifs_err("indexing node without indexing "
++                                "flag");
++                      goto out_print;
++              }
++      }
++
++      if (!is_idx && (lp->flags & LPROPS_INDEX)) {
++              ubifs_err("data node with indexing flag");
++              goto out_print;
++      }
++
++      if (free == c->leb_size)
++              lst->empty_lebs += 1;
++
++      if (is_idx)
++              lst->idx_lebs += 1;
++
++      if (!(lp->flags & LPROPS_INDEX))
++              lst->total_used += c->leb_size - free - dirty;
++      lst->total_free += free;
++      lst->total_dirty += dirty;
++
++      if (!(lp->flags & LPROPS_INDEX)) {
++              int spc = free + dirty;
++
++              if (spc < c->dead_wm)
++                      lst->total_dead += spc;
++              else
++                      lst->total_dark += calc_dark(c, spc);
++      }
++
++      ubifs_scan_destroy(sleb);
++
++      return LPT_SCAN_CONTINUE;
++
++out_print:
++      ubifs_err("bad accounting of LEB %d: free %d, dirty %d flags %#x, "
++                "should be free %d, dirty %d",
++                lnum, lp->free, lp->dirty, lp->flags, free, dirty);
++      dbg_dump_leb(c, lnum);
++out_destroy:
++      ubifs_scan_destroy(sleb);
++out:
++      data->err = -EINVAL;
++      return LPT_SCAN_STOP;
++}
++
++/**
++ * dbg_check_lprops - check all LEB properties.
++ * @c: UBIFS file-system description object
++ *
++ * This function checks all LEB properties and makes sure they are all correct.
++ * It returns zero if everything is fine, %-EINVAL if there is an inconsistency
++ * and other negative error codes in case of other errors. This function is
++ * called while the file system is locked (because of commit start), so no
++ * additional locking is required. Note that locking the LPT mutex would cause
++ * a circular lock dependency with the TNC mutex.
++ */
++int dbg_check_lprops(struct ubifs_info *c)
++{
++      int i, err;
++      struct scan_check_data data;
++      struct ubifs_lp_stats *lst = &data.lst;
++
++      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++              return 0;
++
++      /*
++       * As we are going to scan the media, the write buffers have to be
++       * synchronized.
++       */
++      for (i = 0; i < c->jhead_cnt; i++) {
++              err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
++              if (err)
++                      return err;
++      }
++
++      memset(lst, 0, sizeof(struct ubifs_lp_stats));
++
++      data.err = 0;
++      err = ubifs_lpt_scan_nolock(c, c->main_first, c->leb_cnt - 1,
++                                  (ubifs_lpt_scan_callback)scan_check_cb,
++                                  &data);
++      if (err && err != -ENOSPC)
++              goto out;
++      if (data.err) {
++              err = data.err;
++              goto out;
++      }
++
++      if (lst->empty_lebs != c->lst.empty_lebs ||
++          lst->idx_lebs != c->lst.idx_lebs ||
++          lst->total_free != c->lst.total_free ||
++          lst->total_dirty != c->lst.total_dirty ||
++          lst->total_used != c->lst.total_used) {
++              ubifs_err("bad overall accounting");
++              ubifs_err("calculated: empty_lebs %d, idx_lebs %d, "
++                        "total_free %lld, total_dirty %lld, total_used %lld",
++                        lst->empty_lebs, lst->idx_lebs, lst->total_free,
++                        lst->total_dirty, lst->total_used);
++              ubifs_err("read from lprops: empty_lebs %d, idx_lebs %d, "
++                        "total_free %lld, total_dirty %lld, total_used %lld",
++                        c->lst.empty_lebs, c->lst.idx_lebs, c->lst.total_free,
++                        c->lst.total_dirty, c->lst.total_used);
++              err = -EINVAL;
++              goto out;
++      }
++
++      if (lst->total_dead != c->lst.total_dead ||
++          lst->total_dark != c->lst.total_dark) {
++              ubifs_err("bad dead/dark space accounting");
++              ubifs_err("calculated: total_dead %lld, total_dark %lld",
++                        lst->total_dead, lst->total_dark);
++              ubifs_err("read from lprops: total_dead %lld, total_dark %lld",
++                        c->lst.total_dead, c->lst.total_dark);
++              err = -EINVAL;
++              goto out;
++      }
++
++      err = dbg_check_cats(c);
++out:
++      return err;
++}
++
++#endif /* CONFIG_UBIFS_FS_DEBUG */
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/lpt.c avr32-2.6/fs/ubifs/lpt.c
+--- linux-2.6.25.6/fs/ubifs/lpt.c      1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/lpt.c   2008-06-12 15:09:45.475816115 +0200
+@@ -0,0 +1,2241 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Adrian Hunter
++ *          Artem Bityutskiy (Битюцкий Артём)
++ */
++
++/*
++ * This file implements the LEB properties tree (LPT) area. The LPT area
++ * contains the LEB properties tree, a table of LPT area eraseblocks (ltab), and
++ * (for the "big" model) a table of saved LEB numbers (lsave). The LPT area sits
++ * between the log and the orphan area.
++ *
++ * The LPT area is like a miniature self-contained file system. It is required
++ * that it never runs out of space, is fast to access and update, and scales
++ * logarithmically. The LEB properties tree is implemented as a wandering tree
++ * much like the TNC, and the LPT area has its own garbage collection.
++ *
++ * The LPT has two slightly different forms called the "small model" and the
++ * "big model". The small model is used when the entire LEB properties table
++ * can be written into a single eraseblock. In that case, garbage collection
++ * consists of just writing the whole table, which therefore makes all other
++ * eraseblocks reusable. In the case of the big model, dirty eraseblocks are
++ * selected for garbage collection, which consists are marking the nodes in
++ * that LEB as dirty, and then only the dirty nodes are written out. Also, in
++ * the case of the big model, a table of LEB numbers is saved so that the entire
++ * LPT does not to be scanned looking for empty eraseblocks when UBIFS is first
++ * mounted.
++ */
++
++#include <linux/crc16.h>
++#include "ubifs.h"
++
++/**
++ * do_calc_lpt_geom - calculate sizes for the LPT area.
++ * @c: the UBIFS file-system description object
++ *
++ * Calculate the sizes of LPT bit fields, nodes, and tree, based on the
++ * properties of the flash and whether LPT is "big" (c->big_lpt).
++ */
++static void do_calc_lpt_geom(struct ubifs_info *c)
++{
++      int i, n, bits, per_leb_wastage, max_pnode_cnt;
++      long long sz, tot_wastage;
++
++      n = c->main_lebs + c->max_leb_cnt - c->leb_cnt;
++      max_pnode_cnt = DIV_ROUND_UP(n, UBIFS_LPT_FANOUT);
++
++      c->lpt_hght = 1;
++      n = UBIFS_LPT_FANOUT;
++      while (n < max_pnode_cnt) {
++              c->lpt_hght += 1;
++              n <<= UBIFS_LPT_FANOUT_SHIFT;
++      }
++
++      c->pnode_cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT);
++
++      n = DIV_ROUND_UP(c->pnode_cnt, UBIFS_LPT_FANOUT);
++      c->nnode_cnt = n;
++      for (i = 1; i < c->lpt_hght; i++) {
++              n = DIV_ROUND_UP(n, UBIFS_LPT_FANOUT);
++              c->nnode_cnt += n;
++      }
++
++      c->space_bits = fls(c->leb_size) - 3;
++      c->lpt_lnum_bits = fls(c->lpt_lebs);
++      c->lpt_offs_bits = fls(c->leb_size - 1);
++      c->lpt_spc_bits = fls(c->leb_size);
++
++      n = DIV_ROUND_UP(c->max_leb_cnt, UBIFS_LPT_FANOUT);
++      c->pcnt_bits = fls(n - 1);
++
++      c->lnum_bits = fls(c->max_leb_cnt - 1);
++
++      bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
++             (c->big_lpt ? c->pcnt_bits : 0) +
++             (c->space_bits * 2 + 1) * UBIFS_LPT_FANOUT;
++      c->pnode_sz = (bits + 7) / 8;
++
++      bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
++             (c->big_lpt ? c->pcnt_bits : 0) +
++             (c->lpt_lnum_bits + c->lpt_offs_bits) * UBIFS_LPT_FANOUT;
++      c->nnode_sz = (bits + 7) / 8;
++
++      bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
++             c->lpt_lebs * c->lpt_spc_bits * 2;
++      c->ltab_sz = (bits + 7) / 8;
++
++      bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
++             c->lnum_bits * c->lsave_cnt;
++      c->lsave_sz = (bits + 7) / 8;
++
++      /* Calculate the minimum LPT size */
++      c->lpt_sz = (long long)c->pnode_cnt * c->pnode_sz;
++      c->lpt_sz += (long long)c->nnode_cnt * c->nnode_sz;
++      c->lpt_sz += c->ltab_sz;
++      c->lpt_sz += c->lsave_sz;
++
++      /* Add wastage */
++      sz = c->lpt_sz;
++      per_leb_wastage = max_t(int, c->pnode_sz, c->nnode_sz);
++      sz += per_leb_wastage;
++      tot_wastage = per_leb_wastage;
++      while (sz > c->leb_size) {
++              sz += per_leb_wastage;
++              sz -= c->leb_size;
++              tot_wastage += per_leb_wastage;
++      }
++      tot_wastage += ALIGN(sz, c->min_io_size) - sz;
++      c->lpt_sz += tot_wastage;
++}
++
++/**
++ * ubifs_calc_lpt_geom - calculate and check sizes for the LPT area.
++ * @c: the UBIFS file-system description object
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++int ubifs_calc_lpt_geom(struct ubifs_info *c)
++{
++      int lebs_needed;
++      uint64_t sz;
++
++      do_calc_lpt_geom(c);
++
++      /* Verify that lpt_lebs is big enough */
++      sz = c->lpt_sz * 2; /* Must have at least 2 times the size */
++      sz += c->leb_size - 1;
++      do_div(sz, c->leb_size);
++      lebs_needed = sz;
++      if (lebs_needed > c->lpt_lebs) {
++              ubifs_err("too few LPT LEBs");
++              return -EINVAL;
++      }
++
++      /* Verify that ltab fits in a single LEB (since ltab is a single node */
++      if (c->ltab_sz > c->leb_size) {
++              ubifs_err("LPT ltab too big");
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
++/**
++ * calc_dflt_lpt_geom - calculate default LPT geometry.
++ * @c: the UBIFS file-system description object
++ * @main_lebs: number of main area LEBs is passed and returned here
++ * @big_lpt: whether the LPT area is "big" is returned here
++ *
++ * The size of the LPT area depends on parameters that themselves are dependent
++ * on the size of the LPT area. This function, successively recalculates the LPT
++ * area geometry until the parameters and resultant geometry are consistent.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs,
++                            int *big_lpt)
++{
++      int i, lebs_needed;
++      uint64_t sz;
++
++      /* Start by assuming the minimum number of LPT LEBs */
++      c->lpt_lebs = UBIFS_MIN_LPT_LEBS;
++      c->main_lebs = *main_lebs - c->lpt_lebs;
++      if (c->main_lebs <= 0)
++              return -EINVAL;
++
++      /* And assume we will use the small LPT model */
++      c->big_lpt = 0;
++
++      /*
++       * Calculate the geometry based on assumptions above and then see if it
++       * makes sense
++       */
++      do_calc_lpt_geom(c);
++
++      /* Small LPT model must have lpt_sz < leb_size */
++      if (c->lpt_sz > c->leb_size) {
++              /* Nope, so try again using big LPT model */
++              c->big_lpt = 1;
++              do_calc_lpt_geom(c);
++      }
++
++      /* Now check there are enough LPT LEBs */
++      for (i = 0; i < 64 ; i++) {
++              sz = c->lpt_sz * 4; /* Allow 4 times the size */
++              sz += c->leb_size - 1;
++              do_div(sz, c->leb_size);
++              lebs_needed = sz;
++              if (lebs_needed > c->lpt_lebs) {
++                      /* Not enough LPT LEBs so try again with more */
++                      c->lpt_lebs = lebs_needed;
++                      c->main_lebs = *main_lebs - c->lpt_lebs;
++                      if (c->main_lebs <= 0)
++                              return -EINVAL;
++                      do_calc_lpt_geom(c);
++                      continue;
++              }
++              if (c->ltab_sz > c->leb_size) {
++                      ubifs_err("LPT ltab too big");
++                      return -EINVAL;
++              }
++              *main_lebs = c->main_lebs;
++              *big_lpt = c->big_lpt;
++              return 0;
++      }
++      return -EINVAL;
++}
++
++/**
++ * pack_bits - pack bit fields end-to-end.
++ * @addr: address at which to pack (passed and next address returned)
++ * @pos: bit position at which to pack (passed and next position returned)
++ * @val: value to pack
++ * @nrbits: number of bits of value to pack (1-32)
++ */
++static void pack_bits(uint8_t **addr, int *pos, uint32_t val, int nrbits)
++{
++      uint8_t *p = *addr;
++      int b = *pos;
++
++      ubifs_assert(nrbits > 0);
++      ubifs_assert(nrbits <= 32);
++      ubifs_assert(*pos >= 0);
++      ubifs_assert(*pos < 8);
++      ubifs_assert((val >> nrbits) == 0 || nrbits == 32);
++      if (b) {
++              *p |= ((uint8_t)val) << b;
++              nrbits += b;
++              if (nrbits > 8) {
++                      *++p = (uint8_t)(val >>= (8 - b));
++                      if (nrbits > 16) {
++                              *++p = (uint8_t)(val >>= 8);
++                              if (nrbits > 24) {
++                                      *++p = (uint8_t)(val >>= 8);
++                                      if (nrbits > 32)
++                                              *++p = (uint8_t)(val >>= 8);
++                              }
++                      }
++              }
++      } else {
++              *p = (uint8_t)val;
++              if (nrbits > 8) {
++                      *++p = (uint8_t)(val >>= 8);
++                      if (nrbits > 16) {
++                              *++p = (uint8_t)(val >>= 8);
++                              if (nrbits > 24)
++                                      *++p = (uint8_t)(val >>= 8);
++                      }
++              }
++      }
++      b = nrbits & 7;
++      if (b == 0)
++              p++;
++      *addr = p;
++      *pos = b;
++}
++
++/**
++ * ubifs_unpack_bits - unpack bit fields.
++ * @addr: address at which to unpack (passed and next address returned)
++ * @pos: bit position at which to unpack (passed and next position returned)
++ * @nrbits: number of bits of value to unpack (1-32)
++ *
++ * This functions returns the value unpacked.
++ */
++uint32_t ubifs_unpack_bits(uint8_t **addr, int *pos, int nrbits)
++{
++      const int k = 32 - nrbits;
++      uint8_t *p = *addr;
++      int b = *pos;
++      uint32_t val;
++
++      ubifs_assert(nrbits > 0);
++      ubifs_assert(nrbits <= 32);
++      ubifs_assert(*pos >= 0);
++      ubifs_assert(*pos < 8);
++      if (b) {
++              val = p[1] | ((uint32_t)p[2] << 8) | ((uint32_t)p[3] << 16) |
++                    ((uint32_t)p[4] << 24);
++              val <<= (8 - b);
++              val |= *p >> b;
++              nrbits += b;
++      } else
++              val = p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) |
++                    ((uint32_t)p[3] << 24);
++      val <<= k;
++      val >>= k;
++      b = nrbits & 7;
++      p += nrbits / 8;
++      *addr = p;
++      *pos = b;
++      ubifs_assert((val >> nrbits) == 0 || nrbits - b == 32);
++      return val;
++}
++
++/**
++ * ubifs_pack_pnode - pack all the bit fields of a pnode.
++ * @c: UBIFS file-system description object
++ * @buf: buffer into which to pack
++ * @pnode: pnode to pack
++ */
++void ubifs_pack_pnode(struct ubifs_info *c, void *buf,
++                    struct ubifs_pnode *pnode)
++{
++      uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
++      int i, pos = 0;
++      uint16_t crc;
++
++      pack_bits(&addr, &pos, UBIFS_LPT_PNODE, UBIFS_LPT_TYPE_BITS);
++      if (c->big_lpt)
++              pack_bits(&addr, &pos, pnode->num, c->pcnt_bits);
++      for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
++              pack_bits(&addr, &pos, pnode->lprops[i].free >> 3,
++                        c->space_bits);
++              pack_bits(&addr, &pos, pnode->lprops[i].dirty >> 3,
++                        c->space_bits);
++              if (pnode->lprops[i].flags & LPROPS_INDEX)
++                      pack_bits(&addr, &pos, 1, 1);
++              else
++                      pack_bits(&addr, &pos, 0, 1);
++      }
++      crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
++                  c->pnode_sz - UBIFS_LPT_CRC_BYTES);
++      addr = buf;
++      pos = 0;
++      pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
++}
++
++/**
++ * ubifs_pack_nnode - pack all the bit fields of a nnode.
++ * @c: UBIFS file-system description object
++ * @buf: buffer into which to pack
++ * @nnode: nnode to pack
++ */
++void ubifs_pack_nnode(struct ubifs_info *c, void *buf,
++                    struct ubifs_nnode *nnode)
++{
++      uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
++      int i, pos = 0;
++      uint16_t crc;
++
++      pack_bits(&addr, &pos, UBIFS_LPT_NNODE, UBIFS_LPT_TYPE_BITS);
++      if (c->big_lpt)
++              pack_bits(&addr, &pos, nnode->num, c->pcnt_bits);
++      for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
++              int lnum = nnode->nbranch[i].lnum;
++
++              if (lnum == 0)
++                      lnum = c->lpt_last + 1;
++              pack_bits(&addr, &pos, lnum - c->lpt_first, c->lpt_lnum_bits);
++              pack_bits(&addr, &pos, nnode->nbranch[i].offs,
++                        c->lpt_offs_bits);
++      }
++      crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
++                  c->nnode_sz - UBIFS_LPT_CRC_BYTES);
++      addr = buf;
++      pos = 0;
++      pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
++}
++
++/**
++ * ubifs_pack_ltab - pack the LPT's own lprops table.
++ * @c: UBIFS file-system description object
++ * @buf: buffer into which to pack
++ * @ltab: LPT's own lprops table to pack
++ */
++void ubifs_pack_ltab(struct ubifs_info *c, void *buf,
++                   struct ubifs_lpt_lprops *ltab)
++{
++      uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
++      int i, pos = 0;
++      uint16_t crc;
++
++      pack_bits(&addr, &pos, UBIFS_LPT_LTAB, UBIFS_LPT_TYPE_BITS);
++      for (i = 0; i < c->lpt_lebs; i++) {
++              pack_bits(&addr, &pos, ltab[i].free, c->lpt_spc_bits);
++              pack_bits(&addr, &pos, ltab[i].dirty, c->lpt_spc_bits);
++      }
++      crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
++                  c->ltab_sz - UBIFS_LPT_CRC_BYTES);
++      addr = buf;
++      pos = 0;
++      pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
++}
++
++/**
++ * ubifs_pack_lsave - pack the LPT's save table.
++ * @c: UBIFS file-system description object
++ * @buf: buffer into which to pack
++ * @lsave: LPT's save table to pack
++ */
++void ubifs_pack_lsave(struct ubifs_info *c, void *buf, int *lsave)
++{
++      uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
++      int i, pos = 0;
++      uint16_t crc;
++
++      pack_bits(&addr, &pos, UBIFS_LPT_LSAVE, UBIFS_LPT_TYPE_BITS);
++      for (i = 0; i < c->lsave_cnt; i++)
++              pack_bits(&addr, &pos, lsave[i], c->lnum_bits);
++      crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
++                  c->lsave_sz - UBIFS_LPT_CRC_BYTES);
++      addr = buf;
++      pos = 0;
++      pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
++}
++
++/**
++ * ubifs_add_lpt_dirt - add dirty space to LPT LEB properties.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number to which to add dirty space
++ * @dirty: amount of dirty space to add
++ */
++void ubifs_add_lpt_dirt(struct ubifs_info *c, int lnum, int dirty)
++{
++      if (!dirty || !lnum)
++              return;
++      dbg_lp("LEB %d add %d to %d",
++             lnum, dirty, c->ltab[lnum - c->lpt_first].dirty);
++      ubifs_assert(lnum >= c->lpt_first && lnum <= c->lpt_last);
++      c->ltab[lnum - c->lpt_first].dirty += dirty;
++}
++
++/**
++ * set_ltab - set LPT LEB properties.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number
++ * @free: amount of free space
++ * @dirty: amount of dirty space
++ */
++static void set_ltab(struct ubifs_info *c, int lnum, int free, int dirty)
++{
++      dbg_lp("LEB %d free %d dirty %d to %d %d",
++             lnum, c->ltab[lnum - c->lpt_first].free,
++             c->ltab[lnum - c->lpt_first].dirty, free, dirty);
++      ubifs_assert(lnum >= c->lpt_first && lnum <= c->lpt_last);
++      c->ltab[lnum - c->lpt_first].free = free;
++      c->ltab[lnum - c->lpt_first].dirty = dirty;
++}
++
++/**
++ * ubifs_add_nnode_dirt - add dirty space to LPT LEB properties.
++ * @c: UBIFS file-system description object
++ * @nnode: nnode for which to add dirt
++ */
++void ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode)
++{
++      struct ubifs_nnode *np = nnode->parent;
++
++      if (np)
++              ubifs_add_lpt_dirt(c, np->nbranch[nnode->iip].lnum,
++                                 c->nnode_sz);
++      else {
++              ubifs_add_lpt_dirt(c, c->lpt_lnum, c->nnode_sz);
++              if (!(c->lpt_drty_flgs & LTAB_DIRTY)) {
++                      c->lpt_drty_flgs |= LTAB_DIRTY;
++                      ubifs_add_lpt_dirt(c, c->ltab_lnum, c->ltab_sz);
++              }
++      }
++}
++
++/**
++ * add_pnode_dirt - add dirty space to LPT LEB properties.
++ * @c: UBIFS file-system description object
++ * @pnode: pnode for which to add dirt
++ */
++static void add_pnode_dirt(struct ubifs_info *c, struct ubifs_pnode *pnode)
++{
++      ubifs_add_lpt_dirt(c, pnode->parent->nbranch[pnode->iip].lnum,
++                         c->pnode_sz);
++}
++
++/**
++ * calc_nnode_num - calculate nnode number.
++ * @row: the row in the tree (root is zero)
++ * @col: the column in the row (leftmost is zero)
++ *
++ * The nnode number is a number that uniquely identifies a nnode and can be used
++ * easily to traverse the tree from the root to that nnode.
++ *
++ * This function calculates and returns the nnode number for the nnode at @row
++ * and @col.
++ */
++static int calc_nnode_num(int row, int col)
++{
++      int num, bits;
++
++      num = 1;
++      while (row--) {
++              bits = (col & (UBIFS_LPT_FANOUT - 1));
++              col >>= UBIFS_LPT_FANOUT_SHIFT;
++              num <<= UBIFS_LPT_FANOUT_SHIFT;
++              num |= bits;
++      }
++      return num;
++}
++
++/**
++ * calc_nnode_num_from_parent - calculate nnode number.
++ * @c: UBIFS file-system description object
++ * @parent: parent nnode
++ * @iip: index in parent
++ *
++ * The nnode number is a number that uniquely identifies a nnode and can be used
++ * easily to traverse the tree from the root to that nnode.
++ *
++ * This function calculates and returns the nnode number based on the parent's
++ * nnode number and the index in parent.
++ */
++static int calc_nnode_num_from_parent(struct ubifs_info *c,
++                                    struct ubifs_nnode *parent, int iip)
++{
++      int num, shft;
++
++      if (!parent)
++              return 1;
++      shft = (c->lpt_hght - parent->level) * UBIFS_LPT_FANOUT_SHIFT;
++      num = parent->num ^ (1 << shft);
++      num |= (UBIFS_LPT_FANOUT + iip) << shft;
++      return num;
++}
++
++/**
++ * calc_pnode_num_from_parent - calculate pnode number.
++ * @c: UBIFS file-system description object
++ * @parent: parent nnode
++ * @iip: index in parent
++ *
++ * The pnode number is a number that uniquely identifies a pnode and can be used
++ * easily to traverse the tree from the root to that pnode.
++ *
++ * This function calculates and returns the pnode number based on the parent's
++ * nnode number and the index in parent.
++ */
++static int calc_pnode_num_from_parent(struct ubifs_info *c,
++                                    struct ubifs_nnode *parent, int iip)
++{
++      int i, n = c->lpt_hght - 1, pnum = parent->num, num = 0;
++
++      for (i = 0; i < n; i++) {
++              num <<= UBIFS_LPT_FANOUT_SHIFT;
++              num |= pnum & (UBIFS_LPT_FANOUT - 1);
++              pnum >>= UBIFS_LPT_FANOUT_SHIFT;
++      }
++      num <<= UBIFS_LPT_FANOUT_SHIFT;
++      num |= iip;
++      return num;
++}
++
++/**
++ * ubifs_create_dflt_lpt - create default LPT.
++ * @c: UBIFS file-system description object
++ * @main_lebs: number of main area LEBs is passed and returned here
++ * @lpt_first: LEB number of first LPT LEB
++ * @lpt_lebs: number of LEBs for LPT is passed and returned here
++ * @big_lpt: use big LPT model is passed and returned here
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
++                        int *lpt_lebs, int *big_lpt)
++{
++      int lnum, err = 0, node_sz, iopos, i, j, cnt, len, alen, row;
++      int blnum, boffs, bsz, bcnt;
++      struct ubifs_pnode *pnode = NULL;
++      struct ubifs_nnode *nnode = NULL;
++      void *buf = NULL, *p;
++      struct ubifs_lpt_lprops *ltab = NULL;
++      int *lsave = NULL;
++
++      err = calc_dflt_lpt_geom(c, main_lebs, big_lpt);
++      if (err)
++              return err;
++      *lpt_lebs = c->lpt_lebs;
++
++      /* Needed by 'ubifs_pack_nnode()' and 'set_ltab()' */
++      c->lpt_first = lpt_first;
++      /* Needed by 'set_ltab()' */
++      c->lpt_last = lpt_first + c->lpt_lebs - 1;
++      /* Needed by 'ubifs_pack_lsave()' */
++      c->main_first = c->leb_cnt - *main_lebs;
++
++      lsave = kmalloc(sizeof(int) * c->lsave_cnt, GFP_KERNEL);
++      pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_KERNEL);
++      nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_KERNEL);
++      buf = vmalloc(c->leb_size);
++      ltab = vmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs);
++      if (!pnode || !nnode || !buf || !ltab || !lsave) {
++              err = -ENOMEM;
++              goto out;
++      }
++
++      ubifs_assert(!c->ltab);
++      c->ltab = ltab; /* Needed by set_ltab */
++
++      /* Initialize LPT's own lprops */
++      for (i = 0; i < c->lpt_lebs; i++) {
++              ltab[i].free = c->leb_size;
++              ltab[i].dirty = 0;
++              ltab[i].tgc = 0;
++              ltab[i].cmt = 0;
++      }
++
++      lnum = lpt_first;
++      p = buf;
++      /* Number of leaf nodes (pnodes) */
++      cnt = c->pnode_cnt;
++
++      /*
++       * The first pnode contains the LEB properties for the LEBs that contain
++       * the root inode node and the root index node of the index tree.
++       */
++      node_sz = ALIGN(ubifs_idx_node_sz(c, 1), 8);
++      iopos = ALIGN(node_sz, c->min_io_size);
++      pnode->lprops[0].free = c->leb_size - iopos;
++      pnode->lprops[0].dirty = iopos - node_sz;
++      pnode->lprops[0].flags = LPROPS_INDEX;
++
++      node_sz = UBIFS_INO_NODE_SZ;
++      iopos = ALIGN(node_sz, c->min_io_size);
++      pnode->lprops[1].free = c->leb_size - iopos;
++      pnode->lprops[1].dirty = iopos - node_sz;
++
++      for (i = 2; i < UBIFS_LPT_FANOUT; i++)
++              pnode->lprops[i].free = c->leb_size;
++
++      /* Add first pnode */
++      ubifs_pack_pnode(c, p, pnode);
++      p += c->pnode_sz;
++      len = c->pnode_sz;
++      pnode->num += 1;
++
++      /* Reset pnode values for remaining pnodes */
++      pnode->lprops[0].free = c->leb_size;
++      pnode->lprops[0].dirty = 0;
++      pnode->lprops[0].flags = 0;
++
++      pnode->lprops[1].free = c->leb_size;
++      pnode->lprops[1].dirty = 0;
++
++      /*
++       * To calculate the internal node branches, we keep information about
++       * the level below.
++       */
++      blnum = lnum; /* LEB number of level below */
++      boffs = 0; /* Offset of level below */
++      bcnt = cnt; /* Number of nodes in level below */
++      bsz = c->pnode_sz; /* Size of nodes in level below */
++
++      /* Add all remaining pnodes */
++      for (i = 1; i < cnt; i++) {
++              if (len + c->pnode_sz > c->leb_size) {
++                      alen = ALIGN(len, c->min_io_size);
++                      set_ltab(c, lnum, c->leb_size - alen, alen - len);
++                      memset(p, 0xff, alen - len);
++                      err = ubi_leb_change(c->ubi, lnum++, buf, alen,
++                                           UBI_SHORTTERM);
++                      if (err)
++                              goto out;
++                      p = buf;
++                      len = 0;
++              }
++              ubifs_pack_pnode(c, p, pnode);
++              p += c->pnode_sz;
++              len += c->pnode_sz;
++              /*
++               * pnodes are simply numbered left to right starting at zero,
++               * which means the pnode number can be used easily to traverse
++               * down the tree to the corresponding pnode.
++               */
++              pnode->num += 1;
++      }
++
++      row = 0;
++      for (i = UBIFS_LPT_FANOUT; cnt > i; i <<= UBIFS_LPT_FANOUT_SHIFT)
++              row += 1;
++      /* Add all nnodes, one level at a time */
++      while (1) {
++              /* Number of internal nodes (nnodes) at next level */
++              cnt = DIV_ROUND_UP(cnt, UBIFS_LPT_FANOUT);
++              for (i = 0; i < cnt; i++) {
++                      if (len + c->nnode_sz > c->leb_size) {
++                              alen = ALIGN(len, c->min_io_size);
++                              set_ltab(c, lnum, c->leb_size - alen,
++                                          alen - len);
++                              memset(p, 0xff, alen - len);
++                              err = ubi_leb_change(c->ubi, lnum++, buf, alen,
++                                                   UBI_SHORTTERM);
++                              if (err)
++                                      goto out;
++                              p = buf;
++                              len = 0;
++                      }
++                      /* Only 1 nnode at this level, so it is the root */
++                      if (cnt == 1) {
++                              c->lpt_lnum = lnum;
++                              c->lpt_offs = len;
++                      }
++                      /* Set branches to the level below */
++                      for (j = 0; j < UBIFS_LPT_FANOUT; j++) {
++                              if (bcnt) {
++                                      if (boffs + bsz > c->leb_size) {
++                                              blnum += 1;
++                                              boffs = 0;
++                                      }
++                                      nnode->nbranch[j].lnum = blnum;
++                                      nnode->nbranch[j].offs = boffs;
++                                      boffs += bsz;
++                                      bcnt--;
++                              } else {
++                                      nnode->nbranch[j].lnum = 0;
++                                      nnode->nbranch[j].offs = 0;
++                              }
++                      }
++                      nnode->num = calc_nnode_num(row, i);
++                      ubifs_pack_nnode(c, p, nnode);
++                      p += c->nnode_sz;
++                      len += c->nnode_sz;
++              }
++              /* Only 1 nnode at this level, so it is the root */
++              if (cnt == 1)
++                      break;
++              /* Update the information about the level below */
++              bcnt = cnt;
++              bsz = c->nnode_sz;
++              row -= 1;
++      }
++
++      if (*big_lpt) {
++              /* Need to add LPT's save table */
++              if (len + c->lsave_sz > c->leb_size) {
++                      alen = ALIGN(len, c->min_io_size);
++                      set_ltab(c, lnum, c->leb_size - alen, alen - len);
++                      memset(p, 0xff, alen - len);
++                      err = ubi_leb_change(c->ubi, lnum++, buf, alen,
++                                           UBI_SHORTTERM);
++                      if (err)
++                              goto out;
++                      p = buf;
++                      len = 0;
++              }
++
++              c->lsave_lnum = lnum;
++              c->lsave_offs = len;
++
++              for (i = 0; i < c->lsave_cnt && i < *main_lebs; i++)
++                      lsave[i] = c->main_first + i;
++              for (; i < c->lsave_cnt; i++)
++                      lsave[i] = c->main_first;
++
++              ubifs_pack_lsave(c, p, lsave);
++              p += c->lsave_sz;
++              len += c->lsave_sz;
++      }
++
++      /* Need to add LPT's own LEB properties table */
++      if (len + c->ltab_sz > c->leb_size) {
++              alen = ALIGN(len, c->min_io_size);
++              set_ltab(c, lnum, c->leb_size - alen, alen - len);
++              memset(p, 0xff, alen - len);
++              err = ubi_leb_change(c->ubi, lnum++, buf, alen, UBI_SHORTTERM);
++              if (err)
++                      goto out;
++              p = buf;
++              len = 0;
++      }
++
++      c->ltab_lnum = lnum;
++      c->ltab_offs = len;
++
++      /* Update ltab before packing it */
++      len += c->ltab_sz;
++      alen = ALIGN(len, c->min_io_size);
++      set_ltab(c, lnum, c->leb_size - alen, alen - len);
++
++      ubifs_pack_ltab(c, p, ltab);
++      p += c->ltab_sz;
++
++      /* Write remaining buffer */
++      memset(p, 0xff, alen - len);
++      err = ubi_leb_change(c->ubi, lnum, buf, alen, UBI_SHORTTERM);
++      if (err)
++              goto out;
++
++      c->nhead_lnum = lnum;
++      c->nhead_offs = ALIGN(len, c->min_io_size);
++
++      dbg_lp("space_bits %d", c->space_bits);
++      dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits);
++      dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits);
++      dbg_lp("lpt_spc_bits %d", c->lpt_spc_bits);
++      dbg_lp("pcnt_bits %d", c->pcnt_bits);
++      dbg_lp("lnum_bits %d", c->lnum_bits);
++      dbg_lp("pnode_sz %d", c->pnode_sz);
++      dbg_lp("nnode_sz %d", c->nnode_sz);
++      dbg_lp("ltab_sz %d", c->ltab_sz);
++      dbg_lp("lsave_sz %d", c->lsave_sz);
++      dbg_lp("lsave_cnt %d", c->lsave_cnt);
++      dbg_lp("lpt_hght %d", c->lpt_hght);
++      dbg_lp("big_lpt %d", c->big_lpt);
++      dbg_lp("LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs);
++      dbg_lp("LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs);
++      dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs);
++      if (c->big_lpt)
++              dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs);
++out:
++      c->ltab = NULL;
++      kfree(lsave);
++      vfree(ltab);
++      vfree(buf);
++      kfree(nnode);
++      kfree(pnode);
++      return err;
++}
++
++/**
++ * update_cats - add LEB properties of a pnode to LEB category lists and heaps.
++ * @c: UBIFS file-system description object
++ * @pnode: pnode
++ *
++ * When a pnode is loaded into memory, the LEB properties it contains are added,
++ * by this function, to the LEB category lists and heaps.
++ */
++static void update_cats(struct ubifs_info *c, struct ubifs_pnode *pnode)
++{
++      int i;
++
++      for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
++              int cat = pnode->lprops[i].flags & LPROPS_CAT_MASK;
++              int lnum = pnode->lprops[i].lnum;
++
++              if (!lnum)
++                      return;
++              ubifs_add_to_cat(c, &pnode->lprops[i], cat);
++      }
++}
++
++/**
++ * replace_cats - add LEB properties of a pnode to LEB category lists and heaps.
++ * @c: UBIFS file-system description object
++ * @old_pnode: pnode copied
++ * @new_pnode: pnode copy
++ *
++ * During commit it is sometimes necessary to copy a pnode
++ * (see dirty_cow_pnode).  When that happens, references in
++ * category lists and heaps must be replaced.  This function does that.
++ */
++static void replace_cats(struct ubifs_info *c, struct ubifs_pnode *old_pnode,
++                       struct ubifs_pnode *new_pnode)
++{
++      int i;
++
++      for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
++              if (!new_pnode->lprops[i].lnum)
++                      return;
++              ubifs_replace_cat(c, &old_pnode->lprops[i],
++                                &new_pnode->lprops[i]);
++      }
++}
++
++/**
++ * check_lpt_crc - check LPT node crc is correct.
++ * @c: UBIFS file-system description object
++ * @buf: buffer containing node
++ * @len: length of node
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int check_lpt_crc(void *buf, int len)
++{
++      int pos = 0;
++      uint8_t *addr = buf;
++      uint16_t crc, calc_crc;
++
++      crc = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_CRC_BITS);
++      calc_crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
++                       len - UBIFS_LPT_CRC_BYTES);
++      if (crc != calc_crc) {
++              ubifs_err("invalid crc in LPT node: crc %hx calc %hx", crc,
++                        calc_crc);
++              dbg_dump_stack();
++              return -EINVAL;
++      }
++      return 0;
++}
++
++/**
++ * check_lpt_type - check LPT node type is correct.
++ * @c: UBIFS file-system description object
++ * @addr: address of type bit field is passed and returned updated here
++ * @pos: position of type bit field is passed and returned updated here
++ * @type: expected type
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int check_lpt_type(uint8_t **addr, int *pos, int type)
++{
++      int node_type;
++
++      node_type = ubifs_unpack_bits(addr, pos, UBIFS_LPT_TYPE_BITS);
++      if (node_type != type) {
++              ubifs_err("invalid type (%d) in LPT node type %d", node_type,
++                        type);
++              dbg_dump_stack();
++              return -EINVAL;
++      }
++      return 0;
++}
++
++/**
++ * unpack_pnode - unpack a pnode.
++ * @c: UBIFS file-system description object
++ * @buf: buffer containing packed pnode to unpack
++ * @pnode: pnode structure to fill
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int unpack_pnode(struct ubifs_info *c, void *buf,
++                      struct ubifs_pnode *pnode)
++{
++      uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
++      int i, pos = 0, err;
++
++      err = check_lpt_type(&addr, &pos, UBIFS_LPT_PNODE);
++      if (err)
++              return err;
++      if (c->big_lpt)
++              pnode->num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits);
++      for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
++              struct ubifs_lprops * const lprops = &pnode->lprops[i];
++
++              lprops->free = ubifs_unpack_bits(&addr, &pos, c->space_bits);
++              lprops->free <<= 3;
++              lprops->dirty = ubifs_unpack_bits(&addr, &pos, c->space_bits);
++              lprops->dirty <<= 3;
++
++              if (ubifs_unpack_bits(&addr, &pos, 1))
++                      lprops->flags = LPROPS_INDEX;
++              else
++                      lprops->flags = 0;
++              lprops->flags |= ubifs_categorize_lprops(c, lprops);
++      }
++      err = check_lpt_crc(buf, c->pnode_sz);
++      return err;
++}
++
++/**
++ * unpack_nnode - unpack a nnode.
++ * @c: UBIFS file-system description object
++ * @buf: buffer containing packed nnode to unpack
++ * @nnode: nnode structure to fill
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int unpack_nnode(struct ubifs_info *c, void *buf,
++                      struct ubifs_nnode *nnode)
++{
++      uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
++      int i, pos = 0, err;
++
++      err = check_lpt_type(&addr, &pos, UBIFS_LPT_NNODE);
++      if (err)
++              return err;
++      if (c->big_lpt)
++              nnode->num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits);
++      for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
++              int lnum;
++
++              lnum = ubifs_unpack_bits(&addr, &pos, c->lpt_lnum_bits) +
++                     c->lpt_first;
++              if (lnum == c->lpt_last + 1)
++                      lnum = 0;
++              nnode->nbranch[i].lnum = lnum;
++              nnode->nbranch[i].offs = ubifs_unpack_bits(&addr, &pos,
++                                                   c->lpt_offs_bits);
++      }
++      err = check_lpt_crc(buf, c->nnode_sz);
++      return err;
++}
++
++/**
++ * unpack_ltab - unpack the LPT's own lprops table.
++ * @c: UBIFS file-system description object
++ * @buf: buffer from which to unpack
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int unpack_ltab(struct ubifs_info *c, void *buf)
++{
++      uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
++      int i, pos = 0, err;
++
++      err = check_lpt_type(&addr, &pos, UBIFS_LPT_LTAB);
++      if (err)
++              return err;
++      for (i = 0; i < c->lpt_lebs; i++) {
++              int free = ubifs_unpack_bits(&addr, &pos, c->lpt_spc_bits);
++              int dirty = ubifs_unpack_bits(&addr, &pos, c->lpt_spc_bits);
++
++              if (free < 0 || free > c->leb_size || dirty < 0 ||
++                  dirty > c->leb_size || free + dirty > c->leb_size)
++                      return -EINVAL;
++
++              c->ltab[i].free = free;
++              c->ltab[i].dirty = dirty;
++              c->ltab[i].tgc = 0;
++              c->ltab[i].cmt = 0;
++      }
++      err = check_lpt_crc(buf, c->ltab_sz);
++      return err;
++}
++
++/**
++ * unpack_lsave - unpack the LPT's save table.
++ * @c: UBIFS file-system description object
++ * @buf: buffer from which to unpack
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int unpack_lsave(struct ubifs_info *c, void *buf)
++{
++      uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
++      int i, pos = 0, err;
++
++      err = check_lpt_type(&addr, &pos, UBIFS_LPT_LSAVE);
++      if (err)
++              return err;
++      for (i = 0; i < c->lsave_cnt; i++) {
++              int lnum = ubifs_unpack_bits(&addr, &pos, c->lnum_bits);
++
++              if (lnum < c->main_first || lnum >= c->leb_cnt)
++                      return -EINVAL;
++              c->lsave[i] = lnum;
++      }
++      err = check_lpt_crc(buf, c->lsave_sz);
++      return err;
++}
++
++/**
++ * validate_nnode - validate a nnode.
++ * @c: UBIFS file-system description object
++ * @nnode: nnode to validate
++ * @parent: parent nnode (or NULL for the root nnode)
++ * @iip: index in parent
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int validate_nnode(struct ubifs_info *c, struct ubifs_nnode *nnode,
++                        struct ubifs_nnode *parent, int iip)
++{
++      int i, lvl, max_offs;
++
++      if (c->big_lpt) {
++              int num = calc_nnode_num_from_parent(c, parent, iip);
++
++              if (nnode->num != num)
++                      return -EINVAL;
++      }
++      lvl = parent ? parent->level - 1 : c->lpt_hght;
++      if (lvl < 1)
++              return -EINVAL;
++      if (lvl == 1)
++              max_offs = c->leb_size - c->pnode_sz;
++      else
++              max_offs = c->leb_size - c->nnode_sz;
++      for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
++              int lnum = nnode->nbranch[i].lnum;
++              int offs = nnode->nbranch[i].offs;
++
++              if (lnum == 0) {
++                      if (offs != 0)
++                              return -EINVAL;
++                      continue;
++              }
++              if (lnum < c->lpt_first || lnum > c->lpt_last)
++                      return -EINVAL;
++              if (offs < 0 || offs > max_offs)
++                      return -EINVAL;
++      }
++      return 0;
++}
++
++/**
++ * validate_pnode - validate a pnode.
++ * @c: UBIFS file-system description object
++ * @pnode: pnode to validate
++ * @parent: parent nnode
++ * @iip: index in parent
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int validate_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
++                        struct ubifs_nnode *parent, int iip)
++{
++      int i;
++
++      if (c->big_lpt) {
++              int num = calc_pnode_num_from_parent(c, parent, iip);
++
++              if (pnode->num != num)
++                      return -EINVAL;
++      }
++      for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
++              int free = pnode->lprops[i].free;
++              int dirty = pnode->lprops[i].dirty;
++
++              if (free < 0 || free > c->leb_size || free % c->min_io_size ||
++                  (free & 7))
++                      return -EINVAL;
++              if (dirty < 0 || dirty > c->leb_size || (dirty & 7))
++                      return -EINVAL;
++              if (dirty + free > c->leb_size)
++                      return -EINVAL;
++      }
++      return 0;
++}
++
++/**
++ * set_pnode_lnum - set LEB numbers on a pnode.
++ * @c: UBIFS file-system description object
++ * @pnode: pnode to update
++ *
++ * This function calculates the LEB numbers for the LEB properties it contains
++ * based on the pnode number.
++ */
++static void set_pnode_lnum(struct ubifs_info *c, struct ubifs_pnode *pnode)
++{
++      int i, lnum;
++
++      lnum = (pnode->num << UBIFS_LPT_FANOUT_SHIFT) + c->main_first;
++      for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
++              if (lnum >= c->leb_cnt)
++                      return;
++              pnode->lprops[i].lnum = lnum++;
++      }
++}
++
++/**
++ * ubifs_read_nnode - read a nnode from flash and link it to the tree in memory.
++ * @c: UBIFS file-system description object
++ * @parent: parent nnode (or NULL for the root)
++ * @iip: index in parent
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
++{
++      struct ubifs_nbranch *branch = NULL;
++      struct ubifs_nnode *nnode = NULL;
++      void *buf = c->lpt_nod_buf;
++      int err, lnum, offs;
++
++      if (parent) {
++              branch = &parent->nbranch[iip];
++              lnum = branch->lnum;
++              offs = branch->offs;
++      } else {
++              lnum = c->lpt_lnum;
++              offs = c->lpt_offs;
++      }
++      nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_NOFS);
++      if (!nnode) {
++              err = -ENOMEM;
++              goto out;
++      }
++      if (lnum == 0) {
++              /*
++               * This nnode was not written which just means that the LEB
++               * properties in the subtree below it describe empty LEBs. We
++               * make the nnode as though we had read it, which in fact means
++               * doing almost nothing.
++               */
++              if (c->big_lpt)
++                      nnode->num = calc_nnode_num_from_parent(c, parent, iip);
++      } else {
++              err = ubi_read(c->ubi, lnum, buf, offs, c->nnode_sz);
++              if (err)
++                      goto out;
++              err = unpack_nnode(c, buf, nnode);
++              if (err)
++                      goto out;
++      }
++      err = validate_nnode(c, nnode, parent, iip);
++      if (err)
++              goto out;
++      if (!c->big_lpt)
++              nnode->num = calc_nnode_num_from_parent(c, parent, iip);
++      if (parent) {
++              branch->nnode = nnode;
++              nnode->level = parent->level - 1;
++      } else {
++              c->nroot = nnode;
++              nnode->level = c->lpt_hght;
++      }
++      nnode->parent = parent;
++      nnode->iip = iip;
++      return 0;
++
++out:
++      ubifs_err("error %d reading nnode at %d:%d", err, lnum, offs);
++      kfree(nnode);
++      return err;
++}
++
++/**
++ * read_pnode - read a pnode from flash and link it to the tree in memory.
++ * @c: UBIFS file-system description object
++ * @parent: parent nnode
++ * @iip: index in parent
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
++{
++      struct ubifs_nbranch *branch;
++      struct ubifs_pnode *pnode = NULL;
++      void *buf = c->lpt_nod_buf;
++      int err, lnum, offs;
++
++      branch = &parent->nbranch[iip];
++      lnum = branch->lnum;
++      offs = branch->offs;
++      pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_NOFS);
++      if (!pnode) {
++              err = -ENOMEM;
++              goto out;
++      }
++      if (lnum == 0) {
++              /*
++               * This pnode was not written which just means that the LEB
++               * properties in it describe empty LEBs. We make the pnode as
++               * though we had read it.
++               */
++              int i;
++
++              if (c->big_lpt)
++                      pnode->num = calc_pnode_num_from_parent(c, parent, iip);
++              for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
++                      struct ubifs_lprops * const lprops = &pnode->lprops[i];
++
++                      lprops->free = c->leb_size;
++                      lprops->flags = ubifs_categorize_lprops(c, lprops);
++              }
++      } else {
++              err = ubi_read(c->ubi, lnum, buf, offs, c->pnode_sz);
++              if (err)
++                      goto out;
++              err = unpack_pnode(c, buf, pnode);
++              if (err)
++                      goto out;
++      }
++      err = validate_pnode(c, pnode, parent, iip);
++      if (err)
++              goto out;
++      if (!c->big_lpt)
++              pnode->num = calc_pnode_num_from_parent(c, parent, iip);
++      branch->pnode = pnode;
++      pnode->parent = parent;
++      pnode->iip = iip;
++      set_pnode_lnum(c, pnode);
++      c->pnodes_have += 1;
++      return 0;
++
++out:
++      ubifs_err("error %d reading pnode at %d:%d", err, lnum, offs);
++      dbg_dump_pnode(c, pnode, parent, iip);
++      dbg_msg("calc num: %d", calc_pnode_num_from_parent(c, parent, iip));
++      kfree(pnode);
++      return err;
++}
++
++/**
++ * read_ltab - read LPT's own lprops table.
++ * @c: UBIFS file-system description object
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int read_ltab(struct ubifs_info *c)
++{
++      int err;
++      void *buf;
++
++      buf = vmalloc(c->ltab_sz);
++      if (!buf)
++              return -ENOMEM;
++      err = ubi_read(c->ubi, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz);
++      if (err)
++              goto out;
++      err = unpack_ltab(c, buf);
++out:
++      vfree(buf);
++      return err;
++}
++
++/**
++ * read_lsave - read LPT's save table.
++ * @c: UBIFS file-system description object
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int read_lsave(struct ubifs_info *c)
++{
++      int err, i;
++      void *buf;
++
++      buf = vmalloc(c->lsave_sz);
++      if (!buf)
++              return -ENOMEM;
++      err = ubi_read(c->ubi, c->lsave_lnum, buf, c->lsave_offs, c->lsave_sz);
++      if (err)
++              goto out;
++      err = unpack_lsave(c, buf);
++      if (err)
++              goto out;
++      for (i = 0; i < c->lsave_cnt; i++) {
++              int lnum = c->lsave[i];
++
++              /*
++               * Due to automatic resizing, the values in the lsave table
++               * could be beyond the volume size - just ignore them.
++               */
++              if (lnum >= c->leb_cnt)
++                      continue;
++              ubifs_lpt_lookup(c, lnum);
++      }
++out:
++      vfree(buf);
++      return err;
++}
++
++/**
++ * ubifs_get_nnode - get a nnode.
++ * @c: UBIFS file-system description object
++ * @parent: parent nnode (or NULL for the root)
++ * @iip: index in parent
++ *
++ * This function returns a pointer to the nnode on success or a negative error
++ * code on failure.
++ */
++struct ubifs_nnode *ubifs_get_nnode(struct ubifs_info *c,
++                                  struct ubifs_nnode *parent, int iip)
++{
++      struct ubifs_nbranch *branch;
++      struct ubifs_nnode *nnode;
++      int err;
++
++      branch = &parent->nbranch[iip];
++      nnode = branch->nnode;
++      if (nnode)
++              return nnode;
++      err = ubifs_read_nnode(c, parent, iip);
++      if (err)
++              return ERR_PTR(err);
++      return branch->nnode;
++}
++
++/**
++ * ubifs_get_pnode - get a pnode.
++ * @c: UBIFS file-system description object
++ * @parent: parent nnode
++ * @iip: index in parent
++ *
++ * This function returns a pointer to the pnode on success or a negative error
++ * code on failure.
++ */
++struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c,
++                                  struct ubifs_nnode *parent, int iip)
++{
++      struct ubifs_nbranch *branch;
++      struct ubifs_pnode *pnode;
++      int err;
++
++      branch = &parent->nbranch[iip];
++      pnode = branch->pnode;
++      if (pnode)
++              return pnode;
++      err = read_pnode(c, parent, iip);
++      if (err)
++              return ERR_PTR(err);
++      update_cats(c, branch->pnode);
++      return branch->pnode;
++}
++
++/**
++ * ubifs_lpt_lookup - lookup LEB properties in the LPT.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number to lookup
++ *
++ * This function returns a pointer to the LEB properties on success or a
++ * negative error code on failure.
++ */
++struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum)
++{
++      int err, i, h, iip, shft;
++      struct ubifs_nnode *nnode;
++      struct ubifs_pnode *pnode;
++
++      if (!c->nroot) {
++              err = ubifs_read_nnode(c, NULL, 0);
++              if (err)
++                      return ERR_PTR(err);
++      }
++      nnode = c->nroot;
++      i = lnum - c->main_first;
++      shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
++      for (h = 1; h < c->lpt_hght; h++) {
++              iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
++              shft -= UBIFS_LPT_FANOUT_SHIFT;
++              nnode = ubifs_get_nnode(c, nnode, iip);
++              if (IS_ERR(nnode))
++                      return ERR_PTR(PTR_ERR(nnode));
++      }
++      iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
++      shft -= UBIFS_LPT_FANOUT_SHIFT;
++      pnode = ubifs_get_pnode(c, nnode, iip);
++      if (IS_ERR(pnode))
++              return ERR_PTR(PTR_ERR(pnode));
++      iip = (i & (UBIFS_LPT_FANOUT - 1));
++      dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum,
++             pnode->lprops[iip].free, pnode->lprops[iip].dirty,
++             pnode->lprops[iip].flags);
++      return &pnode->lprops[iip];
++}
++
++/**
++ * dirty_cow_nnode - ensure a nnode is not being committed.
++ * @c: UBIFS file-system description object
++ * @nnode: nnode to check
++ *
++ * Returns dirtied nnode on success or negative error code on failure.
++ */
++static struct ubifs_nnode *dirty_cow_nnode(struct ubifs_info *c,
++                                         struct ubifs_nnode *nnode)
++{
++      struct ubifs_nnode *n;
++      int i;
++
++      if (!test_bit(COW_CNODE, &nnode->flags)) {
++              /* nnode is not being committed */
++              if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) {
++                      c->dirty_nn_cnt += 1;
++                      ubifs_add_nnode_dirt(c, nnode);
++              }
++              return nnode;
++      }
++
++      /* nnode is being committed, so copy it */
++      n = kmalloc(sizeof(struct ubifs_nnode), GFP_NOFS);
++      if (unlikely(!n))
++              return ERR_PTR(-ENOMEM);
++
++      memcpy(n, nnode, sizeof(struct ubifs_nnode));
++      n->cnext = NULL;
++      __set_bit(DIRTY_CNODE, &n->flags);
++      __clear_bit(COW_CNODE, &n->flags);
++
++      /* The children now have new parent */
++      for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
++              struct ubifs_nbranch *branch = &n->nbranch[i];
++
++              if (branch->cnode)
++                      branch->cnode->parent = n;
++      }
++
++      ubifs_assert(!test_bit(OBSOLETE_CNODE, &nnode->flags));
++      __set_bit(OBSOLETE_CNODE, &nnode->flags);
++
++      c->dirty_nn_cnt += 1;
++      ubifs_add_nnode_dirt(c, nnode);
++      if (nnode->parent)
++              nnode->parent->nbranch[n->iip].nnode = n;
++      else
++              c->nroot = n;
++      return n;
++}
++
++/**
++ * dirty_cow_pnode - ensure a pnode is not being committed.
++ * @c: UBIFS file-system description object
++ * @pnode: pnode to check
++ *
++ * Returns dirtied pnode on success or negative error code on failure.
++ */
++static struct ubifs_pnode *dirty_cow_pnode(struct ubifs_info *c,
++                                         struct ubifs_pnode *pnode)
++{
++      struct ubifs_pnode *p;
++
++      if (!test_bit(COW_CNODE, &pnode->flags)) {
++              /* pnode is not being committed */
++              if (!test_and_set_bit(DIRTY_CNODE, &pnode->flags)) {
++                      c->dirty_pn_cnt += 1;
++                      add_pnode_dirt(c, pnode);
++              }
++              return pnode;
++      }
++
++      /* pnode is being committed, so copy it */
++      p = kmalloc(sizeof(struct ubifs_pnode), GFP_NOFS);
++      if (unlikely(!p))
++              return ERR_PTR(-ENOMEM);
++
++      memcpy(p, pnode, sizeof(struct ubifs_pnode));
++      p->cnext = NULL;
++      __set_bit(DIRTY_CNODE, &p->flags);
++      __clear_bit(COW_CNODE, &p->flags);
++      replace_cats(c, pnode, p);
++
++      ubifs_assert(!test_bit(OBSOLETE_CNODE, &pnode->flags));
++      __set_bit(OBSOLETE_CNODE, &pnode->flags);
++
++      c->dirty_pn_cnt += 1;
++      add_pnode_dirt(c, pnode);
++      pnode->parent->nbranch[p->iip].pnode = p;
++      return p;
++}
++
++/**
++ * ubifs_lpt_lookup_dirty - lookup LEB properties in the LPT.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number to lookup
++ *
++ * This function returns a pointer to the LEB properties on success or a
++ * negative error code on failure.
++ */
++struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum)
++{
++      int err, i, h, iip, shft;
++      struct ubifs_nnode *nnode;
++      struct ubifs_pnode *pnode;
++
++      if (!c->nroot) {
++              err = ubifs_read_nnode(c, NULL, 0);
++              if (err)
++                      return ERR_PTR(err);
++      }
++      nnode = c->nroot;
++      nnode = dirty_cow_nnode(c, nnode);
++      if (IS_ERR(nnode))
++              return ERR_PTR(PTR_ERR(nnode));
++      i = lnum - c->main_first;
++      shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
++      for (h = 1; h < c->lpt_hght; h++) {
++              iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
++              shft -= UBIFS_LPT_FANOUT_SHIFT;
++              nnode = ubifs_get_nnode(c, nnode, iip);
++              if (IS_ERR(nnode))
++                      return ERR_PTR(PTR_ERR(nnode));
++              nnode = dirty_cow_nnode(c, nnode);
++              if (IS_ERR(nnode))
++                      return ERR_PTR(PTR_ERR(nnode));
++      }
++      iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
++      shft -= UBIFS_LPT_FANOUT_SHIFT;
++      pnode = ubifs_get_pnode(c, nnode, iip);
++      if (IS_ERR(pnode))
++              return ERR_PTR(PTR_ERR(pnode));
++      pnode = dirty_cow_pnode(c, pnode);
++      if (IS_ERR(pnode))
++              return ERR_PTR(PTR_ERR(pnode));
++      iip = (i & (UBIFS_LPT_FANOUT - 1));
++      dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum,
++             pnode->lprops[iip].free, pnode->lprops[iip].dirty,
++             pnode->lprops[iip].flags);
++      ubifs_assert(test_bit(DIRTY_CNODE, &pnode->flags));
++      return &pnode->lprops[iip];
++}
++
++/**
++ * lpt_init_rd - initialize the LPT for reading.
++ * @c: UBIFS file-system description object
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int lpt_init_rd(struct ubifs_info *c)
++{
++      int err, i;
++
++      c->ltab = vmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs);
++      if (!c->ltab)
++              return -ENOMEM;
++
++      i = max_t(int, c->nnode_sz, c->pnode_sz);
++      c->lpt_nod_buf = kmalloc(i, GFP_KERNEL);
++      if (!c->lpt_nod_buf)
++              return -ENOMEM;
++
++      for (i = 0; i < LPROPS_HEAP_CNT; i++) {
++              c->lpt_heap[i].arr = kmalloc(sizeof(void *) * LPT_HEAP_SZ,
++                                           GFP_KERNEL);
++              if (!c->lpt_heap[i].arr)
++                      return -ENOMEM;
++              c->lpt_heap[i].cnt = 0;
++              c->lpt_heap[i].max_cnt = LPT_HEAP_SZ;
++      }
++
++      c->dirty_idx.arr = kmalloc(sizeof(void *) * LPT_HEAP_SZ, GFP_KERNEL);
++      if (!c->dirty_idx.arr)
++              return -ENOMEM;
++      c->dirty_idx.cnt = 0;
++      c->dirty_idx.max_cnt = LPT_HEAP_SZ;
++
++      err = read_ltab(c);
++      if (err)
++              return err;
++
++      dbg_lp("space_bits %d", c->space_bits);
++      dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits);
++      dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits);
++      dbg_lp("lpt_spc_bits %d", c->lpt_spc_bits);
++      dbg_lp("pcnt_bits %d", c->pcnt_bits);
++      dbg_lp("lnum_bits %d", c->lnum_bits);
++      dbg_lp("pnode_sz %d", c->pnode_sz);
++      dbg_lp("nnode_sz %d", c->nnode_sz);
++      dbg_lp("ltab_sz %d", c->ltab_sz);
++      dbg_lp("lsave_sz %d", c->lsave_sz);
++      dbg_lp("lsave_cnt %d", c->lsave_cnt);
++      dbg_lp("lpt_hght %d", c->lpt_hght);
++      dbg_lp("big_lpt %d", c->big_lpt);
++      dbg_lp("LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs);
++      dbg_lp("LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs);
++      dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs);
++      if (c->big_lpt)
++              dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs);
++
++      return 0;
++}
++
++/**
++ * lpt_init_wr - initialize the LPT for writing.
++ * @c: UBIFS file-system description object
++ *
++ * 'lpt_init_rd()' must have been called already.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int lpt_init_wr(struct ubifs_info *c)
++{
++      int err, i;
++
++      c->ltab_cmt = vmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs);
++      if (!c->ltab_cmt)
++              return -ENOMEM;
++
++      c->lpt_buf = vmalloc(c->leb_size);
++      if (!c->lpt_buf)
++              return -ENOMEM;
++
++      if (c->big_lpt) {
++              c->lsave = kmalloc(sizeof(int) * c->lsave_cnt, GFP_NOFS);
++              if (!c->lsave)
++                      return -ENOMEM;
++              err = read_lsave(c);
++              if (err)
++                      return err;
++      }
++
++      for (i = 0; i < c->lpt_lebs; i++)
++              if (c->ltab[i].free == c->leb_size) {
++                      err = ubifs_leb_unmap(c, i + c->lpt_first);
++                      if (err)
++                              return err;
++              }
++
++      return 0;
++}
++
++/**
++ * ubifs_lpt_init - initialize the LPT.
++ * @c: UBIFS file-system description object
++ * @rd: whether to initialize lpt for reading
++ * @wr: whether to initialize lpt for writing
++ *
++ * For mounting 'rw', @rd and @wr are both true. For mounting 'ro', @rd is true
++ * and @wr is false. For mounting from 'ro' to 'rw', @rd is false and @wr is
++ * true.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++int ubifs_lpt_init(struct ubifs_info *c, int rd, int wr)
++{
++      int err;
++
++      if (rd) {
++              err = lpt_init_rd(c);
++              if (err)
++                      return err;
++      }
++
++      if (wr) {
++              err = lpt_init_wr(c);
++              if (err)
++                      return err;
++      }
++
++      return 0;
++}
++
++/**
++ * struct lpt_scan_node - somewhere to put nodes while we scan LPT.
++ * @nnode: where to keep a nnode
++ * @pnode: where to keep a pnode
++ * @cnode: where to keep a cnode
++ * @in_tree: is the node in the tree in memory
++ * @ptr.nnode: pointer to the nnode (if it is an nnode) which may be here or in
++ * the tree
++ * @ptr.pnode: ditto for pnode
++ * @ptr.cnode: ditto for cnode
++ */
++struct lpt_scan_node {
++      union {
++              struct ubifs_nnode nnode;
++              struct ubifs_pnode pnode;
++              struct ubifs_cnode cnode;
++      };
++      int in_tree;
++      union {
++              struct ubifs_nnode *nnode;
++              struct ubifs_pnode *pnode;
++              struct ubifs_cnode *cnode;
++      } ptr;
++};
++
++/**
++ * scan_get_nnode - for the scan, get a nnode from either the tree or flash.
++ * @c: the UBIFS file-system description object
++ * @path: where to put the nnode
++ * @parent: parent of the nnode
++ * @iip: index in parent of the nnode
++ *
++ * This function returns a pointer to the nnode on success or a negative error
++ * code on failure.
++ */
++static struct ubifs_nnode *scan_get_nnode(struct ubifs_info *c,
++                                        struct lpt_scan_node *path,
++                                        struct ubifs_nnode *parent, int iip)
++{
++      struct ubifs_nbranch *branch;
++      struct ubifs_nnode *nnode;
++      void *buf = c->lpt_nod_buf;
++      int err;
++
++      branch = &parent->nbranch[iip];
++      nnode = branch->nnode;
++      if (nnode) {
++              path->in_tree = 1;
++              path->ptr.nnode = nnode;
++              return nnode;
++      }
++      nnode = &path->nnode;
++      path->in_tree = 0;
++      path->ptr.nnode = nnode;
++      memset(nnode, 0, sizeof(struct ubifs_nnode));
++      if (branch->lnum == 0) {
++              /*
++               * This nnode was not written which just means that the LEB
++               * properties in the subtree below it describe empty LEBs. We
++               * make the nnode as though we had read it, which in fact means
++               * doing almost nothing.
++               */
++              if (c->big_lpt)
++                      nnode->num = calc_nnode_num_from_parent(c, parent, iip);
++      } else {
++              err = ubi_read(c->ubi, branch->lnum, buf, branch->offs,
++                             c->nnode_sz);
++              if (err)
++                      return ERR_PTR(err);
++              err = unpack_nnode(c, buf, nnode);
++              if (err)
++                      return ERR_PTR(err);
++      }
++      err = validate_nnode(c, nnode, parent, iip);
++      if (err)
++              return ERR_PTR(err);
++      if (!c->big_lpt)
++              nnode->num = calc_nnode_num_from_parent(c, parent, iip);
++      nnode->level = parent->level - 1;
++      nnode->parent = parent;
++      nnode->iip = iip;
++      return nnode;
++}
++
++/**
++ * scan_get_pnode - for the scan, get a pnode from either the tree or flash.
++ * @c: the UBIFS file-system description object
++ * @path: where to put the pnode
++ * @parent: parent of the pnode
++ * @iip: index in parent of the pnode
++ *
++ * This function returns a pointer to the pnode on success or a negative error
++ * code on failure.
++ */
++static struct ubifs_pnode *scan_get_pnode(struct ubifs_info *c,
++                                        struct lpt_scan_node *path,
++                                        struct ubifs_nnode *parent, int iip)
++{
++      struct ubifs_nbranch *branch;
++      struct ubifs_pnode *pnode;
++      void *buf = c->lpt_nod_buf;
++      int err;
++
++      branch = &parent->nbranch[iip];
++      pnode = branch->pnode;
++      if (pnode) {
++              path->in_tree = 1;
++              path->ptr.pnode = pnode;
++              return pnode;
++      }
++      pnode = &path->pnode;
++      path->in_tree = 0;
++      path->ptr.pnode = pnode;
++      memset(pnode, 0, sizeof(struct ubifs_pnode));
++      if (branch->lnum == 0) {
++              /*
++               * This pnode was not written which just means that the LEB
++               * properties in it describe empty LEBs. We make the pnode as
++               * though we had read it.
++               */
++              int i;
++
++              if (c->big_lpt)
++                      pnode->num = calc_pnode_num_from_parent(c, parent, iip);
++              for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
++                      struct ubifs_lprops * const lprops = &pnode->lprops[i];
++
++                      lprops->free = c->leb_size;
++                      lprops->flags = ubifs_categorize_lprops(c, lprops);
++              }
++      } else {
++              ubifs_assert(branch->lnum >= c->lpt_first &&
++                           branch->lnum <= c->lpt_last);
++              ubifs_assert(branch->offs >= 0 && branch->offs < c->leb_size);
++              err = ubi_read(c->ubi, branch->lnum, buf, branch->offs,
++                             c->pnode_sz);
++              if (err)
++                      return ERR_PTR(err);
++              err = unpack_pnode(c, buf, pnode);
++              if (err)
++                      return ERR_PTR(err);
++      }
++      err = validate_pnode(c, pnode, parent, iip);
++      if (err)
++              return ERR_PTR(err);
++      if (!c->big_lpt)
++              pnode->num = calc_pnode_num_from_parent(c, parent, iip);
++      pnode->parent = parent;
++      pnode->iip = iip;
++      set_pnode_lnum(c, pnode);
++      return pnode;
++}
++
++/**
++ * ubifs_lpt_scan_nolock - scan the LPT.
++ * @c: the UBIFS file-system description object
++ * @start_lnum: LEB number from which to start scanning
++ * @end_lnum: LEB number at which to stop scanning
++ * @scan_cb: callback function called for each lprops
++ * @data: data to be passed to the callback function
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++int ubifs_lpt_scan_nolock(struct ubifs_info *c, int start_lnum, int end_lnum,
++                        ubifs_lpt_scan_callback scan_cb, void *data)
++{
++      int err = 0, i, h, iip, shft;
++      struct ubifs_nnode *nnode;
++      struct ubifs_pnode *pnode;
++      struct lpt_scan_node *path;
++
++      if (start_lnum == -1) {
++              start_lnum = end_lnum + 1;
++              if (start_lnum >= c->leb_cnt)
++                      start_lnum = c->main_first;
++      }
++
++      ubifs_assert(start_lnum >= c->main_first && start_lnum < c->leb_cnt);
++      ubifs_assert(end_lnum >= c->main_first && end_lnum < c->leb_cnt);
++
++      if (!c->nroot) {
++              err = ubifs_read_nnode(c, NULL, 0);
++              if (err)
++                      return err;
++      }
++
++      path = kmalloc(sizeof(struct lpt_scan_node) * (c->lpt_hght + 1),
++                     GFP_NOFS);
++      if (!path)
++              return -ENOMEM;
++
++      path[0].ptr.nnode = c->nroot;
++      path[0].in_tree = 1;
++again:
++      /* Descend to the pnode containing start_lnum */
++      nnode = c->nroot;
++      i = start_lnum - c->main_first;
++      shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
++      for (h = 1; h < c->lpt_hght; h++) {
++              iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
++              shft -= UBIFS_LPT_FANOUT_SHIFT;
++              nnode = scan_get_nnode(c, path + h, nnode, iip);
++              if (IS_ERR(nnode)) {
++                      err = PTR_ERR(nnode);
++                      goto out;
++              }
++      }
++      iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
++      shft -= UBIFS_LPT_FANOUT_SHIFT;
++      pnode = scan_get_pnode(c, path + h, nnode, iip);
++      if (IS_ERR(pnode)) {
++              err = PTR_ERR(pnode);
++              goto out;
++      }
++      iip = (i & (UBIFS_LPT_FANOUT - 1));
++
++      /* Loop for each lprops */
++      while (1) {
++              struct ubifs_lprops *lprops = &pnode->lprops[iip];
++              int ret, lnum = lprops->lnum;
++
++              ret = scan_cb(c, lprops, path[h].in_tree, data);
++              if (ret < 0) {
++                      err = ret;
++                      goto out;
++              }
++              if (ret & LPT_SCAN_ADD) {
++                      /* Add all the nodes in path to the tree in memory */
++                      for (h = 1; h < c->lpt_hght; h++) {
++                              const size_t sz = sizeof(struct ubifs_nnode);
++                              struct ubifs_nnode *parent;
++
++                              if (path[h].in_tree)
++                                      continue;
++                              nnode = kmalloc(sz, GFP_NOFS);
++                              if (!nnode) {
++                                      err = -ENOMEM;
++                                      goto out;
++                              }
++                              memcpy(nnode, &path[h].nnode, sz);
++                              parent = nnode->parent;
++                              parent->nbranch[nnode->iip].nnode = nnode;
++                              path[h].ptr.nnode = nnode;
++                              path[h].in_tree = 1;
++                              path[h + 1].cnode.parent = nnode;
++                      }
++                      if (path[h].in_tree)
++                              ubifs_ensure_cat(c, lprops);
++                      else {
++                              const size_t sz = sizeof(struct ubifs_pnode);
++                              struct ubifs_nnode *parent;
++
++                              pnode = kmalloc(sz, GFP_NOFS);
++                              if (!pnode) {
++                                      err = -ENOMEM;
++                                      goto out;
++                              }
++                              memcpy(pnode, &path[h].pnode, sz);
++                              parent = pnode->parent;
++                              parent->nbranch[pnode->iip].pnode = pnode;
++                              path[h].ptr.pnode = pnode;
++                              path[h].in_tree = 1;
++                              update_cats(c, pnode);
++                              c->pnodes_have += 1;
++                      }
++                      err = dbg_check_lpt_nodes(c, (struct ubifs_cnode *)
++                                                c->nroot, 0, 0);
++                      if (err)
++                              goto out;
++                      err = dbg_check_cats(c);
++                      if (err)
++                              goto out;
++              }
++              if (ret & LPT_SCAN_STOP) {
++                      err = 0;
++                      break;
++              }
++              /* Get the next lprops */
++              if (lnum == end_lnum) {
++                      /*
++                       * We got to the end without finding what we were
++                       * looking for
++                       */
++                      err = -ENOSPC;
++                      goto out;
++              }
++              if (lnum + 1 >= c->leb_cnt) {
++                      /* Wrap-around to the beginning */
++                      start_lnum = c->main_first;
++                      goto again;
++              }
++              if (iip + 1 < UBIFS_LPT_FANOUT) {
++                      /* Next lprops is in the same pnode */
++                      iip += 1;
++                      continue;
++              }
++              /* We need to get the next pnode. Go up until we can go right */
++              iip = pnode->iip;
++              while (1) {
++                      h -= 1;
++                      ubifs_assert(h >= 0);
++                      nnode = path[h].ptr.nnode;
++                      if (iip + 1 < UBIFS_LPT_FANOUT)
++                              break;
++                      iip = nnode->iip;
++              }
++              /* Go right */
++              iip += 1;
++              /* Descend to the pnode */
++              h += 1;
++              for (; h < c->lpt_hght; h++) {
++                      nnode = scan_get_nnode(c, path + h, nnode, iip);
++                      if (IS_ERR(nnode)) {
++                              err = PTR_ERR(nnode);
++                              goto out;
++                      }
++                      iip = 0;
++              }
++              pnode = scan_get_pnode(c, path + h, nnode, iip);
++              if (IS_ERR(pnode)) {
++                      err = PTR_ERR(pnode);
++                      goto out;
++              }
++              iip = 0;
++      }
++out:
++      kfree(path);
++      return err;
++}
++
++#ifdef CONFIG_UBIFS_FS_DEBUG
++
++/**
++ * dbg_chk_pnode - check a pnode.
++ * @c: the UBIFS file-system description object
++ * @pnode: pnode to check
++ * @col: pnode column
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int dbg_chk_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
++                       int col)
++{
++      int i;
++
++      if (pnode->num != col) {
++              dbg_err("pnode num %d expected %d parent num %d iip %d",
++                      pnode->num, col, pnode->parent->num, pnode->iip);
++              return -EINVAL;
++      }
++      for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
++              struct ubifs_lprops *lp, *lprops = &pnode->lprops[i];
++              int lnum = (pnode->num << UBIFS_LPT_FANOUT_SHIFT) + i +
++                         c->main_first;
++              int found, cat = lprops->flags & LPROPS_CAT_MASK;
++              struct ubifs_lpt_heap *heap;
++              struct list_head *list = NULL;
++
++              if (lnum >= c->leb_cnt)
++                      continue;
++              if (lprops->lnum != lnum) {
++                      dbg_err("bad LEB number %d expected %d",
++                              lprops->lnum, lnum);
++                      return -EINVAL;
++              }
++              if (lprops->flags & LPROPS_TAKEN) {
++                      if (cat != LPROPS_UNCAT) {
++                              dbg_err("LEB %d taken but not uncat %d",
++                                      lprops->lnum, cat);
++                              return -EINVAL;
++                      }
++                      continue;
++              }
++              if (lprops->flags & LPROPS_INDEX) {
++                      switch (cat) {
++                      case LPROPS_UNCAT:
++                      case LPROPS_DIRTY_IDX:
++                      case LPROPS_FRDI_IDX:
++                              break;
++                      default:
++                              dbg_err("LEB %d index but cat %d",
++                                      lprops->lnum, cat);
++                              return -EINVAL;
++                      }
++              } else {
++                      switch (cat) {
++                      case LPROPS_UNCAT:
++                      case LPROPS_DIRTY:
++                      case LPROPS_FREE:
++                      case LPROPS_EMPTY:
++                      case LPROPS_FREEABLE:
++                              break;
++                      default:
++                              dbg_err("LEB %d not index but cat %d",
++                                      lprops->lnum, cat);
++                              return -EINVAL;
++                      }
++              }
++              switch (cat) {
++              case LPROPS_UNCAT:
++                      list = &c->uncat_list;
++                      break;
++              case LPROPS_EMPTY:
++                      list = &c->empty_list;
++                      break;
++              case LPROPS_FREEABLE:
++                      list = &c->freeable_list;
++                      break;
++              case LPROPS_FRDI_IDX:
++                      list = &c->frdi_idx_list;
++                      break;
++              }
++              found = 0;
++              switch (cat) {
++              case LPROPS_DIRTY:
++              case LPROPS_DIRTY_IDX:
++              case LPROPS_FREE:
++                      heap = &c->lpt_heap[cat - 1];
++                      if (lprops->hpos < heap->cnt &&
++                          heap->arr[lprops->hpos] == lprops)
++                              found = 1;
++                      break;
++              case LPROPS_UNCAT:
++              case LPROPS_EMPTY:
++              case LPROPS_FREEABLE:
++              case LPROPS_FRDI_IDX:
++                      list_for_each_entry(lp, list, list)
++                              if (lprops == lp) {
++                                      found = 1;
++                                      break;
++                              }
++                      break;
++              }
++              if (!found) {
++                      dbg_err("LEB %d cat %d not found in cat heap/list",
++                              lprops->lnum, cat);
++                      return -EINVAL;
++              }
++              switch (cat) {
++              case LPROPS_EMPTY:
++                      if (lprops->free != c->leb_size) {
++                              dbg_err("LEB %d cat %d free %d dirty %d",
++                                      lprops->lnum, cat, lprops->free,
++                                      lprops->dirty);
++                              return -EINVAL;
++                      }
++              case LPROPS_FREEABLE:
++              case LPROPS_FRDI_IDX:
++                      if (lprops->free + lprops->dirty != c->leb_size) {
++                              dbg_err("LEB %d cat %d free %d dirty %d",
++                                      lprops->lnum, cat, lprops->free,
++                                      lprops->dirty);
++                              return -EINVAL;
++                      }
++              }
++      }
++      return 0;
++}
++
++/**
++ * dbg_check_lpt_nodes - check nnodes and pnodes.
++ * @c: the UBIFS file-system description object
++ * @cnode: next cnode (nnode or pnode) to check
++ * @row: row of cnode (root is zero)
++ * @col: column of cnode (leftmost is zero)
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
++                      int row, int col)
++{
++      struct ubifs_nnode *nnode, *nn;
++      struct ubifs_cnode *cn;
++      int num, iip = 0, err;
++
++      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++              return 0;
++
++      while (cnode) {
++              ubifs_assert(row >= 0);
++              nnode = cnode->parent;
++              if (cnode->level) {
++                      /* cnode is a nnode */
++                      num = calc_nnode_num(row, col);
++                      if (cnode->num != num) {
++                              dbg_err("nnode num %d expected %d "
++                                      "parent num %d iip %d", cnode->num, num,
++                                      (nnode ? nnode->num : 0), cnode->iip);
++                              return -EINVAL;
++                      }
++                      nn = (struct ubifs_nnode *)cnode;
++                      while (iip < UBIFS_LPT_FANOUT) {
++                              cn = nn->nbranch[iip].cnode;
++                              if (cn) {
++                                      /* Go down */
++                                      row += 1;
++                                      col <<= UBIFS_LPT_FANOUT_SHIFT;
++                                      col += iip;
++                                      iip = 0;
++                                      cnode = cn;
++                                      break;
++                              }
++                              /* Go right */
++                              iip += 1;
++                      }
++                      if (iip < UBIFS_LPT_FANOUT)
++                              continue;
++              } else {
++                      struct ubifs_pnode *pnode;
++
++                      /* cnode is a pnode */
++                      pnode = (struct ubifs_pnode *)cnode;
++                      err = dbg_chk_pnode(c, pnode, col);
++                      if (err)
++                              return err;
++              }
++              /* Go up and to the right */
++              row -= 1;
++              col >>= UBIFS_LPT_FANOUT_SHIFT;
++              iip = cnode->iip + 1;
++              cnode = (struct ubifs_cnode *)nnode;
++      }
++      return 0;
++}
++
++#endif /* CONFIG_UBIFS_FS_DEBUG */
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/lpt_commit.c avr32-2.6/fs/ubifs/lpt_commit.c
+--- linux-2.6.25.6/fs/ubifs/lpt_commit.c       1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/lpt_commit.c    2008-06-12 15:09:45.475816115 +0200
+@@ -0,0 +1,1631 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Adrian Hunter
++ *          Artem Bityutskiy (Битюцкий Артём)
++ */
++
++/*
++ * This file implements commit-related functionality of the LEB properties
++ * subsystem.
++ */
++
++#include <linux/crc16.h>
++#include "ubifs.h"
++
++/**
++ * first_dirty_cnode - find first dirty cnode.
++ * @c: UBIFS file-system description object
++ * @nnode: nnode at which to start
++ *
++ * This function returns the first dirty cnode or %NULL if there is not one.
++ */
++static struct ubifs_cnode *first_dirty_cnode(struct ubifs_nnode *nnode)
++{
++      ubifs_assert(nnode);
++      while (1) {
++              int i, cont = 0;
++
++              for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
++                      struct ubifs_cnode *cnode;
++
++                      cnode = nnode->nbranch[i].cnode;
++                      if (cnode &&
++                          test_bit(DIRTY_CNODE, &cnode->flags)) {
++                              if (cnode->level == 0)
++                                      return cnode;
++                              nnode = (struct ubifs_nnode *)cnode;
++                              cont = 1;
++                              break;
++                      }
++              }
++              if (!cont)
++                      return (struct ubifs_cnode *)nnode;
++      }
++}
++
++/**
++ * next_dirty_cnode - find next dirty cnode.
++ * @cnode: cnode from which to begin searching
++ *
++ * This function returns the next dirty cnode or %NULL if there is not one.
++ */
++static struct ubifs_cnode *next_dirty_cnode(struct ubifs_cnode *cnode)
++{
++      struct ubifs_nnode *nnode;
++      int i;
++
++      ubifs_assert(cnode);
++      nnode = cnode->parent;
++      if (!nnode)
++              return NULL;
++      for (i = cnode->iip + 1; i < UBIFS_LPT_FANOUT; i++) {
++              cnode = nnode->nbranch[i].cnode;
++              if (cnode && test_bit(DIRTY_CNODE, &cnode->flags)) {
++                      if (cnode->level == 0)
++                              return cnode; /* cnode is a pnode */
++                      /* cnode is a nnode */
++                      return first_dirty_cnode((struct ubifs_nnode *)cnode);
++              }
++      }
++      return (struct ubifs_cnode *)nnode;
++}
++
++/**
++ * get_cnodes_to_commit - create list of dirty cnodes to commit.
++ * @c: UBIFS file-system description object
++ *
++ * This function returns the number of cnodes to commit.
++ */
++static int get_cnodes_to_commit(struct ubifs_info *c)
++{
++      struct ubifs_cnode *cnode, *cnext;
++      int cnt = 0;
++
++      if (!c->nroot)
++              return 0;
++
++      if (!test_bit(DIRTY_CNODE, &c->nroot->flags))
++              return 0;
++
++      c->lpt_cnext = first_dirty_cnode(c->nroot);
++      cnode = c->lpt_cnext;
++      if (!cnode)
++              return 0;
++      cnt += 1;
++      while (1) {
++              ubifs_assert(!test_bit(COW_ZNODE, &cnode->flags));
++              __set_bit(COW_ZNODE, &cnode->flags);
++              cnext = next_dirty_cnode(cnode);
++              if (!cnext) {
++                      cnode->cnext = c->lpt_cnext;
++                      break;
++              }
++              cnode->cnext = cnext;
++              cnode = cnext;
++              cnt += 1;
++      }
++      dbg_cmt("committing %d cnodes", cnt);
++      dbg_lp("committing %d cnodes", cnt);
++      ubifs_assert(cnt == c->dirty_nn_cnt + c->dirty_pn_cnt);
++      return cnt;
++}
++
++/**
++ * upd_ltab - update LPT LEB properties.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number
++ * @free: amount of free space
++ * @dirty: amount of dirty space to add
++ */
++static void upd_ltab(struct ubifs_info *c, int lnum, int free, int dirty)
++{
++      dbg_lp("LEB %d free %d dirty %d to %d +%d",
++             lnum, c->ltab[lnum - c->lpt_first].free,
++             c->ltab[lnum - c->lpt_first].dirty, free, dirty);
++      ubifs_assert(lnum >= c->lpt_first && lnum <= c->lpt_last);
++      c->ltab[lnum - c->lpt_first].free = free;
++      c->ltab[lnum - c->lpt_first].dirty += dirty;
++}
++
++/**
++ * alloc_lpt_leb - allocate an LPT LEB that is empty.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number is passed and returned here
++ *
++ * This function finds the next empty LEB in the ltab starting from @lnum. If a
++ * an empty LEB is found it is returned in @lnum and the function returns %0.
++ * Otherwise the function returns -ENOSPC.  Note however, that LPT is designed
++ * never to run out of space.
++ */
++static int alloc_lpt_leb(struct ubifs_info *c, int *lnum)
++{
++      int i, n;
++
++      n = *lnum - c->lpt_first + 1;
++      for (i = n; i < c->lpt_lebs; i++) {
++              if (c->ltab[i].tgc || c->ltab[i].cmt)
++                      continue;
++              if (c->ltab[i].free == c->leb_size) {
++                      c->ltab[i].cmt = 1;
++                      *lnum = i + c->lpt_first;
++                      return 0;
++              }
++      }
++
++      for (i = 0; i < n; i++) {
++              if (c->ltab[i].tgc || c->ltab[i].cmt)
++                      continue;
++              if (c->ltab[i].free == c->leb_size) {
++                      c->ltab[i].cmt = 1;
++                      *lnum = i + c->lpt_first;
++                      return 0;
++              }
++      }
++      dbg_err("last LEB %d", *lnum);
++      dump_stack();
++      return -ENOSPC;
++}
++
++/**
++ * layout_cnodes - layout cnodes for commit.
++ * @c: UBIFS file-system description object
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int layout_cnodes(struct ubifs_info *c)
++{
++      int lnum, offs, len, alen, done_lsave, done_ltab, err;
++      struct ubifs_cnode *cnode;
++
++      cnode = c->lpt_cnext;
++      if (!cnode)
++              return 0;
++      lnum = c->nhead_lnum;
++      offs = c->nhead_offs;
++      /* Try to place lsave and ltab nicely */
++      done_lsave = !c->big_lpt;
++      done_ltab = 0;
++      if (!done_lsave && offs + c->lsave_sz <= c->leb_size) {
++              done_lsave = 1;
++              c->lsave_lnum = lnum;
++              c->lsave_offs = offs;
++              offs += c->lsave_sz;
++      }
++
++      if (offs + c->ltab_sz <= c->leb_size) {
++              done_ltab = 1;
++              c->ltab_lnum = lnum;
++              c->ltab_offs = offs;
++              offs += c->ltab_sz;
++      }
++
++      do {
++              if (cnode->level) {
++                      len = c->nnode_sz;
++                      c->dirty_nn_cnt -= 1;
++              } else {
++                      len = c->pnode_sz;
++                      c->dirty_pn_cnt -= 1;
++              }
++              while (offs + len > c->leb_size) {
++                      alen = ALIGN(offs, c->min_io_size);
++                      upd_ltab(c, lnum, c->leb_size - alen, alen - offs);
++                      err = alloc_lpt_leb(c, &lnum);
++                      if (err)
++                              return err;
++                      offs = 0;
++                      ubifs_assert(lnum >= c->lpt_first &&
++                                   lnum <= c->lpt_last);
++                      /* Try to place lsave and ltab nicely */
++                      if (!done_lsave) {
++                              done_lsave = 1;
++                              c->lsave_lnum = lnum;
++                              c->lsave_offs = offs;
++                              offs += c->lsave_sz;
++                              continue;
++                      }
++                      if (!done_ltab) {
++                              done_ltab = 1;
++                              c->ltab_lnum = lnum;
++                              c->ltab_offs = offs;
++                              offs += c->ltab_sz;
++                              continue;
++                      }
++                      break;
++              }
++              if (cnode->parent) {
++                      cnode->parent->nbranch[cnode->iip].lnum = lnum;
++                      cnode->parent->nbranch[cnode->iip].offs = offs;
++              } else {
++                      c->lpt_lnum = lnum;
++                      c->lpt_offs = offs;
++              }
++              offs += len;
++              cnode = cnode->cnext;
++      } while (cnode && cnode != c->lpt_cnext);
++
++      /* Make sure to place LPT's save table */
++      if (!done_lsave) {
++              if (offs + c->lsave_sz > c->leb_size) {
++                      alen = ALIGN(offs, c->min_io_size);
++                      upd_ltab(c, lnum, c->leb_size - alen, alen - offs);
++                      err = alloc_lpt_leb(c, &lnum);
++                      if (err)
++                              return err;
++                      offs = 0;
++                      ubifs_assert(lnum >= c->lpt_first &&
++                                   lnum <= c->lpt_last);
++              }
++              done_lsave = 1;
++              c->lsave_lnum = lnum;
++              c->lsave_offs = offs;
++              offs += c->lsave_sz;
++      }
++
++      /* Make sure to place LPT's own lprops table */
++      if (!done_ltab) {
++              if (offs + c->ltab_sz > c->leb_size) {
++                      alen = ALIGN(offs, c->min_io_size);
++                      upd_ltab(c, lnum, c->leb_size - alen, alen - offs);
++                      err = alloc_lpt_leb(c, &lnum);
++                      if (err)
++                              return err;
++                      offs = 0;
++                      ubifs_assert(lnum >= c->lpt_first &&
++                                   lnum <= c->lpt_last);
++              }
++              done_ltab = 1;
++              c->ltab_lnum = lnum;
++              c->ltab_offs = offs;
++              offs += c->ltab_sz;
++      }
++
++      alen = ALIGN(offs, c->min_io_size);
++      upd_ltab(c, lnum, c->leb_size - alen, alen - offs);
++      return 0;
++}
++
++/**
++ * realloc_lpt_leb - allocate an LPT LEB that is empty.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number is passed and returned here
++ *
++ * This function duplicates exactly the results of the function alloc_lpt_leb.
++ * It is used during end commit to reallocate the same LEB numbers that were
++ * allocated by alloc_lpt_leb during start commit.
++ *
++ * This function finds the next LEB that was allocated by the alloc_lpt_leb
++ * function starting from @lnum. If a LEB is found it is returned in @lnum and
++ * the function returns %0. Otherwise the function returns -ENOSPC.
++ * Note however, that LPT is designed never to run out of space.
++ */
++static int realloc_lpt_leb(struct ubifs_info *c, int *lnum)
++{
++      int i, n;
++
++      n = *lnum - c->lpt_first + 1;
++      for (i = n; i < c->lpt_lebs; i++)
++              if (c->ltab[i].cmt) {
++                      c->ltab[i].cmt = 0;
++                      *lnum = i + c->lpt_first;
++                      return 0;
++              }
++
++      for (i = 0; i < n; i++)
++              if (c->ltab[i].cmt) {
++                      c->ltab[i].cmt = 0;
++                      *lnum = i + c->lpt_first;
++                      return 0;
++              }
++      dbg_err("last LEB %d", *lnum);
++      dump_stack();
++      return -ENOSPC;
++}
++
++/**
++ * write_cnodes - write cnodes for commit.
++ * @c: UBIFS file-system description object
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int write_cnodes(struct ubifs_info *c)
++{
++      int lnum, offs, len, from, err, wlen, alen, done_ltab, done_lsave;
++      struct ubifs_cnode *cnode;
++      void *buf = c->lpt_buf;
++
++      cnode = c->lpt_cnext;
++      if (!cnode)
++              return 0;
++      lnum = c->nhead_lnum;
++      offs = c->nhead_offs;
++      from = offs;
++      /* Ensure empty LEB is unmapped */
++      if (offs == 0) {
++              err = ubifs_leb_unmap(c, lnum);
++              if (err)
++                      return err;
++      }
++      /* Try to place lsave and ltab nicely */
++      done_lsave = !c->big_lpt;
++      done_ltab = 0;
++      if (!done_lsave && offs + c->lsave_sz <= c->leb_size) {
++              done_lsave = 1;
++              ubifs_pack_lsave(c, buf + offs, c->lsave);
++              offs += c->lsave_sz;
++      }
++
++      if (offs + c->ltab_sz <= c->leb_size) {
++              done_ltab = 1;
++              ubifs_pack_ltab(c, buf + offs, c->ltab_cmt);
++              offs += c->ltab_sz;
++      }
++
++      /* Loop for each cnode */
++      do {
++              if (cnode->level)
++                      len = c->nnode_sz;
++              else
++                      len = c->pnode_sz;
++              while (offs + len > c->leb_size) {
++                      wlen = offs - from;
++                      if (wlen) {
++                              alen = ALIGN(wlen, c->min_io_size);
++                              memset(buf + offs, 0xff, alen - wlen);
++                              err = ubifs_leb_write(c, lnum, buf + from, from,
++                                                     alen, UBI_SHORTTERM);
++                              if (err)
++                                      return err;
++                      }
++                      err = realloc_lpt_leb(c, &lnum);
++                      if (err)
++                              return err;
++                      offs = 0;
++                      from = 0;
++                      ubifs_assert(lnum >= c->lpt_first &&
++                                   lnum <= c->lpt_last);
++                      err = ubifs_leb_unmap(c, lnum);
++                      if (err)
++                              return err;
++                      /* Try to place lsave and ltab nicely */
++                      if (!done_lsave) {
++                              done_lsave = 1;
++                              ubifs_pack_lsave(c, buf + offs, c->lsave);
++                              offs += c->lsave_sz;
++                              continue;
++                      }
++                      if (!done_ltab) {
++                              done_ltab = 1;
++                              ubifs_pack_ltab(c, buf + offs, c->ltab_cmt);
++                              offs += c->ltab_sz;
++                              continue;
++                      }
++                      break;
++              }
++              if (cnode->level)
++                      ubifs_pack_nnode(c, buf + offs,
++                                       (struct ubifs_nnode *)cnode);
++              else
++                      ubifs_pack_pnode(c, buf + offs,
++                                       (struct ubifs_pnode *)cnode);
++              /*
++               * The reason for the barriers is the same as in case of TNC.
++               * See comment in 'write_index()'. 'dirty_cow_nnode()' and
++               * 'dirty_cow_pnode()' are the functions for which this is
++               * important.
++               */
++              clear_bit(DIRTY_CNODE, &cnode->flags);
++              smp_mb__before_clear_bit();
++              clear_bit(COW_ZNODE, &cnode->flags);
++              smp_mb__after_clear_bit();
++              offs += len;
++              cnode = cnode->cnext;
++      } while (cnode && cnode != c->lpt_cnext);
++
++      /* Make sure to place LPT's save table */
++      if (!done_lsave) {
++              if (offs + c->lsave_sz > c->leb_size) {
++                      wlen = offs - from;
++                      alen = ALIGN(wlen, c->min_io_size);
++                      memset(buf + offs, 0xff, alen - wlen);
++                      err = ubifs_leb_write(c, lnum, buf + from, from, alen,
++                                            UBI_SHORTTERM);
++                      if (err)
++                              return err;
++                      err = realloc_lpt_leb(c, &lnum);
++                      if (err)
++                              return err;
++                      offs = 0;
++                      ubifs_assert(lnum >= c->lpt_first &&
++                                   lnum <= c->lpt_last);
++                      err = ubifs_leb_unmap(c, lnum);
++                      if (err)
++                              return err;
++              }
++              done_lsave = 1;
++              ubifs_pack_lsave(c, buf + offs, c->lsave);
++              offs += c->lsave_sz;
++      }
++
++      /* Make sure to place LPT's own lprops table */
++      if (!done_ltab) {
++              if (offs + c->ltab_sz > c->leb_size) {
++                      wlen = offs - from;
++                      alen = ALIGN(wlen, c->min_io_size);
++                      memset(buf + offs, 0xff, alen - wlen);
++                      err = ubifs_leb_write(c, lnum, buf + from, from, alen,
++                                            UBI_SHORTTERM);
++                      if (err)
++                              return err;
++                      err = realloc_lpt_leb(c, &lnum);
++                      if (err)
++                              return err;
++                      offs = 0;
++                      ubifs_assert(lnum >= c->lpt_first &&
++                                   lnum <= c->lpt_last);
++                      err = ubifs_leb_unmap(c, lnum);
++                      if (err)
++                              return err;
++              }
++              done_ltab = 1;
++              ubifs_pack_ltab(c, buf + offs, c->ltab_cmt);
++              offs += c->ltab_sz;
++      }
++
++      /* Write remaining data in buffer */
++      wlen = offs - from;
++      alen = ALIGN(wlen, c->min_io_size);
++      memset(buf + offs, 0xff, alen - wlen);
++      err = ubifs_leb_write(c, lnum, buf + from, from, alen, UBI_SHORTTERM);
++      if (err)
++              return err;
++      c->nhead_lnum = lnum;
++      c->nhead_offs = ALIGN(offs, c->min_io_size);
++
++      dbg_lp("LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs);
++      dbg_lp("LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs);
++      dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs);
++      if (c->big_lpt)
++              dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs);
++      return 0;
++}
++
++/**
++ * next_pnode - find next pnode.
++ * @c: UBIFS file-system description object
++ * @pnode: pnode
++ *
++ * This function returns the next pnode or %NULL if there are no more pnodes.
++ */
++static struct ubifs_pnode *next_pnode(struct ubifs_info *c,
++                                    struct ubifs_pnode *pnode)
++{
++      struct ubifs_nnode *nnode;
++      int iip;
++
++      /* Try to go right */
++      nnode = pnode->parent;
++      iip = pnode->iip + 1;
++      if (iip < UBIFS_LPT_FANOUT) {
++              /* We assume here that LEB zero is never an LPT LEB */
++              if (nnode->nbranch[iip].lnum)
++                      return ubifs_get_pnode(c, nnode, iip);
++              else
++                      return NULL;
++      }
++
++      /* Go up while can't go right */
++      do {
++              iip = nnode->iip + 1;
++              nnode = nnode->parent;
++              if (!nnode)
++                      return NULL;
++              /* We assume here that LEB zero is never an LPT LEB */
++      } while (iip >= UBIFS_LPT_FANOUT || !nnode->nbranch[iip].lnum);
++
++      /* Go right */
++      nnode = ubifs_get_nnode(c, nnode, iip);
++      if (IS_ERR(nnode))
++              return (void *)nnode;
++
++      /* Go down to level 1 */
++      while (nnode->level > 1) {
++              nnode = ubifs_get_nnode(c, nnode, 0);
++              if (IS_ERR(nnode))
++                      return (void *)nnode;
++      }
++
++      return ubifs_get_pnode(c, nnode, 0);
++}
++
++/**
++ * pnode_lookup - lookup a pnode in the LPT.
++ * @c: UBIFS file-system description object
++ * @i: pnode number (0 to main_lebs - 1)
++ *
++ * This function returns a pointer to the pnode on success or a negative
++ * error code on failure.
++ */
++static struct ubifs_pnode *pnode_lookup(struct ubifs_info *c, int i)
++{
++      int err, h, iip, shft;
++      struct ubifs_nnode *nnode;
++
++      if (!c->nroot) {
++              err = ubifs_read_nnode(c, NULL, 0);
++              if (err)
++                      return ERR_PTR(err);
++      }
++      i <<= UBIFS_LPT_FANOUT_SHIFT;
++      nnode = c->nroot;
++      shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
++      for (h = 1; h < c->lpt_hght; h++) {
++              iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
++              shft -= UBIFS_LPT_FANOUT_SHIFT;
++              nnode = ubifs_get_nnode(c, nnode, iip);
++              if (IS_ERR(nnode))
++                      return ERR_PTR(PTR_ERR(nnode));
++      }
++      iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
++      return ubifs_get_pnode(c, nnode, iip);
++}
++
++/**
++ * add_pnode_dirt - add dirty space to LPT LEB properties.
++ * @c: UBIFS file-system description object
++ * @pnode: pnode for which to add dirt
++ */
++static void add_pnode_dirt(struct ubifs_info *c, struct ubifs_pnode *pnode)
++{
++      ubifs_add_lpt_dirt(c, pnode->parent->nbranch[pnode->iip].lnum,
++                         c->pnode_sz);
++}
++
++/**
++ * do_make_pnode_dirty - mark a pnode dirty.
++ * @c: UBIFS file-system description object
++ * @pnode: pnode to mark dirty
++ */
++static void do_make_pnode_dirty(struct ubifs_info *c, struct ubifs_pnode *pnode)
++{
++      /* Assumes cnext list is empty i.e. not called during commit */
++      if (!test_and_set_bit(DIRTY_CNODE, &pnode->flags)) {
++              struct ubifs_nnode *nnode;
++
++              c->dirty_pn_cnt += 1;
++              add_pnode_dirt(c, pnode);
++              /* Mark parent and ancestors dirty too */
++              nnode = pnode->parent;
++              while (nnode) {
++                      if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) {
++                              c->dirty_nn_cnt += 1;
++                              ubifs_add_nnode_dirt(c, nnode);
++                              nnode = nnode->parent;
++                      } else
++                              break;
++              }
++      }
++}
++
++/**
++ * make_tree_dirty - mark the entire LEB properties tree dirty.
++ * @c: UBIFS file-system description object
++ *
++ * This function is used by the "small" LPT model to cause the entire LEB
++ * properties tree to be written.  The "small" LPT model does not use LPT
++ * garbage collection because it is more efficient to write the entire tree
++ * (because it is small).
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int make_tree_dirty(struct ubifs_info *c)
++{
++      struct ubifs_pnode *pnode;
++
++      pnode = pnode_lookup(c, 0);
++      while (pnode) {
++              do_make_pnode_dirty(c, pnode);
++              pnode = next_pnode(c, pnode);
++              if (IS_ERR(pnode))
++                      return PTR_ERR(pnode);
++      }
++      return 0;
++}
++
++/**
++ * need_write_all - determine if the LPT area is running out of free space.
++ * @c: UBIFS file-system description object
++ *
++ * This function returns %1 if the LPT area is running out of free space and %0
++ * if it is not.
++ */
++static int need_write_all(struct ubifs_info *c)
++{
++      long long free = 0;
++      int i;
++
++      for (i = 0; i < c->lpt_lebs; i++) {
++              if (i + c->lpt_first == c->nhead_lnum)
++                      free += c->leb_size - c->nhead_offs;
++              else if (c->ltab[i].free == c->leb_size)
++                      free += c->leb_size;
++              else if (c->ltab[i].free + c->ltab[i].dirty == c->leb_size)
++                      free += c->leb_size;
++      }
++      /* Less than twice the size left */
++      if (free <= c->lpt_sz * 2)
++              return 1;
++      return 0;
++}
++
++/**
++ * lpt_tgc_start - start trivial garbage collection of LPT LEBs.
++ * @c: UBIFS file-system description object
++ *
++ * LPT trivial garbage collection is where a LPT LEB contains only dirty and
++ * free space and so may be reused as soon as the next commit is completed.
++ * This function is called during start commit to mark LPT LEBs for trivial GC.
++ */
++static void lpt_tgc_start(struct ubifs_info *c)
++{
++      int i;
++
++      for (i = 0; i < c->lpt_lebs; i++) {
++              if (i + c->lpt_first == c->nhead_lnum)
++                      continue;
++              if (c->ltab[i].dirty > 0 &&
++                  c->ltab[i].free + c->ltab[i].dirty == c->leb_size) {
++                      c->ltab[i].tgc = 1;
++                      c->ltab[i].free = c->leb_size;
++                      c->ltab[i].dirty = 0;
++                      dbg_lp("LEB %d", i + c->lpt_first);
++              }
++      }
++}
++
++/**
++ * lpt_tgc_end - end trivial garbage collection of LPT LEBs.
++ * @c: UBIFS file-system description object
++ *
++ * LPT trivial garbage collection is where a LPT LEB contains only dirty and
++ * free space and so may be reused as soon as the next commit is completed.
++ * This function is called after the commit is completed (master node has been
++ * written) and unmaps LPT LEBs that were marked for trivial GC.
++ */
++static int lpt_tgc_end(struct ubifs_info *c)
++{
++      int i, err;
++
++      for (i = 0; i < c->lpt_lebs; i++)
++              if (c->ltab[i].tgc) {
++                      err = ubifs_leb_unmap(c, i + c->lpt_first);
++                      if (err)
++                              return err;
++                      c->ltab[i].tgc = 0;
++                      dbg_lp("LEB %d", i + c->lpt_first);
++              }
++      return 0;
++}
++
++/**
++ * populate_lsave - fill the lsave array with important LEB numbers.
++ * @c: the UBIFS file-system description object
++ *
++ * This function is only called for the "big" model. It records a small number
++ * of LEB numbers of important LEBs.  Important LEBs are ones that are (from
++ * most important to least important): empty, freeable, freeable index, dirty
++ * index, dirty or free. Upon mount, we read this list of LEB numbers and bring
++ * their pnodes into memory.  That will stop us from having to scan the LPT
++ * straight away. For the "small" model we assume that scanning the LPT is no
++ * big deal.
++ */
++static void populate_lsave(struct ubifs_info *c)
++{
++      struct ubifs_lprops *lprops;
++      struct ubifs_lpt_heap *heap;
++      int i, cnt = 0;
++
++      ubifs_assert(c->big_lpt);
++      if (!(c->lpt_drty_flgs & LSAVE_DIRTY)) {
++              c->lpt_drty_flgs |= LSAVE_DIRTY;
++              ubifs_add_lpt_dirt(c, c->lsave_lnum, c->lsave_sz);
++      }
++      list_for_each_entry(lprops, &c->empty_list, list) {
++              c->lsave[cnt++] = lprops->lnum;
++              if (cnt >= c->lsave_cnt)
++                      return;
++      }
++      list_for_each_entry(lprops, &c->freeable_list, list) {
++              c->lsave[cnt++] = lprops->lnum;
++              if (cnt >= c->lsave_cnt)
++                      return;
++      }
++      list_for_each_entry(lprops, &c->frdi_idx_list, list) {
++              c->lsave[cnt++] = lprops->lnum;
++              if (cnt >= c->lsave_cnt)
++                      return;
++      }
++      heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1];
++      for (i = 0; i < heap->cnt; i++) {
++              c->lsave[cnt++] = heap->arr[i]->lnum;
++              if (cnt >= c->lsave_cnt)
++                      return;
++      }
++      heap = &c->lpt_heap[LPROPS_DIRTY - 1];
++      for (i = 0; i < heap->cnt; i++) {
++              c->lsave[cnt++] = heap->arr[i]->lnum;
++              if (cnt >= c->lsave_cnt)
++                      return;
++      }
++      heap = &c->lpt_heap[LPROPS_FREE - 1];
++      for (i = 0; i < heap->cnt; i++) {
++              c->lsave[cnt++] = heap->arr[i]->lnum;
++              if (cnt >= c->lsave_cnt)
++                      return;
++      }
++      /* Fill it up completely */
++      while (cnt < c->lsave_cnt)
++              c->lsave[cnt++] = c->main_first;
++}
++
++/**
++ * ubifs_lpt_start_commit - UBIFS commit starts.
++ * @c: the UBIFS file-system description object
++ *
++ * This function has to be called when UBIFS starts the commit operation.
++ * This function "freezes" all currently dirty LEB properties and does not
++ * change them anymore. Further changes are saved and tracked separately
++ * because they are not part of this commit. This function returns zero in case
++ * of success and a negative error code in case of failure.
++ */
++int ubifs_lpt_start_commit(struct ubifs_info *c)
++{
++      int err, cnt;
++
++      dbg_lp("");
++
++      mutex_lock(&c->lp_mutex);
++      err = dbg_check_ltab(c);
++      if (err)
++              goto out;
++
++      lpt_tgc_start(c);
++
++      if (!c->dirty_pn_cnt) {
++              dbg_cmt("no cnodes to commit");
++              err = 0;
++              goto out;
++      }
++
++      if (!c->big_lpt && need_write_all(c)) {
++              /* If needed, write everything */
++              err = make_tree_dirty(c);
++              if (err)
++                      goto out;
++              lpt_tgc_start(c);
++      }
++
++      if (c->big_lpt)
++              populate_lsave(c);
++
++      cnt = get_cnodes_to_commit(c);
++      ubifs_assert(cnt != 0);
++
++      err = layout_cnodes(c);
++      if (err)
++              goto out;
++
++      /* Copy the LPT's own lprops for end commit to write */
++      memcpy(c->ltab_cmt, c->ltab,
++             sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs);
++      c->lpt_drty_flgs &= ~(LTAB_DIRTY | LSAVE_DIRTY);
++
++out:
++      mutex_unlock(&c->lp_mutex);
++      return err;
++}
++
++/**
++ * free_obsolete_cnodes - free obsolete cnodes for commit end.
++ * @c: UBIFS file-system description object
++ */
++static void free_obsolete_cnodes(struct ubifs_info *c)
++{
++      struct ubifs_cnode *cnode, *cnext;
++
++      cnext = c->lpt_cnext;
++      if (!cnext)
++              return;
++      do {
++              cnode = cnext;
++              cnext = cnode->cnext;
++              if (test_bit(OBSOLETE_CNODE, &cnode->flags))
++                      kfree(cnode);
++              else
++                      cnode->cnext = NULL;
++      } while (cnext != c->lpt_cnext);
++      c->lpt_cnext = NULL;
++}
++
++/**
++ * ubifs_lpt_end_commit - finish the commit operation.
++ * @c: the UBIFS file-system description object
++ *
++ * This function has to be called when the commit operation finishes. It
++ * flushes the changes which were "frozen" by 'ubifs_lprops_start_commit()' to
++ * the media. Returns zero in case of success and a negative error code in case
++ * of failure.
++ */
++int ubifs_lpt_end_commit(struct ubifs_info *c)
++{
++      int err;
++
++      dbg_lp("");
++
++      if (!c->lpt_cnext)
++              return 0;
++
++      err = write_cnodes(c);
++      if (err)
++              return err;
++
++      mutex_lock(&c->lp_mutex);
++      free_obsolete_cnodes(c);
++      mutex_unlock(&c->lp_mutex);
++
++      return 0;
++}
++
++/**
++ * nnode_lookup - lookup a nnode in the LPT.
++ * @c: UBIFS file-system description object
++ * @i: nnode number
++ *
++ * This function returns a pointer to the nnode on success or a negative
++ * error code on failure.
++ */
++static struct ubifs_nnode *nnode_lookup(struct ubifs_info *c, int i)
++{
++      int err, iip;
++      struct ubifs_nnode *nnode;
++
++      if (!c->nroot) {
++              err = ubifs_read_nnode(c, NULL, 0);
++              if (err)
++                      return ERR_PTR(err);
++      }
++      nnode = c->nroot;
++      while (1) {
++              iip = i & (UBIFS_LPT_FANOUT - 1);
++              i >>= UBIFS_LPT_FANOUT_SHIFT;
++              if (!i)
++                      break;
++              nnode = ubifs_get_nnode(c, nnode, iip);
++              if (IS_ERR(nnode))
++                      return nnode;
++      }
++      return nnode;
++}
++
++/**
++ * make_nnode_dirty - find a nnode and, if found, make it dirty.
++ * @c: UBIFS file-system description object
++ * @node_num: nnode number of nnode to make dirty
++ * @lnum: LEB number where nnode was written
++ * @offs: offset where nnode was written
++ *
++ * This function is used by LPT garbage collection.  LPT garbage collection is
++ * used only for the "big" LPT model (c->big_lpt == 1).  Garbage collection
++ * simply involves marking all the nodes in the LEB being garbage-collected as
++ * dirty.  The dirty nodes are written next commit, after which the LEB is free
++ * to be reused.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int make_nnode_dirty(struct ubifs_info *c, int node_num, int lnum,
++                          int offs)
++{
++      struct ubifs_nnode *nnode;
++
++      nnode = nnode_lookup(c, node_num);
++      if (IS_ERR(nnode))
++              return PTR_ERR(nnode);
++      if (nnode->parent) {
++              struct ubifs_nbranch *branch;
++
++              branch = &nnode->parent->nbranch[nnode->iip];
++              if (branch->lnum != lnum || branch->offs != offs)
++                      return 0; /* nnode is obsolete */
++      } else if (c->lpt_lnum != lnum || c->lpt_offs != offs)
++                      return 0; /* nnode is obsolete */
++      /* Assumes cnext list is empty i.e. not called during commit */
++      if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) {
++              c->dirty_nn_cnt += 1;
++              ubifs_add_nnode_dirt(c, nnode);
++              /* Mark parent and ancestors dirty too */
++              nnode = nnode->parent;
++              while (nnode) {
++                      if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) {
++                              c->dirty_nn_cnt += 1;
++                              ubifs_add_nnode_dirt(c, nnode);
++                              nnode = nnode->parent;
++                      } else
++                              break;
++              }
++      }
++      return 0;
++}
++
++/**
++ * make_pnode_dirty - find a pnode and, if found, make it dirty.
++ * @c: UBIFS file-system description object
++ * @node_num: pnode number of pnode to make dirty
++ * @lnum: LEB number where pnode was written
++ * @offs: offset where pnode was written
++ *
++ * This function is used by LPT garbage collection.  LPT garbage collection is
++ * used only for the "big" LPT model (c->big_lpt == 1).  Garbage collection
++ * simply involves marking all the nodes in the LEB being garbage-collected as
++ * dirty.  The dirty nodes are written next commit, after which the LEB is free
++ * to be reused.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int make_pnode_dirty(struct ubifs_info *c, int node_num, int lnum,
++                          int offs)
++{
++      struct ubifs_pnode *pnode;
++      struct ubifs_nbranch *branch;
++
++      pnode = pnode_lookup(c, node_num);
++      if (IS_ERR(pnode))
++              return PTR_ERR(pnode);
++      branch = &pnode->parent->nbranch[pnode->iip];
++      if (branch->lnum != lnum || branch->offs != offs)
++              return 0;
++      do_make_pnode_dirty(c, pnode);
++      return 0;
++}
++
++/**
++ * make_ltab_dirty - make ltab node dirty.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number where ltab was written
++ * @offs: offset where ltab was written
++ *
++ * This function is used by LPT garbage collection.  LPT garbage collection is
++ * used only for the "big" LPT model (c->big_lpt == 1).  Garbage collection
++ * simply involves marking all the nodes in the LEB being garbage-collected as
++ * dirty.  The dirty nodes are written next commit, after which the LEB is free
++ * to be reused.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int make_ltab_dirty(struct ubifs_info *c, int lnum, int offs)
++{
++      if (lnum != c->ltab_lnum || offs != c->ltab_offs)
++              return 0; /* This ltab node is obsolete */
++      if (!(c->lpt_drty_flgs & LTAB_DIRTY)) {
++              c->lpt_drty_flgs |= LTAB_DIRTY;
++              ubifs_add_lpt_dirt(c, c->ltab_lnum, c->ltab_sz);
++      }
++      return 0;
++}
++
++/**
++ * make_lsave_dirty - make lsave node dirty.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number where lsave was written
++ * @offs: offset where lsave was written
++ *
++ * This function is used by LPT garbage collection.  LPT garbage collection is
++ * used only for the "big" LPT model (c->big_lpt == 1).  Garbage collection
++ * simply involves marking all the nodes in the LEB being garbage-collected as
++ * dirty.  The dirty nodes are written next commit, after which the LEB is free
++ * to be reused.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int make_lsave_dirty(struct ubifs_info *c, int lnum, int offs)
++{
++      if (lnum != c->lsave_lnum || offs != c->lsave_offs)
++              return 0; /* This lsave node is obsolete */
++      if (!(c->lpt_drty_flgs & LSAVE_DIRTY)) {
++              c->lpt_drty_flgs |= LSAVE_DIRTY;
++              ubifs_add_lpt_dirt(c, c->lsave_lnum, c->lsave_sz);
++      }
++      return 0;
++}
++
++/**
++ * make_node_dirty - make node dirty.
++ * @c: UBIFS file-system description object
++ * @node_type: LPT node type
++ * @node_num: node number
++ * @lnum: LEB number where node was written
++ * @offs: offset where node was written
++ *
++ * This function is used by LPT garbage collection.  LPT garbage collection is
++ * used only for the "big" LPT model (c->big_lpt == 1).  Garbage collection
++ * simply involves marking all the nodes in the LEB being garbage-collected as
++ * dirty.  The dirty nodes are written next commit, after which the LEB is free
++ * to be reused.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int make_node_dirty(struct ubifs_info *c, int node_type, int node_num,
++                         int lnum, int offs)
++{
++      switch (node_type) {
++      case UBIFS_LPT_NNODE:
++              return make_nnode_dirty(c, node_num, lnum, offs);
++      case UBIFS_LPT_PNODE:
++              return make_pnode_dirty(c, node_num, lnum, offs);
++      case UBIFS_LPT_LTAB:
++              return make_ltab_dirty(c, lnum, offs);
++      case UBIFS_LPT_LSAVE:
++              return make_lsave_dirty(c, lnum, offs);
++      }
++      return -EINVAL;
++}
++
++/**
++ * get_lpt_node_len - return the length of a node based on its type.
++ * @c: UBIFS file-system description object
++ * @node_type: LPT node type
++ */
++static int get_lpt_node_len(struct ubifs_info *c, int node_type)
++{
++      switch (node_type) {
++      case UBIFS_LPT_NNODE:
++              return c->nnode_sz;
++      case UBIFS_LPT_PNODE:
++              return c->pnode_sz;
++      case UBIFS_LPT_LTAB:
++              return c->ltab_sz;
++      case UBIFS_LPT_LSAVE:
++              return c->lsave_sz;
++      }
++      return 0;
++}
++
++/**
++ * get_pad_len - return the length of padding in a buffer.
++ * @c: UBIFS file-system description object
++ * @buf: buffer
++ * @len: length of buffer
++ */
++static int get_pad_len(struct ubifs_info *c, uint8_t *buf, int len)
++{
++      int offs, pad_len;
++
++      if (c->min_io_size == 1)
++              return 0;
++      offs = c->leb_size - len;
++      pad_len = ALIGN(offs, c->min_io_size) - offs;
++      return pad_len;
++}
++
++/**
++ * get_lpt_node_type - return type (and node number) of a node in a buffer.
++ * @c: UBIFS file-system description object
++ * @buf: buffer
++ * @node_num: node number is returned here
++ */
++static int get_lpt_node_type(struct ubifs_info *c, uint8_t *buf, int *node_num)
++{
++      uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
++      int pos = 0, node_type;
++
++      node_type = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_TYPE_BITS);
++      *node_num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits);
++      return node_type;
++}
++
++/**
++ * is_a_node - determine if a buffer contains a node.
++ * @c: UBIFS file-system description object
++ * @buf: buffer
++ * @len: length of buffer
++ *
++ * This function returns %1 if the buffer contains a node or %0 if it does not.
++ */
++static int is_a_node(struct ubifs_info *c, uint8_t *buf, int len)
++{
++      uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
++      int pos = 0, node_type, node_len;
++      uint16_t crc, calc_crc;
++
++      node_type = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_TYPE_BITS);
++      if (node_type == UBIFS_LPT_NOT_A_NODE)
++              return 0;
++      node_len = get_lpt_node_len(c, node_type);
++      if (!node_len || node_len > len)
++              return 0;
++      pos = 0;
++      addr = buf;
++      crc = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_CRC_BITS);
++      calc_crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
++                       node_len - UBIFS_LPT_CRC_BYTES);
++      if (crc != calc_crc)
++              return 0;
++      return 1;
++}
++
++
++/**
++ * lpt_gc_lnum - garbage collect a LPT LEB.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number to garbage collect
++ *
++ * LPT garbage collection is used only for the "big" LPT model
++ * (c->big_lpt == 1).  Garbage collection simply involves marking all the nodes
++ * in the LEB being garbage-collected as dirty.  The dirty nodes are written
++ * next commit, after which the LEB is free to be reused.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int lpt_gc_lnum(struct ubifs_info *c, int lnum)
++{
++      int err, len = c->leb_size, node_type, node_num, node_len, offs;
++      void *buf = c->lpt_buf;
++
++      dbg_lp("LEB %d", lnum);
++      err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
++      if (err) {
++              ubifs_err("cannot read LEB %d, error %d", lnum, err);
++              return err;
++      }
++      while (1) {
++              if (!is_a_node(c, buf, len)) {
++                      int pad_len;
++
++                      pad_len = get_pad_len(c, buf, len);
++                      if (pad_len) {
++                              buf += pad_len;
++                              len -= pad_len;
++                              continue;
++                      }
++                      return 0;
++              }
++              node_type = get_lpt_node_type(c, buf, &node_num);
++              node_len = get_lpt_node_len(c, node_type);
++              offs = c->leb_size - len;
++              ubifs_assert(node_len != 0);
++              mutex_lock(&c->lp_mutex);
++              err = make_node_dirty(c, node_type, node_num, lnum, offs);
++              mutex_unlock(&c->lp_mutex);
++              if (err)
++                      return err;
++              buf += node_len;
++              len -= node_len;
++      }
++      return 0;
++}
++
++/**
++ * lpt_gc - LPT garbage collection.
++ * @c: UBIFS file-system description object
++ *
++ * Select a LPT LEB for LPT garbage collection and call 'lpt_gc_lnum()'.
++ * Returns %0 on success and a negative error code on failure.
++ */
++static int lpt_gc(struct ubifs_info *c)
++{
++      int i, lnum = -1, dirty = 0;
++
++      mutex_lock(&c->lp_mutex);
++      for (i = 0; i < c->lpt_lebs; i++) {
++              ubifs_assert(!c->ltab[i].tgc);
++              if (i + c->lpt_first == c->nhead_lnum ||
++                  c->ltab[i].free + c->ltab[i].dirty == c->leb_size)
++                      continue;
++              if (c->ltab[i].dirty > dirty) {
++                      dirty = c->ltab[i].dirty;
++                      lnum = i + c->lpt_first;
++              }
++      }
++      mutex_unlock(&c->lp_mutex);
++      if (lnum == -1)
++              return -ENOSPC;
++      return lpt_gc_lnum(c, lnum);
++}
++
++/**
++ * ubifs_lpt_post_commit - post commit LPT trivial GC and LPT GC.
++ * @c: UBIFS file-system description object
++ *
++ * LPT trivial GC is completed after a commit. Also LPT GC is done after a
++ * commit for the "big" LPT model.
++ */
++int ubifs_lpt_post_commit(struct ubifs_info *c)
++{
++      int err;
++
++      mutex_lock(&c->lp_mutex);
++      err = lpt_tgc_end(c);
++      if (err)
++              goto out;
++      if (c->big_lpt)
++              while (need_write_all(c)) {
++                      mutex_unlock(&c->lp_mutex);
++                      err = lpt_gc(c);
++                      if (err)
++                              return err;
++                      mutex_lock(&c->lp_mutex);
++              }
++out:
++      mutex_unlock(&c->lp_mutex);
++      return err;
++}
++
++/**
++ * first_nnode - find the first nnode in memory.
++ * @c: UBIFS file-system description object
++ * @hght: height of tree where nnode found is returned here
++ *
++ * This function returns a pointer to the nnode found or %NULL if no nnode is
++ * found. This function is a helper to 'ubifs_lpt_free()'.
++ */
++static struct ubifs_nnode *first_nnode(struct ubifs_info *c, int *hght)
++{
++      struct ubifs_nnode *nnode;
++      int h, i, found;
++
++      nnode = c->nroot;
++      *hght = 0;
++      if (!nnode)
++              return NULL;
++      for (h = 1; h < c->lpt_hght; h++) {
++              found = 0;
++              for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
++                      if (nnode->nbranch[i].nnode) {
++                              found = 1;
++                              nnode = nnode->nbranch[i].nnode;
++                              *hght = h;
++                              break;
++                      }
++              }
++              if (!found)
++                      break;
++      }
++      return nnode;
++}
++
++/**
++ * next_nnode - find the next nnode in memory.
++ * @c: UBIFS file-system description object
++ * @nnode: nnode from which to start.
++ * @hght: height of tree where nnode is, is passed and returned here
++ *
++ * This function returns a pointer to the nnode found or %NULL if no nnode is
++ * found. This function is a helper to 'ubifs_lpt_free()'.
++ */
++static struct ubifs_nnode *next_nnode(struct ubifs_info *c,
++                                    struct ubifs_nnode *nnode, int *hght)
++{
++      struct ubifs_nnode *parent;
++      int iip, h, i, found;
++
++      parent = nnode->parent;
++      if (!parent)
++              return NULL;
++      if (nnode->iip == UBIFS_LPT_FANOUT - 1) {
++              *hght -= 1;
++              return parent;
++      }
++      for (iip = nnode->iip + 1; iip < UBIFS_LPT_FANOUT; iip++) {
++              nnode = parent->nbranch[iip].nnode;
++              if (nnode)
++                      break;
++      }
++      if (!nnode) {
++              *hght -= 1;
++              return parent;
++      }
++      for (h = *hght + 1; h < c->lpt_hght; h++) {
++              found = 0;
++              for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
++                      if (nnode->nbranch[i].nnode) {
++                              found = 1;
++                              nnode = nnode->nbranch[i].nnode;
++                              *hght = h;
++                              break;
++                      }
++              }
++              if (!found)
++                      break;
++      }
++      return nnode;
++}
++
++/**
++ * ubifs_lpt_free - free resources owned by the LPT.
++ * @c: UBIFS file-system description object
++ * @wr_only: free only resources used for writing
++ */
++void ubifs_lpt_free(struct ubifs_info *c, int wr_only)
++{
++      struct ubifs_nnode *nnode;
++      int i, hght;
++
++      /* Free write-only things first */
++
++      free_obsolete_cnodes(c); /* Leftover from a failed commit */
++
++      vfree(c->ltab_cmt);
++      c->ltab_cmt = NULL;
++      vfree(c->lpt_buf);
++      c->lpt_buf = NULL;
++      kfree(c->lsave);
++      c->lsave = NULL;
++
++      if (wr_only)
++              return;
++
++      /* Now free the rest */
++
++      nnode = first_nnode(c, &hght);
++      while (nnode) {
++              for (i = 0; i < UBIFS_LPT_FANOUT; i++)
++                      kfree(nnode->nbranch[i].nnode);
++              nnode = next_nnode(c, nnode, &hght);
++      }
++      for (i = 0; i < LPROPS_HEAP_CNT; i++)
++              kfree(c->lpt_heap[i].arr);
++      kfree(c->dirty_idx.arr);
++      kfree(c->nroot);
++      vfree(c->ltab);
++      kfree(c->lpt_nod_buf);
++}
++
++#ifdef CONFIG_UBIFS_FS_DEBUG
++
++/**
++ * dbg_is_all_ff - determine if a buffer contains only 0xff bytes.
++ * @buf: buffer
++ * @len: buffer length
++ */
++static int dbg_is_all_ff(uint8_t *buf, int len)
++{
++      int i;
++
++      for (i = 0; i < len; i++)
++              if (buf[i] != 0xff)
++                      return 0;
++      return 1;
++}
++
++/**
++ * dbg_is_nnode_dirty - determine if a nnode is dirty.
++ * @c: the UBIFS file-system description object
++ * @lnum: LEB number where nnode was written
++ * @offs: offset where nnode was written
++ */
++static int dbg_is_nnode_dirty(struct ubifs_info *c, int lnum, int offs)
++{
++      struct ubifs_nnode *nnode;
++      int hght;
++
++      /* Entire tree is in memory so first_nnode / next_nnode are ok */
++      nnode = first_nnode(c, &hght);
++      for (; nnode; nnode = next_nnode(c, nnode, &hght)) {
++              struct ubifs_nbranch *branch;
++
++              cond_resched();
++              if (nnode->parent) {
++                      branch = &nnode->parent->nbranch[nnode->iip];
++                      if (branch->lnum != lnum || branch->offs != offs)
++                              continue;
++                      if (test_bit(DIRTY_CNODE, &nnode->flags))
++                              return 1;
++                      return 0;
++              } else {
++                      if (c->lpt_lnum != lnum || c->lpt_offs != offs)
++                              continue;
++                      if (test_bit(DIRTY_CNODE, &nnode->flags))
++                              return 1;
++                      return 0;
++              }
++      }
++      return 1;
++}
++
++/**
++ * dbg_is_pnode_dirty - determine if a pnode is dirty.
++ * @c: the UBIFS file-system description object
++ * @lnum: LEB number where pnode was written
++ * @offs: offset where pnode was written
++ */
++static int dbg_is_pnode_dirty(struct ubifs_info *c, int lnum, int offs)
++{
++      int i, cnt;
++
++      cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT);
++      for (i = 0; i < cnt; i++) {
++              struct ubifs_pnode *pnode;
++              struct ubifs_nbranch *branch;
++
++              cond_resched();
++              pnode = pnode_lookup(c, i);
++              if (IS_ERR(pnode))
++                      return PTR_ERR(pnode);
++              branch = &pnode->parent->nbranch[pnode->iip];
++              if (branch->lnum != lnum || branch->offs != offs)
++                      continue;
++              if (test_bit(DIRTY_CNODE, &pnode->flags))
++                      return 1;
++              return 0;
++      }
++      return 1;
++}
++
++/**
++ * dbg_is_ltab_dirty - determine if a ltab node is dirty.
++ * @c: the UBIFS file-system description object
++ * @lnum: LEB number where ltab node was written
++ * @offs: offset where ltab node was written
++ */
++static int dbg_is_ltab_dirty(struct ubifs_info *c, int lnum, int offs)
++{
++      if (lnum != c->ltab_lnum || offs != c->ltab_offs)
++              return 1;
++      return (c->lpt_drty_flgs & LTAB_DIRTY) != 0;
++}
++
++/**
++ * dbg_is_lsave_dirty - determine if a lsave node is dirty.
++ * @c: the UBIFS file-system description object
++ * @lnum: LEB number where lsave node was written
++ * @offs: offset where lsave node was written
++ */
++static int dbg_is_lsave_dirty(struct ubifs_info *c, int lnum, int offs)
++{
++      if (lnum != c->lsave_lnum || offs != c->lsave_offs)
++              return 1;
++      return (c->lpt_drty_flgs & LSAVE_DIRTY) != 0;
++}
++
++/**
++ * dbg_is_node_dirty - determine if a node is dirty.
++ * @c: the UBIFS file-system description object
++ * @node_type: node type
++ * @lnum: LEB number where node was written
++ * @offs: offset where node was written
++ */
++static int dbg_is_node_dirty(struct ubifs_info *c, int node_type, int lnum,
++                           int offs)
++{
++      switch (node_type) {
++      case UBIFS_LPT_NNODE:
++              return dbg_is_nnode_dirty(c, lnum, offs);
++      case UBIFS_LPT_PNODE:
++              return dbg_is_pnode_dirty(c, lnum, offs);
++      case UBIFS_LPT_LTAB:
++              return dbg_is_ltab_dirty(c, lnum, offs);
++      case UBIFS_LPT_LSAVE:
++              return dbg_is_lsave_dirty(c, lnum, offs);
++      }
++      return 1;
++}
++
++/**
++ * dbg_check_ltab_lnum - check the ltab for a LPT LEB number.
++ * @c: the UBIFS file-system description object
++ * @lnum: LEB number where node was written
++ * @offs: offset where node was written
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
++{
++      int err, len = c->leb_size, dirty = 0, node_type, node_num, node_len;
++      int ret;
++      void *buf = c->dbg_buf;
++
++      dbg_lp("LEB %d", lnum);
++      err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
++      if (err) {
++              dbg_msg("ubi_read failed, LEB %d, error %d", lnum, err);
++              return err;
++      }
++      while (1) {
++              if (!is_a_node(c, buf, len)) {
++                      int i, pad_len;
++
++                      pad_len = get_pad_len(c, buf, len);
++                      if (pad_len) {
++                              buf += pad_len;
++                              len -= pad_len;
++                              dirty += pad_len;
++                              continue;
++                      }
++                      if (!dbg_is_all_ff(buf, len)) {
++                              dbg_msg("invalid empty space in LEB %d at %d",
++                                      lnum, c->leb_size - len);
++                              err = -EINVAL;
++                      }
++                      i = lnum - c->lpt_first;
++                      if (len != c->ltab[i].free) {
++                              dbg_msg("invalid free space in LEB %d "
++                                      "(free %d, expected %d)",
++                                      lnum, len, c->ltab[i].free);
++                              err = -EINVAL;
++                      }
++                      if (dirty != c->ltab[i].dirty) {
++                              dbg_msg("invalid dirty space in LEB %d "
++                                      "(dirty %d, expected %d)",
++                                      lnum, dirty, c->ltab[i].dirty);
++                              err = -EINVAL;
++                      }
++                      return err;
++              }
++              node_type = get_lpt_node_type(c, buf, &node_num);
++              node_len = get_lpt_node_len(c, node_type);
++              ret = dbg_is_node_dirty(c, node_type, lnum, c->leb_size - len);
++              if (ret == 1)
++                      dirty += node_len;
++              buf += node_len;
++              len -= node_len;
++      }
++}
++
++/**
++ * dbg_check_ltab - check the free and dirty space in the ltab.
++ * @c: the UBIFS file-system description object
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++int dbg_check_ltab(struct ubifs_info *c)
++{
++      int lnum, err, i, cnt;
++
++      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++              return 0;
++
++      /* Bring the entire tree into memory */
++      cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT);
++      for (i = 0; i < cnt; i++) {
++              struct ubifs_pnode *pnode;
++
++              pnode = pnode_lookup(c, i);
++              if (IS_ERR(pnode))
++                      return PTR_ERR(pnode);
++              cond_resched();
++      }
++
++      /* Check nodes */
++      err = dbg_check_lpt_nodes(c, (struct ubifs_cnode *)c->nroot, 0, 0);
++      if (err)
++              return err;
++
++      /* Check each LEB */
++      for (lnum = c->lpt_first; lnum <= c->lpt_last; lnum++) {
++              err = dbg_check_ltab_lnum(c, lnum);
++              if (err) {
++                      dbg_err("failed at LEB %d", lnum);
++                      return err;
++              }
++      }
++
++      dbg_lp("succeeded");
++      return 0;
++}
++
++#endif /* CONFIG_UBIFS_FS_DEBUG */
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/Makefile avr32-2.6/fs/ubifs/Makefile
+--- linux-2.6.25.6/fs/ubifs/Makefile   1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/Makefile        2008-06-12 15:09:45.311815896 +0200
+@@ -0,0 +1,9 @@
++obj-$(CONFIG_UBIFS_FS) += ubifs.o
++
++ubifs-y += shrinker.o journal.o file.o dir.o super.o sb.o io.o
++ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o
++ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o
++ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o
++
++ubifs-$(CONFIG_UBIFS_FS_DEBUG) += debug.o
++ubifs-$(CONFIG_UBIFS_FS_XATTR) += xattr.o
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/master.c avr32-2.6/fs/ubifs/master.c
+--- linux-2.6.25.6/fs/ubifs/master.c   1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/master.c        2008-06-12 15:09:45.475816115 +0200
+@@ -0,0 +1,387 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Artem Bityutskiy (Битюцкий Артём)
++ *          Adrian Hunter
++ */
++
++/* This file implements reading and writing the master node */
++
++#include "ubifs.h"
++
++/**
++ * scan_for_master - search the valid master node.
++ * @c: UBIFS file-system description object
++ *
++ * This function scans the master node LEBs and search for the latest master
++ * node. Returns zero in case of success and a negative error code in case of
++ * failure.
++ */
++static int scan_for_master(struct ubifs_info *c)
++{
++      struct ubifs_scan_leb *sleb;
++      struct ubifs_scan_node *snod;
++      int lnum, offs = 0, nodes_cnt;
++
++      lnum = UBIFS_MST_LNUM;
++
++      sleb = ubifs_scan(c, lnum, 0, c->sbuf);
++      if (IS_ERR(sleb))
++              return PTR_ERR(sleb);
++      nodes_cnt = sleb->nodes_cnt;
++      if (nodes_cnt > 0) {
++              snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node,
++                                list);
++              if (snod->type != UBIFS_MST_NODE)
++                      goto out;
++              memcpy(c->mst_node, snod->node, snod->len);
++              offs = snod->offs;
++      }
++      ubifs_scan_destroy(sleb);
++
++      lnum += 1;
++
++      sleb = ubifs_scan(c, lnum, 0, c->sbuf);
++      if (IS_ERR(sleb))
++              return PTR_ERR(sleb);
++      if (sleb->nodes_cnt != nodes_cnt)
++              goto out;
++      if (!sleb->nodes_cnt)
++              goto out;
++      snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, list);
++      if (snod->type != UBIFS_MST_NODE)
++              goto out;
++      if (snod->offs != offs)
++              goto out;
++      if (memcmp((void *)c->mst_node + UBIFS_CH_SZ,
++                 (void *)snod->node + UBIFS_CH_SZ,
++                 UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
++              goto out;
++      c->mst_offs = offs;
++      ubifs_scan_destroy(sleb);
++      return 0;
++
++out:
++      ubifs_scan_destroy(sleb);
++      return -EINVAL;
++}
++
++/**
++ * validate_master - validate master node.
++ * @c: UBIFS file-system description object
++ *
++ * This function validates data which was read from master node. Returns zero
++ * if the data is all right and %-EINVAL if not.
++ */
++static int validate_master(const struct ubifs_info *c)
++{
++      unsigned long long main_sz;
++      int err;
++
++      if (c->max_sqnum >= SQNUM_WATERMARK) {
++              err = 1;
++              goto out;
++      }
++
++      if (c->cmt_no >= c->max_sqnum) {
++              err = 2;
++              goto out;
++      }
++
++      if (c->highest_inum >= INUM_WATERMARK) {
++              err = 3;
++              goto out;
++      }
++
++      if (c->lhead_lnum < UBIFS_LOG_LNUM ||
++          c->lhead_lnum >= UBIFS_LOG_LNUM + c->log_lebs ||
++          c->lhead_offs < 0 || c->lhead_offs >= c->leb_size ||
++          c->lhead_offs & (c->min_io_size - 1)) {
++              err = 4;
++              goto out;
++      }
++
++      if (c->zroot.lnum >= c->leb_cnt || c->zroot.lnum < c->main_first ||
++          c->zroot.offs >= c->leb_size || c->zroot.offs & 7) {
++              err = 5;
++              goto out;
++      }
++
++      if (c->zroot.len < c->ranges[UBIFS_IDX_NODE].min_len ||
++          c->zroot.len > c->ranges[UBIFS_IDX_NODE].max_len) {
++              err = 6;
++              goto out;
++      }
++
++      if (c->gc_lnum >= c->leb_cnt || c->gc_lnum < c->main_first) {
++              err = 7;
++              goto out;
++      }
++
++      if (c->ihead_lnum >= c->leb_cnt || c->ihead_lnum < c->main_first ||
++          c->ihead_offs % c->min_io_size || c->ihead_offs < 0 ||
++          c->ihead_offs > c->leb_size || c->ihead_offs & 7) {
++              err = 8;
++              goto out;
++      }
++
++      main_sz = c->main_lebs * (unsigned long long)c->leb_size;
++      if (c->old_idx_sz & 7 || c->old_idx_sz >= main_sz) {
++              err = 9;
++              goto out;
++      }
++
++      if (c->lpt_lnum < c->lpt_first || c->lpt_lnum > c->lpt_last ||
++          c->lpt_offs < 0 || c->lpt_offs + c->nnode_sz > c->leb_size) {
++              err = 10;
++              goto out;
++      }
++
++      if (c->nhead_lnum < c->lpt_first || c->nhead_lnum > c->lpt_last ||
++          c->nhead_offs < 0 || c->nhead_offs % c->min_io_size ||
++          c->nhead_offs > c->leb_size) {
++              err = 11;
++              goto out;
++      }
++
++      if (c->ltab_lnum < c->lpt_first || c->ltab_lnum > c->lpt_last ||
++          c->ltab_offs < 0 ||
++          c->ltab_offs + c->ltab_sz > c->leb_size) {
++              err = 12;
++              goto out;
++      }
++
++      if (c->big_lpt && (c->lsave_lnum < c->lpt_first ||
++          c->lsave_lnum > c->lpt_last || c->lsave_offs < 0 ||
++          c->lsave_offs + c->lsave_sz > c->leb_size)) {
++              err = 13;
++              goto out;
++      }
++
++      if (c->lscan_lnum < c->main_first || c->lscan_lnum >= c->leb_cnt) {
++              err = 14;
++              goto out;
++      }
++
++      if (c->lst.empty_lebs < 0 || c->lst.empty_lebs > c->main_lebs - 2) {
++              err = 15;
++              goto out;
++      }
++
++      if (c->lst.idx_lebs < 0 || c->lst.idx_lebs > c->main_lebs - 1) {
++              err = 16;
++              goto out;
++      }
++
++      if (c->lst.total_free < 0 || c->lst.total_free > main_sz ||
++          c->lst.total_free & 7) {
++              err = 17;
++              goto out;
++      }
++
++      if (c->lst.total_dirty < 0 || (c->lst.total_dirty & 7)) {
++              err = 18;
++              goto out;
++      }
++
++      if (c->lst.total_used < 0 || (c->lst.total_used & 7)) {
++              err = 19;
++              goto out;
++      }
++
++      if (c->lst.total_free + c->lst.total_dirty +
++          c->lst.total_used > main_sz) {
++              err = 20;
++              goto out;
++      }
++
++      if (c->lst.total_dead + c->lst.total_dark +
++          c->lst.total_used + c->old_idx_sz > main_sz) {
++              err = 21;
++              goto out;
++      }
++
++      if (c->lst.total_dead < 0 ||
++          c->lst.total_dead > c->lst.total_free + c->lst.total_dirty ||
++          c->lst.total_dead & 7) {
++              err = 22;
++              goto out;
++      }
++
++      if (c->lst.total_dark < 0 ||
++          c->lst.total_dark > c->lst.total_free + c->lst.total_dirty ||
++          c->lst.total_dark & 7) {
++              err = 23;
++              goto out;
++      }
++
++      return 0;
++
++out:
++      ubifs_err("bad master node at offset %d error %d", c->mst_offs, err);
++      dbg_dump_node(c, c->mst_node);
++      return -EINVAL;
++}
++
++/**
++ * ubifs_read_master - read master node.
++ * @c: UBIFS file-system description object
++ *
++ * This function finds and reads the master node during file-system mount. If
++ * the flash is empty, it creates default master node as well. Returns zero in
++ * case of success and a negative error code in case of failure.
++ */
++int ubifs_read_master(struct ubifs_info *c)
++{
++      int err, old_leb_cnt;
++
++      c->mst_node = kzalloc(c->mst_node_alsz, GFP_KERNEL);
++      if (!c->mst_node)
++              return -ENOMEM;
++
++      err = scan_for_master(c);
++      if (err) {
++              err = ubifs_recover_master_node(c);
++              if (err)
++                      /*
++                       * Note, we do not free 'c->mst_node' here because the
++                       * unmount routine will take care of this.
++                       */
++                      return err;
++      }
++
++      /* Make sure that the recovery flag is clear */
++      c->mst_node->flags &= cpu_to_le32(~UBIFS_MST_RCVRY);
++
++      c->max_sqnum       = le64_to_cpu(c->mst_node->ch.sqnum);
++      c->highest_inum    = le64_to_cpu(c->mst_node->highest_inum);
++      c->cmt_no          = le64_to_cpu(c->mst_node->cmt_no);
++      c->zroot.lnum      = le32_to_cpu(c->mst_node->root_lnum);
++      c->zroot.offs      = le32_to_cpu(c->mst_node->root_offs);
++      c->zroot.len       = le32_to_cpu(c->mst_node->root_len);
++      c->lhead_lnum      = le32_to_cpu(c->mst_node->log_lnum);
++      c->gc_lnum         = le32_to_cpu(c->mst_node->gc_lnum);
++      c->ihead_lnum      = le32_to_cpu(c->mst_node->ihead_lnum);
++      c->ihead_offs      = le32_to_cpu(c->mst_node->ihead_offs);
++      c->old_idx_sz      = le64_to_cpu(c->mst_node->index_size);
++      c->lpt_lnum        = le32_to_cpu(c->mst_node->lpt_lnum);
++      c->lpt_offs        = le32_to_cpu(c->mst_node->lpt_offs);
++      c->nhead_lnum      = le32_to_cpu(c->mst_node->nhead_lnum);
++      c->nhead_offs      = le32_to_cpu(c->mst_node->nhead_offs);
++      c->ltab_lnum       = le32_to_cpu(c->mst_node->ltab_lnum);
++      c->ltab_offs       = le32_to_cpu(c->mst_node->ltab_offs);
++      c->lsave_lnum      = le32_to_cpu(c->mst_node->lsave_lnum);
++      c->lsave_offs      = le32_to_cpu(c->mst_node->lsave_offs);
++      c->lscan_lnum      = le32_to_cpu(c->mst_node->lscan_lnum);
++      c->lst.empty_lebs  = le32_to_cpu(c->mst_node->empty_lebs);
++      c->lst.idx_lebs    = le32_to_cpu(c->mst_node->idx_lebs);
++      old_leb_cnt        = le32_to_cpu(c->mst_node->leb_cnt);
++      c->lst.total_free  = le64_to_cpu(c->mst_node->total_free);
++      c->lst.total_dirty = le64_to_cpu(c->mst_node->total_dirty);
++      c->lst.total_used  = le64_to_cpu(c->mst_node->total_used);
++      c->lst.total_dead  = le64_to_cpu(c->mst_node->total_dead);
++      c->lst.total_dark  = le64_to_cpu(c->mst_node->total_dark);
++
++      c->calc_idx_sz = c->old_idx_sz;
++
++      if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS))
++              c->no_orphs = 1;
++
++      if (old_leb_cnt != c->leb_cnt) {
++              /* The file system has been resized */
++              int growth = c->leb_cnt - old_leb_cnt;
++
++              if (c->leb_cnt < old_leb_cnt ||
++                  c->leb_cnt < UBIFS_MIN_LEB_CNT) {
++                      ubifs_err("bad leb_cnt on master node");
++                      dbg_dump_node(c, c->mst_node);
++                      return -EINVAL;
++              }
++
++              dbg_mnt("Auto resizing (master) from %d LEBs to %d LEBs",
++                      old_leb_cnt, c->leb_cnt);
++              c->lst.empty_lebs += growth;
++              c->lst.total_free += growth * (long long)c->leb_size;
++              c->lst.total_dark += growth * (long long)c->dark_wm;
++
++              /*
++               * Reflect changes back onto the master node. N.B. the master
++               * node gets written immediately whenever mounting (or
++               * remounting) in read-write mode, so we do not need to write it
++               * here.
++               */
++              c->mst_node->leb_cnt = cpu_to_le32(c->leb_cnt);
++              c->mst_node->empty_lebs = cpu_to_le32(c->lst.empty_lebs);
++              c->mst_node->total_free = cpu_to_le64(c->lst.total_free);
++              c->mst_node->total_dark = cpu_to_le64(c->lst.total_dark);
++      }
++
++      err = validate_master(c);
++      if (err)
++              return err;
++
++      err = dbg_old_index_check_init(c, &c->zroot);
++
++      return err;
++}
++
++/**
++ * ubifs_write_master - write master node.
++ * @c: UBIFS file-system description object
++ *
++ * This function writes the master node. The caller has to take the
++ * @c->mst_mutex lock before calling this function. Returns zero in case of
++ * success and a negative error code in case of failure. The master node is
++ * written twice to enable recovery.
++ */
++int ubifs_write_master(struct ubifs_info *c)
++{
++      int err, lnum, offs, len;
++
++      if (c->ro_media)
++              return -EINVAL;
++
++      lnum = UBIFS_MST_LNUM;
++      offs = c->mst_offs + c->mst_node_alsz;
++      len = UBIFS_MST_NODE_SZ;
++
++      if (offs + UBIFS_MST_NODE_SZ > c->leb_size) {
++              err = ubifs_leb_unmap(c, lnum);
++              if (err)
++                      return err;
++              offs = 0;
++      }
++
++      c->mst_offs = offs;
++      c->mst_node->highest_inum = cpu_to_le64(c->highest_inum);
++
++      err = ubifs_write_node(c, c->mst_node, len, lnum, offs, UBI_SHORTTERM);
++      if (err)
++              return err;
++
++      lnum += 1;
++
++      if (offs == 0) {
++              err = ubifs_leb_unmap(c, lnum);
++              if (err)
++                      return err;
++      }
++      err = ubifs_write_node(c, c->mst_node, len, lnum, offs, UBI_SHORTTERM);
++
++      return err;
++}
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/misc.h avr32-2.6/fs/ubifs/misc.h
+--- linux-2.6.25.6/fs/ubifs/misc.h     1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/misc.h  2008-06-12 15:09:45.475816115 +0200
+@@ -0,0 +1,311 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Artem Bityutskiy (Битюцкий Артём)
++ *          Adrian Hunter
++ */
++
++/*
++ * This file contains miscellaneous helper functions.
++ */
++
++#ifndef __UBIFS_MISC_H__
++#define __UBIFS_MISC_H__
++
++/**
++ * ubifs_zn_dirty - check if znode is dirty.
++ * @znode: znode to check
++ *
++ * This helper function returns %1 if @znode is dirty and %0 otherwise.
++ */
++static inline int ubifs_zn_dirty(const struct ubifs_znode *znode)
++{
++      return !!test_bit(DIRTY_ZNODE, &znode->flags);
++}
++
++/**
++ * ubifs_wake_up_bgt - wake up background thread.
++ * @c: UBIFS file-system description object
++ */
++static inline void ubifs_wake_up_bgt(struct ubifs_info *c)
++{
++      if (c->bgt && !c->need_bgt) {
++              c->need_bgt = 1;
++              wake_up_process(c->bgt);
++      }
++}
++
++/**
++ * ubifs_tnc_find_child - find next child in znode.
++ * @znode: znode to search at
++ * @start: the zbranch index to start at
++ *
++ * This helper function looks for znode child starting at index @start. Returns
++ * the child or %NULL if no children were found.
++ */
++static inline struct ubifs_znode *
++ubifs_tnc_find_child(struct ubifs_znode *znode, int start)
++{
++      while (start < znode->child_cnt) {
++              if (znode->zbranch[start].znode)
++                      return znode->zbranch[start].znode;
++              start += 1;
++      }
++
++      return NULL;
++}
++
++/**
++ * ubifs_inode - get UBIFS inode information by VFS 'struct inode' object.
++ * @inode: the VFS 'struct inode' pointer
++ */
++static inline struct ubifs_inode *ubifs_inode(const struct inode *inode)
++{
++      return container_of(inode, struct ubifs_inode, vfs_inode);
++}
++
++/**
++ * ubifs_ro_mode - switch UBIFS to read read-only mode.
++ * @c: UBIFS file-system description object
++ * @err: error code which is the reason of switching to R/O mode
++ */
++static inline void ubifs_ro_mode(struct ubifs_info *c, int err)
++{
++      if (!c->ro_media) {
++              c->ro_media = 1;
++              ubifs_warn("switched to read-only mode, error %d", err);
++              dbg_dump_stack();
++      }
++}
++
++/**
++ * ubifs_compr_present - check if compressor was compiled in.
++ * @compr_type: compressor type to check
++ *
++ * This function returns %1 of compressor of type @compr_type is present, and
++ * %0 if not.
++ */
++static inline int ubifs_compr_present(int compr_type)
++{
++      ubifs_assert(compr_type >= 0 && compr_type < UBIFS_COMPR_TYPES_CNT);
++      return !!ubifs_compressors[compr_type]->capi_name;
++}
++
++/**
++ * ubifs_compr_name - get compressor name string by its type.
++ * @compr_type: compressor type
++ *
++ * This function returns compressor type string.
++ */
++static inline const char *ubifs_compr_name(int compr_type)
++{
++      ubifs_assert(compr_type >= 0 && compr_type < UBIFS_COMPR_TYPES_CNT);
++      return ubifs_compressors[compr_type]->name;
++}
++
++/**
++ * ubifs_wbuf_sync - synchronize write-buffer.
++ * @wbuf: write-buffer to synchronize
++ *
++ * This is the same as as 'ubifs_wbuf_sync_nolock()' but it does not assume
++ * that the write-buffer is already locked.
++ */
++static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf)
++{
++      int err;
++
++      mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
++      err = ubifs_wbuf_sync_nolock(wbuf);
++      mutex_unlock(&wbuf->io_mutex);
++      return err;
++}
++
++/**
++ * ubifs_leb_unmap - unmap an LEB.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number to unmap
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static inline int ubifs_leb_unmap(const struct ubifs_info *c, int lnum)
++{
++      int err;
++
++      err = ubi_leb_unmap(c->ubi, lnum);
++      if (err) {
++              ubifs_err("unmap LEB %d failed, error %d", lnum, err);
++              return err;
++      }
++
++      return 0;
++}
++
++/**
++ * ubifs_leb_write - write to a LEB.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number to write
++ * @buf: buffer to write from
++ * @offs: offset within LEB to write to
++ * @len: length to write
++ * @dtype: data type
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static inline int ubifs_leb_write(const struct ubifs_info *c, int lnum,
++                                const void *buf, int offs, int len, int dtype)
++{
++      int err;
++
++      err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
++      if (err) {
++              ubifs_err("writing %d bytes at %d:%d, error %d",
++                        len, lnum, offs, err);
++              return err;
++      }
++
++      return 0;
++}
++
++/**
++ * ubifs_encode_dev - encode device node IDs.
++ * @dev: UBIFS device node information
++ * @rdev: device IDs to encode
++ *
++ * This is a helper function which encodes major/minor numbers of a device node
++ * into UBIFS device node description. We use standard Linux "new" and "huge"
++ * encodings.
++ */
++static inline int ubifs_encode_dev(union ubifs_dev_desc *dev, dev_t rdev)
++{
++      if (new_valid_dev(rdev)) {
++              dev->new = cpu_to_le32(new_encode_dev(rdev));
++              return sizeof(dev->new);
++      } else {
++              dev->huge = cpu_to_le64(huge_encode_dev(rdev));
++              return sizeof(dev->huge);
++      }
++}
++
++/**
++ * ubifs_add_dirt - add dirty space to LEB properties.
++ * @c: the UBIFS file-system description object
++ * @lnum: LEB to add dirty space for
++ * @dirty: dirty space to add
++ *
++ * This is a helper function which increased amount of dirty LEB space. Returns
++ * zero in case of success and a negative error code in case of failure.
++ */
++static inline int ubifs_add_dirt(struct ubifs_info *c, int lnum, int dirty)
++{
++      return ubifs_update_one_lp(c, lnum, LPROPS_NC, dirty, 0, 0);
++}
++
++/**
++ * ubifs_return_leb - return LEB to lprops.
++ * @c: the UBIFS file-system description object
++ * @lnum: LEB to return
++ *
++ * This helper function cleans the "taken" flag of a logical eraseblock in the
++ * lprops. Returns zero in case of success and a negative error code in case of
++ * failure.
++ */
++static inline int ubifs_return_leb(struct ubifs_info *c, int lnum)
++{
++      return ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
++                                 LPROPS_TAKEN, 0);
++}
++
++/**
++ * ubifs_idx_node_sz - return index node size.
++ * @c: the UBIFS file-system description object
++ * @child_cnt: number of children of this index node
++ */
++static inline int ubifs_idx_node_sz(const struct ubifs_info *c, int child_cnt)
++{
++      return UBIFS_IDX_NODE_SZ + (UBIFS_BRANCH_SZ + c->key_len) * child_cnt;
++}
++
++/**
++ * ubifs_idx_branch - return pointer to an index branch.
++ * @c: the UBIFS file-system description object
++ * @idx: index node
++ * @bnum: branch number
++ */
++static inline
++struct ubifs_branch *ubifs_idx_branch(const struct ubifs_info *c,
++                                    const struct ubifs_idx_node *idx,
++                                    int bnum)
++{
++      return (struct ubifs_branch *)((void *)idx->branches +
++                                     (UBIFS_BRANCH_SZ + c->key_len) * bnum);
++}
++
++/**
++ * ubifs_idx_key - return pointer to an index key.
++ * @c: the UBIFS file-system description object
++ * @idx: index node
++ */
++static inline void *ubifs_idx_key(const struct ubifs_info *c,
++                                const struct ubifs_idx_node *idx)
++{
++      return (void *)((struct ubifs_branch *)idx->branches)->key;
++}
++
++/**
++ * ubifs_reported_space - calculate reported free space.
++ * @c: the UBIFS file-system description object
++ * @free: amount of free space
++ *
++ * This function calculates amount of free space which will be reported to
++ * user-space. User-space application tend to expect that if the file-system
++ * (e.g., via the 'statfs()' call) reports that it has N bytes available, they
++ * are able to write a file of size N. UBIFS attaches node headers to each data
++ * node and it has to write indexind nodes as well. This introduces additional
++ * overhead, and UBIFS it has to report sligtly less free space to meet the
++ * above expectetion.
++ *
++ * This function assumes free space is made up of uncompressed data nodes and
++ * full index nodes (one per data node, doubled because we always allow enough
++ * space to write the index twice).
++ *
++ * Note, the calculation is pessimistic, which means that most of the time
++ * UBIFS reports less space than it actually has.
++ */
++static inline long long ubifs_reported_space(const struct ubifs_info *c,
++                                           uint64_t free)
++{
++      int divisor, factor;
++
++      divisor = UBIFS_MAX_DATA_NODE_SZ + (c->max_idx_node_sz << 1);
++      factor = UBIFS_MAX_DATA_NODE_SZ - UBIFS_DATA_NODE_SZ;
++      do_div(free, divisor);
++
++      return free * factor;
++}
++
++/**
++ * ubifs_current_time - round current time to time granularity.
++ * @inode: inode
++ */
++static inline struct timespec ubifs_current_time(struct inode *inode)
++{
++      return (inode->i_sb->s_time_gran < NSEC_PER_SEC) ?
++              current_fs_time(inode->i_sb) : CURRENT_TIME_SEC;
++}
++
++#endif /* __UBIFS_MISC_H__ */
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/orphan.c avr32-2.6/fs/ubifs/orphan.c
+--- linux-2.6.25.6/fs/ubifs/orphan.c   1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/orphan.c        2008-06-12 15:09:45.475816115 +0200
+@@ -0,0 +1,958 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Author: Adrian Hunter
++ */
++
++#include "ubifs.h"
++
++/*
++ * An orphan is an inode number whose inode node has been committed to the index
++ * with a link count of zero. That happens when an open file is deleted
++ * (unlinked) and then a commit is run. In the normal course of events the inode
++ * would be deleted when the file is closed. However in the case of an unclean
++ * unmount, orphans need to be accounted for. After an unclean unmount, the
++ * orphans' inodes must be deleted which means either scanning the entire index
++ * looking for them, or keeping a list on flash somewhere. This unit implements
++ * the latter approach.
++ *
++ * The orphan area is a fixed number of LEBs situated between the LPT area and
++ * the main area. The number of orphan area LEBs is specified when the file
++ * system is created. The minimum number is 1. The size of the orphan area
++ * should be so that it can hold the maximum number of orphans that are expected
++ * to ever exist at one time.
++ *
++ * The number of orphans that can fit in a LEB is:
++ *
++ *         (c->leb_size - UBIFS_ORPH_NODE_SZ) / sizeof(__le64)
++ *
++ * For example: a 15872 byte LEB can fit 1980 orphans so 1 LEB may be enough.
++ *
++ * Orphans are accumulated in a rb-tree. When an inode's link count drops to
++ * zero, the inode number is added to the rb-tree. It is removed from the tree
++ * when the inode is deleted.  Any new orphans that are in the orphan tree when
++ * the commit is run, are written to the orphan area in 1 or more orph nodes.
++ * If the orphan area is full, it is consolidated to make space.  There is
++ * always enough space because validation prevents the user from creating more
++ * than the maximum number of orphans allowed.
++ */
++
++#ifdef CONFIG_UBIFS_FS_DEBUG
++static int dbg_check_orphans(struct ubifs_info *c);
++#else
++#define dbg_check_orphans(c) 0
++#endif
++
++/**
++ * ubifs_add_orphan - add an orphan.
++ * @c: UBIFS file-system description object
++ * @inum: orphan inode number
++ *
++ * Add an orphan. This function is called when an inodes link count drops to
++ * zero.
++ */
++int ubifs_add_orphan(struct ubifs_info *c, ino_t inum)
++{
++      struct ubifs_orphan *orphan, *o;
++      struct rb_node **p, *parent = NULL;
++
++      orphan = kzalloc(sizeof(struct ubifs_orphan), GFP_NOFS);
++      if (!orphan)
++              return -ENOMEM;
++      orphan->inum = inum;
++      orphan->new = 1;
++
++      spin_lock(&c->orphan_lock);
++      if (c->tot_orphans >= c->max_orphans) {
++              spin_unlock(&c->orphan_lock);
++              kfree(orphan);
++              return -ENFILE;
++      }
++      p = &c->orph_tree.rb_node;
++      while (*p) {
++              parent = *p;
++              o = rb_entry(parent, struct ubifs_orphan, rb);
++              if (inum < o->inum)
++                      p = &(*p)->rb_left;
++              else if (inum > o->inum)
++                      p = &(*p)->rb_right;
++              else {
++                      dbg_err("orphaned twice");
++                      spin_unlock(&c->orphan_lock);
++                      kfree(orphan);
++                      return 0;
++              }
++      }
++      c->tot_orphans += 1;
++      c->new_orphans += 1;
++      rb_link_node(&orphan->rb, parent, p);
++      rb_insert_color(&orphan->rb, &c->orph_tree);
++      list_add_tail(&orphan->list, &c->orph_list);
++      list_add_tail(&orphan->new_list, &c->orph_new);
++      spin_unlock(&c->orphan_lock);
++      dbg_gen("ino %lu", inum);
++      return 0;
++}
++
++/**
++ * ubifs_delete_orphan - delete an orphan.
++ * @c: UBIFS file-system description object
++ * @inum: orphan inode number
++ *
++ * Delete an orphan. This function is called when an inode is deleted.
++ */
++void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum)
++{
++      struct ubifs_orphan *o;
++      struct rb_node *p;
++
++      spin_lock(&c->orphan_lock);
++      p = c->orph_tree.rb_node;
++      while (p) {
++              o = rb_entry(p, struct ubifs_orphan, rb);
++              if (inum < o->inum)
++                      p = p->rb_left;
++              else if (inum > o->inum)
++                      p = p->rb_right;
++              else {
++                      if (o->dnext) {
++                              spin_unlock(&c->orphan_lock);
++                              dbg_gen("deleted twice ino %lu", inum);
++                              return;
++                      }
++                      if (o->cnext) {
++                              o->dnext = c->orph_dnext;
++                              c->orph_dnext = o;
++                              spin_unlock(&c->orphan_lock);
++                              dbg_gen("delete later ino %lu", inum);
++                              return;
++                      }
++                      rb_erase(p, &c->orph_tree);
++                      list_del(&o->list);
++                      c->tot_orphans -= 1;
++                      if (o->new) {
++                              list_del(&o->new_list);
++                              c->new_orphans -= 1;
++                      }
++                      spin_unlock(&c->orphan_lock);
++                      kfree(o);
++                      dbg_gen("inum %lu", inum);
++                      return;
++              }
++      }
++      spin_unlock(&c->orphan_lock);
++      dbg_err("missing orphan ino %lu", inum);
++      dbg_dump_stack();
++}
++
++/**
++ * ubifs_orphan_start_commit - start commit of orphans.
++ * @c: UBIFS file-system description object
++ *
++ * Start commit of orphans.
++ */
++int ubifs_orphan_start_commit(struct ubifs_info *c)
++{
++      struct ubifs_orphan *orphan, **last;
++
++      spin_lock(&c->orphan_lock);
++      last = &c->orph_cnext;
++      list_for_each_entry(orphan, &c->orph_new, new_list) {
++              ubifs_assert(orphan->new);
++              orphan->new = 0;
++              *last = orphan;
++              last = &orphan->cnext;
++      }
++      *last = orphan->cnext;
++      c->cmt_orphans = c->new_orphans;
++      c->new_orphans = 0;
++      dbg_cmt("%d orphans to commit", c->cmt_orphans);
++      INIT_LIST_HEAD(&c->orph_new);
++      if (c->tot_orphans == 0)
++              c->no_orphs = 1;
++      else
++              c->no_orphs = 0;
++      spin_unlock(&c->orphan_lock);
++      return 0;
++}
++
++/**
++ * avail_orphs - calculate available space.
++ * @c: UBIFS file-system description object
++ *
++ * This function returns the number of orphans that can be written in the
++ * available space.
++ */
++static int avail_orphs(struct ubifs_info *c)
++{
++      int avail_lebs, avail, gap;
++
++      avail_lebs = c->orph_lebs - (c->ohead_lnum - c->orph_first) - 1;
++      avail = avail_lebs *
++             ((c->leb_size - UBIFS_ORPH_NODE_SZ) / sizeof(__le64));
++      gap = c->leb_size - c->ohead_offs;
++      if (gap >= UBIFS_ORPH_NODE_SZ + sizeof(__le64))
++              avail += (gap - UBIFS_ORPH_NODE_SZ) / sizeof(__le64);
++      return avail;
++}
++
++/**
++ * tot_avail_orphs - calculate total space.
++ * @c: UBIFS file-system description object
++ *
++ * This function returns the number of orphans that can be written in half
++ * the total space. That leaves half the space for adding new orphans.
++ */
++static int tot_avail_orphs(struct ubifs_info *c)
++{
++      int avail_lebs, avail;
++
++      avail_lebs = c->orph_lebs;
++      avail = avail_lebs *
++             ((c->leb_size - UBIFS_ORPH_NODE_SZ) / sizeof(__le64));
++      return avail / 2;
++}
++
++/**
++ * do_write_orph_node - write a node
++ * @c: UBIFS file-system description object
++ * @len: length of node
++ * @atomic: write atomically
++ *
++ * This function writes a node to the orphan head from the orphan buffer. If
++ * %atomic is not zero, then the write is done atomically. On success, %0 is
++ * returned, otherwise a negative error code is returned.
++ */
++static int do_write_orph_node(struct ubifs_info *c, int len, int atomic)
++{
++      int err = 0;
++
++      if (atomic) {
++              ubifs_assert(c->ohead_offs == 0);
++              ubifs_prepare_node(c, c->orph_buf, len, 1);
++              len = ALIGN(len, c->min_io_size);
++              err = ubi_leb_change(c->ubi, c->ohead_lnum, c->orph_buf, len,
++                                   UBI_SHORTTERM);
++      } else {
++              if (c->ohead_offs == 0) {
++                      /* Ensure LEB has been unmapped */
++                      err = ubifs_leb_unmap(c, c->ohead_lnum);
++                      if (err)
++                              return err;
++              }
++              err = ubifs_write_node(c, c->orph_buf, len, c->ohead_lnum,
++                                     c->ohead_offs, UBI_SHORTTERM);
++      }
++      return err;
++}
++
++/**
++ * write_orph_node - write an orph node
++ * @c: UBIFS file-system description object
++ * @atomic: write atomically
++ *
++ * This function builds an orph node from the cnext list and writes it to the
++ * orphan head. On success, %0 is returned, otherwise a negative error code
++ * is returned.
++ */
++static int write_orph_node(struct ubifs_info *c, int atomic)
++{
++      struct ubifs_orphan *orphan, *cnext;
++      struct ubifs_orph_node *orph;
++      int gap, err, len, cnt, i;
++
++      ubifs_assert(c->cmt_orphans > 0);
++      gap = c->leb_size - c->ohead_offs;
++      if (gap < UBIFS_ORPH_NODE_SZ + sizeof(__le64)) {
++              c->ohead_lnum += 1;
++              c->ohead_offs = 0;
++              gap = c->leb_size;
++              if (c->ohead_lnum > c->orph_last) {
++                      /*
++                       * We limit the number of orphans so that this should
++                       * never happen.
++                       */
++                      ubifs_err("out of space in orphan area");
++                      return -EINVAL;
++              }
++      }
++      cnt = (gap - UBIFS_ORPH_NODE_SZ) / sizeof(__le64);
++      if (cnt > c->cmt_orphans)
++              cnt = c->cmt_orphans;
++      len = UBIFS_ORPH_NODE_SZ + cnt * sizeof(__le64);
++      ubifs_assert(c->orph_buf);
++      orph = c->orph_buf;
++      orph->ch.node_type = UBIFS_ORPH_NODE;
++      spin_lock(&c->orphan_lock);
++      cnext = c->orph_cnext;
++      for (i = 0; i < cnt; i++) {
++              orphan = cnext;
++              orph->inos[i] = cpu_to_le64(orphan->inum);
++              cnext = orphan->cnext;
++              orphan->cnext = NULL;
++      }
++      c->orph_cnext = cnext;
++      c->cmt_orphans -= cnt;
++      spin_unlock(&c->orphan_lock);
++      if (c->cmt_orphans)
++              orph->cmt_no = cpu_to_le64(c->cmt_no + 1);
++      else
++              /* Mark the last node of the commit */
++              orph->cmt_no = cpu_to_le64((c->cmt_no + 1) | (1ULL << 63));
++      ubifs_assert(c->ohead_offs + len <= c->leb_size);
++      ubifs_assert(c->ohead_lnum >= c->orph_first);
++      ubifs_assert(c->ohead_lnum <= c->orph_last);
++      err = do_write_orph_node(c, len, atomic);
++      c->ohead_offs += ALIGN(len, c->min_io_size);
++      c->ohead_offs = ALIGN(c->ohead_offs, 8);
++      return err;
++}
++
++/**
++ * write_orph_nodes - write orph nodes until there are no more to commit
++ * @c: UBIFS file-system description object
++ * @atomic: write atomically
++ *
++ * This function writes orph nodes for all the orphans to commit. On success,
++ * %0 is returned, otherwise a negative error code is returned.
++ */
++static int write_orph_nodes(struct ubifs_info *c, int atomic)
++{
++      int err;
++
++      while (c->cmt_orphans > 0) {
++              err = write_orph_node(c, atomic);
++              if (err)
++                      return err;
++      }
++      if (atomic) {
++              int lnum;
++
++              /* Unmap any unused LEBs after consolidation */
++              lnum = c->ohead_lnum + 1;
++              for (lnum = c->ohead_lnum + 1; lnum <= c->orph_last; lnum++) {
++                      err = ubifs_leb_unmap(c, lnum);
++                      if (err)
++                              return err;
++              }
++      }
++      return 0;
++}
++
++/**
++ * consolidate - consolidate the orphan area.
++ * @c: UBIFS file-system description object
++ *
++ * This function enables consolidation by putting all the orphans into the list
++ * to commit. The list is in the order that the orphans were added, and the
++ * LEBs are written atomically in order, so at no time can orphans be lost by
++ * an unclean unmount.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int consolidate(struct ubifs_info *c)
++{
++      int tot_avail = tot_avail_orphs(c), err = 0;
++
++      spin_lock(&c->orphan_lock);
++      dbg_cmt("there is space for %d orphans and there are %d",
++              tot_avail, c->tot_orphans);
++      if (c->tot_orphans - c->new_orphans <= tot_avail) {
++              struct ubifs_orphan *orphan, **last;
++              int cnt = 0;
++
++              /* Change the cnext list to include all non-new orphans */
++              last = &c->orph_cnext;
++              list_for_each_entry(orphan, &c->orph_list, list) {
++                      if (orphan->new)
++                              continue;
++                      *last = orphan;
++                      last = &orphan->cnext;
++                      cnt += 1;
++              }
++              *last = orphan->cnext;
++              ubifs_assert(cnt == c->tot_orphans - c->new_orphans);
++              c->cmt_orphans = cnt;
++              c->ohead_lnum = c->orph_first;
++              c->ohead_offs = 0;
++      } else {
++              /*
++               * We limit the number of orphans so that this should
++               * never happen.
++               */
++              ubifs_err("out of space in orphan area");
++              err = -EINVAL;
++      }
++      spin_unlock(&c->orphan_lock);
++      return err;
++}
++
++/**
++ * commit_orphans - commit orphans.
++ * @c: UBIFS file-system description object
++ *
++ * This function commits orphans to flash. On success, %0 is returned,
++ * otherwise a negative error code is returned.
++ */
++static int commit_orphans(struct ubifs_info *c)
++{
++      int avail, atomic = 0, err;
++
++      ubifs_assert(c->cmt_orphans > 0);
++      avail = avail_orphs(c);
++      if (avail < c->cmt_orphans) {
++              /* Not enough space to write new orphans, so consolidate */
++              err = consolidate(c);
++              if (err)
++                      return err;
++              atomic = 1;
++      }
++      err = write_orph_nodes(c, atomic);
++      return err;
++}
++
++/**
++ * erase_deleted - erase the orphans marked for deletion.
++ * @c: UBIFS file-system description object
++ *
++ * During commit, the orphans being committed cannot be deleted, so they are
++ * marked for deletion and deleted by this function. Also, the recovery
++ * adds killed orphans to the deletion list, and therefore they are deleted
++ * here too.
++ */
++static void erase_deleted(struct ubifs_info *c)
++{
++      struct ubifs_orphan *orphan, *dnext;
++
++      spin_lock(&c->orphan_lock);
++      dnext = c->orph_dnext;
++      while (dnext) {
++              orphan = dnext;
++              dnext = orphan->dnext;
++              ubifs_assert(!orphan->new);
++              rb_erase(&orphan->rb, &c->orph_tree);
++              list_del(&orphan->list);
++              c->tot_orphans -= 1;
++              dbg_gen("deleting orphan ino %lu", orphan->inum);
++              kfree(orphan);
++      }
++      c->orph_dnext = NULL;
++      spin_unlock(&c->orphan_lock);
++}
++
++/**
++ * ubifs_orphan_end_commit - end commit of orphans.
++ * @c: UBIFS file-system description object
++ *
++ * End commit of orphans.
++ */
++int ubifs_orphan_end_commit(struct ubifs_info *c)
++{
++      int err;
++
++      if (c->cmt_orphans != 0) {
++              err = commit_orphans(c);
++              if (err)
++                      return err;
++      }
++      erase_deleted(c);
++      err = dbg_check_orphans(c);
++      return err;
++}
++
++/**
++ * clear_orphans - erase all LEBs used for orphans.
++ * @c: UBIFS file-system description object
++ *
++ * If recovery is not required, then the orphans from the previous session
++ * are not needed. This function locates the LEBs used to record
++ * orphans, and un-maps them.
++ */
++static int clear_orphans(struct ubifs_info *c)
++{
++      int lnum, err;
++
++      for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
++              err = ubifs_leb_unmap(c, lnum);
++              if (err)
++                      return err;
++      }
++      c->ohead_lnum = c->orph_first;
++      c->ohead_offs = 0;
++      return 0;
++}
++
++/**
++ * insert_dead_orphan - insert an orphan.
++ * @c: UBIFS file-system description object
++ * @inum: orphan inode number
++ *
++ * This function is a helper to the 'do_kill_orphans()' function. The orphan
++ * must be kept until the next commit, so it is added to the rb-tree and the
++ * deletion list.
++ */
++static int insert_dead_orphan(struct ubifs_info *c, ino_t inum)
++{
++      struct ubifs_orphan *orphan, *o;
++      struct rb_node **p, *parent = NULL;
++
++      orphan = kzalloc(sizeof(struct ubifs_orphan), GFP_KERNEL);
++      if (!orphan)
++              return -ENOMEM;
++      orphan->inum = inum;
++
++      p = &c->orph_tree.rb_node;
++      while (*p) {
++              parent = *p;
++              o = rb_entry(parent, struct ubifs_orphan, rb);
++              if (inum < o->inum)
++                      p = &(*p)->rb_left;
++              else if (inum > o->inum)
++                      p = &(*p)->rb_right;
++              else {
++                      /* Already added - no problem */
++                      kfree(orphan);
++                      return 0;
++              }
++      }
++      c->tot_orphans += 1;
++      rb_link_node(&orphan->rb, parent, p);
++      rb_insert_color(&orphan->rb, &c->orph_tree);
++      list_add_tail(&orphan->list, &c->orph_list);
++      orphan->dnext = c->orph_dnext;
++      c->orph_dnext = orphan;
++      dbg_mnt("ino %lu, new %d, tot %d",
++              inum, c->new_orphans, c->tot_orphans);
++      return 0;
++}
++
++/**
++ * do_kill_orphans - remove orphan inodes from the index.
++ * @c: UBIFS file-system description object
++ * @sleb: scanned LEB
++ * @last_cmt_no: cmt_no of last orph node read is passed and returned here
++ * @outofdate: whether the LEB is out of date is returned here
++ * @last_flagged: whether the end orph node is encountered
++ *
++ * This function is a helper to the 'kill_orphans()' function. It goes through
++ * every orphan node in a LEB and for every inode number recorded, removes
++ * all keys for that inode from the TNC.
++ */
++static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
++                         unsigned long long *last_cmt_no, int *outofdate,
++                         int *last_flagged)
++{
++      struct ubifs_scan_node *snod;
++      struct ubifs_orph_node *orph;
++      unsigned long long cmt_no;
++      ino_t inum;
++      int i, n, err, first = 1;
++
++      list_for_each_entry(snod, &sleb->nodes, list) {
++              if (snod->type != UBIFS_ORPH_NODE) {
++                      ubifs_err("invalid node type %d in orphan area at "
++                                "%d:%d", snod->type, sleb->lnum, snod->offs);
++                      dbg_dump_node(c, snod->node);
++                      return -EINVAL;
++              }
++
++              orph = snod->node;
++
++              /* Check commit number */
++              cmt_no = le64_to_cpu(orph->cmt_no) & LLONG_MAX;
++              /*
++               * The commit number on the master node may be less, because
++               * of a failed commit. If there are several failed commits in a
++               * row, the commit number written on orph nodes will continue to
++               * increase (because the commit number is adjusted here) even
++               * though the commit number on the master node stays the same
++               * because the master node has not been re-written.
++               */
++              if (cmt_no > c->cmt_no)
++                      c->cmt_no = cmt_no;
++              if (cmt_no < *last_cmt_no && *last_flagged) {
++                      /*
++                       * The last orph node had a higher commit number and was
++                       * flagged as the last written for that commit number.
++                       * That makes this orph node, out of date.
++                       */
++                      if (!first) {
++                              ubifs_err("out of order commit number %llu in "
++                                        "orphan node at %d:%d",
++                                        cmt_no, sleb->lnum, snod->offs);
++                              dbg_dump_node(c, snod->node);
++                              return -EINVAL;
++                      }
++                      dbg_rcvry("out of date LEB %d", sleb->lnum);
++                      *outofdate = 1;
++                      return 0;
++              }
++
++              if (first)
++                      first = 0;
++
++              n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3;
++              for (i = 0; i < n; i++) {
++                      inum = le64_to_cpu(orph->inos[i]);
++                      dbg_rcvry("deleting orphaned inode %lu", inum);
++                      err = ubifs_tnc_remove_ino(c, inum);
++                      if (err)
++                              return err;
++                      err = insert_dead_orphan(c, inum);
++                      if (err)
++                              return err;
++              }
++
++              *last_cmt_no = cmt_no;
++              if (le64_to_cpu(orph->cmt_no) & (1ULL << 63)) {
++                      dbg_rcvry("last orph node for commit %llu at %d:%d",
++                                cmt_no, sleb->lnum, snod->offs);
++                      *last_flagged = 1;
++              } else
++                      *last_flagged = 0;
++      }
++
++      return 0;
++}
++
++/**
++ * kill_orphans - remove all orphan inodes from the index.
++ * @c: UBIFS file-system description object
++ *
++ * If recovery is required, then orphan inodes recorded during the previous
++ * session (which ended with an unclean unmount) must be deleted from the index.
++ * This is done by updating the TNC, but since the index is not updated until
++ * the next commit, the LEBs where the orphan information is recorded are not
++ * erased until the next commit.
++ */
++static int kill_orphans(struct ubifs_info *c)
++{
++      unsigned long long last_cmt_no = 0;
++      int lnum, err = 0, outofdate = 0, last_flagged = 0;
++
++      c->ohead_lnum = c->orph_first;
++      c->ohead_offs = 0;
++      /* Check no-orphans flag and skip this if no orphans */
++      if (c->no_orphs) {
++              dbg_rcvry("no orphans");
++              return 0;
++      }
++      /*
++       * Orph nodes always start at c->orph_first and are written to each
++       * successive LEB in turn. Generally unused LEBs will have been unmapped
++       * but may contain out of date orph nodes if the unmap didn't go
++       * through. In addition, the last orph node written for each commit is
++       * marked (top bit of orph->cmt_no is set to 1). It is possible that
++       * there are orph nodes from the next commit (i.e. the commit did not
++       * complete successfully). In that case, no orphans will have been lost
++       * due to the way that orphans are written, and any orphans added will
++       * be valid orphans anyway and so can be deleted.
++       */
++      for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
++              struct ubifs_scan_leb *sleb;
++
++              dbg_rcvry("LEB %d", lnum);
++              sleb = ubifs_scan(c, lnum, 0, c->sbuf);
++              if (IS_ERR(sleb)) {
++                      sleb = ubifs_recover_leb(c, lnum, 0, c->sbuf, 0);
++                      if (IS_ERR(sleb)) {
++                              err = PTR_ERR(sleb);
++                              break;
++                      }
++              }
++              err = do_kill_orphans(c, sleb, &last_cmt_no, &outofdate,
++                                    &last_flagged);
++              if (err || outofdate) {
++                      ubifs_scan_destroy(sleb);
++                      break;
++              }
++              if (sleb->endpt) {
++                      c->ohead_lnum = lnum;
++                      c->ohead_offs = sleb->endpt;
++              }
++              ubifs_scan_destroy(sleb);
++      }
++      return err;
++}
++
++/**
++ * ubifs_mount_orphans - delete orphan inodes and erase LEBs that recorded them.
++ * @c: UBIFS file-system description object
++ * @unclean: indicates recovery from unclean unmount
++ * @read_only: indicates read only mount
++ *
++ * This function is called when mounting to erase orphans from the previous
++ * session. If UBIFS was not unmounted cleanly, then the inodes recorded as
++ * orphans are deleted.
++ */
++int ubifs_mount_orphans(struct ubifs_info *c, int unclean, int read_only)
++{
++      int err = 0;
++
++      c->max_orphans = tot_avail_orphs(c);
++
++      if (!read_only) {
++              c->orph_buf = vmalloc(c->leb_size);
++              if (!c->orph_buf)
++                      return -ENOMEM;
++      }
++
++      if (unclean)
++              err = kill_orphans(c);
++      else if (!read_only)
++              err = clear_orphans(c);
++
++      return err;
++}
++
++#ifdef CONFIG_UBIFS_FS_DEBUG
++
++struct check_orphan {
++      struct rb_node rb;
++      ino_t inum;
++};
++
++struct check_info {
++      unsigned long last_ino;
++      unsigned long tot_inos;
++      unsigned long missing;
++      unsigned long long leaf_cnt;
++      struct ubifs_ino_node *node;
++      struct rb_root root;
++};
++
++static int dbg_find_orphan(struct ubifs_info *c, ino_t inum)
++{
++      struct ubifs_orphan *o;
++      struct rb_node *p;
++
++      spin_lock(&c->orphan_lock);
++      p = c->orph_tree.rb_node;
++      while (p) {
++              o = rb_entry(p, struct ubifs_orphan, rb);
++              if (inum < o->inum)
++                      p = p->rb_left;
++              else if (inum > o->inum)
++                      p = p->rb_right;
++              else {
++                      spin_unlock(&c->orphan_lock);
++                      return 1;
++              }
++      }
++      spin_unlock(&c->orphan_lock);
++      return 0;
++}
++
++static int dbg_ins_check_orphan(struct rb_root *root, ino_t inum)
++{
++      struct check_orphan *orphan, *o;
++      struct rb_node **p, *parent = NULL;
++
++      orphan = kzalloc(sizeof(struct check_orphan), GFP_NOFS);
++      if (!orphan)
++              return -ENOMEM;
++      orphan->inum = inum;
++
++      p = &root->rb_node;
++      while (*p) {
++              parent = *p;
++              o = rb_entry(parent, struct check_orphan, rb);
++              if (inum < o->inum)
++                      p = &(*p)->rb_left;
++              else if (inum > o->inum)
++                      p = &(*p)->rb_right;
++              else {
++                      kfree(orphan);
++                      return 0;
++              }
++      }
++      rb_link_node(&orphan->rb, parent, p);
++      rb_insert_color(&orphan->rb, root);
++      return 0;
++}
++
++static int dbg_find_check_orphan(struct rb_root *root, ino_t inum)
++{
++      struct check_orphan *o;
++      struct rb_node *p;
++
++      p = root->rb_node;
++      while (p) {
++              o = rb_entry(p, struct check_orphan, rb);
++              if (inum < o->inum)
++                      p = p->rb_left;
++              else if (inum > o->inum)
++                      p = p->rb_right;
++              else
++                      return 1;
++      }
++      return 0;
++}
++
++static void dbg_free_check_tree(struct rb_root *root)
++{
++      struct rb_node *this = root->rb_node;
++      struct check_orphan *o;
++
++      while (this) {
++              if (this->rb_left) {
++                      this = this->rb_left;
++                      continue;
++              } else if (this->rb_right) {
++                      this = this->rb_right;
++                      continue;
++              }
++              o = rb_entry(this, struct check_orphan, rb);
++              this = rb_parent(this);
++              if (this) {
++                      if (this->rb_left == &o->rb)
++                              this->rb_left = NULL;
++                      else
++                              this->rb_right = NULL;
++              }
++              kfree(o);
++      }
++}
++
++static int dbg_orphan_check(struct ubifs_info *c, struct ubifs_zbranch *zbr,
++                          void *priv)
++{
++      struct check_info *ci = priv;
++      ino_t inum;
++      int err;
++
++      inum = key_inum(c, &zbr->key);
++      if (inum != ci->last_ino) {
++              /* Lowest node type is the inode node, so it comes first */
++              if (key_type(c, &zbr->key) != UBIFS_INO_KEY)
++                      ubifs_err("found orphan node ino %lu, type %d", inum,
++                                key_type(c, &zbr->key));
++              ci->last_ino = inum;
++              ci->tot_inos += 1;
++              err = ubifs_tnc_read_node(c, zbr, ci->node);
++              if (err) {
++                      ubifs_err("node read failed, error %d", err);
++                      return err;
++              }
++              if (ci->node->nlink == 0)
++                      /* Must be recorded as an orphan */
++                      if (!dbg_find_check_orphan(&ci->root, inum) &&
++                          !dbg_find_orphan(c, inum)) {
++                              ubifs_err("missing orphan, ino %lu", inum);
++                              ci->missing += 1;
++                      }
++      }
++      ci->leaf_cnt += 1;
++      return 0;
++}
++
++static int dbg_read_orphans(struct check_info *ci, struct ubifs_scan_leb *sleb)
++{
++      struct ubifs_scan_node *snod;
++      struct ubifs_orph_node *orph;
++      ino_t inum;
++      int i, n, err;
++
++      list_for_each_entry(snod, &sleb->nodes, list) {
++              cond_resched();
++              if (snod->type != UBIFS_ORPH_NODE)
++                      continue;
++              orph = snod->node;
++              n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3;
++              for (i = 0; i < n; i++) {
++                      inum = le64_to_cpu(orph->inos[i]);
++                      err = dbg_ins_check_orphan(&ci->root, inum);
++                      if (err)
++                              return err;
++              }
++      }
++      return 0;
++}
++
++static int dbg_scan_orphans(struct ubifs_info *c, struct check_info *ci)
++{
++      int lnum, err = 0;
++
++      /* Check no-orphans flag and skip this if no orphans */
++      if (c->no_orphs)
++              return 0;
++
++      for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
++              struct ubifs_scan_leb *sleb;
++
++              sleb = ubifs_scan(c, lnum, 0, c->dbg_buf);
++              if (IS_ERR(sleb)) {
++                      err = PTR_ERR(sleb);
++                      break;
++              }
++
++              err = dbg_read_orphans(ci, sleb);
++              ubifs_scan_destroy(sleb);
++              if (err)
++                      break;
++      }
++
++      return err;
++}
++
++static int dbg_check_orphans(struct ubifs_info *c)
++{
++      struct check_info ci;
++      int err;
++
++      if (!(ubifs_chk_flags & UBIFS_CHK_ORPH))
++              return 0;
++
++      ci.last_ino = 0;
++      ci.tot_inos = 0;
++      ci.missing  = 0;
++      ci.leaf_cnt = 0;
++      ci.root = RB_ROOT;
++      ci.node = kmalloc(UBIFS_MAX_INO_NODE_SZ, GFP_NOFS);
++      if (!ci.node) {
++              ubifs_err("out of memory");
++              return -ENOMEM;
++      }
++
++      err = dbg_scan_orphans(c, &ci);
++      if (err)
++              goto out;
++
++      err = dbg_walk_index(c, &dbg_orphan_check, NULL, &ci);
++      if (err) {
++              ubifs_err("cannot scan TNC, error %d", err);
++              goto out;
++      }
++
++      if (ci.missing) {
++              ubifs_err("%lu missing orphan(s)", ci.missing);
++              err = -EINVAL;
++              goto out;
++      }
++
++      dbg_cmt("last inode number is %lu", ci.last_ino);
++      dbg_cmt("total number of inodes is %lu", ci.tot_inos);
++      dbg_cmt("total number of leaf nodes is %llu", ci.leaf_cnt);
++
++out:
++      dbg_free_check_tree(&ci.root);
++      kfree(ci.node);
++      return err;
++}
++
++#endif /* CONFIG_UBIFS_FS_DEBUG */
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/recovery.c avr32-2.6/fs/ubifs/recovery.c
+--- linux-2.6.25.6/fs/ubifs/recovery.c 1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/recovery.c      2008-06-12 15:09:45.475816115 +0200
+@@ -0,0 +1,1537 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Adrian Hunter
++ *          Artem Bityutskiy (Битюцкий Артём)
++ */
++
++/*
++ * This file implements functions needed to recover from unclean un-mounts.
++ * When UBIFS is mounted, it checks a flag on the master node to determine if
++ * an un-mount was completed sucessfully. If not, the process of mounting
++ * incorparates additional checking and fixing of on-flash data structures.
++ * UBIFS always cleans away all remnants of an unclean un-mount, so that
++ * errors do not accumulate. However UBIFS defers recovery if it is mounted
++ * read-only, and the flash is not modified in that case.
++ */
++
++#include <linux/crc32.h>
++#include "ubifs.h"
++
++/**
++ * is_empty - determine whether a buffer is empty (contains all 0xff).
++ * @buf: buffer to clean
++ * @len: length of buffer
++ *
++ * This function returns %1 if the buffer is empty (contains all 0xff) otherwise
++ * %0 is returned.
++ */
++static int is_empty(void *buf, int len)
++{
++      uint8_t *p = buf;
++      int i;
++
++      for (i = 0; i < len; i++)
++              if (*p++ != 0xff)
++                      return 0;
++      return 1;
++}
++
++/**
++ * get_master_node - get the last valid master node allowing for corruption.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number
++ * @pbuf: buffer containing the LEB read, is returned here
++ * @mst: master node, if found, is returned here
++ * @cor: corruption, if found, is returned here
++ *
++ * This function allocates a buffer, reads the LEB into it, and finds and
++ * returns the last valid master node allowing for one area of corruption.
++ * The corrupt area, if there is one, must be consistent with the assumption
++ * that it is the result of an unclean unmount while the master node was being
++ * written. Under those circumstances, it is valid to use the previously written
++ * master node.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int get_master_node(const struct ubifs_info *c, int lnum, void **pbuf,
++                         struct ubifs_mst_node **mst, void **cor)
++{
++      const int sz = c->mst_node_alsz;
++      int err, offs, len;
++      void *sbuf, *buf;
++
++      sbuf = vmalloc(c->leb_size);
++      if (!sbuf)
++              return -ENOMEM;
++
++      err = ubi_read(c->ubi, lnum, sbuf, 0, c->leb_size);
++      if (err && err != -EBADMSG)
++              goto out_free;
++
++      /* Find the first position that is definitely not a node */
++      offs = 0;
++      buf = sbuf;
++      len = c->leb_size;
++      while (offs + UBIFS_MST_NODE_SZ <= c->leb_size) {
++              struct ubifs_ch *ch = buf;
++
++              if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC)
++                      break;
++              offs += sz;
++              buf  += sz;
++              len  -= sz;
++      }
++      /* See if there was a valid master node before that */
++      if (offs) {
++              int ret;
++
++              offs -= sz;
++              buf  -= sz;
++              len  += sz;
++              ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
++              if (ret != SCANNED_A_NODE && offs) {
++                      /* Could have been corruption so check one place back */
++                      offs -= sz;
++                      buf  -= sz;
++                      len  += sz;
++                      ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
++                      if (ret != SCANNED_A_NODE)
++                              /*
++                               * We accept only one area of corruption because
++                               * we are assuming that it was caused while
++                               * trying to write a master node.
++                               */
++                              goto out_err;
++              }
++              if (ret == SCANNED_A_NODE) {
++                      struct ubifs_ch *ch = buf;
++
++                      if (ch->node_type != UBIFS_MST_NODE)
++                              goto out_err;
++                      dbg_rcvry("found a master node at %d:%d", lnum, offs);
++                      *mst = buf;
++                      offs += sz;
++                      buf  += sz;
++                      len  -= sz;
++              }
++      }
++      /* Check for corruption */
++      if (offs < c->leb_size) {
++              if (!is_empty(buf, min_t(int, len, sz))) {
++                      *cor = buf;
++                      dbg_rcvry("found corruption at %d:%d", lnum, offs);
++              }
++              offs += sz;
++              buf  += sz;
++              len  -= sz;
++      }
++      /* Check remaining empty space */
++      if (offs < c->leb_size)
++              if (!is_empty(buf, len))
++                      goto out_err;
++      *pbuf = sbuf;
++      return 0;
++
++out_err:
++      err = -EINVAL;
++out_free:
++      vfree(sbuf);
++      *mst = NULL;
++      *cor = NULL;
++      return err;
++}
++
++/**
++ * write_rcvrd_mst_node - write recovered master node.
++ * @c: UBIFS file-system description object
++ * @mst: master node
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int write_rcvrd_mst_node(struct ubifs_info *c,
++                              struct ubifs_mst_node *mst)
++{
++      int err = 0, lnum = UBIFS_MST_LNUM, sz = c->mst_node_alsz;
++      uint32_t save_flags;
++
++      dbg_rcvry("recovery");
++
++      save_flags = mst->flags;
++      mst->flags = cpu_to_le32(le32_to_cpu(mst->flags) | UBIFS_MST_RCVRY);
++
++      ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1);
++      err = ubi_leb_change(c->ubi, lnum, mst, sz, UBI_SHORTTERM);
++      if (err)
++              goto out;
++      err = ubi_leb_change(c->ubi, lnum + 1, mst, sz, UBI_SHORTTERM);
++      if (err)
++              goto out;
++out:
++      mst->flags = save_flags;
++      return err;
++}
++
++/**
++ * ubifs_recover_master_node - recover the master node.
++ * @c: UBIFS file-system description object
++ *
++ * This function recovers the master node from corruption that may occur due to
++ * an unclean unmount.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++int ubifs_recover_master_node(struct ubifs_info *c)
++{
++      void *buf1 = NULL, *buf2 = NULL, *cor1 = NULL, *cor2 = NULL;
++      struct ubifs_mst_node *mst1 = NULL, *mst2 = NULL, *mst;
++      const int sz = c->mst_node_alsz;
++      int err, offs1, offs2;
++
++      dbg_rcvry("recovery");
++
++      err = get_master_node(c, UBIFS_MST_LNUM, &buf1, &mst1, &cor1);
++      if (err)
++              goto out_free;
++
++      err = get_master_node(c, UBIFS_MST_LNUM + 1, &buf2, &mst2, &cor2);
++      if (err)
++              goto out_free;
++
++      if (mst1) {
++              offs1 = (void *)mst1 - buf1;
++              if ((le32_to_cpu(mst1->flags) & UBIFS_MST_RCVRY) &&
++                  (offs1 == 0 && !cor1)) {
++                      /*
++                       * mst1 was written by recovery at offset 0 with no
++                       * corruption.
++                       */
++                      dbg_rcvry("recovery recovery");
++                      mst = mst1;
++              } else if (mst2) {
++                      offs2 = (void *)mst2 - buf2;
++                      if (offs1 == offs2) {
++                              /* Same offset, so must be the same */
++                              if (memcmp((void *)mst1 + UBIFS_CH_SZ,
++                                         (void *)mst2 + UBIFS_CH_SZ,
++                                         UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
++                                      goto out_err;
++                              mst = mst1;
++                      } else if (offs2 + sz == offs1) {
++                              /* 1st LEB was written, 2nd was not */
++                              if (cor1)
++                                      goto out_err;
++                              mst = mst1;
++                      } else if (offs1 == 0 && offs2 + sz >= c->leb_size) {
++                              /* 1st LEB was unmapped and written, 2nd not */
++                              if (cor1)
++                                      goto out_err;
++                              mst = mst1;
++                      } else
++                              goto out_err;
++              } else {
++                      /*
++                       * 2nd LEB was unmapped and about to be written, so
++                       * there must be only one master node in the first LEB
++                       * and no corruption.
++                       */
++                      if (offs1 != 0 || cor1)
++                              goto out_err;
++                      mst = mst1;
++              }
++      } else {
++              if (!mst2)
++                      goto out_err;
++              /*
++               * 1st LEB was unmapped and about to be written, so there must
++               * be no room left in 2nd LEB.
++               */
++              offs2 = (void *)mst2 - buf2;
++              if (offs2 + sz + sz <= c->leb_size)
++                      goto out_err;
++              mst = mst2;
++      }
++
++      dbg_rcvry("recovered master node from LEB %d",
++                (mst == mst1 ? UBIFS_MST_LNUM : UBIFS_MST_LNUM + 1));
++
++      memcpy(c->mst_node, mst, UBIFS_MST_NODE_SZ);
++
++      if ((c->vfs_sb->s_flags & MS_RDONLY)) {
++              /* Read-only mode. Keep a copy for switching to rw mode */
++              c->rcvrd_mst_node = kmalloc(sz, GFP_KERNEL);
++              if (!c->rcvrd_mst_node) {
++                      err = -ENOMEM;
++                      goto out_free;
++              }
++              memcpy(c->rcvrd_mst_node, c->mst_node, UBIFS_MST_NODE_SZ);
++      } else {
++              /* Write the recovered master node */
++              c->max_sqnum = le64_to_cpu(mst->ch.sqnum) - 1;
++              err = write_rcvrd_mst_node(c, c->mst_node);
++              if (err)
++                      goto out_free;
++      }
++
++      vfree(buf2);
++      vfree(buf1);
++
++      return 0;
++
++out_err:
++      err = -EINVAL;
++out_free:
++      ubifs_err("failed to recover master node");
++      if (mst1) {
++              dbg_err("dumping first master node");
++              dbg_dump_node(c, mst1);
++      }
++      if (mst2) {
++              dbg_err("dumping second master node");
++              dbg_dump_node(c, mst2);
++      }
++      vfree(buf2);
++      vfree(buf1);
++      return err;
++}
++
++/**
++ * ubifs_write_rcvrd_mst_node - write the recovered master node.
++ * @c: UBIFS file-system description object
++ *
++ * This function writes the master node that was recovered during mounting in
++ * read-only mode and must now be written because we are remounting rw.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++int ubifs_write_rcvrd_mst_node(struct ubifs_info *c)
++{
++      int err;
++
++      if (!c->rcvrd_mst_node)
++              return 0;
++      c->rcvrd_mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
++      c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
++      err = write_rcvrd_mst_node(c, c->rcvrd_mst_node);
++      if (err)
++              return err;
++      kfree(c->rcvrd_mst_node);
++      c->rcvrd_mst_node = NULL;
++      return 0;
++}
++
++/**
++ * is_last_write - determine if an offset was in the last write to a LEB.
++ * @c: UBIFS file-system description object
++ * @buf: buffer to check
++ * @offs: offset to check
++ *
++ * This function returns %1 if @offs was in the last write to the LEB whose data
++ * is in @buf, otherwise %0 is returned.  The determination is made by checking
++ * for subsequent empty space starting from the next min_io_size boundary (or a
++ * bit less than the common header size if min_io_size is one).
++ */
++static int is_last_write(const struct ubifs_info *c, void *buf, int offs)
++{
++      int empty_offs;
++      int check_len;
++      uint8_t *p;
++
++      if (c->min_io_size == 1) {
++              check_len = c->leb_size - offs;
++              p = buf + check_len;
++              for (; check_len > 0; check_len--)
++                      if (*--p != 0xff)
++                              break;
++              /*
++               * 'check_len' is the size of the corruption which cannot be
++               * more than the size of 1 node if it was caused by an unclean
++               * unmount.
++               */
++              if (check_len > UBIFS_MAX_NODE_SZ)
++                      return 0;
++              return 1;
++      }
++
++      /*
++       * Round up to the next c->min_io_size boundary i.e. 'offs' is in the
++       * last wbuf written. After that should be empty space.
++       */
++      empty_offs = ALIGN(offs + 1, c->min_io_size);
++      check_len = c->leb_size - empty_offs;
++      p = buf + empty_offs - offs;
++
++      for (; check_len > 0; check_len--)
++              if (*p++ != 0xff)
++                      return 0;
++      return 1;
++}
++
++/**
++ * clean_buf - clean the data from an LEB sitting in a buffer.
++ * @c: UBIFS file-system description object
++ * @buf: buffer to clean
++ * @lnum: LEB number to clean
++ * @offs: offset from which to clean
++ * @len: length of buffer
++ *
++ * This function pads up to the next min_io_size boundary (if there is one) and
++ * sets empty space to all 0xff. @buf, @offs and @len are updated to the next
++ * min_io_size boundary (if there is one).
++ */
++static void clean_buf(const struct ubifs_info *c, void **buf, int lnum,
++                    int *offs, int *len)
++{
++      int empty_offs, pad_len;
++
++      lnum = lnum;
++      dbg_rcvry("cleaning corruption at %d:%d", lnum, *offs);
++
++      if (c->min_io_size == 1) {
++              memset(*buf, 0xff, c->leb_size - *offs);
++              return;
++      }
++
++      ubifs_assert(!(*offs & 7));
++      empty_offs = ALIGN(*offs, c->min_io_size);
++      pad_len = empty_offs - *offs;
++      ubifs_pad(c, *buf, pad_len);
++      *offs += pad_len;
++      *buf += pad_len;
++      *len -= pad_len;
++      memset(*buf, 0xff, c->leb_size - empty_offs);
++}
++
++/**
++ * no_more_nodes - determine if there are no more nodes in a buffer.
++ * @c: UBIFS file-system description object
++ * @buf: buffer to check
++ * @len: length of buffer
++ * @lnum: LEB number of the LEB from which @buf was read
++ * @offs: offset from which @buf was read
++ *
++ * This function scans @buf for more nodes and returns %0 is a node is found and
++ * %1 if no more nodes are found.
++ */
++static int no_more_nodes(const struct ubifs_info *c, void *buf, int len,
++                      int lnum, int offs)
++{
++      int skip, next_offs = 0;
++
++      if (len > UBIFS_DATA_NODE_SZ) {
++              struct ubifs_ch *ch = buf;
++              int dlen = le32_to_cpu(ch->len);
++
++              if (ch->node_type == UBIFS_DATA_NODE && dlen >= UBIFS_CH_SZ &&
++                  dlen <= UBIFS_MAX_DATA_NODE_SZ)
++                      /* The corrupt node looks like a data node */
++                      next_offs = ALIGN(offs + dlen, 8);
++      }
++
++      if (c->min_io_size == 1)
++              skip = 8;
++      else
++              skip = ALIGN(offs + 1, c->min_io_size) - offs;
++
++      offs += skip;
++      buf += skip;
++      len -= skip;
++      while (len > 8) {
++              struct ubifs_ch *ch = buf;
++              uint32_t magic = le32_to_cpu(ch->magic);
++              int ret;
++
++              if (magic == UBIFS_NODE_MAGIC) {
++                      ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
++                      if (ret == SCANNED_A_NODE || ret > 0) {
++                              /*
++                               * There is a small chance this is just data in
++                               * a data node, so check that possibility. e.g.
++                               * this is part of a file that itself contains
++                               * a UBIFS image.
++                               */
++                              if (next_offs && offs + le32_to_cpu(ch->len) <=
++                                  next_offs)
++                                      continue;
++                              dbg_rcvry("unexpected node at %d:%d", lnum,
++                                        offs);
++                              return 0;
++                      }
++              }
++              offs += 8;
++              buf += 8;
++              len -= 8;
++      }
++      return 1;
++}
++
++/**
++ * fix_unclean_leb - fix an unclean LEB.
++ * @c: UBIFS file-system description object
++ * @sleb: scanned LEB information
++ * @start: offset where scan started
++ */
++static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
++                         int start)
++{
++      int lnum = sleb->lnum, endpt = start;
++
++      /* Get the end offset of the last node we are keeping */
++      if (!list_empty(&sleb->nodes)) {
++              struct ubifs_scan_node *snod;
++
++              snod = list_entry(sleb->nodes.prev,
++                                struct ubifs_scan_node, list);
++              endpt = snod->offs + snod->len;
++      }
++
++      if ((c->vfs_sb->s_flags & MS_RDONLY) && !c->remounting_rw) {
++              /* Add to recovery list */
++              struct ubifs_unclean_leb *ucleb;
++
++              dbg_rcvry("need to fix LEB %d start %d endpt %d",
++                        lnum, start, sleb->endpt);
++              ucleb = kzalloc(sizeof(struct ubifs_unclean_leb), GFP_NOFS);
++              if (!ucleb)
++                      return -ENOMEM;
++              ucleb->lnum = lnum;
++              ucleb->endpt = endpt;
++              list_add_tail(&ucleb->list, &c->unclean_leb_list);
++      } else {
++              /* Write the fixed LEB back to flash */
++              int err;
++
++              dbg_rcvry("fixing LEB %d start %d endpt %d",
++                        lnum, start, sleb->endpt);
++              if (endpt == 0) {
++                      err = ubifs_leb_unmap(c, lnum);
++                      if (err)
++                              return err;
++              } else {
++                      int len = ALIGN(endpt, c->min_io_size);
++
++                      if (start) {
++                              err = ubi_read(c->ubi, lnum, sleb->buf, 0,
++                                             start);
++                              if (err)
++                                      return err;
++                      }
++                      /* Pad to min_io_size */
++                      if (len > endpt) {
++                              int pad_len = len - ALIGN(endpt, 8);
++
++                              if (pad_len > 0) {
++                                      void *buf = sleb->buf + len - pad_len;
++
++                                      ubifs_pad(c, buf, pad_len);
++                              }
++                      }
++                      err = ubi_leb_change(c->ubi, lnum, sleb->buf, len,
++                                           UBI_UNKNOWN);
++                      if (err)
++                              return err;
++              }
++      }
++      return 0;
++}
++
++/**
++ * drop_incomplete_group - drop nodes from an incomplete group.
++ * @sleb: scanned LEB information
++ * @offs: offset of dropped nodes is returned here
++ *
++ * This function returns %1 if nodes are dropped and %0 otherwise.
++ */
++static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
++{
++      int dropped = 0;
++
++      while (!list_empty(&sleb->nodes)) {
++              struct ubifs_scan_node *snod;
++              struct ubifs_ch *ch;
++
++              snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node,
++                                list);
++              ch = snod->node;
++              if (ch->group_type != UBIFS_IN_NODE_GROUP)
++                      return dropped;
++              dbg_rcvry("dropping node at %d:%d", sleb->lnum, snod->offs);
++              *offs = snod->offs;
++              list_del(&snod->list);
++              kfree(snod);
++              sleb->nodes_cnt -= 1;
++              dropped = 1;
++      }
++      return dropped;
++}
++
++/**
++ * ubifs_recover_leb - scan and recover a LEB.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number
++ * @offs: offset
++ * @sbuf: LEB-sized buffer to use
++ * @grouped: nodes may be grouped for recovery
++ *
++ * This function does a scan of a LEB, but caters for errors that might have
++ * been caused by the unclean unmount from which we are attempting to recover.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
++                                       int offs, void *sbuf, int grouped)
++{
++      int err, len = c->leb_size - offs, need_clean = 0, quiet = 1;
++      int empty_chkd = 0, start = offs;
++      struct ubifs_scan_leb *sleb;
++      void *buf = sbuf + offs;
++
++      dbg_rcvry("%d:%d", lnum, offs);
++
++      sleb = ubifs_start_scan(c, lnum, offs, sbuf);
++      if (IS_ERR(sleb))
++              return sleb;
++
++      if (sleb->ecc)
++              need_clean = 1;
++
++      while (len >= 8) {
++              int ret;
++
++              dbg_scan("look at LEB %d:%d (%d bytes left)",
++                       lnum, offs, len);
++
++              cond_resched();
++
++              /*
++               * Scan quietly until there is an error from which we cannot
++               * recover
++               */
++              ret = ubifs_scan_a_node(c, buf, len, lnum, offs, quiet);
++
++              if (ret == SCANNED_A_NODE) {
++                      /* A valid node, and not a padding node */
++                      struct ubifs_ch *ch = buf;
++                      int node_len;
++
++                      err = ubifs_add_snod(c, sleb, buf, offs);
++                      if (err)
++                              goto error;
++                      node_len = ALIGN(le32_to_cpu(ch->len), 8);
++                      offs += node_len;
++                      buf += node_len;
++                      len -= node_len;
++                      continue;
++              }
++
++              if (ret > 0) {
++                      /* Padding bytes or a valid padding node */
++                      offs += ret;
++                      buf += ret;
++                      len -= ret;
++                      continue;
++              }
++
++              if (ret == SCANNED_EMPTY_SPACE) {
++                      if (!is_empty(buf, len)) {
++                              if (!is_last_write(c, buf, offs))
++                                      break;
++                              clean_buf(c, &buf, lnum, &offs, &len);
++                              need_clean = 1;
++                      }
++                      empty_chkd = 1;
++                      break;
++              }
++
++              if (ret == SCANNED_GARBAGE || ret == SCANNED_A_BAD_PAD_NODE)
++                      if (is_last_write(c, buf, offs)) {
++                              clean_buf(c, &buf, lnum, &offs, &len);
++                              need_clean = 1;
++                              empty_chkd = 1;
++                              break;
++                      }
++
++              if (ret == SCANNED_A_CORRUPT_NODE)
++                      if (no_more_nodes(c, buf, len, lnum, offs)) {
++                              clean_buf(c, &buf, lnum, &offs, &len);
++                              need_clean = 1;
++                              empty_chkd = 1;
++                              break;
++                      }
++
++              if (quiet) {
++                      /* Redo the last scan but noisily */
++                      quiet = 0;
++                      continue;
++              }
++
++              switch (ret) {
++              case SCANNED_GARBAGE:
++                      dbg_err("garbage");
++                      goto corrupted;
++              case SCANNED_A_CORRUPT_NODE:
++              case SCANNED_A_BAD_PAD_NODE:
++                      dbg_err("bad node");
++                      goto corrupted;
++              default:
++                      dbg_err("unknown");
++                      goto corrupted;
++              }
++      }
++
++      if (!empty_chkd && !is_empty(buf, len)) {
++              if (is_last_write(c, buf, offs)) {
++                      clean_buf(c, &buf, lnum, &offs, &len);
++                      need_clean = 1;
++              } else {
++                      ubifs_err("corrupt empty space at LEB %d:%d",
++                                lnum, offs);
++                      goto corrupted;
++              }
++      }
++
++      /* Drop nodes from incomplete group */
++      if (grouped && drop_incomplete_group(sleb, &offs)) {
++              buf = sbuf + offs;
++              len = c->leb_size - offs;
++              clean_buf(c, &buf, lnum, &offs, &len);
++              need_clean = 1;
++      }
++
++      if (offs % c->min_io_size) {
++              clean_buf(c, &buf, lnum, &offs, &len);
++              need_clean = 1;
++      }
++
++      ubifs_end_scan(c, sleb, lnum, offs);
++
++      if (need_clean) {
++              err = fix_unclean_leb(c, sleb, start);
++              if (err)
++                      goto error;
++      }
++
++      return sleb;
++
++corrupted:
++      ubifs_scanned_corruption(c, lnum, offs, buf);
++      err = -EUCLEAN;
++error:
++      ubifs_err("LEB %d scanning failed", lnum);
++      ubifs_scan_destroy(sleb);
++      return ERR_PTR(err);
++}
++
++/**
++ * get_cs_sqnum - get commit start sequence number.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number of commit start node
++ * @offs: offset of commit start node
++ * @cs_sqnum: commit start sequence number is returned here
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int get_cs_sqnum(struct ubifs_info *c, int lnum, int offs,
++                      unsigned long long *cs_sqnum)
++{
++      struct ubifs_cs_node *cs_node = NULL;
++      int err, ret;
++
++      dbg_rcvry("at %d:%d", lnum, offs);
++      cs_node = kmalloc(UBIFS_CS_NODE_SZ, GFP_KERNEL);
++      if (!cs_node)
++              return -ENOMEM;
++      if (c->leb_size - offs < UBIFS_CS_NODE_SZ)
++              goto out_err;
++      err = ubi_read(c->ubi, lnum, (void *)cs_node, offs, UBIFS_CS_NODE_SZ);
++      if (err && err != -EBADMSG)
++              goto out_free;
++      ret = ubifs_scan_a_node(c, cs_node, UBIFS_CS_NODE_SZ, lnum, offs, 0);
++      if (ret != SCANNED_A_NODE) {
++              dbg_err("Not a valid node");
++              goto out_err;
++      }
++      if (cs_node->ch.node_type != UBIFS_CS_NODE) {
++              dbg_err("Node a CS node, type is %d", cs_node->ch.node_type);
++              goto out_err;
++      }
++      if (le64_to_cpu(cs_node->cmt_no) != c->cmt_no) {
++              dbg_err("CS node cmt_no %llu != current cmt_no %llu",
++                      (unsigned long long)le64_to_cpu(cs_node->cmt_no),
++                      c->cmt_no);
++              goto out_err;
++      }
++      *cs_sqnum = le64_to_cpu(cs_node->ch.sqnum);
++      dbg_rcvry("commit start sqnum %llu", *cs_sqnum);
++      kfree(cs_node);
++      return 0;
++
++out_err:
++      err = -EINVAL;
++out_free:
++      ubifs_err("failed to get CS sqnum");
++      kfree(cs_node);
++      return err;
++}
++
++/**
++ * ubifs_recover_log_leb - scan and recover a log LEB.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number
++ * @offs: offset
++ * @sbuf: LEB-sized buffer to use
++ *
++ * This function does a scan of a LEB, but caters for errors that might have
++ * been caused by the unclean unmount from which we are attempting to recover.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
++                                           int offs, void *sbuf)
++{
++      struct ubifs_scan_leb *sleb;
++      int next_lnum;
++
++      dbg_rcvry("LEB %d", lnum);
++      next_lnum = lnum + 1;
++      if (next_lnum >= UBIFS_LOG_LNUM + c->log_lebs)
++              next_lnum = UBIFS_LOG_LNUM;
++      if (next_lnum != c->ltail_lnum) {
++              /*
++               * We can only recover at the end of the log, so check that the
++               * next log LEB is empty or out of date.
++               */
++              sleb = ubifs_scan(c, next_lnum, 0, sbuf);
++              if (IS_ERR(sleb))
++                      return sleb;
++              if (sleb->nodes_cnt) {
++                      struct ubifs_scan_node *snod;
++                      unsigned long long cs_sqnum = c->cs_sqnum;
++
++                      snod = list_entry(sleb->nodes.next,
++                                        struct ubifs_scan_node, list);
++                      if (cs_sqnum == 0) {
++                              int err;
++
++                              err = get_cs_sqnum(c, lnum, offs, &cs_sqnum);
++                              if (err) {
++                                      ubifs_scan_destroy(sleb);
++                                      return ERR_PTR(err);
++                              }
++                      }
++                      if (snod->sqnum > cs_sqnum) {
++                              ubifs_err("unrecoverable log corruption "
++                                        "in LEB %d", lnum);
++                              ubifs_scan_destroy(sleb);
++                              return ERR_PTR(-EUCLEAN);
++                      }
++              }
++              ubifs_scan_destroy(sleb);
++      }
++      return ubifs_recover_leb(c, lnum, offs, sbuf, 0);
++}
++
++/**
++ * recover_head - recover a head.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number of head to recover
++ * @offs: offset of head to recover
++ * @sbuf: LEB-sized buffer to use
++ *
++ * This function ensures that there is no data on the flash at a head location.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int recover_head(const struct ubifs_info *c, int lnum, int offs,
++                      void *sbuf)
++{
++      int len, err, need_clean = 0;
++
++      if (c->min_io_size > 1)
++              len = c->min_io_size;
++      else
++              len = 512;
++      if (offs + len > c->leb_size)
++              len = c->leb_size - offs;
++
++      if (!len)
++              return 0;
++
++      /* Read at the head location and check it is empty flash */
++      err = ubi_read(c->ubi, lnum, sbuf, offs, len);
++      if (err)
++              need_clean = 1;
++      else {
++              uint8_t *p = sbuf;
++
++              while (len--)
++                      if (*p++ != 0xff) {
++                              need_clean = 1;
++                              break;
++                      }
++      }
++
++      if (need_clean) {
++              dbg_rcvry("cleaning head at %d:%d", lnum, offs);
++              if (offs == 0)
++                      return ubifs_leb_unmap(c, lnum);
++              err = ubi_read(c->ubi, lnum, sbuf, 0, offs);
++              if (err)
++                      return err;
++              return ubi_leb_change(c->ubi, lnum, sbuf, offs, UBI_UNKNOWN);
++      }
++
++      return 0;
++}
++
++/**
++ * ubifs_recover_inl_heads - recover index and LPT heads.
++ * @c: UBIFS file-system description object
++ * @sbuf: LEB-sized buffer to use
++ *
++ * This function ensures that there is no data on the flash at the index and
++ * LPT head locations.
++ *
++ * This deals with the recovery of a half-completed journal commit. UBIFS is
++ * careful never to overwrite the last version of the index or the LPT. Because
++ * the index and LPT are wandering trees, data from a half-completed commit will
++ * not be referenced anywhere in UBIFS. The data will be either in LEBs that are
++ * assumed to be empty and will be unmapped anyway before use, or in the index
++ * and LPT heads.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf)
++{
++      int err;
++
++      ubifs_assert(!(c->vfs_sb->s_flags & MS_RDONLY) || c->remounting_rw);
++
++      dbg_rcvry("checking index head at %d:%d", c->ihead_lnum, c->ihead_offs);
++      err = recover_head(c, c->ihead_lnum, c->ihead_offs, sbuf);
++      if (err)
++              return err;
++
++      dbg_rcvry("checking LPT head at %d:%d", c->nhead_lnum, c->nhead_offs);
++      err = recover_head(c, c->nhead_lnum, c->nhead_offs, sbuf);
++      if (err)
++              return err;
++
++      return 0;
++}
++
++/**
++ *  clean_an_unclean_leb - read and write a LEB to remove corruption.
++ * @c: UBIFS file-system description object
++ * @ucleb: unclean LEB information
++ * @sbuf: LEB-sized buffer to use
++ *
++ * This function reads a LEB up to a point pre-determined by the mount recovery,
++ * checks the nodes, and writes the result back to the flash, thereby cleaning
++ * off any following corruption, or non-fatal ECC errors.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int clean_an_unclean_leb(const struct ubifs_info *c,
++                              struct ubifs_unclean_leb *ucleb, void *sbuf)
++{
++      int err, lnum = ucleb->lnum, offs = 0, len = ucleb->endpt, quiet = 1;
++      void *buf = sbuf;
++
++      dbg_rcvry("LEB %d len %d", lnum, len);
++
++      if (len == 0) {
++              /* Nothing to read, just unmap it */
++              err = ubifs_leb_unmap(c, lnum);
++              if (err)
++                      return err;
++              return 0;
++      }
++
++      err = ubi_read(c->ubi, lnum, buf, offs, len);
++      if (err && err != -EBADMSG)
++              return err;
++
++      while (len >= 8) {
++              int ret;
++
++              cond_resched();
++
++              /* Scan quietly until there is an error */
++              ret = ubifs_scan_a_node(c, buf, len, lnum, offs, quiet);
++
++              if (ret == SCANNED_A_NODE) {
++                      /* A valid node, and not a padding node */
++                      struct ubifs_ch *ch = buf;
++                      int node_len;
++
++                      node_len = ALIGN(le32_to_cpu(ch->len), 8);
++                      offs += node_len;
++                      buf += node_len;
++                      len -= node_len;
++                      continue;
++              }
++
++              if (ret > 0) {
++                      /* Padding bytes or a valid padding node */
++                      offs += ret;
++                      buf += ret;
++                      len -= ret;
++                      continue;
++              }
++
++              if (ret == SCANNED_EMPTY_SPACE) {
++                      ubifs_err("unexpected empty space at %d:%d",
++                                lnum, offs);
++                      return -EUCLEAN;
++              }
++
++              if (quiet) {
++                      /* Redo the last scan but noisily */
++                      quiet = 0;
++                      continue;
++              }
++
++              ubifs_scanned_corruption(c, lnum, offs, buf);
++              return -EUCLEAN;
++      }
++
++      /* Pad to min_io_size */
++      len = ALIGN(ucleb->endpt, c->min_io_size);
++      if (len > ucleb->endpt) {
++              int pad_len = len - ALIGN(ucleb->endpt, 8);
++
++              if (pad_len > 0) {
++                      buf = c->sbuf + len - pad_len;
++                      ubifs_pad(c, buf, pad_len);
++              }
++      }
++
++      /* Write back the LEB atomically */
++      err = ubi_leb_change(c->ubi, lnum, sbuf, len, UBI_UNKNOWN);
++      if (err)
++              return err;
++
++      dbg_rcvry("cleaned LEB %d", lnum);
++
++      return 0;
++}
++
++/**
++ * ubifs_clean_lebs - clean LEBs recovered during read-only mount.
++ * @c: UBIFS file-system description object
++ * @sbuf: LEB-sized buffer to use
++ *
++ * This function cleans a LEB identified during recovery that needs to be
++ * written but was not because UBIFS was mounted read-only. This happens when
++ * remounting to read-write mode.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf)
++{
++      dbg_rcvry("recovery");
++      while (!list_empty(&c->unclean_leb_list)) {
++              struct ubifs_unclean_leb *ucleb;
++              int err;
++
++              ucleb = list_entry(c->unclean_leb_list.next,
++                                 struct ubifs_unclean_leb, list);
++              err = clean_an_unclean_leb(c, ucleb, sbuf);
++              if (err)
++                      return err;
++              list_del(&ucleb->list);
++              kfree(ucleb);
++      }
++      return 0;
++}
++
++/**
++ * ubifs_rcvry_gc_commit - recover the GC LEB number and run the commit.
++ * @c: UBIFS file-system description object
++ *
++ * Out-of-place garbage collection requires always one empty LEB with which to
++ * start garbage collection. The LEB number is recorded in c->gc_lnum and is
++ * written to the master node on unmounting. In the case of an unclean unmount
++ * the value of gc_lnum recorded in the master node is out of date and cannot
++ * be used. Instead, recovery must allocate an empty LEB for this purpose.
++ * However, there may not be enough empty space, in which case it must be
++ * possible to GC the dirtiest LEB into the GC head LEB.
++ *
++ * This function also runs the commit which causes the TNC updates from
++ * size-recovery and orphans to be written to the flash. That is important to
++ * ensure correct replay order for subsequent mounts.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++int ubifs_rcvry_gc_commit(struct ubifs_info *c)
++{
++      struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
++      struct ubifs_lprops lp;
++      int lnum, err;
++
++      c->gc_lnum = -1;
++      if (wbuf->lnum == -1) {
++              dbg_rcvry("no GC head LEB");
++              goto find_free;
++      }
++      /*
++       * See whether the used space in the dirtiest LEB fits in the GC head
++       * LEB.
++       */
++      if (wbuf->offs == c->leb_size) {
++              dbg_rcvry("no room in GC head LEB");
++              goto find_free;
++      }
++      err = ubifs_find_dirty_leb(c, &lp, wbuf->offs, 2);
++      if (err) {
++              if (err == -ENOSPC)
++                      dbg_err("could not find a dirty LEB");
++              return err;
++      }
++      ubifs_assert(!(lp.flags & LPROPS_INDEX));
++      lnum = lp.lnum;
++      if (lp.free + lp.dirty == c->leb_size) {
++              /* An empty LEB was returned */
++              if (lp.free != c->leb_size) {
++                      err = ubifs_change_one_lp(c, lnum, c->leb_size,
++                                                0, 0, 0, 0);
++                      if (err)
++                              return err;
++              }
++              err = ubifs_leb_unmap(c, lnum);
++              if (err)
++                      return err;
++              c->gc_lnum = lnum;
++              dbg_rcvry("allocated LEB %d for GC", lnum);
++              /* Run the commit */
++              dbg_rcvry("committing");
++              return ubifs_run_commit(c);
++      }
++      /*
++       * There was no empty LEB so the used space in the dirtiest LEB must fit
++       * in the GC head LEB.
++       */
++      if (lp.free + lp.dirty < wbuf->offs) {
++              dbg_rcvry("LEB %d doesn't fit in GC head LEB %d:%d",
++                        lnum, wbuf->lnum, wbuf->offs);
++              err = ubifs_return_leb(c, lnum);
++              if (err)
++                      return err;
++              goto find_free;
++      }
++      /*
++       * We run the commit before garbage collection otherwise subsequent
++       * mounts will see the GC and orphan deletion in a different order.
++       */
++      dbg_rcvry("committing");
++      err = ubifs_run_commit(c);
++      if (err)
++              return err;
++      /*
++       * The data in the dirtiest LEB fits in the GC head LEB, so do the GC
++       * - use locking to keep 'ubifs_assert()' happy.
++       */
++      dbg_rcvry("GC'ing LEB %d", lnum);
++      mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
++      err = ubifs_garbage_collect_leb(c, &lp);
++      if (err >= 0) {
++              int err2 = ubifs_wbuf_sync_nolock(wbuf);
++
++              if (err2)
++                      err = err2;
++      }
++      mutex_unlock(&wbuf->io_mutex);
++      if (err < 0) {
++              dbg_err("GC failed, error %d", err);
++              if (err == -EAGAIN)
++                      err = -EINVAL;
++              return err;
++      }
++      if (err != LEB_RETAINED) {
++              dbg_err("GC returned %d", err);
++              return -EINVAL;
++      }
++      err = ubifs_leb_unmap(c, c->gc_lnum);
++      if (err)
++              return err;
++      dbg_rcvry("allocated LEB %d for GC", lnum);
++      return 0;
++
++find_free:
++      /*
++       * There is no GC head LEB or the free space in the GC head LEB is too
++       * small. Allocate gc_lnum by calling 'ubifs_find_free_leb_for_idx()' so
++       * GC is not run.
++       */
++      lnum = ubifs_find_free_leb_for_idx(c);
++      if (lnum < 0) {
++              dbg_err("could not find an empty LEB");
++              return lnum;
++      }
++      /* And reset the index flag */
++      err = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
++                                LPROPS_INDEX, 0);
++      if (err)
++              return err;
++      c->gc_lnum = lnum;
++      dbg_rcvry("allocated LEB %d for GC", lnum);
++      /* Run the commit */
++      dbg_rcvry("committing");
++      return ubifs_run_commit(c);
++}
++
++/**
++ * struct size_entry - inode size information for recovery.
++ * @rb: link in the RB-tree of sizes
++ * @inum: inode number
++ * @i_size: size on inode
++ * @d_size: maximum size based on data nodes
++ * @exists: indicates whether the inode exists
++ * @inode: inode if pinned in memory awaiting rw mode to fix it
++ */
++struct size_entry {
++      struct rb_node rb;
++      ino_t inum;
++      loff_t i_size;
++      loff_t d_size;
++      int exists;
++      struct inode *inode;
++};
++
++/**
++ * add_ino - add an entry to the size tree.
++ * @c: UBIFS file-system description object
++ * @inum: inode number
++ * @i_size: size on inode
++ * @d_size: maximum size based on data nodes
++ * @exists: indicates whether the inode exists
++ */
++static int add_ino(struct ubifs_info *c, ino_t inum, loff_t i_size,
++                 loff_t d_size, int exists)
++{
++      struct rb_node **p = &c->size_tree.rb_node, *parent = NULL;
++      struct size_entry *e;
++
++      while (*p) {
++              parent = *p;
++              e = rb_entry(parent, struct size_entry, rb);
++              if (inum < e->inum)
++                      p = &(*p)->rb_left;
++              else
++                      p = &(*p)->rb_right;
++      }
++
++      e = kzalloc(sizeof(struct size_entry), GFP_KERNEL);
++      if (!e)
++              return -ENOMEM;
++
++      e->inum = inum;
++      e->i_size = i_size;
++      e->d_size = d_size;
++      e->exists = exists;
++
++      rb_link_node(&e->rb, parent, p);
++      rb_insert_color(&e->rb, &c->size_tree);
++
++      return 0;
++}
++
++/**
++ * find_ino - find an entry on the size tree.
++ * @c: UBIFS file-system description object
++ * @inum: inode number
++ */
++static struct size_entry *find_ino(struct ubifs_info *c, ino_t inum)
++{
++      struct rb_node *p = c->size_tree.rb_node;
++      struct size_entry *e;
++
++      while (p) {
++              e = rb_entry(p, struct size_entry, rb);
++              if (inum < e->inum)
++                      p = p->rb_left;
++              else if (inum > e->inum)
++                      p = p->rb_right;
++              else
++                      return e;
++      }
++      return NULL;
++}
++
++/**
++ * remove_ino - remove an entry from the size tree.
++ * @c: UBIFS file-system description object
++ * @inum: inode number
++ */
++static void remove_ino(struct ubifs_info *c, ino_t inum)
++{
++      struct size_entry *e = find_ino(c, inum);
++
++      if (!e)
++              return;
++      rb_erase(&e->rb, &c->size_tree);
++      kfree(e);
++}
++
++/**
++ * ubifs_destroy_size_tree - free resources related to the size tree.
++ * @c: UBIFS file-system description object
++ */
++void ubifs_destroy_size_tree(struct ubifs_info *c)
++{
++      struct rb_node *this = c->size_tree.rb_node;
++      struct size_entry *e;
++
++      while (this) {
++              if (this->rb_left) {
++                      this = this->rb_left;
++                      continue;
++              } else if (this->rb_right) {
++                      this = this->rb_right;
++                      continue;
++              }
++              e = rb_entry(this, struct size_entry, rb);
++              if (e->inode)
++                      iput(e->inode);
++              this = rb_parent(this);
++              if (this) {
++                      if (this->rb_left == &e->rb)
++                              this->rb_left = NULL;
++                      else
++                              this->rb_right = NULL;
++              }
++              kfree(e);
++      }
++      c->size_tree = RB_ROOT;
++}
++
++/**
++ * ubifs_recover_size_accum - accumulate inode sizes for recovery.
++ * @c: UBIFS file-system description object
++ * @key: node key
++ * @deletion: node is for a deletion
++ * @new_size: inode size
++ *
++ * This function has two purposes:
++ *     1) to ensure there are no data nodes that fall outside the inode size
++ *     2) to ensure there are no data nodes for inodes that do not exist
++ * To accomplish those purposes, a rb-tree is constructed containing an entry
++ * for each inode number in the journal that has not been deleted, and recording
++ * the size from the inode node, the maximum size of any data node (also altered
++ * by truncations) and a flag indicating a inode number for which no inode node
++ * was present in the journal.
++ *
++ * Note that there is still the possibility that there are data nodes that have
++ * been committed that are beyond the inode size, however the only way to find
++ * them would be to scan the entire index. Alternatively, some provision could
++ * be made to record the size of inodes at the start of commit, which would seem
++ * very cumbersome for a scenario that is quite unlikely and the only negative
++ * consequence of which is wasted space.
++ *
++ * This functions returns %0 on success and a negative error code on failure.
++ */
++int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key,
++                           int deletion, loff_t new_size)
++{
++      ino_t inum = key_inum(c, key);
++      struct size_entry *e;
++      int err;
++
++      switch (key_type(c, key)) {
++      case UBIFS_INO_KEY:
++              if (deletion)
++                      remove_ino(c, inum);
++              else {
++                      e = find_ino(c, inum);
++                      if (e) {
++                              e->i_size = new_size;
++                              e->exists = 1;
++                      } else {
++                              err = add_ino(c, inum, new_size, 0, 1);
++                              if (err)
++                                      return err;
++                      }
++              }
++              break;
++      case UBIFS_DATA_KEY:
++              e = find_ino(c, inum);
++              if (e) {
++                      if (new_size > e->d_size)
++                              e->d_size = new_size;
++              } else {
++                      err = add_ino(c, inum, 0, new_size, 0);
++                      if (err)
++                              return err;
++              }
++              break;
++      case UBIFS_TRUN_KEY:
++              e = find_ino(c, inum);
++              if (e)
++                      e->d_size = new_size;
++              break;
++      }
++      return 0;
++}
++
++/**
++ * fix_size_in_place - fix inode size in place on flash.
++ * @c: UBIFS file-system description object
++ * @e: inode size information for recovery
++ */
++static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
++{
++      struct ubifs_ino_node *ino = c->sbuf;
++      unsigned char *p;
++      union ubifs_key key;
++      int err, lnum, offs, len;
++      loff_t i_size;
++      uint32_t crc;
++
++      /* Locate the inode node LEB number and offset */
++      ino_key_init(c, &key, e->inum);
++      err = ubifs_tnc_locate(c, &key, ino, &lnum, &offs);
++      if (err)
++              goto out;
++      /*
++       * If the size recorded on the inode node is greater than the size that
++       * was calculated from nodes in the journal then don't change the inode.
++       */
++      i_size = le64_to_cpu(ino->size);
++      if (i_size >= e->d_size)
++              return 0;
++      /* Read the LEB */
++      err = ubi_read(c->ubi, lnum, c->sbuf, 0, c->leb_size);
++      if (err)
++              goto out;
++      /* Change the size field and recalculate the CRC */
++      ino = c->sbuf + offs;
++      ino->size = cpu_to_le64(e->d_size);
++      len = le32_to_cpu(ino->ch.len);
++      crc = crc32(UBIFS_CRC32_INIT, (void *)ino + 8, len - 8);
++      ino->ch.crc = cpu_to_le32(crc);
++      /* Work out where data in the LEB ends and free space begins */
++      p = c->sbuf;
++      len = c->leb_size - 1;
++      while (p[len] == 0xff)
++              len -= 1;
++      len = ALIGN(len + 1, c->min_io_size);
++      /* Atomically write the fixed LEB back again */
++      err = ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN);
++      if (err)
++              goto out;
++      dbg_rcvry("inode %lu at %d:%d size %lld -> %lld ", e->inum, lnum, offs,
++                i_size, e->d_size);
++      return 0;
++
++out:
++      ubifs_warn("inode %lu failed to fix size %lld -> %lld error %d",
++                 e->inum, e->i_size, e->d_size, err);
++      return err;
++}
++
++/**
++ * ubifs_recover_size - recover inode size.
++ * @c: UBIFS file-system description object
++ *
++ * This function attempts to fix inode size discrepancies identified by the
++ * 'ubifs_recover_size_accum()' function.
++ *
++ * This functions returns %0 on success and a negative error code on failure.
++ */
++int ubifs_recover_size(struct ubifs_info *c)
++{
++      struct rb_node *this = rb_first(&c->size_tree);
++
++      while (this) {
++              struct size_entry *e;
++              int err;
++
++              e = rb_entry(this, struct size_entry, rb);
++              if (!e->exists) {
++                      union ubifs_key key;
++
++                      ino_key_init(c, &key, e->inum);
++                      err = ubifs_tnc_lookup(c, &key, c->sbuf);
++                      if (err && err != -ENOENT)
++                              return err;
++                      if (err == -ENOENT) {
++                              /* Remove data nodes that have no inode */
++                              dbg_rcvry("removing ino %lu", e->inum);
++                              err = ubifs_tnc_remove_ino(c, e->inum);
++                              if (err)
++                                      return err;
++                      } else {
++                              struct ubifs_ino_node *ino = c->sbuf;
++
++                              e->exists = 1;
++                              e->i_size = le64_to_cpu(ino->size);
++                      }
++              }
++              if (e->exists && e->i_size < e->d_size) {
++                      if (!e->inode && (c->vfs_sb->s_flags & MS_RDONLY)) {
++                              /* Fix the inode size and pin it in memory */
++                              struct inode *inode;
++
++                              inode = ubifs_iget(c->vfs_sb, e->inum);
++                              if (IS_ERR(inode))
++                                      return PTR_ERR(inode);
++                              if (inode->i_size < e->d_size) {
++                                      dbg_rcvry("ino %lu size %lld -> %lld",
++                                                e->inum, e->d_size,
++                                                inode->i_size);
++                                      inode->i_size = e->d_size;
++                                      e->inode = inode;
++                                      this = rb_next(this);
++                                      continue;
++                              }
++                              iput(inode);
++                      } else {
++                              /* Fix the size in place */
++                              err = fix_size_in_place(c, e);
++                              if (err) {
++                                      if (e->inode)
++                                              /*
++                                               * We have changed the inode
++                                               * size in memory but failed to
++                                               * fix it on flash. Mark it
++                                               * dirty without budgeting, and
++                                               * hope we don't run out of
++                                               * space.
++                                               */
++                                              mark_inode_dirty_sync(e->inode);
++                                      /*
++                                       * We consider that failing to recover
++                                       * the size is not fatal, because it
++                                       * only affects files that were being
++                                       * written without synchronization and
++                                       * the only down side is that some space
++                                       * may be wasted.
++                                       */
++                                      err = 0;
++                              }
++                              if (e->inode)
++                                      iput(e->inode);
++                      }
++              }
++              this = rb_next(this);
++              rb_erase(&e->rb, &c->size_tree);
++              kfree(e);
++      }
++      return 0;
++}
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/replay.c avr32-2.6/fs/ubifs/replay.c
+--- linux-2.6.25.6/fs/ubifs/replay.c   1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/replay.c        2008-06-12 15:09:45.515816461 +0200
+@@ -0,0 +1,1075 @@
 +/*
-+ * AVR32 Performance Counter Driver
++ * This file is part of UBIFS.
 + *
-+ * Copyright (C) 2005-2007 Atmel Corporation
++ * Copyright (C) 2006-2008 Nokia Corporation.
 + *
-+ * 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.
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Adrian Hunter
++ *          Artem Bityutskiy (Битюцкий Артём)
++ */
++
++/*
++ * This file contains journal replay code. It runs when the file-system is being
++ * mounted and requires no locking.
++ *
++ * The larger is the journal, the longer it takes to scan it, so the longer it
++ * takes to mount UBIFS. This is why the journal has limited size which may be
++ * changed depending on the system requirements. But a larger journal gives
++ * faster I/O speed because it writes the index less frequently. So this is a
++ * trade-off. Also, the journal is indexed by the in-memory index (TNC), so the
++ * larger is the journal, the more memory its index may consume.
++ */
++
++#include "ubifs.h"
++
++/*
++ * Replay flags.
++ *
++ * REPLAY_DELETION: node was deleted
++ * REPLAY_REF: node is a reference node
++ */
++enum {
++      REPLAY_DELETION = 1,
++      REPLAY_REF = 2,
++};
++
++/**
++ * struct replay_entry - replay tree entry.
++ * @lnum: logical eraseblock number of the node
++ * @offs: node offset
++ * @len: node length
++ * @sqnum: node sequence number
++ * @flags: replay flags
++ * @rb: links the replay tree
++ * @key: node key
++ * @nm: directory entry name
++ * @old_size: truncation old size
++ * @new_size: truncation new size
++ * @free: amount of free space in a bud
++ * @dirty: amount of dirty space in a bud from padding and deletion nodes
 + *
-+ * Author: Ronny Pedersen
++ * UBIFS journal replay must compare node sequence numbers, which means it must
++ * build a tree of node information to insert into the TNC.
 + */
-+#include <linux/errno.h>
-+#include <linux/interrupt.h>
-+#include <linux/irq.h>
-+#include <linux/oprofile.h>
-+#include <linux/sched.h>
-+#include <linux/types.h>
-+
-+#include <asm/sysreg.h>
-+#include <asm/system.h>
++struct replay_entry {
++      int lnum;
++      int offs;
++      int len;
++      unsigned long long sqnum;
++      int flags;
++      struct rb_node rb;
++      union ubifs_key key;
++      union {
++              struct qstr nm;
++              struct {
++                      loff_t old_size;
++                      loff_t new_size;
++              };
++              struct {
++                      int free;
++                      int dirty;
++              };
++      };
++};
 +
-+#define AVR32_PERFCTR_IRQ_GROUP       0
-+#define AVR32_PERFCTR_IRQ_LINE        1
++/**
++ * struct bud_entry - entry in the list of buds to replay.
++ * @list: next bud in the list
++ * @bud: bud description object
++ * @free: free bytes in the bud
++ * @sqnum: reference node sequence number
++ */
++struct bud_entry {
++      struct list_head list;
++      struct ubifs_bud *bud;
++      int free;
++      unsigned long long sqnum;
++};
 +
-+enum { PCCNT, PCNT0, PCNT1, NR_counter };
++/**
++ * set_bud_lprops - set free and dirty space used by a bud.
++ * @c: UBIFS file-system description object
++ * @r: replay entry of bud
++ */
++static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
++{
++      const struct ubifs_lprops *lp;
++      int err = 0, dirty;
 +
-+struct avr32_perf_counter {
-+      unsigned long   enabled;
-+      unsigned long   event;
-+      unsigned long   count;
-+      unsigned long   unit_mask;
-+      unsigned long   kernel;
-+      unsigned long   user;
++      ubifs_get_lprops(c);
 +
-+      u32             ie_mask;
-+      u32             flag_mask;
-+};
++      lp = ubifs_lpt_lookup_dirty(c, r->lnum);
++      if (IS_ERR(lp)) {
++              err = PTR_ERR(lp);
++              goto out;
++      }
 +
-+static struct avr32_perf_counter counter[NR_counter] = {
-+      {
-+              .ie_mask        = SYSREG_BIT(IEC),
-+              .flag_mask      = SYSREG_BIT(FC),
-+      }, {
-+              .ie_mask        = SYSREG_BIT(IE0),
-+              .flag_mask      = SYSREG_BIT(F0),
-+      }, {
-+              .ie_mask        = SYSREG_BIT(IE1),
-+              .flag_mask      = SYSREG_BIT(F1),
-+      },
-+};
++      dirty = lp->dirty;
++      if (r->offs == 0 && (lp->free != c->leb_size || lp->dirty != 0)) {
++              /*
++               * The LEB was added to the journal with a starting offset of
++               * zero which means the LEB must have been empty. The LEB
++               * property values should be lp->free == c->leb_size and
++               * lp->dirty == 0, but that is not the case. The reason is that
++               * the LEB was garbage collected. The garbage collector resets
++               * the free and dirty space without recording it anywhere except
++               * lprops, so if there is not a commit then lprops does not have
++               * that information next time the file system is mounted.
++               *
++               * We do not need to adjust free space because the scan has told
++               * us the exact value which is recorded in the replay entry as
++               * r->free.
++               *
++               * However we do need to subtract from the dirty space the
++               * amount of space that the garbage collector reclaimed, which
++               * is the whole LEB minus the amount of space that was free.
++               */
++              dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum,
++                      lp->free, lp->dirty);
++              dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum,
++                      lp->free, lp->dirty);
++              dirty -= c->leb_size - lp->free;
++              /*
++               * If the replay order was perfect the dirty space would now be
++               * zero. The order is not perfect because the the journal heads
++               * race with eachother. This is not a problem but is does mean
++               * that the dirty space may temporarily exceed c->leb_size
++               * during the replay.
++               */
++              if (dirty != 0)
++                      dbg_msg("LEB %d lp: %d free %d dirty "
++                              "replay: %d free %d dirty", r->lnum, lp->free,
++                              lp->dirty, r->free, r->dirty);
++      }
++      lp = ubifs_change_lp(c, lp, r->free, dirty + r->dirty,
++                           lp->flags | LPROPS_TAKEN, 0);
++      if (IS_ERR(lp)) {
++              err = PTR_ERR(lp);
++              goto out;
++      }
++out:
++      ubifs_release_lprops(c);
++      return err;
++}
 +
-+static void avr32_perf_counter_reset(void)
++/**
++ * trun_remove_range - apply a replay entry for a truncation to the TNC.
++ * @c: UBIFS file-system description object
++ * @r: replay entry of truncation
++ */
++static int trun_remove_range(struct ubifs_info *c, struct replay_entry *r)
 +{
-+      /* Reset all counter and disable/clear all interrupts */
-+      sysreg_write(PCCR, (SYSREG_BIT(PCCR_R)
-+                              | SYSREG_BIT(PCCR_C)
-+                              | SYSREG_BIT(FC)
-+                              | SYSREG_BIT(F0)
-+                              | SYSREG_BIT(F1)));
++      unsigned min_blk, max_blk;
++      union ubifs_key min_key, max_key;
++      ino_t ino;
++
++      min_blk = r->new_size / UBIFS_BLOCK_SIZE;
++      if (r->new_size & (UBIFS_BLOCK_SIZE - 1))
++              min_blk += 1;
++
++      max_blk = r->old_size / UBIFS_BLOCK_SIZE;
++      if ((r->old_size & (UBIFS_BLOCK_SIZE - 1)) == 0)
++              max_blk -= 1;
++
++      ino = key_inum(c, &r->key);
++
++      data_key_init(c, &min_key, ino, min_blk);
++      data_key_init(c, &max_key, ino, max_blk);
++
++      return ubifs_tnc_remove_range(c, &min_key, &max_key);
 +}
 +
-+static irqreturn_t avr32_perf_counter_interrupt(int irq, void *dev_id)
++/**
++ * apply_replay_entry - apply a replay entry to the TNC.
++ * @c: UBIFS file-system description object
++ * @r: replay entry to apply
++ *
++ * Apply a replay entry to the TNC.
++ */
++static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
 +{
-+      struct avr32_perf_counter *ctr = dev_id;
-+      struct pt_regs *regs;
-+      u32 pccr;
++      int err, deletion = ((r->flags & REPLAY_DELETION) != 0);
++
++      dbg_mnt("LEB %d:%d len %d flgs %d sqnum %llu %s", r->lnum,
++              r->offs, r->len, r->flags, r->sqnum, DBGKEY(&r->key));
++
++      /* Set c->replay_sqnum to help deal with dangling branches. */
++      c->replay_sqnum = r->sqnum;
++
++      if (r->flags & REPLAY_REF)
++              err = set_bud_lprops(c, r);
++      else if (is_hash_key(c, &r->key)) {
++              if (deletion)
++                      err = ubifs_tnc_remove_nm(c, &r->key, &r->nm);
++              else
++                      err = ubifs_tnc_add_nm(c, &r->key, r->lnum, r->offs,
++                                             r->len, &r->nm);
++      } else {
++              if (deletion)
++                      switch (key_type(c, &r->key)) {
++                      case UBIFS_INO_KEY:
++                      {
++                              ino_t inum = key_inum(c, &r->key);
 +
-+      if (likely(!(intc_get_pending(AVR32_PERFCTR_IRQ_GROUP)
-+                                      & (1 << AVR32_PERFCTR_IRQ_LINE))))
-+              return IRQ_NONE;
++                              err = ubifs_tnc_remove_ino(c, inum);
++                              break;
++                      }
++                      case UBIFS_TRUN_KEY:
++                              err = trun_remove_range(c, r);
++                              break;
++                      default:
++                              err = ubifs_tnc_remove(c, &r->key);
++                              break;
++                      }
++              else
++                      err = ubifs_tnc_add(c, &r->key, r->lnum, r->offs,
++                                          r->len);
++              if (err)
++                      return err;
++
++              if (c->need_recovery)
++                      err = ubifs_recover_size_accum(c, &r->key, deletion,
++                                                     r->new_size);
++      }
 +
-+      regs = get_irq_regs();
-+      pccr = sysreg_read(PCCR);
++      return err;
++}
 +
-+      /* Clear the interrupt flags we're about to handle */
-+      sysreg_write(PCCR, pccr);
++/**
++ * destroy_replay_tree - destroy the replay.
++ * @c: UBIFS file-system description object
++ *
++ * Destroy the replay tree.
++ */
++static void destroy_replay_tree(struct ubifs_info *c)
++{
++      struct rb_node *this = c->replay_tree.rb_node;
++      struct replay_entry *r;
 +
-+      /* PCCNT */
-+      if (ctr->enabled && (pccr & ctr->flag_mask)) {
-+              sysreg_write(PCCNT, -ctr->count);
-+              oprofile_add_sample(regs, PCCNT);
++      while (this) {
++              if (this->rb_left) {
++                      this = this->rb_left;
++                      continue;
++              } else if (this->rb_right) {
++                      this = this->rb_right;
++                      continue;
++              }
++              r = rb_entry(this, struct replay_entry, rb);
++              this = rb_parent(this);
++              if (this) {
++                      if (this->rb_left == &r->rb)
++                              this->rb_left = NULL;
++                      else
++                              this->rb_right = NULL;
++              }
++              if (is_hash_key(c, &r->key))
++                      kfree(r->nm.name);
++              kfree(r);
 +      }
-+      ctr++;
-+      /* PCNT0 */
-+      if (ctr->enabled && (pccr & ctr->flag_mask)) {
-+              sysreg_write(PCNT0, -ctr->count);
-+              oprofile_add_sample(regs, PCNT0);
++      c->replay_tree = RB_ROOT;
++}
++
++/**
++ * apply_replay_tree - apply the replay tree to the TNC.
++ * @c: UBIFS file-system description object
++ *
++ * Apply the replay tree.
++ * Returns zero in case of success and a negative error code in case of
++ * failure.
++ */
++static int apply_replay_tree(struct ubifs_info *c)
++{
++      struct rb_node *this = rb_first(&c->replay_tree);
++
++      while (this) {
++              struct replay_entry *r;
++              int err;
++
++              cond_resched();
++
++              r = rb_entry(this, struct replay_entry, rb);
++              err = apply_replay_entry(c, r);
++              if (err)
++                      return err;
++              this = rb_next(this);
 +      }
-+      ctr++;
-+      /* PCNT1 */
-+      if (ctr->enabled && (pccr & ctr->flag_mask)) {
-+              sysreg_write(PCNT1, -ctr->count);
-+              oprofile_add_sample(regs, PCNT1);
++      return 0;
++}
++
++/**
++ * insert_node - insert a node to the replay tree.
++ * @c: UBIFS file-system description object
++ * @lnum: node logical eraseblock number
++ * @offs: node offset
++ * @len: node length
++ * @key: node key
++ * @sqnum: sequence number
++ * @deletion: non-zero if this is a deletion
++ * @used: number of bytes in use in a LEB
++ * @old_size: truncation old size
++ * @new_size: truncation new size
++ *
++ * This function inserts a scanned non-direntry node to the replay tree. The
++ * replay tree is an RB-tree containing @struct replay_entry elements which are
++ * indexed by the sequence number. The replay tree is applied at the very end
++ * of the replay process. Since the tree is sorted in sequence number order,
++ * the older modifications are applied first. This function returns zero in
++ * case of success and a negative error code in case of failure.
++ */
++static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
++                     union ubifs_key *key, unsigned long long sqnum,
++                     int deletion, int *used, loff_t old_size,
++                     loff_t new_size)
++{
++      struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
++      struct replay_entry *r;
++
++      if (key_inum(c, key) >= c->highest_inum)
++              c->highest_inum = key_inum(c, key);
++
++      dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
++      while (*p) {
++              parent = *p;
++              r = rb_entry(parent, struct replay_entry, rb);
++              if (sqnum < r->sqnum) {
++                      p = &(*p)->rb_left;
++                      continue;
++              } else if (sqnum > r->sqnum) {
++                      p = &(*p)->rb_right;
++                      continue;
++              }
++              ubifs_err("duplicate sqnum in replay");
++              return -EINVAL;
 +      }
 +
-+      return IRQ_HANDLED;
++      r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
++      if (!r)
++              return -ENOMEM;
++
++      if (!deletion)
++              *used += ALIGN(len, 8);
++      r->lnum = lnum;
++      r->offs = offs;
++      r->len = len;
++      r->sqnum = sqnum;
++      r->flags = (deletion ? REPLAY_DELETION : 0);
++      r->old_size = old_size;
++      r->new_size = new_size;
++      key_copy(c, key, &r->key);
++
++      rb_link_node(&r->rb, parent, p);
++      rb_insert_color(&r->rb, &c->replay_tree);
++      return 0;
 +}
 +
-+static int avr32_perf_counter_create_files(struct super_block *sb,
-+              struct dentry *root)
-+{
-+      struct dentry *dir;
-+      unsigned int i;
-+      char filename[4];
++/**
++ * insert_dent - insert a directory entry node into the replay tree.
++ * @c: UBIFS file-system description object
++ * @lnum: node logical eraseblock number
++ * @offs: node offset
++ * @len: node length
++ * @key: node key
++ * @name: directory entry name
++ * @nlen: directory entry name length
++ * @sqnum: sequence number
++ * @deletion: non-zero if this is a deletion
++ * @used: number of bytes in use in a LEB
++ *
++ * This function inserts a scanned directory entry node to the replay tree.
++ * Returns zero in case of success and a negative error code in case of
++ * failure.
++ *
++ * This function is also used for extended attribute entries because they are
++ * implemented as directory entry nodes.
++ */
++static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
++                     union ubifs_key *key, const char *name, int nlen,
++                     unsigned long long sqnum, int deletion, int *used)
++{
++      struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
++      struct replay_entry *r;
++      char *nbuf;
++
++      if (key_inum(c, key) >= c->highest_inum)
++              c->highest_inum = key_inum(c, key);
++
++      dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
++      while (*p) {
++              parent = *p;
++              r = rb_entry(parent, struct replay_entry, rb);
++              if (sqnum < r->sqnum) {
++                      p = &(*p)->rb_left;
++                      continue;
++              }
++              if (sqnum > r->sqnum) {
++                      p = &(*p)->rb_right;
++                      continue;
++              }
++              ubifs_err("duplicate sqnum in replay");
++              return -EINVAL;
++      }
++
++      r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
++      if (!r)
++              return -ENOMEM;
++      nbuf = kmalloc(nlen + 1, GFP_KERNEL);
++      if (!nbuf) {
++              kfree(r);
++              return -ENOMEM;
++      }
 +
-+      for (i = 0; i < NR_counter; i++) {
-+              snprintf(filename, sizeof(filename), "%u", i);
-+              dir = oprofilefs_mkdir(sb, root, filename);
++      if (!deletion)
++              *used += ALIGN(len, 8);
++      r->lnum = lnum;
++      r->offs = offs;
++      r->len = len;
++      r->sqnum = sqnum;
++      r->nm.len = nlen;
++      memcpy(nbuf, name, nlen);
++      nbuf[nlen] = '\0';
++      r->nm.name = nbuf;
++      r->flags = (deletion ? REPLAY_DELETION : 0);
++      key_copy(c, key, &r->key);
++
++      ubifs_assert(!*p);
++      rb_link_node(&r->rb, parent, p);
++      rb_insert_color(&r->rb, &c->replay_tree);
++      return 0;
++}
 +
-+              oprofilefs_create_ulong(sb, dir, "enabled",
-+                              &counter[i].enabled);
-+              oprofilefs_create_ulong(sb, dir, "event",
-+                              &counter[i].event);
-+              oprofilefs_create_ulong(sb, dir, "count",
-+                              &counter[i].count);
++/**
++ * ubifs_validate_entry - validate directory or extended attribute entry node.
++ * @c: UBIFS file-system description object
++ * @dent: the node to validate
++ *
++ * This function validates directory or extended attribute entry node @dent.
++ * Returns zero if the node is all right and a %-EINVAL if not.
++ */
++int ubifs_validate_entry(struct ubifs_info *c,
++                       const struct ubifs_dent_node *dent)
++{
++      int key_type = key_type_flash(c, dent->key);
++      int nlen = le16_to_cpu(dent->nlen);
++
++      if (le32_to_cpu(dent->ch.len) != nlen + UBIFS_DENT_NODE_SZ + 1 ||
++          dent->type >= UBIFS_ITYPES_CNT ||
++          nlen > UBIFS_MAX_NLEN || dent->name[nlen] != 0 ||
++          strnlen(dent->name, nlen) != nlen ||
++          le64_to_cpu(dent->inum) > MAX_INUM) {
++              ubifs_err("bad %s node", key_type == UBIFS_DENT_KEY ?
++                        "directory entry" : "extended attribute entry");
++              return -EINVAL;
++      }
 +
-+              /* Dummy entries */
-+              oprofilefs_create_ulong(sb, dir, "kernel",
-+                              &counter[i].kernel);
-+              oprofilefs_create_ulong(sb, dir, "user",
-+                              &counter[i].user);
-+              oprofilefs_create_ulong(sb, dir, "unit_mask",
-+                              &counter[i].unit_mask);
++      if (key_type != UBIFS_DENT_KEY && key_type != UBIFS_XENT_KEY) {
++              ubifs_err("bad key type %d", key_type);
++              return -EINVAL;
 +      }
 +
 +      return 0;
 +}
 +
-+static int avr32_perf_counter_setup(void)
++/**
++ * replay_bud - replay a bud logical eraseblock.
++ * @c: UBIFS file-system description object
++ * @lnum: bud logical eraseblock number to replay
++ * @offs: bud start offset
++ * @jhead: journal head to which this bud belongs
++ * @free: amount of free space in the bud is returned here
++ * @dirty: amount of dirty space from padding and deletion nodes is returned
++ * here
++ *
++ * This function returns zero in case of success and a negative error code in
++ * case of failure.
++ */
++static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
++                    int *free, int *dirty)
 +{
-+      struct avr32_perf_counter *ctr;
-+      u32 pccr;
-+      int ret;
-+      int i;
++      int err = 0, used = 0;
++      struct ubifs_scan_leb *sleb;
++      struct ubifs_scan_node *snod;
++      struct ubifs_bud *bud;
 +
-+      pr_debug("avr32_perf_counter_setup\n");
++      dbg_mnt("replay bud LEB %d, head %d", lnum, jhead);
++      if (c->need_recovery)
++              sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, jhead != GCHD);
++      else
++              sleb = ubifs_scan(c, lnum, offs, c->sbuf);
++      if (IS_ERR(sleb))
++              return PTR_ERR(sleb);
 +
-+      if (sysreg_read(PCCR) & SYSREG_BIT(PCCR_E)) {
-+              printk(KERN_ERR
-+                      "oprofile: setup: perf counter already enabled\n");
-+              return -EBUSY;
-+      }
++      /*
++       * The bud does not have to start from offset zero - the beginning of
++       * the 'lnum' LEB may contain previously committed data. One of the
++       * things we have to do in replay is to correctly update lprops with
++       * newer information about this LEB.
++       *
++       * At this point lprops thinks that this LEB has 'c->leb_size - offs'
++       * bytes of free space because it only contain information about
++       * committed data.
++       *
++       * But we know that real amount of free space is 'c->leb_size -
++       * sleb->endpt', and the space in the 'lnum' LEB between 'offs' and
++       * 'sleb->endpt' is used by bud data. We have to correctly calculate
++       * how much of these data are dirty and update lprops with this
++       * information.
++       *
++       * The dirt in that LEB region is comprised of padding nodes, deletion
++       * nodes, truncation nodes and nodes which are obsoleted by subsequent
++       * nodes in this LEB. So instead of calculating clean space, we
++       * calculate used space ('used' variable).
++       */
 +
-+      ret = request_irq(AVR32_PERFCTR_IRQ_GROUP,
-+                      avr32_perf_counter_interrupt, IRQF_SHARED,
-+                      "oprofile", counter);
-+      if (ret)
-+              return ret;
++      list_for_each_entry(snod, &sleb->nodes, list) {
++              int deletion = 0;
 +
-+      avr32_perf_counter_reset();
++              cond_resched();
 +
-+      pccr = 0;
-+      for (i = PCCNT; i < NR_counter; i++) {
-+              ctr = &counter[i];
-+              if (!ctr->enabled)
-+                      continue;
++              if (snod->sqnum >= SQNUM_WATERMARK) {
++                      ubifs_err("file system's life ended");
++                      goto out_dump;
++              }
 +
-+              pr_debug("enabling counter %d...\n", i);
++              if (snod->sqnum > c->max_sqnum)
++                      c->max_sqnum = snod->sqnum;
 +
-+              pccr |= ctr->ie_mask;
++              switch (snod->type) {
++              case UBIFS_INO_NODE:
++              {
++                      struct ubifs_ino_node *ino = snod->node;
++                      loff_t new_size = le64_to_cpu(ino->size);
 +
-+              switch (i) {
-+              case PCCNT:
-+                      /* PCCNT always counts cycles, so no events */
-+                      sysreg_write(PCCNT, -ctr->count);
++                      if (le32_to_cpu(ino->nlink) == 0)
++                              deletion = 1;
++                      err = insert_node(c, lnum, snod->offs, snod->len,
++                                        &snod->key, snod->sqnum, deletion,
++                                        &used, 0, new_size);
++                      break;
++              }
++              case UBIFS_DATA_NODE:
++              {
++                      struct ubifs_data_node *dn = snod->node;
++                      loff_t new_size = le32_to_cpu(dn->size) +
++                                        key_block(c, &snod->key) *
++                                        UBIFS_BLOCK_SIZE;
++
++                      err = insert_node(c, lnum, snod->offs, snod->len,
++                                        &snod->key, snod->sqnum, deletion,
++                                        &used, 0, new_size);
 +                      break;
-+              case PCNT0:
-+                      pccr |= SYSREG_BF(CONF0, ctr->event);
-+                      sysreg_write(PCNT0, -ctr->count);
++              }
++              case UBIFS_DENT_NODE:
++              case UBIFS_XENT_NODE:
++              {
++                      struct ubifs_dent_node *dent = snod->node;
++
++                      err = ubifs_validate_entry(c, dent);
++                      if (err)
++                              goto out_dump;
++
++                      err = insert_dent(c, lnum, snod->offs, snod->len,
++                                        &snod->key, dent->name,
++                                        le16_to_cpu(dent->nlen), snod->sqnum,
++                                        !le64_to_cpu(dent->inum), &used);
 +                      break;
-+              case PCNT1:
-+                      pccr |= SYSREG_BF(CONF1, ctr->event);
-+                      sysreg_write(PCNT1, -ctr->count);
++              }
++              case UBIFS_TRUN_NODE:
++              {
++                      struct ubifs_trun_node *trun = snod->node;
++                      loff_t old_size = le64_to_cpu(trun->old_size);
++                      loff_t new_size = le64_to_cpu(trun->new_size);
++                      union ubifs_key key;
++
++                      /* Validate truncation node */
++                      if (old_size < 0 || old_size > c->max_inode_sz ||
++                          new_size < 0 || new_size > c->max_inode_sz ||
++                          old_size <= new_size) {
++                              ubifs_err("bad truncation node");
++                              goto out_dump;
++                      }
++
++                      /*
++                       * Create a fake truncation key just to use the same
++                       * functions which expect nodes to have keys.
++                       */
++                      trun_key_init(c, &key, le32_to_cpu(trun->inum));
++                      err = insert_node(c, lnum, snod->offs, snod->len,
++                                        &key, snod->sqnum, 1, &used,
++                                        old_size, new_size);
 +                      break;
 +              }
++              default:
++                      ubifs_err("unexpected node type %d in bud LEB %d:%d",
++                                snod->type, lnum, snod->offs);
++                      err = -EINVAL;
++                      goto out_dump;
++              }
++              if (err)
++                      goto out;
 +      }
 +
-+      pr_debug("oprofile: writing 0x%x to PCCR...\n", pccr);
++      bud = ubifs_search_bud(c, lnum);
++      if (!bud)
++              BUG();
++
++      ubifs_assert(sleb->endpt - offs >= used);
++      ubifs_assert(sleb->endpt % c->min_io_size == 0);
 +
-+      sysreg_write(PCCR, pccr);
++      if (sleb->endpt + c->min_io_size <= c->leb_size &&
++          !(c->vfs_sb->s_flags & MS_RDONLY))
++              err = ubifs_wbuf_seek_nolock(&c->jheads[jhead].wbuf, lnum,
++                                           sleb->endpt, UBI_SHORTTERM);
 +
-+      return 0;
-+}
++      *dirty = sleb->endpt - offs - used;
++      *free = c->leb_size - sleb->endpt;
 +
-+static void avr32_perf_counter_shutdown(void)
-+{
-+      pr_debug("avr32_perf_counter_shutdown\n");
++out:
++      ubifs_scan_destroy(sleb);
++      return err;
 +
-+      avr32_perf_counter_reset();
-+      free_irq(AVR32_PERFCTR_IRQ_GROUP, counter);
++out_dump:
++      ubifs_err("bad node is at LEB %d:%d", lnum, snod->offs);
++      dbg_dump_node(c, snod->node);
++      ubifs_scan_destroy(sleb);
++      return -EINVAL;
 +}
 +
-+static int avr32_perf_counter_start(void)
-+{
-+      pr_debug("avr32_perf_counter_start\n");
++/**
++ * insert_ref_node - insert a reference node to the replay tree.
++ * @c: UBIFS file-system description object
++ * @lnum: node logical eraseblock number
++ * @offs: node offset
++ * @sqnum: sequence number
++ * @free: amount of free space in bud
++ * @dirty: amount of dirty space from padding and deletion nodes
++ *
++ * This function inserts a reference node to the replay tree and returns zero
++ * in case of success ort a negative error code in case of failure.
++ */
++static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
++                         unsigned long long sqnum, int free, int dirty)
++{
++      struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
++      struct replay_entry *r;
++
++      dbg_mnt("add ref LEB %d:%d", lnum, offs);
++      while (*p) {
++              parent = *p;
++              r = rb_entry(parent, struct replay_entry, rb);
++              if (sqnum < r->sqnum) {
++                      p = &(*p)->rb_left;
++                      continue;
++              } else if (sqnum > r->sqnum) {
++                      p = &(*p)->rb_right;
++                      continue;
++              }
++              ubifs_err("duplicate sqnum in replay tree");
++              return -EINVAL;
++      }
++
++      r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
++      if (!r)
++              return -ENOMEM;
 +
-+      sysreg_write(PCCR, sysreg_read(PCCR) | SYSREG_BIT(PCCR_E));
++      r->lnum = lnum;
++      r->offs = offs;
++      r->sqnum = sqnum;
++      r->flags = REPLAY_REF;
++      r->free = free;
++      r->dirty = dirty;
 +
++      rb_link_node(&r->rb, parent, p);
++      rb_insert_color(&r->rb, &c->replay_tree);
 +      return 0;
 +}
 +
-+static void avr32_perf_counter_stop(void)
-+{
-+      pr_debug("avr32_perf_counter_stop\n");
++/**
++ * replay_buds - replay all buds.
++ * @c: UBIFS file-system description object
++ *
++ * This function returns zero in case of success and a negative error code in
++ * case of failure.
++ */
++static int replay_buds(struct ubifs_info *c)
++{
++      struct bud_entry *b;
++      int err, uninitialized_var(free), uninitialized_var(dirty);
++
++      list_for_each_entry(b, &c->replay_buds, list) {
++              err = replay_bud(c, b->bud->lnum, b->bud->start, b->bud->jhead,
++                               &free, &dirty);
++              if (err)
++                      return err;
++              err = insert_ref_node(c, b->bud->lnum, b->bud->start, b->sqnum,
++                                    free, dirty);
++              if (err)
++                      return err;
++      }
 +
-+      sysreg_write(PCCR, sysreg_read(PCCR) & ~SYSREG_BIT(PCCR_E));
++      return 0;
 +}
 +
-+static struct oprofile_operations avr32_perf_counter_ops __initdata = {
-+      .create_files   = avr32_perf_counter_create_files,
-+      .setup          = avr32_perf_counter_setup,
-+      .shutdown       = avr32_perf_counter_shutdown,
-+      .start          = avr32_perf_counter_start,
-+      .stop           = avr32_perf_counter_stop,
-+      .cpu_type       = "avr32",
-+};
++/**
++ * destroy_bud_list - destroy the list of buds to replay.
++ * @c: UBIFS file-system description object
++ */
++static void destroy_bud_list(struct ubifs_info *c)
++{
++      struct bud_entry *b;
 +
-+int __init oprofile_arch_init(struct oprofile_operations *ops)
++      while (!list_empty(&c->replay_buds)) {
++              b = list_entry(c->replay_buds.next, struct bud_entry, list);
++              list_del(&b->list);
++              kfree(b);
++      }
++}
++
++/**
++ * add_replay_bud - add a bud to the list of buds to replay.
++ * @c: UBIFS file-system description object
++ * @lnum: bud logical eraseblock number to replay
++ * @offs: bud start offset
++ * @jhead: journal head to which this bud belongs
++ * @sqnum: reference node sequence number
++ *
++ * This function returns zero in case of success and a negative error code in
++ * case of failure.
++ */
++static int add_replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
++                        unsigned long long sqnum)
 +{
-+      if (!(current_cpu_data.features & AVR32_FEATURE_PCTR))
-+              return -ENODEV;
++      struct ubifs_bud *bud;
++      struct bud_entry *b;
++
++      dbg_mnt("add replay bud LEB %d:%d, head %d", lnum, offs, jhead);
++
++      bud = kmalloc(sizeof(struct ubifs_bud), GFP_KERNEL);
++      if (!bud)
++              return -ENOMEM;
++
++      b = kmalloc(sizeof(struct bud_entry), GFP_KERNEL);
++      if (!b) {
++              kfree(bud);
++              return -ENOMEM;
++      }
 +
-+      memcpy(ops, &avr32_perf_counter_ops,
-+                      sizeof(struct oprofile_operations));
++      bud->lnum = lnum;
++      bud->start = offs;
++      bud->jhead = jhead;
++      ubifs_add_bud(c, bud);
 +
-+      printk(KERN_INFO "oprofile: using AVR32 performance monitoring.\n");
++      b->bud = bud;
++      b->sqnum = sqnum;
++      list_add_tail(&b->list, &c->replay_buds);
 +
 +      return 0;
 +}
 +
-+void oprofile_arch_exit(void)
++/**
++ * validate_ref - validate a reference node.
++ * @c: UBIFS file-system description object
++ * @ref: the reference node to validate
++ * @ref_lnum: LEB number of the reference node
++ * @ref_offs: reference node offset
++ *
++ * This function returns %1 if a bud reference already exists for the LEB. %0 is
++ * returned if the reference node is new, otherwise %-EINVAL is returned if
++ * validation failed.
++ */
++static int validate_ref(struct ubifs_info *c, const struct ubifs_ref_node *ref)
 +{
++      struct ubifs_bud *bud;
++      int lnum = le32_to_cpu(ref->lnum);
++      unsigned int offs = le32_to_cpu(ref->offs);
++      unsigned int jhead = le32_to_cpu(ref->jhead);
 +
-+}
---- a/Documentation/kernel-parameters.txt
-+++ b/Documentation/kernel-parameters.txt
-@@ -34,6 +34,7 @@
-       ALSA    ALSA sound support is enabled.
-       APIC    APIC support is enabled.
-       APM     Advanced Power Management support is enabled.
-+      AVR32   AVR32 architecture is enabled.
-       AX25    Appropriate AX.25 support is enabled.
-       BLACKFIN Blackfin architecture is enabled.
-       DRM     Direct Rendering Management support is enabled.
-@@ -1124,6 +1125,10 @@
-                       of returning the full 64-bit number.
-                       The default is to return 64-bit inode numbers.
-+      nmi_debug=      [KNL,AVR32] Specify one or more actions to take
-+                      when a NMI is triggered.
-+                      Format: [state][,regs][,debounce][,die]
-+
-       nmi_watchdog=   [KNL,BUGS=X86-32] Debugging features for SMP kernels
-       no387           [BUGS=X86-32] Tells the kernel to use the 387 maths
---- a/drivers/clocksource/Makefile
-+++ b/drivers/clocksource/Makefile
-@@ -1,3 +1,4 @@
-+obj-$(CONFIG_ATMEL_TCB_CLKSRC)        += tcb_clksrc.o
- obj-$(CONFIG_X86_CYCLONE_TIMER)       += cyclone.o
- obj-$(CONFIG_X86_PM_TIMER)    += acpi_pm.o
- obj-$(CONFIG_SCx200HR_TIMER)  += scx200_hrt.o
---- /dev/null
-+++ b/drivers/clocksource/tcb_clksrc.c
-@@ -0,0 +1,305 @@
-+#include <linux/init.h>
-+#include <linux/clocksource.h>
-+#include <linux/clockchips.h>
-+#include <linux/interrupt.h>
-+#include <linux/irq.h>
++      /*
++       * ref->offs may point to the end of LEB when the journal head points
++       * to the end of LEB and we write reference node for it during commit.
++       * So this is why we require 'offs > c->leb_size'.
++       */
++      if (jhead >= c->jhead_cnt || lnum >= c->leb_cnt ||
++          lnum < c->main_first || offs > c->leb_size ||
++          offs & (c->min_io_size - 1))
++              return -EINVAL;
 +
-+#include <linux/clk.h>
-+#include <linux/err.h>
-+#include <linux/ioport.h>
-+#include <linux/io.h>
-+#include <linux/platform_device.h>
-+#include <linux/atmel_tc.h>
++      /* Make sure we have not already looked at this bud */
++      bud = ubifs_search_bud(c, lnum);
++      if (bud) {
++              if (bud->jhead == jhead && bud->start <= offs)
++                      return 1;
++              ubifs_err("bud at LEB %d:%d was already referred", lnum, offs);
++              return -EINVAL;
++      }
 +
++      return 0;
++}
 +
-+/*
-+ * We're configured to use a specific TC block, one that's not hooked
-+ * up to external hardware, to provide a time solution:
-+ *
-+ *   - Two channels combine to create a free-running 32 bit counter
-+ *     with a base rate of 5+ MHz, packaged as a clocksource (with
-+ *     resolution better than 200 nsec).
-+ *
-+ *   - The third channel may be used to provide a 16-bit clockevent
-+ *     source, used in either periodic or oneshot mode.  This runs
-+ *     at 32 KiHZ, and can handle delays of up to two seconds.
-+ *
-+ * A boot clocksource and clockevent source are also currently needed,
-+ * unless the relevant platforms (ARM/AT91, AVR32/AT32) are changed so
-+ * this code can be used when init_timers() is called, well before most
-+ * devices are set up.  (Some low end AT91 parts, which can run uClinux,
-+ * have only the timers in one TC block... they currently don't support
-+ * the tclib code, because of that initialization issue.)
++/**
++ * replay_log_leb - replay a log logical eraseblock.
++ * @c: UBIFS file-system description object
++ * @lnum: log logical eraseblock to replay
++ * @offs: offset to start replaying from
++ * @sbuf: scan buffer
 + *
-+ * REVISIT behavior during system suspend states... we should disable
-+ * all clocks and save the power.  Easily done for clockevent devices,
-+ * but clocksources won't necessarily get the needed notifications.
-+ * For deeper system sleep states, this will be mandatory...
++ * This function replays a log LEB and returns zero in case of success, %1 if
++ * this is the last LEB in the log, and a negative error code in case of
++ * failure.
 + */
++static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf)
++{
++      int err;
++      struct ubifs_scan_leb *sleb;
++      struct ubifs_scan_node *snod;
++      const struct ubifs_cs_node *node;
++
++      dbg_mnt("replay log LEB %d:%d", lnum, offs);
++      sleb = ubifs_scan(c, lnum, offs, sbuf);
++      if (IS_ERR(sleb)) {
++              if (c->need_recovery)
++                      sleb = ubifs_recover_log_leb(c, lnum, offs, sbuf);
++              if (IS_ERR(sleb))
++                      return PTR_ERR(sleb);
++      }
++
++      if (sleb->nodes_cnt == 0) {
++              err = 1;
++              goto out;
++      }
++
++      node = sleb->buf;
++
++      snod = list_entry(sleb->nodes.next, struct ubifs_scan_node, list);
++      if (c->cs_sqnum == 0) {
++              /*
++               * This is the first log LEB we are looking at, make sure that
++               * the first node is a commit start node. Also record its
++               * sequence number so that UBIFS can determine where the log
++               * ends, because all nodes which were have higher sequence
++               * numbers.
++               */
++              if (snod->type != UBIFS_CS_NODE) {
++                      dbg_err("first log node at LEB %d:%d is not CS node",
++                              lnum, offs);
++                      goto out_dump;
++              }
++              if (le64_to_cpu(node->cmt_no) != c->cmt_no) {
++                      dbg_err("first CS node at LEB %d:%d has wrong "
++                              "commit number %llu expected %llu",
++                              lnum, offs,
++                              (unsigned long long)le64_to_cpu(node->cmt_no),
++                              c->cmt_no);
++                      goto out_dump;
++              }
++
++              c->cs_sqnum = le64_to_cpu(node->ch.sqnum);
++              dbg_mnt("commit start sqnum %llu", c->cs_sqnum);
++      }
++
++      if (snod->sqnum < c->cs_sqnum) {
++              /*
++               * This means that we reached end of log and now
++               * look to the older log data, which was already
++               * committed but the eraseblock was not erased (UBIFS
++               * only unmaps it). So this basically means we have to
++               * exit with "end of log" code.
++               */
++              err = 1;
++              goto out;
++      }
 +
-+static void __iomem *tcaddr;
++      /* Make sure the first node sits at offset zero of the LEB */
++      if (snod->offs != 0) {
++              dbg_err("first node is not at zero offset");
++              goto out_dump;
++      }
 +
-+static cycle_t tc_get_cycles(void)
-+{
-+      unsigned long   flags;
-+      u32             lower, upper;
++      list_for_each_entry(snod, &sleb->nodes, list) {
 +
-+      raw_local_irq_save(flags);
-+      do {
-+              upper = __raw_readl(tcaddr + ATMEL_TC_REG(1, CV));
-+              lower = __raw_readl(tcaddr + ATMEL_TC_REG(0, CV));
-+      } while (upper != __raw_readl(tcaddr + ATMEL_TC_REG(1, CV)));
++              cond_resched();
 +
-+      raw_local_irq_restore(flags);
-+      return (upper << 16) | lower;
-+}
++              if (snod->sqnum >= SQNUM_WATERMARK) {
++                      ubifs_err("file system's life ended");
++                      goto out_dump;
++              }
 +
-+static struct clocksource clksrc = {
-+      .name           = "tcb_clksrc",
-+      .rating         = 200,
-+      .read           = tc_get_cycles,
-+      .mask           = CLOCKSOURCE_MASK(32),
-+      .shift          = 18,
-+      .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
-+};
++              if (snod->sqnum < c->cs_sqnum) {
++                      dbg_err("bad sqnum %llu, commit sqnum %llu",
++                              snod->sqnum, c->cs_sqnum);
++                      goto out_dump;
++              }
 +
-+#ifdef CONFIG_GENERIC_CLOCKEVENTS
++              if (snod->sqnum > c->max_sqnum)
++                      c->max_sqnum = snod->sqnum;
 +
-+struct tc_clkevt_device {
-+      struct clock_event_device       clkevt;
-+      struct clk                      *clk;
-+      void __iomem                    *regs;
-+};
++              switch (snod->type) {
++              case UBIFS_REF_NODE: {
++                      const struct ubifs_ref_node *ref = snod->node;
 +
-+static struct tc_clkevt_device *to_tc_clkevt(struct clock_event_device *clkevt)
-+{
-+      return container_of(clkevt, struct tc_clkevt_device, clkevt);
++                      err = validate_ref(c, ref);
++                      if (err == 1)
++                              break; /* Already have this bud */
++                      if (err)
++                              goto out_dump;
++
++                      err = add_replay_bud(c, le32_to_cpu(ref->lnum),
++                                           le32_to_cpu(ref->offs),
++                                           le32_to_cpu(ref->jhead),
++                                           snod->sqnum);
++                      if (err)
++                              goto out;
++
++                      break;
++              }
++              case UBIFS_CS_NODE:
++                      /* Make sure it sits at the beginning of LEB */
++                      if (snod->offs != 0) {
++                              ubifs_err("unexpected node in log");
++                              goto out_dump;
++                      }
++                      break;
++              default:
++                      ubifs_err("unexpected node in log");
++                      goto out_dump;
++              }
++      }
++
++      if (sleb->endpt || c->lhead_offs >= c->leb_size) {
++              c->lhead_lnum = lnum;
++              c->lhead_offs = sleb->endpt;
++      }
++
++      err = !sleb->endpt;
++out:
++      ubifs_scan_destroy(sleb);
++      return err;
++
++out_dump:
++      ubifs_err("log error detected while replying the log at LEB %d:%d",
++                lnum, offs + snod->offs);
++      dbg_dump_node(c, snod->node);
++      ubifs_scan_destroy(sleb);
++      return -EINVAL;
 +}
 +
-+/* For now, we always use the 32K clock ... this optimizes for NO_HZ,
-+ * because using one of the divided clocks would usually mean the
-+ * tick rate can never be less than several dozen Hz (vs 0.5 Hz).
++/**
++ * take_ihead - update the status of the index head in lprops to 'taken'.
++ * @c: UBIFS file-system description object
 + *
-+ * A divided clock could be good for high resolution timers, since
-+ * 30.5 usec resolution can seem "low".
++ * This function returns the amount of free space in the index head LEB or a
++ * negative error code.
 + */
-+static u32 timer_clock;
-+
-+static void tc_mode(enum clock_event_mode m, struct clock_event_device *d)
++static int take_ihead(struct ubifs_info *c)
 +{
-+      struct tc_clkevt_device *tcd = to_tc_clkevt(d);
-+      void __iomem            *regs = tcd->regs;
++      const struct ubifs_lprops *lp;
++      int err, free;
 +
-+      if (tcd->clkevt.mode == CLOCK_EVT_MODE_PERIODIC
-+                      || tcd->clkevt.mode == CLOCK_EVT_MODE_ONESHOT) {
-+              __raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR));
-+              __raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR));
-+              clk_disable(tcd->clk);
++      ubifs_get_lprops(c);
++
++      lp = ubifs_lpt_lookup_dirty(c, c->ihead_lnum);
++      if (IS_ERR(lp)) {
++              err = PTR_ERR(lp);
++              goto out;
 +      }
 +
-+      switch (m) {
++      free = lp->free;
 +
-+      /* By not making the gentime core emulate periodic mode on top
-+       * of oneshot, we get lower overhead and improved accuracy.
-+       */
-+      case CLOCK_EVT_MODE_PERIODIC:
-+              clk_enable(tcd->clk);
++      lp = ubifs_change_lp(c, lp, LPROPS_NC, LPROPS_NC,
++                           lp->flags | LPROPS_TAKEN, 0);
++      if (IS_ERR(lp)) {
++              err = PTR_ERR(lp);
++              goto out;
++      }
 +
-+              /* slow clock, count up to RC, then irq and restart */
-+              __raw_writel(timer_clock
-+                              | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO,
-+                              regs + ATMEL_TC_REG(2, CMR));
-+              __raw_writel((32768 + HZ/2) / HZ, tcaddr + ATMEL_TC_REG(2, RC));
++      err = free;
++out:
++      ubifs_release_lprops(c);
++      return err;
++}
 +
-+              /* Enable clock and interrupts on RC compare */
-+              __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
++/**
++ * ubifs_replay_journal - replay journal.
++ * @c: UBIFS file-system description object
++ *
++ * This function scans the journal, replays and cleans it up. It makes sure all
++ * memory data structures related to uncommitted journal are built (dirty TNC
++ * tree, tree of buds, modified lprops, etc).
++ */
++int ubifs_replay_journal(struct ubifs_info *c)
++{
++      int err, i, lnum, offs, free;
++      void *sbuf = NULL;
 +
-+              /* go go gadget! */
-+              __raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG,
-+                              regs + ATMEL_TC_REG(2, CCR));
-+              break;
++      BUILD_BUG_ON(UBIFS_TRUN_KEY > 5);
 +
-+      case CLOCK_EVT_MODE_ONESHOT:
-+              clk_enable(tcd->clk);
++      /* Update the status of the index head in lprops to 'taken' */
++      free = take_ihead(c);
++      if (free < 0)
++              return free; /* Error code */
 +
-+              /* slow clock, count up to RC, then irq and stop */
-+              __raw_writel(timer_clock | ATMEL_TC_CPCSTOP
-+                              | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO,
-+                              regs + ATMEL_TC_REG(2, CMR));
-+              __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
++      if (c->ihead_offs != c->leb_size - free) {
++              ubifs_err("bad index head LEB %d:%d", c->ihead_lnum,
++                        c->ihead_offs);
++              return -EINVAL;
++      }
 +
-+              /* set_next_event() configures and starts the timer */
-+              break;
++      sbuf = vmalloc(c->leb_size);
++      if (!sbuf)
++              return -ENOMEM;
 +
-+      default:
-+              break;
++      dbg_mnt("start replaying the journal");
++
++      c->replaying = 1;
++
++      lnum = c->ltail_lnum = c->lhead_lnum;
++      offs = c->lhead_offs;
++
++      for (i = 0; i < c->log_lebs; i++, lnum++) {
++              if (lnum >= UBIFS_LOG_LNUM + c->log_lebs) {
++                      /*
++                       * The log is logically circular, we reached the last
++                       * LEB, switch to the first one.
++                       */
++                      lnum = UBIFS_LOG_LNUM;
++                      offs = 0;
++              }
++              err = replay_log_leb(c, lnum, offs, sbuf);
++              if (err == 1)
++                      /* We hit the end of the log */
++                      break;
++              if (err)
++                      goto out;
++              offs = 0;
 +      }
-+}
 +
-+static int tc_next_event(unsigned long delta, struct clock_event_device *d)
-+{
-+      __raw_writel(delta, tcaddr + ATMEL_TC_REG(2, RC));
++      err = replay_buds(c);
++      if (err)
++              goto out;
 +
-+      /* go go gadget! */
-+      __raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG,
-+                      tcaddr + ATMEL_TC_REG(2, CCR));
-+      return 0;
++      err = apply_replay_tree(c);
++      if (err)
++              goto out;
++
++      ubifs_assert(c->bud_bytes <= c->max_bud_bytes || c->need_recovery);
++      dbg_mnt("finished, log head LEB %d:%d, max_sqnum %llu, "
++              "highest_inum %lu", c->lhead_lnum, c->lhead_offs, c->max_sqnum,
++              c->highest_inum);
++out:
++      destroy_replay_tree(c);
++      destroy_bud_list(c);
++      vfree(sbuf);
++      c->replaying = 0;
++      return err;
 +}
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/sb.c avr32-2.6/fs/ubifs/sb.c
+--- linux-2.6.25.6/fs/ubifs/sb.c       1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/sb.c    2008-06-12 15:09:45.515816461 +0200
+@@ -0,0 +1,618 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Artem Bityutskiy (Битюцкий Артём)
++ *          Adrian Hunter
++ */
 +
-+static struct tc_clkevt_device clkevt = {
-+      .clkevt = {
-+              .name           = "tc_clkevt",
-+              .features       = CLOCK_EVT_FEAT_PERIODIC
-+                                      | CLOCK_EVT_FEAT_ONESHOT,
-+              .shift          = 32,
-+              /* Should be lower than at91rm9200's system timer */
-+              .rating         = 125,
-+              .cpumask        = CPU_MASK_CPU0,
-+              .set_next_event = tc_next_event,
-+              .set_mode       = tc_mode,
-+      },
-+};
++/*
++ * This file implements UBIFS superblock. The superblock is stored at the first
++ * LEB of the volume and is never changed by UBIFS. Only user-space tools may
++ * change it. The superblock node mostly contains geometry information.
++ */
 +
-+static irqreturn_t ch2_irq(int irq, void *handle)
-+{
-+      struct tc_clkevt_device *dev = handle;
-+      unsigned int            sr;
++#include "ubifs.h"
++#include <linux/random.h>
 +
-+      sr = __raw_readl(dev->regs + ATMEL_TC_REG(2, SR));
-+      if (sr & ATMEL_TC_CPCS) {
-+              dev->clkevt.event_handler(&dev->clkevt);
-+              return IRQ_HANDLED;
-+      }
++/*
++ * Default journal size in logical eraseblocks as a percent of total
++ * flash size.
++ */
++#define DEFAULT_JNL_PERCENT 5
 +
-+      return IRQ_NONE;
-+}
++/* Default maximum journal size in bytes */
++#define DEFAULT_MAX_JNL (32*1024*1024)
 +
-+static struct irqaction tc_irqaction = {
-+      .name           = "tc_clkevt",
-+      .flags          = IRQF_TIMER | IRQF_DISABLED,
-+      .handler        = ch2_irq,
-+};
++/* Default indexing tree fanout */
++#define DEFAULT_FANOUT 8
 +
-+static void __init setup_clkevents(struct atmel_tc *tc,
-+              struct clk *t0_clk, int clk32k_divisor_idx)
-+{
-+      struct platform_device *pdev = tc->pdev;
-+      struct clk *t2_clk = tc->clk[2];
-+      int irq = tc->irq[2];
++/* Default number of LEBs for orphan information */
++#ifdef CONFIG_UBIFS_FS_DEBUG
++#define DEFAULT_ORPHAN_LEBS 2 /* 2 is better for testing */
++#else
++#define DEFAULT_ORPHAN_LEBS 1
++#endif
 +
-+      clkevt.regs = tc->regs;
-+      clkevt.clk = t2_clk;
-+      tc_irqaction.dev_id = &clkevt;
++/* Default number of journal heads */
++#define DEFAULT_JHEADS_CNT 1
 +
-+      timer_clock = clk32k_divisor_idx;
++/* Default positions of different LEBs in the main area */
++#define DEFAULT_IDX_LEB  0
++#define DEFAULT_DATA_LEB 1
++#define DEFAULT_GC_LEB   2
 +
-+      clkevt.clkevt.mult = div_sc(32768, NSEC_PER_SEC, clkevt.clkevt.shift);
-+      clkevt.clkevt.max_delta_ns
-+              = clockevent_delta2ns(0xffff, &clkevt.clkevt);
-+      clkevt.clkevt.min_delta_ns = clockevent_delta2ns(1, &clkevt.clkevt) + 1;
++/* Default number of LEB numbers in LPT's save table */
++#define DEFAULT_LSAVE_CNT 256
 +
-+      setup_irq(irq, &tc_irqaction);
++/* Default reserved pool size as a percent of maximum free space */
++#define DEFAULT_RP_PERCENT 5
 +
-+      clockevents_register_device(&clkevt.clkevt);
-+}
++/* The default maximum size of reserved pool in bytes */
++#define DEFAULT_MAX_RP_SIZE (5*1024*1024)
 +
-+#else /* !CONFIG_GENERIC_CLOCKEVENTS */
++/* Default UBIFS compressor */
++#define DEFAULT_COMPRESSOR UBIFS_COMPR_LZO
 +
-+static void __init setup_clkevents(struct atmel_tc *tc,
-+              struct clk *t0_clk, int clk32k_divisor_idx)
-+{
-+      /* NOTHING */
-+}
++/* Default time granularity in nanoseconds */
++#define DEFAULT_TIME_GRAN 1000000000
 +
-+#endif
++/**
++ * create_default_filesystem - format empty UBI volume.
++ * @c: UBIFS file-system description object
++ *
++ * This function creates default empty file-system. Returns zero in case of
++ * success and a negative error code in case of failure.
++ */
++static int create_default_filesystem(struct ubifs_info *c)
++{
++      struct ubifs_sb_node *sup;
++      struct ubifs_mst_node *mst;
++      struct ubifs_idx_node *idx;
++      struct ubifs_branch *br;
++      struct ubifs_ino_node *ino;
++      struct ubifs_cs_node *cs;
++      union ubifs_key key;
++      int err, tmp, jnl_lebs, log_lebs, max_buds, main_lebs, main_first;
++      int lpt_lebs, lpt_first, orph_lebs, big_lpt, ino_waste, sup_flags = 0;
++      uint64_t tmp64, main_bytes;
++
++      /* Some functions called from here depend on the @c->key_len filed */
++      c->key_len = UBIFS_SK_LEN;
 +
-+static int __init tcb_clksrc_init(void)
-+{
-+      static char bootinfo[] __initdata
-+              = KERN_DEBUG "%s: tc%d at %d.%03d MHz\n";
++      /*
++       * First of all, we have to calculate default file-system geometry -
++       * log size, journal size, etc.
++       */
++      c->max_leb_cnt = c->leb_cnt;
++      if (c->leb_cnt < 0x7FFFFFFF / DEFAULT_JNL_PERCENT)
++              /* We can first multiply then divide and have no overflow */
++              jnl_lebs = c->leb_cnt * DEFAULT_JNL_PERCENT / 100;
++      else
++              jnl_lebs = (c->leb_cnt / 100) * DEFAULT_JNL_PERCENT;
 +
-+      struct platform_device *pdev;
-+      struct atmel_tc *tc;
-+      struct clk *t0_clk, *t1_clk;
-+      u32 rate, divided_rate = 0;
-+      int best_divisor_idx = -1;
-+      int clk32k_divisor_idx = -1;
-+      int i;
++      if (jnl_lebs < UBIFS_MIN_JNL_LEBS)
++              jnl_lebs = UBIFS_MIN_JNL_LEBS;
++      if (jnl_lebs * c->leb_size > DEFAULT_MAX_JNL)
++              jnl_lebs = DEFAULT_MAX_JNL / c->leb_size;
 +
-+      tc = atmel_tc_alloc(CONFIG_ATMEL_TCB_CLKSRC_BLOCK, clksrc.name);
-+      if (!tc) {
-+              pr_debug("can't alloc TC for clocksource\n");
-+              return -ENODEV;
-+      }
-+      tcaddr = tc->regs;
-+      pdev = tc->pdev;
++      /*
++       * The log should be large enough to fit reference nodes for all bud
++       * LEBs. Because buds do not have to start from the beginning of LEBs
++       * (half of the LEB may contain committed data), the log should
++       * generally be larger, make it twice as large.
++       */
++      tmp = 2 * (c->ref_node_alsz * jnl_lebs) + c->leb_size - 1;
++      log_lebs = tmp / c->leb_size;
++      /* Plus one LEB reserved for commit */
++      log_lebs += 1;
++      /* And some extra space to allow writes while committing */
++      log_lebs += 1;
 +
-+      t0_clk = tc->clk[0];
-+      clk_enable(t0_clk);
++      max_buds = jnl_lebs - log_lebs;
++      if (max_buds < UBIFS_MIN_BUD_LEBS)
++              max_buds = UBIFS_MIN_BUD_LEBS;
 +
-+      /* How fast will we be counting?  Pick something over 5 MHz.  */
-+      rate = (u32) clk_get_rate(t0_clk);
-+      for (i = 0; i < 5; i++) {
-+              unsigned divisor = atmel_tc_divisors[i];
-+              unsigned tmp;
++      /*
++       * Orphan nodes are stored in a separate area. One node can store a lot
++       * of orphan inode numbers, but when new orphan comes we just add a new
++       * orphan node. At some point the nodes are consolidated into one
++       * orphan node.
++       */
++      orph_lebs = DEFAULT_ORPHAN_LEBS;
 +
-+              /* remember 32 KiHz clock for later */
-+              if (!divisor) {
-+                      clk32k_divisor_idx = i;
-+                      continue;
-+              }
++      main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS - log_lebs;
++      main_lebs -= orph_lebs;
 +
-+              tmp = rate / divisor;
-+              pr_debug("TC: %u / %-3u [%d] --> %u\n", rate, divisor, i, tmp);
-+              if (best_divisor_idx > 0) {
-+                      if (tmp < 5 * 1000 * 1000)
-+                              continue;
-+              }
-+              divided_rate = tmp;
-+              best_divisor_idx = i;
++      lpt_first = UBIFS_LOG_LNUM + log_lebs;
++      c->lsave_cnt = DEFAULT_LSAVE_CNT;
++      err = ubifs_create_dflt_lpt(c, &main_lebs, lpt_first, &lpt_lebs,
++                                  &big_lpt);
++      if (err)
++              return err;
++
++      dbg_gen("LEB Properties Tree created (LEBs %d-%d)", lpt_first,
++              lpt_first + lpt_lebs - 1);
++
++      main_first = c->leb_cnt - main_lebs;
++
++      /* Create default superblock */
++      tmp = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size);
++      sup = kzalloc(tmp, GFP_KERNEL);
++      if (!sup)
++              return -ENOMEM;
++
++      tmp64 = (uint64_t)max_buds * c->leb_size;
++      if (big_lpt)
++              sup_flags |= UBIFS_FLG_BIGLPT;
++
++      sup->ch.node_type  = UBIFS_SB_NODE;
++      sup->key_hash      = UBIFS_KEY_HASH_R5;
++      sup->flags         = cpu_to_le32(sup_flags);
++      sup->min_io_size   = cpu_to_le32(c->min_io_size);
++      sup->leb_size      = cpu_to_le32(c->leb_size);
++      sup->leb_cnt       = cpu_to_le32(c->leb_cnt);
++      sup->max_leb_cnt   = cpu_to_le32(c->max_leb_cnt);
++      sup->max_bud_bytes = cpu_to_le64(tmp64);
++      sup->log_lebs      = cpu_to_le32(log_lebs);
++      sup->lpt_lebs      = cpu_to_le32(lpt_lebs);
++      sup->orph_lebs     = cpu_to_le32(orph_lebs);
++      sup->jhead_cnt     = cpu_to_le32(DEFAULT_JHEADS_CNT);
++      sup->fanout        = cpu_to_le32(DEFAULT_FANOUT);
++      sup->lsave_cnt     = cpu_to_le32(c->lsave_cnt);
++      sup->fmt_version   = cpu_to_le32(UBIFS_FORMAT_VERSION);
++      sup->default_compr = cpu_to_le16(DEFAULT_COMPRESSOR);
++      sup->time_gran     = cpu_to_le32(DEFAULT_TIME_GRAN);
++
++      generate_random_uuid(sup->uuid);
++
++      main_bytes = (uint64_t)main_lebs * c->leb_size;
++      tmp64 = main_bytes * DEFAULT_RP_PERCENT;
++      do_div(tmp64, 100);
++      if (tmp64 > DEFAULT_MAX_RP_SIZE)
++              tmp64 = DEFAULT_MAX_RP_SIZE;
++      sup->rp_size = cpu_to_le64(tmp64);
++
++      err = ubifs_write_node(c, sup, UBIFS_SB_NODE_SZ, 0, 0, UBI_LONGTERM);
++      kfree(sup);
++      if (err)
++              return err;
++
++      dbg_gen("default superblock created at LEB 0:0");
++
++      /* Create default master node */
++      mst = kzalloc(c->mst_node_alsz, GFP_KERNEL);
++      if (!mst)
++              return -ENOMEM;
++
++      mst->ch.node_type = UBIFS_MST_NODE;
++      mst->log_lnum     = cpu_to_le32(UBIFS_LOG_LNUM);
++      mst->highest_inum = cpu_to_le64(UBIFS_FIRST_INO);
++      mst->cmt_no       = 0;
++      mst->root_lnum    = cpu_to_le32(main_first + DEFAULT_IDX_LEB);
++      mst->root_offs    = 0;
++      tmp = ubifs_idx_node_sz(c, 1);
++      mst->root_len     = cpu_to_le32(tmp);
++      mst->gc_lnum      = cpu_to_le32(main_first + DEFAULT_GC_LEB);
++      mst->ihead_lnum   = cpu_to_le32(main_first + DEFAULT_IDX_LEB);
++      mst->ihead_offs   = cpu_to_le32(ALIGN(tmp, c->min_io_size));
++      mst->index_size   = cpu_to_le64(ALIGN(tmp, 8));
++      mst->lpt_lnum     = cpu_to_le32(c->lpt_lnum);
++      mst->lpt_offs     = cpu_to_le32(c->lpt_offs);
++      mst->nhead_lnum   = cpu_to_le32(c->nhead_lnum);
++      mst->nhead_offs   = cpu_to_le32(c->nhead_offs);
++      mst->ltab_lnum    = cpu_to_le32(c->ltab_lnum);
++      mst->ltab_offs    = cpu_to_le32(c->ltab_offs);
++      mst->lsave_lnum   = cpu_to_le32(c->lsave_lnum);
++      mst->lsave_offs   = cpu_to_le32(c->lsave_offs);
++      mst->lscan_lnum   = cpu_to_le32(main_first);
++      mst->empty_lebs   = cpu_to_le32(main_lebs - 2);
++      mst->idx_lebs     = cpu_to_le32(1);
++      mst->leb_cnt      = cpu_to_le32(c->leb_cnt);
++
++      /* Calculate lprops statistics */
++      tmp64 = main_bytes;
++      tmp64 -= ALIGN(ubifs_idx_node_sz(c, 1), c->min_io_size);
++      tmp64 -= ALIGN(UBIFS_INO_NODE_SZ, c->min_io_size);
++      mst->total_free = cpu_to_le64(tmp64);
++
++      tmp64 = ALIGN(ubifs_idx_node_sz(c, 1), c->min_io_size);
++      ino_waste = ALIGN(UBIFS_INO_NODE_SZ, c->min_io_size) -
++                        UBIFS_INO_NODE_SZ;
++      tmp64 += ino_waste;
++      tmp64 -= ALIGN(ubifs_idx_node_sz(c, 1), 8);
++      mst->total_dirty = cpu_to_le64(tmp64);
++
++      /*  The indexing LEB does not contribute to dark space */
++      tmp64 = (c->main_lebs - 1) * c->dark_wm;
++      mst->total_dark = cpu_to_le64(tmp64);
++
++      mst->total_used = cpu_to_le64(UBIFS_INO_NODE_SZ);
++
++      err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM, 0,
++                             UBI_UNKNOWN);
++      if (err) {
++              kfree(mst);
++              return err;
 +      }
++      err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM + 1, 0,
++                             UBI_UNKNOWN);
++      kfree(mst);
++      if (err)
++              return err;
 +
-+      clksrc.mult = clocksource_hz2mult(divided_rate, clksrc.shift);
++      dbg_gen("default master node created at LEB %d:0", UBIFS_MST_LNUM);
 +
-+      printk(bootinfo, clksrc.name, CONFIG_ATMEL_TCB_CLKSRC_BLOCK,
-+                      divided_rate / 1000000,
-+                      ((divided_rate + 500000) % 1000000) / 1000);
++      /* Create the root indexing node */
++      tmp = ubifs_idx_node_sz(c, 1);
++      idx = kzalloc(ALIGN(tmp, c->min_io_size), GFP_KERNEL);
++      if (!idx)
++              return -ENOMEM;
 +
-+      /* tclib will give us three clocks no matter what the
-+       * underlying platform supports.
-+       */
-+      clk_enable(tc->clk[1]);
++      c->key_fmt = UBIFS_SIMPLE_KEY_FMT;
++      c->key_hash = key_r5_hash;
++
++      idx->ch.node_type = UBIFS_IDX_NODE;
++      idx->child_cnt = cpu_to_le16(1);
++      ino_key_init(c, &key, UBIFS_ROOT_INO);
++      br = ubifs_idx_branch(c, idx, 0);
++      key_write_idx(c, &key, &br->key);
++      br->lnum = cpu_to_le32(main_first + DEFAULT_DATA_LEB);
++      br->len  = cpu_to_le32(UBIFS_INO_NODE_SZ);
++      err = ubifs_write_node(c, idx, tmp, main_first + DEFAULT_IDX_LEB, 0,
++                             UBI_UNKNOWN);
++      kfree(idx);
++      if (err)
++              return err;
 +
-+      /* channel 0:  waveform mode, input mclk/8, clock TIOA0 on overflow */
-+      __raw_writel(best_divisor_idx                   /* likely divide-by-8 */
-+                      | ATMEL_TC_WAVE
-+                      | ATMEL_TC_WAVESEL_UP           /* free-run */
-+                      | ATMEL_TC_ACPA_SET             /* TIOA0 rises at 0 */
-+                      | ATMEL_TC_ACPC_CLEAR,          /* (duty cycle 50%) */
-+                      tcaddr + ATMEL_TC_REG(0, CMR));
-+      __raw_writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA));
-+      __raw_writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC));
-+      __raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR));      /* no irqs */
-+      __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
++      dbg_gen("default root indexing node created LEB %d:0",
++              main_first + DEFAULT_IDX_LEB);
 +
-+      /* channel 1:  waveform mode, input TIOA0 */
-+      __raw_writel(ATMEL_TC_XC1                       /* input: TIOA0 */
-+                      | ATMEL_TC_WAVE
-+                      | ATMEL_TC_WAVESEL_UP,          /* free-run */
-+                      tcaddr + ATMEL_TC_REG(1, CMR));
-+      __raw_writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR));      /* no irqs */
-+      __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR));
++      /* Create default root inode */
++      tmp = ALIGN(UBIFS_INO_NODE_SZ, c->min_io_size);
++      ino = kzalloc(tmp, GFP_KERNEL);
++      if (!ino)
++              return -ENOMEM;
 +
-+      /* chain channel 0 to channel 1, then reset all the timers */
-+      __raw_writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR);
-+      __raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
++      ino_key_init_flash(c, &ino->key, UBIFS_ROOT_INO);
++      ino->ch.node_type = UBIFS_INO_NODE;
++      ino->creat_sqnum = cpu_to_le64(++c->max_sqnum);
++      ino->nlink = cpu_to_le32(2);
++      tmp = cpu_to_le64(CURRENT_TIME_SEC.tv_sec);
++      ino->atime_sec   = tmp;
++      ino->ctime_sec   = tmp;
++      ino->mtime_sec   = tmp;
++      ino->atime_nsec  = 0;
++      ino->ctime_nsec  = 0;
++      ino->mtime_nsec  = 0;
++      ino->mode = cpu_to_le32(S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO);
++      ino->size = cpu_to_le64(UBIFS_INO_NODE_SZ);
++
++      /* Set compression enabled by default */
++      ino->flags = cpu_to_le32(UBIFS_COMPR_FL);
++
++      err = ubifs_write_node(c, ino, UBIFS_INO_NODE_SZ,
++                             main_first + DEFAULT_DATA_LEB, 0,
++                             UBI_UNKNOWN);
++      kfree(ino);
++      if (err)
++              return err;
 +
-+      /* and away we go! */
-+      clocksource_register(&clksrc);
++      dbg_gen("root inode created at LEB %d:0",
++              main_first + DEFAULT_DATA_LEB);
 +
-+      /* channel 2:  periodic and oneshot timer support */
-+      setup_clkevents(tc, t0_clk, clk32k_divisor_idx);
++      /*
++       * The first node in the log has to be the commit start node. This is
++       * always the case during normal file-system operation. Write a fake
++       * commit start node to the log.
++       */
++      tmp = ALIGN(UBIFS_CS_NODE_SZ, c->min_io_size);
++      cs = kzalloc(tmp, GFP_KERNEL);
++      if (!cs)
++              return -ENOMEM;
 +
++      cs->ch.node_type = UBIFS_CS_NODE;
++      err = ubifs_write_node(c, cs, UBIFS_CS_NODE_SZ, UBIFS_LOG_LNUM,
++                             0, UBI_UNKNOWN);
++      kfree(cs);
++
++      ubifs_msg("default file-system created");
 +      return 0;
 +}
-+arch_initcall(tcb_clksrc_init);
---- /dev/null
-+++ b/drivers/i2c/busses/i2c-atmeltwi.c
-@@ -0,0 +1,436 @@
-+/*
-+ * i2c Support for Atmel's Two-Wire Interface (TWI)
-+ *
-+ * Based on the work of Copyright (C) 2004 Rick Bronson
-+ * Converted to 2.6 by Andrew Victor <andrew at sanpeople.com>
-+ * Ported to AVR32 and heavily modified by Espen Krangnes
-+ * <ekrangnes at atmel.com>
-+ *
-+ * Copyright (C) 2006 Atmel Corporation
-+ *
-+ * Borrowed heavily from the original work by:
-+ * Copyright (C) 2000 Philip Edelbrock <phil at stimpy.netroedge.com>
-+ *
-+ * Partialy rewriten by Karel Hojdar <cmkaho at seznam.cz>
-+ * bugs removed, interrupt routine markedly rewritten
++
++/**
++ * validate_sb - validate superblock node.
++ * @c: UBIFS file-system description object
++ * @sup: superblock node
 + *
-+ * 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 function validates superblock node @sup. Since most of data was read
++ * from the superblock and stored in @c, the function validates fields in @c
++ * instead. Returns zero in case of success and %-EINVAL in case of validation
++ * failure.
 + */
-+#undef VERBOSE_DEBUG
++static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
++{
++      long long max_bytes;
++      int err = 1;
 +
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/init.h>
-+#include <linux/clk.h>
-+#include <linux/err.h>
-+#include <linux/interrupt.h>
-+#include <linux/platform_device.h>
-+#include <linux/completion.h>
-+#include <linux/io.h>
++      if (!c->key_hash) {
++              err = 2;
++              goto failed;
++      }
 +
-+#include "i2c-atmeltwi.h"
++      if (sup->key_fmt != UBIFS_SIMPLE_KEY_FMT) {
++              err = 3;
++              goto failed;
++      }
 +
-+static unsigned int baudrate = 100 * 1000;
-+module_param(baudrate, uint, S_IRUGO);
-+MODULE_PARM_DESC(baudrate, "The TWI baudrate");
++      if (le32_to_cpu(sup->min_io_size) != c->min_io_size) {
++              ubifs_err("min. I/O unit mismatch: %d in superblock, %d real",
++                        le32_to_cpu(sup->min_io_size), c->min_io_size);
++              goto failed;
++      }
 +
++      if (le32_to_cpu(sup->leb_size) != c->leb_size) {
++              ubifs_err("LEB size mismatch: %d in superblock, %d real",
++                        le32_to_cpu(sup->leb_size), c->leb_size);
++              goto failed;
++      }
 +
-+struct atmel_twi {
-+      void __iomem *regs;
-+      struct i2c_adapter adapter;
-+      struct clk *pclk;
-+      struct completion comp;
-+      u32 mask;
-+      u8 *buf;
-+      u16 len;
-+      u16 acks_left;
-+      int status;
-+      unsigned int irq;
++      if (c->leb_cnt < UBIFS_MIN_LEB_CNT || c->leb_cnt > c->vi.size) {
++              ubifs_err("bad LEB count: %d in superblock, %d on UBI volume, "
++                        "%d minimum required", c->leb_cnt, c->vi.size,
++                        UBIFS_MIN_LEB_CNT);
++              goto failed;
++      }
 +
-+};
-+#define to_atmel_twi(adap) container_of(adap, struct atmel_twi, adapter)
++      if (c->max_leb_cnt < c->leb_cnt) {
++              ubifs_err("max. LEB count %d less than LEB count %d",
++                        c->max_leb_cnt, c->leb_cnt);
++              goto failed;
++      }
 +
-+/*
-+ * (Re)Initialize the TWI hardware registers.
-+ */
-+static int twi_hwinit(struct atmel_twi *twi)
-+{
-+      unsigned long cdiv, ckdiv = 0;
++      if (c->log_lebs < UBIFS_MIN_LOG_LEBS ||
++          c->lpt_lebs < UBIFS_MIN_LPT_LEBS ||
++          c->orph_lebs < UBIFS_MIN_ORPH_LEBS ||
++          c->main_lebs < UBIFS_MIN_MAIN_LEBS) {
++              err = 6;
++              goto failed;
++      }
 +
-+      /* REVISIT: wait till SCL is high before resetting; otherwise,
-+       * some versions will wedge forever.
-+       */
++      if (c->main_lebs < UBIFS_MIN_MAIN_LEBS) {
++              err = 7;
++              goto failed;
++      }
 +
-+      twi_writel(twi, IDR, ~0UL);
-+      twi_writel(twi, CR, TWI_BIT(SWRST));    /*Reset peripheral*/
-+      twi_readl(twi, SR);
++      if (c->max_bud_bytes < (long long)c->leb_size * UBIFS_MIN_BUD_LEBS ||
++          c->max_bud_bytes > (long long)c->leb_size * c->main_lebs) {
++              err = 8;
++              goto failed;
++      }
 +
-+      cdiv = (clk_get_rate(twi->pclk) / (2 * baudrate)) - 4;
++      if (c->jhead_cnt < NONDATA_JHEADS_CNT + 1 ||
++          c->jhead_cnt > NONDATA_JHEADS_CNT + UBIFS_MAX_JHEADS) {
++              err = 9;
++              goto failed;
++      }
 +
-+      while (cdiv > 255) {
-+              ckdiv++;
-+              cdiv = cdiv >> 1;
++      if (c->fanout < UBIFS_MIN_FANOUT ||
++          ubifs_idx_node_sz(c, c->fanout) > c->leb_size) {
++              err = 10;
++              goto failed;
 +      }
 +
-+      /* REVISIT: there are various errata to consider re CDIV and CHDIV
-+       * here, at least on at91 parts.
-+       */
++      if (c->lsave_cnt < 0 || (c->lsave_cnt > DEFAULT_LSAVE_CNT &&
++          c->lsave_cnt > c->max_leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS -
++          c->log_lebs - c->lpt_lebs - c->orph_lebs)) {
++              err = 11;
++              goto failed;
++      }
++
++      if (UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs + c->lpt_lebs +
++          c->orph_lebs + c->main_lebs != c->leb_cnt) {
++              err = 12;
++              goto failed;
++      }
++
++      if (c->default_compr < 0 || c->default_compr >= UBIFS_COMPR_TYPES_CNT) {
++              err = 13;
++              goto failed;
++      }
++
++      max_bytes = c->main_lebs * (long long)c->leb_size;
++      if (c->rp_size < 0 || max_bytes < c->rp_size) {
++              err = 14;
++              goto failed;
++      }
++
++      if (le32_to_cpu(sup->time_gran) > 1000000000 ||
++          le32_to_cpu(sup->time_gran) < 1) {
++              err = 15;
++              goto failed;
++      }
 +
-+      if (ckdiv > 7)
-+              return -EINVAL;
-+      else
-+              twi_writel(twi, CWGR, TWI_BF(CKDIV, ckdiv)
-+                              | TWI_BF(CHDIV, cdiv)
-+                              | TWI_BF(CLDIV, cdiv));
 +      return 0;
++
++failed:
++      ubifs_err("bad superblock, error %d", err);
++      dbg_dump_node(c, sup);
++      return -EINVAL;
 +}
 +
-+/*
-+ * Waits for the i2c status register to set the specified bitmask
-+ * Returns 0 if timed out ... ~100ms is much longer than the SMBus
-+ * limit, but I2C has no limit at all.
++/**
++ * ubifs_read_sb_node - read superblock node.
++ * @c: UBIFS file-system description object
++ *
++ * This function returns a pointer to the superblock node or a negative error
++ * code.
 + */
-+static int twi_complete(struct atmel_twi *twi, u32 mask)
++struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c)
 +{
-+      int timeout = msecs_to_jiffies(100);
++      struct ubifs_sb_node *sup;
++      int err;
 +
-+      mask |= TWI_BIT(TXCOMP);
-+      twi->mask = mask | TWI_BIT(NACK) | TWI_BIT(OVRE);
-+      init_completion(&twi->comp);
++      sup = kmalloc(ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size), GFP_NOFS);
++      if (!sup)
++              return ERR_PTR(-ENOMEM);
 +
-+      twi_writel(twi, IER, mask);
++      err = ubifs_read_node(c, sup, UBIFS_SB_NODE, UBIFS_SB_NODE_SZ,
++                            UBIFS_SB_LNUM, 0);
++      if (err) {
++              kfree(sup);
++              return ERR_PTR(err);
++      }
 +
-+      if (!wait_for_completion_timeout(&twi->comp, timeout)) {
-+              /* RESET TWI interface */
-+              twi_writel(twi, CR, TWI_BIT(SWRST));
++      return sup;
++}
 +
-+              /* Reinitialize TWI */
-+              twi_hwinit(twi);
++/**
++ * ubifs_write_sb_node - write superblock node.
++ * @c: UBIFS file-system description object
++ * @sup: superblock node read with 'ubifs_read_sb_node()'
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup)
++{
++      int len = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size);
 +
-+              return -ETIMEDOUT;
-+      }
-+      return 0;
++      ubifs_prepare_node(c, sup, UBIFS_SB_NODE_SZ, 1);
++      return ubi_leb_change(c->ubi, UBIFS_SB_LNUM, sup, len, UBI_LONGTERM);
 +}
 +
-+/*
-+ * Generic i2c master transfer entrypoint.
++/**
++ * ubifs_read_superblock - read superblock.
++ * @c: UBIFS file-system description object
++ *
++ * This function finds, reads and checks the superblock. If an empty UBI volume
++ * is being mounted, this function creates default superblock. Returns zero in
++ * case of success, and a negative error code in case of failure.
 + */
-+static int twi_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num)
++int ubifs_read_superblock(struct ubifs_info *c)
 +{
-+      struct atmel_twi *twi = to_atmel_twi(adap);
-+      int i;
++      int err, sup_flags;
++      struct ubifs_sb_node *sup;
 +
-+      dev_dbg(&adap->dev, "twi_xfer: processing %d messages:\n", num);
++      if (c->empty) {
++              err = create_default_filesystem(c);
++              if (err)
++                      return err;
++      }
 +
-+      twi->status = 0;
-+      for (i = 0; i < num; i++, pmsg++) {
-+              twi->len = pmsg->len;
-+              twi->buf = pmsg->buf;
-+              twi->acks_left = pmsg->len;
-+              twi_writel(twi, MMR, TWI_BF(DADR, pmsg->addr) |
-+                      (pmsg->flags & I2C_M_RD ? TWI_BIT(MREAD) : 0));
-+              twi_writel(twi, IADR, TWI_BF(IADR, pmsg->addr));
++      sup = ubifs_read_sb_node(c);
++      if (IS_ERR(sup))
++              return PTR_ERR(sup);
 +
-+              dev_dbg(&adap->dev,
-+                      "#%d: %s %d byte%s %s dev 0x%02x\n",
-+                      i,
-+                      pmsg->flags & I2C_M_RD ? "reading" : "writing",
-+                      pmsg->len,
-+                      pmsg->len > 1 ? "s" : "",
-+                      pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr);
++      /*
++       * The software supports all previous versions but not future versions,
++       * due to the unavailability of time-travelling equipment.
++       */
++      c->fmt_version = le32_to_cpu(sup->fmt_version);
++      if (c->fmt_version > UBIFS_FORMAT_VERSION) {
++              ubifs_err("on-flash format version is %d, but software only "
++                        "supports up to version %d", c->fmt_version,
++                        UBIFS_FORMAT_VERSION);
++              err = -EINVAL;
++              goto out;
++      }
 +
-+              /* enable */
-+              twi_writel(twi, CR, TWI_BIT(MSEN));
++      if (c->fmt_version < 3) {
++              ubifs_err("on-flash format version %d is not supported",
++                        c->fmt_version);
++              err = -EINVAL;
++              goto out;
++      }
 +
-+              if (pmsg->flags & I2C_M_RD) {
-+                      /* cleanup after previous RX overruns */
-+                      while (twi_readl(twi, SR) & TWI_BIT(RXRDY))
-+                              twi_readl(twi, RHR);
++      switch (sup->key_hash) {
++      case UBIFS_KEY_HASH_R5:
++              c->key_hash = key_r5_hash;
++              c->key_hash_type = UBIFS_KEY_HASH_R5;
++              break;
 +
-+                      if (twi->len == 1)
-+                              twi_writel(twi, CR,
-+                                      TWI_BIT(START) | TWI_BIT(STOP));
-+                      else
-+                              twi_writel(twi, CR, TWI_BIT(START));
++      case UBIFS_KEY_HASH_TEST:
++              c->key_hash = key_test_hash;
++              c->key_hash_type = UBIFS_KEY_HASH_TEST;
++              break;
++      };
 +
-+                      if (twi_complete(twi, TWI_BIT(RXRDY)) == -ETIMEDOUT) {
-+                              dev_dbg(&adap->dev, "RX[%d] timeout. "
-+                                      "Stopped with %d bytes left\n",
-+                                      i, twi->acks_left);
-+                              return -ETIMEDOUT;
-+                      }
-+              } else {
-+                      twi_writel(twi, THR, twi->buf[0]);
-+                      twi->acks_left--;
-+                      /* REVISIT: some chips don't start automagically:
-+                       * twi_writel(twi, CR, TWI_BIT(START));
-+                       */
-+                      if (twi_complete(twi, TWI_BIT(TXRDY)) == -ETIMEDOUT) {
-+                              dev_dbg(&adap->dev, "TX[%d] timeout. "
-+                                      "Stopped with %d bytes left\n",
-+                                      i, twi->acks_left);
-+                              return -ETIMEDOUT;
-+                      }
-+                      /* REVISIT: an erratum workaround may be needed here;
-+                       * see sam9261 "STOP not generated" (START either).
-+                       */
++      c->key_fmt = sup->key_fmt;
++
++      switch (c->key_fmt) {
++      case UBIFS_SIMPLE_KEY_FMT:
++              c->key_len = UBIFS_SK_LEN;
++              break;
++      default:
++              ubifs_err("unsupported key format");
++              err = -EINVAL;
++              goto out;
++      }
++
++      c->leb_cnt       = le32_to_cpu(sup->leb_cnt);
++      c->max_leb_cnt   = le32_to_cpu(sup->max_leb_cnt);
++      c->max_bud_bytes = le64_to_cpu(sup->max_bud_bytes);
++      c->log_lebs      = le32_to_cpu(sup->log_lebs);
++      c->lpt_lebs      = le32_to_cpu(sup->lpt_lebs);
++      c->orph_lebs     = le32_to_cpu(sup->orph_lebs);
++      c->jhead_cnt     = le32_to_cpu(sup->jhead_cnt) + NONDATA_JHEADS_CNT;
++      c->fanout        = le32_to_cpu(sup->fanout);
++      c->lsave_cnt     = le32_to_cpu(sup->lsave_cnt);
++      c->default_compr = le16_to_cpu(sup->default_compr);
++      c->rp_size       = le64_to_cpu(sup->rp_size);
++      c->rp_uid        = le32_to_cpu(sup->rp_uid);
++      c->rp_gid        = le32_to_cpu(sup->rp_gid);
++      sup_flags        = le32_to_cpu(sup->flags);
++
++      c->vfs_sb->s_time_gran = le32_to_cpu(sup->time_gran);
++
++      memcpy(&c->uuid, &sup->uuid, 16);
++
++      c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT);
++
++      /* Automatically increase file system size to the maximum size */
++      c->old_leb_cnt = c->leb_cnt;
++      if (c->leb_cnt < c->vi.size && c->leb_cnt < c->max_leb_cnt) {
++              c->leb_cnt = min_t(int, c->max_leb_cnt, c->vi.size);
++              if (c->vfs_sb->s_flags & MS_RDONLY)
++                      dbg_mnt("Auto resizing (ro) from %d LEBs to %d LEBs",
++                              c->old_leb_cnt, c->leb_cnt);
++              else {
++                      dbg_mnt("Auto resizing (sb) from %d LEBs to %d LEBs",
++                              c->old_leb_cnt, c->leb_cnt);
++                      sup->leb_cnt = cpu_to_le32(c->leb_cnt);
++                      err = ubifs_write_sb_node(c, sup);
++                      if (err)
++                              goto out;
++                      c->old_leb_cnt = c->leb_cnt;
 +              }
++      }
++
++      c->log_bytes = (long long)c->log_lebs * c->leb_size;
++      c->log_last = UBIFS_LOG_LNUM + c->log_lebs - 1;
++      c->lpt_first = UBIFS_LOG_LNUM + c->log_lebs;
++      c->lpt_last = c->lpt_first + c->lpt_lebs - 1;
++      c->orph_first = c->lpt_last + 1;
++      c->orph_last = c->orph_first + c->orph_lebs - 1;
++      c->main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS;
++      c->main_lebs -= c->log_lebs + c->lpt_lebs + c->orph_lebs;
++      c->main_first = c->leb_cnt - c->main_lebs;
++      c->report_rp_size = ubifs_reported_space(c, c->rp_size);
++
++      err = validate_sb(c, sup);
++out:
++      kfree(sup);
++      return err;
++}
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/scan.c avr32-2.6/fs/ubifs/scan.c
+--- linux-2.6.25.6/fs/ubifs/scan.c     1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/scan.c  2008-06-12 15:09:45.515816461 +0200
+@@ -0,0 +1,362 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Adrian Hunter
++ *          Artem Bityutskiy (Битюцкий Артём)
++ */
 +
-+              /* Disable TWI interface */
-+              twi_writel(twi, CR, TWI_BIT(MSDIS));
++/*
++ * This file implements the scan which is a general-purpose function for
++ * determining what nodes are in an eraseblock. The scan is used to replay the
++ * journal, to do garbage collection. for the TNC in-the-gaps method, and by
++ * debugging functions.
++ */
 +
-+              if (twi->status)
-+                      return twi->status;
++#include "ubifs.h"
 +
-+              /* WARNING:  This driver lies about properly supporting
-+               * repeated start, or it would *ALWAYS* return here.  It
-+               * has issued a STOP.  Continuing is a false claim -- that
-+               * a second (or third, etc.) message is part of the same
-+               * "combined" (no STOPs between parts) message.
-+               */
++/**
++ * scan_padding_bytes - scan for padding bytes.
++ * @buf: buffer to scan
++ * @len: length of buffer
++ *
++ * This function returns the number of padding bytes on success and
++ * %SCANNED_GARBAGE on failure.
++ */
++static int scan_padding_bytes(void *buf, int len)
++{
++      int pad_len = 0, max_pad_len = min_t(int, UBIFS_PAD_NODE_SZ, len);
++      uint8_t *p = buf;
 +
-+      } /* end cur msg */
++      dbg_scan("not a node");
 +
-+      return i;
-+}
++      while (pad_len < max_pad_len && *p++ == UBIFS_PADDING_BYTE)
++              pad_len += 1;
 +
++      if (!pad_len || (pad_len & 7))
++              return SCANNED_GARBAGE;
 +
-+static irqreturn_t twi_interrupt(int irq, void *dev_id)
++      dbg_scan("%d padding bytes", pad_len);
++
++      return pad_len;
++}
++
++/**
++ * ubifs_scan_a_node - scan for a node or padding.
++ * @c: UBIFS file-system description object
++ * @buf: buffer to scan
++ * @len: length of buffer
++ * @lnum: logical eraseblock number
++ * @offs: offset within the logical eraseblock
++ * @quiet: print no messages
++ *
++ * This function returns a scanning code to indicate what was scanned.
++ */
++int ubifs_scan_a_node(const struct ubifs_info *c, void *buf, int len, int lnum,
++                    int offs, int quiet)
 +{
-+      struct atmel_twi *twi = dev_id;
-+      int status = twi_readl(twi, SR);
++      struct ubifs_ch *ch = buf;
++      uint32_t magic;
 +
-+      /* Save state for later debug prints */
-+      int old_status = status;
++      magic = le32_to_cpu(ch->magic);
 +
-+      if (twi->mask & status) {
++      if (magic == 0xFFFFFFFF) {
++              dbg_scan("hit empty space");
++              return SCANNED_EMPTY_SPACE;
++      }
 +
-+              status &= twi->mask;
++      if (magic != UBIFS_NODE_MAGIC)
++              return scan_padding_bytes(buf, len);
 +
-+              if (status & TWI_BIT(RXRDY)) {
-+                      if ((status & TWI_BIT(OVRE)) && twi->acks_left) {
-+                              /* Note weakness in fault reporting model:
-+                               * we can't say "the first N of these data
-+                               * bytes are valid".
-+                               */
-+                              dev_err(&twi->adapter.dev,
-+                                      "OVERRUN RX! %04x, lost %d\n",
-+                                      old_status, twi->acks_left);
-+                              twi->acks_left = 0;
-+                              twi_writel(twi, CR, TWI_BIT(STOP));
-+                              twi->status = -EOVERFLOW;
-+                      } else if (twi->acks_left > 0) {
-+                              twi->buf[twi->len - twi->acks_left] =
-+                                      twi_readl(twi, RHR);
-+                              twi->acks_left--;
-+                      }
-+                      if (status & TWI_BIT(TXCOMP))
-+                              goto done;
-+                      if (twi->acks_left == 1)
-+                              twi_writel(twi, CR, TWI_BIT(STOP));
++      if (len < UBIFS_CH_SZ)
++              return SCANNED_GARBAGE;
 +
-+              } else if (status & (TWI_BIT(NACK) | TWI_BIT(TXCOMP))) {
-+                      goto done;
++      dbg_scan("scanning %s", dbg_ntype(ch->node_type));
 +
-+              } else if (status & TWI_BIT(TXRDY)) {
-+                      if (twi->acks_left > 0) {
-+                              twi_writel(twi, THR,
-+                                      twi->buf[twi->len - twi->acks_left]);
-+                              twi->acks_left--;
-+                      } else
-+                              twi_writel(twi, CR, TWI_BIT(STOP));
++      if (ubifs_check_node(c, buf, lnum, offs, quiet))
++              return SCANNED_A_CORRUPT_NODE;
++
++      if (ch->node_type == UBIFS_PAD_NODE) {
++              struct ubifs_pad_node *pad = buf;
++              int pad_len = le32_to_cpu(pad->pad_len);
++              int node_len = le32_to_cpu(ch->len);
++
++              /* Validate the padding node */
++              if (pad_len < 0 ||
++                  offs + node_len + pad_len > c->leb_size) {
++                      if (!quiet) {
++                              ubifs_err("bad pad node at LEB %d:%d",
++                                        lnum, offs);
++                              dbg_dump_node(c, pad);
++                      }
++                      return SCANNED_A_BAD_PAD_NODE;
 +              }
 +
-+              if (twi->acks_left == 0)
-+                      twi_writel(twi, IDR, ~TWI_BIT(TXCOMP));
++              /* Make the node pads to 8-byte boundary */
++              if ((node_len + pad_len) & 7) {
++                      if (!quiet) {
++                              dbg_err("bad padding length %d - %d",
++                                      offs, offs + node_len + pad_len);
++                      }
++                      return SCANNED_A_BAD_PAD_NODE;
++              }
++
++              dbg_scan("%d bytes padded, offset now %d",
++                       pad_len, ALIGN(offs + node_len + pad_len, 8));
++
++              return node_len + pad_len;
 +      }
 +
-+      /* enabling this message helps trigger overruns/underruns ... */
-+      dev_vdbg(&twi->adapter.dev,
-+              "ISR: SR 0x%04X, mask 0x%04X, acks %i\n",
-+              old_status,
-+              twi->acks_left ? twi->mask : TWI_BIT(TXCOMP),
-+              twi->acks_left);
++      return SCANNED_A_NODE;
++}
 +
-+      return IRQ_HANDLED;
++/**
++ * ubifs_start_scan - create LEB scanning information at start of scan.
++ * @c: UBIFS file-system description object
++ * @lnum: logical eraseblock number
++ * @offs: offset to start at (usually zero)
++ * @sbuf: scan buffer (must be c->leb_size)
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum,
++                                      int offs, void *sbuf)
++{
++      struct ubifs_scan_leb *sleb;
++      int err;
 +
-+done:
-+      /* Note weak fault reporting model:  we can't report how many
-+       * bytes we sent before the NAK, or let upper layers choose
-+       * whether to continue.  The I2C stack doesn't allow that...
-+       */
-+      if (status & TWI_BIT(NACK)) {
-+              dev_dbg(&twi->adapter.dev, "NACK received! %d to go\n",
-+                      twi->acks_left);
-+              twi->status = -EPIPE;
++      dbg_scan("scan LEB %d:%d", lnum, offs);
 +
-+      /* TX underrun morphs automagically into a premature STOP;
-+       * we'll probably observe UVRE even when it's not documented.
-+       */
-+      } else if (twi->acks_left && (twi->mask & TWI_BIT(TXRDY))) {
-+              dev_err(&twi->adapter.dev, "UNDERRUN TX!  %04x, %d to go\n",
-+                      old_status, twi->acks_left);
-+              twi->status = -ENOSR;
-+      }
++      sleb = kzalloc(sizeof(struct ubifs_scan_leb), GFP_NOFS);
++      if (!sleb)
++              return ERR_PTR(-ENOMEM);
 +
-+      twi_writel(twi, IDR, ~0UL);
-+      complete(&twi->comp);
++      sleb->lnum = lnum;
++      INIT_LIST_HEAD(&sleb->nodes);
++      sleb->buf = sbuf;
 +
-+      dev_dbg(&twi->adapter.dev, "ISR: SR 0x%04X, acks %i --> %d\n",
-+              old_status, twi->acks_left, twi->status);
++      err = ubi_read(c->ubi, lnum, sbuf + offs, offs, c->leb_size - offs);
++      if (err && err != -EBADMSG) {
++              ubifs_err("cannot read %d bytes from LEB %d:%d,"
++                        " error %d", c->leb_size - offs, lnum, offs, err);
++              kfree(sleb);
++              return ERR_PTR(err);
++      }
 +
-+      return IRQ_HANDLED;
++      if (err == -EBADMSG)
++              sleb->ecc = 1;
++
++      return sleb;
 +}
 +
++/**
++ * ubifs_end_scan - update LEB scanning information at end of scan.
++ * @c: UBIFS file-system description object
++ * @sleb: scanning information
++ * @lnum: logical eraseblock number
++ * @offs: offset to start at (usually zero)
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++void ubifs_end_scan(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
++                  int lnum, int offs)
++{
++      lnum = lnum;
++      dbg_scan("stop scanning LEB %d at offset %d", lnum, offs);
++      ubifs_assert(offs % c->min_io_size == 0);
++
++      sleb->endpt = ALIGN(offs, c->min_io_size);
++}
 +
-+/*
-+ * Return list of supported functionality.
++/**
++ * ubifs_add_snod - add a scanned node to LEB scanning information.
++ * @c: UBIFS file-system description object
++ * @sleb: scanning information
++ * @buf: buffer containing node
++ * @offs: offset of node on flash
 + *
-+ * NOTE:  see warning above about repeated starts; this driver is falsely
-+ * claiming to support "combined" transfers.  The mid-message STOPs mean
-+ * some slaves will never work with this driver.  (Use i2c-gpio...)
++ * This function returns %0 on success and a negative error code on failure.
 + */
-+static u32 twi_func(struct i2c_adapter *adapter)
++int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
++                 void *buf, int offs)
 +{
-+      return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL)
-+              & ~I2C_FUNC_SMBUS_QUICK;
++      struct ubifs_ch *ch = buf;
++      struct ubifs_ino_node *ino = buf;
++      struct ubifs_scan_node *snod;
++
++      snod = kzalloc(sizeof(struct ubifs_scan_node), GFP_NOFS);
++      if (!snod)
++              return -ENOMEM;
++
++      snod->sqnum = le64_to_cpu(ch->sqnum);
++      snod->type = ch->node_type;
++      snod->offs = offs;
++      snod->len = le32_to_cpu(ch->len);
++      snod->node = buf;
++
++      switch (ch->node_type) {
++      case UBIFS_INO_NODE:
++      case UBIFS_DENT_NODE:
++      case UBIFS_XENT_NODE:
++      case UBIFS_DATA_NODE:
++      case UBIFS_TRUN_NODE:
++              /*
++               * The key is in the same place in all keyed
++               * nodes.
++               */
++              key_read(c, &ino->key, &snod->key);
++              break;
++      }
++      list_add_tail(&snod->list, &sleb->nodes);
++      sleb->nodes_cnt += 1;
++      return 0;
 +}
 +
-+static struct i2c_algorithm twi_algorithm = {
-+      .master_xfer    = twi_xfer,
-+      .functionality  = twi_func,
-+};
++/**
++ * ubifs_scanned_corruption - print information after UBIFS scanned corruption.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number of corruption
++ * @offs: offset of corruption
++ * @buf: buffer containing corruption
++ */
++void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
++                            void *buf)
++{
++      int len;
 +
-+/*
-+ * Main initialization routine.
++      ubifs_err("corrupted data at LEB %d:%d", lnum, offs);
++      if (dbg_failure_mode)
++              return;
++      len = c->leb_size - offs;
++      if (len > 4096)
++              len = 4096;
++      dbg_err("first %d bytes from LEB %d:%d", len, lnum, offs);
++      print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 4, buf, len, 1);
++}
++
++/**
++ * ubifs_scan - scan a logical eraseblock.
++ * @c: UBIFS file-system description object
++ * @lnum: logical eraseblock number
++ * @offs: offset to start at (usually zero)
++ * @sbuf: scan buffer (must be c->leb_size)
++ *
++ * This function scans LEB number @lnum and returns complete information about
++ * its contents. Returns an error code in case of failure.
 + */
-+static int __init twi_probe(struct platform_device *pdev)
++struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
++                                int offs, void *sbuf)
 +{
-+      struct atmel_twi *twi;
-+      struct resource *regs;
-+      struct clk *pclk;
-+      struct i2c_adapter *adapter;
-+      int rc, irq;
++      void *buf = sbuf + offs;
++      int err, len = c->leb_size - offs;
++      struct ubifs_scan_leb *sleb;
 +
-+      regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      if (!regs)
-+              return -ENXIO;
++      sleb = ubifs_start_scan(c, lnum, offs, sbuf);
++      if (IS_ERR(sleb))
++              return sleb;
 +
-+      pclk = clk_get(&pdev->dev, "twi_pclk");
-+      if (IS_ERR(pclk))
-+              return PTR_ERR(pclk);
-+      clk_enable(pclk);
++      while (len >= 8) {
++              struct ubifs_ch *ch = buf;
++              int node_len, ret;
 +
-+      rc = -ENOMEM;
-+      twi = kzalloc(sizeof(struct atmel_twi), GFP_KERNEL);
-+      if (!twi) {
-+              dev_dbg(&pdev->dev, "can't allocate interface!\n");
-+              goto err_alloc_twi;
-+      }
++              dbg_scan("look at LEB %d:%d (%d bytes left)",
++                       lnum, offs, len);
 +
-+      twi->pclk = pclk;
-+      twi->regs = ioremap(regs->start, regs->end - regs->start + 1);
-+      if (!twi->regs)
-+              goto err_ioremap;
++              cond_resched();
 +
-+      irq = platform_get_irq(pdev, 0);
-+      rc = request_irq(irq, twi_interrupt, 0, "twi", twi);
-+      if (rc) {
-+              dev_dbg(&pdev->dev, "can't bind irq!\n");
-+              goto err_irq;
-+      }
-+      twi->irq = irq;
++              ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 0);
 +
-+      rc = twi_hwinit(twi);
-+      if (rc) {
-+              dev_err(&pdev->dev, "Unable to set baudrate\n");
-+              goto err_hw_init;
++              if (ret > 0) {
++                      /* Padding bytes or a valid padding node */
++                      offs += ret;
++                      buf += ret;
++                      len -= ret;
++                      continue;
++              }
++
++              if (ret == SCANNED_EMPTY_SPACE)
++                      /* Empty space is checked later */
++                      break;
++
++              switch (ret) {
++              case SCANNED_GARBAGE:
++                      dbg_err("garbage");
++                      goto corrupted;
++              case SCANNED_A_NODE:
++                      break;
++              case SCANNED_A_CORRUPT_NODE:
++              case SCANNED_A_BAD_PAD_NODE:
++                      dbg_err("bad node");
++                      goto corrupted;
++              default:
++                      dbg_err("unknown");
++                      goto corrupted;
++              }
++
++              err = ubifs_add_snod(c, sleb, buf, offs);
++              if (err)
++                      goto error;
++
++              node_len = ALIGN(le32_to_cpu(ch->len), 8);
++              offs += node_len;
++              buf += node_len;
++              len -= node_len;
 +      }
 +
-+      adapter = &twi->adapter;
-+      sprintf(adapter->name, "TWI");
-+      adapter->algo = &twi_algorithm;
-+      adapter->class = I2C_CLASS_ALL;
-+      adapter->nr = pdev->id;
-+      adapter->dev.parent = &pdev->dev;
++      if (offs % c->min_io_size)
++              goto corrupted;
 +
-+      platform_set_drvdata(pdev, twi);
++      ubifs_end_scan(c, sleb, lnum, offs);
 +
-+      rc = i2c_add_numbered_adapter(adapter);
-+      if (rc) {
-+              dev_dbg(&pdev->dev, "Adapter %s registration failed\n",
-+                      adapter->name);
-+              goto err_register;
++      for (; len > 4; offs += 4, buf = buf + 4, len -= 4)
++              if (*(uint32_t *)buf != 0xffffffff)
++                      break;
++      for (; len; offs++, buf++, len--)
++              if (*(uint8_t *)buf != 0xff) {
++                      ubifs_err("corrupt empty space at LEB %d:%d",
++                                lnum, offs);
++                      goto corrupted;
++              }
++
++      return sleb;
++
++corrupted:
++      ubifs_scanned_corruption(c, lnum, offs, buf);
++      err = -EUCLEAN;
++error:
++      ubifs_err("LEB %d scanning failed", lnum);
++      ubifs_scan_destroy(sleb);
++      return ERR_PTR(err);
++}
++
++/**
++ * ubifs_scan_destroy - destroy LEB scanning information.
++ * @sleb: scanning information to free
++ */
++void ubifs_scan_destroy(struct ubifs_scan_leb *sleb)
++{
++      struct ubifs_scan_node *node;
++      struct list_head *head;
++
++      head = &sleb->nodes;
++      while (!list_empty(head)) {
++              node = list_entry(head->next, struct ubifs_scan_node, list);
++              list_del(&node->list);
++              kfree(node);
 +      }
++      kfree(sleb);
++}
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/shrinker.c avr32-2.6/fs/ubifs/shrinker.c
+--- linux-2.6.25.6/fs/ubifs/shrinker.c 1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/shrinker.c      2008-06-12 15:09:45.515816461 +0200
+@@ -0,0 +1,322 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Artem Bityutskiy (Битюцкий Артём)
++ *          Adrian Hunter
++ */
 +
-+      dev_info(&pdev->dev,
-+              "Atmel TWI/I2C adapter (baudrate %dk) at 0x%08lx.\n",
-+               baudrate/1000, (unsigned long)regs->start);
++/*
++ * This file implements UBIFS shrinker which evicts clean znodes from the TNC
++ * tree when Linux VM needs more RAM.
++ *
++ * We do not implement any LRU lists to find oldest znodes to free because it
++ * would add additional overhead to the file system fast paths. So the shrinker
++ * just walks the TNC tree when searching for znodes to free.
++ *
++ * If the root of a TNC sub-tree is clean and old enough, then the children are
++ * also clean and old enough. So the shrinker walks the TNC in level order and
++ * dumps entire sub-trees.
++ *
++ * The age of znodes is just the time-stamp when they were last looked at.
++ * The current shrinker first tries to evict old znodes, then young ones.
++ *
++ * Since the shrinker is global, it has to protect against races with FS
++ * un-mounts, which is done by the 'ubifs_infos_lock' and 'c->umount_mutex'.
++ */
 +
-+      return 0;
++#include "ubifs.h"
 +
++/* List of all UBIFS file-system instances */
++LIST_HEAD(ubifs_infos);
 +
-+err_register:
-+      platform_set_drvdata(pdev, NULL);
++/*
++ * We number each shrinker run and record the number on the ubifs_info structure
++ * so that we can easily work out which ubifs_info structures have already been
++ * done by the current run.
++ */
++static unsigned int shrinker_run_no;
 +
-+err_hw_init:
-+      free_irq(irq, twi);
++/* Protects 'ubifs_infos' list */
++DEFINE_SPINLOCK(ubifs_infos_lock);
 +
-+err_irq:
-+      iounmap(twi->regs);
++/* Global clean znode counter (for all mounted UBIFS instances) */
++atomic_long_t ubifs_clean_zn_cnt;
 +
-+err_ioremap:
-+      kfree(twi);
++/**
++ * shrink_tnc - shrink TNC tree.
++ * @c: UBIFS file-system description object
++ * @nr: number of znodes to free
++ * @age: the age of znodes to free
++ * @contention: if any contention, this is set to %1
++ *
++ * This function traverses TNC tree and frees clean znodes. It does not free
++ * clean znodes which younger then @age. Returns number of freed znodes.
++ */
++static int shrink_tnc(struct ubifs_info *c, int nr, int age, int *contention)
++{
++      int total_freed = 0;
++      struct ubifs_znode *znode, *zprev;
++      int time = get_seconds();
 +
-+err_alloc_twi:
-+      clk_disable(pclk);
-+      clk_put(pclk);
++      ubifs_assert(mutex_is_locked(&c->umount_mutex));
++      ubifs_assert(mutex_is_locked(&c->tnc_mutex));
 +
-+      return rc;
-+}
++      if (!c->zroot.znode || atomic_long_read(&c->clean_zn_cnt) == 0)
++              return 0;
++
++      /*
++       * Traverse the TNC tree in levelorder manner, so that it is possible
++       * to destroy large sub-trees. Indeed, if a znode is old, then all its
++       * children are older or of the same age.
++       *
++       * Note, we are holding 'c->tnc_mutex', so we do not have to lock the
++       * 'c->space_lock' when _reading_ 'c->clean_zn_cnt', because it is
++       * changed only when the 'c->tnc_mutex' is held.
++       */
++      zprev = NULL;
++      znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL);
++      while (znode && total_freed < nr &&
++             atomic_long_read(&c->clean_zn_cnt) > 0) {
++              int freed;
 +
-+static int __exit twi_remove(struct platform_device *pdev)
-+{
-+      struct atmel_twi *twi = platform_get_drvdata(pdev);
-+      int res;
++              /*
++               * If the znode is clean, but it is in the 'c->cnext' list, this
++               * means that this znode has just been written to flash as a
++               * part of commit and was marked clean. They will be removed
++               * from the list at end commit. We cannot change the list,
++               * because it is not protected by any mutex (design decision to
++               * make commit really independent and parallel to main I/O). So
++               * we just skip these znodes.
++               *
++               * Note, the 'clean_zn_cnt' counters are not updated until
++               * after the commit, so the UBIFS shrinker does not report
++               * the znodes which are in the 'c->cnext' list as freeable.
++               *
++               * Also note, if the root of a sub-tree is not in 'c->cnext',
++               * then the whole sub-tree is not in 'c->cnext' as well, so it
++               * is safe to dump whole sub-tree.
++               */
 +
-+      platform_set_drvdata(pdev, NULL);
-+      res = i2c_del_adapter(&twi->adapter);
-+      twi_writel(twi, CR, TWI_BIT(MSDIS));
-+      iounmap(twi->regs);
-+      clk_disable(twi->pclk);
-+      clk_put(twi->pclk);
-+      free_irq(twi->irq, twi);
-+      kfree(twi);
++              if (znode->cnext) {
++                      /*
++                       * Very soon these znodes will be removed from the list
++                       * and become freeable.
++                       */
++                      *contention = 1;
++              } else if (!ubifs_zn_dirty(znode) &&
++                         abs(time - znode->time) >= age) {
++                      if (znode->parent)
++                              znode->parent->zbranch[znode->iip].znode = NULL;
++                      else
++                              c->zroot.znode = NULL;
++
++                      freed = ubifs_destroy_tnc_subtree(znode);
++                      atomic_long_sub(freed, &ubifs_clean_zn_cnt);
++                      atomic_long_sub(freed, &c->clean_zn_cnt);
++                      ubifs_assert(atomic_long_read(&c->clean_zn_cnt) >= 0);
++                      total_freed += freed;
++                      znode = zprev;
++              }
 +
-+      return res;
-+}
++              if (unlikely(!c->zroot.znode))
++                      break;
 +
-+static struct platform_driver twi_driver = {
-+      .remove         = __exit_p(twi_remove),
-+      .driver         = {
-+              .name   = "atmel_twi",
-+              .owner  = THIS_MODULE,
-+      },
-+};
++              zprev = znode;
++              znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode);
++              cond_resched();
++      }
 +
-+static int __init atmel_twi_init(void)
-+{
-+      return platform_driver_probe(&twi_driver, twi_probe);
++      return total_freed;
 +}
 +
-+static void __exit atmel_twi_exit(void)
-+{
-+      platform_driver_unregister(&twi_driver);
++/**
++ * shrink_tnc_trees - shrink UBIFS TNC trees.
++ * @nr: number of znodes to free
++ * @age: the age of znodes to free
++ * @contention: if any contention, this is set to %1
++ *
++ * This function walks the list of mounted UBIFS file-systems and frees clean
++ * znodes which are older then @age, until at least @nr znodes are freed.
++ * Returns the number of freed znodes.
++ */
++static int shrink_tnc_trees(int nr, int age, int *contention)
++{
++      struct ubifs_info *c;
++      struct list_head *p;
++      unsigned int run_no;
++      int freed = 0;
++
++      spin_lock(&ubifs_infos_lock);
++      do
++              run_no = ++shrinker_run_no;
++      while (run_no == 0);
++      /* Iterate over all mounted UBIFS file-systems and try to shrink them */
++      p = ubifs_infos.next;
++      while (p != &ubifs_infos) {
++              c = list_entry(p, struct ubifs_info, infos_list);
++              /*
++               * We move the ones we do to the end of the list, so we stop
++               * when we see one we have already done.
++               */
++              if (c->shrinker_run_no == run_no)
++                      break;
++              if (!mutex_trylock(&c->umount_mutex)) {
++                      /* Some un-mount is in progress, try next FS */
++                      *contention = 1;
++                      p = p->next;
++                      continue;
++              }
++              /*
++               * We're holding 'c->umount_mutex', so the file-system won't go
++               * away.
++               */
++              if (!mutex_trylock(&c->tnc_mutex)) {
++                      mutex_unlock(&c->umount_mutex);
++                      *contention = 1;
++                      p = p->next;
++                      continue;
++              }
++              spin_unlock(&ubifs_infos_lock);
++              /*
++               * OK, now we have TNC locked, the file-system cannot go away -
++               * it is safe to reap the cache.
++               */
++              c->shrinker_run_no = run_no;
++              freed += shrink_tnc(c, nr, age, contention);
++              mutex_unlock(&c->tnc_mutex);
++              spin_lock(&ubifs_infos_lock);
++              /* Get the next list element before we move this one */
++              p = p->next;
++              /*
++               * Move this one to the end of the list to provide some
++               * fairness.
++               */
++              list_del(&c->infos_list);
++              list_add_tail(&c->infos_list, &ubifs_infos);
++              mutex_unlock(&c->umount_mutex);
++              if (freed >= nr)
++                      break;
++      }
++      spin_unlock(&ubifs_infos_lock);
++      return freed;
 +}
 +
-+module_init(atmel_twi_init);
-+module_exit(atmel_twi_exit);
-+
-+MODULE_AUTHOR("Espen Krangnes");
-+MODULE_DESCRIPTION("I2C driver for Atmel TWI");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/i2c/busses/i2c-atmeltwi.h
-@@ -0,0 +1,117 @@
-+/*
-+ * Register definitions for the Atmel Two-Wire Interface
++/**
++ * kick_a_thread - kick a background thread to start commit.
++ *
++ * This function kicks a background thread to start background commit. Returns
++ * %-1 if a thread was kicked or there is another reason to assume the memory
++ * will soon be freed or become freeable. If there are no dirty znodes, returns
++ * %0.
 + */
++static int kick_a_thread(void)
++{
++      int i;
++      struct ubifs_info *c;
 +
-+#ifndef __ATMELTWI_H__
-+#define __ATMELTWI_H__
++      /*
++       * Iterate over all mounted UBIFS file-systems and find out if there is
++       * already an ongoing commit operation there. If no, then iterate for
++       * the second time and initiate background commit.
++       */
++      spin_lock(&ubifs_infos_lock);
++      for (i = 0; i < 2; i++) {
++              list_for_each_entry(c, &ubifs_infos, infos_list) {
++                      long dirty_zn_cnt;
++
++                      if (!mutex_trylock(&c->umount_mutex)) {
++                              /*
++                               * Some un-mount is in progress, it will
++                               * certainly free memory, so just return.
++                               */
++                              spin_unlock(&ubifs_infos_lock);
++                              return -1;
++                      }
 +
-+/* TWI register offsets */
-+#define TWI_CR                                        0x0000
-+#define TWI_MMR                                       0x0004
-+#define TWI_SMR                                       0x0008
-+#define TWI_IADR                              0x000c
-+#define TWI_CWGR                              0x0010
-+#define TWI_SR                                        0x0020
-+#define TWI_IER                                       0x0024
-+#define TWI_IDR                                       0x0028
-+#define TWI_IMR                                       0x002c
-+#define TWI_RHR                                       0x0030
-+#define TWI_THR                                       0x0034
++                      dirty_zn_cnt = atomic_long_read(&c->dirty_zn_cnt);
 +
-+/* Bitfields in CR */
-+#define TWI_START_OFFSET                      0
-+#define TWI_START_SIZE                                1
-+#define TWI_STOP_OFFSET                               1
-+#define TWI_STOP_SIZE                         1
-+#define TWI_MSEN_OFFSET                               2
-+#define TWI_MSEN_SIZE                         1
-+#define TWI_MSDIS_OFFSET                      3
-+#define TWI_MSDIS_SIZE                                1
-+#define TWI_SVEN_OFFSET                               4
-+#define TWI_SVEN_SIZE                         1
-+#define TWI_SVDIS_OFFSET                      5
-+#define TWI_SVDIS_SIZE                                1
-+#define TWI_SWRST_OFFSET                      7
-+#define TWI_SWRST_SIZE                                1
++                      if (!dirty_zn_cnt || c->cmt_state == COMMIT_BROKEN ||
++                          c->ro_media) {
++                              mutex_unlock(&c->umount_mutex);
++                              continue;
++                      }
 +
-+/* Bitfields in MMR */
-+#define TWI_IADRSZ_OFFSET                     8
-+#define TWI_IADRSZ_SIZE                               2
-+#define TWI_MREAD_OFFSET                      12
-+#define TWI_MREAD_SIZE                                1
-+#define TWI_DADR_OFFSET                               16
-+#define TWI_DADR_SIZE                         7
++                      if (c->cmt_state != COMMIT_RESTING) {
++                              spin_unlock(&ubifs_infos_lock);
++                              mutex_unlock(&c->umount_mutex);
++                              return -1;
++                      }
 +
-+/* Bitfields in SMR */
-+#define TWI_SADR_OFFSET                               16
-+#define TWI_SADR_SIZE                         7
++                      if (i == 1) {
++                              list_del(&c->infos_list);
++                              list_add_tail(&c->infos_list, &ubifs_infos);
++                              spin_unlock(&ubifs_infos_lock);
 +
-+/* Bitfields in IADR */
-+#define TWI_IADR_OFFSET                               0
-+#define TWI_IADR_SIZE                         24
++                              ubifs_request_bg_commit(c);
++                              mutex_unlock(&c->umount_mutex);
++                              return -1;
++                      }
++                      mutex_unlock(&c->umount_mutex);
++              }
++      }
++      spin_unlock(&ubifs_infos_lock);
 +
-+/* Bitfields in CWGR */
-+#define TWI_CLDIV_OFFSET                      0
-+#define TWI_CLDIV_SIZE                                8
-+#define TWI_CHDIV_OFFSET                      8
-+#define TWI_CHDIV_SIZE                                8
-+#define TWI_CKDIV_OFFSET                      16
-+#define TWI_CKDIV_SIZE                                3
++      return 0;
++}
 +
-+/* Bitfields in SR */
-+#define TWI_TXCOMP_OFFSET                     0
-+#define TWI_TXCOMP_SIZE                               1
-+#define TWI_RXRDY_OFFSET                      1
-+#define TWI_RXRDY_SIZE                                1
-+#define TWI_TXRDY_OFFSET                      2
-+#define TWI_TXRDY_SIZE                                1
-+#define TWI_SVDIR_OFFSET                      3
-+#define TWI_SVDIR_SIZE                                1
-+#define TWI_SVACC_OFFSET                      4
-+#define TWI_SVACC_SIZE                                1
-+#define TWI_GCACC_OFFSET                      5
-+#define TWI_GCACC_SIZE                                1
-+#define TWI_OVRE_OFFSET                               6
-+#define TWI_OVRE_SIZE                         1
-+#define TWI_UNRE_OFFSET                               7
-+#define TWI_UNRE_SIZE                         1
-+#define TWI_NACK_OFFSET                               8
-+#define TWI_NACK_SIZE                         1
-+#define TWI_ARBLST_OFFSET                     9
-+#define TWI_ARBLST_SIZE                               1
++int ubifs_shrinker(int nr, gfp_t gfp_mask)
++{
++      int freed, contention = 0;
++      long clean_zn_cnt = atomic_long_read(&ubifs_clean_zn_cnt);
 +
-+/* Bitfields in RHR */
-+#define TWI_RXDATA_OFFSET                     0
-+#define TWI_RXDATA_SIZE                               8
++      if (nr == 0)
++              return clean_zn_cnt;
 +
-+/* Bitfields in THR */
-+#define TWI_TXDATA_OFFSET                     0
-+#define TWI_TXDATA_SIZE                               8
++      if (!clean_zn_cnt) {
++              /*
++               * No clean znodes, nothing to reap. All we can do in this case
++               * is to kick background threads to start commit, which will
++               * probably make clean znodes which, in turn, will be freeable.
++               * And we return -1 which means will make VM call us again
++               * later.
++               */
++              dbg_tnc("no clean znodes, kick a thread");
++              return kick_a_thread();
++      }
 +
-+/* Constants for IADRSZ */
-+#define TWI_IADRSZ_NO_ADDR                    0
-+#define TWI_IADRSZ_ONE_BYTE                   1
-+#define TWI_IADRSZ_TWO_BYTES                  2
-+#define TWI_IADRSZ_THREE_BYTES                        3
++      freed = shrink_tnc_trees(nr, OLD_ZNODE_AGE, &contention);
++      if (freed >= nr)
++              goto out;
 +
-+/* Bit manipulation macros */
-+#define TWI_BIT(name)                                 \
-+      (1 << TWI_##name##_OFFSET)
-+#define TWI_BF(name, value)                           \
-+      (((value) & ((1 << TWI_##name##_SIZE) - 1))     \
-+       << TWI_##name##_OFFSET)
-+#define TWI_BFEXT(name, value)                                \
-+      (((value) >> TWI_##name##_OFFSET)               \
-+       & ((1 << TWI_##name##_SIZE) - 1))
-+#define TWI_BFINS(name, value, old)                   \
-+      (((old) & ~(((1 << TWI_##name##_SIZE) - 1)      \
-+                  << TWI_##name##_OFFSET))            \
-+       | TWI_BF(name, (value)))
++      dbg_tnc("not enough old znodes, try to free young ones");
++      freed += shrink_tnc_trees(nr - freed, YOUNG_ZNODE_AGE, &contention);
++      if (freed >= nr)
++              goto out;
 +
-+/* Register access macros */
-+#define twi_readl(port, reg)                          \
-+      __raw_readl((port)->regs + TWI_##reg)
-+#define twi_writel(port, reg, value)                  \
-+      __raw_writel((value), (port)->regs + TWI_##reg)
++      dbg_tnc("not enough young znodes, free all");
++      freed += shrink_tnc_trees(nr - freed, 0, &contention);
 +
-+#endif /* __ATMELTWI_H__ */
---- a/drivers/i2c/busses/Kconfig
-+++ b/drivers/i2c/busses/Kconfig
-@@ -88,6 +88,14 @@
-         to support combined I2C messages.  Use the i2c-gpio driver
-         unless your system can cope with those limitations.
-+config I2C_ATMELTWI
-+      tristate "Atmel Two-Wire Interface (TWI)"
-+      depends on I2C && (ARCH_AT91 || PLATFORM_AT32AP)
-+      help
-+        Atmel on-chip TWI controller. Say Y if you have an AT32 or
-+        AT91-based device and want to use its built-in TWI
-+        functionality.
++      if (!freed && contention) {
++              dbg_tnc("freed nothing, but contention");
++              return -1;
++      }
 +
- config I2C_AU1550
-       tristate "Au1550/Au1200 SMBus interface"
-       depends on SOC_AU1550 || SOC_AU1200
---- a/drivers/i2c/busses/Makefile
-+++ b/drivers/i2c/busses/Makefile
-@@ -53,6 +53,7 @@
- obj-$(CONFIG_I2C_VOODOO3)     += i2c-voodoo3.o
- obj-$(CONFIG_SCx200_ACB)      += scx200_acb.o
- obj-$(CONFIG_SCx200_I2C)      += scx200_i2c.o
-+obj-$(CONFIG_I2C_ATMELTWI)    += i2c-atmeltwi.o
- ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
- EXTRA_CFLAGS += -DDEBUG
---- /dev/null
-+++ b/drivers/input/serio/at32psif.c
-@@ -0,0 +1,351 @@
++out:
++      dbg_tnc("%d znodes were freed, requested %d", freed, nr);
++      return freed;
++}
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/super.c avr32-2.6/fs/ubifs/super.c
+--- linux-2.6.25.6/fs/ubifs/super.c    1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/super.c 2008-06-12 15:09:45.600758286 +0200
+@@ -0,0 +1,1969 @@
 +/*
-+ * Copyright (C) 2007 Atmel Corporation
++ * This file is part of UBIFS.
 + *
-+ * Driver for the AT32AP700X PS/2 controller (PSIF).
++ * Copyright (C) 2006-2008 Nokia Corporation.
 + *
 + * 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/kernel.h>
-+#include <linux/module.h>
-+#include <linux/device.h>
-+#include <linux/init.h>
-+#include <linux/serio.h>
-+#include <linux/timer.h>
-+#include <linux/interrupt.h>
-+#include <linux/err.h>
-+#include <linux/io.h>
-+#include <linux/clk.h>
-+#include <linux/platform_device.h>
-+
-+#include "at32psif.h"
-+
-+#define PSIF_BUF_SIZE         16
-+
-+#define ring_is_empty(_psif)  (_psif->head == _psif->tail)
-+#define ring_next_head(_psif) ((_psif->head + 1) & (PSIF_BUF_SIZE - 1))
-+#define ring_next_tail(_psif) ((_psif->tail + 1) & (PSIF_BUF_SIZE - 1))
-+
-+struct psif {
-+      struct platform_device  *pdev;
-+      struct clk              *pclk;
-+      struct serio            *io;
-+      struct timer_list       tx_timer;
-+      void __iomem            *regs;
-+      unsigned int            irq;
-+      unsigned int            open;
-+      /* Prevent concurrent writes to circular buffer. */
-+      spinlock_t              lock;
-+      unsigned int            head;
-+      unsigned int            tail;
-+      unsigned char           buffer[PSIF_BUF_SIZE];
++ * under the terms of the GNU General Public License version 2 as published by
++ * the Free Software Foundation.
++ *
++ * 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
++ *
++ * Authors: Artem Bityutskiy (Битюцкий Артём)
++ *          Adrian Hunter
++ */
++
++/*
++ * This file implements UBIFS initialization and VFS superblock operations. Some
++ * initialization stuff which is rather large and complex is placed at
++ * corresponding subsystems, but most of it is here.
++ */
++
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/ctype.h>
++#include <linux/random.h>
++#include <linux/kthread.h>
++#include <linux/parser.h>
++#include <linux/seq_file.h>
++#include <linux/mount.h>
++#include "ubifs.h"
++
++/* Slab cache for UBIFS inodes */
++struct kmem_cache *ubifs_inode_slab;
++
++/* UBIFS TNC shrinker description */
++static struct shrinker ubifs_shrinker_info = {
++      .shrink = ubifs_shrinker,
++      .seeks = DEFAULT_SEEKS,
 +};
 +
-+static irqreturn_t psif_interrupt(int irq, void *_ptr)
++/**
++ * validate_inode - validate inode.
++ * @c: UBIFS file-system description object
++ * @inode: the inode to validate
++ *
++ * This is a helper function for 'ubifs_iget()' which validates various fields
++ * of a newly built inode to make sure they contain sane values and prevent
++ * possible vulnerabilities. Returns zero if the inode is all right and
++ * a non-zero error code if not.
++ */
++static int validate_inode(struct ubifs_info *c, const struct inode *inode)
 +{
-+      struct psif *psif = _ptr;
-+      int retval = IRQ_NONE;
-+      unsigned int io_flags = 0;
-+      unsigned long status;
++      int err;
++      const struct ubifs_inode *ui = ubifs_inode(inode);
 +
-+      status = psif_readl(psif, SR);
++      if (inode->i_size > c->max_inode_sz) {
++              ubifs_err("inode is too large (%lld)",
++                        (long long)inode->i_size);
++              return 1;
++      }
 +
-+      if (status & PSIF_BIT(RXRDY)) {
-+              unsigned char val = (unsigned char) psif_readl(psif, RHR);
++      if (ui->compr_type < 0 || ui->compr_type >= UBIFS_COMPR_TYPES_CNT) {
++              ubifs_err("unknown compression type %d", ui->compr_type);
++              return 2;
++      }
 +
-+              if (status & PSIF_BIT(PARITY))
-+                      io_flags |= SERIO_PARITY;
-+              if (status & PSIF_BIT(OVRUN))
-+                      dev_err(&psif->pdev->dev, "overrun read error\n");
++      if (ui->xattr_cnt < 0)
++              return 3;
 +
-+              serio_interrupt(psif->io, val, io_flags);
++      if (ui->xattr_size < 0)
++              return 4;
 +
-+              retval = IRQ_HANDLED;
++      if (ui->xattr_names < 0 ||
++          ui->xattr_names + ui->xattr_cnt > XATTR_LIST_MAX)
++              return 5;
++
++      if (ui->data_len < 0 || ui->data_len > UBIFS_MAX_INO_DATA)
++              return 6;
++
++      if (!ubifs_compr_present(ui->compr_type)) {
++              ubifs_warn("inode %lu uses '%s' compression, but it was not "
++                         "compiled in", inode->i_ino,
++                         ubifs_compr_name(ui->compr_type));
 +      }
 +
-+      spin_lock(&psif->lock);
++      err = dbg_check_dir_size(c, inode);
++      return err;
++}
 +
-+      if (status & PSIF_BIT(TXEMPTY)) {
-+              if (status & PSIF_BIT(NACK))
-+                      dev_err(&psif->pdev->dev, "NACK error\n");
++struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
++{
++      int err;
++      union ubifs_key key;
++      struct ubifs_ino_node *ino;
++      struct ubifs_info *c = sb->s_fs_info;
++      struct inode *inode;
++      struct ubifs_inode *ui;
++
++      dbg_gen("inode %lu", inum);
++
++      inode = iget_locked(sb, inum);
++      if (!inode)
++              return ERR_PTR(-ENOMEM);
++      if (!(inode->i_state & I_NEW))
++              return inode;
++      ui = ubifs_inode(inode);
++
++      ino = kmalloc(UBIFS_MAX_INO_NODE_SZ, GFP_NOFS);
++      if (!ino) {
++              err = -ENOMEM;
++              goto out;
++      }
 +
-+              psif_writel(psif, IDR, PSIF_BIT(TXEMPTY));
++      ino_key_init(c, &key, inode->i_ino);
 +
-+              if (!ring_is_empty(psif))
-+                      mod_timer(&psif->tx_timer,
-+                                      jiffies + msecs_to_jiffies(1));
++      err = ubifs_tnc_lookup(c, &key, ino);
++      if (err)
++              goto out_ino;
++
++      inode->i_flags |= (S_NOCMTIME | S_NOATIME);
++      inode->i_nlink = le32_to_cpu(ino->nlink);
++      inode->i_uid   = le32_to_cpu(ino->uid);
++      inode->i_gid   = le32_to_cpu(ino->gid);
++      inode->i_atime.tv_sec  = (int64_t)le64_to_cpu(ino->atime_sec);
++      inode->i_atime.tv_nsec = le32_to_cpu(ino->atime_nsec);
++      inode->i_mtime.tv_sec  = (int64_t)le64_to_cpu(ino->mtime_sec);
++      inode->i_mtime.tv_nsec = le32_to_cpu(ino->mtime_nsec);
++      inode->i_ctime.tv_sec  = (int64_t)le64_to_cpu(ino->ctime_sec);
++      inode->i_ctime.tv_nsec = le32_to_cpu(ino->ctime_nsec);
++      inode->i_mode  = le32_to_cpu(ino->mode);
++      inode->i_size  = le64_to_cpu(ino->size);
++
++      ui->data_len    = le32_to_cpu(ino->data_len);
++      ui->flags       = le32_to_cpu(ino->flags);
++      ui->compr_type  = le16_to_cpu(ino->compr_type);
++      ui->creat_sqnum = le64_to_cpu(ino->creat_sqnum);
++      ui->xattr_cnt   = le32_to_cpu(ino->xattr_cnt);
++      ui->xattr_size  = le64_to_cpu(ino->xattr_size);
++      ui->xattr_names = le32_to_cpu(ino->xattr_names);
++
++      err = validate_inode(c, inode);
++      if (err)
++              goto out_invalid;
++
++      /* Disable readahead */
++      inode->i_mapping->backing_dev_info = &ubifs_backing_dev_info;
++
++      switch (inode->i_mode & S_IFMT) {
++      case S_IFREG:
++              inode->i_mapping->a_ops = &ubifs_file_address_operations;
++              inode->i_op = &ubifs_file_inode_operations;
++              inode->i_fop = &ubifs_file_operations;
++              if (ui->data_len != 0) {
++                      err = 10;
++                      goto out_invalid;
++              }
++              break;
++      case S_IFDIR:
++              inode->i_op  = &ubifs_dir_inode_operations;
++              inode->i_fop = &ubifs_dir_operations;
++              if (ui->data_len != 0) {
++                      err = 11;
++                      goto out_invalid;
++              }
++              break;
++      case S_IFLNK:
++              inode->i_op = &ubifs_symlink_inode_operations;
++              if (ui->data_len <= 0 || ui->data_len > UBIFS_MAX_INO_DATA) {
++                      err = 12;
++                      goto out_invalid;
++              }
++              ui->data = kmalloc(ui->data_len + 1, GFP_NOFS);
++              if (!ui->data) {
++                      err = -ENOMEM;
++                      goto out_ino;
++              }
++              memcpy(ui->data, ino->data, ui->data_len);
++              ((char *)ui->data)[ui->data_len] = '\0';
++              break;
++      case S_IFBLK:
++      case S_IFCHR:
++      {
++              dev_t rdev;
++              union ubifs_dev_desc *dev;
 +
-+              retval = IRQ_HANDLED;
-+      }
++              ui->data = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS);
++              if (!ui->data) {
++                      err = -ENOMEM;
++                      goto out_ino;
++              }
 +
-+      spin_unlock(&psif->lock);
++              dev = (union ubifs_dev_desc *)ino->data;
++              if (ui->data_len == sizeof(dev->new))
++                      rdev = new_decode_dev(le32_to_cpu(dev->new));
++              else if (ui->data_len == sizeof(dev->huge))
++                      rdev = huge_decode_dev(le64_to_cpu(dev->huge));
++              else {
++                      err = 13;
++                      goto out_invalid;
++              }
++              memcpy(ui->data, ino->data, ui->data_len);
++              inode->i_op = &ubifs_file_inode_operations;
++              init_special_inode(inode, inode->i_mode, rdev);
++              break;
++      }
++      case S_IFSOCK:
++      case S_IFIFO:
++              inode->i_op = &ubifs_file_inode_operations;
++              init_special_inode(inode, inode->i_mode, 0);
++              if (ui->data_len != 0) {
++                      err = 14;
++                      goto out_invalid;
++              }
++              break;
++      default:
++              err = 15;
++              goto out_invalid;
++      }
 +
-+      return retval;
++      kfree(ino);
++      ubifs_set_inode_flags(inode);
++      unlock_new_inode(inode);
++      return inode;
++
++out_invalid:
++      ubifs_err("inode %lu validation failed, error %d", inode->i_ino, err);
++      dbg_dump_node(c, ino);
++      dbg_dump_inode(c, inode);
++      err = -EINVAL;
++out_ino:
++      kfree(ino);
++out:
++      ubifs_err("failed to read inode %lu, error %d", inode->i_ino, err);
++      iget_failed(inode);
++      return ERR_PTR(err);
 +}
 +
-+static void psif_transmit_data(unsigned long data)
++static struct inode *ubifs_alloc_inode(struct super_block *sb)
 +{
-+      struct psif *psif = (struct psif *)data;
-+      unsigned long flags;
++      struct ubifs_inode *ui;
 +
-+      spin_lock_irqsave(&psif->lock, flags);
++      ui = kmem_cache_alloc(ubifs_inode_slab, GFP_NOFS);
++      if (!ui)
++              return NULL;
 +
-+      psif_writel(psif, THR, psif->buffer[psif->tail]);
-+      psif->tail = ring_next_tail(psif);
++      memset((void *)ui + sizeof(struct inode), 0,
++             sizeof(struct ubifs_inode) - sizeof(struct inode));
++      mutex_init(&ui->budg_mutex);
++      return &ui->vfs_inode;
++};
 +
-+      if (!ring_is_empty(psif))
-+              psif_writel(psif, IER, PSIF_BIT(TXEMPTY));
++static void ubifs_destroy_inode(struct inode *inode)
++{
++      struct ubifs_inode *ui = ubifs_inode(inode);
 +
-+      spin_unlock_irqrestore(&psif->lock, flags);
++      kfree(ui->data);
++      kmem_cache_free(ubifs_inode_slab, inode);
 +}
 +
-+static int psif_write(struct serio *io, unsigned char val)
++/*
++ * Note, Linux write-back code calls this without 'i_mutex'.
++ */
++static int ubifs_write_inode(struct inode *inode, int wait)
 +{
-+      struct psif *psif = io->port_data;
-+      unsigned long flags;
-+      unsigned int head;
++      int err;
++      struct ubifs_info *c = inode->i_sb->s_fs_info;
++      struct ubifs_inode *ui = ubifs_inode(inode);
++      struct ubifs_budget_req req = {.dd_growth = c->inode_budget,
++                                     .dirtied_ino_d = ui->data_len};
 +
-+      spin_lock_irqsave(&psif->lock, flags);
++      ubifs_assert(!ui->xattr);
++      if (is_bad_inode(inode))
++              return 0;
 +
-+      head = ring_next_head(psif);
++      mutex_lock(&ui->budg_mutex);
 +
-+      if (head != psif->tail) {
-+              psif->buffer[psif->head] = val;
-+              psif->head = head;
-+      } else {
-+              dev_err(&psif->pdev->dev, "underrun write error\n");
++      /*
++       * Due to races between write-back forced by budgeting
++       * (see 'sync_some_inodes()') and pdflush write-back, the inode may
++       * have already been synchronized, do not do this again.
++       *
++       * This might also happen if it was synchronized in e.g. ubifs_link()',
++       * etc.
++       */
++      if (!ui->dirty) {
++              mutex_unlock(&ui->budg_mutex);
++              return 0;
 +      }
 +
-+      spin_unlock_irqrestore(&psif->lock, flags);
++      ubifs_assert(ui->budgeted);
++      dbg_gen("inode %lu", inode->i_ino);
 +
-+      /* Make sure TXEMPTY interrupt is enabled. */
-+      psif_writel(psif, IER, PSIF_BIT(TXEMPTY));
++      err = ubifs_jnl_write_inode(c, inode, 0, IS_SYNC(inode));
++      if (err)
++              ubifs_err("can't write inode %lu, error %d", inode->i_ino, err);
 +
-+      return 0;
++      ui->dirty = 0;
++      UBIFS_DBG(ui->budgeted = 0);
++      atomic_long_dec(&c->dirty_ino_cnt);
++
++      ubifs_release_budget(c, &req);
++      mutex_unlock(&ui->budg_mutex);
++
++      return err;
 +}
 +
-+static int psif_open(struct serio *io)
++static void ubifs_delete_inode(struct inode *inode)
 +{
-+      struct psif *psif = io->port_data;
-+      int retval;
++      struct ubifs_info *c = inode->i_sb->s_fs_info;
++      struct ubifs_inode *ui = ubifs_inode(inode);
++      struct ubifs_budget_req req = {.dd_growth = c->inode_budget,
++                                     .dirtied_ino_d = ui->data_len};
++      int err;
 +
-+      retval = clk_enable(psif->pclk);
-+      if (retval)
++      if (ui->xattr) {
++              /*
++               * Extended attribute inode deletions are fully handled in
++               * 'ubifs_removexattr()'. These inodes are special and have
++               * limited usage, so there is nothing to do here.
++               */
++              ubifs_assert(!ui->dirty);
 +              goto out;
++      }
 +
-+      psif_writel(psif, CR, PSIF_BIT(CR_TXEN) | PSIF_BIT(CR_RXEN));
-+      psif_writel(psif, IER, PSIF_BIT(RXRDY));
++      dbg_gen("inode %lu", inode->i_ino);
++      ubifs_assert(!atomic_read(&inode->i_count));
++      ubifs_assert(inode->i_nlink == 0);
 +
-+      psif->open = 1;
++      truncate_inode_pages(&inode->i_data, 0);
++      if (is_bad_inode(inode))
++              goto out;
++
++      mutex_lock(&ui->budg_mutex);
++
++      inode->i_size = 0;
++
++      err = ubifs_jnl_write_inode(c, inode, 1, IS_SYNC(inode));
++      if (err)
++              /*
++               * Worst case we have a lost orphan inode wasting space, so a
++               * simple error message is ok here.
++               */
++              ubifs_err("can't write inode %lu, error %d", inode->i_ino, err);
++
++      if (ui->dirty) {
++              ubifs_assert(ui->budgeted);
++              atomic_long_dec(&c->dirty_ino_cnt);
++              ui->dirty = 0;
++              UBIFS_DBG(ui->budgeted = 0);
++              ubifs_release_budget(c, &req);
++      }
++
++      mutex_unlock(&ui->budg_mutex);
 +out:
-+      return retval;
++      clear_inode(inode);
 +}
 +
-+static void psif_close(struct serio *io)
++static void ubifs_dirty_inode(struct inode *inode)
 +{
-+      struct psif *psif = io->port_data;
++      struct ubifs_inode *ui = ubifs_inode(inode);
 +
-+      psif->open = 0;
++      ubifs_assert(mutex_is_locked(&ui->budg_mutex));
++      if (!ui->dirty) {
++              struct ubifs_info *c = inode->i_sb->s_fs_info;
 +
-+      psif_writel(psif, IDR, ~0UL);
-+      psif_writel(psif, CR, PSIF_BIT(CR_TXDIS) | PSIF_BIT(CR_RXDIS));
++              ui->dirty = 1;
++              atomic_long_inc(&c->dirty_ino_cnt);
++              dbg_gen("inode %lu",  inode->i_ino);
++      }
++}
 +
-+      clk_disable(psif->pclk);
++static int ubifs_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++      struct ubifs_info *c = dentry->d_sb->s_fs_info;
++      unsigned long long free;
++
++      free = ubifs_budg_get_free_space(c);
++      dbg_gen("free space %lld bytes (%lld blocks)",
++              free, free >> UBIFS_BLOCK_SHIFT);
++
++      buf->f_type = UBIFS_SUPER_MAGIC;
++      buf->f_bsize = UBIFS_BLOCK_SIZE;
++      buf->f_blocks = c->block_cnt;
++      buf->f_bfree = free >> UBIFS_BLOCK_SHIFT;
++      if (free > c->report_rp_size)
++              buf->f_bavail = (free - c->report_rp_size) >> UBIFS_BLOCK_SHIFT;
++      else
++              buf->f_bavail = 0;
++      buf->f_files = 0;
++      buf->f_ffree = 0;
++      buf->f_namelen = UBIFS_MAX_NLEN;
++
++      return 0;
 +}
 +
-+static void psif_set_prescaler(struct psif *psif)
++static int ubifs_show_options(struct seq_file *s, struct vfsmount *mnt)
 +{
-+      unsigned long prscv;
-+      unsigned long rate = clk_get_rate(psif->pclk);
++      struct ubifs_info *c = mnt->mnt_sb->s_fs_info;
 +
-+      /* PRSCV = Pulse length (100 us) * PSIF module frequency. */
-+      prscv = 100 * (rate / 1000000UL);
++      if (c->mount_opts.unmount_mode == 2)
++              seq_printf(s, ",fast_unmount");
++      else if (c->mount_opts.unmount_mode == 1)
++              seq_printf(s, ",norm_unmount");
 +
-+      if (prscv > ((1<<PSIF_PSR_PRSCV_SIZE) - 1)) {
-+              prscv = (1<<PSIF_PSR_PRSCV_SIZE) - 1;
-+              dev_dbg(&psif->pdev->dev, "pclk too fast, "
-+                              "prescaler set to max\n");
-+      }
++      return 0;
++}
 +
-+      clk_enable(psif->pclk);
-+      psif_writel(psif, PSR, prscv);
-+      clk_disable(psif->pclk);
++static int ubifs_sync_fs(struct super_block *sb, int wait)
++{
++      struct ubifs_info *c = sb->s_fs_info;
++      int i, ret = 0, err;
++
++      if (c->jheads)
++              for (i = 0; i < c->jhead_cnt; i++) {
++                      err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
++                      if (err && !ret)
++                              ret = err;
++              }
++      /*
++       * We ought to call sync for c->ubi but it does not have one. If it had
++       * it would in turn call mtd->sync, however mtd operations are
++       * synchronous anyway, so we don't lose any sleep here.
++       */
++      return ret;
 +}
 +
-+static int __init psif_probe(struct platform_device *pdev)
++/**
++ * init_constants_early - initialize UBIFS constants.
++ * @c: UBIFS file-system description object
++ *
++ * This function initialize UBIFS constants which do not need the superblock to
++ * be read. It also checks that the UBI volume satisfies basic UBIFS
++ * requirements. Returns zero in case of success and a negative error code in
++ * case of failure.
++ */
++static int init_constants_early(struct ubifs_info *c)
 +{
-+      struct resource *regs;
-+      struct psif *psif;
-+      struct serio *io;
-+      struct clk *pclk;
-+      int irq;
-+      int ret;
++      if (c->vi.corrupted) {
++              ubifs_warn("UBI volume is corrupted - read-only mode");
++              c->ro_media = 1;
++      }
 +
-+      psif = kzalloc(sizeof(struct psif), GFP_KERNEL);
-+      if (!psif) {
-+              dev_dbg(&pdev->dev, "out of memory\n");
-+              ret = -ENOMEM;
-+              goto out;
++      if (c->di.ro_mode) {
++              ubifs_msg("read-only UBI device");
++              c->ro_media = 1;
 +      }
-+      psif->pdev = pdev;
 +
-+      io = kzalloc(sizeof(struct serio), GFP_KERNEL);
-+      if (!io) {
-+              dev_dbg(&pdev->dev, "out of memory\n");
-+              ret = -ENOMEM;
-+              goto out_free_psif;
++      if (c->vi.vol_type == UBI_STATIC_VOLUME) {
++              ubifs_msg("static UBI volume - read-only mode");
++              c->ro_media = 1;
 +      }
-+      psif->io = io;
 +
-+      regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      if (!regs) {
-+              dev_dbg(&pdev->dev, "no mmio resources defined\n");
-+              ret = -ENOMEM;
-+              goto out_free_io;
++      c->leb_cnt = c->vi.size;
++      c->leb_size = c->vi.usable_leb_size;
++      c->half_leb_size = c->leb_size / 2;
++      c->min_io_size = c->di.min_io_size;
++      c->min_io_shift = fls(c->min_io_size) - 1;
++
++      if (c->leb_size < UBIFS_MIN_LEB_SZ) {
++              ubifs_err("too small LEBs (%d bytes), min. is %d bytes",
++                        c->leb_size, UBIFS_MIN_LEB_SZ);
++              return -EINVAL;
 +      }
 +
-+      psif->regs = ioremap(regs->start, regs->end - regs->start + 1);
-+      if (!psif->regs) {
-+              ret = -ENOMEM;
-+              dev_dbg(&pdev->dev, "could not map I/O memory\n");
-+              goto out_free_io;
++      if (c->leb_cnt < UBIFS_MIN_LEB_CNT) {
++              ubifs_err("too few LEBs (%d), min. is %d",
++                        c->leb_cnt, UBIFS_MIN_LEB_CNT);
++              return -EINVAL;
 +      }
 +
-+      pclk = clk_get(&pdev->dev, "pclk");
-+      if (IS_ERR(pclk)) {
-+              dev_dbg(&pdev->dev, "could not get peripheral clock\n");
-+              ret = PTR_ERR(pclk);
-+              goto out_iounmap;
++      if (!is_power_of_2(c->min_io_size)) {
++              ubifs_err("bad min. I/O size %d", c->min_io_size);
++              return -EINVAL;
 +      }
-+      psif->pclk = pclk;
 +
-+      /* Reset the PSIF to enter at a known state. */
-+      ret = clk_enable(pclk);
-+      if (ret) {
-+              dev_dbg(&pdev->dev, "could not enable pclk\n");
-+              goto out_put_clk;
++      /*
++       * UBIFS aligns all node to 8-byte boundary, so to make function in
++       * io.c simpler, assume minimum I/O unit size to be 8 bytes if it is
++       * less than 8.
++       */
++      if (c->min_io_size < 8) {
++              c->min_io_size = 8;
++              c->min_io_shift = 3;
 +      }
-+      psif_writel(psif, CR, PSIF_BIT(CR_SWRST));
-+      clk_disable(pclk);
 +
-+      setup_timer(&psif->tx_timer, psif_transmit_data, (unsigned long)psif);
++      c->ref_node_alsz = ALIGN(UBIFS_REF_NODE_SZ, c->min_io_size);
++      c->mst_node_alsz = ALIGN(UBIFS_MST_NODE_SZ, c->min_io_size);
 +
-+      irq = platform_get_irq(pdev, 0);
-+      if (irq < 0) {
-+              dev_dbg(&pdev->dev, "could not get irq\n");
-+              ret = -ENXIO;
-+              goto out_put_clk;
-+      }
-+      ret = request_irq(irq, psif_interrupt, IRQF_SHARED, "at32psif", psif);
-+      if (ret) {
-+              dev_dbg(&pdev->dev, "could not request irq %d\n", irq);
-+              goto out_put_clk;
-+      }
-+      psif->irq = irq;
++      /*
++       * Initialize node length ranges which are mostly needed for node
++       * length validation.
++       */
++      c->ranges[UBIFS_PAD_NODE].len  = UBIFS_PAD_NODE_SZ;
++      c->ranges[UBIFS_SB_NODE].len   = UBIFS_SB_NODE_SZ;
++      c->ranges[UBIFS_MST_NODE].len  = UBIFS_MST_NODE_SZ;
++      c->ranges[UBIFS_REF_NODE].len  = UBIFS_REF_NODE_SZ;
++      c->ranges[UBIFS_TRUN_NODE].len = UBIFS_TRUN_NODE_SZ;
++      c->ranges[UBIFS_CS_NODE].len   = UBIFS_CS_NODE_SZ;
++
++      c->ranges[UBIFS_INO_NODE].min_len  = UBIFS_INO_NODE_SZ;
++      c->ranges[UBIFS_INO_NODE].max_len  = UBIFS_MAX_INO_NODE_SZ;
++      c->ranges[UBIFS_ORPH_NODE].min_len =
++                              UBIFS_ORPH_NODE_SZ + sizeof(__le64);
++      c->ranges[UBIFS_ORPH_NODE].max_len = c->leb_size;
++      c->ranges[UBIFS_DENT_NODE].min_len = UBIFS_DENT_NODE_SZ;
++      c->ranges[UBIFS_DENT_NODE].max_len = UBIFS_MAX_DENT_NODE_SZ;
++      c->ranges[UBIFS_XENT_NODE].min_len = UBIFS_XENT_NODE_SZ;
++      c->ranges[UBIFS_XENT_NODE].max_len = UBIFS_MAX_XENT_NODE_SZ;
++      c->ranges[UBIFS_DATA_NODE].min_len = UBIFS_DATA_NODE_SZ;
++      c->ranges[UBIFS_DATA_NODE].max_len = UBIFS_MAX_DATA_NODE_SZ;
++      /*
++       * Minimum indexing node size is amended later when superblock is
++       * read and the key length is known.
++       */
++      c->ranges[UBIFS_IDX_NODE].min_len = UBIFS_IDX_NODE_SZ + UBIFS_BRANCH_SZ;
++      /*
++       * Maximum indexing node size is amended later when superblock is
++       * read and the fanout is known.
++       */
++      c->ranges[UBIFS_IDX_NODE].max_len = INT_MAX;
++
++      /*
++       * Initialize dead and dark LEB space watermarks.
++       *
++       * Dead space is the space which cannot be used. Its watermark is
++       * equivalent to min. I/O unit or minimum node size if it is greater
++       * then min. I/O unit.
++       *
++       * Dark space is the space which might be used, or might not, depending
++       * on which node should be written to the LEB. Its watermark is
++       * equivalent to maximum UBIFS node size.
++       */
++      c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size);
++      c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size);
++
++      return 0;
++}
++
++/**
++ * bud_wbuf_callback - bud LEB write-buffer synchronization call-back.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB the write-buffer was synchronized to
++ * @free: how many free bytes left in this LEB
++ * @pad: how many bytes were padded
++ *
++ * This is a callback function which is called by the I/O unit when the
++ * write-buffer is synchronized. We need this to correctly maintain space
++ * accounting in bud logical eraseblocks. This function returns zero in case of
++ * success and a negative error code in case of failure.
++ *
++ * This function actually belongs to the journal, but we keep it here because
++ * we want to keep it static.
++ */
++static int bud_wbuf_callback(struct ubifs_info *c, int lnum, int free, int pad)
++{
++      return ubifs_update_one_lp(c, lnum, free, pad, 0, 0);
++}
++
++/*
++ * init_constants_late - initialize UBIFS constants.
++ * @c: UBIFS file-system description object
++ *
++ * This is a helper function which initializes various UBIFS constants after
++ * the superblock has been read. It also checks various UBIFS parameters and
++ * makes sure they are all right. Returns zero in case of success and a
++ * negative error code in case of failure.
++ */
++static int init_constants_late(struct ubifs_info *c)
++{
++      int tmp, err;
++      uint64_t tmp64;
++
++      c->main_bytes = c->main_lebs * c->leb_size;
++
++      c->max_znode_sz = sizeof(struct ubifs_znode) +
++                              c->fanout * sizeof(struct ubifs_zbranch);
 +
-+      io->id.type     = SERIO_8042;
-+      io->write       = psif_write;
-+      io->open        = psif_open;
-+      io->close       = psif_close;
-+      strlcpy(io->name, pdev->dev.bus_id, sizeof(io->name));
-+      strlcpy(io->phys, pdev->dev.bus_id, sizeof(io->phys));
-+      io->port_data   = psif;
-+      io->dev.parent  = &pdev->dev;
++      tmp = ubifs_idx_node_sz(c, 1);
++      c->ranges[UBIFS_IDX_NODE].min_len = tmp;
++      c->min_idx_node_sz = ALIGN(tmp, 8);
 +
-+      psif_set_prescaler(psif);
++      tmp = ubifs_idx_node_sz(c, c->fanout);
++      c->ranges[UBIFS_IDX_NODE].max_len = tmp;
++      c->max_idx_node_sz = ALIGN(tmp, 8);
 +
-+      spin_lock_init(&psif->lock);
-+      serio_register_port(psif->io);
-+      platform_set_drvdata(pdev, psif);
++      /* Make sure LEB size is large enough to fit full commit */
++      tmp = UBIFS_CS_NODE_SZ + UBIFS_REF_NODE_SZ * c->jhead_cnt;
++      tmp = ALIGN(tmp, c->min_io_size);
++      if (tmp > c->leb_size) {
++              dbg_err("too small LEB size %d, at least %d needed",
++                      c->leb_size, tmp);
++              return -EINVAL;
++      }
 +
-+      dev_info(&pdev->dev, "Atmel AVR32 PSIF PS/2 driver on 0x%08x irq %d\n",
-+                      (int)psif->regs, psif->irq);
++      /*
++       * Make sure that the log is large enough to fit reference nodes for
++       * all buds plus one reserved LEB.
++       */
++      tmp64 = c->max_bud_bytes;
++      tmp = do_div(tmp64, c->leb_size);
++      c->max_bud_cnt = tmp64 + !!tmp;
++      tmp = (c->ref_node_alsz * c->max_bud_cnt + c->leb_size - 1);
++      tmp /= c->leb_size;
++      tmp += 1;
++      if (c->log_lebs < tmp) {
++              dbg_err("too small log %d LEBs, required min. %d LEBs",
++                      c->log_lebs, tmp);
++              return -EINVAL;
++      }
 +
-+      return 0;
++      /*
++       * When budgeting we assume worst-case scenarios when the pages are not
++       * be compressed and direntries are of the maximum size.
++       *
++       * Note, data, which may be stored in inodes is budgeted separately, so
++       * it is not included into 'c->inode_budget'.
++       */
++      c->page_budget = UBIFS_MAX_DATA_NODE_SZ * UBIFS_BLOCKS_PER_PAGE;
++      c->inode_budget = UBIFS_INO_NODE_SZ;
++      c->dent_budget = UBIFS_MAX_DENT_NODE_SZ;
 +
-+out_put_clk:
-+      clk_put(psif->pclk);
-+out_iounmap:
-+      iounmap(psif->regs);
-+out_free_io:
-+      kfree(io);
-+out_free_psif:
-+      kfree(psif);
-+out:
-+      return ret;
-+}
++      /*
++       * When the amount of flash space used by buds becomes
++       * 'c->max_bud_bytes', UBIFS just blocks all writers and starts commit.
++       * The writers are unblocked when the commit is finished. To avoid
++       * writers to be blocked UBIFS initiates background commit in advance,
++       * when number of bud bytes becomes above the limit defined below.
++       */
++      c->bg_bud_bytes = (c->max_bud_bytes * 13) >> 4;
 +
-+static int __exit psif_remove(struct platform_device *pdev)
-+{
-+      struct psif *psif = platform_get_drvdata(pdev);
++      /*
++       * Ensure minimum journal size. All the bytes in the journal heads are
++       * considered to be used, when calculating the current journal usage.
++       * Consequently, if the journal is too small, UBIFS will treat it as
++       * always full.
++       */
++      tmp64 = (uint64_t)(c->jhead_cnt + 1) * c->leb_size + 1;
++      if (c->bg_bud_bytes < tmp64)
++              c->bg_bud_bytes = tmp64;
++      if (c->max_bud_bytes < tmp64 + c->leb_size)
++              c->max_bud_bytes = tmp64 + c->leb_size;
 +
-+      psif_writel(psif, IDR, ~0UL);
-+      psif_writel(psif, CR, PSIF_BIT(CR_TXDIS) | PSIF_BIT(CR_RXDIS));
++      err = ubifs_calc_lpt_geom(c);
++      if (err)
++              return err;
 +
-+      serio_unregister_port(psif->io);
-+      iounmap(psif->regs);
-+      free_irq(psif->irq, psif);
-+      clk_put(psif->pclk);
-+      kfree(psif);
++      c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
 +
-+      platform_set_drvdata(pdev, NULL);
++      /*
++       * Calculate total amount of FS blocks. This number is not used
++       * internally because it does not make much sense for UBIFS, but it is
++       * necessary to report something for the 'statfs()' call.
++       *
++       * Subtract the LEB reserved for GC and the LEB which is reserved for
++       * deletions.
++       *
++       * Review 'ubifs_calc_available()' if changing this calculation.
++       */
++      tmp64 = c->main_lebs - 2;
++      tmp64 *= c->leb_size - c->dark_wm;
++      tmp64 = ubifs_reported_space(c, tmp64);
++      c->block_cnt = tmp64 >> UBIFS_BLOCK_SHIFT;
 +
 +      return 0;
 +}
 +
-+#ifdef CONFIG_PM
-+static int psif_suspend(struct platform_device *pdev, pm_message_t state)
++/**
++ * take_gc_lnum - reserve GC LEB.
++ * @c: UBIFS file-system description object
++ *
++ * This function ensures that the LEB reserved for garbage collection is
++ * unmapped and is marked as "taken" in lprops. We also have to set free space
++ * to LEB size and dirty space to zero, because lprops may contain out-of-date
++ * information if the file-system was un-mounted before it has been committed.
++ * This function returns zero in case of success and a negative error code in
++ * case of failure.
++ */
++static int take_gc_lnum(struct ubifs_info *c)
 +{
-+      struct psif *psif = platform_get_drvdata(pdev);
++      int err;
 +
-+      if (psif->open) {
-+              psif_writel(psif, CR, PSIF_BIT(CR_RXDIS) | PSIF_BIT(CR_TXDIS));
-+              clk_disable(psif->pclk);
++      if (c->gc_lnum == -1) {
++              ubifs_err("no LEB for GC");
++              return -EINVAL;
 +      }
 +
-+      return 0;
++      err = ubifs_leb_unmap(c, c->gc_lnum);
++      if (err)
++              return err;
++
++      /* And we have to tell lprops that this LEB is taken */
++      err = ubifs_change_one_lp(c, c->gc_lnum, c->leb_size, 0,
++                                LPROPS_TAKEN, 0, 0);
++      return err;
 +}
 +
-+static int psif_resume(struct platform_device *pdev)
++/**
++ * alloc_wbufs - allocate write-buffers.
++ * @c: UBIFS file-system description object
++ *
++ * This helper function allocates and initializes UBIFS write-buffers. Returns
++ * zero in case of success and %-ENOMEM in case of failure.
++ */
++static int alloc_wbufs(struct ubifs_info *c)
 +{
-+      struct psif *psif = platform_get_drvdata(pdev);
++      int i, err;
 +
-+      if (psif->open) {
-+              clk_enable(psif->pclk);
-+              psif_set_prescaler(psif);
-+              psif_writel(psif, CR, PSIF_BIT(CR_RXEN) | PSIF_BIT(CR_TXEN));
++      c->jheads = kzalloc(c->jhead_cnt * sizeof(struct ubifs_jhead),
++                         GFP_KERNEL);
++      if (!c->jheads)
++              return -ENOMEM;
++
++      /* Initialize journal heads */
++      for (i = 0; i < c->jhead_cnt; i++) {
++              INIT_LIST_HEAD(&c->jheads[i].buds_list);
++              err = ubifs_wbuf_init(c, &c->jheads[i].wbuf);
++              if (err)
++                      return err;
++
++              c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback;
++              c->jheads[i].wbuf.jhead = i;
 +      }
 +
++      c->jheads[BASEHD].wbuf.dtype = UBI_SHORTTERM;
++      /*
++       * Garbage Collector head likely contains long-term data and
++       * does not need to be synchronized by timer.
++       */
++      c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM;
++      c->jheads[GCHD].wbuf.timeout = 0;
++
 +      return 0;
 +}
-+#else
-+#define psif_suspend  NULL
-+#define psif_resume   NULL
-+#endif
-+
-+static struct platform_driver psif_driver = {
-+      .remove         = __exit_p(psif_remove),
-+      .driver         = {
-+              .name   = "atmel_psif",
-+      },
-+      .suspend        = psif_suspend,
-+      .resume         = psif_resume,
-+};
 +
-+static int __init psif_init(void)
++/**
++ * free_wbufs - free write-buffers.
++ * @c: UBIFS file-system description object
++ */
++static void free_wbufs(struct ubifs_info *c)
 +{
-+      return platform_driver_probe(&psif_driver, psif_probe);
-+}
++      int i;
 +
-+static void __exit psif_exit(void)
-+{
-+      platform_driver_unregister(&psif_driver);
++      if (c->jheads) {
++              for (i = 0; i < c->jhead_cnt; i++) {
++                      kfree(c->jheads[i].wbuf.buf);
++                      kfree(c->jheads[i].wbuf.inodes);
++              }
++              kfree(c->jheads);
++              c->jheads = NULL;
++      }
 +}
 +
-+module_init(psif_init);
-+module_exit(psif_exit);
-+
-+MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
-+MODULE_DESCRIPTION("Atmel AVR32 PSIF PS/2 driver");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/input/serio/at32psif.h
-@@ -0,0 +1,82 @@
-+/*
-+ * Copyright (C) 2007 Atmel Corporation
-+ *
-+ * Driver for the AT32AP700X PS/2 controller (PSIF).
-+ *
-+ * 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.
++/**
++ * free_orphans - free orphans.
++ * @c: UBIFS file-system description object
 + */
++static void free_orphans(struct ubifs_info *c)
++{
++      struct ubifs_orphan *orph;
 +
-+#ifndef _AT32PSIF_H
-+#define _AT32PSIF_H
++      while (c->orph_dnext) {
++              orph = c->orph_dnext;
++              c->orph_dnext = orph->dnext;
++              list_del(&orph->list);
++              kfree(orph);
++      }
 +
-+/* PSIF register offsets */
-+#define PSIF_CR                               0x00
-+#define PSIF_RHR                      0x04
-+#define PSIF_THR                      0x08
-+#define PSIF_SR                               0x10
-+#define PSIF_IER                      0x14
-+#define PSIF_IDR                      0x18
-+#define PSIF_IMR                      0x1c
-+#define PSIF_PSR                      0x24
++      while (!list_empty(&c->orph_list)) {
++              orph = list_entry(c->orph_list.next, struct ubifs_orphan, list);
++              list_del(&orph->list);
++              kfree(orph);
++              dbg_err("orphan list not empty at unmount");
++      }
 +
-+/* Bitfields in control register. */
-+#define PSIF_CR_RXDIS_OFFSET          1
-+#define PSIF_CR_RXDIS_SIZE            1
-+#define PSIF_CR_RXEN_OFFSET           0
-+#define PSIF_CR_RXEN_SIZE             1
-+#define PSIF_CR_SWRST_OFFSET          15
-+#define PSIF_CR_SWRST_SIZE            1
-+#define PSIF_CR_TXDIS_OFFSET          9
-+#define PSIF_CR_TXDIS_SIZE            1
-+#define PSIF_CR_TXEN_OFFSET           8
-+#define PSIF_CR_TXEN_SIZE             1
++      vfree(c->orph_buf);
++      c->orph_buf = NULL;
++}
 +
-+/* Bitfields in interrupt disable, enable, mask and status register. */
-+#define PSIF_NACK_OFFSET              8
-+#define PSIF_NACK_SIZE                        1
-+#define PSIF_OVRUN_OFFSET             5
-+#define PSIF_OVRUN_SIZE                       1
-+#define PSIF_PARITY_OFFSET            9
-+#define PSIF_PARITY_SIZE              1
-+#define PSIF_RXRDY_OFFSET             4
-+#define PSIF_RXRDY_SIZE                       1
-+#define PSIF_TXEMPTY_OFFSET           1
-+#define PSIF_TXEMPTY_SIZE             1
-+#define PSIF_TXRDY_OFFSET             0
-+#define PSIF_TXRDY_SIZE                       1
++/**
++ * free_buds - free per-bud objects.
++ * @c: UBIFS file-system description object
++ */
++static void free_buds(struct ubifs_info *c)
++{
++      struct rb_node *this = c->buds.rb_node;
++      struct ubifs_bud *bud;
++
++      while (this) {
++              if (this->rb_left)
++                      this = this->rb_left;
++              else if (this->rb_right)
++                      this = this->rb_right;
++              else {
++                      bud = rb_entry(this, struct ubifs_bud, rb);
++                      this = rb_parent(this);
++                      if (this) {
++                              if (this->rb_left == &bud->rb)
++                                      this->rb_left = NULL;
++                              else
++                                      this->rb_right = NULL;
++                      }
++                      kfree(bud);
++              }
++      }
++}
 +
-+/* Bitfields in prescale register. */
-+#define PSIF_PSR_PRSCV_OFFSET         0
-+#define PSIF_PSR_PRSCV_SIZE           12
++/**
++ * check_volume_empty - check if the UBI volume is empty.
++ * @c: UBIFS file-system description object
++ *
++ * This function checks if the UBIFS volume is empty by looking if its LEBs are
++ * mapped or not. The result of checking is stored in the @c->empty variable.
++ * Returns zero in case of success and a negative error code in case of
++ * failure.
++ */
++static int check_volume_empty(struct ubifs_info *c)
++{
++      int lnum, err;
 +
-+/* Bitfields in receive hold register. */
-+#define PSIF_RHR_RXDATA_OFFSET                0
-+#define PSIF_RHR_RXDATA_SIZE          8
++      c->empty = 1;
++      for (lnum = 0; lnum < c->leb_cnt; lnum++) {
++              err = ubi_is_mapped(c->ubi, lnum);
++              if (unlikely(err < 0))
++                      return err;
++              if (err == 1) {
++                      c->empty = 0;
++                      break;
++              }
 +
-+/* Bitfields in transmit hold register. */
-+#define PSIF_THR_TXDATA_OFFSET                0
-+#define PSIF_THR_TXDATA_SIZE          8
++              cond_resched();
++      }
 +
-+/* Bit manipulation macros */
-+#define PSIF_BIT(name)                                        \
-+      (1 << PSIF_##name##_OFFSET)
-+#define PSIF_BF(name, value)                          \
-+      (((value) & ((1 << PSIF_##name##_SIZE) - 1))    \
-+       << PSIF_##name##_OFFSET)
-+#define PSIF_BFEXT(name, value)\
-+      (((value) >> PSIF_##name##_OFFSET)              \
-+       & ((1 << PSIF_##name##_SIZE) - 1))
-+#define PSIF_BFINS(name, value, old)                  \
-+      (((old) & ~(((1 << PSIF_##name##_SIZE) - 1)     \
-+                  << PSIF_##name##_OFFSET))           \
-+       | PSIF_BF(name, value))
++      return 0;
++}
 +
-+/* Register access macros */
-+#define psif_readl(port, reg)                         \
-+      __raw_readl((port)->regs + PSIF_##reg)
-+#define psif_writel(port, reg, value)                 \
-+      __raw_writel((value), (port)->regs + PSIF_##reg)
++/*
++ * UBIFS mount options.
++ *
++ * Opt_fast_unmount: do not run a journal commit before un-mounting
++ * Opt_norm_unmount: run a journal commit before un-mounting
++ * Opt_err: just end of array marker
++ */
++enum {
++      Opt_fast_unmount,
++      Opt_norm_unmount,
++      Opt_err,
++};
 +
-+#endif /* _AT32PSIF_H */
---- a/drivers/input/serio/Kconfig
-+++ b/drivers/input/serio/Kconfig
-@@ -88,6 +88,17 @@
-         To compile this driver as a module, choose M here: the
-         module will be called rpckbd.
-+config SERIO_AT32PSIF
-+      tristate "AVR32 PSIF PS/2 keyboard and mouse controller"
-+      depends on AVR32
-+      default n
-+      help
-+        Say Y here if you want to use the PSIF peripheral on AVR32 devices
-+        and connect a PS/2 keyboard and/or mouse to it.
++static match_table_t tokens = {
++      {Opt_fast_unmount, "fast_unmount"},
++      {Opt_norm_unmount, "norm_unmount"},
++      {Opt_err, NULL},
++};
 +
-+        To compile this driver as a module, choose M here: the module will
-+        be called at32psif.
++/**
++ * ubifs_parse_options - parse mount parameters.
++ * @c: UBIFS file-system description object
++ * @options: parameters to parse
++ * @is_remount: non-zero if this is FS re-mount
++ *
++ * This function parses UBIFS mount options and returns zero in case success
++ * and a negative error code in case of failure.
++ */
++static int ubifs_parse_options(struct ubifs_info *c, char *options,
++                             int is_remount)
++{
++      char *p;
++      substring_t args[MAX_OPT_ARGS];
 +
- config SERIO_AMBAKMI
-       tristate "AMBA KMI keyboard controller"
-       depends on ARM_AMBA
---- a/drivers/input/serio/Makefile
-+++ b/drivers/input/serio/Makefile
-@@ -12,6 +12,7 @@
- obj-$(CONFIG_SERIO_RPCKBD)    += rpckbd.o
- obj-$(CONFIG_SERIO_SA1111)    += sa1111ps2.o
- obj-$(CONFIG_SERIO_AMBAKMI)   += ambakmi.o
-+obj-$(CONFIG_SERIO_AT32PSIF)  += at32psif.o
- obj-$(CONFIG_SERIO_Q40KBD)    += q40kbd.o
- obj-$(CONFIG_SERIO_GSCPS2)    += gscps2.o
- obj-$(CONFIG_HP_SDC)          += hp_sdc.o
---- a/drivers/leds/Kconfig
-+++ b/drivers/leds/Kconfig
-@@ -18,6 +18,13 @@
- comment "LED drivers"
-+config LEDS_ATMEL_PWM
-+      tristate "LED Support using Atmel PWM outputs"
-+      depends on LEDS_CLASS && ATMEL_PWM
-+      help
-+        This option enables support for LEDs driven using outputs
-+        of the dedicated PWM controller found on newer Atmel SOCs.
-+
- config LEDS_CORGI
-       tristate "LED Support for the Sharp SL-C7x0 series"
-       depends on LEDS_CLASS && PXA_SHARP_C7xx
---- /dev/null
-+++ b/drivers/leds/leds-atmel-pwm.c
-@@ -0,0 +1,155 @@
-+#include <linux/kernel.h>
-+#include <linux/platform_device.h>
-+#include <linux/leds.h>
-+#include <linux/io.h>
-+#include <linux/atmel_pwm.h>
++      if (!options)
++              return 0;
 +
++      while ((p = strsep(&options, ","))) {
++              int token;
 +
-+struct pwmled {
-+      struct led_classdev     cdev;
-+      struct pwm_channel      pwmc;
-+      struct gpio_led         *desc;
-+      u32                     mult;
-+      u8                      active_low;
-+};
++              if (!*p)
++                      continue;
++
++              token = match_token(p, tokens, args);
++              switch (token) {
++              case Opt_fast_unmount:
++                      c->mount_opts.unmount_mode = 2;
++                      c->fast_unmount = 1;
++                      break;
++              case Opt_norm_unmount:
++                      c->mount_opts.unmount_mode = 1;
++                      c->fast_unmount = 0;
++                      break;
++              default:
++                      ubifs_err("unrecognized mount option \"%s\" "
++                                "or missing value", p);
++                      return -EINVAL;
++              }
++      }
 +
++      return 0;
++}
 +
-+/*
-+ * For simplicity, we use "brightness" as if it were a linear function
-+ * of PWM duty cycle.  However, a logarithmic function of duty cycle is
-+ * probably a better match for perceived brightness: two is half as bright
-+ * as four, four is half as bright as eight, etc
++/**
++ * destroy_journal - destroy journal data structures.
++ * @c: UBIFS file-system description object
++ *
++ * This function destroys journal data structures including those that may have
++ * been created by recovery functions.
 + */
-+static void pwmled_brightness(struct led_classdev *cdev, enum led_brightness b)
++static void destroy_journal(struct ubifs_info *c)
 +{
-+      struct pwmled            *led;
++      while (!list_empty(&c->unclean_leb_list)) {
++              struct ubifs_unclean_leb *ucleb;
++
++              ucleb = list_entry(c->unclean_leb_list.next,
++                                 struct ubifs_unclean_leb, list);
++              list_del(&ucleb->list);
++              kfree(ucleb);
++      }
++      while (!list_empty(&c->old_buds)) {
++              struct ubifs_bud *bud;
 +
-+      /* update the duty cycle for the *next* period */
-+      led = container_of(cdev, struct pwmled, cdev);
-+      pwm_channel_writel(&led->pwmc, PWM_CUPD, led->mult * (unsigned) b);
++              bud = list_entry(c->old_buds.next, struct ubifs_bud, list);
++              list_del(&bud->list);
++              kfree(bud);
++      }
++      ubifs_destroy_idx_gc(c);
++      ubifs_destroy_size_tree(c);
++      ubifs_tnc_close(c);
++      free_buds(c);
 +}
 +
-+/*
-+ * NOTE:  we reuse the platform_data structure of GPIO leds,
-+ * but repurpose its "gpio" number as a PWM channel number.
++/**
++ * mount_ubifs - mount UBIFS file-system.
++ * @c: UBIFS file-system description object
++ *
++ * This function mounts UBIFS file system. Returns zero in case of success and
++ * a negative error code in case of failure.
++ *
++ * Note, the function does not de-allocate resources it it fails half way
++ * through, and the caller has to do this instead.
 + */
-+static int __init pwmled_probe(struct platform_device *pdev)
++static int mount_ubifs(struct ubifs_info *c)
 +{
-+      const struct gpio_led_platform_data     *pdata;
-+      struct pwmled                           *leds;
-+      unsigned                                i;
-+      int                                     status;
++      struct super_block *sb = c->vfs_sb;
++      int err, mounted_read_only = (sb->s_flags & MS_RDONLY);
++      unsigned long long x;
++      size_t sz;
 +
-+      pdata = pdev->dev.platform_data;
-+      if (!pdata || pdata->num_leds < 1)
-+              return -ENODEV;
++      err = init_constants_early(c);
++      if (err)
++              return err;
 +
-+      leds = kcalloc(pdata->num_leds, sizeof(*leds), GFP_KERNEL);
-+      if (!leds)
++#ifdef CONFIG_UBIFS_FS_DEBUG
++      c->dbg_buf = vmalloc(c->leb_size);
++      if (!c->dbg_buf)
 +              return -ENOMEM;
++#endif
 +
-+      for (i = 0; i < pdata->num_leds; i++) {
-+              struct pwmled           *led = leds + i;
-+              const struct gpio_led   *dat = pdata->leds + i;
-+              u32                     tmp;
-+
-+              led->cdev.name = dat->name;
-+              led->cdev.brightness = LED_OFF;
-+              led->cdev.brightness_set = pwmled_brightness;
-+              led->cdev.default_trigger = dat->default_trigger;
-+
-+              led->active_low = dat->active_low;
-+
-+              status = pwm_channel_alloc(dat->gpio, &led->pwmc);
-+              if (status < 0)
-+                      goto err;
-+
-+              /*
-+               * Prescale clock by 2^x, so PWM counts in low MHz.
-+               * Start each cycle with the LED active, so increasing
-+               * the duty cycle gives us more time on (== brighter).
-+               */
-+              tmp = 5;
-+              if (!led->active_low)
-+                      tmp |= PWM_CPR_CPOL;
-+              pwm_channel_writel(&led->pwmc, PWM_CMR, tmp);
++      err = check_volume_empty(c);
++      if (err)
++              goto out_free;
 +
++      if (c->empty && (mounted_read_only || c->ro_media)) {
 +              /*
-+               * Pick a period so PWM cycles at 100+ Hz; and a multiplier
-+               * for scaling duty cycle:  brightness * mult.
++               * This UBI volume is empty, and read-only, or the file system
++               * is mounted read-only - we cannot format it.
 +               */
-+              tmp = (led->pwmc.mck / (1 << 5)) / 100;
-+              tmp /= 255;
-+              led->mult = tmp;
-+              pwm_channel_writel(&led->pwmc, PWM_CDTY,
-+                              led->cdev.brightness * 255);
-+              pwm_channel_writel(&led->pwmc, PWM_CPRD,
-+                              LED_FULL * tmp);
++              ubifs_err("can't format empty UBI volume: read-only %s",
++                        c->ro_media ? "UBI volume" : "mount");
++              err = -EROFS;
++              goto out_free;
++      }
 +
-+              pwm_channel_enable(&led->pwmc);
++      if (c->ro_media && !mounted_read_only) {
++              ubifs_err("cannot mount read-write - read-only media");
++              err = -EROFS;
++              goto out_free;
++      }
 +
-+              /* Hand it over to the LED framework */
-+              status = led_classdev_register(&pdev->dev, &led->cdev);
-+              if (status < 0) {
-+                      pwm_channel_free(&led->pwmc);
-+                      goto err;
-+              }
++      /*
++       * The requirement for the buffer is that it should fit indexing B-tree
++       * height amount of integers. We assume the height if the TNC tree will
++       * never exceed 64.
++       */
++      err = -ENOMEM;
++      c->bottom_up_buf = kmalloc(BOTTOM_UP_HEIGHT * sizeof(int), GFP_KERNEL);
++      if (!c->bottom_up_buf)
++              goto out_free;
++
++      c->sbuf = vmalloc(c->leb_size);
++      if (!c->sbuf)
++              goto out_free;
++
++      if (!mounted_read_only) {
++              c->ileb_buf = vmalloc(c->leb_size);
++              if (!c->ileb_buf)
++                      goto out_free;
 +      }
 +
-+      platform_set_drvdata(pdev, leds);
-+      return 0;
++      err = ubifs_read_superblock(c);
++      if (err)
++              goto out_free;
 +
-+err:
-+      while (i-- > 0) {
-+              led_classdev_unregister(&leds[i].cdev);
-+              pwm_channel_free(&leds[i].pwmc);
++      /*
++       * Make sure the compressor which is set as the default on in the
++       * superblock was actually compiled in.
++       */
++      if (!ubifs_compr_present(c->default_compr)) {
++              ubifs_warn("'%s' compressor is set by superblock, but not "
++                         "compiled in", ubifs_compr_name(c->default_compr));
++              c->default_compr = UBIFS_COMPR_NONE;
 +      }
-+      kfree(leds);
-+
-+      return status;
-+}
 +
-+static int __exit pwmled_remove(struct platform_device *pdev)
-+{
-+      const struct gpio_led_platform_data     *pdata;
-+      struct pwmled                           *leds;
-+      unsigned                                i;
++      dbg_failure_mode_registration(c);
 +
-+      pdata = pdev->dev.platform_data;
-+      leds = platform_get_drvdata(pdev);
++      err = init_constants_late(c);
++      if (err)
++              goto out_dereg;
++
++      sz = ALIGN(c->max_idx_node_sz, c->min_io_size);
++      sz = ALIGN(sz + c->max_idx_node_sz, c->min_io_size);
++      c->cbuf = kmalloc(sz, GFP_NOFS);
++      if (!c->cbuf) {
++              err = -ENOMEM;
++              goto out_dereg;
++      }
 +
-+      for (i = 0; i < pdata->num_leds; i++) {
-+              struct pwmled           *led = leds + i;
++      if (!mounted_read_only) {
++              err = alloc_wbufs(c);
++              if (err)
++                      goto out_cbuf;
++
++              /* Create background thread */
++              sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num,
++                      c->vi.vol_id);
++              c->bgt = kthread_create(ubifs_bg_thread, c, c->bgt_name);
++              if (!c->bgt)
++                      c->bgt = ERR_PTR(-EINVAL);
++              if (IS_ERR(c->bgt)) {
++                      err = PTR_ERR(c->bgt);
++                      c->bgt = NULL;
++                      ubifs_err("cannot spawn \"%s\", error %d",
++                                c->bgt_name, err);
++                      goto out_wbufs;
++              }
++              wake_up_process(c->bgt);
++      }
 +
-+              led_classdev_unregister(&led->cdev);
-+              pwm_channel_free(&led->pwmc);
++      err = ubifs_read_master(c);
++      if (err)
++              goto out_stop;
++
++      if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) {
++              ubifs_msg("recovery needed");
++              c->need_recovery = 1;
++              if (!mounted_read_only) {
++                      err = ubifs_recover_inl_heads(c, c->sbuf);
++                      if (err)
++                              goto out_master;
++              }
++      } else if (!mounted_read_only) {
++              /*
++               * Set the "dirty" flag so that if we reboot uncleanly we
++               * will notice this immediately on the next mount.
++               */
++              c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
++              err = ubifs_write_master(c);
++              if (err)
++                      goto out_master;
 +      }
 +
-+      kfree(leds);
-+      platform_set_drvdata(pdev, NULL);
-+      return 0;
-+}
++      err = ubifs_lpt_init(c, 1, !mounted_read_only);
++      if (err)
++              goto out_lpt;
 +
-+static struct platform_driver pwmled_driver = {
-+      .driver = {
-+              .name =         "leds-atmel-pwm",
-+              .owner =        THIS_MODULE,
-+      },
-+      /* REVISIT add suspend() and resume() methods */
-+      .remove =       __exit_p(pwmled_remove),
-+};
++      err = dbg_check_idx_size(c, c->old_idx_sz);
++      if (err)
++              goto out_lpt;
 +
-+static int __init modinit(void)
-+{
-+      return platform_driver_probe(&pwmled_driver, pwmled_probe);
-+}
-+module_init(modinit);
++      err = ubifs_replay_journal(c);
++      if (err)
++              goto out_journal;
 +
-+static void __exit modexit(void)
-+{
-+      platform_driver_unregister(&pwmled_driver);
-+}
-+module_exit(modexit);
++      err = ubifs_mount_orphans(c, c->need_recovery, mounted_read_only);
++      if (err)
++              goto out_orphans;
 +
-+MODULE_DESCRIPTION("Driver for LEDs with PWM-controlled brightness");
-+MODULE_LICENSE("GPL");
---- a/drivers/leds/Makefile
-+++ b/drivers/leds/Makefile
-@@ -5,6 +5,7 @@
- obj-$(CONFIG_LEDS_TRIGGERS)           += led-triggers.o
- # LED Platform Drivers
-+obj-$(CONFIG_LEDS_ATMEL_PWM)          += leds-atmel-pwm.o
- obj-$(CONFIG_LEDS_CORGI)              += leds-corgi.o
- obj-$(CONFIG_LEDS_LOCOMO)             += leds-locomo.o
- obj-$(CONFIG_LEDS_SPITZ)              += leds-spitz.o
---- /dev/null
-+++ b/drivers/misc/atmel_pwm.c
-@@ -0,0 +1,409 @@
-+#include <linux/module.h>
-+#include <linux/clk.h>
-+#include <linux/err.h>
-+#include <linux/io.h>
-+#include <linux/interrupt.h>
-+#include <linux/platform_device.h>
-+#include <linux/atmel_pwm.h>
++      if (!mounted_read_only) {
++              int lnum;
 +
++              /* Check for enough free space */
++              if (ubifs_calc_available(c) <= 0) {
++                      ubifs_err("insufficient available space");
++                      err = -EINVAL;
++                      goto out_orphans;
++              }
 +
-+/*
-+ * This is a simple driver for the PWM controller found in various newer
-+ * Atmel SOCs, including the AVR32 series and the AT91sam9263.
-+ *
-+ * Chips with current Linux ports have only 4 PWM channels, out of max 32.
-+ * AT32UC3A and AT32UC3B chips have 7 channels (but currently no Linux).
-+ * Docs are inconsistent about the width of the channel counter registers;
-+ * it's at least 16 bits, but several places say 20 bits.
-+ */
-+#define       PWM_NCHAN       4               /* max 32 */
++              /* Check for enough log space */
++              lnum = c->lhead_lnum + 1;
++              if (lnum >= UBIFS_LOG_LNUM + c->log_lebs)
++                      lnum = UBIFS_LOG_LNUM;
++              if (lnum == c->ltail_lnum) {
++                      err = ubifs_consolidate_log(c);
++                      if (err)
++                              goto out_orphans;
++              }
 +
-+struct pwm {
-+      spinlock_t              lock;
-+      struct platform_device  *pdev;
-+      u32                     mask;
-+      int                     irq;
-+      void __iomem            *base;
-+      struct clk              *clk;
-+      struct pwm_channel      *channel[PWM_NCHAN];
-+      void                    (*handler[PWM_NCHAN])(struct pwm_channel *);
-+};
++              if (c->need_recovery) {
++                      err = ubifs_recover_size(c);
++                      if (err)
++                              goto out_orphans;
++                      err = ubifs_rcvry_gc_commit(c);
++              } else
++                      err = take_gc_lnum(c);
++              if (err)
++                      goto out_orphans;
++
++              err = dbg_check_lprops(c);
++              if (err)
++                      goto out_orphans;
++      } else if (c->need_recovery) {
++              err = ubifs_recover_size(c);
++              if (err)
++                      goto out_orphans;
++      }
 +
++      spin_lock(&ubifs_infos_lock);
++      list_add_tail(&c->infos_list, &ubifs_infos);
++      spin_unlock(&ubifs_infos_lock);
 +
-+/* global PWM controller registers */
-+#define PWM_MR                0x00
-+#define PWM_ENA               0x04
-+#define PWM_DIS               0x08
-+#define PWM_SR                0x0c
-+#define PWM_IER               0x10
-+#define PWM_IDR               0x14
-+#define PWM_IMR               0x18
-+#define PWM_ISR               0x1c
++      if (c->need_recovery) {
++              if (mounted_read_only)
++                      ubifs_msg("recovery deferred");
++              else {
++                      c->need_recovery = 0;
++                      ubifs_msg("recovery completed");
++              }
++      }
 +
-+static inline void pwm_writel(const struct pwm *p, unsigned offset, u32 val)
-+{
-+      __raw_writel(val, p->base + offset);
-+}
++      err = dbg_check_filesystem(c);
++      if (err)
++              goto out_infos;
++
++      ubifs_msg("mounted UBI device %d, volume %d", c->vi.ubi_num,
++                c->vi.vol_id);
++      if (mounted_read_only)
++              ubifs_msg("mounted read-only");
++      ubifs_msg("minimal I/O unit size:   %d bytes", c->min_io_size);
++      ubifs_msg("logical eraseblock size: %d bytes (%d KiB)",
++                c->leb_size, c->leb_size / 1024);
++      x = (unsigned long long)c->main_lebs * c->leb_size;
++      ubifs_msg("file system size:        %lld bytes (%lld KiB, %lld MiB, "
++                "%d LEBs)", x, x >> 10, x >> 20, c->main_lebs);
++      x = (unsigned long long)c->log_lebs * c->leb_size + c->max_bud_bytes;
++      ubifs_msg("journal size:            %lld bytes (%lld KiB, %lld MiB, "
++                "%d LEBs)", x, x >> 10, x >> 20,
++                c->log_lebs + c->max_bud_cnt);
++      ubifs_msg("data journal heads:      %d",
++                c->jhead_cnt - NONDATA_JHEADS_CNT);
++      ubifs_msg("default compressor:      %s",
++                ubifs_compr_name(c->default_compr));
++      ubifs_msg("media format %d, latest format %d",
++                c->fmt_version, UBIFS_FORMAT_VERSION);
++
++      dbg_msg("compiled on:            " __DATE__ " at " __TIME__);
++      dbg_msg("UUID:                   %02X%02X%02X%02X-%02X%02X"
++             "-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
++             c->uuid[0], c->uuid[1], c->uuid[2], c->uuid[3],
++             c->uuid[4], c->uuid[5], c->uuid[6], c->uuid[7],
++             c->uuid[8], c->uuid[9], c->uuid[10], c->uuid[11],
++             c->uuid[12], c->uuid[13], c->uuid[14], c->uuid[15]);
++      dbg_msg("fast unmount:           %d", c->fast_unmount);
++      dbg_msg("big_lpt                 %d", c->big_lpt);
++      dbg_msg("log LEBs:               %d (%d - %d)",
++              c->log_lebs, UBIFS_LOG_LNUM, c->log_last);
++      dbg_msg("LPT area LEBs:          %d (%d - %d)",
++              c->lpt_lebs, c->lpt_first, c->lpt_last);
++      dbg_msg("orphan area LEBs:       %d (%d - %d)",
++              c->orph_lebs, c->orph_first, c->orph_last);
++      dbg_msg("main area LEBs:         %d (%d - %d)",
++              c->main_lebs, c->main_first, c->leb_cnt - 1);
++      dbg_msg("index LEBs:             %d", c->lst.idx_lebs);
++      dbg_msg("total index bytes:      %lld (%lld KiB, %lld MiB)",
++              c->old_idx_sz, c->old_idx_sz >> 10, c->old_idx_sz >> 20);
++      dbg_msg("key hash type:          %d", c->key_hash_type);
++      dbg_msg("tree fanout:            %d", c->fanout);
++      dbg_msg("reserved GC LEB:        %d", c->gc_lnum);
++      dbg_msg("first main LEB:         %d", c->main_first);
++      dbg_msg("dead watermark:         %d", c->dead_wm);
++      dbg_msg("dark watermark:         %d", c->dark_wm);
++      x = c->main_lebs * c->dark_wm;
++      dbg_msg("max. dark space:        %lld (%lld KiB, %lld MiB)",
++              x, x >> 10, x >> 20);
++      dbg_msg("maximum bud bytes:      %lld (%lld KiB, %lld MiB)",
++              c->max_bud_bytes, c->max_bud_bytes >> 10,
++              c->max_bud_bytes >> 20);
++      dbg_msg("BG commit bud bytes:    %lld (%lld KiB, %lld MiB)",
++              c->bg_bud_bytes, c->bg_bud_bytes >> 10,
++              c->bg_bud_bytes >> 20);
++      dbg_msg("current bud bytes       %lld (%lld KiB, %lld MiB)",
++              c->bud_bytes, c->bud_bytes >> 10, c->bud_bytes >> 20);
++      dbg_msg("max. seq. number:       %llu", c->max_sqnum);
++      dbg_msg("commit number:          %llu", c->cmt_no);
 +
-+static inline u32 pwm_readl(const struct pwm *p, unsigned offset)
-+{
-+      return __raw_readl(p->base + offset);
++      return 0;
++
++out_infos:
++      spin_lock(&ubifs_infos_lock);
++      list_del(&c->infos_list);
++      spin_unlock(&ubifs_infos_lock);
++out_orphans:
++      free_orphans(c);
++out_journal:
++      destroy_journal(c);
++out_lpt:
++      ubifs_lpt_free(c, 0);
++out_master:
++      kfree(c->mst_node);
++      kfree(c->rcvrd_mst_node);
++out_stop:
++      if (c->bgt)
++              kthread_stop(c->bgt);
++out_wbufs:
++      free_wbufs(c);
++out_cbuf:
++      kfree(c->cbuf);
++out_dereg:
++      dbg_failure_mode_deregistration(c);
++out_free:
++      vfree(c->ileb_buf);
++      vfree(c->sbuf);
++      kfree(c->bottom_up_buf);
++      UBIFS_DBG(vfree(c->dbg_buf));
++      return err;
 +}
 +
-+static inline void __iomem *pwmc_regs(const struct pwm *p, int index)
++/**
++ * ubifs_umount - un-mount UBIFS file-system.
++ * @c: UBIFS file-system description object
++ *
++ * Note, this function is called to free allocated resourced when un-mounting,
++ * as well as free resources when an error occurred while we were half way
++ * through mounting (error path cleanup function). So it has to make sure the
++ * resource was actually allocated before freeing it.
++ */
++static void ubifs_umount(struct ubifs_info *c)
 +{
-+      return p->base + 0x200 + index * 0x20;
-+}
++      dbg_gen("un-mounting UBI device %d, volume %d", c->vi.ubi_num,
++              c->vi.vol_id);
 +
-+static struct pwm *pwm;
++      spin_lock(&ubifs_infos_lock);
++      list_del(&c->infos_list);
++      spin_unlock(&ubifs_infos_lock);
 +
-+static void pwm_dumpregs(struct pwm_channel *ch, char *tag)
-+{
-+      struct device   *dev = &pwm->pdev->dev;
++      if (c->bgt)
++              kthread_stop(c->bgt);
 +
-+      dev_dbg(dev, "%s: mr %08x, sr %08x, imr %08x\n",
-+              tag,
-+              pwm_readl(pwm, PWM_MR),
-+              pwm_readl(pwm, PWM_SR),
-+              pwm_readl(pwm, PWM_IMR));
-+      dev_dbg(dev,
-+              "pwm ch%d - mr %08x, dty %u, prd %u, cnt %u\n",
-+              ch->index,
-+              pwm_channel_readl(ch, PWM_CMR),
-+              pwm_channel_readl(ch, PWM_CDTY),
-+              pwm_channel_readl(ch, PWM_CPRD),
-+              pwm_channel_readl(ch, PWM_CCNT));
-+}
++      destroy_journal(c);
++      free_wbufs(c);
++      free_orphans(c);
++      ubifs_lpt_free(c, 0);
 +
++      kfree(c->cbuf);
++      kfree(c->rcvrd_mst_node);
++      kfree(c->mst_node);
++      vfree(c->sbuf);
++      kfree(c->bottom_up_buf);
++      UBIFS_DBG(vfree(c->dbg_buf));
++      vfree(c->ileb_buf);
++      dbg_failure_mode_deregistration(c);
++}
 +
 +/**
-+ * pwm_channel_alloc - allocate an unused PWM channel
-+ * @index: identifies the channel
-+ * @ch: structure to be initialized
++ * ubifs_remount_rw - re-mount in read-write mode.
++ * @c: UBIFS file-system description object
 + *
-+ * Drivers allocate PWM channels according to the board's wiring, and
-+ * matching board-specific setup code.  Returns zero or negative errno.
++ * UBIFS avoids allocating many unnecessary resources when mounted in read-only
++ * mode. This function allocates the needed resources and re-mounts UBIFS in
++ * read-write mode.
 + */
-+int pwm_channel_alloc(int index, struct pwm_channel *ch)
++static int ubifs_remount_rw(struct ubifs_info *c)
 +{
-+      unsigned long   flags;
-+      int             status = 0;
-+
-+      /* insist on PWM init, with this signal pinned out */
-+      if (!pwm || !(pwm->mask & 1 << index))
-+              return -ENODEV;
++      int err, lnum;
 +
-+      if (index < 0 || index >= PWM_NCHAN || !ch)
++      if (c->ro_media)
 +              return -EINVAL;
-+      memset(ch, 0, sizeof *ch);
 +
-+      spin_lock_irqsave(&pwm->lock, flags);
-+      if (pwm->channel[index])
-+              status = -EBUSY;
-+      else {
-+              clk_enable(pwm->clk);
++      mutex_lock(&c->umount_mutex);
++      c->remounting_rw = 1;
 +
-+              ch->regs = pwmc_regs(pwm, index);
-+              ch->index = index;
++      /* Check for enough free space */
++      if (ubifs_calc_available(c) <= 0) {
++              ubifs_err("insufficient available space");
++              err = -EINVAL;
++              goto out;
++      }
 +
-+              /* REVISIT: ap7000 seems to go 2x as fast as we expect!! */
-+              ch->mck = clk_get_rate(pwm->clk);
++      if (c->old_leb_cnt != c->leb_cnt) {
++              struct ubifs_sb_node *sup;
 +
-+              pwm->channel[index] = ch;
-+              pwm->handler[index] = NULL;
++              sup = ubifs_read_sb_node(c);
++              if (IS_ERR(sup)) {
++                      err = PTR_ERR(sup);
++                      goto out;
++              }
++              sup->leb_cnt = cpu_to_le32(c->leb_cnt);
++              err = ubifs_write_sb_node(c, sup);
++              if (err)
++                      goto out;
++      }
 +
-+              /* channel and irq are always disabled when we return */
-+              pwm_writel(pwm, PWM_DIS, 1 << index);
-+              pwm_writel(pwm, PWM_IDR, 1 << index);
++      if (c->need_recovery) {
++              ubifs_msg("completing deferred recovery");
++              err = ubifs_write_rcvrd_mst_node(c);
++              if (err)
++                      goto out;
++              err = ubifs_recover_size(c);
++              if (err)
++                      goto out;
++              err = ubifs_clean_lebs(c, c->sbuf);
++              if (err)
++                      goto out;
++              err = ubifs_recover_inl_heads(c, c->sbuf);
++              if (err)
++                      goto out;
 +      }
-+      spin_unlock_irqrestore(&pwm->lock, flags);
-+      return status;
-+}
-+EXPORT_SYMBOL(pwm_channel_alloc);
 +
-+static int pwmcheck(struct pwm_channel *ch)
-+{
-+      int             index;
++      if (!(c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY))) {
++              c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
++              err = ubifs_write_master(c);
++              if (err)
++                      goto out;
++      }
 +
-+      if (!pwm)
-+              return -ENODEV;
-+      if (!ch)
-+              return -EINVAL;
-+      index = ch->index;
-+      if (index < 0 || index >= PWM_NCHAN || pwm->channel[index] != ch)
-+              return -EINVAL;
++      c->ileb_buf = vmalloc(c->leb_size);
++      if (!c->ileb_buf) {
++              err = -ENOMEM;
++              goto out;
++      }
 +
-+      return index;
-+}
++      err = ubifs_lpt_init(c, 0, 1);
++      if (err)
++              goto out;
 +
-+/**
-+ * pwm_channel_free - release a previously allocated channel
-+ * @ch: the channel being released
-+ *
-+ * The channel is completely shut down (counter and IRQ disabled),
-+ * and made available for re-use.  Returns zero, or negative errno.
-+ */
-+int pwm_channel_free(struct pwm_channel *ch)
-+{
-+      unsigned long   flags;
-+      int             t;
++      err = alloc_wbufs(c);
++      if (err)
++              goto out;
 +
-+      spin_lock_irqsave(&pwm->lock, flags);
-+      t = pwmcheck(ch);
-+      if (t >= 0) {
-+              pwm->channel[t] = NULL;
-+              pwm->handler[t] = NULL;
++      ubifs_create_buds_lists(c);
++
++      /* Create background thread */
++      c->bgt = kthread_create(ubifs_bg_thread, c, c->bgt_name);
++      if (!c->bgt)
++              c->bgt = ERR_PTR(-EINVAL);
++      if (IS_ERR(c->bgt)) {
++              err = PTR_ERR(c->bgt);
++              c->bgt = NULL;
++              ubifs_err("cannot spawn \"%s\", error %d",
++                        c->bgt_name, err);
++              return err;
++      }
++      wake_up_process(c->bgt);
 +
-+              /* channel and irq are always disabled when we return */
-+              pwm_writel(pwm, PWM_DIS, 1 << t);
-+              pwm_writel(pwm, PWM_IDR, 1 << t);
++      c->orph_buf = vmalloc(c->leb_size);
++      if (!c->orph_buf)
++              return -ENOMEM;
 +
-+              clk_disable(pwm->clk);
-+              t = 0;
++      /* Check for enough log space */
++      lnum = c->lhead_lnum + 1;
++      if (lnum >= UBIFS_LOG_LNUM + c->log_lebs)
++              lnum = UBIFS_LOG_LNUM;
++      if (lnum == c->ltail_lnum) {
++              err = ubifs_consolidate_log(c);
++              if (err)
++                      goto out;
 +      }
-+      spin_unlock_irqrestore(&pwm->lock, flags);
-+      return t;
-+}
-+EXPORT_SYMBOL(pwm_channel_free);
 +
-+int __pwm_channel_onoff(struct pwm_channel *ch, int enabled)
-+{
-+      unsigned long   flags;
-+      int             t;
-+
-+      /* OMITTED FUNCTIONALITY:  starting several channels in synch */
++      if (c->need_recovery)
++              err = ubifs_rcvry_gc_commit(c);
++      else
++              err = take_gc_lnum(c);
++      if (err)
++              goto out;
 +
-+      spin_lock_irqsave(&pwm->lock, flags);
-+      t = pwmcheck(ch);
-+      if (t >= 0) {
-+              pwm_writel(pwm, enabled ? PWM_ENA : PWM_DIS, 1 << t);
-+              t = 0;
-+              pwm_dumpregs(ch, enabled ? "enable" : "disable");
++      if (c->need_recovery) {
++              c->need_recovery = 0;
++              ubifs_msg("deferred recovery completed");
 +      }
-+      spin_unlock_irqrestore(&pwm->lock, flags);
 +
-+      return t;
++      dbg_gen("re-mounted read-write");
++      c->vfs_sb->s_flags &= ~MS_RDONLY;
++      c->remounting_rw = 0;
++      mutex_unlock(&c->umount_mutex);
++      return 0;
++
++out:
++      vfree(c->orph_buf);
++      c->orph_buf = NULL;
++      if (c->bgt) {
++              kthread_stop(c->bgt);
++              c->bgt = NULL;
++      }
++      free_wbufs(c);
++      vfree(c->ileb_buf);
++      c->ileb_buf = NULL;
++      ubifs_lpt_free(c, 1);
++      c->remounting_rw = 0;
++      mutex_unlock(&c->umount_mutex);
++      return err;
 +}
-+EXPORT_SYMBOL(__pwm_channel_onoff);
 +
 +/**
-+ * pwm_clk_alloc - allocate and configure CLKA or CLKB
-+ * @prescale: from 0..10, the power of two used to divide MCK
-+ * @div: from 1..255, the linear divisor to use
++ * commit_on_unmount - commit the journal when un-mounting.
++ * @c: UBIFS file-system description object
++ *
++ * This function is called during un-mounting and it commits the journal unless
++ * the "fast unmount" mode is enabled. It also avoids committing the journal if
++ * it contains too few data.
 + *
-+ * Returns PWM_CPR_CLKA, PWM_CPR_CLKB, or negative errno.  The allocated
-+ * clock will run with a period of (2^prescale * div) / MCK, or twice as
-+ * long if center aligned PWM output is used.  The clock must later be
-+ * deconfigured using pwm_clk_free().
++ * Sometimes recovery requires the journal to be committed at least once, and
++ * this function takes care about this.
 + */
-+int pwm_clk_alloc(unsigned prescale, unsigned div)
++static void commit_on_unmount(struct ubifs_info *c)
 +{
-+      unsigned long   flags;
-+      u32             mr;
-+      u32             val = (prescale << 8) | div;
-+      int             ret = -EBUSY;
-+
-+      if (prescale >= 10 || div == 0 || div > 255)
-+              return -EINVAL;
++      if (!c->fast_unmount) {
++              long long bud_bytes;
 +
-+      spin_lock_irqsave(&pwm->lock, flags);
-+      mr = pwm_readl(pwm, PWM_MR);
-+      if ((mr & 0xffff) == 0) {
-+              mr |= val;
-+              ret = PWM_CPR_CLKA;
-+      }
-+      if ((mr & (0xffff << 16)) == 0) {
-+              mr |= val << 16;
-+              ret = PWM_CPR_CLKB;
++              spin_lock(&c->buds_lock);
++              bud_bytes = c->bud_bytes;
++              spin_unlock(&c->buds_lock);
++              if (bud_bytes > c->leb_size)
++                      ubifs_run_commit(c);
 +      }
-+      if (ret > 0)
-+              pwm_writel(pwm, PWM_MR, mr);
-+      spin_unlock_irqrestore(&pwm->lock, flags);
-+      return ret;
 +}
-+EXPORT_SYMBOL(pwm_clk_alloc);
 +
 +/**
-+ * pwm_clk_free - deconfigure and release CLKA or CLKB
++ * ubifs_remount_ro - re-mount in read-only mode.
++ * @c: UBIFS file-system description object
 + *
-+ * Reverses the effect of pwm_clk_alloc().
++ * We rely on VFS to have stopped writing. Possibly the background thread could
++ * be running a commit, however kthread_stop will wait in that case.
 + */
-+void pwm_clk_free(unsigned clk)
++static void ubifs_remount_ro(struct ubifs_info *c)
 +{
-+      unsigned long   flags;
-+      u32             mr;
++      int i, err;
 +
-+      spin_lock_irqsave(&pwm->lock, flags);
-+      mr = pwm_readl(pwm, PWM_MR);
-+      if (clk == PWM_CPR_CLKA)
-+              pwm_writel(pwm, PWM_MR, mr & ~(0xffff << 0));
-+      if (clk == PWM_CPR_CLKB)
-+              pwm_writel(pwm, PWM_MR, mr & ~(0xffff << 16));
-+      spin_unlock_irqrestore(&pwm->lock, flags);
-+}
-+EXPORT_SYMBOL(pwm_clk_free);
++      ubifs_assert(!c->need_recovery);
++      commit_on_unmount(c);
 +
-+/**
-+ * pwm_channel_handler - manage channel's IRQ handler
-+ * @ch: the channel
-+ * @handler: the handler to use, possibly NULL
-+ *
-+ * If the handler is non-null, the handler will be called after every
-+ * period of this PWM channel.  If the handler is null, this channel
-+ * won't generate an IRQ.
-+ */
-+int pwm_channel_handler(struct pwm_channel *ch,
-+              void (*handler)(struct pwm_channel *ch))
-+{
-+      unsigned long   flags;
-+      int             t;
++      mutex_lock(&c->umount_mutex);
++      if (c->bgt) {
++              kthread_stop(c->bgt);
++              c->bgt = NULL;
++      }
++
++      for (i = 0; i < c->jhead_cnt; i++) {
++              ubifs_wbuf_sync(&c->jheads[i].wbuf);
++              del_timer_sync(&c->jheads[i].wbuf.timer);
++      }
 +
-+      spin_lock_irqsave(&pwm->lock, flags);
-+      t = pwmcheck(ch);
-+      if (t >= 0) {
-+              pwm->handler[t] = handler;
-+              pwm_writel(pwm, handler ? PWM_IER : PWM_IDR, 1 << t);
-+              t = 0;
++      if (!c->ro_media) {
++              c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY);
++              c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS);
++              c->mst_node->gc_lnum = cpu_to_le32(c->gc_lnum);
++              err = ubifs_write_master(c);
++              if (err)
++                      ubifs_ro_mode(c, err);
 +      }
-+      spin_unlock_irqrestore(&pwm->lock, flags);
 +
-+      return t;
++      ubifs_destroy_idx_gc(c);
++      free_wbufs(c);
++      vfree(c->orph_buf);
++      c->orph_buf = NULL;
++      vfree(c->ileb_buf);
++      c->ileb_buf = NULL;
++      ubifs_lpt_free(c, 1);
++      mutex_unlock(&c->umount_mutex);
 +}
-+EXPORT_SYMBOL(pwm_channel_handler);
 +
-+static irqreturn_t pwm_irq(int id, void *_pwm)
++static void ubifs_put_super(struct super_block *sb)
 +{
-+      struct pwm      *p = _pwm;
-+      irqreturn_t     handled = IRQ_NONE;
-+      u32             irqstat;
-+      int             index;
++      int i;
++      struct ubifs_info *c = sb->s_fs_info;
 +
-+      spin_lock(&p->lock);
++      ubifs_msg("un-mount UBI device %d, volume %d", c->vi.ubi_num,
++                c->vi.vol_id);
++      /*
++       * The following asserts are only valid if there has not been a failure
++       * of the media. For example, there will be dirty inodes if we failed
++       * to write them back because of I/O errors.
++       */
++      ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0);
++      ubifs_assert(atomic_long_read(&c->dirty_ino_cnt) == 0);
++      ubifs_assert(c->budg_idx_growth == 0);
++      ubifs_assert(c->budg_data_growth == 0);
 +
-+      /* ack irqs, then handle them */
-+      irqstat = pwm_readl(pwm, PWM_ISR);
++      /*
++       * The 'c->umount_lock' prevents races between UBIFS memory shrinker
++       * and file system un-mount. Namely, it prevents the shrinker from
++       * picking this superblock for shrinking - it will be just skipped if
++       * the mutex is locked.
++       */
++      mutex_lock(&c->umount_mutex);
++      if (!(c->vfs_sb->s_flags & MS_RDONLY)) {
++              /*
++               * First of all kill the background thread to make sure it does
++               * not interfere with un-mounting and freeing resources.
++               */
++              if (c->bgt) {
++                      kthread_stop(c->bgt);
++                      c->bgt = NULL;
++              }
 +
-+      while (irqstat) {
-+              struct pwm_channel *ch;
-+              void (*handler)(struct pwm_channel *ch);
++              /* Synchronize write-buffers */
++              if (c->jheads)
++                      for (i = 0; i < c->jhead_cnt; i++) {
++                              ubifs_wbuf_sync(&c->jheads[i].wbuf);
++                              del_timer_sync(&c->jheads[i].wbuf.timer);
++                      }
 +
-+              index = ffs(irqstat) - 1;
-+              irqstat &= ~(1 << index);
-+              ch = pwm->channel[index];
-+              handler = pwm->handler[index];
-+              if (handler && ch) {
-+                      spin_unlock(&p->lock);
-+                      handler(ch);
-+                      spin_lock(&p->lock);
-+                      handled = IRQ_HANDLED;
++              /*
++               * On fatal errors c->ro_media is set to 1, in which case we do
++               * not write the master node.
++               */
++              if (!c->ro_media) {
++                      /*
++                       * We are being cleanly unmounted which means the
++                       * orphans were killed - indicate this in the master
++                       * node. Also save the reserved GC LEB number.
++                       */
++                      int err;
++
++                      c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY);
++                      c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS);
++                      c->mst_node->gc_lnum = cpu_to_le32(c->gc_lnum);
++                      err = ubifs_write_master(c);
++                      if (err)
++                              /*
++                               * Recovery will attempt to fix the master area
++                               * next mount, so we just print a message and
++                               * continue to unmount normally.
++                               */
++                              ubifs_err("failed to write master node, "
++                                        "error %d", err);
 +              }
 +      }
 +
-+      spin_unlock(&p->lock);
-+      return handled;
++      ubifs_umount(c);
++      ubi_close_volume(c->ubi);
++      mutex_unlock(&c->umount_mutex);
++      kfree(c);
 +}
 +
-+static int __init pwm_probe(struct platform_device *pdev)
++static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
 +{
-+      struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      int irq = platform_get_irq(pdev, 0);
-+      u32 *mp = pdev->dev.platform_data;
-+      struct pwm *p;
-+      int status = -EIO;
-+
-+      if (pwm)
-+              return -EBUSY;
-+      if (!r || irq < 0 || !mp || !*mp)
-+              return -ENODEV;
-+      if (*mp & ~((1<<PWM_NCHAN)-1)) {
-+              dev_warn(&pdev->dev, "mask 0x%x ... more than %d channels\n",
-+                      *mp, PWM_NCHAN);
-+              return -EINVAL;
-+      }
++      int err;
++      struct ubifs_info *c = sb->s_fs_info;
 +
-+      p = kzalloc(sizeof(*p), GFP_KERNEL);
-+      if (!p)
-+              return -ENOMEM;
++      dbg_gen("old flags %#lx, new flags %#x", sb->s_flags, *flags);
 +
-+      spin_lock_init(&p->lock);
-+      p->pdev = pdev;
-+      p->mask = *mp;
-+      p->irq = irq;
-+      p->base = ioremap(r->start, r->end - r->start + 1);
-+      if (!p->base)
-+              goto fail;
-+      p->clk = clk_get(&pdev->dev, "mck");
-+      if (IS_ERR(p->clk)) {
-+              status = PTR_ERR(p->clk);
-+              p->clk = NULL;
-+              goto fail;
++      err = ubifs_parse_options(c, data, 1);
++      if (err) {
++              ubifs_err("invalid or unknown remount parameter");
++              return err;
 +      }
-+
-+      status = request_irq(irq, pwm_irq, 0, pdev->name, p);
-+      if (status < 0)
-+              goto fail;
-+
-+      pwm = p;
-+      platform_set_drvdata(pdev, p);
++      if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) {
++              err = ubifs_remount_rw(c);
++              if (err)
++                      return err;
++      } else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY))
++              ubifs_remount_ro(c);
 +
 +      return 0;
-+
-+fail:
-+      if (p->clk)
-+              clk_put(p->clk);
-+      if (p->base)
-+              iounmap(p->base);
-+
-+      kfree(p);
-+      return status;
 +}
 +
-+static int __exit pwm_remove(struct platform_device *pdev)
++struct super_operations ubifs_super_operations = {
++      .alloc_inode   = ubifs_alloc_inode,
++      .destroy_inode = ubifs_destroy_inode,
++      .put_super     = ubifs_put_super,
++      .write_inode   = ubifs_write_inode,
++      .delete_inode  = ubifs_delete_inode,
++      .statfs        = ubifs_statfs,
++      .dirty_inode   = ubifs_dirty_inode,
++      .remount_fs    = ubifs_remount_fs,
++      .show_options  = ubifs_show_options,
++      .sync_fs       = ubifs_sync_fs,
++};
++
++/**
++ * open_ubi - parse UBI device name string and open the UBI device.
++ * @name: UBI volume name
++ * @mode: UBI volume open mode
++ *
++ * There are several ways to specify UBI volumes when mounting UBIFS:
++ * o ubiX_Y    - UBI device number X, volume Y;
++ * o ubiY      - UBI device number 0, volume Y;
++ * o ubiX:NAME - mount UBI device X, volume with name NAME;
++ * o ubi:NAME  - mount UBI device 0, volume with name NAME.
++ *
++ * Alternative '!' separator may be used instead of ':' (because some shells
++ * like busybox may interpret ':' as an NFS host name separator). This function
++ * returns ubi volume object in case of success and a negative error code in
++ * case of failure.
++ */
++static struct ubi_volume_desc *open_ubi(const char *name, int mode)
 +{
-+      struct pwm *p = platform_get_drvdata(pdev);
++      int dev, vol;
++      char *endptr;
 +
-+      if (p != pwm)
-+              return -EINVAL;
++      if (name[0] != 'u' || name[1] != 'b' || name[2] != 'i')
++              return ERR_PTR(-EINVAL);
 +
-+      clk_enable(pwm->clk);
-+      pwm_writel(pwm, PWM_DIS, (1 << PWM_NCHAN) - 1);
-+      pwm_writel(pwm, PWM_IDR, (1 << PWM_NCHAN) - 1);
-+      clk_disable(pwm->clk);
++      /* ubi:NAME method */
++      if ((name[3] == ':' || name[3] == '!') && name[4] != '\0')
++              return ubi_open_volume_nm(0, name + 4, mode);
 +
-+      pwm = NULL;
++      if (!isdigit(name[3]))
++              return ERR_PTR(-EINVAL);
 +
-+      free_irq(p->irq, p);
-+      clk_put(p->clk);
-+      iounmap(p->base);
-+      kfree(p);
++      dev = simple_strtoul(name + 3, &endptr, 0);
 +
-+      return 0;
-+}
++      /* ubiY method */
++      if (*endptr == '\0')
++              return ubi_open_volume(0, dev, mode);
 +
-+static struct platform_driver atmel_pwm_driver = {
-+      .driver = {
-+              .name = "atmel_pwm",
-+              .owner = THIS_MODULE,
-+      },
-+      .remove = __exit_p(pwm_remove),
++      /* ubiX_Y method */
++      if (*endptr == '_' && isdigit(endptr[1])) {
++              vol = simple_strtoul(endptr + 1, &endptr, 0);
++              if (*endptr != '\0')
++                      return ERR_PTR(-EINVAL);
++              return ubi_open_volume(dev, vol, mode);
++      }
 +
-+      /* NOTE: PWM can keep running in AVR32 "idle" and "frozen" states;
-+       * and all AT91sam9263 states, albeit at reduced clock rate if
-+       * MCK becomes the slow clock (i.e. what Linux labels STR).
-+       */
-+};
++      /* ubiX:NAME method */
++      if ((*endptr == ':' || *endptr == '!') && endptr[1] != '\0')
++              return ubi_open_volume_nm(dev, ++endptr, mode);
 +
-+static int __init pwm_init(void)
-+{
-+      return platform_driver_probe(&atmel_pwm_driver, pwm_probe);
++      return ERR_PTR(-EINVAL);
 +}
-+module_init(pwm_init);
 +
-+static void __exit pwm_exit(void)
++static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
 +{
-+      platform_driver_unregister(&atmel_pwm_driver);
-+}
-+module_exit(pwm_exit);
-+
-+MODULE_DESCRIPTION("Driver for AT32/AT91 PWM module");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/misc/atmel_tclib.c
-@@ -0,0 +1,161 @@
-+#include <linux/atmel_tc.h>
-+#include <linux/clk.h>
-+#include <linux/err.h>
-+#include <linux/init.h>
-+#include <linux/io.h>
-+#include <linux/ioport.h>
-+#include <linux/kernel.h>
-+#include <linux/platform_device.h>
-+
-+/* Number of bytes to reserve for the iomem resource */
-+#define ATMEL_TC_IOMEM_SIZE   256
-+
-+
-+/*
-+ * This is a thin library to solve the problem of how to portably allocate
-+ * one of the TC blocks.  For simplicity, it doesn't currently expect to
-+ * share individual timers between different drivers.
-+ */
-+
-+#if defined(CONFIG_AVR32)
-+/* AVR32 has these divide PBB */
-+const u8 atmel_tc_divisors[5] = { 0, 4, 8, 16, 32, };
-+EXPORT_SYMBOL(atmel_tc_divisors);
-+
-+#elif defined(CONFIG_ARCH_AT91)
-+/* AT91 has these divide MCK */
-+const u8 atmel_tc_divisors[5] = { 2, 8, 32, 128, 0, };
-+EXPORT_SYMBOL(atmel_tc_divisors);
++      struct ubi_volume_desc *ubi = sb->s_fs_info;
++      struct ubifs_info *c;
++      struct inode *root;
++      int err;
 +
-+#endif
++      c = kzalloc(sizeof(struct ubifs_info), GFP_KERNEL);
++      if (!c)
++              return -ENOMEM;
 +
-+static DEFINE_SPINLOCK(tc_list_lock);
-+static LIST_HEAD(tc_list);
++      spin_lock_init(&c->cnt_lock);
++      spin_lock_init(&c->cs_lock);
++      spin_lock_init(&c->buds_lock);
++      spin_lock_init(&c->space_lock);
++      spin_lock_init(&c->orphan_lock);
++      init_rwsem(&c->commit_sem);
++      mutex_init(&c->lp_mutex);
++      mutex_init(&c->tnc_mutex);
++      mutex_init(&c->log_mutex);
++      mutex_init(&c->mst_mutex);
++      mutex_init(&c->umount_mutex);
++      init_waitqueue_head(&c->cmt_wq);
++      c->buds = RB_ROOT;
++      c->old_idx = RB_ROOT;
++      c->size_tree = RB_ROOT;
++      c->orph_tree = RB_ROOT;
++      INIT_LIST_HEAD(&c->infos_list);
++      INIT_LIST_HEAD(&c->idx_gc);
++      INIT_LIST_HEAD(&c->replay_list);
++      INIT_LIST_HEAD(&c->replay_buds);
++      INIT_LIST_HEAD(&c->uncat_list);
++      INIT_LIST_HEAD(&c->empty_list);
++      INIT_LIST_HEAD(&c->freeable_list);
++      INIT_LIST_HEAD(&c->frdi_idx_list);
++      INIT_LIST_HEAD(&c->unclean_leb_list);
++      INIT_LIST_HEAD(&c->old_buds);
++      INIT_LIST_HEAD(&c->orph_list);
++      INIT_LIST_HEAD(&c->orph_new);
++
++      c->highest_inum = UBIFS_FIRST_INO;
++      get_random_bytes(&c->vfs_gen, sizeof(int));
++      c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM;
++
++      ubi_get_volume_info(ubi, &c->vi);
++      ubi_get_device_info(c->vi.ubi_num, &c->di);
++
++      /* Re-open the UBI device in read-write mode */
++      c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READWRITE);
++      if (IS_ERR(c->ubi)) {
++              err = PTR_ERR(c->ubi);
++              goto out_free;
++      }
 +
-+/**
-+ * atmel_tc_alloc - allocate a specified TC block
-+ * @block: which block to allocate
-+ * @name: name to be associated with the iomem resource
-+ *
-+ * Caller allocates a block.  If it is available, a pointer to a
-+ * pre-initialized struct atmel_tc is returned. The caller can access
-+ * the registers directly through the "regs" field.
-+ */
-+struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name)
-+{
-+      struct atmel_tc         *tc;
-+      struct platform_device  *pdev = NULL;
-+      struct resource         *r;
++      err = ubifs_parse_options(c, data, 0);
++      if (err)
++              goto out_close;
++
++      c->vfs_sb = sb;
++
++      sb->s_fs_info = c;
++      sb->s_magic = UBIFS_SUPER_MAGIC;
++      sb->s_blocksize = UBIFS_BLOCK_SIZE;
++      sb->s_blocksize_bits = UBIFS_BLOCK_SHIFT;
++      sb->s_dev = c->vi.cdev;
++      sb->s_maxbytes = c->max_inode_sz = key_max_inode_size(c);
++      if (c->max_inode_sz > MAX_LFS_FILESIZE)
++              sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE;
++      sb->s_op = &ubifs_super_operations;
++
++      mutex_lock(&c->umount_mutex);
++      err = mount_ubifs(c);
++      if (err) {
++              ubifs_assert(err < 0);
++              goto out_unlock;
++      }
 +
-+      spin_lock(&tc_list_lock);
-+      list_for_each_entry(tc, &tc_list, node) {
-+              if (tc->pdev->id == block) {
-+                      pdev = tc->pdev;
-+                      break;
-+              }
++      /* Read the root inode */
++      root = ubifs_iget(sb, UBIFS_ROOT_INO);
++      if (IS_ERR(root)) {
++              err = PTR_ERR(root);
++              goto out_umount;
 +      }
 +
-+      if (!pdev || tc->iomem)
-+              goto fail;
++      sb->s_root = d_alloc_root(root);
++      if (!sb->s_root)
++              goto out_iput;
 +
-+      r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      r = request_mem_region(r->start, ATMEL_TC_IOMEM_SIZE, name);
-+      if (!r)
-+              goto fail;
++      mutex_unlock(&c->umount_mutex);
 +
-+      tc->regs = ioremap(r->start, ATMEL_TC_IOMEM_SIZE);
-+      if (!tc->regs)
-+              goto fail_ioremap;
++      return 0;
 +
-+      tc->iomem = r;
++out_iput:
++      iput(root);
++out_umount:
++      ubifs_umount(c);
++out_unlock:
++      mutex_unlock(&c->umount_mutex);
++out_close:
++      ubi_close_volume(c->ubi);
++out_free:
++      kfree(c);
++      return err;
++}
 +
-+out:
-+      spin_unlock(&tc_list_lock);
-+      return tc;
++static int sb_test(struct super_block *sb, void *data)
++{
++      dev_t *dev = data;
 +
-+fail_ioremap:
-+      release_resource(r);
-+fail:
-+      tc = NULL;
-+      goto out;
++      return sb->s_dev == *dev;
 +}
-+EXPORT_SYMBOL_GPL(atmel_tc_alloc);
 +
-+/**
-+ * atmel_tc_free - release a specified TC block
-+ * @tc: Timer/counter block that was returned by atmel_tc_alloc()
-+ *
-+ * This reverses the effect of atmel_tc_alloc(), unmapping the I/O
-+ * registers, invalidating the resource returned by that routine and
-+ * making the TC available to other drivers.
-+ */
-+void atmel_tc_free(struct atmel_tc *tc)
++static int sb_set(struct super_block *sb, void *data)
 +{
-+      spin_lock(&tc_list_lock);
-+      if (tc->regs) {
-+              iounmap(tc->regs);
-+              release_resource(tc->iomem);
-+              tc->regs = NULL;
-+              tc->iomem = NULL;
-+      }
-+      spin_unlock(&tc_list_lock);
++      dev_t *dev = data;
++
++      sb->s_dev = *dev;
++      return 0;
 +}
-+EXPORT_SYMBOL_GPL(atmel_tc_free);
 +
-+static int __init tc_probe(struct platform_device *pdev)
++static int ubifs_get_sb(struct file_system_type *fs_type, int flags,
++                      const char *name, void *data, struct vfsmount *mnt)
 +{
-+      struct atmel_tc *tc;
-+      struct clk      *clk;
-+      int             irq;
++      struct ubi_volume_desc *ubi;
++      struct ubi_volume_info vi;
++      struct super_block *sb;
++      int err;
 +
-+      if (!platform_get_resource(pdev, IORESOURCE_MEM, 0))
-+              return -EINVAL;
++      dbg_gen("name %s, flags %#x", name, flags);
 +
-+      irq = platform_get_irq(pdev, 0);
-+      if (irq < 0)
-+              return -EINVAL;
++      /*
++       * Get UBI device number and volume ID. Mount it read-only so far
++       * because this might be a new mount point, and UBI allows only one
++       * read-write user at a time.
++       */
++      ubi = open_ubi(name, UBI_READONLY);
++      if (IS_ERR(ubi)) {
++              ubifs_err("cannot open \"%s\", error %d",
++                        name, (int)PTR_ERR(ubi));
++              return PTR_ERR(ubi);
++      }
++      ubi_get_volume_info(ubi, &vi);
 +
-+      tc = kzalloc(sizeof(struct atmel_tc), GFP_KERNEL);
-+      if (!tc)
-+              return -ENOMEM;
++      dbg_gen("opened ubi%d_%d", vi.ubi_num, vi.vol_id);
 +
-+      tc->pdev = pdev;
++      sb = sget(fs_type, &sb_test, &sb_set, &vi.cdev);
++      if (IS_ERR(sb)) {
++              err = PTR_ERR(sb);
++              goto out_close;
++      }
 +
-+      clk = clk_get(&pdev->dev, "t0_clk");
-+      if (IS_ERR(clk)) {
-+              kfree(tc);
-+              return -EINVAL;
++      if (sb->s_root) {
++              /* A new mount point for already mounted UBIFS */
++              dbg_gen("this ubi volume is already mounted");
++              if ((flags ^ sb->s_flags) & MS_RDONLY) {
++                      err = -EBUSY;
++                      goto out_deact;
++              }
++      } else {
++              sb->s_flags = flags;
++              /*
++               * Pass 'ubi' to 'fill_super()' in sb->s_fs_info where it is
++               * replaced by 'c'.
++               */
++              sb->s_fs_info = ubi;
++              err = ubifs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
++              if (err)
++                      goto out_deact;
++              /* We do not support atime */
++              sb->s_flags |= MS_ACTIVE | MS_NOATIME;
 +      }
 +
-+      tc->clk[0] = clk;
-+      tc->clk[1] = clk_get(&pdev->dev, "t1_clk");
-+      if (IS_ERR(tc->clk[1]))
-+              tc->clk[1] = clk;
-+      tc->clk[2] = clk_get(&pdev->dev, "t2_clk");
-+      if (IS_ERR(tc->clk[2]))
-+              tc->clk[2] = clk;
++      /* 'fill_super()' opens ubi again so we must close it here */
++      ubi_close_volume(ubi);
 +
-+      tc->irq[0] = irq;
-+      tc->irq[1] = platform_get_irq(pdev, 1);
-+      if (tc->irq[1] < 0)
-+              tc->irq[1] = irq;
-+      tc->irq[2] = platform_get_irq(pdev, 2);
-+      if (tc->irq[2] < 0)
-+              tc->irq[2] = irq;
++      return simple_set_mnt(mnt, sb);
 +
-+      spin_lock(&tc_list_lock);
-+      list_add_tail(&tc->node, &tc_list);
-+      spin_unlock(&tc_list_lock);
++out_deact:
++      up_write(&sb->s_umount);
++      deactivate_super(sb);
++out_close:
++      ubi_close_volume(ubi);
++      return err;
++}
 +
-+      return 0;
++static void ubifs_kill_sb(struct super_block *sb)
++{
++      struct ubifs_info *c = sb->s_fs_info;
++
++      /*
++       * We do 'commit_on_unmount()' here instead of 'ubifs_put_super()'
++       * in order to be outside BKL.
++       */
++      if (sb->s_root && !(sb->s_flags & MS_RDONLY))
++              commit_on_unmount(c);
++      /* The un-mount routine is actually done in put_super() */
++      generic_shutdown_super(sb);
 +}
 +
-+static struct platform_driver tc_driver = {
-+      .driver.name    = "atmel_tcb",
++static struct file_system_type ubifs_fs_type = {
++      .name    = "ubifs",
++      .owner   = THIS_MODULE,
++      .get_sb  = ubifs_get_sb,
++      .kill_sb = ubifs_kill_sb
 +};
 +
-+static int __init tc_init(void)
++/*
++ * Inode slab cache constructor.
++ */
++static void inode_slab_ctor(struct kmem_cache *cachep, void *obj)
 +{
-+      return platform_driver_probe(&tc_driver, tc_probe);
++      struct ubifs_inode *inode = obj;
++      inode_init_once(&inode->vfs_inode);
 +}
-+arch_initcall(tc_init);
---- a/drivers/misc/Kconfig
-+++ b/drivers/misc/Kconfig
-@@ -13,6 +13,48 @@
- if MISC_DEVICES
-+config ATMEL_PWM
-+      tristate "Atmel AT32/AT91 PWM support"
-+      depends on AVR32 || ARCH_AT91
-+      help
-+        This option enables device driver support for the PWM channels
-+        on certain Atmel prcoessors.  Pulse Width Modulation is used for
-+        purposes including software controlled power-efficent backlights
-+        on LCD displays, motor control, and waveform generation.
 +
-+config ATMEL_TCLIB
-+      bool "Atmel AT32/AT91 Timer/Counter Library"
-+      depends on (AVR32 || ARCH_AT91)
-+      help
-+        Select this if you want a library to allocate the Timer/Counter
-+        blocks found on many Atmel processors.  This facilitates using
-+        these blocks by different drivers despite processor differences.
++static int __init ubifs_init(void)
++{
++      int err;
 +
-+config ATMEL_TCB_CLKSRC
-+      bool "TC Block Clocksource"
-+      depends on ATMEL_TCLIB && GENERIC_TIME
-+      default y
-+      help
-+        Select this to get a high precision clocksource based on a
-+        TC block with a 5+ MHz base clock rate.  Two timer channels
-+        are combined to make a single 32-bit timer.
++      BUILD_BUG_ON(sizeof(struct ubifs_ch) != 24);
++
++      /* Make sure node sizes are 8-byte aligned */
++      BUILD_BUG_ON(UBIFS_CH_SZ        & 7);
++      BUILD_BUG_ON(UBIFS_INO_NODE_SZ  & 7);
++      BUILD_BUG_ON(UBIFS_DENT_NODE_SZ & 7);
++      BUILD_BUG_ON(UBIFS_XENT_NODE_SZ & 7);
++      BUILD_BUG_ON(UBIFS_DATA_NODE_SZ & 7);
++      BUILD_BUG_ON(UBIFS_TRUN_NODE_SZ & 7);
++      BUILD_BUG_ON(UBIFS_SB_NODE_SZ   & 7);
++      BUILD_BUG_ON(UBIFS_MST_NODE_SZ  & 7);
++      BUILD_BUG_ON(UBIFS_REF_NODE_SZ  & 7);
++      BUILD_BUG_ON(UBIFS_CS_NODE_SZ   & 7);
++      BUILD_BUG_ON(UBIFS_ORPH_NODE_SZ & 7);
++
++      BUILD_BUG_ON(UBIFS_MAX_DENT_NODE_SZ & 7);
++      BUILD_BUG_ON(UBIFS_MAX_XENT_NODE_SZ & 7);
++      BUILD_BUG_ON(UBIFS_MAX_DATA_NODE_SZ & 7);
++      BUILD_BUG_ON(UBIFS_MAX_INO_NODE_SZ  & 7);
++      BUILD_BUG_ON(UBIFS_MAX_NODE_SZ      & 7);
++      BUILD_BUG_ON(MIN_WRITE_SZ           & 7);
++
++      /* Check min. node size */
++      BUILD_BUG_ON(UBIFS_INO_NODE_SZ  < MIN_WRITE_SZ);
++      BUILD_BUG_ON(UBIFS_DENT_NODE_SZ < MIN_WRITE_SZ);
++      BUILD_BUG_ON(UBIFS_XENT_NODE_SZ < MIN_WRITE_SZ);
++      BUILD_BUG_ON(UBIFS_TRUN_NODE_SZ < MIN_WRITE_SZ);
++
++      BUILD_BUG_ON(UBIFS_MAX_DENT_NODE_SZ > UBIFS_MAX_NODE_SZ);
++      BUILD_BUG_ON(UBIFS_MAX_XENT_NODE_SZ > UBIFS_MAX_NODE_SZ);
++      BUILD_BUG_ON(UBIFS_MAX_DATA_NODE_SZ > UBIFS_MAX_NODE_SZ);
++      BUILD_BUG_ON(UBIFS_MAX_INO_NODE_SZ  > UBIFS_MAX_NODE_SZ);
++
++      /* Defined node sizes */
++      BUILD_BUG_ON(UBIFS_SB_NODE_SZ  != 4096);
++      BUILD_BUG_ON(UBIFS_MST_NODE_SZ != 512);
++      BUILD_BUG_ON(UBIFS_INO_NODE_SZ != 160);
++      BUILD_BUG_ON(UBIFS_REF_NODE_SZ != 64);
 +
-+        When GENERIC_CLOCKEVENTS is defined, the third timer channel
-+        may be used as a clock event device supporting oneshot mode
-+        (delays of up to two seconds) based on the 32 KiHz clock.
++      /*
++       * We require that PAGE_CACHE_SIZE is greater-than-or-equal-to
++       * UBIFS_BLOCK_SIZE. It is assumed that both are powers of 2.
++       */
++      if (PAGE_CACHE_SIZE < UBIFS_BLOCK_SIZE) {
++              ubifs_err("VFS page cache size is %u bytes, but UBIFS requires"
++                        " at least 4096 bytes",
++                        (unsigned int)PAGE_CACHE_SIZE);
++              return -EINVAL;
++      }
 +
-+config ATMEL_TCB_CLKSRC_BLOCK
-+      int
-+      depends on ATMEL_TCB_CLKSRC
-+      prompt "TC Block" if ARCH_AT91RM9200 || ARCH_AT91SAM9260 || CPU_AT32AP700X
-+      default 0
-+      range 0 1
-+      help
-+        Some chips provide more than one TC block, so you have the
-+        choice of which one to use for the clock framework.  The other
-+        TC can be used for other purposes, such as PWM generation and
-+        interval timing.
++      err  = bdi_init(&ubifs_backing_dev_info);
++      if (err)
++              return err;
 +
- config IBM_ASM
-       tristate "Device driver for IBM RSA service processor"
-       depends on X86 && PCI && INPUT && EXPERIMENTAL
---- a/drivers/misc/Makefile
-+++ b/drivers/misc/Makefile
-@@ -7,7 +7,9 @@
- obj-$(CONFIG_HDPU_FEATURES)   += hdpuftrs/
- obj-$(CONFIG_MSI_LAPTOP)     += msi-laptop.o
- obj-$(CONFIG_ASUS_LAPTOP)     += asus-laptop.o
-+obj-$(CONFIG_ATMEL_PWM)               += atmel_pwm.o
- obj-$(CONFIG_ATMEL_SSC)               += atmel-ssc.o
-+obj-$(CONFIG_ATMEL_TCLIB)     += atmel_tclib.o
- obj-$(CONFIG_LKDTM)           += lkdtm.o
- obj-$(CONFIG_TIFM_CORE)               += tifm_core.o
- obj-$(CONFIG_TIFM_7XX1)               += tifm_7xx1.o
---- /dev/null
-+++ b/drivers/mmc/host/atmel-mci.c
-@@ -0,0 +1,1220 @@
++      err = register_filesystem(&ubifs_fs_type);
++      if (err) {
++              ubifs_err("cannot register file system, error %d", err);
++              goto out;
++      }
++
++      err = -ENOMEM;
++      ubifs_inode_slab = kmem_cache_create("ubifs_inode_slab",
++                              sizeof(struct ubifs_inode), 0,
++                              SLAB_MEM_SPREAD | SLAB_RECLAIM_ACCOUNT,
++                              &inode_slab_ctor);
++      if (!ubifs_inode_slab)
++              goto out_reg;
++
++      register_shrinker(&ubifs_shrinker_info);
++
++      err = ubifs_compressors_init();
++      if (err)
++              goto out_compr;
++
++      return 0;
++
++out_compr:
++      unregister_shrinker(&ubifs_shrinker_info);
++      kmem_cache_destroy(ubifs_inode_slab);
++out_reg:
++      unregister_filesystem(&ubifs_fs_type);
++out:
++      bdi_destroy(&ubifs_backing_dev_info);
++      return err;
++}
++/* late_initcall to let compressors initialize first */
++late_initcall(ubifs_init);
++
++static void __exit ubifs_exit(void)
++{
++      ubifs_assert(list_empty(&ubifs_infos));
++      ubifs_assert(atomic_long_read(&ubifs_clean_zn_cnt) == 0);
++
++      ubifs_compressors_exit();
++      unregister_shrinker(&ubifs_shrinker_info);
++      kmem_cache_destroy(ubifs_inode_slab);
++      unregister_filesystem(&ubifs_fs_type);
++      bdi_destroy(&ubifs_backing_dev_info);
++}
++module_exit(ubifs_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_VERSION(__stringify(UBIFS_VERSION));
++MODULE_AUTHOR("Artem Bityutskiy, Adrian Hunter");
++MODULE_DESCRIPTION("UBIFS - UBI File System");
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/tnc.c avr32-2.6/fs/ubifs/tnc.c
+--- linux-2.6.25.6/fs/ubifs/tnc.c      1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/tnc.c   2008-06-12 15:09:45.600758286 +0200
+@@ -0,0 +1,2961 @@
 +/*
-+ * Atmel MultiMedia Card Interface driver
++ * This file is part of UBIFS.
 + *
-+ * Copyright (C) 2004-2006 Atmel Corporation
++ * Copyright (C) 2006-2008 Nokia Corporation.
 + *
-+ * 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.
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Adrian Hunter
++ *          Artem Bityutskiy (Битюцкий Артём)
 + */
-+#include <linux/blkdev.h>
-+#include <linux/clk.h>
-+#include <linux/device.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <linux/ioport.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+
-+#include <linux/mmc/host.h>
-+
-+#include <asm/dma-controller.h>
-+#include <asm/io.h>
-+#include <asm/arch/board.h>
-+#include <asm/arch/gpio.h>
-+
-+#include "atmel-mci.h"
 +
-+#define DRIVER_NAME "atmel_mci"
++/*
++ * This file implements TNC (Tree Node Cache) which caches indexing nodes of
++ * the UBIFS B-tree.
++ *
++ * At the moment the locking rules of the TNC tree are quite simple and
++ * straightforward. We just have a mutex and lock it when we traverse the
++ * tree. If a znode is not in memory, we read it from flash while still having
++ * the mutex locked.
++ */
 +
-+#define MCI_DATA_ERROR_FLAGS  (MCI_BIT(DCRCE) | MCI_BIT(DTOE) |       \
-+                               MCI_BIT(OVRE) | MCI_BIT(UNRE))
++#include <linux/crc32.h>
++#include "ubifs.h"
 +
++/*
++ * Returned codes of 'matches_name()' and 'fallible_matches_name()' functions.
++ * @NAME_LESS: name corresponding to the first argument is less than second
++ * @NAME_MATCHES: names match
++ * @NAME_GREATER: name corresponding to the second argument is greater than
++ *                first
++ * @NOT_ON_MEDIA: node referred by zbranch does not exist on the media
++ *
++ * These constants were introduce to improve readability.
++ */
 +enum {
-+      EVENT_CMD_COMPLETE = 0,
-+      EVENT_DATA_COMPLETE,
-+      EVENT_DATA_ERROR,
-+      EVENT_STOP_SENT,
-+      EVENT_STOP_COMPLETE,
-+      EVENT_DMA_COMPLETE,
-+      EVENT_DMA_ERROR,
++      NAME_LESS    = 0,
++      NAME_MATCHES = 1,
++      NAME_GREATER = 2,
++      NOT_ON_MEDIA = 3,
 +};
 +
-+struct atmel_mci_dma {
-+      struct dma_request_sg   req;
-+      unsigned short          rx_periph_id;
-+      unsigned short          tx_periph_id;
-+};
++/**
++ * insert_old_idx - record an index node obsoleted since the last commit start.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number of obsoleted index node
++ * @offs: offset of obsoleted index node
++ *
++ * Returns %0 on success, and a negative error code on failure.
++ *
++ * For recovery, there must always be a complete intact version of the index on
++ * flash at all times. That is called the "old index". It is the index as at the
++ * time of the last successful commit. Many of the index nodes in the old index
++ * may be dirty, but they must not be erased until the next successful commit
++ * (at which point that index becomes the old index).
++ *
++ * That means that the garbage collection and the in-the-gaps method of
++ * committing must be able to determine if an index node is in the old index.
++ * Most of the old index nodes can be found by looking up the TNC using the
++ * 'lookup_znode()' function. However, some of the old index nodes may have
++ * been deleted from the current index or may have been changed so much that
++ * they cannot be easily found. In those cases, an entry is added to an RB-tree.
++ * That is what this function does. The RB-tree is ordered by LEB number and
++ * offset because they uniquely identify the old index node.
++ */
++static int insert_old_idx(struct ubifs_info *c, int lnum, int offs)
++{
++      struct ubifs_old_idx *old_idx, *o;
++      struct rb_node **p, *parent = NULL;
 +
-+struct atmel_mci {
-+      struct mmc_host         *mmc;
-+      void __iomem            *regs;
-+      struct atmel_mci_dma    dma;
++      old_idx = kmalloc(sizeof(struct ubifs_old_idx), GFP_NOFS);
++      if (unlikely(!old_idx))
++              return -ENOMEM;
++      old_idx->lnum = lnum;
++      old_idx->offs = offs;
++
++      p = &c->old_idx.rb_node;
++      while (*p) {
++              parent = *p;
++              o = rb_entry(parent, struct ubifs_old_idx, rb);
++              if (lnum < o->lnum)
++                      p = &(*p)->rb_left;
++              else if (lnum > o->lnum)
++                      p = &(*p)->rb_right;
++              else if (offs < o->offs)
++                      p = &(*p)->rb_left;
++              else if (offs > o->offs)
++                      p = &(*p)->rb_right;
++              else {
++                      ubifs_err("old idx added twice!");
++                      kfree(old_idx);
++                      return 0;
++              }
++      }
++      rb_link_node(&old_idx->rb, parent, p);
++      rb_insert_color(&old_idx->rb, &c->old_idx);
++      return 0;
++}
 +
-+      struct mmc_request      *mrq;
-+      struct mmc_command      *cmd;
-+      struct mmc_data         *data;
++/**
++ * insert_old_idx_znode - record a znode obsoleted since last commit start.
++ * @c: UBIFS file-system description object
++ * @znode: znode of obsoleted index node
++ *
++ * Returns %0 on success, and a negative error code on failure.
++ */
++int insert_old_idx_znode(struct ubifs_info *c, struct ubifs_znode *znode)
++{
++      if (znode->parent) {
++              struct ubifs_zbranch *zbr;
++
++              zbr = &znode->parent->zbranch[znode->iip];
++              if (zbr->len)
++                      return insert_old_idx(c, zbr->lnum, zbr->offs);
++      } else
++              if (c->zroot.len)
++                      return insert_old_idx(c, c->zroot.lnum,
++                                            c->zroot.offs);
++      return 0;
++}
++
++/**
++ * ins_clr_old_idx_znode - record a znode obsoleted since last commit start.
++ * @c: UBIFS file-system description object
++ * @znode: znode of obsoleted index node
++ *
++ * Returns %0 on success, and a negative error code on failure.
++ */
++static int ins_clr_old_idx_znode(struct ubifs_info *c,
++                               struct ubifs_znode *znode)
++{
++      int err;
 +
-+      u32                     cmd_status;
-+      u32                     data_status;
-+      u32                     stop_status;
-+      u32                     stop_cmdr;
++      if (znode->parent) {
++              struct ubifs_zbranch *zbr;
++
++              zbr = &znode->parent->zbranch[znode->iip];
++              if (zbr->len) {
++                      err = insert_old_idx(c, zbr->lnum, zbr->offs);
++                      if (err)
++                              return err;
++                      zbr->lnum = 0;
++                      zbr->offs = 0;
++                      zbr->len = 0;
++              }
++      } else
++              if (c->zroot.len) {
++                      err = insert_old_idx(c, c->zroot.lnum, c->zroot.offs);
++                      if (err)
++                              return err;
++                      c->zroot.lnum = 0;
++                      c->zroot.offs = 0;
++                      c->zroot.len = 0;
++              }
++      return 0;
++}
 +
-+      struct tasklet_struct   tasklet;
-+      unsigned long           pending_events;
-+      unsigned long           completed_events;
++/**
++ * destroy_old_idx - destroy the old_idx RB-tree.
++ * @c: UBIFS file-system description object
++ *
++ * During start commit, the old_idx RB-tree is used to avoid overwriting index
++ * nodes that were in the index last commit but have since been deleted.  This
++ * is necessary for recovery i.e. the old index must be kept intact until the
++ * new index is successfully written.  The old-idx RB-tree is used for the
++ * in-the-gaps method of writing index nodes and is destroyed every commit.
++ */
++void destroy_old_idx(struct ubifs_info *c)
++{
++      struct rb_node *this = c->old_idx.rb_node;
++      struct ubifs_old_idx *old_idx;
 +
-+      int                     present;
-+      int                     detect_pin;
-+      int                     wp_pin;
++      while (this) {
++              if (this->rb_left) {
++                      this = this->rb_left;
++                      continue;
++              } else if (this->rb_right) {
++                      this = this->rb_right;
++                      continue;
++              }
++              old_idx = rb_entry(this, struct ubifs_old_idx, rb);
++              this = rb_parent(this);
++              if (this) {
++                      if (this->rb_left == &old_idx->rb)
++                              this->rb_left = NULL;
++                      else
++                              this->rb_right = NULL;
++              }
++              kfree(old_idx);
++      }
++      c->old_idx = RB_ROOT;
++}
 +
-+      /* For detect pin debouncing */
-+      struct timer_list       detect_timer;
++/**
++ * copy_znode - copy a dirty znode.
++ * @c: UBIFS file-system description object
++ * @znode: znode to copy
++ *
++ * A dirty znode being committed may not be changed, so it is copied.
++ */
++static struct ubifs_znode *copy_znode(struct ubifs_info *c,
++                                    struct ubifs_znode *znode)
++{
++      struct ubifs_znode *zn;
 +
-+      unsigned long           bus_hz;
-+      unsigned long           mapbase;
-+      struct clk              *mck;
-+      struct platform_device  *pdev;
++      zn = kmalloc(c->max_znode_sz, GFP_NOFS);
++      if (unlikely(!zn))
++              return ERR_PTR(-ENOMEM);
 +
-+#ifdef CONFIG_DEBUG_FS
-+      struct dentry           *debugfs_root;
-+      struct dentry           *debugfs_regs;
-+      struct dentry           *debugfs_req;
-+      struct dentry           *debugfs_pending_events;
-+      struct dentry           *debugfs_completed_events;
-+#endif
-+};
++      memcpy(zn, znode, c->max_znode_sz);
++      zn->cnext = NULL;
++      __set_bit(DIRTY_ZNODE, &zn->flags);
++      __clear_bit(COW_ZNODE, &zn->flags);
 +
-+/* Those printks take an awful lot of time... */
-+#ifndef DEBUG
-+static unsigned int fmax = 15000000U;
-+#else
-+static unsigned int fmax = 1000000U;
-+#endif
-+module_param(fmax, uint, 0444);
-+MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
++      ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags));
++      __set_bit(OBSOLETE_ZNODE, &znode->flags);
 +
-+/* Test bit macros for completed events */
-+#define mci_cmd_is_complete(host)                     \
-+      test_bit(EVENT_CMD_COMPLETE, &host->completed_events)
-+#define mci_data_is_complete(host)                    \
-+      test_bit(EVENT_DATA_COMPLETE, &host->completed_events)
-+#define mci_data_error_is_complete(host)              \
-+      test_bit(EVENT_DATA_ERROR, &host->completed_events)
-+#define mci_stop_sent_is_complete(host)                       \
-+      test_bit(EVENT_STOP_SENT, &host->completed_events)
-+#define mci_stop_is_complete(host)                    \
-+      test_bit(EVENT_STOP_COMPLETE, &host->completed_events)
-+#define mci_dma_is_complete(host)                     \
-+      test_bit(EVENT_DMA_COMPLETE, &host->completed_events)
-+#define mci_dma_error_is_complete(host)                       \
-+      test_bit(EVENT_DMA_ERROR, &host->completed_events)
++      if (znode->level != 0) {
++              int i;
++              const int n = zn->child_cnt;
 +
-+/* Test and clear bit macros for pending events */
-+#define mci_clear_cmd_is_pending(host)                        \
-+      test_and_clear_bit(EVENT_CMD_COMPLETE, &host->pending_events)
-+#define mci_clear_data_is_pending(host)                       \
-+      test_and_clear_bit(EVENT_DATA_COMPLETE, &host->pending_events)
-+#define mci_clear_data_error_is_pending(host)         \
-+      test_and_clear_bit(EVENT_DATA_ERROR, &host->pending_events)
-+#define mci_clear_stop_sent_is_pending(host)          \
-+      test_and_clear_bit(EVENT_STOP_SENT, &host->pending_events)
-+#define mci_clear_stop_is_pending(host)                       \
-+      test_and_clear_bit(EVENT_STOP_COMPLETE, &host->pending_events)
-+#define mci_clear_dma_error_is_pending(host)          \
-+      test_and_clear_bit(EVENT_DMA_ERROR, &host->pending_events)
++              /* The children now have new parent */
++              for (i = 0; i < n; i++) {
++                      struct ubifs_zbranch *zbr = &zn->zbranch[i];
 +
-+/* Test and set bit macros for completed events */
-+#define mci_set_cmd_is_completed(host)                        \
-+      test_and_set_bit(EVENT_CMD_COMPLETE, &host->completed_events)
-+#define mci_set_data_is_completed(host)                       \
-+      test_and_set_bit(EVENT_DATA_COMPLETE, &host->completed_events)
-+#define mci_set_data_error_is_completed(host)         \
-+      test_and_set_bit(EVENT_DATA_ERROR, &host->completed_events)
-+#define mci_set_stop_sent_is_completed(host)          \
-+      test_and_set_bit(EVENT_STOP_SENT, &host->completed_events)
-+#define mci_set_stop_is_completed(host)                       \
-+      test_and_set_bit(EVENT_STOP_COMPLETE, &host->completed_events)
-+#define mci_set_dma_error_is_completed(host)          \
-+      test_and_set_bit(EVENT_DMA_ERROR, &host->completed_events)
++                      if (zbr->znode)
++                              zbr->znode->parent = zn;
++              }
++      }
 +
-+/* Set bit macros for completed events */
-+#define mci_set_cmd_complete(host)                    \
-+      set_bit(EVENT_CMD_COMPLETE, &host->completed_events)
-+#define mci_set_data_complete(host)                   \
-+      set_bit(EVENT_DATA_COMPLETE, &host->completed_events)
-+#define mci_set_data_error_complete(host)             \
-+      set_bit(EVENT_DATA_ERROR, &host->completed_events)
-+#define mci_set_stop_sent_complete(host)              \
-+      set_bit(EVENT_STOP_SENT, &host->completed_events)
-+#define mci_set_stop_complete(host)                   \
-+      set_bit(EVENT_STOP_COMPLETE, &host->completed_events)
-+#define mci_set_dma_complete(host)                    \
-+      set_bit(EVENT_DMA_COMPLETE, &host->completed_events)
-+#define mci_set_dma_error_complete(host)              \
-+      set_bit(EVENT_DMA_ERROR, &host->completed_events)
++      atomic_long_inc(&c->dirty_zn_cnt);
++      return zn;
++}
 +
-+/* Set bit macros for pending events */
-+#define mci_set_cmd_pending(host)                     \
-+      set_bit(EVENT_CMD_COMPLETE, &host->pending_events)
-+#define mci_set_data_pending(host)                    \
-+      set_bit(EVENT_DATA_COMPLETE, &host->pending_events)
-+#define mci_set_data_error_pending(host)              \
-+      set_bit(EVENT_DATA_ERROR, &host->pending_events)
-+#define mci_set_stop_sent_pending(host)                       \
-+      set_bit(EVENT_STOP_SENT, &host->pending_events)
-+#define mci_set_stop_pending(host)                    \
-+      set_bit(EVENT_STOP_COMPLETE, &host->pending_events)
-+#define mci_set_dma_error_pending(host)                       \
-+      set_bit(EVENT_DMA_ERROR, &host->pending_events)
++/**
++ * add_idx_dirt - add dirt due to a dirty znode.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number of index node
++ * @dirt: size of index node
++ *
++ * This function updates lprops dirty space and the new size of the index.
++ */
++static int add_idx_dirt(struct ubifs_info *c, int lnum, int dirt)
++{
++      c->calc_idx_sz -= ALIGN(dirt, 8);
++      return ubifs_add_dirt(c, lnum, dirt);
++}
 +
-+/* Clear bit macros for pending events */
-+#define mci_clear_cmd_pending(host)                   \
-+      clear_bit(EVENT_CMD_COMPLETE, &host->pending_events)
-+#define mci_clear_data_pending(host)                  \
-+      clear_bit(EVENT_DATA_COMPLETE, &host->pending_events)
-+#define mci_clear_data_error_pending(host)            \
-+      clear_bit(EVENT_DATA_ERROR, &host->pending_events)
-+#define mci_clear_stop_sent_pending(host)             \
-+      clear_bit(EVENT_STOP_SENT, &host->pending_events)
-+#define mci_clear_stop_pending(host)                  \
-+      clear_bit(EVENT_STOP_COMPLETE, &host->pending_events)
-+#define mci_clear_dma_error_pending(host)             \
-+      clear_bit(EVENT_DMA_ERROR, &host->pending_events)
++/**
++ * dirty_cow_znode - ensure a znode is not being committed.
++ * @c: UBIFS file-system description object
++ * @zbr: branch of znode to check
++ *
++ * Returns dirtied znode on success or negative error code on failure.
++ */
++static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c,
++                                         struct ubifs_zbranch *zbr)
++{
++      struct ubifs_znode *znode = zbr->znode;
++      struct ubifs_znode *zn;
++      int err;
 +
++      if (!test_bit(COW_ZNODE, &znode->flags)) {
++              /* znode is not being committed */
++              if (!test_and_set_bit(DIRTY_ZNODE, &znode->flags)) {
++                      atomic_long_inc(&c->dirty_zn_cnt);
++                      atomic_long_dec(&c->clean_zn_cnt);
++                      atomic_long_dec(&ubifs_clean_zn_cnt);
++                      err = add_idx_dirt(c, zbr->lnum, zbr->len);
++                      if (unlikely(err))
++                              return ERR_PTR(err);
++              }
++              return znode;
++      }
 +
-+#ifdef CONFIG_DEBUG_FS
-+#include <linux/debugfs.h>
++      zn = copy_znode(c, znode);
++      if (unlikely(IS_ERR(zn)))
++              return zn;
 +
-+#define DBG_REQ_BUF_SIZE      (4096 - sizeof(unsigned int))
++      if (zbr->len) {
++              err = insert_old_idx(c, zbr->lnum, zbr->offs);
++              if (unlikely(err))
++                      return ERR_PTR(err);
++              err = add_idx_dirt(c, zbr->lnum, zbr->len);
++      } else
++              err = 0;
 +
-+struct req_dbg_data {
-+      unsigned int nbytes;
-+      char str[DBG_REQ_BUF_SIZE];
-+};
++      zbr->znode = zn;
++      zbr->lnum = 0;
++      zbr->offs = 0;
++      zbr->len = 0;
 +
-+static int req_dbg_open(struct inode *inode, struct file *file)
-+{
-+      struct atmel_mci *host;
-+      struct mmc_request *mrq;
-+      struct mmc_command *cmd, *stop;
-+      struct mmc_data *data;
-+      struct req_dbg_data *priv;
-+      char *str;
-+      unsigned long n = 0;
++      if (unlikely(err))
++              return ERR_PTR(err);
++      return zn;
++}
 +
-+      priv = kzalloc(DBG_REQ_BUF_SIZE, GFP_KERNEL);
-+      if (!priv)
-+              return -ENOMEM;
-+      str = priv->str;
++/**
++ * lnc_add - add a leaf node to the leaf node cache.
++ * @c: UBIFS file-system description object
++ * @zbr: zbranch of leaf node
++ * @node: leaf node
++ *
++ * Leaf nodes are non-index nodes directory entry nodes or data nodes. The
++ * purpose of the leaf node cache is to save re-reading the same leaf node over
++ * and over again. Most things are cached by VFS, however the file system must
++ * cache directory entries for readdir and for resolving hash collisions. The
++ * present implementation of the leaf node cache is extremely simple, and
++ * allows for error returns that are not used but that may be needed if a more
++ * complex implementation is created.
++ *
++ * Note, this function does not add the @node object to LNC directly, but
++ * allocates a copy of the object and adds the copy to LNC. The reason for this
++ * is that @node has been allocated outside of the TNC subsystem and will be
++ * used with @c->tnc_mutex unlock upon return from the TNC subsystem. But LNC
++ * may be changed at any time, e.g. freed by the shrinker.
++ */
++static int lnc_add(struct ubifs_info *c, struct ubifs_zbranch *zbr,
++                 const void *node)
++{
++      int err;
++      void *lnc_node;
++      const struct ubifs_dent_node *dent = node;
 +
-+      mutex_lock(&inode->i_mutex);
-+      host = inode->i_private;
++      ubifs_assert(!zbr->leaf);
++      ubifs_assert(zbr->len != 0);
++      ubifs_assert(is_hash_key(c, &zbr->key));
 +
-+      spin_lock_irq(&host->mmc->lock);
-+      mrq = host->mrq;
-+      if (mrq) {
-+              cmd = mrq->cmd;
-+              data = mrq->data;
-+              stop = mrq->stop;
-+              n = snprintf(str, DBG_REQ_BUF_SIZE,
-+                           "CMD%u(0x%x) %x %x %x %x %x (err %u)\n",
-+                           cmd->opcode, cmd->arg, cmd->flags,
-+                           cmd->resp[0], cmd->resp[1], cmd->resp[2],
-+                           cmd->resp[3], cmd->error);
-+              if (n < DBG_REQ_BUF_SIZE && data)
-+                      n += snprintf(str + n, DBG_REQ_BUF_SIZE - n,
-+                                    "DATA %u * %u (%u) %x (err %u)\n",
-+                                    data->blocks, data->blksz,
-+                                    data->bytes_xfered, data->flags,
-+                                    data->error);
-+              if (n < DBG_REQ_BUF_SIZE && stop)
-+                      n += snprintf(str + n, DBG_REQ_BUF_SIZE - n,
-+                                    "CMD%u(0x%x) %x %x %x %x %x (err %u)\n",
-+                                    stop->opcode, stop->arg, stop->flags,
-+                                    stop->resp[0], stop->resp[1],
-+                                    stop->resp[2], stop->resp[3],
-+                                    stop->error);
++      err = ubifs_validate_entry(c, dent);
++      if (err) {
++              dbg_dump_stack();
++              dbg_dump_node(c, dent);
++              return err;
 +      }
-+      spin_unlock_irq(&host->mmc->lock);
-+      mutex_unlock(&inode->i_mutex);
 +
-+      priv->nbytes = min(n, DBG_REQ_BUF_SIZE);
-+      file->private_data = priv;
++      lnc_node = kmalloc(zbr->len, GFP_NOFS);
++      if (!lnc_node)
++              /* We don't have to have the cache, so no error */
++              return 0;
 +
++      memcpy(lnc_node, node, zbr->len);
++      zbr->leaf = lnc_node;
 +      return 0;
 +}
 +
-+static ssize_t req_dbg_read(struct file *file, char __user *buf,
-+                          size_t nbytes, loff_t *ppos)
++ /**
++ * lnc_add_directly - add a leaf node to the leaf-node-cache.
++ * @c: UBIFS file-system description object
++ * @zbr: zbranch of leaf node
++ * @node: leaf node
++ *
++ * This function is similar to 'lnc_add()', but it does not create a copy of
++ * @node but inserts @node to TNC directly.
++ */
++static int lnc_add_directly(struct ubifs_info *c, struct ubifs_zbranch *zbr,
++                          void *node)
 +{
-+      struct req_dbg_data *priv = file->private_data;
++      int err;
 +
-+      return simple_read_from_buffer(buf, nbytes, ppos,
-+                                     priv->str, priv->nbytes);
++      ubifs_assert(!zbr->leaf);
++      ubifs_assert(zbr->len != 0);
++
++      err = ubifs_validate_entry(c, node);
++      if (err) {
++              dbg_dump_stack();
++              dbg_dump_node(c, node);
++              return err;
++      }
++
++      zbr->leaf = node;
++      return 0;
 +}
 +
-+static int req_dbg_release(struct inode *inode, struct file *file)
++/**
++ * lnc_free - remove a leaf node from the leaf node cache.
++ * @zbr: zbranch of leaf node
++ * @node: leaf node
++ */
++static void lnc_free(struct ubifs_zbranch *zbr)
 +{
-+      kfree(file->private_data);
-+      return 0;
++      if (!zbr->leaf)
++              return;
++      kfree(zbr->leaf);
++      zbr->leaf = NULL;
 +}
 +
-+static const struct file_operations req_dbg_fops = {
-+      .owner          = THIS_MODULE,
-+      .open           = req_dbg_open,
-+      .llseek         = no_llseek,
-+      .read           = req_dbg_read,
-+      .release        = req_dbg_release,
-+};
++/**
++ * tnc_read_node_nm - read a "hashed" leaf node.
++ * @c: UBIFS file-system description object
++ * @zbr: key and position of the node
++ * @node: node is returned here
++ *
++ * This function reads a "hashed" node defined by @zbr from the leaf node cache
++ * (in it is there) or from the hash media, in which case the node is also
++ * added to LNC. Returns zero in case of success or a negative negative error
++ * code in case of failure.
++ */
++static int tnc_read_node_nm(struct ubifs_info *c, struct ubifs_zbranch *zbr,
++                          void *node)
++{
++      int err;
 +
-+static int regs_dbg_open(struct inode *inode, struct file *file)
++      ubifs_assert(is_hash_key(c, &zbr->key));
++
++      if (zbr->leaf) {
++              /* Read from the leaf node cache */
++              ubifs_assert(zbr->len != 0);
++              memcpy(node, zbr->leaf, zbr->len);
++              return 0;
++      }
++
++      err = ubifs_tnc_read_node(c, zbr, node);
++      if (err)
++              return err;
++
++      /* Add the node to the leaf node cache */
++      err = lnc_add(c, zbr, node);
++      return err;
++}
++
++/**
++ * try_read_node - read a node if it is a node.
++ * @c: UBIFS file-system description object
++ * @buf: buffer to read to
++ * @type: node type
++ * @len: node length (not aligned)
++ * @lnum: LEB number of node to read
++ * @offs: offset of node to read
++ *
++ * This function tries to read a node of known type and length, checks it and
++ * stores it in @buf. This function returns %1 if a node is present and %0 if
++ * a node is not present. A negative error code is returned for I/O errors.
++ * This function performs that same function as ubifs_read_node except that
++ * it does not require that there is actually a node present and instead
++ * the return code indicates if a node was read.
++ */
++static int try_read_node(const struct ubifs_info *c, void *buf, int type,
++                       int len, int lnum, int offs)
 +{
-+      struct atmel_mci *host;
-+      unsigned int i;
-+      u32 *data;
-+      int ret = -ENOMEM;
++      int err, node_len;
++      struct ubifs_ch *ch = buf;
++      uint32_t crc, node_crc;
 +
-+      mutex_lock(&inode->i_mutex);
-+      host = inode->i_private;
-+      data = kmalloc(inode->i_size, GFP_KERNEL);
-+      if (!data)
-+              goto out;
++      dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len);
 +
-+      spin_lock_irq(&host->mmc->lock);
-+      for (i = 0; i < inode->i_size / 4; i++)
-+              data[i] = __raw_readl(host->regs + i * 4);
-+      spin_unlock_irq(&host->mmc->lock);
++      err = ubi_read(c->ubi, lnum, buf, offs, len);
++      if (err) {
++              ubifs_err("cannot read node type %d from LEB %d:%d, error %d",
++                        type, lnum, offs, err);
++              return err;
++      }
 +
-+      file->private_data = data;
-+      ret = 0;
++      if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC)
++              return 0;
 +
-+out:
-+      mutex_unlock(&inode->i_mutex);
++      if (ch->node_type != type)
++              return 0;
 +
-+      return ret;
++      node_len = le32_to_cpu(ch->len);
++      if (node_len != len)
++              return 0;
++
++      crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
++      node_crc = le32_to_cpu(ch->crc);
++      if (crc != node_crc)
++              return 0;
++
++      return 1;
 +}
 +
-+static ssize_t regs_dbg_read(struct file *file, char __user *buf,
-+                           size_t nbytes, loff_t *ppos)
++/**
++ * fallible_read_node - try to read a leaf node.
++ * @c: UBIFS file-system description object
++ * @key:  key of node to read
++ * @zbr:  position of node
++ * @node: node returned
++ *
++ * This function tries to read a node and returns %1 if the node is read, %0
++ * if the node is not present, and a negative error code in the case of error.
++ */
++static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
++                            struct ubifs_zbranch *zbr, void *node)
 +{
-+      struct inode *inode = file->f_dentry->d_inode;
 +      int ret;
 +
-+      mutex_lock(&inode->i_mutex);
-+      ret = simple_read_from_buffer(buf, nbytes, ppos,
-+                                    file->private_data,
-+                                    file->f_dentry->d_inode->i_size);
-+      mutex_unlock(&inode->i_mutex);
++      dbg_tnc("LEB %d:%d, key %s", zbr->lnum, zbr->offs, DBGKEY(key));
++
++      ret = try_read_node(c, node, key_type(c, key), zbr->len, zbr->lnum,
++                          zbr->offs);
++      if (ret == 1) {
++              union ubifs_key node_key;
++              struct ubifs_dent_node *dent = node;
 +
++              /* All nodes have key in the same place */
++              key_read(c, &dent->key, &node_key);
++              if (keys_cmp(c, key, &node_key) != 0)
++                      ret = 0;
++      }
++      if (ret == 0)
++              dbg_mnt("dangling branch LEB %d:%d len %d, key %s",
++                      zbr->lnum, zbr->offs, zbr->len, DBGKEY(key));
 +      return ret;
 +}
 +
-+static int regs_dbg_release(struct inode *inode, struct file *file)
-+{
-+      kfree(file->private_data);
-+      return 0;
++/**
++ * matches_name - determine if a directory or extended attribute entry matches
++ *                a given name.
++ * @c: UBIFS file-system description object
++ * @zbr: zbranch of dent
++ * @nm: name to match
++ *
++ * This function checks if xentry/direntry referred by zbranch @zbr matches name
++ * @nm. Returns %NAME_MATCHES if it does, %NAME_LESS if the name referred by
++ * @zbr is less than @nm, and %NAME_GREATER if it is greater than @nm. In case
++ * of failure, a negative error code is returned.
++ */
++static int matches_name(struct ubifs_info *c, struct ubifs_zbranch *zbr,
++                      const struct qstr *nm)
++{
++      struct ubifs_dent_node *dent;
++      int nlen, err;
++
++      /* If possible, match against the dent in the leaf node cache */
++      if (!zbr->leaf) {
++              dent = kmalloc(zbr->len, GFP_NOFS);
++              if (!dent)
++                      return -ENOMEM;
++
++              err = ubifs_tnc_read_node(c, zbr, dent);
++              if (err)
++                      goto out_free;
++
++              /* Add the node to the leaf node cache */
++              err = lnc_add_directly(c, zbr, dent);
++              if (err)
++                      goto out_free;
++      } else
++              dent = zbr->leaf;
++
++      nlen = le16_to_cpu(dent->nlen);
++      err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len));
++      if (err == 0) {
++              if (nlen == nm->len)
++                      return NAME_MATCHES;
++              else if (nlen < nm->len)
++                      return NAME_LESS;
++              else
++                      return NAME_GREATER;
++      } else if (err < 0)
++              return NAME_LESS;
++      else
++              return NAME_GREATER;
++
++out_free:
++      kfree(dent);
++      return err;
 +}
 +
-+static const struct file_operations regs_dbg_fops = {
-+      .owner          = THIS_MODULE,
-+      .open           = regs_dbg_open,
-+      .llseek         = generic_file_llseek,
-+      .read           = regs_dbg_read,
-+      .release        = regs_dbg_release,
-+};
++/**
++ * get_znode - get a TNC znode that may not be loaded yet.
++ * @c: UBIFS file-system description object
++ * @znode: parent znode
++ * @n: znode branch slot number
++ *
++ * This function returns the znode or a negative error code.
++ */
++static struct ubifs_znode *get_znode(struct ubifs_info *c,
++                                   struct ubifs_znode *znode, int n)
++{
++      struct ubifs_zbranch *zbr;
 +
-+static void atmci_init_debugfs(struct atmel_mci *host)
++      zbr = &znode->zbranch[n];
++      if (zbr->znode)
++              znode = zbr->znode;
++      else
++              znode = ubifs_load_znode(c, zbr, znode, n);
++      return znode;
++}
++
++/**
++ * tnc_next - find next TNC entry.
++ * @c: UBIFS file-system description object
++ * @zn: znode is passed and returned here
++ * @n: znode branch slot number is passed and returned here
++ *
++ * This function returns %0 if the next TNC entry is found, %-ENOENT if there is
++ * no next entry, or a negative error code otherwise.
++ */
++static int tnc_next(struct ubifs_info *c, struct ubifs_znode **zn, int *n)
 +{
-+      struct mmc_host *mmc;
-+      struct dentry *root, *regs;
-+      struct resource *res;
++      struct ubifs_znode *znode = *zn;
++      int nn = *n;
 +
-+      mmc = host->mmc;
-+      root = debugfs_create_dir(mmc_hostname(mmc), NULL);
-+      if (IS_ERR(root) || !root)
-+              goto err_root;
-+      host->debugfs_root = root;
++      nn += 1;
++      if (nn < znode->child_cnt) {
++              *n = nn;
++              return 0;
++      }
++      while (1) {
++              struct ubifs_znode *zp;
++
++              zp = znode->parent;
++              if (!zp)
++                      return -ENOENT;
++              nn = znode->iip + 1;
++              znode = zp;
++              if (nn < znode->child_cnt) {
++                      znode = get_znode(c, znode, nn);
++                      if (IS_ERR(znode))
++                              return PTR_ERR(znode);
++                      while (znode->level != 0) {
++                              znode = get_znode(c, znode, 0);
++                              if (IS_ERR(znode))
++                                      return PTR_ERR(znode);
++                      }
++                      nn = 0;
++                      break;
++              }
++      }
++      *zn = znode;
++      *n = nn;
++      return 0;
++}
 +
-+      regs = debugfs_create_file("regs", 0400, root, host, &regs_dbg_fops);
-+      if (!regs)
-+              goto err_regs;
++/**
++ * tnc_prev - find previous TNC entry.
++ * @c: UBIFS file-system description object
++ * @zn: znode is returned here
++ * @n: znode branch slot number is passed and returned here
++ *
++ * This function returns %0 if the previous TNC entry is found, %-ENOENT if
++ * there is no next entry, or a negative error code otherwise.
++ */
++static int tnc_prev(struct ubifs_info *c, struct ubifs_znode **zn, int *n)
++{
++      struct ubifs_znode *znode = *zn;
++      int nn = *n;
 +
-+      res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0);
-+      regs->d_inode->i_size = res->end - res->start + 1;
-+      host->debugfs_regs = regs;
++      if (nn > 0) {
++              *n = nn - 1;
++              return 0;
++      }
++      while (1) {
++              struct ubifs_znode *zp;
++
++              zp = znode->parent;
++              if (!zp)
++                      return -ENOENT;
++              nn = znode->iip - 1;
++              znode = zp;
++              if (nn >= 0) {
++                      znode = get_znode(c, znode, nn);
++                      if (IS_ERR(znode))
++                              return PTR_ERR(znode);
++                      while (znode->level != 0) {
++                              nn = znode->child_cnt - 1;
++                              znode = get_znode(c, znode, nn);
++                              if (IS_ERR(znode))
++                                      return PTR_ERR(znode);
++                      }
++                      nn = znode->child_cnt - 1;
++                      break;
++              }
++      }
++      *zn = znode;
++      *n = nn;
++      return 0;
++}
 +
-+      host->debugfs_req = debugfs_create_file("req", 0400, root,
-+                                              host, &req_dbg_fops);
-+      if (!host->debugfs_req)
-+              goto err_req;
++/**
++ * resolve_collision - resolve a collision.
++ * @c: UBIFS file-system description object
++ * @key: key of a directory or extended attribute entry
++ * @zn: znode is returned here
++ * @n: zbranch number is passed and returned here
++ * @nm: name of the entry
++ *
++ * This function is called for "hashed" keys to make sure that the found key
++ * really corresponds to the looked up node (directory or extended attribute
++ * entry). It returns %1 and sets @zn and @n if the collision is resolved.
++ * %0 is returned if @nm is not found and @zn and @n are set to the previous
++ * entry, i.e. to the entry after which @nm could follow if it were in TNC.
++ * This means that @n may be set to %-1 if the leftmost key in @zn is the
++ * previous one. A negative error code is returned on failures.
++ */
++static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
++                           struct ubifs_znode **zn, int *n,
++                           const struct qstr *nm)
++{
++      int err;
 +
-+      host->debugfs_pending_events
-+              = debugfs_create_u32("pending_events", 0400, root,
-+                                   (u32 *)&host->pending_events);
-+      if (!host->debugfs_pending_events)
-+              goto err_pending_events;
++      err = matches_name(c, &(*zn)->zbranch[*n], nm);
++      if (unlikely(err < 0))
++              return err;
++      if (err == NAME_MATCHES)
++              return 1;
++
++      if (err == NAME_GREATER) {
++              /* Look left */
++              while (1) {
++                      err = tnc_prev(c, zn, n);
++                      if (err == -ENOENT) {
++                              ubifs_assert(*n == 0);
++                              *n = -1;
++                              return 0;
++                      }
++                      if (err < 0)
++                              return err;
++                      if (keys_cmp(c, &(*zn)->zbranch[*n].key, key)) {
++                              /*
++                               * We have found the branch after which we would
++                               * like to insert, but inserting in this znode
++                               * may still be wrong. Consider the following 3
++                               * znodes, in the case where we are resolving a
++                               * collision with Key2.
++                               *
++                               *                  znode zp
++                               *            ----------------------
++                               * level 1     |  Key0  |  Key1  |
++                               *            -----------------------
++                               *                 |            |
++                               *       znode za  |            |  znode zb
++                               *          ------------      ------------
++                               * level 0  |  Key0  |        |  Key2  |
++                               *          ------------      ------------
++                               *
++                               * The lookup finds Key2 in znode zb. Lets say
++                               * there is no match and the name is greater so
++                               * we look left. When we find Key0, we end up
++                               * here. If we return now, we will insert into
++                               * znode za at slot n = 1.  But that is invalid
++                               * according to the parent's keys.  Key2 must
++                               * be inserted into znode zb.
++                               *
++                               * Note, this problem is not relevant for the
++                               * case when we go right, because
++                               * 'tnc_insert()' would correct the parent key.
++                               */
++                              if (*n == (*zn)->child_cnt - 1) {
++                                      err = tnc_next(c, zn, n);
++                                      if (err) {
++                                              /* Should be impossible */
++                                              ubifs_assert(0);
++                                              if (err == -ENOENT)
++                                                      err = -EINVAL;
++                                              return err;
++                                      }
++                                      ubifs_assert(*n == 0);
++                                      *n = -1;
++                              }
++                              return 0;
++                      }
++                      err = matches_name(c, &(*zn)->zbranch[*n], nm);
++                      if (err < 0)
++                              return err;
++                      if (err == NAME_LESS)
++                              return 0;
++                      if (err == NAME_MATCHES)
++                              return 1;
++                      ubifs_assert(err == NAME_GREATER);
++              }
++      } else {
++              int nn = *n;
++              struct ubifs_znode *znode = *zn;
++
++              /* Look right */
++              while (1) {
++                      err = tnc_next(c, &znode, &nn);
++                      if (err == -ENOENT)
++                              return 0;
++                      if (err < 0)
++                              return err;
++                      if (keys_cmp(c, &znode->zbranch[nn].key, key))
++                              return 0;
++                      err = matches_name(c, &znode->zbranch[nn], nm);
++                      if (err < 0)
++                              return err;
++                      if (err == NAME_GREATER)
++                              return 0;
++                      *zn = znode;
++                      *n = nn;
++                      if (err == NAME_MATCHES)
++                              return 1;
++                      ubifs_assert(err == NAME_LESS);
++              }
++      }
++}
 +
-+      host->debugfs_completed_events
-+              = debugfs_create_u32("completed_events", 0400, root,
-+                                   (u32 *)&host->completed_events);
-+      if (!host->debugfs_completed_events)
-+              goto err_completed_events;
++/**
++ * fallible_matches_name - determine if a dent matches a given name.
++ * @c: UBIFS file-system description object
++ * @zbr: zbranch of dent
++ * @nm: name to match
++ *
++ * This is a "fallible" version of 'matches_name()' function which does not
++ * panic if the direntry/xentry referred by @zbr does not exist on the media.
++ *
++ * This function checks if xentry/direntry referred by zbranch @zbr matches name
++ * @nm. Returns %NAME_MATCHES it does, %NAME_LESS if the name referred by @zbr
++ * is less than @nm, %NAME_GREATER if it is greater than @nm, and @NOT_ON_MEDIA
++ * if xentry/direntry referred by @zbr does not exist on the media. A negative
++ * error code is returned in case of failure.
++ */
++static int fallible_matches_name(struct ubifs_info *c,
++                               struct ubifs_zbranch *zbr,
++                               const struct qstr *nm)
++{
++      struct ubifs_dent_node *dent;
++      int nlen, err;
++
++      /* If possible, match against the dent in the leaf node cache */
++      if (!zbr->leaf) {
++              dent = kmalloc(zbr->len, GFP_NOFS);
++              if (!dent)
++                      return -ENOMEM;
++
++              err = fallible_read_node(c, &zbr->key, zbr, dent);
++              if (err < 0)
++                      goto out_free;
++              if (err == 0) {
++                      /* The node was not present */
++                      err = NOT_ON_MEDIA;
++                      goto out_free;
++              }
++              ubifs_assert(err == 1);
 +
-+      return;
++              err = lnc_add_directly(c, zbr, dent);
++              if (err)
++                      goto out_free;
++      } else
++              dent = zbr->leaf;
++
++      nlen = le16_to_cpu(dent->nlen);
++      err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len));
++      if (err == 0) {
++              if (nlen == nm->len)
++                      return NAME_MATCHES;
++              else if (nlen < nm->len)
++                      return NAME_LESS;
++              else
++                      return NAME_GREATER;
++      } else if (err < 0)
++              return NAME_LESS;
++      else
++              return NAME_GREATER;
 +
-+err_completed_events:
-+      debugfs_remove(host->debugfs_pending_events);
-+err_pending_events:
-+      debugfs_remove(host->debugfs_req);
-+err_req:
-+      debugfs_remove(host->debugfs_regs);
-+err_regs:
-+      debugfs_remove(host->debugfs_root);
-+err_root:
-+      host->debugfs_root = NULL;
-+      dev_err(&host->pdev->dev,
-+              "failed to initialize debugfs for %s\n",
-+              mmc_hostname(mmc));
++out_free:
++      kfree(dent);
++      return err;
 +}
 +
-+static void atmci_cleanup_debugfs(struct atmel_mci *host)
-+{
-+      if (host->debugfs_root) {
-+              debugfs_remove(host->debugfs_completed_events);
-+              debugfs_remove(host->debugfs_pending_events);
-+              debugfs_remove(host->debugfs_req);
-+              debugfs_remove(host->debugfs_regs);
-+              debugfs_remove(host->debugfs_root);
-+              host->debugfs_root = NULL;
++/**
++ * fallible_resolve_collision - resolve a collision even if nodes are missing.
++ * @c: UBIFS file-system description object
++ * @key: key
++ * @zn: znode is returned here
++ * @n: branch number is passed and returned here
++ * @nm: name of directory entry
++ * @adding: indicates caller is adding a key to the TNC
++ *
++ * This is a "fallible" version of the 'resolve_collision()' function which
++ * does not panic if one of the nodes referred to by TNC does not exist on the
++ * media. This may happen when replaying the journal if a deleted node was
++ * Garbage-collected and the commit was not done. A branch that refers to a node
++ * that is not present is called a dangling branch. The following are the return
++ * codes for this function:
++ *  o if @nm was found, %1 is returned and @zn and @n are set to the found
++ *    branch;
++ *  o if we are @adding and @nm was not found, %0 is returned;
++ *  o if we are not @adding and @nm was not found, but a dangling branch was
++ *    found, then %1 is returned and @zn and @n are set to the dangling branch;
++ *  o a negative error code is returned in case of failure.
++ */
++static int fallible_resolve_collision(struct ubifs_info *c,
++                                    const union ubifs_key *key,
++                                    struct ubifs_znode **zn, int *n,
++                                    const struct qstr *nm, int adding)
++{
++      struct ubifs_znode *o_znode = NULL, *znode = *zn;
++      int uninitialized_var(o_n), err, cmp, unsure = 0, nn = *n;
++
++      cmp = fallible_matches_name(c, &znode->zbranch[nn], nm);
++      if (unlikely(cmp < 0))
++              return cmp;
++      if (cmp == NAME_MATCHES)
++              return 1;
++      if (cmp == NOT_ON_MEDIA) {
++              o_znode = znode;
++              o_n = nn;
++              /*
++               * We are unlucky and hit a dangling branch straight away.
++               * Now we do not really know where to go to find the needed
++               * branch - to the left or to the right. Well, let's try left.
++               */
++              unsure = 1;
++      } else if (!adding)
++              unsure = 1; /* Remove a dangling branch wherever it is */
++
++      if (cmp == NAME_GREATER || unsure) {
++              /* Look left */
++              while (1) {
++                      err = tnc_prev(c, zn, n);
++                      if (err == -ENOENT) {
++                              ubifs_assert(*n == 0);
++                              *n = -1;
++                              break;
++                      }
++                      if (err < 0)
++                              return err;
++                      if (keys_cmp(c, &(*zn)->zbranch[*n].key, key)) {
++                              /* See comments in 'resolve_collision()' */
++                              if (*n == (*zn)->child_cnt - 1) {
++                                      err = tnc_next(c, zn, n);
++                                      if (err) {
++                                              /* Should be impossible */
++                                              ubifs_assert(0);
++                                              if (err == -ENOENT)
++                                                      err = -EINVAL;
++                                              return err;
++                                      }
++                                      ubifs_assert(*n == 0);
++                                      *n = -1;
++                              }
++                              break;
++                      }
++                      err = fallible_matches_name(c, &(*zn)->zbranch[*n], nm);
++                      if (err < 0)
++                              return err;
++                      if (err == NAME_MATCHES)
++                              return 1;
++                      if (err == NOT_ON_MEDIA) {
++                              o_znode = *zn;
++                              o_n = *n;
++                              continue;
++                      }
++                      if (!adding)
++                              continue;
++                      if (err == NAME_LESS)
++                              break;
++                      else
++                              unsure = 0;
++              }
 +      }
-+}
-+#else
-+static inline void atmci_init_debugfs(struct atmel_mci *host)
-+{
 +
-+}
++      if (cmp == NAME_LESS || unsure) {
++              /* Look right */
++              *zn = znode;
++              *n = nn;
++              while (1) {
++                      err = tnc_next(c, &znode, &nn);
++                      if (err == -ENOENT)
++                              break;
++                      if (err < 0)
++                              return err;
++                      if (keys_cmp(c, &znode->zbranch[nn].key, key))
++                              break;
++                      err = fallible_matches_name(c, &znode->zbranch[nn], nm);
++                      if (err < 0)
++                              return err;
++                      if (err == NAME_GREATER)
++                              break;
++                      *zn = znode;
++                      *n = nn;
++                      if (err == NAME_MATCHES)
++                              return 1;
++                      if (err == NOT_ON_MEDIA) {
++                              o_znode = znode;
++                              o_n = nn;
++                      }
++              }
++      }
 +
-+static inline void atmci_cleanup_debugfs(struct atmel_mci *host)
-+{
++      /* Never match a dangling branch when adding */
++      if (adding || !o_znode)
++              return 0;
 +
++      dbg_mnt("dangling match LEB %d:%d len %d %s",
++              o_znode->zbranch[o_n].lnum, o_znode->zbranch[o_n].offs,
++              o_znode->zbranch[o_n].len, DBGKEY(key));
++      *zn = o_znode;
++      *n = o_n;
++      return 1;
 +}
-+#endif /* CONFIG_DEBUG_FS */
 +
-+static inline unsigned int ns_to_clocks(struct atmel_mci *host,
-+                                      unsigned int ns)
++/**
++ * matches_position - determine if a zbranch matches a given position.
++ * @zbr: zbranch of dent
++ * @lnum: LEB number of dent to match
++ * @offs: offset of dent to match
++ *
++ * This function returns %1 if @lnum:@offs matches, and %0 otherwise.
++ */
++static int matches_position(struct ubifs_zbranch *zbr, int lnum, int offs)
 +{
-+      return (ns * (host->bus_hz / 1000000) + 999) / 1000;
++      if (zbr->lnum == lnum && zbr->offs == offs)
++              return 1;
++      else
++              return 0;
 +}
 +
-+static void atmci_set_timeout(struct atmel_mci *host,
-+                            struct mmc_data *data)
-+{
-+      static unsigned dtomul_to_shift[] = {
-+              0, 4, 7, 8, 10, 12, 16, 20
-+      };
-+      unsigned timeout;
-+      unsigned dtocyc, dtomul;
++/**
++ * resolve_collision_directly - resolve a collision directly.
++ * @c: UBIFS file-system description object
++ * @key: key of directory entry
++ * @zn: znode is passed and returned here
++ * @n: zbranch number is passed and returned here
++ * @lnum: LEB number of dent node to match
++ * @offs: offset of dent node to match
++ *
++ * This function is used for "hashed" keys to make sure the found directory or
++ * extended attribute entry node is what was looked for. It is used when the
++ * flash address of the right node is known (@lnum:@offs) which makes it much
++ * easier to resolve collisions (no need to read entries and match full
++ * names). This function returns %1 and sets @zn and @n if the collision is
++ * resolved, %0 if @lnum:@offs is not found and @zn and @n are set to the
++ * previous directory entry. Otherwise a negative error code is returned.
++ */
++static int resolve_collision_directly(struct ubifs_info *c,
++                                    const union ubifs_key *key,
++                                    struct ubifs_znode **zn, int *n,
++                                    int lnum, int offs)
++{
++      struct ubifs_znode *znode;
++      int nn, err;
++
++      znode = *zn;
++      nn = *n;
++      if (matches_position(&znode->zbranch[nn], lnum, offs))
++              return 1;
++
++      /* Look left */
++      while (1) {
++              err = tnc_prev(c, &znode, &nn);
++              if (err == -ENOENT)
++                      break;
++              if (err < 0)
++                      return err;
++              if (keys_cmp(c, &znode->zbranch[nn].key, key))
++                      break;
++              if (matches_position(&znode->zbranch[nn], lnum, offs)) {
++                      *zn = znode;
++                      *n = nn;
++                      return 1;
++              }
++      }
 +
-+      timeout = ns_to_clocks(host, data->timeout_ns) + data->timeout_clks;
++      /* Look right */
++      znode = *zn;
++      nn = *n;
++      while (1) {
++              err = tnc_next(c, &znode, &nn);
++              if (err == -ENOENT)
++                      return 0;
++              if (err < 0)
++                      return err;
++              if (keys_cmp(c, &znode->zbranch[nn].key, key))
++                      return 0;
++              *zn = znode;
++              *n = nn;
++              if (matches_position(&znode->zbranch[nn], lnum, offs))
++                      return 1;
++      }
++}
 +
-+      for (dtomul = 0; dtomul < 8; dtomul++) {
-+              unsigned shift = dtomul_to_shift[dtomul];
-+              dtocyc = (timeout + (1 << shift) - 1) >> shift;
-+              if (dtocyc < 15)
-+                      break;
++/**
++ * dirty_cow_bottom_up - dirty a znode and its ancestors.
++ * @c: UBIFS file-system description object
++ * @znode: znode to dirty
++ *
++ * If we do not have a unique key that resides in a znode, then we cannot
++ * dirty that znode from the top down (i.e. by using lookup_level0_dirty)
++ * This function records the path back to the last dirty ancestor, and then
++ * dirties the znodes on that path.
++ */
++static struct ubifs_znode *dirty_cow_bottom_up(struct ubifs_info *c,
++                                             struct ubifs_znode *znode)
++{
++      struct ubifs_znode *zp;
++      int *path = c->bottom_up_buf, p = 0;
++
++      ubifs_assert(c->zroot.znode);
++      ubifs_assert(znode);
++      if (c->zroot.znode->level > BOTTOM_UP_HEIGHT) {
++              kfree(c->bottom_up_buf);
++              c->bottom_up_buf = kmalloc(c->zroot.znode->level * sizeof(int),
++                                         GFP_NOFS);
++              if (!c->bottom_up_buf)
++                      return ERR_PTR(-ENOMEM);
++              path = c->bottom_up_buf;
 +      }
++      if (c->zroot.znode->level) {
++              /* Go up until parent is dirty */
++              while (1) {
++                      int n;
 +
-+      if (dtomul >= 8) {
-+              dtomul = 7;
-+              dtocyc = 15;
++                      zp = znode->parent;
++                      if (!zp)
++                              break;
++                      n = znode->iip;
++                      ubifs_assert(p < c->zroot.znode->level);
++                      path[p++] = n;
++                      if (!zp->cnext && ubifs_zn_dirty(znode))
++                              break;
++                      znode = zp;
++              }
 +      }
 +
-+      dev_dbg(&host->mmc->class_dev, "setting timeout to %u cycles\n",
-+                      dtocyc << dtomul_to_shift[dtomul]);
-+      mci_writel(host, DTOR, (MCI_BF(DTOMUL, dtomul)
-+                              | MCI_BF(DTOCYC, dtocyc)));
++      /* Come back down, dirtying as we go */
++      while (1) {
++              struct ubifs_zbranch *zbr;
++
++              zp = znode->parent;
++              if (zp) {
++                      ubifs_assert(path[p - 1] >= 0);
++                      ubifs_assert(path[p - 1] < zp->child_cnt);
++                      zbr = &zp->zbranch[path[--p]];
++                      znode = dirty_cow_znode(c, zbr);
++              } else {
++                      ubifs_assert(znode == c->zroot.znode);
++                      znode = dirty_cow_znode(c, &c->zroot);
++              }
++              if (unlikely(IS_ERR(znode)) || !p)
++                      break;
++              ubifs_assert(path[p - 1] >= 0);
++              ubifs_assert(path[p - 1] < znode->child_cnt);
++              znode = znode->zbranch[path[p - 1]].znode;
++      }
++
++      return znode;
 +}
 +
-+/*
-+ * Return mask with command flags to be enabled for this command.
++/**
++ * ubifs_lookup_level0 - search for zero-level znode.
++ * @c: UBIFS file-system description object
++ * @key:  key to lookup
++ * @zn: znode is returned here
++ * @n: znode branch slot number is returned here
++ *
++ * This function looks up the TNC tree and search for zero-level znode which
++ * refers key @key. The found zero-level znode is returned in @zn. There are 3
++ * cases:
++ *   o exact match, i.e. the found zero-level znode contains key @key, then %1
++ *     is returned and slot number of the matched branch is stored in @n;
++ *   o not exact match, which means that zero-level znode does not contain
++ *     @key, then %0 is returned and slot number of the closed branch is stored
++ *     in  @n;
++ *   o @key is so small that it is even less than the lowest key of the
++ *     leftmost zero-level node, then %0 is returned and %0 is stored in @n.
++ *
++ * Note, when the TNC tree is traversed, some znodes may be absent, then this
++ * function reads corresponding indexing nodes and inserts them to TNC. In
++ * case of failure, a negative error code is returned.
 + */
-+static u32 atmci_prepare_command(struct mmc_host *mmc,
-+                               struct mmc_command *cmd)
-+{
-+      u32 cmdr;
-+
-+      cmd->error = 0;
++int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
++                      struct ubifs_znode **zn, int *n)
++{
++      int err, exact;
++      struct ubifs_znode *znode;
++      unsigned long time = get_seconds();
 +
-+      cmdr = MCI_BF(CMDNB, cmd->opcode);
++      dbg_tnc("search key %s", DBGKEY(key));
 +
-+      if (cmd->flags & MMC_RSP_PRESENT) {
-+              if (cmd->flags & MMC_RSP_136)
-+                      cmdr |= MCI_BF(RSPTYP, MCI_RSPTYP_136_BIT);
-+              else
-+                      cmdr |= MCI_BF(RSPTYP, MCI_RSPTYP_48_BIT);
++      znode = c->zroot.znode;
++      if (unlikely(!znode)) {
++              znode = ubifs_load_znode(c, &c->zroot, NULL, 0);
++              if (IS_ERR(znode))
++                      return PTR_ERR(znode);
 +      }
 +
-+      /*
-+       * This should really be MAXLAT_5 for CMD2 and ACMD41, but
-+       * it's too difficult to determine whether this is an ACMD or
-+       * not. Better make it 64.
-+       */
-+      cmdr |= MCI_BIT(MAXLAT);
++      znode->time = time;
 +
-+      if (mmc->ios.bus_mode == MMC_BUSMODE_OPENDRAIN)
-+              cmdr |= MCI_BIT(OPDCMD);
++      while (1) {
++              struct ubifs_zbranch *zbr;
 +
-+      dev_dbg(&mmc->class_dev,
-+              "cmd: op %02x arg %08x flags %08x, cmdflags %08lx\n",
-+              cmd->opcode, cmd->arg, cmd->flags, (unsigned long)cmdr);
++              exact = ubifs_search_zbranch(c, znode, key, n);
 +
-+      return cmdr;
-+}
++              if (znode->level == 0)
++                      break;
 +
-+static void atmci_start_command(struct atmel_mci *host,
-+                              struct mmc_command *cmd,
-+                              u32 cmd_flags)
-+{
-+      WARN_ON(host->cmd);
-+      host->cmd = cmd;
++              if (*n < 0)
++                      *n = 0;
++              zbr = &znode->zbranch[*n];
 +
-+      mci_writel(host, ARGR, cmd->arg);
-+      mci_writel(host, CMDR, cmd_flags);
++              if (zbr->znode) {
++                      znode->time = time;
++                      znode = zbr->znode;
++                      continue;
++              }
 +
-+      if (cmd->data)
-+              dma_start_request(host->dma.req.req.dmac,
-+                                host->dma.req.req.channel);
++              /* znode is not in TNC cache, load it from the media */
++              znode = ubifs_load_znode(c, zbr, znode, *n);
++              if (IS_ERR(znode))
++                      return PTR_ERR(znode);
++      }
++
++      *zn = znode;
++      if (exact || !is_hash_key(c, key) || *n != -1) {
++              dbg_tnc("found %d, lvl %d, n %d", exact, znode->level, *n);
++              return exact;
++      }
++
++      /*
++       * Here is a tricky place. We have not found the key and this is a
++       * "hashed" key, which may collide. The rest of the code deals with
++       * situations like this:
++       *
++       *                  | 3 | 5 |
++       *                  /       \
++       *          | 3 | 5 |      | 6 | 7 | (x)
++       *
++       * Or more a complex example:
++       *
++       *                | 1 | 5 |
++       *                /       \
++       *       | 1 | 3 |         | 5 | 8 |
++       *              \           /
++       *          | 5 | 5 |   | 6 | 7 | (x)
++       *
++       * In the examples, if we are looking for key "5", we may reach nodes
++       * marked with "(x)". In this case what we have do is to look at the
++       * left and see if there is "5" key there. If there is, we have to
++       * return it.
++       *
++       * Note, this whole situation is possible because we allow to have
++       * elements which are equivalent to the next key in the parent in the
++       * children of current znode. For example, this happens if we split a
++       * znode like this: | 3 | 5 | 5 | 6 | 7 |, which results in something
++       * like this:
++       *                      | 3 | 5 |
++       *                       /     \
++       *                | 3 | 5 |   | 5 | 6 | 7 |
++       *                              ^
++       * And this becomes what is at the first "picture" after key "5" marked
++       * with "^" is removed. What could be done is we could prohibit
++       * splitting in the middle of the colliding sequence. Also, when
++       * removing the leftmost key, we would have to correct the key of the
++       * parent node, which would introduce additional complications. Namely,
++       * if we changed the the leftmost key of the parent znode, the garbage
++       * collector would be unable to find it (GC is doing this when GC'ing
++       * indexing LEBs). Although we already have an additional RB-tree where
++       * we save such changed znodes (see 'ins_clr_old_idx_znode()') until
++       * after the commit. But anyway, this does not look easy to implement
++       * so we did not try this.
++       */
++      err = tnc_prev(c, &znode, n);
++      if (err == -ENOENT) {
++              dbg_tnc("found 0, lvl %d, n -1", znode->level);
++              *n = -1;
++              return 0;
++      }
++      if (unlikely(err < 0))
++              return err;
++      if (keys_cmp(c, key, &znode->zbranch[*n].key)) {
++              dbg_tnc("found 0, lvl %d, n -1", znode->level);
++              *n = -1;
++              return 0;
++      }
++
++      dbg_tnc("found 1, lvl %d, n %d", znode->level, *n);
++      *zn = znode;
++      return 1;
 +}
 +
-+/*
-+ * Returns a mask of flags to be set in the command register when the
-+ * command to start the transfer is to be sent.
++/**
++ * lookup_level0_dirty - search for zero-level znode dirtying.
++ * @c: UBIFS file-system description object
++ * @key:  key to lookup
++ * @zn: znode is returned here
++ * @n: znode branch slot number is returned here
++ *
++ * This function looks up the TNC tree and search for zero-level znode which
++ * refers key @key. The found zero-level znode is returned in @zn. There are 3
++ * cases:
++ *   o exact match, i.e. the found zero-level znode contains key @key, then %1
++ *     is returned and slot number of the matched branch is stored in @n;
++ *   o not exact match, which means that zero-level znode does not contain @key
++ *     then %0 is returned and slot number of the closed branch is stored in
++ *     @n;
++ *   o @key is so small that it is even less than the lowest key of the
++ *     leftmost zero-level node, then %0 is returned and %-1 is stored in @n.
++ *
++ * Additionally all znodes in the path from the root to the located zero-level
++ * znode are marked as dirty.
++ *
++ * Note, when the TNC tree is traversed, some znodes may be absent, then this
++ * function reads corresponding indexing nodes and inserts them to TNC. In
++ * case of failure, a negative error code is returned.
 + */
-+static u32 atmci_prepare_data(struct mmc_host *mmc, struct mmc_data *data)
++static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key,
++                             struct ubifs_znode **zn, int *n)
 +{
-+      struct atmel_mci *host = mmc_priv(mmc);
-+      u32 cmd_flags;
++      int err, exact;
++      struct ubifs_znode *znode;
++      unsigned long time = get_seconds();
 +
-+      WARN_ON(host->data);
-+      host->data = data;
++      dbg_tnc("search and dirty key %s", DBGKEY(key));
 +
-+      atmci_set_timeout(host, data);
-+      mci_writel(host, BLKR, (MCI_BF(BCNT, data->blocks)
-+                              | MCI_BF(BLKLEN, data->blksz)));
-+      host->dma.req.block_size = data->blksz;
-+      host->dma.req.nr_blocks = data->blocks;
++      znode = c->zroot.znode;
++      if (unlikely(!znode)) {
++              znode = ubifs_load_znode(c, &c->zroot, NULL, 0);
++              if (IS_ERR(znode))
++                      return PTR_ERR(znode);
++      }
 +
-+      cmd_flags = MCI_BF(TRCMD, MCI_TRCMD_START_TRANS);
-+      if (data->flags & MMC_DATA_STREAM)
-+              cmd_flags |= MCI_BF(TRTYP, MCI_TRTYP_STREAM);
-+      else if (data->blocks > 1)
-+              cmd_flags |= MCI_BF(TRTYP, MCI_TRTYP_MULTI_BLOCK);
-+      else
-+              cmd_flags |= MCI_BF(TRTYP, MCI_TRTYP_BLOCK);
++      znode = dirty_cow_znode(c, &c->zroot);
++      if (IS_ERR(znode))
++              return PTR_ERR(znode);
 +
-+      if (data->flags & MMC_DATA_READ) {
-+              cmd_flags |= MCI_BIT(TRDIR);
-+              host->dma.req.nr_sg
-+                      = dma_map_sg(&host->pdev->dev, data->sg,
-+                                   data->sg_len, DMA_FROM_DEVICE);
-+              host->dma.req.periph_id = host->dma.rx_periph_id;
-+              host->dma.req.direction = DMA_DIR_PERIPH_TO_MEM;
-+              host->dma.req.data_reg = host->mapbase + MCI_RDR;
-+      } else {
-+              host->dma.req.nr_sg
-+                      = dma_map_sg(&host->pdev->dev, data->sg,
-+                                   data->sg_len, DMA_TO_DEVICE);
-+              host->dma.req.periph_id = host->dma.tx_periph_id;
-+              host->dma.req.direction = DMA_DIR_MEM_TO_PERIPH;
-+              host->dma.req.data_reg = host->mapbase + MCI_TDR;
-+      }
-+      host->dma.req.sg = data->sg;
++      znode->time = time;
 +
-+      dma_prepare_request_sg(host->dma.req.req.dmac, &host->dma.req);
++      while (1) {
++              struct ubifs_zbranch *zbr;
 +
-+      return cmd_flags;
-+}
++              exact = ubifs_search_zbranch(c, znode, key, n);
 +
-+static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
-+{
-+      struct atmel_mci *host = mmc_priv(mmc);
-+      struct mmc_data *data = mrq->data;
-+      u32 iflags;
-+      u32 cmdflags = 0;
++              if (znode->level == 0)
++                      break;
 +
-+      iflags = mci_readl(host, IMR);
-+      if (iflags)
-+              dev_warn(&mmc->class_dev, "WARNING: IMR=0x%08x\n",
-+                              mci_readl(host, IMR));
++              if (*n < 0)
++                      *n = 0;
++              zbr = &znode->zbranch[*n];
 +
-+      WARN_ON(host->mrq != NULL);
++              if (zbr->znode) {
++                      znode->time = time;
++                      znode = dirty_cow_znode(c, zbr);
++                      if (IS_ERR(znode))
++                              return PTR_ERR(znode);
++                      continue;
++              }
++
++              /* znode is not in TNC cache, load it from the media */
++              znode = ubifs_load_znode(c, zbr, znode, *n);
++              if (IS_ERR(znode))
++                      return PTR_ERR(znode);
++              znode = dirty_cow_znode(c, zbr);
++              if (IS_ERR(znode))
++                      return PTR_ERR(znode);
++      }
++
++      *zn = znode;
++      if (exact || !is_hash_key(c, key) || *n != -1) {
++              dbg_tnc("found %d, lvl %d, n %d", exact, znode->level, *n);
++              return exact;
++      }
 +
 +      /*
-+       * We may "know" the card is gone even though there's still an
-+       * electrical connection. If so, we really need to communicate
-+       * this to the MMC core since there won't be any more
-+       * interrupts as the card is completely removed. Otherwise,
-+       * the MMC core might believe the card is still there even
-+       * though the card was just removed very slowly.
++       * See huge comment at 'lookup_level0_dirty()' what is the rest of the
++       * code.
 +       */
-+      if (!host->present) {
-+              mrq->cmd->error = -ENOMEDIUM;
-+              mmc_request_done(mmc, mrq);
-+              return;
++      err = tnc_prev(c, &znode, n);
++      if (err == -ENOENT) {
++              *n = -1;
++              dbg_tnc("found 0, lvl %d, n -1", znode->level);
++              return 0;
++      }
++      if (unlikely(err < 0))
++              return err;
++      if (keys_cmp(c, key, &znode->zbranch[*n].key)) {
++              *n = -1;
++              dbg_tnc("found 0, lvl %d, n -1", znode->level);
++              return 0;
 +      }
 +
-+      host->mrq = mrq;
-+      host->pending_events = 0;
-+      host->completed_events = 0;
++      if (znode->cnext || !ubifs_zn_dirty(znode)) {
++              znode = dirty_cow_bottom_up(c, znode);
++              if (IS_ERR(znode))
++                      return PTR_ERR(znode);
++      }
 +
-+      iflags = MCI_BIT(CMDRDY);
-+      cmdflags = atmci_prepare_command(mmc, mrq->cmd);
++      dbg_tnc("found 1, lvl %d, n %d", znode->level, *n);
++      *zn = znode;
++      return 1;
++}
 +
-+      if (mrq->stop) {
-+              WARN_ON(!data);
++/**
++ * ubifs_tnc_lookup - look up a file-system node.
++ * @c: UBIFS file-system description object
++ * @key: node key to lookup
++ * @node: the node is returned here
++ *
++ * This function look up and reads node with key @key. The caller has to make
++ * sure the @node buffer is large enough to fit the node. Returns zero in case
++ * of success, %-ENOENT if the node was not found, and a negative error code in
++ * case of failure.
++ */
++int ubifs_tnc_lookup(struct ubifs_info *c, const union ubifs_key *key,
++                   void *node)
++{
++      int found, n, err;
++      struct ubifs_znode *znode;
++      struct ubifs_zbranch zbr, *zt;
 +
-+              host->stop_cmdr = atmci_prepare_command(mmc, mrq->stop);
-+              host->stop_cmdr |= MCI_BF(TRCMD, MCI_TRCMD_STOP_TRANS);
-+              if (!(data->flags & MMC_DATA_WRITE))
-+                      host->stop_cmdr |= MCI_BIT(TRDIR);
-+              if (data->flags & MMC_DATA_STREAM)
-+                      host->stop_cmdr |= MCI_BF(TRTYP, MCI_TRTYP_STREAM);
-+              else
-+                      host->stop_cmdr |= MCI_BF(TRTYP, MCI_TRTYP_MULTI_BLOCK);
++      mutex_lock(&c->tnc_mutex);
++      found = ubifs_lookup_level0(c, key, &znode, &n);
++      if (!found) {
++              err = -ENOENT;
++              goto out;
++      } else if (found < 0) {
++              err = found;
++              goto out;
 +      }
-+      if (data) {
-+              cmdflags |= atmci_prepare_data(mmc, data);
-+              iflags |= MCI_DATA_ERROR_FLAGS;
++      zt = &znode->zbranch[n];
++      if (is_hash_key(c, key)) {
++              /*
++               * In this case the leaf node cache gets used, so we pass the
++               * address of the zbranch and keep the mutex locked
++               */
++              err = tnc_read_node_nm(c, zt, node);
++              goto out;
 +      }
++      zbr = znode->zbranch[n];
++      mutex_unlock(&c->tnc_mutex);
 +
-+      atmci_start_command(host, mrq->cmd, cmdflags);
-+      mci_writel(host, IER, iflags);
++      err = ubifs_tnc_read_node(c, &zbr, node);
++      return err;
++
++out:
++      mutex_unlock(&c->tnc_mutex);
++      return err;
 +}
 +
-+static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
++/**
++ * ubifs_tnc_locate - look up a file-system node and return it and its location.
++ * @c: UBIFS file-system description object
++ * @key: node key to lookup
++ * @node: the node is returned here
++ * @lnum: LEB number is returned here
++ * @offs: offset is returned here
++ *
++ * This function is the same as 'ubifs_tnc_lookup()' but it returns the node
++ * location also. See 'ubifs_tnc_lookup()'.
++ */
++int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
++                   void *node, int *lnum, int *offs)
 +{
-+      struct atmel_mci *host = mmc_priv(mmc);
-+      u32 mr;
++      int found, n, err;
++      struct ubifs_znode *znode;
++      struct ubifs_zbranch zbr, *zt;
 +
-+      if (ios->clock) {
-+              u32 clkdiv;
++      mutex_lock(&c->tnc_mutex);
++      found = ubifs_lookup_level0(c, key, &znode, &n);
++      if (!found) {
++              err = -ENOENT;
++              goto out;
++      } else if (found < 0) {
++              err = found;
++              goto out;
++      }
++      zt = &znode->zbranch[n];
++      if (is_hash_key(c, key)) {
++              /*
++               * In this case the leaf node cache gets used, so we pass the
++               * address of the zbranch and keep the mutex locked
++               */
++              *lnum = zt->lnum;
++              *offs = zt->offs;
++              err = tnc_read_node_nm(c, zt, node);
++              goto out;
++      }
++      zbr = znode->zbranch[n];
++      mutex_unlock(&c->tnc_mutex);
 +
-+              /* Set clock rate */
-+              clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * ios->clock) - 1;
-+              if (clkdiv > 255) {
-+                      dev_warn(&mmc->class_dev,
-+                              "clock %u too slow; using %lu\n",
-+                              ios->clock, host->bus_hz / (2 * 256));
-+                      clkdiv = 255;
-+              }
++      *lnum = zbr.lnum;
++      *offs = zbr.offs;
 +
-+              mr = mci_readl(host, MR);
-+              mr = MCI_BFINS(CLKDIV, clkdiv, mr)
-+                      | MCI_BIT(WRPROOF) | MCI_BIT(RDPROOF);
-+              mci_writel(host, MR, mr);
++      err = ubifs_tnc_read_node(c, &zbr, node);
++      return err;
 +
-+              /* Enable the MCI controller */
-+              mci_writel(host, CR, MCI_BIT(MCIEN));
-+      } else {
-+              /* Disable the MCI controller */
-+              mci_writel(host, CR, MCI_BIT(MCIDIS));
-+      }
++out:
++      mutex_unlock(&c->tnc_mutex);
++      return err;
++}
 +
-+      switch (ios->bus_width) {
-+      case MMC_BUS_WIDTH_1:
-+              mci_writel(host, SDCR, 0);
-+              break;
-+      case MMC_BUS_WIDTH_4:
-+              mci_writel(host, SDCR, MCI_BIT(SDCBUS));
-+              break;
++/**
++ * do_lookup_nm- look up a "hashed" node.
++ * directory entry file-system node.
++ * @c: UBIFS file-system description object
++ * @key: node key to lookup
++ * @node: the node is returned here
++ * @nm: node name
++ *
++ * This function look up and reads a node which contains name hash in the key.
++ * Since the hash may have collisions, there may be many nodes with the same
++ * key, so we have to sequentially look to all of them until the needed one is
++ * found. This function returns zero in case of success, %-ENOENT if the node
++ * was not found, and a negative error code in case of failure.
++ */
++static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
++                      void *node, const struct qstr *nm)
++{
++      int found, n, err;
++      struct ubifs_znode *znode;
++      struct ubifs_zbranch zbr;
++
++      dbg_tnc("name '%.*s' key %s", nm->len, nm->name, DBGKEY(key));
++      mutex_lock(&c->tnc_mutex);
++      found = ubifs_lookup_level0(c, key, &znode, &n);
++      if (!found) {
++              err = -ENOENT;
++              goto out_unlock;
++      } else if (found < 0) {
++              err = found;
++              goto out_unlock;
 +      }
 +
-+      switch (ios->power_mode) {
-+      case MMC_POWER_ON:
-+              /* Send init sequence (74 clock cycles) */
-+              mci_writel(host, IDR, ~0UL);
-+              mci_writel(host, CMDR, MCI_BF(SPCMD, MCI_SPCMD_INIT_CMD));
-+              while (!(mci_readl(host, SR) & MCI_BIT(CMDRDY)))
-+                      cpu_relax();
-+              break;
-+      default:
-+              /*
-+               * TODO: None of the currently available AVR32-based
-+               * boards allow MMC power to be turned off. Implement
-+               * power control when this can be tested properly.
-+               */
-+              break;
++      ubifs_assert(n >= 0);
++
++      err = resolve_collision(c, key, &znode, &n, nm);
++      dbg_tnc("rc returned %d, znode %p, n %d", err, znode, n);
++      if (unlikely(err < 0))
++              goto out_unlock;
++      if (err == 0) {
++              err = -ENOENT;
++              goto out_unlock;
 +      }
-+}
 +
-+static int atmci_get_ro(struct mmc_host *mmc)
-+{
-+      int read_only = 0;
-+      struct atmel_mci *host = mmc_priv(mmc);
++      zbr = znode->zbranch[n];
++      mutex_unlock(&c->tnc_mutex);
 +
-+      if (host->wp_pin >= 0) {
-+              read_only = gpio_get_value(host->wp_pin);
-+              dev_dbg(&mmc->class_dev, "card is %s\n",
-+                              read_only ? "read-only" : "read-write");
-+      } else {
-+              dev_dbg(&mmc->class_dev,
-+                      "no pin for checking read-only switch."
-+                      " Assuming write-enable.\n");
-+      }
++      err = tnc_read_node_nm(c, &zbr, node);
++      return err;
 +
-+      return read_only;
++out_unlock:
++      mutex_unlock(&c->tnc_mutex);
++      return err;
 +}
 +
-+static struct mmc_host_ops atmci_ops = {
-+      .request        = atmci_request,
-+      .set_ios        = atmci_set_ios,
-+      .get_ro         = atmci_get_ro,
-+};
-+
-+static void atmci_request_end(struct mmc_host *mmc, struct mmc_request *mrq)
++/**
++ * ubifs_tnc_lookup_nm- look up a "hashed" node.
++ * directory entry file-system node.
++ * @c: UBIFS file-system description object
++ * @key: node key to lookup
++ * @node: the node is returned here
++ * @nm: node name
++ *
++ * This function look up and reads a node which contains name hash in the key.
++ * Since the hash may have collisions, there may be many nodes with the same
++ * key, so we have to sequentially look to all of them until the needed one is
++ * found. This function returns zero in case of success, %-ENOENT if the node
++ * was not found, and a negative error code in case of failure.
++ */
++int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
++                      void *node, const struct qstr *nm)
 +{
-+      struct atmel_mci *host = mmc_priv(mmc);
++      int err, len;
++      const struct ubifs_dent_node *dent = node;
++
++      /*
++       * We assume that in most of the cases there are no name collisions and
++       * 'ubifs_tnc_lookup()' returns us the right direntry.
++       */
++      err = ubifs_tnc_lookup(c, key, node);
++      if (err)
++              return err;
 +
-+      WARN_ON(host->cmd || host->data);
-+      host->mrq = NULL;
++      len = le16_to_cpu(dent->nlen);
++      if (nm->len == len && !memcmp(dent->name, nm->name, len))
++              return 0;
 +
-+      mmc_request_done(mmc, mrq);
++      /*
++       * Unluckily, there are hash collisions and we have to iterate over
++       * them look at each direntry with colliding name hash sequentially.
++       */
++      return do_lookup_nm(c, key, node, nm);
 +}
 +
-+static void send_stop_cmd(struct mmc_host *mmc, struct mmc_data *data,
-+                        u32 flags)
++/**
++ * correct_parent_keys - correct parent znodes' keys.
++ * @c: UBIFS file-system description object
++ * @znode: znode to correct parent znodes for
++ *
++ * This is a helper function for 'tnc_insert()'. When the key of the leftmost
++ * zbranch changes, keys of parent znodes have to be corrected. This helper
++ * function is called in such situations and corrects the keys if needed.
++ */
++static void correct_parent_keys(const struct ubifs_info *c,
++                              struct ubifs_znode *znode)
 +{
-+      struct atmel_mci *host = mmc_priv(mmc);
++      union ubifs_key *key, *key1;
 +
-+      atmci_start_command(host, data->stop, host->stop_cmdr | flags);
-+      mci_writel(host, IER, MCI_BIT(CMDRDY));
++      ubifs_assert(znode->parent);
++      ubifs_assert(znode->iip == 0);
++
++      key = &znode->zbranch[0].key;
++      key1 = &znode->parent->zbranch[0].key;
++
++      while (keys_cmp(c, key, key1) < 0) {
++              key_copy(c, key, key1);
++              znode = znode->parent;
++              if (!znode->parent || znode->iip)
++                      break;
++              key1 = &znode->parent->zbranch[0].key;
++      }
 +}
 +
-+static void atmci_data_complete(struct atmel_mci *host, struct mmc_data *data)
++/**
++ * insert_zbranch - insert a zbranch into a znode.
++ * @znode: znode into which to insert
++ * @zbr: zbranch to insert
++ * @n: slot number to insert to
++ *
++ * This is a helper function for 'tnc_insert()'. UBIFS does not allow "gaps" in
++ * znode's array of zbranches and keeps zbranches consolidated, so when a new
++ * zbranch has to be inserted to the @znode->zbranches[]' array at the @n-th
++ * slot, zbranches starting from @n have to be moved right.
++ */
++static void insert_zbranch(struct ubifs_znode *znode,
++                         const struct ubifs_zbranch *zbr, int n)
 +{
-+      host->data = NULL;
-+      dma_unmap_sg(&host->pdev->dev, data->sg, host->dma.req.nr_sg,
-+                   ((data->flags & MMC_DATA_WRITE)
-+                    ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
++      int i;
++
++      ubifs_assert(ubifs_zn_dirty(znode));
++
++      if (znode->level) {
++              for (i = znode->child_cnt; i > n; i--) {
++                      znode->zbranch[i] = znode->zbranch[i - 1];
++                      if (znode->zbranch[i].znode)
++                              znode->zbranch[i].znode->iip = i;
++              }
++              if (zbr->znode)
++                      zbr->znode->iip = n;
++      } else
++              for (i = znode->child_cnt; i > n; i--)
++                      znode->zbranch[i] = znode->zbranch[i - 1];
++
++      znode->zbranch[n] = *zbr;
++      znode->child_cnt += 1;
 +
 +      /*
-+       * Data might complete before command for very short transfers
-+       * (like READ_SCR)
++       * After inserting at slot zero, the lower bound of the key range of
++       * this znode may have changed. If this znode is subsequently split
++       * then the upper bound of the key range may change, and furthermore
++       * it could change to be lower than the original lower bound. If that
++       * happens, then it will no longer be possible to find this znode in the
++       * TNC using the key from the index node on flash. That is bad because
++       * if it is not found, we will assume it is obsolete and may overwrite
++       * it. Then if there is an unclean unmount, we will start using the
++       * old index which will be broken.
++       *
++       * So we first mark znodes that have insertions at slot zero, and then
++       * if they are split we add their lnum/offs to the old_idx tree.
 +       */
-+      if (mci_cmd_is_complete(host)
-+          && (!data->stop || mci_stop_is_complete(host)))
-+              atmci_request_end(host->mmc, data->mrq);
++      if (n == 0)
++              znode->alt = 1;
 +}
 +
-+static void atmci_command_complete(struct atmel_mci *host,
-+                      struct mmc_command *cmd, u32 status)
++/**
++ * tnc_insert - insert a node into TNC.
++ * @c: UBIFS file-system description object
++ * @znode: znode to insert into
++ * @zbr: branch to insert
++ * @n: slot number to insert new zbranch to
++ *
++ * This function inserts a new node described by @zbr into znode @znode. If
++ * znode does not have a free slot for new zbranch, it is split. Parent znodes
++ * are splat as well if needed. Returns zero in case of success or a negative
++ * error code in case of failure.
++ */
++static int tnc_insert(struct ubifs_info *c, struct ubifs_znode *znode,
++                    struct ubifs_zbranch *zbr, int n)
 +{
-+      if (status & MCI_BIT(RTOE))
-+              cmd->error = -ETIMEDOUT;
-+      else if ((cmd->flags & MMC_RSP_CRC)
-+                      && (status & MCI_BIT(RCRCE)))
-+              cmd->error = -EILSEQ;
-+      else if (status & (MCI_BIT(RINDE) | MCI_BIT(RDIRE) | MCI_BIT(RENDE)))
-+              cmd->error = -EIO;
++      struct ubifs_znode *zn, *zi, *zp;
++      int i, keep, move, appending = 0;
++      union ubifs_key *key = &zbr->key;
 +
-+      if (cmd->error) {
-+              dev_dbg(&host->mmc->class_dev,
-+                              "command error: op=0x%x status=0x%08x\n",
-+                              cmd->opcode, status);
++      ubifs_assert(n >= 0 && n <= c->fanout);
 +
-+              if (cmd->data) {
-+                      dma_stop_request(host->dma.req.req.dmac,
-+                                      host->dma.req.req.channel);
-+                      mci_writel(host, IDR, MCI_BIT(NOTBUSY)
-+                                      | MCI_DATA_ERROR_FLAGS);
-+                      host->data = NULL;
-+              }
-+      }
-+}
++      /* Implement naive insert for now */
++again:
++      zp = znode->parent;
++      if (znode->child_cnt < c->fanout) {
++              ubifs_assert(n != c->fanout);
++              dbg_tnc("inserted at %d level %d, key %s", n, znode->level,
++                      DBGKEY(key));
 +
-+static void atmci_detect_change(unsigned long data)
-+{
-+      struct atmel_mci *host = (struct atmel_mci *)data;
-+      struct mmc_request *mrq = host->mrq;
-+      int present;
++              insert_zbranch(znode, zbr, n);
++
++              /* Ensure parent's key is correct */
++              if (n == 0 && zp && znode->iip == 0)
++                      correct_parent_keys(c, znode);
++
++              return 0;
++      }
 +
 +      /*
-+       * atmci_remove() sets detect_pin to -1 before freeing the
-+       * interrupt. We must not re-enable the interrupt if it has
-+       * been freed.
++       * Unfortunately, @znode does not have more empty slots and we have to
++       * split it.
 +       */
-+      smp_rmb();
-+      if (host->detect_pin < 0)
-+              return;
++      dbg_tnc("splitting level %d, key %s", znode->level, DBGKEY(key));
 +
-+      enable_irq(gpio_to_irq(host->detect_pin));
-+      present = !gpio_get_value(host->detect_pin);
++      if (znode->alt)
++              /*
++               * We can no longer be sure of finding this znode by key, so we
++               * record it in the old_idx tree.
++               */
++              ins_clr_old_idx_znode(c, znode);
 +
-+      dev_vdbg(&host->pdev->dev, "detect change: %d (was %d)\n",
-+                      present, host->present);
++      zn = kzalloc(c->max_znode_sz, GFP_NOFS);
++      if (!zn)
++              return -ENOMEM;
++      zn->parent = zp;
++      zn->level = znode->level;
 +
-+      if (present != host->present) {
-+              dev_dbg(&host->mmc->class_dev, "card %s\n",
-+                      present ? "inserted" : "removed");
-+              host->present = present;
++      /* Decide where to split */
++      if (znode->level == 0 && n == c->fanout &&
++          key_type(c, key) == UBIFS_DATA_KEY) {
++              union ubifs_key *key1;
 +
-+              /* Reset controller if card is gone */
-+              if (!present) {
-+                      mci_writel(host, CR, MCI_BIT(SWRST));
-+                      mci_writel(host, IDR, ~0UL);
-+                      mci_writel(host, CR, MCI_BIT(MCIEN));
-+              }
++              /*
++               * If this is an inode which is being appended - do not split
++               * it because no other zbranches can be inserted between
++               * zbranches of consecutive data nodes anyway.
++               */
++              key1 = &znode->zbranch[n - 1].key;
++              if (key_inum(c, key1) == key_inum(c, key) &&
++                  key_type(c, key1) == UBIFS_DATA_KEY &&
++                  key_block(c, key1) == key_block(c, key) - 1)
++                      appending = 1;
++      }
 +
-+              /* Clean up queue if present */
-+              if (mrq) {
-+                      if (!mci_cmd_is_complete(host))
-+                              mrq->cmd->error = -ENOMEDIUM;
-+                      if (mrq->data && !mci_data_is_complete(host)
-+                          && !mci_data_error_is_complete(host)) {
-+                              dma_stop_request(host->dma.req.req.dmac,
-+                                              host->dma.req.req.channel);
-+                              host->data->error = -ENOMEDIUM;
-+                              atmci_data_complete(host, host->data);
-+                      }
-+                      if (mrq->stop && !mci_stop_is_complete(host))
-+                              mrq->stop->error = -ENOMEDIUM;
++      if (appending) {
++              keep = c->fanout;
++              move = 0;
++      } else {
++              keep = (c->fanout + 1) / 2;
++              move = c->fanout - keep;
++      }
 +
-+                      host->cmd = NULL;
-+                      atmci_request_end(host->mmc, mrq);
-+              }
++      /*
++       * Although we don't at present, we could look at the neighbors and see
++       * if we can move some zbranches there.
++       */
 +
-+              mmc_detect_change(host->mmc, 0);
++      if (n < keep) {
++              /* Insert into existing znode */
++              zi = znode;
++              move += 1;
++              keep -= 1;
++      } else {
++              /* Insert into new znode */
++              zi = zn;
++              n -= keep;
++              /* Re-parent */
++              if (zn->level != 0)
++                      zbr->znode->parent = zn;
 +      }
-+}
 +
-+static void atmci_tasklet_func(unsigned long priv)
-+{
-+      struct mmc_host *mmc = (struct mmc_host *)priv;
-+      struct atmel_mci *host = mmc_priv(mmc);
-+      struct mmc_request *mrq = host->mrq;
-+      struct mmc_data *data = host->data;
++      __set_bit(DIRTY_ZNODE, &zn->flags);
++      atomic_long_inc(&c->dirty_zn_cnt);
 +
-+      dev_vdbg(&mmc->class_dev,
-+              "tasklet: pending/completed/mask %lx/%lx/%x\n",
-+               host->pending_events, host->completed_events,
-+               mci_readl(host, IMR));
++      zn->child_cnt = move;
++      znode->child_cnt = keep;
 +
-+      if (mci_clear_cmd_is_pending(host)) {
-+              mci_set_cmd_complete(host);
-+              atmci_command_complete(host, mrq->cmd, host->cmd_status);
-+              if (!host->data || mci_data_is_complete(host)
-+                  || mci_data_error_is_complete(host))
-+                      atmci_request_end(mmc, mrq);
-+      }
-+      if (mci_clear_stop_is_pending(host)) {
-+              mci_set_stop_complete(host);
-+              atmci_command_complete(host, mrq->stop, host->stop_status);
-+              if (mci_data_is_complete(host)
-+                  || mci_data_error_is_complete(host))
-+                      atmci_request_end(mmc, mrq);
++      dbg_tnc("moving %d, keeping %d", move, keep);
++
++      /* Move zbranch */
++      for (i = 0; i < move; i++) {
++              zn->zbranch[i] = znode->zbranch[keep + i];
++              /* Re-parent */
++              if (zn->level != 0)
++                      if (zn->zbranch[i].znode) {
++                              zn->zbranch[i].znode->parent = zn;
++                              zn->zbranch[i].znode->iip = i;
++                      }
 +      }
-+      if (mci_clear_dma_error_is_pending(host)) {
-+              mci_set_dma_error_complete(host);
-+              mci_clear_data_pending(host);
 +
-+              /* DMA controller got bus error => invalid address */
-+              data->error = -EIO;
++      /* Insert new key and branch */
++      dbg_tnc("inserting at %d level %d, key %s", n, zn->level, DBGKEY(key));
 +
-+              dev_dbg(&mmc->class_dev, "dma error after %u bytes xfered\n",
-+                              host->data->bytes_xfered);
++      insert_zbranch(zi, zbr, n);
 +
-+              if (data->stop
-+                  && !mci_set_stop_sent_is_completed(host))
-+                      /* TODO: Check if card is still present */
-+                      send_stop_cmd(host->mmc, data, 0);
++      /* Insert new znode (produced by spitting) into the parent */
++      if (zp) {
++              i = n;
++              /* Locate insertion point */
++              n = znode->iip + 1;
++              if (appending && n != c->fanout)
++                      appending = 0;
 +
-+              atmci_data_complete(host, data);
++              if (i == 0 && zi == znode && znode->iip == 0)
++                      correct_parent_keys(c, znode);
++
++              /* Tail recursion */
++              zbr->key = zn->zbranch[0].key;
++              zbr->znode = zn;
++              zbr->lnum = 0;
++              zbr->offs = 0;
++              zbr->len = 0;
++              znode = zp;
++
++              goto again;
 +      }
-+      if (mci_clear_data_error_is_pending(host)) {
-+              u32 status = host->data_status;
 +
-+              mci_set_data_error_complete(host);
-+              mci_clear_data_pending(host);
++      /* We have to split root znode */
++      dbg_tnc("creating new zroot at level %d", znode->level + 1);
 +
-+              dma_stop_request(host->dma.req.req.dmac,
-+                               host->dma.req.req.channel);
++      zi = kzalloc(c->max_znode_sz, GFP_NOFS);
++      if (!zi)
++              return -ENOMEM;
 +
-+              if (status & MCI_BIT(DCRCE)) {
-+                      dev_dbg(&mmc->class_dev, "data CRC error\n");
-+                      data->error = -EILSEQ;
-+              } else if (status & MCI_BIT(DTOE)) {
-+                      dev_dbg(&mmc->class_dev, "data timeout error\n");
-+                      data->error = -ETIMEDOUT;
-+              } else {
-+                      dev_dbg(&mmc->class_dev, "data FIFO error\n");
-+                      data->error = -EIO;
-+              }
-+              dev_dbg(&mmc->class_dev, "bytes xfered: %u\n",
-+                              data->bytes_xfered);
++      zi->child_cnt = 2;
++      zi->level = znode->level + 1;
 +
-+              if (data->stop
-+                  && !mci_set_stop_sent_is_completed(host))
-+                      /* TODO: Check if card is still present */
-+                      send_stop_cmd(host->mmc, data, 0);
++      __set_bit(DIRTY_ZNODE, &zi->flags);
++      atomic_long_inc(&c->dirty_zn_cnt);
 +
-+              atmci_data_complete(host, data);
-+      }
-+      if (mci_clear_data_is_pending(host)) {
-+              mci_set_data_complete(host);
-+              data->bytes_xfered = data->blocks * data->blksz;
-+              atmci_data_complete(host, data);
-+      }
++      zi->zbranch[0].key = znode->zbranch[0].key;
++      zi->zbranch[0].znode = znode;
++      zi->zbranch[0].lnum = c->zroot.lnum;
++      zi->zbranch[0].offs = c->zroot.offs;
++      zi->zbranch[0].len = c->zroot.len;
++      zi->zbranch[1].key = zn->zbranch[0].key;
++      zi->zbranch[1].znode = zn;
++
++      c->zroot.lnum = 0;
++      c->zroot.offs = 0;
++      c->zroot.len = 0;
++      c->zroot.znode = zi;
++
++      zn->parent = zi;
++      zn->iip = 1;
++      znode->parent = zi;
++      znode->iip = 0;
++
++      return 0;
 +}
 +
-+static void atmci_cmd_interrupt(struct mmc_host *mmc, u32 status)
-+{
-+      struct atmel_mci *host = mmc_priv(mmc);
-+      struct mmc_command *cmd = host->cmd;
++/**
++ * ubifs_tnc_add - add a node to TNC.
++ * @c: UBIFS file-system description object
++ * @key: key to add
++ * @lnum: LEB number of node
++ * @offs: node offset
++ * @len: node length
++ *
++ * This function adds a node with key @key to TNC. The node may be new or it may
++ * obsolete some existing one. Returns %0 on success or negative error code on
++ * failure.
++ */
++int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
++                int offs, int len)
++{
++      int found, n, err = 0;
++      struct ubifs_znode *znode;
++
++      mutex_lock(&c->tnc_mutex);
++      dbg_tnc("%d:%d, len %d, key %s", lnum, offs, len, DBGKEY(key));
++      found = lookup_level0_dirty(c, key, &znode, &n);
++      if (!found) {
++              struct ubifs_zbranch zbr;
++
++              zbr.znode = NULL;
++              zbr.lnum = lnum;
++              zbr.offs = offs;
++              zbr.len = len;
++              key_copy(c, key, &zbr.key);
++              err = tnc_insert(c, znode, &zbr, n + 1);
++      } else if (found == 1) {
++              struct ubifs_zbranch *zbr = &znode->zbranch[n];
++
++              lnc_free(zbr);
++              err = ubifs_add_dirt(c, zbr->lnum, zbr->len);
++              zbr->lnum = lnum;
++              zbr->offs = offs;
++              zbr->len = len;
++      } else
++              err = found;
++      if (!err)
++              err = dbg_check_tnc(c, 0);
++      mutex_unlock(&c->tnc_mutex);
 +
-+      /*
-+       * Read the response now so that we're free to send a new
-+       * command immediately.
-+       */
-+      cmd->resp[0] = mci_readl(host, RSPR);
-+      cmd->resp[1] = mci_readl(host, RSPR);
-+      cmd->resp[2] = mci_readl(host, RSPR);
-+      cmd->resp[3] = mci_readl(host, RSPR);
++      return err;
++}
 +
-+      mci_writel(host, IDR, MCI_BIT(CMDRDY));
-+      host->cmd = NULL;
++/**
++ * ubifs_tnc_replace - replace a node in the TNC only if the old node is found.
++ * @c: UBIFS file-system description object
++ * @key: key to add
++ * @old_lnum: LEB number of old node
++ * @old_offs: old node offset
++ * @lnum: LEB number of node
++ * @offs: node offset
++ * @len: node length
++ *
++ * This function replaces a node with key @key in the TNC only if the old node
++ * is found.  This function is called by garbage collection when node are moved.
++ * Returns %0 on success or negative error code on failure.
++ */
++int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
++                    int old_lnum, int old_offs, int lnum, int offs, int len)
++{
++      int found, n, err = 0;
++      struct ubifs_znode *znode;
++
++      mutex_lock(&c->tnc_mutex);
++      dbg_tnc("old LEB %d:%d, new LEB %d:%d, len %d, key %s", old_lnum,
++              old_offs, lnum, offs, len, DBGKEY(key));
++      found = lookup_level0_dirty(c, key, &znode, &n);
++      if (found < 0) {
++              err = found;
++              goto out_unlock;
++      }
 +
-+      if (mci_stop_sent_is_complete(host)) {
-+              host->stop_status = status;
-+              mci_set_stop_pending(host);
-+      } else {
-+              struct mmc_request *mrq = host->mrq;
++      if (found == 1) {
++              struct ubifs_zbranch *zbr = &znode->zbranch[n];
++
++              found = 0;
++              if (zbr->lnum == old_lnum && zbr->offs == old_offs) {
++                      lnc_free(zbr);
++                      err = ubifs_add_dirt(c, zbr->lnum, zbr->len);
++                      if (err)
++                              goto out_unlock;
++                      zbr->lnum = lnum;
++                      zbr->offs = offs;
++                      zbr->len = len;
++                      found = 1;
++              } else if (is_hash_key(c, key)) {
++                      found = resolve_collision_directly(c, key, &znode, &n,
++                                                         old_lnum, old_offs);
++                      dbg_tnc("rc returned %d, znode %p, n %d, LEB %d:%d",
++                              found, znode, n, old_lnum, old_offs);
++                      if (found < 0) {
++                              err = found;
++                              goto out_unlock;
++                      }
 +
-+              if (mrq->stop && mci_dma_is_complete(host)
-+                              && !mci_set_stop_sent_is_completed(host))
-+                      send_stop_cmd(host->mmc, mrq->data, 0);
-+              host->cmd_status = status;
-+              mci_set_cmd_pending(host);
++                      if (found) {
++                              /* Ensure the znode is dirtied */
++                              if (znode->cnext || !ubifs_zn_dirty(znode)) {
++                                          znode = dirty_cow_bottom_up(c,
++                                                                      znode);
++                                          if (IS_ERR(znode)) {
++                                                  err = PTR_ERR(znode);
++                                                  goto out_unlock;
++                                          }
++                              }
++                              zbr = &znode->zbranch[n];
++                              lnc_free(zbr);
++                              err = ubifs_add_dirt(c, zbr->lnum,
++                                                   zbr->len);
++                              if (err)
++                                      goto out_unlock;
++                              zbr->lnum = lnum;
++                              zbr->offs = offs;
++                              zbr->len = len;
++                      }
++              }
 +      }
 +
-+      tasklet_schedule(&host->tasklet);
++      if (!found)
++              err = ubifs_add_dirt(c, lnum, len);
++
++      if (!err)
++              err = dbg_check_tnc(c, 0);
++
++out_unlock:
++      mutex_unlock(&c->tnc_mutex);
++      return err;
 +}
 +
-+static void atmci_xfer_complete(struct dma_request *_req)
-+{
-+      struct dma_request_sg *req = to_dma_request_sg(_req);
-+      struct atmel_mci_dma *dma;
-+      struct atmel_mci *host;
-+      struct mmc_data *data;
++/**
++ * ubifs_tnc_add_nm - add a "hashed" node to TNC.
++ * @c: UBIFS file-system description object
++ * @key: key to add
++ * @lnum: LEB number of node
++ * @offs: node offset
++ * @len: node length
++ * @nm: node name
++ *
++ * This is the same as 'ubifs_tnc_add()' but it should be used with keys which
++ * may have collisions, like directory entry keys.
++ */
++int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
++                   int lnum, int offs, int len, const struct qstr *nm)
++{
++      int found, n, err = 0;
++      struct ubifs_znode *znode;
++
++      mutex_lock(&c->tnc_mutex);
++      dbg_tnc("LEB %d:%d, name '%.*s', key %s", lnum, offs, nm->len, nm->name,
++              DBGKEY(key));
++      found = lookup_level0_dirty(c, key, &znode, &n);
++      if (found < 0) {
++              err = found;
++              goto out_unlock;
++      }
++
++      if (found == 1) {
++              if (c->replaying)
++                      found = fallible_resolve_collision(c, key, &znode, &n,
++                                                         nm, 1);
++              else
++                      found = resolve_collision(c, key, &znode, &n, nm);
++              dbg_tnc("rc returned %d, znode %p, n %d", found, znode, n);
++              if (found < 0) {
++                      err = found;
++                      goto out_unlock;
++              }
++
++              /* Ensure the znode is dirtied */
++              if (znode->cnext || !ubifs_zn_dirty(znode)) {
++                          znode = dirty_cow_bottom_up(c, znode);
++                          if (IS_ERR(znode)) {
++                                  err = PTR_ERR(znode);
++                                  goto out_unlock;
++                          }
++              }
++
++              if (found == 1) {
++                      struct ubifs_zbranch *zbr = &znode->zbranch[n];
++
++                      lnc_free(zbr);
++                      err = ubifs_add_dirt(c, zbr->lnum, zbr->len);
++                      zbr->lnum = lnum;
++                      zbr->offs = offs;
++                      zbr->len = len;
++                      goto out_unlock;
++              }
++      }
 +
-+      dma = container_of(req, struct atmel_mci_dma, req);
-+      host = container_of(dma, struct atmel_mci, dma);
-+      data = host->data;
++      if (!found) {
++              struct ubifs_zbranch zbr;
++
++              zbr.znode = NULL;
++              zbr.lnum = lnum;
++              zbr.offs = offs;
++              zbr.len = len;
++              key_copy(c, key, &zbr.key);
++              err = tnc_insert(c, znode, &zbr, n + 1);
++              if (err)
++                      goto out_unlock;
++              if (c->replaying && c->replay_sqnum < c->cs_sqnum) {
++                      /*
++                       * This node was moved by garbage collection. We can
++                       * tell because it is in the journal but it has a
++                       * sequence number earlier than the last commit-start.
++                       * We did not find it in the index so there may be a
++                       * dangling branch still in the index. So we remove it
++                       * by passing 'ubifs_tnc_remove_nm()' the same key but
++                       * an unmatchable name.
++                       */
++                      struct qstr noname = { .len = 0, .name = "" };
 +
-+      /*
-+       * This callback may be called before we see the CMDRDY
-+       * interrupt under heavy irq load (possibly caused by other
-+       * drivers) or when interrupts are disabled for a long time.
-+       */
-+      mci_set_dma_complete(host);
-+      if (data->stop && mci_cmd_is_complete(host)
-+                      && !mci_set_stop_sent_is_completed(host))
-+              send_stop_cmd(host->mmc, data, 0);
++                      err = dbg_check_tnc(c, 0);
++                      mutex_unlock(&c->tnc_mutex);
++                      if (err)
++                              return err;
++                      return ubifs_tnc_remove_nm(c, key, &noname);
++              }
++      }
 +
-+      /*
-+       * Regardless of what the documentation says, we have to wait
-+       * for NOTBUSY even after block read operations.
-+       *
-+       * When the DMA transfer is complete, the controller may still
-+       * be reading the CRC from the card, i.e. the data transfer is
-+       * still in progress and we haven't seen all the potential
-+       * error bits yet.
-+       */
-+      mci_writel(host, IER, MCI_BIT(NOTBUSY));
++out_unlock:
++      if (!err)
++              err = dbg_check_tnc(c, 0);
++      mutex_unlock(&c->tnc_mutex);
++      return err;
 +}
 +
-+static void atmci_dma_error(struct dma_request *_req)
++/**
++ * tnc_delete - delete a znode form TNC.
++ * @c: UBIFS file-system description object
++ * @znode: znode to delete from
++ * @n: zbranch slot number to delete
++ *
++ * This function deletes a leaf node from @n-th slot of @znode. Returns zero in
++ * case of success and a negative error code in case of failure.
++ */
++static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
 +{
-+      struct dma_request_sg *req = to_dma_request_sg(_req);
-+      struct atmel_mci_dma *dma;
-+      struct atmel_mci *host;
++      struct ubifs_zbranch *zbr;
++      struct ubifs_znode *zp;
++      int i, err;
 +
-+      dma = container_of(req, struct atmel_mci_dma, req);
-+      host = container_of(dma, struct atmel_mci, dma);
++      /* Delete without merge for now */
++      ubifs_assert(znode->level == 0);
++      ubifs_assert(n >= 0 && n < c->fanout);
++      dbg_tnc("deleting %s", DBGKEY(&znode->zbranch[n].key));
 +
-+      mci_writel(host, IDR, (MCI_BIT(NOTBUSY)
-+                             | MCI_DATA_ERROR_FLAGS));
++      zbr = &znode->zbranch[n];
++      lnc_free(zbr);
 +
-+      mci_set_dma_error_pending(host);
-+      tasklet_schedule(&host->tasklet);
-+}
++      err = ubifs_add_dirt(c, zbr->lnum, zbr->len);
++      if (err) {
++              dbg_dump_znode(c, znode);
++              return err;
++      }
 +
-+static irqreturn_t atmci_interrupt(int irq, void *dev_id)
-+{
-+      struct mmc_host *mmc = dev_id;
-+      struct atmel_mci *host = mmc_priv(mmc);
-+      u32 status, mask, pending;
++      /* We do not "gap" zbranch slots */
++      for (i = n; i < znode->child_cnt - 1; i++)
++              znode->zbranch[i] = znode->zbranch[i + 1];
++      znode->child_cnt -= 1;
 +
-+      spin_lock(&mmc->lock);
++      if (znode->child_cnt > 0)
++              return 0;
 +
-+      status = mci_readl(host, SR);
-+      mask = mci_readl(host, IMR);
-+      pending = status & mask;
++      /*
++       * This was the last zbranch, we have to delete this znode from the
++       * parent.
++       */
 +
 +      do {
-+              if (pending & MCI_DATA_ERROR_FLAGS) {
-+                      mci_writel(host, IDR, (MCI_BIT(NOTBUSY)
-+                                             | MCI_DATA_ERROR_FLAGS));
-+                      host->data_status = status;
-+                      mci_set_data_error_pending(host);
-+                      tasklet_schedule(&host->tasklet);
-+                      break;
-+              }
-+              if (pending & MCI_BIT(CMDRDY))
-+                      atmci_cmd_interrupt(mmc, status);
-+              if (pending & MCI_BIT(NOTBUSY)) {
-+                      mci_writel(host, IDR, (MCI_BIT(NOTBUSY)
-+                                             | MCI_DATA_ERROR_FLAGS));
-+                      mci_set_data_pending(host);
-+                      tasklet_schedule(&host->tasklet);
-+              }
++              ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags));
++              ubifs_assert(ubifs_zn_dirty(znode));
 +
-+              status = mci_readl(host, SR);
-+              mask = mci_readl(host, IMR);
-+              pending = status & mask;
-+      } while (pending);
++              zp = znode->parent;
++              n = znode->iip;
 +
-+      spin_unlock(&mmc->lock);
++              atomic_long_dec(&c->dirty_zn_cnt);
 +
-+      return IRQ_HANDLED;
-+}
++              err = insert_old_idx_znode(c, znode);
++              if (err)
++                      return err;
 +
-+static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
-+{
-+      struct mmc_host *mmc = dev_id;
-+      struct atmel_mci *host = mmc_priv(mmc);
++              if (znode->cnext) {
++                      __set_bit(OBSOLETE_ZNODE, &znode->flags);
++                      atomic_long_inc(&c->clean_zn_cnt);
++                      atomic_long_inc(&ubifs_clean_zn_cnt);
++              } else
++                      kfree(znode);
++              znode = zp;
++      } while (znode->child_cnt == 1); /* while removing last child */
++
++      /* Remove from znode, entry n - 1 */
++      znode->child_cnt -= 1;
++      ubifs_assert(znode->level != 0);
++      for (i = n; i < znode->child_cnt; i++) {
++              znode->zbranch[i] = znode->zbranch[i + 1];
++              if (znode->zbranch[i].znode)
++                      znode->zbranch[i].znode->iip = i;
++      }
 +
 +      /*
-+       * Disable interrupts until the pin has stabilized and check
-+       * the state then. Use mod_timer() since we may be in the
-+       * middle of the timer routine when this interrupt triggers.
++       * If this is the root and it has only 1 child then
++       * collapse the tree.
 +       */
-+      disable_irq_nosync(irq);
-+      mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(20));
++      if (!znode->parent) {
++              while (znode->child_cnt == 1 && znode->level != 0) {
++                      zp = znode;
++                      zbr = &znode->zbranch[0];
++                      znode = get_znode(c, znode, 0);
++                      if (IS_ERR(znode))
++                              return PTR_ERR(znode);
++                      znode = dirty_cow_znode(c, zbr);
++                      if (IS_ERR(znode))
++                              return PTR_ERR(znode);
++                      znode->parent = NULL;
++                      znode->iip = 0;
++                      if (c->zroot.len) {
++                              err = insert_old_idx(c, c->zroot.lnum,
++                                                   c->zroot.offs);
++                              if (err)
++                                      return err;
++                      }
++                      c->zroot.lnum = zbr->lnum;
++                      c->zroot.offs = zbr->offs;
++                      c->zroot.len = zbr->len;
++                      c->zroot.znode = znode;
++                      ubifs_assert(!test_bit(OBSOLETE_ZNODE,
++                                   &zp->flags));
++                      ubifs_assert(test_bit(DIRTY_ZNODE, &zp->flags));
++                      atomic_long_dec(&c->dirty_zn_cnt);
++
++                      if (zp->cnext) {
++                              __set_bit(OBSOLETE_ZNODE, &zp->flags);
++                              atomic_long_inc(&c->clean_zn_cnt);
++                              atomic_long_inc(&ubifs_clean_zn_cnt);
++                      } else
++                              kfree(zp);
++              }
++      }
 +
-+      return IRQ_HANDLED;
++      return 0;
 +}
 +
-+static int __devinit atmci_probe(struct platform_device *pdev)
++/**
++ * ubifs_tnc_remove - remove an index entry of a node.
++ * @c: UBIFS file-system description object
++ * @key: key of node
++ *
++ * Returns %0 on success or negative error code on failure.
++ */
++int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key)
 +{
-+      struct mci_platform_data *board;
-+      struct atmel_mci *host;
-+      struct mmc_host *mmc;
-+      struct resource *regs;
-+      int irq;
-+      int ret;
++      int found, n, err = 0;
++      struct ubifs_znode *znode;
 +
-+      regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      if (!regs)
-+              return -ENXIO;
-+      irq = platform_get_irq(pdev, 0);
-+      if (irq < 0)
-+              return irq;
++      mutex_lock(&c->tnc_mutex);
++      dbg_tnc("key %s", DBGKEY(key));
++      found = lookup_level0_dirty(c, key, &znode, &n);
++      if (found < 0) {
++              err = found;
++              goto out_unlock;
++      }
++      if (found == 1)
++              err = tnc_delete(c, znode, n);
++      if (!err)
++              err = dbg_check_tnc(c, 0);
 +
-+      board = pdev->dev.platform_data;
++out_unlock:
++      mutex_unlock(&c->tnc_mutex);
++      return err;
++}
 +
-+      mmc = mmc_alloc_host(sizeof(struct atmel_mci), &pdev->dev);
-+      if (!mmc)
-+              return -ENOMEM;
++/**
++ * ubifs_tnc_remove_nm - remove an index entry for a "hashed" node.
++ * @c: UBIFS file-system description object
++ * @key: key of node
++ * @nm: directory entry name
++ *
++ * Returns %0 on success or negative error code on failure.
++ */
++int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
++                      const struct qstr *nm)
++{
++      int n, err;
++      struct ubifs_znode *znode;
 +
-+      host = mmc_priv(mmc);
-+      host->pdev = pdev;
-+      host->mmc = mmc;
-+      if (board) {
-+              host->detect_pin = board->detect_pin;
-+              host->wp_pin = board->wp_pin;
-+      } else {
-+              host->detect_pin = -1;
-+              host->wp_pin = -1;
++      mutex_lock(&c->tnc_mutex);
++      dbg_tnc("%.*s, key %s", nm->len, nm->name, DBGKEY(key));
++      err = lookup_level0_dirty(c, key, &znode, &n);
++      if (err < 0)
++              goto out_unlock;
++
++      if (err) {
++              if (c->replaying)
++                      err = fallible_resolve_collision(c, key, &znode, &n,
++                                                       nm, 0);
++              else
++                      err = resolve_collision(c, key, &znode, &n, nm);
++              dbg_tnc("rc returned %d, znode %p, n %d", err, znode, n);
++              if (err < 0)
++                      goto out_unlock;
++              if (err) {
++                      /* Ensure the znode is dirtied */
++                      if (znode->cnext || !ubifs_zn_dirty(znode)) {
++                                  znode = dirty_cow_bottom_up(c, znode);
++                                  if (IS_ERR(znode)) {
++                                          err = PTR_ERR(znode);
++                                          goto out_unlock;
++                                  }
++                      }
++                      err = tnc_delete(c, znode, n);
++              }
 +      }
 +
-+      host->mck = clk_get(&pdev->dev, "mci_clk");
-+      if (IS_ERR(host->mck)) {
-+              ret = PTR_ERR(host->mck);
-+              goto out_free_host;
++out_unlock:
++      if (!err)
++              err = dbg_check_tnc(c, 0);
++      mutex_unlock(&c->tnc_mutex);
++      return err;
++}
++
++/**
++ * key_in_range - determine if a key falls within a range of keys.
++ * @c: UBIFS file-system description object
++ * @key: key to check
++ * @from_key: lowest key in range
++ * @to_key: highest key in range
++ *
++ * This function returns %1 if the key is in range and %0 otherwise.
++ */
++static int key_in_range(struct ubifs_info *c, union ubifs_key *key,
++                      union ubifs_key *from_key, union ubifs_key *to_key)
++{
++      if (keys_cmp(c, key, from_key) < 0)
++              return 0;
++      if (keys_cmp(c, key, to_key) > 0)
++              return 0;
++      return 1;
++}
++
++/**
++ * ubifs_tnc_remove_range - remove index entries in range.
++ * @c: UBIFS file-system description object
++ * @from_key: lowest key to remove
++ * @to_key: highest key to remove
++ *
++ * This function removes index entries starting at @from_key and ending at
++ * @to_key.  This function returns zero in case of success and a negative error
++ * code in case of failure.
++ */
++int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
++                         union ubifs_key *to_key)
++{
++      int i, n, k, err = 0;
++      struct ubifs_znode *znode;
++      union ubifs_key *key;
++
++      mutex_lock(&c->tnc_mutex);
++      while (1) {
++              /* Find first level 0 znode that contains keys to remove */
++              err = ubifs_lookup_level0(c, from_key, &znode, &n);
++              if (err < 0)
++                      goto out_unlock;
++
++              if (err)
++                      key = from_key;
++              else {
++                      err = tnc_next(c, &znode, &n);
++                      if (err == -ENOENT) {
++                              err = 0;
++                              goto out_unlock;
++                      }
++                      if (err < 0)
++                              goto out_unlock;
++                      key = &znode->zbranch[n].key;
++                      if (!key_in_range(c, key, from_key, to_key)) {
++                              err = 0;
++                              goto out_unlock;
++                      }
++              }
++
++              /* Ensure the znode is dirtied */
++              if (znode->cnext || !ubifs_zn_dirty(znode)) {
++                          znode = dirty_cow_bottom_up(c, znode);
++                          if (IS_ERR(znode)) {
++                                  err = PTR_ERR(znode);
++                                  goto out_unlock;
++                          }
++              }
++
++              /* Remove all keys in range except the first */
++              for (i = n + 1, k = 0; i < znode->child_cnt; i++, k++) {
++                      key = &znode->zbranch[i].key;
++                      if (!key_in_range(c, key, from_key, to_key))
++                              break;
++                      lnc_free(&znode->zbranch[i]);
++                      err = ubifs_add_dirt(c, znode->zbranch[i].lnum,
++                                           znode->zbranch[i].len);
++                      if (err) {
++                              dbg_dump_znode(c, znode);
++                              goto out_unlock;
++                      }
++                      dbg_tnc("removing %s", DBGKEY(key));
++              }
++              if (k) {
++                      for (i = n + 1 + k; i < znode->child_cnt; i++)
++                              znode->zbranch[i - k] = znode->zbranch[i];
++                      znode->child_cnt -= k;
++              }
++
++              /* Now delete the first */
++              err = tnc_delete(c, znode, n);
++              if (err)
++                      goto out_unlock;
 +      }
-+      clk_enable(host->mck);
 +
-+      ret = -ENOMEM;
-+      host->regs = ioremap(regs->start, regs->end - regs->start + 1);
-+      if (!host->regs)
-+              goto out_disable_clk;
++out_unlock:
++      if (!err)
++              err = dbg_check_tnc(c, 0);
++      mutex_unlock(&c->tnc_mutex);
++      return err;
++}
 +
-+      host->bus_hz = clk_get_rate(host->mck);
-+      host->mapbase = regs->start;
++/**
++ * ubifs_tnc_remove_ino - remove an inode from TNC.
++ * @c: UBIFS file-system description object
++ * @inum: inode number to remove
++ *
++ * This function remove inode @inum and all the extended attributes associated
++ * with the anode from TNC and returns zero in case of success or a negative
++ * error code in case of failure.
++ */
++int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
++{
++      union ubifs_key key1, key2;
++      struct ubifs_dent_node *xent, *pxent = NULL;
++      struct qstr nm = { .name = NULL };
 +
-+      mmc->ops = &atmci_ops;
-+      mmc->f_min = (host->bus_hz + 511) / 512;
-+      mmc->f_max = min((unsigned int)(host->bus_hz / 2), fmax);
-+      mmc->ocr_avail  = MMC_VDD_32_33 | MMC_VDD_33_34;
-+      mmc->caps |= MMC_CAP_4_BIT_DATA;
++      dbg_tnc("ino %lu", inum);
 +
-+      tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)mmc);
++      /*
++       * Walk all extended attribute entries and remove them together with
++       * corresponding extended attribute inodes.
++       */
++      lowest_xent_key(c, &key1, inum);
++      while (1) {
++              ino_t xattr_inum;
++              int err;
++
++              xent = ubifs_tnc_next_ent(c, &key1, &nm);
++              if (IS_ERR(xent)) {
++                      err = PTR_ERR(xent);
++                      if (err == -ENOENT)
++                              break;
++                      return err;
++              }
 +
-+      ret = request_irq(irq, atmci_interrupt, 0, "mmci", mmc);
-+      if (ret)
-+              goto out_unmap;
++              xattr_inum = le64_to_cpu(xent->inum);
++              dbg_tnc("xent '%s', ino %lu", xent->name, xattr_inum);
 +
-+      /* Assume card is present if we don't have a detect pin */
-+      host->present = 1;
-+      if (host->detect_pin >= 0) {
-+              if (gpio_request(host->detect_pin, "mmc_detect")) {
-+                      dev_dbg(&mmc->class_dev, "no detect pin available\n");
-+                      host->detect_pin = -1;
-+              } else {
-+                      host->present = !gpio_get_value(host->detect_pin);
++              nm.name = xent->name;
++              nm.len = le16_to_cpu(xent->nlen);
++              err = ubifs_tnc_remove_nm(c, &key1, &nm);
++              if (err) {
++                      kfree(xent);
++                      return err;
 +              }
-+      }
-+      if (host->wp_pin >= 0) {
-+              if (gpio_request(host->wp_pin, "mmc_wp")) {
-+                      dev_dbg(&mmc->class_dev, "no WP pin available\n");
-+                      host->wp_pin = -1;
++
++              lowest_ino_key(c, &key1, xattr_inum);
++              highest_ino_key(c, &key2, xattr_inum);
++              err = ubifs_tnc_remove_range(c, &key1, &key2);
++              if (err) {
++                      kfree(xent);
++                      return err;
 +              }
-+      }
 +
-+      /* TODO: Get this information from platform data */
-+      ret = -ENOMEM;
-+      host->dma.req.req.dmac = find_dma_controller(0);
-+      if (!host->dma.req.req.dmac) {
-+              dev_dbg(&mmc->class_dev, "no DMA controller available\n");
-+              goto out_free_irq;
-+      }
-+      ret = dma_alloc_channel(host->dma.req.req.dmac);
-+      if (ret < 0) {
-+              dev_dbg(&mmc->class_dev, "unable to allocate DMA channel\n");
-+              goto out_free_irq;
++              kfree(pxent);
++              pxent = xent;
++              key_read(c, &xent->key, &key1);
 +      }
-+      host->dma.req.req.channel = ret;
-+      host->dma.req.width = DMA_WIDTH_32BIT;
-+      host->dma.req.req.xfer_complete = atmci_xfer_complete;
-+      host->dma.req.req.block_complete = NULL; // atmci_block_complete;
-+      host->dma.req.req.error = atmci_dma_error;
-+      host->dma.rx_periph_id = 0;
-+      host->dma.tx_periph_id = 1;
-+
-+      mci_writel(host, CR, MCI_BIT(SWRST));
-+      mci_writel(host, IDR, ~0UL);
 +
-+      platform_set_drvdata(pdev, host);
++      kfree(pxent);
++      lowest_ino_key(c, &key1, inum);
++      highest_ino_key(c, &key2, inum);
 +
-+      mmc_add_host(mmc);
++      return ubifs_tnc_remove_range(c, &key1, &key2);
++}
 +
-+      if (host->detect_pin >= 0) {
-+              setup_timer(&host->detect_timer, atmci_detect_change,
-+                              (unsigned long)host);
++/**
++ * ubifs_tnc_next_ent - walk directory or extended attribute entries.
++ * @c: UBIFS file-system description object
++ * @key: key of last entry
++ * @nm: name of last entry found or %NULL
++ *
++ * This function finds and reads the next directory or extended attribute entry
++ * after the given key (@key) if there is one. @nm is used to resolve
++ * collisions.
++ *
++ * If the name of the current entry is not known and only the key is known,
++ * @nm->name has to be %NULL. In this case the semantics of this function is a
++ * little bit different and it returns the entry corresponding to this key, not
++ * the next one. If the key was not found, the closest "right" entry is
++ * returned.
++ *
++ * If the fist entry has to be found, @key has to contain the lowest possible
++ * key value for this inode and @name has to be %NULL.
++ *
++ * This function returns the found directory or extended attribute entry node
++ * in case of success, %-ENOENT is returned if no entry was found, and a
++ * negative error code is returned in case of failure.
++ */
++struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
++                                         union ubifs_key *key,
++                                         const struct qstr *nm)
++{
++      int n, err, type = key_type(c, key);
++      struct ubifs_znode *znode;
++      struct ubifs_dent_node *dent;
++      struct ubifs_zbranch *zbr;
++      union ubifs_key *dkey;
++
++      dbg_tnc("%s %s", nm->name ? (char *)nm->name : "(lowest)", DBGKEY(key));
++      ubifs_assert(is_hash_key(c, key));
++
++      mutex_lock(&c->tnc_mutex);
++      err = ubifs_lookup_level0(c, key, &znode, &n);
++      if (unlikely(err < 0))
++              goto out_unlock;
++
++      if (nm->name) {
++              if (err) {
++                      /* Handle collisions */
++                      err = resolve_collision(c, key, &znode, &n, nm);
++                      dbg_tnc("rc returned %d, znode %p, n %d",
++                              err, znode, n);
++                      if (unlikely(err < 0))
++                              goto out_unlock;
++              }
 +
-+              ret = request_irq(gpio_to_irq(host->detect_pin),
-+                                atmci_detect_interrupt,
-+                                IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
-+                                DRIVER_NAME, mmc);
-+              if (ret) {
-+                      dev_dbg(&mmc->class_dev,
-+                              "could not request IRQ %d for detect pin\n",
-+                              gpio_to_irq(host->detect_pin));
-+                      gpio_free(host->detect_pin);
-+                      host->detect_pin = -1;
++              /* Now find next entry */
++              err = tnc_next(c, &znode, &n);
++              if (unlikely(err))
++                      goto out_unlock;
++      } else {
++              /*
++               * The full name of the entry was not given, in which case the
++               * behavior of this function is a little different and it
++               * returns current entry, not the next one.
++               */
++              if (!err) {
++                      /*
++                       * However, the given key does not exist in the TNC
++                       * tree and @znode/@n variables contain the closest
++                       * "preceding" element. Switch to the next one.
++                       */
++                      err = tnc_next(c, &znode, &n);
++                      if (err)
++                              goto out_unlock;
 +              }
 +      }
 +
-+      dev_info(&mmc->class_dev, "Atmel MCI controller at 0x%08lx irq %d\n",
-+                      host->mapbase, irq);
++      zbr = &znode->zbranch[n];
++      dent = kmalloc(zbr->len, GFP_NOFS);
++      if (unlikely(!dent)) {
++              err = -ENOMEM;
++              goto out_unlock;
++      }
 +
-+      atmci_init_debugfs(host);
++      /*
++       * The above 'tnc_next()' call could lead us to the next inode, check
++       * this.
++       */
++      dkey = &zbr->key;
++      if (key_inum(c, dkey) != key_inum(c, key) ||
++          key_type(c, dkey) != type) {
++              err = -ENOENT;
++              goto out_free;
++      }
 +
-+      return 0;
++      err = tnc_read_node_nm(c, zbr, dent);
++      if (unlikely(err))
++              goto out_free;
 +
-+out_free_irq:
-+      if (host->detect_pin >= 0)
-+              gpio_free(host->detect_pin);
-+      if (host->wp_pin >= 0)
-+              gpio_free(host->wp_pin);
-+      free_irq(irq, mmc);
-+out_unmap:
-+      iounmap(host->regs);
-+out_disable_clk:
-+      clk_disable(host->mck);
-+      clk_put(host->mck);
-+out_free_host:
-+      mmc_free_host(mmc);
-+      return ret;
++      mutex_unlock(&c->tnc_mutex);
++      return dent;
++
++out_free:
++      kfree(dent);
++out_unlock:
++      mutex_unlock(&c->tnc_mutex);
++      return ERR_PTR(err);
 +}
 +
-+static int __devexit atmci_remove(struct platform_device *pdev)
++/**
++ * tnc_destroy_cnext - destroy left-over obsolete znodes from a failed commit.
++ * @c: UBIFS file-system description object
++ *
++ * Destroy left-over obsolete znodes from a failed commit.
++ */
++static void tnc_destroy_cnext(struct ubifs_info *c)
 +{
-+      struct atmel_mci *host = platform_get_drvdata(pdev);
++      struct ubifs_znode *cnext;
 +
-+      platform_set_drvdata(pdev, NULL);
++      if (!c->cnext)
++              return;
++      ubifs_assert(c->cmt_state == COMMIT_BROKEN);
++      cnext = c->cnext;
++      do {
++              struct ubifs_znode *znode = cnext;
 +
-+      if (host) {
-+              atmci_cleanup_debugfs(host);
++              cnext = cnext->cnext;
++              if (test_bit(OBSOLETE_ZNODE, &znode->flags))
++                      kfree(znode);
++      } while (cnext && cnext != c->cnext);
++}
 +
-+              if (host->detect_pin >= 0) {
-+                      int pin = host->detect_pin;
++/**
++ * ubifs_tnc_close - close TNC subsystem and free all related resources.
++ * @c: UBIFS file-system description object
++ */
++void ubifs_tnc_close(struct ubifs_info *c)
++{
++      long clean_freed;
 +
-+                      /* Make sure our timer doesn't enable the interrupt */
-+                      host->detect_pin = -1;
-+                      smp_wmb();
++      tnc_destroy_cnext(c);
++      if (c->zroot.znode) {
++              clean_freed = ubifs_destroy_tnc_subtree(c->zroot.znode);
++              atomic_long_sub(clean_freed, &ubifs_clean_zn_cnt);
++      }
++      kfree(c->gap_lebs);
++      kfree(c->ilebs);
++      destroy_old_idx(c);
++}
 +
-+                      free_irq(gpio_to_irq(pin), host->mmc);
-+                      del_timer_sync(&host->detect_timer);
-+                      cancel_delayed_work(&host->mmc->detect);
-+                      gpio_free(pin);
++/**
++ * left_znode - get the znode to the left.
++ * @c: UBIFS file-system description object
++ * @znode: znode
++ *
++ * This function returns a pointer to the znode to the left of @znode or NULL if
++ * there is not one. A negative error code is returned on failure.
++ */
++static struct ubifs_znode *left_znode(struct ubifs_info *c,
++                                    struct ubifs_znode *znode)
++{
++      int level = znode->level;
++
++      while (1) {
++              int n = znode->iip - 1;
++
++              /* Go up until we can go left */
++              znode = znode->parent;
++              if (!znode)
++                      return NULL;
++              if (n >= 0) {
++                      /* Now go down the rightmost branch to 'level' */
++                      znode = get_znode(c, znode, n);
++                      if (IS_ERR(znode))
++                              return znode;
++                      while (znode->level != level) {
++                              n = znode->child_cnt - 1;
++                              znode = get_znode(c, znode, n);
++                              if (IS_ERR(znode))
++                                      return znode;
++                      }
++                      break;
 +              }
++      }
++      return znode;
++}
 +
-+              mmc_remove_host(host->mmc);
++/**
++ * right_znode - get the znode to the right.
++ * @c: UBIFS file-system description object
++ * @znode: znode
++ *
++ * This function returns a pointer to the znode to the right of @znode or NULL
++ * if there is not one. A negative error code is returned on failure.
++ */
++static struct ubifs_znode *right_znode(struct ubifs_info *c,
++                                     struct ubifs_znode *znode)
++{
++      int level = znode->level;
++
++      while (1) {
++              int n = znode->iip + 1;
++
++              /* Go up until we can go right */
++              znode = znode->parent;
++              if (!znode)
++                      return NULL;
++              if (n < znode->child_cnt) {
++                      /* Now go down the leftmost branch to 'level' */
++                      znode = get_znode(c, znode, n);
++                      if (IS_ERR(znode))
++                              return znode;
++                      while (znode->level != level) {
++                              znode = get_znode(c, znode, 0);
++                              if (IS_ERR(znode))
++                                      return znode;
++                      }
++                      break;
++              }
++      }
++      return znode;
++}
 +
-+              mci_writel(host, IDR, ~0UL);
-+              mci_writel(host, CR, MCI_BIT(MCIDIS));
-+              mci_readl(host, SR);
++/**
++ * lookup_znode - find a particular indexing node from TNC.
++ * @c: UBIFS file-system description object
++ * @key: index node key to lookup
++ * @level: index node level
++ * @lnum: index node LEB number
++ * @offs: index node offset
++ *
++ * This function searches an indexing node by its first key @key and its
++ * address @lnum:@offs. It looks up the indexing tree by pulling all indexing
++ * nodes it traverses to TNC. This function is called fro indexing nodes which
++ * were found on the media by scanning, for example when garbage-collecting or
++ * when doing in-the-gaps commit. This means that the indexing node which is
++ * looked for does not have to have exactly the same leftmost key @key, because
++ * the leftmost key may have been changed, in which case TNC will contain a
++ * dirty znode which still refers the same @lnum:@offs. This function is clever
++ * enough to recognize such indexing nodes.
++ *
++ * Note, if a znode was deleted or changed too much, then this function will
++ * not find it. For situations like this UBIFS has the old index RB-tree
++ * (indexed by @lnum:@offs).
++ *
++ * This function returns a pointer to the znode found or %NULL if it is not
++ * found. A negative error code is returned on failure.
++ */
++static struct ubifs_znode *lookup_znode(struct ubifs_info *c,
++                                      union ubifs_key *key, int level,
++                                      int lnum, int offs)
++{
++      struct ubifs_znode *znode, *zn;
++      int n, nn;
 +
-+              dma_release_channel(host->dma.req.req.dmac,
-+                                  host->dma.req.req.channel);
++      /*
++       * The arguments have probably been read off flash, so don't assume
++       * they are valid.
++       */
++      if (level < 0)
++              return ERR_PTR(-EINVAL);
++
++      /* Get the root znode */
++      znode = c->zroot.znode;
++      if (!znode) {
++              znode = ubifs_load_znode(c, &c->zroot, NULL, 0);
++              if (IS_ERR(znode))
++                      return znode;
++      }
++      /* Check if it is the one we are looking for */
++      if (c->zroot.lnum == lnum && c->zroot.offs == offs)
++              return znode;
++      /* Descend to the parent level i.e. (level + 1) */
++      if (level >= znode->level)
++              return NULL;
++      while (1) {
++              ubifs_search_zbranch(c, znode, key, &n);
++              if (n < 0) {
++                      /*
++                       * We reached a znode where the leftmost key is greater
++                       * than the key we are searching for. This is the same
++                       * situation as the one described in a huge comment at
++                       * the end of the 'ubifs_lookup_level0()' function. And
++                       * for exactly the same reasons we have to try to look
++                       * left before giving up.
++                       */
++                      znode = left_znode(c, znode);
++                      if (!znode)
++                              return NULL;
++                      if (IS_ERR(znode))
++                              return znode;
++                      ubifs_search_zbranch(c, znode, key, &n);
++                      ubifs_assert(n >= 0);
++              }
++              if (znode->level == level + 1)
++                      break;
++              znode = get_znode(c, znode, n);
++              if (IS_ERR(znode))
++                      return znode;
++      }
++      /* Check if the child is the one we are looking for */
++      if (znode->zbranch[n].lnum == lnum && znode->zbranch[n].offs == offs)
++              return get_znode(c, znode, n);
++      /* If the key is unique, there is nowhere else to look */
++      if (!is_hash_key(c, key))
++              return NULL;
++      /*
++       * The key is not unique and so may be also in the znodes to either
++       * side.
++       */
++      zn = znode;
++      nn = n;
++      /* Look left */
++      while (1) {
++              /* Move one branch to the left */
++              if (n)
++                      n -= 1;
++              else {
++                      znode = left_znode(c, znode);
++                      if (!znode)
++                              break;
++                      if (IS_ERR(znode))
++                              return znode;
++                      n = znode->child_cnt - 1;
++              }
++              /* Check it */
++              if (znode->zbranch[n].lnum == lnum &&
++                  znode->zbranch[n].offs == offs)
++                      return get_znode(c, znode, n);
++              /* Stop if the key is less than the one we are looking for */
++              if (keys_cmp(c, &znode->zbranch[n].key, key) < 0)
++                      break;
++      }
++      /* Back to the middle */
++      znode = zn;
++      n = nn;
++      /* Look right */
++      while (1) {
++              /* Move one branch to the right */
++              if (++n >= znode->child_cnt) {
++                      znode = right_znode(c, znode);
++                      if (!znode)
++                              break;
++                      if (IS_ERR(znode))
++                              return znode;
++                      n = 0;
++              }
++              /* Check it */
++              if (znode->zbranch[n].lnum == lnum &&
++                  znode->zbranch[n].offs == offs)
++                      return get_znode(c, znode, n);
++              /* Stop if the key is greater than the one we are looking for */
++              if (keys_cmp(c, &znode->zbranch[n].key, key) > 0)
++                      break;
++      }
++      return NULL;
++}
 +
-+              if (host->wp_pin >= 0)
-+                      gpio_free(host->wp_pin);
++/**
++ * is_idx_node_in_tnc - determine if an index node is in the TNC.
++ * @c: UBIFS file-system description object
++ * @key: key of index node
++ * @level: index node level
++ * @lnum: LEB number of index node
++ * @offs: offset of index node
++ *
++ * This function returns %0 if the index node is not referred to in the TNC, %1
++ * if the index node is referred to in the TNC and the corresponding znode is
++ * dirty, %2 if an index node is referred to in the TNC and the corresponding
++ * znode is clean, and a negative error code in case of failure.
++ *
++ * Note, the @key argument has to be the key of the first child. Also note,
++ * this function relies on the fact that 0:0 is never a valid LEB number and
++ * offset for a main-area node.
++ */
++int is_idx_node_in_tnc(struct ubifs_info *c, union ubifs_key *key, int level,
++                     int lnum, int offs)
++{
++      struct ubifs_znode *znode;
 +
-+              free_irq(platform_get_irq(pdev, 0), host->mmc);
-+              iounmap(host->regs);
++      znode = lookup_znode(c, key, level, lnum, offs);
++      if (!znode)
++              return 0;
++      if (IS_ERR(znode))
++              return PTR_ERR(znode);
 +
-+              clk_disable(host->mck);
-+              clk_put(host->mck);
++      return ubifs_zn_dirty(znode) ? 1 : 2;
++}
 +
-+              mmc_free_host(host->mmc);
++/**
++ * is_leaf_node_in_tnc - determine if a non-indexing not is in the TNC.
++ * @c: UBIFS file-system description object
++ * @key: node key
++ * @lnum: node LEB number
++ * @offs: node offset
++ *
++ * This function returns %1 if the node is referred to in the TNC, %0 if it is
++ * not, and a negative error code in case of failure.
++ *
++ * Note, this function relies on the fact that 0:0 is never a valid LEB number
++ * and offset for a main-area node.
++ */
++static int is_leaf_node_in_tnc(struct ubifs_info *c, union ubifs_key *key,
++                             int lnum, int offs)
++{
++      struct ubifs_zbranch *zbr;
++      struct ubifs_znode *znode, *zn;
++      int n, found, err, nn;
++      const int unique = !is_hash_key(c, key);
++
++      found = ubifs_lookup_level0(c, key, &znode, &n);
++      if (found < 0)
++              return found; /* Error code */
++      if (!found)
++              return 0;
++      zbr = &znode->zbranch[n];
++      if (lnum == zbr->lnum && offs == zbr->offs)
++              return 1; /* Found it */
++      if (unique)
++              return 0;
++      /*
++       * Because the key is not unique, we have to look left
++       * and right as well
++       */
++      zn = znode;
++      nn = n;
++      /* Look left */
++      while (1) {
++              err = tnc_prev(c, &znode, &n);
++              if (err == -ENOENT)
++                      break;
++              if (err)
++                      return err;
++              if (keys_cmp(c, key, &znode->zbranch[n].key))
++                      break;
++              zbr = &znode->zbranch[n];
++              if (lnum == zbr->lnum && offs == zbr->offs)
++                      return 1; /* Found it */
++      }
++      /* Look right */
++      znode = zn;
++      n = nn;
++      while (1) {
++              err = tnc_next(c, &znode, &n);
++              if (err) {
++                      if (err == -ENOENT)
++                              return 0;
++                      return err;
++              }
++              if (keys_cmp(c, key, &znode->zbranch[n].key))
++                      break;
++              zbr = &znode->zbranch[n];
++              if (lnum == zbr->lnum && offs == zbr->offs)
++                      return 1; /* Found it */
 +      }
 +      return 0;
 +}
 +
-+static struct platform_driver atmci_driver = {
-+      .probe          = atmci_probe,
-+      .remove         = __devexit_p(atmci_remove),
-+      .driver         = {
-+              .name           = DRIVER_NAME,
-+      },
-+};
-+
-+static int __init atmci_init(void)
++/**
++ * ubifs_tnc_has_node - determine whether a node is in the TNC.
++ * @c: UBIFS file-system description object
++ * @key: node key
++ * @level: index node level (if it is an index node)
++ * @lnum: node LEB number
++ * @offs: node offset
++ * @is_idx: non-zero if the node is an index node
++ *
++ * This function returns %1 if the node is in the TNC, %0 if it is not, and a
++ * negative error code in case of failure. For index nodes, @key has to be the
++ * key of the first child. An index node is considered to be in the TNC only if
++ * the corresponding znode is clean or has not been loaded.
++ */
++int ubifs_tnc_has_node(struct ubifs_info *c, union ubifs_key *key, int level,
++                     int lnum, int offs, int is_idx)
 +{
-+      return platform_driver_register(&atmci_driver);
-+}
++      int err;
 +
-+static void __exit atmci_exit(void)
-+{
-+      platform_driver_unregister(&atmci_driver);
++      mutex_lock(&c->tnc_mutex);
++      if (is_idx) {
++              err = is_idx_node_in_tnc(c, key, level, lnum, offs);
++              if (err < 0)
++                      goto out_unlock;
++              if (err == 1)
++                      /* The index node was found but it was dirty */
++                      err = 0;
++              else if (err == 2)
++                      /* The index node was found and it was clean */
++                      err = 1;
++              else
++                      BUG_ON(err != 0);
++      } else
++              err = is_leaf_node_in_tnc(c, key, lnum, offs);
++
++out_unlock:
++      mutex_unlock(&c->tnc_mutex);
++      return err;
 +}
 +
-+module_init(atmci_init);
-+module_exit(atmci_exit);
++/**
++ * ubifs_dirty_idx_node - dirty an index node.
++ * @c: UBIFS file-system description object
++ * @key: index node key
++ * @level: index node level
++ * @lnum: index node LEB number
++ * @offs: index node offset
++ *
++ * This function loads and dirties an index node so that it can be garbage
++ * collected. The @key argument has to be the key of the first child. This
++ * function relies on the fact that 0:0 is never a valid LEB number and offset
++ * for a main-area node. Returns %0 on success and a negative error code on
++ * failure.
++ */
++int ubifs_dirty_idx_node(struct ubifs_info *c, union ubifs_key *key, int level,
++                       int lnum, int offs)
++{
++      struct ubifs_znode *znode;
++      int err = 0;
++
++      mutex_lock(&c->tnc_mutex);
++      znode = lookup_znode(c, key, level, lnum, offs);
++      if (!znode)
++              goto out_unlock;
++      if (IS_ERR(znode)) {
++              err = PTR_ERR(znode);
++              goto out_unlock;
++      }
++      znode = dirty_cow_bottom_up(c, znode);
++      if (IS_ERR(znode)) {
++              err = PTR_ERR(znode);
++              goto out_unlock;
++      }
 +
-+MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/mmc/host/atmel-mci.h
-@@ -0,0 +1,192 @@
++out_unlock:
++      mutex_unlock(&c->tnc_mutex);
++      return err;
++}
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/tnc_commit.c avr32-2.6/fs/ubifs/tnc_commit.c
+--- linux-2.6.25.6/fs/ubifs/tnc_commit.c       1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/tnc_commit.c    2008-06-12 15:09:45.603817614 +0200
+@@ -0,0 +1,1105 @@
 +/*
-+ * Atmel MultiMedia Card Interface driver
++ * This file is part of UBIFS.
 + *
-+ * Copyright (C) 2004-2006 Atmel Corporation
++ * Copyright (C) 2006-2008 Nokia Corporation.
 + *
-+ * 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.
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Adrian Hunter
++ *          Artem Bityutskiy (Битюцкий Артём)
 + */
-+#ifndef __DRIVERS_MMC_ATMEL_MCI_H__
-+#define __DRIVERS_MMC_ATMEL_MCI_H__
-+
-+/* MCI register offsets */
-+#define MCI_CR                                        0x0000
-+#define MCI_MR                                        0x0004
-+#define MCI_DTOR                              0x0008
-+#define MCI_SDCR                              0x000c
-+#define MCI_ARGR                              0x0010
-+#define MCI_CMDR                              0x0014
-+#define MCI_BLKR                              0x0018
-+#define MCI_RSPR                              0x0020
-+#define MCI_RSPR1                             0x0024
-+#define MCI_RSPR2                             0x0028
-+#define MCI_RSPR3                             0x002c
-+#define MCI_RDR                                       0x0030
-+#define MCI_TDR                                       0x0034
-+#define MCI_SR                                        0x0040
-+#define MCI_IER                                       0x0044
-+#define MCI_IDR                                       0x0048
-+#define MCI_IMR                                       0x004c
-+
-+/* Bitfields in CR */
-+#define MCI_MCIEN_OFFSET                      0
-+#define MCI_MCIEN_SIZE                                1
-+#define MCI_MCIDIS_OFFSET                     1
-+#define MCI_MCIDIS_SIZE                               1
-+#define MCI_PWSEN_OFFSET                      2
-+#define MCI_PWSEN_SIZE                                1
-+#define MCI_PWSDIS_OFFSET                     3
-+#define MCI_PWSDIS_SIZE                               1
-+#define MCI_SWRST_OFFSET                      7
-+#define MCI_SWRST_SIZE                                1
-+
-+/* Bitfields in MR */
-+#define MCI_CLKDIV_OFFSET                     0
-+#define MCI_CLKDIV_SIZE                               8
-+#define MCI_PWSDIV_OFFSET                     8
-+#define MCI_PWSDIV_SIZE                               3
-+#define MCI_RDPROOF_OFFSET                    11
-+#define MCI_RDPROOF_SIZE                      1
-+#define MCI_WRPROOF_OFFSET                    12
-+#define MCI_WRPROOF_SIZE                      1
-+#define MCI_DMAPADV_OFFSET                    14
-+#define MCI_DMAPADV_SIZE                      1
-+#define MCI_BLKLEN_OFFSET                     16
-+#define MCI_BLKLEN_SIZE                               16
-+
-+/* Bitfields in DTOR */
-+#define MCI_DTOCYC_OFFSET                     0
-+#define MCI_DTOCYC_SIZE                               4
-+#define MCI_DTOMUL_OFFSET                     4
-+#define MCI_DTOMUL_SIZE                               3
-+
-+/* Bitfields in SDCR */
-+#define MCI_SDCSEL_OFFSET                     0
-+#define MCI_SDCSEL_SIZE                               4
-+#define MCI_SDCBUS_OFFSET                     7
-+#define MCI_SDCBUS_SIZE                               1
 +
-+/* Bitfields in ARGR */
-+#define MCI_ARG_OFFSET                                0
-+#define MCI_ARG_SIZE                          32
++/* This file implements TNC functions for committing */
 +
-+/* Bitfields in CMDR */
-+#define MCI_CMDNB_OFFSET                      0
-+#define MCI_CMDNB_SIZE                                6
-+#define MCI_RSPTYP_OFFSET                     6
-+#define MCI_RSPTYP_SIZE                               2
-+#define MCI_SPCMD_OFFSET                      8
-+#define MCI_SPCMD_SIZE                                3
-+#define MCI_OPDCMD_OFFSET                     11
-+#define MCI_OPDCMD_SIZE                               1
-+#define MCI_MAXLAT_OFFSET                     12
-+#define MCI_MAXLAT_SIZE                               1
-+#define MCI_TRCMD_OFFSET                      16
-+#define MCI_TRCMD_SIZE                                2
-+#define MCI_TRDIR_OFFSET                      18
-+#define MCI_TRDIR_SIZE                                1
-+#define MCI_TRTYP_OFFSET                      19
-+#define MCI_TRTYP_SIZE                                2
++#include "ubifs.h"
 +
-+/* Bitfields in BLKR */
-+#define MCI_BCNT_OFFSET                               0
-+#define MCI_BCNT_SIZE                         16
++/**
++ * make_idx_node - make an index node for fill-the-gaps method of TNC commit.
++ * @c: UBIFS file-system description object
++ * @idx: buffer in which to place new index node
++ * @znode: znode from which to make new index node
++ * @lnum: LEB number where new index node will be written
++ * @offs: offset where new index node will be written
++ * @len: length of new index node
++ */
++static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
++                       struct ubifs_znode *znode, int lnum, int offs, int len)
++{
++      struct ubifs_znode *zp;
++      int i, err;
++
++      /* Make index node */
++      idx->ch.node_type = UBIFS_IDX_NODE;
++      idx->child_cnt = cpu_to_le16(znode->child_cnt);
++      idx->level = cpu_to_le16(znode->level);
++      for (i = 0; i < znode->child_cnt; i++) {
++              struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
++              struct ubifs_zbranch *zbr = &znode->zbranch[i];
++
++              key_write_idx(c, &zbr->key, &br->key);
++              br->lnum = cpu_to_le32(zbr->lnum);
++              br->offs = cpu_to_le32(zbr->offs);
++              br->len = cpu_to_le32(zbr->len);
++              if (!zbr->lnum || !zbr->len) {
++                      ubifs_err("bad ref in znode");
++                      dbg_dump_znode(c, znode);
++                      if (zbr->znode)
++                              dbg_dump_znode(c, zbr->znode);
++              }
++      }
++      ubifs_prepare_node(c, idx, len, 0);
 +
-+/* Bitfields in RSPRn */
-+#define MCI_RSP_OFFSET                                0
-+#define MCI_RSP_SIZE                          32
++#ifdef CONFIG_UBIFS_FS_DEBUG
++      znode->lnum = lnum;
++      znode->offs = offs;
++      znode->len = len;
++#endif
 +
-+/* Bitfields in SR/IER/IDR/IMR */
-+#define MCI_CMDRDY_OFFSET                     0
-+#define MCI_CMDRDY_SIZE                               1
-+#define MCI_RXRDY_OFFSET                      1
-+#define MCI_RXRDY_SIZE                                1
-+#define MCI_TXRDY_OFFSET                      2
-+#define MCI_TXRDY_SIZE                                1
-+#define MCI_BLKE_OFFSET                               3
-+#define MCI_BLKE_SIZE                         1
-+#define MCI_DTIP_OFFSET                               4
-+#define MCI_DTIP_SIZE                         1
-+#define MCI_NOTBUSY_OFFSET                    5
-+#define MCI_NOTBUSY_SIZE                      1
-+#define MCI_ENDRX_OFFSET                      6
-+#define MCI_ENDRX_SIZE                                1
-+#define MCI_ENDTX_OFFSET                      7
-+#define MCI_ENDTX_SIZE                                1
-+#define MCI_RXBUFF_OFFSET                     14
-+#define MCI_RXBUFF_SIZE                               1
-+#define MCI_TXBUFE_OFFSET                     15
-+#define MCI_TXBUFE_SIZE                               1
-+#define MCI_RINDE_OFFSET                      16
-+#define MCI_RINDE_SIZE                                1
-+#define MCI_RDIRE_OFFSET                      17
-+#define MCI_RDIRE_SIZE                                1
-+#define MCI_RCRCE_OFFSET                      18
-+#define MCI_RCRCE_SIZE                                1
-+#define MCI_RENDE_OFFSET                      19
-+#define MCI_RENDE_SIZE                                1
-+#define MCI_RTOE_OFFSET                               20
-+#define MCI_RTOE_SIZE                         1
-+#define MCI_DCRCE_OFFSET                      21
-+#define MCI_DCRCE_SIZE                                1
-+#define MCI_DTOE_OFFSET                               22
-+#define MCI_DTOE_SIZE                         1
-+#define MCI_OVRE_OFFSET                               30
-+#define MCI_OVRE_SIZE                         1
-+#define MCI_UNRE_OFFSET                               31
-+#define MCI_UNRE_SIZE                         1
++      err = insert_old_idx_znode(c, znode);
 +
-+/* Constants for DTOMUL */
-+#define MCI_DTOMUL_1_CYCLE                    0
-+#define MCI_DTOMUL_16_CYCLES                  1
-+#define MCI_DTOMUL_128_CYCLES                 2
-+#define MCI_DTOMUL_256_CYCLES                 3
-+#define MCI_DTOMUL_1024_CYCLES                        4
-+#define MCI_DTOMUL_4096_CYCLES                        5
-+#define MCI_DTOMUL_65536_CYCLES                       6
-+#define MCI_DTOMUL_1048576_CYCLES             7
++      /* Update the parent */
++      zp = znode->parent;
++      if (zp) {
++              struct ubifs_zbranch *zbr;
 +
-+/* Constants for RSPTYP */
-+#define MCI_RSPTYP_NO_RESP                    0
-+#define MCI_RSPTYP_48_BIT                     1
-+#define MCI_RSPTYP_136_BIT                    2
++              zbr = &zp->zbranch[znode->iip];
++              zbr->lnum = lnum;
++              zbr->offs = offs;
++              zbr->len = len;
++      } else {
++              c->zroot.lnum = lnum;
++              c->zroot.offs = offs;
++              c->zroot.len = len;
++      }
++      c->calc_idx_sz += ALIGN(len, 8);
 +
-+/* Constants for SPCMD */
-+#define MCI_SPCMD_NO_SPEC_CMD                 0
-+#define MCI_SPCMD_INIT_CMD                    1
-+#define MCI_SPCMD_SYNC_CMD                    2
-+#define MCI_SPCMD_INT_CMD                     4
-+#define MCI_SPCMD_INT_RESP                    5
++      atomic_long_dec(&c->dirty_zn_cnt);
 +
-+/* Constants for TRCMD */
-+#define MCI_TRCMD_NO_TRANS                    0
-+#define MCI_TRCMD_START_TRANS                 1
-+#define MCI_TRCMD_STOP_TRANS                  2
++      ubifs_assert(ubifs_zn_dirty(znode));
++      ubifs_assert(test_bit(COW_ZNODE, &znode->flags));
 +
-+/* Constants for TRTYP */
-+#define MCI_TRTYP_BLOCK                               0
-+#define MCI_TRTYP_MULTI_BLOCK                 1
-+#define MCI_TRTYP_STREAM                      2
++      __clear_bit(DIRTY_ZNODE, &znode->flags);
++      __clear_bit(COW_ZNODE, &znode->flags);
 +
-+/* Bit manipulation macros */
-+#define MCI_BIT(name)                                 \
-+      (1 << MCI_##name##_OFFSET)
-+#define MCI_BF(name,value)                            \
-+      (((value) & ((1 << MCI_##name##_SIZE) - 1))     \
-+       << MCI_##name##_OFFSET)
-+#define MCI_BFEXT(name,value)                         \
-+      (((value) >> MCI_##name##_OFFSET)               \
-+       & ((1 << MCI_##name##_SIZE) - 1))
-+#define MCI_BFINS(name,value,old)                     \
-+      (((old) & ~(((1 << MCI_##name##_SIZE) - 1)      \
-+                  << MCI_##name##_OFFSET))            \
-+       | MCI_BF(name,value))
++      return err;
++}
 +
-+/* Register access macros */
-+#define mci_readl(port,reg)                           \
-+      __raw_readl((port)->regs + MCI_##reg)
-+#define mci_writel(port,reg,value)                    \
-+      __raw_writel((value), (port)->regs + MCI_##reg)
++/**
++ * fill_gap - make index nodes in gaps in dirty index LEBs.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number that gap appears in
++ * @gap_start: offset of start of gap
++ * @gap_end: offset of end of gap
++ * @dirt: adds dirty space to this
++ *
++ * This function returns the number of index nodes written into the gap.
++ */
++static int fill_gap(struct ubifs_info *c, int lnum, int gap_start, int gap_end,
++                  int *dirt)
++{
++      int len, gap_remains, gap_pos, written, pad_len;
 +
-+#endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */
---- a/drivers/mmc/host/Kconfig
-+++ b/drivers/mmc/host/Kconfig
-@@ -91,6 +91,16 @@
-         If unsure, say N.
-+config MMC_ATMELMCI
-+      tristate "Atmel Multimedia Card Interface support"
-+      depends on AVR32 && MMC
-+      help
-+        This selects the Atmel Multimedia Card Interface. If you have
-+        a AT91 (ARM) or AT32 (AVR32) platform with a Multimedia Card
-+        slot, say Y or M here.
++      ubifs_assert((gap_start & 7) == 0);
++      ubifs_assert((gap_end & 7) == 0);
++      ubifs_assert(gap_end >= gap_start);
 +
-+        If unsure, say N.
++      gap_remains = gap_end - gap_start;
++      if (!gap_remains)
++              return 0;
++      gap_pos = gap_start;
++      written = 0;
++      while (c->enext) {
++              len = ubifs_idx_node_sz(c, c->enext->child_cnt);
++              if (len < gap_remains) {
++                      struct ubifs_znode *znode = c->enext;
++                      const int alen = ALIGN(len, 8);
++                      int err;
++
++                      ubifs_assert(alen <= gap_remains);
++                      err = make_idx_node(c, c->ileb_buf + gap_pos, znode,
++                                          lnum, gap_pos, len);
++                      if (err)
++                              return err;
++                      gap_remains -= alen;
++                      gap_pos += alen;
++                      c->enext = znode->cnext;
++                      if (c->enext == c->cnext)
++                              c->enext = NULL;
++                      written += 1;
++              } else
++                      break;
++      }
++      if (gap_end == c->leb_size) {
++              c->ileb_len = ALIGN(gap_pos, c->min_io_size);
++              /* Pad to end of min_io_size */
++              pad_len = c->ileb_len - gap_pos;
++      } else
++              /* Pad to end of gap */
++              pad_len = gap_remains;
++      dbg_gc("LEB %d:%d to %d len %d nodes written %d wasted bytes %d",
++             lnum, gap_start, gap_end, gap_end - gap_start, written, pad_len);
++      ubifs_pad(c, c->ileb_buf + gap_pos, pad_len);
++      *dirt += pad_len;
++      return written;
++}
 +
- config MMC_IMX
-       tristate "Motorola i.MX Multimedia Card Interface support"
-       depends on ARCH_IMX
---- a/drivers/mmc/host/Makefile
-+++ b/drivers/mmc/host/Makefile
-@@ -15,6 +15,7 @@
- obj-$(CONFIG_MMC_AU1X)                += au1xmmc.o
- obj-$(CONFIG_MMC_OMAP)                += omap.o
- obj-$(CONFIG_MMC_AT91)                += at91_mci.o
-+obj-$(CONFIG_MMC_ATMELMCI)    += atmel-mci.o
- obj-$(CONFIG_MMC_TIFM_SD)     += tifm_sd.o
- obj-$(CONFIG_MMC_SPI)         += mmc_spi.o
---- a/drivers/mtd/chips/cfi_cmdset_0001.c
-+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
-@@ -50,6 +50,7 @@
- #define I82802AC      0x00ac
- #define MANUFACTURER_ST         0x0020
- #define M50LPW080       0x002F
-+#define AT49BV640D    0x02de
- static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
- static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
-@@ -157,6 +158,47 @@
- }
- #endif
-+/* Atmel chips don't use the same PRI format as Intel chips */
-+static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
-+{
-+      struct map_info *map = mtd->priv;
-+      struct cfi_private *cfi = map->fldrv_priv;
-+      struct cfi_pri_intelext *extp = cfi->cmdset_priv;
-+      struct cfi_pri_atmel atmel_pri;
-+      uint32_t features = 0;
-+
-+      /* Reverse byteswapping */
-+      extp->FeatureSupport = cpu_to_le32(extp->FeatureSupport);
-+      extp->BlkStatusRegMask = cpu_to_le16(extp->BlkStatusRegMask);
-+      extp->ProtRegAddr = cpu_to_le16(extp->ProtRegAddr);
-+
-+      memcpy(&atmel_pri, extp, sizeof(atmel_pri));
-+      memset((char *)extp + 5, 0, sizeof(*extp) - 5);
-+
-+      printk(KERN_ERR "atmel Features: %02x\n", atmel_pri.Features);
-+
-+      if (atmel_pri.Features & 0x01) /* chip erase supported */
-+              features |= (1<<0);
-+      if (atmel_pri.Features & 0x02) /* erase suspend supported */
-+              features |= (1<<1);
-+      if (atmel_pri.Features & 0x04) /* program suspend supported */
-+              features |= (1<<2);
-+      if (atmel_pri.Features & 0x08) /* simultaneous operations supported */
-+              features |= (1<<9);
-+      if (atmel_pri.Features & 0x20) /* page mode read supported */
-+              features |= (1<<7);
-+      if (atmel_pri.Features & 0x40) /* queued erase supported */
-+              features |= (1<<4);
-+      if (atmel_pri.Features & 0x80) /* Protection bits supported */
-+              features |= (1<<6);
-+
-+      extp->FeatureSupport = features;
-+
-+      /* burst write mode not supported */
-+      cfi->cfiq->BufWriteTimeoutTyp = 0;
-+      cfi->cfiq->BufWriteTimeoutMax = 0;
-+}
-+
- #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
- /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
- static void fixup_intel_strataflash(struct mtd_info *mtd, void* param)
-@@ -234,6 +276,7 @@
- }
- static struct cfi_fixup cfi_fixup_table[] = {
-+      { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
- #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
-       { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL },
- #endif
---- a/drivers/mtd/chips/cfi_cmdset_0002.c
-+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
-@@ -186,6 +186,10 @@
-               extp->TopBottom = 2;
-       else
-               extp->TopBottom = 3;
++/**
++ * find_old_idx - find an index node obsoleted since the last commit start.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB number of obsoleted index node
++ * @offs: offset of obsoleted index node
++ *
++ * Returns %1 if found and %0 otherwise.
++ */
++static int find_old_idx(struct ubifs_info *c, int lnum, int offs)
++{
++      struct ubifs_old_idx *o;
++      struct rb_node *p;
++
++      p = c->old_idx.rb_node;
++      while (p) {
++              o = rb_entry(p, struct ubifs_old_idx, rb);
++              if (lnum < o->lnum)
++                      p = p->rb_left;
++              else if (lnum > o->lnum)
++                      p = p->rb_right;
++              else if (offs < o->offs)
++                      p = p->rb_left;
++              else if (offs > o->offs)
++                      p = p->rb_right;
++              else
++                      return 1;
++      }
++      return 0;
++}
 +
-+      /* burst write mode not supported */
-+      cfi->cfiq->BufWriteTimeoutTyp = 0;
-+      cfi->cfiq->BufWriteTimeoutMax = 0;
- }
- static void fixup_use_secsi(struct mtd_info *mtd, void *param)
-@@ -218,6 +222,7 @@
- }
- static struct cfi_fixup cfi_fixup_table[] = {
-+      { 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 },
- #endif
-@@ -230,7 +235,6 @@
- #if !FORCE_WORD_WRITE
-       { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, },
- #endif
--      { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
-       { 0, 0, NULL, NULL }
- };
- static struct cfi_fixup jedec_fixup_table[] = {
---- /dev/null
-+++ b/drivers/pcmcia/at32_cf.c
-@@ -0,0 +1,533 @@
-+/*
-+ * Driver for AVR32 Static Memory Controller: CompactFlash support
++/**
++ * is_idx_node_in_use - determine if an index node can be overwritten.
++ * @c: UBIFS file-system description object
++ * @key: key of index node
++ * @level: index node level
++ * @lnum: LEB number of index node
++ * @offs: offset of index node
 + *
-+ * Copyright (C) 2006 Atmel Norway
++ * If @key / @lnum / @offs identify an index node that was not part of the old
++ * index, then this function returns %0 (obsolete).  Else if the index node was
++ * part of the old index but is now dirty %1 is returned, else if it is clean %2
++ * is returned. A negative error code is returned on failure.
++ */
++static int is_idx_node_in_use(struct ubifs_info *c, union ubifs_key *key,
++                            int level, int lnum, int offs)
++{
++      int ret;
++
++      ret = is_idx_node_in_tnc(c, key, level, lnum, offs);
++      if (ret < 0)
++              return ret; /* Error code */
++      if (ret == 0)
++              if (find_old_idx(c, lnum, offs))
++                      return 1;
++      return ret;
++}
++
++/**
++ * layout_leb_in_gaps - layout index nodes using in-the-gaps method.
++ * @c: UBIFS file-system description object
++ * @p: return LEB number here
 + *
-+ * 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 function lays out new index nodes for dirty znodes using in-the-gaps
++ * method of TNC commit.
++ * This function merely puts the next znode into the next gap, making no attempt
++ * to try to maximise the number of znodes that fit.
++ * This function returns the number of index nodes written into the gaps, or a
++ * negative error code on failure.
++ */
++static int layout_leb_in_gaps(struct ubifs_info *c, int *p)
++{
++      struct ubifs_scan_leb *sleb;
++      struct ubifs_scan_node *snod;
++      int lnum, dirt = 0, gap_start, gap_end, err, written, tot_written;
++
++      tot_written = 0;
++      /* Get an index LEB with lots of obsolete index nodes */
++      lnum = ubifs_find_dirty_idx_leb(c);
++      if (lnum < 0)
++              /*
++               * There also may be dirt in the index head that could be
++               * filled, however we do not check there at present.
++               */
++              return lnum; /* Error code */
++      *p = lnum;
++      dbg_gc("LEB %d", lnum);
++      /*
++       * Scan the index LEB.  We use the generic scan for this even though
++       * it is more comprehensive and less efficient than is needed for this
++       * purpose.
++       */
++      sleb = ubifs_scan(c, lnum, 0, c->ileb_buf);
++      c->ileb_len = 0;
++      if (IS_ERR(sleb))
++              return PTR_ERR(sleb);
++      gap_start = 0;
++      list_for_each_entry(snod, &sleb->nodes, list) {
++              struct ubifs_idx_node *idx;
++              int in_use, level;
++
++              ubifs_assert(snod->type == UBIFS_IDX_NODE);
++              idx = snod->node;
++              key_read(c, ubifs_idx_key(c, idx), &snod->key);
++              level = le16_to_cpu(idx->level);
++              /* Determine if the index node is in use (not obsolete) */
++              in_use = is_idx_node_in_use(c, &snod->key, level, lnum,
++                                          snod->offs);
++              if (in_use < 0) {
++                      ubifs_scan_destroy(sleb);
++                      return in_use; /* Error code */
++              }
++              if (in_use) {
++                      if (in_use == 1)
++                              dirt += ALIGN(snod->len, 8);
++                      /*
++                       * The obsolete index nodes form gaps that can be
++                       * overwritten.  This gap has ended because we have
++                       * found an index node that is still in use
++                       * i.e. not obsolete
++                       */
++                      gap_end = snod->offs;
++                      /* Try to fill gap */
++                      written = fill_gap(c, lnum, gap_start, gap_end, &dirt);
++                      if (written < 0) {
++                              ubifs_scan_destroy(sleb);
++                              return written; /* Error code */
++                      }
++                      tot_written += written;
++                      gap_start = ALIGN(snod->offs + snod->len, 8);
++              }
++      }
++      ubifs_scan_destroy(sleb);
++      c->ileb_len = c->leb_size;
++      gap_end = c->leb_size;
++      /* Try to fill gap */
++      written = fill_gap(c, lnum, gap_start, gap_end, &dirt);
++      if (written < 0)
++              return written; /* Error code */
++      tot_written += written;
++      if (tot_written == 0) {
++              struct ubifs_lprops lp;
++
++              dbg_gc("LEB %d wrote %d index nodes", lnum, tot_written);
++              err = ubifs_read_one_lp(c, lnum, &lp);
++              if (err)
++                      return err;
++              if (lp.free == c->leb_size) {
++                      /*
++                       * We must have snatched this LEB from the idx_gc list
++                       * so we need to correct the free and dirty space.
++                       */
++                      err = ubifs_change_one_lp(c, lnum,
++                                                c->leb_size - c->ileb_len,
++                                                dirt, 0, 0, 0);
++                      if (err)
++                              return err;
++              }
++              return 0;
++      }
++      err = ubifs_change_one_lp(c, lnum, c->leb_size - c->ileb_len, dirt,
++                                0, 0, 0);
++      if (err)
++              return err;
++      err = ubi_leb_change(c->ubi, lnum, c->ileb_buf, c->ileb_len,
++                           UBI_SHORTTERM);
++      if (err) {
++              ubifs_err("ubi_leb_change failed, error %d", err);
++              return err;
++      }
++      dbg_gc("LEB %d wrote %d index nodes", lnum, tot_written);
++      return tot_written;
++}
++
++/**
++ * get_leb_cnt - calculate the number of empty LEBs needed to commit.
++ * @c: UBIFS file-system description object
++ * @cnt: number of znodes to commit
 + *
-+ * 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.
++ * This function returns the number of empty LEBs needed to commit @cnt znodes
++ * to the current index head.  The number is not exact and may be more than
++ * needed.
++ */
++static int get_leb_cnt(struct ubifs_info *c, int cnt)
++{
++      int d;
++
++      /* Assume maximum index node size (i.e. overestimate space needed) */
++      cnt -= (c->leb_size - c->ihead_offs) / c->max_idx_node_sz;
++      if (cnt < 0)
++              cnt = 0;
++      d = c->leb_size / c->max_idx_node_sz;
++      return DIV_ROUND_UP(cnt, d);
++}
++
++/**
++ * layout_in_gaps - in-the-gaps method of committing TNC.
++ * @c: UBIFS file-system description object
++ * @cnt: number of dirty znodes to commit.
 + *
-+ * 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.
++ * This function lays out new index nodes for dirty znodes using in-the-gaps
++ * method of TNC commit.
 + *
-+ * The full GNU General Public License is included in this
-+ * distribution in the file called COPYING.
++ * This function returns %0 on success and a negative error code on failure.
 + */
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/platform_device.h>
-+#include <linux/init.h>
-+#include <linux/device.h>
-+#include <linux/delay.h>
-+#include <linux/interrupt.h>
-+#include <linux/err.h>
-+#include <linux/clk.h>
-+#include <linux/dma-mapping.h>
-+
-+#include <pcmcia/ss.h>
++static int layout_in_gaps(struct ubifs_info *c, int cnt)
++{
++      int err, leb_needed_cnt, written, *p;
 +
-+#include <asm/gpio.h>
-+#include <asm/io.h>
-+#include <asm/arch/board.h>
++      dbg_gc("%d znodes to write", cnt);
 +
-+#include <asm/arch/smc.h>
++      c->gap_lebs = kmalloc(sizeof(int) * (c->lst.idx_lebs + 1), GFP_NOFS);
++      if (!c->gap_lebs)
++              return -ENOMEM;
 +
-+struct at32_cf_socket {
-+      struct pcmcia_socket    socket;
-+      int                     detect_pin;
-+      int                     reset_pin;
-+      int                     vcc_pin;
-+      int                     ready_pin;
-+      struct resource         res_attr;
-+      struct resource         res_mem;
-+      struct resource         res_io;
-+      struct smc_config       smc;
-+      unsigned int            irq;
-+      unsigned int            cf_cs;
-+      socket_state_t          state;
-+      unsigned                present:1;
-+};
-+#define to_at32_cf(sock) container_of(sock, struct at32_cf_socket, socket)
++      p = c->gap_lebs;
++      do {
++              ubifs_assert(p < c->gap_lebs + sizeof(int) * c->lst.idx_lebs);
++              written = layout_leb_in_gaps(c, p);
++              if (written < 0) {
++                      err = written;
++                      if (err == -ENOSPC) {
++                              if (!dbg_force_in_the_gaps_enabled) {
++                                      /*
++                                       * Do not print scary warnings if the
++                                       * debugging option which forces
++                                       * in-the-gaps is enabled.
++                                       */
++                                      ubifs_err("out of space");
++                                      spin_lock(&c->space_lock);
++                                      dbg_dump_budg(c);
++                                      spin_unlock(&c->space_lock);
++                                      dbg_dump_lprops(c);
++                              }
++                              /* Try to commit anyway */
++                              err = 0;
++                              break;
++                      }
++                      kfree(c->gap_lebs);
++                      c->gap_lebs = NULL;
++                      return err;
++              }
++              p++;
++              cnt -= written;
++              leb_needed_cnt = get_leb_cnt(c, cnt);
++              dbg_gc("%d znodes remaining, need %d LEBs, have %d", cnt,
++                     leb_needed_cnt, c->ileb_cnt);
++      } while (leb_needed_cnt > c->ileb_cnt);
++
++      *p = -1;
++      return 0;
++}
 +
-+/*
-+ * We have the following memory layout relative to the base address:
-+ *
-+ *   Alt IDE Mode:      00e0 0000 -> 00ff ffff
-+ *   True IDE Mode:     00c0 0000 -> 00df ffff
-+ *   I/O memory:        0080 0000 -> 00bf ffff
-+ *   Common memory:     0040 0000 -> 007f ffff
-+ *   Attribute memory:  0000 0000 -> 003f ffff
++/**
++ * layout_in_empty_space - layout index nodes in empty space.
++ * @c: UBIFS file-system description object
++ *
++ * This function lays out new index nodes for dirty znodes using empty LEBs.
++ *
++ * This function returns %0 on success and a negative error code on failure.
 + */
-+#define CF_ATTR_OFFSET        0x00000000
-+#define CF_MEM_OFFSET 0x00400000
-+#define CF_IO_OFFSET  0x00800000
-+#define CF_RES_SIZE   4096
++static int layout_in_empty_space(struct ubifs_info *c)
++{
++      struct ubifs_znode *znode, *cnext, *zp;
++      int lnum, offs, len, next_len, buf_len, buf_offs, used, avail;
++      int wlen, blen, err;
 +
-+#ifdef DEBUG
++      cnext = c->enext;
++      if (!cnext)
++              return 0;
 +
-+static int pc_debug;
-+module_param(pc_debug, int, 0644);
++      lnum = c->ihead_lnum;
++      buf_offs = c->ihead_offs;
 +
-+static void at32_cf_debug(struct at32_cf_socket *cf, const char *func,
-+                        int level, const char *fmt, ...)
-+{
-+      va_list args;
++      buf_len = ubifs_idx_node_sz(c, c->fanout);
++      buf_len = ALIGN(buf_len, c->min_io_size);
++      used = 0;
++      avail = buf_len;
 +
-+      if (pc_debug > level) {
-+              printk(KERN_DEBUG "at32_cf/%u: %s: ", cf->cf_cs, func);
-+              va_start(args, fmt);
-+              vprintk(fmt, args);
-+              va_end(args);
-+      }
-+}
++      /* Ensure there is enough room for first write */
++      next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
++      if (buf_offs + next_len > c->leb_size)
++              lnum = -1;
 +
-+#define debug(cf, lvl, fmt, arg...)                   \
-+      at32_cf_debug(cf, __func__, lvl, fmt, ##arg)
++      while (1) {
++              znode = cnext;
 +
-+#else
-+#define debug(cf, lvl, fmt, arg...) do { } while (0)
++              len = ubifs_idx_node_sz(c, znode->child_cnt);
++
++              /* Determine the index node position */
++              if (lnum == -1) {
++                      if (c->ileb_nxt >= c->ileb_cnt) {
++                              ubifs_err("out of space");
++                              return -ENOSPC;
++                      }
++                      lnum = c->ilebs[c->ileb_nxt++];
++                      buf_offs = 0;
++                      used = 0;
++                      avail = buf_len;
++              }
++
++              offs = buf_offs + used;
++
++#ifdef CONFIG_UBIFS_FS_DEBUG
++              znode->lnum = lnum;
++              znode->offs = offs;
++              znode->len = len;
 +#endif
 +
-+static inline int at32_cf_present(struct at32_cf_socket *cf)
-+{
-+      int present = 1;
++              /* Update the parent */
++              zp = znode->parent;
++              if (zp) {
++                      struct ubifs_zbranch *zbr;
++                      int i;
++
++                      i = znode->iip;
++                      zbr = &zp->zbranch[i];
++                      zbr->lnum = lnum;
++                      zbr->offs = offs;
++                      zbr->len = len;
++              } else {
++                      c->zroot.lnum = lnum;
++                      c->zroot.offs = offs;
++                      c->zroot.len = len;
++              }
++              c->calc_idx_sz += ALIGN(len, 8);
 +
-+      /* If we don't have a detect pin, assume the card is present */
-+      if (cf->detect_pin >= 0)
-+              present = !gpio_get_value(cf->detect_pin);
++              /*
++               * Once lprops is updated, we can decrease the dirty znode count
++               * but it is easier to just do it here.
++               */
++              atomic_long_dec(&c->dirty_zn_cnt);
 +
-+      return present;
-+}
++              /*
++               * Calculate the next index node length to see if there is
++               * enough room for it
++               */
++              cnext = znode->cnext;
++              if (cnext == c->cnext)
++                      next_len = 0;
++              else
++                      next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
 +
-+static irqreturn_t at32_cf_irq(int irq, void *dev_id)
-+{
-+      struct at32_cf_socket *cf = dev_id;
-+      unsigned int present;
++              if (c->min_io_size == 1) {
++                      buf_offs += ALIGN(len, 8);
++                      if (next_len) {
++                              if (buf_offs + next_len <= c->leb_size)
++                                      continue;
++                              err = ubifs_update_one_lp(c, lnum, 0,
++                                              c->leb_size - buf_offs, 0, 0);
++                              if (err)
++                                      return err;
++                              lnum = -1;
++                              continue;
++                      }
++                      err = ubifs_update_one_lp(c, lnum,
++                                      c->leb_size - buf_offs, 0, 0, 0);
++                      if (err)
++                              return err;
++                      break;
++              }
 +
-+      present = at32_cf_present(cf);
-+      if (present != cf->present) {
-+              cf->present = present;
-+              debug(cf, 3, "card %s\n", present ? "present" : "gone");
-+              pcmcia_parse_events(&cf->socket, SS_DETECT);
++              /* Update buffer positions */
++              wlen = used + len;
++              used += ALIGN(len, 8);
++              avail -= ALIGN(len, 8);
++
++              if (next_len != 0 &&
++                  buf_offs + used + next_len <= c->leb_size &&
++                  avail > 0)
++                      continue;
++
++              if (avail <= 0 && next_len &&
++                  buf_offs + used + next_len <= c->leb_size)
++                      blen = buf_len;
++              else
++                      blen = ALIGN(wlen, c->min_io_size);
++
++              /* The buffer is full or there are no more znodes to do */
++              buf_offs += blen;
++              if (next_len) {
++                      if (buf_offs + next_len > c->leb_size) {
++                              err = ubifs_update_one_lp(c, lnum,
++                                      c->leb_size - buf_offs, blen - used,
++                                      0, 0);
++                              if (err)
++                                      return err;
++                              lnum = -1;
++                      }
++                      used -= blen;
++                      if (used < 0)
++                              used = 0;
++                      avail = buf_len - used;
++                      continue;
++              }
++              err = ubifs_update_one_lp(c, lnum, c->leb_size - buf_offs,
++                                        blen - used, 0, 0);
++              if (err)
++                      return err;
++              break;
 +      }
 +
-+      return IRQ_HANDLED;
++#ifdef CONFIG_UBIFS_FS_DEBUG
++      c->new_ihead_lnum = lnum;
++      c->new_ihead_offs = buf_offs;
++#endif
++
++      return 0;
 +}
 +
-+static int at32_cf_get_status(struct pcmcia_socket *sock, u_int *value)
++/**
++ * layout_commit - determine positions of index nodes to commit.
++ * @c: UBIFS file-system description object
++ * @no_space: indicates that insufficient empty LEBs were allocated
++ * @cnt: number of znodes to commit
++ *
++ * Calculate and update the positions of index nodes to commit.  If there were
++ * an insufficient number of empty LEBs allocated, then index nodes are placed
++ * into the gaps created by obsolete index nodes in non-empty index LEBs.  For
++ * this purpose, an obsolete index node is one that was not in the index as at
++ * the end of the last commit.  To write "in-the-gaps" requires that those index
++ * LEBs are updated atomically in-place.
++ */
++static int layout_commit(struct ubifs_info *c, int no_space, int cnt)
 +{
-+      struct at32_cf_socket *cf;
-+      u_int status = 0;
-+
-+      cf = container_of(sock, struct at32_cf_socket, socket);
++      int err;
 +
-+      if (at32_cf_present(cf)) {
-+              /* NOTE: gpio on AP7xxx is 3.3V */
-+              status = SS_DETECT | SS_3VCARD;
-+              if (cf->ready_pin < 0 || gpio_get_value(cf->ready_pin))
-+                      status |= SS_READY;
-+              if (cf->vcc_pin < 0 || gpio_get_value(cf->vcc_pin))
-+                      status |= SS_POWERON;
++      if (no_space) {
++              err = layout_in_gaps(c, cnt);
++              if (err)
++                      return err;
 +      }
-+
-+      *value = status;
-+      return 0;
++      err = layout_in_empty_space(c);
++      return err;
 +}
 +
-+static int at32_cf_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
++/**
++ * find_first_dirty - find first dirty znode.
++ * @znode: znode to begin searching from
++ */
++static struct ubifs_znode *find_first_dirty(struct ubifs_znode *znode)
 +{
-+      struct at32_cf_socket *cf = container_of(sock, struct at32_cf_socket, socket);
++      int i, cont;
 +
-+      debug(cf, 2, "mask: %s%s%s%s%s%sflags: %s%s%s%s%s%sVcc %d Vpp %d irq %d\n",
-+                      (state->csc_mask==0)?"<NONE> ":"",
-+                      (state->csc_mask&SS_DETECT)?"DETECT ":"",
-+                      (state->csc_mask&SS_READY)?"READY ":"",
-+                      (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"",
-+                      (state->csc_mask&SS_BATWARN)?"BATWARN ":"",
-+                      (state->csc_mask&SS_STSCHG)?"STSCHG ":"",
-+                      (state->flags==0)?"<NONE> ":"",
-+                      (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"",
-+                      (state->flags&SS_IOCARD)?"IOCARD ":"",
-+                      (state->flags&SS_RESET)?"RESET ":"",
-+                      (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"",
-+                      (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"",
-+                      state->Vcc, state->Vpp, state->io_irq);
++      if (!znode)
++              return NULL;
 +
-+      /*
-+       * TODO: Allow boards to override this in case they have level
-+       * converters.
-+       */
-+      switch (state->Vcc) {
-+      case 0:
-+              if (cf->vcc_pin >= 0)
-+                      gpio_set_value(cf->vcc_pin, 0);
-+              break;
-+      case 33:
-+              if (cf->vcc_pin >= 0)
-+                      gpio_set_value(cf->vcc_pin, 1);
-+              break;
-+      default:
-+              return -EINVAL;
++      while (1) {
++              if (znode->level == 0) {
++                      if (ubifs_zn_dirty(znode))
++                              return znode;
++                      return NULL;
++              }
++              cont = 0;
++              for (i = 0; i < znode->child_cnt; i++) {
++                      struct ubifs_zbranch *zbr = &znode->zbranch[i];
++
++                      if (zbr->znode && ubifs_zn_dirty(zbr->znode)) {
++                              znode = zbr->znode;
++                              cont = 1;
++                              break;
++                      }
++              }
++              if (!cont) {
++                      if (ubifs_zn_dirty(znode))
++                              return znode;
++                      return NULL;
++              }
 +      }
++}
 +
-+      if (cf->reset_pin >= 0)
-+              gpio_set_value(cf->reset_pin, state->flags & SS_RESET);
++/**
++ * find_next_dirty - find next dirty znode.
++ * @znode: znode to begin searching from
++ */
++static struct ubifs_znode *find_next_dirty(struct ubifs_znode *znode)
++{
++      int n = znode->iip + 1;
 +
-+      cf->state = *state;
++      znode = znode->parent;
++      if (!znode)
++              return NULL;
++      for (; n < znode->child_cnt; n++) {
++              struct ubifs_zbranch *zbr = &znode->zbranch[n];
 +
-+      return 0;
++              if (zbr->znode && ubifs_zn_dirty(zbr->znode))
++                      return find_first_dirty(zbr->znode);
++      }
++      return znode;
 +}
 +
-+static int at32_cf_socket_init(struct pcmcia_socket *sock)
++/**
++ * get_znodes_to_commit - create list of dirty znodes to commit.
++ * @c: UBIFS file-system description object
++ *
++ * This function returns the number of znodes to commit.
++ */
++static int get_znodes_to_commit(struct ubifs_info *c)
 +{
-+      debug(to_at32_cf(sock), 2, "called\n");
++      struct ubifs_znode *znode, *cnext;
++      int cnt = 0;
 +
-+      return 0;
++      c->cnext = find_first_dirty(c->zroot.znode);
++      znode = c->enext = c->cnext;
++      if (!znode) {
++              dbg_cmt("no znodes to commit");
++              return 0;
++      }
++      cnt += 1;
++      while (1) {
++              ubifs_assert(!test_bit(COW_ZNODE, &znode->flags));
++              __set_bit(COW_ZNODE, &znode->flags);
++              znode->alt = 0;
++              cnext = find_next_dirty(znode);
++              if (!cnext) {
++                      znode->cnext = c->cnext;
++                      break;
++              }
++              znode->cnext = cnext;
++              znode = cnext;
++              cnt += 1;
++      }
++      dbg_cmt("committing %d znodes", cnt);
++      ubifs_assert(cnt == atomic_long_read(&c->dirty_zn_cnt));
++      return cnt;
 +}
 +
-+static int at32_cf_suspend(struct pcmcia_socket *sock)
++/**
++ * alloc_idx_lebs - allocate empty LEBs to be used to commit.
++ * @c: UBIFS file-system description object
++ * @cnt: number of znodes to commit
++ *
++ * This function returns %-ENOSPC if it cannot allocate a sufficient number of
++ * empty LEBs.  %0 is returned on success, otherwise a negative error code
++ * is returned.
++ */
++static int alloc_idx_lebs(struct ubifs_info *c, int cnt)
 +{
-+      debug(to_at32_cf(sock), 2, "called\n");
-+
-+      at32_cf_set_socket(sock, &dead_socket);
++      int i, leb_cnt, lnum;
 +
++      c->ileb_cnt = 0;
++      c->ileb_nxt = 0;
++      leb_cnt = get_leb_cnt(c, cnt);
++      dbg_cmt("need about %d empty LEBS for TNC commit", leb_cnt);
++      if (!leb_cnt)
++              return 0;
++      c->ilebs = kmalloc(leb_cnt * sizeof(int), GFP_NOFS);
++      if (!c->ilebs)
++              return -ENOMEM;
++      for (i = 0; i < leb_cnt; i++) {
++              lnum = ubifs_find_free_leb_for_idx(c);
++              if (lnum < 0)
++                      return lnum;
++              c->ilebs[c->ileb_cnt++] = lnum;
++              dbg_cmt("LEB %d", lnum);
++      }
++      if (dbg_force_in_the_gaps())
++              return -ENOSPC;
 +      return 0;
 +}
 +
-+static int at32_cf_set_io_map(struct pcmcia_socket *sock,
-+                            struct pccard_io_map *map)
++/**
++ * free_unused_idx_lebs - free unused LEBs that were allocated for the commit.
++ * @c: UBIFS file-system description object
++ *
++ * It is possible that we allocate more empty LEBs for the commit than we need.
++ * This functions frees the surplus.
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int free_unused_idx_lebs(struct ubifs_info *c)
 +{
-+      struct at32_cf_socket *cf = container_of(sock, struct at32_cf_socket, socket);
-+      int retval;
++      int i, err = 0, lnum, er;
 +
-+      debug(cf, 2, "map %u  speed %u start 0x%08x stop 0x%08x\n",
-+              map->map, map->speed, map->start, map->stop);
-+      debug(cf, 2, "flags: %s%s%s%s%s%s%s%s\n",
-+              (map->flags == 0) ? "<NONE>":"",
-+              (map->flags & MAP_ACTIVE) ? "ACTIVE " : "",
-+              (map->flags & MAP_16BIT) ? "16BIT " : "",
-+              (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "",
-+              (map->flags & MAP_0WS) ? "0WS " : "",
-+              (map->flags & MAP_WRPROT) ? "WRPROT " : "",
-+              (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "",
-+              (map->flags & MAP_PREFETCH) ? "PREFETCH " : "");
++      for (i = c->ileb_nxt; i < c->ileb_cnt; i++) {
++              lnum = c->ilebs[i];
++              dbg_cmt("LEB %d", lnum);
++              er = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
++                                       LPROPS_INDEX | LPROPS_TAKEN, 0);
++              if (!err)
++                      err = er;
++      }
++      return err;
++}
 +
-+      map->flags &= MAP_ACTIVE | MAP_16BIT | MAP_USE_WAIT;
++/**
++ * free_idx_lebs - free unused LEBs after commit end.
++ * @c: UBIFS file-system description object
++ *
++ * This function returns %0 on success and a negative error code on failure.
++ */
++static int free_idx_lebs(struct ubifs_info *c)
++{
++      int err;
 +
-+      if (map->flags & MAP_16BIT)
-+              cf->smc.bus_width = 2;
-+      else
-+              cf->smc.bus_width = 1;
++      err = free_unused_idx_lebs(c);
++      kfree(c->ilebs);
++      c->ilebs = NULL;
++      return err;
++}
 +
-+      if (map->flags & MAP_USE_WAIT)
-+              cf->smc.nwait_mode = 3;
-+      else
-+              cf->smc.nwait_mode = 0;
++/**
++ * ubifs_tnc_start_commit - start TNC commit.
++ * @c: UBIFS file-system description object
++ * @zroot: new index root position is returned here
++ *
++ * This function prepares the list of indexing nodes to commit and lays out
++ * their positions on flash. If there is not enough free space it uses the
++ * in-gap commit method. Returns zero in case of success and a negative error
++ * code in case of failure.
++ */
++int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot)
++{
++      int err = 0, cnt;
 +
-+      retval = smc_set_configuration(cf->cf_cs, &cf->smc);
-+      if (retval) {
-+              printk(KERN_ERR "at32_cf: could not set up SMC for I/O\n");
-+              return retval;
++      mutex_lock(&c->tnc_mutex);
++      err = dbg_check_tnc(c, 1);
++      if (err)
++              goto out;
++      cnt = get_znodes_to_commit(c);
++      if (cnt != 0) {
++              int no_space = 0;
++
++              err = alloc_idx_lebs(c, cnt);
++              if (err == -ENOSPC)
++                      no_space = 1;
++              else if (err)
++                      goto out_free;
++              err = layout_commit(c, no_space, cnt);
++              if (err)
++                      goto out_free;
++              ubifs_assert(atomic_long_read(&c->dirty_zn_cnt) == 0);
++              err = free_unused_idx_lebs(c);
++              if (err)
++                      goto out;
 +      }
++      destroy_old_idx(c);
++      memcpy(zroot, &c->zroot, sizeof(struct ubifs_zbranch));
 +
-+      map->start = cf->socket.io_offset;
-+      map->stop = map->start + CF_RES_SIZE - 1;
++      err = ubifs_save_dirty_idx_lnums(c);
++      if (err)
++              goto out;
 +
-+      return 0;
++      spin_lock(&c->space_lock);
++      /*
++       * Although we have not finished committing yet, update size of the
++       * committed index ('c->old_idx_sz') and zero out the index growth
++       * budget. It is OK to do this now, because we've reserved all the
++       * space which is needed to commit the index, and it is save for the
++       * budgeting subsystem to assume the index is already committed,
++       * even though it is not.
++       */
++      c->old_idx_sz = c->calc_idx_sz;
++      c->budg_uncommitted_idx = 0;
++      spin_unlock(&c->space_lock);
++      mutex_unlock(&c->tnc_mutex);
++
++      dbg_cmt("number of index LEBs %d", c->lst.idx_lebs);
++      dbg_cmt("size of index %llu", c->calc_idx_sz);
++      return err;
++
++out_free:
++      free_idx_lebs(c);
++out:
++      mutex_unlock(&c->tnc_mutex);
++      return err;
 +}
 +
-+static int
-+at32_cf_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map)
++/**
++ * write_index - write index nodes.
++ * @c: UBIFS file-system description object
++ *
++ * This function writes the index nodes whose positions were laid out in the
++ * layout_in_empty_space function.
++ */
++static int write_index(struct ubifs_info *c)
 +{
-+      struct at32_cf_socket *cf;
-+      struct resource *res;
-+      int retval;
++      struct ubifs_idx_node *idx;
++      struct ubifs_znode *znode, *cnext;
++      int i, lnum, offs, len, next_len, buf_len, buf_offs, used;
++      int avail, wlen, err, lnum_pos = 0;
 +
-+      cf = container_of(sock, struct at32_cf_socket, socket);
++      cnext = c->enext;
++      if (!cnext)
++              return 0;
 +
-+      debug(cf, 2, "map %u speed %u card_start %08x\n",
-+              map->map, map->speed, map->card_start);
-+      debug(cf, 2, "flags: %s%s%s%s%s%s%s%s\n",
-+              (map->flags==0)?"<NONE>":"",
-+              (map->flags&MAP_ACTIVE)?"ACTIVE ":"",
-+              (map->flags&MAP_16BIT)?"16BIT ":"",
-+              (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"",
-+              (map->flags&MAP_0WS)?"0WS ":"",
-+              (map->flags&MAP_WRPROT)?"WRPROT ":"",
-+              (map->flags&MAP_ATTRIB)?"ATTRIB ":"",
-+              (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"");
++      /*
++       * Always write index nodes to the index head so that index nodes and
++       * other types of nodes are never mixed in the same erase block.
++       */
++      lnum = c->ihead_lnum;
++      buf_offs = c->ihead_offs;
++
++      /* Allocate commit buffer */
++      buf_len = ALIGN(c->max_idx_node_sz, c->min_io_size);
++      used = 0;
++      avail = buf_len;
++
++      /* Ensure there is enough room for first write */
++      next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
++      if (buf_offs + next_len > c->leb_size) {
++              err = ubifs_update_one_lp(c, lnum, LPROPS_NC, 0, 0,
++                                        LPROPS_TAKEN);
++              if (err)
++                      return err;
++              lnum = -1;
++      }
++
++      while (1) {
++              cond_resched();
++
++              znode = cnext;
++              idx = c->cbuf + used;
++
++              /* Make index node */
++              idx->ch.node_type = UBIFS_IDX_NODE;
++              idx->child_cnt = cpu_to_le16(znode->child_cnt);
++              idx->level = cpu_to_le16(znode->level);
++              for (i = 0; i < znode->child_cnt; i++) {
++                      struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
++                      struct ubifs_zbranch *zbr = &znode->zbranch[i];
++
++                      key_write_idx(c, &zbr->key, &br->key);
++                      br->lnum = cpu_to_le32(zbr->lnum);
++                      br->offs = cpu_to_le32(zbr->offs);
++                      br->len = cpu_to_le32(zbr->len);
++                      if (!zbr->lnum || !zbr->len) {
++                              ubifs_err("bad ref in znode");
++                              dbg_dump_znode(c, znode);
++                              if (zbr->znode)
++                                      dbg_dump_znode(c, zbr->znode);
++                      }
++              }
++              len = ubifs_idx_node_sz(c, znode->child_cnt);
++              ubifs_prepare_node(c, idx, len, 0);
++
++              /* Determine the index node position */
++              if (lnum == -1) {
++                      lnum = c->ilebs[lnum_pos++];
++                      buf_offs = 0;
++                      used = 0;
++                      avail = buf_len;
++              }
++              offs = buf_offs + used;
++
++#ifdef CONFIG_UBIFS_FS_DEBUG
++              if (lnum != znode->lnum || offs != znode->offs ||
++                  len != znode->len) {
++                      ubifs_err("inconsistent znode posn");
++                      return -EINVAL;
++              }
++#endif
++
++              /* Grab some stuff from znode while we still can */
++              cnext = znode->cnext;
 +
-+      if (map->card_start)
-+              return -EINVAL;
++              ubifs_assert(ubifs_zn_dirty(znode));
++              ubifs_assert(test_bit(COW_ZNODE, &znode->flags));
 +
-+      map->flags &= MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT | MAP_USE_WAIT;
++              /*
++               * It is important that other threads should see %DIRTY_ZNODE
++               * flag cleared before %COW_ZNODE. Specifically, it matters in
++               * the 'dirty_cow_znode()' function. This is the reason for the
++               * first barrier. Also, we want the bit changes to be seen to
++               * other threads ASAP, to avoid unnecesarry copying, which is
++               * the reason for the second barrier.
++               */
++              clear_bit(DIRTY_ZNODE, &znode->flags);
++              smp_mb__before_clear_bit();
++              clear_bit(COW_ZNODE, &znode->flags);
++              smp_mb__after_clear_bit();
 +
-+      if (map->flags & MAP_ATTRIB) {
-+              res = &cf->res_attr;
++              /* Do not access znode from this point on */
 +
-+              /* Linksys WCF12 seems to use WAIT when reading CIS */
-+              map->flags |= MAP_USE_WAIT;
-+      } else {
-+              res = &cf->res_mem;
-+      }
++              /* Update buffer positions */
++              wlen = used + len;
++              used += ALIGN(len, 8);
++              avail -= ALIGN(len, 8);
 +
-+      if (map->flags & MAP_USE_WAIT)
-+              cf->smc.nwait_mode = 3;
-+      else
-+              cf->smc.nwait_mode = 0;
++              /*
++               * Calculate the next index node length to see if there is
++               * enough room for it
++               */
++              if (cnext == c->cnext)
++                      next_len = 0;
++              else
++                      next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
 +
-+      retval = smc_set_configuration(cf->cf_cs, &cf->smc);
-+      if (retval) {
-+              printk(KERN_ERR "at32_cf: could not set up SMC for mem\n");
-+              return retval;
++              if (c->min_io_size == 1) {
++                      /*
++                       * Write the prepared index node immediately if there is
++                       * no minimum IO size
++                       */
++                      err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs,
++                                            wlen, UBI_SHORTTERM);
++                      if (err)
++                              return err;
++                      buf_offs += ALIGN(wlen, 8);
++                      if (next_len) {
++                              used = 0;
++                              avail = buf_len;
++                              if (buf_offs + next_len > c->leb_size) {
++                                      err = ubifs_update_one_lp(c, lnum,
++                                              LPROPS_NC, 0, 0, LPROPS_TAKEN);
++                                      if (err)
++                                              return err;
++                                      lnum = -1;
++                              }
++                              continue;
++                      }
++              } else {
++                      int blen, nxt_offs = buf_offs + used + next_len;
++
++                      if (next_len && nxt_offs <= c->leb_size) {
++                              if (avail > 0)
++                                      continue;
++                              else
++                                      blen = buf_len;
++                      } else {
++                              wlen = ALIGN(wlen, 8);
++                              blen = ALIGN(wlen, c->min_io_size);
++                              ubifs_pad(c, c->cbuf + wlen, blen - wlen);
++                      }
++                      /*
++                       * The buffer is full or there are no more znodes
++                       * to do
++                       */
++                      err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs,
++                                            blen, UBI_SHORTTERM);
++                      if (err)
++                              return err;
++                      buf_offs += blen;
++                      if (next_len) {
++                              if (nxt_offs > c->leb_size) {
++                                      err = ubifs_update_one_lp(c, lnum,
++                                              LPROPS_NC, 0, 0, LPROPS_TAKEN);
++                                      if (err)
++                                              return err;
++                                      lnum = -1;
++                              }
++                              used -= blen;
++                              if (used < 0)
++                                      used = 0;
++                              avail = buf_len - used;
++                              memmove(c->cbuf, c->cbuf + blen, used);
++                              continue;
++                      }
++              }
++              break;
 +      }
 +
-+      map->static_start = res->start;
++#ifdef CONFIG_UBIFS_FS_DEBUG
++      if (lnum != c->new_ihead_lnum || buf_offs != c->new_ihead_offs) {
++              ubifs_err("inconsistent ihead");
++              return -EINVAL;
++      }
++#endif
++
++      c->ihead_lnum = lnum;
++      c->ihead_offs = buf_offs;
 +
 +      return 0;
 +}
 +
-+static struct pccard_operations at32_cf_ops = {
-+      .init                   = at32_cf_socket_init,
-+      .suspend                = at32_cf_suspend,
-+      .get_status             = at32_cf_get_status,
-+      .set_socket             = at32_cf_set_socket,
-+      .set_io_map             = at32_cf_set_io_map,
-+      .set_mem_map            = at32_cf_set_mem_map,
-+};
++/**
++ * free_obsolete_znodes - free obsolete znodes.
++ * @c: UBIFS file-system description object
++ *
++ * At the end of commit end, obsolete znodes are freed.
++ */
++static void free_obsolete_znodes(struct ubifs_info *c)
++{
++      struct ubifs_znode *znode, *cnext;
 +
-+static int __init request_pin(struct platform_device *pdev,
-+                            unsigned int pin, const char *name)
++      cnext = c->cnext;
++      do {
++              znode = cnext;
++              cnext = znode->cnext;
++              if (test_bit(OBSOLETE_ZNODE, &znode->flags))
++                      kfree(znode);
++              else {
++                      znode->cnext = NULL;
++                      atomic_long_inc(&c->clean_zn_cnt);
++                      atomic_long_inc(&ubifs_clean_zn_cnt);
++              }
++      } while (cnext != c->cnext);
++}
++
++/**
++ * return_gap_lebs - return LEBs used by the in-gap commit method.
++ * @c: UBIFS file-system description object
++ *
++ * This function clears the "taken" flag for the LEBs which were used by the
++ * "commit in-the-gaps" method.
++ */
++static int return_gap_lebs(struct ubifs_info *c)
 +{
-+      if (gpio_request(pin, name)) {
-+              dev_warn(&pdev->dev, "failed to request %s pin\n", name);
-+              return -1;
++      int *p, err;
++
++      if (!c->gap_lebs)
++              return 0;
++
++      dbg_cmt("");
++      for (p = c->gap_lebs; *p != -1; p++) {
++              err = ubifs_change_one_lp(c, *p, LPROPS_NC, LPROPS_NC, 0,
++                                        LPROPS_TAKEN, 0);
++              if (err)
++                      return err;
 +      }
 +
-+      return pin;
++      kfree(c->gap_lebs);
++      c->gap_lebs = NULL;
++      return 0;
 +}
 +
-+static struct smc_timing at32_cf_timing __initdata = {
-+      .ncs_read_setup         = 30,
-+      .nrd_setup              = 100,
-+      .ncs_write_setup        = 30,
-+      .nwe_setup              = 100,
++/**
++ * ubifs_tnc_end_commit - update the TNC for commit end.
++ * @c: UBIFS file-system description object
++ *
++ * Write the dirty znodes.
++ */
++int ubifs_tnc_end_commit(struct ubifs_info *c)
++{
++      int err;
 +
-+      .ncs_read_pulse         = 360,
-+      .nrd_pulse              = 290,
-+      .ncs_write_pulse        = 360,
-+      .nwe_pulse              = 290,
++      if (!c->cnext)
++              return 0;
 +
-+      .read_cycle             = 420,
-+      .write_cycle            = 420,
-+};
++      err = return_gap_lebs(c);
++      if (err)
++              return err;
 +
-+static int __init at32_cf_probe(struct platform_device *pdev)
-+{
-+      struct at32_cf_socket   *cf;
-+      struct cf_platform_data *board = pdev->dev.platform_data;
-+      struct resource         *res_skt;
-+      int                     irq;
-+      int                     ret;
++      err = write_index(c);
++      if (err)
++              return err;
 +
-+      dev_dbg(&pdev->dev, "probe");
++      mutex_lock(&c->tnc_mutex);
 +
-+      if (!board)
-+              return -ENXIO;
++      dbg_cmt("TNC height is %d", c->zroot.znode->level + 1);
 +
-+      res_skt = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      if (!res_skt)
-+              return -ENXIO;
++      free_obsolete_znodes(c);
 +
-+      irq = platform_get_irq(pdev, 0);
-+      if (irq < 0)
-+              return irq;
++      c->cnext = NULL;
++      kfree(c->ilebs);
++      c->ilebs = NULL;
 +
-+      cf = kzalloc(sizeof(struct at32_cf_socket), GFP_KERNEL);
-+      if (!cf)
-+              return -ENOMEM;
++      mutex_unlock(&c->tnc_mutex);
 +
-+      cf->detect_pin = -1;
-+      cf->reset_pin = -1;
-+      cf->vcc_pin = -1;
-+      cf->ready_pin = -1;
-+      cf->cf_cs = board->cs;
++      return 0;
++}
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/tnc_misc.c avr32-2.6/fs/ubifs/tnc_misc.c
+--- linux-2.6.25.6/fs/ubifs/tnc_misc.c 1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/tnc_misc.c      2008-06-12 15:09:45.603817614 +0200
+@@ -0,0 +1,496 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Adrian Hunter
++ *          Artem Bityutskiy (Битюцкий Артём)
++ */
 +
-+      if (board->detect_pin != GPIO_PIN_NONE)
-+              cf->detect_pin = request_pin(pdev, board->detect_pin,
-+                                           "cf_detect");
-+      if (board->reset_pin != GPIO_PIN_NONE)
-+              cf->reset_pin = request_pin(pdev, board->reset_pin,
-+                                          "cf_reset");
-+      if (board->vcc_pin != GPIO_PIN_NONE)
-+              cf->vcc_pin = request_pin(pdev, board->vcc_pin,
-+                                        "cf_vcc");
-+      if (board->ready_pin != GPIO_PIN_NONE)
-+              /* READY is also used for irq through EIM */
-+              cf->ready_pin = board->ready_pin;
++/*
++ * This file contains miscelanious TNC-related functions shared betweend
++ * different files. This file does not form any logically separate TNC
++ * sub-system. The file was created because there is a lot of TNC code and
++ * putting it all in one file would make that file too big and unreadable.
++ */
 +
-+      debug(cf, 2, "pins: detect=%d reset=%d vcc=%d\n",
-+            cf->detect_pin, cf->reset_pin, cf->vcc_pin);
++#include "ubifs.h"
 +
-+      cf->socket.pci_irq = irq;
-+      cf->socket.ops = &at32_cf_ops;
-+      cf->socket.resource_ops = &pccard_static_ops;
-+      cf->socket.dev.parent = &pdev->dev;
-+      cf->socket.owner = THIS_MODULE;
-+      cf->socket.features =
-+              SS_CAP_MEM_ALIGN | SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
-+      cf->socket.map_size = CF_RES_SIZE;
++/**
++ * ubifs_tnc_levelorder_next - next TNC tree element in levelorder traversal.
++ * @zr: root of the subtree to traverse
++ * @znode: previous znode
++ *
++ * This function implements levelorder TNC traversal. The LNC is ignored.
++ * Returns the next element or %NULL if @znode is already the last one.
++ */
++struct ubifs_znode *ubifs_tnc_levelorder_next(struct ubifs_znode *zr,
++                                            struct ubifs_znode *znode)
++{
++      int level, iip, level_search = 0;
++      struct ubifs_znode *zn;
 +
-+      cf->res_attr.start = res_skt->start + CF_ATTR_OFFSET;
-+      cf->res_attr.end = cf->res_attr.start + CF_RES_SIZE - 1;
-+      cf->res_attr.name = "attribute";
-+      cf->res_attr.flags = IORESOURCE_MEM;
-+      ret = request_resource(res_skt, &cf->res_attr);
-+      if (ret)
-+              goto err_request_res_attr;
++      ubifs_assert(zr);
 +
-+      cf->res_mem.start = res_skt->start + CF_MEM_OFFSET;
-+      cf->res_mem.end = cf->res_mem.start + CF_RES_SIZE - 1;
-+      cf->res_mem.name = "memory";
-+      cf->res_mem.flags = IORESOURCE_MEM;
-+      ret = request_resource(res_skt, &cf->res_mem);
-+      if (ret)
-+              goto err_request_res_mem;
++      if (unlikely(!znode))
++              return zr;
 +
-+      cf->res_io.start = res_skt->start + CF_IO_OFFSET;
-+      cf->res_io.end = cf->res_io.start + CF_RES_SIZE - 1;
-+      cf->res_io.name = "io";
-+      cf->res_io.flags = IORESOURCE_MEM;
-+      ret = request_resource(res_skt, &cf->res_io);
-+      if (ret)
-+              goto err_request_res_io;
++      if (unlikely(znode == zr)) {
++              if (znode->level == 0)
++                      return NULL;
++              return ubifs_tnc_find_child(zr, 0);
++      }
 +
-+      cf->socket.io_offset = cf->res_io.start;
++      level = znode->level;
 +
-+      if (cf->detect_pin >= 0) {
-+              ret = request_irq(gpio_to_irq(cf->detect_pin), at32_cf_irq,
-+                                IRQF_SHARED, "cf_detect", cf);
-+              if (ret) {
-+                      debug(cf, 1,
-+                            "failed to request cf_detect interrupt\n");
-+                      goto err_detect_irq;
++      iip = znode->iip;
++      while (1) {
++              ubifs_assert(znode->level <= zr->level);
++
++              /*
++               * First walk up until there is a znode with next branch to
++               * look at.
++               */
++              while (znode->parent != zr && iip >= znode->parent->child_cnt) {
++                      znode = znode->parent;
++                      iip = znode->iip;
 +              }
-+      }
 +
-+      cf->present = at32_cf_present(cf);
++              if (unlikely(znode->parent == zr &&
++                           iip >= znode->parent->child_cnt)) {
++                      /* This level is done, switch to the lower one */
++                      level -= 1;
++                      if (level_search || level < 0)
++                              /*
++                               * We were already looking for znode at lower
++                               * level ('level_search'). As we are here
++                               * again, it just does not exist. Or all levels
++                               * were finished ('level < 0').
++                               */
++                              return NULL;
 +
-+      /* Setup SMC timings */
-+      smc_set_timing(&cf->smc, &at32_cf_timing);
++                      level_search = 1;
++                      iip = -1;
++                      znode = ubifs_tnc_find_child(zr, 0);
++                      ubifs_assert(znode);
++              }
 +
-+      cf->smc.bus_width = 2;
-+      cf->smc.nrd_controlled = 1;
-+      cf->smc.nwe_controlled = 1;
-+      cf->smc.nwait_mode = 0;
-+      cf->smc.byte_write = 0;
-+      cf->smc.tdf_cycles = 8;
-+      cf->smc.tdf_mode = 0;
++              /* Switch to the next index */
++              zn = ubifs_tnc_find_child(znode->parent, iip + 1);
++              if (!zn) {
++                      /* No more children to look at, we have walk up */
++                      iip = znode->parent->child_cnt;
++                      continue;
++              }
 +
-+      ret = smc_set_configuration(cf->cf_cs, &cf->smc);
-+      if (ret) {
-+              debug(cf, 1, "failed to configure SMC\n", ret);
-+              goto err_smc;
-+      }
++              /* Walk back down to the level we came from ('level') */
++              while (zn->level != level) {
++                      znode = zn;
++                      zn = ubifs_tnc_find_child(zn, 0);
++                      if (!zn) {
++                              /*
++                               * This path is not too deep so it does not
++                               * reach 'level'. Try next path.
++                               */
++                              iip = znode->iip;
++                              break;
++                      }
++              }
 +
-+      ret = pcmcia_register_socket(&cf->socket);
-+      if (ret) {
-+              debug(cf, 1, "failed to register socket: %d\n", ret);
-+              goto err_register_socket;
++              if (zn) {
++                      ubifs_assert(zn->level >= 0);
++                      return zn;
++              }
 +      }
++}
 +
-+      if (cf->reset_pin >= 0)
-+              gpio_direction_output(cf->reset_pin, 0);
++/**
++ * ubifs_search_zbranch - search znode branch.
++ * @c: UBIFS file-system description object
++ * @znode: znode to search in
++ * @key: key to search for
++ * @n: znode branch slot number is returned here
++ *
++ * This is a helper function which search branch with key @key in @znode using
++ * binary search. The result of the search may be:
++ *   o exact match, then %1 is returned, and the slot number of the branch is
++ *     stored in @n;
++ *   o no exact match, then %0 is returned and the slot number of the left
++ *     closest branch is returned in @n; the slot if all keys in this znode are
++ *     greater than @key, then %-1 is returned in @n.
++ */
++int ubifs_search_zbranch(const struct ubifs_info *c,
++                       const struct ubifs_znode *znode,
++                       const union ubifs_key *key, int *n)
++{
++      int beg = 0, end = znode->child_cnt, uninitialized_var(mid);
++      int uninitialized_var(cmp);
++      const struct ubifs_zbranch *zbr = &znode->zbranch[0];
++
++      ubifs_assert(end > beg);
++
++      while (end > beg) {
++              mid = (beg + end) >> 1;
++              cmp = keys_cmp(c, key, &zbr[mid].key);
++              if (cmp > 0)
++                      beg = mid + 1;
++              else if (cmp < 0)
++                      end = mid;
++              else {
++                      *n = mid;
++                      return 1;
++              }
++      }
 +
-+      platform_set_drvdata(pdev, cf);
++      *n = end - 1;
 +
-+      dev_info(&pdev->dev, "Atmel SMC CF interface at 0x%08lx\n",
-+               (unsigned long)res_skt->start);
++      /* The insert point is after *n */
++      ubifs_assert(*n >= -1 && *n < znode->child_cnt);
++      if (*n == -1)
++              ubifs_assert(keys_cmp(c, key, &zbr[0].key) < 0);
++      else
++              ubifs_assert(keys_cmp(c, key, &zbr[*n].key) > 0);
++      if (*n + 1 < znode->child_cnt)
++              ubifs_assert(keys_cmp(c, key, &zbr[*n + 1].key) < 0);
 +
 +      return 0;
++}
 +
-+err_register_socket:
-+err_smc:
-+      if (cf->detect_pin >= 0)
-+              free_irq(gpio_to_irq(cf->detect_pin), cf);
-+err_detect_irq:
-+      release_resource(&cf->res_io);
-+err_request_res_io:
-+      release_resource(&cf->res_mem);
-+err_request_res_mem:
-+      release_resource(&cf->res_attr);
-+err_request_res_attr:
-+      if (cf->vcc_pin >= 0)
-+              gpio_free(cf->vcc_pin);
-+      if (cf->reset_pin >= 0)
-+              gpio_free(cf->reset_pin);
-+      if (cf->detect_pin >= 0)
-+              gpio_free(cf->detect_pin);
-+      kfree(cf);
++/**
++ * ubifs_tnc_postorder_first - find first znode to do postorder tree traversal.
++ * @znode: znode to start at (root of the sub-tree to traverse)
++ *
++ * Find the lowest leftmost znode in a subtree of the TNC tree. The LNC is
++ * ignored.
++ */
++struct ubifs_znode *ubifs_tnc_postorder_first(struct ubifs_znode *znode)
++{
++      if (unlikely(!znode))
++              return NULL;
 +
-+      return ret;
++      while (znode->level > 0) {
++              struct ubifs_znode *child;
++
++              child = ubifs_tnc_find_child(znode, 0);
++              if (!child)
++                      return znode;
++              znode = child;
++      }
++
++      return znode;
 +}
 +
-+static int __exit at32_cf_remove(struct platform_device *pdev)
++/**
++ * ubifs_tnc_postorder_next - next TNC tree element in postorder traversal.
++ * @znode: previous znode
++ *
++ * This function implements postorder TNC traversal. The LNC is ignored.
++ * Returns the next element or %NULL if @znode is already the last one.
++ */
++struct ubifs_znode *ubifs_tnc_postorder_next(struct ubifs_znode *znode)
 +{
-+      struct at32_cf_socket *cf = platform_get_drvdata(pdev);
++      struct ubifs_znode *zn;
 +
-+      pcmcia_unregister_socket(&cf->socket);
-+      if (cf->detect_pin >= 0) {
-+              free_irq(gpio_to_irq(cf->detect_pin), cf);
-+              gpio_free(cf->detect_pin);
-+      }
-+      if (cf->vcc_pin >= 0)
-+              gpio_free(cf->vcc_pin);
-+      if (cf->reset_pin >= 0)
-+              gpio_free(cf->reset_pin);
++      ubifs_assert(znode);
++      if (unlikely(!znode->parent))
++              return NULL;
 +
-+      release_resource(&cf->res_io);
-+      release_resource(&cf->res_mem);
-+      release_resource(&cf->res_attr);
-+      kfree(cf);
-+      platform_set_drvdata(pdev, NULL);
++      /* Switch to the next index in the parent */
++      zn = ubifs_tnc_find_child(znode->parent, znode->iip + 1);
++      if (!zn)
++              /* This is in fact the last child, return parent */
++              return znode->parent;
 +
-+      return 0;
++      /* Go to the first znode in this new subtree */
++      return ubifs_tnc_postorder_first(zn);
 +}
 +
-+static struct platform_driver at32_cf_driver = {
-+      .remove         = __exit_p(at32_cf_remove),
-+      .driver         = {
-+              .name   = "at32_cf",
-+              .owner  = THIS_MODULE,
-+      },
-+};
-+
-+static int __init at32_cf_init(void)
++/**
++ * ubifs_destroy_tnc_subtree - destroy all znodes connected to a subtree.
++ * @znode: znode defining subtree to destroy
++ *
++ * This function destroys subtree of the TNC tree. Returns number of clean
++ * znodes in the subtree.
++ */
++long ubifs_destroy_tnc_subtree(struct ubifs_znode *znode)
 +{
-+      int ret;
++      struct ubifs_znode *zn = ubifs_tnc_postorder_first(znode);
++      long clean_freed = 0;
++      int n;
 +
-+      ret = platform_driver_probe(&at32_cf_driver, at32_cf_probe);
-+      if (ret)
-+              printk(KERN_ERR "at32_cf: probe failed: %d\n", ret);
-+      return ret;
++      ubifs_assert(zn);
++      while (1) {
++              for (n = 0; n < zn->child_cnt; n++) {
++                      if (!zn->zbranch[n].znode)
++                              continue;
++
++                      if (zn->level > 0 &&
++                          !ubifs_zn_dirty(zn->zbranch[n].znode))
++                              clean_freed += 1;
++
++                      cond_resched();
++                      kfree(zn->zbranch[n].znode);
++              }
++
++              if (zn == znode) {
++                      if (!ubifs_zn_dirty(zn))
++                              clean_freed += 1;
++                      kfree(zn);
++                      return clean_freed;
++              }
++
++              zn = ubifs_tnc_postorder_next(zn);
++      }
 +}
 +
-+static void __exit at32_cf_exit(void)
++/**
++ * read_znode - read an indexing node from flash and fill znode.
++ * @c: UBIFS file-system description object
++ * @lnum: LEB of the indexing node to read
++ * @offs: node offset
++ * @len: node length
++ * @znode: znode to read to
++ *
++ * This function reads an indexing node from the flash media and fills znode
++ * with the read data. Returns zero in case of success and a negative error
++ * code in case of failure. The read indexing node is validated and if anything
++ * is wrong with it, this function prints complaint messages and returns
++ * %-EINVAL.
++ */
++static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
++                    struct ubifs_znode *znode)
 +{
-+      platform_driver_unregister(&at32_cf_driver);
-+}
++      int i, err, type, cmp;
++      struct ubifs_idx_node *idx;
 +
-+module_init(at32_cf_init);
-+module_exit(at32_cf_exit);
++      idx = kmalloc(c->max_idx_node_sz, GFP_NOFS);
++      if (!idx)
++              return -ENOMEM;
 +
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Driver for SMC PCMCIA interface");
-+MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
---- a/drivers/pcmcia/Kconfig
-+++ b/drivers/pcmcia/Kconfig
-@@ -276,6 +276,13 @@
-         Say Y here to support the CompactFlash controller on the
-         PA Semi Electra eval board.
-+config AT32_CF
-+      tristate "AT32AP CompactFlash Controller"
-+      depends on PCMCIA && AVR32 && PLATFORM_AT32AP
-+      help
-+        Say Y here to support the CompactFlash controller on AT32 chips.
-+        Or choose M to compile the driver as a module named "at32_cf".
++      err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs);
++      if (err < 0) {
++              kfree(idx);
++              return err;
++      }
 +
- config PCCARD_NONSTATIC
-       tristate
---- a/drivers/pcmcia/Makefile
-+++ b/drivers/pcmcia/Makefile
-@@ -38,6 +38,7 @@
- obj-$(CONFIG_OMAP_CF)                         += omap_cf.o
- obj-$(CONFIG_AT91_CF)                         += at91_cf.o
- obj-$(CONFIG_ELECTRA_CF)                      += electra_cf.o
-+obj-$(CONFIG_AT32_CF)                         += at32_cf.o
- sa11xx_core-y                                 += soc_common.o sa11xx_base.o
- pxa2xx_core-y                                 += soc_common.o pxa2xx_base.o
---- a/drivers/serial/atmel_serial.c
-+++ b/drivers/serial/atmel_serial.c
-@@ -7,6 +7,8 @@
-  *  Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
-  *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
-  *
-+ *  DMA support added by Chip Coldwell.
-+ *
-  * 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
-@@ -33,7 +35,9 @@
- #include <linux/sysrq.h>
- #include <linux/tty_flip.h>
- #include <linux/platform_device.h>
-+#include <linux/dma-mapping.h>
- #include <linux/atmel_pdc.h>
-+#include <linux/atmel_serial.h>
- #include <asm/io.h>
-@@ -45,7 +49,9 @@
- #include <asm/arch/gpio.h>
- #endif
--#include "atmel_serial.h"
-+#define PDC_BUFFER_SIZE               512
-+/* Revisit: We should calculate this based on the actual port settings */
-+#define PDC_RX_TIMEOUT                (3 * 10)                /* 3 bytes */
- #if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
- #define SUPPORT_SYSRQ
-@@ -74,6 +80,7 @@
- #define ATMEL_ISR_PASS_LIMIT  256
-+/* UART registers. CR is write-only, hence no GET macro */
- #define UART_PUT_CR(port,v)   __raw_writel(v, (port)->membase + ATMEL_US_CR)
- #define UART_GET_MR(port)     __raw_readl((port)->membase + ATMEL_US_MR)
- #define UART_PUT_MR(port,v)   __raw_writel(v, (port)->membase + ATMEL_US_MR)
-@@ -87,8 +94,6 @@
- #define UART_PUT_BRGR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_BRGR)
- #define UART_PUT_RTOR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_RTOR)
--// #define UART_GET_CR(port)  __raw_readl((port)->membase + ATMEL_US_CR)              // is write-only
--
-  /* PDC registers */
- #define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR)
- #define UART_GET_PTSR(port)   __raw_readl((port)->membase + ATMEL_PDC_PTSR)
-@@ -101,12 +106,24 @@
- #define UART_PUT_TPR(port,v)  __raw_writel(v, (port)->membase + ATMEL_PDC_TPR)
- #define UART_PUT_TCR(port,v)  __raw_writel(v, (port)->membase + ATMEL_PDC_TCR)
--//#define UART_PUT_TNPR(port,v)       __raw_writel(v, (port)->membase + ATMEL_PDC_TNPR)
--//#define UART_PUT_TNCR(port,v)       __raw_writel(v, (port)->membase + ATMEL_PDC_TNCR)
- static int (*atmel_open_hook)(struct uart_port *);
- static void (*atmel_close_hook)(struct uart_port *);
-+struct atmel_dma_buffer {
-+      unsigned char   *buf;
-+      dma_addr_t      dma_addr;
-+      unsigned int    dma_size;
-+      unsigned int    ofs;
-+};
++      znode->child_cnt = le16_to_cpu(idx->child_cnt);
++      znode->level = le16_to_cpu(idx->level);
 +
-+struct atmel_uart_char {
-+      u16             status;
-+      u16             ch;
-+};
++      dbg_tnc("LEB %d:%d, level %d, %d branch",
++              lnum, offs, znode->level, znode->child_cnt);
 +
-+#define ATMEL_SERIAL_RINGSIZE 1024
++      if (znode->child_cnt > c->fanout || znode->level > UBIFS_MAX_LEVELS) {
++              dbg_err("current fanout %d, branch count %d",
++                      c->fanout, znode->child_cnt);
++              dbg_err("max levels %d, znode level %d",
++                      UBIFS_MAX_LEVELS, znode->level);
++              err = 1;
++              goto out_dump;
++      }
 +
- /*
-  * We wrap our port structure around the generic uart_port.
-  */
-@@ -115,6 +132,19 @@
-       struct clk              *clk;           /* uart clock */
-       unsigned short          suspended;      /* is port suspended? */
-       int                     break_active;   /* break being received */
++      for (i = 0; i < znode->child_cnt; i++) {
++              const struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
++              struct ubifs_zbranch *zbr = &znode->zbranch[i];
 +
-+      short                   use_dma_rx;     /* enable PDC receiver */
-+      short                   pdc_rx_idx;     /* current PDC RX buffer */
-+      struct atmel_dma_buffer pdc_rx[2];      /* PDC receier */
++              key_read(c, &br->key, &zbr->key);
++              zbr->lnum = le32_to_cpu(br->lnum);
++              zbr->offs = le32_to_cpu(br->offs);
++              zbr->len  = le32_to_cpu(br->len);
++              zbr->znode = NULL;
 +
-+      short                   use_dma_tx;     /* enable PDC transmitter */
-+      struct atmel_dma_buffer pdc_tx;         /* PDC transmitter */
++              /* Validate branch */
 +
-+      struct tasklet_struct   tasklet;
-+      unsigned int            irq_status;
-+      unsigned int            irq_status_prev;
++              if (zbr->lnum < c->main_first ||
++                  zbr->lnum >= c->leb_cnt || zbr->offs < 0 ||
++                  zbr->offs + zbr->len > c->leb_size || zbr->offs & 7) {
++                      dbg_err("bad branch %d", i);
++                      err = 2;
++                      goto out_dump;
++              }
 +
-+      struct circ_buf         rx_ring;
- };
- static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
-@@ -123,6 +153,38 @@
- static struct console atmel_console;
- #endif
-+static inline struct atmel_uart_port *
-+to_atmel_uart_port(struct uart_port *uart)
-+{
-+      return container_of(uart, struct atmel_uart_port, uart);
-+}
++              switch (key_type(c, &zbr->key)) {
++              case UBIFS_INO_KEY:
++              case UBIFS_DATA_KEY:
++              case UBIFS_DENT_KEY:
++              case UBIFS_XENT_KEY:
++                      break;
++              default:
++                      dbg_msg("bad key type at slot %d: %s", i,
++                              DBGKEY(&zbr->key));
++                      err = 3;
++                      goto out_dump;
++              }
 +
-+#ifdef CONFIG_SERIAL_ATMEL_PDC
-+static bool atmel_use_dma_rx(struct uart_port *port)
-+{
-+      struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
++              if (znode->level)
++                      continue;
 +
-+      return atmel_port->use_dma_rx;
-+}
++              type = key_type(c, &zbr->key);
++              if (c->ranges[type].max_len == 0) {
++                      if (zbr->len != c->ranges[type].len) {
++                              dbg_err("bad target node (type %d) length (%d)",
++                                      type, zbr->len);
++                              dbg_err("have to be %d", c->ranges[type].len);
++                              err = 4;
++                              goto out_dump;
++                      }
++              } else if (zbr->len < c->ranges[type].min_len ||
++                         zbr->len > c->ranges[type].max_len) {
++                      dbg_err("bad target node (type %d) length (%d)",
++                              type, zbr->len);
++                      dbg_err("have to be in range of %d-%d",
++                              c->ranges[type].min_len,
++                              c->ranges[type].max_len);
++                      err = 5;
++                      goto out_dump;
++              }
++      }
 +
-+static bool atmel_use_dma_tx(struct uart_port *port)
-+{
-+      struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
++      /*
++       * Ensure that the next key is greater or equivalent to the
++       * previous one.
++       */
++      for (i = 0; i < znode->child_cnt - 1; i++) {
++              const union ubifs_key *key1, *key2;
++
++              key1 = &znode->zbranch[i].key;
++              key2 = &znode->zbranch[i + 1].key;
++
++              cmp = keys_cmp(c, key1, key2);
++              if (cmp > 0) {
++                      dbg_err("bad key order (keys %d and %d)", i, i + 1);
++                      err = 6;
++                      goto out_dump;
++              } else if (cmp == 0 && !is_hash_key(c, key1)) {
++                      /* These can only be keys with colliding hash */
++                      dbg_err("keys %d and %d are not hashed but equivalent",
++                              i, i + 1);
++                      err = 7;
++                      goto out_dump;
++              }
++      }
 +
-+      return atmel_port->use_dma_tx;
-+}
-+#else
-+static bool atmel_use_dma_rx(struct uart_port *port)
-+{
-+      return false;
-+}
++      kfree(idx);
++      return 0;
 +
-+static bool atmel_use_dma_tx(struct uart_port *port)
-+{
-+      return false;
++out_dump:
++      ubifs_err("bad indexing node at LEB %d:%d, error %d", lnum, offs, err);
++      dbg_dump_node(c, idx);
++      kfree(idx);
++      return -EINVAL;
 +}
-+#endif
-+
- /*
-  * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
-  */
-@@ -142,8 +204,8 @@
- #ifdef CONFIG_ARCH_AT91RM9200
-       if (cpu_is_at91rm9200()) {
-               /*
--               * AT91RM9200 Errata #39: RTS0 is not internally connected to PA21.
--               *  We need to drive the pin manually.
-+               * AT91RM9200 Errata #39: RTS0 is not internally connected
-+               * to PA21. We need to drive the pin manually.
-                */
-               if (port->mapbase == AT91RM9200_BASE_US0) {
-                       if (mctrl & TIOCM_RTS)
-@@ -204,7 +266,12 @@
-  */
- static void atmel_stop_tx(struct uart_port *port)
- {
--      UART_PUT_IDR(port, ATMEL_US_TXRDY);
-+      if (atmel_use_dma_tx(port)) {
-+              /* disable PDC transmit */
-+              UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
-+              UART_PUT_IDR(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE);
-+      } else
-+              UART_PUT_IDR(port, ATMEL_US_TXRDY);
- }
- /*
-@@ -212,7 +279,17 @@
-  */
- static void atmel_start_tx(struct uart_port *port)
- {
--      UART_PUT_IER(port, ATMEL_US_TXRDY);
-+      if (atmel_use_dma_tx(port)) {
-+              if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN)
-+                      /* The transmitter is already running.  Yes, we
-+                         really need this.*/
-+                      return;
 +
-+              UART_PUT_IER(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE);
-+              /* re-enable PDC transmit */
-+              UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
-+      } else
-+              UART_PUT_IER(port, ATMEL_US_TXRDY);
- }
- /*
-@@ -220,7 +297,12 @@
-  */
- static void atmel_stop_rx(struct uart_port *port)
- {
--      UART_PUT_IDR(port, ATMEL_US_RXRDY);
-+      if (atmel_use_dma_rx(port)) {
-+              /* disable PDC receive */
-+              UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS);
-+              UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
-+      } else
-+              UART_PUT_IDR(port, ATMEL_US_RXRDY);
- }
- /*
-@@ -228,7 +310,8 @@
-  */
- static void atmel_enable_ms(struct uart_port *port)
- {
--      UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC);
-+      UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC
-+                      | ATMEL_US_DCDIC | ATMEL_US_CTSIC);
- }
- /*
-@@ -243,22 +326,63 @@
- }
- /*
-+ * Stores the incoming character in the ring buffer
++/**
++ * ubifs_load_znode - load znode to TNC cache.
++ * @c: UBIFS file-system description object
++ * @zbr: znode branch
++ * @parent: znode's parent
++ * @iip: index in parent
++ *
++ * This function loads znode pointed to by @zbr into the TNC cache and
++ * returns pointer to it in case of success and a negative error code in case
++ * of failure.
 + */
-+static void
-+atmel_buffer_rx_char(struct uart_port *port, unsigned int status,
-+                   unsigned int ch)
++struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c,
++                                   struct ubifs_zbranch *zbr,
++                                   struct ubifs_znode *parent, int iip)
 +{
-+      struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-+      struct circ_buf *ring = &atmel_port->rx_ring;
-+      struct atmel_uart_char *c;
++      int err;
++      struct ubifs_znode *znode;
 +
-+      if (!CIRC_SPACE(ring->head, ring->tail, ATMEL_SERIAL_RINGSIZE))
-+              /* Buffer overflow, ignore char */
-+              return;
++      ubifs_assert(!zbr->znode);
++      /*
++       * A slab cache is not presently used for znodes because the znode size
++       * depends on the fanout which is stored in the superblock.
++       */
++      znode = kzalloc(c->max_znode_sz, GFP_NOFS);
++      if (!znode)
++              return ERR_PTR(-ENOMEM);
++
++      err = read_znode(c, zbr->lnum, zbr->offs, zbr->len, znode);
++      if (err)
++              goto out;
++
++      atomic_long_inc(&c->clean_zn_cnt);
++
++      /*
++       * Increment the global clean znode counter as well. It is OK that
++       * global and per-FS clean znode counters may be inconsistent for some
++       * short time (because we might be preempted at this point), the global
++       * one is only used in shrinker.
++       */
++      atomic_long_inc(&ubifs_clean_zn_cnt);
 +
-+      c = &((struct atmel_uart_char *)ring->buf)[ring->head];
-+      c->status       = status;
-+      c->ch           = ch;
++      zbr->znode = znode;
++      znode->parent = parent;
++      znode->time = get_seconds();
++      znode->iip = iip;
 +
-+      /* Make sure the character is stored before we update head. */
-+      smp_wmb();
++      return znode;
 +
-+      ring->head = (ring->head + 1) & (ATMEL_SERIAL_RINGSIZE - 1);
++out:
++      kfree(znode);
++      return ERR_PTR(err);
 +}
 +
-+/*
-+ * Deal with parity, framing and overrun errors.
++/**
++ * ubifs_tnc_read_node - read a leaf node from the flash media.
++ * @c: UBIFS file-system description object
++ * @zbr: key and position of the node
++ * @node: node is returned here
++ *
++ * This function reads a node defined by @zbr from the flash media. Returns
++ * zero in case of success or a negative negative error code in case of
++ * failure.
 + */
-+static void atmel_pdc_rxerr(struct uart_port *port, unsigned int status)
++int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
++                      void *node)
 +{
-+      /* clear error */
-+      UART_PUT_CR(port, ATMEL_US_RSTSTA);
++      union ubifs_key key1, *key = &zbr->key;
++      int err, type = key_type(c, key);
++      struct ubifs_wbuf *wbuf;
++
++      ubifs_assert(!zbr->leaf);
++
++      /*
++       * 'zbr' has to point to on-flash node. The node may sit in a bud and
++       * may even be in a write buffer, so we have to take care about this.
++       */
++      wbuf = ubifs_get_wbuf(c, zbr->lnum);
++      if (wbuf)
++              err = ubifs_read_node_wbuf(wbuf, node, type, zbr->len,
++                                         zbr->lnum, zbr->offs);
++      else
++              err = ubifs_read_node(c, node, type, zbr->len, zbr->lnum,
++                                    zbr->offs);
++
++      if (err) {
++              dbg_tnc("key %s", DBGKEY(key));
++              return err;
++      }
 +
-+      if (status & ATMEL_US_RXBRK) {
-+              /* ignore side-effect */
-+              status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);
-+              port->icount.brk++;
++      /* Make sure the key of the read node is correct */
++      key_read(c, key, &key1);
++      if (memcmp(node + UBIFS_KEY_OFFSET, &key1, c->key_len)) {
++              ubifs_err("bad key in node at LEB %d:%d",
++                        zbr->lnum, zbr->offs);
++              dbg_tnc("looked for key %s found node's key %s",
++                      DBGKEY(key), DBGKEY1(&key1));
++              dbg_dump_node(c, node);
++              return -EINVAL;
 +      }
-+      if (status & ATMEL_US_PARE)
-+              port->icount.parity++;
-+      if (status & ATMEL_US_FRAME)
-+              port->icount.frame++;
-+      if (status & ATMEL_US_OVRE)
-+              port->icount.overrun++;
++
++      return 0;
 +}
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/ubifs.h avr32-2.6/fs/ubifs/ubifs.h
+--- linux-2.6.25.6/fs/ubifs/ubifs.h    1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/ubifs.h 2008-06-12 15:09:45.603817614 +0200
+@@ -0,0 +1,1605 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Artem Bityutskiy (Битюцкий Артём)
++ *          Adrian Hunter
++ */
++
++/* Implementation version 0.7 */
++
++#ifndef __UBIFS_H__
++#define __UBIFS_H__
++
++#include <asm/div64.h>
++#include <linux/statfs.h>
++#include <linux/fs.h>
++#include <linux/err.h>
++#include <linux/sched.h>
++#include <linux/vmalloc.h>
++#include <linux/spinlock.h>
++#include <linux/mutex.h>
++#include <linux/rwsem.h>
++#include <linux/mtd/ubi.h>
++#include <linux/pagemap.h>
++#include <linux/backing-dev.h>
++#include "ubifs-media.h"
++
++/* Version of this UBIFS implementation */
++#define UBIFS_VERSION 1
++
++/* Normal UBIFS messages */
++#define ubifs_msg(fmt, ...) \
++              printk(KERN_NOTICE "UBIFS: " fmt "\n", ##__VA_ARGS__)
++/* UBIFS error messages */
++#define ubifs_err(fmt, ...)                                                  \
++      printk(KERN_ERR "UBIFS error (pid %d): %s: " fmt "\n", current->pid, \
++             __func__, ##__VA_ARGS__)
++/* UBIFS warning messages */
++#define ubifs_warn(fmt, ...)                                         \
++      printk(KERN_WARNING "UBIFS warning (pid %d): %s: " fmt "\n", \
++             current->pid, __func__, ##__VA_ARGS__)
++
++/* UBIFS file system VFS magic number */
++#define UBIFS_SUPER_MAGIC 0x24051905
++
++/* Number of UBIFS blocks per VFS page */
++#define UBIFS_BLOCKS_PER_PAGE (PAGE_CACHE_SIZE / UBIFS_BLOCK_SIZE)
++#define UBIFS_BLOCKS_PER_PAGE_SHIFT (PAGE_CACHE_SHIFT - UBIFS_BLOCK_SHIFT)
++
++/* "File system end of life" sequence number watermark */
++#define SQNUM_WARN_WATERMARK 0xFFFFFFFF00000000ULL
++#define SQNUM_WATERMARK      0xFFFFFFFFFF000000ULL
++
++/* Minimum amount of data UBIFS writes to the flash */
++#define MIN_WRITE_SZ (UBIFS_DATA_NODE_SZ + 8)
 +
 +/*
-  * Characters received (called from interrupt handler)
-  */
- static void atmel_rx_chars(struct uart_port *port)
- {
--      struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
--      struct tty_struct *tty = port->info->tty;
--      unsigned int status, ch, flg;
-+      struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-+      unsigned int status, ch;
-       status = UART_GET_CSR(port);
-       while (status & ATMEL_US_RXRDY) {
-               ch = UART_GET_CHAR(port);
--              port->icount.rx++;
--
--              flg = TTY_NORMAL;
--
-               /*
-                * note that the error handling code is
-                * out of the main execution path
-@@ -266,15 +390,14 @@
-               if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
-                                      | ATMEL_US_OVRE | ATMEL_US_RXBRK)
-                            || atmel_port->break_active)) {
--                      UART_PUT_CR(port, ATMEL_US_RSTSTA);     /* clear error */
-+
-+                      /* clear error */
-+                      UART_PUT_CR(port, ATMEL_US_RSTSTA);
-+
-                       if (status & ATMEL_US_RXBRK
-                           && !atmel_port->break_active) {
--                              status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);    /* ignore side-effect */
--                              port->icount.brk++;
-                               atmel_port->break_active = 1;
-                               UART_PUT_IER(port, ATMEL_US_RXBRK);
--                              if (uart_handle_break(port))
--                                      goto ignore_char;
-                       } else {
-                               /*
-                                * This is either the end-of-break
-@@ -287,52 +410,30 @@
-                               status &= ~ATMEL_US_RXBRK;
-                               atmel_port->break_active = 0;
-                       }
--                      if (status & ATMEL_US_PARE)
--                              port->icount.parity++;
--                      if (status & ATMEL_US_FRAME)
--                              port->icount.frame++;
--                      if (status & ATMEL_US_OVRE)
--                              port->icount.overrun++;
--
--                      status &= port->read_status_mask;
--
--                      if (status & ATMEL_US_RXBRK)
--                              flg = TTY_BREAK;
--                      else if (status & ATMEL_US_PARE)
--                              flg = TTY_PARITY;
--                      else if (status & ATMEL_US_FRAME)
--                              flg = TTY_FRAME;
-               }
--              if (uart_handle_sysrq_char(port, ch))
--                      goto ignore_char;
--
--              uart_insert_char(port, status, ATMEL_US_OVRE, ch, flg);
--
--      ignore_char:
-+              atmel_buffer_rx_char(port, status, ch);
-               status = UART_GET_CSR(port);
-       }
--      tty_flip_buffer_push(tty);
-+      tasklet_schedule(&atmel_port->tasklet);
- }
- /*
-- * Transmit characters (called from interrupt handler)
-+ * Transmit characters (called from tasklet with TXRDY interrupt
-+ * disabled)
-  */
- static void atmel_tx_chars(struct uart_port *port)
- {
-       struct circ_buf *xmit = &port->info->xmit;
--      if (port->x_char) {
-+      if (port->x_char && UART_GET_CSR(port) & ATMEL_US_TXRDY) {
-               UART_PUT_CHAR(port, port->x_char);
-               port->icount.tx++;
-               port->x_char = 0;
--              return;
-       }
--      if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
--              atmel_stop_tx(port);
-+      if (uart_circ_empty(xmit) || uart_tx_stopped(port))
-               return;
--      }
-       while (UART_GET_CSR(port) & ATMEL_US_TXRDY) {
-               UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
-@@ -345,8 +446,88 @@
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
--      if (uart_circ_empty(xmit))
--              atmel_stop_tx(port);
-+      if (!uart_circ_empty(xmit))
-+              UART_PUT_IER(port, ATMEL_US_TXRDY);
-+}
++ * Currently we do not support inode number overlapping and re-using, so this
++ * watermark defines dangerous inode number level. This should be fixed later,
++ * although it is difficult to exceed current limit. Another option is to use
++ * 64-bit inode numbers, but this means more overhead.
++ */
++#define INUM_WARN_WATERMARK 0xFFF00000
++#define INUM_WATERMARK      0xFFFFFF00
++
++/* Largest key size supported in this implementation */
++#define CUR_MAX_KEY_LEN UBIFS_SK_LEN
++
++/* Maximum number of entries in each LPT (LEB category) heap */
++#define LPT_HEAP_SZ 256
++
++/*
++ * Background thread name pattern. The numbers are UBI device and volume
++ * numbers.
++ */
++#define BGT_NAME_PATTERN "ubifs_bgt%d_%d"
++
++/* Default write-buffer synchronization timeout (5 secs) */
++#define DEFAULT_WBUF_TIMEOUT (5 * HZ)
++
++/* Maximum possible inode number (only 32-bit inodes are supported now) */
++#define MAX_INUM 0xFFFFFFFF
++
++/* Number of non-data journal heads */
++#define NONDATA_JHEADS_CNT 2
++
++/* Garbage collector head */
++#define GCHD   0
++/* Base journal head number */
++#define BASEHD 1
++/* First "general purpose" journal head */
++#define DATAHD 2
++
++/* 'No change' value for 'ubifs_change_lp()' */
++#define LPROPS_NC 0x80000001
++
++/*
++ * There is no notion of truncation key because truncation nodes do not exist
++ * in TNC. However, when replaying, it is handy to introduce fake "truncation"
++ * keys for truncation nodes because the code becomes simpler. So we define
++ * %UBIFS_TRUN_KEY type.
++ */
++#define UBIFS_TRUN_KEY UBIFS_KEY_TYPES_CNT
 +
 +/*
-+ * receive interrupt handler.
++ * How much a directory entry/extended attribute entry adds to the parent/host
++ * inode.
 + */
-+static void
-+atmel_handle_receive(struct uart_port *port, unsigned int pending)
-+{
-+      struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-+
-+      if (atmel_use_dma_rx(port)) {
-+              /*
-+               * PDC receive. Just schedule the tasklet and let it
-+               * figure out the details.
-+               *
-+               * TODO: We're not handling error flags correctly at
-+               * the moment.
-+               */
-+              if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) {
-+                      UART_PUT_IDR(port, (ATMEL_US_ENDRX
-+                                              | ATMEL_US_TIMEOUT));
-+                      tasklet_schedule(&atmel_port->tasklet);
-+              }
++#define CALC_DENT_SIZE(name_len) ALIGN(UBIFS_DENT_NODE_SZ + (name_len) + 1, 8)
 +
-+              if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE |
-+                              ATMEL_US_FRAME | ATMEL_US_PARE))
-+                      atmel_pdc_rxerr(port, pending);
-+      }
++/* How much an extended attribute adds to the host inode */
++#define CALC_XATTR_BYTES(data_len) ALIGN(UBIFS_INO_NODE_SZ + (data_len) + 1, 8)
 +
-+      /* Interrupt receive */
-+      if (pending & ATMEL_US_RXRDY)
-+              atmel_rx_chars(port);
-+      else if (pending & ATMEL_US_RXBRK) {
-+              /*
-+               * End of break detected. If it came along with a
-+               * character, atmel_rx_chars will handle it.
-+               */
-+              UART_PUT_CR(port, ATMEL_US_RSTSTA);
-+              UART_PUT_IDR(port, ATMEL_US_RXBRK);
-+              atmel_port->break_active = 0;
-+      }
-+}
++/*
++ * Znodes which were not touched for 'OLD_ZNODE_AGE' seconds are considered
++ * "old", and znode which were touched last 'YOUNG_ZNODE_AGE' seconds ago are
++ * considered "young". This is used by shrinker when selecting znode to trim
++ * off.
++ */
++#define OLD_ZNODE_AGE 20
++#define YOUNG_ZNODE_AGE 5
 +
 +/*
-+ * transmit interrupt handler. (Transmit is IRQF_NODELAY safe)
++ * Some compressors, like LZO, may end up with more data then the input buffer.
++ * So UBIFS always allocates larger output buffer, to be sure the compressor
++ * will not corrupt memory in case of worst case compression.
 + */
-+static void
-+atmel_handle_transmit(struct uart_port *port, unsigned int pending)
-+{
-+      struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
++#define WORST_COMPR_FACTOR 2
 +
-+      if (atmel_use_dma_tx(port)) {
-+              /* PDC transmit */
-+              if (pending & (ATMEL_US_ENDTX | ATMEL_US_TXBUFE)) {
-+                      UART_PUT_IDR(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE);
-+                      tasklet_schedule(&atmel_port->tasklet);
-+              }
-+      } else {
-+              /* Interrupt transmit */
-+              if (pending & ATMEL_US_TXRDY) {
-+                      UART_PUT_IDR(port, ATMEL_US_TXRDY);
-+                      tasklet_schedule(&atmel_port->tasklet);
-+              }
-+      }
-+}
++/* Maximum expected tree height for use by bottom_up_buf */
++#define BOTTOM_UP_HEIGHT 64
 +
 +/*
-+ * status flags interrupt handler.
++ * Znode flags (actually, bit numbers which store the flags).
++ *
++ * DIRTY_ZNODE: znode is dirty
++ * COW_ZNODE: znode is being committed and a new instance of this znode has to
++ *            be created before changing this znode
++ * OBSOLETE_ZNODE: znode is obsolete, which means it was deleted, but it is
++ *                 still in the commit list and the ongoing commit operation
++ *                 will commit it, and delete this znode after it is done
 + */
-+static void
-+atmel_handle_status(struct uart_port *port, unsigned int pending,
-+                  unsigned int status)
-+{
-+      struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-+
-+      if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC
-+                              | ATMEL_US_CTSIC)) {
-+              atmel_port->irq_status = status;
-+              tasklet_schedule(&atmel_port->tasklet);
-+      }
- }
- /*
-@@ -355,47 +536,255 @@
- static irqreturn_t atmel_interrupt(int irq, void *dev_id)
- {
-       struct uart_port *port = dev_id;
--      struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
-       unsigned int status, pending, pass_counter = 0;
--      status = UART_GET_CSR(port);
--      pending = status & UART_GET_IMR(port);
--      while (pending) {
--              /* Interrupt receive */
--              if (pending & ATMEL_US_RXRDY)
--                      atmel_rx_chars(port);
--              else if (pending & ATMEL_US_RXBRK) {
-+      do {
-+              status = UART_GET_CSR(port);
-+              pending = status & UART_GET_IMR(port);
-+              if (!pending)
-+                      break;
++enum {
++      DIRTY_ZNODE    = 0,
++      COW_ZNODE      = 1,
++      OBSOLETE_ZNODE = 2
++};
 +
-+              atmel_handle_receive(port, pending);
-+              atmel_handle_status(port, pending, status);
-+              atmel_handle_transmit(port, pending);
-+      } while (pass_counter++ < ATMEL_ISR_PASS_LIMIT);
++/*
++ * Commit states.
++ *
++ * COMMIT_RESTING: commit is not wanted
++ * COMMIT_BACKGROUND: background commit has been requested
++ * COMMIT_REQUIRED: commit is required
++ * COMMIT_RUNNING_BACKGROUND: background commit is running
++ * COMMIT_RUNNING_REQUIRED: commit is running and it is required
++ * COMMIT_BROKEN: commit failed
++ */
++enum {
++      COMMIT_RESTING = 0,
++      COMMIT_BACKGROUND,
++      COMMIT_REQUIRED,
++      COMMIT_RUNNING_BACKGROUND,
++      COMMIT_RUNNING_REQUIRED,
++      COMMIT_BROKEN,
++};
 +
-+      return IRQ_HANDLED;
-+}
++/*
++ * 'ubifs_scan_a_node()' return values.
++ *
++ * SCANNED_GARBAGE:  scanned garbage
++ * SCANNED_EMPTY_SPACE: scanned empty space
++ * SCANNED_A_NODE: scanned a valid node
++ * SCANNED_A_CORRUPT_NODE: scanned a corrupted node
++ * SCANNED_A_BAD_PAD_NODE: scanned a padding node with invalid pad length
++ *
++ * Greater than zero means: 'scanned that number of padding bytes'
++ */
++enum {
++      SCANNED_GARBAGE        = 0,
++      SCANNED_EMPTY_SPACE    = -1,
++      SCANNED_A_NODE         = -2,
++      SCANNED_A_CORRUPT_NODE = -3,
++      SCANNED_A_BAD_PAD_NODE = -4,
++};
 +
 +/*
-+ * Called from tasklet with ENDTX and TXBUFE interrupts disabled.
++ * LPT cnode flag bits.
++ *
++ * DIRTY_CNODE: cnode is dirty
++ * COW_CNODE: cnode is being committed and must be copied before writing
++ * OBSOLETE_CNODE: cnode is being committed and has been copied (or deleted),
++ * so it can (and must) be freed when the commit is finished
 + */
-+static void atmel_tx_dma(struct uart_port *port)
-+{
-+      struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-+      struct circ_buf *xmit = &port->info->xmit;
-+      struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
-+      int count;
++enum {
++      DIRTY_CNODE    = 0,
++      COW_CNODE      = 1,
++      OBSOLETE_CNODE = 2,
++};
 +
-+      xmit->tail += pdc->ofs;
-+      xmit->tail &= UART_XMIT_SIZE - 1;
++/*
++ * Dirty flag bits (lpt_drty_flgs) for LPT special nodes.
++ *
++ * LTAB_DIRTY: ltab node is dirty
++ * LSAVE_DIRTY: lsave node is dirty
++ */
++enum {
++      LTAB_DIRTY  = 1,
++      LSAVE_DIRTY = 2,
++};
 +
-+      port->icount.tx += pdc->ofs;
-+      pdc->ofs = 0;
++/*
++ * Return codes used by the garbage collector.
++ * @LEB_FREED: the logical eraseblock was freed and is ready to use
++ * @LEB_FREED_IDX: indexing LEB was freed and can be used only after the commit
++ * @LEB_RETAINED: the logical eraseblock was freed and retained for GC purposes
++ */
++enum {
++      LEB_FREED,
++      LEB_FREED_IDX,
++      LEB_RETAINED,
++};
 +
-+      if (!uart_circ_empty(xmit)) {
-+              /* more to transmit - setup next transfer */
++/**
++ * struct ubifs_old_idx - index node obsoleted since last commit start.
++ * @rb: rb-tree node
++ * @lnum: LEB number of obsoleted index node
++ * @offs: offset of obsoleted index node
++ */
++struct ubifs_old_idx {
++      struct rb_node rb;
++      int lnum;
++      int offs;
++};
 +
-+              /* disable PDC transmit */
-+              UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
-+              dma_sync_single_for_device(port->dev,
-+                                         pdc->dma_addr,
-+                                         pdc->dma_size,
-+                                         DMA_TO_DEVICE);
++/* The below union makes it easier to deal with keys */
++union ubifs_key {
++      uint8_t u8[CUR_MAX_KEY_LEN];
++      uint32_t u32[CUR_MAX_KEY_LEN/4];
++      uint64_t u64[CUR_MAX_KEY_LEN/8];
++      __le32 j32[CUR_MAX_KEY_LEN/4];
++};
 +
-+              count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
-+              pdc->ofs = count;
++/**
++ * struct ubifs_scan_node - UBIFS scanned node information.
++ * @list: list of scanned nodes
++ * @key: key of node scanned (if it has one)
++ * @sqnum: sequence number
++ * @type: type of node scanned
++ * @offs: offset with LEB of node scanned
++ * @len: length of node scanned
++ * @node: raw node
++ */
++struct ubifs_scan_node {
++      struct list_head list;
++      union ubifs_key key;
++      unsigned long long sqnum;
++      int type;
++      int offs;
++      int len;
++      void *node;
++};
 +
-+              UART_PUT_TPR(port, pdc->dma_addr + xmit->tail);
-+              UART_PUT_TCR(port, count);
-+              /* re-enable PDC transmit and interrupts */
-+              UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
-+              UART_PUT_IER(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE);
-+      } else {
-+              /* nothing left to transmit - disable the transmitter */
++/**
++ * struct ubifs_scan_leb - UBIFS scanned LEB information.
++ * @lnum: logical eraseblock number
++ * @nodes_cnt: number of nodes scanned
++ * @nodes: list of struct ubifs_scan_node
++ * @endpt: end point (and therefore the start of empty space)
++ * @ecc: read returned -EBADMSG
++ * @buf: buffer containing entire LEB scanned
++ */
++struct ubifs_scan_leb {
++      int lnum;
++      int nodes_cnt;
++      struct list_head nodes;
++      int endpt;
++      int ecc;
++      void *buf;
++};
 +
-+              /* disable PDC transmit */
-+              UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
-+      }
++/**
++ * struct ubifs_gced_idx_leb - garbage-collected indexing LEB.
++ * @list: list
++ * @lnum: LEB number
++ * @unmap: OK to unmap this LEB
++ *
++ * This data structure is used to temporary store garbage-collected indexing
++ * LEBs - they are not released immediately, but only after the next commit.
++ * This is needed to guarantee recoverability.
++ */
++struct ubifs_gced_idx_leb {
++      struct list_head list;
++      int lnum;
++      int unmap;
++};
 +
-+      if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-+              uart_write_wakeup(port);
-+}
++/**
++ * struct ubifs_inode - UBIFS in-memory inode description.
++ * @vfs_inode: VFS inode description object
++ * @creat_sqnum: sequence number at time of creation
++ * @xattr_size: summarized size of all extended attributes in bytes, protected
++ *              by @inode->i_lock
++ * @xattr_cnt: count of extended attributes this inode has
++ * @xattr_names: sum of lengths of all extended attribute names belonging to
++ *               this inode
++ * @dirty: non-zero if the inode is dirty
++ * @xattr: non-zero if this is an extended attribute inode
++ * @budgeted: non-zero if the inode has been budgeted (used for debugging)
++ * @budg_mutex: serializes inode budgeting and write-back
++ * @flags: inode flags (@UBIFS_COMPR_FL, etc)
++ * @compr_type: default compression type used for this inode
++ * @data_len: length of the data attached to the inode
++ * @data: inode's data
++ *
++ * UBIFS has its own inode mutex, besides the VFS 'i_mutex'. The reason for
++ * this is budgeting - UBIFS has to budget each operation. So, if an operation
++ * is going to mark an inode dirty, it has to allocate budget for this. It
++ * cannot just mark it dirty because there is no guarantee there will be enough
++ * flash space when it is time to write the inode back. This means that UBIFS
++ * has to have full control over "clean <-> dirty" transitions of inodes (and
++ * pages actually, but it is easy for pages, because we have
++ * 'ubifs_prepare_write()' which is called _before_ every page change). But
++ * unfortunately, VFS marks inodes dirty in many places, and it does not ask
++ * the file-system if it is allowed to do so (there is a notifier, but it is
++ * not enough), i.e., there is no mechanism to synchronize with this. So we
++ * introduce our own dirty flag to UBIFS inodes and our own inode mutex to
++ * serialize "clean <-> dirty" transitions.
++ */
++struct ubifs_inode {
++      struct inode vfs_inode;
++      unsigned long long creat_sqnum;
++      long long xattr_size;
++      int xattr_cnt;
++      int xattr_names;
++      unsigned int dirty:1;
++      unsigned int xattr:1;
++#ifdef CONFIG_UBIFS_FS_DEBUG
++      unsigned int budgeted:1;
++#endif
++      struct mutex budg_mutex;
++      int flags;
++      int compr_type;
++      int data_len;
++      void *data;
++};
 +
-+static void atmel_rx_from_ring(struct uart_port *port)
-+{
-+      struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-+      struct circ_buf *ring = &atmel_port->rx_ring;
-+      unsigned int flg;
-+      unsigned int status;
++/**
++ * struct ubifs_unclean_leb - records a LEB recovered under read-only mode.
++ * @list: list
++ * @lnum: LEB number of recovered LEB
++ * @endpt: offset where recovery ended
++ *
++ * This structure records a LEB identified during recovery that needs to be
++ * cleaned but was not because UBIFS was mounted read-only. The information
++ * is used to clean the LEB when remounting to read-write mode.
++ */
++struct ubifs_unclean_leb {
++      struct list_head list;
++      int lnum;
++      int endpt;
++};
 +
-+      while (ring->head != ring->tail) {
-+              struct atmel_uart_char c;
++/*
++ * LEB properties flags.
++ *
++ * LPROPS_UNCAT: not categorized
++ * LPROPS_DIRTY: dirty > 0, not index
++ * LPROPS_DIRTY_IDX: dirty + free > UBIFS_CH_SZ and index
++ * LPROPS_FREE: free > 0, not empty, not index
++ * LPROPS_HEAP_CNT: number of heaps used for storing categorized LEBs
++ * LPROPS_EMPTY: LEB is empty, not taken
++ * LPROPS_FREEABLE: free + dirty == leb_size, not index, not taken
++ * LPROPS_FRDI_IDX: free + dirty == leb_size and index, may be taken
++ * LPROPS_CAT_MASK: mask for the LEB categories above
++ * LPROPS_TAKEN: LEB was taken (this flag is not saved on the media)
++ * LPROPS_INDEX: LEB contains indexing nodes (this flag also exists on flash)
++ */
++enum {
++      LPROPS_UNCAT     =  0,
++      LPROPS_DIRTY     =  1,
++      LPROPS_DIRTY_IDX =  2,
++      LPROPS_FREE      =  3,
++      LPROPS_HEAP_CNT  =  3,
++      LPROPS_EMPTY     =  4,
++      LPROPS_FREEABLE  =  5,
++      LPROPS_FRDI_IDX  =  6,
++      LPROPS_CAT_MASK  = 15,
++      LPROPS_TAKEN     = 16,
++      LPROPS_INDEX     = 32,
++};
 +
-+              /* Make sure c is loaded after head. */
-+              smp_rmb();
++/**
++ * struct ubifs_lprops - logical eraseblock properties.
++ * @free: amount of free space in bytes
++ * @dirty: amount of dirty space in bytes
++ * @flags: LEB properties flags (see above)
++ * @lnum: LEB number
++ * @list: list of same-category lprops (for LPROPS_EMPTY and LPROPS_FREEABLE)
++ * @hpos: heap position in heap of same-category lprops (other categories)
++ */
++struct ubifs_lprops {
++      int free;
++      int dirty;
++      int flags;
++      int lnum;
++      union {
++              struct list_head list;
++              int hpos;
++      };
++};
 +
-+              c = ((struct atmel_uart_char *)ring->buf)[ring->tail];
++/**
++ * struct ubifs_lpt_lprops - LPT logical eraseblock properties.
++ * @free: amount of free space in bytes
++ * @dirty: amount of dirty space in bytes
++ * @tgc: trivial GC flag (1 => unmap after commit end)
++ * @cmt: commit flag (1 => reserved for commit)
++ */
++struct ubifs_lpt_lprops {
++      int free;
++      int dirty;
++      unsigned tgc : 1;
++      unsigned cmt : 1;
++};
 +
-+              ring->tail = (ring->tail + 1) & (ATMEL_SERIAL_RINGSIZE - 1);
++/**
++ * struct ubifs_lp_stats - statistics of eraseblocks in the main area.
++ * @empty_lebs: number of empty LEBs
++ * @taken_empty_lebs: number of taken LEBs
++ * @idx_lebs: number of indexing LEBs
++ * @total_free: total free space in bytes
++ * @total_dirty: total dirty space in bytes
++ * @total_used: total used space in bytes (includes only data LEBs)
++ * @total_dead: total dead space in bytes (includes only data LEBs)
++ * @total_dark: total dark space in bytes (includes only data LEBs)
++ *
++ * N.B. total_dirty and total_used are different to other total_* fields,
++ * because they account _all_ LEBs, not just data LEBs.
++ *
++ * 'taken_empty_lebs' counts the LEBs that are in the transient state of having
++ * been 'taken' for use but not yet written to. 'taken_empty_lebs' is needed
++ * to account correctly for gc_lnum, otherwise 'empty_lebs' could be used
++ * by itself (in which case 'unused_lebs' would be a better name). In the case
++ * of gc_lnum, it is 'taken' at mount time or whenever a LEB is retained by GC,
++ * but unlike other empty LEBs that are 'taken', it may not be written straight
++ * away (i.e. before the next commit start or unmount), so either gc_lnum must
++ * be specially accounted for, or the current approach followed i.e. count it
++ * under 'taken_empty_lebs'.
++ */
++struct ubifs_lp_stats {
++      int empty_lebs;
++      int taken_empty_lebs;
++      int idx_lebs;
++      long long total_free;
++      long long total_dirty;
++      long long total_used;
++      long long total_dead;
++      long long total_dark;
++};
 +
-+              port->icount.rx++;
-+              status = c.status;
-+              flg = TTY_NORMAL;
++struct ubifs_nnode;
 +
-+              /*
-+               * note that the error handling code is
-+               * out of the main execution path
-+               */
-+              if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
-+                                     | ATMEL_US_OVRE | ATMEL_US_RXBRK))) {
-+                      if (status & ATMEL_US_RXBRK) {
-+                              /* ignore side-effect */
-+                              status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);
-+
-+                              port->icount.brk++;
-+                              if (uart_handle_break(port))
-+                                      continue;
-+                      }
-+                      if (status & ATMEL_US_PARE)
-+                              port->icount.parity++;
-+                      if (status & ATMEL_US_FRAME)
-+                              port->icount.frame++;
-+                      if (status & ATMEL_US_OVRE)
-+                              port->icount.overrun++;
++/**
++ * struct ubifs_cnode - LEB Properties Tree common node.
++ * @parent: parent nnode
++ * @cnext: next cnode to commit
++ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE)
++ * @iip: index in parent
++ * @level: level in the tree (zero for pnodes, greater than zero for nnodes)
++ * @num: node number
++ */
++struct ubifs_cnode {
++      struct ubifs_nnode *parent;
++      struct ubifs_cnode *cnext;
++      unsigned long flags;
++      int iip;
++      int level;
++      int num;
++};
 +
-+                      status &= port->read_status_mask;
++/**
++ * struct ubifs_pnode - LEB Properties Tree leaf node.
++ * @parent: parent nnode
++ * @cnext: next cnode to commit
++ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE)
++ * @iip: index in parent
++ * @level: level in the tree (always zero for pnodes)
++ * @num: node number
++ * @lprops: LEB properties array
++ */
++struct ubifs_pnode {
++      struct ubifs_nnode *parent;
++      struct ubifs_cnode *cnext;
++      unsigned long flags;
++      int iip;
++      int level;
++      int num;
++      struct ubifs_lprops lprops[UBIFS_LPT_FANOUT];
++};
 +
-+                      if (status & ATMEL_US_RXBRK)
-+                              flg = TTY_BREAK;
-+                      else if (status & ATMEL_US_PARE)
-+                              flg = TTY_PARITY;
-+                      else if (status & ATMEL_US_FRAME)
-+                              flg = TTY_FRAME;
-+              }
++/**
++ * struct ubifs_nbranch - LEB Properties Tree internal node branch.
++ * @lnum: LEB number of child
++ * @offs: offset of child
++ * @nnode: nnode child
++ * @pnode: pnode child
++ * @cnode: cnode child
++ */
++struct ubifs_nbranch {
++      int lnum;
++      int offs;
++      union {
++              struct ubifs_nnode *nnode;
++              struct ubifs_pnode *pnode;
++              struct ubifs_cnode *cnode;
++      };
++};
 +
++/**
++ * struct ubifs_nnode - LEB Properties Tree internal node.
++ * @parent: parent nnode
++ * @cnext: next cnode to commit
++ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE)
++ * @iip: index in parent
++ * @level: level in the tree (always greater than zero for nnodes)
++ * @num: node number
++ * @nbranch: branches to child nodes
++ */
++struct ubifs_nnode {
++      struct ubifs_nnode *parent;
++      struct ubifs_cnode *cnext;
++      unsigned long flags;
++      int iip;
++      int level;
++      int num;
++      struct ubifs_nbranch nbranch[UBIFS_LPT_FANOUT];
++};
 +
-+              if (uart_handle_sysrq_char(port, c.ch))
-+                      continue;
++/**
++ * struct ubifs_lpt_heap - heap of categorized lprops.
++ * @arr: heap array
++ * @cnt: number in heap
++ * @max_cnt: maximum number allowed in heap
++ *
++ * There are %LPROPS_HEAP_CNT heaps.
++ */
++struct ubifs_lpt_heap {
++      struct ubifs_lprops **arr;
++      int cnt;
++      int max_cnt;
++};
 +
-+              uart_insert_char(port, status, ATMEL_US_OVRE, c.ch, flg);
-+      }
++/*
++ * Return codes for LPT scan callback function.
++ *
++ * LPT_SCAN_CONTINUE: continue scanning
++ * LPT_SCAN_ADD: add the LEB properties scanned to the tree in memory
++ * LPT_SCAN_STOP: stop scanning
++ */
++enum {
++      LPT_SCAN_CONTINUE = 0,
++      LPT_SCAN_ADD = 1,
++      LPT_SCAN_STOP = 2,
++};
 +
-+      /*
-+       * Drop the lock here since it might end up calling
-+       * uart_start(), which takes the lock.
-+       */
-+      spin_unlock(&port->lock);
-+      tty_flip_buffer_push(port->info->tty);
-+      spin_lock(&port->lock);
-+}
++struct ubifs_info;
 +
-+static void atmel_rx_from_dma(struct uart_port *port)
-+{
-+      struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-+      struct tty_struct *tty = port->info->tty;
-+      struct atmel_dma_buffer *pdc;
-+      int rx_idx = atmel_port->pdc_rx_idx;
-+      unsigned int head;
-+      unsigned int tail;
-+      unsigned int count;
++/* Callback used by the 'ubifs_lpt_scan_nolock()' function */
++typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c,
++                                     const struct ubifs_lprops *lprops,
++                                     int in_tree, void *data);
 +
-+      do {
-+              /* Reset the UART timeout early so that we don't miss one */
-+              UART_PUT_CR(port, ATMEL_US_STTTO);
++/**
++ * struct ubifs_wbuf - UBIFS write-buffer.
++ * @c: UBIFS file-system description object
++ * @buf: write-buffer (of min. flash I/O unit size)
++ * @lnum: logical eraseblock number the write-buffer points to
++ * @offs: write-buffer offset in this logical eraseblock
++ * @avail: number of bytes available in the write-buffer
++ * @used:  number of used bytes in the write-buffer
++ * @dtype: type of data stored in this LEB (%UBI_LONGTERM, %UBI_SHORTTERM,
++ * %UBI_UNKNOWN)
++ * @jhead: journal head the mutex belongs to (note, needed only to shut lockdep
++ * up by 'mutex_lock_nested()).
++ * @sync_callback: write-buffer synchronization callback
++ * @io_mutex: serializes write-buffer I/O
++ * @lock: serializes @buf, @lnum, @offs, @avail, @used, @next_ino and @inodes
++ * fields
++ * @timer: write-buffer timer
++ * @timeout: timer expire interval in jiffies
++ * @need_sync: it is set if its timer expired and needs sync
++ * @next_ino: points to the next position of the following inode number
++ * @inodes: stores the inode numbers of the nodes which are in wbuf
++ *
++ * The write-buffer synchronization callback is called when the write-buffer is
++ * synchronized in order to notify how much space was wasted due to
++ * write-buffer padding and how much free space is left in the LEB.
++ *
++ * Note: the fields @buf, @lnum, @offs, @avail and @used can be read under
++ * spin-lock or mutex because they are written under both mutex and spin-lock.
++ * @buf is appended to under mutex but overwritten under both mutex and
++ * spin-lock. Thus the data between @buf and @buf + @used can be read under
++ * spinlock.
++ */
++struct ubifs_wbuf {
++      struct ubifs_info *c;
++      void *buf;
++      int lnum;
++      int offs;
++      int avail;
++      int used;
++      int dtype;
++      int jhead;
++      int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad);
++      struct mutex io_mutex;
++      spinlock_t lock;
++      struct timer_list timer;
++      int timeout;
++      int need_sync;
++      int next_ino;
++      ino_t *inodes;
++};
 +
-+              pdc = &atmel_port->pdc_rx[rx_idx];
-+              head = UART_GET_RPR(port) - pdc->dma_addr;
-+              tail = pdc->ofs;
++/**
++ * struct ubifs_bud - bud logical eraseblock.
++ * @lnum: logical eraseblock number
++ * @start: where the (uncommitted) bud data starts
++ * @jhead: journal head number this bud belongs to
++ * @list: link in the list buds belonging to the same journal head
++ * @rb: link in the tree of all buds
++ */
++struct ubifs_bud {
++      int lnum;
++      int start;
++      int jhead;
++      struct list_head list;
++      struct rb_node rb;
++};
 +
-+              /* If the PDC has switched buffers, RPR won't contain
-+               * any address within the current buffer. Since head
-+               * is unsigned, we just need a one-way comparison to
-+               * find out.
-+               *
-+               * In this case, we just need to consume the entire
-+               * buffer and resubmit it for DMA. This will clear the
-+               * ENDRX bit as well, so that we can safely re-enable
-+               * all interrupts below.
-+               */
-+              head = min(head, pdc->dma_size);
-+
-+              if (likely(head != tail)) {
-+                      dma_sync_single_for_cpu(port->dev, pdc->dma_addr,
-+                                      pdc->dma_size, DMA_FROM_DEVICE);
-+
-                       /*
--                       * End of break detected. If it came along
--                       * with a character, atmel_rx_chars will
--                       * handle it.
-+                       * head will only wrap around when we recycle
-+                       * the DMA buffer, and when that happens, we
-+                       * explicitly set tail to 0. So head will
-+                       * always be greater than tail.
-                        */
--                      UART_PUT_CR(port, ATMEL_US_RSTSTA);
--                      UART_PUT_IDR(port, ATMEL_US_RXBRK);
--                      atmel_port->break_active = 0;
-+                      count = head - tail;
++/**
++ * struct ubifs_jhead - journal head.
++ * @wbuf: head's write-buffer
++ * @buds_list: list of bud LEBs belonging to this journal head
++ *
++ * Note, the @buds list is protected by the @c->buds_lock.
++ */
++struct ubifs_jhead {
++      struct ubifs_wbuf wbuf;
++      struct list_head buds_list;
++};
 +
-+                      tty_insert_flip_string(tty, pdc->buf + pdc->ofs, count);
++/**
++ * struct ubifs_zbranch - key/coordinate/length branch stored in znodes.
++ * @key: key
++ * @znode: znode address in memory
++ * @lnum: LEB number of the indexing node
++ * @offs: offset of the indexing node within @lnum
++ * @len: target node length
++ */
++struct ubifs_zbranch {
++      union ubifs_key key;
++      union {
++              struct ubifs_znode *znode;
++              void *leaf;
++      };
++      int lnum;
++      int offs;
++      int len;
++};
 +
-+                      dma_sync_single_for_device(port->dev, pdc->dma_addr,
-+                                      pdc->dma_size, DMA_FROM_DEVICE);
++/**
++ * struct ubifs_znode - in-memory representation of an indexing node.
++ * @parent: parent znode or NULL if it is the root
++ * @cnext: next znode to commit
++ * @flags: znode flags (%DIRTY_ZNODE, %COW_ZNODE or %OBSOLETE_ZNODE)
++ * @time: last access time (seconds)
++ * @level: level of the entry in the TNC tree
++ * @child_cnt: count of child znodes
++ * @iip: index in parent's zbranch array
++ * @alt: lower bound of key range has altered i.e. child inserted at slot 0
++ * @lnum: LEB number of the corresponding indexing node
++ * @offs: offset of the corresponding indexing node
++ * @len: length  of the corresponding indexing node
++ * @zbranch: array of znode branches (@c->fanout elements)
++ */
++struct ubifs_znode {
++      struct ubifs_znode *parent;
++      struct ubifs_znode *cnext;
++      unsigned long flags;
++      unsigned long time;
++      int level;
++      int child_cnt;
++      int iip;
++      int alt;
++#ifdef CONFIG_UBIFS_FS_DEBUG
++      int lnum, offs, len;
++#endif
++      struct ubifs_zbranch zbranch[];
++};
 +
-+                      port->icount.rx += count;
-+                      pdc->ofs = head;
-+              }
++/**
++ * struct ubifs_node_range - node length range description data structure.
++ * @len: fixed node length
++ * @min_len: minimum possible node length
++ * @max_len: maximum possible node length
++ *
++ * If @max_len is %0, the node has fixed length @len.
++ */
++struct ubifs_node_range {
++      union {
++              int len;
++              int min_len;
++      };
++      int max_len;
++};
 +
-+              /*
-+               * If the current buffer is full, we need to check if
-+               * the next one contains any additional data.
-+               */
-+              if (head >= pdc->dma_size) {
-+                      pdc->ofs = 0;
-+                      UART_PUT_RNPR(port, pdc->dma_addr);
-+                      UART_PUT_RNCR(port, pdc->dma_size);
++/**
++ * struct ubifs_compressor - UBIFS compressor description structure.
++ * @compr_type: compressor type (%UBIFS_COMPR_LZO, etc)
++ * @cc: cryptoapi compressor handle
++ * @comp_mutex: mutex used during compression
++ * @decomp_mutex: mutex used during decompression
++ * @name: compressor name
++ * @capi_name: cryptoapi compressor name
++ */
++struct ubifs_compressor {
++      int compr_type;
++      struct crypto_comp *cc;
++      struct mutex *comp_mutex;
++      struct mutex *decomp_mutex;
++      const char *name;
++      const char *capi_name;
++};
 +
-+                      rx_idx = !rx_idx;
-+                      atmel_port->pdc_rx_idx = rx_idx;
-               }
-+      } while (head >= pdc->dma_size);
++/**
++ * struct ubifs_budget_req - budget requirements of an operation.
++ *
++ * @new_ino: non-zero if the operation adds a new inode
++ * @dirtied_ino: how many inodes the operation makes dirty
++ * @new_page: non-zero if the operation adds a new page
++ * @dirtied_page: non-zero if the operation makes a page dirty
++ * @new_dent: non-zero if the operation adds a new directory entry
++ * @mod_dent: non-zero if the operation removes or modifies an existing
++ *            directory entry
++ * @new_ino_d: now much data newly created inode contains
++ * @dirtied_ino_d: now much data dirtied inode contains
++ * @idx_growth: how much the index will supposedly grow
++ * @data_growth: how much new data the operation will supposedly add
++ * @dd_growth: how much data that makes other data dirty the operation will
++ *             supposedly add
++ *
++ * @idx_growth, @data_growth and @dd_growth are not used in budget request. The
++ * budgeting subsystem caches index and data growth values there to avoid
++ * re-calculating them when the budget is released. However, if @idx_growth is
++ * %-1, it is calculated by the release function using other fields.
++ *
++ * An inode may contain 4KiB of data at max., thus the widths of @new_ino_d
++ * is 13 bits, and @dirtied_ino_d - 15, because up to 4 inodes may be made
++ * dirty by the re-name operation.
++ */
++struct ubifs_budget_req {
++      unsigned int new_ino:1;
++      unsigned int dirtied_ino:4;
++      unsigned int new_page:1;
++      unsigned int dirtied_page:1;
++      unsigned int new_dent:1;
++      unsigned int mod_dent:1;
++      unsigned int new_ino_d:13;
++      unsigned int dirtied_ino_d:15;
++      int idx_growth;
++      int data_growth;
++      int dd_growth;
++};
 +
-+      /*
-+       * Drop the lock here since it might end up calling
-+       * uart_start(), which takes the lock.
-+       */
-+      spin_unlock(&port->lock);
-+      tty_flip_buffer_push(tty);
-+      spin_lock(&port->lock);
++/**
++ * struct ubifs_orphan - stores the inode number of an orphan.
++ * @rb: rb-tree node of rb-tree of orphans sorted by inode number
++ * @list: list head of list of orphans in order added
++ * @new_list: list head of list of orphans added since the last commit
++ * @cnext: next orphan to commit
++ * @dnext: next orphan to delete
++ * @inum: inode number
++ * @new: %1 => added since the last commit, otherwise %0
++ */
++struct ubifs_orphan {
++      struct rb_node rb;
++      struct list_head list;
++      struct list_head new_list;
++      struct ubifs_orphan *cnext;
++      struct ubifs_orphan *dnext;
++      ino_t inum;
++      int new;
++};
 +
-+      UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
-+}
--              // TODO: All reads to CSR will clear these interrupts!
--              if (pending & ATMEL_US_RIIC) port->icount.rng++;
--              if (pending & ATMEL_US_DSRIC) port->icount.dsr++;
--              if (pending & ATMEL_US_DCDIC)
-+/*
-+ * tasklet handling tty stuff outside the interrupt handler.
++/**
++ * struct ubifs_mount_opts - UBIFS-specific mount options information.
++ * @unmount_mode: selected unmount mode (%0 default, %1 normal, %2 fast)
 + */
-+static void atmel_tasklet_func(unsigned long data)
-+{
-+      struct uart_port *port = (struct uart_port *)data;
-+      struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-+      unsigned int status;
-+      unsigned int status_change;
++struct ubifs_mount_opts {
++      unsigned int unmount_mode:2;
++};
 +
-+      /* The interrupt handler does not take the lock */
-+      spin_lock(&port->lock);
++/**
++ * struct ubifs_info - UBIFS file-system description data structure
++ * (per-superblock).
++ * @vfs_sb: VFS @struct super_block object
++ *
++ * @highest_inum: highest used inode number
++ * @vfs_gen: VFS inode generation counter
++ * @max_sqnum: current global sequence number
++ * @cmt_no: commit number (last successfully completed commit)
++ * @cnt_lock: protects @highest_inum, @vfs_gen, and @max_sqnum counters
++ * @fmt_version: UBIFS on-flash format version
++ * @uuid: UUID from super block
++ *
++ * @lhead_lnum: log head logical eraseblock number
++ * @lhead_offs: log head offset
++ * @ltail_lnum: log tail logical eraseblock number (offset is always 0)
++ * @log_mutex: protects the log, @lhead_lnum, @lhead_offs, @ltail_lnum, and
++ *             @bud_bytes
++ * @min_log_bytes: minimum required number of bytes in the log
++ * @cmt_bud_bytes: used during commit to temporarily amount of bytes in
++ *                 committed buds
++ *
++ * @buds: tree of all buds indexed by bud LEB number
++ * @bud_bytes: how many bytes of flash is used by buds
++ * @buds_lock: protects the @buds tree, @bud_bytes, and per-journal head bud
++ *             lists
++ * @jhead_cnt: count of journal heads
++ * @jheads: journal heads (head zero is base head)
++ * @max_bud_bytes: maximum number of bytes allowed in buds
++ * @bg_bud_bytes: number of bud bytes when background commit is initiated
++ * @old_buds: buds to be released after commit ends
++ * @max_bud_cnt: maximum number of buds
++ *
++ * @commit_sem: synchronizes committer with other processes
++ * @cmt_state: commit state
++ * @cs_lock: commit state lock
++ * @cmt_wq: wait queue to sleep on if the log is full and a commit is running
++ * @fast_unmount: do not run journal commit before unmounting
++ * @big_lpt: flag that LPT is too big to write whole during commit
++ *
++ * @tnc_mutex: protects the Tree Node Cache (TNC), @zroot, @cnext, @enext, and
++ *             @calc_idx_sz
++ * @zroot: zbranch which points to the root index node and znode
++ * @cnext: next znode to commit
++ * @enext: next znode to commit to empty space
++ * @gap_lebs: array of LEBs used by the in-gaps commit method
++ * @cbuf: commit buffer
++ * @ileb_buf: buffer for commit in-the-gaps method
++ * @ileb_len: length of data in ileb_buf
++ * @ihead_lnum: LEB number of index head
++ * @ihead_offs: offset of index head
++ * @ilebs: pre-allocated index LEBs
++ * @ileb_cnt: number of pre-allocated index LEBs
++ * @ileb_nxt: next pre-allocated index LEBs
++ * @old_idx: tree of index nodes obsoleted since the last commit start
++ * @bottom_up_buf: a buffer which is used by 'dirty_cow_bottom_up()' in tnc.c
++ * @new_ihead_lnum: used by debugging to check ihead_lnum
++ * @new_ihead_offs: used by debugging to check ihead_offs
++ *
++ * @mst_node: master node
++ * @mst_offs: offset of valid master node
++ * @mst_mutex: protects the master node area, @mst_node, and @mst_offs
++ *
++ * @log_lebs: number of logical eraseblocks in the log
++ * @log_bytes: log size in bytes
++ * @log_last: last LEB of the log
++ * @lpt_lebs: number of LEBs used for lprops table
++ * @lpt_first: first LEB of the lprops table area
++ * @lpt_last: last LEB of the lprops table area
++ * @orph_lebs: number of LEBs used for the orphan area
++ * @orph_first: first LEB of the orphan area
++ * @orph_last: last LEB of the orphan area
++ * @main_lebs: count of LEBs in the main area
++ * @main_first: first LEB of the main area
++ * @main_bytes: main area size in bytes
++ * @default_compr: default compression type
++ *
++ * @key_hash_type: type of the key hash
++ * @key_hash: direntry key hash function
++ * @key_fmt: key format
++ * @key_len: key length
++ * @fanout: fanout of the index tree (number of links per indexing node)
++ *
++ * @min_io_size: minimal input/output unit size
++ * @min_io_shift: number of bits in @min_io_size minus one
++ * @leb_size: logical eraseblock size in bytes
++ * @half_leb_size: half LEB size
++ * @leb_cnt: count of logical eraseblocks
++ * @max_leb_cnt: maximum count of logical eraseblocks
++ * @old_leb_cnt: count of logical eraseblocks before resize
++ * @ro_media: the underlying UBI volume is read-only
++ *
++ * @dirty_pg_cnt: number of dirty pages (not used)
++ * @dirty_ino_cnt: number of dirty inodes (not used)
++ * @dirty_zn_cnt: number of dirty znodes
++ * @clean_zn_cnt: number of clean znodes
++ *
++ * @budg_idx_growth: amount of bytes budgeted for index growth
++ * @budg_data_growth: amount of bytes budgeted for cached data
++ * @budg_dd_growth: amount of bytes budgeted for cached data that will make
++ *                  other data dirty
++ * @budg_uncommitted_idx: amount of bytes were budgeted for growth of the index,
++ *                        but which still have to be taken into account because
++ *                        the index has not been committed so far
++ * @space_lock: protects @budg_idx_growth, @budg_data_growth, @budg_dd_growth,
++ *              @budg_uncommited_idx, @min_idx_lebs, @old_idx_sz, and @lst;
++ * @min_idx_lebs: minimum number of LEBs required for the index
++ * @old_idx_sz: size of index on flash
++ * @calc_idx_sz: temporary variable which is used to calculate new index size
++ *               (contains accurate new index size at end of TNC commit start)
++ * @lst: lprops statistics
++ *
++ * @page_budget: budget for a page
++ * @inode_budget: budget for an inode
++ * @dent_budget: budget for a directory entry
++ *
++ * @ref_node_alsz: size of the LEB reference node aligned to the min. flash
++ * I/O unit
++ * @mst_node_alsz: master node aligned size
++ * @min_idx_node_sz: minimum indexing node aligned on 8-bytes boundary
++ * @max_idx_node_sz: maximum indexing node aligned on 8-bytes boundary
++ * @max_inode_sz: maximum possible inode size in bytes
++ * @max_znode_sz: size of znode in bytes
++ * @dead_wm: LEB dead space watermark
++ * @dark_wm: LEB dark space watermark
++ * @block_cnt: count of 4KiB blocks on the FS
++ *
++ * @ranges: UBIFS node length ranges
++ * @ubi: UBI volume descriptor
++ * @di: UBI device information
++ * @vi: UBI volume information
++ *
++ * @orph_tree: rb-tree of orphan inode numbers
++ * @orph_list: list of orphan inode numbers in order added
++ * @orph_new: list of orphan inode numbers added since last commit
++ * @orph_cnext: next orphan to commit
++ * @orph_dnext: next orphan to delete
++ * @orphan_lock: lock for orph_tree and orph_new
++ * @orph_buf: buffer for orphan nodes
++ * @new_orphans: number of orphans since last commit
++ * @cmt_orphans: number of orphans being committed
++ * @tot_orphans: number of orphans in the rb_tree
++ * @max_orphans: maximum number of orphans allowed
++ * @ohead_lnum: orphan head LEB number
++ * @ohead_offs: orphan head offset
++ * @no_orphs: non-zero if there are no orphans
++ *
++ * @bgt: UBIFS background thread
++ * @bgt_name: background thread name
++ * @need_bgt: if background thread should run
++ * @need_wbuf_sync: if write-buffers have to be synchronized
++ *
++ * @gc_lnum: LEB number used for garbage collection
++ * @sbuf: a buffer of LEB size used by GC and replay for scanning
++ * @idx_gc: list of index LEBs that have been garbage collected
++ * @idx_gc_cnt: number of elements on the idx_gc list
++ *
++ * @infos_list: links all 'ubifs_info' objects
++ * @umount_mutex: serializes shrinker and un-mount
++ * @shrinker_run_no: shrinker run number
++ *
++ * @space_bits: number of bits needed to record free or dirty space
++ * @lpt_lnum_bits: number of bits needed to record a LEB number in the LPT
++ * @lpt_offs_bits: number of bits needed to record an offset in the LPT
++ * @lpt_spc_bits: number of bits needed to space in the LPT
++ * @pcnt_bits: number of bits needed to record pnode or nnode number
++ * @lnum_bits: number of bits needed to record LEB number
++ * @nnode_sz: size of on-flash nnode
++ * @pnode_sz: size of on-flash pnode
++ * @ltab_sz: size of on-flash LPT lprops table
++ * @lsave_sz: size of on-flash LPT save table
++ * @pnode_cnt: number of pnodes
++ * @nnode_cnt: number of nnodes
++ * @lpt_hght: height of the LPT
++ * @pnodes_have: number of pnodes in memory
++ *
++ * @lp_mutex: protects lprops table and all the other lprops-related fields
++ * @lpt_lnum: LEB number of the root nnode of the LPT
++ * @lpt_offs: offset of the root nnode of the LPT
++ * @nhead_lnum: LEB number of LPT head
++ * @nhead_offs: offset of LPT head
++ * @lpt_drty_flgs: dirty flags for LPT special nodes e.g. ltab
++ * @dirty_nn_cnt: number of dirty nnodes
++ * @dirty_pn_cnt: number of dirty pnodes
++ * @lpt_sz: LPT size
++ * @lpt_nod_buf: buffer for an on-flash nnode or pnode
++ * @lpt_buf: buffer of LEB size used by LPT
++ * @nroot: address in memory of the root nnode of the LPT
++ * @lpt_cnext: next LPT node to commit
++ * @lpt_heap: array of heaps of categorized lprops
++ * @dirty_idx: a (reverse sorted) copy of the LPROPS_DIRTY_IDX heap as at
++ *             previous commit start
++ * @uncat_list: list of un-categorized LEBs
++ * @empty_list: list of empty LEBs
++ * @freeable_list: list of freeable non-index LEBs (free + dirty == leb_size)
++ * @frdi_idx_list: list of freeable index LEBs (free + dirty == leb_size)
++ * @freeable_cnt: number of freeable LEBs in @freeable_list
++ *
++ * @ltab_lnum: LEB number of LPT's own lprops table
++ * @ltab_offs: offset of LPT's own lprops table
++ * @ltab: LPT's own lprops table
++ * @ltab_cmt: LPT's own lprops table (commit copy)
++ * @lsave_cnt: number of LEB numbers in LPT's save table
++ * @lsave_lnum: LEB number of LPT's save table
++ * @lsave_offs: offset of LPT's save table
++ * @lsave: LPT's save table
++ * @lscan_lnum: LEB number of last LPT scan
++ *
++ * @rp_size: size of the reserved pool in bytes
++ * @report_rp_size: size of the reserved pool reported to userspace
++ * @rp_uid: reserved pool user ID
++ * @rp_gid: reserved pool group ID
++ *
++ * @empty: if the UBI device is empty
++ * @replay_tree: temporary tree used during journal replay
++ * @replay_list: temporary list used during journal replay
++ * @replay_buds: list of buds to replay
++ * @cs_sqnum: sequence number of first node in the log (commit start node)
++ * @replay_sqnum: sequence number of node currently being replayed
++ * @need_recovery: file-system needs recovery
++ * @replaying: set to %1 during journal replay
++ * @unclean_leb_list: LEBs to recover when mounting ro to rw
++ * @rcvrd_mst_node: recovered master node to write when mounting ro to rw
++ * @size_tree: inode size information for recovery
++ * @remounting_rw: set while remounting from ro to rw (sb flags have MS_RDONLY)
++ * @mount_opts: UBIFS-specific mount options
++ *
++ * @dbg_buf: a buffer of LEB size used for debugging purposes
++ * @old_zroot: old index root - used by 'dbg_check_old_index()'
++ * @old_zroot_level: old index root level - used by 'dbg_check_old_index()'
++ * @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()'
++ * @failure_mode: failure mode for recovery testing
++ * @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
++ * @fail_timeout: time in jiffies when delay of failure mode expires
++ * @fail_cnt: current number of calls to failure mode I/O functions
++ * @fail_cnt_max: number of calls by which to delay failure mode
++ */
++struct ubifs_info {
++      struct super_block *vfs_sb;
++
++      ino_t highest_inum;
++      unsigned int vfs_gen;
++      unsigned long long max_sqnum;
++      unsigned long long cmt_no;
++      spinlock_t cnt_lock;
++      int fmt_version;
++      unsigned char uuid[16];
++
++      int lhead_lnum;
++      int lhead_offs;
++      int ltail_lnum;
++      struct mutex log_mutex;
++      int min_log_bytes;
++      long long cmt_bud_bytes;
++
++      struct rb_root buds;
++      long long bud_bytes;
++      spinlock_t buds_lock;
++      int jhead_cnt;
++      struct ubifs_jhead *jheads;
++      long long max_bud_bytes;
++      long long bg_bud_bytes;
++      struct list_head old_buds;
++      int max_bud_cnt;
++
++      struct rw_semaphore commit_sem;
++      int cmt_state;
++      spinlock_t cs_lock;
++      wait_queue_head_t cmt_wq;
++      unsigned int fast_unmount:1;
++      unsigned int big_lpt:1;
++
++      struct mutex tnc_mutex;
++      struct ubifs_zbranch zroot;
++      struct ubifs_znode *cnext;
++      struct ubifs_znode *enext;
++      int *gap_lebs;
++      void *cbuf;
++      void *ileb_buf;
++      int ileb_len;
++      int ihead_lnum;
++      int ihead_offs;
++      int *ilebs;
++      int ileb_cnt;
++      int ileb_nxt;
++      struct rb_root old_idx;
++      int *bottom_up_buf;
++#ifdef CONFIG_UBIFS_FS_DEBUG
++      int new_ihead_lnum;
++      int new_ihead_offs;
++#endif
 +
-+      if (atmel_use_dma_tx(port))
-+              atmel_tx_dma(port);
-+      else
-+              atmel_tx_chars(port);
-+
-+      status = atmel_port->irq_status;
-+      status_change = status ^ atmel_port->irq_status_prev;
-+
-+      if (status_change & (ATMEL_US_RI | ATMEL_US_DSR
-+                              | ATMEL_US_DCD | ATMEL_US_CTS)) {
-+              /* TODO: All reads to CSR will clear these interrupts! */
-+              if (status_change & ATMEL_US_RI)
-+                      port->icount.rng++;
-+              if (status_change & ATMEL_US_DSR)
-+                      port->icount.dsr++;
-+              if (status_change & ATMEL_US_DCD)
-                       uart_handle_dcd_change(port, !(status & ATMEL_US_DCD));
--              if (pending & ATMEL_US_CTSIC)
-+              if (status_change & ATMEL_US_CTS)
-                       uart_handle_cts_change(port, !(status & ATMEL_US_CTS));
--              if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC))
--                      wake_up_interruptible(&port->info->delta_msr_wait);
--
--              /* Interrupt transmit */
--              if (pending & ATMEL_US_TXRDY)
--                      atmel_tx_chars(port);
--              if (pass_counter++ > ATMEL_ISR_PASS_LIMIT)
--                      break;
-+              wake_up_interruptible(&port->info->delta_msr_wait);
--              status = UART_GET_CSR(port);
--              pending = status & UART_GET_IMR(port);
-+              atmel_port->irq_status_prev = status;
-       }
--      return IRQ_HANDLED;
++      struct ubifs_mst_node *mst_node;
++      int mst_offs;
++      struct mutex mst_mutex;
++
++      int log_lebs;
++      long long log_bytes;
++      int log_last;
++      int lpt_lebs;
++      int lpt_first;
++      int lpt_last;
++      int orph_lebs;
++      int orph_first;
++      int orph_last;
++      int main_lebs;
++      int main_first;
++      long long main_bytes;
++      int default_compr;
++
++      uint8_t key_hash_type;
++      uint32_t (*key_hash)(const char *str, int len);
++      int key_fmt;
++      int key_len;
++      int fanout;
++
++      int min_io_size;
++      int min_io_shift;
++      int leb_size;
++      int half_leb_size;
++      int leb_cnt;
++      int max_leb_cnt;
++      int old_leb_cnt;
++      int ro_media;
++
++      atomic_long_t dirty_pg_cnt;
++      atomic_long_t dirty_ino_cnt;
++      atomic_long_t dirty_zn_cnt;
++      atomic_long_t clean_zn_cnt;
++
++      long long budg_idx_growth;
++      long long budg_data_growth;
++      long long budg_dd_growth;
++      long long budg_uncommitted_idx;
++      spinlock_t space_lock;
++      int min_idx_lebs;
++      unsigned long long old_idx_sz;
++      unsigned long long calc_idx_sz;
++      struct ubifs_lp_stats lst;
++
++      int page_budget;
++      int inode_budget;
++      int dent_budget;
++
++      int ref_node_alsz;
++      int mst_node_alsz;
++      int min_idx_node_sz;
++      int max_idx_node_sz;
++      long long max_inode_sz;
++      int max_znode_sz;
++      int dead_wm;
++      int dark_wm;
++      int block_cnt;
++
++      struct ubifs_node_range ranges[UBIFS_NODE_TYPES_CNT];
++      struct ubi_volume_desc *ubi;
++      struct ubi_device_info di;
++      struct ubi_volume_info vi;
++
++      struct rb_root orph_tree;
++      struct list_head orph_list;
++      struct list_head orph_new;
++      struct ubifs_orphan *orph_cnext;
++      struct ubifs_orphan *orph_dnext;
++      spinlock_t orphan_lock;
++      void *orph_buf;
++      int new_orphans;
++      int cmt_orphans;
++      int tot_orphans;
++      int max_orphans;
++      int ohead_lnum;
++      int ohead_offs;
++      int no_orphs;
++
++      struct task_struct *bgt;
++      char bgt_name[sizeof(BGT_NAME_PATTERN) + 9];
++      int need_bgt;
++      int need_wbuf_sync;
++
++      int gc_lnum;
++      void *sbuf;
++      struct list_head idx_gc;
++      int idx_gc_cnt;
++
++      struct list_head infos_list;
++      struct mutex umount_mutex;
++      unsigned int shrinker_run_no;
++
++      int space_bits;
++      int lpt_lnum_bits;
++      int lpt_offs_bits;
++      int lpt_spc_bits;
++      int pcnt_bits;
++      int lnum_bits;
++      int nnode_sz;
++      int pnode_sz;
++      int ltab_sz;
++      int lsave_sz;
++      int pnode_cnt;
++      int nnode_cnt;
++      int lpt_hght;
++      int pnodes_have;
++
++      struct mutex lp_mutex;
++      int lpt_lnum;
++      int lpt_offs;
++      int nhead_lnum;
++      int nhead_offs;
++      int lpt_drty_flgs;
++      int dirty_nn_cnt;
++      int dirty_pn_cnt;
++      long long lpt_sz;
++      void *lpt_nod_buf;
++      void *lpt_buf;
++      struct ubifs_nnode *nroot;
++      struct ubifs_cnode *lpt_cnext;
++      struct ubifs_lpt_heap lpt_heap[LPROPS_HEAP_CNT];
++      struct ubifs_lpt_heap dirty_idx;
++      struct list_head uncat_list;
++      struct list_head empty_list;
++      struct list_head freeable_list;
++      struct list_head frdi_idx_list;
++      int freeable_cnt;
++
++      int ltab_lnum;
++      int ltab_offs;
++      struct ubifs_lpt_lprops *ltab;
++      struct ubifs_lpt_lprops *ltab_cmt;
++      int lsave_cnt;
++      int lsave_lnum;
++      int lsave_offs;
++      int *lsave;
++      int lscan_lnum;
++
++      long long rp_size;
++      long long report_rp_size;
++      uid_t rp_uid;
++      gid_t rp_gid;
++
++      /* The below fields are used only during mounting and re-mounting */
++      int empty;
++      struct rb_root replay_tree;
++      struct list_head replay_list;
++      struct list_head replay_buds;
++      unsigned long long cs_sqnum;
++      unsigned long long replay_sqnum;
++      int need_recovery;
++      int replaying;
++      struct list_head unclean_leb_list;
++      struct ubifs_mst_node *rcvrd_mst_node;
++      struct rb_root size_tree;
++      int remounting_rw;
++      struct ubifs_mount_opts mount_opts;
++
++#ifdef CONFIG_UBIFS_FS_DEBUG
++      void *dbg_buf;
++      struct ubifs_zbranch old_zroot;
++      int old_zroot_level;
++      unsigned long long old_zroot_sqnum;
++      int failure_mode;
++      int fail_delay;
++      unsigned long fail_timeout;
++      unsigned int fail_cnt;
++      unsigned int fail_cnt_max;
++#endif
++};
 +
-+      if (atmel_use_dma_rx(port))
-+              atmel_rx_from_dma(port);
-+      else
-+              atmel_rx_from_ring(port);
++extern struct list_head ubifs_infos;
++extern spinlock_t ubifs_infos_lock;
++extern atomic_long_t ubifs_clean_zn_cnt;
++extern struct kmem_cache *ubifs_inode_slab;
++extern struct super_operations ubifs_super_operations;
++extern struct address_space_operations ubifs_file_address_operations;
++extern struct file_operations ubifs_file_operations;
++extern struct inode_operations ubifs_file_inode_operations;
++extern struct file_operations ubifs_dir_operations;
++extern struct inode_operations ubifs_dir_inode_operations;
++extern struct inode_operations ubifs_symlink_inode_operations;
++extern struct backing_dev_info ubifs_backing_dev_info;
++extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
++
++/* io.c */
++int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len);
++int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
++                         int dtype);
++int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf);
++int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
++                  int lnum, int offs);
++int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
++                       int lnum, int offs);
++int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum,
++                   int offs, int dtype);
++int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
++                   int offs, int quiet);
++void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int pad);
++void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last);
++int ubifs_io_init(struct ubifs_info *c);
++void ubifs_pad(const struct ubifs_info *c, void *buf, int pad);
++int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf);
++int ubifs_bg_wbufs_sync(struct ubifs_info *c);
++void ubifs_wbuf_add_ino_nolock(struct ubifs_wbuf *wbuf, ino_t inum);
++int ubifs_sync_wbufs_by_inodes(struct ubifs_info *c,
++                             struct inode * const *inodes, int count);
++
++/* scan.c */
++struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
++                                int offs, void *sbuf);
++void ubifs_scan_destroy(struct ubifs_scan_leb *sleb);
++int ubifs_scan_a_node(const struct ubifs_info *c, void *buf, int len, int lnum,
++                    int offs, int quiet);
++struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum,
++                                      int offs, void *sbuf);
++void ubifs_end_scan(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
++                  int lnum, int offs);
++int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
++                 void *buf, int offs);
++void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
++                            void *buf);
++
++/* log.c */
++void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud);
++void ubifs_create_buds_lists(struct ubifs_info *c);
++int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs);
++struct ubifs_bud *ubifs_search_bud(struct ubifs_info *c, int lnum);
++struct ubifs_wbuf *ubifs_get_wbuf(struct ubifs_info *c, int lnum);
++int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum);
++int ubifs_log_end_commit(struct ubifs_info *c, int new_ltail_lnum);
++int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum);
++int ubifs_consolidate_log(struct ubifs_info *c);
++
++/* journal.c */
++int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
++                   const struct qstr *nm, const struct inode *inode,
++                   int deletion, int sync, int xent);
++int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
++                       const union ubifs_key *key, const void *buf, int len);
++int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode,
++                        int last_reference, int sync);
++int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
++                   const struct dentry *old_dentry,
++                   const struct inode *new_dir,
++                   const struct dentry *new_dentry, int sync);
++int ubifs_jnl_truncate(struct ubifs_info *c, ino_t inum,
++                     loff_t old_size, loff_t new_size);
++int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
++                         const struct inode *inode, const struct qstr *nm,
++                         int sync);
++int ubifs_jnl_write_2_inodes(struct ubifs_info *c, const struct inode *inode1,
++                           const struct inode *inode2, int sync);
++
++/* budget.c */
++int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req);
++void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req);
++int ubifs_budget_inode_op(struct ubifs_info *c, struct inode *inode,
++                        struct ubifs_budget_req *req);
++void ubifs_release_ino_dirty(struct ubifs_info *c, struct inode *inode,
++                              struct ubifs_budget_req *req);
++void ubifs_cancel_ino_op(struct ubifs_info *c, struct inode *inode,
++                       struct ubifs_budget_req *req);
++int ubifs_budget_ino_cleaning(struct ubifs_info *c, struct inode *inode,
++                            struct ubifs_budget_req *req);
++void ubifs_release_ino_clean(struct ubifs_info *c, struct inode *inode,
++                           struct ubifs_budget_req *req);
++long long ubifs_budg_get_free_space(struct ubifs_info *c);
++int ubifs_calc_min_idx_lebs(struct ubifs_info *c);
++void ubifs_convert_page_budget(struct ubifs_info *c);
++void ubifs_release_new_page_budget(struct ubifs_info *c);
++long long ubifs_calc_available(const struct ubifs_info *c);
++
++/* find.c */
++int ubifs_find_free_space(struct ubifs_info *c, int min_space, int *free,
++                        int squeeze);
++int ubifs_find_free_leb_for_idx(struct ubifs_info *c);
++int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
++                       int min_space, int pick_free);
++int ubifs_find_dirty_idx_leb(struct ubifs_info *c);
++int ubifs_save_dirty_idx_lnums(struct ubifs_info *c);
++
++/* tnc.c */
++int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
++                      struct ubifs_znode **zn, int *n);
++int ubifs_tnc_lookup(struct ubifs_info *c, const union ubifs_key *key,
++                   void *node);
++int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
++                      void *node, const struct qstr *nm);
++int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
++                   void *node, int *lnum, int *offs);
++int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
++                int offs, int len);
++int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
++                    int old_lnum, int old_offs, int lnum, int offs, int len);
++int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
++                   int lnum, int offs, int len, const struct qstr *nm);
++int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key);
++int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
++                      const struct qstr *nm);
++int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
++                         union ubifs_key *to_key);
++int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum);
++struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
++                                         union ubifs_key *key,
++                                         const struct qstr *nm);
++void ubifs_tnc_close(struct ubifs_info *c);
++int ubifs_tnc_has_node(struct ubifs_info *c, union ubifs_key *key, int level,
++                     int lnum, int offs, int is_idx);
++int ubifs_dirty_idx_node(struct ubifs_info *c, union ubifs_key *key, int level,
++                       int lnum, int offs);
++/* Shared by tnc.c for tnc_commit.c */
++void destroy_old_idx(struct ubifs_info *c);
++int is_idx_node_in_tnc(struct ubifs_info *c, union ubifs_key *key, int level,
++                     int lnum, int offs);
++int insert_old_idx_znode(struct ubifs_info *c, struct ubifs_znode *znode);
++
++/* tnc_misc.c */
++struct ubifs_znode *ubifs_tnc_levelorder_next(struct ubifs_znode *zr,
++                                            struct ubifs_znode *znode);
++int ubifs_search_zbranch(const struct ubifs_info *c,
++                       const struct ubifs_znode *znode,
++                       const union ubifs_key *key, int *n);
++struct ubifs_znode *ubifs_tnc_postorder_first(struct ubifs_znode *znode);
++struct ubifs_znode *ubifs_tnc_postorder_next(struct ubifs_znode *znode);
++long ubifs_destroy_tnc_subtree(struct ubifs_znode *zr);
++struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c,
++                                   struct ubifs_zbranch *zbr,
++                                   struct ubifs_znode *parent, int iip);
++int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
++                      void *node);
++
++/* tnc_commit.c */
++int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot);
++int ubifs_tnc_end_commit(struct ubifs_info *c);
++
++/* shrinker.c */
++int ubifs_shrinker(int nr_to_scan, gfp_t gfp_mask);
++
++/* commit.c */
++int ubifs_bg_thread(void *info);
++void ubifs_commit_required(struct ubifs_info *c);
++void ubifs_request_bg_commit(struct ubifs_info *c);
++int ubifs_run_commit(struct ubifs_info *c);
++void ubifs_recovery_commit(struct ubifs_info *c);
++int ubifs_gc_should_commit(struct ubifs_info *c);
++void ubifs_wait_for_commit(struct ubifs_info *c);
++
++/* master.c */
++int ubifs_read_master(struct ubifs_info *c);
++int ubifs_write_master(struct ubifs_info *c);
++
++/* sb.c */
++int ubifs_read_superblock(struct ubifs_info *c);
++struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c);
++int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup);
++
++/* replay.c */
++int ubifs_validate_entry(struct ubifs_info *c,
++                       const struct ubifs_dent_node *dent);
++int ubifs_replay_journal(struct ubifs_info *c);
++
++/* gc.c */
++int ubifs_garbage_collect(struct ubifs_info *c, int anyway);
++int ubifs_gc_start_commit(struct ubifs_info *c);
++int ubifs_gc_end_commit(struct ubifs_info *c);
++void ubifs_destroy_idx_gc(struct ubifs_info *c);
++int ubifs_get_idx_gc_leb(struct ubifs_info *c);
++int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp);
++
++/* orphan.c */
++int ubifs_add_orphan(struct ubifs_info *c, ino_t inum);
++void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum);
++int ubifs_orphan_start_commit(struct ubifs_info *c);
++int ubifs_orphan_end_commit(struct ubifs_info *c);
++int ubifs_mount_orphans(struct ubifs_info *c, int unclean, int read_only);
++
++/* lpt.c */
++int ubifs_calc_lpt_geom(struct ubifs_info *c);
++int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
++                        int *lpt_lebs, int *big_lpt);
++int ubifs_lpt_init(struct ubifs_info *c, int rd, int wr);
++struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum);
++struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum);
++int ubifs_lpt_scan_nolock(struct ubifs_info *c, int start_lnum, int end_lnum,
++                        ubifs_lpt_scan_callback scan_cb, void *data);
++
++/* Shared by lpt.c for lpt_commit.c */
++void ubifs_pack_lsave(struct ubifs_info *c, void *buf, int *lsave);
++void ubifs_pack_ltab(struct ubifs_info *c, void *buf,
++                   struct ubifs_lpt_lprops *ltab);
++void ubifs_pack_pnode(struct ubifs_info *c, void *buf,
++                    struct ubifs_pnode *pnode);
++void ubifs_pack_nnode(struct ubifs_info *c, void *buf,
++                    struct ubifs_nnode *nnode);
++struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c,
++                                  struct ubifs_nnode *parent, int iip);
++struct ubifs_nnode *ubifs_get_nnode(struct ubifs_info *c,
++                                  struct ubifs_nnode *parent, int iip);
++int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip);
++void ubifs_add_lpt_dirt(struct ubifs_info *c, int lnum, int dirty);
++void ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode);
++uint32_t ubifs_unpack_bits(uint8_t **addr, int *pos, int nrbits);
++struct ubifs_nnode *ubifs_first_nnode(struct ubifs_info *c, int *hght);
++
++/* lpt_commit.c */
++int ubifs_lpt_start_commit(struct ubifs_info *c);
++int ubifs_lpt_end_commit(struct ubifs_info *c);
++int ubifs_lpt_post_commit(struct ubifs_info *c);
++void ubifs_lpt_free(struct ubifs_info *c, int wr_only);
++
++/* lprops.c */
++void ubifs_get_lprops(struct ubifs_info *c);
++const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
++                                         const struct ubifs_lprops *lp,
++                                         int free, int dirty, int flags,
++                                         int idx_gc_cnt);
++void ubifs_release_lprops(struct ubifs_info *c);
++void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *stats);
++void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops,
++                    int cat);
++void ubifs_replace_cat(struct ubifs_info *c, struct ubifs_lprops *old_lprops,
++                     struct ubifs_lprops *new_lprops);
++void ubifs_ensure_cat(struct ubifs_info *c, struct ubifs_lprops *lprops);
++int ubifs_categorize_lprops(const struct ubifs_info *c,
++                          const struct ubifs_lprops *lprops);
++int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
++                      int flags_set, int flags_clean, int idx_gc_cnt);
++int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
++                      int flags_set, int flags_clean);
++int ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp);
++const struct ubifs_lprops *ubifs_fast_find_free(struct ubifs_info *c);
++const struct ubifs_lprops *ubifs_fast_find_empty(struct ubifs_info *c);
++const struct ubifs_lprops *ubifs_fast_find_freeable(struct ubifs_info *c);
++const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c);
++
++/* file.c */
++int ubifs_fsync(struct file *file, struct dentry *dentry, int datasync);
++int ubifs_setattr(struct dentry *dentry, struct iattr *attr);
++
++/* dir.c */
++struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
++                            int mode);
++int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
++                struct kstat *stat);
++
++/* xattr.c */
++int ubifs_setxattr(struct dentry *dentry, const char *name,
++                 const void *value, size_t size, int flags);
++ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
++                     size_t size);
++ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
++int ubifs_removexattr(struct dentry *dentry, const char *name);
++
++/* super.c */
++struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
++
++/* recovery.c */
++int ubifs_recover_master_node(struct ubifs_info *c);
++int ubifs_write_rcvrd_mst_node(struct ubifs_info *c);
++struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
++                                       int offs, void *sbuf, int grouped);
++struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
++                                           int offs, void *sbuf);
++int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf);
++int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf);
++int ubifs_rcvry_gc_commit(struct ubifs_info *c);
++int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key,
++                           int deletion, loff_t new_size);
++int ubifs_recover_size(struct ubifs_info *c);
++void ubifs_destroy_size_tree(struct ubifs_info *c);
++
++/* ioctl.c */
++long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
++void ubifs_set_inode_flags(struct inode *inode);
++#ifdef CONFIG_COMPAT
++long ubifs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
++#endif
 +
-+      spin_unlock(&port->lock);
- }
- /*
-@@ -403,6 +792,8 @@
-  */
- static int atmel_startup(struct uart_port *port)
- {
-+      struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-+      struct tty_struct *tty = port->info->tty;
-       int retval;
-       /*
-@@ -415,13 +806,64 @@
-       /*
-        * Allocate the IRQ
-        */
--      retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED, "atmel_serial", port);
-+      retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED,
-+                      tty ? tty->name : "atmel_serial", port);
-       if (retval) {
-               printk("atmel_serial: atmel_startup - Can't get irq\n");
-               return retval;
-       }
-       /*
-+       * Initialize DMA (if necessary)
-+       */
-+      if (atmel_use_dma_rx(port)) {
-+              int i;
++/* compressor.c */
++int __init ubifs_compressors_init(void);
++void __exit ubifs_compressors_exit(void);
++void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len,
++                  int *compr_type);
++int ubifs_decompress(const void *buf, int len, void *out, int *out_len,
++                   int compr_type);
++
++#include "debug.h"
++#include "misc.h"
++#include "key.h"
++
++#endif /* !__UBIFS_H__ */
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/ubifs-media.h avr32-2.6/fs/ubifs/ubifs-media.h
+--- linux-2.6.25.6/fs/ubifs/ubifs-media.h      1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/ubifs-media.h   2008-06-12 15:09:45.603817614 +0200
+@@ -0,0 +1,729 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Artem Bityutskiy (Битюцкий Артём)
++ *          Adrian Hunter
++ */
 +
-+              for (i = 0; i < 2; i++) {
-+                      struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
-+
-+                      pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL);
-+                      if (pdc->buf == NULL) {
-+                              if (i != 0) {
-+                                      dma_unmap_single(port->dev,
-+                                              atmel_port->pdc_rx[0].dma_addr,
-+                                              PDC_BUFFER_SIZE,
-+                                              DMA_FROM_DEVICE);
-+                                      kfree(atmel_port->pdc_rx[0].buf);
-+                              }
-+                              free_irq(port->irq, port);
-+                              return -ENOMEM;
-+                      }
-+                      pdc->dma_addr = dma_map_single(port->dev,
-+                                                     pdc->buf,
-+                                                     PDC_BUFFER_SIZE,
-+                                                     DMA_FROM_DEVICE);
-+                      pdc->dma_size = PDC_BUFFER_SIZE;
-+                      pdc->ofs = 0;
-+              }
++/*
++ * This file describes UBIFS on-flash format and contains definitions of all the
++ * relevant data structures and constants.
++ *
++ * All UBIFS on-flash objects are stored in the form of nodes. All nodes start
++ * with the UBIFS node magic number and have the same common header. Nodes
++ * always sit at 8-byte aligned positions on the media and node header sizes are
++ * also 8-byte aligned (except for the indexing node and the padding node).
++ */
 +
-+              atmel_port->pdc_rx_idx = 0;
++#ifndef __UBIFS_MEDIA_H__
++#define __UBIFS_MEDIA_H__
 +
-+              UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr);
-+              UART_PUT_RCR(port, PDC_BUFFER_SIZE);
++/* UBIFS node magic number (must not have the padding byte first or last) */
++#define UBIFS_NODE_MAGIC  0x06101831
 +
-+              UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr);
-+              UART_PUT_RNCR(port, PDC_BUFFER_SIZE);
-+      }
-+      if (atmel_use_dma_tx(port)) {
-+              struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
-+              struct circ_buf *xmit = &port->info->xmit;
++/* UBIFS on-flash format version */
++#define UBIFS_FORMAT_VERSION 4
 +
-+              pdc->buf = xmit->buf;
-+              pdc->dma_addr = dma_map_single(port->dev,
-+                                             pdc->buf,
-+                                             UART_XMIT_SIZE,
-+                                             DMA_TO_DEVICE);
-+              pdc->dma_size = UART_XMIT_SIZE;
-+              pdc->ofs = 0;
-+      }
++/* Minimum logical eraseblock size in bytes */
++#define UBIFS_MIN_LEB_SZ (15*1024)
 +
-+      /*
-        * If there is a specific "open" function (to register
-        * control line interrupts)
-        */
-@@ -437,9 +879,21 @@
-        * Finally, enable the serial port
-        */
-       UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
--      UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);               /* enable xmit & rcvr */
-+      /* enable xmit & rcvr */
-+      UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
--      UART_PUT_IER(port, ATMEL_US_RXRDY);             /* enable receive only */
-+      if (atmel_use_dma_rx(port)) {
-+              /* set UART timeout */
-+              UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
-+              UART_PUT_CR(port, ATMEL_US_STTTO);
-+
-+              UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
-+              /* enable PDC controller */
-+              UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
-+      } else {
-+              /* enable receive only */
-+              UART_PUT_IER(port, ATMEL_US_RXRDY);
-+      }
-       return 0;
- }
-@@ -449,6 +903,38 @@
-  */
- static void atmel_shutdown(struct uart_port *port)
- {
-+      struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-+      /*
-+       * Ensure everything is stopped.
-+       */
-+      atmel_stop_rx(port);
-+      atmel_stop_tx(port);
++/* Initial CRC32 value used when calculating CRC checksums */
++#define UBIFS_CRC32_INIT 0xFFFFFFFFU
 +
-+      /*
-+       * Shut-down the DMA.
-+       */
-+      if (atmel_use_dma_rx(port)) {
-+              int i;
++/*
++ * UBIFS does not try to compress data if its length is less than the below
++ * constant.
++ */
++#define UBIFS_MIN_COMPR_LEN 128
 +
-+              for (i = 0; i < 2; i++) {
-+                      struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
++/* Root inode number */
++#define UBIFS_ROOT_INO 1
 +
-+                      dma_unmap_single(port->dev,
-+                                       pdc->dma_addr,
-+                                       pdc->dma_size,
-+                                       DMA_FROM_DEVICE);
-+                      kfree(pdc->buf);
-+              }
-+      }
-+      if (atmel_use_dma_tx(port)) {
-+              struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
++/* Lowest inode number used for regular inodes (not UBIFS-only internal ones) */
++#define UBIFS_FIRST_INO 64
 +
-+              dma_unmap_single(port->dev,
-+                               pdc->dma_addr,
-+                               pdc->dma_size,
-+                               DMA_TO_DEVICE);
-+      }
++/*
++ * Maximum file name and extended attribute length (must be a multiple of 8,
++ * minus 1).
++ */
++#define UBIFS_MAX_NLEN 255
 +
-       /*
-        * Disable all interrupts, port and break condition.
-        */
-@@ -471,45 +957,48 @@
- /*
-  * Power / Clock management.
-  */
--static void atmel_serial_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
-+static void atmel_serial_pm(struct uart_port *port, unsigned int state,
-+                          unsigned int oldstate)
- {
--      struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
-+      struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       switch (state) {
--              case 0:
--                      /*
--                       * Enable the peripheral clock for this serial port.
--                       * This is called on uart_open() or a resume event.
--                       */
--                      clk_enable(atmel_port->clk);
--                      break;
--              case 3:
--                      /*
--                       * Disable the peripheral clock for this serial port.
--                       * This is called on uart_close() or a suspend event.
--                       */
--                      clk_disable(atmel_port->clk);
--                      break;
--              default:
--                      printk(KERN_ERR "atmel_serial: unknown pm %d\n", state);
-+      case 0:
-+              /*
-+               * Enable the peripheral clock for this serial port.
-+               * This is called on uart_open() or a resume event.
-+               */
-+              clk_enable(atmel_port->clk);
-+              break;
-+      case 3:
-+              /*
-+               * Disable the peripheral clock for this serial port.
-+               * This is called on uart_close() or a suspend event.
-+               */
-+              clk_disable(atmel_port->clk);
-+              break;
-+      default:
-+              printk(KERN_ERR "atmel_serial: unknown pm %d\n", state);
-       }
- }
- /*
-  * Change the port parameters
-  */
--static void atmel_set_termios(struct uart_port *port, struct ktermios * termios, struct ktermios * old)
-+static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
-+                            struct ktermios *old)
- {
-       unsigned long flags;
-       unsigned int mode, imr, quot, baud;
-       /* Get current mode register */
--      mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP | ATMEL_US_PAR);
-+      mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
-+                                      | ATMEL_US_NBSTOP | ATMEL_US_PAR);
--      baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
-+      baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
-       quot = uart_get_divisor(port, baud);
--      if (quot > 65535) {             /* BRGR is 16-bit, so switch to slower clock */
-+      if (quot > 65535) {     /* BRGR is 16-bit, so switch to slower clock */
-               quot /= 8;
-               mode |= ATMEL_US_USCLKS_MCK_DIV8;
-       }
-@@ -536,18 +1025,17 @@
-       /* parity */
-       if (termios->c_cflag & PARENB) {
--              if (termios->c_cflag & CMSPAR) {                        /* Mark or Space parity */
-+              /* Mark or Space parity */
-+              if (termios->c_cflag & CMSPAR) {
-                       if (termios->c_cflag & PARODD)
-                               mode |= ATMEL_US_PAR_MARK;
-                       else
-                               mode |= ATMEL_US_PAR_SPACE;
--              }
--              else if (termios->c_cflag & PARODD)
-+              } else if (termios->c_cflag & PARODD)
-                       mode |= ATMEL_US_PAR_ODD;
-               else
-                       mode |= ATMEL_US_PAR_EVEN;
--      }
--      else
-+      } else
-               mode |= ATMEL_US_PAR_NONE;
-       spin_lock_irqsave(&port->lock, flags);
-@@ -558,6 +1046,10 @@
-       if (termios->c_iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= ATMEL_US_RXBRK;
-+      if (atmel_use_dma_rx(port))
-+              /* need to enable error interrupts */
-+              UART_PUT_IER(port, port->read_status_mask);
++/* Maximum number of data journal heads */
++#define UBIFS_MAX_JHEADS 1
 +
-       /*
-        * Characters to ignore
-        */
-@@ -573,16 +1065,16 @@
-               if (termios->c_iflag & IGNPAR)
-                       port->ignore_status_mask |= ATMEL_US_OVRE;
-       }
--
--      // TODO: Ignore all characters if CREAD is set.
-+      /* TODO: Ignore all characters if CREAD is set.*/
-       /* update the per-port timeout */
-       uart_update_timeout(port, termios->c_cflag, baud);
--      /* disable interrupts and drain transmitter */
--      imr = UART_GET_IMR(port);       /* get interrupt mask */
--      UART_PUT_IDR(port, -1);         /* disable all interrupts */
--      while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) { barrier(); }
-+      /* save/disable interrupts and drain transmitter */
-+      imr = UART_GET_IMR(port);
-+      UART_PUT_IDR(port, -1);
-+      while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY))
-+              cpu_relax();
-       /* disable receiver and transmitter */
-       UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
-@@ -708,7 +1200,8 @@
- /*
-  * Configure the port from the platform device resource info.
-  */
--static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct platform_device *pdev)
-+static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
-+                                    struct platform_device *pdev)
- {
-       struct uart_port *port = &atmel_port->uart;
-       struct atmel_uart_data *data = pdev->dev.platform_data;
-@@ -723,6 +1216,11 @@
-       port->mapbase   = pdev->resource[0].start;
-       port->irq       = pdev->resource[1].start;
-+      tasklet_init(&atmel_port->tasklet, atmel_tasklet_func,
-+                      (unsigned long)port);
-+
-+      memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
-+
-       if (data->regs)
-               /* Already mapped by setup code */
-               port->membase = data->regs;
-@@ -731,11 +1229,17 @@
-               port->membase   = NULL;
-       }
--      if (!atmel_port->clk) {         /* for console, the clock could already be configured */
-+      /* for console, the clock could already be configured */
-+      if (!atmel_port->clk) {
-               atmel_port->clk = clk_get(&pdev->dev, "usart");
-               clk_enable(atmel_port->clk);
-               port->uartclk = clk_get_rate(atmel_port->clk);
-       }
++/*
++ * Size of UBIFS data block. Note, UBIFS is not a block oriented file-system,
++ * which means that it does not treat the underlying media as consisting of
++ * blocks like in case of hard drives. Do not be confused. UBIFS block is just
++ * the maximum amount of data which one data node can have or which can be
++ * attached to an inode node.
++ */
++#define UBIFS_BLOCK_SIZE  4096
++#define UBIFS_BLOCK_SHIFT 12
++#define UBIFS_BLOCK_MASK  0x00000FFF
 +
-+      atmel_port->use_dma_rx = data->use_dma_rx;
-+      atmel_port->use_dma_tx = data->use_dma_tx;
-+      if (atmel_use_dma_tx(port))
-+              port->fifosize = PDC_BUFFER_SIZE;
- }
- /*
-@@ -755,12 +1259,11 @@
-       atmel_pops.set_wake     = fns->set_wake;
- }
--
- #ifdef CONFIG_SERIAL_ATMEL_CONSOLE
- static void atmel_console_putchar(struct uart_port *port, int ch)
- {
-       while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY))
--              barrier();
-+              cpu_relax();
-       UART_PUT_CHAR(port, ch);
- }
-@@ -773,38 +1276,40 @@
-       unsigned int status, imr;
-       /*
--       *      First, save IMR and then disable interrupts
-+       * First, save IMR and then disable interrupts
-        */
--      imr = UART_GET_IMR(port);       /* get interrupt mask */
-+      imr = UART_GET_IMR(port);
-       UART_PUT_IDR(port, ATMEL_US_RXRDY | ATMEL_US_TXRDY);
-       uart_console_write(port, s, count, atmel_console_putchar);
-       /*
--       *      Finally, wait for transmitter to become empty
--       *      and restore IMR
-+       * Finally, wait for transmitter to become empty
-+       * and restore IMR
-        */
-       do {
-               status = UART_GET_CSR(port);
-       } while (!(status & ATMEL_US_TXRDY));
--      UART_PUT_IER(port, imr);        /* set interrupts back the way they were */
-+      /* set interrupts back the way they were */
-+      UART_PUT_IER(port, imr);
- }
- /*
-- * If the port was already initialised (eg, by a boot loader), try to determine
-- * the current setup.
-+ * If the port was already initialised (eg, by a boot loader),
-+ * try to determine the current setup.
-  */
--static void __init atmel_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
-+static void __init atmel_console_get_options(struct uart_port *port, int *baud,
-+                                           int *parity, int *bits)
- {
-       unsigned int mr, quot;
--// TODO: CR is a write-only register
--//    unsigned int cr;
--//
--//    cr = UART_GET_CR(port) & (ATMEL_US_RXEN | ATMEL_US_TXEN);
--//    if (cr == (ATMEL_US_RXEN | ATMEL_US_TXEN)) {
--//            /* ok, the port was enabled */
--//    }
-+      /*
-+       * If the baud rate generator isn't running, the port wasn't
-+       * initialized by the boot loader.
-+       */
-+      quot = UART_GET_BRGR(port);
-+      if (!quot)
-+              return;
-       mr = UART_GET_MR(port) & ATMEL_US_CHRL;
-       if (mr == ATMEL_US_CHRL_8)
-@@ -824,7 +1329,6 @@
-        * lower than one of those, as it would make us fall through
-        * to a much lower baud rate than we really want.
-        */
--      quot = UART_GET_BRGR(port);
-       *baud = port->uartclk / (16 * (quot - 1));
- }
-@@ -836,10 +1340,12 @@
-       int parity = 'n';
-       int flow = 'n';
--      if (port->membase == 0)         /* Port not initialized yet - delay setup */
-+      if (port->membase == NULL) {
-+              /* Port not initialized yet - delay setup */
-               return -ENODEV;
-+      }
--      UART_PUT_IDR(port, -1);                         /* disable interrupts */
-+      UART_PUT_IDR(port, -1);
-       UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
-       UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
-@@ -871,13 +1377,16 @@
- static int __init atmel_console_init(void)
- {
-       if (atmel_default_console_device) {
--              add_preferred_console(ATMEL_DEVICENAME, atmel_default_console_device->id, NULL);
--              atmel_init_port(&(atmel_ports[atmel_default_console_device->id]), atmel_default_console_device);
-+              add_preferred_console(ATMEL_DEVICENAME,
-+                                    atmel_default_console_device->id, NULL);
-+              atmel_init_port(&atmel_ports[atmel_default_console_device->id],
-+                              atmel_default_console_device);
-               register_console(&atmel_console);
-       }
-       return 0;
- }
++/* UBIFS padding byte pattern (must not be first or last byte of node magic) */
++#define UBIFS_PADDING_BYTE 0xCE
 +
- console_initcall(atmel_console_init);
- /*
-@@ -885,34 +1394,48 @@
-  */
- static int __init atmel_late_console_init(void)
- {
--      if (atmel_default_console_device && !(atmel_console.flags & CON_ENABLED))
-+      if (atmel_default_console_device
-+          && !(atmel_console.flags & CON_ENABLED))
-               register_console(&atmel_console);
-       return 0;
- }
++/* Maximum possible key length */
++#define UBIFS_MAX_KEY_LEN 16
 +
- core_initcall(atmel_late_console_init);
-+static inline bool atmel_is_console_port(struct uart_port *port)
-+{
-+      return port->cons && port->cons->index == port->line;
-+}
++/* Key length ("simple" format) */
++#define UBIFS_SK_LEN 8
 +
- #else
- #define ATMEL_CONSOLE_DEVICE  NULL
++/* Minimum index tree fanout */
++#define UBIFS_MIN_FANOUT 2
 +
-+static inline bool atmel_is_console_port(struct uart_port *port)
-+{
-+      return false;
-+}
- #endif
- static struct uart_driver atmel_uart = {
--      .owner                  = THIS_MODULE,
--      .driver_name            = "atmel_serial",
--      .dev_name               = ATMEL_DEVICENAME,
--      .major                  = SERIAL_ATMEL_MAJOR,
--      .minor                  = MINOR_START,
--      .nr                     = ATMEL_MAX_UART,
--      .cons                   = ATMEL_CONSOLE_DEVICE,
-+      .owner          = THIS_MODULE,
-+      .driver_name    = "atmel_serial",
-+      .dev_name       = ATMEL_DEVICENAME,
-+      .major          = SERIAL_ATMEL_MAJOR,
-+      .minor          = MINOR_START,
-+      .nr             = ATMEL_MAX_UART,
-+      .cons           = ATMEL_CONSOLE_DEVICE,
- };
- #ifdef CONFIG_PM
--static int atmel_serial_suspend(struct platform_device *pdev, pm_message_t state)
-+static int atmel_serial_suspend(struct platform_device *pdev,
-+                              pm_message_t state)
- {
-       struct uart_port *port = platform_get_drvdata(pdev);
--      struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
-+      struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
--      if (device_may_wakeup(&pdev->dev) && !at91_suspend_entering_slow_clock())
-+      if (device_may_wakeup(&pdev->dev)
-+          && !at91_suspend_entering_slow_clock())
-               enable_irq_wake(port->irq);
-       else {
-               uart_suspend_port(&atmel_uart, port);
-@@ -925,13 +1448,12 @@
- static int atmel_serial_resume(struct platform_device *pdev)
- {
-       struct uart_port *port = platform_get_drvdata(pdev);
--      struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
-+      struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       if (atmel_port->suspended) {
-               uart_resume_port(&atmel_uart, port);
-               atmel_port->suspended = 0;
--      }
--      else
-+      } else
-               disable_irq_wake(port->irq);
-       return 0;
-@@ -944,15 +1466,40 @@
- static int __devinit atmel_serial_probe(struct platform_device *pdev)
- {
-       struct atmel_uart_port *port;
-+      void *data;
-       int ret;
-+      BUILD_BUG_ON(!is_power_of_2(ATMEL_SERIAL_RINGSIZE));
++/* Maximum number of levels in UBIFS indexing B-tree */
++#define UBIFS_MAX_LEVELS 512
 +
-       port = &atmel_ports[pdev->id];
-       atmel_init_port(port, pdev);
-+      if (!atmel_use_dma_rx(&port->uart)) {
-+              ret = -ENOMEM;
-+              data = kmalloc(sizeof(struct atmel_uart_char)
-+                              * ATMEL_SERIAL_RINGSIZE, GFP_KERNEL);
-+              if (!data)
-+                      goto err_alloc_ring;
-+              port->rx_ring.buf = data;
-+      }
++/* Maximum amount of data attached to an inode in bytes */
++#define UBIFS_MAX_INO_DATA UBIFS_BLOCK_SIZE
 +
-       ret = uart_add_one_port(&atmel_uart, &port->uart);
--      if (!ret) {
--              device_init_wakeup(&pdev->dev, 1);
--              platform_set_drvdata(pdev, port);
-+      if (ret)
-+              goto err_add_port;
++/* LEB Properties Tree fanout (must be power of 2) and fanout shift */
++#define UBIFS_LPT_FANOUT 4
++#define UBIFS_LPT_FANOUT_SHIFT 2
 +
-+      device_init_wakeup(&pdev->dev, 1);
-+      platform_set_drvdata(pdev, port);
++/* LEB Properties Tree bit field sizes */
++#define UBIFS_LPT_CRC_BITS 16
++#define UBIFS_LPT_CRC_BYTES 2
++#define UBIFS_LPT_TYPE_BITS 4
 +
-+      return 0;
++/* The key is always at the same position in all keyed nodes */
++#define UBIFS_KEY_OFFSET offsetof(struct ubifs_ino_node, key)
 +
-+err_add_port:
-+      kfree(port->rx_ring.buf);
-+      port->rx_ring.buf = NULL;
-+err_alloc_ring:
-+      if (!atmel_is_console_port(&port->uart)) {
-+              clk_disable(port->clk);
-+              clk_put(port->clk);
-+              port->clk = NULL;
-       }
-       return ret;
-@@ -961,19 +1508,21 @@
- static int __devexit atmel_serial_remove(struct platform_device *pdev)
- {
-       struct uart_port *port = platform_get_drvdata(pdev);
--      struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
-+      struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       int ret = 0;
--      clk_disable(atmel_port->clk);
--      clk_put(atmel_port->clk);
--
-       device_init_wakeup(&pdev->dev, 0);
-       platform_set_drvdata(pdev, NULL);
--      if (port) {
--              ret = uart_remove_one_port(&atmel_uart, port);
--              kfree(port);
--      }
-+      ret = uart_remove_one_port(&atmel_uart, port);
++/*
++ * LEB Properties Tree node types.
++ *
++ * UBIFS_LPT_PNODE: LPT leaf node (contains LEB properties)
++ * UBIFS_LPT_NNODE: LPT internal node
++ * UBIFS_LPT_LTAB: LPT's own lprops table
++ * UBIFS_LPT_LSAVE: LPT's save table (big model only)
++ * UBIFS_LPT_NODE_CNT: count of LPT node types
++ * UBIFS_LPT_NOT_A_NODE: all ones (15 for 4 bits) is never a valid node type
++ */
++enum {
++      UBIFS_LPT_PNODE,
++      UBIFS_LPT_NNODE,
++      UBIFS_LPT_LTAB,
++      UBIFS_LPT_LSAVE,
++      UBIFS_LPT_NODE_CNT,
++      UBIFS_LPT_NOT_A_NODE = (1 << UBIFS_LPT_TYPE_BITS) - 1,
++};
 +
-+      tasklet_kill(&atmel_port->tasklet);
-+      kfree(atmel_port->rx_ring.buf);
++/*
++ * UBIFS inode types.
++ *
++ * UBIFS_ITYPE_REG: regular file
++ * UBIFS_ITYPE_DIR: directory
++ * UBIFS_ITYPE_LNK: soft link
++ * UBIFS_ITYPE_BLK: block device node
++ * UBIFS_ITYPE_CHR: character device node
++ * UBIFS_ITYPE_FIFO: fifo
++ * UBIFS_ITYPE_SOCK: socket
++ * UBIFS_ITYPES_CNT: count of supported file types
++ */
++enum {
++      UBIFS_ITYPE_REG,
++      UBIFS_ITYPE_DIR,
++      UBIFS_ITYPE_LNK,
++      UBIFS_ITYPE_BLK,
++      UBIFS_ITYPE_CHR,
++      UBIFS_ITYPE_FIFO,
++      UBIFS_ITYPE_SOCK,
++      UBIFS_ITYPES_CNT,
++};
 +
-+      /* "port" is allocated statically, so we shouldn't free it */
++/*
++ * Supported key hash functions.
++ *
++ * UBIFS_KEY_HASH_R5: R5 hash
++ * UBIFS_KEY_HASH_TEST: test hash which just returns first 4 bytes of the name
++ */
++enum {
++      UBIFS_KEY_HASH_R5,
++      UBIFS_KEY_HASH_TEST,
++};
 +
-+      clk_disable(atmel_port->clk);
-+      clk_put(atmel_port->clk);
-       return ret;
- }
---- a/drivers/serial/atmel_serial.h
-+++ /dev/null
-@@ -1,127 +0,0 @@
--/*
-- * drivers/serial/atmel_serial.h
-- *
-- * Copyright (C) 2005 Ivan Kokshaysky
-- * Copyright (C) SAN People
-- *
-- * USART registers.
-- * Based on AT91RM9200 datasheet revision E.
-- *
-- * 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.
-- */
--
--#ifndef ATMEL_SERIAL_H
--#define ATMEL_SERIAL_H
--
--#define ATMEL_US_CR           0x00                    /* Control Register */
--#define               ATMEL_US_RSTRX          (1 <<  2)               /* Reset Receiver */
--#define               ATMEL_US_RSTTX          (1 <<  3)               /* Reset Transmitter */
--#define               ATMEL_US_RXEN           (1 <<  4)               /* Receiver Enable */
--#define               ATMEL_US_RXDIS          (1 <<  5)               /* Receiver Disable */
--#define               ATMEL_US_TXEN           (1 <<  6)               /* Transmitter Enable */
--#define               ATMEL_US_TXDIS          (1 <<  7)               /* Transmitter Disable */
--#define               ATMEL_US_RSTSTA         (1 <<  8)               /* Reset Status Bits */
--#define               ATMEL_US_STTBRK         (1 <<  9)               /* Start Break */
--#define               ATMEL_US_STPBRK         (1 << 10)               /* Stop Break */
--#define               ATMEL_US_STTTO          (1 << 11)               /* Start Time-out */
--#define               ATMEL_US_SENDA          (1 << 12)               /* Send Address */
--#define               ATMEL_US_RSTIT          (1 << 13)               /* Reset Iterations */
--#define               ATMEL_US_RSTNACK        (1 << 14)               /* Reset Non Acknowledge */
--#define               ATMEL_US_RETTO          (1 << 15)               /* Rearm Time-out */
--#define               ATMEL_US_DTREN          (1 << 16)               /* Data Terminal Ready Enable [AT91RM9200 only] */
--#define               ATMEL_US_DTRDIS         (1 << 17)               /* Data Terminal Ready Disable [AT91RM9200 only] */
--#define               ATMEL_US_RTSEN          (1 << 18)               /* Request To Send Enable */
--#define               ATMEL_US_RTSDIS         (1 << 19)               /* Request To Send Disable */
--
--#define ATMEL_US_MR           0x04                    /* Mode Register */
--#define               ATMEL_US_USMODE         (0xf <<  0)             /* Mode of the USART */
--#define                       ATMEL_US_USMODE_NORMAL          0
--#define                       ATMEL_US_USMODE_RS485           1
--#define                       ATMEL_US_USMODE_HWHS            2
--#define                       ATMEL_US_USMODE_MODEM           3
--#define                       ATMEL_US_USMODE_ISO7816_T0      4
--#define                       ATMEL_US_USMODE_ISO7816_T1      6
--#define                       ATMEL_US_USMODE_IRDA            8
--#define               ATMEL_US_USCLKS         (3   <<  4)             /* Clock Selection */
--#define                       ATMEL_US_USCLKS_MCK             (0 <<  4)
--#define                       ATMEL_US_USCLKS_MCK_DIV8        (1 <<  4)
--#define                       ATMEL_US_USCLKS_SCK             (3 <<  4)
--#define               ATMEL_US_CHRL           (3   <<  6)             /* Character Length */
--#define                       ATMEL_US_CHRL_5                 (0 <<  6)
--#define                       ATMEL_US_CHRL_6                 (1 <<  6)
--#define                       ATMEL_US_CHRL_7                 (2 <<  6)
--#define                       ATMEL_US_CHRL_8                 (3 <<  6)
--#define               ATMEL_US_SYNC           (1 <<  8)               /* Synchronous Mode Select */
--#define               ATMEL_US_PAR            (7 <<  9)               /* Parity Type */
--#define                       ATMEL_US_PAR_EVEN               (0 <<  9)
--#define                       ATMEL_US_PAR_ODD                (1 <<  9)
--#define                       ATMEL_US_PAR_SPACE              (2 <<  9)
--#define                       ATMEL_US_PAR_MARK               (3 <<  9)
--#define                       ATMEL_US_PAR_NONE               (4 <<  9)
--#define                       ATMEL_US_PAR_MULTI_DROP         (6 <<  9)
--#define               ATMEL_US_NBSTOP         (3 << 12)               /* Number of Stop Bits */
--#define                       ATMEL_US_NBSTOP_1               (0 << 12)
--#define                       ATMEL_US_NBSTOP_1_5             (1 << 12)
--#define                       ATMEL_US_NBSTOP_2               (2 << 12)
--#define               ATMEL_US_CHMODE         (3 << 14)               /* Channel Mode */
--#define                       ATMEL_US_CHMODE_NORMAL          (0 << 14)
--#define                       ATMEL_US_CHMODE_ECHO            (1 << 14)
--#define                       ATMEL_US_CHMODE_LOC_LOOP        (2 << 14)
--#define                       ATMEL_US_CHMODE_REM_LOOP        (3 << 14)
--#define               ATMEL_US_MSBF           (1 << 16)               /* Bit Order */
--#define               ATMEL_US_MODE9          (1 << 17)               /* 9-bit Character Length */
--#define               ATMEL_US_CLKO           (1 << 18)               /* Clock Output Select */
--#define               ATMEL_US_OVER           (1 << 19)               /* Oversampling Mode */
--#define               ATMEL_US_INACK          (1 << 20)               /* Inhibit Non Acknowledge */
--#define               ATMEL_US_DSNACK         (1 << 21)               /* Disable Successive NACK */
--#define               ATMEL_US_MAX_ITER       (7 << 24)               /* Max Iterations */
--#define               ATMEL_US_FILTER         (1 << 28)               /* Infrared Receive Line Filter */
--
--#define ATMEL_US_IER          0x08                    /* Interrupt Enable Register */
--#define               ATMEL_US_RXRDY          (1 <<  0)               /* Receiver Ready */
--#define               ATMEL_US_TXRDY          (1 <<  1)               /* Transmitter Ready */
--#define               ATMEL_US_RXBRK          (1 <<  2)               /* Break Received / End of Break */
--#define               ATMEL_US_ENDRX          (1 <<  3)               /* End of Receiver Transfer */
--#define               ATMEL_US_ENDTX          (1 <<  4)               /* End of Transmitter Transfer */
--#define               ATMEL_US_OVRE           (1 <<  5)               /* Overrun Error */
--#define               ATMEL_US_FRAME          (1 <<  6)               /* Framing Error */
--#define               ATMEL_US_PARE           (1 <<  7)               /* Parity Error */
--#define               ATMEL_US_TIMEOUT        (1 <<  8)               /* Receiver Time-out */
--#define               ATMEL_US_TXEMPTY        (1 <<  9)               /* Transmitter Empty */
--#define               ATMEL_US_ITERATION      (1 << 10)               /* Max number of Repetitions Reached */
--#define               ATMEL_US_TXBUFE         (1 << 11)               /* Transmission Buffer Empty */
--#define               ATMEL_US_RXBUFF         (1 << 12)               /* Reception Buffer Full */
--#define               ATMEL_US_NACK           (1 << 13)               /* Non Acknowledge */
--#define               ATMEL_US_RIIC           (1 << 16)               /* Ring Indicator Input Change [AT91RM9200 only] */
--#define               ATMEL_US_DSRIC          (1 << 17)               /* Data Set Ready Input Change [AT91RM9200 only] */
--#define               ATMEL_US_DCDIC          (1 << 18)               /* Data Carrier Detect Input Change [AT91RM9200 only] */
--#define               ATMEL_US_CTSIC          (1 << 19)               /* Clear to Send Input Change */
--#define               ATMEL_US_RI             (1 << 20)               /* RI */
--#define               ATMEL_US_DSR            (1 << 21)               /* DSR */
--#define               ATMEL_US_DCD            (1 << 22)               /* DCD */
--#define               ATMEL_US_CTS            (1 << 23)               /* CTS */
--
--#define ATMEL_US_IDR          0x0c                    /* Interrupt Disable Register */
--#define ATMEL_US_IMR          0x10                    /* Interrupt Mask Register */
--#define ATMEL_US_CSR          0x14                    /* Channel Status Register */
--#define ATMEL_US_RHR          0x18                    /* Receiver Holding Register */
--#define ATMEL_US_THR          0x1c                    /* Transmitter Holding Register */
--#define               ATMEL_US_SYNH           (1 << 15)               /* Transmit/Receive Sync [AT91SAM9261 only] */
--
--#define ATMEL_US_BRGR         0x20                    /* Baud Rate Generator Register */
--#define               ATMEL_US_CD             (0xffff << 0)           /* Clock Divider */
--
--#define ATMEL_US_RTOR         0x24                    /* Receiver Time-out Register */
--#define               ATMEL_US_TO             (0xffff << 0)           /* Time-out Value */
--
--#define ATMEL_US_TTGR         0x28                    /* Transmitter Timeguard Register */
--#define               ATMEL_US_TG             (0xff << 0)             /* Timeguard Value */
--
--#define ATMEL_US_FIDI         0x40                    /* FI DI Ratio Register */
--#define ATMEL_US_NER          0x44                    /* Number of Errors Register */
--#define ATMEL_US_IF           0x4c                    /* IrDA Filter Register */
--
--#endif
---- a/drivers/serial/Kconfig
-+++ b/drivers/serial/Kconfig
-@@ -380,6 +380,21 @@
-         console is the device which receives all kernel messages and
-         warnings and which allows logins in single user mode).
-+config SERIAL_ATMEL_PDC
-+      bool "Support DMA transfers on AT91 / AT32 serial port"
-+      depends on SERIAL_ATMEL
-+      default y
-+      help
-+        Say Y here if you wish to use the PDC to do DMA transfers to
-+        and from the Atmel AT91 / AT32 serial port. In order to
-+        actually use DMA transfers, make sure that the use_dma_tx
-+        and use_dma_rx members in the atmel_uart_data struct is set
-+        appropriately for each port.
-+
-+        Note that break and error handling currently doesn't work
-+        properly when DMA is enabled. Make sure that ports where
-+        this matters don't use DMA.
-+
- config SERIAL_ATMEL_TTYAT
-       bool "Install as device ttyATn instead of ttySn"
-       depends on SERIAL_ATMEL=y
---- a/drivers/spi/atmel_spi.c
-+++ b/drivers/spi/atmel_spi.c
-@@ -51,7 +51,9 @@
-       u8                      stopping;
-       struct list_head        queue;
-       struct spi_transfer     *current_transfer;
--      unsigned long           remaining_bytes;
-+      unsigned long           current_remaining_bytes;
-+      struct spi_transfer     *next_transfer;
-+      unsigned long           next_remaining_bytes;
-       void                    *buffer;
-       dma_addr_t              buffer_dma;
-@@ -113,6 +115,16 @@
-       unsigned gpio = (unsigned) spi->controller_data;
-       unsigned active = spi->mode & SPI_CS_HIGH;
-       u32 mr;
-+      int i;
-+      u32 csr;
-+      u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0;
++/*
++ * Supported key formats.
++ *
++ * UBIFS_SIMPLE_KEY_FMT: simple key format
++ */
++enum {
++      UBIFS_SIMPLE_KEY_FMT,
++};
 +
-+      /* Make sure clock polarity is correct */
-+      for (i = 0; i < spi->master->num_chipselect; i++) {
-+              csr = spi_readl(as, CSR0 + 4 * i);
-+              if ((csr ^ cpol) & SPI_BIT(CPOL))
-+                      spi_writel(as, CSR0 + 4 * i, csr ^ SPI_BIT(CPOL));
-+      }
-       /* only deactivate *this* device; sometimes transfers to
-        * another device may be active when this routine is called.
-@@ -131,6 +143,48 @@
-               gpio_set_value(gpio, !active);
- }
-+static inline int atmel_spi_xfer_is_last(struct spi_message *msg,
-+                                      struct spi_transfer *xfer)
-+{
-+      return msg->transfers.prev == &xfer->transfer_list;
-+}
++/*
++ * The simple key format uses 29 bits for storing UBIFS block number and hash
++ * value.
++ */
++#define UBIFS_S_KEY_BLOCK_BITS 29
++#define UBIFS_S_KEY_BLOCK_MASK 0x1FFFFFFF
++#define UBIFS_S_KEY_HASH_BITS  UBIFS_S_KEY_BLOCK_BITS
++#define UBIFS_S_KEY_HASH_MASK  UBIFS_S_KEY_BLOCK_MASK
 +
-+static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer)
-+{
-+      return xfer->delay_usecs == 0 && !xfer->cs_change;
-+}
++/*
++ * Key types.
++ *
++ * UBIFS_INO_KEY: inode node key
++ * UBIFS_DATA_KEY: data node key
++ * UBIFS_DENT_KEY: directory entry node key
++ * UBIFS_XENT_KEY: extended attribute entry key
++ * UBIFS_KEY_TYPES_CNT: number of supported key types
++ */
++enum {
++      UBIFS_INO_KEY,
++      UBIFS_DATA_KEY,
++      UBIFS_DENT_KEY,
++      UBIFS_XENT_KEY,
++      UBIFS_KEY_TYPES_CNT,
++};
 +
-+static void atmel_spi_next_xfer_data(struct spi_master *master,
-+                              struct spi_transfer *xfer,
-+                              dma_addr_t *tx_dma,
-+                              dma_addr_t *rx_dma,
-+                              u32 *plen)
-+{
-+      struct atmel_spi        *as = spi_master_get_devdata(master);
-+      u32                     len = *plen;
++/* Count of LEBs reserved for the superblock area */
++#define UBIFS_SB_LEBS 1
++/* Count of LEBs reserved for the master area */
++#define UBIFS_MST_LEBS 2
++
++/* First LEB of the superblock area */
++#define UBIFS_SB_LNUM 0
++/* First LEB of the master area */
++#define UBIFS_MST_LNUM (UBIFS_SB_LNUM + UBIFS_SB_LEBS)
++/* First LEB of the log area */
++#define UBIFS_LOG_LNUM (UBIFS_MST_LNUM + UBIFS_MST_LEBS)
++
++/* Minimum number of logical eraseblocks in the log */
++#define UBIFS_MIN_LOG_LEBS 2
++/* Minimum number of bud logical eraseblocks */
++#define UBIFS_MIN_BUD_LEBS 2
++/* Minimum number of journal logical eraseblocks */
++#define UBIFS_MIN_JNL_LEBS (UBIFS_MIN_LOG_LEBS + UBIFS_MIN_BUD_LEBS)
++/* Minimum number of LPT area logical eraseblocks */
++#define UBIFS_MIN_LPT_LEBS 2
++/* Minimum number of orphan area logical eraseblocks */
++#define UBIFS_MIN_ORPH_LEBS 1
++/* Minimum number of main area logical eraseblocks */
++#define UBIFS_MIN_MAIN_LEBS 8
++
++/* Minimum number of logical eraseblocks */
++#define UBIFS_MIN_LEB_CNT (UBIFS_SB_LEBS + UBIFS_MST_LEBS + \
++                         UBIFS_MIN_LOG_LEBS + UBIFS_MIN_BUD_LEBS  + \
++                         UBIFS_MIN_LPT_LEBS + UBIFS_MIN_ORPH_LEBS + \
++                         UBIFS_MIN_MAIN_LEBS)
++
++/* Node sizes (N.B. these are guaranteed to be multiples of 8) */
++#define UBIFS_CH_SZ        sizeof(struct ubifs_ch)
++#define UBIFS_INO_NODE_SZ  sizeof(struct ubifs_ino_node)
++#define UBIFS_DATA_NODE_SZ sizeof(struct ubifs_data_node)
++#define UBIFS_DENT_NODE_SZ sizeof(struct ubifs_dent_node)
++#define UBIFS_TRUN_NODE_SZ sizeof(struct ubifs_trun_node)
++#define UBIFS_PAD_NODE_SZ  sizeof(struct ubifs_pad_node)
++#define UBIFS_SB_NODE_SZ   sizeof(struct ubifs_sb_node)
++#define UBIFS_MST_NODE_SZ  sizeof(struct ubifs_mst_node)
++#define UBIFS_REF_NODE_SZ  sizeof(struct ubifs_ref_node)
++#define UBIFS_IDX_NODE_SZ  sizeof(struct ubifs_idx_node)
++#define UBIFS_CS_NODE_SZ   sizeof(struct ubifs_cs_node)
++#define UBIFS_ORPH_NODE_SZ sizeof(struct ubifs_orph_node)
++/* Extended attribute entry nodes are identical to directory entry nodes */
++#define UBIFS_XENT_NODE_SZ UBIFS_DENT_NODE_SZ
++/* Only this does not have to be multiple of 8 bytes */
++#define UBIFS_BRANCH_SZ    sizeof(struct ubifs_branch)
++
++/* Maximum node sizes (N.B. these are guaranteed to be multiples of 8) */
++#define UBIFS_MAX_DATA_NODE_SZ  (UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE)
++#define UBIFS_MAX_INO_NODE_SZ   (UBIFS_INO_NODE_SZ + UBIFS_MAX_INO_DATA)
++#define UBIFS_MAX_DENT_NODE_SZ  (UBIFS_DENT_NODE_SZ + UBIFS_MAX_NLEN + 1)
++#define UBIFS_MAX_XENT_NODE_SZ  UBIFS_MAX_DENT_NODE_SZ
++
++/* The largest UBIFS node */
++#define UBIFS_MAX_NODE_SZ UBIFS_MAX_INO_NODE_SZ
 +
-+      /* use scratch buffer only when rx or tx data is unspecified */
-+      if (xfer->rx_buf)
-+              *rx_dma = xfer->rx_dma + xfer->len - len;
-+      else {
-+              *rx_dma = as->buffer_dma;
-+              if (len > BUFFER_SIZE)
-+                      len = BUFFER_SIZE;
-+      }
-+      if (xfer->tx_buf)
-+              *tx_dma = xfer->tx_dma + xfer->len - len;
-+      else {
-+              *tx_dma = as->buffer_dma;
-+              if (len > BUFFER_SIZE)
-+                      len = BUFFER_SIZE;
-+              memset(as->buffer, 0, len);
-+              dma_sync_single_for_device(&as->pdev->dev,
-+                              as->buffer_dma, len, DMA_TO_DEVICE);
-+      }
++/*
++ * On-flash inode flags.
++ *
++ * UBIFS_COMPR_FL: use compression for this inode
++ * UBIFS_SYNC_FL:  I/O on this inode has to be synchronous
++ * UBIFS_IMMUTABLE_FL: inode is immutable
++ * UBIFS_APPEND_FL: writes to the inode may only append data
++ * UBIFS_DIRSYNC_FL: I/O on this directory inode has to be synchronous
++ *
++ * Note, these are on-flash flags which correspond to ioctl flags
++ * (@FS_COMPR_FL, etc). They have the same values now, but generally, do not
++ * have to be the same.
++ */
++enum {
++      UBIFS_COMPR_FL     = 0x01,
++      UBIFS_SYNC_FL      = 0x02,
++      UBIFS_IMMUTABLE_FL = 0x04,
++      UBIFS_APPEND_FL    = 0x08,
++      UBIFS_DIRSYNC_FL   = 0x10,
++};
++
++/* Inode flag bits used by UBIFS */
++#define UBIFS_FL_MASK 0x0000001F
++
++/*
++ * UBIFS compression types.
++ *
++ * UBIFS_COMPR_NONE: no compression
++ * UBIFS_COMPR_LZO: LZO compression
++ * UBIFS_COMPR_ZLIB: ZLIB compression
++ * UBIFS_COMPR_TYPES_CNT: count of supported compression types
++ */
++enum {
++      UBIFS_COMPR_NONE,
++      UBIFS_COMPR_LZO,
++      UBIFS_COMPR_ZLIB,
++      UBIFS_COMPR_TYPES_CNT,
++};
 +
-+      *plen = len;
-+}
++/*
++ * UBIFS node types.
++ *
++ * UBIFS_INO_NODE: inode node
++ * UBIFS_DATA_NODE: data node
++ * UBIFS_DENT_NODE: directory entry node
++ * UBIFS_XENT_NODE: extended attribute node
++ * UBIFS_TRUN_NODE: truncation node
++ * UBIFS_PAD_NODE: padding node
++ * UBIFS_SB_NODE: superblock node
++ * UBIFS_MST_NODE: master node
++ * UBIFS_REF_NODE: LEB reference node
++ * UBIFS_IDX_NODE: index node
++ * UBIFS_CS_NODE: commit start node
++ * UBIFS_ORPH_NODE: orphan node
++ * UBIFS_NODE_TYPES_CNT: count of supported node types
++ *
++ * Note, we index arrays by these numbers, so keep them low and contiguous.
++ * Node type constants for inodes, direntries and so on have to be the same as
++ * corresponding key type constants.
++ */
++enum {
++      UBIFS_INO_NODE,
++      UBIFS_DATA_NODE,
++      UBIFS_DENT_NODE,
++      UBIFS_XENT_NODE,
++      UBIFS_TRUN_NODE,
++      UBIFS_PAD_NODE,
++      UBIFS_SB_NODE,
++      UBIFS_MST_NODE,
++      UBIFS_REF_NODE,
++      UBIFS_IDX_NODE,
++      UBIFS_CS_NODE,
++      UBIFS_ORPH_NODE,
++      UBIFS_NODE_TYPES_CNT,
++};
 +
- /*
-  * Submit next transfer for DMA.
-  * lock is held, spi irq is blocked
-@@ -140,53 +194,78 @@
- {
-       struct atmel_spi        *as = spi_master_get_devdata(master);
-       struct spi_transfer     *xfer;
--      u32                     len;
-+      u32                     len, remaining, total;
-       dma_addr_t              tx_dma, rx_dma;
--      xfer = as->current_transfer;
--      if (!xfer || as->remaining_bytes == 0) {
--              if (xfer)
--                      xfer = list_entry(xfer->transfer_list.next,
--                                      struct spi_transfer, transfer_list);
--              else
--                      xfer = list_entry(msg->transfers.next,
--                                      struct spi_transfer, transfer_list);
--              as->remaining_bytes = xfer->len;
--              as->current_transfer = xfer;
-+      if (!as->current_transfer)
-+              xfer = list_entry(msg->transfers.next,
-+                              struct spi_transfer, transfer_list);
-+      else if (!as->next_transfer)
-+              xfer = list_entry(as->current_transfer->transfer_list.next,
-+                              struct spi_transfer, transfer_list);
-+      else
-+              xfer = NULL;
++/*
++ * Master node flags.
++ *
++ * UBIFS_MST_DIRTY: rebooted uncleanly - master node is dirty
++ * UBIFS_MST_NO_ORPHS: no orphan inodes present
++ * UBIFS_MST_RCVRY: written by recovery
++ */
++enum {
++      UBIFS_MST_DIRTY = 1,
++      UBIFS_MST_NO_ORPHS = 2,
++      UBIFS_MST_RCVRY = 4,
++};
 +
-+      if (xfer) {
-+              len = xfer->len;
-+              atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
-+              remaining = xfer->len - len;
++/*
++ * Node group type (used by recovery to recover whole group or none).
++ *
++ * UBIFS_NO_NODE_GROUP: this node is not part of a group
++ * UBIFS_IN_NODE_GROUP: this node is a part of a group
++ * UBIFS_LAST_OF_NODE_GROUP: this node is the last in a group
++ */
++enum {
++      UBIFS_NO_NODE_GROUP = 0,
++      UBIFS_IN_NODE_GROUP,
++      UBIFS_LAST_OF_NODE_GROUP,
++};
 +
-+              spi_writel(as, RPR, rx_dma);
-+              spi_writel(as, TPR, tx_dma);
++/*
++ * Superblock flags.
++ *
++ * UBIFS_FLG_BIGLPT: if "big" LPT model is used if set
++ */
++enum {
++      UBIFS_FLG_BIGLPT = 0x02,
++};
 +
-+              if (msg->spi->bits_per_word > 8)
-+                      len >>= 1;
-+              spi_writel(as, RCR, len);
-+              spi_writel(as, TCR, len);
++/**
++ * struct ubifs_ch - common header node.
++ * @magic: UBIFS node magic number (%UBIFS_NODE_MAGIC)
++ * @crc: CRC-32 checksum of the node header
++ * @sqnum: sequence number
++ * @len: full node length
++ * @node_type: node type
++ * @group_type: node group type
++ * @padding: reserved for future, zeroes
++ *
++ * Every UBIFS node starts with this common part. If the node has a key, the
++ * key always goes next.
++ */
++struct ubifs_ch {
++      __le32 magic;
++      __le32 crc;
++      __le64 sqnum;
++      __le32 len;
++      __u8 node_type;
++      __u8 group_type;
++      __u8 padding[2];
++} __attribute__ ((packed));
 +
-+              dev_dbg(&msg->spi->dev,
-+                      "  start xfer %p: len %u tx %p/%08x rx %p/%08x\n",
-+                      xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
-+                      xfer->rx_buf, xfer->rx_dma);
-+      } else {
-+              xfer = as->next_transfer;
-+              remaining = as->next_remaining_bytes;
-       }
--      len = as->remaining_bytes;
-+      as->current_transfer = xfer;
-+      as->current_remaining_bytes = remaining;
--      tx_dma = xfer->tx_dma + xfer->len - len;
--      rx_dma = xfer->rx_dma + xfer->len - len;
-+      if (remaining > 0)
-+              len = remaining;
-+      else if (!atmel_spi_xfer_is_last(msg, xfer)
-+                      && atmel_spi_xfer_can_be_chained(xfer)) {
-+              xfer = list_entry(xfer->transfer_list.next,
-+                              struct spi_transfer, transfer_list);
-+              len = xfer->len;
-+      } else
-+              xfer = NULL;
--      /* use scratch buffer only when rx or tx data is unspecified */
--      if (!xfer->rx_buf) {
--              rx_dma = as->buffer_dma;
--              if (len > BUFFER_SIZE)
--                      len = BUFFER_SIZE;
--      }
--      if (!xfer->tx_buf) {
--              tx_dma = as->buffer_dma;
--              if (len > BUFFER_SIZE)
--                      len = BUFFER_SIZE;
--              memset(as->buffer, 0, len);
--              dma_sync_single_for_device(&as->pdev->dev,
--                              as->buffer_dma, len, DMA_TO_DEVICE);
--      }
-+      as->next_transfer = xfer;
--      spi_writel(as, RPR, rx_dma);
--      spi_writel(as, TPR, tx_dma);
-+      if (xfer) {
-+              total = len;
-+              atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
-+              as->next_remaining_bytes = total - len;
-+
-+              spi_writel(as, RNPR, rx_dma);
-+              spi_writel(as, TNPR, tx_dma);
-+
-+              if (msg->spi->bits_per_word > 8)
-+                      len >>= 1;
-+              spi_writel(as, RNCR, len);
-+              spi_writel(as, TNCR, len);
-+
-+              dev_dbg(&msg->spi->dev,
-+                      "  next xfer %p: len %u tx %p/%08x rx %p/%08x\n",
-+                      xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
-+                      xfer->rx_buf, xfer->rx_dma);
-+      } else {
-+              spi_writel(as, RNCR, 0);
-+              spi_writel(as, TNCR, 0);
-+      }
--      as->remaining_bytes -= len;
--      if (msg->spi->bits_per_word > 8)
--              len >>= 1;
--
--      /* REVISIT: when xfer->delay_usecs == 0, the PDC "next transfer"
--       * mechanism might help avoid the IRQ latency between transfers
--       * (and improve the nCS0 errata handling on at91rm9200 chips)
--       *
--       * We're also waiting for ENDRX before we start the next
-+      /* REVISIT: We're waiting for ENDRX before we start the next
-        * transfer because we need to handle some difficult timing
-        * issues otherwise. If we wait for ENDTX in one transfer and
-        * then starts waiting for ENDRX in the next, it's difficult
-@@ -196,17 +275,7 @@
-        *
-        * It should be doable, though. Just not now...
-        */
--      spi_writel(as, TNCR, 0);
--      spi_writel(as, RNCR, 0);
-       spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES));
--
--      dev_dbg(&msg->spi->dev,
--              "  start xfer %p: len %u tx %p/%08x rx %p/%08x imr %03x\n",
--              xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
--              xfer->rx_buf, xfer->rx_dma, spi_readl(as, IMR));
--
--      spi_writel(as, RCR, len);
--      spi_writel(as, TCR, len);
-       spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
- }
-@@ -304,6 +373,7 @@
-       spin_lock(&as->lock);
-       as->current_transfer = NULL;
-+      as->next_transfer = NULL;
-       /* continue if needed */
-       if (list_empty(&as->queue) || as->stopping)
-@@ -387,7 +457,7 @@
-               spi_writel(as, IDR, pending);
--              if (as->remaining_bytes == 0) {
-+              if (as->current_remaining_bytes == 0) {
-                       msg->actual_length += xfer->len;
-                       if (!msg->is_dma_mapped)
-@@ -397,7 +467,7 @@
-                       if (xfer->delay_usecs)
-                               udelay(xfer->delay_usecs);
--                      if (msg->transfers.prev == &xfer->transfer_list) {
-+                      if (atmel_spi_xfer_is_last(msg, xfer)) {
-                               /* report completed message */
-                               atmel_spi_msg_done(master, as, msg, 0,
-                                               xfer->cs_change);
-@@ -500,9 +570,14 @@
-       if (!(spi->mode & SPI_CPHA))
-               csr |= SPI_BIT(NCPHA);
--      /* TODO: DLYBS and DLYBCT */
--      csr |= SPI_BF(DLYBS, 10);
--      csr |= SPI_BF(DLYBCT, 10);
-+      /* DLYBS is mostly irrelevant since we manage chipselect using GPIOs.
-+       *
-+       * DLYBCT would add delays between words, slowing down transfers.
-+       * It could potentially be useful to cope with DMA bottlenecks, but
-+       * in those cases it's probably best to just use a lower bitrate.
-+       */
-+      csr |= SPI_BF(DLYBS, 0);
-+      csr |= SPI_BF(DLYBCT, 0);
-       /* chipselect must have been muxed as GPIO (e.g. in board setup) */
-       npcs_pin = (unsigned int)spi->controller_data;
---- a/drivers/usb/gadget/atmel_usba_udc.c
-+++ b/drivers/usb/gadget/atmel_usba_udc.c
-@@ -18,6 +18,7 @@
- #include <linux/platform_device.h>
- #include <linux/usb/ch9.h>
- #include <linux/usb/gadget.h>
-+#include <linux/usb/atmel_usba_udc.h>
- #include <linux/delay.h>
- #include <asm/gpio.h>
-@@ -27,6 +28,7 @@
- static struct usba_udc the_udc;
-+static struct usba_ep *usba_ep;
- #ifdef CONFIG_USB_GADGET_DEBUG_FS
- #include <linux/debugfs.h>
-@@ -324,53 +326,6 @@
-       return 1;
- }
--static void copy_to_fifo(void __iomem *fifo, const void *buf, int len)
--{
--      unsigned long tmp;
--
--      DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len);
--      for (; len > 0; len -= 4, buf += 4, fifo += 4) {
--              tmp = *(unsigned long *)buf;
--              if (len >= 4) {
--                      DBG(DBG_FIFO, "  -> %08lx\n", tmp);
--                      __raw_writel(tmp, fifo);
--              } else {
--                      do {
--                              DBG(DBG_FIFO, "  -> %02lx\n", tmp >> 24);
--                              __raw_writeb(tmp >> 24, fifo);
--                              fifo++;
--                              tmp <<= 8;
--                      } while (--len);
--                      break;
--              }
--      }
--}
--
--static void copy_from_fifo(void *buf, void __iomem *fifo, int len)
--{
--      union {
--              unsigned long *w;
--              unsigned char *b;
--      } p;
--      unsigned long tmp;
--
--      DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len);
--      for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) {
--              if (len >= 4) {
--                      tmp = __raw_readl(fifo);
--                      *p.w = tmp;
--                      DBG(DBG_FIFO, "  -> %08lx\n", tmp);
--              } else {
--                      do {
--                              tmp = __raw_readb(fifo);
--                              *p.b = tmp;
--                              DBG(DBG_FIFO, " -> %02lx\n", tmp);
--                              fifo++, p.b++;
--                      } while (--len);
--              }
--      }
--}
--
- static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
- {
-       unsigned int transaction_len;
-@@ -387,7 +342,7 @@
-               ep->ep.name, req, transaction_len,
-               req->last_transaction ? ", done" : "");
--      copy_to_fifo(ep->fifo, req->req.buf + req->req.actual, transaction_len);
-+      memcpy_toio(ep->fifo, req->req.buf + req->req.actual, transaction_len);
-       usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
-       req->req.actual += transaction_len;
- }
-@@ -476,7 +431,7 @@
-                       bytecount = req->req.length - req->req.actual;
-               }
--              copy_from_fifo(req->req.buf + req->req.actual,
-+              memcpy_fromio(req->req.buf + req->req.actual,
-                               ep->fifo, bytecount);
-               req->req.actual += bytecount;
-@@ -1029,33 +984,6 @@
-       .set_selfpowered        = usba_udc_set_selfpowered,
- };
--#define EP(nam, idx, maxpkt, maxbk, dma, isoc)                        \
--{                                                             \
--      .ep     = {                                             \
--              .ops            = &usba_ep_ops,                 \
--              .name           = nam,                          \
--              .maxpacket      = maxpkt,                       \
--      },                                                      \
--      .udc            = &the_udc,                             \
--      .queue          = LIST_HEAD_INIT(usba_ep[idx].queue),   \
--      .fifo_size      = maxpkt,                               \
--      .nr_banks       = maxbk,                                \
--      .index          = idx,                                  \
--      .can_dma        = dma,                                  \
--      .can_isoc       = isoc,                                 \
--}
--
--static struct usba_ep usba_ep[] = {
--      EP("ep0", 0, 64, 1, 0, 0),
--      EP("ep1in-bulk", 1, 512, 2, 1, 1),
--      EP("ep2out-bulk", 2, 512, 2, 1, 1),
--      EP("ep3in-int", 3, 64, 3, 1, 0),
--      EP("ep4out-int", 4, 64, 3, 1, 0),
--      EP("ep5in-iso", 5, 1024, 3, 1, 1),
--      EP("ep6out-iso", 6, 1024, 3, 1, 1),
--};
--#undef EP
--
- static struct usb_endpoint_descriptor usba_ep0_desc = {
-       .bLength = USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType = USB_DT_ENDPOINT,
-@@ -1074,7 +1002,6 @@
- static struct usba_udc the_udc = {
-       .gadget = {
-               .ops            = &usba_udc_ops,
--              .ep0            = &usba_ep[0].ep,
-               .ep_list        = LIST_HEAD_INIT(the_udc.gadget.ep_list),
-               .is_dualspeed   = 1,
-               .name           = "atmel_usba_udc",
-@@ -1231,7 +1158,7 @@
-               } else {
-                       usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
-                       usba_writel(udc, TST, USBA_TST_PKT_MODE);
--                      copy_to_fifo(ep->fifo, test_packet_buffer,
-+                      memcpy_toio(ep->fifo, test_packet_buffer,
-                                       sizeof(test_packet_buffer));
-                       usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
-                       dev_info(dev, "Entering Test_Packet mode...\n");
-@@ -1539,7 +1466,7 @@
-               }
-               DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo);
--              copy_from_fifo(crq.data, ep->fifo, sizeof(crq));
-+              memcpy_fromio(crq.data, ep->fifo, sizeof(crq));
-               /* Free up one bank in the FIFO so that we can
-                * generate or receive a reply right away. */
-@@ -1911,7 +1838,7 @@
-       regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID);
-       fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID);
--      if (!regs || !fifo)
-+      if (!regs || !fifo || !pdata)
-               return -ENXIO;
-       irq = platform_get_irq(pdev, 0);
-@@ -1959,16 +1886,44 @@
-       usba_writel(udc, CTRL, 0);
-       clk_disable(pclk);
-+      usba_ep = kmalloc(sizeof(struct usba_ep) * pdata->num_ep,
-+                        GFP_KERNEL);
-+      if (!usba_ep)
-+              goto err_alloc_ep;
++/**
++ * union ubifs_dev_desc - device node descriptor.
++ * @new: new type device descriptor
++ * @huge: huge type device descriptor
++ *
++ * This data structure describes major/minor numbers of a device node. In an
++ * inode is a device node then its data contains an object of this type. UBIFS
++ * uses standard Linux "new" and "huge" device node encodings.
++ */
++union ubifs_dev_desc {
++      __le32 new;
++      __le64 huge;
++} __attribute__ ((packed));
++
++/**
++ * struct ubifs_ino_node - inode node.
++ * @ch: common header
++ * @key: node key
++ * @creat_sqnum: sequence number at time of creation
++ * @size: inode size in bytes (amount of uncompressed data)
++ * @atime_sec: access time seconds
++ * @ctime_sec: creation time seconds
++ * @mtime_sec: modification time seconds
++ * @atime_nsec: access time nanoseconds
++ * @ctime_nsec: creation time nanoseconds
++ * @mtime_nsec: modification time nanoseconds
++ * @nlink: number of hard links
++ * @uid: owner ID
++ * @gid: group ID
++ * @mode: access flags
++ * @flags: per-inode flags (%UBIFS_COMPR_FL, %UBIFS_SYNC_FL, etc)
++ * @data_len: inode data length
++ * @xattr_cnt: count of extended attributes this inode has
++ * @xattr_size: summarized size of all extended attributes in bytes
++ * @xattr_names: sum of lengths of all extended attribute names belonging to
++ *               this inode
++ * @compr_type: compression type used for this inode
++ * @padding: reserved for future, zeroes
++ * @data: data attached to the inode
++ *
++ * Note, even though inode compression type is defined by @compr_type, some
++ * nodes of this inode may be compressed with different compressor - this
++ * happens if compression type is changed while the inode already has data
++ * nodes. But @compr_type will be use for further writes to the inode.
++ *
++ * Note, do not forget to amend 'zero_ino_node_unused()' function when changing
++ * the padding fields.
++ */
++struct ubifs_ino_node {
++      struct ubifs_ch ch;
++      __u8 key[UBIFS_MAX_KEY_LEN];
++      __le64 creat_sqnum;
++      __le64 size;
++      __le64 atime_sec;
++      __le64 ctime_sec;
++      __le64 mtime_sec;
++      __le32 atime_nsec;
++      __le32 ctime_nsec;
++      __le32 mtime_nsec;
++      __le32 nlink;
++      __le32 uid;
++      __le32 gid;
++      __le32 mode;
++      __le32 flags;
++      __le32 data_len;
++      __le32 xattr_cnt;
++      __le64 xattr_size;
++      __le32 xattr_names;
++      __le16 compr_type;
++      __u8 padding[26]; /* Watch 'zero_ino_node_unused()' if changing! */
++      __u8 data[];
++} __attribute__ ((packed));
++
++/**
++ * struct ubifs_dent_node - directory entry node.
++ * @ch: common header
++ * @key: node key
++ * @inum: target inode number
++ * @padding1: reserved for future, zeroes
++ * @type: type of the target inode (%UBIFS_ITYPE_REG, %UBIFS_ITYPE_DIR, etc)
++ * @nlen: name length
++ * @padding2: reserved for future, zeroes
++ * @name: zero-terminated name
++ *
++ * Note, do not forget to amend 'zero_dent_node_unused()' function when
++ * changing the padding fields.
++ */
++struct ubifs_dent_node {
++      struct ubifs_ch ch;
++      __u8 key[UBIFS_MAX_KEY_LEN];
++      __le64 inum;
++      __u8 padding1;
++      __u8 type;
++      __le16 nlen;
++      __u8 padding2[4]; /* Watch 'zero_dent_node_unused()' if changing! */
++      __u8 name[];
++} __attribute__ ((packed));
 +
-+      the_udc.gadget.ep0 = &usba_ep[0].ep;
++/**
++ * struct ubifs_data_node - data node.
++ * @ch: common header
++ * @key: node key
++ * @size: uncompressed data size in bytes
++ * @compr_type: compression type (%UBIFS_COMPR_NONE, %UBIFS_COMPR_LZO, etc)
++ * @padding: reserved for future, zeroes
++ * @data: data
++ *
++ * Note, do not forget to amend 'zero_data_node_unused()' function when
++ * changing the padding fields.
++ */
++struct ubifs_data_node {
++      struct ubifs_ch ch;
++      __u8 key[UBIFS_MAX_KEY_LEN];
++      __le32 size;
++      __le16 compr_type;
++      __u8 padding[2]; /* Watch 'zero_data_node_unused()' if changing! */
++      __u8 data[];
++} __attribute__ ((packed));
 +
-       INIT_LIST_HEAD(&usba_ep[0].ep.ep_list);
-       usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0);
-       usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0);
-       usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0);
--      for (i = 1; i < ARRAY_SIZE(usba_ep); i++) {
-+      usba_ep[0].ep.ops = &usba_ep_ops;
-+      usba_ep[0].ep.name = pdata->ep[0].name;
-+      usba_ep[0].ep.maxpacket = pdata->ep[0].fifo_size;
-+      usba_ep[0].udc = &the_udc;
-+      INIT_LIST_HEAD(&usba_ep[0].queue);
-+      usba_ep[0].fifo_size = pdata->ep[0].fifo_size;
-+      usba_ep[0].nr_banks = pdata->ep[0].nr_banks;
-+      usba_ep[0].index = pdata->ep[0].index;
-+      usba_ep[0].can_dma = pdata->ep[0].can_dma;
-+      usba_ep[0].can_isoc = pdata->ep[0].can_isoc;
++/**
++ * struct ubifs_trun_node - truncation node.
++ * @ch: common header
++ * @inum: truncated inode number
++ * @padding: reserved for future, zeroes
++ * @old_size: size before truncation
++ * @new_size: size after truncation
++ *
++ * This node exists only in the journal and never goes to the main area. Note,
++ * do not forget to amend 'zero_trun_node_unused()' function when changing the
++ * padding fields.
++ */
++struct ubifs_trun_node {
++      struct ubifs_ch ch;
++      __le32 inum;
++      __u8 padding[12]; /* Watch 'zero_trun_node_unused()' if changing! */
++      __le64 old_size;
++      __le64 new_size;
++} __attribute__ ((packed));
 +
-+      for (i = 1; i < pdata->num_ep; i++) {
-               struct usba_ep *ep = &usba_ep[i];
-               ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
-               ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
-               ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
-+              ep->ep.ops = &usba_ep_ops;
-+              ep->ep.name = pdata->ep[i].name;
-+              ep->ep.maxpacket = pdata->ep[i].fifo_size;
-+              ep->udc = &the_udc;
-+              INIT_LIST_HEAD(&ep->queue);
-+              ep->fifo_size = pdata->ep[i].fifo_size;
-+              ep->nr_banks = pdata->ep[i].nr_banks;
-+              ep->index = pdata->ep[i].index;
-+              ep->can_dma = pdata->ep[i].can_dma;
-+              ep->can_isoc = pdata->ep[i].can_isoc;
-               list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
-       }
-@@ -1987,7 +1942,7 @@
-               goto err_device_add;
-       }
--      if (pdata && pdata->vbus_pin != GPIO_PIN_NONE) {
-+      if (pdata->vbus_pin >= 0) {
-               if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
-                       udc->vbus_pin = pdata->vbus_pin;
-@@ -2007,7 +1962,7 @@
-       }
-       usba_init_debugfs(udc);
--      for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
-+      for (i = 1; i < pdata->num_ep; i++)
-               usba_ep_init_debugfs(udc, &usba_ep[i]);
-       return 0;
-@@ -2015,6 +1970,8 @@
- err_device_add:
-       free_irq(irq, udc);
- err_request_irq:
-+      kfree(usba_ep);
-+err_alloc_ep:
-       iounmap(udc->fifo);
- err_map_fifo:
-       iounmap(udc->regs);
-@@ -2032,10 +1989,11 @@
- {
-       struct usba_udc *udc;
-       int i;
-+      struct usba_platform_data *pdata = pdev->dev.platform_data;
-       udc = platform_get_drvdata(pdev);
--      for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
-+      for (i = 1; i < pdata->num_ep; i++)
-               usba_ep_cleanup_debugfs(&usba_ep[i]);
-       usba_cleanup_debugfs(udc);
---- a/drivers/video/atmel_lcdfb.c
-+++ b/drivers/video/atmel_lcdfb.c
-@@ -16,6 +16,7 @@
- #include <linux/fb.h>
- #include <linux/init.h>
- #include <linux/delay.h>
-+#include <linux/backlight.h>
- #include <asm/arch/board.h>
- #include <asm/arch/cpu.h>
-@@ -37,7 +38,9 @@
- #endif
- #if defined(CONFIG_ARCH_AT91)
--#define       ATMEL_LCDFB_FBINFO_DEFAULT      FBINFO_DEFAULT
-+#define       ATMEL_LCDFB_FBINFO_DEFAULT      (FBINFO_DEFAULT \
-+                                       | FBINFO_PARTIAL_PAN_OK \
-+                                       | FBINFO_HWACCEL_YPAN)
- static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
-                                       struct fb_var_screeninfo *var)
-@@ -69,12 +72,113 @@
- }
- #endif
-+static const u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
-+              | ATMEL_LCDC_POL_POSITIVE
-+              | ATMEL_LCDC_ENA_PWMENABLE;
++/**
++ * struct ubifs_pad_node - padding node.
++ * @ch: common header
++ * @pad_len: how many bytes after this node are unused (because padded)
++ * @padding: reserved for future, zeroes
++ */
++struct ubifs_pad_node {
++      struct ubifs_ch ch;
++      __le32 pad_len;
++} __attribute__ ((packed));
++
++/**
++ * struct ubifs_sb_node - superblock node.
++ * @ch: common header
++ * @padding: reserved for future, zeroes
++ * @key_hash: type of hash function used in keys
++ * @key_fmt: format of the key
++ * @flags: file-system flags (%UBIFS_FLG_BIGLPT, etc)
++ * @min_io_size: minimal input/output unit size
++ * @leb_size: logical eraseblock size in bytes
++ * @leb_cnt: count of LEBs used by filesystem
++ * @max_leb_cnt: maximum count of LEBs used by filesystem
++ * @max_bud_bytes: maximum amount of data stored in buds
++ * @log_lebs: log size in logical eraseblocks
++ * @lpt_lebs: number of LEBs used for lprops table
++ * @orph_lebs: number of LEBs used for recording orphans
++ * @jhead_cnt: count of journal heads
++ * @fanout: tree fanout (max. number of links per indexing node)
++ * @lsave_cnt: number of LEB numbers in LPT's save table
++ * @fmt_version: UBIFS on-flash format version
++ * @default_compr: default compression
++ * @padding1: reserved for future, zeroes
++ * @rp_uid: reserve pool UID
++ * @rp_gid: reserve pool GID
++ * @rp_size: size of the reserved pool in bytes
++ * @padding2: reserved for future, zeroes
++ * @time_gran: time granularity in nanoseconds
++ * @uuid: UUID generated when the file system image was created
++ */
++struct ubifs_sb_node {
++      struct ubifs_ch ch;
++      __u8 padding[2];
++      __u8 key_hash;
++      __u8 key_fmt;
++      __le32 flags;
++      __le32 min_io_size;
++      __le32 leb_size;
++      __le32 leb_cnt;
++      __le32 max_leb_cnt;
++      __le64 max_bud_bytes;
++      __le32 log_lebs;
++      __le32 lpt_lebs;
++      __le32 orph_lebs;
++      __le32 jhead_cnt;
++      __le32 fanout;
++      __le32 lsave_cnt;
++      __le32 fmt_version;
++      __le16 default_compr;
++      __u8 padding1[2];
++      __le32 rp_uid;
++      __le32 rp_gid;
++      __le64 rp_size;
++      __le32 time_gran;
++      __u8 uuid[16];
++      __u8 padding2[3972];
++} __attribute__ ((packed));
++
++/**
++ * struct ubifs_mst_node - master node.
++ * @ch: common header
++ * @highest_inum: highest inode number in the committed index
++ * @cmt_no: commit number
++ * @flags: various flags (%UBIFS_MST_DIRTY, etc)
++ * @log_lnum: start of the log
++ * @root_lnum: LEB number of the root indexing node
++ * @root_offs: offset within @root_lnum
++ * @root_len: root indexing node length
++ * @gc_lnum: LEB reserved for garbage collection (%-1 value means the LEB was
++ * not reserved and should be reserved on mount)
++ * @ihead_lnum: LEB number of index head
++ * @ihead_offs: offset of index head
++ * @index_size: size of index on flash
++ * @total_free: total free space in bytes
++ * @total_dirty: total dirty space in bytes
++ * @total_used: total used space in bytes (includes only data LEBs)
++ * @total_dead: total dead space in bytes (includes only data LEBs)
++ * @total_dark: total dark space in bytes (includes only data LEBs)
++ * @lpt_lnum: LEB number of LPT root nnode
++ * @lpt_offs: offset of LPT root nnode
++ * @nhead_lnum: LEB number of LPT head
++ * @nhead_offs: offset of LPT head
++ * @ltab_lnum: LEB number of LPT's own lprops table
++ * @ltab_offs: offset of LPT's own lprops table
++ * @lsave_lnum: LEB number of LPT's save table (big model only)
++ * @lsave_offs: offset of LPT's save table (big model only)
++ * @lscan_lnum: LEB number of last LPT scan
++ * @empty_lebs: number of empty logical eraseblocks
++ * @idx_lebs: number of indexing logical eraseblocks
++ * @leb_cnt: count of LEBs used by filesystem
++ * @padding: reserved for future, zeroes
++ */
++struct ubifs_mst_node {
++      struct ubifs_ch ch;
++      __le64 highest_inum;
++      __le64 cmt_no;
++      __le32 flags;
++      __le32 log_lnum;
++      __le32 root_lnum;
++      __le32 root_offs;
++      __le32 root_len;
++      __le32 gc_lnum;
++      __le32 ihead_lnum;
++      __le32 ihead_offs;
++      __le64 index_size;
++      __le64 total_free;
++      __le64 total_dirty;
++      __le64 total_used;
++      __le64 total_dead;
++      __le64 total_dark;
++      __le32 lpt_lnum;
++      __le32 lpt_offs;
++      __le32 nhead_lnum;
++      __le32 nhead_offs;
++      __le32 ltab_lnum;
++      __le32 ltab_offs;
++      __le32 lsave_lnum;
++      __le32 lsave_offs;
++      __le32 lscan_lnum;
++      __le32 empty_lebs;
++      __le32 idx_lebs;
++      __le32 leb_cnt;
++      __u8 padding[344];
++} __attribute__ ((packed));
++
++/**
++ * struct ubifs_ref_node - logical eraseblock reference node.
++ * @ch: common header
++ * @lnum: the referred logical eraseblock number
++ * @offs: start offset in the referred LEB
++ * @jhead: journal head number
++ * @padding: reserved for future, zeroes
++ */
++struct ubifs_ref_node {
++      struct ubifs_ch ch;
++      __le32 lnum;
++      __le32 offs;
++      __le32 jhead;
++      __u8 padding[28];
++} __attribute__ ((packed));
++
++/**
++ * struct ubifs_branch - key/reference/length branch
++ * @lnum: LEB number of the target node
++ * @offs: offset within @lnum
++ * @len: target node length
++ * @key: key
++ */
++struct ubifs_branch {
++      __le32 lnum;
++      __le32 offs;
++      __le32 len;
++      __u8 key[];
++} __attribute__ ((packed));
++
++/**
++ * struct ubifs_idx_node - indexing node.
++ * @ch: common header
++ * @child_cnt: number of child index nodes
++ * @level: tree level
++ * @branches: LEB number / offset / length / key branches
++ */
++struct ubifs_idx_node {
++      struct ubifs_ch ch;
++      __le16 child_cnt;
++      __le16 level;
++      __u8 branches[];
++} __attribute__ ((packed));
++
++/**
++ * struct ubifs_cs_node - commit start node.
++ * @ch: common header
++ * @cmt_no: commit number
++ */
++struct ubifs_cs_node {
++      struct ubifs_ch ch;
++      __le64 cmt_no;
++} __attribute__ ((packed));
++
++/**
++ * struct ubifs_orph_node - orphan node.
++ * @ch: common header
++ * @cmt_no: commit number (also top bit is set on the last node of the commit)
++ * @inos: inode numbers of orphans
++ */
++struct ubifs_orph_node {
++      struct ubifs_ch ch;
++      __le64 cmt_no;
++      __le64 inos[];
++} __attribute__ ((packed));
++
++#endif /* __UBIFS_MEDIA_H__ */
+diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/xattr.c avr32-2.6/fs/ubifs/xattr.c
+--- linux-2.6.25.6/fs/ubifs/xattr.c    1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/fs/ubifs/xattr.c 2008-06-12 15:09:45.603817614 +0200
+@@ -0,0 +1,581 @@
++/*
++ * This file is part of UBIFS.
++ *
++ * Copyright (C) 2006-2008 Nokia Corporation.
++ *
++ * 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.
++ *
++ * 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
++ *
++ * Authors: Artem Bityutskiy (Битюцкий Артём)
++ *          Adrian Hunter
++ */
++
++/*
++ * This file implements UBIFS extended attributes support.
++ *
++ * Extended attributes are implemented as regular inodes with attached data,
++ * which limits extended attribute size to UBIFS block size (4KiB). Names of
++ * extended attributes are described by extended attribute entries (xentries),
++ * which are almost identical to directory entries, but have different key type.
++ *
++ * In other words, the situation with extended attributes is very similar to
++ * directories. Indeed, any inode (but of course not xattr inodes) may have a
++ * number of associated xentries, just like directory inodes have associated
++ * directory entries. Extended attribute entries store the name of the extended
++ * attribute, the host inode number, and the extended attribute inode number.
++ * Similarly, direntries store the name, the parent and the target inode
++ * numbers. Thus, most of the common UBIFS mechanisms may be re-used for
++ * extended attributes.
++ *
++ * The number of extended attributes is not limited, but there is Linux
++ * limitation on the maximum possible size of the list of all extended
++ * attributes associated with an inode (%XATTR_LIST_MAX), so UBIFS makes sure
++ * the sum of all extended attribute names of the inode does not exceed that
++ * limit.
++ *
++ * Extended attributes are synchronous, which means they are written to the
++ * flash media synchronously and there is no write-back for extended attribute
++ * inodes. The extended attribute values are not stored in compressed form on
++ * the media.
++ *
++ * Since extended attributes are represented by regular inodes, they are cached
++ * in the VFS inode cache. The xentries are cached in the LNC cache (see
++ * tnc.c).
++ *
++ * ACL support is not implemented.
++ */
++
++#include <linux/xattr.h>
++#include <linux/posix_acl_xattr.h>
++#include "ubifs.h"
++
++/*
++ * Extended attribute type constants.
++ *
++ * USER_XATTR: user extended attribute ("user.*")
++ * TRUSTED_XATTR: trusted extended attribute ("trusted.*)
++ * SECURITY_XATTR: security extended attribute ("security.*")
++ */
++enum {
++      USER_XATTR,
++      TRUSTED_XATTR,
++      SECURITY_XATTR,
++};
 +
-+#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
++static struct inode_operations none_inode_operations;
++static struct address_space_operations none_address_operations;
++static struct file_operations none_file_operations;
 +
-+/* some bl->props field just changed */
-+static int atmel_bl_update_status(struct backlight_device *bl)
++/**
++ * create_xattr - create an extended attribute.
++ * @c: UBIFS file-system description object
++ * @host: host inode
++ * @nm: extended attribute name
++ * @value: extended attribute value
++ * @size: size of extended attribute value
++ *
++ * This is a helper function which creates an extended attribute of name @nm
++ * and value @value for inode @host. The host inode is also updated on flash
++ * because the ctime and extended attribute accounting data changes. This
++ * function returns zero in case of success and a negative error code in case
++ * of failure.
++ */
++static int create_xattr(struct ubifs_info *c, struct inode *host,
++                      const struct qstr *nm, const void *value, int size)
 +{
-+      struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
-+      int                     power = sinfo->bl_power;
-+      int                     brightness = bl->props.brightness;
++      struct ubifs_inode *ui, *host_ui = ubifs_inode(host);
++      struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
++                                      .new_ino_d = size };
++      struct inode *inode;
++      int err;
 +
-+      /* REVISIT there may be a meaningful difference between
-+       * fb_blank and power ... there seem to be some cases
-+       * this doesn't handle correctly.
++      /*
++       * Linux limits the maximum size of the extended attribute names list
++       * to %XATTR_LIST_MAX. This means we should not allow creating more*
++       * extended attributes if the name list becomes larger. This limitation
++       * is artificial for UBIFS, though.
 +       */
-+      if (bl->props.fb_blank != sinfo->bl_power)
-+              power = bl->props.fb_blank;
-+      else if (bl->props.power != sinfo->bl_power)
-+              power = bl->props.power;
++      if (host_ui->xattr_names + host_ui->xattr_cnt +
++                                      nm->len + 1 > XATTR_LIST_MAX)
++              return -ENOSPC;
++
++      err = ubifs_budget_inode_op(c, host, &req);
++      if (err)
++              return err;
++
++      inode = ubifs_new_inode(c, host, S_IFREG | S_IRWXUGO);
++      if (IS_ERR(inode)) {
++              err = PTR_ERR(inode);
++              goto out_budg;
++      }
++
++      /* Re-define all operations to be "nothing" */
++      inode->i_mapping->a_ops = &none_address_operations;
++      inode->i_op = &none_inode_operations;
++      inode->i_fop = &none_file_operations;
++
++      inode->i_flags |= S_SYNC | S_NOATIME | S_NOCMTIME | S_NOQUOTA;
++      ui = ubifs_inode(inode);
++      ui->xattr = 1;
++      ui->data = kmalloc(size, GFP_NOFS);
++      if (!ui->data) {
++              err = -ENOMEM;
++              goto out_inode;
++      }
 +
-+      if (brightness < 0 && power == FB_BLANK_UNBLANK)
-+              brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
-+      else if (power != FB_BLANK_UNBLANK)
-+              brightness = 0;
++      memcpy(ui->data, value, size);
++      host->i_ctime = ubifs_current_time(host);
++      host_ui->xattr_cnt += 1;
++      spin_lock(&host->i_lock);
++      host_ui->xattr_size += CALC_DENT_SIZE(nm->len);
++      host_ui->xattr_size += CALC_XATTR_BYTES(size);
++      spin_unlock(&host->i_lock);
++      host_ui->xattr_names += nm->len;
 +
-+      lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
-+      lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
-+                      brightness ? contrast_ctr : 0);
++      /*
++       * We do not use i_size_write() because nobody can race with us as we
++       * are holding host @host->i_mutex - every xattr operation for this
++       * inode is serialized by it.
++       */
++      inode->i_size = size;
++      ui->data_len = size;
 +
-+      bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
++      /*
++       * Note, it is important that 'ubifs_jnl_update()' writes the @host
++       * inode last, so when it gets synchronized and the write-buffer is
++       * flushed, the extended attribute is flushed as well.
++       */
++      err = ubifs_jnl_update(c, host, nm, inode, 0, IS_DIRSYNC(host), 1);
++      if (err)
++              goto out_cancel;
 +
++      ubifs_release_ino_clean(c, host, &req);
++      insert_inode_hash(inode);
++      iput(inode);
 +      return 0;
++
++out_cancel:
++      host_ui->xattr_cnt -= 1;
++      spin_lock(&host->i_lock);
++      host_ui->xattr_size -= CALC_DENT_SIZE(nm->len);
++      host_ui->xattr_size -= CALC_XATTR_BYTES(size);
++      spin_unlock(&host->i_lock);
++out_inode:
++      make_bad_inode(inode);
++      iput(inode);
++out_budg:
++      ubifs_cancel_ino_op(c, host, &req);
++      return err;
 +}
 +
-+static int atmel_bl_get_brightness(struct backlight_device *bl)
++/**
++ * change_xattr - change an extended attribute.
++ * @c: UBIFS file-system description object
++ * @host: host inode
++ * @inode: extended attribute inode
++ * @value: extended attribute value
++ * @size: size of extended attribute value
++ *
++ * This helper function changes the value of extended attribute @inode with new
++ * data from @value. Returns zero in case of success and a negative error code
++ * in case of failure.
++ */
++static int change_xattr(struct ubifs_info *c, struct inode *host,
++                      struct inode *inode, const void *value, int size)
 +{
-+      struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
++      struct ubifs_inode *host_ui = ubifs_inode(host);
++      struct ubifs_inode *ui = ubifs_inode(inode);
++      struct ubifs_budget_req req = { .dirtied_ino = 1,
++                                      .dirtied_ino_d = ui->data_len };
++      int err;
++
++      ubifs_assert(ui->data_len == inode->i_size);
++
++      err = ubifs_budget_inode_op(c, host, &req);
++      if (err)
++              return err;
++
++      host->i_ctime = ubifs_current_time(host);
++      spin_lock(&host->i_lock);
++      host_ui->xattr_size -= CALC_XATTR_BYTES(ui->data_len);
++      host_ui->xattr_size += CALC_XATTR_BYTES(size);
++      spin_unlock(&host->i_lock);
++
++      kfree(ui->data);
++      ui->data = kmalloc(size, GFP_NOFS);
++      if (!ui->data) {
++              err = -ENOMEM;
++              goto out_budg;
++      }
++
++      memcpy(ui->data, value, size);
++      inode->i_size = size;
++      ui->data_len = size;
++
++      /*
++       * It is important to write the host inode after the xattr inode
++       * because if the host inode gets synchronized, then the extended
++       * attribute inode gets synchronized, because it goes before the host
++       * inode in the write-buffer.
++       */
++      err = ubifs_jnl_write_2_inodes(c, inode, host, IS_DIRSYNC(host));
++      if (err)
++              goto out_cancel;
++
++      ubifs_release_ino_clean(c, host, &req);
++      return 0;
 +
-+      return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
++out_cancel:
++      spin_lock(&host->i_lock);
++      host_ui->xattr_size -= CALC_XATTR_BYTES(size);
++      host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len);
++      spin_unlock(&host->i_lock);
++      make_bad_inode(inode);
++out_budg:
++      ubifs_cancel_ino_op(c, host, &req);
++      return err;
 +}
 +
-+static struct backlight_ops atmel_lcdc_bl_ops = {
-+      .update_status = atmel_bl_update_status,
-+      .get_brightness = atmel_bl_get_brightness,
-+};
++/**
++ * check_namespace - check extended attribute name-space.
++ * @nm: extended attribute name
++ *
++ * This function makes sure the extended attribute name belongs to one of the
++ * supported extended attribute name-spaces. Returns name-space index in case
++ * of success and a negative error code in case of failure.
++ */
++static int check_namespace(const struct qstr *nm)
++{
++      int type;
++
++      if (nm->len > UBIFS_MAX_NLEN)
++              return -ENAMETOOLONG;
++
++      if (!strncmp(nm->name, XATTR_TRUSTED_PREFIX,
++                   XATTR_TRUSTED_PREFIX_LEN)) {
++              if (nm->name[sizeof(XATTR_TRUSTED_PREFIX) - 1] == '\0')
++                      return -EINVAL;
++              type = TRUSTED_XATTR;
++      } else if (!strncmp(nm->name, XATTR_USER_PREFIX,
++                                    XATTR_USER_PREFIX_LEN)) {
++              if (nm->name[XATTR_USER_PREFIX_LEN] == '\0')
++                      return -EINVAL;
++              type = USER_XATTR;
++      } else if (!strncmp(nm->name, XATTR_SECURITY_PREFIX,
++                                   XATTR_SECURITY_PREFIX_LEN)) {
++              if (nm->name[sizeof(XATTR_SECURITY_PREFIX) - 1] == '\0')
++                      return -EINVAL;
++              type = SECURITY_XATTR;
++      } else
++              return -EOPNOTSUPP;
++
++      return type;
++}
 +
-+static void init_backlight(struct atmel_lcdfb_info *sinfo)
++int ubifs_setxattr(struct dentry *dentry, const char *name,
++                 const void *value, size_t size, int flags)
 +{
-+      struct backlight_device *bl;
++      struct inode *inode, *host = dentry->d_inode;
++      struct ubifs_info *c = host->i_sb->s_fs_info;
++      struct qstr nm = { .name = name, .len = strlen(name) };
++      struct ubifs_dent_node *xent;
++      union ubifs_key key;
++      int err, type;
 +
-+      sinfo->bl_power = FB_BLANK_UNBLANK;
++      dbg_gen("xattr '%s', host ino %lu ('%.*s'), size %zd", name,
++              host->i_ino, dentry->d_name.len, dentry->d_name.name, size);
++      ubifs_assert(ubifs_inode(host)->xattr_cnt >= 0);
++      ubifs_assert(ubifs_inode(host)->xattr_size >= 0);
++      ubifs_assert(ubifs_inode(host)->xattr_names >= 0);
 +
-+      if (sinfo->backlight)
-+              return;
++      if (size > UBIFS_MAX_INO_DATA)
++              return -ERANGE;
 +
-+      bl = backlight_device_register("backlight", &sinfo->pdev->dev,
-+                      sinfo, &atmel_lcdc_bl_ops);
-+      if (IS_ERR(sinfo->backlight)) {
-+              dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
-+                              PTR_ERR(bl));
-+              return;
++      type = check_namespace(&nm);
++      if (type < 0)
++              return type;
++
++      xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
++      if (!xent)
++              return -ENOMEM;
++
++      /*
++       * The extended attribute entries are stored in LNC, so multiple
++       * look-ups do not involve reading the flash.
++       */
++      xent_key_init(c, &key, host->i_ino, &nm);
++      err = ubifs_tnc_lookup_nm(c, &key, xent, &nm);
++      if (err) {
++              if (err != -ENOENT)
++                      goto out_free;
++
++              if (flags & XATTR_REPLACE)
++                      /* We are asked not to create the xattr */
++                      err = -ENODATA;
++              else
++                      err = create_xattr(c, host, &nm, value, size);
++              goto out_free;
++      }
++
++      if (flags & XATTR_CREATE) {
++              /* We are asked not to replace the xattr */
++              err = -EEXIST;
++              goto out_free;
++      }
++
++      inode = ubifs_iget(c->vfs_sb, le64_to_cpu(xent->inum));
++      if (IS_ERR(inode)) {
++              ubifs_err("dead extended attribute entry, error %d", err);
++              ubifs_ro_mode(c, err);
++              err = PTR_ERR(inode);
++              goto out_free;
++      }
++
++      err = change_xattr(c, host, inode, value, size);
++      iput(inode);
++
++out_free:
++      kfree(xent);
++      return err;
++}
++
++ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
++                     size_t size)
++{
++      struct inode *inode, *host = dentry->d_inode;
++      struct ubifs_info *c = host->i_sb->s_fs_info;
++      struct qstr nm = { .name = name, .len = strlen(name) };
++      struct ubifs_inode *ui;
++      struct ubifs_dent_node *xent;
++      union ubifs_key key;
++      int err;
++
++      dbg_gen("xattr '%s', ino %lu ('%.*s'), buf size %zd", name,
++              host->i_ino, dentry->d_name.len, dentry->d_name.name, size);
++      ubifs_assert(ubifs_inode(host)->xattr_cnt >= 0);
++      ubifs_assert(ubifs_inode(host)->xattr_size >= 0);
++      ubifs_assert(ubifs_inode(host)->xattr_names >= 0);
++
++      err = check_namespace(&nm);
++      if (err < 0)
++              return err;
++
++      xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
++      if (!xent)
++              return -ENOMEM;
++
++      mutex_lock(&host->i_mutex);
++      xent_key_init(c, &key, host->i_ino, &nm);
++      err = ubifs_tnc_lookup_nm(c, &key, xent, &nm);
++      if (err) {
++              if (err == -ENOENT)
++                      err = -ENODATA;
++              goto out_unlock;
++      }
++
++      inode = ubifs_iget(c->vfs_sb, le64_to_cpu(xent->inum));
++      if (IS_ERR(inode)) {
++              ubifs_err("dead extended attribute entry, error %d", err);
++              ubifs_ro_mode(c, err);
++              err = PTR_ERR(inode);
++              goto out_unlock;
++      }
++
++      ui = ubifs_inode(inode);
++      ubifs_assert(inode->i_size == ui->data_len);
++      ubifs_assert(ubifs_inode(host)->xattr_size > ui->data_len);
++
++      if (buf) {
++              /* If @buf is %NULL we are supposed to return the length */
++              if (ui->data_len > size) {
++                      dbg_err("buffer size %zd, xattr len %d",
++                              size, ui->data_len);
++                      err = -ERANGE;
++                      goto out_iput;
++              }
++
++              memcpy(buf, ui->data, ui->data_len);
++      }
++      err = ui->data_len;
++
++out_iput:
++      iput(inode);
++out_unlock:
++      mutex_unlock(&host->i_mutex);
++      kfree(xent);
++      return err;
++}
++
++ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
++{
++      struct inode *host = dentry->d_inode;
++      struct ubifs_info *c = host->i_sb->s_fs_info;
++      struct ubifs_inode *host_ui = ubifs_inode(host);
++      union ubifs_key key;
++      struct ubifs_dent_node *xent, *pxent = NULL;
++      int err, len, written = 0;
++      struct qstr nm = { .name = NULL };
++
++      dbg_gen("ino %lu ('%.*s'), buffer size %zd", host->i_ino,
++              dentry->d_name.len, dentry->d_name.name, size);
++      ubifs_assert(host_ui->xattr_cnt >= 0);
++      ubifs_assert(host_ui->xattr_size >= 0);
++      ubifs_assert(host_ui->xattr_names >= 0);
++
++      len = host_ui->xattr_names + host_ui->xattr_cnt;
++      if (!buffer)
++              /*
++               * We should return the minimum buffer size which will fit a
++               * null-terminated list of all the extended attribute names.
++               */
++              return len;
++
++      if (len > size)
++              return -ERANGE;
++
++      lowest_xent_key(c, &key, host->i_ino);
++
++      mutex_lock(&host->i_mutex);
++      while (1) {
++              int type;
++
++              xent = ubifs_tnc_next_ent(c, &key, &nm);
++              if (unlikely(IS_ERR(xent))) {
++                      err = PTR_ERR(xent);
++                      break;
++              }
++
++              nm.name = xent->name;
++              nm.len = le16_to_cpu(xent->nlen);
++
++              type = check_namespace(&nm);
++              if (unlikely(type < 0)) {
++                      err = type;
++                      break;
++              }
++
++              /* Show trusted namespace only for "power" users */
++              if (type != TRUSTED_XATTR || capable(CAP_SYS_ADMIN)) {
++                      memcpy(buffer + written, nm.name, nm.len + 1);
++                      written += nm.len + 1;
++              }
++
++              kfree(pxent);
++              pxent = xent;
++              key_read(c, &xent->key, &key);
++      }
++      mutex_unlock(&host->i_mutex);
++
++      kfree(pxent);
++      if (err != -ENOENT) {
++              ubifs_err("cannot find next direntry, error %d", err);
++              return err;
 +      }
-+      sinfo->backlight = bl;
 +
-+      bl->props.power = FB_BLANK_UNBLANK;
-+      bl->props.fb_blank = FB_BLANK_UNBLANK;
-+      bl->props.max_brightness = 0xff;
-+      bl->props.brightness = atmel_bl_get_brightness(bl);
-+}
++      ubifs_assert(written <= size);
++      return written;
++}
++
++static int remove_xattr(struct ubifs_info *c, struct inode *host,
++                      struct inode *inode, const struct qstr *nm)
++{
++      struct ubifs_inode *host_ui = ubifs_inode(host);
++      struct ubifs_inode *ui = ubifs_inode(inode);
++      struct ubifs_budget_req req = { .dirtied_ino = 1, .mod_dent = 1 };
++      int err;
++
++      ubifs_assert(ui->data_len == inode->i_size);
++
++      err = ubifs_budget_inode_op(c, host, &req);
++      if (err)
++              return err;
++
++      host->i_ctime = ubifs_current_time(host);
++      host_ui->xattr_cnt -= 1;
++      spin_lock(&host->i_lock);
++      host_ui->xattr_size -= CALC_DENT_SIZE(nm->len);
++      host_ui->xattr_size -= CALC_XATTR_BYTES(ui->data_len);
++      spin_unlock(&host->i_lock);
++      host_ui->xattr_names -= nm->len;
 +
-+static void exit_backlight(struct atmel_lcdfb_info *sinfo)
-+{
-+      if (sinfo->backlight)
-+              backlight_device_unregister(sinfo->backlight);
-+}
++      err = ubifs_jnl_delete_xattr(c, host, inode, nm, IS_DIRSYNC(host));
++      if (err)
++              goto out_cancel;
 +
-+#else
++      ubifs_release_ino_clean(c, host, &req);
++      return 0;
 +
-+static void init_backlight(struct atmel_lcdfb_info *sinfo)
-+{
-+      dev_warn(&sinfo->pdev->dev, "backlight control is not available\n");
++out_cancel:
++      ubifs_cancel_ino_op(c, host, &req);
++      host_ui->xattr_cnt += 1;
++      spin_lock(&host->i_lock);
++      host_ui->xattr_size += CALC_DENT_SIZE(nm->len);
++      host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len);
++      spin_unlock(&host->i_lock);
++      make_bad_inode(inode);
++      return err;
 +}
 +
-+static void exit_backlight(struct atmel_lcdfb_info *sinfo)
++int ubifs_removexattr(struct dentry *dentry, const char *name)
 +{
-+}
++      struct inode *inode, *host = dentry->d_inode;
++      struct ubifs_info *c = host->i_sb->s_fs_info;
++      struct qstr nm = { .name = name, .len = strlen(name) };
++      struct ubifs_dent_node *xent;
++      union ubifs_key key;
++      int err;
 +
-+#endif
++      dbg_gen("xattr '%s', ino %lu ('%.*s')", name,
++              host->i_ino, dentry->d_name.len, dentry->d_name.name);
++      ubifs_assert(mutex_is_locked(&host->i_mutex));
++      ubifs_assert(ubifs_inode(host)->xattr_cnt >= 0);
++      ubifs_assert(ubifs_inode(host)->xattr_size >= 0);
++      ubifs_assert(ubifs_inode(host)->xattr_names >= 0);
 +
-+static void init_contrast(struct atmel_lcdfb_info *sinfo)
-+{
-+      /* have some default contrast/backlight settings */
-+      lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
-+      lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
++      err = check_namespace(&nm);
++      if (err < 0)
++              return err;
 +
-+      if (sinfo->lcdcon_is_backlight)
-+              init_backlight(sinfo);
-+}
++      xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
++      if (!xent)
++              return -ENOMEM;
 +
- static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
-       .type           = FB_TYPE_PACKED_PIXELS,
-       .visual         = FB_VISUAL_TRUECOLOR,
-       .xpanstep       = 0,
--      .ypanstep       = 0,
-+      .ypanstep       = 1,
-       .ywrapstep      = 0,
-       .accel          = FB_ACCEL_NONE,
- };
-@@ -148,6 +252,8 @@
-               return -ENOMEM;
-       }
-+      memset(info->screen_base, 0, info->fix.smem_len);
++      xent_key_init(c, &key, host->i_ino, &nm);
++      err = ubifs_tnc_lookup_nm(c, &key, xent, &nm);
++      if (err) {
++              if (err == -ENOENT)
++                      err = -ENODATA;
++              goto out_free;
++      }
 +
-       return 0;
- }
-@@ -203,6 +309,26 @@
-       var->transp.offset = var->transp.length = 0;
-       var->xoffset = var->yoffset = 0;
-+      /* Saturate vertical and horizontal timings at maximum values */
-+      var->vsync_len = min_t(u32, var->vsync_len,
-+                      (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
-+      var->upper_margin = min_t(u32, var->upper_margin,
-+                      ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
-+      var->lower_margin = min_t(u32, var->lower_margin,
-+                      ATMEL_LCDC_VFP);
-+      var->right_margin = min_t(u32, var->right_margin,
-+                      (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
-+      var->hsync_len = min_t(u32, var->hsync_len,
-+                      (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
-+      var->left_margin = min_t(u32, var->left_margin,
-+                      ATMEL_LCDC_HBP + 1);
-+
-+      /* Some parameters can't be zero */
-+      var->vsync_len = max_t(u32, var->vsync_len, 1);
-+      var->right_margin = max_t(u32, var->right_margin, 1);
-+      var->hsync_len = max_t(u32, var->hsync_len, 1);
-+      var->left_margin = max_t(u32, var->left_margin, 1);
-+
-       switch (var->bits_per_pixel) {
-       case 1:
-       case 2:
-@@ -370,10 +496,6 @@
-       /* Disable all interrupts */
-       lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
--      /* Set contrast */
--      value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE;
--      lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value);
--      lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
-       /* ...wait for DMA engine to become idle... */
-       while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
-               msleep(10);
-@@ -516,7 +638,6 @@
-       struct fb_info *info = sinfo->info;
-       int ret = 0;
--      memset_io(info->screen_base, 0, info->fix.smem_len);
-       info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
-       dev_info(info->device,
-@@ -577,6 +698,7 @@
-               sinfo->default_monspecs = pdata_sinfo->default_monspecs;
-               sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
-               sinfo->guard_time = pdata_sinfo->guard_time;
-+              sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
-       } else {
-               dev_err(dev, "cannot get default configuration\n");
-               goto free_info;
-@@ -645,6 +767,11 @@
-               info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
-               if (!info->screen_base)
-                       goto release_intmem;
++      inode = ubifs_iget(c->vfs_sb, le64_to_cpu(xent->inum));
++      if (IS_ERR(inode)) {
++              ubifs_err("dead extended attribute node entry");
++              ubifs_ro_mode(c, err);
++              err = PTR_ERR(inode);
++              goto out_free;
++      }
 +
-+              /*
-+               * Don't clear the framebuffer -- someone may have set
-+               * up a splash image.
-+               */
-       } else {
-               /* alocate memory buffer */
-               ret = atmel_lcdfb_alloc_video_memory(sinfo);
-@@ -670,6 +797,9 @@
-               goto release_mem;
-       }
-+      /* Initialize PWM for contrast or backlight ("off") */
-+      init_contrast(sinfo);
-+
-       /* interrupt */
-       ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
-       if (ret) {
-@@ -721,6 +851,7 @@
- unregister_irqs:
-       free_irq(sinfo->irq_base, info);
- unmap_mmio:
-+      exit_backlight(sinfo);
-       iounmap(sinfo->mmio);
- release_mem:
-       release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
-@@ -755,6 +886,7 @@
-       if (!sinfo)
-               return 0;
-+      exit_backlight(sinfo);
-       if (sinfo->atmel_lcdfb_power_control)
-               sinfo->atmel_lcdfb_power_control(0);
-       unregister_framebuffer(info);
-@@ -781,6 +913,9 @@
- static struct platform_driver atmel_lcdfb_driver = {
-       .remove         = __exit_p(atmel_lcdfb_remove),
++      ubifs_assert(inode->i_nlink == 1);
++      inode->i_nlink = 0;
++      err = remove_xattr(c, host, inode, &nm);
++      if (err)
++              inode->i_nlink = 1;
 +
-+// FIXME need suspend, resume
++      /* If @i_nlink is 0, 'iput()' will delete the inode */
++      iput(inode);
 +
-       .driver         = {
-               .name   = "atmel_lcdfb",
-               .owner  = THIS_MODULE,
---- a/drivers/video/backlight/Kconfig
-+++ b/drivers/video/backlight/Kconfig
-@@ -50,6 +50,19 @@
-         To have support for your specific LCD panel you will have to
-         select the proper drivers which depend on this option.
-+config BACKLIGHT_ATMEL_LCDC
-+      bool "Atmel LCDC Contrast-as-Backlight control"
-+      depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL
-+      default y if MACH_SAM9261EK || MACH_SAM9263EK
-+      help
-+        This provides a backlight control internal to the Atmel LCDC
-+        driver.  If the LCD "contrast control" on your board is wired
-+        so it controls the backlight brightness, select this option to
-+        export this as a PWM-based backlight control.
-+
-+        If in doubt, it's safe to enable this option; it doesn't kick
-+        in unless the board's description says it's wired that way.
-+
- config BACKLIGHT_CORGI
-       tristate "Generic (aka Sharp Corgi) Backlight Driver"
-       depends on BACKLIGHT_CLASS_DEVICE
---- a/drivers/video/console/Kconfig
-+++ b/drivers/video/console/Kconfig
-@@ -6,7 +6,7 @@
- config VGA_CONSOLE
-       bool "VGA text console" if EMBEDDED || !X86
--      depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN
-+      depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN && !AVR32
-       default y
-       help
-         Saying Y here will allow you to use Linux in text mode through a
---- a/drivers/watchdog/Kconfig
-+++ b/drivers/watchdog/Kconfig
-@@ -223,7 +223,7 @@
- config AT32AP700X_WDT
-       tristate "AT32AP700x watchdog"
--      depends on CPU_AT32AP7000
-+      depends on CPU_AT32AP700X
-       help
-         Watchdog timer embedded into AT32AP700x devices. This will reboot
-         your system when the timeout is reached.
---- a/include/asm-avr32/arch-at32ap/at32ap7000.h
-+++ /dev/null
-@@ -1,35 +0,0 @@
++out_free:
++      kfree(xent);
++      return err;
++}
+diff --exclude=.git -urN linux-2.6.25.6/include/asm-arm/arch-at91/at91_ecc.h avr32-2.6/include/asm-arm/arch-at91/at91_ecc.h
+--- linux-2.6.25.6/include/asm-arm/arch-at91/at91_ecc.h        2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/include/asm-arm/arch-at91/at91_ecc.h     1970-01-01 01:00:00.000000000 +0100
+@@ -1,38 +0,0 @@
 -/*
-- * Pin definitions for AT32AP7000.
+- * include/asm-arm/arch-at91/at91_ecc.h
 - *
-- * Copyright (C) 2006 Atmel Corporation
+- * Error Corrected Code Controller (ECC) - System peripherals regsters.
+- * Based on AT91SAM9260 datasheet revision B.
 - *
-- * 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.
+- * 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.
 - */
--#ifndef __ASM_ARCH_AT32AP7000_H__
--#define __ASM_ARCH_AT32AP7000_H__
 -
--#define GPIO_PERIPH_A 0
--#define GPIO_PERIPH_B 1
+-#ifndef AT91_ECC_H
+-#define AT91_ECC_H
 -
--#define NR_GPIO_CONTROLLERS   4
+-#define AT91_ECC_CR           (AT91_ECC + 0x00)       /* Control register */
+-#define               AT91_ECC_RST            (1 << 0)                /* Reset parity */
 -
--/*
-- * Pin numbers identifying specific GPIO pins on the chip. They can
-- * also be converted to IRQ numbers by passing them through
-- * gpio_to_irq().
-- */
--#define GPIO_PIOA_BASE        (0)
--#define GPIO_PIOB_BASE        (GPIO_PIOA_BASE + 32)
--#define GPIO_PIOC_BASE        (GPIO_PIOB_BASE + 32)
--#define GPIO_PIOD_BASE        (GPIO_PIOC_BASE + 32)
--#define GPIO_PIOE_BASE        (GPIO_PIOD_BASE + 32)
+-#define AT91_ECC_MR           (AT91_ECC + 0x04)       /* Mode register */
+-#define               AT91_ECC_PAGESIZE       (3 << 0)                /* Page Size */
+-#define                       AT91_ECC_PAGESIZE_528           (0)
+-#define                       AT91_ECC_PAGESIZE_1056          (1)
+-#define                       AT91_ECC_PAGESIZE_2112          (2)
+-#define                       AT91_ECC_PAGESIZE_4224          (3)
+-
+-#define AT91_ECC_SR           (AT91_ECC + 0x08)       /* Status register */
+-#define               AT91_ECC_RECERR         (1 << 0)                /* Recoverable Error */
+-#define               AT91_ECC_ECCERR         (1 << 1)                /* ECC Single Bit Error */
+-#define               AT91_ECC_MULERR         (1 << 2)                /* Multiple Errors */
+-
+-#define AT91_ECC_PR           (AT91_ECC + 0x0c)       /* Parity register */
+-#define               AT91_ECC_BITADDR        (0xf << 0)              /* Bit Error Address */
+-#define               AT91_ECC_WORDADDR       (0xfff << 4)            /* Word Error Address */
 -
--#define GPIO_PIN_PA(N)        (GPIO_PIOA_BASE + (N))
--#define GPIO_PIN_PB(N)        (GPIO_PIOB_BASE + (N))
--#define GPIO_PIN_PC(N)        (GPIO_PIOC_BASE + (N))
--#define GPIO_PIN_PD(N)        (GPIO_PIOD_BASE + (N))
--#define GPIO_PIN_PE(N)        (GPIO_PIOE_BASE + (N))
+-#define AT91_ECC_NPR          (AT91_ECC + 0x10)       /* NParity register */
+-#define               AT91_ECC_NPARITY        (0xffff << 0)           /* NParity */
 -
--#endif /* __ASM_ARCH_AT32AP7000_H__ */
---- /dev/null
-+++ b/include/asm-avr32/arch-at32ap/at32ap700x.h
-@@ -0,0 +1,35 @@
+-#endif
+diff --exclude=.git -urN linux-2.6.25.6/include/asm-arm/arch-at91/board.h avr32-2.6/include/asm-arm/arch-at91/board.h
+--- linux-2.6.25.6/include/asm-arm/arch-at91/board.h   2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/include/asm-arm/arch-at91/board.h        2008-06-12 15:09:45.803815435 +0200
+@@ -85,7 +85,7 @@
+ extern void __init at91_add_device_usbh(struct at91_usbh_data *data);
+  /* NAND / SmartMedia */
+-struct at91_nand_data {
++struct atmel_nand_data {
+       u8              enable_pin;     /* chip enable */
+       u8              det_pin;        /* card detect */
+       u8              rdy_pin;        /* ready/busy */
+@@ -94,7 +94,7 @@
+       u8              bus_width_16;   /* buswidth is 16 bit */
+       struct mtd_partition* (*partition_info)(int, int*);
+ };
+-extern void __init at91_add_device_nand(struct at91_nand_data *data);
++extern void __init at91_add_device_nand(struct atmel_nand_data *data);
+  /* I2C*/
+ extern void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices);
+diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/arch-at32ap/board.h avr32-2.6/include/asm-avr32/arch-at32ap/board.h
+--- linux-2.6.25.6/include/asm-avr32/arch-at32ap/board.h       2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/include/asm-avr32/arch-at32ap/board.h    2008-06-12 15:09:45.855816193 +0200
+@@ -8,6 +8,12 @@
+ #define GPIO_PIN_NONE (-1)
 +/*
-+ * Pin definitions for AT32AP7000.
-+ *
-+ * Copyright (C) 2006 Atmel Corporation
-+ *
-+ * 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.
++ * Clock rates for various on-board oscillators. The number of entries
++ * in this array is chip-dependent.
 + */
-+#ifndef __ASM_ARCH_AT32AP700X_H__
-+#define __ASM_ARCH_AT32AP700X_H__
-+
-+#define GPIO_PERIPH_A 0
-+#define GPIO_PERIPH_B 1
-+
-+#define NR_GPIO_CONTROLLERS   4
-+
-+/*
-+ * Pin numbers identifying specific GPIO pins on the chip. They can
-+ * also be converted to IRQ numbers by passing them through
-+ * gpio_to_irq().
-+ */
-+#define GPIO_PIOA_BASE        (0)
-+#define GPIO_PIOB_BASE        (GPIO_PIOA_BASE + 32)
-+#define GPIO_PIOC_BASE        (GPIO_PIOB_BASE + 32)
-+#define GPIO_PIOD_BASE        (GPIO_PIOC_BASE + 32)
-+#define GPIO_PIOE_BASE        (GPIO_PIOD_BASE + 32)
-+
-+#define GPIO_PIN_PA(N)        (GPIO_PIOA_BASE + (N))
-+#define GPIO_PIN_PB(N)        (GPIO_PIOB_BASE + (N))
-+#define GPIO_PIN_PC(N)        (GPIO_PIOC_BASE + (N))
-+#define GPIO_PIN_PD(N)        (GPIO_PIOD_BASE + (N))
-+#define GPIO_PIN_PE(N)        (GPIO_PIOE_BASE + (N))
-+
-+#endif /* __ASM_ARCH_AT32AP700X_H__ */
---- a/include/asm-avr32/arch-at32ap/board.h
-+++ b/include/asm-avr32/arch-at32ap/board.h
-@@ -38,9 +38,7 @@
++extern unsigned long at32_board_osc_rates[];
++  
+ /* Add basic devices: system manager, interrupt controller, portmuxes, etc. */
+ void at32_add_system_devices(void);
+@@ -36,11 +42,10 @@
+ struct atmel_lcdfb_info;
+ struct platform_device *
  at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
-                    unsigned long fbmem_start, unsigned long fbmem_len);
+-                   unsigned long fbmem_start, unsigned long fbmem_len);
++                   unsigned long fbmem_start, unsigned long fbmem_len,
++                   unsigned int pin_config);
  
 -struct usba_platform_data {
 -      int vbus_pin;
  struct platform_device *
  at32_add_device_usba(unsigned int id, struct usba_platform_data *data);
  
-@@ -51,6 +49,9 @@
- at32_add_device_ide(unsigned int id, unsigned int extint,
-                   struct ide_platform_data *data);
-+/* mask says which PWM channels to mux */
-+struct platform_device *at32_add_device_pwm(u32 mask);
-+
- /* depending on what's hooked up, not all SSC pins will be used */
- #define       ATMEL_SSC_TK            0x01
- #define       ATMEL_SSC_TF            0x02
-@@ -65,8 +66,17 @@
+@@ -68,8 +73,17 @@
  struct platform_device *
  at32_add_device_ssc(unsigned int id, unsigned int flags);
  
 -struct platform_device *at32_add_device_mci(unsigned int id);
 +struct i2c_board_info;
 +struct platform_device *at32_add_device_twi(unsigned int id,
-+                                           struct i2c_board_info *b,
-+                                           unsigned int n);
++                                          struct i2c_board_info *b,
++                                          unsigned int n);
 +
 +struct mci_platform_data {
 +      int detect_pin;
  struct platform_device *at32_add_device_ac97c(unsigned int id);
  struct platform_device *at32_add_device_abdac(unsigned int id);
  
-@@ -81,4 +91,7 @@
+@@ -84,4 +98,20 @@
  at32_add_device_cf(unsigned int id, unsigned int extint,
                struct cf_platform_data *data);
  
 +struct platform_device *
 +at32_add_device_psif(unsigned int id);
++
++/* NAND / SmartMedia */
++struct atmel_nand_data {
++      int     enable_pin;     /* chip enable */
++      int     det_pin;        /* card detect */
++      int     rdy_pin;        /* ready/busy */
++      u8      ale;            /* address line number connected to ALE */
++      u8      cle;            /* address line number connected to CLE */
++      u8      bus_width_16;   /* buswidth is 16 bit */
++      struct mtd_partition *(*partition_info)(int size, int *num_partitions);
++};
++struct platform_device *
++at32_add_device_nand(unsigned int id, struct atmel_nand_data *data);
 +
  #endif /* __ASM_ARCH_BOARD_H */
---- a/include/asm-avr32/arch-at32ap/cpu.h
-+++ b/include/asm-avr32/arch-at32ap/cpu.h
-@@ -14,7 +14,7 @@
-  * Only AT32AP7000 is defined for now. We can identify the specific
-  * chip at runtime, but I'm not sure if it's really worth it.
-  */
--#ifdef CONFIG_CPU_AT32AP7000
-+#ifdef CONFIG_CPU_AT32AP700X
- # define cpu_is_at32ap7000()  (1)
- #else
- # define cpu_is_at32ap7000()  (0)
---- a/include/asm-avr32/arch-at32ap/io.h
-+++ b/include/asm-avr32/arch-at32ap/io.h
-@@ -4,7 +4,7 @@
- /* For "bizarre" halfword swapping */
- #include <linux/byteorder/swabb.h>
--#if defined(CONFIG_AP7000_32_BIT_SMC)
-+#if defined(CONFIG_AP700X_32_BIT_SMC)
- # define __swizzle_addr_b(addr)       (addr ^ 3UL)
- # define __swizzle_addr_w(addr)       (addr ^ 2UL)
- # define __swizzle_addr_l(addr)       (addr)
-@@ -14,7 +14,7 @@
- # define __mem_ioswabb(a, x)  (x)
- # define __mem_ioswabw(a, x)  swab16(x)
- # define __mem_ioswabl(a, x)  swab32(x)
--#elif defined(CONFIG_AP7000_16_BIT_SMC)
-+#elif defined(CONFIG_AP700X_16_BIT_SMC)
- # define __swizzle_addr_b(addr)       (addr ^ 1UL)
- # define __swizzle_addr_w(addr)       (addr)
- # define __swizzle_addr_l(addr)       (addr)
---- /dev/null
-+++ b/include/asm-avr32/arch-at32ap/pm.h
-@@ -0,0 +1,48 @@
+diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/arch-at32ap/init.h avr32-2.6/include/asm-avr32/arch-at32ap/init.h
+--- linux-2.6.25.6/include/asm-avr32/arch-at32ap/init.h        2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/include/asm-avr32/arch-at32ap/init.h     2008-06-12 15:09:45.855816193 +0200
+@@ -13,10 +13,6 @@
+ void setup_platform(void);
+ void setup_board(void);
+-/* Called by setup_platform */
+-void at32_clock_init(void);
+-void at32_portmux_init(void);
+-
+ void at32_setup_serial_console(unsigned int usart_id);
+ #endif /* __ASM_AVR32_AT32AP_INIT_H__ */
+diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/arch-at32ap/pm.h avr32-2.6/include/asm-avr32/arch-at32ap/pm.h
+--- linux-2.6.25.6/include/asm-avr32/arch-at32ap/pm.h  1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/include/asm-avr32/arch-at32ap/pm.h       2008-06-12 15:09:45.855816193 +0200
+@@ -0,0 +1,51 @@
 +/*
 + * AVR32 AP Power Management.
 + *
 +
 +#ifndef __ASSEMBLY__
 +extern void cpu_enter_idle(void);
++extern void cpu_enter_standby(unsigned long sdramc_base);
 +
 +extern bool disable_idle_sleep;
 +
 +      else
 +              cpu_enter_idle();
 +}
++
++void intc_set_suspend_handler(unsigned long offset);
 +#endif
 +
 +#endif /* __ASM_AVR32_ARCH_PM_H */
---- a/include/asm-avr32/arch-at32ap/portmux.h
-+++ b/include/asm-avr32/arch-at32ap/portmux.h
+diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/arch-at32ap/portmux.h avr32-2.6/include/asm-avr32/arch-at32ap/portmux.h
+--- linux-2.6.25.6/include/asm-avr32/arch-at32ap/portmux.h     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/include/asm-avr32/arch-at32ap/portmux.h  2008-06-12 15:09:45.859816144 +0200
 @@ -26,4 +26,16 @@
  void at32_select_gpio(unsigned int pin, unsigned long flags);
  void at32_reserve_pin(unsigned int pin);
 +#endif /* CONFIG_GPIO_DEV */
 +
  #endif /* __ASM_ARCH_PORTMUX_H__ */
---- a/include/asm-avr32/arch-at32ap/time.h
-+++ /dev/null
+diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/arch-at32ap/sram.h avr32-2.6/include/asm-avr32/arch-at32ap/sram.h
+--- linux-2.6.25.6/include/asm-avr32/arch-at32ap/sram.h        1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/include/asm-avr32/arch-at32ap/sram.h     2008-06-12 15:09:45.859816144 +0200
+@@ -0,0 +1,30 @@
++/*
++ * Simple SRAM allocator
++ *
++ * Copyright (C) 2008 Atmel Corporation
++ *
++ * 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.
++ */
++#ifndef __ASM_AVR32_ARCH_SRAM_H
++#define __ASM_AVR32_ARCH_SRAM_H
++
++#include <linux/genalloc.h>
++
++extern struct gen_pool *sram_pool;
++
++static inline unsigned long sram_alloc(size_t len)
++{
++      if (!sram_pool)
++              return 0UL;
++
++      return gen_pool_alloc(sram_pool, len);
++}
++
++static inline void sram_free(unsigned long addr, size_t len)
++{
++      return gen_pool_free(sram_pool, addr, len);
++}
++
++#endif /* __ASM_AVR32_ARCH_SRAM_H */
+diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/arch-at32ap/time.h avr32-2.6/include/asm-avr32/arch-at32ap/time.h
+--- linux-2.6.25.6/include/asm-avr32/arch-at32ap/time.h        2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/include/asm-avr32/arch-at32ap/time.h     1970-01-01 01:00:00.000000000 +0100
 @@ -1,112 +0,0 @@
 -/*
 - * Copyright (C) 2007 Atmel Corporation
 -      __raw_writel((value), port + (0x40 * instance) + TIMER_##reg)
 -
 -#endif /* _ASM_AVR32_ARCH_AT32AP_TIME_H */
---- a/include/asm-avr32/asm.h
-+++ b/include/asm-avr32/asm.h
+diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/asm.h avr32-2.6/include/asm-avr32/asm.h
+--- linux-2.6.25.6/include/asm-avr32/asm.h     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/include/asm-avr32/asm.h  2008-06-12 15:04:04.683816631 +0200
 @@ -12,10 +12,10 @@
  #include <asm/asm-offsets.h>
  #include <asm/thread_info.h>
  
  #ifdef CONFIG_FRAME_POINTER
        .macro  save_fp
---- a/include/asm-avr32/byteorder.h
-+++ b/include/asm-avr32/byteorder.h
-@@ -12,8 +12,10 @@
- extern unsigned short __builtin_bswap_16(unsigned short x);
- #endif
-+#if 0
- #define __arch__swab32(x) __builtin_bswap_32(x)
- #define __arch__swab16(x) __builtin_bswap_16(x)
-+#endif
- #if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
- # define __BYTEORDER_HAS_U64__
---- /dev/null
-+++ b/include/asm-avr32/dma-controller.h
+diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/dma-controller.h avr32-2.6/include/asm-avr32/dma-controller.h
+--- linux-2.6.25.6/include/asm-avr32/dma-controller.h  1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/include/asm-avr32/dma-controller.h       2008-06-12 15:09:45.859816144 +0200
 @@ -0,0 +1,166 @@
 +/*
 + * Copyright (C) 2005-2006 Atmel Corporation
 +extern struct dma_controller *find_dma_controller(int id);
 +
 +#endif /* __ASM_AVR32_DMA_CONTROLLER_H */
---- a/include/asm-avr32/intc.h
-+++ /dev/null
+diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/intc.h avr32-2.6/include/asm-avr32/intc.h
+--- linux-2.6.25.6/include/asm-avr32/intc.h    2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/include/asm-avr32/intc.h 1970-01-01 01:00:00.000000000 +0100
 @@ -1,128 +0,0 @@
 -#ifndef __ASM_AVR32_INTC_H
 -#define __ASM_AVR32_INTC_H
 -extern int intc_register_controller(struct irq_controller *ctrl);
 -
 -#endif /* __ASM_AVR32_INTC_H */
---- a/include/asm-avr32/irq.h
-+++ b/include/asm-avr32/irq.h
-@@ -11,4 +11,14 @@
- #define irq_canonicalize(i)   (i)
-+#ifndef __ASSEMBLER__
-+int nmi_enable(void);
-+void nmi_disable(void);
+diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/irq.h avr32-2.6/include/asm-avr32/irq.h
+--- linux-2.6.25.6/include/asm-avr32/irq.h     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/include/asm-avr32/irq.h  2008-06-12 15:04:04.687816302 +0200
+@@ -14,6 +14,11 @@
+ #ifndef __ASSEMBLER__
+ int nmi_enable(void);
+ void nmi_disable(void);
 +
 +/*
 + * Returns a bitmask of pending interrupts in a group.
 + */
 +extern unsigned long intc_get_pending(unsigned int group);
-+#endif
-+
- #endif /* __ASM_AVR32_IOCTLS_H */
---- a/include/asm-avr32/kdebug.h
-+++ b/include/asm-avr32/kdebug.h
-@@ -5,6 +5,7 @@
- enum die_val {
-       DIE_BREAKPOINT,
-       DIE_SSTEP,
-+      DIE_NMI,
- };
- #endif /* __ASM_AVR32_KDEBUG_H */
---- a/include/asm-avr32/ocd.h
-+++ b/include/asm-avr32/ocd.h
-@@ -533,6 +533,11 @@
- #define ocd_read(reg)                 __ocd_read(OCD_##reg)
- #define ocd_write(reg, value)         __ocd_write(OCD_##reg, value)
-+struct task_struct;
-+
-+void ocd_enable(struct task_struct *child);
-+void ocd_disable(struct task_struct *child);
-+
- #endif /* !__ASSEMBLER__ */
- #endif /* __ASM_AVR32_OCD_H */
---- a/include/asm-avr32/pgtable.h
-+++ b/include/asm-avr32/pgtable.h
-@@ -157,6 +157,7 @@
- #define _PAGE_S(x)    _PAGE_NORMAL(x)
- #define PAGE_COPY     _PAGE_P(PAGE_WRITE | PAGE_READ)
-+#define PAGE_SHARED   _PAGE_S(PAGE_WRITE | PAGE_READ)
+ #endif
  
- #ifndef __ASSEMBLY__
- /*
---- a/include/asm-avr32/processor.h
-+++ b/include/asm-avr32/processor.h
-@@ -57,11 +57,25 @@
-       unsigned short cpu_revision;
-       enum tlb_config tlb_config;
-       unsigned long features;
-+      u32 device_id;
-       struct cache_info icache;
-       struct cache_info dcache;
- };
+ #endif /* __ASM_AVR32_IOCTLS_H */
+diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/page.h avr32-2.6/include/asm-avr32/page.h
+--- linux-2.6.25.6/include/asm-avr32/page.h    2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/include/asm-avr32/page.h 2008-06-12 15:04:04.691816253 +0200
+@@ -8,13 +8,11 @@
+ #ifndef __ASM_AVR32_PAGE_H
+ #define __ASM_AVR32_PAGE_H
++#include <linux/const.h>
++
+ /* PAGE_SHIFT determines the page size */
+ #define PAGE_SHIFT    12
+-#ifdef __ASSEMBLY__
+-#define PAGE_SIZE     (1 << PAGE_SHIFT)
+-#else
+-#define PAGE_SIZE     (1UL << PAGE_SHIFT)
+-#endif
++#define PAGE_SIZE     (_AC(1, UL) << PAGE_SHIFT)
+ #define PAGE_MASK     (~(PAGE_SIZE-1))
+ #define PTE_MASK      PAGE_MASK
  
-+static inline unsigned int avr32_get_manufacturer_id(struct avr32_cpuinfo *cpu)
-+{
-+      return (cpu->device_id >> 1) & 0x7f;
-+}
-+static inline unsigned int avr32_get_product_number(struct avr32_cpuinfo *cpu)
-+{
-+      return (cpu->device_id >> 12) & 0xffff;
-+}
-+static inline unsigned int avr32_get_chip_revision(struct avr32_cpuinfo *cpu)
-+{
-+      return (cpu->device_id >> 28) & 0x0f;
-+}
-+
- extern struct avr32_cpuinfo boot_cpu_data;
+diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/pci.h avr32-2.6/include/asm-avr32/pci.h
+--- linux-2.6.25.6/include/asm-avr32/pci.h     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/include/asm-avr32/pci.h  2008-06-12 15:09:45.859816144 +0200
+@@ -5,4 +5,6 @@
  
- #ifdef CONFIG_SMP
---- a/include/asm-avr32/ptrace.h
-+++ b/include/asm-avr32/ptrace.h
-@@ -121,7 +121,15 @@
- };
+ #define PCI_DMA_BUS_IS_PHYS   (1)
  
- #ifdef __KERNEL__
--# define user_mode(regs) (((regs)->sr & MODE_MASK) == MODE_USER)
-+
-+#include <asm/ocd.h>
++#include <asm-generic/pci-dma-compat.h>
 +
-+#define arch_ptrace_attach(child)       ocd_enable(child)
+ #endif /* __ASM_AVR32_PCI_H__ */
+diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/serial.h avr32-2.6/include/asm-avr32/serial.h
+--- linux-2.6.25.6/include/asm-avr32/serial.h  1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/include/asm-avr32/serial.h       2008-06-12 15:04:04.695816483 +0200
+@@ -0,0 +1,13 @@
++#ifndef _ASM_SERIAL_H
++#define _ASM_SERIAL_H
 +
-+#define user_mode(regs)                 (((regs)->sr & MODE_MASK) == MODE_USER)
-+#define instruction_pointer(regs)       ((regs)->pc)
-+#define profile_pc(regs)                instruction_pointer(regs)
++/*
++ * This assumes you have a 1.8432 MHz clock for your UART.
++ *
++ * It'd be nice if someone built a serial card with a 24.576 MHz
++ * clock, since the 16550A is capable of handling a top speed of 1.5
++ * megabits/second; but this requires the faster clock.
++ */
++#define BASE_BAUD (1843200 / 16)
 +
- extern void show_regs (struct pt_regs *);
- static __inline__ int valid_user_regs(struct pt_regs *regs)
-@@ -141,9 +149,6 @@
-       return 0;
- }
--#define instruction_pointer(regs) ((regs)->pc)
--
--#define profile_pc(regs) instruction_pointer(regs)
- #endif /* __KERNEL__ */
---- a/include/asm-avr32/thread_info.h
-+++ b/include/asm-avr32/thread_info.h
++#endif /* _ASM_SERIAL_H */
+diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/thread_info.h avr32-2.6/include/asm-avr32/thread_info.h
+--- linux-2.6.25.6/include/asm-avr32/thread_info.h     2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/include/asm-avr32/thread_info.h  2008-06-12 15:09:45.859816144 +0200
 @@ -88,6 +88,7 @@
  #define TIF_MEMDIE            6
  #define TIF_RESTORE_SIGMASK   7       /* restore signal mask in do_signal */
  #define TIF_CPU_GOING_TO_SLEEP        8       /* CPU is entering sleep 0 mode */
-+#define TIF_DEBUG             30      /* debugging enabled */
++#define TIF_FREEZE            29
+ #define TIF_DEBUG             30      /* debugging enabled */
  #define TIF_USERSPACE         31      /* true if FS sets userspace */
  
- #define _TIF_SYSCALL_TRACE    (1 << TIF_SYSCALL_TRACE)
---- /dev/null
-+++ b/include/linux/atmel_pwm.h
-@@ -0,0 +1,70 @@
-+#ifndef __LINUX_ATMEL_PWM_H
-+#define __LINUX_ATMEL_PWM_H
-+
-+/**
-+ * struct pwm_channel - driver handle to a PWM channel
-+ * @regs: base of this channel's registers
-+ * @index: number of this channel (0..31)
-+ * @mck: base clock rate, which can be prescaled and maybe subdivided
-+ *
-+ * Drivers initialize a pwm_channel structure using pwm_channel_alloc().
-+ * Then they configure its clock rate (derived from MCK), alignment,
-+ * polarity, and duty cycle by writing directly to the channel registers,
-+ * before enabling the channel by calling pwm_channel_enable().
-+ *
-+ * After emitting a PWM signal for the desired length of time, drivers
-+ * may then pwm_channel_disable() or pwm_channel_free().  Both of these
-+ * disable the channel, but when it's freed the IRQ is deconfigured and
-+ * the channel must later be re-allocated and reconfigured.
-+ *
-+ * Note that if the period or duty cycle need to be changed while the
-+ * PWM channel is operating, drivers must use the PWM_CUPD double buffer
-+ * mechanism, either polling until they change or getting implicitly
-+ * notified through a once-per-period interrupt handler.
-+ */
-+struct pwm_channel {
-+      void __iomem    *regs;
-+      unsigned        index;
-+      unsigned long   mck;
-+};
-+
-+extern int pwm_channel_alloc(int index, struct pwm_channel *ch);
-+extern int pwm_channel_free(struct pwm_channel *ch);
-+
-+extern int pwm_clk_alloc(unsigned prescale, unsigned div);
-+extern void pwm_clk_free(unsigned clk);
-+
-+extern int __pwm_channel_onoff(struct pwm_channel *ch, int enabled);
-+
-+#define pwm_channel_enable(ch)        __pwm_channel_onoff((ch), 1)
-+#define pwm_channel_disable(ch)       __pwm_channel_onoff((ch), 0)
-+
-+/* periodic interrupts, mostly for CUPD changes to period or cycle */
-+extern int pwm_channel_handler(struct pwm_channel *ch,
-+              void (*handler)(struct pwm_channel *ch));
-+
-+/* per-channel registers (banked at pwm_channel->regs) */
-+#define PWM_CMR               0x00            /* mode register */
-+#define               PWM_CPR_CPD     (1 << 10)       /* set: CUPD modifies period */
-+#define               PWM_CPR_CPOL    (1 << 9)        /* set: idle high */
-+#define               PWM_CPR_CALG    (1 << 8)        /* set: center align */
-+#define               PWM_CPR_CPRE    (0xf << 0)      /* mask: rate is mck/(2^pre) */
-+#define               PWM_CPR_CLKA    (0xb << 0)      /* rate CLKA */
-+#define               PWM_CPR_CLKB    (0xc << 0)      /* rate CLKB */
-+#define PWM_CDTY      0x04            /* duty cycle (max of CPRD) */
-+#define PWM_CPRD      0x08            /* period (count up from zero) */
-+#define PWM_CCNT      0x0c            /* counter (20 bits?) */
-+#define PWM_CUPD      0x10            /* update CPRD (or CDTY) next period */
-+
-+static inline void
-+pwm_channel_writel(struct pwm_channel *pwmc, unsigned offset, u32 val)
-+{
-+      __raw_writel(val, pwmc->regs + offset);
-+}
-+
-+static inline u32 pwm_channel_readl(struct pwm_channel *pwmc, unsigned offset)
-+{
-+      return __raw_readl(pwmc->regs + offset);
-+}
+diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/xor.h avr32-2.6/include/asm-avr32/xor.h
+--- linux-2.6.25.6/include/asm-avr32/xor.h     1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/include/asm-avr32/xor.h  2008-06-12 15:04:04.707817453 +0200
+@@ -0,0 +1,6 @@
++#ifndef _ASM_XOR_H
++#define _ASM_XOR_H
 +
-+#endif /* __LINUX_ATMEL_PWM_H */
---- /dev/null
-+++ b/include/linux/atmel_serial.h
-@@ -0,0 +1,127 @@
-+/*
-+ * include/linux/atmel_serial.h
-+ *
-+ * Copyright (C) 2005 Ivan Kokshaysky
-+ * Copyright (C) SAN People
-+ *
-+ * USART registers.
-+ * Based on AT91RM9200 datasheet revision E.
-+ *
-+ * 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.
-+ */
-+
-+#ifndef ATMEL_SERIAL_H
-+#define ATMEL_SERIAL_H
-+
-+#define ATMEL_US_CR           0x00                    /* Control Register */
-+#define               ATMEL_US_RSTRX          (1 <<  2)               /* Reset Receiver */
-+#define               ATMEL_US_RSTTX          (1 <<  3)               /* Reset Transmitter */
-+#define               ATMEL_US_RXEN           (1 <<  4)               /* Receiver Enable */
-+#define               ATMEL_US_RXDIS          (1 <<  5)               /* Receiver Disable */
-+#define               ATMEL_US_TXEN           (1 <<  6)               /* Transmitter Enable */
-+#define               ATMEL_US_TXDIS          (1 <<  7)               /* Transmitter Disable */
-+#define               ATMEL_US_RSTSTA         (1 <<  8)               /* Reset Status Bits */
-+#define               ATMEL_US_STTBRK         (1 <<  9)               /* Start Break */
-+#define               ATMEL_US_STPBRK         (1 << 10)               /* Stop Break */
-+#define               ATMEL_US_STTTO          (1 << 11)               /* Start Time-out */
-+#define               ATMEL_US_SENDA          (1 << 12)               /* Send Address */
-+#define               ATMEL_US_RSTIT          (1 << 13)               /* Reset Iterations */
-+#define               ATMEL_US_RSTNACK        (1 << 14)               /* Reset Non Acknowledge */
-+#define               ATMEL_US_RETTO          (1 << 15)               /* Rearm Time-out */
-+#define               ATMEL_US_DTREN          (1 << 16)               /* Data Terminal Ready Enable [AT91RM9200 only] */
-+#define               ATMEL_US_DTRDIS         (1 << 17)               /* Data Terminal Ready Disable [AT91RM9200 only] */
-+#define               ATMEL_US_RTSEN          (1 << 18)               /* Request To Send Enable */
-+#define               ATMEL_US_RTSDIS         (1 << 19)               /* Request To Send Disable */
-+
-+#define ATMEL_US_MR           0x04                    /* Mode Register */
-+#define               ATMEL_US_USMODE         (0xf <<  0)             /* Mode of the USART */
-+#define                       ATMEL_US_USMODE_NORMAL          0
-+#define                       ATMEL_US_USMODE_RS485           1
-+#define                       ATMEL_US_USMODE_HWHS            2
-+#define                       ATMEL_US_USMODE_MODEM           3
-+#define                       ATMEL_US_USMODE_ISO7816_T0      4
-+#define                       ATMEL_US_USMODE_ISO7816_T1      6
-+#define                       ATMEL_US_USMODE_IRDA            8
-+#define               ATMEL_US_USCLKS         (3   <<  4)             /* Clock Selection */
-+#define                       ATMEL_US_USCLKS_MCK             (0 <<  4)
-+#define                       ATMEL_US_USCLKS_MCK_DIV8        (1 <<  4)
-+#define                       ATMEL_US_USCLKS_SCK             (3 <<  4)
-+#define               ATMEL_US_CHRL           (3   <<  6)             /* Character Length */
-+#define                       ATMEL_US_CHRL_5                 (0 <<  6)
-+#define                       ATMEL_US_CHRL_6                 (1 <<  6)
-+#define                       ATMEL_US_CHRL_7                 (2 <<  6)
-+#define                       ATMEL_US_CHRL_8                 (3 <<  6)
-+#define               ATMEL_US_SYNC           (1 <<  8)               /* Synchronous Mode Select */
-+#define               ATMEL_US_PAR            (7 <<  9)               /* Parity Type */
-+#define                       ATMEL_US_PAR_EVEN               (0 <<  9)
-+#define                       ATMEL_US_PAR_ODD                (1 <<  9)
-+#define                       ATMEL_US_PAR_SPACE              (2 <<  9)
-+#define                       ATMEL_US_PAR_MARK               (3 <<  9)
-+#define                       ATMEL_US_PAR_NONE               (4 <<  9)
-+#define                       ATMEL_US_PAR_MULTI_DROP         (6 <<  9)
-+#define               ATMEL_US_NBSTOP         (3 << 12)               /* Number of Stop Bits */
-+#define                       ATMEL_US_NBSTOP_1               (0 << 12)
-+#define                       ATMEL_US_NBSTOP_1_5             (1 << 12)
-+#define                       ATMEL_US_NBSTOP_2               (2 << 12)
-+#define               ATMEL_US_CHMODE         (3 << 14)               /* Channel Mode */
-+#define                       ATMEL_US_CHMODE_NORMAL          (0 << 14)
-+#define                       ATMEL_US_CHMODE_ECHO            (1 << 14)
-+#define                       ATMEL_US_CHMODE_LOC_LOOP        (2 << 14)
-+#define                       ATMEL_US_CHMODE_REM_LOOP        (3 << 14)
-+#define               ATMEL_US_MSBF           (1 << 16)               /* Bit Order */
-+#define               ATMEL_US_MODE9          (1 << 17)               /* 9-bit Character Length */
-+#define               ATMEL_US_CLKO           (1 << 18)               /* Clock Output Select */
-+#define               ATMEL_US_OVER           (1 << 19)               /* Oversampling Mode */
-+#define               ATMEL_US_INACK          (1 << 20)               /* Inhibit Non Acknowledge */
-+#define               ATMEL_US_DSNACK         (1 << 21)               /* Disable Successive NACK */
-+#define               ATMEL_US_MAX_ITER       (7 << 24)               /* Max Iterations */
-+#define               ATMEL_US_FILTER         (1 << 28)               /* Infrared Receive Line Filter */
-+
-+#define ATMEL_US_IER          0x08                    /* Interrupt Enable Register */
-+#define               ATMEL_US_RXRDY          (1 <<  0)               /* Receiver Ready */
-+#define               ATMEL_US_TXRDY          (1 <<  1)               /* Transmitter Ready */
-+#define               ATMEL_US_RXBRK          (1 <<  2)               /* Break Received / End of Break */
-+#define               ATMEL_US_ENDRX          (1 <<  3)               /* End of Receiver Transfer */
-+#define               ATMEL_US_ENDTX          (1 <<  4)               /* End of Transmitter Transfer */
-+#define               ATMEL_US_OVRE           (1 <<  5)               /* Overrun Error */
-+#define               ATMEL_US_FRAME          (1 <<  6)               /* Framing Error */
-+#define               ATMEL_US_PARE           (1 <<  7)               /* Parity Error */
-+#define               ATMEL_US_TIMEOUT        (1 <<  8)               /* Receiver Time-out */
-+#define               ATMEL_US_TXEMPTY        (1 <<  9)               /* Transmitter Empty */
-+#define               ATMEL_US_ITERATION      (1 << 10)               /* Max number of Repetitions Reached */
-+#define               ATMEL_US_TXBUFE         (1 << 11)               /* Transmission Buffer Empty */
-+#define               ATMEL_US_RXBUFF         (1 << 12)               /* Reception Buffer Full */
-+#define               ATMEL_US_NACK           (1 << 13)               /* Non Acknowledge */
-+#define               ATMEL_US_RIIC           (1 << 16)               /* Ring Indicator Input Change [AT91RM9200 only] */
-+#define               ATMEL_US_DSRIC          (1 << 17)               /* Data Set Ready Input Change [AT91RM9200 only] */
-+#define               ATMEL_US_DCDIC          (1 << 18)               /* Data Carrier Detect Input Change [AT91RM9200 only] */
-+#define               ATMEL_US_CTSIC          (1 << 19)               /* Clear to Send Input Change */
-+#define               ATMEL_US_RI             (1 << 20)               /* RI */
-+#define               ATMEL_US_DSR            (1 << 21)               /* DSR */
-+#define               ATMEL_US_DCD            (1 << 22)               /* DCD */
-+#define               ATMEL_US_CTS            (1 << 23)               /* CTS */
-+
-+#define ATMEL_US_IDR          0x0c                    /* Interrupt Disable Register */
-+#define ATMEL_US_IMR          0x10                    /* Interrupt Mask Register */
-+#define ATMEL_US_CSR          0x14                    /* Channel Status Register */
-+#define ATMEL_US_RHR          0x18                    /* Receiver Holding Register */
-+#define ATMEL_US_THR          0x1c                    /* Transmitter Holding Register */
-+#define               ATMEL_US_SYNH           (1 << 15)               /* Transmit/Receive Sync [AT91SAM9261 only] */
-+
-+#define ATMEL_US_BRGR         0x20                    /* Baud Rate Generator Register */
-+#define               ATMEL_US_CD             (0xffff << 0)           /* Clock Divider */
-+
-+#define ATMEL_US_RTOR         0x24                    /* Receiver Time-out Register */
-+#define               ATMEL_US_TO             (0xffff << 0)           /* Time-out Value */
-+
-+#define ATMEL_US_TTGR         0x28                    /* Transmitter Timeguard Register */
-+#define               ATMEL_US_TG             (0xff << 0)             /* Timeguard Value */
-+
-+#define ATMEL_US_FIDI         0x40                    /* FI DI Ratio Register */
-+#define ATMEL_US_NER          0x44                    /* Number of Errors Register */
-+#define ATMEL_US_IF           0x4c                    /* IrDA Filter Register */
++#include <asm-generic/xor.h>
 +
 +#endif
---- /dev/null
-+++ b/include/linux/atmel_tc.h
+diff --exclude=.git -urN linux-2.6.25.6/include/linux/atmel_tc.h avr32-2.6/include/linux/atmel_tc.h
+--- linux-2.6.25.6/include/linux/atmel_tc.h    1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/include/linux/atmel_tc.h 2008-06-12 15:04:07.586819080 +0200
 @@ -0,0 +1,252 @@
 +/*
 + * Timer/Counter Unit (TC) registers.
 +#define     ATMEL_TC_ETRGS    (1 <<  7)       /* external trigger */
 +
 +#endif
---- /dev/null
-+++ b/include/linux/usb/atmel_usba_udc.h
+diff --exclude=.git -urN linux-2.6.25.6/include/linux/fs.h avr32-2.6/include/linux/fs.h
+--- linux-2.6.25.6/include/linux/fs.h  2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/include/linux/fs.h       2008-06-12 15:09:46.255815187 +0200
+@@ -1691,6 +1691,8 @@
+ extern int invalidate_inode_pages2(struct address_space *mapping);
+ extern int invalidate_inode_pages2_range(struct address_space *mapping,
+                                        pgoff_t start, pgoff_t end);
++extern void generic_sync_sb_inodes(struct super_block *sb,
++                              struct writeback_control *wbc);
+ extern int write_inode_now(struct inode *, int);
+ extern int filemap_fdatawrite(struct address_space *);
+ extern int filemap_flush(struct address_space *);
+diff --exclude=.git -urN linux-2.6.25.6/include/linux/usb/atmel_usba_udc.h avr32-2.6/include/linux/usb/atmel_usba_udc.h
+--- linux-2.6.25.6/include/linux/usb/atmel_usba_udc.h  1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/include/linux/usb/atmel_usba_udc.h       2008-06-12 15:04:07.986816119 +0200
 @@ -0,0 +1,22 @@
 +/*
 + * Platform data definitions for Atmel USBA gadget driver.
 +};
 +
 +#endif /* __LINUX_USB_USBA_H */
---- a/include/video/atmel_lcdc.h
-+++ b/include/video/atmel_lcdc.h
-@@ -22,7 +22,7 @@
- #ifndef __ATMEL_LCDC_H__
- #define __ATMEL_LCDC_H__
-- /* LCD Controller info data structure */
-+ /* LCD Controller info data structure, stored in device platform_data */
- struct atmel_lcdfb_info {
-       spinlock_t              lock;
-       struct fb_info          *info;
-@@ -33,7 +33,14 @@
-       struct platform_device  *pdev;
-       struct clk              *bus_clk;
-       struct clk              *lcdc_clk;
--      unsigned int            default_bpp;
-+
-+#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
-+      struct backlight_device *backlight;
-+      u8                      bl_power;
-+#endif
-+      bool                    lcdcon_is_backlight;
-+
-+      u8                      default_bpp;
-       unsigned int            default_lcdcon2;
-       unsigned int            default_dmacon;
-       void (*atmel_lcdfb_power_control)(int on);
-@@ -115,20 +122,20 @@
- #define               ATMEL_LCDC_MEMOR_LITTLE         (1 << 31)
- #define ATMEL_LCDC_TIM1               0x0808
--#define       ATMEL_LCDC_VFP          (0xff <<  0)
-+#define       ATMEL_LCDC_VFP          (0xffU <<  0)
- #define       ATMEL_LCDC_VBP_OFFSET           8
--#define       ATMEL_LCDC_VBP          (0xff <<  ATMEL_LCDC_VBP_OFFSET)
-+#define       ATMEL_LCDC_VBP          (0xffU <<  ATMEL_LCDC_VBP_OFFSET)
- #define       ATMEL_LCDC_VPW_OFFSET           16
--#define       ATMEL_LCDC_VPW          (0x3f << ATMEL_LCDC_VPW_OFFSET)
-+#define       ATMEL_LCDC_VPW          (0x3fU << ATMEL_LCDC_VPW_OFFSET)
- #define       ATMEL_LCDC_VHDLY_OFFSET         24
--#define       ATMEL_LCDC_VHDLY        (0xf  << ATMEL_LCDC_VHDLY_OFFSET)
-+#define       ATMEL_LCDC_VHDLY        (0xfU  << ATMEL_LCDC_VHDLY_OFFSET)
- #define ATMEL_LCDC_TIM2               0x080c
--#define       ATMEL_LCDC_HBP          (0xff  <<  0)
-+#define       ATMEL_LCDC_HBP          (0xffU  <<  0)
- #define       ATMEL_LCDC_HPW_OFFSET           8
--#define       ATMEL_LCDC_HPW          (0x3f  <<  ATMEL_LCDC_HPW_OFFSET)
-+#define       ATMEL_LCDC_HPW          (0x3fU  <<  ATMEL_LCDC_HPW_OFFSET)
- #define       ATMEL_LCDC_HFP_OFFSET           21
--#define       ATMEL_LCDC_HFP          (0x7ff << ATMEL_LCDC_HFP_OFFSET)
-+#define       ATMEL_LCDC_HFP          (0x7ffU << ATMEL_LCDC_HFP_OFFSET)
- #define ATMEL_LCDC_LCDFRMCFG  0x0810
- #define       ATMEL_LCDC_LINEVAL      (0x7ff <<  0)
---- a/init/do_mounts.c
-+++ b/init/do_mounts.c
-@@ -219,8 +219,14 @@
+diff --exclude=.git -urN linux-2.6.25.6/include/mtd/Kbuild avr32-2.6/include/mtd/Kbuild
+--- linux-2.6.25.6/include/mtd/Kbuild  2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/include/mtd/Kbuild       2008-06-12 15:04:08.018816005 +0200
+@@ -3,5 +3,4 @@
+ header-y += mtd-abi.h
+ header-y += mtd-user.h
+ header-y += nftl-user.h
+-header-y += ubi-header.h
+ header-y += ubi-user.h
+diff --exclude=.git -urN linux-2.6.25.6/include/mtd/ubi-header.h avr32-2.6/include/mtd/ubi-header.h
+--- linux-2.6.25.6/include/mtd/ubi-header.h    2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/include/mtd/ubi-header.h 1970-01-01 01:00:00.000000000 +0100
+@@ -1,372 +0,0 @@
+-/*
+- * Copyright (c) International Business Machines Corp., 2006
+- *
+- * 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
+- *
+- * Authors: Artem Bityutskiy (Битюцкий Артём)
+- *          Thomas Gleixner
+- *          Frank Haverkamp
+- *          Oliver Lohmann
+- *          Andreas Arnez
+- */
+-
+-/*
+- * This file defines the layout of UBI headers and all the other UBI on-flash
+- * data structures. May be included by user-space.
+- */
+-
+-#ifndef __UBI_HEADER_H__
+-#define __UBI_HEADER_H__
+-
+-#include <asm/byteorder.h>
+-
+-/* The version of UBI images supported by this implementation */
+-#define UBI_VERSION 1
+-
+-/* The highest erase counter value supported by this implementation */
+-#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF
+-
+-/* The initial CRC32 value used when calculating CRC checksums */
+-#define UBI_CRC32_INIT 0xFFFFFFFFU
+-
+-/* Erase counter header magic number (ASCII "UBI#") */
+-#define UBI_EC_HDR_MAGIC  0x55424923
+-/* Volume identifier header magic number (ASCII "UBI!") */
+-#define UBI_VID_HDR_MAGIC 0x55424921
+-
+-/*
+- * Volume type constants used in the volume identifier header.
+- *
+- * @UBI_VID_DYNAMIC: dynamic volume
+- * @UBI_VID_STATIC: static volume
+- */
+-enum {
+-      UBI_VID_DYNAMIC = 1,
+-      UBI_VID_STATIC  = 2
+-};
+-
+-/*
+- * 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
+- * to the flash
+- * @UBI_COMPAT_RO: attach this device in read-only mode
+- * @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its
+- * physical eraseblocks, don't allow the wear-leveling unit to move them
+- * @UBI_COMPAT_REJECT: reject this UBI image
+- */
+-enum {
+-      UBI_COMPAT_DELETE   = 1,
+-      UBI_COMPAT_RO       = 2,
+-      UBI_COMPAT_PRESERVE = 4,
+-      UBI_COMPAT_REJECT   = 5
+-};
+-
+-/* Sizes of UBI headers */
+-#define UBI_EC_HDR_SIZE  sizeof(struct ubi_ec_hdr)
+-#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr)
+-
+-/* Sizes of UBI headers without the ending CRC */
+-#define UBI_EC_HDR_SIZE_CRC  (UBI_EC_HDR_SIZE  - sizeof(__be32))
+-#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(__be32))
+-
+-/**
+- * struct ubi_ec_hdr - UBI erase counter header.
+- * @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC)
+- * @version: version of UBI implementation which is supposed to accept this
+- * UBI image
+- * @padding1: reserved for future, zeroes
+- * @ec: the erase counter
+- * @vid_hdr_offset: where the VID header starts
+- * @data_offset: where the user data start
+- * @padding2: reserved for future, zeroes
+- * @hdr_crc: erase counter header CRC checksum
+- *
+- * The erase counter header takes 64 bytes and has a plenty of unused space for
+- * future usage. The unused fields are zeroed. The @version field is used to
+- * indicate the version of UBI implementation which is supposed to be able to
+- * work with this UBI image. If @version is greater then the current UBI
+- * version, the image is rejected. This may be useful in future if something
+- * is changed radically. This field is duplicated in the volume identifier
+- * header.
+- *
+- * The @vid_hdr_offset and @data_offset fields contain the offset of the the
+- * volume identifier header and user data, relative to the beginning of the
+- * physical eraseblock. These values have to be the same for all physical
+- * eraseblocks.
+- */
+-struct ubi_ec_hdr {
+-      __be32  magic;
+-      __u8    version;
+-      __u8    padding1[3];
+-      __be64  ec; /* Warning: the current limit is 31-bit anyway! */
+-      __be32  vid_hdr_offset;
+-      __be32  data_offset;
+-      __u8    padding2[36];
+-      __be32  hdr_crc;
+-} __attribute__ ((packed));
+-
+-/**
+- * struct ubi_vid_hdr - on-flash UBI volume identifier header.
+- * @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC)
+- * @version: UBI implementation version which is supposed to accept this UBI
+- * image (%UBI_VERSION)
+- * @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC)
+- * @copy_flag: if this logical eraseblock was copied from another physical
+- * eraseblock (for wear-leveling reasons)
+- * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE,
+- * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
+- * @vol_id: ID of this volume
+- * @lnum: logical eraseblock number
+- * @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be
+- * removed, kept only for not breaking older UBI users)
+- * @data_size: how many bytes of data this logical eraseblock contains
+- * @used_ebs: total number of used logical eraseblocks in this volume
+- * @data_pad: how many bytes at the end of this physical eraseblock are not
+- * used
+- * @data_crc: CRC checksum of the data stored in this logical eraseblock
+- * @padding1: reserved for future, zeroes
+- * @sqnum: sequence number
+- * @padding2: reserved for future, zeroes
+- * @hdr_crc: volume identifier header CRC checksum
+- *
+- * The @sqnum is the value of the global sequence counter at the time when this
+- * VID header was created. The global sequence counter is incremented each time
+- * UBI writes a new VID header to the flash, i.e. when it maps a logical
+- * eraseblock to a new physical eraseblock. The global sequence counter is an
+- * unsigned 64-bit integer and we assume it never overflows. The @sqnum
+- * (sequence number) is used to distinguish between older and newer versions of
+- * logical eraseblocks.
+- *
+- * There are 2 situations when there may be more then one physical eraseblock
+- * corresponding to the same logical eraseblock, i.e., having the same @vol_id
+- * and @lnum values in the volume identifier header. Suppose we have a logical
+- * eraseblock L and it is mapped to the physical eraseblock P.
+- *
+- * 1. Because UBI may erase physical eraseblocks asynchronously, the following
+- * situation is possible: L is asynchronously erased, so P is scheduled for
+- * erasure, then L is written to,i.e. mapped to another physical eraseblock P1,
+- * so P1 is written to, then an unclean reboot happens. Result - there are 2
+- * physical eraseblocks P and P1 corresponding to the same logical eraseblock
+- * L. But P1 has greater sequence number, so UBI picks P1 when it attaches the
+- * flash.
+- *
+- * 2. From time to time UBI moves logical eraseblocks to other physical
+- * eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P
+- * to P1, and an unclean reboot happens before P is physically erased, there
+- * are two physical eraseblocks P and P1 corresponding to L and UBI has to
+- * select one of them when the flash is attached. The @sqnum field says which
+- * PEB is the original (obviously P will have lower @sqnum) and the copy. But
+- * it is not enough to select the physical eraseblock with the higher sequence
+- * number, because the unclean reboot could have happen in the middle of the
+- * copying process, so the data in P is corrupted. It is also not enough to
+- * just select the physical eraseblock with lower sequence number, because the
+- * data there may be old (consider a case if more data was added to P1 after
+- * the copying). Moreover, the unclean reboot may happen when the erasure of P
+- * was just started, so it result in unstable P, which is "mostly" OK, but
+- * still has unstable bits.
+- *
+- * UBI uses the @copy_flag field to indicate that this logical eraseblock is a
+- * copy. UBI also calculates data CRC when the data is moved and stores it at
+- * the @data_crc field of the copy (P1). So when UBI needs to pick one physical
+- * eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is
+- * examined. If it is cleared, the situation* is simple and the newer one is
+- * picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC
+- * checksum is correct, this physical eraseblock is selected (P1). Otherwise
+- * the older one (P) is selected.
+- *
+- * Note, there is an obsolete @leb_ver field which was used instead of @sqnum
+- * in the past. But it is not used anymore and we keep it in order to be able
+- * to deal with old UBI images. It will be removed at some point.
+- *
+- * There are 2 sorts of volumes in UBI: user volumes and internal volumes.
+- * Internal volumes are not seen from outside and are used for various internal
+- * UBI purposes. In this implementation there is only one internal volume - the
+- * layout volume. Internal volumes are the main mechanism of UBI extensions.
+- * For example, in future one may introduce a journal internal volume. Internal
+- * volumes have their own reserved range of IDs.
+- *
+- * The @compat field is only used for internal volumes and contains the "degree
+- * of their compatibility". It is always zero for user volumes. This field
+- * provides a mechanism to introduce UBI extensions and to be still compatible
+- * with older UBI binaries. For example, if someone introduced a journal in
+- * future, he would probably use %UBI_COMPAT_DELETE compatibility for the
+- * journal volume.  And in this case, older UBI binaries, which know nothing
+- * about the journal volume, would just delete this volume and work perfectly
+- * fine. This is similar to what Ext2fs does when it is fed by an Ext3fs image
+- * - it just ignores the Ext3fs journal.
+- *
+- * The @data_crc field contains the CRC checksum of the contents of the logical
+- * eraseblock if this is a static volume. In case of dynamic volumes, it does
+- * not contain the CRC checksum as a rule. The only exception is when the
+- * data of the physical eraseblock was moved by the wear-leveling unit, then
+- * the wear-leveling unit calculates the data CRC and stores it in the
+- * @data_crc field. And of course, the @copy_flag is %in this case.
+- *
+- * The @data_size field is used only for static volumes because UBI has to know
+- * how many bytes of data are stored in this eraseblock. For dynamic volumes,
+- * this field usually contains zero. The only exception is when the data of the
+- * physical eraseblock was moved to another physical eraseblock for
+- * wear-leveling reasons. In this case, UBI calculates CRC checksum of the
+- * contents and uses both @data_crc and @data_size fields. In this case, the
+- * @data_size field contains data size.
+- *
+- * The @used_ebs field is used only for static volumes and indicates how many
+- * eraseblocks the data of the volume takes. For dynamic volumes this field is
+- * not used and always contains zero.
+- *
+- * The @data_pad is calculated when volumes are created using the alignment
+- * parameter. So, effectively, the @data_pad field reduces the size of logical
+- * eraseblocks of this volume. This is very handy when one uses block-oriented
+- * software (say, cramfs) on top of the UBI volume.
+- */
+-struct ubi_vid_hdr {
+-      __be32  magic;
+-      __u8    version;
+-      __u8    vol_type;
+-      __u8    copy_flag;
+-      __u8    compat;
+-      __be32  vol_id;
+-      __be32  lnum;
+-      __be32  leb_ver; /* obsolete, to be removed, don't use */
+-      __be32  data_size;
+-      __be32  used_ebs;
+-      __be32  data_pad;
+-      __be32  data_crc;
+-      __u8    padding1[4];
+-      __be64  sqnum;
+-      __u8    padding2[12];
+-      __be32  hdr_crc;
+-} __attribute__ ((packed));
+-
+-/* Internal UBI volumes count */
+-#define UBI_INT_VOL_COUNT 1
+-
+-/*
+- * Starting ID of internal volumes. There is reserved room for 4096 internal
+- * volumes.
+- */
+-#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096)
+-
+-/* The layout volume contains the volume table */
+-
+-#define UBI_LAYOUT_VOLUME_ID     UBI_INTERNAL_VOL_START
+-#define UBI_LAYOUT_VOLUME_TYPE   UBI_VID_DYNAMIC
+-#define UBI_LAYOUT_VOLUME_ALIGN  1
+-#define UBI_LAYOUT_VOLUME_EBS    2
+-#define UBI_LAYOUT_VOLUME_NAME   "layout volume"
+-#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT
+-
+-/* The maximum number of volumes per one UBI device */
+-#define UBI_MAX_VOLUMES 128
+-
+-/* The maximum volume name length */
+-#define UBI_VOL_NAME_MAX 127
+-
+-/* Size of the volume table record */
+-#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
+-
+-/* Size of the volume table record without the ending CRC */
+-#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(__be32))
+-
+-/**
+- * struct ubi_vtbl_record - a record in the volume table.
+- * @reserved_pebs: how many physical eraseblocks are reserved for this volume
+- * @alignment: volume alignment
+- * @data_pad: how many bytes are unused at the end of the each physical
+- * eraseblock to satisfy the requested alignment
+- * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+- * @upd_marker: if volume update was started but not finished
+- * @name_len: volume name length
+- * @name: the volume name
+- * @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
+- * the layout volume. The layout volume consists of 2 logical eraseblock, each
+- * of which contains a copy of the volume table (i.e., the volume table is
+- * duplicated). The volume table is an array of &struct ubi_vtbl_record
+- * objects indexed by the volume ID.
+- *
+- * If the size of the logical eraseblock is large enough to fit
+- * %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES
+- * records. Otherwise, it contains as many records as it can fit (i.e., size of
+- * logical eraseblock divided by sizeof(struct ubi_vtbl_record)).
+- *
+- * The @upd_marker flag is used to implement volume update. It is set to %1
+- * before update and set to %0 after the update. So if the update operation was
+- * interrupted, UBI knows that the volume is corrupted.
+- *
+- * The @alignment field is specified when the volume is created and cannot be
+- * later changed. It may be useful, for example, when a block-oriented file
+- * system works on top of UBI. The @data_pad field is calculated using the
+- * logical eraseblock size and @alignment. The alignment must be multiple to the
+- * minimal flash I/O unit. If @alignment is 1, all the available space of
+- * the physical eraseblocks is used.
+- *
+- * Empty records contain all zeroes and the CRC checksum of those zeroes.
+- */
+-struct ubi_vtbl_record {
+-      __be32  reserved_pebs;
+-      __be32  alignment;
+-      __be32  data_pad;
+-      __u8    vol_type;
+-      __u8    upd_marker;
+-      __be16  name_len;
+-      __u8    name[UBI_VOL_NAME_MAX+1];
+-      __u8    flags;
+-      __u8    padding[23];
+-      __be32  crc;
+-} __attribute__ ((packed));
+-
+-#endif /* !__UBI_HEADER_H__ */
+diff --exclude=.git -urN linux-2.6.25.6/init/do_mounts.c avr32-2.6/init/do_mounts.c
+--- linux-2.6.25.6/init/do_mounts.c    2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/init/do_mounts.c 2008-06-12 15:09:46.451815572 +0200
+@@ -126,8 +126,14 @@
  
  static int __init rootwait_setup(char *str)
  {
        root_wait = 1;
        return 1;
  }
---- a/kernel/ptrace.c
-+++ b/kernel/ptrace.c
-@@ -470,6 +470,8 @@
-       lock_kernel();
-       if (request == PTRACE_TRACEME) {
-               ret = ptrace_traceme();
-+              if (!ret)
-+                      arch_ptrace_attach(current);
-               goto out;
-       }
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -671,6 +671,12 @@
- W:    http://www.at91.com/
- S:    Maintained
-+ATMEL AT91 / AT32 SERIAL DRIVER
-+P:    Haavard Skinnemoen
-+M:    hskinnemoen@atmel.com
-+L:    linux-kernel@vger.kernel.org
-+S:    Supported
-+
- ATMEL LCDFB DRIVER
- P:    Nicolas Ferre
- M:    nicolas.ferre@atmel.com
---- /dev/null
-+++ b/sound/avr32/ac97c.c
+@@ -347,7 +353,8 @@
+       if (saved_root_name[0]) {
+               root_device_name = saved_root_name;
+-              if (!strncmp(root_device_name, "mtd", 3)) {
++              if (!strncmp(root_device_name, "mtd", 3) ||
++                  !strncmp(root_device_name, "ubi", 3)) {
+                       mount_block_root(root_device_name, root_mountflags);
+                       goto out;
+               }
+diff --exclude=.git -urN linux-2.6.25.6/sound/avr32/ac97c.c avr32-2.6/sound/avr32/ac97c.c
+--- linux-2.6.25.6/sound/avr32/ac97c.c 1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/sound/avr32/ac97c.c      2008-06-12 15:09:47.011815952 +0200
 @@ -0,0 +1,914 @@
 +/*
 + * Driver for the Atmel AC97 controller
 +                      ac97c_writel(chip, COTHR, word);
 +                      goto read_reg;
 +              }
-+              mdelay(10);
++              udelay(10);
 +      } while (--timeout);
 +
 +      if (!--write)
 +                      unsigned short val = ac97c_readl(chip, CORHR);
 +                      return val;
 +              }
-+              mdelay(10);
++              udelay(10);
 +      } while (--timeout);
 +
 +      if (!--write)
 +MODULE_LICENSE("GPL");
 +MODULE_DESCRIPTION("Driver for Atmel AC97 Controller");
 +MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
---- /dev/null
-+++ b/sound/avr32/ac97c.h
+diff --exclude=.git -urN linux-2.6.25.6/sound/avr32/ac97c.h avr32-2.6/sound/avr32/ac97c.h
+--- linux-2.6.25.6/sound/avr32/ac97c.h 1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/sound/avr32/ac97c.h      2008-06-12 15:09:47.011815952 +0200
 @@ -0,0 +1,71 @@
 +/*
 + * Register definitions for the Atmel AC97 Controller.
 +#define AC97C_CHANNEL_B               0x2
 +
 +#endif /* __SOUND_AVR32_AC97C_H */
---- /dev/null
-+++ b/sound/avr32/Kconfig
+diff --exclude=.git -urN linux-2.6.25.6/sound/avr32/Kconfig avr32-2.6/sound/avr32/Kconfig
+--- linux-2.6.25.6/sound/avr32/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/sound/avr32/Kconfig      2008-06-12 15:09:47.011815952 +0200
 @@ -0,0 +1,11 @@
 +menu "AVR32 devices"
 +      depends on SND != n && AVR32
 +        ALSA sound driver for the Atmel AC97 controller.
 +
 +endmenu
---- /dev/null
-+++ b/sound/avr32/Makefile
+diff --exclude=.git -urN linux-2.6.25.6/sound/avr32/Makefile avr32-2.6/sound/avr32/Makefile
+--- linux-2.6.25.6/sound/avr32/Makefile        1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/sound/avr32/Makefile     2008-06-12 15:09:47.011815952 +0200
 @@ -0,0 +1,3 @@
 +snd-atmel-ac97-objs           := ac97c.o
 +
 +obj-$(CONFIG_SND_ATMEL_AC97)  += snd-atmel-ac97.o
---- a/sound/Kconfig
-+++ b/sound/Kconfig
+diff --exclude=.git -urN linux-2.6.25.6/sound/Kconfig avr32-2.6/sound/Kconfig
+--- linux-2.6.25.6/sound/Kconfig       2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/sound/Kconfig    2008-06-12 15:09:47.011815952 +0200
 @@ -63,6 +63,8 @@
  
  source "sound/arm/Kconfig"
  if SPI
  source "sound/spi/Kconfig"
  endif
---- a/sound/Makefile
-+++ b/sound/Makefile
+diff --exclude=.git -urN linux-2.6.25.6/sound/Makefile avr32-2.6/sound/Makefile
+--- linux-2.6.25.6/sound/Makefile      2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/sound/Makefile   2008-06-12 15:09:47.011815952 +0200
 @@ -6,7 +6,7 @@
  obj-$(CONFIG_SOUND_PRIME) += oss/
  obj-$(CONFIG_DMASOUND) += oss/
  obj-$(CONFIG_SND_AOA) += aoa/
  
  # This one must be compilable even if sound is configured out
---- /dev/null
-+++ b/sound/oss/at32_abdac.c
+diff --exclude=.git -urN linux-2.6.25.6/sound/oss/at32_abdac.c avr32-2.6/sound/oss/at32_abdac.c
+--- linux-2.6.25.6/sound/oss/at32_abdac.c      1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/sound/oss/at32_abdac.c   2008-06-12 15:09:47.027815755 +0200
 @@ -0,0 +1,722 @@
 +/*
 + * OSS Sound Driver for the Atmel AT32 on-chip DAC.
 +MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
 +MODULE_DESCRIPTION("Sound Driver for the Atmel AT32 ABDAC");
 +MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/sound/oss/at32_abdac.h
+diff --exclude=.git -urN linux-2.6.25.6/sound/oss/at32_abdac.h avr32-2.6/sound/oss/at32_abdac.h
+--- linux-2.6.25.6/sound/oss/at32_abdac.h      1970-01-01 01:00:00.000000000 +0100
++++ avr32-2.6/sound/oss/at32_abdac.h   2008-06-12 15:09:47.027815755 +0200
 @@ -0,0 +1,59 @@
 +/*
 + * Register definitions for the Atmel AT32 on-chip DAC.
 +      __raw_writel((value), (port)->regs + DAC_##reg)
 +
 +#endif /* __SOUND_OSS_AT32_ABDAC_H__ */
---- a/sound/oss/Kconfig
-+++ b/sound/oss/Kconfig
+diff --exclude=.git -urN linux-2.6.25.6/sound/oss/Kconfig avr32-2.6/sound/oss/Kconfig
+--- linux-2.6.25.6/sound/oss/Kconfig   2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/sound/oss/Kconfig        2008-06-12 15:09:47.023815804 +0200
 @@ -654,3 +654,7 @@
        int "DAC channel"
        default "1"
 +config SOUND_AT32_ABDAC
 +      tristate "Atmel AT32 Audio Bitstream DAC (ABDAC) support"
 +      depends on SOUND_PRIME && AVR32
---- a/sound/oss/Makefile
-+++ b/sound/oss/Makefile
-@@ -10,6 +10,7 @@
+diff --exclude=.git -urN linux-2.6.25.6/sound/oss/Makefile avr32-2.6/sound/oss/Makefile
+--- linux-2.6.25.6/sound/oss/Makefile  2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/sound/oss/Makefile       2008-06-12 15:09:47.023815804 +0200
+@@ -9,6 +9,7 @@
  
  # Please leave it as is, cause the link order is significant !
  
  obj-$(CONFIG_SOUND_SH_DAC_AUDIO)      += sh_dac_audio.o
  obj-$(CONFIG_SOUND_HAL2)      += hal2.o
  obj-$(CONFIG_SOUND_AEDSP16)   += aedsp16.o
---- a/sound/spi/at73c213.c
-+++ b/sound/spi/at73c213.c
-@@ -744,7 +744,7 @@
+diff --exclude=.git -urN linux-2.6.25.6/sound/spi/at73c213.c avr32-2.6/sound/spi/at73c213.c
+--- linux-2.6.25.6/sound/spi/at73c213.c        2008-06-09 20:27:19.000000000 +0200
++++ avr32-2.6/sound/spi/at73c213.c     2008-06-12 15:09:47.247815006 +0200
+@@ -737,7 +737,7 @@
  /*
   * Device functions
   */
  {
        /*
         * Continuous clock output.
-@@ -774,7 +774,7 @@
+@@ -767,7 +767,7 @@
        return 0;
  }
  
  {
        int retval;
        unsigned char dac_ctrl = 0;
-@@ -939,7 +939,7 @@
+@@ -933,7 +933,7 @@
        return retval;
  }
  
diff --git a/target/linux/avr32/patches/120-cpufreq_panic.patch b/target/linux/avr32/patches/120-cpufreq_panic.patch
deleted file mode 100644 (file)
index fe9576c..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-From: Haavard Skinnemoen <haavard.skinnemoen@atmel.com>
-Date: Tue, 27 May 2008 07:37:42 +0000 (+0200)
-Subject: avr32: Fix cpufreq oops when ondemand governor is default
-X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fhskinnemoen%2Favr32-2.6.git;a=commitdiff_plain;h=f04d264afc51acdffeba9cdf3baf04116687680c
-
-avr32: Fix cpufreq oops when ondemand governor is default
-
-Move the AP7 cpufreq init to late_initcall() so that we don't try to
-bring up cpufreq until the governor is ready. x86 also uses
-late_initcall() for this.
-
-Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com>
----
-
-diff --git a/arch/avr32/mach-at32ap/cpufreq.c b/arch/avr32/mach-at32ap/cpufreq.c
-index 235524b..5dd8d25 100644
---- a/arch/avr32/mach-at32ap/cpufreq.c
-+++ b/arch/avr32/mach-at32ap/cpufreq.c
-@@ -108,5 +108,4 @@ static int __init at32_cpufreq_init(void)
- {
-       return cpufreq_register_driver(&at32_driver);
- }
--
--arch_initcall(at32_cpufreq_init);
-+late_initcall(at32_cpufreq_init);