Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6 
diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c
index 51f430c..2786f7c 100644
--- a/arch/arm/common/locomo.c
+++ b/arch/arm/common/locomo.c
@@ -541,6 +541,103 @@
 	return ret;
 }
 
+#ifdef CONFIG_PM
+
+struct locomo_save_data {
+	u16	LCM_GPO;
+	u16	LCM_SPICT;
+	u16	LCM_GPE;
+	u16	LCM_ASD;
+	u16	LCM_SPIMD;
+};
+
+static int locomo_suspend(struct device *dev, u32 pm_message_t, u32 level)
+{
+	struct locomo *lchip = dev_get_drvdata(dev);
+	struct locomo_save_data *save;
+	unsigned long flags;
+
+	if (level != SUSPEND_DISABLE)
+		return 0;
+
+	save = kmalloc(sizeof(struct locomo_save_data), GFP_KERNEL);
+	if (!save)
+		return -ENOMEM;
+
+	dev->power.saved_state = (void *) save;
+
+	spin_lock_irqsave(&lchip->lock, flags);
+
+	save->LCM_GPO     = locomo_readl(lchip->base + LOCOMO_GPO);	/* GPIO */
+	locomo_writel(0x00, lchip->base + LOCOMO_GPO);
+	save->LCM_SPICT   = locomo_readl(lchip->base + LOCOMO_SPICT);	/* SPI */
+	locomo_writel(0x40, lchip->base + LOCOMO_SPICT);
+	save->LCM_GPE     = locomo_readl(lchip->base + LOCOMO_GPE);	/* GPIO */
+	locomo_writel(0x00, lchip->base + LOCOMO_GPE);
+	save->LCM_ASD     = locomo_readl(lchip->base + LOCOMO_ASD);	/* ADSTART */
+	locomo_writel(0x00, lchip->base + LOCOMO_ASD);
+	save->LCM_SPIMD   = locomo_readl(lchip->base + LOCOMO_SPIMD);	/* SPI */
+	locomo_writel(0x3C14, lchip->base + LOCOMO_SPIMD);
+
+	locomo_writel(0x00, lchip->base + LOCOMO_PAIF);
+	locomo_writel(0x00, lchip->base + LOCOMO_DAC);
+	locomo_writel(0x00, lchip->base + LOCOMO_BACKLIGHT + LOCOMO_TC);
+
+	if ( (locomo_readl(lchip->base + LOCOMO_LED + LOCOMO_LPT0) & 0x88) && (locomo_readl(lchip->base + LOCOMO_LED + LOCOMO_LPT1) & 0x88) )
+		locomo_writel(0x00, lchip->base + LOCOMO_C32K); 	/* CLK32 off */
+	else
+		/* 18MHz already enabled, so no wait */
+		locomo_writel(0xc1, lchip->base + LOCOMO_C32K); 	/* CLK32 on */
+
+	locomo_writel(0x00, lchip->base + LOCOMO_TADC);		/* 18MHz clock off*/
+	locomo_writel(0x00, lchip->base + LOCOMO_AUDIO + LOCOMO_ACC);			/* 22MHz/24MHz clock off */
+	locomo_writel(0x00, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS);			/* FL */
+
+	spin_unlock_irqrestore(&lchip->lock, flags);
+
+	return 0;
+}
+
+static int locomo_resume(struct device *dev, u32 level)
+{
+	struct locomo *lchip = dev_get_drvdata(dev);
+	struct locomo_save_data *save;
+	unsigned long r;
+	unsigned long flags;
+	
+	if (level != RESUME_ENABLE)
+		return 0;
+
+	save = (struct locomo_save_data *) dev->power.saved_state;
+	if (!save)
+		return 0;
+
+	spin_lock_irqsave(&lchip->lock, flags);
+
+	locomo_writel(save->LCM_GPO, lchip->base + LOCOMO_GPO);
+	locomo_writel(save->LCM_SPICT, lchip->base + LOCOMO_SPICT);
+	locomo_writel(save->LCM_GPE, lchip->base + LOCOMO_GPE);
+	locomo_writel(save->LCM_ASD, lchip->base + LOCOMO_ASD);
+	locomo_writel(save->LCM_SPIMD, lchip->base + LOCOMO_SPIMD);
+
+	locomo_writel(0x00, lchip->base + LOCOMO_C32K);
+	locomo_writel(0x90, lchip->base + LOCOMO_TADC);
+
+	locomo_writel(0, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KSC);
+	r = locomo_readl(lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC);
+	r &= 0xFEFF;
+	locomo_writel(r, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC);
+	locomo_writel(0x1, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KCMD);
+
+	spin_unlock_irqrestore(&lchip->lock, flags);
+
+	dev->power.saved_state = NULL;
+	kfree(save);
+
+	return 0;
+}
+#endif
+
 /**
  *	locomo_probe - probe for a single LoCoMo chip.
  *	@phys_addr: physical address of device.
@@ -707,6 +804,10 @@
 	.bus		= &platform_bus_type,
 	.probe		= locomo_probe,
 	.remove		= locomo_remove,
+#ifdef CONFIG_PM
+	.suspend	= locomo_suspend,
+	.resume		= locomo_resume,
+#endif
 };
 
 /*
diff --git a/arch/arm/configs/s3c2410_defconfig b/arch/arm/configs/s3c2410_defconfig
index 96a794d..756348b 100644
--- a/arch/arm/configs/s3c2410_defconfig
+++ b/arch/arm/configs/s3c2410_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-git4
-# Wed Jun 22 15:56:42 2005
+# Linux kernel version: 2.6.13-git8
+# Thu Sep  8 19:24:02 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
@@ -22,6 +22,7 @@
 # General setup
 #
 CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
@@ -31,6 +32,7 @@
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
@@ -88,7 +90,9 @@
 #
 # S3C24XX Implementations
 #
+CONFIG_MACH_ANUBIS=y
 CONFIG_ARCH_BAST=y
+CONFIG_BAST_PC104_IRQ=y
 CONFIG_ARCH_H1940=y
 CONFIG_MACH_N30=y
 CONFIG_ARCH_SMDK2410=y
@@ -112,6 +116,7 @@
 # CONFIG_S3C2410_DMA_DEBUG is not set
 # CONFIG_S3C2410_PM_DEBUG is not set
 # CONFIG_S3C2410_PM_CHECK is not set
+CONFIG_PM_SIMTEC=y
 CONFIG_S3C2410_LOWLEVEL_UART_PORT=0
 
 #
@@ -149,7 +154,15 @@
 #
 # CONFIG_SMP is not set
 # CONFIG_PREEMPT is not set
-# CONFIG_DISCONTIGMEM is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_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_ALIGNMENT_TRAP=y
 
 #
@@ -186,6 +199,74 @@
 CONFIG_APM=y
 
 #
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+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=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP 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_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP 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_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
 # Device Drivers
 #
 
@@ -258,6 +339,7 @@
 # CONFIG_MTD_IMPA7 is not set
 CONFIG_MTD_BAST=y
 CONFIG_MTD_BAST_MAXSIZE=4
+# CONFIG_MTD_PLATRAM is not set
 
 #
 # Self-contained MTD device drivers
@@ -312,7 +394,6 @@
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CDROM_PKTCDVD is not set
 
 #
@@ -354,6 +435,7 @@
 #
 # SCSI device support
 #
+# CONFIG_RAID_ATTRS is not set
 # CONFIG_SCSI is not set
 
 #
@@ -376,70 +458,8 @@
 #
 
 #
-# Networking support
+# Network device support
 #
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_FIB_HASH=y
-# CONFIG_IP_FIB_TRIE is not set
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IP_PNP_RARP 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_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP 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_NET_DIVERT 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
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
@@ -447,6 +467,11 @@
 # CONFIG_TUN is not set
 
 #
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
@@ -480,6 +505,8 @@
 # CONFIG_SLIP 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
@@ -562,7 +589,6 @@
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
 # CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_MULTIPORT is not set
 # CONFIG_SERIAL_8250_RSA is not set
 
 #
@@ -605,7 +631,6 @@
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
 #
@@ -628,7 +653,7 @@
 #
 # I2C Hardware Bus support
 #
-# CONFIG_I2C_ISA is not set
+CONFIG_I2C_ISA=m
 # CONFIG_I2C_PARPORT is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
 CONFIG_I2C_S3C2410=y
@@ -636,14 +661,33 @@
 # CONFIG_I2C_PCA_ISA is not set
 
 #
-# Hardware Sensors Chip support
+# Miscellaneous I2C Chip support
 #
-CONFIG_I2C_SENSOR=m
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+CONFIG_SENSORS_EEPROM=m
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_MAX6875 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
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+CONFIG_HWMON_VID=m
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
 # CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
 # CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
 # CONFIG_SENSORS_FSCPOS is not set
@@ -662,30 +706,24 @@
 # CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
 # CONFIG_SENSORS_W83L785TS is not set
 # CONFIG_SENSORS_W83627HF is not set
-
-#
-# Other I2C Chip support
-#
-# CONFIG_SENSORS_DS1337 is not set
-CONFIG_SENSORS_EEPROM=m
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_RTC8564 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_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
 # Misc devices
 #
 
 #
+# Multimedia Capabilities Port drivers
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -731,7 +769,7 @@
 # USB support
 #
 CONFIG_USB_ARCH_HAS_HCD=y
-# CONFIG_USB_ARCH_HAS_OHCI is not set
+CONFIG_USB_ARCH_HAS_OHCI=y
 # CONFIG_USB is not set
 
 #
@@ -749,6 +787,7 @@
 #
 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_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
@@ -758,6 +797,7 @@
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
 
 #
 # XFS support
@@ -765,6 +805,7 @@
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
@@ -791,11 +832,11 @@
 #
 CONFIG_PROC_FS=y
 CONFIG_SYSFS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
 # CONFIG_TMPFS is not set
 # CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -812,8 +853,7 @@
 # CONFIG_JFFS_PROC_FS is not set
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
-# CONFIG_JFFS2_FS_NAND is not set
-# CONFIG_JFFS2_FS_NOR_ECC is not set
+CONFIG_JFFS2_FS_WRITEBUFFER=y
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
 CONFIG_JFFS2_RTIME=y
@@ -835,6 +875,7 @@
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -920,6 +961,7 @@
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_MAGIC_SYSRQ is not set
 CONFIG_LOG_BUF_SHIFT=16
+CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
diff --git a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c
index 112f1d68..e216ab8 100644
--- a/arch/arm/mach-clps7500/core.c
+++ b/arch/arm/mach-clps7500/core.c
@@ -354,7 +354,7 @@
 
 static struct platform_device serial_device = {
 	.name			= "serial8250",
-	.id			= 0,
+	.id			= PLAT8250_DEV_PLATFORM,
 	.dev			= {
 		.platform_data	= serial_platform_data,
 	},
diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
index 23c4da1..5aeadfd 100644
--- a/arch/arm/mach-ebsa110/core.c
+++ b/arch/arm/mach-ebsa110/core.c
@@ -219,7 +219,7 @@
 
 static struct platform_device serial_device = {
 	.name			= "serial8250",
-	.id			= 0,
+	.id			= PLAT8250_DEV_PLATFORM,
 	.dev			= {
 		.platform_data	= serial_platform_data,
 	},
diff --git a/arch/arm/mach-epxa10db/arch.c b/arch/arm/mach-epxa10db/arch.c
index 7daa021..44c5657 100644
--- a/arch/arm/mach-epxa10db/arch.c
+++ b/arch/arm/mach-epxa10db/arch.c
@@ -52,7 +52,7 @@
 
 static struct platform_device serial_device = {
 	.name			= "serial8250",
-	.id			= 0,
+	.id			= PLAT8250_DEV_PLATFORM,
 	.dev			= {
 		.platform_data	= serial_platform_data,
 	},
diff --git a/arch/arm/mach-footbridge/isa.c b/arch/arm/mach-footbridge/isa.c
index aa3a1fe..28846c7 100644
--- a/arch/arm/mach-footbridge/isa.c
+++ b/arch/arm/mach-footbridge/isa.c
@@ -34,7 +34,7 @@
 
 static struct platform_device serial_device = {
 	.name			= "serial8250",
-	.id			= 0,
+	.id			= PLAT8250_DEV_PLATFORM,
 	.dev			= {
 		.platform_data	= serial_platform_data,
 	},
diff --git a/arch/arm/mach-h720x/cpu-h7202.c b/arch/arm/mach-h720x/cpu-h7202.c
index 4b31993..a4a7c01 100644
--- a/arch/arm/mach-h720x/cpu-h7202.c
+++ b/arch/arm/mach-h720x/cpu-h7202.c
@@ -90,7 +90,7 @@
 
 static struct platform_device serial_device = {
 	.name			= "serial8250",
-	.id			= 0,
+	.id			= PLAT8250_DEV_PLATFORM,
 	.dev			= {
 		.platform_data	= serial_platform_data,
 	},
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
index 098c817..74bd2fd 100644
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -174,7 +174,7 @@
 
 static struct platform_device ixp2000_serial_device = {
 	.name		= "serial8250",
-	.id		= 0,
+	.id		= PLAT8250_DEV_PLATFORM,
 	.dev		= {
 		.platform_data		= ixp2000_serial_port,
 	},
diff --git a/arch/arm/mach-ixp4xx/coyote-setup.c b/arch/arm/mach-ixp4xx/coyote-setup.c
index 8b2f253..050c927 100644
--- a/arch/arm/mach-ixp4xx/coyote-setup.c
+++ b/arch/arm/mach-ixp4xx/coyote-setup.c
@@ -66,7 +66,7 @@
 
 static struct platform_device coyote_uart = {
 	.name		= "serial8250",
-	.id		= 0,
+	.id		= PLAT8250_DEV_PLATFORM,
 	.dev			= {
 		.platform_data	= coyote_uart_data,
 	},
diff --git a/arch/arm/mach-ixp4xx/gtwx5715-setup.c b/arch/arm/mach-ixp4xx/gtwx5715-setup.c
index 3fd92c5..29a6d02 100644
--- a/arch/arm/mach-ixp4xx/gtwx5715-setup.c
+++ b/arch/arm/mach-ixp4xx/gtwx5715-setup.c
@@ -93,7 +93,7 @@
 
 static struct platform_device gtwx5715_uart_device = {
 	.name		= "serial8250",
-	.id		= 0,
+	.id		= PLAT8250_DEV_PLATFORM,
 	.dev			= {
 		.platform_data	= gtwx5715_uart_platform_data,
 	},
diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
index 6c14ff3..ae1fa09 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
@@ -96,7 +96,7 @@
 
 static struct platform_device ixdp425_uart = {
 	.name			= "serial8250",
-	.id			= 0,
+	.id			= PLAT8250_DEV_PLATFORM,
 	.dev.platform_data	= ixdp425_uart_data,
 	.num_resources		= 2,
 	.resource		= ixdp425_uart_resources
diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
index 7408ac9..27fc2e8 100644
--- a/arch/arm/mach-omap1/Kconfig
+++ b/arch/arm/mach-omap1/Kconfig
@@ -47,6 +47,14 @@
 	  TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here
           if you have such a board.
 
+config OMAP_OSK_MISTRAL
+	bool "Mistral QVGA board Support"
+	depends on MACH_OMAP_OSK
+    	help
+	  The OSK supports an optional add-on board with a Quarter-VGA
+	  touchscreen, PDA-ish buttons, a resume button, bicolor LED,
+	  and camera connector.  Say Y here if you have this board.
+
 config MACH_OMAP_PERSEUS2
 	bool "TI Perseus2"
 	depends on ARCH_OMAP1 && ARCH_OMAP730
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index d386fd9..181a93d 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -3,7 +3,7 @@
 #
 
 # Common support
-obj-y := io.o id.o irq.o time.o serial.o
+obj-y := io.o id.o irq.o time.o serial.o devices.o
 led-y := leds.o
 
 # Specific board support
@@ -23,6 +23,7 @@
 
 # LEDs support
 led-$(CONFIG_MACH_OMAP_H2)		+= leds-h2p2-debug.o
+led-$(CONFIG_MACH_OMAP_H3)		+= leds-h2p2-debug.o
 led-$(CONFIG_MACH_OMAP_INNOVATOR)	+= leds-innovator.o
 led-$(CONFIG_MACH_OMAP_PERSEUS2)	+= leds-h2p2-debug.o
 led-$(CONFIG_MACH_OMAP_OSK)		+= leds-osk.o
diff --git a/arch/arm/mach-omap1/board-generic.c b/arch/arm/mach-omap1/board-generic.c
index 122796e..c209c71 100644
--- a/arch/arm/mach-omap1/board-generic.c
+++ b/arch/arm/mach-omap1/board-generic.c
@@ -48,19 +48,43 @@
 
 #if defined(CONFIG_ARCH_OMAP16XX)
 static struct omap_usb_config generic1610_usb_config __initdata = {
+#ifdef CONFIG_USB_OTG
+	.otg		= 1,
+#endif
 	.register_host	= 1,
 	.register_dev	= 1,
 	.hmc_mode	= 16,
 	.pins[0]	= 6,
 };
+
+static struct omap_mmc_config generic_mmc_config __initdata = {
+	.mmc [0] = {
+		.enabled 	= 0,
+		.wire4		= 0,
+		.wp_pin		= -1,
+		.power_pin	= -1,
+		.switch_pin	= -1,
+	},
+	.mmc [1] = {
+		.enabled 	= 0,
+		.wire4		= 0,
+		.wp_pin		= -1,
+		.power_pin	= -1,
+		.switch_pin	= -1,
+	},
+};
+
 #endif
 
 static struct omap_board_config_kernel generic_config[] = {
 	{ OMAP_TAG_USB,           NULL },
+	{ OMAP_TAG_MMC,           &generic_mmc_config },
 };
 
 static void __init omap_generic_init(void)
 {
+	const struct omap_uart_config *uart_conf;
+
 	/*
 	 * Make sure the serial ports are muxed on at this point.
 	 * You have to mux them off in device drivers later on
@@ -76,6 +100,18 @@
 		generic_config[0].data = &generic1610_usb_config;
 	}
 #endif
+
+	uart_conf = omap_get_config(OMAP_TAG_UART, struct omap_uart_config);
+	if (uart_conf != NULL) {
+		unsigned int enabled_ports, i;
+
+		enabled_ports = uart_conf->enabled_uarts;
+		for (i = 0; i < 3; i++) {
+			if (!(enabled_ports & (1 << i)))
+				generic_serial_ports[i] = 0;
+		}
+	}
+
 	omap_board_config = generic_config;
 	omap_board_config_size = ARRAY_SIZE(generic_config);
 	omap_serial_init(generic_serial_ports);
@@ -83,7 +119,7 @@
 
 static void __init omap_generic_map_io(void)
 {
-	omap_map_common_io()
+	omap_map_common_io();
 }
 
 MACHINE_START(OMAP_GENERIC, "Generic OMAP1510/1610/1710")
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index f4983ee..d46a700 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -33,6 +33,7 @@
 #include <asm/mach/map.h>
 
 #include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
 #include <asm/arch/tc.h>
 #include <asm/arch/usb.h>
 #include <asm/arch/common.h>
@@ -80,8 +81,7 @@
 };
 
 static struct resource h2_flash_resource = {
-	.start		= OMAP_CS2B_PHYS,
-	.end		= OMAP_CS2B_PHYS + OMAP_CS2B_SIZE - 1,
+	/* This is on CS3, wherever it's mapped */
 	.flags		= IORESOURCE_MEM,
 };
 
@@ -126,10 +126,9 @@
 		printk("Error requesting gpio 0 for smc91x irq\n");
 		return;
 	}
-	omap_set_gpio_edge_ctrl(0, OMAP_GPIO_FALLING_EDGE);
 }
 
-void h2_init_irq(void)
+static void __init h2_init_irq(void)
 {
 	omap_init_irq();
 	omap_gpio_init();
@@ -152,9 +151,13 @@
 };
 
 static struct omap_mmc_config h2_mmc_config __initdata = {
-	.mmc_blocks		= 1,
-	.mmc1_power_pin		= -1,	/* tps65010 gpio3 */
-	.mmc1_switch_pin	= OMAP_MPUIO(1),
+	.mmc [0] = {
+		.enabled 	= 1,
+		.wire4		= 1,
+		.wp_pin		= OMAP_MPUIO(3),
+		.power_pin	= -1,	/* tps65010 gpio3 */
+		.switch_pin	= OMAP_MPUIO(1),
+	},
 };
 
 static struct omap_board_config_kernel h2_config[] = {
@@ -164,6 +167,16 @@
 
 static void __init h2_init(void)
 {
+	/* NOTE: revC boards support NAND-boot, which can put NOR on CS2B
+	 * and NAND (either 16bit or 8bit) on CS3.
+	 */
+	h2_flash_resource.end = h2_flash_resource.start = omap_cs3_phys();
+	h2_flash_resource.end += SZ_32M - 1;
+
+	/* MMC:  card detect and WP */
+	// omap_cfg_reg(U19_ARMIO1);		/* CD */
+	omap_cfg_reg(BALLOUT_V8_ARMIO3);	/* WP */
+
 	platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
 	omap_board_config = h2_config;
 	omap_board_config_size = ARRAY_SIZE(h2_config);
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 7cd419d..2798613 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -82,8 +82,7 @@
 };
 
 static struct resource h3_flash_resource = {
-	.start		= OMAP_CS2B_PHYS,
-	.end		= OMAP_CS2B_PHYS + OMAP_CS2B_SIZE - 1,
+	/* This is on CS3, wherever it's mapped */
 	.flags		= IORESOURCE_MEM,
 };
 
@@ -161,13 +160,26 @@
 	.pins[1]	= 3,
 };
 
