diff -druN linux-libre-3.2.19-gnu/arch/arm/Kconfig linux-libre-3.2.20-gnu/arch/arm/Kconfig
--- linux-libre-3.2.19-gnu/arch/arm/Kconfig	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/arch/arm/Kconfig	2012-06-10 09:42:13.000000000 -0400
@@ -520,7 +520,7 @@
 	depends on MMU
 	select CLKSRC_MMIO
 	select CPU_XSCALE
-	select GENERIC_GPIO
+	select ARCH_REQUIRE_GPIOLIB
 	select GENERIC_CLOCKEVENTS
 	select HAVE_SCHED_CLOCK
 	select MIGHT_HAVE_PCI
diff -druN linux-libre-3.2.19-gnu/arch/arm/mach-ixp4xx/common.c linux-libre-3.2.20-gnu/arch/arm/mach-ixp4xx/common.c
--- linux-libre-3.2.19-gnu/arch/arm/mach-ixp4xx/common.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/arch/arm/mach-ixp4xx/common.c	2012-06-10 09:42:13.000000000 -0400
@@ -29,6 +29,7 @@
 #include <linux/clockchips.h>
 #include <linux/io.h>
 #include <linux/export.h>
+#include <linux/gpio.h>
 
 #include <mach/udc.h>
 #include <mach/hardware.h>
@@ -106,7 +107,7 @@
 	 7,  8,  9, 10, 11, 12, -1, -1,
 };
 
-int gpio_to_irq(int gpio)
+static int ixp4xx_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
 {
 	int irq;
 
@@ -116,7 +117,6 @@
 	}
 	return -EINVAL;
 }
-EXPORT_SYMBOL(gpio_to_irq);
 
 int irq_to_gpio(unsigned int irq)
 {
@@ -376,12 +376,56 @@
 unsigned long ixp4xx_exp_bus_size;
 EXPORT_SYMBOL(ixp4xx_exp_bus_size);
 
+static int ixp4xx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+	gpio_line_config(gpio, IXP4XX_GPIO_IN);
+
+	return 0;
+}
+
+static int ixp4xx_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
+					int level)
+{
+	gpio_line_set(gpio, level);
+	gpio_line_config(gpio, IXP4XX_GPIO_OUT);
+
+	return 0;
+}
+
+static int ixp4xx_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+	int value;
+
+	gpio_line_get(gpio, &value);
+
+	return value;
+}
+
+static void ixp4xx_gpio_set_value(struct gpio_chip *chip, unsigned gpio,
+				  int value)
+{
+	gpio_line_set(gpio, value);
+}
+
+static struct gpio_chip ixp4xx_gpio_chip = {
+	.label			= "IXP4XX_GPIO_CHIP",
+	.direction_input	= ixp4xx_gpio_direction_input,
+	.direction_output	= ixp4xx_gpio_direction_output,
+	.get			= ixp4xx_gpio_get_value,
+	.set			= ixp4xx_gpio_set_value,
+	.to_irq			= ixp4xx_gpio_to_irq,
+	.base			= 0,
+	.ngpio			= 16,
+};
+
 void __init ixp4xx_sys_init(void)
 {
 	ixp4xx_exp_bus_size = SZ_16M;
 
 	platform_add_devices(ixp4xx_devices, ARRAY_SIZE(ixp4xx_devices));
 
+	gpiochip_add(&ixp4xx_gpio_chip);
+
 	if (cpu_is_ixp46x()) {
 		int region;
 
diff -druN linux-libre-3.2.19-gnu/arch/arm/mach-ixp4xx/include/mach/gpio.h linux-libre-3.2.20-gnu/arch/arm/mach-ixp4xx/include/mach/gpio.h
--- linux-libre-3.2.19-gnu/arch/arm/mach-ixp4xx/include/mach/gpio.h	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/arch/arm/mach-ixp4xx/include/mach/gpio.h	2012-06-10 09:42:13.000000000 -0400
@@ -1,79 +1,2 @@
-/*
- * arch/arm/mach-ixp4xx/include/mach/gpio.h
- *
- * IXP4XX GPIO wrappers for arch-neutral GPIO calls
- *
- * Written by Milan Svoboda <msvoboda@ra.rockwell.com>
- * Based on PXA implementation by Philipp Zabel <philipp.zabel@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#ifndef __ASM_ARCH_IXP4XX_GPIO_H
-#define __ASM_ARCH_IXP4XX_GPIO_H
-
-#include <linux/kernel.h>
-#include <mach/hardware.h>
-
-#define __ARM_GPIOLIB_COMPLEX
-
-static inline int gpio_request(unsigned gpio, const char *label)
-{
-	return 0;
-}
-
-static inline void gpio_free(unsigned gpio)
-{
-	might_sleep();
-
-	return;
-}
-
-static inline int gpio_direction_input(unsigned gpio)
-{
-	gpio_line_config(gpio, IXP4XX_GPIO_IN);
-	return 0;
-}
-
-static inline int gpio_direction_output(unsigned gpio, int level)
-{
-	gpio_line_set(gpio, level);
-	gpio_line_config(gpio, IXP4XX_GPIO_OUT);
-	return 0;
-}
-
-static inline int gpio_get_value(unsigned gpio)
-{
-	int value;
-
-	gpio_line_get(gpio, &value);
-
-	return value;
-}
-
-static inline void gpio_set_value(unsigned gpio, int value)
-{
-	gpio_line_set(gpio, value);
-}
-
-#include <asm-generic/gpio.h>			/* cansleep wrappers */
-
-extern int gpio_to_irq(int gpio);
-#define gpio_to_irq gpio_to_irq
-extern int irq_to_gpio(unsigned int irq);
-
-#endif
+/* empty */
 
diff -druN linux-libre-3.2.19-gnu/arch/microblaze/Kconfig linux-libre-3.2.20-gnu/arch/microblaze/Kconfig
--- linux-libre-3.2.19-gnu/arch/microblaze/Kconfig	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/arch/microblaze/Kconfig	2012-06-10 09:42:13.000000000 -0400
@@ -46,7 +46,7 @@
 	def_bool y
 
 config GENERIC_GPIO
-	def_bool y
+	bool
 
 config GENERIC_CSUM
 	def_bool y
diff -druN linux-libre-3.2.19-gnu/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h linux-libre-3.2.20-gnu/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h
--- linux-libre-3.2.19-gnu/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h	2012-06-10 09:42:13.000000000 -0400
@@ -2,6 +2,7 @@
 #define BCM63XX_GPIO_H
 
 #include <linux/init.h>
+#include <bcm63xx_cpu.h>
 
 int __init bcm63xx_gpio_init(void);
 
diff -druN linux-libre-3.2.19-gnu/arch/parisc/kernel/entry.S linux-libre-3.2.20-gnu/arch/parisc/kernel/entry.S
--- linux-libre-3.2.19-gnu/arch/parisc/kernel/entry.S	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/arch/parisc/kernel/entry.S	2012-06-10 09:42:13.000000000 -0400
@@ -552,7 +552,7 @@
 	 * entry (identifying the physical page) and %r23 up with
 	 * the from tlb entry (or nothing if only a to entry---for
 	 * clear_user_page_asm) */
-	.macro		do_alias	spc,tmp,tmp1,va,pte,prot,fault
+	.macro		do_alias	spc,tmp,tmp1,va,pte,prot,fault,patype
 	cmpib,COND(<>),n 0,\spc,\fault
 	ldil		L%(TMPALIAS_MAP_START),\tmp
 #if defined(CONFIG_64BIT) && (TMPALIAS_MAP_START >= 0x80000000)
@@ -581,11 +581,15 @@
 	 */
 	cmpiclr,=	0x01,\tmp,%r0
 	ldi		(_PAGE_DIRTY|_PAGE_READ|_PAGE_WRITE),\prot
-#ifdef CONFIG_64BIT
+.ifc \patype,20
 	depd,z		\prot,8,7,\prot
-#else
+.else
+.ifc \patype,11
 	depw,z		\prot,8,7,\prot
-#endif
+.else
+	.error "undefined PA type to do_alias"
+.endif
+.endif
 	/*
 	 * OK, it is in the temp alias region, check whether "from" or "to".
 	 * Check "subtle" note in pacache.S re: r23/r26.
@@ -1189,7 +1193,7 @@
 	nop
 
 dtlb_check_alias_20w:
-	do_alias	spc,t0,t1,va,pte,prot,dtlb_fault
+	do_alias	spc,t0,t1,va,pte,prot,dtlb_fault,20
 
 	idtlbt          pte,prot
 
@@ -1213,7 +1217,7 @@
 	nop
 
 nadtlb_check_alias_20w:
-	do_alias	spc,t0,t1,va,pte,prot,nadtlb_emulate
+	do_alias	spc,t0,t1,va,pte,prot,nadtlb_emulate,20
 
 	idtlbt          pte,prot
 
@@ -1245,7 +1249,7 @@
 	nop
 
 dtlb_check_alias_11:
-	do_alias	spc,t0,t1,va,pte,prot,dtlb_fault
+	do_alias	spc,t0,t1,va,pte,prot,dtlb_fault,11
 
 	idtlba          pte,(va)
 	idtlbp          prot,(va)
@@ -1277,7 +1281,7 @@
 	nop
 
 nadtlb_check_alias_11:
-	do_alias	spc,t0,t1,va,pte,prot,nadtlb_emulate
+	do_alias	spc,t0,t1,va,pte,prot,nadtlb_emulate,11
 
 	idtlba          pte,(va)
 	idtlbp          prot,(va)
@@ -1304,7 +1308,7 @@
 	nop
 
 dtlb_check_alias_20:
-	do_alias	spc,t0,t1,va,pte,prot,dtlb_fault
+	do_alias	spc,t0,t1,va,pte,prot,dtlb_fault,20
 	
 	idtlbt          pte,prot
 
@@ -1330,7 +1334,7 @@
 	nop
 
 nadtlb_check_alias_20:
-	do_alias	spc,t0,t1,va,pte,prot,nadtlb_emulate
+	do_alias	spc,t0,t1,va,pte,prot,nadtlb_emulate,20
 
 	idtlbt          pte,prot
 
@@ -1457,7 +1461,7 @@
 	nop
 
 naitlb_check_alias_20w:
-	do_alias	spc,t0,t1,va,pte,prot,naitlb_fault
+	do_alias	spc,t0,t1,va,pte,prot,naitlb_fault,20
 
 	iitlbt		pte,prot
 
@@ -1511,7 +1515,7 @@
 	nop
 
 naitlb_check_alias_11:
-	do_alias	spc,t0,t1,va,pte,prot,itlb_fault
+	do_alias	spc,t0,t1,va,pte,prot,itlb_fault,11
 
 	iitlba          pte,(%sr0, va)
 	iitlbp          prot,(%sr0, va)
@@ -1557,7 +1561,7 @@
 	nop
 
 naitlb_check_alias_20:
-	do_alias	spc,t0,t1,va,pte,prot,naitlb_fault
+	do_alias	spc,t0,t1,va,pte,prot,naitlb_fault,20
 
 	iitlbt          pte,prot
 
diff -druN linux-libre-3.2.19-gnu/arch/parisc/kernel/vmlinux.lds.S linux-libre-3.2.20-gnu/arch/parisc/kernel/vmlinux.lds.S
--- linux-libre-3.2.19-gnu/arch/parisc/kernel/vmlinux.lds.S	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/arch/parisc/kernel/vmlinux.lds.S	2012-06-10 09:42:13.000000000 -0400
@@ -50,8 +50,10 @@
 	. = KERNEL_BINARY_TEXT_START;
 
 	_text = .;		/* Text and read-only data */
-	.text ALIGN(16) : {
+	.head ALIGN(16) : {
 		HEAD_TEXT
+	} = 0
+	.text ALIGN(16) : {
 		TEXT_TEXT
 		SCHED_TEXT
 		LOCK_TEXT
@@ -65,7 +67,7 @@
 		*(.fixup)
 		*(.lock.text)		/* out-of-line lock text */
 		*(.gnu.warning)
-	} = 0
+	}
 	/* End of text section */
 	_etext = .;
 
diff -druN linux-libre-3.2.19-gnu/arch/x86/xen/enlighten.c linux-libre-3.2.20-gnu/arch/x86/xen/enlighten.c
--- linux-libre-3.2.19-gnu/arch/x86/xen/enlighten.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/arch/x86/xen/enlighten.c	2012-06-10 09:42:13.000000000 -0400
@@ -982,7 +982,10 @@
 	.wbinvd = native_wbinvd,
 
 	.read_msr = native_read_msr_safe,
+	.rdmsr_regs = native_rdmsr_safe_regs,
 	.write_msr = xen_write_msr_safe,
+	.wrmsr_regs = native_wrmsr_safe_regs,
+
 	.read_tsc = native_read_tsc,
 	.read_pmc = native_read_pmc,
 
diff -druN linux-libre-3.2.19-gnu/drivers/acpi/battery.c linux-libre-3.2.20-gnu/drivers/acpi/battery.c
--- linux-libre-3.2.19-gnu/drivers/acpi/battery.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/acpi/battery.c	2012-06-10 09:42:13.000000000 -0400
@@ -643,11 +643,19 @@
 
 static void acpi_battery_refresh(struct acpi_battery *battery)
 {
+	int power_unit;
+
 	if (!battery->bat.dev)
 		return;
 
+	power_unit = battery->power_unit;
+
 	acpi_battery_get_info(battery);
-	/* The battery may have changed its reporting units. */
+
+	if (power_unit == battery->power_unit)
+		return;
+
+	/* The battery has changed its reporting units. */
 	sysfs_remove_battery(battery);
 	sysfs_add_battery(battery);
 }
diff -druN linux-libre-3.2.19-gnu/drivers/atm/solos-pci.c linux-libre-3.2.20-gnu/drivers/atm/solos-pci.c
--- linux-libre-3.2.19-gnu/drivers/atm/solos-pci.c	2012-06-05 00:50:36.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/atm/solos-pci.c	2012-06-11 15:40:45.000000000 -0400
@@ -982,6 +982,7 @@
 			} else if (skb && card->using_dma) {
 				SKB_CB(skb)->dma_addr = pci_map_single(card->dev, skb->data,
 								       skb->len, PCI_DMA_TODEVICE);
+				card->tx_skb[port] = skb;
 				iowrite32(SKB_CB(skb)->dma_addr,
 					  card->config_regs + TX_DMA_ADDR(port));
 			}
@@ -1150,7 +1151,8 @@
 		db_fpga_upgrade = db_firmware_upgrade = 0;
 	}
 
-	if (card->fpga_version >= DMA_SUPPORTED){
+	if (card->fpga_version >= DMA_SUPPORTED) {
+		pci_set_master(dev);
 		card->using_dma = 1;
 	} else {
 		card->using_dma = 0;
diff -druN linux-libre-3.2.19-gnu/drivers/bluetooth/ath3k.c linux-libre-3.2.20-gnu/drivers/bluetooth/ath3k.c
--- linux-libre-3.2.19-gnu/drivers/bluetooth/ath3k.c	2012-06-05 01:18:47.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/bluetooth/ath3k.c	2012-06-11 15:49:57.000000000 -0400
@@ -74,10 +74,15 @@
 	{ USB_DEVICE(0x0CF3, 0x311D) },
 	{ USB_DEVICE(0x13d3, 0x3375) },
 	{ USB_DEVICE(0x04CA, 0x3005) },
+	{ USB_DEVICE(0x13d3, 0x3362) },
+	{ USB_DEVICE(0x0CF3, 0xE004) },
 
 	/* Atheros AR5BBU12 with sflash firmware */
 	{ USB_DEVICE(0x0489, 0xE02C) },
 
+	/* Atheros AR5BBU22 with sflash firmware */
+	{ USB_DEVICE(0x0489, 0xE03C) },
+
 	{ }	/* Terminating entry */
 };
 
@@ -93,6 +98,11 @@
 	{ USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
+
+	/* Atheros AR5BBU22 with sflash firmware */
+	{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
 
 	{ }	/* Terminating entry */
 };
diff -druN linux-libre-3.2.19-gnu/drivers/bluetooth/btusb.c linux-libre-3.2.20-gnu/drivers/bluetooth/btusb.c
--- linux-libre-3.2.19-gnu/drivers/bluetooth/btusb.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/bluetooth/btusb.c	2012-06-10 09:42:13.000000000 -0400
@@ -61,7 +61,7 @@
 	{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
 
 	/* Broadcom SoftSailing reporting vendor specific */
-	{ USB_DEVICE(0x05ac, 0x21e1) },
+	{ USB_DEVICE(0x0a5c, 0x21e1) },
 
 	/* Apple MacBookPro 7,1 */
 	{ USB_DEVICE(0x05ac, 0x8213) },
@@ -101,9 +101,16 @@
 	{ USB_DEVICE(0x0c10, 0x0000) },
 
 	/* Broadcom BCM20702A0 */
+	{ USB_DEVICE(0x0489, 0xe042) },
 	{ USB_DEVICE(0x0a5c, 0x21e3) },
+	{ USB_DEVICE(0x0a5c, 0x21e6) },
+	{ USB_DEVICE(0x0a5c, 0x21e8) },
+	{ USB_DEVICE(0x0a5c, 0x21f3) },
 	{ USB_DEVICE(0x413c, 0x8197) },
 
+	/* Foxconn - Hon Hai */
+	{ USB_DEVICE(0x0489, 0xe033) },
+
 	{ }	/* Terminating entry */
 };
 
@@ -130,10 +137,15 @@
 	{ USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
 
 	/* Atheros AR5BBU12 with sflash firmware */
 	{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
 
+	/* Atheros AR5BBU12 with sflash firmware */
+	{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
+
 	/* Broadcom BCM2035 */
 	{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
 	{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
diff -druN linux-libre-3.2.19-gnu/drivers/gpu/drm/i915/i915_reg.h linux-libre-3.2.20-gnu/drivers/gpu/drm/i915/i915_reg.h
--- linux-libre-3.2.19-gnu/drivers/gpu/drm/i915/i915_reg.h	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/gpu/drm/i915/i915_reg.h	2012-06-10 09:42:13.000000000 -0400
@@ -3533,7 +3533,11 @@
 #define   GEN6_CAGF_MASK			(0x7f << GEN6_CAGF_SHIFT)
 #define GEN6_RP_CONTROL				0xA024
 #define   GEN6_RP_MEDIA_TURBO			(1<<11)
-#define   GEN6_RP_USE_NORMAL_FREQ		(1<<9)
+#define   GEN6_RP_MEDIA_MODE_MASK		(3<<9)
+#define   GEN6_RP_MEDIA_HW_TURBO_MODE		(3<<9)
+#define   GEN6_RP_MEDIA_HW_NORMAL_MODE		(2<<9)
+#define   GEN6_RP_MEDIA_HW_MODE			(1<<9)
+#define   GEN6_RP_MEDIA_SW_MODE			(0<<9)
 #define   GEN6_RP_MEDIA_IS_GFX			(1<<8)
 #define   GEN6_RP_ENABLE			(1<<7)
 #define   GEN6_RP_UP_IDLE_MIN			(0x1<<3)
diff -druN linux-libre-3.2.19-gnu/drivers/gpu/drm/i915/intel_display.c linux-libre-3.2.20-gnu/drivers/gpu/drm/i915/intel_display.c
--- linux-libre-3.2.19-gnu/drivers/gpu/drm/i915/intel_display.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/gpu/drm/i915/intel_display.c	2012-06-10 09:42:13.000000000 -0400
@@ -1864,7 +1864,7 @@
 	if (enable_fbc < 0) {
 		DRM_DEBUG_KMS("fbc set to per-chip default\n");
 		enable_fbc = 1;
-		if (INTEL_INFO(dev)->gen <= 5)
+		if (INTEL_INFO(dev)->gen <= 6)
 			enable_fbc = 0;
 	}
 	if (!enable_fbc) {
@@ -8005,7 +8005,7 @@
 	I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
 	I915_WRITE(GEN6_RP_CONTROL,
 		   GEN6_RP_MEDIA_TURBO |
-		   GEN6_RP_USE_NORMAL_FREQ |
+		   GEN6_RP_MEDIA_HW_NORMAL_MODE |
 		   GEN6_RP_MEDIA_IS_GFX |
 		   GEN6_RP_ENABLE |
 		   GEN6_RP_UP_BUSY_AVG |
diff -druN linux-libre-3.2.19-gnu/drivers/gpu/drm/i915/intel_dp.c linux-libre-3.2.20-gnu/drivers/gpu/drm/i915/intel_dp.c
--- linux-libre-3.2.19-gnu/drivers/gpu/drm/i915/intel_dp.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/gpu/drm/i915/intel_dp.c	2012-06-10 09:42:13.000000000 -0400
@@ -1149,10 +1149,10 @@
 
 	DRM_DEBUG_KMS("Turn eDP power off\n");
 
-	WARN(intel_dp->want_panel_vdd, "Cannot turn power off while VDD is on\n");
+	WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n");
 
 	pp = ironlake_get_pp_control(dev_priv);
-	pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE);
+	pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_BLC_ENABLE);
 	I915_WRITE(PCH_PP_CONTROL, pp);
 	POSTING_READ(PCH_PP_CONTROL);
 
@@ -1260,18 +1260,16 @@
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 
+
+	/* Make sure the panel is off before trying to change the mode. But also
+	 * ensure that we have vdd while we switch off the panel. */
+	ironlake_edp_panel_vdd_on(intel_dp);
 	ironlake_edp_backlight_off(intel_dp);
 	ironlake_edp_panel_off(intel_dp);
 
-	/* Wake up the sink first */
-	ironlake_edp_panel_vdd_on(intel_dp);
 	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
 	intel_dp_link_down(intel_dp);
 	ironlake_edp_panel_vdd_off(intel_dp, false);
-
-	/* Make sure the panel is off before trying to
-	 * change the mode
-	 */
 }
 
 static void intel_dp_commit(struct drm_encoder *encoder)
@@ -1303,10 +1301,11 @@
 	uint32_t dp_reg = I915_READ(intel_dp->output_reg);
 
 	if (mode != DRM_MODE_DPMS_ON) {
+		/* Switching the panel off requires vdd. */
+		ironlake_edp_panel_vdd_on(intel_dp);
 		ironlake_edp_backlight_off(intel_dp);
 		ironlake_edp_panel_off(intel_dp);
 
-		ironlake_edp_panel_vdd_on(intel_dp);
 		intel_dp_sink_dpms(intel_dp, mode);
 		intel_dp_link_down(intel_dp);
 		ironlake_edp_panel_vdd_off(intel_dp, false);
diff -druN linux-libre-3.2.19-gnu/drivers/gpu/drm/i915/intel_lvds.c linux-libre-3.2.20-gnu/drivers/gpu/drm/i915/intel_lvds.c
--- linux-libre-3.2.19-gnu/drivers/gpu/drm/i915/intel_lvds.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/gpu/drm/i915/intel_lvds.c	2012-06-10 09:42:13.000000000 -0400
@@ -716,6 +716,14 @@
 		},
 	},
 	{
+                .callback = intel_no_lvds_dmi_callback,
+                .ident = "Clientron E830",
+                .matches = {
+                        DMI_MATCH(DMI_SYS_VENDOR, "Clientron"),
+                        DMI_MATCH(DMI_PRODUCT_NAME, "E830"),
+                },
+        },
+        {
 		.callback = intel_no_lvds_dmi_callback,
 		.ident = "Asus EeeBox PC EB1007",
 		.matches = {
@@ -732,6 +740,30 @@
 		},
 	},
 	{
+		.callback = intel_no_lvds_dmi_callback,
+		.ident = "Hewlett-Packard HP t5740e Thin Client",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "HP t5740e Thin Client"),
+		},
+	},
+	{
+		.callback = intel_no_lvds_dmi_callback,
+		.ident = "Hewlett-Packard t5745",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+			DMI_MATCH(DMI_BOARD_NAME, "hp t5745"),
+		},
+	},
+	{
+		.callback = intel_no_lvds_dmi_callback,
+		.ident = "Hewlett-Packard st5747",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+			DMI_MATCH(DMI_BOARD_NAME, "hp st5747"),
+		},
+	},
+	{
 		.callback = intel_no_lvds_dmi_callback,
 		.ident = "MSI Wind Box DC500",
 		.matches = {
diff -druN linux-libre-3.2.19-gnu/drivers/gpu/drm/i915/intel_sdvo.c linux-libre-3.2.20-gnu/drivers/gpu/drm/i915/intel_sdvo.c
--- linux-libre-3.2.19-gnu/drivers/gpu/drm/i915/intel_sdvo.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/gpu/drm/i915/intel_sdvo.c	2012-06-10 09:42:13.000000000 -0400
@@ -769,10 +769,12 @@
 		((v_sync_len & 0x30) >> 4);
 
 	dtd->part2.dtd_flags = 0x18;
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		dtd->part2.dtd_flags |= DTD_FLAG_INTERLACE;
 	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
-		dtd->part2.dtd_flags |= 0x2;
+		dtd->part2.dtd_flags |= DTD_FLAG_HSYNC_POSITIVE;
 	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
-		dtd->part2.dtd_flags |= 0x4;
+		dtd->part2.dtd_flags |= DTD_FLAG_VSYNC_POSITIVE;
 
 	dtd->part2.sdvo_flags = 0;
 	dtd->part2.v_sync_off_high = v_sync_offset & 0xc0;
@@ -806,9 +808,11 @@
 	mode->clock = dtd->part1.clock * 10;
 
 	mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
-	if (dtd->part2.dtd_flags & 0x2)
+	if (dtd->part2.dtd_flags & DTD_FLAG_INTERLACE)
+		mode->flags |= DRM_MODE_FLAG_INTERLACE;
+	if (dtd->part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE)
 		mode->flags |= DRM_MODE_FLAG_PHSYNC;
-	if (dtd->part2.dtd_flags & 0x4)
+	if (dtd->part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE)
 		mode->flags |= DRM_MODE_FLAG_PVSYNC;
 }
 
diff -druN linux-libre-3.2.19-gnu/drivers/gpu/drm/i915/intel_sdvo_regs.h linux-libre-3.2.20-gnu/drivers/gpu/drm/i915/intel_sdvo_regs.h
--- linux-libre-3.2.19-gnu/drivers/gpu/drm/i915/intel_sdvo_regs.h	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/gpu/drm/i915/intel_sdvo_regs.h	2012-06-10 09:42:13.000000000 -0400
@@ -61,6 +61,11 @@
 	u16 output_flags;
 } __attribute__((packed));
 
+/* Note: SDVO detailed timing flags match EDID misc flags. */
+#define DTD_FLAG_HSYNC_POSITIVE (1 << 1)
+#define DTD_FLAG_VSYNC_POSITIVE (1 << 2)
+#define DTD_FLAG_INTERLACE	(1 << 7)
+
 /** This matches the EDID DTD structure, more or less */
 struct intel_sdvo_dtd {
 	struct {
diff -druN linux-libre-3.2.19-gnu/drivers/gpu/drm/i915/intel_tv.c linux-libre-3.2.20-gnu/drivers/gpu/drm/i915/intel_tv.c
--- linux-libre-3.2.19-gnu/drivers/gpu/drm/i915/intel_tv.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/gpu/drm/i915/intel_tv.c	2012-06-10 09:42:13.000000000 -0400
@@ -1307,6 +1307,11 @@
 
 	I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
 	I915_WRITE(TV_CTL, save_tv_ctl);
+	POSTING_READ(TV_CTL);
+
+	/* For unknown reasons the hw barfs if we don't do this vblank wait. */
+	intel_wait_for_vblank(intel_tv->base.base.dev,
+			      to_intel_crtc(intel_tv->base.base.crtc)->pipe);
 
 	/* Restore interrupt config */
 	if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
diff -druN linux-libre-3.2.19-gnu/drivers/gpu/drm/radeon/evergreen.c linux-libre-3.2.20-gnu/drivers/gpu/drm/radeon/evergreen.c
--- linux-libre-3.2.19-gnu/drivers/gpu/drm/radeon/evergreen.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/gpu/drm/radeon/evergreen.c	2012-06-10 09:42:13.000000000 -0400
@@ -977,6 +977,11 @@
 		WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp);
 		WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp);
 		WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp);
+		if ((rdev->family == CHIP_JUNIPER) ||
+		    (rdev->family == CHIP_CYPRESS) ||
+		    (rdev->family == CHIP_HEMLOCK) ||
+		    (rdev->family == CHIP_BARTS))
+			WREG32(MC_VM_MD_L1_TLB3_CNTL, tmp);
 	}
 	WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp);
 	WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp);
@@ -2074,9 +2079,12 @@
 	/* num banks is 8 on all fusion asics. 0 = 4, 1 = 8, 2 = 16 */
 	if (rdev->flags & RADEON_IS_IGP)
 		rdev->config.evergreen.tile_config |= 1 << 4;