+static struct omap_mmc_config h3_mmc_config __initdata = {
+	.mmc[0] = {
+		.enabled 	= 1,
+		.power_pin	= -1,   /* tps65010 GPIO4 */
+		.switch_pin	= OMAP_MPUIO(1),
+	},
+};
+
 static struct omap_board_config_kernel h3_config[] = {
 	{ OMAP_TAG_USB,	 &h3_usb_config },
+	{ OMAP_TAG_MMC,  &h3_mmc_config },
 };
 
 static void __init h3_init(void)
 {
+	h3_flash_resource.end = h3_flash_resource.start = omap_cs3_phys();
+	h3_flash_resource.end += OMAP_CS3_SIZE - 1;
 	(void) platform_add_devices(devices, ARRAY_SIZE(devices));
+	omap_board_config = h3_config;
+	omap_board_config_size = ARRAY_SIZE(h3_config);
 }
 
 static void __init h3_init_smc91x(void)
@@ -177,7 +189,6 @@
 		printk("Error requesting gpio 40 for smc91x irq\n");
 		return;
 	}
-	omap_set_gpio_edge_ctrl(40, OMAP_GPIO_FALLING_EDGE);
 }
 
 void h3_init_irq(void)
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
index 91de60a..df0312b 100644
--- a/arch/arm/mach-omap1/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -29,6 +29,7 @@
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
+#include <asm/arch/mux.h>
 #include <asm/arch/fpga.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/tc.h>
@@ -173,7 +174,6 @@
 			printk("Error requesting gpio 0 for smc91x irq\n");
 			return;
 		}
-		omap_set_gpio_edge_ctrl(0, OMAP_GPIO_RISING_EDGE);
 	}
 }
 
@@ -220,8 +220,19 @@
 };
 #endif
 
+static struct omap_mmc_config innovator_mmc_config __initdata = {
+	.mmc [0] = {
+		.enabled 	= 1,
+		.wire4		= 1,
+		.wp_pin		= OMAP_MPUIO(3),
+		.power_pin	= -1,	/* FPGA F3 UIO42 */
+		.switch_pin	= -1,	/* FPGA F4 UIO43 */
+	},
+};
+
 static struct omap_board_config_kernel innovator_config[] = {
 	{ OMAP_TAG_USB,         NULL },
+	{ OMAP_TAG_MMC,		&innovator_mmc_config },
 };
 
 static void __init innovator_init(void)
diff --git a/arch/arm/mach-omap1/board-netstar.c b/arch/arm/mach-omap1/board-netstar.c
index 6750b20..d904e64 100644
--- a/arch/arm/mach-omap1/board-netstar.c
+++ b/arch/arm/mach-omap1/board-netstar.c
@@ -75,16 +75,15 @@
 	mdelay(50);	/* 50ms until PHY ready */
 	/* smc91x interrupt pin */
 	omap_request_gpio(8);
-	omap_set_gpio_edge_ctrl(8, OMAP_GPIO_RISING_EDGE);
 
 	omap_request_gpio(12);
 	omap_request_gpio(13);
 	omap_request_gpio(14);
 	omap_request_gpio(15);
-	omap_set_gpio_edge_ctrl(12, OMAP_GPIO_FALLING_EDGE);
-	omap_set_gpio_edge_ctrl(13, OMAP_GPIO_FALLING_EDGE);
-	omap_set_gpio_edge_ctrl(14, OMAP_GPIO_FALLING_EDGE);
-	omap_set_gpio_edge_ctrl(15, OMAP_GPIO_FALLING_EDGE);
+	set_irq_type(OMAP_GPIO_IRQ(12), IRQT_FALLING);
+	set_irq_type(OMAP_GPIO_IRQ(13), IRQT_FALLING);
+	set_irq_type(OMAP_GPIO_IRQ(14), IRQT_FALLING);
+	set_irq_type(OMAP_GPIO_IRQ(15), IRQT_FALLING);
 
 	platform_add_devices(netstar_devices, ARRAY_SIZE(netstar_devices));
 
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index 6844e53..21103df 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -29,11 +29,16 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/interrupt.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/mach/flash.h>
 
 #include <asm/arch/gpio.h>
 #include <asm/arch/usb.h>
@@ -41,12 +46,56 @@
 #include <asm/arch/tc.h>
 #include <asm/arch/common.h>
 
-static struct map_desc osk5912_io_desc[] __initdata = {
-{ OMAP_OSK_NOR_FLASH_BASE, OMAP_OSK_NOR_FLASH_START, OMAP_OSK_NOR_FLASH_SIZE,
-	MT_DEVICE },
+static int __initdata osk_serial_ports[OMAP_MAX_NR_PORTS] = {1, 0, 0};
+
+static struct mtd_partition osk_partitions[] = {
+	/* bootloader (U-Boot, etc) in first sector */
+	{
+	      .name		= "bootloader",
+	      .offset		= 0,
+	      .size		= SZ_128K,
+	      .mask_flags	= MTD_WRITEABLE, /* force read-only */
+	},
+	/* bootloader params in the next sector */
+	{
+	      .name		= "params",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_128K,
+	      .mask_flags	= 0,
+	}, {
+	      .name		= "kernel",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_2M,
+	      .mask_flags	= 0
+	}, {
+	      .name		= "filesystem",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= MTDPART_SIZ_FULL,
+	      .mask_flags	= 0
+	}
 };
 
-static int __initdata osk_serial_ports[OMAP_MAX_NR_PORTS] = {1, 0, 0};
+static struct flash_platform_data osk_flash_data = {
+	.map_name	= "cfi_probe",
+	.width		= 2,
+	.parts		= osk_partitions,
+	.nr_parts	= ARRAY_SIZE(osk_partitions),
+};
+
+static struct resource osk_flash_resource = {
+	/* this is on CS3, wherever it's mapped */
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device osk5912_flash_device = {
+	.name		= "omapflash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &osk_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= &osk_flash_resource,
+};
 
 static struct resource osk5912_smc91x_resources[] = {
 	[0] = {
@@ -86,9 +135,16 @@
 	.resource	= osk5912_cf_resources,
 };
 
+static struct platform_device osk5912_mcbsp1_device = {
+	.name		= "omap_mcbsp",
+	.id		= 1,
+};
+
 static struct platform_device *osk5912_devices[] __initdata = {
+	&osk5912_flash_device,
 	&osk5912_smc91x_device,
 	&osk5912_cf_device,
+	&osk5912_mcbsp1_device,
 };
 
 static void __init osk_init_smc91x(void)
@@ -97,7 +153,6 @@
 		printk("Error requesting gpio 0 for smc91x irq\n");
 		return;
 	}
-	omap_set_gpio_edge_ctrl(0, OMAP_GPIO_RISING_EDGE);
 
 	/* Check EMIFS wait states to fix errors with SMC_GET_PKT_HDR */
 	EMIFS_CCS(1) |= 0x2;
@@ -110,11 +165,11 @@
 		printk("Error requesting gpio 62 for CF irq\n");
 		return;
 	}
-	/* it's really active-low */
-	omap_set_gpio_edge_ctrl(62, OMAP_GPIO_FALLING_EDGE);
+	/* the CF I/O IRQ is really active-low */
+	set_irq_type(OMAP_GPIO_IRQ(62), IRQT_FALLING);
 }
 
-void osk_init_irq(void)
+static void __init osk_init_irq(void)
 {
 	omap_init_irq();
 	omap_gpio_init();
@@ -142,18 +197,69 @@
 	{ OMAP_TAG_USB,           &osk_usb_config },
 };
 
+#ifdef	CONFIG_OMAP_OSK_MISTRAL
+
+#ifdef	CONFIG_PM
+static irqreturn_t
+osk_mistral_wake_interrupt(int irq, void *ignored, struct pt_regs *regs)
+{
+	return IRQ_HANDLED;
+}
+#endif
+
+static void __init osk_mistral_init(void)
+{
+	/* FIXME here's where to feed in framebuffer, touchpad, and
+	 * keyboard setup ...  not in the drivers for those devices!
+	 *
+	 * NOTE:  we could actually tell if there's a Mistral board
+	 * attached, e.g. by trying to read something from the ads7846.
+	 * But this is too early for that...
+	 */
+
+	/* the sideways button (SW1) is for use as a "wakeup" button */
+	omap_cfg_reg(N15_1610_MPUIO2);
+	if (omap_request_gpio(OMAP_MPUIO(2)) == 0) {
+		int ret = 0;
+		omap_set_gpio_direction(OMAP_MPUIO(2), 1);
+		set_irq_type(OMAP_GPIO_IRQ(OMAP_MPUIO(2)), IRQT_RISING);
+#ifdef	CONFIG_PM
+		/* share the IRQ in case someone wants to use the
+		 * button for more than wakeup from system sleep.
+		 */
+		ret = request_irq(OMAP_GPIO_IRQ(OMAP_MPUIO(2)),
+				&osk_mistral_wake_interrupt,
+				SA_SHIRQ, "mistral_wakeup",
+				&osk_mistral_wake_interrupt);
+		if (ret != 0) {
+			omap_free_gpio(OMAP_MPUIO(2));
+			printk(KERN_ERR "OSK+Mistral: no wakeup irq, %d?\n",
+				ret);
+		} else
+			enable_irq_wake(OMAP_GPIO_IRQ(OMAP_MPUIO(2)));
+#endif
+	} else
+		printk(KERN_ERR "OSK+Mistral: wakeup button is awol\n");
+}
+#else
+static void __init osk_mistral_init(void) { }
+#endif
+
 static void __init osk_init(void)
 {
+	osk_flash_resource.end = osk_flash_resource.start = omap_cs3_phys();
+	osk_flash_resource.end += SZ_32M - 1;
 	platform_add_devices(osk5912_devices, ARRAY_SIZE(osk5912_devices));
 	omap_board_config = osk_config;
 	omap_board_config_size = ARRAY_SIZE(osk_config);
 	USB_TRANSCEIVER_CTRL_REG |= (3 << 1);
+
+	osk_mistral_init();
 }
 
 static void __init osk_map_io(void)
 {
 	omap_map_common_io();
-	iotable_init(osk5912_io_desc, ARRAY_SIZE(osk5912_io_desc));
 	omap_serial_init(osk_serial_ports);
 }
 
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index 2133173..107c68c 100644
--- a/arch/arm/mach-omap1/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -24,6 +24,7 @@
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
+#include <asm/arch/tc.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/fpga.h>
@@ -83,8 +84,8 @@
 };
 
 static struct resource p2_flash_resource = {
-	.start		= OMAP_FLASH_0_START,
-	.end		= OMAP_FLASH_0_START + OMAP_FLASH_0_SIZE - 1,
+	.start		= OMAP_CS0_PHYS,
+	.end		= OMAP_CS0_PHYS + SZ_32M - 1,
 	.flags		= IORESOURCE_MEM,
 };
 
diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c
index e422819..bf30b1a 100644
--- a/arch/arm/mach-omap1/board-voiceblue.c
+++ b/arch/arm/mach-omap1/board-voiceblue.c
@@ -25,13 +25,14 @@
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
-#include <asm/arch/gpio.h>
-#include <asm/arch/tc.h>
-#include <asm/arch/mux.h>
-#include <asm/arch/usb.h>
 #include <asm/arch/common.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/tc.h>
+#include <asm/arch/usb.h>
 
 extern void omap_init_time(void);
 extern int omap_gpio_init(void);
@@ -74,7 +75,7 @@
 
 static struct platform_device serial_device = {
 	.name			= "serial8250",
-	.id			= 1,
+	.id			= PLAT8250_DEV_PLATFORM1,
 	.dev			= {
 		.platform_data	= voiceblue_ports,
 	},
@@ -86,6 +87,27 @@
 }
 arch_initcall(ext_uart_init);
 
+static struct flash_platform_data voiceblue_flash_data = {
+	.map_name	= "cfi_probe",
+	.width		= 2,
+};
+
+static struct resource voiceblue_flash_resource = {
+	.start	= OMAP_CS0_PHYS,
+	.end	= OMAP_CS0_PHYS + SZ_32M - 1,
+	.flags	= IORESOURCE_MEM,
+};
+
+static struct platform_device voiceblue_flash_device = {
+	.name		= "omapflash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &voiceblue_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= &voiceblue_flash_resource,
+};
+
 static struct resource voiceblue_smc91x_resources[] = {
 	[0] = {
 		.start	= OMAP_CS2_PHYS + 0x300,
@@ -107,6 +129,7 @@
 };
 
 static struct platform_device *voiceblue_devices[] __initdata = {
+	&voiceblue_flash_device,
 	&voiceblue_smc91x_device,
 };
 
@@ -119,8 +142,17 @@
 	.pins[2]	= 6,
 };
 
+static struct omap_mmc_config voiceblue_mmc_config __initdata = {
+	.mmc[0] = {
+		.enabled	= 1,
+		.power_pin	= 2,
+		.switch_pin	= -1,
+	},
+};
+
 static struct omap_board_config_kernel voiceblue_config[] = {
 	{ OMAP_TAG_USB, &voiceblue_usb_config },
+	{ OMAP_TAG_MMC, &voiceblue_mmc_config },
 };
 
 static void __init voiceblue_init_irq(void)
@@ -131,9 +163,6 @@
 
 static void __init voiceblue_init(void)
 {
-	/* There is a good chance board is going up, so enable Power LED
-	 * (it is connected through invertor) */
-	omap_writeb(0x00, OMAP_LPG1_LCR);
 	/* Watchdog */
 	omap_request_gpio(0);
 	/* smc91x reset */
@@ -145,7 +174,6 @@
 	mdelay(50);	/* 50ms until PHY ready */
 	/* smc91x interrupt pin */
 	omap_request_gpio(8);
-	omap_set_gpio_edge_ctrl(8, OMAP_GPIO_RISING_EDGE);
 	/* 16C554 reset*/
 	omap_request_gpio(6);
 	omap_set_gpio_direction(6, 0);
@@ -155,14 +183,19 @@
 	omap_request_gpio(13);
 	omap_request_gpio(14);
 	omap_request_gpio(15);
-	omap_set_gpio_edge_ctrl(12, OMAP_GPIO_RISING_EDGE);
-	omap_set_gpio_edge_ctrl(13, OMAP_GPIO_RISING_EDGE);
-	omap_set_gpio_edge_ctrl(14, OMAP_GPIO_RISING_EDGE);
-	omap_set_gpio_edge_ctrl(15, OMAP_GPIO_RISING_EDGE);
+	set_irq_type(OMAP_GPIO_IRQ(12), IRQT_RISING);
+	set_irq_type(OMAP_GPIO_IRQ(13), IRQT_RISING);
+	set_irq_type(OMAP_GPIO_IRQ(14), IRQT_RISING);
+	set_irq_type(OMAP_GPIO_IRQ(15), IRQT_RISING);
 
 	platform_add_devices(voiceblue_devices, ARRAY_SIZE(voiceblue_devices));
 	omap_board_config = voiceblue_config;
 	omap_board_config_size = ARRAY_SIZE(voiceblue_config);
+
+	/* There is a good chance board is going up, so enable power LED
+	 * (it is connected through invertor) */
+	omap_writeb(0x00, OMAP_LPG1_LCR);
+	omap_writeb(0x00, OMAP_LPG1_PMR);	/* Disable clock */
 }
 
 static int __initdata omap_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
@@ -184,9 +217,9 @@
 	if (test_and_set_bit(MACHINE_PANICED, &machine_state))
 		return NOTIFY_DONE;
 
-	/* Flash Power LED
-	 * (TODO: Enable clock right way (enabled in bootloader already)) */
+	/* Flash power LED */
 	omap_writeb(0x78, OMAP_LPG1_LCR);
+	omap_writeb(0x01, OMAP_LPG1_PMR);	/* Enable clock */
 
 	return NOTIFY_DONE;
 }
@@ -195,15 +228,14 @@
 	.notifier_call	= panic_event,
 };
 
-static int __init setup_notifier(void)
+static int __init voiceblue_setup(void)
 {
 	/* Setup panic notifier */
 	notifier_chain_register(&panic_notifier_list, &panic_block);
 
 	return 0;
 }
-
-postcore_initcall(setup_notifier);
+postcore_initcall(voiceblue_setup);
 
 static int wdt_gpio_state;
 
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
new file mode 100644
index 0000000..e8b3981
--- /dev/null
+++ b/arch/arm/mach-omap1/devices.c
@@ -0,0 +1,351 @@
+/*
+ * linux/arch/arm/mach-omap1/devices.c
+ *
+ * OMAP1 platform device setup/initialization
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/tc.h>
+#include <asm/arch/board.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+
+
+static void omap_nop_release(struct device *dev)
+{
+        /* Nothing */
+}
+
+/*-------------------------------------------------------------------------*/
+
+#if	defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
+
+#define	OMAP_I2C_BASE		0xfffb3800
+
+static struct resource i2c_resources[] = {
+	{
+		.start		= OMAP_I2C_BASE,
+		.end		= OMAP_I2C_BASE + 0x3f,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= INT_I2C,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+/* DMA not used; works around erratum writing to non-empty i2c fifo */
+
+static struct platform_device omap_i2c_device = {
+        .name           = "i2c_omap",
+        .id             = -1,
+        .dev = {
+                .release        = omap_nop_release,
+        },
+	.num_resources	= ARRAY_SIZE(i2c_resources),
+	.resource	= i2c_resources,
+};
+
+static void omap_init_i2c(void)
+{
+	/* FIXME define and use a boot tag, in case of boards that
+	 * either don't wire up I2C, or chips that mux it differently...
+	 * it can include clocking and address info, maybe more.
+	 */
+	omap_cfg_reg(I2C_SCL);
+	omap_cfg_reg(I2C_SDA);
+
+	(void) platform_device_register(&omap_i2c_device);
+}
+#else
+static inline void omap_init_i2c(void) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#if	defined(CONFIG_OMAP1610_IR) || defined(CONFIG_OMAP161O_IR_MODULE)
+
+static u64 irda_dmamask = 0xffffffff;
+
+static struct platform_device omap1610ir_device = {
+	.name = "omap1610-ir",
+	.id = -1,
+	.dev = {
+		.release	= omap_nop_release,
+		.dma_mask	= &irda_dmamask,
+	},
+};
+
+static void omap_init_irda(void)
+{
+	/* FIXME define and use a boot tag, members something like:
+	 *  u8		uart;		// uart1, or uart3
+	 * ... but driver only handles uart3 for now
+	 *  s16		fir_sel;	// gpio for SIR vs FIR
+	 * ... may prefer a callback for SIR/MIR/FIR mode select;
+	 * while h2 uses a GPIO, H3 uses a gpio expander
+	 */
+	if (machine_is_omap_h2()
+			|| machine_is_omap_h3())
+		(void) platform_device_register(&omap1610ir_device);
+}
+#else
+static inline void omap_init_irda(void) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#if	defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+
+#define	OMAP_MMC1_BASE		0xfffb7800
+#define	OMAP_MMC2_BASE		0xfffb7c00	/* omap16xx only */
+
+static struct omap_mmc_conf mmc1_conf;
+
+static u64 mmc1_dmamask = 0xffffffff;
+
+static struct resource mmc1_resources[] = {
+	{
+		.start		= IO_ADDRESS(OMAP_MMC1_BASE),
+		.end		= IO_ADDRESS(OMAP_MMC1_BASE) + 0x7f,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= INT_MMC,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device mmc_omap_device1 = {
+	.name		= "mmci-omap",
+	.id		= 1,
+	.dev = {
+		.release	= omap_nop_release,
+		.dma_mask	= &mmc1_dmamask,
+		.platform_data	= &mmc1_conf,
+	},
+	.num_resources	= ARRAY_SIZE(mmc1_resources),
+	.resource	= mmc1_resources,
+};
+
+#ifdef	CONFIG_ARCH_OMAP16XX
+
+static struct omap_mmc_conf mmc2_conf;
+
+static u64 mmc2_dmamask = 0xffffffff;
+
+static struct resource mmc2_resources[] = {
+	{
+		.start		= IO_ADDRESS(OMAP_MMC2_BASE),
+		.end		= IO_ADDRESS(OMAP_MMC2_BASE) + 0x7f,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= INT_1610_MMC2,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device mmc_omap_device2 = {
+	.name		= "mmci-omap",
+	.id		= 2,
+	.dev = {
+		.release	= omap_nop_release,
+		.dma_mask	= &mmc2_dmamask,
+		.platform_data	= &mmc2_conf,
+	},
+	.num_resources	= ARRAY_SIZE(mmc2_resources),
+	.resource	= mmc2_resources,
+};
+#endif
+
+static void __init omap_init_mmc(void)
+{
+	const struct omap_mmc_config	*mmc_conf;
+	const struct omap_mmc_conf	*mmc;
+
+	/* NOTE:  assumes MMC was never (wrongly) enabled */
+	mmc_conf = omap_get_config(OMAP_TAG_MMC, struct omap_mmc_config);
+	if (!mmc_conf)
+		return;
+
+	/* block 1 is always available and has just one pinout option */
+	mmc = &mmc_conf->mmc[0];
+	if (mmc->enabled) {
+		omap_cfg_reg(MMC_CMD);
+		omap_cfg_reg(MMC_CLK);
+		omap_cfg_reg(MMC_DAT0);
+		if (cpu_is_omap1710()) {
+	              omap_cfg_reg(M15_1710_MMC_CLKI);
+	              omap_cfg_reg(P19_1710_MMC_CMDDIR);
+	              omap_cfg_reg(P20_1710_MMC_DATDIR0);
+	        }
+		if (mmc->wire4) {
+			omap_cfg_reg(MMC_DAT1);
+			/* NOTE:  DAT2 can be on W10 (here) or M15 */
+			if (!mmc->nomux)
+				omap_cfg_reg(MMC_DAT2);
+			omap_cfg_reg(MMC_DAT3);
+		}
+		mmc1_conf = *mmc;
+		(void) platform_device_register(&mmc_omap_device1);
+	}
+
+#ifdef	CONFIG_ARCH_OMAP16XX
+	/* block 2 is on newer chips, and has many pinout options */
+	mmc = &mmc_conf->mmc[1];
+	if (mmc->enabled) {
+		if (!mmc->nomux) {
+			omap_cfg_reg(Y8_1610_MMC2_CMD);
+			omap_cfg_reg(Y10_1610_MMC2_CLK);
+			omap_cfg_reg(R18_1610_MMC2_CLKIN);
+			omap_cfg_reg(W8_1610_MMC2_DAT0);
+			if (mmc->wire4) {
+				omap_cfg_reg(V8_1610_MMC2_DAT1);
+				omap_cfg_reg(W15_1610_MMC2_DAT2);
+				omap_cfg_reg(R10_1610_MMC2_DAT3);
+			}
+
+			/* These are needed for the level shifter */
+			omap_cfg_reg(V9_1610_MMC2_CMDDIR);
+			omap_cfg_reg(V5_1610_MMC2_DATDIR0);
+			omap_cfg_reg(W19_1610_MMC2_DATDIR1);
+		}
+
+		/* Feedback clock must be set on OMAP-1710 MMC2 */
+		if (cpu_is_omap1710())
+			omap_writel(omap_readl(MOD_CONF_CTRL_1) | (1 << 24),
+				     MOD_CONF_CTRL_1);
+		mmc2_conf = *mmc;
+		(void) platform_device_register(&mmc_omap_device2);
+	}
+#endif
+	return;
+}
+#else
+static inline void omap_init_mmc(void) {}
+#endif
+
+#if	defined(CONFIG_OMAP_RTC) || defined(CONFIG_OMAP_RTC)
+
+#define	OMAP_RTC_BASE		0xfffb4800
+
+static struct resource rtc_resources[] = {
+	{
+		.start		= OMAP_RTC_BASE,
+		.end		= OMAP_RTC_BASE + 0x5f,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= INT_RTC_TIMER,
+		.flags		= IORESOURCE_IRQ,
+	},
+	{
+		.start		= INT_RTC_ALARM,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device omap_rtc_device = {
+	.name           = "omap_rtc",
+	.id             = -1,
+	.dev = {
+		.release        = omap_nop_release,
+	},
+	.num_resources	= ARRAY_SIZE(rtc_resources),
+	.resource	= rtc_resources,
+};
+
+static void omap_init_rtc(void)
+{
+	(void) platform_device_register(&omap_rtc_device);
+}
+#else
+static inline void omap_init_rtc(void) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#if	defined(CONFIG_OMAP16XX_WATCHDOG) || defined(CONFIG_OMAP16XX_WATCHDOG_MODULE)
+
+#define	OMAP_WDT_BASE		0xfffeb000
+
+static struct resource wdt_resources[] = {
+	{
+		.start		= OMAP_WDT_BASE,
+		.end		= OMAP_WDT_BASE + 0x4f,
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device omap_wdt_device = {
+	.name	   = "omap1610_wdt",
+	.id	     = -1,
+	.dev = {
+		.release	= omap_nop_release,
+	},
+	.num_resources	= ARRAY_SIZE(wdt_resources),
+	.resource	= wdt_resources,
+};
+
+static void omap_init_wdt(void)
+{
+	(void) platform_device_register(&omap_wdt_device);
+}
+#else
+static inline void omap_init_wdt(void) {}
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * This gets called after board-specific INIT_MACHINE, and initializes most
+ * on-chip peripherals accessible on this board (except for few like USB):
+ *
+ *  (a) Does any "standard config" pin muxing needed.  Board-specific
+ *	code will have muxed GPIO pins and done "nonstandard" setup;
+ *	that code could live in the boot loader.
+ *  (b) Populating board-specific platform_data with the data drivers
+ *	rely on to handle wiring variations.
+ *  (c) Creating platform devices as meaningful on this board and
+ *	with this kernel configuration.
+ *
+ * Claiming GPIOs, and setting their direction and initial values, is the
+ * responsibility of the device drivers.  So is responding to probe().
+ *
+ * Board-specific knowlege like creating devices or pin setup is to be
+ * kept out of drivers as much as possible.  In particular, pin setup
+ * may be handled by the boot loader, and drivers should expect it will
+ * normally have been done by the time they're probed.
+ */
+static int __init omap_init_devices(void)
+{
+	/* please keep these calls, and their implementations above,
+	 * in alphabetical order so they're easier to sort through.
+	 */
+	omap_init_i2c();
+	omap_init_irda();
+	omap_init_mmc();
+	omap_init_rtc();
+	omap_init_wdt();
+
+	return 0;
+}
+arch_initcall(omap_init_devices);
+
diff --git a/arch/arm/mach-omap1/fpga.c b/arch/arm/mach-omap1/fpga.c
index c12a783..aca2a12 100644
--- a/arch/arm/mach-omap1/fpga.c
+++ b/arch/arm/mach-omap1/fpga.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/fpga.c
+ * linux/arch/arm/mach-omap1/fpga.c
  *
  * Interrupt handler for OMAP-1510 Innovator FPGA
  *
@@ -181,7 +181,7 @@
 	 */
 	omap_request_gpio(13);
 	omap_set_gpio_direction(13, 1);
-	omap_set_gpio_edge_ctrl(13, OMAP_GPIO_RISING_EDGE);
+	set_irq_type(OMAP_GPIO_IRQ(13), IRQT_RISING);
 	set_irq_chained_handler(OMAP1510_INT_FPGA, innovator_fpga_IRQ_demux);
 }
 
diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c
index 207df0f..eb8261d 100644
--- a/arch/arm/mach-omap1/io.c
+++ b/arch/arm/mach-omap1/io.c
@@ -19,6 +19,7 @@
 
 extern int clk_init(void);
 extern void omap_check_revision(void);
+extern void omap_sram_init(void);
 
 /*
  * The machine specific code may provide the extra mapping besides the
@@ -32,7 +33,6 @@
 static struct map_desc omap730_io_desc[] __initdata = {
  { OMAP730_DSP_BASE,    OMAP730_DSP_START,    OMAP730_DSP_SIZE,    MT_DEVICE },
  { OMAP730_DSPREG_BASE, OMAP730_DSPREG_START, OMAP730_DSPREG_SIZE, MT_DEVICE },
- { OMAP730_SRAM_BASE,   OMAP730_SRAM_START,   OMAP730_SRAM_SIZE,   MT_DEVICE }
 };
 #endif
 
@@ -40,27 +40,13 @@
 static struct map_desc omap1510_io_desc[] __initdata = {
  { OMAP1510_DSP_BASE,    OMAP1510_DSP_START,    OMAP1510_DSP_SIZE,    MT_DEVICE },
  { OMAP1510_DSPREG_BASE, OMAP1510_DSPREG_START, OMAP1510_DSPREG_SIZE, MT_DEVICE },
- { OMAP1510_SRAM_BASE,   OMAP1510_SRAM_START,   OMAP1510_SRAM_SIZE,   MT_DEVICE }
 };
 #endif
 
 #if defined(CONFIG_ARCH_OMAP16XX)
-static struct map_desc omap1610_io_desc[] __initdata = {
+static struct map_desc omap16xx_io_desc[] __initdata = {
  { OMAP16XX_DSP_BASE,    OMAP16XX_DSP_START,    OMAP16XX_DSP_SIZE,    MT_DEVICE },
  { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE },
- { OMAP16XX_SRAM_BASE,   OMAP16XX_SRAM_START,   OMAP1610_SRAM_SIZE,   MT_DEVICE }
-};
-
-static struct map_desc omap5912_io_desc[] __initdata = {
- { OMAP16XX_DSP_BASE,    OMAP16XX_DSP_START,    OMAP16XX_DSP_SIZE,    MT_DEVICE },
- { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE },
-/*
- * The OMAP5912 has 250kByte internal SRAM. Because the mapping is baseed on page
- * size (4kByte), it seems that the last 2kByte (=0x800) of the 250kByte are not mapped.
- * Add additional 2kByte (0x800) so that the last page is mapped and the last 2kByte
- * can be used.
- */
- { OMAP16XX_SRAM_BASE,   OMAP16XX_SRAM_START,   OMAP5912_SRAM_SIZE + 0x800,   MT_DEVICE }
 };
 #endif
 
@@ -86,14 +72,13 @@
 	}
 #endif
 #if defined(CONFIG_ARCH_OMAP16XX)
-	if (cpu_is_omap1610() || cpu_is_omap1710()) {
-		iotable_init(omap1610_io_desc, ARRAY_SIZE(omap1610_io_desc));
-	}
-	if (cpu_is_omap5912()) {
-		iotable_init(omap5912_io_desc, ARRAY_SIZE(omap5912_io_desc));
+	if (cpu_is_omap16xx()) {
+		iotable_init(omap16xx_io_desc, ARRAY_SIZE(omap16xx_io_desc));
 	}
 #endif
 
+	omap_sram_init();
+
 	/* REVISIT: Refer to OMAP5910 Errata, Advisory SYS_1: "Timeout Abort
 	 * on a Posted Write in the TIPB Bridge".
 	 */
@@ -108,8 +93,9 @@
 /*
  * This should only get called from board specific init
  */
-void omap_map_common_io(void)
+void __init omap_map_common_io(void)
 {
 	if (!initialized)
 		_omap_map_io();
 }
+
diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c
index afd5d67..192ce60 100644
--- a/arch/arm/mach-omap1/irq.c
+++ b/arch/arm/mach-omap1/irq.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/irq.c
+ * linux/arch/arm/mach-omap1/irq.c
  *
  * Interrupt handler for all OMAP boards
  *
diff --git a/arch/arm/mach-omap1/leds-h2p2-debug.c b/arch/arm/mach-omap1/leds-h2p2-debug.c
index ec0d828..be283cd 100644
--- a/arch/arm/mach-omap1/leds-h2p2-debug.c
+++ b/arch/arm/mach-omap1/leds-h2p2-debug.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/leds-h2p2-debug.c
+ * linux/arch/arm/mach-omap1/leds-h2p2-debug.c
  *
  * Copyright 2003 by Texas Instruments Incorporated
  *
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/kernel_stat.h>
 #include <linux/sched.h>
+#include <linux/version.h>
 
 #include <asm/io.h>
 #include <asm/hardware.h>
diff --git a/arch/arm/mach-omap1/leds-innovator.c b/arch/arm/mach-omap1/leds-innovator.c
index 8043b7d..c8ffd1d 100644
--- a/arch/arm/mach-omap1/leds-innovator.c
+++ b/arch/arm/mach-omap1/leds-innovator.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/leds-innovator.c
+ * linux/arch/arm/mach-omap1/leds-innovator.c
  */
 #include <linux/config.h>
 #include <linux/init.h>
diff --git a/arch/arm/mach-omap1/leds-osk.c b/arch/arm/mach-omap1/leds-osk.c
index 4a0e8b9..2c8bda8 100644
--- a/arch/arm/mach-omap1/leds-osk.c
+++ b/arch/arm/mach-omap1/leds-osk.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/leds-osk.c
+ * linux/arch/arm/mach-omap1/leds-osk.c
  *
  * LED driver for OSK, and optionally Mistral QVGA, boards
  */
@@ -64,7 +64,7 @@
 
 static DECLARE_WORK(work, tps_work, NULL);
 
-#ifdef	CONFIG_FB_OMAP
+#ifdef	CONFIG_OMAP_OSK_MISTRAL
 
 /* For now, all system indicators require the Mistral board, since that
  * LED can be manipulated without a task context.  This LED is either red,
@@ -127,7 +127,7 @@
 		hw_led_state = 0;
 		break;
 
-#ifdef	CONFIG_FB_OMAP
+#ifdef	CONFIG_OMAP_OSK_MISTRAL
 
 	case led_timer:
 		hw_led_state ^= TIMER_LED;
@@ -144,7 +144,7 @@
 		mistral_setled();
 		break;
 
-#endif	/* CONFIG_FB_OMAP */
+#endif	/* CONFIG_OMAP_OSK_MISTRAL */
 
 	/* "green" == tps LED1 (leftmost, normally power-good)
 	 * works only with DC adapter, not on battery power!
diff --git a/arch/arm/mach-omap1/leds.c b/arch/arm/mach-omap1/leds.c
index 8ab21fe..5c6b1bb 100644
--- a/arch/arm/mach-omap1/leds.c
+++ b/arch/arm/mach-omap1/leds.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/leds.c
+ * linux/arch/arm/mach-omap1/leds.c
  *
  * OMAP LEDs dispatcher
  */
@@ -20,7 +20,9 @@
 	if (machine_is_omap_innovator())
 		leds_event = innovator_leds_event;
 
-	else if (machine_is_omap_h2() || machine_is_omap_perseus2())
+	else if (machine_is_omap_h2()
+			|| machine_is_omap_h3()
+			|| machine_is_omap_perseus2())
 		leds_event = h2p2_dbg_leds_event;
 
 	else if (machine_is_omap_osk())
@@ -30,8 +32,12 @@
 		return -1;
 
 	if (machine_is_omap_h2()
+			|| machine_is_omap_h3()
 			|| machine_is_omap_perseus2()
-			|| machine_is_omap_osk()) {
+#ifdef	CONFIG_OMAP_OSK_MISTRAL
+			|| machine_is_omap_osk()
+#endif
+			) {
 
 		/* LED1/LED2 pins can be used as GPIO (as done here), or by
 		 * the LPG (works even in deep sleep!), to drive a bicolor
diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c
index 214e5d1..40c4f7c 100644
--- a/arch/arm/mach-omap1/serial.c
+++ b/arch/arm/mach-omap1/serial.c
@@ -24,7 +24,11 @@
 
 #include <asm/arch/board.h>
 #include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
 #include <asm/arch/fpga.h>
+#ifdef CONFIG_PM
+#include <asm/arch/pm.h>
+#endif
 
 static struct clk * uart1_ck = NULL;
 static struct clk * uart2_ck = NULL;
@@ -94,7 +98,7 @@
 
 static struct platform_device serial_device = {
 	.name			= "serial8250",
-	.id			= 0,
+	.id			= PLAT8250_DEV_PLATFORM,
 	.dev			= {
 		.platform_data	= serial_platform_data,
 	},
@@ -193,6 +197,86 @@
 	}
 }
 
+#ifdef CONFIG_OMAP_SERIAL_WAKE
+
+static irqreturn_t omap_serial_wake_interrupt(int irq, void *dev_id,
+					      struct pt_regs *regs)
+{
+	/* Need to do something with serial port right after wake-up? */
+	return IRQ_HANDLED;
+}
+
+/*
+ * Reroutes serial RX lines to GPIO lines for the duration of
+ * sleep to allow waking up the device from serial port even
+ * in deep sleep.
+ */
+void omap_serial_wake_trigger(int enable)
+{
+	if (!cpu_is_omap16xx())
+		return;
+
+	if (uart1_ck != NULL) {
+		if (enable)
+			omap_cfg_reg(V14_16XX_GPIO37);
+		else
+			omap_cfg_reg(V14_16XX_UART1_RX);
+	}
+	if (uart2_ck != NULL) {
+		if (enable)
+			omap_cfg_reg(R9_16XX_GPIO18);
+		else
+			omap_cfg_reg(R9_16XX_UART2_RX);
+	}
+	if (uart3_ck != NULL) {
+		if (enable)
+			omap_cfg_reg(L14_16XX_GPIO49);
+		else
+			omap_cfg_reg(L14_16XX_UART3_RX);
+	}
+}
+
+static void __init omap_serial_set_port_wakeup(int gpio_nr)
+{
+	int ret;
+
+	ret = omap_request_gpio(gpio_nr);
+	if (ret < 0) {
+		printk(KERN_ERR "Could not request UART wake GPIO: %i\n",
+		       gpio_nr);
+		return;
+	}
+	omap_set_gpio_direction(gpio_nr, 1);
+	set_irq_type(OMAP_GPIO_IRQ(gpio_nr), IRQT_RISING);
+	ret = request_irq(OMAP_GPIO_IRQ(gpio_nr), &omap_serial_wake_interrupt,
+			  0, "serial wakeup", NULL);
+	if (ret) {
+		omap_free_gpio(gpio_nr);
+		printk(KERN_ERR "No interrupt for UART wake GPIO: %i\n",
+		       gpio_nr);
+		return;
+	}
+	enable_irq_wake(OMAP_GPIO_IRQ(gpio_nr));
+}
+
+static int __init omap_serial_wakeup_init(void)
+{
+	if (!cpu_is_omap16xx())
+		return 0;
+
+	if (uart1_ck != NULL)
+		omap_serial_set_port_wakeup(37);
+	if (uart2_ck != NULL)
+		omap_serial_set_port_wakeup(18);
+	if (uart3_ck != NULL)
+		omap_serial_set_port_wakeup(49);
+
+	return 0;
+}
+late_initcall(omap_serial_wakeup_init);
+
+#endif	/* CONFIG_OMAP_SERIAL_WAKE */
+
 static int __init omap_init(void)
 {
 	return platform_device_register(&serial_device);
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
index d540539..191a9b1 100644
--- a/arch/arm/mach-omap1/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -247,13 +247,6 @@
 #define OMAP_32K_TIMER_TCR		0x04
 
 #define OMAP_32K_TICKS_PER_HZ		(32768 / HZ)
-#if (32768 % HZ) != 0
-/* We cannot ignore modulo.
- * Potential error can be as high as several percent.
- */
-#define OMAP_32K_TICK_MODULO		(32768 % HZ)
-static unsigned modulo_count = 0; /* Counts 1/HZ units */
-#endif
 
 /*
  * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1
@@ -296,13 +289,22 @@
 }
 
 /*
- * Rounds down to nearest usec
+ * Rounds down to nearest usec. Note that this will overflow for larger values.
  */
 static inline unsigned long omap_32k_ticks_to_usecs(unsigned long ticks_32k)
 {
 	return (ticks_32k * 5*5*5*5*5*5) >> 9;
 }
 
+/*
+ * Rounds down to nearest nsec.
+ */
+static inline unsigned long long
+omap_32k_ticks_to_nsecs(unsigned long ticks_32k)
+{
+	return (unsigned long long) ticks_32k * 1000 * 5*5*5*5*5*5 >> 9;
+}
+
 static unsigned long omap_32k_last_tick = 0;
 
 /*
@@ -315,6 +317,15 @@
 }
 
 /*
+ * Returns current time from boot in nsecs. It's OK for this to wrap
+ * around for now, as it's just a relative time stamp.
+ */
+unsigned long long sched_clock(void)
+{
+	return omap_32k_ticks_to_nsecs(omap_32k_sync_timer_read());
+}
+
+/*
  * Timer interrupt for 32KHz timer. When dynamic tick is enabled, this
  * function is also called from other interrupts to remove latency
  * issues with dynamic tick. In the dynamic tick case, we need to lock
@@ -330,19 +341,6 @@
 	now = omap_32k_sync_timer_read();
 
 	while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) {
-#ifdef OMAP_32K_TICK_MODULO
-		/* Modulo addition may put omap_32k_last_tick ahead of now
-		 * and cause unwanted repetition of the while loop.
-		 */
-		if (unlikely(now - omap_32k_last_tick == ~0))
-			break;
-
-		modulo_count += OMAP_32K_TICK_MODULO;
-		if (modulo_count > HZ) {
-			++omap_32k_last_tick;
-			modulo_count -= HZ;
-		}
-#endif
 		omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
 		timer_tick(regs);
 	}
diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c
index a102686..e3587ef 100644
--- a/arch/arm/mach-rpc/riscpc.c
+++ b/arch/arm/mach-rpc/riscpc.c
@@ -140,7 +140,7 @@
 
 static struct platform_device serial_device = {
 	.name			= "serial8250",
-	.id			= 0,
+	.id			= PLAT8250_DEV_PLATFORM,
 	.dev			= {
 		.platform_data	= serial_platform_data,
 	},
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
index e918224..1a3367d 100644
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -381,7 +381,7 @@
 
 static struct platform_device bast_sio = {
 	.name			= "serial8250",
-	.id			= 0,
+	.id			= PLAT8250_DEV_PLATFORM,
 	.dev			= {
 		.platform_data	= &bast_sio_data,
 	},
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c
index 924e846..8f9ab28 100644
--- a/arch/arm/mach-s3c2410/mach-vr1000.c
+++ b/arch/arm/mach-s3c2410/mach-vr1000.c
@@ -221,7 +221,7 @@
 
 static struct platform_device serial_device = {
 	.name			= "serial8250",
-	.id			= 0,
+	.id			= PLAT8250_DEV_PLATFORM,
 	.dev			= {
 		.platform_data	= serial_platform_data,
 	},
diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c
index e737eae..946c0d1 100644
--- a/arch/arm/mach-shark/core.c
+++ b/arch/arm/mach-shark/core.c
@@ -41,7 +41,7 @@
 
 static struct platform_device serial_device = {
 	.name			= "serial8250",
-	.id			= 0,
+	.id			= PLAT8250_DEV_PLATFORM,
 	.dev			= {
 		.platform_data	= serial_platform_data,
 	},
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 191788f..b0208c9 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -16,6 +16,58 @@
 #include <asm/tlbflush.h>
 
 #ifdef CONFIG_CPU_CACHE_VIPT
+
+void flush_cache_mm(struct mm_struct *mm)
+{
+	if (cache_is_vivt()) {
+		if (cpu_isset(smp_processor_id(), mm->cpu_vm_mask))
+			__cpuc_flush_user_all();
+		return;
+	}
+
+	if (cache_is_vipt_aliasing()) {
+		asm(	"mcr	p15, 0, %0, c7, c14, 0\n"
+		"	mcr	p15, 0, %0, c7, c5, 0\n"
+		"	mcr	p15, 0, %0, c7, c10, 4"
+		    :
+		    : "r" (0)
+		    : "cc");
+	}
+}
+
+void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
+{
+	if (cache_is_vivt()) {
+		if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask))
+			__cpuc_flush_user_range(start & PAGE_MASK, PAGE_ALIGN(end),
+						vma->vm_flags);
+		return;
+	}
+
+	if (cache_is_vipt_aliasing()) {
+		asm(	"mcr	p15, 0, %0, c7, c14, 0\n"
+		"	mcr	p15, 0, %0, c7, c5, 0\n"
+		"	mcr	p15, 0, %0, c7, c10, 4"
+		    :
+		    : "r" (0)
+		    : "cc");
+	}
+}
+
+void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn)
+{
+	if (cache_is_vivt()) {
+		if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask)) {
+			unsigned long addr = user_addr & PAGE_MASK;
+			__cpuc_flush_user_range(addr, addr + PAGE_SIZE, vma->vm_flags);
+		}
+		return;
+	}
+
+	if (cache_is_vipt_aliasing())
+		flush_pfn_alias(pfn, user_addr);
+}
+
 #define ALIAS_FLUSH_START	0xffff4000
 
 #define TOP_PTE(x)	pte_offset_kernel(top_pmd, x)
diff --git a/arch/ppc/syslib/mpc10x_common.c b/arch/ppc/syslib/mpc10x_common.c
index 87065e2..3e03970 100644
--- a/arch/ppc/syslib/mpc10x_common.c
+++ b/arch/ppc/syslib/mpc10x_common.c
@@ -140,12 +140,12 @@
 	},
 	[MPC10X_UART0] = {
 		.name = "serial8250",
-		.id	= 0,
+		.id	= PLAT8250_DEV_PLATFORM,
 		.dev.platform_data = serial_plat_uart0,
 	},
 	[MPC10X_UART1] = {
 		.name = "serial8250",
-		.id	= 1,
+		.id	= PLAT8250_DEV_PLATFORM1,
 		.dev.platform_data = serial_plat_uart1,
 	},
 
diff --git a/arch/ppc/syslib/mpc83xx_devices.c b/arch/ppc/syslib/mpc83xx_devices.c
index 5aaf0e5..95b3b8a 100644
--- a/arch/ppc/syslib/mpc83xx_devices.c
+++ b/arch/ppc/syslib/mpc83xx_devices.c
@@ -165,7 +165,7 @@
 	},
 	[MPC83xx_DUART] = {
 		.name = "serial8250",
-		.id	= 0,
+		.id	= PLAT8250_DEV_PLATFORM,
 		.dev.platform_data = serial_platform_data,
 	},
 	[MPC83xx_SEC2] = {
diff --git a/arch/ppc/syslib/mpc85xx_devices.c b/arch/ppc/syslib/mpc85xx_devices.c
index 8af322d..bbc5ac0 100644
--- a/arch/ppc/syslib/mpc85xx_devices.c
+++ b/arch/ppc/syslib/mpc85xx_devices.c
@@ -282,7 +282,7 @@
 	},
 	[MPC85xx_DUART] = {
 		.name = "serial8250",
-		.id	= 0,
+		.id	= PLAT8250_DEV_PLATFORM,
 		.dev.platform_data = serial_platform_data,
 	},
 	[MPC85xx_PERFMON] = {
diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c
index d0bb68a..bfa8791c 100644
--- a/arch/ppc64/kernel/setup.c
+++ b/arch/ppc64/kernel/setup.c
@@ -1283,7 +1283,7 @@
 
 static struct platform_device serial_device = {
 	.name	= "serial8250",
-	.id	= 0,
+	.id	= PLAT8250_DEV_PLATFORM,
 	.dev	= {
 		.platform_data = serial_ports,
 	},
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 6e9da13..8334496 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -144,6 +144,22 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-i810.
 
+config I2C_PXA
+	tristate "Intel PXA2XX I2C adapter (EXPERIMENTAL)"
+	depends on I2C && EXPERIMENTAL && ARCH_PXA
+	help
+	  If you have devices in the PXA I2C bus, say yes to this option.
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-pxa.
+
+config I2C_PXA_SLAVE
+	bool "Intel PXA2XX I2C Slave comms support"
+	depends on I2C_PXA
+	help
+	  Support I2C slave mode communications on the PXA I2C bus.  This
+	  is necessary for systems where the PXA may be a target on the
+	  I2C bus.
+
 config I2C_PIIX4
 	tristate "Intel PIIX4"
 	depends on I2C && PCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 42d6d81..980b3e9 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -28,6 +28,7 @@
 obj-$(CONFIG_I2C_PCA_ISA)	+= i2c-pca-isa.o
 obj-$(CONFIG_I2C_PIIX4)		+= i2c-piix4.o
 obj-$(CONFIG_I2C_PROSAVAGE)	+= i2c-prosavage.o
+obj-$(CONFIG_I2C_PXA)		+= i2c-pxa.o
 obj-$(CONFIG_I2C_RPXLITE)	+= i2c-rpx.o
 obj-$(CONFIG_I2C_S3C2410)	+= i2c-s3c2410.o
 obj-$(CONFIG_I2C_SAVAGE4)	+= i2c-savage4.o
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
new file mode 100644
index 0000000..fdf53ce
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -0,0 +1,1022 @@
+/*
+ *  i2c_adap_pxa.c
+ *
+ *  I2C adapter for the PXA I2C bus access.
+ *
+ *  Copyright (C) 2002 Intrinsyc Software Inc.
+ *  Copyright (C) 2004-2005 Deep Blue Solutions Ltd.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  History:
+ *    Apr 2002: Initial version [CS]
+ *    Jun 2002: Properly seperated algo/adap [FB]
+ *    Jan 2003: Fixed several bugs concerning interrupt handling [Kai-Uwe Bloem]
+ *    Jan 2003: added limited signal handling [Kai-Uwe Bloem]
+ *    Sep 2004: Major rework to ensure efficient bus handling [RMK]
+ *    Dec 2004: Added support for PXA27x and slave device probing [Liam Girdwood]
+ *    Feb 2005: Rework slave mode handling [RMK]
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/i2c-pxa.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/i2c.h>
+#include <asm/arch/pxa-regs.h>
+
+struct pxa_i2c {
+	spinlock_t		lock;
+	wait_queue_head_t	wait;
+	struct i2c_msg		*msg;
+	unsigned int		msg_num;
+	unsigned int		msg_idx;
+	unsigned int		msg_ptr;
+	unsigned int		slave_addr;
+
+	struct i2c_adapter	adap;
+#ifdef CONFIG_I2C_PXA_SLAVE
+	struct i2c_slave_client *slave;
+#endif
+
+	unsigned int		irqlogidx;
+	u32			isrlog[32];
+	u32			icrlog[32];
+};
+
+/*
+ * I2C Slave mode address
+ */
+#define I2C_PXA_SLAVE_ADDR      0x1
+
+#ifdef DEBUG
+
+struct bits {
+	u32	mask;
+	const char *set;
+	const char *unset;
+};
+#define BIT(m, s, u)	{ .mask = m, .set = s, .unset = u }
+
+static inline void
+decode_bits(const char *prefix, const struct bits *bits, int num, u32 val)
+{
+	printk("%s %08x: ", prefix, val);
+	while (num--) {
+		const char *str = val & bits->mask ? bits->set : bits->unset;
+		if (str)
+			printk("%s ", str);
+		bits++;
+	}
+}
+
+static const struct bits isr_bits[] = {
+	BIT(ISR_RWM,	"RX",		"TX"),
+	BIT(ISR_ACKNAK,	"NAK",		"ACK"),
+	BIT(ISR_UB,	"Bsy",		"Rdy"),
+	BIT(ISR_IBB,	"BusBsy",	"BusRdy"),
+	BIT(ISR_SSD,	"SlaveStop",	NULL),
+	BIT(ISR_ALD,	"ALD",		NULL),
+	BIT(ISR_ITE,	"TxEmpty",	NULL),
+	BIT(ISR_IRF,	"RxFull",	NULL),
+	BIT(ISR_GCAD,	"GenCall",	NULL),
+	BIT(ISR_SAD,	"SlaveAddr",	NULL),
+	BIT(ISR_BED,	"BusErr",	NULL),
+};
+
+static void decode_ISR(unsigned int val)
+{
+	decode_bits(KERN_DEBUG "ISR", isr_bits, ARRAY_SIZE(isr_bits), val);
+	printk("\n");
+}
+
+static const struct bits icr_bits[] = {
+	BIT(ICR_START,  "START",	NULL),
+	BIT(ICR_STOP,   "STOP",		NULL),
+	BIT(ICR_ACKNAK, "ACKNAK",	NULL),
+	BIT(ICR_TB,     "TB",		NULL),
+	BIT(ICR_MA,     "MA",		NULL),
+	BIT(ICR_SCLE,   "SCLE",		"scle"),
+	BIT(ICR_IUE,    "IUE",		"iue"),
+	BIT(ICR_GCD,    "GCD",		NULL),
+	BIT(ICR_ITEIE,  "ITEIE",	NULL),
+	BIT(ICR_IRFIE,  "IRFIE",	NULL),
+	BIT(ICR_BEIE,   "BEIE",		NULL),
+	BIT(ICR_SSDIE,  "SSDIE",	NULL),
+	BIT(ICR_ALDIE,  "ALDIE",	NULL),
+	BIT(ICR_SADIE,  "SADIE",	NULL),
+	BIT(ICR_UR,     "UR",		"ur"),
+};
+
+static void decode_ICR(unsigned int val)
+{
+	decode_bits(KERN_DEBUG "ICR", icr_bits, ARRAY_SIZE(icr_bits), val);
+	printk("\n");
+}
+
+static unsigned int i2c_debug = DEBUG;
+
+static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname)
+{
+	dev_dbg(&i2c->adap.dev, "state:%s:%d: ISR=%08x, ICR=%08x, IBMR=%02x\n", fname, lno, ISR, ICR, IBMR);
+}
+
+#define show_state(i2c) i2c_pxa_show_state(i2c, __LINE__, __FUNCTION__)
+#else
+#define i2c_debug	0
+
+#define show_state(i2c) do { } while (0)
+#define decode_ISR(val) do { } while (0)
+#define decode_ICR(val) do { } while (0)
+#endif
+
+#define eedbg(lvl, x...) do { if ((lvl) < 1) { printk(KERN_DEBUG "" x); } } while(0)
+
+static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret);
+
+static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why)
+{
+	unsigned int i;
+	printk("i2c: error: %s\n", why);
+	printk("i2c: msg_num: %d msg_idx: %d msg_ptr: %d\n",
+		i2c->msg_num, i2c->msg_idx, i2c->msg_ptr);
+	printk("i2c: ICR: %08x ISR: %08x\n"
+	       "i2c: log: ", ICR, ISR);
+	for (i = 0; i < i2c->irqlogidx; i++)
+		printk("[%08x:%08x] ", i2c->isrlog[i], i2c->icrlog[i]);
+	printk("\n");
+}
+
+static inline int i2c_pxa_is_slavemode(struct pxa_i2c *i2c)
+{
+	return !(ICR & ICR_SCLE);
+}
+
+static void i2c_pxa_abort(struct pxa_i2c *i2c)
+{
+	unsigned long timeout = jiffies + HZ/4;
+
+	if (i2c_pxa_is_slavemode(i2c)) {
+		dev_dbg(&i2c->adap.dev, "%s: called in slave mode\n", __func__);
+		return;
+	}
+
+	while (time_before(jiffies, timeout) && (IBMR & 0x1) == 0) {
+		unsigned long icr = ICR;
+
+		icr &= ~ICR_START;
+		icr |= ICR_ACKNAK | ICR_STOP | ICR_TB;
+
+		ICR = icr;
+
+		show_state(i2c);
+
+		msleep(1);
+	}
+
+	ICR &= ~(ICR_MA | ICR_START | ICR_STOP);
+}
+
+static int i2c_pxa_wait_bus_not_busy(struct pxa_i2c *i2c)
+{
+	int timeout = DEF_TIMEOUT;
+
+	while (timeout-- && ISR & (ISR_IBB | ISR_UB)) {
+		if ((ISR & ISR_SAD) != 0)
+			timeout += 4;
+
+		msleep(2);
+		show_state(i2c);
+	}
+
+	if (timeout <= 0)
+		show_state(i2c);
+
+	return timeout <= 0 ? I2C_RETRY : 0;
+}
+
+static int i2c_pxa_wait_master(struct pxa_i2c *i2c)
+{
+	unsigned long timeout = jiffies + HZ*4;
+
+	while (time_before(jiffies, timeout)) {
+		if (i2c_debug > 1)
+			dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n",
+				__func__, (long)jiffies, ISR, ICR, IBMR);
+
+		if (ISR & ISR_SAD) {
+			if (i2c_debug > 0)
+				dev_dbg(&i2c->adap.dev, "%s: Slave detected\n", __func__);
+			goto out;
+		}
+
+		/* wait for unit and bus being not busy, and we also do a
+		 * quick check of the i2c lines themselves to ensure they've
+		 * gone high...
+		 */
+		if ((ISR & (ISR_UB | ISR_IBB)) == 0 && IBMR == 3) {
+			if (i2c_debug > 0)
+				dev_dbg(&i2c->adap.dev, "%s: done\n", __func__);
+			return 1;
+		}
+
+		msleep(1);
+	}
+
+	if (i2c_debug > 0)
+		dev_dbg(&i2c->adap.dev, "%s: did not free\n", __func__);
+ out:
+	return 0;
+}
+
+static int i2c_pxa_set_master(struct pxa_i2c *i2c)
+{
+	if (i2c_debug)
+		dev_dbg(&i2c->adap.dev, "setting to bus master\n");
+
+	if ((ISR & (ISR_UB | ISR_IBB)) != 0) {
+		dev_dbg(&i2c->adap.dev, "%s: unit is busy\n", __func__);
+		if (!i2c_pxa_wait_master(i2c)) {
+			dev_dbg(&i2c->adap.dev, "%s: error: unit busy\n", __func__);
+			return I2C_RETRY;
+		}
+	}
+
+	ICR |= ICR_SCLE;
+	return 0;
+}
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+static int i2c_pxa_wait_slave(struct pxa_i2c *i2c)
+{
+	unsigned long timeout = jiffies + HZ*1;
+
+	/* wait for stop */
+
+	show_state(i2c);
+
+	while (time_before(jiffies, timeout)) {
+		if (i2c_debug > 1)
+			dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n",
+				__func__, (long)jiffies, ISR, ICR, IBMR);
+
+		if ((ISR & (ISR_UB|ISR_IBB|ISR_SAD)) == ISR_SAD ||
+		    (ICR & ICR_SCLE) == 0) {
+			if (i2c_debug > 1)
+				dev_dbg(&i2c->adap.dev, "%s: done\n", __func__);
+			return 1;
+		}
+
+		msleep(1);
+	}
+
+	if (i2c_debug > 0)
+		dev_dbg(&i2c->adap.dev, "%s: did not free\n", __func__);
+	return 0;
+}
+
+/*
+ * clear the hold on the bus, and take of anything else
+ * that has been configured
+ */
+static void i2c_pxa_set_slave(struct pxa_i2c *i2c, int errcode)
+{
+	show_state(i2c);
+
+	if (errcode < 0) {
+		udelay(100);   /* simple delay */
+	} else {
+		/* we need to wait for the stop condition to end */
+
+		/* if we where in stop, then clear... */
+		if (ICR & ICR_STOP) {
+			udelay(100);
+			ICR &= ~ICR_STOP;
+		}
+
+		if (!i2c_pxa_wait_slave(i2c)) {
+			dev_err(&i2c->adap.dev, "%s: wait timedout\n",
+				__func__);
+			return;
+		}
+	}
+
+	ICR &= ~(ICR_STOP|ICR_ACKNAK|ICR_MA);
+	ICR &= ~ICR_SCLE;
+
+	if (i2c_debug) {
+		dev_dbg(&i2c->adap.dev, "ICR now %08x, ISR %08x\n", ICR, ISR);
+		decode_ICR(ICR);
+	}
+}
+#else
+#define i2c_pxa_set_slave(i2c, err)	do { } while (0)
+#endif
+
+static void i2c_pxa_reset(struct pxa_i2c *i2c)
+{
+	pr_debug("Resetting I2C Controller Unit\n");
+
+	/* abort any transfer currently under way */
+	i2c_pxa_abort(i2c);
+
+	/* reset according to 9.8 */
+	ICR = ICR_UR;
+	ISR = I2C_ISR_INIT;
+	ICR &= ~ICR_UR;
+
+	ISAR = i2c->slave_addr;
+
+	/* set control register values */
+	ICR = I2C_ICR_INIT;
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+	dev_info(&i2c->adap.dev, "Enabling slave mode\n");
+	ICR |= ICR_SADIE | ICR_ALDIE | ICR_SSDIE;
+#endif
+
+	i2c_pxa_set_slave(i2c, 0);
+
+	/* enable unit */
+	ICR |= ICR_IUE;
+	udelay(100);
+}
+
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+/*
+ * I2C EEPROM emulation.
+ */
+static struct i2c_eeprom_emu eeprom = {
+	.size = I2C_EEPROM_EMU_SIZE,
+	.watch = LIST_HEAD_INIT(eeprom.watch),
+};
+
+struct i2c_eeprom_emu *i2c_pxa_get_eeprom(void)
+{
+	return &eeprom;
+}
+
+int i2c_eeprom_emu_addwatcher(struct i2c_eeprom_emu *emu, void *data,
+			      unsigned int addr, unsigned int size,
+			      struct i2c_eeprom_emu_watcher *watcher)
+{
+	struct i2c_eeprom_emu_watch *watch;
+	unsigned long flags;
+
+	if (addr + size > emu->size)
+		return -EINVAL;
+
+	watch = kmalloc(sizeof(struct i2c_eeprom_emu_watch), GFP_KERNEL);
+	if (watch) {
+		watch->start = addr;
+		watch->end = addr + size - 1;
+		watch->ops = watcher;
+		watch->data = data;
+
+		local_irq_save(flags);
+		list_add(&watch->node, &emu->watch);
+		local_irq_restore(flags);
+	}
+
+	return watch ? 0 : -ENOMEM;
+}
+
+void i2c_eeprom_emu_delwatcher(struct i2c_eeprom_emu *emu, void *data,
+			       struct i2c_eeprom_emu_watcher *watcher)
+{
+	struct i2c_eeprom_emu_watch *watch, *n;
+	unsigned long flags;
+
+	list_for_each_entry_safe(watch, n, &emu->watch, node) {
+		if (watch->ops == watcher && watch->data == data) {
+			local_irq_save(flags);
+			list_del(&watch->node);
+			local_irq_restore(flags);
+			kfree(watch);
+		}
+	}
+}
+
+static void i2c_eeprom_emu_event(void *ptr, i2c_slave_event_t event)
+{
+	struct i2c_eeprom_emu *emu = ptr;
+
+	eedbg(3, "i2c_eeprom_emu_event: %d\n", event);
+
+	switch (event) {
+	case I2C_SLAVE_EVENT_START_WRITE:
+		emu->seen_start = 1;
+		eedbg(2, "i2c_eeprom: write initiated\n");
+		break;
+
+	case I2C_SLAVE_EVENT_START_READ:
+		emu->seen_start = 0;
+		eedbg(2, "i2c_eeprom: read initiated\n");
+		break;
+
+	case I2C_SLAVE_EVENT_STOP:
+		emu->seen_start = 0;
+		eedbg(2, "i2c_eeprom: received stop\n");
+		break;
+
+	default:
+		eedbg(0, "i2c_eeprom: unhandled event\n");
+		break;
+	}
+}
+
+static int i2c_eeprom_emu_read(void *ptr)
+{
+	struct i2c_eeprom_emu *emu = ptr;
+	int ret;
+
+	ret = emu->bytes[emu->ptr];
+	emu->ptr = (emu->ptr + 1) % emu->size;
+
+	return ret;
+}
+
+static void i2c_eeprom_emu_write(void *ptr, unsigned int val)
+{
+	struct i2c_eeprom_emu *emu = ptr;
+	struct i2c_eeprom_emu_watch *watch;
+
+	if (emu->seen_start != 0) {
+		eedbg(2, "i2c_eeprom_emu_write: setting ptr %02x\n", val);
+		emu->ptr = val;
+		emu->seen_start = 0;
+		return;
+	}
+
+	emu->bytes[emu->ptr] = val;
+
+	eedbg(1, "i2c_eeprom_emu_write: ptr=0x%02x, val=0x%02x\n",
+	      emu->ptr, val);
+
+	list_for_each_entry(watch, &emu->watch, node) {
+		if (!watch->ops || !watch->ops->write)
+			continue;
+		if (watch->start <= emu->ptr && watch->end >= emu->ptr)
+			watch->ops->write(watch->data, emu->ptr, val);
+	}
+
+	emu->ptr = (emu->ptr + 1) % emu->size;
+}
+
+struct i2c_slave_client eeprom_client = {
+	.data	= &eeprom,
+	.event	= i2c_eeprom_emu_event,
+	.read	= i2c_eeprom_emu_read,
+	.write	= i2c_eeprom_emu_write
+};
+
+/*
+ * PXA I2C Slave mode
+ */
+
+static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr)
+{
+	if (isr & ISR_BED) {
+		/* what should we do here? */
+	} else {
+		int ret = i2c->slave->read(i2c->slave->data);
+
+		IDBR = ret;
+		ICR |= ICR_TB;   /* allow next byte */
+	}
+}
+
+static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr)
+{
+	unsigned int byte = IDBR;
+
+	if (i2c->slave != NULL)
+		i2c->slave->write(i2c->slave->data, byte);
+
+	ICR |= ICR_TB;
+}
+
+static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
+{
+	int timeout;
+
+	if (i2c_debug > 0)
+		dev_dbg(&i2c->adap.dev, "SAD, mode is slave-%cx\n",
+		       (isr & ISR_RWM) ? 'r' : 't');
+
+	if (i2c->slave != NULL)
+		i2c->slave->event(i2c->slave->data,
+				 (isr & ISR_RWM) ? I2C_SLAVE_EVENT_START_READ : I2C_SLAVE_EVENT_START_WRITE);
+
+	/*
+	 * slave could interrupt in the middle of us generating a
+	 * start condition... if this happens, we'd better back off
+	 * and stop holding the poor thing up
+	 */
+	ICR &= ~(ICR_START|ICR_STOP);
+	ICR |= ICR_TB;
+
+	timeout = 0x10000;
+
+	while (1) {
+		if ((IBMR & 2) == 2)
+			break;
+
+		timeout--;
+
+		if (timeout <= 0) {
+			dev_err(&i2c->adap.dev, "timeout waiting for SCL high\n");
+			break;
+		}
+	}
+
+	ICR &= ~ICR_SCLE;
+}
+
+static void i2c_pxa_slave_stop(struct pxa_i2c *i2c)
+{
+	if (i2c_debug > 2)
+		dev_dbg(&i2c->adap.dev, "ISR: SSD (Slave Stop)\n");
+
+	if (i2c->slave != NULL)
+		i2c->slave->event(i2c->slave->data, I2C_SLAVE_EVENT_STOP);
+
+	if (i2c_debug > 2)
+		dev_dbg(&i2c->adap.dev, "ISR: SSD (Slave Stop) acked\n");
+
+	/*
+	 * If we have a master-mode message waiting,
+	 * kick it off now that the slave has completed.
+	 */
+	if (i2c->msg)
+		i2c_pxa_master_complete(i2c, I2C_RETRY);
+}
+#else
+static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr)
+{
+	if (isr & ISR_BED) {
+		/* what should we do here? */
+	} else {
+		IDBR = 0;
+		ICR |= ICR_TB;
+	}
+}
+
+static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr)
+{
+	ICR |= ICR_TB | ICR_ACKNAK;
+}
+
+static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
+{
+	int timeout;
+
+	/*
+	 * slave could interrupt in the middle of us generating a
+	 * start condition... if this happens, we'd better back off
+	 * and stop holding the poor thing up
+	 */
+	ICR &= ~(ICR_START|ICR_STOP);
+	ICR |= ICR_TB | ICR_ACKNAK;
+
+	timeout = 0x10000;
+
+	while (1) {
+		if ((IBMR & 2) == 2)
+			break;
+
+		timeout--;
+
+		if (timeout <= 0) {
+			dev_err(&i2c->adap.dev, "timeout waiting for SCL high\n");
+			break;
+		}
+	}
+
+	ICR &= ~ICR_SCLE;
+}
+
+static void i2c_pxa_slave_stop(struct pxa_i2c *i2c)
+{
+	if (i2c->msg)
+		i2c_pxa_master_complete(i2c, I2C_RETRY);
+}
+#endif
+
+/*
+ * PXA I2C Master mode
+ */
+
+static inline unsigned int i2c_pxa_addr_byte(struct i2c_msg *msg)
+{
+	unsigned int addr = (msg->addr & 0x7f) << 1;
+
+	if (msg->flags & I2C_M_RD)
+		addr |= 1;
+
+	return addr;
+}
+
+static inline void i2c_pxa_start_message(struct pxa_i2c *i2c)
+{
+	u32 icr;
+
+	/*
+	 * Step 1: target slave address into IDBR
+	 */
+	IDBR = i2c_pxa_addr_byte(i2c->msg);
+
+	/*
+	 * Step 2: initiate the write.
+	 */
+	icr = ICR & ~(ICR_STOP | ICR_ALDIE);
+	ICR = icr | ICR_START | ICR_TB;
+}
+
+/*
+ * We are protected by the adapter bus semaphore.
+ */
+static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num)
+{
+	long timeout;
+	int ret;
+
+	/*
+	 * Wait for the bus to become free.
+	 */
+	ret = i2c_pxa_wait_bus_not_busy(i2c);
+	if (ret) {
+		dev_err(&i2c->adap.dev, "i2c_pxa: timeout waiting for bus free\n");
+		goto out;
+	}
+
+	/*
+	 * Set master mode.
+	 */
+	ret = i2c_pxa_set_master(i2c);
+	if (ret) {
+		dev_err(&i2c->adap.dev, "i2c_pxa_set_master: error %d\n", ret);
+		goto out;
+	}
+
+	spin_lock_irq(&i2c->lock);
+
+	i2c->msg = msg;
+	i2c->msg_num = num;
+	i2c->msg_idx = 0;
+	i2c->msg_ptr = 0;
+	i2c->irqlogidx = 0;
+
+	i2c_pxa_start_message(i2c);
+
+	spin_unlock_irq(&i2c->lock);
+
+	/*
+	 * The rest of the processing occurs in the interrupt handler.
+	 */
+	timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
+
+	/*
+	 * We place the return code in i2c->msg_idx.
+	 */
+	ret = i2c->msg_idx;
+
+	if (timeout == 0)
+		i2c_pxa_scream_blue_murder(i2c, "timeout");
+
+ out:
+	return ret;
+}
+
+/*
+ * i2c_pxa_master_complete - complete the message and wake up.
+ */
+static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret)
+{
+	i2c->msg_ptr = 0;
+	i2c->msg = NULL;
+	i2c->msg_idx ++;
+	i2c->msg_num = 0;
+	if (ret)
+		i2c->msg_idx = ret;
+	wake_up(&i2c->wait);
+}
+
+static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr)
+{
+	u32 icr = ICR & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB);
+
+ again:
+	/*
+	 * If ISR_ALD is set, we lost arbitration.
+	 */
+	if (isr & ISR_ALD) {
+		/*
+		 * Do we need to do anything here?  The PXA docs
+		 * are vague about what happens.
+		 */
+		i2c_pxa_scream_blue_murder(i2c, "ALD set");
+
+		/*
+		 * We ignore this error.  We seem to see spurious ALDs
+		 * for seemingly no reason.  If we handle them as I think
+		 * they should, we end up causing an I2C error, which
+		 * is painful for some systems.
+		 */
+		return; /* ignore */
+	}
+
+	if (isr & ISR_BED) {
+		int ret = BUS_ERROR;
+
+		/*
+		 * I2C bus error - either the device NAK'd us, or
+		 * something more serious happened.  If we were NAK'd
+		 * on the initial address phase, we can retry.
+		 */
+		if (isr & ISR_ACKNAK) {
+			if (i2c->msg_ptr == 0 && i2c->msg_idx == 0)
+				ret = I2C_RETRY;
+			else
+				ret = XFER_NAKED;
+		}
+		i2c_pxa_master_complete(i2c, ret);
+	} else if (isr & ISR_RWM) {
+		/*
+		 * Read mode.  We have just sent the address byte, and
+		 * now we must initiate the transfer.
+		 */
+		if (i2c->msg_ptr == i2c->msg->len - 1 &&
+		    i2c->msg_idx == i2c->msg_num - 1)
+			icr |= ICR_STOP | ICR_ACKNAK;
+
+		icr |= ICR_ALDIE | ICR_TB;
+	} else if (i2c->msg_ptr < i2c->msg->len) {
+		/*
+		 * Write mode.  Write the next data byte.
+		 */
+		IDBR = i2c->msg->buf[i2c->msg_ptr++];
+
+		icr |= ICR_ALDIE | ICR_TB;
+
+		/*
+		 * If this is the last byte of the last message, send
+		 * a STOP.
+		 */
+		if (i2c->msg_ptr == i2c->msg->len &&
+		    i2c->msg_idx == i2c->msg_num - 1)
+			icr |= ICR_STOP;
+	} else if (i2c->msg_idx < i2c->msg_num - 1) {
+		/*
+		 * Next segment of the message.
+		 */
+		i2c->msg_ptr = 0;
+		i2c->msg_idx ++;
+		i2c->msg++;
+
+		/*
+		 * If we aren't doing a repeated start and address,
+		 * go back and try to send the next byte.  Note that
+		 * we do not support switching the R/W direction here.
+		 */
+		if (i2c->msg->flags & I2C_M_NOSTART)
+			goto again;
+
+		/*
+		 * Write the next address.
+		 */
+		IDBR = i2c_pxa_addr_byte(i2c->msg);
+
+		/*
+		 * And trigger a repeated start, and send the byte.
+		 */
+		icr &= ~ICR_ALDIE;
+		icr |= ICR_START | ICR_TB;
+	} else {
+		if (i2c->msg->len == 0) {
+			/*
+			 * Device probes have a message length of zero
+			 * and need the bus to be reset before it can
+			 * be used again.
+			 */
+			i2c_pxa_reset(i2c);
+		}
+		i2c_pxa_master_complete(i2c, 0);
+	}
+
+	i2c->icrlog[i2c->irqlogidx-1] = icr;
+
+	ICR = icr;
+	show_state(i2c);
+}
+
+static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr)
+{
+	u32 icr = ICR & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB);
+
+	/*
+	 * Read the byte.
+	 */
+	i2c->msg->buf[i2c->msg_ptr++] = IDBR;
+
+	if (i2c->msg_ptr < i2c->msg->len) {
+		/*
+		 * If this is the last byte of the last
+		 * message, send a STOP.
+		 */
+		if (i2c->msg_ptr == i2c->msg->len - 1)
+			icr |= ICR_STOP | ICR_ACKNAK;
+
+		icr |= ICR_ALDIE | ICR_TB;
+	} else {
+		i2c_pxa_master_complete(i2c, 0);
+	}
+
+	i2c->icrlog[i2c->irqlogidx-1] = icr;
+
+	ICR = icr;
+}
+
+static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pxa_i2c *i2c = dev_id;
+	u32 isr = ISR;
+
+	if (i2c_debug > 2 && 0) {
+		dev_dbg(&i2c->adap.dev, "%s: ISR=%08x, ICR=%08x, IBMR=%02x\n",
+			__func__, isr, ICR, IBMR);
+		decode_ISR(isr);
+	}
+
+	if (i2c->irqlogidx < sizeof(i2c->isrlog)/sizeof(u32))
+		i2c->isrlog[i2c->irqlogidx++] = isr;
+
+	show_state(i2c);
+
+	/*
+	 * Always clear all pending IRQs.
+	 */
+	ISR = isr & (ISR_SSD|ISR_ALD|ISR_ITE|ISR_IRF|ISR_SAD|ISR_BED);
+
+	if (isr & ISR_SAD)
+		i2c_pxa_slave_start(i2c, isr);
+	if (isr & ISR_SSD)
+		i2c_pxa_slave_stop(i2c);
+
+	if (i2c_pxa_is_slavemode(i2c)) {
+		if (isr & ISR_ITE)
+			i2c_pxa_slave_txempty(i2c, isr);
+		if (isr & ISR_IRF)
+			i2c_pxa_slave_rxfull(i2c, isr);
+	} else if (i2c->msg) {
+		if (isr & ISR_ITE)
+			i2c_pxa_irq_txempty(i2c, isr);
+		if (isr & ISR_IRF)
+			i2c_pxa_irq_rxfull(i2c, isr);
+	} else {
+		i2c_pxa_scream_blue_murder(i2c, "spurious irq");
+	}
+
+	return IRQ_HANDLED;
+}
+
+
+static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	struct pxa_i2c *i2c = adap->algo_data;
+	int ret, i;
+
+	for (i = adap->retries; i >= 0; i--) {
+		ret = i2c_pxa_do_xfer(i2c, msgs, num);
+		if (ret != I2C_RETRY)
+			goto out;
+
+		if (i2c_debug)
+			dev_dbg(&adap->dev, "Retrying transmission\n");
+		udelay(100);
+	}
+	i2c_pxa_scream_blue_murder(i2c, "exhausted retries");
+	ret = -EREMOTEIO;
+ out:
+	i2c_pxa_set_slave(i2c, ret);
+	return ret;
+}
+
+static struct i2c_algorithm i2c_pxa_algorithm = {
+	.name		= "PXA-I2C-Algorithm",
+	.id		= I2C_ALGO_PXA,
+	.master_xfer	= i2c_pxa_xfer,
+};
+
+static struct pxa_i2c i2c_pxa = {
+	.lock	= SPIN_LOCK_UNLOCKED,
+	.wait	= __WAIT_QUEUE_HEAD_INITIALIZER(i2c_pxa.wait),
+	.adap	= {
+		.name		= "pxa2xx-i2c",
+		.id		= I2C_ALGO_PXA,
+		.algo		= &i2c_pxa_algorithm,
+		.retries	= 5,
+	},
+};
+
+static int i2c_pxa_probe(struct device *dev)
+{
+	struct pxa_i2c *i2c = &i2c_pxa;
+	struct i2c_pxa_platform_data *plat = dev->platform_data;
+	int ret;
+
+#ifdef CONFIG_PXA27x
+	pxa_gpio_mode(GPIO117_I2CSCL_MD);
+	pxa_gpio_mode(GPIO118_I2CSDA_MD);
+	udelay(100);
+#endif
+
+	i2c->slave_addr = I2C_PXA_SLAVE_ADDR;
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+	i2c->slave = &eeprom_client;
+	if (plat) {
+		i2c->slave_addr = plat->slave_addr;
+		if (plat->slave)
+			i2c->slave = plat->slave;
+	}
+#endif
+
+	pxa_set_cken(CKEN14_I2C, 1);
+	ret = request_irq(IRQ_I2C, i2c_pxa_handler, SA_INTERRUPT,
+			  "pxa2xx-i2c", i2c);
+	if (ret)
+		goto out;
+
+	i2c_pxa_reset(i2c);
+
+	i2c->adap.algo_data = i2c;
+	i2c->adap.dev.parent = dev;
+
+	ret = i2c_add_adapter(&i2c->adap);
+	if (ret < 0) {
+		printk(KERN_INFO "I2C: Failed to add bus\n");
+		goto err_irq;
+	}
+
+	dev_set_drvdata(dev, i2c);
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+	printk(KERN_INFO "I2C: %s: PXA I2C adapter, slave address %d\n",
+	       i2c->adap.dev.bus_id, i2c->slave_addr);
+#else
+	printk(KERN_INFO "I2C: %s: PXA I2C adapter\n",
+	       i2c->adap.dev.bus_id);
+#endif
+	return 0;
+
+ err_irq:
+	free_irq(IRQ_I2C, i2c);
+ out:
+	return ret;
+}
+
+static int i2c_pxa_remove(struct device *dev)
+{
+	struct pxa_i2c *i2c = dev_get_drvdata(dev);
+
+	dev_set_drvdata(dev, NULL);
+
+	i2c_del_adapter(&i2c->adap);
+	free_irq(IRQ_I2C, i2c);
+	pxa_set_cken(CKEN14_I2C, 0);
+
+	return 0;
+}
+
+static struct device_driver i2c_pxa_driver = {
+	.name		= "pxa2xx-i2c",
+	.bus		= &platform_bus_type,
+	.probe		= i2c_pxa_probe,
+	.remove		= i2c_pxa_remove,
+};
+
+static int __init i2c_adap_pxa_init(void)
+{
+	return driver_register(&i2c_pxa_driver);
+}
+
+static void i2c_adap_pxa_exit(void)
+{
+	return driver_unregister(&i2c_pxa_driver);
+}
+
+module_init(i2c_adap_pxa_init);
+module_exit(i2c_adap_pxa_exit);
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 0a117c6..ceae379 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -1079,13 +1079,17 @@
 /**
  *	mmc_detect_change - process change of state on a MMC socket
  *	@host: host which changed state.
+ *	@delay: optional delay to wait before detection (jiffies)
  *
  *	All we know is that card(s) have been inserted or removed
  *	from the socket(s).  We don't know which socket or cards.
  */