-	else
-		rdev->config.evergreen.tile_config |=
-			((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4;
+	else {
+		if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT)
+			rdev->config.evergreen.tile_config |= 1 << 4;
+		else
+			rdev->config.evergreen.tile_config |= 0 << 4;
+	}
 	rdev->config.evergreen.tile_config |=
 		((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) << 8;
 	rdev->config.evergreen.tile_config |=
@@ -2108,9 +2116,9 @@
 		WREG32(CC_SYS_RB_BACKEND_DISABLE, rb);
 		WREG32(GC_USER_RB_BACKEND_DISABLE, rb);
 		WREG32(CC_GC_SHADER_PIPE_CONFIG, sp);
-        }
+	}
 
-	grbm_gfx_index |= SE_BROADCAST_WRITES;
+	grbm_gfx_index = INSTANCE_BROADCAST_WRITES | SE_BROADCAST_WRITES;
 	WREG32(GRBM_GFX_INDEX, grbm_gfx_index);
 	WREG32(RLC_GFX_INDEX, grbm_gfx_index);
 
diff -druN linux-libre-3.2.19-gnu/drivers/gpu/drm/radeon/evergreend.h linux-libre-3.2.20-gnu/drivers/gpu/drm/radeon/evergreend.h
--- linux-libre-3.2.19-gnu/drivers/gpu/drm/radeon/evergreend.h	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/gpu/drm/radeon/evergreend.h	2012-06-10 09:42:13.000000000 -0400
@@ -230,6 +230,7 @@
 #define	MC_VM_MD_L1_TLB0_CNTL				0x2654
 #define	MC_VM_MD_L1_TLB1_CNTL				0x2658
 #define	MC_VM_MD_L1_TLB2_CNTL				0x265C
+#define	MC_VM_MD_L1_TLB3_CNTL				0x2698
 
 #define	FUS_MC_VM_MD_L1_TLB0_CNTL			0x265C
 #define	FUS_MC_VM_MD_L1_TLB1_CNTL			0x2660
diff -druN linux-libre-3.2.19-gnu/drivers/gpu/drm/radeon/ni.c linux-libre-3.2.20-gnu/drivers/gpu/drm/radeon/ni.c
--- linux-libre-3.2.19-gnu/drivers/gpu/drm/radeon/ni.c	2012-06-05 00:52:24.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/gpu/drm/radeon/ni.c	2012-06-11 15:41:19.000000000 -0400
@@ -763,8 +763,10 @@
 		rdev->config.cayman.tile_config |= (3 << 0);
 		break;
 	}
-	rdev->config.cayman.tile_config |=
-		((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4;
+	if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT)
+		rdev->config.cayman.tile_config |= 1 << 4;
+	else
+		rdev->config.cayman.tile_config |= 0 << 4;
 	rdev->config.cayman.tile_config |=
 		((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8;
 	rdev->config.cayman.tile_config |=
diff -druN linux-libre-3.2.19-gnu/drivers/gpu/drm/radeon/radeon_atombios.c linux-libre-3.2.20-gnu/drivers/gpu/drm/radeon/radeon_atombios.c
--- linux-libre-3.2.19-gnu/drivers/gpu/drm/radeon/radeon_atombios.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/gpu/drm/radeon/radeon_atombios.c	2012-06-10 09:42:13.000000000 -0400
@@ -438,7 +438,9 @@
 	 */
 	if ((dev->pdev->device == 0x9498) &&
 	    (dev->pdev->subsystem_vendor == 0x1682) &&
-	    (dev->pdev->subsystem_device == 0x2452)) {
+	    (dev->pdev->subsystem_device == 0x2452) &&
+	    (i2c_bus->valid == false) &&
+	    !(supported_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))) {
 		struct radeon_device *rdev = dev->dev_private;
 		*i2c_bus = radeon_lookup_i2c_gpio(rdev, 0x93);
 	}
diff -druN linux-libre-3.2.19-gnu/drivers/gpu/drm/radeon/rv770.c linux-libre-3.2.20-gnu/drivers/gpu/drm/radeon/rv770.c
--- linux-libre-3.2.19-gnu/drivers/gpu/drm/radeon/rv770.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/gpu/drm/radeon/rv770.c	2012-06-10 09:42:13.000000000 -0400
@@ -151,6 +151,8 @@
 	WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp);
 	WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp);
 	WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp);
+	if (rdev->family == CHIP_RV740)
+		WREG32(MC_VM_MD_L1_TLB3_CNTL, tmp);
 	WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp);
 	WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp);
 	WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp);
@@ -689,8 +691,12 @@
 
 	if (rdev->family == CHIP_RV770)
 		gb_tiling_config |= BANK_TILING(1);
-	else
-		gb_tiling_config |= BANK_TILING((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT);
+	else {
+		if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT)
+			gb_tiling_config |= BANK_TILING(1);
+		else
+			gb_tiling_config |= BANK_TILING(0);
+	}
 	rdev->config.rv770.tiling_nbanks = 4 << ((gb_tiling_config >> 4) & 0x3);
 	gb_tiling_config |= GROUP_SIZE((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT);
 	if ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT)
diff -druN linux-libre-3.2.19-gnu/drivers/gpu/drm/radeon/rv770d.h linux-libre-3.2.20-gnu/drivers/gpu/drm/radeon/rv770d.h
--- linux-libre-3.2.19-gnu/drivers/gpu/drm/radeon/rv770d.h	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/gpu/drm/radeon/rv770d.h	2012-06-10 09:42:13.000000000 -0400
@@ -174,6 +174,7 @@
 #define	MC_VM_MD_L1_TLB0_CNTL				0x2654
 #define	MC_VM_MD_L1_TLB1_CNTL				0x2658
 #define	MC_VM_MD_L1_TLB2_CNTL				0x265C
+#define	MC_VM_MD_L1_TLB3_CNTL				0x2698
 #define	MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR		0x203C
 #define	MC_VM_SYSTEM_APERTURE_HIGH_ADDR			0x2038
 #define	MC_VM_SYSTEM_APERTURE_LOW_ADDR			0x2034
diff -druN linux-libre-3.2.19-gnu/drivers/gpu/drm/ttm/ttm_bo.c linux-libre-3.2.20-gnu/drivers/gpu/drm/ttm/ttm_bo.c
--- linux-libre-3.2.19-gnu/drivers/gpu/drm/ttm/ttm_bo.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/gpu/drm/ttm/ttm_bo.c	2012-06-10 09:42:13.000000000 -0400
@@ -1816,6 +1816,7 @@
 			spin_unlock(&glob->lru_lock);
 			(void) ttm_bo_cleanup_refs(bo, false, false, false);
 			kref_put(&bo->list_kref, ttm_bo_release_list);
+			spin_lock(&glob->lru_lock);
 			continue;
 		}
 
diff -druN linux-libre-3.2.19-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c linux-libre-3.2.20-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c
--- linux-libre-3.2.19-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c	2012-06-10 09:42:13.000000000 -0400
@@ -66,7 +66,7 @@
 	cmd += sizeof(remap_cmd) / sizeof(uint32);
 
 	for (i = 0; i < num_pages; ++i) {
-		if (VMW_PPN_SIZE > 4)
+		if (VMW_PPN_SIZE <= 4)
 			*cmd = page_to_pfn(*pages++);
 		else
 			*((uint64_t *)cmd) = page_to_pfn(*pages++);
diff -druN linux-libre-3.2.19-gnu/drivers/iommu/amd_iommu.c linux-libre-3.2.20-gnu/drivers/iommu/amd_iommu.c
--- linux-libre-3.2.19-gnu/drivers/iommu/amd_iommu.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/iommu/amd_iommu.c	2012-06-10 09:42:13.000000000 -0400
@@ -381,12 +381,27 @@
 
 static void iommu_print_event(struct amd_iommu *iommu, void *__evt)
 {
-	u32 *event = __evt;
-	int type  = (event[1] >> EVENT_TYPE_SHIFT)  & EVENT_TYPE_MASK;
-	int devid = (event[0] >> EVENT_DEVID_SHIFT) & EVENT_DEVID_MASK;
-	int domid = (event[1] >> EVENT_DOMID_SHIFT) & EVENT_DOMID_MASK;
-	int flags = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK;
-	u64 address = (u64)(((u64)event[3]) << 32) | event[2];
+	int type, devid, domid, flags;
+	volatile u32 *event = __evt;
+	int count = 0;
+	u64 address;
+
+retry:
+	type    = (event[1] >> EVENT_TYPE_SHIFT)  & EVENT_TYPE_MASK;
+	devid   = (event[0] >> EVENT_DEVID_SHIFT) & EVENT_DEVID_MASK;
+	domid   = (event[1] >> EVENT_DOMID_SHIFT) & EVENT_DOMID_MASK;
+	flags   = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK;
+	address = (u64)(((u64)event[3]) << 32) | event[2];
+
+	if (type == 0) {
+		/* Did we hit the erratum? */
+		if (++count == LOOP_TIMEOUT) {
+			pr_err("AMD-Vi: No event written to event log\n");
+			return;
+		}
+		udelay(1);
+		goto retry;
+	}
 
 	printk(KERN_ERR "AMD-Vi: Event logged [");
 
@@ -439,6 +454,8 @@
 	default:
 		printk(KERN_ERR "UNKNOWN type=0x%02x]\n", type);
 	}
+
+	memset(__evt, 0, 4 * sizeof(u32));
 }
 
 static void iommu_poll_events(struct amd_iommu *iommu)
diff -druN linux-libre-3.2.19-gnu/drivers/iommu/amd_iommu_init.c linux-libre-3.2.20-gnu/drivers/iommu/amd_iommu_init.c
--- linux-libre-3.2.19-gnu/drivers/iommu/amd_iommu_init.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/iommu/amd_iommu_init.c	2012-06-10 09:42:13.000000000 -0400
@@ -943,6 +943,9 @@
 	if (!iommu->dev)
 		return 1;
 
+	iommu->root_pdev = pci_get_bus_and_slot(iommu->dev->bus->number,
+						PCI_DEVFN(0, 0));
+
 	iommu->cap_ptr = h->cap_ptr;
 	iommu->pci_seg = h->pci_seg;
 	iommu->mmio_phys = h->mmio_phys;
@@ -1225,20 +1228,16 @@
 {
 	int i, j;
 	u32 ioc_feature_control;
-	struct pci_dev *pdev = NULL;
+	struct pci_dev *pdev = iommu->root_pdev;
 
 	/* RD890 BIOSes may not have completely reconfigured the iommu */
-	if (!is_rd890_iommu(iommu->dev))
+	if (!is_rd890_iommu(iommu->dev) || !pdev)
 		return;
 
 	/*
 	 * First, we need to ensure that the iommu is enabled. This is
 	 * controlled by a register in the northbridge
 	 */
-	pdev = pci_get_bus_and_slot(iommu->dev->bus->number, PCI_DEVFN(0, 0));
-
-	if (!pdev)
-		return;
 
 	/* Select Northbridge indirect register 0x75 and enable writing */
 	pci_write_config_dword(pdev, 0x60, 0x75 | (1 << 7));
@@ -1248,8 +1247,6 @@
 	if (!(ioc_feature_control & 0x1))
 		pci_write_config_dword(pdev, 0x64, ioc_feature_control | 1);
 
-	pci_dev_put(pdev);
-
 	/* Restore the iommu BAR */
 	pci_write_config_dword(iommu->dev, iommu->cap_ptr + 4,
 			       iommu->stored_addr_lo);
diff -druN linux-libre-3.2.19-gnu/drivers/iommu/amd_iommu_types.h linux-libre-3.2.20-gnu/drivers/iommu/amd_iommu_types.h
--- linux-libre-3.2.19-gnu/drivers/iommu/amd_iommu_types.h	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/iommu/amd_iommu_types.h	2012-06-10 09:42:13.000000000 -0400
@@ -385,6 +385,9 @@
 	/* Pointer to PCI device of this IOMMU */
 	struct pci_dev *dev;
 
+	/* Cache pdev to root device for resume quirks */
+	struct pci_dev *root_pdev;
+
 	/* physical address of MMIO space */
 	u64 mmio_phys;
 	/* virtual address of MMIO space */
diff -druN linux-libre-3.2.19-gnu/drivers/mtd/Kconfig linux-libre-3.2.20-gnu/drivers/mtd/Kconfig
--- linux-libre-3.2.19-gnu/drivers/mtd/Kconfig	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/mtd/Kconfig	2012-06-10 09:42:13.000000000 -0400
@@ -128,7 +128,7 @@
 
 config MTD_OF_PARTS
 	tristate "OpenFirmware partitioning information support"
-	default Y
+	default y
 	depends on OF
 	help
 	  This provides a partition parsing function which derives
diff -druN linux-libre-3.2.19-gnu/drivers/mtd/nand/nand_bbt.c linux-libre-3.2.20-gnu/drivers/mtd/nand/nand_bbt.c
--- linux-libre-3.2.19-gnu/drivers/mtd/nand/nand_bbt.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/mtd/nand/nand_bbt.c	2012-06-10 09:42:13.000000000 -0400
@@ -324,6 +324,7 @@
 
 		buf += mtd->oobsize + mtd->writesize;
 		len -= mtd->writesize;
+		offs += mtd->writesize;
 	}
 	return 0;
 }
diff -druN linux-libre-3.2.19-gnu/drivers/net/ethernet/freescale/fec_mpc52xx.c linux-libre-3.2.20-gnu/drivers/net/ethernet/freescale/fec_mpc52xx.c
--- linux-libre-3.2.19-gnu/drivers/net/ethernet/freescale/fec_mpc52xx.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/net/ethernet/freescale/fec_mpc52xx.c	2012-06-10 09:42:13.000000000 -0400
@@ -437,7 +437,7 @@
 		length = status & BCOM_FEC_RX_BD_LEN_MASK;
 		skb_put(rskb, length - 4);	/* length without CRC32 */
 		rskb->protocol = eth_type_trans(rskb, dev);
-		if (!skb_defer_rx_timestamp(skb))
+		if (!skb_defer_rx_timestamp(rskb))
 			netif_rx(rskb);
 
 		spin_lock(&priv->lock);
diff -druN linux-libre-3.2.19-gnu/drivers/net/ethernet/realtek/r8169.c linux-libre-3.2.20-gnu/drivers/net/ethernet/realtek/r8169.c
--- linux-libre-3.2.19-gnu/drivers/net/ethernet/realtek/r8169.c	2012-06-05 01:07:20.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/net/ethernet/realtek/r8169.c	2012-06-11 15:45:55.000000000 -0400
@@ -62,8 +62,12 @@
 #define R8169_MSG_DEFAULT \
 	(NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN)
 