-void mmc_detect_change(struct mmc_host *host)
+void mmc_detect_change(struct mmc_host *host, unsigned long delay)
 {
-	schedule_work(&host->detect);
+	if (delay)
+		schedule_delayed_work(&host->detect, delay);
+	else
+		schedule_work(&host->detect);
 }
 
 EXPORT_SYMBOL(mmc_detect_change);
@@ -1189,7 +1193,7 @@
 	ret = mmc_add_host_sysfs(host);
 	if (ret == 0) {
 		mmc_power_off(host);
-		mmc_detect_change(host);
+		mmc_detect_change(host, 0);
 	}
 
 	return ret;
@@ -1259,7 +1263,7 @@
  */
 int mmc_resume_host(struct mmc_host *host)
 {
-	mmc_detect_change(host);
+	mmc_detect_change(host, 0);
 
 	return 0;
 }
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
index 716c4ef..91c7484 100644
--- a/drivers/mmc/mmci.c
+++ b/drivers/mmc/mmci.c
@@ -442,7 +442,7 @@
 
 	status = host->plat->status(mmc_dev(host->mmc));
 	if (status ^ host->oldstat)
-		mmc_detect_change(host->mmc);
+		mmc_detect_change(host->mmc, 0);
 
 	host->oldstat = status;
 	mod_timer(&host->timer, jiffies + HZ);
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
index e99a53b..b53af57 100644
--- a/drivers/mmc/pxamci.c
+++ b/drivers/mmc/pxamci.c
@@ -423,7 +423,9 @@
 
 static irqreturn_t pxamci_detect_irq(int irq, void *devid, struct pt_regs *regs)
 {
-	mmc_detect_change(devid);
+	struct pxamci_host *host = mmc_priv(devid);
+
+	mmc_detect_change(devid, host->pdata->detect_delay);
 	return IRQ_HANDLED;
 }
 
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
index dec01d3..a62c86f 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -1122,7 +1122,7 @@
 	
 	DBG("Executing card detection\n");
 	
-	mmc_detect_change(host->mmc);	
+	mmc_detect_change(host->mmc, 0);	
 }
 
 /*
@@ -1198,7 +1198,7 @@
 		 */
 		spin_unlock(&host->lock);
 
-		mmc_detect_change(host->mmc);
+		mmc_detect_change(host->mmc, 0);
 	}
 	else
 		spin_unlock(&host->lock);
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 55a72c7..83598e3 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -14,8 +14,8 @@
 
 #define DRV_MODULE_NAME		"bnx2"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"1.2.20"
-#define DRV_MODULE_RELDATE	"August 22, 2005"
+#define DRV_MODULE_VERSION	"1.2.21"
+#define DRV_MODULE_RELDATE	"September 7, 2005"
 
 #define RUN_AT(x) (jiffies + (x))
 
@@ -1533,6 +1533,7 @@
 	struct net_device *dev = dev_instance;
 	struct bnx2 *bp = dev->priv;
 
+	prefetch(bp->status_blk);
 	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
 		BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
 		BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
@@ -1558,7 +1559,7 @@
 	 * When using MSI, the MSI message will always complete after
 	 * the status block write.
 	 */
-	if ((bp->status_blk->status_idx == bp->last_status_idx) ||
+	if ((bp->status_blk->status_idx == bp->last_status_idx) &&
 	    (REG_RD(bp, BNX2_PCICFG_MISC_STATUS) &
 	     BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
 		return IRQ_NONE;
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index 9ad3f57..62857b6 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -50,6 +50,7 @@
 #endif
 #include <linux/workqueue.h>
 #include <linux/crc32.h>
+#include <linux/prefetch.h>
 
 /* Hardware data structures and register definitions automatically
  * generated from RTL code. Do not modify.
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 30a0a3d..5b65e20 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -2536,7 +2536,7 @@
 		goto out;
 
 	serial8250_isa_devs = platform_device_register_simple("serial8250",
-							      -1, NULL, 0);
+					 PLAT8250_DEV_LEGACY, NULL, 0);
 	if (IS_ERR(serial8250_isa_devs)) {
 		ret = PTR_ERR(serial8250_isa_devs);
 		goto unreg;
diff --git a/drivers/serial/8250_accent.c b/drivers/serial/8250_accent.c
index 1f2c276..9c10262 100644
--- a/drivers/serial/8250_accent.c
+++ b/drivers/serial/8250_accent.c
@@ -29,7 +29,7 @@
 
 static struct platform_device accent_device = {
 	.name			= "serial8250",
-	.id			= 2,
+	.id			= PLAT8250_DEV_ACCENT,
 	.dev			= {
 		.platform_data	= accent_data,
 	},
diff --git a/drivers/serial/8250_boca.c b/drivers/serial/8250_boca.c
index 465c9ea..3bfe0f7 100644
--- a/drivers/serial/8250_boca.c
+++ b/drivers/serial/8250_boca.c
@@ -43,7 +43,7 @@
 
 static struct platform_device boca_device = {
 	.name			= "serial8250",
-	.id			= 3,
+	.id			= PLAT8250_DEV_BOCA,
 	.dev			= {
 		.platform_data	= boca_data,
 	},
diff --git a/drivers/serial/8250_fourport.c b/drivers/serial/8250_fourport.c
index e9b4d90..6375d68 100644
--- a/drivers/serial/8250_fourport.c
+++ b/drivers/serial/8250_fourport.c
@@ -35,7 +35,7 @@
 
 static struct platform_device fourport_device = {
 	.name			= "serial8250",
-	.id			= 1,
+	.id			= PLAT8250_DEV_FOURPORT,
 	.dev			= {
 		.platform_data	= fourport_data,
 	},
diff --git a/drivers/serial/8250_hub6.c b/drivers/serial/8250_hub6.c
index 77f396f..daf569c 100644
--- a/drivers/serial/8250_hub6.c
+++ b/drivers/serial/8250_hub6.c
@@ -40,7 +40,7 @@
 
 static struct platform_device hub6_device = {
 	.name			= "serial8250",
-	.id			= 4,
+	.id			= PLAT8250_DEV_HUB6,
 	.dev			= {
 		.platform_data	= hub6_data,
 	},
diff --git a/drivers/serial/8250_mca.c b/drivers/serial/8250_mca.c
index f0c40d6..ac20525 100644
--- a/drivers/serial/8250_mca.c
+++ b/drivers/serial/8250_mca.c
@@ -44,7 +44,7 @@
 
 static struct platform_device mca_device = {
 	.name			= "serial8250",
-	.id			= 5,
+	.id			= PLAT8250_DEV_MCA,
 	.dev			= {
 		.platform_data	= mca_data,
 	},
diff --git a/include/asm-arm/arch-pxa/hardware.h b/include/asm-arm/arch-pxa/hardware.h
index 72b04d8..cf35721 100644
--- a/include/asm-arm/arch-pxa/hardware.h
+++ b/include/asm-arm/arch-pxa/hardware.h
@@ -44,24 +44,12 @@
 
 #ifndef __ASSEMBLY__
 
-#if 0
-# define __REG(x)	(*((volatile u32 *)io_p2v(x)))
-#else
-/*
- * This __REG() version gives the same results as the one above,  except
- * that we are fooling gcc somehow so it generates far better and smaller
- * assembly code for access to contigous registers.  It's a shame that gcc
- * doesn't guess this by itself.
- */
-#include <asm/types.h>
-typedef struct { volatile u32 offset[4096]; } __regbase;
-# define __REGP(x)	((__regbase *)((x)&~4095))->offset[((x)&4095)>>2]
-# define __REG(x)	__REGP(io_p2v(x))
-#endif
+# define __REG(x)	(*((volatile unsigned long *)io_p2v(x)))
 
 /* With indexed regs we don't want to feed the index through io_p2v()
    especially if it is a variable, otherwise horrible code will result. */
-# define __REG2(x,y)     (*(volatile u32 *)((u32)&__REG(x) + (y)))
+# define __REG2(x,y)	\
+	(*(volatile unsigned long *)((unsigned long)&__REG(x) + (y)))
 
 # define __PREG(x)	(io_v2p((u32)&(x)))
 
diff --git a/include/asm-arm/arch-pxa/i2c.h b/include/asm-arm/arch-pxa/i2c.h
new file mode 100644
index 0000000..46ec224
--- /dev/null
+++ b/include/asm-arm/arch-pxa/i2c.h
@@ -0,0 +1,70 @@
+/*
+ *  i2c_pxa.h
+ *
+ *  Copyright (C) 2002 Intrinsyc 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.
+ *
+ */
+#ifndef _I2C_PXA_H_
+#define _I2C_PXA_H_
+
+#if 0
+#define DEF_TIMEOUT             3
+#else
+/* need a longer timeout if we're dealing with the fact we may well be
+ * looking at a multi-master environment
+*/
+#define DEF_TIMEOUT             32
+#endif
+
+#define BUS_ERROR               (-EREMOTEIO)
+#define XFER_NAKED              (-ECONNREFUSED)
+#define I2C_RETRY               (-2000) /* an error has occurred retry transmit */
+
+/* ICR initialize bit values
+*
+*  15. FM       0 (100 Khz operation)
+*  14. UR       0 (No unit reset)
+*  13. SADIE    0 (Disables the unit from interrupting on slave addresses
+*                                       matching its slave address)
+*  12. ALDIE    0 (Disables the unit from interrupt when it loses arbitration
+*                                       in master mode)
+*  11. SSDIE    0 (Disables interrupts from a slave stop detected, in slave mode)
+*  10. BEIE     1 (Enable interrupts from detected bus errors, no ACK sent)
+*  9.  IRFIE    1 (Enable interrupts from full buffer received)
+*  8.  ITEIE    1 (Enables the I2C unit to interrupt when transmit buffer empty)
+*  7.  GCD      1 (Disables i2c unit response to general call messages as a slave)
+*  6.  IUE      0 (Disable unit until we change settings)
+*  5.  SCLE     1 (Enables the i2c clock output for master mode (drives SCL)
+*  4.  MA       0 (Only send stop with the ICR stop bit)
+*  3.  TB       0 (We are not transmitting a byte initially)
+*  2.  ACKNAK   0 (Send an ACK after the unit receives a byte)
+*  1.  STOP     0 (Do not send a STOP)
+*  0.  START    0 (Do not send a START)
+*
+*/
+#define I2C_ICR_INIT	(ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE)
+
+/* I2C status register init values
+ *
+ * 10. BED      1 (Clear bus error detected)
+ * 9.  SAD      1 (Clear slave address detected)
+ * 7.  IRF      1 (Clear IDBR Receive Full)
+ * 6.  ITE      1 (Clear IDBR Transmit Empty)
+ * 5.  ALD      1 (Clear Arbitration Loss Detected)
+ * 4.  SSD      1 (Clear Slave Stop Detected)
+ */
+#define I2C_ISR_INIT	0x7FF  /* status register init */
+
+struct i2c_slave_client;
+
+struct i2c_pxa_platform_data {
+	unsigned int		slave_addr;
+	struct i2c_slave_client	*slave;
+};
+
+extern void pxa_set_i2c_info(struct i2c_pxa_platform_data *info);
+#endif
diff --git a/include/asm-arm/arch-pxa/mmc.h b/include/asm-arm/arch-pxa/mmc.h
index 9718063..88c17dd 100644
--- a/include/asm-arm/arch-pxa/mmc.h
+++ b/include/asm-arm/arch-pxa/mmc.h
@@ -9,6 +9,7 @@
 
 struct pxamci_platform_data {
 	unsigned int ocr_mask;			/* available voltages */
+	unsigned long detect_delay;		/* delay in jiffies before detecting cards after interrupt */
 	int (*init)(struct device *, irqreturn_t (*)(int, void *, struct pt_regs *), void *);
 	int (*get_ro)(struct device *);
 	void (*setpower)(struct device *, unsigned int);
diff --git a/include/asm-arm/arch-sa1100/hardware.h b/include/asm-arm/arch-sa1100/hardware.h
index 10c62db..19c3b1e 100644
--- a/include/asm-arm/arch-sa1100/hardware.h
+++ b/include/asm-arm/arch-sa1100/hardware.h
@@ -49,23 +49,9 @@
    ( (((x)&0x00ffffff) | (((x)&(0x30000000>>VIO_SHIFT))<<VIO_SHIFT)) + PIO_START )
 
 #ifndef __ASSEMBLY__
-#include <asm/types.h>
 
-#if 0
-# define __REG(x)	(*((volatile u32 *)io_p2v(x)))
-#else
-/*
- * This __REG() version gives the same results as the one above,  except
- * that we are fooling gcc somehow so it generates far better and smaller
- * assembly code for access to contigous registers.  It's a shame that gcc
- * doesn't guess this by itself.
- */
-typedef struct { volatile u32 offset[4096]; } __regbase;
-# define __REGP(x)	((__regbase *)((x)&~4095))->offset[((x)&4095)>>2]
-# define __REG(x)	__REGP(io_p2v(x))
-#endif
-
-# define __PREG(x)	(io_v2p((u32)&(x)))
+# define __REG(x)	(*((volatile unsigned long *)io_p2v(x)))
+# define __PREG(x)	(io_v2p((unsigned long)&(x)))
 
 #else
 
diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h
index 035cdcf..e81baff 100644
--- a/include/asm-arm/cacheflush.h
+++ b/include/asm-arm/cacheflush.h
@@ -256,7 +256,7 @@
  * Convert calls to our calling convention.
  */
 #define flush_cache_all()		__cpuc_flush_kern_all()
-
+#ifndef CONFIG_CPU_CACHE_VIPT
 static inline void flush_cache_mm(struct mm_struct *mm)
 {
 	if (cpu_isset(smp_processor_id(), mm->cpu_vm_mask))
@@ -279,6 +279,11 @@
 		__cpuc_flush_user_range(addr, addr + PAGE_SIZE, vma->vm_flags);
 	}
 }
+#else
+extern void flush_cache_mm(struct mm_struct *mm);
+extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
+extern void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn);
+#endif
 
 /*
  * flush_cache_user_range is used when we want to ensure that the
diff --git a/include/linux/i2c-pxa.h b/include/linux/i2c-pxa.h
new file mode 100644
index 0000000..5f3eaf8
--- /dev/null
+++ b/include/linux/i2c-pxa.h
@@ -0,0 +1,48 @@
+#ifndef _LINUX_I2C_ALGO_PXA_H
+#define _LINUX_I2C_ALGO_PXA_H
+
+struct i2c_eeprom_emu_watcher {
+	void (*write)(void *, unsigned int addr, unsigned char newval);
+};
+
+struct i2c_eeprom_emu_watch {
+	struct list_head node;
+	unsigned int start;
+	unsigned int end;
+	struct i2c_eeprom_emu_watcher *ops;
+	void *data;
+};
+
+#define I2C_EEPROM_EMU_SIZE (256)
+
+struct i2c_eeprom_emu {
+	unsigned int size;
+	unsigned int ptr;
+	unsigned int seen_start;
+	struct list_head watch;
+
+	unsigned char bytes[I2C_EEPROM_EMU_SIZE];
+};
+
+typedef enum i2c_slave_event_e {
+	I2C_SLAVE_EVENT_START_READ,
+	I2C_SLAVE_EVENT_START_WRITE,
+	I2C_SLAVE_EVENT_STOP
+} i2c_slave_event_t;
+
+struct i2c_slave_client {
+	void *data;
+	void (*event)(void *ptr, i2c_slave_event_t event);
+	int  (*read) (void *ptr);
+	void (*write)(void *ptr, unsigned int val);
+};
+
+extern int i2c_eeprom_emu_addwatcher(struct i2c_eeprom_emu *, void *data,
+				     unsigned int addr, unsigned int size,
+				     struct i2c_eeprom_emu_watcher *);
+
+extern void i2c_eeprom_emu_delwatcher(struct i2c_eeprom_emu *, void *data, struct i2c_eeprom_emu_watcher *watcher);
+
+extern struct i2c_eeprom_emu *i2c_pxa_get_eeprom(void);
+
+#endif /* _LINUX_I2C_ALGO_PXA_H */
diff --git a/include/linux/in6.h b/include/linux/in6.h
index dcf5720..bd32b79 100644
--- a/include/linux/in6.h
+++ b/include/linux/in6.h
@@ -148,13 +148,13 @@
  */
 
 #define IPV6_ADDRFORM		1
-#define IPV6_PKTINFO		2
-#define IPV6_HOPOPTS		3
-#define IPV6_DSTOPTS		4
-#define IPV6_RTHDR		5
-#define IPV6_PKTOPTIONS		6
+#define IPV6_2292PKTINFO	2
+#define IPV6_2292HOPOPTS	3
+#define IPV6_2292DSTOPTS	4
+#define IPV6_2292RTHDR		5
+#define IPV6_2292PKTOPTIONS	6
 #define IPV6_CHECKSUM		7
-#define IPV6_HOPLIMIT		8
+#define IPV6_2292HOPLIMIT	8
 #define IPV6_NEXTHOP		9
 #define IPV6_AUTHHDR		10	/* obsolete */
 #define IPV6_FLOWINFO		11
@@ -198,4 +198,28 @@
  * MCAST_MSFILTER		48
  */
 
+/* RFC3542 advanced socket options (50-67) */
+#define IPV6_RECVPKTINFO	50
+#define IPV6_PKTINFO		51
+#if 0
+#define IPV6_RECVPATHMTU	52
+#define IPV6_PATHMTU		53
+#define IPV6_DONTFRAG		54
+#define IPV6_USE_MIN_MTU	55
+#endif
+#define IPV6_RECVHOPOPTS	56
+#define IPV6_HOPOPTS		57
+#if 0
+#define IPV6_RECVRTHDRDSTOPTS	58	/* Unused, see net/ipv6/datagram.c */
+#endif
+#define IPV6_RTHDRDSTOPTS	59
+#define IPV6_RECVRTHDR		60
+#define IPV6_RTHDR		61
+#define IPV6_RECVDSTOPTS	62
+#define IPV6_DSTOPTS		63
+#define IPV6_RECVHOPLIMIT	64
+#define IPV6_HOPLIMIT		65
+#define IPV6_RECVTCLASS		66
+#define IPV6_TCLASS		67
+
 #endif
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 3c7dbc6..6c5f7b3 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -189,6 +189,7 @@
 	__u16			dst0;
 	__u16			srcrt;
 	__u16			dst1;
+	__u16			lastopt;
 };
 
 #define IP6CB(skb)	((struct inet6_skb_parm*)((skb)->cb))
@@ -234,14 +235,20 @@
 	/* pktoption flags */
 	union {
 		struct {
-			__u8	srcrt:2,
+			__u16	srcrt:2,
+				osrcrt:2,
 			        rxinfo:1,
+			        rxoinfo:1,
 				rxhlim:1,
+				rxohlim:1,
 				hopopts:1,
+				ohopopts:1,
 				dstopts:1,
-                                rxflow:1;
+				odstopts:1,
+                                rxflow:1,
+				rxtclass:1;
 		} bits;
-		__u8		all;
+		__u16		all;
 	} rxopt;
 
 	/* sockopt flags */
@@ -250,6 +257,7 @@
 	                        sndflow:1,
 				pmtudisc:2,
 				ipv6only:1;
+	__u8			tclass;
 
 	__u32			dst_cookie;
 
@@ -263,6 +271,7 @@
 		struct ipv6_txoptions *opt;
 		struct rt6_info	*rt;
 		int hop_limit;
+		int tclass;
 	} cork;
 };
 
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 6014160..c1f021e 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -109,6 +109,8 @@
 	struct mmc_card		*card_selected;	/* the selected MMC card */
 
 	struct work_struct	detect;