-#define TX_BUFFS_AVAIL(tp) \
-	(tp->dirty_tx + NUM_TX_DESC - tp->cur_tx - 1)
+#define TX_SLOTS_AVAIL(tp) \
+	(tp->dirty_tx + NUM_TX_DESC - tp->cur_tx)
+
+/* A skbuff with nr_frags needs nr_frags+1 entries in the tx queue */
+#define TX_FRAGS_READY_FOR(tp,nr_frags) \
+	(TX_SLOTS_AVAIL(tp) >= (nr_frags + 1))
 
 /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
    The RTL chips use a 64 element hash table based on the Ethernet CRC. */
@@ -5505,7 +5509,7 @@
 	u32 opts[2];
 	int frags;
 
-	if (unlikely(TX_BUFFS_AVAIL(tp) < skb_shinfo(skb)->nr_frags)) {
+	if (unlikely(!TX_FRAGS_READY_FOR(tp, skb_shinfo(skb)->nr_frags))) {
 		netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n");
 		goto err_stop_0;
 	}
@@ -5553,10 +5557,21 @@
 
 	RTL_W8(TxPoll, NPQ);
 
-	if (TX_BUFFS_AVAIL(tp) < MAX_SKB_FRAGS) {
+	if (!TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
+		/* Avoid wrongly optimistic queue wake-up: rtl_tx thread must
+		 * not miss a ring update when it notices a stopped queue.
+		 */
+		smp_wmb();
 		netif_stop_queue(dev);
-		smp_rmb();
-		if (TX_BUFFS_AVAIL(tp) >= MAX_SKB_FRAGS)
+		/* Sync with rtl_tx:
+		 * - publish queue status and cur_tx ring index (write barrier)
+		 * - refresh dirty_tx ring index (read barrier).
+		 * May the current thread have a pessimistic view of the ring
+		 * status and forget to wake up queue, a racing rtl_tx thread
+		 * can't.
+		 */
+		smp_mb();
+		if (TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS))
 			netif_wake_queue(dev);
 	}
 
@@ -5656,9 +5671,16 @@
 
 	if (tp->dirty_tx != dirty_tx) {
 		tp->dirty_tx = dirty_tx;
-		smp_wmb();
+		/* Sync with rtl8169_start_xmit:
+		 * - publish dirty_tx ring index (write barrier)
+		 * - refresh cur_tx ring index and queue status (read barrier)
+		 * May the current thread miss the stopped queue condition,
+		 * a racing xmit thread can only have a right view of the
+		 * ring status.
+		 */
+		smp_mb();
 		if (netif_queue_stopped(dev) &&
-		    (TX_BUFFS_AVAIL(tp) >= MAX_SKB_FRAGS)) {
+		    TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
 			netif_wake_queue(dev);
 		}
 		/*
@@ -5667,7 +5689,6 @@
 		 * of start_xmit activity is detected (if it is not detected,
 		 * it is slow enough). -- FR
 		 */
-		smp_rmb();
 		if (tp->cur_tx != dirty_tx)
 			RTL_W8(TxPoll, NPQ);
 	}
diff -druN linux-libre-3.2.19-gnu/drivers/net/macvlan.c linux-libre-3.2.20-gnu/drivers/net/macvlan.c
--- linux-libre-3.2.19-gnu/drivers/net/macvlan.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/net/macvlan.c	2012-06-10 09:42:13.000000000 -0400
@@ -258,7 +258,7 @@
 
 xmit_world:
 	skb->ip_summed = ip_summed;
-	skb_set_dev(skb, vlan->lowerdev);
+	skb->dev = vlan->lowerdev;
 	return dev_queue_xmit(skb);
 }
 
diff -druN linux-libre-3.2.19-gnu/drivers/net/usb/asix.c linux-libre-3.2.20-gnu/drivers/net/usb/asix.c
--- linux-libre-3.2.19-gnu/drivers/net/usb/asix.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/net/usb/asix.c	2012-06-10 09:42:13.000000000 -0400
@@ -35,6 +35,7 @@
 #include <linux/crc32.h>
 #include <linux/usb/usbnet.h>
 #include <linux/slab.h>
+#include <linux/if_vlan.h>
 
 #define DRIVER_VERSION "08-Nov-2011"
 #define DRIVER_NAME "asix"
@@ -348,7 +349,7 @@
 			return 2;
 		}
 
-		if (size > dev->net->mtu + ETH_HLEN) {
+		if (size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) {
 			netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
 				   size);
 			return 0;
diff -druN linux-libre-3.2.19-gnu/drivers/net/wireless/ath/ath9k/xmit.c linux-libre-3.2.20-gnu/drivers/net/wireless/ath/ath9k/xmit.c
--- linux-libre-3.2.19-gnu/drivers/net/wireless/ath/ath9k/xmit.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/net/wireless/ath/ath9k/xmit.c	2012-06-10 09:42:13.000000000 -0400
@@ -64,7 +64,8 @@
 static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
 					   struct ath_txq *txq,
 					   struct ath_atx_tid *tid,
-					   struct sk_buff *skb);
+					   struct sk_buff *skb,
+					   bool dequeue);
 
 enum {
 	MCS_HT20,
@@ -761,7 +762,7 @@
 		fi = get_frame_info(skb);
 		bf = fi->bf;
 		if (!fi->bf)
-			bf = ath_tx_setup_buffer(sc, txq, tid, skb);
+			bf = ath_tx_setup_buffer(sc, txq, tid, skb, true);
 
 		if (!bf)
 			continue;
@@ -1669,7 +1670,7 @@
 		return;
 	}
 
-	bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb);
+	bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false);
 	if (!bf)
 		return;
 
@@ -1696,7 +1697,7 @@
 
 	bf = fi->bf;
 	if (!bf)
-		bf = ath_tx_setup_buffer(sc, txq, tid, skb);
+		bf = ath_tx_setup_buffer(sc, txq, tid, skb, false);
 
 	if (!bf)
 		return;
@@ -1761,7 +1762,8 @@
 static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
 					   struct ath_txq *txq,
 					   struct ath_atx_tid *tid,
-					   struct sk_buff *skb)
+					   struct sk_buff *skb,
+					   bool dequeue)
 {
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_frame_info *fi = get_frame_info(skb);
@@ -1802,6 +1804,8 @@
 	return bf;
 
 error:
+	if (dequeue)
+		__skb_unlink(skb, &tid->buf_q);
 	dev_kfree_skb_any(skb);
 	return NULL;
 }
@@ -1833,7 +1837,7 @@
 		 */
 		ath_tx_send_ampdu(sc, tid, skb, txctl);
 	} else {
-		bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb);
+		bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false);
 		if (!bf)
 			goto out;
 
diff -druN linux-libre-3.2.19-gnu/drivers/net/wireless/iwlwifi/iwl-2000.c linux-libre-3.2.20-gnu/drivers/net/wireless/iwlwifi/iwl-2000.c
--- linux-libre-3.2.19-gnu/drivers/net/wireless/iwlwifi/iwl-2000.c	2012-06-05 01:14:05.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/net/wireless/iwlwifi/iwl-2000.c	2012-06-11 15:47:58.000000000 -0400
@@ -211,7 +211,7 @@
 	.chain_noise_scale = 1000,
 	.wd_timeout = IWL_DEF_WD_TIMEOUT,
 	.max_event_log_size = 512,
-	.shadow_reg_enable = true,
+	.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
 	.hd_v2 = true,
 };
 
@@ -230,7 +230,7 @@
 	.chain_noise_scale = 1000,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
-	.shadow_reg_enable = true,
+	.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
 	.hd_v2 = true,
 };
 
diff -druN linux-libre-3.2.19-gnu/drivers/net/wireless/iwlwifi/iwl-6000.c linux-libre-3.2.20-gnu/drivers/net/wireless/iwlwifi/iwl-6000.c
--- linux-libre-3.2.19-gnu/drivers/net/wireless/iwlwifi/iwl-6000.c	2012-06-05 01:13:54.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/net/wireless/iwlwifi/iwl-6000.c	2012-06-11 15:47:54.000000000 -0400
@@ -308,7 +308,7 @@
 	.chain_noise_scale = 1000,
 	.wd_timeout = IWL_DEF_WD_TIMEOUT,
 	.max_event_log_size = 512,
-	.shadow_reg_enable = true,
+	.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
 };
 
 static struct iwl_base_params iwl6050_base_params = {
@@ -325,7 +325,7 @@
 	.chain_noise_scale = 1500,
 	.wd_timeout = IWL_DEF_WD_TIMEOUT,
 	.max_event_log_size = 1024,
-	.shadow_reg_enable = true,
+	.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
 };
 static struct iwl_base_params iwl6000_g2_base_params = {
 	.eeprom_size = OTP_LOW_IMAGE_SIZE,
@@ -341,7 +341,7 @@
 	.chain_noise_scale = 1000,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
-	.shadow_reg_enable = true,
+	.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
 };
 
 static struct iwl_ht_params iwl6000_ht_params = {
diff -druN linux-libre-3.2.19-gnu/drivers/net/wireless/iwlwifi/iwl-agn-rs.c linux-libre-3.2.20-gnu/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
--- linux-libre-3.2.19-gnu/drivers/net/wireless/iwlwifi/iwl-agn-rs.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/net/wireless/iwlwifi/iwl-agn-rs.c	2012-06-10 09:42:13.000000000 -0400
@@ -886,6 +886,7 @@
 	if ((priv->bt_traffic_load != priv->last_bt_traffic_load) ||
 	    (priv->bt_full_concurrent != full_concurrent)) {
 		priv->bt_full_concurrent = full_concurrent;
+		priv->last_bt_traffic_load = priv->bt_traffic_load;
 
 		/* Update uCode's rate table. */
 		tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
diff -druN linux-libre-3.2.19-gnu/drivers/net/wireless/wl1251/sdio.c linux-libre-3.2.20-gnu/drivers/net/wireless/wl1251/sdio.c
--- linux-libre-3.2.19-gnu/drivers/net/wireless/wl1251/sdio.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/net/wireless/wl1251/sdio.c	2012-06-10 09:42:13.000000000 -0400
@@ -260,6 +260,7 @@
 	}
 
 	if (wl->irq) {
+		irq_set_status_flags(wl->irq, IRQ_NOAUTOEN);
 		ret = request_irq(wl->irq, wl1251_line_irq, 0, "wl1251", wl);
 		if (ret < 0) {
 			wl1251_error("request_irq() failed: %d", ret);
@@ -267,7 +268,6 @@
 		}
 
 		irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
-		disable_irq(wl->irq);
 
 		wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq;
 		wl1251_sdio_ops.disable_irq = wl1251_disable_line_irq;
diff -druN linux-libre-3.2.19-gnu/drivers/net/wireless/wl1251/spi.c linux-libre-3.2.20-gnu/drivers/net/wireless/wl1251/spi.c
--- linux-libre-3.2.19-gnu/drivers/net/wireless/wl1251/spi.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/net/wireless/wl1251/spi.c	2012-06-10 09:42:13.000000000 -0400
@@ -281,6 +281,7 @@
 
 	wl->use_eeprom = pdata->use_eeprom;
 
+	irq_set_status_flags(wl->irq, IRQ_NOAUTOEN);
 	ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl);
 	if (ret < 0) {
 		wl1251_error("request_irq() failed: %d", ret);
@@ -289,8 +290,6 @@
 
 	irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
 
-	disable_irq(wl->irq);
-
 	ret = wl1251_init_ieee80211(wl);
 	if (ret)
 		goto out_irq;
diff -druN linux-libre-3.2.19-gnu/drivers/scsi/scsi_lib.c linux-libre-3.2.20-gnu/drivers/scsi/scsi_lib.c
--- linux-libre-3.2.19-gnu/drivers/scsi/scsi_lib.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/scsi/scsi_lib.c	2012-06-10 09:42:13.000000000 -0400
@@ -1382,16 +1382,19 @@
 {
 	struct scsi_device *sdev = q->queuedata;
 	struct Scsi_Host *shost;
-	struct scsi_target *starget;
 
 	if (!sdev)
 		return 0;
 
 	shost = sdev->host;
-	starget = scsi_target(sdev);
 
-	if (scsi_host_in_recovery(shost) || scsi_host_is_busy(shost) ||
-	    scsi_target_is_busy(starget) || scsi_device_is_busy(sdev))
+	/*
+	 * Ignore host/starget busy state.
+	 * Since block layer does not have a concept of fairness across
+	 * multiple queues, congestion of host/starget needs to be handled
+	 * in SCSI layer.
+	 */
+	if (scsi_host_in_recovery(shost) || scsi_device_is_busy(sdev))
 		return 1;
 
 	return 0;
diff -druN linux-libre-3.2.19-gnu/drivers/scsi/scsi_wait_scan.c linux-libre-3.2.20-gnu/drivers/scsi/scsi_wait_scan.c
--- linux-libre-3.2.19-gnu/drivers/scsi/scsi_wait_scan.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/scsi/scsi_wait_scan.c	2012-06-10 09:42:13.000000000 -0400
@@ -12,7 +12,7 @@
 
 #include <linux/module.h>
 #include <linux/device.h>
-#include <scsi/scsi_scan.h>
+#include "scsi_priv.h"
 
 static int __init wait_scan_init(void)
 {
diff -druN linux-libre-3.2.19-gnu/drivers/target/target_core_file.c linux-libre-3.2.20-gnu/drivers/target/target_core_file.c
--- linux-libre-3.2.19-gnu/drivers/target/target_core_file.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/target/target_core_file.c	2012-06-10 09:42:13.000000000 -0400
@@ -134,21 +134,11 @@
 		ret = PTR_ERR(dev_p);
 		goto fail;
 	}
-#if 0
-	if (di->no_create_file)
-		flags = O_RDWR | O_LARGEFILE;
-	else
-		flags = O_RDWR | O_CREAT | O_LARGEFILE;
-#else
-	flags = O_RDWR | O_CREAT | O_LARGEFILE;
-#endif
-/*	flags |= O_DIRECT; */
 	/*
-	 * If fd_buffered_io=1 has not been set explicitly (the default),
-	 * use O_SYNC to force FILEIO writes to disk.
+	 * Use O_DSYNC by default instead of O_SYNC to forgo syncing
+	 * of pure timestamp updates.
 	 */
-	if (!(fd_dev->fbd_flags & FDBD_USE_BUFFERED_IO))
-		flags |= O_SYNC;
+	flags = O_RDWR | O_CREAT | O_LARGEFILE | O_DSYNC;
 
 	file = filp_open(dev_p, flags, 0600);
 	if (IS_ERR(file)) {
@@ -400,26 +390,6 @@
 		transport_complete_sync_cache(cmd, ret == 0);
 }
 
-/*
- * WRITE Force Unit Access (FUA) emulation on a per struct se_task
- * LBA range basis..
- */
-static void fd_emulate_write_fua(struct se_cmd *cmd, struct se_task *task)
-{
-	struct se_device *dev = cmd->se_dev;
-	struct fd_dev *fd_dev = dev->dev_ptr;
-	loff_t start = task->task_lba * dev->se_sub_dev->se_dev_attrib.block_size;
-	loff_t end = start + task->task_size;
-	int ret;
-
-	pr_debug("FILEIO: FUA WRITE LBA: %llu, bytes: %u\n",
-			task->task_lba, task->task_size);
-
-	ret = vfs_fsync_range(fd_dev->fd_file, start, end, 1);
-	if (ret != 0)
-		pr_err("FILEIO: vfs_fsync_range() failed: %d\n", ret);
-}
-
 static int fd_do_task(struct se_task *task)
 {
 	struct se_cmd *cmd = task->task_se_cmd;
@@ -434,19 +404,21 @@
 		ret = fd_do_readv(task);
 	} else {
 		ret = fd_do_writev(task);
-
+		/*
+		 * Perform implict vfs_fsync_range() for fd_do_writev() ops
+		 * for SCSI WRITEs with Forced Unit Access (FUA) set.
+		 * Allow this to happen independent of WCE=0 setting.
+		 */
 		if (ret > 0 &&
-		    dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0 &&
 		    dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 &&
 		    (cmd->se_cmd_flags & SCF_FUA)) {
-			/*
-			 * We might need to be a bit smarter here
-			 * and return some sense data to let the initiator
-			 * know the FUA WRITE cache sync failed..?
-			 */
-			fd_emulate_write_fua(cmd, task);
-		}
+			struct fd_dev *fd_dev = dev->dev_ptr;
+			loff_t start = task->task_lba *
+				dev->se_sub_dev->se_dev_attrib.block_size;
+			loff_t end = start + task->task_size;
 
+			vfs_fsync_range(fd_dev->fd_file, start, end, 1);
+		}
 	}
 
 	if (ret < 0) {
@@ -478,7 +450,6 @@
 static match_table_t tokens = {
 	{Opt_fd_dev_name, "fd_dev_name=%s"},
 	{Opt_fd_dev_size, "fd_dev_size=%s"},
-	{Opt_fd_buffered_io, "fd_buffered_io=%d"},
 	{Opt_err, NULL}
 };
 
@@ -490,7 +461,7 @@
 	struct fd_dev *fd_dev = se_dev->se_dev_su_ptr;
 	char *orig, *ptr, *arg_p, *opts;
 	substring_t args[MAX_OPT_ARGS];
-	int ret = 0, arg, token;
+	int ret = 0, token;
 
 	opts = kstrdup(page, GFP_KERNEL);
 	if (!opts)
@@ -534,19 +505,6 @@
 					" bytes\n", fd_dev->fd_dev_size);
 			fd_dev->fbd_flags |= FBDF_HAS_SIZE;
 			break;
-		case Opt_fd_buffered_io:
-			match_int(args, &arg);
-			if (arg != 1) {
-				pr_err("bogus fd_buffered_io=%d value\n", arg);
-				ret = -EINVAL;
-				goto out;
-			}
-
-			pr_debug("FILEIO: Using buffered I/O"
-				" operations for struct fd_dev\n");
-
-			fd_dev->fbd_flags |= FDBD_USE_BUFFERED_IO;
-			break;
 		default:
 			break;
 		}
@@ -578,10 +536,8 @@
 	ssize_t bl = 0;
 
 	bl = sprintf(b + bl, "TCM FILEIO ID: %u", fd_dev->fd_dev_id);
-	bl += sprintf(b + bl, "        File: %s  Size: %llu  Mode: %s\n",
-		fd_dev->fd_dev_name, fd_dev->fd_dev_size,
-		(fd_dev->fbd_flags & FDBD_USE_BUFFERED_IO) ?
-		"Buffered" : "Synchronous");
+	bl += sprintf(b + bl, "        File: %s  Size: %llu  Mode: O_DSYNC\n",
+		fd_dev->fd_dev_name, fd_dev->fd_dev_size);
 	return bl;
 }
 