+
+	unsigned long		private[0] ____cacheline_aligned;
 };
 
 extern struct mmc_host *mmc_alloc_host(int extra, struct device *);
@@ -116,14 +118,18 @@
 extern void mmc_remove_host(struct mmc_host *);
 extern void mmc_free_host(struct mmc_host *);
 
-#define mmc_priv(x)	((void *)((x) + 1))
+static inline void *mmc_priv(struct mmc_host *host)
+{
+	return (void *)host->private;
+}
+
 #define mmc_dev(x)	((x)->dev)
 #define mmc_hostname(x)	((x)->class_dev.class_id)
 
 extern int mmc_suspend_host(struct mmc_host *, pm_message_t);
 extern int mmc_resume_host(struct mmc_host *);
 
-extern void mmc_detect_change(struct mmc_host *);
+extern void mmc_detect_change(struct mmc_host *, unsigned long delay);
 extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
 
 #endif
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index d8a023d..317a979 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -30,6 +30,21 @@
 };
 
 /*
+ * Allocate 8250 platform device IDs.  Nothing is implied by
+ * the numbering here, except for the legacy entry being -1.
+ */
+enum {
+	PLAT8250_DEV_LEGACY = -1,
+	PLAT8250_DEV_PLATFORM,
+	PLAT8250_DEV_PLATFORM1,
+	PLAT8250_DEV_FOURPORT,
+	PLAT8250_DEV_ACCENT,
+	PLAT8250_DEV_BOCA,
+	PLAT8250_DEV_HUB6,
+	PLAT8250_DEV_MCA,
+};
+
+/*
  * This should be used by drivers which want to register
  * their own 8250 ports without registering their own
  * platform device.  Using these will make your driver
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 9b12fe7..27db8da 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -401,6 +401,9 @@
 #endif
 	return 0;
 }
+#ifndef SUPPORT_SYSRQ
+#define uart_handle_sysrq_char(port,ch,regs) uart_handle_sysrq_char(port, 0, NULL)
+#endif
 
 /*
  * We do the SysRQ and SAK checking like this...
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index da7da9c..2741c0c 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1167,7 +1167,7 @@
 
 static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len)
 {
-	if (len >= skb->len)
+	if (likely(len >= skb->len))
 		return 0;
 	if (skb->ip_summed == CHECKSUM_HW)
 		skb->ip_summed = CHECKSUM_NONE;
diff --git a/include/net/ax25.h b/include/net/ax25.h
index 364b046..227d337 100644
--- a/include/net/ax25.h
+++ b/include/net/ax25.h
@@ -258,7 +258,7 @@
 /* ax25_addr.c */
 extern ax25_address null_ax25_address;
 extern char *ax2asc(char *buf, ax25_address *);
-extern ax25_address *asc2ax(char *);
+extern void asc2ax(ax25_address *addr, char *callsign);
 extern int  ax25cmp(ax25_address *, ax25_address *);
 extern int  ax25digicmp(ax25_digi *, ax25_digi *);
 extern unsigned char *ax25_addr_parse(unsigned char *, int, ax25_address *, ax25_address *, ax25_digi *, int *, int *);
diff --git a/include/net/compat.h b/include/net/compat.h
index 482eb82..290bab4 100644
--- a/include/net/compat.h
+++ b/include/net/compat.h
@@ -33,7 +33,8 @@
 extern asmlinkage long compat_sys_recvmsg(int,struct compat_msghdr __user *,unsigned);
 extern asmlinkage long compat_sys_getsockopt(int, int, int, char __user *, int __user *);
 extern int put_cmsg_compat(struct msghdr*, int, int, int, void *);
-extern int cmsghdr_from_user_compat_to_kern(struct msghdr *, struct sock *, unsigned char *,
-		int);
+
+struct sock;
+extern int cmsghdr_from_user_compat_to_kern(struct msghdr *, struct sock *, unsigned char *, int);
 
 #endif /* NET_COMPAT_H */
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 3203eaf..65ec866 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -233,6 +233,10 @@
 extern int			ipv6_parse_hopopts(struct sk_buff *skb, int);
 
 extern struct ipv6_txoptions *  ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt);
+extern struct ipv6_txoptions *	ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
+						   int newtype,
+						   struct ipv6_opt_hdr __user *newopt,
+						   int newoptlen);
 
 extern int ip6_frag_nqueues;
 extern atomic_t ip6_frag_mem;
@@ -373,6 +377,7 @@
 						int length,
 						int transhdrlen,
 		      				int hlimit,
+		      				int tclass,
 						struct ipv6_txoptions *opt,
 						struct flowi *fl,
 						struct rt6_info *rt,
diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h
index 8b075ab..4e86f2d 100644
--- a/include/net/transp_v6.h
+++ b/include/net/transp_v6.h
@@ -37,7 +37,7 @@
 extern int			datagram_send_ctl(struct msghdr *msg,
 						  struct flowi *fl,
 						  struct ipv6_txoptions *opt,
-						  int *hlimit);
+						  int *hlimit, int *tclass);
 
 #define		LOOPBACK4_IPV6		__constant_htonl(0x7f000006)
 
diff --git a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c
index dca179d..0164a15 100644
--- a/net/ax25/ax25_addr.c
+++ b/net/ax25/ax25_addr.c
@@ -67,37 +67,34 @@
 /*
  *	ascii -> ax25 conversion
  */
-ax25_address *asc2ax(char *callsign)
+void asc2ax(ax25_address *addr, char *callsign)
 {
-	static ax25_address addr;
 	char *s;
 	int n;
 
 	for (s = callsign, n = 0; n < 6; n++) {
 		if (*s != '\0' && *s != '-')
-			addr.ax25_call[n] = *s++;
+			addr->ax25_call[n] = *s++;
 		else
-			addr.ax25_call[n] = ' ';
-		addr.ax25_call[n] <<= 1;
-		addr.ax25_call[n] &= 0xFE;
+			addr->ax25_call[n] = ' ';
+		addr->ax25_call[n] <<= 1;
+		addr->ax25_call[n] &= 0xFE;
 	}
 
 	if (*s++ == '\0') {
-		addr.ax25_call[6] = 0x00;
-		return &addr;
+		addr->ax25_call[6] = 0x00;
+		return;
 	}
 
-	addr.ax25_call[6] = *s++ - '0';
+	addr->ax25_call[6] = *s++ - '0';
 
 	if (*s != '\0') {
-		addr.ax25_call[6] *= 10;
-		addr.ax25_call[6] += *s++ - '0';
+		addr->ax25_call[6] *= 10;
+		addr->ax25_call[6] += *s++ - '0';
 	}
 
-	addr.ax25_call[6] <<= 1;
-	addr.ax25_call[6] &= 0x1E;
-
-	return &addr;
+	addr->ax25_call[6] <<= 1;
+	addr->ax25_call[6] &= 0x1E;
 }
 
 /*
diff --git a/net/ieee80211/Kconfig b/net/ieee80211/Kconfig
index 58ed431..91b16fb 100644
--- a/net/ieee80211/Kconfig
+++ b/net/ieee80211/Kconfig
@@ -1,6 +1,5 @@
 config IEEE80211
 	tristate "Generic IEEE 802.11 Networking Stack"
-	select NET_RADIO
 	---help---
 	This option enables the hardware independent IEEE 802.11
 	networking stack.
diff --git a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
index 2b5cf9c..bb72466 100644
--- a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
+++ b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
@@ -104,12 +104,28 @@
 static struct ip_conntrack_helper helper = {
 	.name			= "netbios-ns",
 	.tuple = {
-		.src.u.udp.port	= __constant_htons(137),
-		.dst.protonum	= IPPROTO_UDP,
+		.src = {
+			.u = {
+				.udp = {
+					.port	= __constant_htons(137),
+				}
+			}
+		},
+		.dst = {
+			.protonum	= IPPROTO_UDP,
+		},
 	},
 	.mask = {
-		.src.u.udp.port	= 0xFFFF,
-		.dst.protonum	= 0xFF,
+		.src = {
+			.u = {
+				.udp = {
+					.port	= 0xFFFF,
+				}
+			}
+		},
+		.dst = {
+			.protonum	= 0xFF,
+		},
 	},
 	.max_expected		= 1,
 	.me			= THIS_MODULE,
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index f115a84..f057025 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -92,10 +92,7 @@
 	fl.fl_ip_sport = tcph->dest;
 	fl.fl_ip_dport = tcph->source;
 
-	if (xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0)) {
-		dst_release(&rt->u.dst);
-		rt = NULL;
-	}
+	xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0);
 
 	return rt;
 }
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 8c0b14e..8549f26 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1760,6 +1760,7 @@
 		goto cleanup;
 	}
 
+	atomic_set(&rth->u.dst.__refcnt, 1);
 	rth->u.dst.flags= DST_HOST;
 #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
 	if (res->fi->fib_nhs > 1)
@@ -1820,7 +1821,6 @@
 	err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, &rth);
 	if (err)
 		return err;
-	atomic_set(&rth->u.dst.__refcnt, 1);
 
 	/* put it into the cache */
 	hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos);
@@ -1834,8 +1834,8 @@
 				   u32 daddr, u32 saddr, u32 tos)
 {
 #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
-	struct rtable* rth = NULL;
-	unsigned char hop, hopcount, lasthop;
+	struct rtable* rth = NULL, *rtres;
+	unsigned char hop, hopcount;
 	int err = -EINVAL;
 	unsigned int hash;
 
@@ -1844,8 +1844,6 @@
 	else
 		hopcount = 1;
 
-	lasthop = hopcount - 1;
-
 	/* distinguish between multipath and singlepath */
 	if (hopcount < 2)
 		return ip_mkroute_input_def(skb, res, fl, in_dev, daddr,
@@ -1855,6 +1853,10 @@
 	for (hop = 0; hop < hopcount; hop++) {
 		res->nh_sel = hop;
 
+		/* put reference to previous result */
+		if (hop)
+			ip_rt_put(rtres);
+
 		/* create a routing cache entry */
 		err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos,
 				      &rth);
@@ -1863,7 +1865,7 @@
 
 		/* put it into the cache */
 		hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos);
-		err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
+		err = rt_intern_hash(hash, rth, &rtres);
 		if (err)
 			return err;
 
@@ -1873,13 +1875,8 @@
 				     FIB_RES_NETMASK(*res),
 				     res->prefixlen,
 				     &FIB_RES_NH(*res));
-
-		/* only for the last hop the reference count is handled
-		 * outside
-		 */
-		if (hop == lasthop)
-			atomic_set(&(skb->dst->__refcnt), 1);
 	}
+	skb->dst = &rtres->u.dst;
 	return err;
 #else /* CONFIG_IP_ROUTE_MULTIPATH_CACHED  */
 	return ip_mkroute_input_def(skb, res, fl, in_dev, daddr, saddr, tos);
@@ -2208,6 +2205,7 @@
 		goto cleanup;
 	}		
 
+	atomic_set(&rth->u.dst.__refcnt, 1);
 	rth->u.dst.flags= DST_HOST;
 #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
 	if (res->fi) {
@@ -2290,8 +2288,6 @@
 	if (err == 0) {
 		u32 tos = RT_FL_TOS(oldflp);
 
-		atomic_set(&rth->u.dst.__refcnt, 1);
-		
 		hash = rt_hash_code(oldflp->fl4_dst, 
 				    oldflp->fl4_src ^ (oldflp->oif << 5), tos);
 		err = rt_intern_hash(hash, rth, rp);
@@ -2326,6 +2322,10 @@
 			dev2nexthop = FIB_RES_DEV(*res);
 			dev_hold(dev2nexthop);
 
+			/* put reference to previous result */
+			if (hop)
+				ip_rt_put(*rp);
+
 			err = __mkroute_output(&rth, res, fl, oldflp,
 					       dev2nexthop, flags);
 
@@ -2350,7 +2350,6 @@
 			if (err != 0)
 				return err;
 		}
-		atomic_set(&(*rp)->u.dst.__refcnt, 1);
 		return err;
 	} else {
 		return ip_mkroute_output_def(rp, res, fl, oldflp, dev_out,
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 6094db5..15e1134 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -499,7 +499,7 @@
 	/* If this packet has been sent out already, we must
 	 * adjust the various packet counters.
 	 */
-	if (after(tp->snd_nxt, TCP_SKB_CB(buff)->end_seq)) {
+	if (!before(tp->snd_nxt, TCP_SKB_CB(buff)->end_seq)) {
 		int diff = old_factor - tcp_skb_pcount(skb) -
 			tcp_skb_pcount(buff);
 
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index e5beca7..e0bd101 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1141,7 +1141,7 @@
 	if (ulen > len || ulen < sizeof(*uh))
 		goto short_packet;
 
-	if (pskb_trim(skb, ulen))
+	if (pskb_trim_rcsum(skb, ulen))
 		goto short_packet;
 
 	if (udp_checksum_init(skb, uh, ulen, saddr, daddr) < 0)
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 01468fa..cc51840 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -175,10 +175,8 @@
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
-		dst_release(dst);
+	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
 		goto out;
-	}
 
 	/* source address lookup done in ip6_dst_lookup */
 
@@ -390,32 +388,101 @@
 		put_cmsg(msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
 	}
 
+	if (np->rxopt.bits.rxtclass) {
+		int tclass = (ntohl(*(u32 *)skb->nh.ipv6h) >> 20) & 0xff;
+		put_cmsg(msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass);
+	}
+
 	if (np->rxopt.bits.rxflow && (*(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK)) {
 		u32 flowinfo = *(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK;
 		put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo);
 	}
+
+	/* HbH is allowed only once */
 	if (np->rxopt.bits.hopopts && opt->hop) {
 		u8 *ptr = skb->nh.raw + opt->hop;
 		put_cmsg(msg, SOL_IPV6, IPV6_HOPOPTS, (ptr[1]+1)<<3, ptr);
 	}
-	if (np->rxopt.bits.dstopts && opt->dst0) {
+
+	if (opt->lastopt &&
+	    (np->rxopt.bits.dstopts || np->rxopt.bits.srcrt)) {
+		/*
+		 * Silly enough, but we need to reparse in order to
+		 * report extension headers (except for HbH)
+		 * in order.
+		 *
+		 * Also note that IPV6_RECVRTHDRDSTOPTS is NOT 
+		 * (and WILL NOT be) defined because
+		 * IPV6_RECVDSTOPTS is more generic. --yoshfuji
+		 */
+		unsigned int off = sizeof(struct ipv6hdr);
+		u8 nexthdr = skb->nh.ipv6h->nexthdr;
+
+		while (off <= opt->lastopt) {
+			unsigned len;
+			u8 *ptr = skb->nh.raw + off;
+
+			switch(nexthdr) {
+			case IPPROTO_DSTOPTS:
+				nexthdr = ptr[0];
+				len = (ptr[1] + 1) << 3;
+				if (np->rxopt.bits.dstopts)
+					put_cmsg(msg, SOL_IPV6, IPV6_DSTOPTS, len, ptr);
+				break;
+			case IPPROTO_ROUTING:
+				nexthdr = ptr[0];
+				len = (ptr[1] + 1) << 3;
+				if (np->rxopt.bits.srcrt)
+					put_cmsg(msg, SOL_IPV6, IPV6_RTHDR, len, ptr);
+				break;
+			case IPPROTO_AH:
+				nexthdr = ptr[0];
+				len = (ptr[1] + 1) << 2;
+				break;
+			default:
+				nexthdr = ptr[0];
+				len = (ptr[1] + 1) << 3;
+				break;
+			}
+
+			off += len;
+		}
+	}
+
+	/* socket options in old style */
+	if (np->rxopt.bits.rxoinfo) {
+		struct in6_pktinfo src_info;
+
+		src_info.ipi6_ifindex = opt->iif;
+		ipv6_addr_copy(&src_info.ipi6_addr, &skb->nh.ipv6h->daddr);
+		put_cmsg(msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);
+	}
+	if (np->rxopt.bits.rxohlim) {
+		int hlim = skb->nh.ipv6h->hop_limit;
+		put_cmsg(msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim);
+	}
+	if (np->rxopt.bits.ohopopts && opt->hop) {
+		u8 *ptr = skb->nh.raw + opt->hop;
+		put_cmsg(msg, SOL_IPV6, IPV6_2292HOPOPTS, (ptr[1]+1)<<3, ptr);
+	}
+	if (np->rxopt.bits.odstopts && opt->dst0) {
 		u8 *ptr = skb->nh.raw + opt->dst0;
-		put_cmsg(msg, SOL_IPV6, IPV6_DSTOPTS, (ptr[1]+1)<<3, ptr);
+		put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr);
 	}
-	if (np->rxopt.bits.srcrt && opt->srcrt) {
+	if (np->rxopt.bits.osrcrt && opt->srcrt) {
 		struct ipv6_rt_hdr *rthdr = (struct ipv6_rt_hdr *)(skb->nh.raw + opt->srcrt);
-		put_cmsg(msg, SOL_IPV6, IPV6_RTHDR, (rthdr->hdrlen+1) << 3, rthdr);
+		put_cmsg(msg, SOL_IPV6, IPV6_2292RTHDR, (rthdr->hdrlen+1) << 3, rthdr);
 	}
-	if (np->rxopt.bits.dstopts && opt->dst1) {
+	if (np->rxopt.bits.odstopts && opt->dst1) {
 		u8 *ptr = skb->nh.raw + opt->dst1;
-		put_cmsg(msg, SOL_IPV6, IPV6_DSTOPTS, (ptr[1]+1)<<3, ptr);
+		put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr);
 	}
 	return 0;
 }
 
 int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
 		      struct ipv6_txoptions *opt,
-		      int *hlimit)
+		      int *hlimit, int *tclass)
 {
 	struct in6_pktinfo *src_info;
 	struct cmsghdr *cmsg;
@@ -438,6 +505,7 @@
 
 		switch (cmsg->cmsg_type) {
  		case IPV6_PKTINFO:
+ 		case IPV6_2292PKTINFO:
  			if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct in6_pktinfo))) {
 				err = -EINVAL;
 				goto exit_f;
@@ -492,6 +560,7 @@
 			fl->fl6_flowlabel = IPV6_FLOWINFO_MASK & *(u32 *)CMSG_DATA(cmsg);
 			break;
 
+		case IPV6_2292HOPOPTS:
 		case IPV6_HOPOPTS:
                         if (opt->hopopt || cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) {
 				err = -EINVAL;
@@ -512,7 +581,7 @@
 			opt->hopopt = hdr;
 			break;
 
-		case IPV6_DSTOPTS:
+		case IPV6_2292DSTOPTS:
                         if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) {
 				err = -EINVAL;
 				goto exit_f;
@@ -536,6 +605,33 @@
 			opt->dst1opt = hdr;
 			break;
 
+		case IPV6_DSTOPTS:
+		case IPV6_RTHDRDSTOPTS:
+			if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) {
+				err = -EINVAL;
+				goto exit_f;
+			}
+
+			hdr = (struct ipv6_opt_hdr *)CMSG_DATA(cmsg);
+			len = ((hdr->hdrlen + 1) << 3);
+			if (cmsg->cmsg_len < CMSG_LEN(len)) {
+				err = -EINVAL;
+				goto exit_f;
+			}
+			if (!capable(CAP_NET_RAW)) {
+				err = -EPERM;
+				goto exit_f;
+			}
+			if (cmsg->cmsg_type == IPV6_DSTOPTS) {
+				opt->opt_flen += len;
+				opt->dst1opt = hdr;
+			} else {
+				opt->opt_nflen += len;
+				opt->dst0opt = hdr;
+			}
+			break;
+
+		case IPV6_2292RTHDR:
 		case IPV6_RTHDR:
                         if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_rt_hdr))) {
 				err = -EINVAL;
@@ -568,7 +664,7 @@
 			opt->opt_nflen += len;
 			opt->srcrt = rthdr;
 
-			if (opt->dst1opt) {
+			if (cmsg->cmsg_type == IPV6_2292RTHDR && opt->dst1opt) {
 				int dsthdrlen = ((opt->dst1opt->hdrlen+1)<<3);
 
 				opt->opt_nflen += dsthdrlen;
@@ -579,6 +675,7 @@
 
 			break;
 
+		case IPV6_2292HOPLIMIT:
 		case IPV6_HOPLIMIT:
 			if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) {
 				err = -EINVAL;
@@ -588,6 +685,24 @@
 			*hlimit = *(int *)CMSG_DATA(cmsg);
 			break;
 
+		case IPV6_TCLASS:
+		    {
+			int tc;
+
+			err = -EINVAL;
+			if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) {
+				goto exit_f;
+			}
+
+			tc = *(int *)CMSG_DATA(cmsg);
+			if (tc < 0 || tc > 0xff)
+				goto exit_f;
+
+			err = 0;
+			*tclass = tc;
+
+			break;
+		    }
 		default:
 			LIMIT_NETDEBUG(KERN_DEBUG "invalid cmsg type: %d\n",
 			               cmsg->cmsg_type);
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 5be6da2..4712272 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -164,6 +164,7 @@
 		return -1;
 	}
 
+	opt->lastopt = skb->h.raw - skb->nh.raw;
 	opt->dst1 = skb->h.raw - skb->nh.raw;
 
 	if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
@@ -243,6 +244,7 @@
 
 looped_back:
 	if (hdr->segments_left == 0) {
+		opt->lastopt = skb->h.raw - skb->nh.raw;
 		opt->srcrt = skb->h.raw - skb->nh.raw;
 		skb->h.raw += (hdr->hdrlen + 1) << 3;
 		opt->dst0 = opt->dst1;
@@ -459,11 +461,10 @@
 		IP6_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS);
 		goto drop;
 	}
-	if (pkt_len + sizeof(struct ipv6hdr) < skb->len) {
-		__pskb_trim(skb, pkt_len + sizeof(struct ipv6hdr));
-		if (skb->ip_summed == CHECKSUM_HW)
-			skb->ip_summed = CHECKSUM_NONE;
-	}
+
+	if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr)))
+		goto drop;
+
 	return 1;
 
 drop:
@@ -539,10 +540,15 @@
 			  u8 *proto,
 			  struct in6_addr **daddr)
 {
-	if (opt->srcrt)
+	if (opt->srcrt) {
 		ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
-	if (opt->dst0opt)
-		ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
+		/*
+		 * IPV6_RTHDRDSTOPTS is ignored
+		 * unless IPV6_RTHDR is set (RFC3542).
+		 */
+		if (opt->dst0opt)
+			ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
+	}
 	if (opt->hopopt)
 		ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
 }
@@ -573,3 +579,97 @@
 	}
 	return opt2;
 }
+
+static int ipv6_renew_option(void *ohdr,
+			     struct ipv6_opt_hdr __user *newopt, int newoptlen,
+			     int inherit,
+			     struct ipv6_opt_hdr **hdr,
+			     char **p)
+{
+	if (inherit) {
+		if (ohdr) {
+			memcpy(*p, ohdr, ipv6_optlen((struct ipv6_opt_hdr *)ohdr));
+			*hdr = (struct ipv6_opt_hdr *)*p;
+			*p += CMSG_ALIGN(ipv6_optlen(*(struct ipv6_opt_hdr **)hdr));
+		}
+	} else {
+		if (newopt) {
+			if (copy_from_user(*p, newopt, newoptlen))
+				return -EFAULT;
+			*hdr = (struct ipv6_opt_hdr *)*p;
+			if (ipv6_optlen(*(struct ipv6_opt_hdr **)hdr) > newoptlen)
+				return -EINVAL;
+			*p += CMSG_ALIGN(newoptlen);
+		}
+	}
+	return 0;
+}
+
+struct ipv6_txoptions *
+ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
+		   int newtype,
+		   struct ipv6_opt_hdr __user *newopt, int newoptlen)
+{
+	int tot_len = 0;
+	char *p;
+	struct ipv6_txoptions *opt2;
+	int err;
+
+	if (newtype != IPV6_HOPOPTS && opt->hopopt)
+		tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt));
+	if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt)
+		tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt));
+	if (newtype != IPV6_RTHDR && opt->srcrt)
+		tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt));
+	if (newtype != IPV6_DSTOPTS && opt->dst1opt)
+		tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt));
+	if (newopt && newoptlen)
+		tot_len += CMSG_ALIGN(newoptlen);
+
+	if (!tot_len)
+		return NULL;
+
+	opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);
+	if (!opt2)
+		return ERR_PTR(-ENOBUFS);
+
+	memset(opt2, 0, tot_len);
+
+	opt2->tot_len = tot_len;
+	p = (char *)(opt2 + 1);
+
+	err = ipv6_renew_option(opt->hopopt, newopt, newoptlen,
+				newtype != IPV6_HOPOPTS,
+				&opt2->hopopt, &p);
+	if (err)
+		goto out;
+
+	err = ipv6_renew_option(opt->dst0opt, newopt, newoptlen,
+				newtype != IPV6_RTHDRDSTOPTS,
+				&opt2->dst0opt, &p);
+	if (err)
+		goto out;
+
+	err = ipv6_renew_option(opt->srcrt, newopt, newoptlen,
+				newtype != IPV6_RTHDR,
+				(struct ipv6_opt_hdr **)opt2->srcrt, &p);
+	if (err)
+		goto out;
+
+	err = ipv6_renew_option(opt->dst1opt, newopt, newoptlen,
+				newtype != IPV6_DSTOPTS,
+				&opt2->dst1opt, &p);
+	if (err)
+		goto out;
+
+	opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) +
+			  (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) +
+			  (opt2->srcrt ? ipv6_optlen(opt2->srcrt) : 0);
+	opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0);
+
+	return opt2;
+out:
+	sock_kfree_s(sk, p, tot_len);
+	return ERR_PTR(err);
+}
+
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index fa8f1bb..b7185fb 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -287,7 +287,7 @@
 	int iif = 0;
 	int addr_type = 0;
 	int len;
-	int hlimit;
+	int hlimit, tclass;
 	int err = 0;
 
 	if ((u8*)hdr < skb->head || (u8*)(hdr+1) > skb->tail)
@@ -374,7 +374,7 @@
 	if (err)
 		goto out;
 	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
-		goto out_dst_release;
+		goto out;
 
 	if (ipv6_addr_is_multicast(&fl.fl6_dst))
 		hlimit = np->mcast_hops;
@@ -385,6 +385,10 @@
 	if (hlimit < 0)
 		hlimit = ipv6_get_hoplimit(dst->dev);
 
+	tclass = np->cork.tclass;
+	if (tclass < 0)
+		tclass = 0;
+
 	msg.skb = skb;
 	msg.offset = skb->nh.raw - skb->data;
 
@@ -400,7 +404,7 @@
 	err = ip6_append_data(sk, icmpv6_getfrag, &msg,
 			      len + sizeof(struct icmp6hdr),
 			      sizeof(struct icmp6hdr),
-			      hlimit, NULL, &fl, (struct rt6_info*)dst,
+			      hlimit, tclass, NULL, &fl, (struct rt6_info*)dst,
 			      MSG_DONTWAIT);
 	if (err) {
 		ip6_flush_pending_frames(sk);
@@ -434,6 +438,7 @@
 	struct dst_entry *dst;
 	int err = 0;
 	int hlimit;
+	int tclass;
 
 	saddr = &skb->nh.ipv6h->daddr;
 
@@ -464,7 +469,7 @@
 	if (err)
 		goto out;
 	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
-		goto out_dst_release;
+		goto out;
 
 	if (ipv6_addr_is_multicast(&fl.fl6_dst))
 		hlimit = np->mcast_hops;
@@ -475,13 +480,17 @@
 	if (hlimit < 0)
 		hlimit = ipv6_get_hoplimit(dst->dev);
 
+	tclass = np->cork.tclass;
+	if (tclass < 0)
+		tclass = 0;
+
 	idev = in6_dev_get(skb->dev);
 
 	msg.skb = skb;
 	msg.offset = 0;
 
 	err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr),