diff -druN linux-libre-3.2.19-gnu/drivers/target/target_core_file.h linux-libre-3.2.20-gnu/drivers/target/target_core_file.h
--- linux-libre-3.2.19-gnu/drivers/target/target_core_file.h	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/drivers/target/target_core_file.h	2012-06-10 09:42:13.000000000 -0400
@@ -18,7 +18,6 @@
 
 #define FBDF_HAS_PATH		0x01
 #define FBDF_HAS_SIZE		0x02
-#define FDBD_USE_BUFFERED_IO	0x04
 
 struct fd_dev {
 	u32		fbd_flags;
diff -druN linux-libre-3.2.19-gnu/fs/attr.c linux-libre-3.2.20-gnu/fs/attr.c
--- linux-libre-3.2.19-gnu/fs/attr.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/fs/attr.c	2012-06-10 09:42:13.000000000 -0400
@@ -176,6 +176,11 @@
 			return -EPERM;
 	}
 
+	if ((ia_valid & ATTR_SIZE) && IS_I_VERSION(inode)) {
+		if (attr->ia_size != inode->i_size)
+			inode_inc_iversion(inode);
+	}
+
 	if ((ia_valid & ATTR_MODE)) {
 		mode_t amode = attr->ia_mode;
 		/* Flag setting protected by i_mutex */
diff -druN linux-libre-3.2.19-gnu/fs/cifs/cifsglob.h linux-libre-3.2.20-gnu/fs/cifs/cifsglob.h
--- linux-libre-3.2.19-gnu/fs/cifs/cifsglob.h	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/fs/cifs/cifsglob.h	2012-06-10 09:42:13.000000000 -0400
@@ -43,6 +43,7 @@
 
 #define CIFS_MIN_RCV_POOL 4
 
+#define MAX_REOPEN_ATT	5 /* these many maximum attempts to reopen a file */
 /*
  * default attribute cache timeout (jiffies)
  */
diff -druN linux-libre-3.2.19-gnu/fs/cifs/cifsproto.h linux-libre-3.2.20-gnu/fs/cifs/cifsproto.h
--- linux-libre-3.2.19-gnu/fs/cifs/cifsproto.h	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/fs/cifs/cifsproto.h	2012-06-10 09:42:13.000000000 -0400
@@ -184,11 +184,13 @@
 
 extern int CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
 		const char *searchName, const struct nls_table *nls_codepage,
-		__u16 *searchHandle, struct cifs_search_info *psrch_inf,
+		__u16 *searchHandle, __u16 search_flags,
+		struct cifs_search_info *psrch_inf,
 		int map, const char dirsep);
 
 extern int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
-		__u16 searchHandle, struct cifs_search_info *psrch_inf);
+		__u16 searchHandle, __u16 search_flags,
+		struct cifs_search_info *psrch_inf);
 
 extern int CIFSFindClose(const int, struct cifs_tcon *tcon,
 			const __u16 search_handle);
diff -druN linux-libre-3.2.19-gnu/fs/cifs/cifssmb.c linux-libre-3.2.20-gnu/fs/cifs/cifssmb.c
--- linux-libre-3.2.19-gnu/fs/cifs/cifssmb.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/fs/cifs/cifssmb.c	2012-06-10 09:42:13.000000000 -0400
@@ -4327,7 +4327,7 @@
 CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
 	      const char *searchName,
 	      const struct nls_table *nls_codepage,
-	      __u16 *pnetfid,
+	      __u16 *pnetfid, __u16 search_flags,
 	      struct cifs_search_info *psrch_inf, int remap, const char dirsep)
 {
 /* level 257 SMB_ */
@@ -4399,8 +4399,7 @@
 	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
 			ATTR_DIRECTORY);
 	pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
-	pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
-		CIFS_SEARCH_RETURN_RESUME);
+	pSMB->SearchFlags = cpu_to_le16(search_flags);
 	pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
 
 	/* BB what should we set StorageType to? Does it matter? BB */
@@ -4470,8 +4469,8 @@
 	return rc;
 }
 
-int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
-		 __u16 searchHandle, struct cifs_search_info *psrch_inf)
+int CIFSFindNext(const int xid, struct cifs_tcon *tcon, __u16 searchHandle,
+		 __u16 search_flags, struct cifs_search_info *psrch_inf)
 {
 	TRANSACTION2_FNEXT_REQ *pSMB = NULL;
 	TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
@@ -4514,8 +4513,7 @@
 		cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
 	pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
 	pSMB->ResumeKey = psrch_inf->resume_key;
-	pSMB->SearchFlags =
-	      cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
+	pSMB->SearchFlags = cpu_to_le16(search_flags);
 
 	name_len = psrch_inf->resume_name_len;
 	params += name_len;
diff -druN linux-libre-3.2.19-gnu/fs/cifs/file.c linux-libre-3.2.20-gnu/fs/cifs/file.c
--- linux-libre-3.2.19-gnu/fs/cifs/file.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/fs/cifs/file.c	2012-06-10 09:42:13.000000000 -0400
@@ -1534,10 +1534,11 @@
 struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
 					bool fsuid_only)
 {
-	struct cifsFileInfo *open_file;
+	struct cifsFileInfo *open_file, *inv_file = NULL;
 	struct cifs_sb_info *cifs_sb;
 	bool any_available = false;
 	int rc;
+	unsigned int refind = 0;
 
 	/* Having a null inode here (because mapping->host was set to zero by
 	the VFS or MM) should not happen but we had reports of on oops (due to
@@ -1557,40 +1558,25 @@
 
 	spin_lock(&cifs_file_list_lock);
 refind_writable:
+	if (refind > MAX_REOPEN_ATT) {
+		spin_unlock(&cifs_file_list_lock);
+		return NULL;
+	}
 	list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
 		if (!any_available && open_file->pid != current->tgid)
 			continue;
 		if (fsuid_only && open_file->uid != current_fsuid())
 			continue;
 		if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
-			cifsFileInfo_get(open_file);
-
 			if (!open_file->invalidHandle) {
 				/* found a good writable file */
+				cifsFileInfo_get(open_file);
 				spin_unlock(&cifs_file_list_lock);
 				return open_file;
+			} else {
+				if (!inv_file)
+					inv_file = open_file;
 			}
-
-			spin_unlock(&cifs_file_list_lock);
-
-			/* Had to unlock since following call can block */
-			rc = cifs_reopen_file(open_file, false);
-			if (!rc)
-				return open_file;
-
-			/* if it fails, try another handle if possible */
-			cFYI(1, "wp failed on reopen file");
-			cifsFileInfo_put(open_file);
-
-			spin_lock(&cifs_file_list_lock);
-
-			/* else we simply continue to the next entry. Thus
-			   we do not loop on reopen errors.  If we
-			   can not reopen the file, for example if we
-			   reconnected to a server with another client
-			   racing to delete or lock the file we would not
-			   make progress if we restarted before the beginning
-			   of the loop here. */
 		}
 	}
 	/* couldn't find useable FH with same pid, try any available */
@@ -1598,7 +1584,30 @@
 		any_available = true;
 		goto refind_writable;
 	}
+
+	if (inv_file) {
+		any_available = false;
+		cifsFileInfo_get(inv_file);
+	}
+
 	spin_unlock(&cifs_file_list_lock);
+
+	if (inv_file) {
+		rc = cifs_reopen_file(inv_file, false);
+		if (!rc)
+			return inv_file;
+		else {
+			spin_lock(&cifs_file_list_lock);
+			list_move_tail(&inv_file->flist,
+					&cifs_inode->openFileList);
+			spin_unlock(&cifs_file_list_lock);
+			cifsFileInfo_put(inv_file);
+			spin_lock(&cifs_file_list_lock);
+			++refind;
+			goto refind_writable;
+		}
+	}
+
 	return NULL;
 }
 
diff -druN linux-libre-3.2.19-gnu/fs/cifs/readdir.c linux-libre-3.2.20-gnu/fs/cifs/readdir.c
--- linux-libre-3.2.19-gnu/fs/cifs/readdir.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/fs/cifs/readdir.c	2012-06-10 09:42:13.000000000 -0400
@@ -219,6 +219,7 @@
 
 static int initiate_cifs_search(const int xid, struct file *file)
 {
+	__u16 search_flags;
 	int rc = 0;
 	char *full_path = NULL;
 	struct cifsFileInfo *cifsFile;
@@ -270,8 +271,12 @@
 		cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO;
 	}
 
+	search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME;
+	if (backup_cred(cifs_sb))
+		search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
+
 	rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls,
-		&cifsFile->netfid, &cifsFile->srch_inf,
+		&cifsFile->netfid, search_flags, &cifsFile->srch_inf,
 		cifs_sb->mnt_cifs_flags &
 			CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
 	if (rc == 0)
@@ -502,11 +507,13 @@
 static int find_cifs_entry(const int xid, struct cifs_tcon *pTcon,
 	struct file *file, char **ppCurrentEntry, int *num_to_ret)
 {
+	__u16 search_flags;
 	int rc = 0;
 	int pos_in_buf = 0;
 	loff_t first_entry_in_buffer;
 	loff_t index_to_find = file->f_pos;
 	struct cifsFileInfo *cifsFile = file->private_data;
+	struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 	/* check if index in the buffer */
 
 	if ((cifsFile == NULL) || (ppCurrentEntry == NULL) ||
@@ -560,10 +567,14 @@
 						cifsFile);
 	}
 