-				sizeof(struct icmp6hdr), hlimit, NULL, &fl,
+				sizeof(struct icmp6hdr), hlimit, tclass, NULL, &fl,
 				(struct rt6_info*)dst, MSG_DONTWAIT);
 
 	if (err) {
@@ -496,7 +505,6 @@
 out_put: 
 	if (likely(idev != NULL))
 		in6_dev_put(idev);
-out_dst_release:
 	dst_release(dst);
 out: 
 	icmpv6_xmit_unlock();
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index b6c73da..a7db762 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -225,16 +225,20 @@
 					 struct ip6_flowlabel * fl,
 					 struct ipv6_txoptions * fopt)
 {
-	struct ipv6_txoptions * fl_opt = fl->opt;
+	struct ipv6_txoptions * fl_opt = fl ? fl->opt : NULL;
 
-	if (fopt == NULL || fopt->opt_flen == 0)
-		return fl_opt;
+	if (fopt == NULL || fopt->opt_flen == 0) {
+		if (!fl_opt || !fl_opt->dst0opt || fl_opt->srcrt)
+			return fl_opt;
+	}
 
 	if (fl_opt != NULL) {
 		opt_space->hopopt = fl_opt->hopopt;
-		opt_space->dst0opt = fl_opt->dst0opt;
+		opt_space->dst0opt = fl_opt->srcrt ? fl_opt->dst0opt : NULL;
 		opt_space->srcrt = fl_opt->srcrt;
 		opt_space->opt_nflen = fl_opt->opt_nflen;
+		if (fl_opt->dst0opt && !fl_opt->srcrt)
+			opt_space->opt_nflen -= ipv6_optlen(fl_opt->dst0opt);
 	} else {
 		if (fopt->opt_nflen == 0)
 			return fopt;
@@ -310,7 +314,7 @@
 		msg.msg_control = (void*)(fl->opt+1);
 		flowi.oif = 0;
 
-		err = datagram_send_ctl(&msg, &flowi, fl->opt, &junk);
+		err = datagram_send_ctl(&msg, &flowi, fl->opt, &junk, &junk);
 		if (err)
 			goto done;
 		err = -EINVAL;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 01ef94f..2f589f2 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -166,7 +166,7 @@
 	struct ipv6hdr *hdr;
 	u8  proto = fl->proto;
 	int seg_len = skb->len;
-	int hlimit;
+	int hlimit, tclass;
 	u32 mtu;
 
 	if (opt) {
@@ -202,7 +202,6 @@
 	 *	Fill in the IPv6 header
 	 */
 
-	*(u32*)hdr = htonl(0x60000000) | fl->fl6_flowlabel;
 	hlimit = -1;
 	if (np)
 		hlimit = np->hop_limit;
@@ -211,6 +210,14 @@
 	if (hlimit < 0)
 		hlimit = ipv6_get_hoplimit(dst->dev);
 
+	tclass = -1;
+	if (np)
+		tclass = np->tclass;
+	if (tclass < 0)
+		tclass = 0;
+
+	*(u32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl->fl6_flowlabel;
+
 	hdr->payload_len = htons(seg_len);
 	hdr->nexthdr = proto;
 	hdr->hop_limit = hlimit;
@@ -762,10 +769,11 @@
 	return err;
 }
 
-int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb),
-		    void *from, int length, int transhdrlen,
-		    int hlimit, struct ipv6_txoptions *opt, struct flowi *fl, struct rt6_info *rt,
-		    unsigned int flags)
+int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
+	int offset, int len, int odd, struct sk_buff *skb),
+	void *from, int length, int transhdrlen,
+	int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi *fl,
+	struct rt6_info *rt, unsigned int flags)
 {
 	struct inet_sock *inet = inet_sk(sk);
 	struct ipv6_pinfo *np = inet6_sk(sk);
@@ -803,6 +811,7 @@
 		np->cork.rt = rt;
 		inet->cork.fl = *fl;
 		np->cork.hop_limit = hlimit;
+		np->cork.tclass = tclass;
 		inet->cork.fragsize = mtu = dst_mtu(rt->u.dst.path);
 		if (dst_allfrag(rt->u.dst.path))
 			inet->cork.flags |= IPCORK_ALLFRAG;
@@ -1084,7 +1093,8 @@
 
 	skb->nh.ipv6h = hdr = (struct ipv6hdr*) skb_push(skb, sizeof(struct ipv6hdr));
 	
-	*(u32*)hdr = fl->fl6_flowlabel | htonl(0x60000000);
+	*(u32*)hdr = fl->fl6_flowlabel |
+		     htonl(0x60000000 | ((int)np->cork.tclass << 20));
 
 	if (skb->len <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN)
 		hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 0961372..cf94372 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -673,11 +673,12 @@
 
 	if ((dst = ip6_tnl_dst_check(t)) != NULL)
 		dst_hold(dst);
-	else
+	else {
 		dst = ip6_route_output(NULL, &fl);
 
-	if (dst->error || xfrm_lookup(&dst, &fl, NULL, 0) < 0)
-		goto tx_err_link_failure;
+		if (dst->error || xfrm_lookup(&dst, &fl, NULL, 0) < 0)
+			goto tx_err_link_failure;
+	}
 
 	tdev = dst->dev;
 
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 76466af..8567873 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -210,39 +210,139 @@
 		retv = 0;
 		break;
 
-	case IPV6_PKTINFO:
+	case IPV6_RECVPKTINFO:
 		np->rxopt.bits.rxinfo = valbool;
 		retv = 0;
 		break;
+		
+	case IPV6_2292PKTINFO:
+		np->rxopt.bits.rxoinfo = valbool;
+		retv = 0;
+		break;
 
-	case IPV6_HOPLIMIT:
+	case IPV6_RECVHOPLIMIT:
 		np->rxopt.bits.rxhlim = valbool;
 		retv = 0;
 		break;
 
-	case IPV6_RTHDR:
+	case IPV6_2292HOPLIMIT:
+		np->rxopt.bits.rxohlim = valbool;
+		retv = 0;
+		break;
+
+	case IPV6_RECVRTHDR:
 		if (val < 0 || val > 2)
 			goto e_inval;
 		np->rxopt.bits.srcrt = val;
 		retv = 0;
 		break;
 
-	case IPV6_HOPOPTS:
+	case IPV6_2292RTHDR:
+		if (val < 0 || val > 2)
+			goto e_inval;
+		np->rxopt.bits.osrcrt = val;
+		retv = 0;
+		break;
+
+	case IPV6_RECVHOPOPTS:
 		np->rxopt.bits.hopopts = valbool;
 		retv = 0;
 		break;
 
-	case IPV6_DSTOPTS:
+	case IPV6_2292HOPOPTS:
+		np->rxopt.bits.ohopopts = valbool;
+		retv = 0;
+		break;
+
+	case IPV6_RECVDSTOPTS:
 		np->rxopt.bits.dstopts = valbool;
 		retv = 0;
 		break;
 
+	case IPV6_2292DSTOPTS:
+		np->rxopt.bits.odstopts = valbool;
+		retv = 0;
+		break;
+
+	case IPV6_TCLASS:
+		if (val < 0 || val > 0xff)
+			goto e_inval;
+		np->tclass = val;
+		retv = 0;
+		break;
+		
+	case IPV6_RECVTCLASS:
+		np->rxopt.bits.rxtclass = valbool;
+		retv = 0;
+		break;
+
 	case IPV6_FLOWINFO:
 		np->rxopt.bits.rxflow = valbool;
 		retv = 0;
 		break;
 
-	case IPV6_PKTOPTIONS:
+	case IPV6_HOPOPTS:
+	case IPV6_RTHDRDSTOPTS:
+	case IPV6_RTHDR:
+	case IPV6_DSTOPTS:
+	{
+		struct ipv6_txoptions *opt;
+		if (optlen == 0)
+			optval = 0;
+
+		/* hop-by-hop / destination options are privileged option */
+		retv = -EPERM;
+		if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW))
+			break;
+
+		retv = -EINVAL;
+		if (optlen & 0x7 || optlen > 8 * 255)
+			break;
+
+		opt = ipv6_renew_options(sk, np->opt, optname,
+					 (struct ipv6_opt_hdr __user *)optval,
+					 optlen);
+		if (IS_ERR(opt)) {
+			retv = PTR_ERR(opt);
+			break;
+		}
+
+		/* routing header option needs extra check */
+		if (optname == IPV6_RTHDR && opt->srcrt) {
+			struct ipv6_rt_hdr *rthdr = opt->srcrt;
+			if (rthdr->type)
+				goto sticky_done;
+			if ((rthdr->hdrlen & 1) ||
+			    (rthdr->hdrlen >> 1) != rthdr->segments_left)
+				goto sticky_done;
+		}
+
+		retv = 0;
+		if (sk->sk_type == SOCK_STREAM) {
+			if (opt) {
+				struct tcp_sock *tp = tcp_sk(sk);
+				if (!((1 << sk->sk_state) &
+				      (TCPF_LISTEN | TCPF_CLOSE))
+				    && inet_sk(sk)->daddr != LOOPBACK4_IPV6) {
+					tp->ext_header_len = opt->opt_flen + opt->opt_nflen;
+					tcp_sync_mss(sk, tp->pmtu_cookie);
+				}
+			}
+			opt = xchg(&np->opt, opt);
+			sk_dst_reset(sk);
+		} else {
+			write_lock(&sk->sk_dst_lock);
+			opt = xchg(&np->opt, opt);
+			write_unlock(&sk->sk_dst_lock);
+			sk_dst_reset(sk);
+		}
+sticky_done:
+		if (opt)
+			sock_kfree_s(sk, opt, opt->tot_len);
+		break;
+	}
+
+	case IPV6_2292PKTOPTIONS:
 	{
 		struct ipv6_txoptions *opt = NULL;
 		struct msghdr msg;
@@ -276,7 +376,7 @@
 		msg.msg_controllen = optlen;
 		msg.msg_control = (void*)(opt+1);
 
-		retv = datagram_send_ctl(&msg, &fl, opt, &junk);
+		retv = datagram_send_ctl(&msg, &fl, opt, &junk, &junk);
 		if (retv)
 			goto done;
 update:
@@ -529,6 +629,17 @@
 	return -EINVAL;
 }
 
+int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr,
+			   char __user *optval, int len)
+{
+	if (!hdr)
+		return 0;
+	len = min_t(int, len, ipv6_optlen(hdr));
+	if (copy_to_user(optval, hdr, ipv6_optlen(hdr)))
+		return -EFAULT;
+	return len;
+}
+
 int ipv6_getsockopt(struct sock *sk, int level, int optname,
 		    char __user *optval, int __user *optlen)
 {
@@ -567,7 +678,7 @@
 		return err;
 	}
 
-	case IPV6_PKTOPTIONS:
+	case IPV6_2292PKTOPTIONS:
 	{
 		struct msghdr msg;
 		struct sk_buff *skb;
@@ -601,6 +712,16 @@
 				int hlim = np->mcast_hops;
 				put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
 			}
+			if (np->rxopt.bits.rxoinfo) {
+				struct in6_pktinfo src_info;
+				src_info.ipi6_ifindex = np->mcast_oif;
+				ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr);
+				put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);
+			}
+			if (np->rxopt.bits.rxohlim) {
+				int hlim = np->mcast_hops;
+				put_cmsg(&msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim);
+			}
 		}
 		len -= msg.msg_controllen;
 		return put_user(len, optlen);
@@ -625,26 +746,67 @@
 		val = np->ipv6only;
 		break;
 
-	case IPV6_PKTINFO:
+	case IPV6_RECVPKTINFO:
 		val = np->rxopt.bits.rxinfo;
 		break;
 
-	case IPV6_HOPLIMIT:
+	case IPV6_2292PKTINFO:
+		val = np->rxopt.bits.rxoinfo;
+		break;
+
+	case IPV6_RECVHOPLIMIT:
 		val = np->rxopt.bits.rxhlim;
 		break;
 
-	case IPV6_RTHDR:
+	case IPV6_2292HOPLIMIT:
+		val = np->rxopt.bits.rxohlim;
+		break;
+
+	case IPV6_RECVRTHDR:
 		val = np->rxopt.bits.srcrt;
 		break;
 
+	case IPV6_2292RTHDR:
+		val = np->rxopt.bits.osrcrt;
+		break;
+
 	case IPV6_HOPOPTS:
+	case IPV6_RTHDRDSTOPTS:
+	case IPV6_RTHDR:
+	case IPV6_DSTOPTS:
+	{
+
+		lock_sock(sk);
+		len = ipv6_getsockopt_sticky(sk, np->opt->hopopt,
+					     optval, len);
+		release_sock(sk);
+		return put_user(len, optlen);
+	}
+
+	case IPV6_RECVHOPOPTS:
 		val = np->rxopt.bits.hopopts;
 		break;
 
-	case IPV6_DSTOPTS:
+	case IPV6_2292HOPOPTS:
+		val = np->rxopt.bits.ohopopts;
+		break;
+
+	case IPV6_RECVDSTOPTS:
 		val = np->rxopt.bits.dstopts;
 		break;
 
+	case IPV6_2292DSTOPTS:
+		val = np->rxopt.bits.odstopts;
+		break;
+
+	case IPV6_TCLASS:
+		val = np->tclass;
+		break;
+
+	case IPV6_RECVTCLASS:
+		val = np->rxopt.bits.rxtclass;
+		break;
+
 	case IPV6_FLOWINFO:
 		val = np->rxopt.bits.rxflow;
 		break;
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index a7eae30..555a313 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -447,10 +447,8 @@
 		return;
 
 	err = xfrm_lookup(&dst, &fl, NULL, 0);
-	if (err < 0) {
-		dst_release(dst);
+	if (err < 0)
 		return;
-	}
 
 	if (inc_opt) {
 		if (dev->addr_len)
@@ -539,10 +537,8 @@
 		return;
 
 	err = xfrm_lookup(&dst, &fl, NULL, 0);
-	if (err < 0) {
-		dst_release(dst);
+	if (err < 0)
 		return;
-	}
 
 	len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
 	send_llinfo = dev->addr_len && !ipv6_addr_any(saddr);
@@ -616,10 +612,8 @@
 		return;
 
 	err = xfrm_lookup(&dst, &fl, NULL, 0);
-	if (err < 0) {
-		dst_release(dst);
+	if (err < 0)
 		return;
-	}
 
 	len = sizeof(struct icmp6hdr);
 	if (dev->addr_len)
@@ -1353,10 +1347,8 @@
 		return;
 
 	err = xfrm_lookup(&dst, &fl, NULL, 0);
-	if (err) {
-		dst_release(dst);
+	if (err)
 		return;
-	}
 
 	rt = (struct rt6_info *) dst;
 
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index 14316c3..b03e87a 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -100,11 +100,8 @@
 	dst = ip6_route_output(NULL, &fl);
 	if (dst == NULL)
 		return;
-	if (dst->error ||
-	    xfrm_lookup(&dst, &fl, NULL, 0)) {
-		dst_release(dst);
+	if (dst->error || xfrm_lookup(&dst, &fl, NULL, 0))
 		return;
-	}
 
 	hh_len = (dst->dev->hard_header_len + 15)&~15;
 	nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr)
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index ed3a76b..5aa3691 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -655,6 +655,7 @@
 	struct flowi fl;
 	int addr_len = msg->msg_namelen;
 	int hlimit = -1;
+	int tclass = -1;
 	u16 proto;
 	int err;
 
@@ -740,7 +741,7 @@
 		memset(opt, 0, sizeof(struct ipv6_txoptions));
 		opt->tot_len = sizeof(struct ipv6_txoptions);
 
-		err = datagram_send_ctl(msg, &fl, opt, &hlimit);
+		err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass);
 		if (err < 0) {
 			fl6_sock_release(flowlabel);
 			return err;
@@ -755,8 +756,7 @@
 	}
 	if (opt == NULL)
 		opt = np->opt;
-	if (flowlabel)
-		opt = fl6_merge_options(&opt_space, flowlabel, opt);
+	opt = fl6_merge_options(&opt_space, flowlabel, opt);
 
 	fl.proto = proto;
 	rawv6_probe_proto_opt(&fl, msg);
@@ -782,10 +782,8 @@
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
-		dst_release(dst);
+	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
 		goto out;
-	}
 
 	if (hlimit < 0) {
 		if (ipv6_addr_is_multicast(&fl.fl6_dst))
@@ -798,6 +796,12 @@
 			hlimit = ipv6_get_hoplimit(dst->dev);
 	}
 
+	if (tclass < 0) {
+		tclass = np->cork.tclass;
+		if (tclass < 0)
+			tclass = 0;
+	}
+
 	if (msg->msg_flags&MSG_CONFIRM)
 		goto do_confirm;
 
@@ -806,8 +810,9 @@
 		err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl, (struct rt6_info*)dst, msg->msg_flags);
 	} else {
 		lock_sock(sk);
-		err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, len, 0,
-					hlimit, opt, &fl, (struct rt6_info*)dst, msg->msg_flags);
+		err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov,
+			len, 0, hlimit, tclass, opt, &fl, (struct rt6_info*)dst,
+			msg->msg_flags);
 
 		if (err)
 			ip6_flush_pending_frames(sk);
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 9d9e043..e4fe9ee 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -479,12 +479,9 @@
 	/* Point into the IP datagram 'data' part. */
 	if (!pskb_pull(skb, (u8 *) (fhdr + 1) - skb->data))
 		goto err;
-	if (end-offset < skb->len) {
-		if (pskb_trim(skb, end - offset))
-			goto err;
-		if (skb->ip_summed != CHECKSUM_UNNECESSARY)
-			skb->ip_summed = CHECKSUM_NONE;
-	}
+	
+	if (pskb_trim_rcsum(skb, end - offset))
+		goto err;
 
 	/* Find out which fragments are in front and at the back of us
 	 * in the chain of fragments so far.  We must know where to put
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 794734f..80643e6 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -632,10 +632,8 @@
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
-		dst_release(dst);
+	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
 		goto failure;
-	}
 
 	if (saddr == NULL) {
 		saddr = &fl.fl6_src;
@@ -849,7 +847,7 @@
 	if (dst == NULL) {
 		opt = np->opt;
 		if (opt == NULL &&
-		    np->rxopt.bits.srcrt == 2 &&
+		    np->rxopt.bits.osrcrt == 2 &&
 		    treq->pktopts) {
 			struct sk_buff *pktopts = treq->pktopts;
 			struct inet6_skb_parm *rxopt = IP6CB(pktopts);
@@ -888,7 +886,6 @@
 	}
 
 done:
-	dst_release(dst);
         if (opt && opt != np->opt)
 		sock_kfree_s(sk, opt, opt->tot_len);
 	return err;
@@ -915,11 +912,10 @@
 	struct inet6_skb_parm *opt = IP6CB(skb);
 
 	if (np->rxopt.all) {
-		if ((opt->hop && np->rxopt.bits.hopopts) ||
-		    ((IPV6_FLOWINFO_MASK&*(u32*)skb->nh.raw) &&
-		     np->rxopt.bits.rxflow) ||
-		    (opt->srcrt && np->rxopt.bits.srcrt) ||
-		    ((opt->dst1 || opt->dst0) && np->rxopt.bits.dstopts))
+		if ((opt->hop && (np->rxopt.bits.hopopts || np->rxopt.bits.ohopopts)) ||
+		    ((IPV6_FLOWINFO_MASK & *(u32*)skb->nh.raw) && np->rxopt.bits.rxflow) ||
+		    (opt->srcrt && (np->rxopt.bits.srcrt || np->rxopt.bits.osrcrt)) ||
+		    ((opt->dst1 || opt->dst0) && (np->rxopt.bits.dstopts || np->rxopt.bits.odstopts)))
 			return 1;
 	}
 	return 0;
@@ -1001,10 +997,8 @@
 	/* sk = NULL, but it is safe for now. RST socket required. */
 	if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
 
-		if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0) {
-			dst_release(buff->dst);
+		if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0)
 			return;
-		}
 
 		ip6_xmit(NULL, buff, &fl, NULL, 0);
 		TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
@@ -1068,10 +1062,8 @@
 	fl.fl_ip_sport = t1->source;
 
 	if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
-		if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0) {
-			dst_release(buff->dst);
+		if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0)
 			return;
-		}
 		ip6_xmit(NULL, buff, &fl, NULL, 0);
 		TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
 		return;
@@ -1190,8 +1182,8 @@
 	TCP_ECN_create_request(req, skb->h.th);
 	treq->pktopts = NULL;
 	if (ipv6_opt_accepted(sk, skb) ||
-	    np->rxopt.bits.rxinfo ||
-	    np->rxopt.bits.rxhlim) {
+	    np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
+	    np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
 		atomic_inc(&skb->users);
 		treq->pktopts = skb;
 	}
@@ -1288,7 +1280,7 @@
 	if (sk_acceptq_is_full(sk))
 		goto out_overflow;
 
-	if (np->rxopt.bits.srcrt == 2 &&
+	if (np->rxopt.bits.osrcrt == 2 &&
 	    opt == NULL && treq->pktopts) {
 		struct inet6_skb_parm *rxopt = IP6CB(treq->pktopts);
 		if (rxopt->srcrt)
@@ -1544,9 +1536,9 @@
 	tp = tcp_sk(sk);
 	if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
 	    !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
-		if (np->rxopt.bits.rxinfo)
+		if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
 			np->mcast_oif = inet6_iif(opt_skb);
-		if (np->rxopt.bits.rxhlim)
+		if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
 			np->mcast_hops = opt_skb->nh.ipv6h->hop_limit;
 		if (ipv6_opt_accepted(sk, opt_skb)) {
 			skb_set_owner_r(opt_skb, sk);
@@ -1734,7 +1726,6 @@
 
 		if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
 			sk->sk_err_soft = -err;
-			dst_release(dst);
 			return err;
 		}
 
@@ -1787,7 +1778,6 @@
 
 		if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
 			sk->sk_route_caps = 0;
-			dst_release(dst);
 			return err;
 		}
 
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 390d750..69b1468 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -483,7 +483,7 @@
 	}
 
 	if (ulen < skb->len) {
-		if (__pskb_trim(skb, ulen))
+		if (pskb_trim_rcsum(skb, ulen))
 			goto discard;
 		saddr = &skb->nh.ipv6h->saddr;
 		daddr = &skb->nh.ipv6h->daddr;
@@ -637,6 +637,7 @@
 	int addr_len = msg->msg_namelen;
 	int ulen = len;
 	int hlimit = -1;
+	int tclass = -1;
 	int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
 	int err;
 
@@ -758,7 +759,7 @@
 		memset(opt, 0, sizeof(struct ipv6_txoptions));
 		opt->tot_len = sizeof(*opt);
 
-		err = datagram_send_ctl(msg, fl, opt, &hlimit);
+		err = datagram_send_ctl(msg, fl, opt, &hlimit, &tclass);
 		if (err < 0) {
 			fl6_sock_release(flowlabel);
 			return err;
@@ -773,8 +774,7 @@
 	}
 	if (opt == NULL)
 		opt = np->opt;
-	if (flowlabel)
-		opt = fl6_merge_options(&opt_space, flowlabel, opt);
+	opt = fl6_merge_options(&opt_space, flowlabel, opt);
 
 	fl->proto = IPPROTO_UDP;
 	ipv6_addr_copy(&fl->fl6_dst, daddr);
@@ -799,10 +799,8 @@
 	if (final_p)
 		ipv6_addr_copy(&fl->fl6_dst, final_p);
 
-	if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0) {
-		dst_release(dst);
+	if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0)
 		goto out;
-	}
 
 	if (hlimit < 0) {
 		if (ipv6_addr_is_multicast(&fl->fl6_dst))
@@ -815,6 +813,12 @@
 			hlimit = ipv6_get_hoplimit(dst->dev);
 	}
 
+	if (tclass < 0) {
+		tclass = np->tclass;
+		if (tclass < 0)
+			tclass = 0;
+	}
+
 	if (msg->msg_flags&MSG_CONFIRM)
 		goto do_confirm;
 back_from_confirm:
@@ -834,9 +838,10 @@
 
 do_append_data:
 	up->len += ulen;
-	err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, sizeof(struct udphdr),
-			      hlimit, opt, fl, (struct rt6_info*)dst,
-			      corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
+	err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen,
+		sizeof(struct udphdr), hlimit, tclass, opt, fl,
+		(struct rt6_info*)dst,
+		corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
 	if (err)
 		udp_v6_flush_pending_frames(sk);
 	else if (!corkreq)
diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c
index 02891ce..36a7794 100644
--- a/net/rose/rose_subr.c
+++ b/net/rose/rose_subr.c
@@ -337,13 +337,13 @@
 				memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN);
 				memcpy(callsign, p + 12,   l - 10);
 				callsign[l - 10] = '\0';
-				facilities->source_call = *asc2ax(callsign);
+				asc2ax(&facilities->source_call, callsign);
 			}
 			if (*p == FAC_CCITT_SRC_NSAP) {
 				memcpy(&facilities->dest_addr, p + 7, ROSE_ADDR_LEN);
 				memcpy(callsign, p + 12, l - 10);
 				callsign[l - 10] = '\0';
-				facilities->dest_call = *asc2ax(callsign);
+				asc2ax(&facilities->dest_call, callsign);
 			}
 			p   += l + 2;
 			n   += l + 2;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 83c8135..fda737d 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -765,8 +765,8 @@
 	switch (policy->action) {
 	case XFRM_POLICY_BLOCK:
 		/* Prohibit the flow */
-		xfrm_pol_put(policy);
-		return -EPERM;
+		err = -EPERM;
+		goto error;
 
 	case XFRM_POLICY_ALLOW:
 		if (policy->xfrm_nr == 0) {
@@ -782,8 +782,8 @@
 		 */
 		dst = xfrm_find_bundle(fl, policy, family);
 		if (IS_ERR(dst)) {
-			xfrm_pol_put(policy);
-			return PTR_ERR(dst);
+			err = PTR_ERR(dst);
+			goto error;
 		}
 
 		if (dst)