+	search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME;
+	if (backup_cred(cifs_sb))
+		search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
+
 	while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
 	      (rc == 0) && !cifsFile->srch_inf.endOfSearch) {
 		cFYI(1, "calling findnext2");
-		rc = CIFSFindNext(xid, pTcon, cifsFile->netfid,
+		rc = CIFSFindNext(xid, pTcon, cifsFile->netfid, search_flags,
 				  &cifsFile->srch_inf);
 		/* FindFirst/Next set last_entry to NULL on malformed reply */
 		if (cifsFile->srch_inf.last_entry)
diff -druN linux-libre-3.2.19-gnu/fs/exofs/super.c linux-libre-3.2.20-gnu/fs/exofs/super.c
--- linux-libre-3.2.19-gnu/fs/exofs/super.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/fs/exofs/super.c	2012-06-10 09:42:13.000000000 -0400
@@ -745,7 +745,6 @@
 	sbi->one_comp.obj.partition = opts->pid;
 	sbi->one_comp.obj.id = 0;
 	exofs_make_credential(sbi->one_comp.cred, &sbi->one_comp.obj);
-	sbi->oc.numdevs = 1;
 	sbi->oc.single_comp = EC_SINGLE_COMP;
 	sbi->oc.comps = &sbi->one_comp;
 
@@ -803,6 +802,7 @@
 			goto free_sbi;
 
 		ore_comp_set_dev(&sbi->oc, 0, od);
+		sbi->oc.numdevs = 1;
 	}
 
 	__sbi_read_stats(sbi);
diff -druN linux-libre-3.2.19-gnu/fs/ext4/balloc.c linux-libre-3.2.20-gnu/fs/ext4/balloc.c
--- linux-libre-3.2.19-gnu/fs/ext4/balloc.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/fs/ext4/balloc.c	2012-06-10 09:42:13.000000000 -0400
@@ -88,8 +88,8 @@
 	 * unusual file system layouts.
 	 */
 	if (ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp), block_group)) {
-		block_cluster = EXT4_B2C(sbi, (start -
-					       ext4_block_bitmap(sb, gdp)));
+		block_cluster = EXT4_B2C(sbi,
+					 ext4_block_bitmap(sb, gdp) - start);
 		if (block_cluster < num_clusters)
 			block_cluster = -1;
 		else if (block_cluster == num_clusters) {
@@ -100,7 +100,7 @@
 
 	if (ext4_block_in_group(sb, ext4_inode_bitmap(sb, gdp), block_group)) {
 		inode_cluster = EXT4_B2C(sbi,
-					 start - ext4_inode_bitmap(sb, gdp));
+					 ext4_inode_bitmap(sb, gdp) - start);
 		if (inode_cluster < num_clusters)
 			inode_cluster = -1;
 		else if (inode_cluster == num_clusters) {
@@ -112,7 +112,7 @@
 	itbl_blk = ext4_inode_table(sb, gdp);
 	for (i = 0; i < sbi->s_itb_per_group; i++) {
 		if (ext4_block_in_group(sb, itbl_blk + i, block_group)) {
-			c = EXT4_B2C(sbi, start - itbl_blk + i);
+			c = EXT4_B2C(sbi, itbl_blk + i - start);
 			if ((c < num_clusters) || (c == inode_cluster) ||
 			    (c == block_cluster) || (c == itbl_cluster))
 				continue;
diff -druN linux-libre-3.2.19-gnu/fs/ext4/ioctl.c linux-libre-3.2.20-gnu/fs/ext4/ioctl.c
--- linux-libre-3.2.19-gnu/fs/ext4/ioctl.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/fs/ext4/ioctl.c	2012-06-10 09:42:13.000000000 -0400
@@ -36,7 +36,7 @@
 		handle_t *handle = NULL;
 		int err, migrate = 0;
 		struct ext4_iloc iloc;
-		unsigned int oldflags;
+		unsigned int oldflags, mask, i;
 		unsigned int jflag;
 
 		if (!inode_owner_or_capable(inode))
@@ -113,9 +113,14 @@
 		if (err)
 			goto flags_err;
 
-		flags = flags & EXT4_FL_USER_MODIFIABLE;
-		flags |= oldflags & ~EXT4_FL_USER_MODIFIABLE;
-		ei->i_flags = flags;
+		for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
+			if (!(mask & EXT4_FL_USER_MODIFIABLE))
+				continue;
+			if (mask & flags)
+				ext4_set_inode_flag(inode, i);
+			else
+				ext4_clear_inode_flag(inode, i);
+		}
 
 		ext4_set_inode_flags(inode);
 		inode->i_ctime = ext4_current_time(inode);
diff -druN linux-libre-3.2.19-gnu/fs/ext4/mballoc.c linux-libre-3.2.20-gnu/fs/ext4/mballoc.c
--- linux-libre-3.2.19-gnu/fs/ext4/mballoc.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/fs/ext4/mballoc.c	2012-06-10 09:42:13.000000000 -0400
@@ -2567,6 +2567,9 @@
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits);
 
+	if (sbi->s_proc)
+		remove_proc_entry("mb_groups", sbi->s_proc);
+
 	if (sbi->s_group_info) {
 		for (i = 0; i < ngroups; i++) {
 			grinfo = ext4_get_group_info(sb, i);
@@ -2614,8 +2617,6 @@
 	}
 
 	free_percpu(sbi->s_locality_groups);
-	if (sbi->s_proc)
-		remove_proc_entry("mb_groups", sbi->s_proc);
 
 	return 0;
 }
@@ -4693,6 +4694,7 @@
 		 */
 		new_entry = kmem_cache_alloc(ext4_free_ext_cachep, GFP_NOFS);
 		if (!new_entry) {
+			ext4_mb_unload_buddy(&e4b);
 			err = -ENOMEM;
 			goto error_return;
 		}
diff -druN linux-libre-3.2.19-gnu/fs/ext4/namei.c linux-libre-3.2.20-gnu/fs/ext4/namei.c
--- linux-libre-3.2.19-gnu/fs/ext4/namei.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/fs/ext4/namei.c	2012-06-10 09:42:13.000000000 -0400
@@ -1037,6 +1037,12 @@
 			EXT4_ERROR_INODE(dir, "bad inode number: %u", ino);
 			return ERR_PTR(-EIO);
 		}
+		if (unlikely(ino == dir->i_ino)) {
+			EXT4_ERROR_INODE(dir, "'%.*s' linked to parent dir",
+					 dentry->d_name.len,
+					 dentry->d_name.name);
+			return ERR_PTR(-EIO);
+		}
 		inode = ext4_iget(dir->i_sb, ino);
 		if (inode == ERR_PTR(-ESTALE)) {
 			EXT4_ERROR_INODE(dir,
diff -druN linux-libre-3.2.19-gnu/fs/ext4/super.c linux-libre-3.2.20-gnu/fs/ext4/super.c
--- linux-libre-3.2.19-gnu/fs/ext4/super.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/fs/ext4/super.c	2012-06-10 09:42:13.000000000 -0400
@@ -480,6 +480,7 @@
 	printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: comm %s: %pV\n",
 	       sb->s_id, function, line, current->comm, &vaf);
 	va_end(args);
+	save_error_info(sb, function, line);
 
 	ext4_handle_error(sb);
 }
@@ -3727,7 +3728,8 @@
 		goto failed_mount4;
 	}
 
-	ext4_setup_super(sb, es, sb->s_flags & MS_RDONLY);
+	if (ext4_setup_super(sb, es, sb->s_flags & MS_RDONLY))
+		sb->s_flags |= MS_RDONLY;
 
 	/* determine the minimum size of new large inodes, if present */
 	if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) {
diff -druN linux-libre-3.2.19-gnu/fs/namespace.c linux-libre-3.2.20-gnu/fs/namespace.c
--- linux-libre-3.2.19-gnu/fs/namespace.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/fs/namespace.c	2012-06-10 09:42:13.000000000 -0400
@@ -1244,8 +1244,9 @@
 		list_del_init(&p->mnt_expire);
 		list_del_init(&p->mnt_list);
 		__touch_mnt_namespace(p->mnt_ns);
+		if (p->mnt_ns)
+			__mnt_make_shortterm(p);
 		p->mnt_ns = NULL;
-		__mnt_make_shortterm(p);
 		list_del_init(&p->mnt_child);
 		if (p->mnt_parent != p) {
 			p->mnt_parent->mnt_ghosts++;
diff -druN linux-libre-3.2.19-gnu/fs/nfs/nfs4proc.c linux-libre-3.2.20-gnu/fs/nfs/nfs4proc.c
--- linux-libre-3.2.19-gnu/fs/nfs/nfs4proc.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/fs/nfs/nfs4proc.c	2012-06-10 09:42:13.000000000 -0400
@@ -96,6 +96,8 @@
 	case -NFS4ERR_BADOWNER:
 	case -NFS4ERR_BADNAME:
 		return -EINVAL;
+	case -NFS4ERR_SHARE_DENIED:
+		return -EACCES;
 	default:
 		dprintk("%s could not handle NFSv4 error %d\n",
 				__func__, -err);
diff -druN linux-libre-3.2.19-gnu/include/drm/drm_pciids.h linux-libre-3.2.20-gnu/include/drm/drm_pciids.h
--- linux-libre-3.2.19-gnu/include/drm/drm_pciids.h	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/include/drm/drm_pciids.h	2012-06-10 09:42:13.000000000 -0400
@@ -181,6 +181,7 @@
 	{0x1002, 0x6747, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6748, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6749, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x674A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6758, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \
@@ -198,6 +199,7 @@
 	{0x1002, 0x6767, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6768, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6770, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \
+	{0x1002, 0x6771, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6778, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x6779, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \
@@ -493,6 +495,7 @@
 	{0x1002, 0x9645, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x9647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\
 	{0x1002, 0x9648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\
+	{0x1002, 0x9649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\
 	{0x1002, 0x964a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x964b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x964c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
@@ -512,6 +515,7 @@
 	{0x1002, 0x9807, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x9808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0x1002, 0x9809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+	{0x1002, 0x980A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
 	{0, 0, 0}
 
 #define r128_PCI_IDS \
diff -druN linux-libre-3.2.19-gnu/include/linux/Kbuild linux-libre-3.2.20-gnu/include/linux/Kbuild
--- linux-libre-3.2.19-gnu/include/linux/Kbuild	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/include/linux/Kbuild	2012-06-10 09:42:13.000000000 -0400
@@ -224,6 +224,7 @@
 header-y += kdev_t.h
 header-y += kernel.h
 header-y += kernelcapi.h
+header-y += kernel-page-flags.h
 header-y += keyboard.h
 header-y += keyctl.h
 header-y += l2tp.h
diff -druN linux-libre-3.2.19-gnu/include/linux/kernel-page-flags.h linux-libre-3.2.20-gnu/include/linux/kernel-page-flags.h
--- linux-libre-3.2.19-gnu/include/linux/kernel-page-flags.h	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/include/linux/kernel-page-flags.h	2012-06-10 09:42:13.000000000 -0400
@@ -31,6 +31,8 @@
 
 #define KPF_KSM			21
 
+#ifdef __KERNEL__
+
 /* kernel hacking assistances
  * WARNING: subject to change, never rely on them!
  */
@@ -43,4 +45,6 @@
 #define KPF_ARCH		38
 #define KPF_UNCACHED		39
 
+#endif /* __KERNEL__ */
+
 #endif /* LINUX_KERNEL_PAGE_FLAGS_H */
diff -druN linux-libre-3.2.19-gnu/include/linux/netdevice.h linux-libre-3.2.20-gnu/include/linux/netdevice.h
--- linux-libre-3.2.19-gnu/include/linux/netdevice.h	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/include/linux/netdevice.h	2012-06-10 09:42:13.000000000 -0400
@@ -1420,15 +1420,6 @@
 	return 0;
 }
 
-#ifndef CONFIG_NET_NS
-static inline void skb_set_dev(struct sk_buff *skb, struct net_device *dev)
-{
-	skb->dev = dev;
-}
-#else /* CONFIG_NET_NS */
-void skb_set_dev(struct sk_buff *skb, struct net_device *dev);
-#endif
-
 static inline bool netdev_uses_trailer_tags(struct net_device *dev)
 {
 #ifdef CONFIG_NET_DSA_TAG_TRAILER
diff -druN linux-libre-3.2.19-gnu/include/linux/netfilter_bridge.h linux-libre-3.2.20-gnu/include/linux/netfilter_bridge.h
--- linux-libre-3.2.19-gnu/include/linux/netfilter_bridge.h	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/include/linux/netfilter_bridge.h	2012-06-10 09:42:13.000000000 -0400
@@ -104,9 +104,18 @@
 	} daddr;
 };
 
+static inline void br_drop_fake_rtable(struct sk_buff *skb)
+{
+	struct dst_entry *dst = skb_dst(skb);
+
+	if (dst && (dst->flags & DST_FAKE_RTABLE))
+		skb_dst_drop(skb);
+}
+
 #else
 #define nf_bridge_maybe_copy_header(skb)	(0)
 #define nf_bridge_pad(skb)			(0)
+#define br_drop_fake_rtable(skb)	        do { } while (0)
 #endif /* CONFIG_BRIDGE_NETFILTER */
 
 #endif /* __KERNEL__ */
diff -druN linux-libre-3.2.19-gnu/include/linux/skbuff.h linux-libre-3.2.20-gnu/include/linux/skbuff.h
--- linux-libre-3.2.19-gnu/include/linux/skbuff.h	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/include/linux/skbuff.h	2012-06-10 09:42:13.000000000 -0400
@@ -1866,8 +1866,6 @@
 {
 	int delta = 0;
 
-	if (headroom < NET_SKB_PAD)
-		headroom = NET_SKB_PAD;
 	if (headroom > skb_headroom(skb))
 		delta = headroom - skb_headroom(skb);
 
diff -druN linux-libre-3.2.19-gnu/include/net/dst.h linux-libre-3.2.20-gnu/include/net/dst.h
--- linux-libre-3.2.19-gnu/include/net/dst.h	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/include/net/dst.h	2012-06-10 09:42:13.000000000 -0400
@@ -54,6 +54,8 @@
 #define DST_NOCACHE		0x0010
 #define DST_NOCOUNT		0x0020
 #define DST_NOPEER		0x0040
+#define DST_FAKE_RTABLE		0x0080
+#define DST_XFRM_TUNNEL		0x0100
 
 	short			error;
 	short			obsolete;
diff -druN linux-libre-3.2.19-gnu/include/net/sctp/sctp.h linux-libre-3.2.20-gnu/include/net/sctp/sctp.h
--- linux-libre-3.2.19-gnu/include/net/sctp/sctp.h	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/include/net/sctp/sctp.h	2012-06-10 09:42:13.000000000 -0400
@@ -703,4 +703,17 @@
 	addr->v6.sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
 }
 
+/* The cookie is always 0 since this is how it's used in the
+ * pmtu code.
+ */
+static inline struct dst_entry *sctp_transport_dst_check(struct sctp_transport *t)
+{
+	if (t->dst && !dst_check(t->dst, 0)) {
+		dst_release(t->dst);
+		t->dst = NULL;
+	}
+
+	return t->dst;
+}
+
 #endif /* __net_sctp_h__ */
diff -druN linux-libre-3.2.19-gnu/kernel/fork.c linux-libre-3.2.20-gnu/kernel/fork.c
--- linux-libre-3.2.19-gnu/kernel/fork.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/kernel/fork.c	2012-06-10 09:42:13.000000000 -0400
@@ -352,7 +352,8 @@
 		}
 		charge = 0;
 		if (mpnt->vm_flags & VM_ACCOUNT) {
-			unsigned int len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
+			unsigned long len;
+			len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
 			if (security_vm_enough_memory(len))
 				goto fail_nomem;
 			charge = len;
diff -druN linux-libre-3.2.19-gnu/lib/btree.c linux-libre-3.2.20-gnu/lib/btree.c
--- linux-libre-3.2.19-gnu/lib/btree.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/lib/btree.c	2012-06-10 09:42:13.000000000 -0400
@@ -319,8 +319,8 @@
 
 	if (head->height == 0)
 		return NULL;
-retry:
 	longcpy(key, __key, geo->keylen);
+retry:
 	dec_key(geo, key);
 
 	node = head->node;
@@ -351,7 +351,7 @@
 	}
 miss:
 	if (retry_key) {
-		__key = retry_key;
+		longcpy(key, retry_key, geo->keylen);
 		retry_key = NULL;
 		goto retry;
 	}
diff -druN linux-libre-3.2.19-gnu/Makefile linux-libre-3.2.20-gnu/Makefile
--- linux-libre-3.2.19-gnu/Makefile	2012-06-05 00:48:24.000000000 -0400
+++ linux-libre-3.2.20-gnu/Makefile	2012-06-11 15:40:02.000000000 -0400
@@ -1,6 +1,6 @@
 VERSION = 3
 PATCHLEVEL = 2
-SUBLEVEL = 19
+SUBLEVEL = 20
 EXTRAVERSION =-gnu
 NAME = Saber-toothed Squirrel
 
diff -druN linux-libre-3.2.19-gnu/mm/hugetlb.c linux-libre-3.2.20-gnu/mm/hugetlb.c
--- linux-libre-3.2.19-gnu/mm/hugetlb.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/mm/hugetlb.c	2012-06-10 09:42:13.000000000 -0400
@@ -2068,6 +2068,15 @@
 		kref_get(&reservations->refs);
 }
 
+static void resv_map_put(struct vm_area_struct *vma)
+{
+	struct resv_map *reservations = vma_resv_map(vma);
+
+	if (!reservations)
+		return;
+	kref_put(&reservations->refs, resv_map_release);
+}
+
 static void hugetlb_vm_op_close(struct vm_area_struct *vma)
 {
 	struct hstate *h = hstate_vma(vma);
@@ -2083,7 +2092,7 @@
 		reserve = (end - start) -
 			region_count(&reservations->regions, start, end);
 
-		kref_put(&reservations->refs, resv_map_release);
+		resv_map_put(vma);
 
 		if (reserve) {
 			hugetlb_acct_memory(h, -reserve);
@@ -2884,12 +2893,16 @@
 		set_vma_resv_flags(vma, HPAGE_RESV_OWNER);
 	}
 
-	if (chg < 0)
-		return chg;
+	if (chg < 0) {
+		ret = chg;
+		goto out_err;
+	}
 
 	/* There must be enough filesystem quota for the mapping */
-	if (hugetlb_get_quota(inode->i_mapping, chg))
-		return -ENOSPC;
+	if (hugetlb_get_quota(inode->i_mapping, chg)) {
+		ret = -ENOSPC;
+		goto out_err;
+	}
 
 	/*
 	 * Check enough hugepages are available for the reservation.
@@ -2898,7 +2911,7 @@
 	ret = hugetlb_acct_memory(h, chg);
 	if (ret < 0) {
 		hugetlb_put_quota(inode->i_mapping, chg);
-		return ret;
+		goto out_err;
 	}
 
 	/*
@@ -2915,6 +2928,10 @@
 	if (!vma || vma->vm_flags & VM_MAYSHARE)
 		region_add(&inode->i_mapping->private_list, from, to);
 	return 0;
+out_err:
+	if (vma)
+		resv_map_put(vma);
+	return ret;
 }
 
 void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed)
diff -druN linux-libre-3.2.19-gnu/mm/slub.c linux-libre-3.2.20-gnu/mm/slub.c
--- linux-libre-3.2.19-gnu/mm/slub.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/mm/slub.c	2012-06-10 09:42:13.000000000 -0400
@@ -1506,15 +1506,19 @@
 		freelist = page->freelist;
 		counters = page->counters;
 		new.counters = counters;
-		if (mode)
+		if (mode) {
 			new.inuse = page->objects;
+			new.freelist = NULL;
+		} else {
+			new.freelist = freelist;
+		}
 
 		VM_BUG_ON(new.frozen);
 		new.frozen = 1;
 
 	} while (!__cmpxchg_double_slab(s, page,
 			freelist, counters,
-			NULL, new.counters,
+			new.freelist, new.counters,
 			"lock and freeze"));
 
 	remove_partial(n, page);
@@ -1556,7 +1560,6 @@
 			object = t;
 			available =  page->objects - page->inuse;
 		} else {
-			page->freelist = t;
 			available = put_cpu_partial(s, page, 0);
 		}
 		if (kmem_cache_debug(s) || available > s->cpu_partial / 2)
diff -druN linux-libre-3.2.19-gnu/mm/vmalloc.c linux-libre-3.2.20-gnu/mm/vmalloc.c
--- linux-libre-3.2.19-gnu/mm/vmalloc.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/mm/vmalloc.c	2012-06-10 09:42:13.000000000 -0400
@@ -256,7 +256,7 @@
 	struct rb_node rb_node;		/* address sorted rbtree */
 	struct list_head list;		/* address sorted list */
 	struct list_head purge_list;	/* "lazy purge" list */
-	void *private;
+	struct vm_struct *vm;
 	struct rcu_head rcu_head;
 };
 
@@ -1160,9 +1160,10 @@
 	/* Import existing vmlist entries. */
 	for (tmp = vmlist; tmp; tmp = tmp->next) {
 		va = kzalloc(sizeof(struct vmap_area), GFP_NOWAIT);
-		va->flags = tmp->flags | VM_VM_AREA;
+		va->flags = VM_VM_AREA;
 		va->va_start = (unsigned long)tmp->addr;
 		va->va_end = va->va_start + tmp->size;
+		va->vm = tmp;
 		__insert_vmap_area(va);
 	}
 
@@ -1260,7 +1261,7 @@
 	vm->addr = (void *)va->va_start;
 	vm->size = va->va_end - va->va_start;
 	vm->caller = caller;
-	va->private = vm;
+	va->vm = vm;
 	va->flags |= VM_VM_AREA;
 }
 
@@ -1383,7 +1384,7 @@
 
 	va = find_vmap_area((unsigned long)addr);
 	if (va && va->flags & VM_VM_AREA)
-		return va->private;
+		return va->vm;
 
 	return NULL;
 }
@@ -1402,7 +1403,7 @@
 
 	va = find_vmap_area((unsigned long)addr);
 	if (va && va->flags & VM_VM_AREA) {
-		struct vm_struct *vm = va->private;
+		struct vm_struct *vm = va->vm;
 
 		if (!(vm->flags & VM_UNLIST)) {
 			struct vm_struct *tmp, **p;
diff -druN linux-libre-3.2.19-gnu/mm/vmscan.c linux-libre-3.2.20-gnu/mm/vmscan.c
--- linux-libre-3.2.19-gnu/mm/vmscan.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/mm/vmscan.c	2012-06-10 09:42:13.000000000 -0400
@@ -697,7 +697,7 @@
 		return PAGEREF_RECLAIM;
 
 	if (referenced_ptes) {
-		if (PageAnon(page))
+		if (PageSwapBacked(page))
 			return PAGEREF_ACTIVATE;
 		/*
 		 * All mapped pages start out with page table
diff -druN linux-libre-3.2.19-gnu/net/8021q/vlan_dev.c linux-libre-3.2.20-gnu/net/8021q/vlan_dev.c
--- linux-libre-3.2.19-gnu/net/8021q/vlan_dev.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/net/8021q/vlan_dev.c	2012-06-10 09:42:13.000000000 -0400
@@ -156,7 +156,7 @@
 		skb = __vlan_hwaccel_put_tag(skb, vlan_tci);
 	}
 
-	skb_set_dev(skb, vlan_dev_info(dev)->real_dev);
+	skb->dev = vlan_dev_info(dev)->real_dev;
 	len = skb->len;
 	ret = dev_queue_xmit(skb);
 
diff -druN linux-libre-3.2.19-gnu/net/bridge/br_forward.c linux-libre-3.2.20-gnu/net/bridge/br_forward.c
--- linux-libre-3.2.19-gnu/net/bridge/br_forward.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/net/bridge/br_forward.c	2012-06-10 09:42:13.000000000 -0400
@@ -47,6 +47,7 @@
 		kfree_skb(skb);
 	} else {
 		skb_push(skb, ETH_HLEN);
+		br_drop_fake_rtable(skb);
 		dev_queue_xmit(skb);
 	}
 
diff -druN linux-libre-3.2.19-gnu/net/bridge/br_netfilter.c linux-libre-3.2.20-gnu/net/bridge/br_netfilter.c
--- linux-libre-3.2.19-gnu/net/bridge/br_netfilter.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/net/bridge/br_netfilter.c	2012-06-10 09:42:13.000000000 -0400
@@ -147,7 +147,7 @@
 	rt->dst.dev = br->dev;
 	rt->dst.path = &rt->dst;
 	dst_init_metrics(&rt->dst, br_dst_default_metrics, true);
-	rt->dst.flags	= DST_NOXFRM | DST_NOPEER;
+	rt->dst.flags	= DST_NOXFRM | DST_NOPEER | DST_FAKE_RTABLE;
 	rt->dst.ops = &fake_dst_ops;
 }
 
@@ -687,11 +687,7 @@
 				   const struct net_device *out,
 				   int (*okfn)(struct sk_buff *))
 {
-	struct rtable *rt = skb_rtable(skb);
-
-	if (rt && rt == bridge_parent_rtable(in))
-		skb_dst_drop(skb);
-
+	br_drop_fake_rtable(skb);
 	return NF_ACCEPT;
 }
 
diff -druN linux-libre-3.2.19-gnu/net/core/dev.c linux-libre-3.2.20-gnu/net/core/dev.c
--- linux-libre-3.2.19-gnu/net/core/dev.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/net/core/dev.c	2012-06-10 09:42:13.000000000 -0400
@@ -1607,10 +1607,14 @@
 		kfree_skb(skb);
 		return NET_RX_DROP;
 	}
-	skb_set_dev(skb, dev);
+	skb->dev = dev;
+	skb_dst_drop(skb);
 	skb->tstamp.tv64 = 0;
 	skb->pkt_type = PACKET_HOST;
 	skb->protocol = eth_type_trans(skb, dev);
+	skb->mark = 0;
+	secpath_reset(skb);
+	nf_reset(skb);
 	return netif_rx(skb);
 }
 EXPORT_SYMBOL_GPL(dev_forward_skb);
@@ -1865,36 +1869,6 @@
 }
 EXPORT_SYMBOL(netif_device_attach);
 
-/**
- * skb_dev_set -- assign a new device to a buffer
- * @skb: buffer for the new device
- * @dev: network device
- *
- * If an skb is owned by a device already, we have to reset
- * all data private to the namespace a device belongs to
- * before assigning it a new device.
- */
-#ifdef CONFIG_NET_NS
-void skb_set_dev(struct sk_buff *skb, struct net_device *dev)
-{
-	skb_dst_drop(skb);
-	if (skb->dev && !net_eq(dev_net(skb->dev), dev_net(dev))) {
-		secpath_reset(skb);
-		nf_reset(skb);
-		skb_init_secmark(skb);
-		skb->mark = 0;
-		skb->priority = 0;
-		skb->nf_trace = 0;
-		skb->ipvs_property = 0;
-#ifdef CONFIG_NET_SCHED
-		skb->tc_index = 0;
-#endif
-	}
-	skb->dev = dev;
-}
-EXPORT_SYMBOL(skb_set_dev);
-#endif /* CONFIG_NET_NS */
-
 /*
  * Invalidate hardware checksum when packet is to be mangled, and
  * complete checksum manually on outgoing path.
diff -druN linux-libre-3.2.19-gnu/net/ipv4/esp4.c linux-libre-3.2.20-gnu/net/ipv4/esp4.c
--- linux-libre-3.2.19-gnu/net/ipv4/esp4.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/net/ipv4/esp4.c	2012-06-10 09:42:13.000000000 -0400
@@ -457,28 +457,22 @@
 	struct esp_data *esp = x->data;
 	u32 blksize = ALIGN(crypto_aead_blocksize(esp->aead), 4);
 	u32 align = max_t(u32, blksize, esp->padlen);
-	u32 rem;
-
-	mtu -= x->props.header_len + crypto_aead_authsize(esp->aead);
-	rem = mtu & (align - 1);
-	mtu &= ~(align - 1);
+	unsigned int net_adj;
 
 	switch (x->props.mode) {
-	case XFRM_MODE_TUNNEL:
-		break;
-	default:
 	case XFRM_MODE_TRANSPORT:
-		/* The worst case */
-		mtu -= blksize - 4;
-		mtu += min_t(u32, blksize - 4, rem);
-		break;
 	case XFRM_MODE_BEET:
-		/* The worst case. */
-		mtu += min_t(u32, IPV4_BEET_PHMAXLEN, rem);
+		net_adj = sizeof(struct iphdr);
+		break;
+	case XFRM_MODE_TUNNEL:
+		net_adj = 0;
 		break;
+	default:
+		BUG();
 	}
 
-	return mtu - 2;
+	return ((mtu - x->props.header_len - crypto_aead_authsize(esp->aead) -
+		 net_adj) & ~(align - 1)) + (net_adj - 2);
 }
 
 static void esp4_err(struct sk_buff *skb, u32 info)
diff -druN linux-libre-3.2.19-gnu/net/ipv4/fib_semantics.c linux-libre-3.2.20-gnu/net/ipv4/fib_semantics.c
--- linux-libre-3.2.19-gnu/net/ipv4/fib_semantics.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/net/ipv4/fib_semantics.c	2012-06-10 09:42:13.000000000 -0400
@@ -146,6 +146,12 @@
 {
 	struct fib_info *fi = container_of(head, struct fib_info, rcu);
 
+	change_nexthops(fi) {
+		if (nexthop_nh->nh_dev)
+			dev_put(nexthop_nh->nh_dev);
+	} endfor_nexthops(fi);
+
+	release_net(fi->fib_net);
 	if (fi->fib_metrics != (u32 *) dst_default_metrics)
 		kfree(fi->fib_metrics);
 	kfree(fi);
@@ -157,13 +163,7 @@
 		pr_warning("Freeing alive fib_info %p\n", fi);
 		return;
 	}
-	change_nexthops(fi) {
-		if (nexthop_nh->nh_dev)
-			dev_put(nexthop_nh->nh_dev);
-		nexthop_nh->nh_dev = NULL;
-	} endfor_nexthops(fi);
 	fib_info_cnt--;
-	release_net(fi->fib_net);
 	call_rcu(&fi->rcu, free_fib_info_rcu);
 }
 
diff -druN linux-libre-3.2.19-gnu/net/ipv4/fib_trie.c linux-libre-3.2.20-gnu/net/ipv4/fib_trie.c
--- linux-libre-3.2.19-gnu/net/ipv4/fib_trie.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/net/ipv4/fib_trie.c	2012-06-10 09:42:13.000000000 -0400
@@ -1372,6 +1372,8 @@
 
 			if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos)
 				continue;
+			if (fi->fib_dead)
+				continue;
 			if (fa->fa_info->fib_scope < flp->flowi4_scope)
 				continue;
 			fib_alias_accessed(fa);
diff -druN linux-libre-3.2.19-gnu/net/ipv6/esp6.c linux-libre-3.2.20-gnu/net/ipv6/esp6.c
--- linux-libre-3.2.19-gnu/net/ipv6/esp6.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/net/ipv6/esp6.c	2012-06-10 09:42:13.000000000 -0400
@@ -411,19 +411,15 @@
 	struct esp_data *esp = x->data;
 	u32 blksize = ALIGN(crypto_aead_blocksize(esp->aead), 4);
 	u32 align = max_t(u32, blksize, esp->padlen);
-	u32 rem;
-
-	mtu -= x->props.header_len + crypto_aead_authsize(esp->aead);
-	rem = mtu & (align - 1);
-	mtu &= ~(align - 1);
+	unsigned int net_adj;
 
-	if (x->props.mode != XFRM_MODE_TUNNEL) {
-		u32 padsize = ((blksize - 1) & 7) + 1;
-		mtu -= blksize - padsize;
-		mtu += min_t(u32, blksize - padsize, rem);
-	}
+	if (x->props.mode != XFRM_MODE_TUNNEL)
+		net_adj = sizeof(struct ipv6hdr);
+	else
+		net_adj = 0;
 
-	return mtu - 2;
+	return ((mtu - x->props.header_len - crypto_aead_authsize(esp->aead) -
+		 net_adj) & ~(align - 1)) + (net_adj - 2);
 }
 
 static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
diff -druN linux-libre-3.2.19-gnu/net/ipv6/ip6_output.c linux-libre-3.2.20-gnu/net/ipv6/ip6_output.c
--- linux-libre-3.2.19-gnu/net/ipv6/ip6_output.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/net/ipv6/ip6_output.c	2012-06-10 09:42:13.000000000 -0400
@@ -1178,6 +1178,29 @@
 	return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL;
 }
 
+static void ip6_append_data_mtu(int *mtu,
+				int *maxfraglen,
+				unsigned int fragheaderlen,
+				struct sk_buff *skb,
+				struct rt6_info *rt)
+{
+	if (!(rt->dst.flags & DST_XFRM_TUNNEL)) {
+		if (skb == NULL) {
+			/* first fragment, reserve header_len */
+			*mtu = *mtu - rt->dst.header_len;
+
+		} else {
+			/*
+			 * this fragment is not first, the headers
+			 * space is regarded as data space.
+			 */
+			*mtu = dst_mtu(rt->dst.path);
+		}
+		*maxfraglen = ((*mtu - fragheaderlen) & ~7)
+			      + fragheaderlen - sizeof(struct frag_hdr);
+	}
+}
+
 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,
@@ -1187,7 +1210,7 @@
 	struct inet_sock *inet = inet_sk(sk);
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct inet_cork *cork;
-	struct sk_buff *skb;
+	struct sk_buff *skb, *skb_prev = NULL;
 	unsigned int maxfraglen, fragheaderlen;
 	int exthdrlen;
 	int dst_exthdrlen;
@@ -1245,8 +1268,12 @@
 		inet->cork.fl.u.ip6 = *fl6;
 		np->cork.hop_limit = hlimit;
 		np->cork.tclass = tclass;
-		mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ?
-		      rt->dst.dev->mtu : dst_mtu(&rt->dst);
+		if (rt->dst.flags & DST_XFRM_TUNNEL)
+			mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ?
+			      rt->dst.dev->mtu : dst_mtu(&rt->dst);
+		else
+			mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ?
+			      rt->dst.dev->mtu : dst_mtu(rt->dst.path);
 		if (np->frag_size < mtu) {
 			if (np->frag_size)
 				mtu = np->frag_size;
@@ -1342,25 +1369,27 @@
 			unsigned int fraglen;
 			unsigned int fraggap;
 			unsigned int alloclen;
-			struct sk_buff *skb_prev;
 alloc_new_skb:
-			skb_prev = skb;
-
 			/* There's no room in the current skb */
-			if (skb_prev)
-				fraggap = skb_prev->len - maxfraglen;
+			if (skb)
+				fraggap = skb->len - maxfraglen;
 			else
 				fraggap = 0;
+			/* update mtu and maxfraglen if necessary */
+			if (skb == NULL || skb_prev == NULL)
+				ip6_append_data_mtu(&mtu, &maxfraglen,
+						    fragheaderlen, skb, rt);
+
+			skb_prev = skb;
 
 			/*
 			 * If remaining data exceeds the mtu,
 			 * we know we need more fragment(s).
 			 */
 			datalen = length + fraggap;
-			if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen)
-				datalen = maxfraglen - fragheaderlen;
 
-			fraglen = datalen + fragheaderlen;
+			if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen)
+				datalen = maxfraglen - fragheaderlen - rt->dst.trailer_len;
 			if ((flags & MSG_MORE) &&
 			    !(rt->dst.dev->features&NETIF_F_SG))
 				alloclen = mtu;
@@ -1369,13 +1398,16 @@
 
 			alloclen += dst_exthdrlen;
 
-			/*
-			 * The last fragment gets additional space at tail.
-			 * Note: we overallocate on fragments with MSG_MODE
-			 * because we have no idea if we're the last one.
-			 */
-			if (datalen == length + fraggap)
-				alloclen += rt->dst.trailer_len;
+			if (datalen != length + fraggap) {
+				/*
+				 * this is not the last fragment, the trailer
+				 * space is regarded as data space.
+				 */
+				datalen += rt->dst.trailer_len;
+			}
+
+			alloclen += rt->dst.trailer_len;
+			fraglen = datalen + fragheaderlen;
 
 			/*
 			 * We just reserve space for fragment header.
diff -druN linux-libre-3.2.19-gnu/net/l2tp/l2tp_ip.c linux-libre-3.2.20-gnu/net/l2tp/l2tp_ip.c
--- linux-libre-3.2.19-gnu/net/l2tp/l2tp_ip.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/net/l2tp/l2tp_ip.c	2012-06-10 09:42:13.000000000 -0400
@@ -251,9 +251,16 @@
 {
 	struct inet_sock *inet = inet_sk(sk);
 	struct sockaddr_l2tpip *addr = (struct sockaddr_l2tpip *) uaddr;
-	int ret = -EINVAL;
+	int ret;
 	int chk_addr_ret;
 
+	if (!sock_flag(sk, SOCK_ZAPPED))
+		return -EINVAL;
+	if (addr_len < sizeof(struct sockaddr_l2tpip))
+		return -EINVAL;
+	if (addr->l2tp_family != AF_INET)
+		return -EINVAL;
+
 	ret = -EADDRINUSE;
 	read_lock_bh(&l2tp_ip_lock);
 	if (__l2tp_ip_bind_lookup(&init_net, addr->l2tp_addr.s_addr, sk->sk_bound_dev_if, addr->l2tp_conn_id))
@@ -283,6 +290,8 @@
 	sk_del_node_init(sk);
 	write_unlock_bh(&l2tp_ip_lock);
 	ret = 0;
+	sock_reset_flag(sk, SOCK_ZAPPED);
+
 out:
 	release_sock(sk);
 
@@ -303,13 +312,14 @@
 	__be32 saddr;
 	int oif, rc;
 
-	rc = -EINVAL;
+	if (sock_flag(sk, SOCK_ZAPPED)) /* Must bind first - autobinding does not work */
+		return -EINVAL;
+
 	if (addr_len < sizeof(*lsa))
-		goto out;
+		return -EINVAL;
 
-	rc = -EAFNOSUPPORT;
 	if (lsa->l2tp_family != AF_INET)
-		goto out;
+		return -EAFNOSUPPORT;
 
 	lock_sock(sk);
 
@@ -363,6 +373,14 @@
 	return rc;
 }
 
+static int l2tp_ip_disconnect(struct sock *sk, int flags)
+{
+	if (sock_flag(sk, SOCK_ZAPPED))
+		return 0;
+
+	return udp_disconnect(sk, flags);
+}
+
 static int l2tp_ip_getname(struct socket *sock, struct sockaddr *uaddr,
 			   int *uaddr_len, int peer)
 {
@@ -598,7 +616,7 @@
 	.close		   = l2tp_ip_close,
 	.bind		   = l2tp_ip_bind,
 	.connect	   = l2tp_ip_connect,
-	.disconnect	   = udp_disconnect,
+	.disconnect	   = l2tp_ip_disconnect,
 	.ioctl		   = udp_ioctl,
 	.destroy	   = l2tp_ip_destroy_sock,
 	.setsockopt	   = ip_setsockopt,
diff -druN linux-libre-3.2.19-gnu/net/mac80211/util.c linux-libre-3.2.20-gnu/net/mac80211/util.c
--- linux-libre-3.2.19-gnu/net/mac80211/util.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/net/mac80211/util.c	2012-06-10 09:42:13.000000000 -0400
@@ -1111,6 +1111,12 @@
 		}
 	}
 
+	/* add back keys */
+	list_for_each_entry(sdata, &local->interfaces, list)
+		if (ieee80211_sdata_running(sdata))
+			ieee80211_enable_keys(sdata);
+
+ wake_up:
 	/*
 	 * Clear the WLAN_STA_BLOCK_BA flag so new aggregation
 	 * sessions can be established after a resume.
@@ -1132,12 +1138,6 @@
 		mutex_unlock(&local->sta_mtx);
 	}
 
-	/* add back keys */
-	list_for_each_entry(sdata, &local->interfaces, list)
-		if (ieee80211_sdata_running(sdata))
-			ieee80211_enable_keys(sdata);
-
- wake_up:
 	ieee80211_wake_queues_by_reason(hw,
 			IEEE80211_QUEUE_STOP_REASON_SUSPEND);
 
diff -druN linux-libre-3.2.19-gnu/net/sctp/output.c linux-libre-3.2.20-gnu/net/sctp/output.c
--- linux-libre-3.2.19-gnu/net/sctp/output.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/net/sctp/output.c	2012-06-10 09:42:13.000000000 -0400
@@ -377,9 +377,7 @@
 	 */
 	skb_set_owner_w(nskb, sk);
 
-	/* The 'obsolete' field of dst is set to 2 when a dst is freed. */
-	if (!dst || (dst->obsolete > 1)) {
-		dst_release(dst);
+	if (!sctp_transport_dst_check(tp)) {
 		sctp_transport_route(tp, NULL, sctp_sk(sk));
 		if (asoc && (asoc->param_flags & SPP_PMTUD_ENABLE)) {
 			sctp_assoc_sync_pmtu(asoc);
diff -druN linux-libre-3.2.19-gnu/net/sctp/transport.c linux-libre-3.2.20-gnu/net/sctp/transport.c
--- linux-libre-3.2.19-gnu/net/sctp/transport.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/net/sctp/transport.c	2012-06-10 09:42:13.000000000 -0400
@@ -226,23 +226,6 @@
 		transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT;
 }
 
-/* this is a complete rip-off from __sk_dst_check
- * the cookie is always 0 since this is how it's used in the
- * pmtu code
- */
-static struct dst_entry *sctp_transport_dst_check(struct sctp_transport *t)
-{
-	struct dst_entry *dst = t->dst;
-
-	if (dst && dst->obsolete && dst->ops->check(dst, 0) == NULL) {
-		dst_release(t->dst);
-		t->dst = NULL;
-		return NULL;
-	}
-
-	return dst;
-}
-
 void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu)
 {
 	struct dst_entry *dst;
diff -druN linux-libre-3.2.19-gnu/net/sunrpc/clnt.c linux-libre-3.2.20-gnu/net/sunrpc/clnt.c
--- linux-libre-3.2.19-gnu/net/sunrpc/clnt.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/net/sunrpc/clnt.c	2012-06-10 09:42:13.000000000 -0400
@@ -959,6 +959,8 @@
 	}
 
 	switch (status) {
+	case -ENOMEM:
+		rpc_delay(task, HZ >> 2);
 	case -EAGAIN:	/* woken up; retry */
 		task->tk_action = call_reserve;
 		return;
diff -druN linux-libre-3.2.19-gnu/net/sunrpc/xprt.c linux-libre-3.2.20-gnu/net/sunrpc/xprt.c
--- linux-libre-3.2.19-gnu/net/sunrpc/xprt.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/net/sunrpc/xprt.c	2012-06-10 09:42:13.000000000 -0400
@@ -977,15 +977,16 @@
 		goto out_init_req;
 	switch (PTR_ERR(req)) {
 	case -ENOMEM:
-		rpc_delay(task, HZ >> 2);
 		dprintk("RPC:       dynamic allocation of request slot "
 				"failed! Retrying\n");
+		task->tk_status = -ENOMEM;
 		break;
 	case -EAGAIN:
 		rpc_sleep_on(&xprt->backlog, task, NULL);
 		dprintk("RPC:       waiting for request slot\n");
+	default:
+		task->tk_status = -EAGAIN;
 	}
-	task->tk_status = -EAGAIN;
 	return;
 out_init_req:
 	task->tk_status = 0;
diff -druN linux-libre-3.2.19-gnu/net/xfrm/xfrm_policy.c linux-libre-3.2.20-gnu/net/xfrm/xfrm_policy.c
--- linux-libre-3.2.19-gnu/net/xfrm/xfrm_policy.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/net/xfrm/xfrm_policy.c	2012-06-10 09:42:13.000000000 -0400
@@ -1919,6 +1919,9 @@
 	}
 ok:
 	xfrm_pols_put(pols, drop_pols);
+	if (dst && dst->xfrm &&
+	    dst->xfrm->props.mode == XFRM_MODE_TUNNEL)
+		dst->flags |= DST_XFRM_TUNNEL;
 	return dst;
 
 nopol:
diff -druN linux-libre-3.2.19-gnu/sound/usb/pcm.c linux-libre-3.2.20-gnu/sound/usb/pcm.c
--- linux-libre-3.2.19-gnu/sound/usb/pcm.c	2012-05-30 19:44:12.000000000 -0400
+++ linux-libre-3.2.20-gnu/sound/usb/pcm.c	2012-06-10 09:42:13.000000000 -0400
@@ -698,6 +698,9 @@
 	int count = 0, needs_knot = 0;
 	int err;
 
+	kfree(subs->rate_list.list);
+	subs->rate_list.list = NULL;
+
 	list_for_each_entry(fp, &subs->fmt_list, list) {
 		if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)
 			return 0;
